diff options
author | Karl Berry <karl@freefriends.org> | 2011-08-12 22:57:30 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2011-08-12 22:57:30 +0000 |
commit | 7b90a8aacceb4fdb1bfd9d67a541880603099624 (patch) | |
tree | e5793d331ca4d2d4d4e98244570cce17f281be74 /Master/texmf-dist/tex/latex/catoptions/catoptions.sty | |
parent | a07c67c54f352666c40d9af55958e6da1a1b659b (diff) |
catoptions (12aug11)
git-svn-id: svn://tug.org/texlive/trunk@23517 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/catoptions/catoptions.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/catoptions/catoptions.sty | 1785 |
1 files changed, 1221 insertions, 564 deletions
diff --git a/Master/texmf-dist/tex/latex/catoptions/catoptions.sty b/Master/texmf-dist/tex/latex/catoptions/catoptions.sty index ade4194d75b..9cda3633ae1 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.4, July 2011) % +% This is 'catoptions' package (Version 0.2.5, July 2011) % % % % The catoptions package changes LaTeX package loading internals % % so that all subsequently loaded packages can rely on having % @@ -85,17 +85,18 @@ \catcode94=7 \catcode126=13 \edef\cpt@hashchar{\string#} +% Just in case: \m@ne=-1\z@=0pt\p@=1pt \@ifdefinable\m@one{\newcount\m@one\m@one\m@ne} \@ifdefinable\z@pt{\newdimen\z@pt\z@pt\z@} \chardef\active=13 \NeedsTeXFormat{LaTeX2e}[1995/12/01] \ProvidesPackage{catoptions} - [2011/07/07 v0.2.4 Securing catcodes and parsing options (AM)] + [2011/07/30 v0.2.5 Securing catcodes and parsing options (AM)] \ifcase% \ifx\eTeXversion\cpt@undefined\z@pt\else \ifnum\eTeXversion<\tw@\z@pt\else\@ne\fi\fi - \PackageError{catoptions}{eTeX not loaded or old version}% + \PackageError{catoptions}{eTeX not loaded or old version} {This package requires eTeX version 2 or higher.}% \expandafter\endinput \fi @@ -104,6 +105,8 @@ {You aren't using pdfTeX version 1.50.0} {This package requires pdfTeX version 1.50.0}% \fi + +\newcommand*\MsgBrk{\MessageBreak} \def\cptloggingall{\loggingall\tracingifs\@ne} \newcommand*\showcsn{} \protected\def\showcsn#1{\expandafter\show\csname#1\endcsname} @@ -210,7 +213,7 @@ \simpleexpandarg\siso@@loop\cpt@otherchars \cptexpandsecond\endgroup {\edef\noexpand##1{\noexpand\unexpanded{##2}}}% - } + }% \endgroup } \newcommand*\declarefutureletset[2][fl@]{% @@ -335,11 +338,90 @@ } \endgroup +\@ifdefinable\CurrIfnextchar\relax +\long\protected\def\cpt@ifnextchar#1#2#3{% + \begingroup + \let\reserved@a=#1% + \toks@{\endgroup#2}\toks1{\endgroup#3}% + \global\futurelet\@let@token\cpt@ifnext +} +\let\CurrIfnextchar\cpt@ifnextchar +\protected\def\cpt@ifnext{% + \ifx\@let@token\@sptoken + \toks2{\cpt@ifn@xt}% + \else + \ifx\@let@token\reserved@a + \toks2\expandafter{\the\toks@}% + \else + \toks2\expandafter{\the\toks1}% + \fi + \fi + \the\toks2 +} +\@namedef{cpt@ifn@xt} {\global\futurelet\@let@token\cpt@ifnext} +\long\protected\def\ifnextcharTF#1#2#3{% + \begingroup + \cpt@ifnextchar\relax + {\cpt@ifnextcharacter{#1}{#2}{#3}}% + {\cpt@ifnextcharacter{#1}{#2}{#3}}% +} +\long\def\cpt@ifnextcharacter#1#2#3{% + \ifcase + \ifcat\noexpand\@let@token\bgroup 1\fi + \ifcat\noexpand\@let@token\egroup 1\fi + 0\let\next\cpt@ifn@xtcharacter + \else + \def\next{\endgroup\cpt@ifnextchar}% + \fi + \next{#1}{#2}{#3}% +} +\long\def\cpt@ifn@xtcharacter#1#2#3#4{% + \escapechar92\relax + \edef\x{\cpt@ifn@xtch@racter{#1}\cpt@ifn@xtch@racter{#4}}% + \expandafter\endgroup\csname @\expandafter + \ifx\x first\else second\fi oftwo\endcsname + {#2}{#3}#4% +} +\long\def\cpt@ifn@xtch@racter#1{% + \expandafter\cpt@ifn@xtch@r@cter\string#1\relax\noboundary{#1}% +} +\long\def\cpt@ifn@xtch@r@cter#1#2\noboundary#3{% + \ifx\relax#2#1\else\noexpand#3\fi +} \newcommand\cptswap[2]{#2#1} \newcommand\cptswapfirstbraced[2]{#2{#1}} \newcommand\cptswapsecondbraced[2]{{#2}#1} \cptswap{ }{\let\cptsptoken= } \def\@space{ } +\newcommand\aftercsname[2]{% + \expandafter\cptswap\expandafter{\csname#2\endcsname}{#1}% +} +\newcommand\xaftercsname[2]{% + \expandafter\expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\cptswap + \expandafter\expandafter\expandafter{\csname#2\endcsname}{#1}% +} +\newcommand\cptremovescape[1]{% + \ifx\noboundary#1\noboundary + \expandafter\@gobble\else\expandafter\@iden\fi + {\expandafter\@gobble\string#1}% +} +\newcommand\cptgobblescape[1]{% + \ifx\noboundary#1\noboundary + \expandafter\@gobble\else\expandafter\@iden\fi + {\ifnum\escapechar>\@cclv\else + \ifnum\escapechar<\z@pt\else + \expandafter\expandafter + \csname @gobble\ifnum\escapechar=\@xxxii @space\fi + \cptthreexp\endcsname + \fi + \fi + \string#1}% +} +\@ifdefinable\defpass\relax +\@ifdefinable\edefpass\relax +\protected\def\defpass#1#2#{\afterassignment#1\long\def#1#2} +\protected\def\edefpass#1#2#{\afterassignment#1\long\edef#1#2} \newcommand\usename[1]{\csname#1\endcsname}% long! \newcommand\usecsn[1]{% \ifcsname#1\endcsname\expandafter\@iden\else @@ -349,22 +431,23 @@ \usename{@\ifx#1#2\@empty first\else second\fi oftwo}% } \newcommand\ifxFT[2]{\ifxTF{#1}{#2}\@secondoftwo\@firstoftwo} +\newcommand\ifcsemptyTF[1]{\ifxTF#1\@empty} \newcommand*\defifxTF[2]{% \begingroup \edef\cpt@tempa{\unexpanded{#1}}% \expandafter\endgroup\ifx#2\cpt@tempa \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi } -\newcommand*\cptifcondTF[1]{% - \long\def\cptifcondTF##1\fi##2##3{% +\newcommand*\ifcondTF[1]{% + \long\def\ifcondTF##1\fi##2##3{% \romannumeral##1#1\expandafter\@firstoftwo\else \expandafter\@secondoftwo\fi{0 ##2}{0 ##3}% }% } -\cptifcondTF{ } -\long\def\cptifcondFT#1\fi#2#3{\cptifcondTF#1\fi{#3}{#2}} +\ifcondTF{ } +\long\def\ifcondFT#1\fi#2#3{\ifcondTF#1\fi{#3}{#2}} \newcommand*\ifcsnameTF[1]{% - \cptifcondTF\ifcat$\detokenize{#1}$\fi{% + \ifcondTF\ifcat$\detokenize{#1}$\fi{% \@secondoftwo }{% \usename{@\ifcsname#1\endcsname first\else second\fi oftwo}% @@ -379,72 +462,191 @@ \@secondoftwo }% } -\newcommand*\kernel@ifdefinable[2]{% - \cptifcondTF\ifcat$\detokenize{#1}$\fi{% - \@latex@error{Empty command for \string\kernel@ifdefinable}\@ehc +\protected\def\cpt@notdefinable{% + \@latex@error + {Command \@backslashchar\reserved@a\@space already exists}% + {Command \@backslashchar\reserved@a\@space already defined, + \MsgBrk or name \@backslashchar\@qend... illegal.} +} +\newcommand*\if@@definable[2]{% + \edef\reserved@a{\cptremovescape{#1}}% + \begingroup + \ifnamedefTF\reserved@a{% + \endgroup\cpt@notdefinable }{% - \edef\reserved@a{\expandafter\@gobble\string#1}% - \begingroup - \ifnamedefTF\reserved@a{% - \endgroup\@notdefinable - }{% - \edef\reserved@b{\expandafter\@carcube\reserved@a xxx\@nil}% - \ifx\reserved@b\@qend - \toks@{\@notdefinable}% + \edef\reserved@b{\expandafter\@carcube\reserved@a xxx\@nil}% + \ifx\reserved@b\@qend + \toks@{\cpt@notdefinable}% + \else + \ifx\reserved@a\@qrelax + \toks@{\cpt@notdefinable}% \else - \ifx\reserved@a\@qrelax - \toks@{\@notdefinable}% - \else - \toks@{#2}% - \fi + \toks@{#2}% \fi - \expandafter\endgroup\the\toks@ - }% + \fi + \expandafter\endgroup\the\toks@ }% } \protected\def\cpt@oneorgobble\endgroup{% \expandafter\endgroup\ifcpt@choicefd - \expandafter\@iden\else\expandafter\@gobble\fi + \expandafter\@iden + \else + \expandafter\@gobble + \fi } \protected\def\cpt@oneoftwo#1\endgroup{% \let\@firstoftwo\relax \let\@secondoftwo\relax - \edef\cpt@tempa{% - \ifnumcmpTF{#1}{1}{% + \cptpassexpanded{% + \endgroup + \ifcase#1\relax \if@boolTF{cpt@choicefd}\@firstoftwo\@secondoftwo + \or + \if@boolTF{cpt@choicefd}\@secondoftwo\@firstoftwo + \else + \cpt@err{Invalid number '#1'}\noexpand\@ehc + \fi + }% +} +\if@@definable\if@@seeparameter\relax +\protected\def\if@@seeparameter#1#{% + \xifinsetTF + {\detokenize{macro parameter character}} + {\meaning\@let@token}% +} +\newcommand*\cptnewbool[1]{% + \expandafter\if@@definable\csname if#1\endcsname + {\expandafter\newif\csname if#1\endcsname}% +} +\newcommand*\cptnewcount[1]{% + \expandafter\if@@definable\csname#1\endcsname + {\expandafter\newcount\csname#1\endcsname}% +} +\newcommand\iflacus[1]{% + \ifcat$\detokenize\expandafter{\@gobble#1.}$% + \expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi +} +% \cptcommanormalize and \docommalist are cheap but are restricted +% to comma lists only. Also, they aren't meant for parsing key-val +% lists. See \kv@@normalize and \kv@@parse: +\begingroup +\uccode`\~=`\,% +\uppercase{\endgroup + \def\cptcommanormalize#1{% + \unexpanded\expandafter{\romannumeral-`\q + \cpt@activecomma,#1,~\cpt@nil}% + }% + \def\cpt@activecomma#1~#2\cpt@nil{% + \iflacus{#2} + {\cpt@spacecomma#1 ,\cpt@nil} + {\cpt@activecomma#1,#2\cpt@nil}% + }% +} +\def\cpt@spacecomma#1 ,#2\cpt@nil{% + \iflacus{#2} + {\cpt@commaspace#1, \cpt@nil} + {\cpt@spacecomma#1,#2\cpt@nil}% +} +\def\cpt@commaspace#1, #2\cpt@nil{% + \iflacus{#2} + {\cpt@doublecomma#1,,\cpt@nil} + {\cpt@commaspace#1,#2\cpt@nil}% +} +\def\cpt@doublecomma#1,,#2\cpt@nil{% + \iflacus{#2} + {\iflacus{#1}{}{\expandafter\noexpand\@gobble#1}} + {\cpt@doublecomma#1,#2\cpt@nil}% +} +\newcommand*\cptexpandnext[1]{% + \iflacus{#1}{% + \cpt@undefined + }{% + \expandafter\iflacus\expandafter{\@gobble#1}{% + \expandafter#1\expandafter }{% - \ifnumcmpTF{#1}{2}{% - \if@boolTF{cpt@choicefd}\@secondoftwo\@firstoftwo - }{% - \cpt@err{Invalid number '#1'}\noexpand\@ehc - }% + \cpt@undefined }% }% - \expandafter\endgroup\cpt@tempa } -\protected\def\cpt@seeparameter#1#{% +\newcommand*\cpt@ppcmds[3]{% + \global\advance#3\@ne \begingroup - \toks@{#1}% - \@expandtwoargs\in@ - {\detokenize{macro parameter character}}% - {\meaning\@let@token}% + \toks@{}\toks1{}% + \def\cpt@tempa##1{\cptremovescape##1@\romannumeral#3\endcsname}% + \def\push@do##1,{% + \ifnot@nil{##1}{% + \toks@\expandafter\expandafter\expandafter + {\expandafter\the\expandafter\toks@\expandafter + \let\csname\cpt@tempa{##1}##1}% + \toks1\expandafter\expandafter\expandafter + {\expandafter\the\expandafter\toks1\expandafter + \let\expandafter##1\csname\cpt@tempa{##1}}% + \push@do + }% + }% + \edef\reserved@a{\cptcommanormalize{#2}}% + \expandafter\push@do\reserved@a,\@nil,% + \expandafter\xdef\csname\cptremovescape#1@stack\endcsname{% + \the\toks1\global\advance#3\m@one + \@ifundefined{\cptremovescape#1@stack}{{}}{% + {\unexpanded\expandafter\expandafter\expandafter + {\csname\cptremovescape#1@stack\endcsname}}% + }% + }% + \expandafter\endgroup\the\toks@ } -\newif\ifcpt@kernelifnextchar\cpt@kernelifnextchartrue -\kernel@ifdefinable\CurrIfnextchar{% - \ifcpt@kernelifnextchar - \let\CurrIfnextchar\kernel@ifnextchar - \else - \let\CurrIfnextchar\ifnextcharTF - \fi +\cptnewcount{cpt@csvdepth} +\cptnewbool{loopbreak} +\if@@definable\loopbreak{\let\loopbreak\loopbreaktrue} +\newcommand*\cpt@commanil{\cpt@commanil} +\newcommand*\docommalist[2]{% + \cpt@ppcmds\docommalist{\ifloopbreak,\cpt@commaact}\cpt@csvdepth + \def\cpt@commaact##1{#2}% + \def\cpt@commado##1,{% + \@nameuse{@\@nameuse{ifloopbreak}first\else second\fi oftwo}{% + \def\reserved@a####1\cpt@commanil,{}\reserved@a + }{% + \edef\reserved@a{\unexpanded\expandafter{\@gobble##1}}% + \ifxTF\reserved@a\cpt@commanil{}{% + \expandafter\cpt@commaact\expandafter{\reserved@a}\relax + \cpt@commado.% + }% + }% + }% + \loopbreakfalse + \edef\reserved@a{\cptcommanormalize{#1}}% + \expandafter\cpt@commado\expandafter.\reserved@a,\cpt@commanil,% + \def\reserved@a##1##{##1\gdef\docommalist@stack}% + \expandafter\reserved@a\docommalist@stack } +\docommalist{st,pl,pm,cl}{\cptnewbool{cpt@#1}} \protected\def\cpt@starorlong#1{% \cpt@ifstar{\let\l@ngrel@x\relax#1}{\let\l@ngrel@x\long#1}% } \protected\def\cpt@ifstar#1{\CurrIfnextchar*{\@firstoftwo{#1}}} -\newcommand*\shelldef{} -\protected\def\shelldef{\cpt@starorlong\cpt@shelldef} -\protected\def\cpt@shelldef#1{% - \kernel@ifdefinable{#1}{\l@ngrel@x\protected\def#1}% +\newcommand*\cpt@cmdsuffixcheck{\@iden} +\AtEndOfPackage{\DefSuffixChecker\cpt@cmdsuffixcheck{*}{!}} +\if@@definable\shelldef{% + \protected\def\shelldef{% + \cpt@cmdsuffixcheck{% + \cpt@ifstar{\cpt@sttrue\cpt@shelldef} + {\cpt@stfalse\cpt@shelldef}% + }% + }% +} +\protected\def\cpt@shelldef{% + \CurrIfnextchar + !{\@firstoftwo{\cpt@cltrue\cpt@shelld@f}} + {\cpt@clfalse\cpt@shelld@f}% +} +\protected\def\cpt@shelld@f#1{% + \if\expandafter\@car\string#1x\@nil\@backslashchar\else + \@latex@error{Token '\detokenize{#1}' not escaped}\@ehc + \fi + \if@@definable#1{% + \ifcpt@cl\global\fi\ifcpt@st\else\long\fi + \protected\def#1% + }% } \shelldef*\cpt@notdeferr#1{% \@latex@error{Command '\detokenize{#1}' isn't defined} @@ -472,8 +674,8 @@ } \shelldef*\cpt@isescapederr#1{% \@latex@error{Token '\detokenize{#1}' is escaped}{% - I didn't expect the first token of\MsgBrk - '\detokenize{#1}' to be escape character.}% + I didn't expect the first token of '\detokenize{#1}' + \MsgBrk to be escape character.}% } \shelldef*\cpt@notbracederr#1{% \@latex@error{Token '\detokenize{#1}' isn't braced} @@ -500,6 +702,15 @@ {Blank/empty token for command '\detokenize{#1}'} {I didn't expect a blank token here.}% } +\shelldef*\cpt@notexpandableerr#1{% + \@latex@error{'\detokenize{#1}' is not expandable + \MsgBrk or is undefined} + {I expected '\detokenize{#1}' to be expandable.}% +} +\shelldef*\cpt@toodeep#1#2{% + \@latex@error{Command '\detokenize{#1}' nested too deeply} + {Command '\detokenize{#1}' nested beyond level '#2'.}% +} \begingroup \catcode`\&=7 @@ -539,10 +750,10 @@ \shelldef*\shelllet#1{\cpt@ifeql{\cpt@shelllet{#1}}{\cpt@shelllet{#1}}} \shelldef*\cpt@shelllet#1#2{% - \cptifcondTF\ifx\noboundary#2\noboundary\fi{% + \ifcondTF\ifx\noboundary#2\noboundary\fi{% \cpt@isblankerr\shelllet }{% - \cptifcondTF\expandafter\ifx\expandafter + \ifcondTF\expandafter\ifx\expandafter \noboundary\@gobble#2\noboundary\fi{% \ifcsdefinable#1{% \ifprotectedTF#2{\let#1=#2}{% @@ -581,7 +792,7 @@ }% }% } -\kernel@ifdefinable\rsv@UseNormalCatcodes{% +\if@@definable\rsv@UseNormalCatcodes{% \let\rsv@UseNormalCatcodes\UseNormalCatcodes } \newcommand*\newcomment{% @@ -652,51 +863,69 @@ \long\def\@thirdofthree#1#2#3{#3} \let\@iden\@firstofone \newcommand\cptalloftwo[2]{#1#2} -\kernel@ifdefinable\cpt@nil{\let\cpt@nil\relax} -\kernel@ifdefinable\cpt@relax{\let\cpt@relax\relax} +\if@@definable\cpt@nil{\let\cpt@nil\relax} \def\cpt@nnil{\cpt@nil} -\newcommand*\cpt@rmstop{0 } +\if@@definable\cpt@relax{\let\cpt@relax\relax} +\newcommand*\cptrmstop{0 } +\if@@definable\cptrm{\let\cptrm\romannumeral} \long\def\cpt@car#1#2\car@nil{#1} \long\def\cpt@cdr#1#2\cdr@nil{#2} \long\def\remove@to@nnil#1\@nnil{} \long\def\catch@to@nnil#1\@nnil{#1} \long\def\remove@to@dot#1.{} \long\def\catch@to@dot#1.{#1} -\long\def\remove@to@space#1 {} -\@namedef{@gobblespace} {} -\kernel@ifdefinable\remainder@do{\let\remainder@do\@gobble} +\defpass\reserved@a#1{% + \long\def\remove@to@space##1#1{}% + \def\@gobblespace#1{}% +}{ } +\protected\def\ifnot@nil#1{% + \edef\reserved@g{\unexpanded{#1}}% + \ifxTF\reserved@g\@nnil\@gobble\@iden +} +\newcommand*\ifsentinelTF[1]{% + \edef\reserved@g{\unexpanded{#1}}% + \ifxTF\reserved@g\currsentinel +} +\if@@definable\csvbreak{\let\csvbreak\relax} +\newcommand*\cpt@csvbreak{\csvbreak} +\if@@definable\csvpause{\let\csvpause=\relax} +\newcommand*\cpt@csvpause{\csvpause} +\if@@definable\tsvbreak{\let\tsvbreak\relax} +\newcommand*\cpt@tsvbreak{\tsvbreak} +\newcommand*\ifcsvbreakTF[1]{% + \edef\reserved@g{\unexpanded{#1}}% + \ifxTF\reserved@g\cpt@csvbreak +} +\if@@definable\cptdoremainder{\let\cptdoremainder\@gobble} \shelldef*\gobble@to@sentinel#1#2{% - \begingroup - \defpass\cpt@tempa##1#1#2{\endgroup\remainder@do{##1}}% + \defpass\reserved@a##1#1#2{\cptdoremainder{##1}}% } \newcommand*\cptthreexp{\expandafter\expandafter\expandafter} -\newcommand*\cptsevenxp{\expandafter\expandafter\expandafter - \expandafter\expandafter\expandafter\expandafter} +\newcommand*\cptsevenxp{% + \expandafter\expandafter\expandafter + \expandafter\expandafter\expandafter\expandafter +} \shelldef\cptlocalxp#1{\begingroup\cptthreexp\endgroup#1} \newcommand*\cptzapspaces[1]{% - \def\cptzapspaces##1{% - \romannumeral\cpt@zapspaces.##1#1\zap@nil - }% + \def\cptzapspaces##1{\romannumeral\cpt@zapspaces.##1#1\zap@nil}% } \cptzapspaces{ } \long\def\cpt@zapspaces#1 #2\zap@nil{% - \usename{@\ifx\noboundary#2\noboundary - first\else second\fi oftwo}{% - \expandafter\cpt@rmstop\remove@to@dot#1% + \usename{@\ifx\noboundary#2\noboundary first\else second\fi oftwo}{% + \expandafter\cptrmstop\remove@to@dot#1% }{% - \expandafter\cpt@zapspaces\expandafter - .\remove@to@dot#1#2\zap@nil + \expandafter\cpt@zapspaces\expandafter.\remove@to@dot#1#2\zap@nil }% } \newcommand*\cptsupergobble[1]{% \romannumeral-`\q\expandafter\@gobble\romannumeral-`\q - \expandafter\cpt@sup@rgobble + \expandafter\cpt@supergobble \romannumeral\the\numexpr#1000{m\endcsname}% } -\newcommand*\cpt@sup@rgobble[1]{% - \csname cpt@sup@rg@bble#1\cpt@sup@rgobble +\newcommand*\cpt@supergobble[1]{% + \csname cpt@superg@bble#1\cpt@supergobble } -\newcommand\cpt@sup@rg@bblem[1]{\endcsname} +\newcommand\cpt@superg@bblem[1]{\endcsname} \newcommand*\cptdotimes[1]{% \ifblankTF{#1}{% \if@boolTF{cpt@useempty}{\cpt@dotimes{m}}\@gobble @@ -758,28 +987,22 @@ } \def\cpt@ifcmdsdefinable#1[#2]{% \begingroup + \edef\reserved@a{\cptcommanormalize{#1}}% \@tempswafalse \def\do##1,{% \ifnot@nil{##1}{% - \edef\cpt@tempa{% - \unexpanded\expandafter{\romannumeral-`\q\noexpand##1}% - }% - \ifxTF\cpt@tempa\@empty\do{% - \edef\cpt@tempb{\expandafter\expandafter\expandafter - \@car\expandafter\string\cpt@tempa\@nil}% - \ifxTF\cpt@tempb\@backslashchar{% - \@tempswafalse - \expandafter\kernel@ifdefinable\cpt@tempa\@tempswatrue - }{% - \s@expandarg\cpt@notescapederr\cpt@tempa - }% - \usename{@\if@tempswa first\else second\fi oftwo}% - \do{\gobble@to@sentinel\@nil,}% - }% + \if\expandafter\@car\string##1x\@nil\@backslashchar + \@tempswafalse + \if@@definable##1\@tempswatrue + \else + \cpt@notescapederr{##1}% + \fi + \usename{@\if@tempswa first\else second\fi oftwo}% + \do{\gobble@to@sentinel\@nil,}% }% }% - \do#1,\@nil,% - \cptifcondTF\if@tempswa\fi{\endgroup#2}\endgroup + \expandafter\do\reserved@a,\@nil,% + \ifcondTF\if@tempswa\fi{\endgroup#2}\endgroup } \ifcommandsdefinable{\cpttrimspace,\cpttrimspaces}\relax \def\cpttrimspaces#1{\cpt@trimspaces@a\relax{#1}} @@ -800,7 +1023,9 @@ {\romannumeral-`\q\expandafter\noexpand\@gobble#2}% }% } -\gdef\cpt@trimspaces@e#1#2#3{\expandafter#1\expandafter{\@gobble#3}{#2}} +\gdef\cpt@trimspaces@e#1#2#3{% + \expandafter#1\expandafter{\@gobble#3}{#2}% +} \gdef\cpttrimspace#1{\cpt@trimspace@a.#1& &} \gdef\cpt@trimspace@a#1 &{\cpt@trimspace@b#1&} \gdef\cpt@trimspace@b#1{% @@ -810,6 +1035,7 @@ \endgroup \shelldef*\trim@@spaces#1#2{\edef#2{\cpttrimspaces{#1}}} \shelldef*\trim@@space#1#2{\edef#2{\cpttrimspace{#1}}} + \shelldef*\despacecontent#1{% \edef#1{\simpleexpandarg\cpttrimspaces{#1}}% } @@ -827,79 +1053,101 @@ \if@boolFT{cpt@st}{}{\let#2=\cpt@rsvda}% }% } -\ifcommandsdefinable{\newboxtype,\newboxcontent}\relax -\let\newboxtype=\hbox -\def\newboxcontent{} % \newvariables{<type>}[<prf>]{<variables>}[<state/value>] -% Valid types are 'if, toks, dimen, count, box, tog'. +% Valid <types> are 'if, toks, box, dimen, count, tog, switch'. +% Boxes can be defined but not initialized by this command. \shelldef*\newvariables#1{\@testopt{\cpt@newvariables{#1}}{}} +\if@@definable\newvariable{\let\newvariable\newvariables} \shelldef*\cpt@newvariables#1[#2]#3{% \@testopt{\cpt@newv@riables{#1}{#2}{#3}}{}% } \shelldef*\cpt@newv@riables#1#2#3[#4]{% \def\cpt@rsvda##1{% - \ifx\noindent#4\noindent + \ifx\noboundary#4\noboundary \def\cpt@tempc{##1}\else\def\cpt@tempc{#4}\fi }% \edef\cpt@tempb{\ifstrcmpTF{#1}{if}{if}{}}% - \def\gobble@to@do##1\do{\do}% - \def\do##1,{% - \ifnot@nil{##1}{% - \edef\cpt@tempa{\cpttrimspace{##1}}% - \ifxTF\cpt@tempa\@empty\gobble@to@do\relax - \ifnamedefTF{\cpt@tempb#2\cpt@tempa}{% - \edef\reserved@a{\cpt@tempb#2\cpt@tempa}% - \ifstrcmpTF{#1}{tog}{}{\@notdefinable}% - }{% - \ifstrcmpTF{#1}{tog}{% - \@tempswatrue - \ifnamedefTF{cpt@tog@#2\cpt@tempa}{% - \cpt@err{Toggle '#2\cpt@tempa' already defined}\@ehc - }{% - \lowercase{% - \ifstrcmpTF{#4}{true}{% - \let\cpt@togstate\@firstoftwo + \docommalist{#3}{% + \iflacus{##1}{% + \def\cpt@relax####1\cpt@relax{\let\cpt@relax\relax}% + }{}% + \cpt@relax + \ifnamedefTF{\cpt@tempb#2##1}{% + \edef\reserved@a{\cpt@tempb#2##1}% + \ifstrcmpTF{#1}{tog}{}{\cpt@notdefinable}% + }{% + \ifstrcmpTF{#1}{tog}{% + \@tempswatrue + \ifnamedefTF{cpt@tog@#2##1}{% + \cpt@err{Toggle '#2##1' already defined}\@ehc + }{% + \lowercase{% + \ifstrcmpTF{#4}{true}{% + \let\cpt@togstate\@firstoftwo + }{% + \ifstrcmpTF{#4}{false}{% + \let\cpt@togstate\@secondoftwo }{% - \ifstrcmpTF{#4}{false}{% + \ifx\noboundary#4\noboundary \let\cpt@togstate\@secondoftwo - }{% - \ifx\noindent#4\noindent - \let\cpt@togstate\@secondoftwo - \else - \@latex@error{Invalid toggle value '#4'}\@ehc - \fi - }% + \else + \@latex@error{Invalid toggle value '#4'}\@ehc + \fi }% }% - \expandafter\let\csname cpt@tog@#2\cpt@tempa\endcsname - \cpt@togstate }% + \expandafter\let\csname + cpt@tog@#2##1\endcsname\cpt@togstate + }% + }{% + \@tempswatrue + \ifstrcmpTF{#1}{switch}{% + \lowercase{% + \ifstrcmpTF{#4}{true}{% + \def\reserved@a{00}% + }{% + \ifstrcmpTF{#4}{false}{% + \def\reserved@a{01}% + }{% + \ifx\noboundary#4\noboundary + \def\reserved@a{01}% + \else + \@latex@error{Invalid switch value '#4'}\@ehc + \fi + }% + }% + }% + \expandafter\let\csname#2##1\endcsname\reserved@a }{% \@tempswafalse \csname new#1\expandafter\endcsname\csname - \cpt@tempb#2\cpt@tempa\endcsname + \cpt@tempb#2##1\endcsname \ifstrcmpTF{#1}{if}{% \cpt@rsvda{false}% - \csname#2\cpt@tempa\cpt@tempc\endcsname + \csname#2##1\cpt@tempc\endcsname }{% \ifstrcmpTF{#1}{toks}{% \cpt@rsvda{}% - \csname#2\cpt@tempa\endcsname\expandafter{\cpt@tempc}% + \csname#2##1\endcsname\expandafter{\cpt@tempc}% }{% - \ifstrcmpTF{#1}{box}{% - \cpt@rsvda\z@pt - \setbox\csname#2\cpt@tempa\endcsname\newboxtype - to\cpt@tempc{\newboxcontent}% - }{% + % It is dangerous to initialize boxes here: + \ifstrcmpTF{#1}{box}{}{% \ifstrcmpTF{#1}{count}{% \cpt@rsvda\z@pt - \csname#2\cpt@tempa\endcsname\cpt@tempc\relax + \csname#2##1\endcsname\cpt@tempc\relax }{% \ifstrcmpTF{#1}{dimen}{% \cpt@rsvda\z@pt - \csname#2\cpt@tempa\endcsname\cpt@tempc\relax + \csname#2##1\endcsname\cpt@tempc\relax }{% - \cpt@newvarerr{#1}% + \ifstrcmpTF{#1}{skip}{% + \cpt@rsvda{\z@pt plus \z@pt minus \z@pt}% + \csname#2##1\endcsname\cpt@tempc\relax + }{% + \ifstrcmpTF{#1}{write}{}{% + \cpt@newvarerr{#1}% + }% + }% }% }% }% @@ -907,11 +1155,9 @@ }% }% }% - \do }% + \cpt@relax }% - \do#3,\@nil,% - \let\gobble@to@do\cpt@undefined } \def\cpt@newvarerr#1{% \if@tempswa\else @@ -922,7 +1168,9 @@ \ifstrcmpTF{#1}{token}{\x{toks}}{% \ifstrcmpTF{#1}{tok}{\x{toks}}{% \ifstrcmpTF{#1}{toggle}{\x{tog}}{% - No variable of type '#1'. + \ifstrcmpTF{#1}{sw}{\x{switch}}{% + No variable of type '#1'. + }% }% }% }% @@ -931,17 +1179,13 @@ \endgroup \fi } -\newvariables{if}[cpt@]{st,pl,pm,cl,verbose,usepox,optfd, - igopt,inpox,olddx,in,check,breakloop,choicefd,useempty,swa, - lastitem +\newvariables{if}[cpt@]{verbose,usepox,optfd, + igopt,inpox,olddx,in,check,choicefd,useempty,swa, }[false] -\newvariables{tog}{biboolkeys}[false] -\newvariables{count}[cpt@]{optdepth,csvdepth, - sisodepth,foxdepth,grouplevel,grouptype,cnta}[\z@pt] -\kernel@ifdefinable\cptbreakloop{\let\cptbreakloop\cpt@breaklooptrue} +\newvariables{tog}{biboolopts}[false] +\newvariables{count}[cpt@]{optdepth,grouplevel,grouptype,cnta}[\z@pt] \newcommand*\UseEmptyEntry{\global\cpt@useemptytrue} \newcommand*\DiscardEmptyEntry{\global\cpt@useemptyfalse} -\newcommand*\MsgBrk{\MessageBreak} \newcommand*\cptgetcatcode[1]{% \number \ifcat\noexpand#1\bgroup1\else @@ -957,23 +1201,6 @@ \ifcat\noexpand#1\noexpand~13\else -1\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi } -\newcommand\cptremovescape[1]{% - \ifx\noboundary#1\noboundary - \expandafter\@gobble\else\expandafter\@iden\fi - {\expandafter\@gobble\string#1}% -} -\newcommand\cptgobblescape[1]{% - \ifx\noboundary#1\noboundary - \expandafter\@gobble\else\expandafter\@iden\fi - {\ifnum\escapechar>\@cclv\else - \ifnum\escapechar<\z@pt\else - \expandafter\expandafter - \csname @gobble\ifnum\escapechar=\@xxxii @space\fi - \cptthreexp\endcsname - \fi - \fi - \string#1}% -} \newcommand\ifnullTF[1]{% \usename{@\ifnum\pdfstrcmp{}{\detokenize{#1}}% =\z@pt first\else second\fi oftwo}% @@ -990,14 +1217,13 @@ \newcommand\ifblankFT[1]{\ifblankTF{#1}\@secondoftwo\@firstoftwo} \newcommand\oifblankTF[1]{\expandafter\ifblankTF\expandafter{#1}} \newcommand\oifblankFT[1]{\expandafter\ifblankFT\expandafter{#1}} -% Expandable: \newcommand\xifblankTF[1]{% \usename{@\ifnum\pdfstrcmp{}{\@gobble#1.}=\z@pt first\else second\fi oftwo}% } \newcommand\xifblankFT[1]{\xifblankTF{#1}\@secondoftwo\@firstoftwo} \newcommand*\ifdefTF[1]{% - \usename{@\ifx\\#1\\second\else first\fi oftwo}% + \usename{@\ifx\noboundary#1\noboundary second\else first\fi oftwo}% {\usename{@\ifx#1\cpt@undefined second\else \ifx#1\relax second\else first\fi\fi oftwo}}% \@secondoftwo @@ -1022,20 +1248,20 @@ \newcommand*\xifcsndefFT[1]{\cptexpandarg\ifcsndefFT{#1}} \shelldef*\ifcsdefinable#1#2{% \ifblankTF{#1}{% - \cpt@err{Empty command for \string\ifcsdefinable}\@ehc + \cpt@isblankerr\ifcsdefinable }{% \edef\reserved@a{\cptgobblescape#1}% - \ifdefTF{#1}\@notdefinable{% - \ifcsndefTF{end\reserved@a}\@notdefinable{#2}% + \ifdefTF{#1}\cpt@notdefinable{% + \ifcsndefTF{end\reserved@a}\cpt@notdefinable{#2}% }% }% } -\ifcsdefinable\@ifcsdefinable{\let\@ifcsdefinable=\ifcsdefinable} +\ifcsdefinable\@ifcsdefinable{\let\@ifcsdefinable\ifcsdefinable} \shelldef\rc@ifcsdefinable#1#2{\let\ifcsdefinable\@ifcsdefinable#2} \shelldef*\ifcsndefinable#1{\cptlocalxp\aftercsname\ifcsdefinable{#1}} \shelldef*\ifdefinableTF#1{% \ifblankTF{#1}{% - \cpt@err{Empty command for \string\ifdefinableTF}\@ehc + \cpt@isblankerr\ifdefinableTF \@secondoftwo }{% \ifdefTF{#1}\@secondoftwo{% @@ -1043,57 +1269,6 @@ }% }% } -\shelldef\cpt@ifnextchar#1#2#3{% - \begingroup - \let\reserved@a=#1\toks@{\endgroup#2}\toks1{\endgroup#3}% - \global\futurelet\@let@token\cpt@ifnext -} -\shelldef*\cpt@ifnext{% - \ifx\@let@token\@sptoken - \toks2{\cpt@ifn@xt}% - \else - \ifx\@let@token\reserved@a - \toks2\expandafter{\the\toks@}% - \else - \toks2\expandafter{\the\toks1}% - \fi - \fi - \the\toks2 -} -\@namedef{cpt@ifn@xt} {\global\futurelet\@let@token\cpt@ifnext} -\shelldef\ifnextcharTF#1#2#3{% - \begingroup - \cpt@ifnextchar\relax - {\cpt@ifnextcharacter{#1}{#2}{#3}}% - {\cpt@ifnextcharacter{#1}{#2}{#3}}% -} -\long\def\cpt@ifnextcharacter#1#2#3{% - \ifcase - \ifcat\noexpand\@let@token\bgroup 1\fi - \ifcat\noexpand\@let@token\egroup 1\fi - 0\let\next\cpt@ifn@xtcharacter - \else - \def\next{\endgroup\cpt@ifnextchar}% - \fi - \next{#1}{#2}{#3}% -} -\long\def\cpt@ifn@xtcharacter#1#2#3#4{% - \escapechar92\relax - \edef\x{\cpt@ifn@xtch@racter{#1}\cpt@ifn@xtch@racter{#4}}% - \expandafter\endgroup\csname @\expandafter - \ifx\x first\else second\fi oftwo\endcsname - {#2}{#3}#4% -} -\long\def\cpt@ifn@xtch@racter#1{% - \expandafter\cpt@ifn@xtch@r@cter\string#1\relax\noindent{#1}% -} -\long\def\cpt@ifn@xtch@r@cter#1#2\noindent#3{% - \ifx\relax#2#1\else\noexpand#3\fi -} -\shelldef*\if@seeparameter#1#{% - \xifinsetTF{\detokenize{macro parameter character}}% - {\meaning\@let@token}% -} \shelldef\cpt@def@#1#2#3{% \ifcsdefinable#3{% \ifnullTF{#2}{}\protected @@ -1119,6 +1294,37 @@ }% \ifstrcmpTF{#1}{p}\protected\relax\l@ngrel@x\def#2% } +\robust@def*\provide@def{% + \cpt@cmdsuffixcheck{% + \cpt@testst{\cpt@testcl{\cpt@providedef\relax}}% + }% +} +\robust@def*\providerobust@def{% + \cpt@cmdsuffixcheck{% + \cpt@testst{\cpt@testcl{\cpt@providedef\protected}}% + }% +} +\new@def\cpt@providedef#1#2{% + \ifescapedTF{#2}{}{\cpt@notescapederr{#2}}% + \ifdefTF#2{% + \ifcpt@verbose + \cpt@info{Command '\string#2' already defined: + \MsgBrk not redefined}% + \fi + \def\reserved@a{\undefcs\reserved@b}% + }{% + \def\reserved@a{% + \ifcpt@cl\global\fi\let#2\reserved@b + \undefcs\reserved@b + }% + }% + \afterassignment\reserved@a + \ifcpt@st\else\long\fi + #1\def\reserved@b +} +\robust@def*\@ltx@warn{\@latex@warning@no@line} +\robust@def*\@ltx@info{\@latex@info@no@line} +\robust@def*\@ltx@err{\@latex@error} \robust@def\cpt@testopt#1#2{\CurrIfnextchar[{#1}{#1[{#2}]}} \robust@def*\cpt@ifbrack#1#2{\CurrIfnextchar[{#1}{#2}} \new@def*\cpt@xtestopt#1#2#3{% @@ -1128,6 +1334,7 @@ \usename{@\ifblankTF{#1#2}{first}{second}oftwo}% } \robust@def\cpt@testpnopt#1#2{\CurrIfnextchar({#1}{#1({#2})}} +\robust@def\cpt@testltopt#1#2{\CurrIfnextchar<{#1}{#1<{#2}>}} \robust@def\cpt@ifplus#1{\CurrIfnextchar+{\@firstoftwo{#1}}} \robust@def\cpt@ifclam#1{\CurrIfnextchar!{\@firstoftwo{#1}}} \robust@def\cpt@ifprime#1{\CurrIfnextchar'{\@firstoftwo{#1}}} @@ -1139,11 +1346,16 @@ \robust@def\cpt@teststpl#1{\cpt@testst{\cpt@testpl{#1}}} \robust@def\cpt@teststpm#1{\cpt@testst{\cpt@testpm{#1}}} \robust@def\cpt@teststopt#1#2{\cpt@testst{\cpt@testopt{#1}{#2}}} +% */' -> don't define, otherwise attempt to define: \robust@def*\cptmaybedef{\cpt@teststpm\cpt@maybedef} \robust@def*\cpt@maybedef#1{% \if@boolTF{cpt@st}\@firstoftwo{% \if@boolTF{cpt@pm}\@firstoftwo\@secondoftwo - }\@gobble{\new@def#1}% + }{% + \@gobble + }{% + \new@def#1% + }% } \robust@def*\newletcs#1{% \begingroup @@ -1198,10 +1410,9 @@ }% } \robust@def*\cptletcsset#1#2{% - \def\csv@do##1{% + \docommalist{#1}{% \oifblankTF{\@gobble##1}{}{\fulllet##1#2}% }% - \csv@@parse[,]{#1}% } \begingroup @@ -1216,6 +1427,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{% \ifstrcmpTF\dimen{#1}\@secondoftwo{% \expandafter\cpt@ifdimen@a\meaning#1:&% @@ -1265,14 +1477,15 @@ \chardef#3=\@ne }% \begingroup - \edef\cpt@stack{\expandafter\@gobble\string#1@stack}% + \edef\cpt@stack{\cptremovescape{#1}@stack}% \ifcsndefTF\cpt@stack{}{\csn@gdef\cpt@stack{}}% - \toks@{}\toks1{}\escapechar92 + \toks@{}\toks1{}\escapechar92\relax + % Using \csv@@loop or \csv@@parse here will bomb out, + % because \pushfunctions is called within those loops: \let\xp\expandcsonce \def\push@do##1{% \ifescapedTF{##1}{}{\cpt@notescapederr{##1}}% - \edef\cpt@tempa{\noexpandcsn - {\expandafter\@gobble\string##1@\romannumeral#3}}% + \edef\cpt@tempa{\noexpandcsn{\cptremovescape{##1}@\cptrm#3}}% \cptpassexpanded{% \toks@{\the\toks@\let\xp\cpt@tempa\noexpand##1}% \toks1{\the\toks1\let\noexpand##1\xp\cpt@tempa @@ -1280,13 +1493,13 @@ }% }% }% - \push@@parse{#2}% - \csn@xdef\cpt@stack{\the\toks1{\expandcsnonce\cpt@stack}}% + \cptpushparse{#2}% + \csn@xdef\cpt@stack{\the\toks1\cpt@nil{\expandcsnonce\cpt@stack}}% \expandafter\endgroup\the\toks@ } -\robust@def*\push@@parse#1{% - \cpt@stfalse\cpt@csvnormalize[,]{#1}% - \expandafter\cpt@pushparse\normalized@list,\@nil,% +\robust@def*\cptpushparse#1{% + \edef\reserved@a{\cptcommanormalize{#1}}% + \expandafter\cpt@pushparse\reserved@a,\@nil,% } \robust@def*\cpt@pushparse#1,{% \ifnot@nil{#1}{\push@do{#1}\relax\cpt@pushparse}% @@ -1297,12 +1510,13 @@ \cpt@err{Number '\string#2' is currently '0'}\@ehc \fi }{% - \cpt@err{Pop function with unknown number \string#2}\@ehc + \cpt@err{Can't pop functions with unknown + \MsgBrk number \string#2}\@ehc }% - \edef\cpt@stack{\expandafter\@gobble\string#1@stack}% + \edef\cpt@stack{\cptremovescape{#1}@stack}% \ifcsndefTF\cpt@stack{% \edef\reserved@a{\expandcsnonce\cpt@stack}% - \def\reserved@b##1##{##1\csn@gdef\cpt@stack}% + \def\reserved@b##1\cpt@nil{##1\csn@gdef\cpt@stack}% \expandafter\reserved@b\reserved@a }{% \cpt@err{Unknown stack for function \string#1}\@ehc @@ -1314,24 +1528,16 @@ \xdef#2{\the\numexpr#2-1}% }% } -\robust@def*\push@onefunction#1#2{% - \global\advance#2\@ne - \letcsntocs{\cptremovescape#1@\romannumeral#2}#1% -} -\robust@def*\pop@onefunction#1#2{% - \letcstocsn#1{\cptremovescape#1@\romannumeral#2}% - \undefcsn{\cptremovescape#1@\romannumeral#2}% - \global\advance#2\m@one -} \chardef\cpt@optionstacklimit4 \robust@def*\cpt@pushstate#1#2#3{% \ifnum#3>\cpt@optionstacklimit\relax \let\reserved@a\cpt@optionstacklimit \@latex@error{Current option/key state is being pushed \MsgBrk beyond level '\reserved@a'. I suspect infinite - \MsgBrk re-entrance. Please set package option - \MsgBrk 'option-stack-limit' or 'key-stack-limit' - \MsgBrk to the required value in \noexpand\documentclass + \MsgBrk re-entrance. If this isn't the case, please + \MsgBrk set package option 'option-stack-limit' or + 'key-stack-limit' to the required value in + \MsgBrk\noexpand\documentclass }\@ehc \fi \expandafter\pushfunctions\expandafter#1\expandafter{#2}#3% @@ -1339,7 +1545,7 @@ \robust@def*\cpt@popstate#1#2{\popfunctions#1#2} \robust@def*\cpt@stchoose#1#2#3#4{% \if@boolTF{#1}{% - \cptifmacroTF{#2}{% + \ifmacroTF{#2}{% \let#3=#2% }{% \cpt@err{Bad arguments to macro '\detokenize{#4}'. @@ -1350,8 +1556,46 @@ \edef#3{\unexpanded{#2}}% }% } +\robust@def*\cpt@delimitcs#1#2{% + \begingroup + \def\cpt@tempb##1{% + \edef\cpt@tempa####1{% + \def####1########1\detokenize{macro:}########2% + ->########3\cpt@nil{% + ########1\def\string\cpt@tempa########2% + \ifblankTF{##1}{}{\string##1}{########3}% + }% + \edef####1{####1\meaning#1\cpt@nil}% + }% + \cpt@tempa\cpt@tempa + }% + \cpt@tempb{}% + \cpteveryscan + \scantokens\expandafter{\cpt@tempa}\relax + \ifxTF#1\cpt@tempa{% + \cpt@tempb{#2}% + \scantokens\expandafter{\cpt@tempa}\relax + }{% + \cpt@err{Your command \noexpand#1 isn't scannable. + \MsgBrk I needed to delimit its last parameter text}\@ehc + }% + \gletcs#1\cpt@tempa + \endgroup +} +% \dofunclist[<parser>]{<list>} +% \dofunclist*[<parser>]{<listcmd>} +% This expects \do, which can be multi-parametered. \robust@def*\dofunclist{% - \let\csv@do\do + \pushnumber\dofunclistnr + \begingroup + \edef\sav@do{\cptmakecs{sav@do@\cptrm\dofunclistnr}}% + \expandafter\let\sav@do\do + \expandafter\cpt@delimitcs\sav@do\cpt@nil + \toks@{\def\csv@do##1}% + \toks1\expandafter{\expandafter\expandafter\sav@do + \cptrm\ifbracedTF{##1}{0{##1}}{0 ##1}\cpt@nil}% + \expandafter\expandafter\expandafter\endgroup\expandafter + \the\expandafter\toks@\expandafter{\the\toks1}% \csv@@parse } \robust@def*\csv@@loop{% @@ -1374,115 +1618,127 @@ \let\cpt@inkv\cpttrue \cpt@teststopt\cpt@csvkvparse,% } -\robust@def*\cpt@csvstate{% - \csv@parse@a,\csv@parse@b,\csv@doo,\ifcpt@useempty,% - \ifcpt@breakloop,\remainder@do -} \new@def*\cpt@csvnil{\cpt@csvnil} -\newcommand\cpt@csvkvparse[2][,]{% +\newcommand*\cpt@csvkvparse[2][,]{% \cpt@stchoose{cpt@st}{#2}\cpt@csvarg\cpt@csvkvparse - \expandafter\pushfunctions\expandafter\cpt@csvkvparse - \expandafter{\cpt@csvstate}\cpt@csvdepth - \letcstocsn\csv@doo{\if\cpt@inkv kv\else csv\fi @do}% - \ifdefTF\csv@doo{}{% + \pushfunctions\cpt@csvkvparse{\cpt@csvdo@a,\cpt@csvdo,% + \sav@csv@do,\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\csv@parse@a{% - \if@boolTF{cpt@breakloop}{% - \defpass\cpt@tempa####1\cpt@csvnil#1{\remainder@do{####1}}% + \def\cpt@csvdo@a{% + \if@boolTF{loopbreak}{% + \gobble@to@sentinel\cpt@csvnil#1% }{% - \csv@parse@b.% + \cpt@csvdo.% }% }% - \long\def\csv@parse@b##1#1{% + \def\cpt@csvdo##1#1{% \edef\cpt@csvarg{\expandcsonce{\@gobble##1}}% \ifxTF\cpt@csvarg\cpt@csvnil{}{% - \ifxTF\@empty\cpt@csvarg{% - \if@boolFT{cpt@useempty}{}{\csv@doo{}\relax}% + \ifxTF\cpt@csvarg\cpt@csvbreak{% + \loopbreaktrue }{% - \expandafter\csv@doo\expandafter{\cpt@csvarg}\relax + \ifcsemptyTF\cpt@csvarg{% + \if@boolFT{cpt@useempty}{}{\sav@csv@do{}\relax}% + }{% + \expandafter\sav@csv@do\expandafter{\cpt@csvarg}\relax + }% }% - \csv@parse@a + \cpt@csvdo@a }% }% - \ifpsiboolFT{cpt@nmlz}{}{% - \ifxTF\@empty\cpt@csvarg{}{% + \ifswitchFT{cpt@nmlz}{}{% + \ifcsemptyTF\cpt@csvarg{}{% \cpt@sttrue - \usename{cpt@\ifpsiboolTF{cpt@inkv}{kv}{csv}normalize}% + \usename{cpt@\ifswitchTF{cpt@inkv}{kv}{csv}normalize}% [#1]\cpt@csvarg }% }% - \cpt@breakloopfalse - \expandafter\csv@parse@a\cpt@csvarg#1\cpt@csvnil#1% + \loopbreakfalse + \expandafter\cpt@csvdo@a\cpt@csvarg#1\cpt@csvnil#1% \popfunctions\cpt@csvkvparse\cpt@csvdepth \ifnum\cpt@csvdepth=\z@pt - \global\let\remainder@do\@gobble - \undefcs\csv@do\undefcs\kv@do + \let\cptdoremainder\@gobble + \undefcsset{\csv@do,\kv@do,\dofunclistnr}% \fi } +%% Robust, multi-level, general-purpose tsv processor: \robust@def*\tsv@@loop{% - \let\tsv@type\cptfalse + \let\tsv@inparse\cptfalse \cpt@testst\cpt@tsvparse@a } \robust@def*\tsv@@parse{% - \let\tsv@type\cpttrue + \let\tsv@inparse\cpttrue \cpt@testst\cpt@tsvparse@a } \new@def*\cpt@tsvnil{\cpt@tsvnil} \robust@def\cpt@tsvparse@a#1{% \cpt@stchoose{cpt@st}{#1}\cpt@tsvarg\cpt@tsvparse@a - \pushfunctions\tsv@@parse{% - \tsv@doo,\ifcpt@useempty,\ifcpt@breakloop,% - \remainder@do,\tsv@type - }\cpt@csvdepth - \let\tsv@doo\tsv@do - \cpt@breakloopfalse + \pushfunctions\tsv@@parse{\sav@tsv@do,\ifcpt@useempty, + \ifloopbreak,\cptdoremainder,\tsv@inparse}\cpt@csvdepth + \ifdefTF\tsv@do{}{% + \cpt@err{'\string\tsv@do' is undefined}\@ehc + }% + \let\sav@tsv@do\tsv@do + \loopbreakfalse \expandafter\cpt@tsvparse@b\cpt@tsvarg\cpt@tsvnil \popfunctions\tsv@@parse\cpt@csvdepth \ifnum\cpt@csvdepth=\z@pt - \global\let\remainder@do\@gobble + \let\cptdoremainder\@gobble \undefcs\tsv@do \fi } \robust@def*\cpt@tsvparse@b{% - \if@boolTF{cpt@breakloop}{% - \defpass\cpt@tempa##1\cpt@tsvnil{\remainder@do{##1}}% + \if@boolTF{loopbreak}{% + \gobble@to@sentinel\cpt@tsvnil{}% }{% \begingroup \let\bgr@up\bgroup \let\bgroup\cpt@undefined + % Don't use \CurrIfnextchar here: \cpt@ifnextchar\bgr@up\cpt@tsvparse@c\cpt@tsvparse@c }% } \robust@def\cpt@tsvparse@c#1{% - \expandafter\endgroup\ifx\@let@token\bgr@up - \let\reserved@a\cpttrue\else\let\reserved@a\cptfalse\fi - \ifpsiboolTF{reserved@a}{% + \ifxTF\@let@token\bgr@up{% + \endgroup \edef\cpt@tsvarg{{\unexpanded{#1}}}% }{% - \edef\cpt@tsvarg{\usename{cpttrimspace\if\tsv@type s\fi}{#1}}% + \endgroup + \edef\cpt@tsvarg{\usename{cpttrimspace\if\tsv@inparse s\fi}{#1}}% }% \ifxTF\cpt@tsvarg\cpt@tsvnil{}{% - \ifxTF\@empty\cpt@tsvarg{% - \ifcpt@useempty\tsv@doo{}\relax\fi + \ifxTF\cpt@tsvarg\cpt@tsvbreak{% + \loopbreak }{% - \expandafter\tsv@doo\expandafter{\cpt@tsvarg}\relax + \ifxTF\@empty\cpt@tsvarg{% + \ifcpt@useempty\sav@tsv@do{}\relax\fi + }{% + \expandafter\sav@tsv@do\expandafter{\cpt@tsvarg}\relax + }% }% \cpt@tsvparse@b }% } -\new@def*\siso@nil{\siso@nil} +% \tsv@@parse does preserve outer braces but sometimes this +% isn't required, necessitating a call to a brace stripper. +% \siso@@loop strips outer braces in its arguments, but can +% be nested to any level: +\new@def*\cpt@sisonil{\cpt@sisonil} \robust@def*\siso@@loop#1{% - \push@onefunction\siso@doo\cpt@sisodepth + \pushfunctions\siso@@loop{\siso@doo}\cpt@sisodepth \ifdefTF\siso@do{}{\cpt@notdeferr\siso@do}% \let\siso@doo\siso@do - \cpt@sisoloop#1\siso@nil - \pop@onefunction\siso@doo\cpt@sisodepth + \cpt@sisoloop#1\cpt@sisonil + \popfunctions\siso@@loop\cpt@sisodepth \undefcs\siso@do } \robust@def*\cpt@sisoloop#1{% - \edef\siso@arg{\unexpanded{#1}}% - \ifxTF\siso@arg\siso@nil{}{% + \edef\reserved@g{\unexpanded{#1}}% + \ifxTF\reserved@g\cpt@sisonil{}{% \siso@doo{#1}\relax\cpt@sisoloop }% } @@ -1499,9 +1755,9 @@ {\noexpandcsn{\cptgobblescape#2@\romannumeral\curr@level}}% } \new@def*\cptliststack#1#2{% - \ifdefFT{#2}{}{% - \ifxTF#2\@empty{}{\expandcsonce{#2}#1}% - }% + \ifdefFT{#2} + {} + {\ifxTF#2\@empty{}{\expandcsonce{#2}#1}}% } \new@def\cptafterfi#1\fi{\fi#1} \new@def\cptafterelsefi#1\else#2\fi{\fi#1} @@ -1518,21 +1774,21 @@ \cpt@testst{\cpt@testcl\cpt@emptifycsset}% } \robust@def*\cpt@emptifycsset#1{% - \let\ifempcl\ifcpt@cl - \cpt@stchoose{cpt@st}{#1}\cpt@rsvda\cpt@emptifycsset - \def\csv@do##1{% - \ifsingletokenFT{##1}{% - \cpt@notonetokenerr{##1}% - }{% + \docommalist{#1}{% + \ifsingletoken@sp@TF{##1}{% \ifescapedTF{##1}{% - \ifempcl\global\fi\def##1{}% + \ifcpt@cl\global\fi\def##1{}% }{% \cpt@notescapederr{##1}% }% + }{% + \cpt@notonetokenerr{##1}% }% }% - \csv@@parse*[,]\cpt@rsvda - \undefcs\ifempcl +} +\robust@def*\emptifycsnset{\cpt@testopt\cpt@emptifycsnset{}} +\robust@def*\cpt@emptifycsnset[#1]#2{% + \docommalist{#2}{\csn@def{#1##1}{}}% } \AtEndOfPackage{% \AfterStartOfDocument{% @@ -1576,6 +1832,19 @@ \csv@@parse[,]{#1}% \endgroup } +\robust@def*\cptelementcount{\cpt@teststopt\cpt@elemcount,} +\robust@def*\cpt@elemcount[#1]#2{% + \begingroup + \def\cpt@elemnr{0}% + \edef\reserved@a{\ifcpt@st*\fi}% + \def\csv@do##1{% + \edef\cpt@elemnr{\the\numexpr\cpt@elemnr+1}% + }% + \expandafter\csv@@loop\reserved@a[#1]{#2}% + \postgroupdef\cpt@elemnr\endgroup +} +% Eg, \ifelemcountTF[;](>)[2]{a;b;c}{T}{F}; +% * -> #4 is a macro \robust@def*\ifelemcountTF{% \cpt@testst{\cpt@testopt\cpt@ifelemcount@a,}% } @@ -1596,12 +1865,31 @@ \aftercsname\endgroup{@\ifnum\@tempcnta#2#3 % first\else second\fi oftwo}% } +\robust@def*\cptfindduplicates{\cpt@teststopt\cpt@findduplicates,} +\robust@def*\cpt@findduplicates[#1]#2{% + \begingroup + \edef\reserved@a{\ifcpt@st*\fi}% + \edef\parser{\detokenize{#1}}% + \def\cpt@currstack{}\gdef\duplicates{}% + \def\csv@do##1{% + \xifinsetTF{\detokenize{#1##1#1}} + {\parser\cptoxdetok\cpt@currstack\parser}{% + \xdef\duplicates{\cptliststack#1\duplicates\unexpanded{##1}}% + }{% + \edef\cpt@currstack{\cptliststack#1\cpt@currstack\unexpanded{##1}}% + }% + }% + \expandafter\csv@@parse\reserved@a[#1]{#2}% + \ifcsemptyTF\duplicates + {\endgroup\@firstoftwo}{\endgroup\@secondoftwo}% +} \new@def*\ifcsnullTF#1{% - \cptifcondTF\expandafter\ifx\expandafter + % Don't use \ifxTF here: + \ifcondTF\expandafter\ifx\expandafter \noboundary\@gobble#1.\noboundary\fi{% \@secondoftwo }{% - \cptifcondTF\expandafter\ifx\expandafter + \ifcondTF\expandafter\ifx\expandafter \noboundary\@gobble#1\noboundary\fi{% \ifxTF#1\@empty }{% @@ -1609,7 +1897,6 @@ }% }% } -\new@def*\ifcsemptyTF#1{\ifxTF#1\@empty} \new@def*\ifcsnullFT#1{\ifcsnullTF{#1}\@secondoftwo\@firstoftwo} \new@def*\oifcsnullTF#1{\expandafter\ifcsnullTF\expandafter{#1}} \new@def*\oifcsnullFT#1{\expandafter\ifcsnullFT\expandafter{#1}} @@ -1641,8 +1928,13 @@ \ifcsnnullTF{#1}\@secondoftwo\@firstoftwo }\@secondoftwo } +% For private use only where #1 is surely a single token. +% For reasons of efficiency, we don't want to confirm +% here if #1 is actually a single token: \new@def*\simpleexpandarg#1#2{\expandafter#1\expandafter{#2}} \newletcs\s@expandarg=\simpleexpandarg +%%-- + \new@def*\expandcsonce#1{\unexpanded\expandafter{#1}} \new@def*\expandcsnonce#1{\aftercsname\expandcsonce{#1}} \new@def*\expandcstwice#1{\unexpanded\cptthreexp{#1}} @@ -1657,8 +1949,6 @@ } \newletcs\cptexpanded=\cptpassexpanded \robust@def\cptpassunexpanded#1{\begingroup\long\def\x{\endgroup#1}\x} -\robust@def\defpass#1#2#{\afterassignment#1\long\def#1#2} -\robust@def\edefpass#1#2#{\afterassignment#1\long\edef#1#2} \robust@def*\cptexpandarg#1#2{\cptpassexpanded{\unexpanded{#1}{#2}}} \robust@def*\cptexpandargonce#1#2{% \cptpassexpanded{\unexpanded{#1}{\expandcsonce{#2}}}% @@ -1687,7 +1977,7 @@ \def\cpt@fileauthor{#6\@space#7}% } \new@def*\cpt@filedesc{} -\defpass\cpt@tempa#1{% +\defpass\reserved@a#1{% \robust@def*\StyleFilePurpose##1{% \gdef\cpt@filedesc{##1#1(\cpt@fileauthor)}% }% @@ -1721,7 +2011,7 @@ }% \do#2,#3,#4,\@nil,% \if@tempswa - \@notdefinable + \cpt@notdefinable \else \cptpassexpanded{% \cpt@tempb{#1#2}####1{\cpt@tempa{\cpt@tempc Info}% @@ -1761,7 +2051,9 @@ }% } \new@def*\ifboolFT#1{\ifboolTF{#1}\@secondoftwo\@firstoftwo} -\new@def*\ifbooleanTF#1#{\ifboolTF{#1}} +\new@def*\ifbooleanTF#1{% + \ifboolTF{#1}{\endgroup\@firstoftwo}{\endgroup\@secondoftwo}% +} \new@def*\if@boolTF#1{% \usename{@\usename{if#1}first\else second\fi oftwo}% } @@ -1844,17 +2136,33 @@ \begingroup \toks@{}% \def\cpt@tempa{% - \ifsingleTF{##2}{% - \ifsingleTF{##3}{\toks@{##1##2##3}}{\toks@{##1##2{##3}}}% + \ifsingletokenTF{##2}{% + \ifsingletokenTF{##3}{% + \toks@{##1##2##3}% + }{% + \toks@{##1##2{##3}}% + }% }{% - \ifsingleTF{##3}{\toks@{##1{##2}##3}}{\toks@{##1{##2}{##3}}}% + \ifsingletokenTF{##3}{% + \toks@{##1{##2}##3}% + }{% + \toks@{##1{##2}{##3}}% + }% }% }% \defpass\cpt@tempb{% - \ifstrcmpTF{##2}{#2}{\cpt@tempa}{% + \ifstrcmpTF{##2}{#2}{% + \cpt@tempa + }{% \ifstrcmpTF{##2}{#3}{% - \ifstrcmpTF{##3}{#2}{\toks@{##1##3##2}}{\cpt@tempa}% - }{\cpt@tempa}% + \ifstrcmpTF{##3}{#2}{% + \toks@{##1##3##2}% + }{% + \cpt@tempa + }% + }{% + \cpt@tempa + }% }% }% \expandafter\endgroup\the\toks@ @@ -1890,13 +2198,25 @@ } \robust@def\oifstrcmp@sp@TF#1#2{% \ifsingletokenTF{#1}{% - \ifsingletokenTF{#2}{% - \oifstrcmpTF{#1}{#2}% + \ifexpandableTF{#1}{% + \ifsingletokenTF{#2}{% + \ifexpandableTF{#2}{% + \oifstrcmpTF{#1}{#2}% + }{% + \cpt@notexpandableerr{#2}% + \@secondoftwo + }% + }{% + \cpt@notonetokenerr{#2}% + \@secondoftwo + }% }{% - \cpt@notonetokenerr{#2}% + \cpt@notexpandableerr{#1}% + \@secondoftwo }% }{% \cpt@notonetokenerr{#1}% + \@secondoftwo }% } \robust@def\oifstrcmpFT#1#2{% @@ -2024,17 +2344,21 @@ }% }{0 #2}{0 #3}% } -\newletcs\ifsingleTF=\ifsingletokenTF \robust@def*\ifsingletokenFT#1{% \ifsingletokenTF{#1}\@secondoftwo\@firstoftwo } +% Don't test for \ifleadspaceTF: \new@def\ifsingletoken@sp@TF#1#2#3{% - \romannumeral-`\q\ifblankTF{#1}\@secondoftwo{% - \ifbracedTF{#1}\@secondoftwo{% + \romannumeral\ifblankTF{#1}{% + \@secondoftwo + }{% + \ifbracedTF{#1}{% + \@secondoftwo + }{% \expandafter\ifblankTF\expandafter{\@gobble#1}% \@firstoftwo\@secondoftwo }% - }{#2}{#3}% + }{0 #2}{0 #3}% } \robust@def*\ifsingledigitTF#1{% \begingroup @@ -2046,12 +2370,14 @@ } \new@def*\cpt@parserlist{,;:/|*><=-+"'} \robust@def*\cpt@checklistparser#1#2{% - \cptifmacroTF{#1}{% - \cpt@err{Parser '\detokenize{#1}' is a macro}\@ehc + \ifmacroTF{#1}{% + \ifcpt@verbose + \cpt@info{Parser '\detokenize{#1}' is a macro}\@ehc + \fi }{% \ifsingletokenTF{#1}{% \xifinsetTF{\detokenize{#1}}\cpt@parserlist{% - #2% Don't put \relax here! + #2% }{% \cpt@listparsererr{#1}% }% @@ -2060,24 +2386,23 @@ }% }% } - \robust@def*\cpt@checklistparser@b#1{% - \expandafter\ifx\expandafter\\\@gobble#1.\\% + \ifblankTF{#1}{% \cpt@listparsererr{#1}% - \else - \def\cpt@tempa##1##2\cpt@nil{% - \ifx##2\relax - \xifinsetTF{\detokenize{#1}}\cpt@parserlist{}{% - \cpt@listparsererr{#1}% - }% - \else + }{% + \expandafter\ifsecondis@nnil\string#1\cpt@nnil\cpt@nil{% + \xifinsetTF{\detokenize{#1}}\cpt@parserlist{}{% \cpt@listparsererr{#1}% - \fi + }% + }{% + \cpt@listparsererr{#1}% }% - \expandafter\cpt@tempa\string#1\relax\cpt@nil - \fi + }% } - +\robust@def*\cpt@listparsererr#1{% + \cpt@err{Invalid list parser '\detokenize{#1}'}\@ehc +} +\new@def*\ifsecondis@nnil#1#2\cpt@nil{\ifxTF#2\cpt@nnil} \robust@def*\postgroupdef#1\endgroup{% \cptpassexpanded{\endgroup\cpt@csexit{#1}}% } @@ -2106,7 +2431,7 @@ } \robust@def*\cptexpandmacro#1#2{% \ifsingletokenTF{#1}{% - \cptifmacroTF{#1}{% + \ifmacroTF{#1}{% \ifexpandableTF{#1}{% \simpleexpandarg\cptexpandmacro{#1}#2% }{% @@ -2121,7 +2446,7 @@ } \new@def*\cptexpandcs#1{% \ifsingletokenTF{#1}{% - \cptifmacroTF{#1}{% + \ifmacroTF{#1}{% \ifexpandableTF{#1}{% \simpleexpandarg\cptexpandcs{#1}% }{% @@ -2134,6 +2459,7 @@ \unexpanded{#1}% }% } + \begingroup \catcode`\&=7 \new@gdef*\cptfullexpand#1{% @@ -2143,7 +2469,7 @@ \expandafter\cpt@f@llexp@nd\romannumeral\cpt@f@llexpand#1&% } \new@gdef*\cpt@f@llexpand#1{% - \cptifmacroTF{#1}{% + \ifmacroTF{#1}{% \ifexpandableTF{#1}{% \expandafter\cpt@f@llexpand\expandafter{#1}% }{% @@ -2185,6 +2511,8 @@ }% }% } +% Test if <str1>, etc, is in <teststr> +% [<default act>]{<teststr>}{<{str1}{act1}{str2}{act2}...>} \new@def*\IfStrPresentCase#1{\cpt@xtestopt{#1}\cpt@ifstrincase{}} \new@def\cpt@ifstrincase[#1]#2#3{% \expandafter\cptswapfirstbraced\expandafter{#2}% @@ -2248,23 +2576,34 @@ \the\toks@ }% } -\robust@def*\cptfilterremoveelements{% +\robust@def*\cptfilterremovecsv{% + \begingroup + \let\cpt@inkv\cptfalse + \let\temp@parse\csv@@parse \cpt@testopt\cpt@filterremoveelements{,}% } -\robust@def*\cpt@filterremoveelements[#1]#2#3#4{% +\robust@def*\cptfilterremovekv{% \begingroup + \let\cpt@inkv\cpttrue + \let\temp@parse\kv@@parse + \cpt@testopt\cpt@filterremoveelements{,}% +} +\robust@def*\cpt@filterremoveelements[#1]#2#3#4{% + \edef\temp@do + {\cptmakecs{\ifxTF\temp@parse\csv@@parse{csv}{kv}@do}}% \cptdeclarefilter{#4}% \ifdefTF{#2}{}{\def#2{}}% \edef\cpt@delete{\unexpanded{#3}}% \ifcsnullTF\cpt@delete{}{% - \cpt@sttrue\cpt@csvnormalize[#1]\cpt@delete + \cpt@sttrue + \usename{cpt@\if\cpt@inkv k\else cs\fi vnormalize}[#1]\cpt@delete }% \edef\cpt@tempd##1{% {\detokenize{#1}\noexpand\cptoxdetok{##1}\detokenize{#1}}% {\detokenize{#1}\cptoxdetok\cpt@delete\detokenize{#1}}% }% \def\cpt@tempc{}% - \def\csv@do##1{% + \expandafter\def\temp@do##1{% \edef\cpt@tempa{\unexpanded{##1}}% \cpt@usefilter\cpt@tempa\cpt@tempb \expandafter\xifinsetTF\cpt@tempd\cpt@tempb{}{% @@ -2273,7 +2612,7 @@ }% \ifcsnullTF#2{}{% \ifcsnullTF\cpt@delete{}{% - \csv@@parse*[#1]#2% + \temp@parse*[#1]#2% }% }% \let#2\cpt@tempc @@ -2306,8 +2645,11 @@ {\cptmakecs{\ifxTF\temp@parse\csv@@parse{csv}{kv}@do}}% \cptdeclarefilter{#4}% \ifdefTF{#2}{}{\def#2{}}% - \ifblankTF{#3}{\def\cpt@update{}} - {\edef\cpt@update{\unexpanded{#3}}}% + \ifblankTF{#3}{% + \def\cpt@update{}% + }{% + \edef\cpt@update{\unexpanded{#3}}% + }% \def\cpt@add##1{% \edef#2{\cptliststack#1#2\everymergeitem{\expandcsonce{##1}}}% }% @@ -2339,6 +2681,114 @@ \postgroupdef#2\endgroup \let\everymergeitem\@firstofone } +\newvariables{switch}[cpt@]{fromrepl,fromrem}[false] +\robust@def*\cptremoveoneelement{\cpt@teststopt\cpt@removeoneelement,} +\robust@def\cpt@removeoneelement[#1]#2#3{% + \begingroup + \let\ifremovest\ifcpt@st + \edef\pser{\detokenize{#1}}% + \def\cpt@remove@a##1{% + \def\cpt@remove@b####1#1##1#1####2\remove@nil{% + \edef#2{\unexpanded{####1#1####2}}% + \cpt@trimparsers[#1]#2% + }% + \xifinsetTF{\detokenize{#1##1#1}}{\pser\cptoxdetok{#2}\pser}{% + \expandafter\cpt@remove@b\expandafter#1#2#1\remove@nil + \if@boolTF{removest}{% + \expandafter\cpt@remove@a\expandafter{\cpt@remove@c}% + }{}% + }{}% + }% + \ifswitchTF{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% + \edef\cpt@remove@c{\cpttrimspaces{#3}}% + }% + \let\cpt@remove@d#2% + \expandafter\cpt@remove@a\expandafter{\cpt@remove@c}% + \ifswitchTF{cpt@fromrem}{}{% + \ifx\cpt@remove@d#2\ifcpt@verbose + \cpt@warn{The list in \noexpand#2 not updated: + \MsgBrk perhaps something was wrong}% + \fi\fi + }% + \postgroupdef#2\endgroup +} +\robust@def*\cptremoveelements{\cpt@teststopt\cpt@removeelements,} +\robust@def\cpt@removeelements[#1]#2#3{% + \begingroup + \edef\cpt@resa{\ifcpt@st*\fi}% + \let\cpt@fromrem\cpttrue + \cpt@sttrue\cpt@csvnormalize[#1]#2% + \long\def\csv@do##1{% + \expandafter\cptremoveoneelement\cpt@resa[#1]#2{##1}% + }% + \csv@@parse[#1]{#3}% + \postgroupdef#2\endgroup +} +\robust@def*\cptreplaceoneelement{\cpt@teststopt\cpt@replaceoneelement,} +\robust@def\cpt@replaceoneelement[#1]#2#3#4{% + \begingroup + \let\ifreplst\ifcpt@st + \edef\pser{\detokenize{#1}}% + \def\cpt@replace@a##1{% + \def\cpt@replace@b####1#1##1#1####2\rep@nil{% + \edef#2{\unexpanded{####1#1#4#1####2}}% + \cpt@trimparsers[#1]#2% + }% + \xifinsetTF{\detokenize{#1##1#1}}{\pser\cptoxdetok#2\pser}{% + \expandafter\cpt@replace@b\expandafter#1#2#1\rep@nil + \if@boolTF{replst}{% + \expandafter\cpt@replace@a\expandafter{\cpt@replace@c}% + }{}% + }{}% + }% + \ifswitchTF{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% + \edef\cpt@replace@c{\cpttrimspaces{#3}}% + }% + \let\cpt@replace@d#2% + \expandafter\cpt@replace@a\expandafter{\cpt@replace@c}% + \ifswitchTF{cpt@fromrepl}{}{% + \ifx\cpt@replace@d#2\ifcpt@verbose + \cpt@warn{The list in \noexpand#2 not updated: + \MsgBrk something was wrong}% + \fi\fi + }% + \postgroupdef#2\endgroup +} +\robust@def*\cptreplaceelements{\cpt@teststopt\cpt@replaceelements,} +\robust@def\cpt@replaceelements[#1]#2#3#4{% + \begingroup + \edef\cpt@replace@a{\unexpanded{#3}}% + \edef\cpt@replace@b{\unexpanded{#4}}% + \edef\cpt@replace@c{\ifcpt@st*\fi}% + \def\do##1,{% + \ifnot@nil{##1}{\cpt@sttrue\cpt@csvnormalize[#1]##1\do}% + }% + \do#2,\cpt@replace@a,\cpt@replace@b,\@nil,% + \def\cpt@replace@d##1#1##2\noboundary##3#1##4\noboundary{% + \expandafter\cptreplaceoneelement\cpt@replace@c[#1]#2{##1}{##3}% + \ifblankTF{##2}{}{% + \ifblankTF{##4}{}{% + \cpt@replace@d##2\noboundary##4\noboundary + }% + }% + }% + \let\cpt@fromrepl\cpttrue + \cptexpandsecond\cpt@replace@d{% + \expandcsonce\cpt@replace@a#1\noboundary + \expandcsonce\cpt@replace@b#1\noboundary + }% + \postgroupdef#2\endgroup +} \robust@def*\preservebracedefQ#1#2{% \def\preserve@prefix{#1}% \def\preserve@delimiter{#2}% @@ -2375,30 +2825,21 @@ \robust@def*\csn@gdef{\aftercsname\gdef} \robust@def*\csn@edef{\aftercsname\edef} \robust@def*\csn@xdef{\aftercsname\xdef} -\new@def*\cpt@csnd@f#1{\l@ngrel@x\aftercsname\aftercsname{#1def}} -\robust@def*\csndef{\cpt@starorlong{\cpt@csnd@f{}}} -\robust@def*\csnpdef{\cpt@starorlong{\protected\cpt@csnd@f{}}} -\robust@def*\csngdef{\cpt@starorlong{\cpt@csnd@f{g}}} -\robust@def*\csnpgdef{\cpt@starorlong{\protected\cpt@csnd@f{g}}} -\robust@def*\csnedef{\cpt@starorlong{\cpt@csnd@f{e}}} -\robust@def*\csnpedef{\cpt@starorlong{\protected\cpt@csnd@f{e}}} -\robust@def*\csnxdef{\cpt@starorlong{\cpt@csnd@f{x}}} -\robust@def*\csnpxdef{\cpt@starorlong{\protected\cpt@csnd@f{x}}} -\robust@def*\newcsndef{\cpt@newcsn{}} -\robust@def*\newcsngdef{\cpt@newcsn{g}} -\robust@def*\newcsnedef{\cpt@newcsn{e}} -\robust@def*\newcsnxdef{\cpt@newcsn{x}} -\robust@def*\cpt@newcsn#1{\cpt@starorlong{\cpt@n@wcsn{#1def}}} -\robust@def*\cpt@n@wcsn#1#2{% - \begingroup - \edef\reserved@a{\noexpandcsn{#2}}% - \expandafter\ifdefTF\reserved@a{% - \@notdefinable\endgroup +\new@def*\cpt@csnd@f#1#2#3{% + \ifcsndefTF{#3}{% + \def\reserved@a{#3}\cpt@notdefinable }{% - \edef\reserved@b{\endgroup\l@ngrel@x\noexpandcsn{#1}}% - \expandafter\reserved@b\reserved@a + #1\l@ngrel@x\aftercsname\aftercsname{#2def}{#3}% }% } +\robust@def*\csndef{\cpt@starorlong{\cpt@csnd@f{}{}}} +\robust@def*\csnpdef{\cpt@starorlong{\cpt@csnd@f\protected{}}} +\robust@def*\csngdef{\cpt@starorlong{\cpt@csnd@f{}{g}}} +\robust@def*\csnpgdef{\cpt@starorlong{\cpt@csnd@f\protected{g}}} +\robust@def*\csnedef{\cpt@starorlong{\cpt@csnd@f{}{e}}} +\robust@def*\csnpedef{\cpt@starorlong{\cpt@csnd@f\protected{e}}} +\robust@def*\csnxdef{\cpt@starorlong{\cpt@csnd@f{}{x}}} +\robust@def*\csnpxdef{\cpt@starorlong{\cpt@csnd@f\protected{x}}} \robust@def*\letcsntocs#1{\cptthreexp\let\usename{#1}} \robust@def*\gletcsntocs#1{\global\cptthreexp\let\usename{#1}} \robust@def*\letcstocsn#1#2{% @@ -2419,12 +2860,6 @@ \global\expandafter\let\csname#1\expandafter \endcsname\csname#2\endcsname } -\new@def\aftercsname#1#2{% - \expandafter\cptswap\expandafter{\csname#2\endcsname}{#1}% -} -\new@def\xaftercsname#1#2{% - \cptsevenxp\cptswap\cptthreexp{\csname#2\endcsname}{#1}% -} \robust@def*\globalize#1{\gletcs#1#1} \robust@def*\globalizecsn#1{% \begingroup\expandafter\endgroup\expandafter @@ -2435,49 +2870,63 @@ \robust@def*\gundefcs{\global\undefcs} \robust@def*\undefcsn#1{\aftercsname\undefcs{#1}} \robust@def*\gundefcsn{\global\undefcsn} -\robust@def*\undefcsset{% - \cpt@testst{\cpt@testcl\cpt@undefcsset}% -} +\robust@def*\undefcsset{\cpt@testst{\cpt@testcl\cpt@undefcsset}} \robust@def*\cpt@undefcsset#1{% - \let\ifundefcl\ifcpt@cl - \cpt@stchoose{cpt@st}{#1}\cpt@rsvda\cpt@undefcsset - \def\csv@do##1{% - \ifescapedTF{##1}{% - \ifundefcl\global\fi\undefcs##1% - }{% - \cpt@notescapederr{##1}% + \cpt@stchoose{cpt@st}{#1}\cpt@rsvda\undefcsset + \cpt@sttrue\cpt@csvnormalize[,]\cpt@rsvda + \def\do##1,{% + \ifnot@nil{##1}{% + \ifsingletoken@sp@TF{##1}{% + \ifescapedTF{##1}{% + \ifcpt@cl\global\fi\undefcs##1% + }{% + \cpt@notescapederr{##1}% + }% + }{% + \cpt@notonetokenerr{##1}% + }% + \do }% }% - \csv@@parse*[,]\cpt@rsvda - \undefcs\ifundefcl + \expandafter\do\cpt@rsvda,\@nil,% } -\robust@def*\cpttrimparser{\cpt@testopt\cpt@trimparser{,}} -\robust@def\cpt@trimparser[#1]#2{% +\robust@def*\cpttrimleadparsers#1#2{% + \ifcat$\detokenize\expandafter{\@gobble#1.}$% + \cpt@err{Empty parser in \string\cpttrimleadparsers}\@ehc + \fi \begingroup - \edef\cpt@tempd{\detokenize{#1}}% - \let\trimpr@nil\relax - \def\cpt@trimb{% - \xifinsetFT{\cpt@tempd\trimpr@nil}{\cptoxdetok{#2}\trimpr@nil}{}{% - \cptexpandsecond - {\def\cpt@trimc####1}\cpt@tempd\trimpr@nil{% - \edef#2{\expandcsonce{\@gobble####1}}% - \cpt@trimb - }% - \expandafter\cpt@trimc\expandafter.#2\trimpr@nil - }% + \ifcat$\detokenize\expandafter\expandafter\expandafter + {\expandafter\@gobble#2.}$\cpt@defrelax\fi + \cpt@relax + \def\reserved@e##1#1{% + \edef\reserved@a{\unexpanded\expandafter{\@gobble##1}}% + \ifx\reserved@a\@empty + \def\next{\reserved@e.}% + \else + \def\@next####1#1\noboundary + {\edef#2{\unexpanded\expandafter{\@gobble####1}}}% + \edef\next{\unexpanded{\@next##1#1}}% + \fi + \next }% - \defpass\cpt@trima{% - \xifinsetTF{\trimpr@nil\cpt@tempd}{\trimpr@nil\cptoxdetok{#2}}{% - \expandafter\def\expandafter\cpt@trimc - \cpt@tempd####1\trimpr@nil{% - \edef#2{\unexpanded{####1}}% - \cpt@trima + \expandafter\reserved@e\expandafter.#2#1\noboundary + \postgroupdef#2\endgroup\cpt@relax +} +\robust@def*\cpttrimparsers{\cpt@testopt\cpt@trimparsers{,}} +\robust@def\cpt@trimparsers[#1]#2{% + \begingroup + \def\cpt@trima##1{% + \xifinsetTF{##1\batchmode}{\cptoxdetok{#2}\batchmode}{% + \def\reserved@a####1##1\batchmode{% + \edef#2{\expandcsonce{\@gobble####1}}% + \cpt@trima{##1}% }% - \expandafter\cpt@trimc#2\trimpr@nil + \expandafter\reserved@a\expandafter.#2\batchmode }{% - \cpt@trimb + \cpttrimleadparsers{##1}#2% }% }% + \s@expandarg\cpt@trima{\detokenize{#1}}% \postgroupdef#2\endgroup } \robust@def*\stripouterbraces{\cpt@testopt\cpt@stripouterbraces\@ne} @@ -2520,6 +2969,7 @@ }{0 #1}% }{0 #1}% } + \robust@def\cpt@starafter#1#2{% \begingroup \def\cpt@tempa{#1}% @@ -2548,7 +2998,9 @@ \repeat \postgroupdef#3\endgroup } -\edef\cptifmacroTF#1{% + +% Expandable: +\edef\ifmacroTF#1{% \noexpand\ifblankTF{#1}{% \noexpand\@secondoftwo }{% @@ -2560,7 +3012,9 @@ }% }% } -\new@def*\cptifmacroFT#1{\cptifmacroTF{#1}\@secondoftwo\@firstoftwo} +\new@def*\ifmacroFT#1{\ifmacroTF{#1}\@secondoftwo\@firstoftwo} +\new@def*\oifmacroTF#1{\simpleexpandarg\ifmacroTF{#1}} +\new@def*\ifcsnmacroTF{\aftercsname\ifmacroTF} \edef\cpt@ifmacro{% \def\noexpand\cpt@ifmacro##1\detokenize{macro}:##2\cpt@nil } @@ -2570,12 +3024,15 @@ \robust@def*\ifescapedTF#1{% \begingroup \escapechar92\relax - \edef\cpt@tempa{\expandafter\cpt@car\string#1x\car@nil}% - \cptthreexp\endgroup - \usename{@\ifx\cpt@tempa - \@backslashchar first\else second\fi oftwo}% + \edef\x{\expandafter\cpt@car\string#1x\car@nil}% + \aftercsname\endgroup + {@\ifx\x\@backslashchar first\else second\fi oftwo}% } \robust@def*\ifescapedFT#1{\ifescapedTF{#1}\@secondoftwo\@firstoftwo} +% \robustaliascount counts the number of 'robustified' commands. +% It may be used to set a threshold for the no. of allowable +% aliases. Only non-parametered macros may be aliased in the +% following way! \ifcsdefinable\maxrobustalias{\chardef\maxrobustalias20} \newcommand*\cptrobustify[1]{% \def\csv@do##1{% @@ -2621,7 +3078,7 @@ \ifdefTF#1{% \cpt@getmacroprefix{#1}% \macroprefix\cpt@def - #1{\swap{\expandcsonce{#1}}{\unexpanded{#2}}}% + #1{\swap{\expandcsonce{#1}}{\unexpanded{#2}}}% }{% \cpt@def#1{\unexpanded{#2}}% }% @@ -2642,6 +3099,7 @@ \catcode`\{\@ne \catcode`\}\tw@ } +% #1 must be a non-parametered macro: \robust@def*\cptscantokens#1{% \begingroup \edef#1{\long\def\string#1{\cptoxdetok{#1}}}% @@ -2650,27 +3108,52 @@ \postgroupdef#1\endgroup } \robust@def*\cpt@lowercasecs#1{% - \cptifmacroTF{#1}{% + \ifmacroTF{#1}{% \cptexpandarg\lowercase{\def\noexpand#1{#1}}% }{% \cpt@notcserr{#1}% }% } \robust@def*\providecount#1{% - \ifdefTF{#1}{% - \ifcounterTF{#1}{}{% - \cpt@warn{Command '\noexpand#1' is already - \MsgBrk defined but not a counter}% + \ifescapedTF{#1}{% + \ifdefTF{#1}{% + \ifcounterTF{#1}{}{% + \cpt@warn{Command '\noexpand#1' is already + \MsgBrk defined but not a counter}% + }% + }{% + \newcount#1% }% - }{\newcount#1}% + }{% + \cpt@notescapederr{#1}% + }% } \robust@def*\providedimen#1{% - \ifdefTF{#1}{% - \ifdimenTF{#1}{}{% - \cpt@warn{Command '\noexpand#1' is already - \MsgBrk defined but not a dimension}% + \ifescapedTF{#1}{% + \ifdefTF{#1}{% + \ifdimenTF{#1}{}{% + \cpt@warn{Command '\noexpand#1' is already + \MsgBrk defined but not a dimension}% + }% + }{% + \newdimen#1% }% - }{\newdimen#1}% + }{% + \cpt@notescapederr{#1}% + }% +} +\robust@def*\newtog#1{\cpt@testopt{\cpt@newtog{#1}}{false}} +\new@def*\cpt@newtog#1[#2]{% + \ifinsetTF{,}{#1}{% + \cpt@err{Command \noexpand\newtog doesn't accept list} + {Please submit only one toggle to \noexpand\newtog.}% + }{}% + \ifcsndefTF{cpt@tog@#1}{% + \cpt@err{Toggle '#1' already defined}% + {Please provide a new toggle.}% + }{}% + \cpt@gettogstate{#2}% + \letcsntocs{cpt@tog@#1}\cpt@togstate } \robust@def*\providetog#1{% \ifcsndefTF{cpt@tog@#1}{}{% @@ -2678,26 +3161,27 @@ }% } \robust@def*\cpt@gettogstate#1{% - \cptexpandarg\lowercase{\def\noexpand\reserved@a{#1}}% - \xifstrcmpTF\reserved@a{true}{% - \let\cpt@togstate\@firstoftwo - }{% - \xifstrcmpTF\reserved@a{false}{% - \let\cpt@togstate\@secondoftwo + \lowercase{% + \xifstrcmpTF{#1}{true}{% + \let\cpt@togstate\@firstoftwo }{% - \cpt@err{Invalid toggle switch value '#1'}% - {Valid toggle values are 'true' and 'false'.}% + \xifstrcmpTF{#1}{false}{% + \let\cpt@togstate\@secondoftwo + }{% + \cpt@err{Invalid toggle value '#1'}% + {Valid toggle values are 'true' and 'false'.}% + }% }% }% } -\robust@def*\cpt@undeftogerr#1{% - \cpt@err{Toggle switch '#1' undefined}\@ehc +\robust@def*\cpt@notogerr#1{% + \cpt@err{Toggle switch '#1' is undefined}\@ehc } \robust@def*\settogtrue#1{% \ifcsndefTF{cpt@tog@#1}{% \letcsntocs{cpt@tog@#1}\@firstoftwo }{% - \cpt@undeftogerr{#1}% + \cpt@notogerr{#1}% }% } \newletcs\togtrue=\settogtrue @@ -2705,7 +3189,7 @@ \ifcsndefTF{cpt@tog@#1}{% \letcsntocs{cpt@tog@#1}\@secondoftwo }{% - \cpt@undeftogerr{#1}% + \cpt@notogerr{#1}% }% } \newletcs\togfalse=\settogfalse @@ -2714,22 +3198,24 @@ \cpt@gettogstate{#2}% \letcsntocs{cpt@tog@#1}\cpt@togstate }{% - \cpt@undeftogerr{#1}% + \cpt@notogerr{#1}% }% } \robust@def*\undeftog#1{% \ifcsndefTF{cpt@tog@#1}{% \letcsntocs{cpt@tog@#1}\cpt@undefined }{% - \cpt@info{Toggle switch '#1' not defined}% + \cpt@info{Null instruction to undefine unknown toggle '#1'}% }% } \new@def*\iftogTF#1{% - \ifcsndefTF{cpt@tog@#1}{\usename{cpt@tog@#1}}% - {\cpt@undeftogerr{#1}\@gobbletwo}% + \ifcsndefTF{cpt@tog@#1}{% + \usename{cpt@tog@#1}% + }{% + \cpt@notogerr{#1}\@gobbletwo + }% } \new@def*\iftogFT#1{\iftogTF{#1}\@secondoftwo\@firstoftwo} - \new@def*\cpttrue{00} \new@def*\cptfalse{01} \def\reserved@a#1{% @@ -2744,10 +3230,76 @@ }% } \reserved@a{ } -\new@def*\ifpsiboolTF#1{\cptifcondTF\if\usename{#1}\fi} -\new@def*\ifpsiboolFT#1{\cptifcondFT\if\usename{#1}\fi} +\robust@def*\newswitch#1{\cpt@testopt{\cpt@newswitch#1}{false}} +\robust@def*\cpt@newswitch#1[#2]{% + \ifinsetTF{,}{#1}{% + \cpt@err{Command \noexpand\newswitch doesn't accept list} + {Please submit only one switch to \string\newswitch.}% + }{}% + \xifinsetTF{,#1,}{,if,x,switch,tog,bool,}{% + \cpt@err{Invalid switch name '#1'}\@ehc + }{}% + \ifcsndefinable{#1}\relax + \cpt@getswitchstate{#2}% + \letcsntocsn{#1}{cpt\cpt@switchstate}% +} +\robust@def*\cpt@getswitchstate#1{% + \lowercase{% + \xifinsetTF{,#1,}{,true,false,}{% + \edef\cpt@switchstate{#1}% + }{% + \cpt@err{Invalid switch value '#1'} + {Valid switch values are 'true' and 'false'.}% + }% + }% +} +\robust@def*\cpt@noswitcherr#1{% + \cpt@err{Switch '\string#1' is undefined}\@ehc +} +\robust@def*\setswitch#1#2{% + \ifcsndefTF{#1}{% + \cpt@getswitchstate{#2}% + \letcsntocsn{#1}{cpt\cpt@switchstate}% + }{% + \cpt@noswitcherr{#1}% + }% +} +\robust@def*\setswitchtrue#1{% + \ifcsndefTF{#1}{% + \letcsntocs{#1}\cpttrue + }{% + \cpt@noswitcherr{#1}% + }% +} +\newletcs\switchtrue\setswitchtrue +\robust@def*\setswitchfalse#1{% + \ifcsndefTF{#1}{% + \letcsntocs{#1}\cptfalse + }{% + \cpt@noswitcherr{#1}% + }% +} +\newletcs\switchfalse\setswitchfalse +\new@def*\ifswitchTF#1{% + \ifcsndefFT{#1}{% + \cpt@err{Switch '#1' is not defined}\@ehc + \@gobbletwo + }{% + \ifcondTF\if\usename{#1}\fi + }% +} +\new@def*\if@switchTF#1{\ifcondTF\if\usename{#1}\fi} +\new@def*\ifswitchFT#1{\ifswitchTF{#1}\@secondoftwo\@firstoftwo} \new@def*\thebool@normal#1{\ifboolTF{#1}{true}{false}} \new@def*\thebool@reverse#1{\ifboolTF{#1}{false}{true}} +\new@def*\cpt@beforeprocessoptions{} +\new@def*\cpt@afterprocessoptions{} +\robust@def*\BeforeProcessOptions{% + \grightaddtocs\cpt@beforeprocessoptions +} +\robust@def*\AfterProcessOptions{% + \grightaddtocs\cpt@afterprocessoptions +} \robust@def*\BeforeStartOfDocument{% \grightaddtocs\cpt@beforestartdoc } @@ -2778,8 +3330,12 @@ \gundefcsn{\@currname.\@currext-cpt@hook}% }% } -\robust@def*\ifpackagewithTF{\cpt@ifoptions\@pkgextension} -\robust@def*\ifclasswithTF{\cpt@ifoptions\@clsextension} +\robust@def*\ifpackagewithoptionsTF{% + \begingroup\cpt@ifoptions\@pkgextension +} +\robust@def*\ifclasswithoptionsTF{% + \begingroup\cpt@ifoptions\@clsextension +} \robust@def*\cpt@ifoptions#1#2{% \cptexpandarg\cpt@ifopti@ns{\cpt@optionlist{#2.#1}}% } @@ -2789,21 +3345,25 @@ \cpt@choicefdtrue \def\kv@do##1{% \oifinset@sp@TF,{##1}\temp@optlist - {}{\cpt@choicefdfalse\cptbreakloop}% + {} + {\cpt@choicefdfalse\loopbreak}% }% \kv@@parse{#2}% - \undefcs\temp@optlist - \if@boolTF{cpt@choicefd}\@firstoftwo\@secondoftwo + \if@boolTF{cpt@choicefd} + {\endgroup\@firstoftwo}{\endgroup\@secondoftwo}% } -\robust@def*\ifpackageafterTF{\cpt@ifpkgafter\@pkgextension} -\robust@def*\ifclassafterTF{\cpt@ifpkgafter\@clsextension} -\robust@def*\cpt@ifpkgafter#1#2#3{% +\robust@def*\ifpackageloadedlaterTF{\cpt@ifpkgloadedlater\@pkgextension} +\robust@def*\ifclassloadedlaterTF{\cpt@ifpkgloadedlater\@clsextension} +\robust@def*\cpt@ifpkgloadedlater#1#2#3#4{% \usename{@if#1loaded}{#2}{}{% \AfterStartOfDocument{% \usename{@if#1loaded}{#2}{% - \cpt@warn{\@cls@pkg '#2' was loaded afterwards}% + \cpt@info{\@cls@pkg\@space '#2' was loaded afterwards}% #3\relax - }{}% + }{% + \cpt@info{\@cls@pkg\@space '#2' wasn't loaded afterwards}% + #4\relax + }% }% }% } @@ -2849,7 +3409,7 @@ }{% \def\kv@do########1{% \xifinsetTF{,\detokenize{########1},}{,\cpt@rsvdb,}{}{% - \@tempswatrue\cptbreakloop + \@tempswatrue\loopbreak }% }% \kv@@parse*[,]\cpt@rsvda @@ -2893,7 +3453,7 @@ \begingroup \@makeother{\#}% \endlinechar\m@one - \cpt@pop@hash + \cpt@push@hash } \robust@def\cpt@push@hash#1#2{% \xifinsetTF\cpt@hashchar{\detokenize{#1}}{% @@ -2919,7 +3479,7 @@ \begingroup \@makeother{\#}% \endlinechar\m@one - \cpt@push@hash + \cpt@pop@hash } \robust@def\cpt@pop@hash#1#2{% \xifinsetTF{\detokenize{##}}{\detokenize{#1}}{% @@ -2943,21 +3503,21 @@ \robust@def*\csv@@normalize{\cpt@teststopt\cpt@csvnormalize,} \robust@def\cpt@csvnormalize[#1]#2{% \let\cpt@inkv\cptfalse - \cpt@normalize{#1}{#2}% + \cpt@normalizelist{#1}{#2}% } \robust@def*\kv@@normalize{\cpt@teststopt\cpt@kvnormalize,} \robust@def\cpt@kvnormalize[#1]#2{% \let\cpt@inkv\cpttrue - \cpt@normalize{#1}{#2}% + \cpt@normalizelist{#1}{#2}% } \ifcsdefinable\normalized@list\relax -\robust@def\cpt@normalize#1#2{% +\robust@def\cpt@normalizelist#1#2{% \begingroup \let\ifnmlzst\ifcpt@st - \cpt@stchoose{cpt@st}{#2}\reserved@e\cpt@normalize + \cpt@stchoose{cpt@st}{#2}\reserved@e\cpt@normalizelist \ifx\reserved@e\@empty \def\normalized@list{}% - \def\cpt@relax##1\cpt@relax{\endgroup}% + \def\cpt@relax##1\cpt@relax{\endgroup\let\cpt@relax\relax}% \fi \cpt@relax \cpt@checklistparser@b{#1}% @@ -2967,20 +3527,15 @@ \expandafter\nmlz@spaceletter\string#1% \expandafter\nmlz@letterspace\string#1% \expandafter\nmlz@doubleletter\string#1% - \ifpsiboolFT{cpt@inkv}{}{% + \ifswitchFT{cpt@inkv}{}{% \nmlz@activeequal \nmlz@spaceletter=% \nmlz@letterspace=% \nmlz@doubleletter=% \cpt@commaequalerr }% - \def\reserved@a##1{% - \@nameuse{@\if\string#1\noexpand##1first\else - second\fi oftwo}\reserved@a{0 ##1}% - }% - \edef\normalized@list{% - \expandcsonce{\romannumeral\expandafter\reserved@a\the\toks@}% - }% + \edef\normalized@list{\the\toks@}% + \cpttrimleadparsers#1\normalized@list \cptexpandsecond\endgroup{% \if@boolTF{nmlzst}{% \edef\noexpand#2{\ox@unexpanded\normalized@list}% @@ -3077,7 +3632,7 @@ }% }% \fi - \ifx\cpt@documentclass\cpt@undefined\else\cpt@breaklooptrue\fi + \ifx\cpt@documentclass\cpt@undefined\else\loopbreak\fi }% \csv@@parse*\@filelist \ifdefTF\cpt@documentclass{}{% @@ -3104,12 +3659,13 @@ \def\@fileswith@ptions##1[##2]##3{% \cpt@stfalse\cpt@csvnormalize[,]{##3}% \cpt@choicefdfalse - \def\csv@do####1{% - \xifinsetTF{,####1,}{,\normalized@list,}{% - \cpt@choicefdtrue - }{}% + \def\do####1,{% + \ifnot@nil{####1}{% + \xifinsetFT{,####1,}{,\normalized@list,}{}\cpt@choicefdtrue + \do + }% }% - \csv@@loop[,]{xkeyval,kvoptions,ltxkeys}% + \do xkeyval,kvoptions,ltxkeys,\@nil,% \ifcpt@choicefd \let\@classoptionslist\cpt@classoptionslist \fi @@ -3132,7 +3688,7 @@ \robust@redef\@pass@ptions#1#2#3{% \begingroup \ifsingletokenTF{#2}{% - \cptifmacroTF{#2}{% + \ifmacroTF{#2}{% \let\@expand\expandcsonce }{% \let\@expand\unexpanded @@ -3159,7 +3715,7 @@ } \robust@redef*\@use@ption{% \oifinset@sp@FT,\CurrentOption\@unusedoptionlist{}{% - \cptexpandargonce{\cpt@filterremoveelements[,]% + \cptexpandargonce{\cptfilterremovekv[,]% \@unusedoptionlist}\CurrentOption\nofilter }% \csname ds@\CurrentOption\endcsname @@ -3194,15 +3750,13 @@ \let\@@fileswith@pti@ns\@fileswith@pti@ns \robust@def*\RecoverAtRequirePackage#1{% \ifblankFT{#1}{}{% - \cpt@err{Blank argument to command - \string\RecoverAtRequirePackage}\@ehc + \cpt@isblankerr\RecoverAtRequirePackage }% \begingroup \def\csv@do##1{% \ifescapedTF{##1}{% \ifdefTF{##1}{}{% - \cpt@notdeferr{##1}% - \@gobble + \cpt@notdeferr{##1}\@gobble }% }{% \cpt@notescapederr{##1}% @@ -3225,9 +3779,9 @@ } \robust@def*\cpt@badoptionerr#1{% \expandafter\ifescapedTF\expandafter{#1}{% - \cpt@escapederr{#1}% + \cpt@isescapederr{#1}% }{% - \expandafter\cptifmacroFT\expandafter{#1}{}{% + \expandafter\ifmacroFT\expandafter{#1}{}{% \cpt@err{Macro as option name '\expandcsonce{#1}'}\@ehc }% }% @@ -3367,6 +3921,16 @@ \let\cmdoption\cptfalse \cpt@testfam\cpt@declarecmdoptions } +\robust@def*\cpt@checkbool#1#2#3{% + \lowercase{% + \edef\cpt@resa{\s@expandarg\cpttrimspaces{\cptrm-`\q#1}}% + }% + \xifinsetTF{,\cpt@resa,}{,true,false,}{% + #3\relax + }{% + \@latex@error{Invalid value '#1' for '#2'}\@ehc + }% +} \robust@def*\cpt@declarecmdoption<#1>#2{% \trim@@space{#1}\cpt@currfam \trim@@space{#2}\cpt@curropt @@ -3385,10 +3949,7 @@ \else \csn@newif{#4#2}% \def\cpt@rsvda{% - \ifinsetTF{,####1,}{,true,false,}{}{% - \@latex@error{Invalid value for option '#2'}\@ehc - }% - \usename{#4#2####1}% + \cpt@checkbool{####1}{option #2}{\usename{#4#2\cpt@resa}}% }% \fi \long\def\cpt@rsvdb##1{% @@ -3405,11 +3966,18 @@ } \robust@def\cpt@d@cl@recmdoptions#1#2#3(#4)#5{% \trim@@spaces{#1}\cpt@currfam + \begingroup + \toks@{{#3}(#4){#5}}\toks1{}% \def\csv@do##1{% \cpt@badoptionerr{##1}% - \simpleexpandarg\cpt@d@cl@recmdoption\cpt@currfam{##1}{#3}(#4){#5}% + \cptexpanded{% + \toks1{\the\toks1\relax + \cpt@d@cl@recmdoption{\cpt@currfam}{##1}\the\toks@ + }% + }% }% \csv@@parse[,]{#2}% + \expandafter\endgroup\the\toks1 } \robust@def*\XDeclareBiBooleanOptions{% \let\@fileswith@pti@ns\@badrequireerror @@ -3456,15 +4024,69 @@ \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: \iftogTF{#5@#1}{}{% \settogtrue{#5@#2}% - \settogtrue{biboolkeys}% + \settogtrue{biboolopts}% \cptexpandarg{\XExecuteOptions<#5>}{#2=\thebool@reverse{#4#1}}% - \settogfalse{biboolkeys}% + \settogfalse{biboolopts}% \settogfalse{#5@#2}% }% }% } +\robust@def*\XDeclareSwitchOption{% + \let\@fileswith@pti@ns\@badrequireerror + \cpt@testfam\cpt@declareswoption +} +\robust@def*\XDeclareSwitchOptions{% + \let\@fileswith@pti@ns\@badrequireerror + \cpt@testfam\cpt@declareswoptions +} +\robust@def*\cpt@declareswoption<#1>#2{% + \trim@@space{#1}\cpt@currfam + \trim@@space{#2}\cpt@curropt + \cpt@badoptionerr\cpt@curropt + \cptexpandarg\cpt@testopt + {\cpt@d@clareswoption{\cpt@currfam}{\cpt@curropt}}{}% +} +\robust@def\cpt@d@clareswoption#1#2[#3]{% + \cptexpandarg{\cpt@testpnopt{\cpt@d@cl@reswoption + {#1}{#2}{#3}}}{\@currname @}% +} +\robust@def\cpt@d@cl@reswoption#1#2#3(#4)#5{% + \cpt@d@cl@reoption{#1}{#2}{#3}% + \def\cpt@rsvda{% + \cpt@checkbool{####1}{#2}{% + \letcsntocsn{#4#2}{cpt\cpt@resa}% + }% + }% + \long\def\cpt@rsvdb##1{% + \long\csn@gdef{#1@ds@#2}####1{##1\relax}% + }% + \expandafter\cpt@rsvdb\expandafter{\cpt@rsvda#5}% +} +\robust@def*\cpt@declareswoptions<#1>#2{% + \cpt@testopt{\cpt@d@clareswoptions{#1}{#2}}{}% +} +\robust@def\cpt@d@clareswoptions#1#2[#3]{% + \cptexpandarg{\cpt@testpnopt{\cpt@d@cl@reswoptions + {#1}{#2}{#3}}}{\@currname @}% +} +\robust@def\cpt@d@cl@reswoptions#1#2#3(#4)#5{% + \trim@@spaces{#1}\cpt@currfam + \begingroup + \toks@{{#3}(#4){#5}}\toks1{}% + \def\csv@do##1{% + \cpt@badoptionerr{##1}% + \cptexpanded{% + \toks1{\the\toks1\relax + \cpt@d@cl@reswoption{\cpt@currfam}{##1}\the\toks@ + }% + }% + }% + \csv@@parse[,]{#2}% + \expandafter\endgroup\the\toks1 +} \robust@def\cpt@d@cl@reoption#1#2#3{% \ifcsndefTF{#1@declaredoptions}{% \xifinsetTF{,\cptoxdetok{#2},}{,\cpt@getdeclaredoptions{#1},}{% @@ -3586,7 +4208,7 @@ \robust@def*\cpt@ifoptdis@bled#1#2{% \ifcsndefFT{#1@disabledoptions}{}{% \xifinsetFT{,#2,}{,\expandcsnonce{#1@disabledoptions},}{}{% - \cptbreakloop\cpt@choicefdtrue + \loopbreak\cpt@choicefdtrue }% }% } @@ -3607,7 +4229,7 @@ } \robust@def*\cpt@ifoptd@f#1#2{% \ifcsndefFT{#1@ds@#2}{}{% - \cpt@choicefdtrue\cptbreakloop + \cpt@choicefdtrue\loopbreak }% } \new@def*\cpt@getdeclaredoptions#1{% @@ -3655,6 +4277,8 @@ } \newletcs\cpt@processedoptions\@empty \robust@def*\XProcessOptions{% + \cpt@beforeprocessoptions + \let\cpt@beforeprocessoptions\relax \cpt@inpoxtrue \let\@fileswith@pti@ns\@badrequireerror \edef\cpt@testname{\@currname.\@currext}% @@ -3678,13 +4302,14 @@ }% } \robust@def*\cpt@yprocessoptions#1[#2]{% - \def\cpt@currfams{#1}% - \def\cpt@currna{#2}% - \cpt@sttrue\cpt@csvnormalize[,]\cpt@currna - \def\csv@do##1{% + \iflacus{#2}{% + \def\cpt@currna{}% + }{% + \edef\cpt@currna{\cptcommanormalize{#2}}% + }% + \docommalist{#1}{% \cpt@ypr@cessoptions{##1}% }% - \csv@@parse*[,]\cpt@currfams \cpt@pr@cessoptions \cpt@pr@cessopti@ns } @@ -3711,20 +4336,22 @@ }% }% \ifxTF\cpt@classoptions\@empty{}{% - \ifcsnnullTF{#1@declaredoptions}{}{% - \aftercsname{\kv@@parse*}{#1@declaredoptions}% + \ifcsndefFT{#1@declaredoptions}{}{% + \ifcsnnullTF{#1@declaredoptions}{}{% + \aftercsname{\kv@@parse*}{#1@declaredoptions}% + }% }% }% } \robust@def*\cpt@xprocessoptions#1[#2]{% - \def\cpt@currfams{#1}% - \cpt@sttrue\cpt@csvnormalize[,]\cpt@currfams - \def\cpt@currna{#2}% - \csv@@normalize*[,]\cpt@currna - \def\csv@do##1{% + \iflacus{#2}{% + \def\cpt@currna{}% + }{% + \edef\cpt@currna{\cptcommanormalize{#2}}% + }% + \docommalist{#1}{% \cpt@xpr@cessoptions{##1}% }% - \csv@@parse*[,]\cpt@currfams \cpt@pr@cessoptions \cpt@pr@cessopti@ns } @@ -3798,6 +4425,8 @@ \let\@fileswith@pti@ns\@@fileswith@pti@ns \cpt@olddxfalse \AtEndOfPackage{\let\@unprocessedoptions\relax}% + \cpt@afterprocessoptions + \let\cpt@afterprocessoptions\relax } \robust@def*\ifindefaultdsTF{% \begingroup @@ -3912,7 +4541,7 @@ \oifinset@sp@TF,\cpt@curropt\DeclaredOptions{% \oifinset@sp@TF,\cpt@curropt\ExecutedOptions{% \oifinset@sp@TF,\cpt@curropt\cpt@execwarnlist{}{% - \iftogTF{biboolkeys}{}{% + \iftogTF{biboolopts}{}{% \ifcpt@verbose \cpt@info{Option '\cpt@curropt' of family '\cpt@currfam'\MsgBrk multiply submitted to @@ -3935,6 +4564,7 @@ }% \kv@@loop*[,]\cpt@curroptvals } +% Alias keys must always come from the parent's family: \robust@def*\XExecuteAliasOption#1{% \cpt@testopt{\cpt@executealiasoption#1}{}% } @@ -3956,7 +4586,7 @@ \let\cpt@currval\@empty }% \ifx\cpt@curropt\CurrentOption - \cpt@optfdtrue\cptbreakloop + \cpt@optfdtrue\loopbreak \edef\OptionFound{\unexpanded{##1}}% \else \let\cpt@curropt\@empty @@ -4026,22 +4656,20 @@ % Only 'article', 'report', 'memoir' options have been added % to \XExternalOptions. Other external options (eg, those of % script and KOMA-Script classes) haven't been added. -\BeginOverlookWhiteSpace \newcommand*\XExternalOptions{% - 10pt,11pt,12pt,14pt,17pt,20pt,25pt,30pt,36pt,48pt,60pt, - a0paper,a1paper,a2paper,a3paper,a4paper,a6paper, - b0paper,b1paper,b2paper,b3paper,b4paper,b5paper,b6paper, - letterpaper,legalpaper,executivepaper,landscape,oneside, - twoside,draft,final,titlepage,notitlepage,onecolumn, - twocolumn,leqno,fleqn,openbib,openright,openleft,openany, - article,ms,showtrims,oldfontcommands,extrafontsizes,noetex -} -\EndOverlookWhiteSpace + 10pt,11pt,12pt,14pt,17pt,20pt,25pt,30pt,36pt,48pt,60pt,% + a0paper,a1paper,a2paper,a3paper,a4paper,a6paper,% + b0paper,b1paper,b2paper,b3paper,b4paper,b5paper,b6paper,% + letterpaper,legalpaper,executivepaper,landscape,oneside,% + twoside,draft,final,titlepage,notitlepage,onecolumn,% + twocolumn,leqno,fleqn,openbib,openright,openleft,openany,% + article,ms,showtrims,oldfontcommands,extrafontsizes,noetex% +} \robust@def*\AddToExternalOptions#1{% \cptfiltermergecsv[,]\XExternalOptions{#1}\nofilter } \robust@def*\RemoveFromExternalOptions#1{% - \cpt@filterremoveelements[,]\XExternalOptions{#1}\nofilter + \cptfilterremovecsv[,]\XExternalOptions{#1}\nofilter } \robust@def*\cpt@addto@undecl@opts{% \edef\everymergeitem##1{\@space##1}% @@ -4078,7 +4706,7 @@ }% }} \robust@def*\cpt@usedefault#1#2\cpt@nil{% - \cptifmacroTF{#1}{% + \ifmacroTF{#1}{% \edef\cpt@tempa{\cptremovescape#1}% }{% \cpt@notcserr{#1}% @@ -4108,11 +4736,11 @@ \ExecutedOptions } \robust@def*\cpt@removecurroption#1{% - \cptexpandargonce{\cpt@filterremoveelements[,]% + \cptexpandargonce{\cptfilterremovekv[,]% \@unusedoptionlist}{#1}\nofilter } \robust@def*\cpt@cleanup#1{% - \cptifmacroTF{#1}{}{\cpt@notcserr{#1}}% + \ifmacroTF{#1}{}{\cpt@notcserr{#1}}% \BeforeStartOfDocument{% \ifdefFT#1{}{% \ifcsnullTF#1{}{% @@ -4131,7 +4759,9 @@ \def#1{}% }% } -\cpt@cleanup\cpt@processedoptions +\BeforeStartOfDocument{% + \cpt@cleanup\cpt@processedoptions +} \cptpassunexpanded{% \begingroup \def\cpt@tempa{\endgroup @@ -4163,14 +4793,15 @@ \expandafter\cpt@tempa\else\expandafter\endgroup\fi } \cptonlypreamble{% - \cptonlypreamble, - \cptloadpackages,\ifpackagewithTF,\ifclasswithTF,\cpt@ifoptions, + \cptonlypreamble,\cptloadpackages,\ifpackagewithoptionsTF, + \ifclasswithoptionsTF,\cpt@ifoptions, \cptpushcatcodes,\cptpopcatcodes,\UseNormalCatcodes, \rsv@UseNormalCatcodes,\StyleFilePurpose,\StyleFileInfo, \AfterEndOfStyleFile,\StyleFileRCSInfo,\SetStyleFileMessages, \XDeclareOption,\XDeclareOptions,\XDeclareCommandOption, \XDeclareCommandOptions,\XDeclareBooleanOption, \XDeclareBooleanOptions,\XDeclareBiBooleanOptions, + \XDeclareSwitchOption,\XDeclareSwitchOptions, \XProcessOptions,\XExecuteOptions,\XExecuteAliasOption, \cpt@processedoptions,\cpt@optionlist,\cpt@findoption@a, \cpt@findoption@b,\cpt@processoptions,\cpt@xprocessoptions, @@ -4205,35 +4836,61 @@ } \XDisableOptions*{draft,final} \XDeclareOption*{\cpt@warn{Unknown option '\CurrentOption' ignored}} -\XExecuteOptions{verbose=false,usepox=true,optionstacklimit=4}\relax +\XExecuteOptions{% + verbose=false,usepox=true,optionstacklimit=4, + kernelifnextchar=false +}\relax \XProcessOptions*\relax -\robust@def*\@ltx@warn{\@latex@warning@no@line} -\robust@def*\@ltx@info{\@latex@info@no@line} -\robust@def*\@ltx@err{\@latex@error} -\robust@def\gen@nil#1\fi#2\gen@do#3\gen@nil{\fi#1#2} -\robust@def*\cpt@fox{\cpt@teststopt\cpt@f@x,} -\robust@def*\cpt@f@x[#1]#2#3{% - \advance\cpt@foxdepth\@ne - \ifnum\cpt@foxdepth>\@ne - \cpt@err{\noexpand\cpt@fox nesting}\@ehc - \fi - \cpt@stchoose{cpt@st}{#2}\cpt@rsvda\cpt@fox + +\robust@def\indris@nil#1\fi#2\indris@do#3\indris@nil{\fi#1#2} +\newvariables{if}{lastindris}[false] +\robust@def*\indrisloop{\cpt@teststopt\cpt@indrisloop{,}} +\robust@def*\cpt@indrisloop[#1]#2#3{% + \pushfunctions\cpt@indrisloop + {\indris@do,\indrisnr,\iflastindris,% + \ifloopbreak,\user@do,\getnextindris}\indrisdepth + \cpt@stchoose{cpt@st}{#2}\cpt@rsvda\indrisloop \cpt@sttrue\cpt@csvnormalize[#1]\cpt@rsvda - \cpt@lastitemfalse\chardef\foxnr\z@pt - \def\gen@do##1#1##2\gen@nil{% - \ifcat$\detokenize\expandafter{\@gobble##2.}$\gen@nil - \cpt@lastitemtrue\fi - \edef\foxnr{\the\numexpr\foxnr+1}% - #3{##1}% - \gen@do##2\gen@nil + \lastindrisfalse\loopbreakfalse + \chardef\indrisnr\z@pt + \ifsingletokenTF{#3}{% + \ifmacroTF{#3}{}{\cpt@notcserr{#3}}% + }{% + \cpt@notonetokenerr{#3}% + }% + \let\user@do#3% + \def\getnextindris##1#1##2\indris@nil{% + \edef\nextindris{\unexpanded\expandafter{\@gobble##1}}% + \letcsntocs{nextindris@\cptrm\indrisdepth}\nextindris + }% + \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 + \if@boolTF{lastindris}{% + \def\nextindris{}% + \csn@def{nextindris@\cptrm\indrisdepth}{}% + }{% + \ifcsvbreakTF{##1}\loopbreak\relax + \if@boolTF{loopbreak}{% + \defpass\reserved@a####1\indris@nil{\cptdoremainder{####1}}% + }{% + \getnextindris.##2\indris@nil + }% + }% + \pushnumber\indrisnr + \expandafter\user@do\expandafter{\@gobble##1}% + \indris@do.##2\indris@nil }% - \expandafter\gen@do\cpt@rsvda#1\gen@nil - \advance\cpt@foxdepth\m@one + \expandafter\indris@do\expandafter.\cpt@rsvda#1\indris@nil + \popfunctions\cpt@indrisloop\indrisdepth } - \cptpopcatcodes \cptrestorecatcodes \declarefutureletset[fl@]{lbracket,star,rquote} + \endinput %% End of file catoptions.sty %% + |