% \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 useful adding (newset).
%    \begin{macrocode}
\cs_new:Nn\tl_new:Nn
  {\tl_new:N#1
   \tl_gset:Nn#1{#2}}
\cs_new:Nn\tl_new_eq:NN
  {\tl_new:N#1
   \tl_gset_eq:NN#1#2}
\cs_new:Nn\bool_new_true:N
  {\bool_new:N#1
   \bool_gset_true:N#1}
\cs_new:Nn\bool_new_false:N
  {\bool_new:N#1
   \bool_gset_false:N#1}
\cs_new:Nn\bool_set_text:Nn
  {\use:c{bool_set_#2:N}#1}
\cs_generate_variant:Nn\tl_new:Nn{Nx,cn,cx}
\cs_generate_variant:Nn\tl_new_eq:NN{Nc,cN,cc}
\cs_generate_variant:Nn\bool_new_true:N{c}
\cs_generate_variant:Nn\bool_new_false:N{c}
\cs_generate_variant:Nn\bool_set_text:Nn{cn}
%    \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:Npn\tl_if_exist_ne:NTF#1
   {\tl_if_exist:NTF#1{\tl_if_empty:NTF#1\use_ii:nn\use_i:nn}\use_ii:nn}
\cs_new:Npn\tl_if_exist_ne:NT#1
   {\tl_if_exist:NTF#1{\tl_if_empty:NTF#1\use_none:n\use:n}\use_none:n}
\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_new:N\kaux_pretreatment_tl
\tl_gset:Nn\kaux_pretreatment_tl{}
\tl_new:N\kaux_posttreatment_tl
\tl_gset:Nn\kaux_posttreatment_tl{}
\tl_new:N\kaux_inittreatment_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_new:c{kaux_\cs_to_str:N#1-args_tl}
  \tl_gset:cn{kaux_\cs_to_str:N#1-args_tl}{#2}
  \tl_gput_right:Nn\kaux_command_list_tl{#1}
}
\NewDocumentCommand\KAuxCommand{mmm}
  {  \cs_if_exist:NTF #1 
       {}
       {\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_clear_new: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}}

\cs_new:Nn\kaux_current_location:{\kauxCurrentFile :\kauxCurrentLine :}
\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




