summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx')
-rw-r--r--Master/texmf-dist/source/latex/knowledge/knowledge-utils.dtx1185
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
+
+
+
+