summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/catoptions
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-08-19 22:18:46 +0000
committerKarl Berry <karl@freefriends.org>2012-08-19 22:18:46 +0000
commit193b74d3d594d824d23f6413dd0d784fd4a756fc (patch)
treed51c5f2613702b8e1d9596b49bbdc644446b83f1 /Master/texmf-dist/tex/latex/catoptions
parentf5cea8308088d502f2e2760a784b372c4ebe711f (diff)
catoptions (19aug12)
git-svn-id: svn://tug.org/texlive/trunk@27460 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/catoptions')
-rw-r--r--Master/texmf-dist/tex/latex/catoptions/catoptions.sty1368
1 files changed, 1110 insertions, 258 deletions
diff --git a/Master/texmf-dist/tex/latex/catoptions/catoptions.sty b/Master/texmf-dist/tex/latex/catoptions/catoptions.sty
index 1678941a59a..b5cd097fc37 100644
--- a/Master/texmf-dist/tex/latex/catoptions/catoptions.sty
+++ b/Master/texmf-dist/tex/latex/catoptions/catoptions.sty
@@ -1,5 +1,5 @@
%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
-% This is 'catoptions' package, version 0.2.7b, 2011/12/17. %
+% This is 'catoptions' package, version 0.2.7d, 2012/08/02. %
% %
% The catoptions package changes LaTeX package loading internals %
% so that all subsequently loaded packages can rely on having %
@@ -20,8 +20,7 @@
% %
% The LPPL maintenance status of this software is 'author-maintained'. %
% %
-% Copyright (c) 2010-2011 Ahmed Musa (amusa22@gmail.com). %
-% %
+% Copyright (c) 2010-2012 Ahmed Musa (amusa22@gmail.com). %
%+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++%
\begingroup
@@ -85,15 +84,21 @@
\catcode94=7
\catcode126=13
\AtEndOfPackage{%
+ % Commands to discard later, after all the packages that
+ % need them have been updated on CTAN:
\newletcsset{%
\dofunclist=\cptdofunclist,
\docommalist=\cptdocommalist,
+ \dosisolist=\cptdosisolist,
\newvariables=\cptnewvariables,
\stripallouterbraces=\cptstripallouterbraces,
\stripouterbraces=\cptstripNouterbraces,
+ \stripallouterbracesincs=\cptstripallouterbracesincs,
\gobble@to@relax=\cptgobbletorelax,
\cpt@gobbletorelax=\cptgobbletorelax,
- \cpt@gobbletorelax@fi@endgroup=\cptbgobbletorelax
+ \cpt@gobbletorelax@fi@endgroup=\cptbgobbletorelax,
+ \ifcasse=\cptifcasse,
+ \docasse=\cptdocasse,
}%
}
\edef\cpt@hashchar{\string#}
@@ -107,7 +112,7 @@
\chardef\active=13
\NeedsTeXFormat{LaTeX2e}[2011/06/27]
\ProvidesPackage{catoptions}
- [2011/12/17 v0.2.7b Securing catcodes and parsing options (AM)]
+ [2012/08/02 v0.2.7d Securing catcodes and parsing options (AM)]
\ifcase%
\ifx\eTeXversion\cpt@undefined\z@pt\else
\ifnum\eTeXversion<\tw@\z@pt\else\@ne\fi\fi
@@ -115,34 +120,49 @@
{This package requires eTeX version 2 or higher.}%
\expandafter\endinput
\fi
+\protected\def\cptloggingall{%
+ \tracinggroups\@ne\tracingifs\@ne\tracingall\tracingassigns\@ne
+}
+\let\cpttracingall\cptloggingall
% \ifcsdefinable, \cpt@starorlong, \cptcommanormalize, etc,
% change later on:
\@ifdefinable\ifcsdefinable{\let\ifcsdefinable\@ifdefinable}
-\@ifdefinable\ifdefinablelet\relax
-\protected\def\ifdefinablelet#1{\ifcsdefinable#1\relax\let#1}
-\ifdefinablelet\cpt@nil\relax
+\@ifdefinable\cptnewlet\relax
+% Don't put '=' after \let#1, in case the caller uses '=':
+\protected\def\cptnewlet#1{\ifcsdefinable#1\relax\let#1}
+\cptnewlet\cpt@nil\relax
\newcommand*\cpt@nnil{\cpt@nil}
\let\@iden\@firstofone
-\ifdefinablelet\iofii\@firstoftwo
-\ifdefinablelet\iiofii\@secondoftwo
+\cptnewlet\iofii\@firstoftwo
+\cptnewlet\iiofii\@secondoftwo
\@ifdefinable\ifforbreak{\newif\ifforbreak}
-\ifdefinablelet\cpt@starorlong\@star@or@long
-\ifdefinablelet\cpt@testopt\@testopt
-\ifdefinablelet\cptcommanormalize\unexpanded
-\protected\def\ifnot@nil#1{%
+\cptnewlet\cpt@starorlong\@star@or@long
+\cptnewlet\cpt@testopt\@testopt
+\cptnewlet\cptcommanormalize\unexpanded
+\protected\def\ifnotnilTF#1#2{%
\begingroup
- \edef\reserved@a{\unexpanded{#1}}%
+ \edef\reserved@a{\cpttrimspace{#1}}%
+ \def\reserved@b{#2}%
\expandafter\endgroup
- \ifx\reserved@a\@nnil\expandafter\@gobble
+ \ifx\reserved@a\reserved@b\expandafter\@gobble
\else\expandafter\@iden\fi
}
+\newcommand*\defifxTF[2]{%
+ \begingroup
+ \edef\reserved@a{\cpttrimspace{#1}}%
+ \expandafter\endgroup\ifx#2\reserved@a
+ \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
+}
\newcommand*\cpt@for@nil{\cpt@for@nil}
+% Simple, 1-dimensional comma loop. \forbreak can be used to break
+% out of the loop. \do may appear in #1; so we can't use \do as delimiter:
\protected\def\cptfor#1\dofor#2{%
\def\cpt@fordo##1,{\cpt@for@a,\cpt@fordo{##1}{#2}}%
\edef\reserved@a{\cptcommanormalize{#1}}%
\forbreakfalse
\expandafter\cpt@fordo\reserved@a,\cpt@for@nil,%
}
+% Simple, 1-dimensional tsv loop:
\protected\def\cpttfor#1\dofor#2{%
\def\cpt@tfordo##1{\cpt@for@a{}\cpt@tfordo{##1}{#2}}%
\forbreakfalse\cpt@tfordo#1\cpt@for@nil
@@ -155,6 +175,19 @@
{\def\reserved@a##1\cpt@for@nil#1{}\reserved@a}{#4#2}%
}%
}
+% \foreachmeer{<list>}<processor>
+% Expandable comma loop. The \noexpand before #1 is required when #1
+% begins with a command. <processor> must be pre-defined by the user:
+\newcommand*\foreachmeer[2]{%
+ \expandafter\cpt@foreachmeer@a\romannumeral
+ -`\q\cptcommanormalize{\noexpand#1},\cpt@nnil,\meer@nil{#2}%
+}
+\def\cpt@foreachmeer@a#1,#2\meer@nil#3{%
+ \expandafter\ifx\cpt@car#1\car@nil\cpt@nnil
+ \expandafter\iofii\else\expandafter\iiofii\fi
+ {}{#3{#1}\cpt@foreachmeer@a#2\meer@nil{#3}}%
+}
+% Unique \chardef'd token:
\ifcsdefinable\cptchardef{%
\protected\def\cptchardef#1#2 {%
\ifcsdefinable#1{%
@@ -183,8 +216,19 @@
{\expandafter\newcount\csname#1##1\endcsname}%
}%
}
-\newcommand*\cptnewcounters[2][]{%
- \cptfor#2\dofor{\newcounter{#1##1}}%
+% \cptnewcounters[<pref>]{a,b}[<master>]
+\newcommand*\cptnewcounters{\cpt@testopt\cpt@newcounters{}}
+\def\cpt@newcounters[#1]#2{%
+ \cpt@testopt{\cpt@newc@unters{#1}{#2}}{}%
+}
+\def\cpt@newc@unters#1#2[#3]{%
+ \cptfor#2\dofor{%
+ \ifcat&\detokenize{#3}&\relax
+ \newcounter{#1##1}%
+ \else
+ \newcounter{#1##1}[#3]%
+ \fi
+ }%
}
\newcommand*\cptnewdimens[2][]{%
\cptfor#2\dofor{%
@@ -211,8 +255,11 @@
}%
}
\newcommand\ifxFT[2]{\ifxTF{#1}{#2}\iiofii\iofii}
+\def\cpt@ifcseq@#1#2\cpt@ifcseq@nil{\expandafter#1}
\newcommand\ifcseqTF[2]{%
- \ifx#1#2\cpt@quark\expandafter\iofii\else\expandafter\iiofii\fi
+ \csname @\expandafter\expandafter\expandafter
+ \ifx\cpt@ifcseq@#1\batchmode\cpt@ifcseq@nil\cpt@car#2\noboundary\car@nil
+ first\else second\fi oftwo\endcsname
}
\newcommand\ifcseqFT[2]{\ifcseqTF{#1}{#2}\iiofii\iofii}
\newcommand*\ifxcseqTF[2]{%
@@ -224,12 +271,6 @@
\iofii\iiofii
}%
}
-\newcommand*\defifxTF[2]{%
- \begingroup
- \edef\reserved@a{\unexpanded{#1}}%
- \expandafter\endgroup\ifx#2\reserved@a
- \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi
-}
\newcommand\ifnullTF[3]{%
\romannumeral\iffalse{\fi\expandafter\@secondoftwo\expandafter
{\expandafter{\string#1}\expandafter\@secondoftwo\string}%
@@ -247,20 +288,9 @@
\ifcat$\detokenize\expandafter{\@gobble#1.}$%
}
\newcommand\ifbracedTF[3]{%
- \romannumeral
- \ifcase
- \iffalse{{{\fi\expandafter\expandafter\expandafter
- \@gobble\expandafter\expandafter\expandafter
- {\expandafter\expandafter\expandafter{\expandafter
- \iffalse\expandafter}\expandafter}\expandafter\fi
- \string#1}\m@one}\@ne}\z@pt
- \expandafter\@secondoftwo
- \or
- \expandafter\@secondoftwo
- \else
- \expandafter\@firstoftwo
- \fi
- {0 #2}{0 #3}%
+ \romannumeral\expandafter\@secondoftwo\expandafter{\expandafter
+ {\string#1.}\expandafter\@firstoftwo\expandafter{\iffalse}\fi
+ 0 #2}{0 #3}%
}
\newcommand\ifbracedFT[1]{\ifbracedTF{#1}\iiofii\iofii}
\newcommand\ifleadspaceTF[3]{%
@@ -272,7 +302,6 @@
\expandafter\ifnullTF\expandafter{\@gobble#1}{first}{second}%
\expandafter\@gobble\expandafter{\iffalse}\fi
}
-%%++ Ulrich Diez:
\newcommand\iftrailspaceTF[1]{%
\romannumeral-`\q
\csname @\expandafter\@firstofone\expandafter{%
@@ -299,7 +328,6 @@
\expandafter\cpt@iftrailspace\expandafter{\cpt@removetospace.#1}%
}%
}
-%%--
\ifxTF\pdfstrcmp\cpt@undefined{%
\RequirePackage{pdftexcmds}%
@@ -517,7 +545,7 @@
\def\neededfutureletchars{}%
\def\cpt@tempa##1\@##2\@{%
\ifx##1\end\else
- \cptgaddtolist\neededfutureletchars{##1}%
+ \cptguaddtolist\neededfutureletchars{##1}%
\expandafter\cpt@tempa
\fi
}%
@@ -662,6 +690,7 @@
\ifcat\noexpand#1\noexpand~13\else
-1\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
}
+
\robust@def\cpt@ifnextchar#1#2#3{%
\begingroup
\let\reserved@a=#1%
@@ -704,6 +733,7 @@
\ifx\x first\else second\fi oftwo\endcsname
{#2}{#3}#4%
}
+% Must be expandable:
\new@def\cpt@ifn@xtch@racter#1{%
\expandafter\cpt@ifn@xtch@r@cter\string#1\relax\noboundary{#1}%
}
@@ -714,8 +744,12 @@
\robust@redef*\cpt@starorlong#1{%
\cpt@ifstar{\let\l@ngrel@x\relax#1}{\let\l@ngrel@x\long#1}%
}
-\new@def*\ifsecondisnnilTF#1#2\cpt@nil{%
- \expandafter\ifxTF\cpt@car#2\car@nil\cpt@nnil
+\new@def*\ifsecondisnnilTF#1{%
+ \expandafter\expandafter\expandafter\cpt@ifsecondisnnil
+ \expandafter\string\noexpand#1\cpt@nnil\cpt@nil
+}
+\new@def*\cpt@ifsecondisnnil#1#2\cpt@nil{%
+ \expandafter\ifcseqTF\cpt@car#2\car@nil\cpt@nnil
}
\new@def\aftercsname#1#2{%
\expandafter\cptswap\expandafter{\csname#2\endcsname}{#1}%
@@ -732,7 +766,7 @@
}
%% For internal use; #1 must be one token:
\new@def*\simpleexpandarg#1#2{\expandafter#1\expandafter{#2}}
-\ifdefinablelet\s@expandarg\simpleexpandarg
+\cptnewlet\s@expandarg\simpleexpandarg
%%--
\new@def*\cptexpandnext#1#2{%
@@ -745,7 +779,7 @@
\new@def*\cptexpandbracenext#1#2{%
\expandafter\cptswapbracefirst\expandafter{#2}{#1}%
}
-\ifdefinablelet\cptexpandbrnext\cptexpandbracenext
+\cptnewlet\cptexpandbrnext\cptexpandbracenext
\new@def*\cptexpandsome#1\expandthis#2#3\expandstop{%
\cptexpandnext{#1}{#2}#3%
}
@@ -773,11 +807,21 @@
\ifdefTF{#1}{#1}{\cpt@notdeferr{#1}}%
}
\new@def*\usecsifdef#1{\ifdefTF#1{#1}{}}
+\new@def*\expandonceifmacroelsenil#1{%
+ \ifmacroTF{#1}{%
+ \ifexpandableTF{#1}{%
+ \expandcsonce{#1}%
+ }{%
+ \unexpanded{#1}%
+ }%
+ }{}%
+}
\new@def\usename#1{\csname#1\endcsname}% long!
\new@def\usecsn#1{%
\ifcsname#1\endcsname\expandafter\@iden\else
\expandafter\@gobble\fi{\usename{#1}}%
}
+% \usecsnifdef is stronger than \usecsn:
\new@def*\usecsnifdef#1{\ifcsndefTF{#1}{\usename{#1}}{}}
\new@def\uselivecsn#1{%
\ifcsndefTF{#1}{%
@@ -787,11 +831,13 @@
\cpt@err{Command '\@backslashchar#1' undefined}\@ehc
}%
}
-\new@def*\ifcondTF#1\fi#2#3{%
- \romannumeral#1 \expandafter\@firstoftwo\else
- \expandafter\@secondoftwo\fi{0 #2}{0 #3}%
+
+% The following syntax is needed for calling \ifcondTF in \edef.
+\new@def\ifcondTF#1\endcond#2#3{%
+ \romannumeral\csname @#1first\else second\fi oftwo\endcsname
+ {0 #2}{0 #3}%
}
-\long\def\ifcondFT#1\fi#2#3{\ifcondTF#1\fi{#3}{#2}}
+\new@def\ifcondFT#1\endcond#2#3{\ifcondTF#1\endcond{#3}{#2}}
\new@def*\ifcsnameTF#1{%
\ifblankTF{#1}\@secondoftwo{%
\usename{@\ifcsname#1\endcsname first\else second\fi oftwo}%
@@ -825,9 +871,9 @@
\cptpassexpanded{%
\endgroup
\ifcase#1\relax
- \ifboolTF{cpt@choicefd}\iofii\iiofii
+ \ifdefboolTF{cpt@choicefd}\iofii\iiofii
\or
- \ifboolTF{cpt@choicefd}\iiofii\iofii
+ \ifdefboolTF{cpt@choicefd}\iiofii\iofii
\else
\cpt@err{Invalid number '#1'}\noexpand\@ehc
\fi
@@ -838,6 +884,9 @@
{\detokenize{macro parameter character}}
{\meaning\@let@token}%
}
+% \cptcommanormalize is cheap but is restricted to comma lists only.
+% Also, it isn't meant for parsing keyval lists. See \kv@@normalize
+% and \kv@@parse:
\begingroup
\uccode`\~=`\,%
\uppercase{\endgroup
@@ -968,6 +1017,9 @@
\cpt@tempb\cpt@tempa
}
\endgroup
+
+% We need the equivalent of '\protected\let' and we want to be able to
+% do \shelllet\x=\y:
\robust@def*\shelllet#1{\cpt@ifeql{\cpt@shelllet{#1}}{\cpt@shelllet{#1}}}
\robust@def*\cpt@shelllet#1#2{%
\ifblankTF{#2}{%
@@ -975,6 +1027,7 @@
}{%
\expandafter\ifblankTF\expandafter{\@gobble#2}{%
\ifcsdefinable#1{%
+ % Here we must use \let and not \def (for immediate inheritance):
\ifprotectedTF#2{\let#1=#2}{%
\ifcsndefinable{shell@\cptremovescape#1}{%
\letcsntocs{shell@\cptremovescape#1}=#2%
@@ -1005,6 +1058,8 @@
\new@def\cpt@car#1#2\car@nil{#1}
\new@def\cpt@cdr#1#2\cdr@nil{#2}
\ifcsdefinable\cpt@relax{\let\cpt@relax\relax}
+% This is needed to define phantom environments:
+\newcommand*\phantom@env{\relax}
\new@def\cptgobbletorelax#1\cpt@relax{}
\new@def\cptbgobbletorelax\fi#1\cpt@relax{\fi\endgroup}
\new@def\cpt@removetonnil#1\cpt@nnil{}
@@ -1023,6 +1078,7 @@
\ifcseqTF\reserved@a\cpt@csvbreak
}
\ifcsdefinable\cptdoremainder{\let\cptdoremainder\@gobble}
+% #1: sentinel; #2: parser
\robust@def*\gobble@to@sentinel#1#2{%
\defpass\reserved@a##1#1#2{\cptdoremainder{##1}}%
}
@@ -1045,7 +1101,7 @@
}
\new@def*\cptdotimes#1{%
\ifblankTF{#1}{%
- \ifboolTF{cpt@useempty}{\cpt@dotimes{m}}\@gobble
+ \ifdefboolTF{cpt@useempty}{\cpt@dotimes{m}}\@gobble
}{%
\expandafter\cpt@dotimes\expandafter
{\romannumeral\number#1000}%
@@ -1078,7 +1134,7 @@
\new@def*\normal@reverse#1{\cpt@normalreverse{}#1\@nnil}
\long\def\cpt@normalreverse#1#2{%
\expandafter\ifxTF\cpt@car#2\car@nil\@nnil{%
- \ifboolTF{@test}\@iden\unexpanded{#1}%
+ \ifdefboolTF{@test}\@iden\unexpanded{#1}%
}{%
\cpt@normalreverse{#2#1}%
}%
@@ -1101,7 +1157,7 @@
}
\long\def\cpt@r@bustreverse#1#2.#3{%
\expandafter\ifxTF\cpt@car#3\car@nil\@nnil{%
- \ifboolTF{@test}\@iden\unexpanded{#1}%
+ \ifdefboolTF{@test}\@iden\unexpanded{#1}%
}{%
#2{\cpt@robustreverse{{#3}#1}}{\cpt@robustreverse{#3#1}}.%
}%
@@ -1161,7 +1217,22 @@
\robust@def*\despacecontent#1{%
\edef#1{\simpleexpandarg\cpttrimspaces{#1}}%
}
+\robust@def\cptusesimpletrimspaces{%
+ \let\cptcurrtrimspaces\cpttrimspace
+}
+\cptusesimpletrimspaces
+\let\cptusesimpletrimspace\cptusesimpletrimspaces
+\robust@def\cptusehardtrimspaces{%
+ \let\cptcurrtrimspaces\cpttrimspaces
+}
+\let\cptusehardtrimspace\cptusehardtrimspaces
+% It is more efficient to use \csv@@normalize in place
+% of \cptdespacecsvlist. Also, \csv@@normalize allows parsers
+% to be made innocent. But the following is needed in some
+% instances (eg, where we don't want to sanitize the parser):
\robust@def*\cptdespacecsvlist{\cpt@teststopt\cpt@despacecsvlist,}
+% #1: arbitrary parser
+% * -> #2 is a <listcmd>, otherwise a <list>
\robust@def*\cpt@despacecsvlist[#1]#2{%
\cpt@stchoose{cpt@st}{#2}\cpt@tempa\cpt@despacecsvlist
\ifcsnullTF\cpt@tempa{}{%
@@ -1169,13 +1240,17 @@
\UseEmptyEntry
\def\csv@do##1{%
\edef\cpt@tempa{\cpttrimspaces{##1}}%
- \cptaddtolist[#1]\cpt@rsvda\cpt@tempa
+ \cptoaddtolist[#1]\cpt@rsvda\cpt@tempa
}%
\csv@@loop*[#1]\cpt@tempa
\ifdefboolFT{cpt@st}{}{\let#2=\cpt@rsvda}%
}%
}
% \cptnewvariables{<type>}[<prf>]{<variables>}[<state/value>]
+% If <type> is 'toks', <state/value> is the content of the
+% new token register.
+% Valid <types> are 'if, toks, dimen, count, tog, switch'.
+% Boxes can't be initialized by this command.
\robust@def*\cptnewvariables#1{\cpt@testopt{\cpt@newvariables{#1}}{}}
\robust@def*\cpt@newvariables#1[#2]#3{%
\edef\reserved@a{\noexpand\cpt@testopt{%
@@ -1219,6 +1294,7 @@
}%
}{%
\@tempswatrue
+ % Declare the new switch:
\ifstrcmpTF{#1}{switch}{%
\lowercase{%
\ifstrcmpTF{#4}{true}{%
@@ -1238,8 +1314,10 @@
\expandafter\let\csname#2##1\endcsname\reserved@a
}{%
\@tempswafalse
+ % Declare the new variable:
\csname new#1\expandafter\endcsname\csname
\cpt@tempb#2##1\endcsname
+ % Initialize the new variable:
\ifstrcmpTF{#1}{if}{%
\cpt@rsvda{false}%
\csname#2##1\cpt@tempc\endcsname
@@ -1300,8 +1378,28 @@
\endgroup
\fi
}
-\cptnewvariables{if}[cpt@]{usepox,optfd,igopt,inpox,olddx,
+
+\cptnewvariables{if}[cpt@]{usepox,optfd,noval,igopt,inpox,olddx,
in,check,choicefd,useempty,swa}[false]
+
+% st -> I saw star
+% pl -> I saw plus
+% pm -> I saw prime
+% cl -> I saw exclamation mark
+% verbose -> log information (package option)
+% usepox -> use \XDeclareOption and \XProcessOptions for
+% \DeclareOption and \ProcessOptions (package option)
+% igopt -> ignore option
+% optfd -> option found
+% inpox -> we're in \XProcessOptions
+% olddx -> we're in \DeclareOption and not in \XDeclareOption
+% in -> for use in \cpt@in
+% check,sw -> generic booleans ('check' for short intervals;
+% 'sw' for longer intervals)
+% choicefd -> generic (choice found)
+% loopbreak -> terminate loop
+% useempty -> use empty entry (in loops)
+%
\cptnewvariables{tog}{biboolopts}[false]
\cptnewvariables{count}[cpt@]{optdepth,cnta}[\z@pt]
\new@def*\UseEmptyEntry{\global\cpt@useemptytrue}
@@ -1370,7 +1468,16 @@
\robust@def*\ltxmsg@info{\@latex@info@no@line}
\robust@def*\ltxmsg@err{\@latex@error}
\robust@redef\cpt@testopt#1#2{\ifnextcharTF[{#1}{#1[{#2}]}}
+
+% Eg, \def\csa{\cpt@testcharopt\csb<{default}>}
+% \def\csb<#1>{...}
\robust@def*\cpt@testcharopt#1#2#3#4{\ifnextcharTF#2{#1}{#1#2{#3}#4}}
+
+% Expandable \@testopt:
+% Eg, \def\macroa#1{\cpt@xtestopt{#1}\macrob{Mr.}}
+% \def\macrob[#1]#2{#1 #2}
+% \edef\testa{\macroa{John Johnson}}
+% \edef\testb{\macroa[Dr.]{Haiki Heiki}}
\new@def*\cpt@xtestopt#1#2#3{%
\cpt@xifbrack#1\\[\\{#2#1}{#2[{#3}]{#1}}%
}
@@ -1378,7 +1485,13 @@
\ifcat$\detokenize{#1#2}$\expandafter\@firstoftwo
\else\expandafter\@secondoftwo\fi
}
+% Eg, \def\macroa{\cpt@newxtestopt\macrob{Mr.}}
+% \def\macrob[#1]#2{#1 #2}
+% \edef\testa{\expandafter\macroa\activespace{John Johnson}}
+% \edef\testb{\macroa[Dr.]{Haiki Heiki}}
\new@def*\cpt@newxtestopt#1#2#3{%
+ % #3 will be a space only if that space is active. But
+ % \ifstrcmpTF will detokenize that space before comparison.
\ifstrcmpTF{ }{#3}{%
\cpt@newxtestopt#1{#2}%
}{%
@@ -1456,8 +1569,15 @@
\cpt@notonetokenerr{#1}%
}%
}
-% Eg, \newletcsset{\a=\b,\x\y}
+\robust@def*\letcsset{%
+ \@tempswafalse
+ \cpt@ifstar
+ {\let\dolet\ltsfulllet\cpt@newletcsset}%
+ {\let\dolet\let\cpt@newletcsset}%
+}
+% Eg, \newletcsset{\a\b,\x\y}
\robust@def*\newletcsset{%
+ \@tempswatrue
\cpt@ifstar
{\let\dolet\ltsfulllet\cpt@newletcsset}%
{\let\dolet\let\cpt@newletcsset}%
@@ -1470,11 +1590,15 @@
\ifblankFT{##2}{}{%
\cpt@err{The partner of command '\string##1' is void}\@ehc
}%
- \ifdefTF{##1}{%
- \ifx##1##2\else\cpt@isdeferr{##1}\fi
- }{%
+ \if@tempswa
+ \ifdefTF{##1}{%
+ \ifx##1##2\else\cpt@isdeferr{##1}\fi
+ }{%
+ \dolet##1=##2%
+ }%
+ \else
\dolet##1=##2%
- }%
+ \fi
}%
\cptfor#1\dofor{%
\ifinsetTF{=}{##1}{%
@@ -1504,6 +1628,7 @@
\gdef#2##1\string\count##2&{\noexpand\ifblankTF{##1}}%
}
\cpt@ifcounter@a\cpt@ifcounter@a\cpt@ifcounter@b
+% Similar to \ifcounterTF. Don't call this \ifdimTF:
\new@gdef*\ifdimenTF#1{%
\ifcseqTF#1\dimen{%
\@secondoftwo
@@ -1518,6 +1643,7 @@
\cpt@ifdimen@a\cpt@ifdimen@a\cpt@ifdimen@b
\endgroup
+% #1 can be arbitrary number (\countdef'd or otherwise):
\robust@def*\pushnumber#1{%
\ifsingletokenTF{#1}{%
\ifdefTF{#1}{%
@@ -1552,12 +1678,17 @@
\cpt@notonetokenerr{#1}%
}%
}
+% #1: calling/base function to push
+% #2: comma-separated state list (subsidiary functions) to push
+% #3: arbitrary number
\robust@def*\pushfunctions#1#2#3{%
\pushnumber{#3}%
\begingroup
\edef\cpt@stack{\cptremovescape{#1}@stack}%
- \ifcsndefTF\cpt@stack{}{\csn@gdef\cpt@stack{}}%
+ \ifcsndefTF\cpt@stack{}{\csn@def\cpt@stack{}}%
\toks@{}\toks1{}\escapechar92\relax
+ % Using \csv@@loop or \csv@@parse here will bomb out,
+ % because \pushfunctions is called within those loops:
\let\xp\expandcsonce
\cptfor#2\dofor{%
\ifescapedTF{##1}{}{\cpt@notescapederr{##1}}%
@@ -1571,6 +1702,8 @@
\csn@xdef\cpt@stack{\the\toks1\cpt@nil{\expandcsnonce\cpt@stack}}%
\expandafter\endgroup\the\toks@
}
+% #1: calling/base function to pop
+% #2: depth counter
\robust@def*\popfunctions#1#2{%
\ifdefTF{#2}{%
\ifnum#2=\z@pt
@@ -1592,6 +1725,9 @@
\popnumber{#2}%
}
\cptchardef\cpt@optionstacklimit=4
+% #1: calling (base) function
+% #2: state list (a macro)
+% #3: state counter
\robust@def*\cpt@pushstate#1#2#3{%
\ifnum#3>\cpt@optionstacklimit\relax
\let\x\cpt@optionstacklimit
@@ -1605,9 +1741,11 @@
\fi
\cptexpandargonce{\pushfunctions#1}{#2}{#3}%
}
+% #1: calling/base function
+% #2: state counter
\robust@def*\cpt@popstate#1#2{\popfunctions{#1}{#2}}
\robust@def*\cpt@stchoose#1#2#3#4{%
- \ifboolTF{#1}{%
+ \ifdefboolTF{#1}{%
\ifmacroTF{#2}{%
\let#3=#2%
}{%
@@ -1619,7 +1757,7 @@
\edef#3{\unexpanded{#2}}%
}%
}
-\robust@def*\cpt@delimitcs#1#2{%
+\robust@def*\cptdelimitcs#1#2{%
\begingroup
\def\cpt@tempb##1{%
\edef\cpt@tempa####1{%
@@ -1642,15 +1780,23 @@
\cpt@err{Your command \noexpand#1 isn't scannable.
\MsgBrk I needed to delimit its last parameter text}\@ehc
}%
+ % Because of parameters, \postgroupdef can be used here:
\gletcs#1\cpt@tempa
\endgroup
}
+% First provide \def\do<params>{<defn>}
+% \cptdofunclist[<parser>]{<list>}
+% \cptdofunclist*[<parser>]{<listcmd>}
+% The command expects \do, which can be multi-parametered.
+% Parameters of \do are delimited internally, relieving the user
+% of this need. Calling \dofunclist is equivalent to defining
+% a multi-parametered \do within \csv@do:
\robust@def*\cptdofunclist{%
\pushnumber\dofunclistdepth
\begingroup
\edef\sav@do{\cptmakecs{sav@do@\cptrm\dofunclistdepth}}%
\expandafter\let\sav@do\do
- \expandafter\cpt@delimitcs\sav@do\cpt@nil
+ \expandafter\cptdelimitcs\sav@do\cpt@nil
\toks@{\def\csv@do##1}%
\toks1\expandafter{\expandafter\expandafter\sav@do
\cptrm\ifbracedTF{##1}{0{##1}}{0 ##1}\cpt@nil}%
@@ -1661,44 +1807,45 @@
\robust@def*\cptdocommalist{\cpt@testst\cpt@docommalist}
\robust@def*\cpt@docommalist#1#2{%
\def\csv@do##1{#2}%
- \edefpass\reserved@a{\csv@@parse\ifcpt@st*\fi}%
- {#1}%
-}
-\robust@def*\csv@@loop{\cpt@csvkvparse{01}{01}}
-\robust@def*\csv@@parse{\cpt@csvkvparse{00}{01}}
-\robust@def*\kv@@loop{\cpt@csvkvparse{01}{00}}
-\robust@def*\kv@@parse{\cpt@csvkvparse{00}{00}}
-\new@def*\cpt@csvkvparse#1#2{%
+ \cptexpanded{\csv@@parse\ifcpt@st*\fi}{#1}%
+}
+\robust@def*\csv@@loop{\cpt@listparse{01}{01}}
+\robust@def*\csv@@parse{\cpt@listparse{00}{01}}
+\robust@def*\kv@@loop{\cpt@listparse{01}{00}}
+\robust@def*\kv@@parse{\cpt@listparse{00}{00}}
+\new@def*\cpt@listparse#1#2{%
\def\cpt@nmlz{#1}\def\cpt@inkv{#2}%
- \cpt@teststopt\cpt@csvkvp@rse,%
+ \cpt@teststopt\cpt@listp@rse,%
}
\newletcs\cpt@csvnil\relax
\new@def*\cpt@csvnnil{\cpt@csvnil}
-\newcommand*\cpt@csvkvp@rse[2][,]{%
- \cpt@stchoose{cpt@st}{#2}\cpt@csvarg\cpt@csvkvparse
- \pushfunctions\cpt@csvkvparse{\cpt@csvdo@a,\cpt@csvdo@b,\sav@csv@do,%
- \cpt@loopcbk,\ifcpt@useempty,\ifloopbreak,\cptdoremainder}\cpt@csvdepth
- \letcstocsn\sav@csv@do{\if\cpt@inkv kv\else csv\fi @do}%
- \ifdefTF\sav@csv@do{}{%
- \cpt@err{'\string\csv@do' or '\string\kv@do' undefined}\@ehc
- }%
- \def\cpt@csvdo@a{%
- \ifboolTF{loopbreak}
- {\gobble@to@sentinel\cpt@csvnil#1}{\cpt@csvdo@b.}%
- }%
- \def\cpt@csvdo@b##1#1{%
+\newcommand*\cpt@listp@rse[2][,]{%
+ \cpt@stchoose{cpt@st}{#2}\cpt@csvarg\cpt@listparse
+ % \cpt@nmlz and \cpt@inkv are used before the commencement
+ % of the loop: no need to include them in the state list.
+ % \cpt@loopcbk is meant for callbacks with hash characters.
+ % It can be defined outside \csv@do or \kv@do and called within
+ % \csv@do or \kv@do.
+ \pushfunctions\cpt@listparse{\cpt@listdo,\curr@do,\cpt@loopcbk,%
+ \ifcpt@useempty,\ifloopbreak,\cptdoremainder}\cpt@csvdepth
+ \letcstocsn\curr@do{\if\cpt@inkv kv\else csv\fi @do}%
+ \ifdefTF\curr@do{}{%
+ \cpt@err{'\string\csv@do' or '\string\kv@do' is undefined}\@ehc
+ }%
+ \def\cpt@listdo##1#1{%
\edef\cpt@csvarg{\expandcsonce{\@gobble##1}}%
\ifcseqTF\cpt@csvarg\cpt@csvnnil{}{%
\ifcseqTF\cpt@csvarg\cpt@csvbreak{%
\loopbreaktrue
}{%
\ifcsemptyTF\cpt@csvarg{%
- \ifboolFT{cpt@useempty}{}{\sav@csv@do{}\relax}%
+ \ifboolFT{cpt@useempty}{}{\curr@do{}\relax}%
}{%
- \expandafter\sav@csv@do\expandafter{\cpt@csvarg}\relax
+ \s@expandarg\curr@do\cpt@csvarg\relax
}%
}%
- \cpt@csvdo@a
+ \ifdefboolTF{loopbreak}
+ {\gobble@to@sentinel\cpt@csvnil#1}{\cpt@listdo.}%
}%
}%
\ifswitchFT{cpt@nmlz}{}{%
@@ -1709,59 +1856,164 @@
}%
}%
\loopbreakfalse
- \expandafter\cpt@csvdo@a\cpt@csvarg#1\cpt@csvnil#1%
- \popfunctions\cpt@csvkvparse\cpt@csvdepth
+ \expandafter\cpt@listdo\expandafter.\cpt@csvarg#1\cpt@csvnil#1%
+ \popfunctions\cpt@listparse\cpt@csvdepth
\ifnum\cpt@csvdepth=\z@pt
- \cptfor\csv@do,\kv@do,\dofunclistdepth\dofor{\undefcs##1}%
+ % So that these functions are defined before the loop is called:
+ \undefcs\csv@do\undefcs\kv@do\undefcs\dofunclistdepth
\fi
}
-\robust@def\indris@nil#1\fi#2\indris@do#3\indris@nil{\fi#1#2}
+% #1=keyval list, #2=processor
+\robust@def*\kv@@process#1#2{%
+ \pushfunctions\kv@@process{\kv@do,\ifloopbreak,#2}\cpt@csvdepth
+ \def\kv@do##1,{%
+ \defifxTF{##1}\cpt@nnil{}{%
+ \def\reserved@a####1={%
+ \edef\key@name{\unexpanded{####1}}%
+ \def\reserved@a########1=########2\cpt@nil{%
+ \edef\key@value{\expandcsonce{\@gobble########1}}%
+ \ifx\key@value\cpt@rej
+ \cpt@novaltrue\def\key@value{}%
+ \else
+ \cpt@novalfalse
+ \fi
+ \cptexpandtwoargsonce{#2}\key@name\key@value
+ }%
+ \reserved@a.%
+ }%
+ \reserved@a##1=^?^=\cpt@nil
+ \ifloopbreak
+ \def\kv@do####1\cpt@nil,{}%
+ \fi
+ \kv@do
+ }%
+ }%
+ \kv@@normalize{#1}%
+ \expandafter\kv@do\normalized@list,\cpt@nil,%
+ \popfunctions\kv@@process\cpt@csvdepth
+}
+\robust@def*\cpt@setupuserdo#1{%
+ \ifsingletokenTF{#1}{%
+ \ifmacroTF{#1}{\let\user@do#1}{\cpt@notcserr{#1}}%
+ }{%
+ \cpt@notonetokenerr{#1}%
+ }%
+}
+\robust@def*\cpt@setupnextindris#1{%
+ \def\getnextindris##1#1##2\indris@nil{%
+ \if\cpt@incsv
+ \edef\nextindris{\expandcsonce{\@gobble##1}}%
+ \else
+ \edef\nextindris{\s@expandarg\cpttrimspace{\@gobble##1}}%
+ \fi
+ \letcsntocs{nextindris@\cptrm\indrisdepth}\nextindris
+ }%
+}
\cptnewvariables{if}{lastindris}[false]
+\cptnewvariables{count}{indrisdepth}[\z@pt]
\robust@def*\indrisloop{\cpt@teststopt\cpt@indrisloop,}
+% #1: parser
+% #2: list
+% #3: a one-parameter recurrent macro (eg, \do)
\robust@def*\cpt@indrisloop[#1]#2#3{%
- \pushfunctions\cpt@indrisloop{%
- \indris@do,\indrisnr,\iflastindris,\ifloopbreak,%
- \user@do,\getnextindris,\cptdoremainder
- }\cpt@csvdepth
- \pushnumber\indrisdepth
+ \pushfunctions\indrisloop{\indris@do,\indrisnr,%
+ \iflastindris,\ifloopbreak,\user@do,\getnextindris,%
+ \cptdoremainder}\cpt@csvdepth
+ \advance\indrisdepth\@ne
\cpt@stchoose{cpt@st}{#2}\cpt@rsvda\indrisloop
\cpt@sttrue\cpt@csvnormalize[#1]\cpt@rsvda
\lastindrisfalse\loopbreakfalse
\chardef\indrisnr\z@pt
- \ifsingletokenTF{#3}{%
- \ifmacroTF{#3}{}{\cpt@notcserr{#3}}%
- }{%
- \cpt@notonetokenerr{#3}%
+ \cpt@setupuserdo{#3}%
+ \cpt@setupnextindris{#1}%
+ \let\cpt@incsv\cptswtrue
+ \def\indris@do##1#1##2\indris@nil{%
+ \s@expandarg\ifcsvbreakTF{\@gobble##1}\loopbreak\relax
+ \ifdefboolTF{loopbreak}{%
+ \cptdoremainder{##2}%
+ }{%
+ \edef\currindris{\expandcsonce{\@gobble##1}}%
+ \letcsntocs{currindris@\cptrm\indrisdepth}\currindris
+ \edef\indrisnr{\the\numexpr\indrisnr+1}%
+ \getnextindris.##2\indris@nil
+ \ifcseqTF\nextindris\cpt@nnil{%
+ \lastindristrue\def\nextindris{}%
+ \csn@def{nextindris@\cptrm\indrisdepth}{}%
+ \s@expandarg\user@do\currindris\relax
+ }{%
+ \s@expandarg\user@do\currindris\relax
+ \indris@do.##2\indris@nil
+ }%
+ }%
}%
- \let\user@do#3%
- \def\getnextindris##1#1##2\indris@nil{%
- \edef\nextindris{\unexpanded\expandafter{\@gobble##1}}%
- \letcsntocs{nextindris@\cptrm\indrisdepth}\nextindris
+ \expandafter\indris@do\expandafter.\cpt@rsvda#1\cpt@nil#1\indris@nil
+ \popfunctions\indrisloop\cpt@csvdepth
+ \advance\indrisdepth\m@one
+}
+
+% #1=list, #2=operator/format
+% Eg,
+% \def\pkg{%
+% \ifnextcharTF'%
+% {\@firstoftwo{\def\pkgsw{00}\@pkg}}
+% {\def\pkgsw{01}\@pkg}%
+% }
+% \def\@pkg#1{%
+% \def\do##1{\textcolor{ForestGreen}{\texttt{##1}}}%
+% \cptprintcommalist{#1}\do
+% \if\pkgsw\@space package\ifnum\maxindrisnr>\@ne s\fi\fi
+% }
+\robust@def*\cptprintcommalist{\cpt@testst\cpt@printcommalist}
+\robust@def*\cpt@printcommalist#1#2{%
+ \cpt@stchoose{cpt@st}{#1}\cpt@tempa\cptprintcommalist
+ \def\print@do##1{%
+ \ifnum\indrisnr>\@ne
+ \iflastindris
+ \edef\maxindrisnr{\number\indrisnr}%
+ \@space and\@space
+ \else
+ ,\@space
+ \fi
+ \fi
+ #2{##1}%
}%
- \def\indris@do##1#1##2\indris@nil{%
- \edef\currindris{\unexpanded\expandafter{\@gobble##1}}%
- \letcsntocs{currindris@\cptrm\indrisdepth}\currindris
- \ifcat$\detokenize\expandafter{\@gobble##2.}$\indris@nil
- \lastindristrue\fi
- \ifboolTF{lastindris}{%
- \def\nextindris{}%
- \csn@def{nextindris@\cptrm\indrisdepth}{}%
+ \indrisloop*\cpt@tempa\print@do
+}
+\robust@def*\indristloop#1#2{\cpt@testst\cpt@indristloop}
+\robust@def*\cpt@indristloop#1#2{%
+ \pushfunctions\indristloop{\user@do,\indrisnr,\iflastindris,
+ \ifloopbreak}\cpt@csvdepth
+ \cpt@stchoose{cpt@st}{#1}\cpt@rsvda\indristloop
+ \advance\indrisdepth\@ne
+ \lastindrisfalse\loopbreakfalse
+ \chardef\indrisnr\z@pt
+ \cpt@setupuserdo{#2}%
+ \cpt@setupnextindris{}%
+ \let\cpt@incsv\cptswfalse
+ \def\cpt@indristl@op##1##2\indris@nil{%
+ \ifdefboolTF{loopbreak}{%
+ \cptdoremainder{##2}%
}{%
- \ifcsvbreakTF{##1}\loopbreak\relax
- \ifboolTF{loopbreak}{%
- \defpass\reserved@a####1\indris@nil{\cptdoremainder{####1}}%
+ \edef\currindris{\s@expandarg\cpttrimspace{\@gobble##1}}%
+ \letcsntocs{currindris@\cptrm\indrisdepth}\currindris
+ \edef\indrisnr{\the\numexpr\indrisnr+1}%
+ \getnextindris.##2\indris@nil
+ \ifcseqTF\nextindris\cpt@nnil{%
+ \lastindristrue
+ \def\nextindris{}%
+ \csn@def{nextindris@\cptrm\indrisdepth}{}%
+ \s@expandarg\user@do\currindris\relax
}{%
- \getnextindris.##2\indris@nil
+ \s@expandarg\user@do\currindris\relax
+ \cpt@indristl@op##2\indris@nil
}%
}%
- \pushnumber\indrisnr
- \expandafter\user@do\expandafter{\@gobble##1}%
- \indris@do.##2\indris@nil
}%
- \expandafter\indris@do\expandafter.\cpt@rsvda#1\indris@nil
- \popfunctions\cpt@indrisloop\cpt@csvdepth
- \popnumber\indrisdepth
+ \expandafter\cpt@indristl@op\expandafter.\cpt@rsvda\cpt@nil\indris@nil
+ \popfunctions\indristloop\cpt@csvdepth
+ \advance\indrisdepth\m@one
}
+%% Robust, multi-level, general-purpose tsv processor:
\robust@def*\tsv@@loop{%
\let\tsv@inparse\cptswfalse
\cpt@testst\cpt@tsvparse@a
@@ -1773,6 +2025,9 @@
\new@def*\cpt@tsvnil{\cpt@tsvnil}
\robust@def\cpt@tsvparse@a#1{%
\cpt@stchoose{cpt@st}{#1}\cpt@tsvarg\cpt@tsvparse@a
+ % Use \cpt@csvdepth here also, to avoid premature undefining
+ % of pushed counterparts of \ifcpt@useempty, \ifloopbreak and
+ % \cptdoremainder by \popfunctions:
\pushfunctions\tsv@@parse{\sav@tsv@do,\ifcpt@useempty,
\ifloopbreak,\cptdoremainder,\tsv@inparse}\cpt@csvdepth
\ifdefTF\tsv@do{}{%
@@ -1787,12 +2042,13 @@
\fi
}
\robust@def*\cpt@tsvparse@b{%
- \ifboolTF{loopbreak}{%
- \defpass\reserved@a##1\cpt@tsvnil{\cptdoremainder{##1}}%
+ \ifdefboolTF{loopbreak}{%
+ \gobble@to@sentinel\cpt@tsvnil{}%
}{%
\begingroup
\let\bgr@up\bgroup
\let\bgroup\cpt@undefined
+ % Don't use \ifnextcharTF here:
\cpt@ifnextchar\bgr@up\cpt@tsvparse@c\cpt@tsvparse@c
}%
}
@@ -1822,27 +2078,98 @@
% \siso@@loop strips outer braces in its arguments and
% doesn't trim leading and trailing spaces, but can
% be nested to any level:
-\new@def*\cpt@sisonil{\cpt@sisonil}
-\robust@def*\siso@@loop#1{%
+\newletcs\cpt@sisonil\relax
+\new@def*\cpt@sisonnil{\cpt@sisonil}
+\robust@def*\siso@@loop{\cpt@testst\cpt@sisoloop}
+\robust@def*\cpt@sisoloop#1{%
+ \cpt@stchoose{cpt@st}{#1}\siso@arg\siso@@loop
+ % Use \cpt@csvdepth here also, to avoid premature un-defining
+ % of pushed counterparts of \ifloopbreak:
\pushfunctions\siso@@loop{\sav@siso@do,\ifloopbreak}\cpt@csvdepth
\ifdefTF\siso@do{}{\cpt@notdeferr\siso@do}%
\let\sav@siso@do\siso@do
\loopbreakfalse
- \cpt@sisoloop#1\cpt@sisonil
+ \expandafter\cpt@sisoloop@a\siso@arg\cpt@sisonil
\popfunctions\siso@@loop\cpt@csvdepth
\ifnum\cpt@csvdepth=\z@pt\undefcs\siso@do\fi
}
-\robust@def*\cpt@sisoloop#1{%
+\robust@def*\cpt@sisoloop@a#1{%
\edef\siso@arg{\unexpanded{#1}}%
- \ifcseqTF\siso@arg\cpt@sisonil{}{%
- \ifboolTF{loopbreak}{%
- \defpass\reserved@a##1\cpt@sisonil{%
- \cptdoremainder{##1}%
- }%
+ \ifcseqTF\siso@arg\cpt@sisonnil{}{%
+ \ifdefboolTF{loopbreak}{%
+ \gobble@to@sentinel\cpt@sisonil{}%
+ }{%
+ \sav@siso@do{#1}\relax\cpt@sisoloop@a
+ }%
+ }%
+}
+\robust@def*\cptdosisolist{\cpt@testst\cpt@dosisolist}
+\robust@def*\cpt@dosisolist#1#2{%
+ \def\siso@do##1{#2}%
+ \cptexpanded{\siso@@loop\ifcpt@st*\fi}{#1}%
+}
+% Any type of argument and delimiter is allowed in \cptforeach.
+% Eg,
+% \newcount\nr
+% \cptforeach[;] \xa/\ya/\za \in a1/b1/c1; a2/b2/c2; a3/b3/c3 \do{%
+% \nr\z@pt
+% It is permissible to use #1, #2, #3 to refer to the elements
+% of each list, but they won't be despaced as \x, \y, \z will be:
+% \cptforeach[,] \xs|\ys|\zs \in s1|t1|u1, s2|t2|u2, s3|t3|u3 \do{%
+% \advance\nr\@ne
+% \ifnum\nr>\@ne\loopbreak\fi
+% \edef\cmda####1{#1#2#3*####1*##1##2##3}%
+% \edef\cmdb####1{\xa\ya\za*####1*\xs\ys\zs}%
+% }%
+% }
+% Control sequences can't be used as delimiters in #2.
+% Star (*) suffix implies that <list> is a command.
+\robust@def*\cptforeach{\cpt@teststopt\cpt@foreach,}
+\robust@def*\cpt@foreach[#1]#2\in#3\do#4{%
+ \let\ifforeach@st\ifcpt@st
+ \def\cpt@tempa{}%
+ \cpttfor#2\dofor{%
+ \ifescapedTF{##1}{\cptuaddtolist\cpt@tempa{##1}}{}%
+ }%
+ \cptexpandargonce{\pushfunctions\cptforeach}\cpt@tempa\cpt@csvdepth
+ \begingroup
+ % We need a special scanner here:
+ \def\rescan##1{%
+ \begingroup
+ \endlinechar\m@one\newlinechar\m@one
+ \everyeof{\@@nnil}%
+ \def\reserved@a####1\@@nnil{\endgroup\edef##1{\unexpanded{####1}}}%
+ \expandafter\reserved@a\scantokens\expandafter{##1}%
+ }%
+ \@tempcnta\z@pt
+ \def\cmds{}\def\params{}%
+ \cpttfor#2\dofor{%
+ \ifescapedTF{##1}{%
+ \advance\@tempcnta\@ne
+ \edef\cmds{\expandcsonce\cmds\edef\unexpanded{##1}%
+ {\noexpand\cpttrimspace{\cpt@hashchar\number\@tempcnta}}}%
+ \edef\params{\expandcsonce\params\cpt@hashchar\number\@tempcnta}%
}{%
- \sav@siso@do{#1}\relax\cpt@sisoloop
+ \ifnum\@tempcnta=\z@pt
+ \cpt@err{First item of \noexpand\cptforeach can't
+ \MsgBrk be a delimiter}\@ehc
+ \fi
+ \edef\params{\expandcsonce\params\unexpanded{##1}}%
}%
}%
+ \rescan\cmds\rescan\params
+ \cptexpanded{%
+ \endgroup
+ \def\noexpandcsn{foreach@do@\romannumeral\cpt@csvdepth}%
+ \expandcsonce\params\noexpand\foreach@nil
+ {\expandcsonce\cmds\unexpanded{#4}}%
+ \def\noexpand\csv@do####1{\noexpandcsn
+ {foreach@do@\romannumeral\cpt@csvdepth}####1\noexpand\foreach@nil}%
+ \csv@@parse\ifforeach@st*\fi
+ }%
+ [#1]{#3}%
+ \popfunctions\cptforeach\cpt@csvdepth
+ \undefcs\ifforeach@st
}
\robust@def*\cpt@oncurrlevel#1#2{%
\ifdefTF\curr@level{%
@@ -1856,6 +2183,8 @@
\cptexpandsecond{#1}
{\noexpandcsn{\cptgobblescape#2@\romannumeral\curr@level}}%
}
+% #1: parser
+% #2: token list
\new@def*\csliststack#1#2{%
\iflacus#2\dolacus\else
\expandafter\ifnullTF\expandafter{\iiofii#2{}}{%
@@ -1895,7 +2224,7 @@
}
\robust@def*\cpt@emptifycsset#1{%
\cptfor#1\dofor{%
- \ifsingletoken@sp@TF{##1}{%
+ \ifsingletokenTF{##1}{%
\ifescapedTF{##1}{%
\ifcpt@cl\global\fi\def##1{}%
}{%
@@ -1913,7 +2242,7 @@
\AtEndOfPackage{%
\AfterStartOfDocument{%
\def\do#1{%
- \ifcsnameTF{\cptgobblescape#1}{%
+ \ifdefTF#1{%
\gdef#1{%
\@latex@error{'\string#1' is a preamble command}
{Move command '\string#1' to document preamble.}%
@@ -1966,6 +2295,8 @@
\expandafter\csv@@loop\reserved@a[#1]{#2}%
\postgroupdef\cptelemnr\endgroup
}
+% Eg, \ifelemcountTF[;](>)[2]{a;b;c}{T}{F};
+% * -> #4 is a macro
\robust@def*\ifelemcountTF{\cpt@teststopt\cpt@ifelemcount@a,}
\robust@def*\cpt@ifelemcount@a[#1]{%
\cpt@testpnopt{\cpt@ifelemcount@b{#1}}=%
@@ -2014,7 +2345,9 @@
\new@def*\ifcsnullFT#1{\ifcsnullTF{#1}\iiofii\iofii}
\new@def*\oifcsnullTF#1{\expandafter\ifcsnullTF\expandafter{#1}}
\new@def*\oifcsnullFT#1{\expandafter\ifcsnullFT\expandafter{#1}}
-\new@def\ifcsemptyTF#1{\ifcondTF\ifx#1\@empty\cpt@quark\fi}
+\new@def\ifcsemptyTF#1{%
+ \expandafter\ifcseqTF\cpt@car#1\@undefined\car@nil\@empty
+}
\new@def*\ifcsnnullTF#1{%
\ifblankTF{#1}{%
\@secondoftwo
@@ -2129,29 +2462,31 @@
}%
\fi
\endgroup
- \interactionmode\thr@@
}
\SetStyleFileMessages[cpt@]{info}{warn}{err}
-\new@def*\ifdefboolTF#1{%
+\new@def*\ifboolTF#1{%
\ifblankTF{#1}{%
\cpt@err{Empty boolean}\@ehc
}{%
\ifcsndefTF{if#1}{%
- \ifboolTF{#1}%
+ \ifdefboolTF{#1}%
}{%
\cpt@err{Boolean '\@backslashchar#1' undefined}\@ehc
}%
}%
}
-\new@def*\ifdefboolFT#1{\ifdefboolTF{#1}\iiofii\iofii}
-\new@def*\ifboolTF#1{%
+\new@def*\ifdefboolFT#1{\ifboolTF{#1}\iiofii\iofii}
+\new@def*\ifdefboolTF#1{%
\usename{@\usename{if#1}first\else second\fi oftwo}%
}
-\new@def*\ifboolFT#1{\ifboolTF{#1}\iiofii\iofii}
+\new@def*\ifboolFT#1{\ifdefboolTF{#1}\iiofii\iofii}
+\new@def*\ifgroupboolTF#1{%
+ \ifboolTF{#1}{\endgroup\iofii}{\endgroup\iiofii}%
+}
\new@def*\ifbooleanTF#1#{%
\ifsingletokenTF{#1}{%
\ifescapedTF{#1}{%
- \ifdefboolTF{\cptremovescape#1}\iofii\iiofii
+ \ifboolTF{\cptremovescape#1}\iofii\iiofii
}{%
\cpt@notescapederr
}%
@@ -2166,7 +2501,7 @@
#1\relax\expandafter\cpt@iterate\fi\@gobble{#1}%
}
\new@def\cptwhileexpr#1\do#2{%
- #1\cptswap{#2\cptwhileexpr{#1}\do{#2}}\fi
+ #1 \cptswap{#2\cptwhileexpr{#1}\do{#2}}\fi
}
\new@def*\cpt@numlt#1<{#1<\numexpr}
\new@def*\cpt@numgt#1>{#1>\numexpr}
@@ -2174,11 +2509,13 @@
\new@def*\cpt@dimlt#1<{#1<\dimexpr}
\new@def*\cpt@dimgt#1>{#1>\dimexpr}
\new@def*\cpt@dimeq#1={#1=\dimexpr}
+% Don't put \numexpr in the arg #2 when calling \cptwhilenum:
\new@def*\cptwhilenum#1\do#2{%
\ifnum\numexpr\cpt@numlt\cpt@numgt\cpt@numeq#1%
\cpt@removetonnil<=>\cpt@nnil\relax
\cptswap{#2\cptwhilenum{#1}\do{#2}}\fi
}
+% Don't put \dimexpr in the arg #2 when calling \cptwhiledim:
\new@def*\cptwhiledim#1\do#2{%
\ifdim\dimexpr\cpt@dimlt\cpt@dimgt\cpt@dimeq#1%
\cpt@removetonnil<=>\cpt@nnil\relax
@@ -2194,6 +2531,8 @@
\cpt@removetonnil<=>\cpt@nnil first\else second\fi oftwo}%
}
\new@def*\ifdimcmpFT#1#{\usename{@\ifdimcmpTF#1{second}{first}oftwo}}
+% Define control sequences to check for a token (eg, dash):
+% \cpt@defcheck<cs><testtoken>\cpt@nil
\robust@def*\cpt@defcheck#1#2\cpt@nil{%
\new@def*#1##1\cpt@nil{%
\begingroup
@@ -2204,6 +2543,9 @@
}%
}
\cpt@defcheck\cpt@checkeq=\cpt@nil
+%%--
+% Define control sequences to split tokens (eg, at a dash):
+% \cpt@defsplit@at<cs><splitter/testtoken>\cpt@nil
\robust@def*\cpt@defsplit@at#1#2\cpt@nil{%
\def#1##1\cpt@nil{%
\begingroup
@@ -2218,6 +2560,9 @@
}%
}
\cpt@defsplit@at\cpt@split@ateq=\cpt@nil
+
+% Define a control sequence to check for the presence
+% of a suffix in/for another control sequence:
\robust@def\DefSuffixChecker#1#2#3#4{%
\long\gdef#1##1##2##3##4{%
\begintoksgroup
@@ -2441,11 +2786,12 @@
\robust@def\oifstrcmpFT#1#2{%
\oifstrcmpTF{#1}{#2}\iiofii\iofii
}
+% Expandable:
\new@def\ifstreqTF#1#2{%
- \expandafter\cptswapbracefirst\expandafter
- {\romannumeral-`\q\cpttrimspaces{#1}}
+ \expandafter\cptswap\expandafter
+ {\expandafter{\romannumeral-`\q\cpttrimspaces{#1}}}
{\expandafter\ifstrcmpTF\expandafter
- {\romannumeral-`\q\cpttrimspaces{#2}}}
+ {\romannumeral-`\q\cpttrimspaces{#2}}}%
}
\robust@def\ifstreqFT#1#2{\ifstreqTF{#1}{#2}\iiofii\iofii}
\robust@def\oifstreqTF#1#2{\cptexpandtwoargsonce\ifstreqTF{#1}{#2}}
@@ -2470,6 +2816,7 @@
}
\new@def\ifdefeqFT#1#2{\ifdefeqTF{#1}{#2}\iiofii\iofii}
\new@def\ifcateqTF#1#{\usename{@\ifcat#1first\else second\fi oftwo}}
+% Expand and detokenize before comparison:
\new@def\ifcharcmpTF#1#2{%
\ifsingletokenTF{#1}{%
\ifsingletokenTF{#2}{%
@@ -2503,17 +2850,22 @@
}
\new@def\ifsingletokenFT#1{\ifsingletokenTF{#1}\iiofii\iofii}
% Don't test for \ifleadspaceTF:
-\new@def\ifsingletoken@sp@TF#1#2#3{%
- \romannumeral\ifblankTF{#1}{%
- \@secondoftwo
+\new@def\ifsingleindrisTF#1{%
+ \romannumeral
+ \ifblankTF{#1}{%
+ 0 \iiofii
}{%
- \ifbracedTF{#1}{%
- \@secondoftwo
- }{%
- \expandafter\ifblankTF\expandafter{\@gobble#1}%
- \iofii\iiofii
- }%
- }{0 #2}{0 #3}%
+ % Eat one token and take the rest to \cpt@ifsingleindris:
+ \expandafter
+ \cpt@ifsingleindris\cpt@cdr#1\cdr@nil\single@nil{#1}%
+ }%
+}
+\new@def\cpt@ifsingleindris#1\single@nil#2{%
+ \ifblankTF{#1}{%
+ \xifstrcmpTF{\expandafter\cpt@car
+ \detokenize{#2}x\car@nil}\cpt@leftbracechar
+ {0 \iiofii}{0 \iofii}%
+ }{0 \iiofii}%
}
\robust@def*\ifsingledigitTF#1{%
\begingroup
@@ -2535,7 +2887,7 @@
}{%
\ifsingletokenTF{#1}{%
\xifinsetTF{\detokenize{#1}}\cpt@parserlist{%
- #2%
+ #2% Don't put \relax here!
}{%
\cpt@listparsererr{#1}%
}%
@@ -2548,7 +2900,8 @@
\ifblankTF{#1}{%
\cpt@listparsererr{#1}%
}{%
- \expandafter\ifsecondisnnilTF\string#1\cpt@nnil\cpt@nil{%
+ % if #1 is a single token:
+ \ifsecondisnnilTF{#1}{%
\xifinsetTF{\detokenize{#1}}\cpt@parserlist{}{%
\cpt@listparsererr{#1}%
}%
@@ -2566,6 +2919,8 @@
\robust@def*\postgroupcsndef#1\endgroup{%
\aftercsname\postgroupdef{#1}\endgroup
}
+% #1: macro;
+% #2: arbitrary token (eg, \endgroup):
\robust@def*\cptpassacross#1#2{%
\cptpassexpanded{\unexpanded{#2}\cpt@csexit#1}%
}
@@ -2604,6 +2959,7 @@
\edef#2{\unexpanded{#1}}%
}%
}
+% Expandable:
\new@def*\cptexpandcs#1{%
\ifsingletokenTF{#1}{%
\ifmacroTF{#1}{%
@@ -2619,6 +2975,8 @@
\unexpanded{#1}%
}%
}
+% Expandable full expand; strips braces and leading
+% spaces, but not trailing spaces:
\begingroup
\catcode`\&=7
\new@gdef*\cptfullexpand#1{%
@@ -2642,6 +3000,9 @@
\ifblankTF{#2}{0 #3#1}{\cpt@fullexpand{#2}{#3#1}}%
}
\endgroup
+
+% [<fallback>]{<teststr>}{<{str1}{act1}{str2}{act2}...>}
+% Expandable:
\new@def*\cptifstreqcase#1{\cpt@xtestopt{#1}\cpt@ifstreqcase{}}
\new@def\cpt@ifstreqcase[#1]#2#3{%
\expandafter\cptswapbracefirst\expandafter{#2}%
@@ -2654,6 +3015,10 @@
}%
}%
}
+% #1: test string (choice)
+% #2: nominations and callbacks, eg, {{a}1,{b}2,{ x }3}
+% #3: no-match fallback
+% Expandable:
\new@def\cptcheckchoice#1#2#3{%
\expandafter\cptswapbracefirst\expandafter
{\romannumeral-`\q\cpttrimspace{#1}}
@@ -2668,6 +3033,8 @@
}%
}%
}
+% Test if <str1>, etc, is in <teststr>
+% [<default act>]{<teststr>}{<{str1}{act1}{str2}{act2}...>}
\new@def*\cptifstrpresentcase#1{\cpt@xtestopt{#1}\cpt@ifstrincase{}}
\new@def\cpt@ifstrincase[#1]#2#3{%
\expandafter\cptswapbracefirst\expandafter{#2}%
@@ -2680,15 +3047,41 @@
}%
}%
}
-\new@def\all@to@endif#1\endif{#1}
-\new@def\first@to@endif#1#2\endif{#1}
-\new@def*\ifcassenumcmpTF#1#2#3{\ifdimcmpTF#1pt#2pt{#3}}
+\new@def\do@else@part\do#1#2\endif{\unexpanded{#1}}
+\new@def\all@to@endif#1\endif{\unexpanded{#1}}
+\new@def\first@to@endif#1#2\endif{\unexpanded{#1}}
+\new@def\gobble@to@endif#1\endif{}
+\new@def*\ifcassedimcmpTF#1#2#3{\ifdimcmpTF#1#2{#3}}
+\new@def*\ifcassenumcmpTF#1#2#3{\ifnumcmpTF#1#2{#3}}
+% Eg,
+% \edef\x{%
+% \cptifcasse\ifstrcmpTF{teststr}
+% {str1}{case1 callback}
+% {str2}{case2 callback}
+% \ifnone
+% no match
+% \endif
+% }
+% \edef\x{%
+% \cptifcasse\ifcassenumcmpTF{testnum}
+% {=2}{equal to 2}
+% {<3}{less than 3}
+% {>4}{greater than 4}
+% \ifnone
+% no match
+% \endif
+% }
+% The comparator command is any test command that yields
+% <iofii> or <iiofii> but \ifnumcmpTF can't be used directly.
+% Use \ifcassenumcmpTF instead. The user can also define his own
+% logical test command and pass it to \cptifcasse, eg,
+% \def\test#1#2{\ifinsetTF{#2}{#1}}
\new@def*\cptifcasse#1#2{%
- \ifstrcmpTF{#1}\elseif{%
+ \ifstrcmpTF{#1}\ifnone{%
\all@to@endif
}{%
\ifstrcmpTF{#1}\endif{}{%
- \ifstrcmpTF{#2}\elseif{%
+ \ifstrcmpTF{#2}\ifnone{%
\all@to@endif
}{%
\ifstrcmpTF{#2}\endif{}{\cpt@ifcasse{#1}{#2}}%
@@ -2697,7 +3090,7 @@
}%
}
\new@def*\cpt@ifcasse#1#2#3{%
- \ifstrcmpTF{#3}\elseif{%
+ \ifstrcmpTF{#3}\ifnone{%
\all@to@endif
}{%
\ifstrcmpTF{#3}\endif{}{%
@@ -2706,12 +3099,89 @@
}%
}
\new@def*\cpt@ifcasse@i#1#2#3{\cpt@ifcasse{#1}{#2}}
+
+% Eg,
+% \edef\x{%
+% \cptdocasse\ifcassedimcmpTF{1pt+2pt+3pt}
+% {=2pt}\do{equal to 2pt}
+% \elseif
+% {<3pt}\do{less than 3pt}
+% \elseif
+% \do{no match}
+% \endif
+% }
+% \edef\x{%
+% \cptdocasse\ifcassenumcmpTF{1+2+3}
+% {=2}\do{equal to 2}
+% \elseif
+% {<3}\do{less than 3}
+% \elseif
+% \do{no match}
+% \endif
+% }
+% \edef\x{%
+% \cptdocasse\ifcassenumcmpTF{5}
+% {=2}\do{equal to 2}
+% \elseif
+% {<3}\do{less than 3}
+% \elseif
+% {>4}\do{greater than 4}
+% \elseif
+% \do{no match}
+% \endif
+% }
+% \edef\x{%
+% \cptdocasse\ifstrcmpTF{x}
+% a\do{\def\y{a}}
+% \elseif
+% b\do{\def\y{b}}
+% \elseif
+% \endif
+% }
+\new@def*\cptdocasse#1#2{%
+ \ifstrcmpTF{#1}\elseif{%
+ \gobble@to@endif
+ }{%
+ \ifstrcmpTF{#1}\endif{}{%
+ \ifstrcmpTF{#2}\elseif{%
+ \gobble@to@endif
+ }{%
+ \ifstrcmpTF{#2}\endif{}{\cptdocasse@i{#1}{#2}}%
+ }%
+ }%
+ }%
+}
+\new@def*\cptdocasse@i#1#2#3{%
+ \ifstrcmpTF{#3}\elseif{%
+ \cptdocasse@i{#1}{#2}%
+ }{%
+ \ifstrcmpTF{#3}\endif{}{%
+ \ifstrcmpTF{#3}\do{%
+ \do@else@part\do
+ }{%
+ \cptdocasse@ii{#1}{#2}{#3}%
+ }%
+ }%
+ }%
+}
+\new@def*\cptdocasse@ii#1#2#3\do#4{%
+ \ifstrcmpTF{#4}\elseif{%
+ \cptdocasse@ii{#1}{#2}%
+ }{%
+ \ifstrcmpTF{#4}\endif{}{%
+ #1{#2}{#3}{%
+ \unexpanded{#4}%
+ \gobble@to@endif
+ }{%
+ \cptdocasse@i{#1}{#2}%
+ }%
+ }%
+ }%
+}
+
\robust@def\cpt@in#1#2{%
\long\def\in@@##1#1##2\in@@{%
- \begingroup
- \toks@{##2}%
- \edef\in@@{\the\toks@}%
- \expandafter\endgroup
+ \edef\in@@{\unexpanded{##2}}%
\ifx\in@@\@empty\cpt@infalse\else\cpt@intrue\fi
}%
\in@@#2{\in@@}#1\in@@
@@ -2754,22 +3224,32 @@
\cpt@notonetokenerr{#2}%
}%
}
-\robust@def*\cptaddtolist{\cpt@teststopt{\cpt@addtolist\expandcsonce{e}},}
-\robust@def*\cptgaddtolist{\cpt@teststopt{\cpt@addtolist\expandcsonce{x}},}
+% \cptaddtolist[<parser>]<\cs>{<newitem>}
+% * -> use \protected@(e)xdef.
+% uadd -> don't expand <newitem> at all.
+% oadd -> expand <newitem> once.
+% xadd -> fully expand <newitem>.
+% gadd -> add globally.
+\robust@def*\cptuaddtolist{\cpt@teststopt{\cpt@addtolist\unexpanded{e}},}
+\robust@def*\cptguaddtolist{\cpt@teststopt{\cpt@addtolist\unexpanded{x}},}
+\robust@def*\cptoaddtolist{\cpt@teststopt{\cpt@addtolist\expandcsonce{e}},}
+\robust@def*\cptgoaddtolist{\cpt@teststopt{\cpt@addtolist\expandcsonce{x}},}
\robust@def*\cptxaddtolist{\cpt@teststopt{\cpt@addtolist\@firstofone{e}},}
\robust@def*\cptgxaddtolist{\cpt@teststopt{\cpt@addtolist\@firstofone{x}},}
+\newletcs\cptaddtolist\cptuaddtolist
+\newletcs\cptgaddtolist\cptguaddtolist
\robust@def\cpt@addtolist#1#2[#3]#4#5{%
\ifcpt@check\cpt@checklistparser{#3}\relax\fi
\begingroup
\toks@{\endgroup
\ifdefTF#4{%
- \ifboolTF{cpt@st}{%
+ \ifdefboolTF{cpt@st}{%
\usename{protected@#2def}#4{\csliststack#3#4#1{#5}}%
}{%
\usename{#2def}#4{\csliststack#3#4#1{#5}}%
}%
}{%
- \ifboolTF{cpt@st}{%
+ \ifdefboolTF{cpt@st}{%
\usename{protected@#2def}#4{#1{#5}}%
}{%
\usename{#2def}#4{#1{#5}}%
@@ -2782,6 +3262,25 @@
\the\toks@
}%
}
+\robust@def*\cptapptomacro{\cpt@testst{\cpt@hooktomacro>}}
+\robust@def*\cptpreptomacro{\cpt@testst{\cpt@hooktomacro<}}
+\robust@def\cpt@hooktomacro#1#2#3{%
+ \cpt@getmacroprefix{#2}%
+ \ifcpt@st\let\reserved@a\expandcsonce\else\let\reserved@a\unexpanded\fi
+ \ifdefTF{#2}{%
+ \ifx#1>%
+ \macroprefix\edef#2{\expandcsonce{#2}\reserved@a{#3}}%
+ \else
+ \macroprefix\edef#2{\reserved@a{#3}\expandcsonce{#2}}%
+ \fi
+ }{%
+ \macroprefix\edef#2{\reserved@a{#3}}%
+ }%
+}
+% #1 : optional list parser
+% #2 : control sequence of main list
+% #3 : sublist to remove (not cs)
+% #4 : filter/wrapper
\robust@def*\cptfilterremovecsv{%
\begingroup
\let\cpt@inkv\cptswfalse
@@ -2812,8 +3311,9 @@
\expandafter\def\temp@do##1{%
\edef\cpt@tempa{\unexpanded{##1}}%
\cpt@usefilter\cpt@tempa\cpt@tempb
+ % no \oifinset@sp@TF here (see detokenization above):
\expandafter\xifinsetTF\cpt@tempd\cpt@tempb{}{%
- \cptaddtolist[#1]\cpt@tempc{##1}%
+ \cptuaddtolist[#1]\cpt@tempc{##1}%
}%
}%
\ifcsnullTF#2{}{%
@@ -2835,6 +3335,10 @@
}%
}%
}
+% #1 : parser
+% #2 : old list (a control sequence) of parser-separated list
+% #3 : new update (a non-command list)
+% #4 : element-wise filter/wrapper
\newletcs\everymergeitem=\@iden
\robust@def*\cptfiltermergecsv{%
\begingroup
@@ -2867,8 +3371,8 @@
\expandafter\def\temp@do####1{%
\edef\cpt@merge@c{\unexpanded{####1}}%
\cpt@usefilter\cpt@merge@c\cpt@merge@d
- \cptscantokens\cpt@merge@b
- \cptscantokens\cpt@merge@d
+ \cptscancs\cpt@merge@b
+ \cptscancs\cpt@merge@d
\ifx\cpt@merge@b\cpt@merge@d
\cpt@choicefdtrue\cpt@add\cpt@merge@a
\else
@@ -2876,7 +3380,7 @@
\fi
}%
\cptexpandargonce{\def#2{}\temp@parse[#1]}#2%
- \ifboolTF{cpt@choicefd}{}{\cpt@add\cpt@merge@a}%
+ \ifdefboolTF{cpt@choicefd}{}{\cpt@add\cpt@merge@a}%
}%
\ifcsnullTF#2{%
\edef#2{\expandcsonce\cpt@update}%
@@ -2887,8 +3391,16 @@
}%
\postgroupdef#2\endgroup
\let\everymergeitem\@firstofone
+ % No need to undefine \temp@parse, \temp@do, etc:
+ % they have been defined in a local group.
}
\cptnewvariables{switch}[cpt@]{fromrepl,fromrem}[false]
+
+% See also \cptfilterremovecsv:
+% #1 : optional list parser
+% #2 : listcmd
+% #3 : single element to remove
+% * -> remove all occurrences of #3
\robust@def*\cptremoveoneelement{\cpt@teststopt\cpt@removeoneelement,}
\robust@def\cpt@removeoneelement[#1]#2#3{%
\begingroup
@@ -2901,12 +3413,15 @@
}%
\xifinsetTF{\detokenize{#1##1#1}}{\pser\cptoxdetok{#2}\pser}{%
\expandafter\cpt@remove@b\expandafter#1#2#1\remove@nil
- \ifboolTF{removest}{%
+ % If removing all occurrences:
+ \ifdefboolTF{removest}{%
\expandafter\cpt@remove@a\expandafter{\cpt@remove@c}%
}{}%
}{}%
}%
\ifdefswitchTF{cpt@fromrem}{%
+ % We're coming from \cptremoveelements, #3 has been
+ % trimmed and #2 has already been normalized:
\edef\cpt@remove@c{\unexpanded{#3}}%
}{%
\cpt@sttrue\cpt@csvnormalize[#1]#2%
@@ -2922,6 +3437,9 @@
}%
\postgroupdef#2\endgroup
}
+% #1 : optional list parser
+% #2 : control sequence of list
+% #3 : sublist to remove
\robust@def*\cptremoveelements{\cpt@teststopt\cpt@removeelements,}
\robust@def\cpt@removeelements[#1]#2#3{%
\begingroup
@@ -2934,6 +3452,12 @@
\csv@@parse[#1]{#3}%
\postgroupdef#2\endgroup
}
+% \cptreplaceoneelement[<parser>]{<cs>}{<search>}{<replace>}
+% #1: optional list parser
+% #2: control sequence of list
+% #3: single item to replace
+% #4: item to substitute
+% * -> replace all occurrences
\robust@def*\cptreplaceoneelement{\cpt@teststopt\cpt@replaceoneelement,}
\robust@def\cpt@replaceoneelement[#1]#2#3#4{%
\begingroup
@@ -2946,12 +3470,15 @@
}%
\xifinsetTF{\detokenize{#1##1#1}}{\pser\cptoxdetok#2\pser}{%
\expandafter\cpt@replace@b\expandafter#1#2#1\rep@nil
- \ifboolTF{replst}{%
+ % If replacing all occurrences of #3 in #2:
+ \ifdefboolTF{replst}{%
\expandafter\cpt@replace@a\expandafter{\cpt@replace@c}%
}{}%
}{}%
}%
\ifdefswitchTF{cpt@fromrepl}{%
+ % We're coming from \cptreplaceelements, #3 has been
+ % trimmed and #2 has already been normalized:
\edef\cpt@replace@c{\unexpanded{#3}}%
}{%
\cpt@sttrue\cpt@csvnormalize[#1]#2%
@@ -2969,6 +3496,11 @@
}%
\postgroupdef#2\endgroup
}
+% #1: optional list parser
+% #2: listcmd
+% #3: items to replace
+% #4: items to substitute
+% * -> replace all occurrences
\robust@def*\cptreplaceelements{\cpt@teststopt\cpt@replaceelements,}
\robust@def\cpt@replaceelements[#1]#2#3#4{%
\begingroup
@@ -3064,7 +3596,7 @@
\robust@def*\cpt@undefcsset#1{%
\cpt@stchoose{cpt@st}{#1}\cpt@rsvda\undefcsset
\expandafter\cptfor\cpt@rsvda\dofor{%
- \ifsingletoken@sp@TF{##1}{%
+ \ifsingletokenTF{##1}{%
\ifescapedTF{##1}{%
\ifcpt@cl\global\fi\undefcs##1%
}{%
@@ -3075,6 +3607,8 @@
}%
}%
}
+% #1: parser, #2: listcmd
+% This is one way to preserve braces in #2:
\robust@def*\cpttrimleadparsers#1#2{%
\ifblankTF{#1}{%
\cpt@err{Empty parser in \string\cpttrimleadparsers}\@ehc
@@ -3096,6 +3630,7 @@
\expandafter\reserved@e\expandafter.#2#1\noboundary
\postgroupdef#2\endgroup\cpt@relax
}
+% #1: parser, #2: list command
\robust@def\cpttrimtrailparsers#1#2{%
\begingroup
\def\cpt@trima{%
@@ -3120,6 +3655,7 @@
\cpt@notonetokenerr{#1}%
}%
}
+% #1: token on command, #2: test token:
\robust@def\cpt@stripsuffix#1#2{%
\ifblankTF{#2}{%
\cpt@err{Blank test token for \string\cpt@stripsuffix}\@ehc
@@ -3129,6 +3665,7 @@
}%
}%
}
+% Strip #1 number of outer braces in #2; return result in #3:
\robust@def*\cptstripNouterbraces{\cpt@testopt\cpt@stripouterbraces\@ne}
\newletcs\cptstripnbr\cptstripNouterbraces
\robust@def*\cpt@stripouterbraces[#1]{%
@@ -3200,6 +3737,7 @@
\repeat
\postgroupdef#3\endgroup
}
+% Expandable:
\edef\ifmacroTF#1{%
\noexpand\ifblankTF{#1}{%
\noexpand\@secondoftwo
@@ -3229,6 +3767,10 @@
{@\ifx\x\@backslashchar first\else second\fi oftwo}%
}
\robust@def*\ifescapedFT#1{\ifescapedTF{#1}\iiofii\iofii}
+% \robustaliascount counts the number of 'robustified' commands.
+% It may be used to set a threshold for the no. of allowable
+% aliases. \cptrobustify avoids \scantokens, because some commands
+% aren't scannable:
\cptchardef\maxrobustalias50
\robust@def*\cptrobustify#1{%
\def\csv@do##1{%
@@ -3300,13 +3842,45 @@
\catcode`\{\@ne
\catcode`\}\tw@
}
-\robust@def*\cptscantokens#1{%
+% #1 must be a non-parametered macro:
+\robust@def*\cptscancs#1{%
\begingroup
\edef#1{\long\def\string#1{\cptoxdetok{#1}}}%
\cpteveryscan
\scantokens\expandafter{#1}\relax
\postgroupdef#1\endgroup
}
+\newletcs\cptscantokens\cptscancs
+\begingroup
+ \lccode`\A =`\@ %
+ \lccode`\B =`\@ %
+ \catcode`\A = 8 %
+ \catcode`\B = 3 %
+\lowercase{\endgroup\def\cpt@rescan@marker{AB}}
+\robust@def*\cptrescan{\cpt@rescan@a\def}
+\robust@def*\cptgrescan{\cpt@rescan@a\gdef}
+% #1 = \def or \gdef
+% #2 = command to receive the re-scanned stuff
+% #3 = arbitrary code to execute before \scantokens
+% #4 = stuff to rescan
+\robust@def*\cpt@rescan@a#1#2#3#4{%
+ \begingroup
+ \everyeof\expandafter{\cpt@rescan@marker\noexpand}%
+ \endlinechar\m@one\newlinechar\m@one
+ #3%
+ \cptexpanded{\endgroup
+ #1\noexpand#2{%
+ \expandafter\cpt@rescan@b\expandafter\@empty
+ \scantokens\expandafter{#4}%
+ }%
+ }%
+}
+\edefpass\reserved@a{%
+ % The \expandafter here is to get rid of \@empty:
+ \def\noexpand\cpt@rescan@b##1\cpt@rescan@marker{%
+ \noexpand\unexpanded\noexpand\expandafter{##1}%
+ }%
+}
\robust@def*\cpt@lowercasecs#1{%
\ifmacroTF{#1}{%
\cptexpandarg\lowercase{\def\noexpand#1{#1}}%
@@ -3432,6 +4006,26 @@
}%
}
\reserved@a{ }
+% Convert bool value (true or false) to switch value (00 or 01):
+\robust@def*\booltoswitch#1#2{%
+ \begingroup
+ \def\reserved@a##1#1##2##3\@nil{%
+ \def#2{##2}%
+ \ifx#2\@nnil
+ \cpt@err{Bad boolean value '#1' can't be
+ \MsgBrk converted to switch value}\@ehc
+ \fi
+ }%
+ \reserved@a true{00}false{01}#1{\@nil}\@nil
+ \postgroupdef#2\endgroup
+}
+% Expandable:
+\new@def*\bbooltoswitch#1{%
+ \expandafter\ifstrcmpTF\expandafter
+ {\romannumeral-`\q\expandafter\cpttrimspace
+ \expandafter{\romannumeral-`\q#1}}{true}{00}{01}%
+}
+
\robust@def*\newswitch#1{\cpt@testopt{\cpt@newswitch#1}{false}}
\robust@def*\cpt@newswitch#1[#2]{%
\ifinsetTF{,}{#1}{%
@@ -3457,7 +4051,7 @@
\robust@def*\cpt@noswitcherr#1{%
\cpt@err{Switch '\string#1' is undefined}\@ehc
}
-\robust@def*\setswitch#1#2{%
+\robust@def*\cptsetswitch#1#2{%
\ifcsndefTF{#1}{%
\cpt@getswitchstate{#2}%
\letcsntocsn{#1}{cptsw\cpt@switchstate}%
@@ -3465,36 +4059,38 @@
\cpt@noswitcherr{#1}%
}%
}
-\robust@def*\setswitchtrue#1{%
+\robust@def*\cptsetswitchtrue#1{%
\ifcsndefTF{#1}{%
\letcsntocs{#1}\cptswtrue
}{%
\cpt@noswitcherr{#1}%
}%
}
-\newletcs\switchtrue\setswitchtrue
-\robust@def*\setswitchfalse#1{%
+\newletcs\cptswitchtrue\cptsetswitchtrue
+\robust@def*\cptsetswitchfalse#1{%
\ifcsndefTF{#1}{%
\letcsntocs{#1}\cptswfalse
}{%
\cpt@noswitcherr{#1}%
}%
}
-\newletcs\switchfalse\setswitchfalse
+\newletcs\cptswitchfalse\cptsetswitchfalse
\new@def*\ifdefswitchTF#1{%
\ifcsndefFT{#1}{%
\cpt@err{Switch '#1' is not defined}\@ehc
\@gobbletwo
}{%
- \ifcondTF\if\usename{#1}\fi
+ \if\usename{#1}\expandafter\iofii\else\expandafter\iiofii\fi
}%
}
\new@def*\ifdefswitchFT#1{\ifdefswitchTF{#1}\iiofii\iofii}
-\new@def*\ifswitchTF#1{\ifcondTF\if\usename{#1}\fi}
+\new@def*\ifswitchTF#1{%
+ \if\usename{#1}\expandafter\iofii\else\expandafter\iiofii\fi
+}
\new@def*\ifswitchFT#1{\ifswitchTF{#1}\iiofii\iofii}
-\new@def*\thebool@normal#1{\ifdefboolTF{#1}{true}{false}}
-\new@def*\thebool@reverse#1{\ifdefboolTF{#1}{false}{true}}
-\cptnewcounts{cpt@exprcnt}
+\new@def*\thebool@normal#1{\ifboolTF{#1}{true}{false}}
+\new@def*\thebool@reverse#1{\ifboolTF{#1}{false}{true}}
+\cptnewcounts[cpt@]{exprcnt}
\robust@def*\ifexprTF#1{%
\begingroup
\let\cpt@expr@neg\cptswfalse
@@ -3581,7 +4177,7 @@
\robust@def\cpt@expr@bool@a#1#2\expr@nil{%
\edef\reserved@a{\cpttrimspaces{#1}}%
\ifcsndefTF{if\reserved@a}{%
- \ifboolTF\reserved@a\cpt@expr@true\cpt@expr@false
+ \ifdefboolTF\reserved@a\cpt@expr@true\cpt@expr@false
}{%
\cpt@err{Invalid test expression:
\MsgBrk boolean '\reserved@a' is undefined}\@ehc
@@ -3630,6 +4226,8 @@
\expandafter\endgroup\ifcpt@choicefd
\expandafter\iofii\else\expandafter\iiofii\fi
}
+% #1: listcmd
+% #2: comparator: < (ascending) or > (descending)
% Eg, \def\x{13251{8/2}} \cptnumbersort\x>
\robust@def*\cptnumbersort#1#2{%
\begingroup
@@ -3652,6 +4250,8 @@
{You need to first load 'fp' package before
\MsgBrk calling \string\cptbignumbersort.}%
}%
+ % If #1 contains expressions, evaluate them first before
+ % sorting the results:
\cptexpandarg{\cptifonepresentTF{/*-+}}{\cptoxdetok{#1}}{%
\def\siso@do##1{%
\FPeval\resulta{clip(##1)}%
@@ -3672,23 +4272,25 @@
}
\robust@def*\cpt@sortlist#1#2{%
\def\sortedlist{}%
- \cpt@s@rtlist{#1}{#2}%
+ \cpt@sortlist@a{#1}{#2}%
\edefpass#1{\endgroup\def\noexpand#1{\sortedlist}}%
}
\new@def*\cpt@sortwrapper#1{{#1}}
-\robust@def*\cpt@s@rtlist#1#2{%
+\robust@def*\cpt@sortlist@a#1#2{%
+ % Get the largest/smallest number and return:
\def\do##1{%
\def\smaller@bigger{}%
\defpass\do####1{%
\defifxTF{####1}\@nnil{%
+ % Store the largest/smallest number:
\edef\sortedlist{\sortedlist\cpt@sortwrapper{##1}}%
\ifcsemptyTF\smaller@bigger{}{%
\let#1=\smaller@bigger
- \cpt@s@rtlist#1#2%
+ \cpt@sortlist@a#1#2%
}%
}{%
\numcmp####1#2##1{%
- \cpt@s@rtl@st{#1}{#2}{{####1}{##1}}.%
+ \cpt@sortlist@b{#1}{#2}{{####1}{##1}}.%
}{%
\edef\smaller@bigger{\smaller@bigger{####1}}%
\do
@@ -3698,11 +4300,11 @@
}%
\expandafter\do#1\@nil
}
-\robust@def*\cpt@s@rtl@st#1#2#3#4\@nil{%
+\robust@def*\cpt@sortlist@b#1#2#3#4\@nil{%
+ % \@gobble is for gobbling the dot:
\edef#1{#3\smaller@bigger\@gobble#4}%
- \cpt@s@rtlist{#1}{#2}%
+ \cpt@sortlist@a{#1}{#2}%
}
-
\robust@def*\BeforeProcessOptions{%
\ifcsndefTF{\@currname @\@currext @beginprocessopt}{%
\cpt@warn{\noexpand\BeforeProcessOptions wrongly located}%
@@ -3773,7 +4375,7 @@
}%
}
% If package has been loaded with <options>.
-% \ifpackagewithoptionsTF{<package>}{<options>}
+% \ifpackagewithoptionsTF{<package>}{<options>}{<true>}{<false>}
\robust@def*\ifpackagewithoptionsTF{\cpt@ifoptions\@pkgextension}
\robust@def*\ifclasswithoptionsTF{\cpt@ifoptions\@clsextension}
\robust@def*\cpt@ifoptions#1#2{%
@@ -3802,9 +4404,35 @@
\checkopts
}%
}%
- \ifboolTF{cpt@choicefd}
+ \ifdefboolTF{cpt@choicefd}
{\endgroup\@firstoftwo}{\endgroup\@secondoftwo}%
}
+% #1=package, #2=options
+\robust@def*\cptcheckoptionclash#1#2{%
+ \begingroup
+ \edef\cpt@rsvda{\detokenize\expandafter
+ {\romannumeral-`\q\cpt@optionlist{#1.\@pkgextension}}}%
+ \@tempswafalse
+ \ifblankTF{#2}{%
+ \ifcsnullTF\cpt@rsvda{}\@tempswatrue
+ }{%
+ \ifcsnullTF\cpt@rsvda{%
+ \@tempswatrue
+ }{%
+ \def\kv@do####1{%
+ \xifinsetTF{,\detokenize{####1},}{,\cpt@rsvda,}{}{%
+ \@tempswatrue\loopbreak
+ }%
+ }%
+ \kv@@parse[,]{#2}%
+ }%
+ }%
+ \expandafter\endgroup
+ \if@tempswa
+ \cpt@err{Option clash for package ##1.\@pkgextension}\@ehc
+ \expandafter\@gobble
+ \fi
+}
% If package was later loaded (before begin-document).
% \ifpackageloadedlaterTF{<package>}{<true>}{<false>}
\robust@def*\ifpackageloadedlaterTF{\cpt@ifpkgloadedlater\@pkgextension}
@@ -3831,6 +4459,10 @@
}%
}%
}
+% \cptloadpackages[<inner-parser><outer-parser>]{%
+% pkga<inner>options<inner>date<outer>
+% pkgb<inner>options<inner>date<outer>
+% }
\robust@def*\cptloadpackages{%
\begingroup
\endlinechar=-1
@@ -3839,6 +4471,7 @@
\robust@def\cpt@loadpackages[#1]#2{%
\begingroup
\toks@{}%
+ % ##1: inner parser; ##2 outer parser:
\def\cpt@tempa##1##2\cpt@nil{%
\ifblankTF{##2}{%
\cpt@err{No outer parser or something wrong
@@ -3851,6 +4484,7 @@
\expandafter\@gobble
}%
}%
+ % \cpt@lo@dpackages can't be taken outside \cpt@loadpackages:
\def\cpt@lo@dpackages####1##1####2##1####3##1####4\cpt@nil{%
\ifblankTF{####1}{%
\cpt@err{No package name while in \string\cptloadpackages}\@ehc
@@ -3862,6 +4496,7 @@
\cptstripallouterbraces{####2}\cpt@rsvda
}%
\@ifpackageloaded{####1}{%
+ % Check if package was previously loaded with options:
\edef\cpt@rsvdb{\detokenize\expandafter
{\romannumeral-`\q\cpt@optionlist{####1.\@pkgextension}}}%
\@tempswafalse
@@ -3902,6 +4537,86 @@
\cpt@tempa#1\cpt@nil
\expandafter\endgroup\the\toks@
}
+% Eg,
+% \cptrequirepackages{%
+% pkga|options|date; pkgb|options|date; etc.
+% }
+\robust@def*\cptrequirepackages#1{%
+ \begintoksgroup
+ \let\RequirePackage\relax
+ \def\cpt@requirepackage##1|##2|##3|##4\@nil{%
+ \edef\cpt@tempa{\cpttrimspaces{##1}}%
+ \edef\cpt@tempb{\cpttrimspaces{##2}}%
+ \edef\cpt@tempc{\cpttrimspaces{##3}}%
+ \@ifpackageloaded{\cpt@tempa}{%
+ \xifstrcmpTF\cpt@tempc{^?^}{}{%
+ \@ifpackagelater\cpt@tempa\cpt@tempc{%
+ \cptexpandbracenext\cptstripallouterbraces\cpt@tempb\cpt@tempb
+ \cptexpandsecond\cptcheckoptionclash
+ {{\expandcsonce\cpt@tempa}{\expandcsonce\cpt@tempb}}%
+ }{%
+ \addto@hook\toks@{\@latex@error{Loaded version of
+ '\cpt@tempa' package is not current}\@ehc}%
+ }%
+ }%
+ }{%
+ \xifstrcmpTF\cpt@tempb{^?^}{%
+ \xifstrcmpTF\cpt@tempc{^?^}{%
+ \addto@hook\toks@{\RequirePackage{\cpt@tempa}}%
+ }{%
+ \addto@hook\toks@{\RequirePackage{\cpt@tempa}[\cpt@tempc]}%
+ }%
+ }{%
+ \xifstrcmpTF\cpt@tempc{^?^}{%
+ \addto@hook\toks@{\RequirePackage[\cpt@tempb]{\cpt@tempa}}%
+ }{%
+ \addto@hook\toks@{\RequirePackage[\cpt@tempb]{\cpt@tempa}[\cpt@tempc]}%
+ }%
+ }%
+ }%
+ }%
+ \def\csv@do##1{%
+ \cpt@requirepackage##1|^?^|^?^|\@nil
+ }%
+ \csv@@parse[;]{#1}%
+ \endtoksgroup
+}
+% #1=base, #2=modules to be load
+\robust@def*\cptloadmodules#1#2{%
+ \begintoksgroup
+ \def\clash@list{}%
+ \def\do##1##2{%
+ \ifcpt@noval
+ \def\curr@optlist{}%
+ \else
+ \cptstripallouterbraces{##2}\curr@optlist
+ \fi
+ \@ifpackageloaded{##1}{%
+ % check option clash
+ \cptexpandarg{\cpt@ifoptions{sty}{##1}}{\expandcsonce\curr@optlist}{}{%
+ \ifx\curr@optlist\@empty
+ \cptuaddtolist\clash@list{##1}%
+ \else
+ \cptuaddtolist\clash@list{##1=##2}%
+ \fi
+ }%
+ }{%
+ \cptexpanded{\toks@{\the\toks@
+ \noexpand\RequirePackage[\expandcsonce\curr@optlist]{%
+ \ifblankTF{#1}{}{#1-}##1%
+ }}%
+ }%
+ }%
+ }%
+ \kv@@process{#2}\do
+ \ifx\clash@list\@empty
+ \expandafter\endtoksgroup
+ \else
+ \cptexpanded{\endgroup
+ \cpt@err{Option clash for module(s):
+ \noexpand\unexpanded{\expandcsonce\clash@list}}}\@ehc
+ \fi
+}
\robust@def*\AfterEndOfStyleFile{%
\begingroup
\def\cpt@tempa{\endgroup
@@ -3914,9 +4629,7 @@
\cpt@tempa
}%
}
-\robust@def*\ifinstylefileTF{%
- \ifcsemptyTF\@currname\iiofii\iofii
-}
+\robust@def*\ifinstylefileTF{\ifcsemptyTF\@currname\iiofii\iofii}
\robust@def*\cpt@pushhash{%
\begingroup
\@makeother{\#}%
@@ -3968,6 +4681,7 @@
\edef#2{\the\toks@}%
\postgroupdef#2\endgroup
}
+% * -> #2 is a listcmd, else it is a list:
\robust@def*\csv@@normalize{\cpt@teststopt\cpt@csvnormalize,}
\robust@def\cpt@csvnormalize[#1]#2{%
\let\cpt@inkv\cptswfalse
@@ -3990,8 +4704,10 @@
\def\normalized@list{}%
\cptbgobbletorelax
\fi
+ % It is absolutely necessary to check parser here, since this
+ % normalizer doesn't take multiple parsers at once:
\cpt@ch@cklistparser{#1}%
- \expandafter\setup@parser@nmlz\string#1%
+ \expandafter\SetupParserNormalizer\string#1%
\toks@\expandafter{\expandafter#1\reserved@e#1}%
\nmlz@activeparser
\expandafter\nmlz@spaceletter\string#1%
@@ -4001,16 +4717,19 @@
\nmlz@activeequal
\nmlz@spaceletter=%
\nmlz@letterspace=%
+ % We put '^?' at the end of #1 to preserve any trailing '='.
+ % This can happen if a key has an empty value.
\toks@\expandafter{\the\toks@^?}%
\nmlz@doubleletter=%
\cpt@commaequalerr
- \def\reserved@a##1^?##2\cpt@nil{\toks@{##1##2}}%
- \expandafter\reserved@a\the\toks@\cpt@nil
- }%
- \edef\normalized@list{\the\toks@}%
- \cpttrimleadparsers#1\normalized@list
- \cptexpandsecond\endgroup{%
- \ifboolTF{@nmlzst}{%
+ \def\reserved@a##1^?##2\nmlz@nil{\toks@{##1##2}}%
+ \expandafter\reserved@a\the\toks@\nmlz@nil
+ }%
+ \def\reserved@a#1##1\nmlz@nil{\edef\normalized@list{\unexpanded{##1}}}%
+ \expandafter\reserved@a\the\toks@\nmlz@nil
+% \cpttrimleadparsers#1\normalized@list
+ \cptexpanded{\endgroup
+ \ifdefboolTF{@nmlzst}{%
\edef\noexpand#2{\ox@unexpanded\normalized@list}%
}{%
\cpt@csexit\normalized@list
@@ -4020,7 +4739,7 @@
}
\endgroup
-\def\setup@parser@nmlz#1{%
+\new@def*\SetupParserNormalizer#1{%
\begingroup
\uccode`\~=`#1%
\uppercase{\endgroup
@@ -4043,11 +4762,8 @@
\uppercase{\endgroup
\def\nmlz@activeequal{%
\def\cpt@tempa##1~##2\nmlz@nil{%
- \ifblankTF{##2}{%
- \toks@{##1}%
- }{%
- \cpt@tempa##1=##2\nmlz@nil
- }%
+ \ifblankTF{##2}
+ {\toks@{##1}}{\cpt@tempa##1=##2\nmlz@nil}%
}%
\toks@\expandafter{\expandafter}\expandafter
\cpt@tempa\the\toks@~\nmlz@nil
@@ -4055,32 +4771,23 @@
}
\def\nmlz@doubleletter#1{%
\def\cpt@tempa##1#1#1##2\nmlz@nil{%
- \ifblankTF{##2}{%
- \toks@{##1}%
- }{%
- \cpt@tempa##1#1##2\nmlz@nil
- }%
+ \ifblankTF{##2}
+ {\toks@{##1}}{\cpt@tempa##1#1##2\nmlz@nil}%
}%
\expandafter\cpt@tempa\the\toks@#1#1\nmlz@nil
}
\defpass\cpt@tempa#1{%
\def\nmlz@spaceletter##1{%
\def\cpt@tempa####1#1##1####2\nmlz@nil{%
- \ifblankTF{####2}{%
- \toks@{####1}%
- }{%
- \cpt@tempa####1##1####2\nmlz@nil
- }%
+ \ifblankTF{####2}
+ {\toks@{####1}}{\cpt@tempa####1##1####2\nmlz@nil}%
}%
\expandafter\cpt@tempa\the\toks@#1##1\nmlz@nil
}%
\def\nmlz@letterspace##1{%
\def\cpt@tempa####1##1#1####2\nmlz@nil{%
- \ifblankTF{####2}{%
- \toks@{####1}%
- }{%
- \cpt@tempa####1##1####2\nmlz@nil
- }%
+ \ifblankTF{####2}
+ {\toks@{####1}}{\cpt@tempa####1##1####2\nmlz@nil}%
}%
\expandafter\cpt@tempa\the\toks@##1#1\nmlz@nil
}%
@@ -4094,6 +4801,108 @@
}%
\expandafter\cpt@tempa\the\toks@,=\nmlz@nil
}
+% Double parser normalizer. This is for normalizing lists
+% like {x|| y|||| z}, where the parser is double bar ||:
+\new@def*\SetupDoubleParserNormalizer#1{%
+ \begingroup
+ \uccode`\~=`#1%
+ \uppercase{\endgroup
+ \def\cptnormalizedoubleparser##1{%
+ \unexpanded\expandafter{\romannumeral-`\q
+ \nmlz@activedoubleparser#1#1##1#1#1~~\nmlz@nil}%
+ }%
+ \def\nmlz@activedoubleparser##1~~##2\nmlz@nil{%
+ \ifblankTF{##2}
+ {\nmlz@spacedoubleparser##1 #1#1\nmlz@nil}
+ {\nmlz@activedoubleparser##1#1#1##2\nmlz@nil}%
+ }%
+ }%
+ \def\nmlz@spacedoubleparser##1 #1#1##2\nmlz@nil{%
+ \ifblankTF{##2}
+ {\nmlz@doubleparserspace##1#1#1 \nmlz@nil}
+ {\nmlz@spacedoubleparser##1#1#1##2\nmlz@nil}%
+ }%
+ \def\nmlz@doubleparserspace##1#1#1 ##2\nmlz@nil{%
+ \ifblankTF{##2}
+ {\nmlz@fourparser##1#1#1#1#1\nmlz@nil}
+ {\nmlz@doubleparserspace##1#1#1##2\nmlz@nil}%
+ }%
+ \def\nmlz@fourparser##1#1#1#1#1##2\nmlz@nil{%
+ \ifblankTF{##2}
+ {\ifblankTF{##1}{}{\@gobbletwo##1}}
+ {\nmlz@fourparser##1#1#1##2\nmlz@nil}%
+ }%
+}
+% This is for normalizing lists like {x\\ y\\\\ z}, where \\ is
+% a control sequence:
+\robust@def*\SetupSpecialParserNormalizer#1{%
+ \def\cptspecialnormalize##1{%
+ \unexpanded\expandafter{\romannumeral-`\q
+ \spnmlz@spaceparser##1 #1\nmlz@nil}%
+ }%
+ \def\spnmlz@spaceparser##1 #1##2\nmlz@nil{%
+ \ifblankTF{##2}
+ {\spnmlz@parserspace##1#1 \nmlz@nil}
+ {\spnmlz@spaceparser##1#1##2\nmlz@nil}%
+ }%
+ \def\spnmlz@parserspace##1#1 ##2\nmlz@nil{%
+ \ifblankTF{##2}
+ {\spnmlz@doubleparser##1#1#1\nmlz@nil}
+ {\spnmlz@parserspace##1#1##2\nmlz@nil}%
+ }%
+ \def\spnmlz@doubleparser##1#1#1##2\nmlz@nil{%
+ \ifblankTF{##2}{##1}
+ {\spnmlz@doubleparser##1#1##2\nmlz@nil}%
+ }%
+}
+% See file 'commands-with-different-meaning-in-environment' for examples:
+\robust@def*\AtBeginColony#1{\grightaddtocsn{atbegin@#1@colonyhook}}
+\robust@def*\AtEndColony#1{\grightaddtocsn{atend@#1@colonyhook}}
+\new@def*\colonyarg#1{\@nameuse{colony@arg@\romannumeral#1}}
+\robust@def*\newcolony{\cpt@starorlong\new@colony}
+\def\new@colony#1{\cpt@testopt{\newcolony@a#1}0}
+\def\newcolony@a#1[#2]{%
+ \cpt@ifbrack{\newcolony@b{#1}{#2}}{\newcolony@c{#1}{[#2]}}%
+}
+\def\newcolony@b#1#2[#3]{\newcolony@c{#1}{[#2][{#3}]}}
+\robust@def*\renewcolony{\cpt@starorlong\renew@colony}
+\def\renew@colony#1{%
+ \ifcsndefTF{#1}{}{\cpt@err{Environment '#1' is undefined}\@ehc}%
+ \expandafter\let\csname#1\endcsname\relax
+ \expandafter\let\csname end#1\endcsname\relax
+ \new@colony{#1}%
+}
+\long\def\newcolony@c#1#2#3#4{%
+ \ifcsndefTF{#1}{}{\letcsntocsn{#1}{end#1}}%
+ \def\reserved@a[##1]##2\@nil{%
+ \chardef\@tempa\z@pt
+ \loop\ifnum\@tempa<##1\relax
+ \edef\@tempa{\the\numexpr\@tempa+1}%
+ \cptexpandarg{\rightaddtocs\@tempb}{%
+ \csn@edef{colony@arg@\romannumeral\@tempa}%
+ {\noexpand\unexpanded{################\number\@tempa}}%
+ }%
+ \repeat
+ }%
+ \reserved@a#2\@nil
+ \cptexpandbracenext{\aftercsname\new@command{#1}#2}{%
+ \@tempb
+ \@nameuse{atbegin@#1@colonyhook}%
+ \@nameuse{#1@env@defs}#3%
+ }%
+ \l@ngrel@x\csn@def{end#1}{%
+ #4\@nameuse{atend@#1@colonyhook}%
+ }%
+}
+% #1 = environment name; #2 = command
+\robust@def*\newcolonycmd{\cpt@testst\new@colonycmd}
+\robust@def\new@colonycmd#1#2{%
+ \aftercsname\rightaddtocs{#1@env@defs}{\colonyletcs{#1}{#2}}%
+ \cptexpanded{\noexpand\newcommand\ifcpt@st*\fi
+ \noexpandcsn{#1@\cptgobblescape#2}}%
+}
+\def\colonyletcs#1#2{\letcstocsn{#2}{#1@\cptgobblescape#2}}
+
\robust@def*\cptcheckbool#1#2#3{%
\lowercase{%
\edef\cpt@resa{\s@expandarg\cpttrimspaces{\cptrm-`\q#1}}%
@@ -4104,6 +4913,14 @@
\@latex@error{Invalid value '#1' for '#2'}\@ehc
}%
}
+\robust@def*\cptcheckswitch#1#2{%
+ \edef\cpt@resa{\s@expandarg\cpttrimspaces{\cptrm-`\q#1}}%
+ \xifinsetTF{,\cpt@resa,}{,00,01,}{%
+ #2\relax
+ }{%
+ \@latex@error{Invalid switch value '#1'}\@ehc
+ }%
+}
\robust@def*\RecoverAtRequirePackage#1{%
\ifblankFT{#1}{}{%
\cpt@isblankerr\RecoverAtRequirePackage
@@ -4112,6 +4929,8 @@
\cptfor#1\dofor{%
\ifescapedTF{##1}{%
\ifdefTF{##1}{}{%
+ % If the argument was undefined, then it couldn't be
+ % executed later:
\cpt@notdeferr{##1}%
\@gobble
}%
@@ -4184,7 +5003,7 @@
}%
\def\csv@do##1{%
\ifinsetTF{=}{##1}{}{%
- \cptgaddtolist\@classoptionslist{##1}%
+ \cptguaddtolist\@classoptionslist{##1}%
}%
}%
\expandafter\def\expandafter\@classoptionslist\expandafter
@@ -4219,7 +5038,10 @@
}
\robust@def\cpt@d@clareoption#1#2[#3]#4{%
\cpt@d@cl@reoption{#1}{#2}{#3}%
- \ifboolTF{cpt@olddx}{%
+ \ifdefboolTF{cpt@olddx}{%
+ % The old style of \DeclareOption may have used the
+ % parameter character in a format different from the
+ % system here:
\xifstrcmpTF{\@currname.\@currext}{xcolor.sty}{%
\csn@xdef{#1@ds@#2}{%
\unexpanded{\edef\XC@@opt{\XC@@opt#2,}#4}%
@@ -4269,6 +5091,8 @@
Second invalid option handler for family '##1'?
}%
}{%
+ % The error message will replace key macro, hence
+ % it needs a parameter:
\csn@gdef{##1@invalidoptionerr}####1{#2####1}%
}%
}%
@@ -4308,7 +5132,7 @@
\MsgBrk is invalid or null}{%
Invalid option '##1' of family '#1'.}%
}%
- \ifboolTF{cpt@olddx}{%
+ \ifdefboolTF{cpt@olddx}{%
\csn@xdef{#1@ds@##1}{\cpt@temp@err}%
}{%
\csn@xdef{#1@ds@##1}####1{\cpt@temp@err}%
@@ -4429,10 +5253,16 @@
\cptexpandsecond\cpt@tempa{\cpt@curropts\cpt@nil{\cpt@currfam}}%
\cpt@tempa{#5}{#6}%
}
+% #1: primary option name
+% #2: secondary option name
+% #3: default value
+% #4: macro prefix
+% #5: current family
+% #6: callback for primary option
\robust@def\cpt@d@cl@rebib@oloptions#1#2#3#4#5#6{%
\cpt@d@cl@recmdoption{#5}{#1}{#3}(#4){%
#6\relax
- % If called by sister, don't call back:
+ % If called by sister, don't callback:
\iftogTF{#5@#1}{}{%
\settogtrue{#5@#2}%
\settogtrue{biboolopts}%
@@ -4503,7 +5333,7 @@
family '#1'\MsgBrk (in \@cls@pkg\@space'\@currname')%
}%
}{%
- \aftercsname{\cptaddtolist*}{#1@declaredoptions}{#2}%
+ \aftercsname{\cptoaddtolist*}{#1@declaredoptions}{#2}%
}%
}{%
\csn@xdef{#1@declaredoptions}{\expandcsonce{#2}}%
@@ -4612,7 +5442,7 @@
\cpt@ifoptdis@bled{##1}{#2}%
}%
\csv@@parse*[,]\cpt@currfams
- \ifboolTF{cpt@swa}\ifboolTF\ifdefboolFT{cpt@choicefd}%
+ \ifdefboolTF{cpt@swa}\ifdefboolTF\ifdefboolFT{cpt@choicefd}%
}
\robust@def*\cpt@ifoptdis@bled#1#2{%
\ifcsndefFT{#1@disabledoptions}{}{%
@@ -4630,11 +5460,12 @@
\robust@def*\cpt@ifoptdef<#1>#2{%
\def\cpt@currfams{#1}%
\cpt@choicefdfalse
+ % may break out of loop:
\def\csv@do##1{%
\cpt@ifoptd@f{##1}{#2}%
}%
\csv@@parse*[,]\cpt@currfams
- \ifboolTF{cpt@swa}\ifboolTF\ifdefboolFT{cpt@choicefd}%
+ \ifdefboolTF{cpt@swa}\ifdefboolTF\ifdefboolFT{cpt@choicefd}%
}
\robust@def*\cpt@ifoptd@f#1#2{%
\ifcsndefFT{#1@ds@#2}{}{%
@@ -4684,11 +5515,17 @@
}%
}
\newletcs\rsv@cpt@define@default@ds\cpt@define@default@ds
+% In case a \RequirePackage comes up before end of package:
\RecoverAtRequirePackage\cpt@define@default@ds
+
\new@def*\cpt@optionlist#1{%
\ifcsndefFT{opt@#1}{}{\unexpanded\cptsevenxp{\usename{opt@#1}}}%
}
+% Use \kv@@parse and \csv@@parse for all options processing
+% because there might be the need to break out of the loop
+% prematurely.
\newletcs\cpt@processedoptions\@empty
+
\robust@def*\XProcessOptions{%
\csn@def{\@currname @\@currext @beginprocessopt}{}%
\letcstocsn\reserved@a{\@currname @\@currext @beforeprocessopt}%
@@ -4710,7 +5547,7 @@
\cpt@testst{\cpt@testfam\cpt@processoptions}%
}
\robust@def*\cpt@processoptions<#1>{%
- \ifboolTF{cpt@st}{%
+ \ifdefboolTF{cpt@st}{%
\cpt@testopt{\cpt@xprocessoptions#1}{}%
}{%
\cpt@testopt{\cpt@yprocessoptions#1}{}%
@@ -4726,7 +5563,7 @@
\cpt@ypr@cessoptions{##1}%
}%
\csv@@parse{#1}%
- \cpt@pr@cessoptions
+ \cpt@pr@cessoptions{#1}%
\cpt@pr@cessopti@ns
}
\robust@def*\cpt@ypr@cessoptions#1{%
@@ -4769,7 +5606,7 @@
\cpt@xpr@cessoptions{##1}%
}%
\csv@@parse{#1}%
- \cpt@pr@cessoptions
+ \cpt@pr@cessoptions{#1}%
\cpt@pr@cessopti@ns
}
\robust@def*\cpt@xpr@cessoptions#1{%
@@ -4798,7 +5635,7 @@
\ifcsnullTF\cpt@classoptions{}
{\kv@@parse*[,]\cpt@classoptions}%
}
-\robust@def*\cpt@pr@cessoptions{%
+\robust@def*\cpt@pr@cessoptions#1{%
\def\kv@do##1{%
\edef\CurrentOption{\unexpanded{##1}}%
\ifcsnullTF\CurrentOption{}{%
@@ -4831,7 +5668,7 @@
}%
}%
}%
- \csv@@loop*[,]\cpt@currfams
+ \csv@@loop[,]{#1}%
}%
}%
\ifcsnullTF\@curroptions{}{\kv@@parse*[,]\@curroptions}%
@@ -4967,11 +5804,11 @@
\string\XExecuteOptions:\MsgBrk re-executed}%
\fi
}%
- \aftercsname{\cptgaddtolist*}
+ \aftercsname{\cptgoaddtolist}
{\cpt@currfam @exec@warnlist}\cpt@curropt
}%
}{%
- \aftercsname{\cptgaddtolist*}
+ \aftercsname{\cptgoaddtolist}
{\cpt@currfam @executedoptions}\cpt@curropt
}%
\cpt@useoption
@@ -4983,6 +5820,7 @@
}%
\kv@@loop*[,]\cpt@curroptvals
}
+% Alias keys must always come from the parent's family:
\robust@def*\XExecuteAliasOption#1{%
\cpt@testopt{\cpt@executealiasoption#1}{}%
}
@@ -4993,6 +5831,10 @@
\cptexpandsecond\cpt@executeoptions
{<\cpt@currfam>{#1=\expandcsonce\reserved@a}}\relax
}
+% \OptionFound is always the option with its current value,
+% while \CurrentOption may have no value (as in
+% \cpt@ypr@cessoptions, the only function calling
+% \cpt@findoption@a):
\robust@def\cpt@findoption@a{%
\cpt@optfdfalse
\def\kv@do##1{%
@@ -5012,9 +5854,11 @@
\fi
}%
}%
+ % This loop may break prematurely:
\kv@@loop*[,]\cpt@classoptions
}
\robust@def\cpt@findoption@b{%
+ % Here \CurrentOption may have a value:
\let\OptionFound\CurrentOption
\xifinsetTF{=}{\cptoxdetok\CurrentOption}{%
\expandafter\cpt@splitoption\CurrentOption=\opt@split@nil
@@ -5039,19 +5883,20 @@
\robust@def*\cpt@useoption{%
\ifdefboolFT{cpt@inpox}{}{%
\oifinset@sp@TF,\OptionFound\cpt@processedoptions{}{%
- \cptgaddtolist*\cpt@processedoptions\OptionFound
+ \cptgoaddtolist\cpt@processedoptions\OptionFound
}%
\oifinset@sp@TF,\CurrentOption\cpt@processedoptions{}{%
- \cptgaddtolist*\cpt@processedoptions\CurrentOption
+ \cptgoaddtolist\cpt@processedoptions\CurrentOption
}%
\ifcsnullTF\OptionFound{}{\cpt@removecurroption\OptionFound}%
\ifcseqTF\OptionFound\CurrentOption{}{%
\cpt@removecurroption\CurrentOption
}%
}%
- \ifboolTF{cpt@igopt}{}{%
+ \ifdefboolTF{cpt@igopt}{}{%
+ % Don't attempt to catch undefined options here:
\ifcsndefFT{\cpt@currfam @ds@\cpt@curropt}{}{%
- \ifboolTF{cpt@olddx}{%
+ \ifdefboolTF{cpt@olddx}{%
\usename{\cpt@currfam @ds@\cpt@curropt}%
}{%
\ifcsnullTF\cpt@currval{%
@@ -5092,16 +5937,17 @@
\robust@def*\cpt@addto@undecl@opts{%
\edef\everymergeitem##1{\@space##1}%
\cptexpandarg{\cptfiltermergekv[;]\cpt@undeclaredopts}%
- {\cpt@currfam,\cpt@curropt,\cpt@currval}\nofilter
+ {\cpt@currfam,\cpt@curropt,\expandcsonce\cpt@currval}\nofilter
}
\robust@def*\cpt@addto@undef@opts{%
\edef\everymergeitem##1{\@space##1}%
\oifinset@sp@TF,\cpt@curropt\XExternalOptions{}{%
\cptexpandarg{\cptfiltermergekv[;]\cpt@undefinedopts}%
- {\cpt@currfam,\cpt@curropt,\cpt@currval}\nofilter
+ {\cpt@currfam,\cpt@curropt,\expandcsonce\cpt@currval}\nofilter
}%
}
\AfterStartOfDocument{\AtEndDocument{%
+ % \cpt@undeclaredopts from \XExecuteOptions:
\ifdefFT\cpt@undeclaredopts{}{%
\ifcsnullTF\cpt@undeclaredopts{}{%
\despacecontent\cpt@undeclaredopts
@@ -5112,6 +5958,7 @@
}%
}%
}%
+ % \cpt@undefinedopts from \XProcessOptions:
\ifdefFT\cpt@undefinedopts{}{%
\ifcsnullTF\cpt@undefinedopts{}{%
\despacecontent\cpt@undefinedopts
@@ -5157,6 +6004,7 @@
\cptexpandargonce{\cptfilterremovekv[,]%
\@unusedoptionlist}{#1}\nofilter
}
+% Remove processed options from \@unusedoptionlist:
\robust@def*\cpt@optioncleanup#1{%
\ifmacroTF{#1}{}{\cpt@notcserr{#1}}%
\BeforeStartOfDocument{%
@@ -5383,6 +6231,10 @@
\let\@fileswith@pti@ns\@@fileswith@pti@ns
\AtEndOfPackage{\let\@unprocessedoptions\relax}%
}
+% If catoptions is loaded before \documentclass, it will
+% automatically use \XDeclareOption, etc. At \documentclass,
+% if usepox is false, the package will revert to \DeclareOption,
+% etc:
\cptpassunexpanded{%
\begingroup
\def\cpt@tempa{\endgroup