diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx | 1185 |
1 files changed, 1185 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx b/Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx new file mode 100644 index 00000000000..d0cb09aa137 --- /dev/null +++ b/Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx @@ -0,0 +1,1185 @@ +% \iffalse meta-comment +% +% Copyright (C) 2016 by Thomas Colcombet +% ----------------------------------- +% +% This file may be distributed and/or modified under the +% conditions of the LaTeX Project Public License, either version 1.2 % of this license or (at your option) any later version. +% The latest version of this license is in: +% +% http://www.latex-project.org/lppl.txt +% +% and version 1.2 or later is part of all distributions of LaTeX +% version 1999/12/01 or later. +% +% \fi +% +% \iffalse +% +%<*driver> +\documentclass{ltxdoc} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{paralist} +\usepackage{hyperref} +\usepackage{expl3} +\EnableCrossrefs +\CodelineIndex +\RecordChanges + + +\newcommand\kl[2][]{#2} + +\begin{document} +\DocInput{knowledge-utils.dtx} +\end{document} +%</driver> +% \fi +% +% \CheckSum{0} +% +% \CharacterTable +% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z +% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z +% Digits \0\1\2\3\4\5\6\7\8\9 +% Exclamation \! Double quote \" Hash (number) \# +% Dollar \$ Percent \% Ampersand \& +% Acute accent \' Left paren \( Right paren \) +% Asterisk \* Plus \+ Comma \, +% Minus \- Point \. Solidus \/ +% Colon \: Semicolon \; Less than \< +% Equals \= Greater than \> Question mark \? +% Commercial at \@ Left bracket \[ Backslash \\ +% Right bracket \] Circumflex \^ Underscore \_ +% Grave accent \` Left brace \{ Vertical bar \| +% Right brace \} Tilde \~} +% +% +% \changes{v2.0}{2016/02/26}{Initial version} % +% \GetFileInfo{knowledge-utils.sty} % +% \DoNotIndex{} +% +% \title{The \textsf{knowledge-utils} package} +% \author{Thomas Colcombet \\ \texttt{thomas.colcombet@irif.fr}} +% \maketitle +% +% \begin{abstract} +% This code is incorporated in the knowledge.sty file. It essentially contains a certain number of useful functions. +% +% This includes dealing with the kaux file (a single file which is output during the compilation, and then postprocessed for extracting information). +% In contains some primitives for creating fields in tuples, macros for overloading other macros, and code for recreating an argument list (reversing par of the xparse syntax). +% +% This file needs to be cleaned and reorganize. +% \end{abstract} +% +%\tableofcontents +% +% +% \section{Introduction} +% +% The main file is knowledge.dtx. +% +% +% +% +% +% \section{Implementation} +% +% \def\cs{\ExplSyntaxOn\csARG} +% \def\csARG#1{\ExplSyntaxOff\texttt{\detokenize{#1}}} +% +%\let\ifcode\iffalse +% +% \subsection{Code preparation} +% \begin{macrocode} +\usepackage{xparse} +\usepackage{currfile} +% \end{macrocode} +% The interface of expl3 since Mars 2015 has changed and a small patch is required: +% \begin{macrocode} +\tl_if_exist:NTF + \c_sys_jobname_str + {} + {\tl_set_eq:Nc\c_sys_jobname_str{c_job_name_tl}} +% \end{macrocode} +% Some new \kl{latex3} commands: +% \cs{cs_new_with_variants:Nnn}, +% \cs{if_mode_preamble:TF}, +% \cs{kl_hide_begin:} and \cs{kl_hide_begin:} +% (that stand for \cs{@bsphack} and \cs{@esphack} of \kl{latex2e}). +% +% Creating new macros with their variants at the same time... +% \begin{macrocode} +\cs_new_protected:Nn\cs_new_protected_with_variants:Nnn + {\cs_new_protected:Nn#1{#3} + \cs_generate_variant:Nn#1{#2}} +\cs_generate_variant:Nn\cs_new_protected_with_variants:Nnn{cnn} + +\cs_new_protected:Nn\cs_new_with_variants:Nnn + {\cs_new:Nn#1{#3} + \cs_generate_variant:Nn#1{#2}} +\cs_generate_variant:Nn\cs_new_with_variants:Nnn{cnn} + +\cs_generate_variant:Nn\tl_show:n{x} +% \end{macrocode} +% +% Now comes a command for simultaneously testing existence and non emptiness. +% \begin{macrocode} +\cs_new:Nn\tl_if_exist_ne:NTF + {\tl_if_exist:NTF#1{\tl_if_empty:NTF#1{#3}{#2}}{#3}} +\cs_generate_variant:Nn\tl_if_empty:nTF{xTF} +% \end{macrocode} +% +% +% Immediate execution of code with parameters without explicit abstraction. +%\begin{description} +%\item \cs{kl_apply_inline:nnw} takes an argument specifier, a code with +% arguments ($\sharp$1,\dots), and sufficiently many arguments, and executes +% the code with arguments substituted (this is not expandable). +%\item \cs{kl_apply_inline_variant:nnnw} does the same thing, and furthermore use a variant +% of the code in which the arguments are executed as specified in the second argument. +% For instance, +%\begin{verbatim} +%\kl_apply_inline_variant:nnnw{nn}{VV} +% {\cs_new:Nn\wrap:n{#1##1#2}} +% \leftdelimiter\rightdelimiter +%\end{verbatim} +%Define a new function \cs{wrap:n} that takes a parameter, and encloses it with the \textbf{content} of +%\cs{leftdelimiter} and \cs{rightdelimiter}. +%\end{description} +%\ifcode +% \begin{macrocode} +\cs_new_protected:Npn\kl_apply_inline:nnw#1#2 + {\group_begin: + \cs_set:cn{g_tmpa_cs:#1} + {\group_end:#2} + \use:c{g_tmpa_cs:#1}} + +\cs_new_protected:Npn\kl_apply_inline_variant:nnnw#1#2#3 + {\group_begin: + \cs_set:cn{g_tmpa_cs:#1} + {\group_end:#3} + \exp_args:Nc + \cs_generate_variant:Nn{g_tmpa_cs:#1}{#2} + \use:c{g_tmpa_cs:#2}} +% \end{macrocode} +%\fi +% +% \begin{macrocode} +\cs_new:Nn\mode_if_preamble:TF{#1} +\AtBeginDocument + {\cs_gset:Nn\mode_if_preamble:TF{#2}} +% \end{macrocode} +% \begin{macrocode} +\makeatletter +\int_new:N\kl_sphack_int +\cs_set_eq:NN\kl_stored_@bsphack\@bsphack +\cs_set_eq:NN\kl_stored_@esphack\@esphack +\cs_set:Nn\kl_hide_begin: + {\@bsphack + \cs_set_eq:NN\@bsphack\relax + \cs_set_eq:NN\@esphack\relax + \int_incr:N\kl_sphack_int} +\cs_set:Nn\kl_hide_end: + {\int_decr:N\kl_sphack_int + \int_compare:nNnTF{\kl_sphack_int}=0 + {\cs_set_eq:NN\@bsphack\kl_stored_@bsphack + \cs_set_eq:NN\@esphack\kl_stored_@esphack}{} + \@esphack} +\makeatother +% \end{macrocode} +% \begin{macrocode} +\cs_new:Nn\if_true:TF{#1} +\cs_new:Nn\if_false:TF{#2} +\cs_generate_variant:Nn\int_compare:nNnTF{cNnTF} +\cs_generate_variant:Nn\use:nn{nx} +% \end{macrocode} +% The command |\cs_apply_inline:n<n's>| takes a first argument +% with as many parameters as in |<n's>|, and apply it to them. +% \ifcode +% \begin{macrocode} +\cs_new:Npn\cs_apply_inline:nn#1 + {\cs_set:Npn\g_tmpa_cs:##1{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2##3{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnnnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2##3##4{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnnnnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2##3##4##5{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnnnnnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2##3##4##5##6{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnnnnnnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2##3##4##5##6##7{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnnnnnnnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2##3##4##5##6##7##8{#1} + \g_tmpa_cs:} +\cs_new:Npn\cs_apply_inline:nnnnnnnnnn#1 + {\cs_set:Npn\g_tmpa_cs:##1##2##3##4##5##6##7##8##9{#1} + \g_tmpa_cs:} +% \end{macrocode} +% +% \begin{macrocode} +\cs_generate_variant:Nn\cs_apply_inline:nn{nc} +\cs_generate_variant:Nn\cs_apply_inline:nnn{ncc} +\cs_generate_variant:Nn\cs_apply_inline:nnnn{nccc} +\cs_generate_variant:Nn\cs_apply_inline:nnnnn{ncccc} +\cs_generate_variant:Nn\cs_apply_inline:nnnnnn{nccccc} +\cs_generate_variant:Nn\cs_apply_inline:nnnnnnn{ncccccc} +\cs_generate_variant:Nn\cs_apply_inline:nnnnnnnn{nccccccc} +\cs_generate_variant:Nn\cs_apply_inline:nnnnnnnnn{ncccccccc} +\cs_generate_variant:Nn\cs_apply_inline:nnnnnnnnnn{nccccccccc} +% \end{macrocode} +%\fi +% +% +% \subsection{KAux file} +% +% We introduce here the KAux file. +% The principle of the KAux file is to play the role of an aux file, but at the same time it +% has some facilities for using it with several subpackages. +% Essentially, the code in the KAUX file is executed, and is supposed to use only functions defined by the +% |\NewKAuxCommand| (using \texttt{xparse} syntax). Such functions do nothing by default, +% unless explicitly activated when rereading the file. +% At the beginning of the KAUX file, each command that may occur is declared, +% the package that produced it is named, its arguments are provided, and its use +% is succinctly described. +% +% By default, the location is stored in the KAux file, unless the writing command has a star. +% When the KAux file is processed, the variables \cs{\kauxCurrentFile} +% and \cs{\kauxCurrentLine} contain the filename and the line at the moment the information was processed. +% The location can be explicitely written using \cs{\KAuwWriteLocation}. +% Thus, by the user can decide when to write the line (at the begining of a command may be better when it has several lines). +% +% The file is open for writing when \cs{KAuxActivate} is called the +% first time. So, commands may ensure that the file is activated using +% \cs{KAuxActivate}, but this should be used after the configuration +% is finished. So the rule is: when a package is loaded, one should never use +% \cs{KAuxActivate}. +% \begin{macrocode} +\AtBeginDocument{\KAuxActivate} + +\NewDocumentCommand\KAuxActivate{}{ + \cs_gset_eq:NN\KAuxActivate\relax + \KAuxOpen{}} +% \end{macrocode} +% \begin{macrocode} +\AtEndDocument{\KAuxClose} +% \end{macrocode} +% \begin{macrocode} +\iow_new:N\knowledge_kaux_iow + +\NewDocumentCommand\KAuxOpen{} + {\kaux_pretreatment_tl + \tl_gclear:N\kaux_pretreatment_tl + \iow_open:Nn + \knowledge_kaux_iow + {\c_sys_jobname_str.kaux} + \KAuxWrite*{} + \kaux_inittreatment_tl + \tl_gclear:N\kaux_inittreatment_tl + \KAuxWrite*{}} + +\NewDocumentCommand\KAuxClose{} + {\iow_close:N\knowledge_kaux_iow + \bool_gset_true:N\kaux_can_be_used_bool + \kaux_posttreatment_tl + } +% \end{macrocode} +% +% +% +% Using the command |\KAuxBefore|, |\KAuxInit| and |\KAuxAfter|, one can add +% code to be executed before the opening, at the beginning and after the writing of the KAUX file. +% \begin{macrocode} +\NewDocumentCommand\KAuxBefore{m} + {\tl_put_right:Nn\kaux_pretreatment_tl{#1}} +\NewDocumentCommand\KAuxAfter{m} + {\tl_put_right:Nn\kaux_posttreatment_tl{#1}} +\NewDocumentCommand\KAuxInit{m} + {\tl_put_right:Nn\kaux_inittreatment_tl{#1}} +% \end{macrocode} +% \begin{macrocode} +\tl_gset:Nn\kaux_pretreatment_tl{} +\tl_gset:Nn\kaux_posttreatment_tl{} +\tl_gset:Nn\kaux_inittreatment_tl{} +% \end{macrocode} +% +% +% \subsubsection{KAux phases and commands} +% +% The idea is that the KAux file will be read several times. Once at the begining, before rewriting it, +% and then more times afterward (maybe several times). Each time it is read corresponds to a `phase'. +% By default, when a KAuxCommand is defined, then it does nothing (and absorbs its only parameter). +% Then, when a phase is activated (and several phases can be activated simultaneously), each command +% executes the corresponding code (declares using |\DeclareKAuxPhaseCommand|). +% +% +% The list of KAux commands are kept in |\kaux_command_list_tl|. +% \begin{macrocode} +\tl_new:N\kaux_command_list_tl +% \end{macrocode} +% +% When one wants to use some command in the KAux file, one has to first declare +% it using |\NewKAuxCommand\commandname{arguments}{description}| +% in which |\commandname| is the token of the command, |arguments| +% is the description of arguments following the \texttt{xparse} package syntax, +% and |description| is an informal description of what the command is intended to do. +% Note that for efficiency reason, in the KAux file itself, +% \emph{arguments have to be surrounded by curly brackets}, +% but when used, these will parsed using the argument description as defined by \texttt{xparse}. +% +% Technically, |\NewKAuxCommand| declares the command in the KAux file using |\KAuxCommand|, +% then the arguments description is stored in |\kaux_commandname-args_tl|, and |\commandname| +% itself is created, as a code that executes, followed by the arguments, all the tokens in |\kaux_commandname-active_tl|. Also, the command is appended to |\kaux_command_list_tl|. +% \begin{macrocode} +\NewDocumentCommand\NewKAuxCommand{ m m m } +{ \ProvideDocumentCommand#1{#2}{} + \KAuxInit + {\KAuxWrite*{\KAuxCommand#1{#2}{#3}}} + \tl_gset:cn{kaux_\cs_to_str:N#1-args_tl}{#2} + \tl_gput_right:Nn\kaux_command_list_tl{#1} +} +\NewDocumentCommand\KAuxCommand{mmm} + {\ProvideDocumentCommand#1{#2}{}} +% \end{macrocode} +% +% |\ActivateKAuxPhase{phase1,phase2,...}| sets the KAux commands to use +% for all KAux commands the +% code corresponding to |phase1|, |phase2|, \dots{} This is obtained by +% defining for each command |\commandname| the tl variable |\kaux_commandname-active_tl| +% accordingly. +% \begin{macrocode} +\NewDocumentCommand\ActivateKAuxPhase{m}{ + \tl_map_inline:Nn\kaux_command_list_tl + {\kaux_activate_command_phase:Nn##1{#1}} + } +% \end{macrocode} +% \begin{macrocode} +\cs_new:Nn\kaux_activate_command_phase:Nn +{ \tl_gclear:c{kaux_\cs_to_str:N#1-active_tl} + % + \kaux_code_set:Nn\tmpa_code{} + \clist_map_inline:nn{#2} + {\cs_if_exist:cTF{kaux_\cs_to_str:N#1-##1:nnnnnnnnn} + {\exp_args:NNc + \kaux_code_put_right:NN + \tmpa_code{kaux_\cs_to_str:N#1-##1:nnnnnnnnn}} + {}} + \kaux_code_wrap:N\tmpa_code + \exp_args:NNx\kaux_code_put_left:Nn\tmpa_code + {\DeclareDocumentCommand\exp_not:N#1 + {\exp_not:v{kaux_\cs_to_str:N#1-args_tl}}} + \kaux_code_exec:N\tmpa_code +} +% \end{macrocode} +% +% Here comes a bunch of commands for manipulating code. +% The idea is to replicate some of the commands for the type tl (in a much less efficient way, it is true), +% but make it compatible with arguments |#1|, |#2|. There may be much more efficient ways to do that, +% but the expansion system makes it not obvious for me. +% \begin{macrocode} +\cs_new:Nn\kaux_code_set_eq:NN + {\cs_set_eq:NN#1#2} +\cs_new:Nn\kaux_code_set:Nn + {\cs_set:Npn#1##1##2##3##4##5##6##7##8##9{#2}} +\cs_new:Nn\kaux_code_put_right:NN + {\exp_args:NNo\kaux_code_put_right:Nn#1 + {#2{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}}} +\cs_new:Nn\kaux_code_put_right:Nn + {\exp_args:NNo\cs_set:Nn + \tmp:nnnnnnnnn + {#1{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}#2} + \cs_set_eq:NN#1\tmp:nnnnnnnnn} +\cs_new:Nn\kaux_code_put_left:Nn + {\kaux_code_set:Nn\g_tmpc_code{#2} + \kaux_code_put_right:NN\g_tmpc_code#1 + \kaux_code_set_eq:NN#1\g_tmpc_code} +\cs_new:Nn\kaux_code_wrap:N + {\expandafter\cs_set:Nn + \expandafter\tmp:nnnnnnnnn + \expandafter{ + \expandafter{#1{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}}} + \cs_set_eq:NN#1\tmp:nnnnnnnnn} +\cs_new:Nn\kaux_code_exec:N + {#1{##1}{##2}{##3}{##4}{##5}{##6}{##7}{##8}{##9}} +% \end{macrocode} +% Declaring a code for a KAuxCommand associated to a specific phase +% is done using |\DeclareKAuxPhaseCommand\commandname{phase}{code}|. +% The code is stored in a `cs' with nine parameters. +% \begin{macrocode} +\NewDocumentCommand\DeclareKAuxPhaseCommand{mmm} +{ \tl_if_exist:cTF{kaux_\cs_to_str:N#1-args_tl}{} + {\ERROR_KAuxCommand_UNDEFINED} + \cs_gset:cn{kaux_\cs_to_str:N#1-#2:nnnnnnnnn}{#3}} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentCommand\KAuxWriteLocation{} + {\KAuxActivate + \group_begin: + \tl_set:Nx\l_tmpa_tl{{\currfilename}{\the\inputlineno}} + \tl_if_eq:NNTF\l_tmpa_tl\kaux_location_tl + {} + {\tl_gset_eq:NN\kaux_location_tl\l_tmpa_tl + \iow_now:Nx\knowledge_kaux_iow{} + \iow_now:Nx\knowledge_kaux_iow + {\KAuxFileAt\kaux_location_tl}} + \group_end:} + +\tl_new:N\kaux_location_tl + +\NewDocumentCommand\KAuxWriteX{sm} + {\KAuxActivate + \IfBooleanTF{#1}{}{\KAuxWriteLocation} + \exp_args:NNx\iow_now:Nn\knowledge_kaux_iow{#2}} + +\NewDocumentCommand\KAuxWrite{sm} + {\KAuxActivate + \IfBooleanTF{#1}{}{\KAuxWriteLocation} + \iow_now:Nn\knowledge_kaux_iow{#2}} + +\NewDocumentCommand\KAuxFileAt{mm} + {\tl_set:Nn\kauxCurrentFile{#1} + \tl_set:Nn\kauxCurrentLine{#2}} + +\tl_new:N\kauxCurrentFile +\tl_new:N\kauxCurrentLine +% \end{macrocode} +% +% The kaux file is allowed to be used at the beginning if it exists (of course), +% and if the aux file also exists. This is for tools that delete the aux file for cleaning the directory +% to virtually also delete the kaux file. +% \begin{macrocode} +\bool_new:N\kaux_can_be_used_bool +\bool_gset_false:N\kaux_can_be_used_bool + +\file_if_exist:nT{\c_sys_jobname_str.aux} +{\file_if_exist:nT{\c_sys_jobname_str.kaux} + {\bool_gset_true:N\kaux_can_be_used_bool}} + +\NewDocumentCommand\KAuxProcess{m} +{ \bool_if:NT\kaux_can_be_used_bool + {\ActivateKAuxPhase{#1} + \input{\c_sys_jobname_str.kaux}}} +% \end{macrocode} +% +% +% +% +% +% +% +% +% \subsection{References} +% +% \begin{macrocode} +\cs_new:Nn\cell_new_type:nnn + { + \cs_new:cn{#1_id:#2}{#3} + \cs_new:cn{#1_id_b:#2}{{#3}} + \cs_new:cpx{#1_at:N#2}##1 + {\exp_not:n{\exp_after:wN\exp_args:Nc\exp_after:wN} + ##1 \exp_not:c{#1_id_b:#2}} + } + +\cs_new:Nn\cell_specialize:nnn + {\cs_new:cpx{#1_#2_id:#3} + {\exp_not:c{#1_id:n#3}{#2}} + \cs_new:cpx{#1_#2_at:N#3}##1 + {\exp_not:c{#1_at:Nn#3}##1{#2}} + } + +\cs_new:Nn\cell_make_tl:nn + {\cs_set:Nn\l_tmpa_cs:nn + {\cs_new:cpx{#1_##1:#2##2} + {\exp_not:c{#1_at:N#2}\exp_not:c{tl_##1:N##2}}} + \l_tmpa_cs:nn{set}{n} + \l_tmpa_cs:nn{gset}{n} + \l_tmpa_cs:nn{set}{x} + \l_tmpa_cs:nn{gset}{x} + \l_tmpa_cs:nn{gput_right}{n} + \l_tmpa_cs:nn{gput_left}{n} + \l_tmpa_cs:nn{put_right}{n} + \l_tmpa_cs:nn{put_left}{n} + \l_tmpa_cs:nn{show}{} + \l_tmpa_cs:nn{use}{} + \l_tmpa_cs:nn{if_exist}{TF} + \l_tmpa_cs:nn{if_empty}{TF} + } + +\cs_new:Nn\cell_make_int:nn + { + \cs_set:Nn\l_tmpa_cs:nn + {\cs_new:cpx{#1_##1:#2##2} + {\exp_not:c{#1_at:N#2}\exp_not:c{int_##1:N##2}}} + \l_tmpa_cs:nn{new}{} + \l_tmpa_cs:nn{show}{} + \l_tmpa_cs:nn{set}{n} + \l_tmpa_cs:nn{gset}{n} + \l_tmpa_cs:nn{incr}{} + \l_tmpa_cs:nn{gincr}{} + \l_tmpa_cs:nn{decr}{} + \l_tmpa_cs:nn{gdecr}{} + \l_tmpa_cs:nn{use}{} + \l_tmpa_cs:nn{to_arabic}{} + } + + +\cs_new:Nn\cell_make_bool:nn + { + \cs_set:Nn\l_tmpa_cs:nn + {\cs_new:cpx{#1_##1:#2##2} + {\exp_not:c{#1_at:N#2}\exp_not:c{bool_##1:N##2}}} + \l_tmpa_cs:nn{set_true}{} + \l_tmpa_cs:nn{set_false}{} + \l_tmpa_cs:nn{gset_true}{} + \l_tmpa_cs:nn{gset_false}{} + \l_tmpa_cs:nn{set}{n} + \l_tmpa_cs:nn{gset}{n} + \l_tmpa_cs:nn{if}{TF} + } + +\cs_new:Nn\seq_use:N + {\seq_use:Nn#1,} + +\cs_new:Nn\cell_make_seq:nn + { + \cs_set:Nn\l_tmpa_cs:nn + {\cs_new:cpx{#1_##1:#2##2} + {\exp_not:c{#1_at:N#2}\exp_not:c{seq_##1:N##2}}} + \l_tmpa_cs:nn{new}{} + \l_tmpa_cs:nn{set_from_clist}{n} + \l_tmpa_cs:nn{gset_from_clist}{n} + \l_tmpa_cs:nn{gpush}{n} + \l_tmpa_cs:nn{if_exist}{TF} + \l_tmpa_cs:nn{if_empty}{TF} + \l_tmpa_cs:nn{if_in}{nTF} + \l_tmpa_cs:nn{show}{} + \l_tmpa_cs:nn{use}{n} + \l_tmpa_cs:nn{use}{} + \l_tmpa_cs:nn{map_inline}{n} + } + +\cs_new:Nn\cell_make_tuple:nn + { + \cs_set:Nn\l_tmpa_cs:nn + {\cs_new:cpx{#1_##1:#2##2} + {\exp_not:c{#1_at:N#2}\exp_not:c{tuple_##1:N##2}}} + } + +\cs_new:Nn\cell_specialize_int:nnn + { + \cell_specialize:nnn{#1}{#2}{#3} + \cell_make_int:nn{#1_#2}{#3} + } + +\cs_new:Nn\cell_specialize_tl:nnn + { + \cell_specialize:nnn{#1}{#2}{#3} + \cell_make_tl:nn{#1_#2}{#3} + } + +\cs_new:Nn\cell_specialize_bool:nnn + { + \cell_specialize:nnn{#1}{#2}{#3} + \cell_make_bool:nn{#1_#2}{#3} + } + +\cs_new:Nn\cell_specialize_seq:nnn + { + \cell_specialize:nnn{#1}{#2}{#3} + \cell_make_seq:nn{#1_#2}{#3} + } +% \end{macrocode} +% +% \subsection{Tuples} +% +% ensure +% \cs{\tuple_empty_tl}, \cs{\tuple_new:N}, +% \cs{\tuple_gclear:N}, \cs{\tuple_if_exist:NTF}, +% \cs{\tuple_if_no_index:NNTF}, +% \cs{\tuple_gset:NNn}, \cs{\tuple_gset:NNN}, +% \cs{\tuple_gdel:NN}, \cs{\tuple_apply:NNNn}, +% \cs{\tuple_apply_inline:NNnn}, \cs{\tuple_get_default_tl:NNNn}, +% \cs{\tuple_get_int:NNN}, \cs{\tuple_incr:NN}, +% \cs{\tuple_decr:NN}, \cs{\tuple_gset_true:NN}, +% \cs{\bool_set_false:NN} +% +% \cs\tuple_new_expandable_index:Nnn takes a token acting as an index, a name, +% and a default value, and creates a command |tuple_exp_|name|:N| which given +% a tuple, retrieve in an expandable way the index, and if it does not exists outputs the default value. +% +% +% +% +% +% +% +% +% +% +% \begin{macrocode} +\cs_new:Nn\tuple_new:n + { + \cs_new:cx{#1_new:N} + {\exp_not:N\tl_new:N##1 + \exp_not:N\tl_gset:Nn##1{\exp_not:c{#1:}}} + \cs_new:cx{#1_gclear:N} + {\exp_not:N\tl_gset:Nn##1{\exp_not:c{#1:}}} + \cs_new:cx{#1_ensure:N} + {\exp_not:N\tl_if_exist:NTF##1{} + {\exp_not:N\tl_new:N##1 + \exp_not:N\tl_gset:Nn##1{\exp_not:c{#1:}}}} + \cs_new:cn{#1:}{} + % + \cs_set:Nn\l_tmpa_cs:nn + { \cs_new:cpx{#1_##1:##2} + {\exp_not:c{tuple_##1:n##2}{\exp_not:n{#1}}}} + \l_tmpa_cs:nn{new_tl_index}{Nnn} + \l_tmpa_cs:nn{new_tl_index}{nn} + \l_tmpa_cs:nn{new_tl_index}{n} + \l_tmpa_cs:nn{new_int_index}{Nnn} + \l_tmpa_cs:nn{new_int_index}{nn} + \l_tmpa_cs:nn{new_int_index}{n} + \l_tmpa_cs:nn{new_bool_index}{Nn} + \l_tmpa_cs:nn{new_bool_index}{n} + \l_tmpa_cs:nn{show}{N} + \l_tmpa_cs:nn{if_exist}{NTF} + } +\cs_new:Npn\tuple_if_exist:nNTF#1{\tl_if_exist:NTF} +% \end{macrocode} +% +% +% \begin{macrocode} +\cs_new:Nn\tuple_new_bool_index:nNNn + { + \cs_new:cn{#1_#4_expands_to:TF}{ + \cs_set:Nn#2{##1} + \cs_set:Nn#3{##2}} + \cs_gset:Nn#2{} + \cs_gset:Nn#3{} + % + \cs_new:cx{#1_#4_if:NTF} + {\exp_not:N\expandafter + \exp_not:c{#1_#4_if~i:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}{##3}{##2}} + \cs_new:cpn{#1_#4_if~i:w} + ##1 #2 ##2 #2 ##3 \tuple_end: + {\tl_if_single:nTF{##3}} + % + \cs_new:cx{#1_#4_gset_false:N} + {\exp_not:N\expandafter + \exp_not:c{#1_#4_gset_false~i:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}##1} + \cs_new:cpn{#1_#4_gset_false~i:w} + ##1 #2 ##2 #2 ##3 \tuple_end:##4 + {\tl_if_single:nTF{##3} + {\tl_gset:Nn##4{##1}} + {\tl_gset:Nn##4{##1##2}}} + % + \cs_new:cx{#1_#4_gset_true:N} + {\exp_not:N\expandafter + \exp_not:c{#1_#4_gset_true~:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}##1} + \cs_new:cpn{#1_#4_gset_true~:w} + ##1 #2 ##2 #2 ##3 \tuple_end: ##4 + {\tl_if_single:nTF{##4} + {\tl_gset:Nn##4{##1 #2}}{}} +} +\cs_new:Nn\tuple_new_bool_index:nn + {\use:x{\exp_not:n{\tuple_new_bool_index:nNNn{#1}} + \exp_not:c{BOOL_#1_#2_true:} + \exp_not:c{BOOL_#1_#2_false:} + {#2}}} +% \end{macrocode} +% +% +% +% \begin{macrocode} +\cs_new:Nn\tuple_new_index:nNnn{ + \cs_new:cn{#1_#3_expands_to:n}{\cs_set:Nn#2{##1}} + \cs_gset:Nn#2{} + % + \cs_new:cx{#1_#3_use:N} + {\exp_not:N\expandafter + \exp_not:c{#1_#3_use~i:w} + ##1 \exp_not:n{#2 {#4}\tuple_end:}} + \cs_new:cpx{#1_#3_use~i:w} + ##1 #2 ##2 ##3 \tuple_end:{##2} + % + \cs_new:cx{#1_#3_if_exist:NTF} + {\exp_not:N\expandafter + \exp_not:c{#1_#3_if_exist~i:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}{##3}{##2}} + \cs_new:cpn{#1_#3_if_exist~i:w} + ##1 #2 ##2 ##3 #2 ##4 \tuple_end: + {\tl_if_single:nTF{##4}} + % + \cs_new:cx{#1_#3_gdel:N} + {\exp_not:N\expandafter + \exp_not:c{#1_#3_gdel~i:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}##1} + \cs_new:cpn{#1_#3_gdel~i:w} + ##1 #2 ##2 ##3 #2 ##4 \tuple_end:##5 + {\tl_if_single:nTF{##4} + {\tl_gset:Nn##5{##1}} + {\tl_gset:Nn##5{##1##3}}} + % + \cs_new:cx{#1_#3_gapply:NN} + {\exp_not:N\expandafter + \exp_not:c{#1_#3_gapply~i:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}##1##2} + \cs_new:cpn{#1_#3_gapply~i:w} + ##1 #2 ##2 ##3 #2 ##4 \tuple_end: ##5 ##6 + {\tl_if_single:nTF{##4} + {\tl_gset:Nx##5{\exp_not:n{##1 #2}{##6{#4}}}} + {\tl_gset:Nx##5{\exp_not:n{##1 #2}{##6{##2}} \exp_not:n{##3}}}} +} + + + +\cs_new:Nn\tuple_new_tl_index:nNnn + {\tuple_new_index:nNnn{#1}#2{#3}{#4} + % + \cs_new:cx{#1_#3_gset:Nn} + {\exp_not:N\expandafter + \exp_not:c{#1_#3_gset~:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}##1{##2}} + \cs_new:cpn{#1_#3_gset~:w} + ##1 #2 ##2 ##3 #2 ##4 \tuple_end: ##5 ##6 + {\tl_if_single:nTF{##4} + {\tl_gset:Nn##5{##1 #2{##6}}} + {\tl_gset:Nn##5{##1 #2{##6} ##3}}} +} +\cs_new:Nn\tuple_new_tl_index:nnn + {\exp_args:Nnc\tuple_new_tl_index:nNnn{#1}{TL_#1_#2_:n}{#2}{#3}} +\cs_new:Nn\tuple_new_tl_index:nn + {\tuple_new_tl_index:nnn{#1}{#2}{}} + +\cs_new:Nn\int_incr:n{\int_eval:n{#1+1}} +\cs_new:Nn\int_decr:n{\int_eval:n{#1-1}} + +\cs_new:Nn\tuple_new_int_index:nNnn{ + \tuple_new_index:nNnn{#1}#2{#3}{#4} + % + \cs_new:cx{#1_#3_get_int:NN} + {\exp_not:n{\int_set:Nn} ##2 {\exp_not:c{#1_#3_use:N} \exp_not:N##1}} + % + \cs_new:cx{#1_#3_gincr:N} + {\exp_not:c{#1_#3_gapply:NN}##1\exp_not:N\int_incr:n} + % + \cs_new:cx{#1_#3_gdecr:N} + {\exp_not:c{#1_#3_gapply:NN}##1\exp_not:N\int_decr:n} + % + \cs_new:cx{#1_#3_gset:Nn} + {\exp_not:N\expandafter + \exp_not:c{#1_#3_gset~:w} + ##1 \exp_not:n{#2 ab #2 c \tuple_end:}##1{##2}} + \cs_new:cpn{#1_#3_gset~:w} + ##1 #2 ##2 ##3 #2 ##4 \tuple_end: ##5 ##6 + {\tl_if_single:nTF{##4} + {\tl_gset:Nx##5{##1 \exp_not:N#2 {\int_eval:n{##6}}}} + {\tl_gset:Nx##5{##1 \exp_not:N#2 {\int_eval:n{##6}} ##3}}} + % + \cs_new:cpx{#1_#3_case:NnTF}##1 + {\exp_not:N\int_case:nnTF{\exp_not:c{#1_#3_eval:n}##1}} +} +\cs_new:Nn\tuple_new_int_index:nnn + {\exp_args:Nnc\tuple_new_int_index:nNnn{#1}{INT_#1_#2_:n}{#2}{#3}} +\cs_new:Nn\tuple_new_int_index:nn + {\tuple_new_int_index:nnn{#1}{#2}{0}} +% \end{macrocode} +% +% \begin{macrocode} +%\cs_new:Nn\tuple_index_default_cs_set_eq:NN{ +% \cs_set:Npn#1{\cs_set_eq:NN#2}} +%\cs_new:Nn\tuple_index_default_tl_set:NN{ +% \cs_set:Npn#1{\tl_set:Nn#2}} +%\cs_new:Nn\tuple_index_default_tl_put_left:NN{ +% \cs_set:Npn#1{\tl_put_left:Nn#2}} +%\cs_new:Nn\tuple_index_default_tl_put_right:NN{ +% \cs_set:Npn#1{\tl_put_right:Nn#2}} +%\cs_new:Nn\tuple_index_default_int_set:NN{ +% \int_new:N#2 +% \cs_set:Npn#1{\int_set:Nn#2}} +%\cs_new:Nn\tuple_index_default_bool_set:NN{ +% \bool_new:N#2 +% \cs_set:Npn#1##1{##1#2}} +%\cs_new:Nn\tuple_index_default_ignore:N{ +% \cs_set:Npn#1##1{}} +%\cs_new:Nn\tuple_index_default_show:N{ +% \cs_set_eq:NN#1\tl_show:n} +% \end{macrocode} +% +% +% \subsection{Variables encoding} +% +% We use an automatic generator of variables, of different types. +% For global \texttt{tl} variables, the command is |\NewGTl| +%\begin{verbatim} +%\NewGTl{variable}[default value]{arguments}[identifier] +%\end{verbatim} +% The arguments satisfy the syntax of \texttt{xparse}, and the identifier uses these arguments for +% creating a token list that can be used in a csname. +% The result of this command is that new commands |\variableIfTF|, |\variableSet|, +% |\variableSetX|, |\variableGet|, |\variableApply|, |\variableApplyInline| and |\variableIfEmpty| +% are created. +% For instance +%\begin{verbatim} +% \NewGTl{Test}{ m o }[test default]{\IfNoValue{#1}{#2}{#2-#1}} +%\end{verbatim} +% Gives right to |\TestSet{first}[1]{success}| +% |\TestApplyInline{first}[1]{The test was a #1!}|. +% +% +% +% \begin{macrocode} +\cs_new:Nn\int_get_default:N + {\int_if_exist:NTF#1{\int_use:N#1}{0}} +\cs_generate_variant:Nn\int_get_default:N{c} +\cs_new:Nn\int_force:N + {\int_if_exist:NTF#1{}{\int_new:N#1}} +\cs_new:Npn\int_force_gset:Nn#1 + {\int_force:N#1\int_gset:Nn#1} +% \end{macrocode} +% +% +% \begin{macrocode} +\NewDocumentCommand\NewGBool{ m m o }{ + \IfNoValueTF{#3}{ + \tl_gset:Nn\g_tmpa_tl{#2} + \tl_remove_all:Nn\g_tmpa_tl{~} + \int_case:nnTF{\tl_count:N\g_tmpa_tl}{ + 0 {\NewGBoolComplete {#1}{#2}{#1:_bool}} + 1 {\NewGBoolComplete {#1}{#2}{#1:##1_bool}} + 2 {\NewGBoolComplete {#1}{#2}{#1:##1...##2_bool}} + 3 {\NewGBoolComplete {#1}{#2}{#1:##1...##2...##3_bool}} + 4 {\NewGBoolComplete {#1}{#2}{#1:##1...##2...##3...##4_bool}} + 5 {\NewGBoolComplete {#1}{#2}{#1:##1...##2...##3...##4...##5_bool}} + 6 {\NewGBoolComplete {#1}{#2}{#1:##1...##2...##3...##4...##5...##6_bool}} + 7 {\NewGBoolComplete {#1}{#2}{#1:##1...##2...##3...##4...##5...##6...##7_bool}} + 8 {\NewGBoolComplete {#1}{#2}{#1:##1...##2...##3...##4...##5...##6...##7...##8_bool}} + 9 {\NewGBoolComplete {#1}{#2}{#1:##1...##2...##3...##4...##5...##6...##7...##8...##9_bool}} + }{}{\ERROR}}{\NewGBoolComplete{#1}{#2}{#3}}} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentCommand\NewGBoolComplete{ m m m }{ + \exp_args:Nc\NewDocumentCommand{#1SetTrue}{#2} + {\bool_gset_true:c{#3}} + \exp_args:Nc\NewDocumentCommand{#1SetFalse}{#2} + {\bool_gset_false:c{#3}} + \exp_args:Nc\NewDocumentCommand{#1Set}{#2} + {\exp_args:Nc\bool_gset_tl:Nn{#3}} + \exp_args:Nc\DeclareExpandableDocumentCommand{#1IfTF}{#2} + {\bool_if:cTF{#3}} +} +\cs_new:Nn\bool_gset_tl:Nn + {\use:c{bool_gset_#2:N}#1} +% \end{macrocode} +% +% +% +% \begin{macrocode} +\NewDocumentCommand\NewGCs{ m m o }{ + \IfNoValueTF{#3}{ + \tl_gset:Nn\g_tmpa_tl{#2} + \tl_remove_all:Nn\g_tmpa_tl{~} + \int_case:nnTF{\tl_count:N\g_tmpa_tl}{ + 0 {\NewGCsComplete {#1}{#2}{#1_:}} + 1 {\NewGCsComplete {#1}{#2}{#1_##1_cs:w}} + 2 {\NewGCsComplete {#1}{#2}{#1_##1...##2_cs:w}} + 3 {\NewGCsComplete {#1}{#2}{#1_##1...##2...##3_cs:w}} + 4 {\NewGCsComplete {#1}{#2}{#1_##1...##2...##3...##4_cs:w}} + 5 {\NewGCsComplete {#1}{#2}{#1_##1...##2...##3...##4...##5_cs:w}} + 6 {\NewGCsComplete {#1}{#2}{#1_##1...##2...##3...##4...##5...##6_cs:w}} + 7 {\NewGCsComplete {#1}{#2}{#1_##1...##2...##3...##4...##5...##6...##7_cs:w}} + 8 {\NewGCsComplete {#1}{#2}{#1_##1...##2...##3...##4...##5...##6...##7...##8_cs:w}} + 9 {\NewGCsComplete {#1}{#2}{#1_##1...##2...##3...##4...##5...##6...##7...##8...##9_cs:w}} + }{}{\ERROR}}{\NewGCsComplete{#1}{#2}{#3}}} +% \end{macrocode} +% +% \begin{macrocode} +\NewDocumentCommand\NewGCsComplete{ m m m }{} +% \exp_args:Nc\NewDocumentCommand{#1New_internal}{ m m m } +% {\NewDocumentCommand##1{ m ##2}{##3} } +% \exp_args:Nc\NewDocumentCommand{#1New}{#2} +% {\cs_new:cn{#2}{#2_internal{#2}} +% \exp_args:Nc{#2_internal}} +% \end{macrocode} +% +% +% +% +% +% \subsection{The \texttt{knowledge} file handling} +% +% +% The knowledge package uses two macros for file handling: +%\begin{itemize} +%\item |\kl_copy_file:nn|(|nV|, |Vn|, |VV|) takes the name of two files +% and copies the first one to the second (does nothing if the first file does not exist), +%\item |kl_compare_files:Nnn|(|NnV|, |NVn|, |NVV|) takes a boolean and the name of two files, +% and sets the boolean (locally) according to the result of their comparison for equality, +%\item |\kl_tl_to_file:nn| takes the name of a file, and a token list, and creates the file with the tl as content. +% This is a conveninent way to create empty files (since deleting files is not possible with \kl{TeX}...) +%\end{itemize} +% +% \begin{macrocode} +\cs_new_protected_with_variants:Nnn\kl_copy_file:nn{nV,Vn,VV} + {\file_if_exist:nT{#1} + {\group_begin: + \bool_set_false:N\l_tmpa_bool + \ior_open:Nn\g_tmpa_ior{#1} + \iow_open:Nn\g_tmpa_iow{#2} + \bool_do_until:Nn\l_tmpa_bool{ + \ior_if_eof:NTF\g_tmpa_ior + {\bool_set_true:N\l_tmpa_bool} + {\ior_get_str:NN + \g_tmpa_ior + \l_tmpa_tl + \exp_args:NNV + \iow_now:Nn + \g_tmpa_iow + \l_tmpa_tl} + } + \ior_close:N\g_tmpa_ior + \iow_close:N\g_tmpa_iow + \group_end:}} + +\cs_new_protected_with_variants:Nnn\kl_compare_files:Nnn{NnV,NVn,NVV} + {\group_begin: + \bool_set_false:N\l_tmpa_bool% set when finished + \bool_set_true:N\l_tmpb_bool% result + \file_if_exist:nTF{#2} + {\file_if_exist:nF{#3} + {\bool_set_true:N\l_tmpa_bool + \bool_set_false:N\l_tmpb_bool}} + {\bool_set_true:N\l_tmpa_bool + \file_if_exist:nT{#3} + {\bool_set_false:N\l_tmpb_bool}} + \bool_if:NF\l_tmpa_bool{ + \ior_open:Nn\g_tmpa_ior{#2} + \ior_open:Nn\g_tmpb_ior{#3} + % + \bool_do_until:Nn\l_tmpa_bool{ + \ior_if_eof:NTF\g_tmpa_ior + {\bool_set_true:N\l_tmpa_bool + \ior_if_eof:NF\g_tmpb_ior + {\bool_set_false:N\l_tmp_bool}} + {\ior_if_eof:NTF\g_tmpb_ior + {\bool_set_true:N\l_tmpa_bool + \bool_set_false:N\l_tmp_bool} + {\ior_get_str:NN + \g_tmpa_ior + \l_tmpa_tl + \ior_get_str:NN + \g_tmpb_ior + \l_tmpb_tl + \tl_if_eq:NNF + \l_tmpa_tl\l_tmpb_tl + {\bool_set_true:N\l_tmpa_bool + \bool_set_false:N\l_tmpb_bool} + }} + } + \ior_close:N\g_tmpa_ior + \ior_close:N\g_tmpb_ior} + \bool_if:NTF\l_tmpb_bool + {\group_end:\bool_set_true:N#1} + {\group_end:\bool_set_false:N#1} + } + +\cs_new_protected:Nn\kl_tl_to_file:nn + {\iow_open:Nn\g_tmpa_iow{#1} + \iow_now:Nn\g_tmpa_iow{#2} + \iow_close:N\g_tmpa_iow} +% \end{macrocode} +% +% These macros are used for testing the modification of knowledges. +% At the begining, jobname.knowledge.aux is transferred to jobname.knowledge.tmp. +% During the file reading, the file jobname.knowledge.aux is again written. +% At the end, the two are compared. +% +% \begin{macrocode} +\ior_new:N\g_tmpa_ior +\ior_new:N\g_tmpb_ior +\iow_new:N\g_tmpa_iow +\iow_new:N\g_tmpb_iow +% \end{macrocode} +% +% +% +% +% +% \subsection{Dealing with LaTeX commands} +% +% +% We define now a certain number of commands that allows to +% \begin{itemize} +% \item Store known commands with a protected name. +% \item Declare commands as obsolete when used in a document. +% \item Create variants using \textsc{xsparse} that remove the hassle of optional parameters/stars, and so on. +% \end{itemize} +% +% +% \subsubsection{Overloading command} +% Overloading a command is similar in syntax to |\NewDocumentCommand| +% of the \texttt{xparse} package, but it further offer the macro |\SUPERcommand| +% (where |\command| is the token under definition), which can be used for calling the original code. +% It is often used in combination with |\XparseArgs| for recreating the arguments if necesssary. +% +% +% \begin{macrocode} +\cs_generate_variant:Nn\cs_gset_eq:NN{cN,cc} +\NewDocumentCommand\OverloadCommand{mmm} + {\exp_args:Nc\cs_gset_eq:NN{SUPER\cs_to_str:N#1}#1 + \exp_args:Nc\NewDocumentCommand{NEW\cs_to_str:N#1}{#2}{#3} + \cs_gset_eq:Nc#1{NEW\cs_to_str:N#1}} +% \end{macrocode} +% +% +% +% \subsubsection{Xparse reversing} +% The package \texttt{xparse} offers a convenient way for describing the profile of parameters +% of new commands (optional star, optional parameters, and so on) +% We provide converse commands, that recreates these arguments. +% For instance, the command |\section| is supposed to have an optional star (numbering or not), followed by an optional argument (title in the toc), followed by a mandatory argument (the title of the section). +% This would be defined with \texttt{xparse} as |\NewDocumentCommand\section{som}{...code...}|, +% where \texttt{som} means star-optional-mandatory. +% Imagine you want to overload this command. The command |\XParseArgs| is meant for that. +% One first stores the old command |\section| as |\oldsection|: +%\begin{verbatim} +% \let\oldsection\section +%\end{verbatim} +% and then redefine it, calling in the code the old version: +% \begin{verbatim} +% \RenewDocumentCommand\section{som}{% +% <pre-code>% +% \XparseArgs\oldsection{som}{#1}{#2}{#3} +% <post-code>} +% \end{verbatim} +% (please refer to \texttt{xparse} documentation for knowing how to use the arguments +% in the pre- and post-code) +% +% The command |\ExpXparseArgs| is the expandable variant of it (I was unable to produce +% a version that would work in both situations !). +% +% For parameter types treated so far are: +% \begin{compactdesc} +% \item[i]= ignore +% \item[m]= mandatory +% \item[o]= optional (under square brackets) +% \item[s]= stars +% \end{compactdesc} +% \begin{macrocode} +\NewDocumentCommand\XparseArgs{mm} + {\kutils_reverting_args:Nn#1{#2}} +\DeclareExpandableDocumentCommand\ExpXparseArgs{mm} + {\kutils_exec_xreverting_args:Nn#1{#2}} +% \end{macrocode} +% \begin{macrocode} +\cs_new:Nn\kutils_xrevert_arg_s:n + { \IfBooleanTF{#1}{*}{}} +\cs_new:Nn\kutils_xrevert_arg_o:n + { \IfValueTF{#1}{[\exp_not:n{#1}]}{}} +\cs_new:Nn\kutils_xrevert_arg_m:n + { {\exp_not:n{#1}} } +\cs_new:Nn\kutils_xrevert_arg_i:n + { } +% \end{macrocode} +% \begin{macrocode} +\cs_new:Nn\kutils_reverting_args:Nn{ + \use:c{kutils_process_\tl_count:n{#2}:w} + #1{\kutils_exec_xreverting_args:n{#2}}} +% \end{macrocode} +% \begin{macrocode} +\cs_new:Nn\kutils_exec_xreverting_args:n{ + \tl_if_empty:nTF{#1}{} + {\kutils_exec_xreverting_args_internal:w#1\kutils_end:}} +\cs_new:Nn\kutils_exec_xreverting_args:Nn{ + \exp_not:N#1 + \tl_if_empty:nTF{#2}{} + {\kutils_exec_xreverting_args_internal:w#2\kutils_end:}} +\cs_new:Npn\kutils_exec_xreverting_args_internal:w#1#2\kutils_end:#3 + { \use:c{kutils_xrevert_arg_#1:n}{#3} + \tl_if_empty:nTF{#2}{} + {\kutils_exec_xreverting_args_internal:w#2\kutils_end:}} +% \end{macrocode} +% The following internal commands |\cs_new:Nn\kutils_process_args:nn...| eat a token list `|\com|', +% then an expandable command token list |\proc|, that is totally expanded with as arguments the following arguments (the number of which is fixed from the signature). +% In the end, |\com| is prefixed. +% Hence |\kutils_process_args:nnnn\com\proc a b| +% completely expands |{\proc a b}| yielding some `result', and then executes |\com| followed by the `result'. +% E.g. if |\swap#1#2| is |{#2}{#1}|, then |\kutils_process_args:nnnn\com\swap| +% expands to the same as |\com| but with arguments reversed. +% \begin{macrocode} +\cs_new:Nn\kutils_process_args:nn + {#1} +\cs_new:Nn\kutils_process_args:nnn + {\use:nx{#1}{#2{#3}}} +\cs_new:Nn\kutils_process_args:nnnn + {\use:nx{#1}{#2{#3}{#4}}} +\cs_new:Nn\kutils_process_args:nnnnn + {\use:nx{#1}{#2{#3}{#4}{#5}}} +\cs_new:Nn\kutils_process_args:nnnnnn + {\use:nx{#1}{#2{#3}{#4}{#5}{#6}}} +\cs_new:Nn\kutils_process_args:nnnnnnn + {\use:nx{#1}{#2{#3}{#4}{#5}{#6}{#7}}} +\cs_new:Nn\kutils_process_args:nnnnnnnn + {\use:nx{#1}{#2{#3}{#4}{#5}{#6}{#7}{#8}}} +\cs_new:Nn\kutils_process_args:nnnnnnnnn + {\use:nx{#1}{#2{#3}{#4}{#5}{#6}{#7}{#8}{#9}}} +\exp_args:Nc\let{kutils_process_0:w}\kutils_process_args:nn +\exp_args:Nc\let{kutils_process_1:w}\kutils_process_args:nnn +\exp_args:Nc\let{kutils_process_2:w}\kutils_process_args:nnnn +\exp_args:Nc\let{kutils_process_3:w}\kutils_process_args:nnnnn +\exp_args:Nc\let{kutils_process_4:w}\kutils_process_args:nnnnnn +\exp_args:Nc\let{kutils_process_5:w}\kutils_process_args:nnnnnnn +\exp_args:Nc\let{kutils_process_6:w}\kutils_process_args:nnnnnnnn +\exp_args:Nc\let{kutils_process_7:w}\kutils_process_args:nnnnnnnnn +% \end{macrocode} +% +% \subsubsection{Obsolescence and vaulting} +% +% \begin{macrocode} +\msg_new:nnn{scope}{LaTeX~obsolete} + {The~command~'#1'~is~deprecated.~ + See~documentation~for~a~replacement.} + +\cs_new:Nn\kutils_secure_latex_command:N + {\cs_new_eq:cN{LaTeX\cs_to_str:N#1}#1} + +\cs_new:Nn\kutils_latex_to_vault:N + {\kutils_secure_latex_command:N#1 + \cs_undefine:N#1} + +\cs_new:Nn\kutils_latex_to_obsolete:N + {\kutils_latex_to_vault:N#1 + \cs_new:Npx#1{\exp_not:N\msg_error:nnn{scope}{LaTeX~obsolete}{\string #1}}} + +\cs_new:Nn\kutils_secure_latex_command:n + {\tl_map_function:nN{#1}\kutils_secure_latex_command:N} +\cs_new:Nn\kutils_latex_to_vault:n + {\tl_map_function:nN{#1}\kutils_latex_to_vault:N} +\cs_new:Nn\kutils_latex_to_obsolete:n + {\tl_map_function:nN{#1}\kutils_latex_to_obsolete:N} +% \end{macrocode} +% +% +% +% +% \Finale +\endinput + + + + |