%\iffalse meta-comment %<*internal> \iffalse % %<*readme> Abstract ---- The `cdcmd` package provides some conditional command, just like `styledcmd` package. The difference is `cdcmd` can define expandable command. See `cdcmd.pdf` (in English) or `cdcmd-cn.pdf` (in Chinese) for more details. Contributing ---- [Issues](https://github.com/Sophanatprime/cdcmd/issues) and [pull requests](https://github.com/Sophanatprime/cdcmd/pulls) are always welcome. Copyright and license ---- Copyright (C) 2021--2021 Wenjian Chern (Longaster) and any individual authors listed elsewhere in this file. -------------------------------------------------------------------------- This work may be distributed and/or modified under the conditions of the LaTeX Project Public License, either version 1.3c of this license or (at your option) any later version. This version of this license is in http://www.latex-project.org/lppl/lppl-1-3c.txt and the latest version of this license is in http://www.latex-project.org/lppl.txt and version 1.3 or later is part of all distributions of LaTeX version 2005/12/01 or later. This work has the LPPL maintenance status `maintained`. The Current Maintainers of this work are Wenjian Chern (Longaster). -------------------------------------------------------------------------- % %<*internal> \fi % %\fi %\iffalse %\NeedsTeXFormat{LaTeX2e} %\RequirePackage{expl3}[2021/05/11] %\GetIdInfo$Id: cdcmd.dtx 1.0 2021/10/12 +0815 Longaster$ % {Expandable Conditional Command In LaTeX2e} %\ProvidesExplPackage{cdcmd} % {\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription} %<*driver> \documentclass{l3doc} \usepackage{xcolor} \usepackage{cdcmd} \EnableCrossrefs \CodelineIndex \RecordChanges \begin{document} \DocInput{\jobname.dtx} \PrintChanges \PrintIndex \end{document} % %\fi % %\GetFileInfo{cdcmd.sty} % \title{The \pkg{cdcmd} package} % % \author{Wenjian Chern % (Longaster\thanks{Email: \url{longaster@163.com}}~)} % % \date{Released \today, version \fileversion} % % \maketitle % % \begin{documentation} % \ExplSyntaxOn \let\strcmp\tex_strcmp:D \ExplSyntaxOff % % \begin{abstract} % \pkg{cdcmd} is a package that allows you define `polymorphic' command. Like \pkg{styledcmd} package, % you can define \tn{protected} command, but \pkg{cdcmd} can define expandable conditional command as well. % \end{abstract} % %\section{Main Interface} % %\begin{function}{\newcondition,\setcondition,\clearcondition} % \begin{syntax} % \cs{newcondition} \marg{identifier} \marg{id(s)} % \cs{setcondition} + \marg{identifier=ids list} % \cs{clearcondition}\oarg{identifier(s)} % \end{syntax} % \cs{newcondition} new \meta{identifier} and its \meta{ids}. % The leading and trailing spaces in \meta{identifier} will be removed. % % \cs{setcondition} sets \meta{ids} of \meta{identifier} locally. % The un-\verb|+| version will clear \meta{ids} formerly set. % % Both \meta{identifier} and \meta{id} cannot be \verb|*|. % % \cs{clearcondition} will clear ids from given \meta{identifiers} locally. Default value is \verb|*|, that is, clear all. %\end{function} % %\begin{function}{ % \conditionif,\conditioncmd, % \econditionif,\econditioncmd, %} % \begin{syntax} % \cs{conditionif} * \oarg{identifier=ids list} \marg{true} \marg{false} % \cs{conditioncmd} * \oarg{identifier=ids list} \marg{material} % \end{syntax} % When the \meta{identifier=ids list} makes \texttt{true} condition, leave \meta{true}/\marg{material} in the input stream. % Leaving \meta{false} when the condition is \texttt{false}. % % The starred version is \texttt{all}, unstarred version is \text{any}. % See below for more details. % % The \cs{econditionif} and \cs{econditioncmd} are expandable (\verb|f-|expandable). % \cs{conditionif}, \cs{conditioncmd} are \tn{protected}. % % The default value of \meta{identifier=id list} is \verb|*|, will leave \meta{true}/\meta{material} in the input stream. %\end{function} % %\begin{function}{ % \conditioncase,\conditioncaseTF, % \econditioncase,\econditioncaseTF %} % \begin{syntax} % \cs{conditioncaseTF} * ! % ~~\{ % ~~~~\marg{identifier=ids list case_1} \marg{code_1} % ~~~~\marg{identifier=ids list case_2} \marg{code_2} % ~~~~... % ~~~~\marg{identifier=ids list case_n} \marg{code_n} % ~~\} % ~~\marg{true code} % ~~\marg{false code} % \end{syntax} % Evaluates in turn each of the \meta{identifier=ids list} until the first one that evaluates % to \texttt{true} or to \texttt{false}, for un-\verb|!| version or \verb|!| version, respectively. % The \meta{code} associated to this first case is left in the input stream, followed by the \meta{true code}, % and other cases are discarded. If none of the cases match then only the \meta{false code} is inserted. % % The unstarred version is \verb|any|, starred version is \verb|all|. %\end{function} % %\begin{texnote} % The process in \meta{ids} is using \cs{clist_map_...} of \LaTeX3. It will view \verb|{,}| as empty, % while \verb|{{},}| are not. See \pkg{interface3.pdf} for more details. %\end{texnote} % % Supposing following commands have been used. %\begin{verbatim} % \newcondition{defined}{} % \newcondition{paper}{a4,a5,b5} % \setcondition{paper={a5,b5}} %\end{verbatim} % It will define an identifier named \verb|defined|, which has not id. % And define an identifier named \verb|paper|, which has three ids: \verb|a4, a5, b5|. % Then set two ids: \verb|a5,b5| for \verb|paper| identifier. % % \verb|any| will be evaluated to \texttt{true} if \meta{identifier=ids list} % matches any of one statement described followed: %\begin{enumerate} % \item \meta{identifier=ids list} is exactly \verb|*|; % \item \meta{identifier=ids list} is exactly a defined $\mathit{identifier}$, such as \verb|paper|, or \verb|defined|; % \item \meta{identifier=ids list} is a defined $\mathit{identifier}$, and its \meta{id} is \verb|*|, such as \verb|paper=*| or \verb|defined=*|; % \item \meta{identifier=ids list} is a defined $\mathit{identifier}$, and \emph{one of} item in \meta{ids} has been set, such as \verb|paper=b5| or \verb|paper={a5,b5}| or \verb|paper={a5,a0}| (\verb|a0| unset, but \verb|a5| already set. Any id set to \meta{identifier} \verb|defined| will evaluate to \texttt{false}, except \verb|*|, because the $\mathit{identifier}$ never have defined id, even the \meta{ids} is empty (\verb|defined=|); % \item \emph{Any} single item in \meta{identifier=ids list} matches any statements listed above, such as \verb|paper={a5,a0},undefined|. %\end{enumerate} % % \verb|all| will be evaluated to \text{true} if \meta{identifier=ids list} % matches any of one statement described followed. %\begin{enumerate} % \item \meta{identifier=ids list} is exactly \verb|*|; % \item \meta{identifier=ids list} is exactly a defined $\mathit{identifier}$, such as \verb|paper|, or \verb|defined|; % \item \meta{identifier=ids list} is a defined $\mathit{identifier}$, and its \meta{id} is \verb|*|, such as \verb|paper=*| or \verb|defined=*|; % \item \meta{identifier=ids list} is a defined $\mathit{identifier}$, and \emph{all of} the \meta{ids} has been set, such as \verb|paper=b5| or \verb|paper={a5,b5}|. The any id set to \meta{identifier} \verb|defined| will evaluate to \texttt{false}, except \verb|*|, because the $\mathit{identifier}$ never have defined id, even the \meta{ids} is empty (\verb|defined=|); % \item \emph{All} items in \meta{identifier=ids list} match any statements listed above, such as \verb|paper={a5,b5},defined|. %\end{enumerate} % %\begin{function}{ % \newconditioncommand, % \renewconditioncommand, % \provideconditioncommand, % \declareconditioncommand, % \neweconditioncommand, % \reneweconditioncommand, % \provideeconditioncommand, % \declareeconditioncommand, %} % \begin{syntax} % \cs{newconditioncommand} * \meta{function} \oarg{arg nums} \oarg{default} \marg{code} % \cs{neweconditioncommand} * \meta{function} \oarg{arg nums} \marg{code} % \end{syntax} % Those commands are just like \tn{newcommand}, \tn{renewcommand}, etc. They will define command like % \verb|\foo+|\marg{identifier=ids list}\meta{args}. The optional argument cannot contain \tn{par}. % % The \verb|e|-version commands define expandable command, and cannot set default value. % However you can use \pkg{xparse}-like command illustrated followed, % which can set default value. % % Unstarred version is \tn{long}, just like \LaTeX's. % % The new \meta{function} will take one optional argument: \verb|+|, the function is just like % the \verb|*| in \cs{conditionif}, etc. And one mandatory argument \meta{identifier=ids list}. % After absorbing these two arguments, then absorb arguments of given \meta{arg nums}, or use \meta{default}, if given. %\end{function} % %\begin{function}{ % \NewConditionCommand , % \RenewConditionCommand , % \ProvideConditionCommand , % \DeclareConditionCommand , % \NewExpandableConditionCommand , % \RenewExpandableConditionCommand , % \ProvideExpandableConditionCommand , % \DeclareExpandableConditionCommand , %} % \begin{syntax} % \cs{NewConditionCommand} \meta{function} \marg{arg spec} \marg{code} % \end{syntax} % Those commands are just like \pkg{xparse}'s \cs{NewDocumentCommand}, etc. % They will define command like \verb|\foo+|\marg{identifier=ids list}\meta{args}. % % \meta{arg spec} must follow the rules of the \pkg{xparse} package. % % The new \meta{function} will take one optional argument: \verb|+|, the function is just like % the \verb|*| in \cs{conditionif}, etc. And one mandatory argument \meta{identifier=ids list}. % After absorbing these two arguments, then absorb arguments of given \meta{arg spec}. %\end{function} % % \section{Examples} % % \input{cdcmd-test.tex} % % \section{For package authors} % % \begin{function}[pTF]{ % \cdcmd_any_if:n, % \cdcmd_all_if:n, % \cdcmd_any_if:o, % \cdcmd_all_if:o, % \cdcmd_any_if:V, % \cdcmd_all_if:V, % \cdcmd_any_if:f, % \cdcmd_all_if:f, % } % The meaning should be obvious. % \end{function} % % \begin{function}[TF]{ % \cdcmd_any_case_true:n, % \cdcmd_any_case_false:n, % \cdcmd_all_case_true:n, % \cdcmd_all_case_false:n, % } % The meaning should be obvious. % \end{function} % % \end{documentation} % % \begin{implementation} % % \section{Implementation} % % \begin{macrocode} %<*package> % \end{macrocode} % \begin{macrocode} %<@@=cdcmd> % \end{macrocode} % \begin{macrocode} \str_const:Nn \c_cdcmd_all_str { * } \clist_new:N \g__cdcmd_clist \bool_new:N \l__cdcmd_clear_set_bool \msg_new:nnn { cdcmd } { condition-exist } { The~ condition~ `#1'~ you~ try~ to~ new~ already~ exists. } \msg_new:nnn { cdcmd } { condition-not-exist } { The~ condition~ `#1'~ not~ exists. } \msg_new:nnn { cdcmd } { condition-id-not-exist } { The~ id~ `#2' of~ condition~ `#1'~ not~ exists. } % \end{macrocode} % \begin{macro}[pTF]{\cdcmd_if_exist:n} % Condition \meta{indentifier} if exist. % \begin{macrocode} \prg_new_conditional:Npnn \cdcmd_if_exist:n #1 { p, T, F, TF } { \clist_if_exist:cTF { c__cdcmd_condition@ #1 _clist } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}[TF]{\cdcmd_cd_id_if_exist:nn} % ID \meta{id} of condition \meta{indentifier} if exist. % \begin{macrocode} \prg_new_conditional:Npnn \cdcmd_cd_id_if_exist:nn #1#2 { T, F, TF } { \clist_if_in:cnTF { c__cdcmd_condition@ #1 _clist } {#2} { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}{ % \cdcmd_new:nn, % \cdcmd_set:nn, % \cdcmd_set_cdcmd_single:nn, % \cdcmd_set_cdcmd_all:n, % \cdcmd_set:n, % \cdcmd_clear_set:n, % } % \begin{macrocode} \cs_new_nopar:Npn \cdcmd_new:nn #1#2 { \cdcmd_if_exist:nTF {#1} { \msg_error:nnn { cdcmd } { condition-exist } {#1} } { \clist_gput_right:Nn \g__cdcmd_clist {#1} \clist_const:cn { c__cdcmd_condition@ #1 _clist } {#2} \clist_new:c { l__cdcmd_curr_condition@ #1 _clist } } } \cs_new_nopar:Npn \cdcmd_set:nn #1#2 { \cdcmd_if_exist:nTF {#1} { \bool_if:NT \l__cdcmd_clear_set_bool { \clist_clear:c { l__cdcmd_curr_condition@ #1 _clist } } \clist_map_inline:nn {#2} { \str_if_eq:eeTF {##1} { \c_cdcmd_all_str } { \clist_map_break:n { \cdcmd_set_cdcmd_all:n {#1} } } { \cdcmd_set_cdcmd_single:nn {#1} {##1} } } } { \msg_warning:nnn { cdcmd } { condition-not-exist } {#1} } } \cs_new_nopar:Npn \cdcmd_set_cdcmd_single:nn #1#2 { \cdcmd_if_exist:nTF {#1} { \cdcmd_cd_id_if_exist:nnTF {#1} {#2} { \clist_put_right:cn { l__cdcmd_curr_condition@ #1 _clist } {#2} } { \msg_warning:nnnn { cdcmd } { condition-id-not-exist } {#1} {#2} } } { \msg_warning:nnn { cdcmd } { condition-not-exist } } } \cs_new_nopar:Npn \cdcmd_set_cdcmd_all:n #1 { \cdcmd_if_exist:nTF {#1} { \clist_set_eq:cc { l__cdcmd_curr_condition@ #1 _clist } { c__cdcmd_condition@ #1 _clist } } { \msg_warning:nnn { cdcmd } { condition-not-exist } {#1} } } \cs_new_nopar:Npn \cdcmd_set:n { \keyval_parse:NNn \cdcmd_set_cdcmd_all:n \cdcmd_set:nn } \cs_new_nopar:Npn \cdcmd_clear_set:n #1 { \bool_set_true:N \l__cdcmd_clear_set_bool \keyval_parse:NNn \cdcmd_set_cdcmd_all:n \cdcmd_set:nn {#1} \bool_set_false:N \l__cdcmd_clear_set_bool } % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{ % \cdcmd_any_if:n, % \cdcmd_any_if:o, % \cdcmd_any_if:V, % \cdcmd_any_if:f, % } % \begin{macrocode} \cs_new:Npn \cdcmd_any_if:nTF #1 { \bool_if:nTF { \keyval_parse:NNn \__cdcmd_any_i:n \__cdcmd_any_ii:nn {#1} \c_false_bool } } \cs_new:Npn \cdcmd_any_if_p:n #1 { \bool_if_p:n { \keyval_parse:NNn \__cdcmd_any_i:n \__cdcmd_any_ii:nn {#1} \c_false_bool } } \cs_new:Npn \cdcmd_any_if:nT #1#2 { \cdcmd_any_if:nTF {#1} {#2} { } } \cs_new:Npn \cdcmd_any_if:nF #1 { \cdcmd_any_if:nTF {#1} { } } \cs_new:Npn \cdcmd_any_if:nFT #1#2#3 { \cdcmd_any_if:nTF {#1} {#3} {#2} } \prg_generate_conditional_variant:Nnn \cdcmd_any_if:n { o, V, f } { p, T, F, TF } \cs_new:Npn \__cdcmd_any_i:n #1 { \str_if_eq:eeTF {#1} { \c_cdcmd_all_str } { \c_true_bool || } { \cdcmd_if_exist:nT {#1} { \c_true_bool || } } } \cs_new:Npn \__cdcmd_any_ii:nn #1#2 { \cdcmd_if_exist:nT {#1} { \clist_map_tokens:nn {#2} { \__cdcmd_any_ii_aux:nn {#1} } } } \cs_new:Npn \__cdcmd_any_ii_aux:nn #1#2 { \str_if_eq:eeTF {#2} { \c_cdcmd_all_str } { \clist_map_break:n { \tex_the:D \c_true_bool || } } { \__cdcmd_clist_if_in:cnT { l__cdcmd_curr_condition@ #1 _clist } {#2} { \clist_map_break:n { \tex_the:D \c_true_bool || } } } } % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{ % \cdcmd_all_if:n, % \cdcmd_all_if:o, % \cdcmd_all_if:V, % \cdcmd_all_if:f, % } % \begin{macrocode} \cs_new:Npn \cdcmd_all_if:nTF #1 { \bool_if:nTF { \keyval_parse:NNn \__cdcmd_all_i:n \__cdcmd_all_ii:nn {#1} \c_true_bool } } \cs_new:Npn \cdcmd_all_if_p:n #1 { \bool_if_p:n { \keyval_parse:NNn \__cdcmd_all_i:n \__cdcmd_all_ii:nn {#1} \c_true_bool } } \cs_new:Npn \cdcmd_all_if:nT #1#2 { \cdcmd_all_if:nTF {#1} {#2} { } } \cs_new:Npn \cdcmd_all_if:nF #1 { \cdcmd_all_if:nTF {#1} { } } \cs_new:Npn \cdcmd_all_if:nFT #1#2#3 { \cdcmd_all_if:nTF {#1} {#3} {#2} } \prg_generate_conditional_variant:Nnn \cdcmd_all_if:n { o, V, f } { p, T, F, TF } \cs_new:Npn \__cdcmd_all_i:n #1 { \str_if_eq:eeF {#1} { \c_cdcmd_all_str } { \cdcmd_if_exist:nF {#1} { \c_false_bool && } } } \cs_new:Npn \__cdcmd_all_ii:nn #1#2 { \cdcmd_if_exist:nTF {#1} { \bool_lazy_and_p:nn { \int_compare_p:n { \clist_count:n {#2} > 0 } } { \int_compare_p:n { \clist_map_tokens:nn {#2} { \__cdcmd_all_ii_aux:nn {#1} } 1 > 0 } } && } { \c_false_bool && } } \cs_new:Npn \__cdcmd_all_ii_aux:nn #1#2 { \str_if_eq:eeF {#2} { \c_cdcmd_all_str } { \__cdcmd_clist_if_in:cnF { l__cdcmd_curr_condition@ #1 _clist } {#2} { \clist_map_break:n { - } } } } % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{ % \__cdcmd_clist_if_in:Nn, % \__cdcmd_clist_if_in:NV, % \__cdcmd_clist_if_in:No, % \__cdcmd_clist_if_in:cn, % \__cdcmd_clist_if_in:cV, % \__cdcmd_clist_if_in:co, % \__cdcmd_clist_if_in:nn, % \__cdcmd_clist_if_in:nV, % \__cdcmd_clist_if_in:no, % } % \begin{macrocode} \prg_new_conditional:Npnn \__cdcmd_clist_if_in:Nn #1#2 { p, T, F, TF } { \int_compare:nTF { 0 \clist_map_tokens:Nn #1 { \__cdcmd_if_eq_break:ee {#2} } > 0 } { \prg_return_true: } { \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__cdcmd_clist_if_in:Nn { NV, No, cn, cV, co } { p, T, F, TF } \prg_new_conditional:Npnn \__cdcmd_clist_if_in:nn #1#2 { p, T, F, TF } { \int_compare:nTF { 0 \clist_map_tokens:nn {#1} { \__cdcmd_if_eq_break:ee {#2} } > 0 } { \prg_return_true: } { \prg_return_false: } } \prg_generate_conditional_variant:Nnn \__cdcmd_clist_if_in:nn { nV, no } { p, T, F, TF } \cs_new:Npn \__cdcmd_if_eq_break:ee #1#2 { \str_if_eq:eeT {#1} {#2} { \clist_map_break:n { 1 } } } % \end{macrocode} % \end{macro} % \begin{macro}[TF]{ % \cdcmd_any_case_true:n, % \cdcmd_any_case_false:n, % \cdcmd_all_case_true:n, % \cdcmd_all_case_false:n, % } % Conditional case, see also \cs{bool_case_true:n} and \cs{bool_case_false:n} in \pkg{source3.pdf}. % \begin{macrocode} \scan_new:N \s__cdcmd_mark \scan_new:N \s__cdcmd_stop \cs_new:Npn \cdcmd_any_case_true:nTF { \exp:w \__cdcmd_any_case_true:nTF } \cs_new:Npn \cdcmd_any_case_true:n #1 { \exp:w \__cdcmd_any_case_true:nTF {#1} { } { } } \cs_new:Npn \cdcmd_all_case_true:nTF { \exp:w \__cdcmd_all_case_true:nTF } \cs_new:Npn \cdcmd_all_case_true:n #1 { \exp:w \__cdcmd_all_case_true:nTF {#1} { } { } } \cs_new:Npn \cdcmd_any_case_false:nTF { \exp:w \__cdcmd_any_case_false:nTF } \cs_new:Npn \cdcmd_any_case_false:n #1 { \exp:w \__cdcmd_any_case_false:nTF {#1} { } { } } \cs_new:Npn \cdcmd_all_case_false:nTF { \exp:w \__cdcmd_all_case_false:nTF } \cs_new:Npn \cdcmd_all_case_false:n #1 { \exp:w \__cdcmd_all_case_false:nTF {#1} { } { } } \cs_new:Npn \__cdcmd_any_case_true:nTF #1#2#3 { \__cdcmd_case:Nw \cdcmd_any_if:nTF #1 { * } { } \s__cdcmd_mark {#2} \s__cdcmd_mark {#3} \s__cdcmd_stop } \cs_new:Npn \__cdcmd_all_case_true:nTF #1#2#3 { \__cdcmd_case:Nw \cdcmd_all_if:nTF #1 { * } { } \s__cdcmd_mark {#2} \s__cdcmd_mark {#3} \s__cdcmd_stop } \cs_new:Npn \__cdcmd_any_case_false:nTF #1#2#3 { \__cdcmd_case:Nw \cdcmd_any_if:nFT #1 { * } { } \s__cdcmd_mark {#2} \s__cdcmd_mark {#3} \s__cdcmd_stop } \cs_new:Npn \__cdcmd_all_case_false:nTF #1#2#3 { \__cdcmd_case:Nw \cdcmd_all_if:nFT #1 { * } { } \s__cdcmd_mark {#2} \s__cdcmd_mark {#3} \s__cdcmd_stop } \cs_new:Npn \__cdcmd_case:Nw #1#2#3 { #1 {#2} { \__cdcmd_case_end:nw {#3} } { \__cdcmd_case:Nw #1 } } \cs_new:Npn \__cdcmd_case_end:nw #1#2#3 \s__cdcmd_mark #4#5 \s__cdcmd_stop { \exp_end: #1 #4 } % \end{macrocode} % \end{macro} % \begin{macro}{\newcondition,\setcondition,\clearcondition} % Conditional setting command for document. % \begin{macrocode} \NewDocumentCommand \newcondition { >{ \TrimSpaces } m } { \cdcmd_new:nn {#1} } \NewDocumentCommand \setcondition { t+ } { \IfBooleanTF {#1} { \cdcmd_set:n } { \cdcmd_clear_set:n } } \NewDocumentCommand \clearcondition { !O{*} } { \clist_map_inline:nn {#1} { \str_if_eq:eeTF {##1} { \c_cdcmd_all_str } { \clist_map_break:n { \exp_after:wN \clearcondition \exp_after:wN [ \g__cdcmd_clist ] } } { \cdcmd_if_exist:nTF {##1} { \clist_clear:c { l__cdcmd_curr_condition@ ##1 _clist } } { \msg_warning:nnn { cdcmd } { condition-not-exist } {##1} } } } } % \end{macrocode} % \end{macro} % \begin{macrocode} \NewExpandableDocumentCommand \econditionif { s O{*} +m +m } { \IfBooleanTF {#1} { \cdcmd_all_if:nTF } { \cdcmd_any_if:nTF } {#2} {#3} {#4} } \NewExpandableDocumentCommand \econditioncmd { s O{*} +m } { \IfBooleanTF {#1} { \cdcmd_all_if:nTF } { \cdcmd_any_if:nTF } {#2} {#3} { } } \NewExpandableDocumentCommand \econditioncase { s +m } { \IfBooleanTF {#1} { \cdcmd_all_case:n {#2} } { \cdcmd_any_case:n {#2} } } \NewExpandableDocumentCommand \econditioncaseTF { s +m } { \IfBooleanTF {#1} { \cdcmd_all_case:nTF {#2} } { \cdcmd_any_case:nTF {#2} } } \NewDocumentCommand \conditionif { s O{*} +m +m } { \IfBooleanTF {#1} { \cdcmd_all_if:nTF } { \cdcmd_any_if:nTF } {#2} {#3} {#4} } \NewDocumentCommand \conditioncmd { s O{*} +m } { \IfBooleanTF {#1} { \cdcmd_all_if:nTF } { \cdcmd_any_if:nTF } {#2} {#3} { } } \NewDocumentCommand \conditioncase { s t! +m } { \IfBooleanTF {#2} { \IfBooleanTF {#1} { \cdcmd_all_case_false:n {#3} } { \cdcmd_any_case_false:n {#3} } } { \IfBooleanTF {#1} { \cdcmd_all_case_true:n {#3} } { \cdcmd_any_case_true:n {#3} } } } \NewDocumentCommand \conditioncaseTF { s t! +m } { \IfBooleanTF {#2} { \IfBooleanTF {#1} { \cdcmd_all_case_false:nTF {#3} } { \cdcmd_any_case_false:nTF {#3} } } { \IfBooleanTF {#1} { \cdcmd_all_case_true:nTF {#3} } { \cdcmd_any_case_true:nTF {#3} } } } % \end{macrocode} % \begin{macro}{} % Define new \pkg{xparse} like conditional command. % \begin{macrocode} \str_const:Nn \c_cdcmd_pair_u_str { cdcmd@u@ } \str_const:Nn \c_cdcmd_pair_n_str { cdcmd@n@ } \cs_new_nopar:Npn \__cdcmd_cs_pair_u:N #1 { \c_cdcmd_pair_u_str \cs_to_str:N #1 } \cs_new_nopar:Npn \__cdcmd_cs_pair_n:N #1 { \c_cdcmd_pair_n_str \cs_to_str:N #1 } \cs_new:Npn \__cdcmd_arg_spec_from_num:nn #1#2 { \if_case:w 0#1 \exp_stop_f: \or: #2 \or: #2#2 \or: #2#2#2 \or: #2#2#2#2 \or: #2#2#2#2#2 \or: #2#2#2#2#2#2 \or: #2#2#2#2#2#2#2 \or: #2#2#2#2#2#2#2#2 \else: #2#2#2#2#2#2#2#2#2 \fi: } \cs_new_nopar:Npn \__cdcmd_cs_pair_u:Nn #1#2 { \c_cdcmd_pair_u_str \cs_to_str:N #1 : \__cdcmd_arg_spec_from_num:nn {#2} { n } } \cs_new_nopar:Npn \__cdcmd_cs_pair_n:Nn #1#2 { \c_cdcmd_pair_n_str \cs_to_str:N #1 : \__cdcmd_arg_spec_from_num:nn {#2} { n } } % do not check cs_if_free, let xparse do it \cs_new:Npn \__cdcmd_new_cdcmd_command:NN #1#2 { \cs_new_protected:Npn #1 ##1##2##3 { #2 ##1 { t+ m } { \IfBooleanTF {####1} { \cdcmd_all_if:nTF } { \cdcmd_any_if:nTF } {####2} { \use:c { \__cdcmd_cs_pair_u:N ##1 } } { \use:c { \__cdcmd_cs_pair_n:N ##1 } } } \exp_args:Nc #2 { \__cdcmd_cs_pair_u:N ##1 } {##2} {##3} \exp_args:Nc #2 { \__cdcmd_cs_pair_n:N ##1 } {##2} { } } } \seq_const_from_clist:Nn \c__cdcmd_Command_seq { \NewDocumentCommand , \RenewDocumentCommand , \ProvideDocumentCommand , \DeclareDocumentCommand , \NewExpandableDocumentCommand , \RenewExpandableDocumentCommand , \ProvideExpandableDocumentCommand , \DeclareExpandableDocumentCommand , } \seq_const_from_clist:Nn \c__cdcmd_COMMAND_seq { \NewConditionCommand , \RenewConditionCommand , \ProvideConditionCommand , \DeclareConditionCommand , \NewExpandableConditionCommand , \RenewExpandableConditionCommand , \ProvideExpandableConditionCommand , \DeclareExpandableConditionCommand , } \seq_mapthread_function:NNN \c__cdcmd_COMMAND_seq \c__cdcmd_Command_seq \__cdcmd_new_cdcmd_command:NN % \end{macrocode} % \end{macro} % \begin{macro}{} % Define \LaTeX{} like command. % \begin{macrocode} % do not check cs_if_free, let xparse do it \cs_new:Npn \__cdcmd_new_cdcmd_cmd_no:nnn #1#2#3 { \cs_new_protected:Npn #1 ##1##2##3 { #3 ##1 { t+ m } { \IfBooleanTF {####1} { \cdcmd_all_if:nTF } { \cdcmd_any_if:nTF } { ####2 } { \use:c { \__cdcmd_cs_pair_u:Nn ##1 {##2} } } { \use:c { \__cdcmd_cs_pair_n:Nn ##1 {##2} } } } #2 { \__cdcmd_cs_pair_u:Nn ##1 {##2} } {##3} #2 { \__cdcmd_cs_pair_n:Nn ##1 {##2} } { } } } \cs_generate_variant:Nn \__cdcmd_new_cdcmd_cmd_no:nnn { xxx } \seq_const_from_clist:Nn \c__cdcmd_cmd_no_seq { \cs_set_protected:cn , \cs_set_protected_nopar:cn , \cs_set_protected:cn , \cs_set_protected_nopar:cn , \cs_set_protected:cn , \cs_set_protected_nopar:cn , \cs_set:cn , \cs_set_nopar:cn , \cs_set:cn , \cs_set_nopar:cn , \cs_set:cn , \cs_set_nopar:cn , } \seq_const_from_clist:Nn \c__cdcmd_Cmd_no_seq { \NewDocumentCommand , \NewDocumentCommand , \RenewDocumentCommand , \RenewDocumentCommand , \DeclareDocumentCommand , \DeclareDocumentCommand , \NewExpandableDocumentCommand , \NewExpandableDocumentCommand , \RenewExpandableDocumentCommand , \RenewExpandableDocumentCommand , \DeclareExpandableDocumentCommand , \DeclareExpandableDocumentCommand , } \seq_const_from_clist:Nn \c__cdcmd_CMD_no_seq { \__cdcmd_new_cdcmd_p_l_num:Nnn , \__cdcmd_new_cdcmd_p_nl_num:Nnn , \__cdcmd_renew_cdcmd_p_l_num:Nnn , \__cdcmd_renew_cdcmd_p_nl_num:Nnn , \__cdcmd_declare_cdcmd_p_l_num:Nnn , \__cdcmd_declare_cdcmd_p_nl_num:Nnn , \__cdcmd_new_cdcmd_np_l_num:Nnn , \__cdcmd_new_cdcmd_np_nl_num:Nnn , \__cdcmd_renew_cdcmd_np_l_num:Nnn , \__cdcmd_renew_cdcmd_np_nl_num:Nnn , \__cdcmd_declare_cdcmd_np_l_num:Nnn , \__cdcmd_declare_cdcmd_np_nl_num:Nnn , } \int_step_inline:nn { 6 } { \__cdcmd_new_cdcmd_cmd_no:xxx { \seq_item:Nn \c__cdcmd_CMD_no_seq {#1} } { \seq_item:Nn \c__cdcmd_cmd_no_seq {#1} } { \seq_item:Nn \c__cdcmd_Cmd_no_seq {#1} } } \tl_new:N \l__cdcmd_arg_spec_tl \cs_new:Npn \__cdcmd_generate_arg_spec:nnn #1#2#3 { \tl_set:Nn \l__cdcmd_arg_spec_tl { O{#2} } \if_int_compare:w #1 > 1 \exp_stop_f: \int_step_inline:nn {#1-1} { \tl_put_right:Nn \l__cdcmd_arg_spec_tl {#3} } \fi: } \cs_new:Npn \__cdcmd_new_cdcmd_cmd_o_aux:nn #1#2 { \cs_new_protected:Npn #1 ##1##2##3##4##5 { #2 ##1 { t+ m } { \IfBooleanTF{####1} { \cdcmd_all_if:nTF } { \cdcmd_any_if:nTF } {####2} { \use:c { \__cdcmd_cs_pair_u:N ##1 } } { \use:c { \__cdcmd_cs_pair_n:N ##1 } } } \__cdcmd_generate_arg_spec:nnn {##2} {##3} {##5} \exp_args:NcV #2 { \__cdcmd_cs_pair_u:N ##1 } \l__cdcmd_arg_spec_tl {##4} \exp_args:NcV #2 { \__cdcmd_cs_pair_n:N ##1 } \l__cdcmd_arg_spec_tl { } } } \seq_const_from_clist:Nn \c__cdcmd_CMD_o_seq { \NewDocumentCommand , \RenewDocumentCommand , \DeclareDocumentCommand } \seq_const_from_clist:Nn \c__cdcmd_cmd_o_seq { \__cdcmd_new_cdcmd_o_num:Nnnnn , \__cdcmd_renew_cdcmd_o_num:Nnnnn , \__cdcmd_declare_cdcmd_o_num:Nnnnn , } \seq_mapthread_function:NNN \c__cdcmd_cmd_o_seq \c__cdcmd_CMD_o_seq \__cdcmd_new_cdcmd_cmd_o_aux:nn \cs_new_protected:Npn \__cdcmd_new_cdcmd_cmd_ne_aux:n #1 { \exp_args:Nc \NewDocumentCommand { #1 conditioncommand } { s m O{0} o +m } { \IfBooleanTF{##1} { \IfNoValueTF{##4} { \use:c { __cdcmd_ #1 _cdcmd_p_nl_num:Nnn } ##2 {##3} {##5} } { \use:c { __cdcmd_ #1 _cdcmd_o_num:Nnnnn } ##2 {##3} {##4} {##5} { m } } } { \IfNoValueTF{##4} { \use:c { __cdcmd_ #1 _cdcmd_p_l_num:Nnn } ##2 {##3} {##5} } { \use:c { __cdcmd_ #1 _cdcmd_o_num:Nnnnn } ##2 {##3} {##4} {##5} { +m } } } } } \clist_map_function:nN { new, renew, declare } \__cdcmd_new_cdcmd_cmd_ne_aux:n \NewDocumentCommand \provideconditioncommand { s m O{0} o +m } { \cs_if_free:NT #2 { \IfBooleanTF{#1} { \IfNoValueTF{#4} { \newconditioncommand * #2 [#3] {#5} } { \newconditioncommand * #2 [#3] [#4] {#5} } } { \IfNoValueTF{#4} { \newconditioncommand #2 [#3] {#5} } { \newconditioncommand #2 [#3] [#4] {#5} } } } } \int_step_inline:nnnn { 7 } { 1 } { 12 } { \__cdcmd_new_cdcmd_cmd_no:xxx { \seq_item:Nn \c__cdcmd_CMD_no_seq {#1} } { \seq_item:Nn \c__cdcmd_cmd_no_seq {#1} } { \seq_item:Nn \c__cdcmd_Cmd_no_seq {#1} } } \cs_new_protected:Npn \__cdcmd_new_cdcmd_cmd_e_no_aux:n #1 { \exp_args:Nc \NewDocumentCommand { #1 econditioncommand } { s m O{0} +m } { \IfBooleanTF{##1} { \use:c { __cdcmd_ #1 _cdcmd_np_nl_num:Nnn } ##2 {##3} {##4} } { \use:c { __cdcmd_ #1 _cdcmd_np_l_num:Nnn } ##2 {##3} {##4} } } } \clist_map_function:nN { new, renew, declare } \__cdcmd_new_cdcmd_cmd_e_no_aux:n \NewDocumentCommand \provideeconditioncommand { s m O{0} +m } { \cs_if_free:NT #2 { \IfBooleanTF{#1} { \neweconditioncommand * #2 [#3] {#4} } { \neweconditioncommand #2 [#2] {#4} } } } % \end{macrocode} % \end{macro} % \begin{macrocode} % % \end{macrocode} % % \end{implementation} % % \endinput % %<*test> {\color{red!90!black} \begin{verbatim} \newcondition{defined}{} \newcondition{paper}{a4,a5,b5} \setcondition{paper={a5,b5}} \end{verbatim} } { \newcondition{defined}{} \newcondition{paper}{a4,a5,b5} \setcondition{paper={a5,b5}} \def\cdcmdtest#1->#2 /{\textcolor{red!90!black}{\detokenize{#1}}:~ #1 \newline} \parindent=0pt\ttfamily \cdcmdtest\conditionif[*]{t}{f}->t / \cdcmdtest\conditionif[defined]{t}{f}->t / \cdcmdtest\conditionif[defined=]{t}{f}->f / \cdcmdtest\conditionif[defined=*]{t}{f}->t / \cdcmdtest\conditionif[defined=a]{t}{f}->f / \cdcmdtest\conditionif[paper={a5,a0},undefined]{t}{f}->t / \cdcmdtest\conditionif*[*]{t}{f}->t / \cdcmdtest\conditionif*[defined]{t}{f}->t / \cdcmdtest\conditionif*[defined={,,}]{t}{f}->f / \cdcmdtest\conditionif*[defined=*]{t}{f}->t / \cdcmdtest\conditionif*[defined=a]{t}{f}->f / \cdcmdtest\conditionif*[paper={a5,a0},undefined]{t}{f}->f / \cdcmdtest\conditionif*[*,undefined]{t}{f}->f / \cdcmdtest\conditionif*[paper={a5,b5}]{t}{f}->t / \cdcmdtest\conditionif*[paper={a5,,b5}]{t}{f}->t / \cdcmdtest\conditionif*[paper={a5,b6,a5}]{t}{f}->f / \cdcmdtest\conditionif*[paper={a5,{ },45}]{t}{f}->f / \cdcmdtest\conditionif*[*,defined,paper={a5,b5}]{t}{f}->t / } {\color{red!90!black} \begin{verbatim} \def\truetext{true} \def\falsetext{false} \edef\testa{\econditionif[*]{true}{false}} \ifx\testa\truetext t\else f\fi \ifx\testa\falsetext t\else f\fi \strcmp {\econditionif[*]{true}{false}} {true} \strcmp {\econditionif[*]{true}{false}} {false} \strcmp {\testa} {\truetext} \strcmp {\testa} {\falsetext} \end{verbatim} } \def\truetext{true} \def\falsetext{false} \edef\testa{\econditionif[*]{true}{false}} \ifx\testa\truetext t\else f\fi \ifx\testa\falsetext t\else f\fi \strcmp{\econditionif[*]{true}{false}}{true} \strcmp{\econditionif[*]{true}{false}}{false} \strcmp{\testa}{\truetext} \strcmp{\testa}{\falsetext} {\color{red!90!black} \begin{verbatim} \conditioncase{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} } \end{verbatim} } \conditioncase{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} } {\color{red!90!black} \begin{verbatim} \conditioncaseTF{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} }{true}{false} \end{verbatim} } \conditioncaseTF{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} }{true}{false} {\color{red!90!black} \begin{verbatim} \conditioncase!{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} } \end{verbatim} } \conditioncase!{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} } {\color{red!90!black} \begin{verbatim} \conditioncaseTF!{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} }{true}{false} \end{verbatim} } \conditioncaseTF!{ {paper=a3} {a3} {paper=a4} {a4} {paper,defined} {pd} }{true}{false} {\color{red!90!black} \begin{verbatim} \newconditioncommand\longprotectedcdcmd{longprotectedcdcmd} \newconditioncommand\longprotectedcdcmdi[1]{longprotectedcdcmdi<#1>} \newconditioncommand\longprotectedcdcmdio[1][DFT]{longprotectedcdcmdio<#1>} \newconditioncommand*\shortprotectedcdcmd{shortprotectedcdcmd} \newconditioncommand*\shortprotectedcdcmdi[1]{shortprotectedcdcmdi<#1>} \newconditioncommand*\shortprotectedcdcmdio[1][DFT]{shortprotectedcdcmdio<#1>} \setcondition{paper={a4,a5}} \longprotectedcdcmd{*} \longprotectedcdcmdi{*}{1\par arg} \longprotectedcdcmdio{*} \longprotectedcdcmdio{*}[1opt] \longprotectedcdcmdio{paper=a4}[1opt a4] \longprotectedcdcmdio+{paper={a4,a7}}[1opt a4a7] \shortprotectedcdcmd{*} \shortprotectedcdcmdi{*}{1\par arg} \shortprotectedcdcmdio{*} \shortprotectedcdcmdio{*}[1opt] \shortprotectedcdcmdio{paper=a4}[1opt a4] \shortprotectedcdcmdio+{paper={a4,a7}}[1opt a4a7] \end{verbatim} } \newconditioncommand\longprotectedcdcmd{longprotectedcdcmd} \newconditioncommand\longprotectedcdcmdi[1]{longprotectedcdcmdi<#1>} \newconditioncommand\longprotectedcdcmdio[1][DFT]{longprotectedcdcmdio<#1>} \newconditioncommand*\shortprotectedcdcmd{shortprotectedcdcmd} \newconditioncommand*\shortprotectedcdcmdi[1]{shortprotectedcdcmdi<#1>} \newconditioncommand*\shortprotectedcdcmdio[1][DFT]{shortprotectedcdcmdio<#1>} {\ttfamily\setcondition{paper={a4,a5}}\obeylines \longprotectedcdcmd{*} \longprotectedcdcmdi{*}{1\par arg} \longprotectedcdcmdio{*} \longprotectedcdcmdio{*}[1opt] \longprotectedcdcmdio{paper=a4}[1opt a4] \longprotectedcdcmdio+{paper={a4,a7}}[1opt a4a7] \shortprotectedcdcmd{*} \shortprotectedcdcmdi{*}{1arg} \shortprotectedcdcmdio{*} \shortprotectedcdcmdio{*}[1opt] \shortprotectedcdcmdio{paper=a4}[1opt a4] \shortprotectedcdcmdio+{paper={a4,a7}}[1opt a4a7] } %