% \iffalse meta-comment
%
% Copyright (C) 2023-2025
% The LaTeX Project and any individual authors listed elsewhere
% in this file.
%
% This file is part of the LaTeX base system.
% -------------------------------------------
%
% It may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3c
% of this license or (at your option) any later version.
% The latest version of this license is in
%    https://www.latex-project.org/lppl.txt
% and version 1.3c or later is part of all distributions of LaTeX
% version 2008 or later.
%
% This file has the LPPL maintenance status "maintained".
%
% The list of all files belonging to the LaTeX base distribution is
% given in the file `manifest.txt'. See also `legal.txt' for additional
% information.
%
% The list of derived (unpacked) files belonging to the distribution
% and covered by LPPL is defined by the unpacking scripts (with
% extension .ins) which are part of the distribution.
%
% \fi
%
% \iffalse
%%% From File: lttagging.dtx
%
%<*driver>
% \fi
\ProvidesFile{lttagging.dtx}
             [2025/08/21 v1.0t LaTeX Kernel (tagging support)]
% \iffalse
\documentclass{l3doc}
\GetFileInfo{lttagging.dtx}
\title{\filename}
\date{\filedate}
\author{\LaTeX{} project}

\begin{document}
% \MaintainedByLaTeXTeam{latex}     % should be added again the moment
                                    % it is supported by l3doc
 \maketitle
 \DocInput{\filename}
\end{document}
%</driver>
% \fi
%
% \providecommand\env[1]{\texttt{#1}}
%
% \providecommand\hook[1]{\texttt{#1\DescribeHook[noprint]{#1}}}
% \providecommand\socket[1]{\texttt{#1\DescribeSocket[noprint]{#1}}}
% \providecommand\plug[1]{\texttt{#1\DescribePlug[noprint]{#1}}}
%
% \ProvideDocElement[printtype=\textit{socket},idxtype=socket,idxgroup=Sockets]{Socket}{socketdecl}
% \ProvideDocElement[printtype=\textit{hook},idxtype=hook,idxgroup=Hooks]{Hook}{hookdecl}
% \ProvideDocElement[printtype=\textit{plug},idxtype=plug,idxgroup=Plugs]{Plug}{plugdecl}
%
% \ProvideDocElement[printtype=\textit{tag socket},idxtype=tag socket,
%                    idxgroup=Tagging sockets]{TaggingSocket}{taggingsocketdecl}
% \ProvideDocElement[printtype=\textit{tag plug},idxtype=tag plug,
%                    idxgroup=Tagging Plugs]{TaggingPlug}{taggingplugdecl}
%
%
%    \begin{macrocode}
%<*2ekernel|latexrelease>
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
%
% \section{General support for tagged output}
%
%  \DescribeMacro\SuspendTagging
%  \DescribeMacro\ResumeTagging
%  \DescribeMacro\tag_suspend:n
%  \DescribeMacro\tag_resume:n

%
%  There are places in code where it is important to stop any tagging
%  activities, e.g., when we are doing trial typesetting that it is
%  done several times. In such a case one must tag only the final
%  version that is actually used, otherwise tagging structures are
%  generated which then do not end up in the PDF and confuse the
%  mechanism. For this we have two commands that can be used in
%  packages: \cs{SuspendTagging} and \cs{ResumeTagging} (with corresponding
%  L3 programming layer commands). They are
%  available as part of the \LaTeX{} kernel, so that they can be
%  safely used in packages whether or not tagging is requested. They
%  all take a string argument that is used for debugging to easily
%  identify why tagging was suspended or restarted, for example, in
%  \pkg{tabularx} you find \verb=\SuspendTagging{tabularx}=. By default
%  these four commands do nothing.
%
%  The argument is used literally (in \cs{typeout} messages) without any
%  expansion when  debugging is turned on and otherwise it is not used at all.
%  This means it is safe to write something like
%  \verb=\SuspendTagging{\foo}= or even \verb=\SuspendTagging\foo=
%  which means \LaTeX{} has to parse only
%  a single token instead of putting a string of characters into the
%  argument. This means a tiny speed improvement but with many such
%  debugging strings\ldots
%
%
%
%
% \DescribeMacro\NewTaggingSocket
% \DescribeMacro\NewTaggingSocketPlug
% \DescribeMacro\AssignTaggingSocketPlug
% Tagging sockets are implemented as normal sockets but with a name
% that starts with \texttt{tagsupport/} and some special conventions
% how their arguments (if any) are to be interpreted. This means in
% principle one can use the standard socket commands, which is what
% we started out with.
%
% However, providing dedicated declaration commands is more convenient
% and helps in keeping the interfaces clearer and simpler, e.g.,
% \cs{NewTaggingSocket} not only declares the socket but also
% automatially sets up necessary plugs and assigns a suitable default
% plug when tagging is not enabled.
%
% \cs{NewTaggingSocketPlug} and \cs{AssignTaggingSocketPlug} on the
% other hand are mainly syntactic sugar and do nothing more than
% adding the \texttt{tagsupport/} to the socket name behind the
% scenes.
%
%
%
%
% \DescribeMacro\UseTaggingSocket
% \DescribeMacro\tag_socket_use:n
% \DescribeMacro\tag_socket_use:nn
% \DescribeMacro\tag_socket_use:nnn
% Given that we sometimes have to suspend tagging, it would be fairly
% inefficient to put different plugs into these sockets whenever that
% happens. We therefore offer \cs{UseTaggingSocket} which is like
% \cs{UseSocket} except that is expects a socket starting with
% \texttt{tagsupport/} but the socket name is specified without
% this prefix, i.e.,
% \begin{quote}
%   \verb=\UseTaggingSocket{foo}=      $\to$
%   \verb=\UseSocket{tagsupport/foo}=
% \end{quote}.
%
% Beside being slightly shorter, the big advantage is that this way
% we can change \cs{UseTaggingSocket} to do nothing by switching a boolean
% instead of changing the plugs of the tagging support sockets back and forth.
%
% Usually, these sockets have (beside the default plug defined for every socket)
% one additional plug defined and directly assigned. This plug is used when
% tagging is active.
% There may be more plugs, e.g., tagging with special debugging or special behavior
% depending on the class or PDF version etc., but right now it is usually just on or off.
%
% When tagging is suspended they all have the same predefined behavior:
% The sockets with zero arguments do nothing. The sockets with one argument
% gobble their argument. The sockets with two arguments
% will drop their first argument and pass the second unchanged.
%
% It is possible to use the tagging support sockets with
% \cs{UseSocket} directly, but in this case the socket remains active
% if \cs{SuspendTagging} is in force. There may be reasons for doing
% that but in general we expect to always use \cs{UseTaggingSocket}.
%
% \DescribeMacro\UseExpandableTaggingSocket
% \DescribeMacro\tag_socket_use_expandable:n
%  For special cases like in some \cs{halign} contexts we need a fully expandable
%  version of the command. For these cases, \cs{UseExpandableTaggingSocket} can be
%  used. To allow being expandable, it does not output any debugging information
%  if \cs{DebugSocketsOn} is in effect and therefore should be avoided whenever possible.
%
%  The L3 programming layer versions \cs{tag_socket_use_expandable:n},
%  \cs{tag_socket_use:n}, \cs{tag_socket_use:nn}, and \cs{tag_socket_use:nnn}
%  are slightly more efficient than
%  \cs{UseTaggingSocket} because they do not have to determine how
%  many arguments the socket takes when disabling it.
%
% \DescribeMacro\MathCollectTrue
% \DescribeMacro\MathCollectFalse
% The tagging of math has to collect/grab the math first. This is not wanted
% for all uses of \verb+$+. These command allow to control the behavior of the
% math shift token. Without the  math tagging code they do nothing. Their behavior
% with the math tagging code is documented in latex-lab-math.pdf 
%  
%
% \DescribeMacro\MathMLintent
% \DescribeMacro\MathMLarg
% \changes{v1.0r}{2025/08/23}{MathML intent macros added}
% These two commands take two arguments. The first argument is the value of the
% \verb|intent| or \verb|arg| attribute to be added to the MathML generated by
% the term in the second argument.
% By default the commands are no-op and discard the first argument and expand to
% the second. If \pkg{luamml} is loaded via the math tagging code, then these commands
% are redefined. They could also potentially be used by other \TeX{} to MathML convertors
% to control the generated MathML.
%
%  \DescribeMacro\NewStructureName
%  \DescribeMacro\UseStructureName
%  \DescribeMacro\AssignStructureRole
%  Structure elements in a document can use as tag a name from the standard PDF namespaces 
%  like \verb|Sect|, \verb|H1| or \verb|Figure| but they can also use new names 
%  (which then must be rolemapped to a standard name). The second option is useful for three reasons:
%  \begin{itemize}
%  \item It looks nicer, if, e.g., a bible uses tag names like \texttt{Testament} or 
%  \texttt{Chapter} or \texttt{Book} instead of \texttt{Sect}.
%  \item It is possible to formulate additional constraint on such structures in a Schema
%  and thus ensure that there is no \texttt{Testament} inside a \texttt{Book},
%  something that can not be done if \texttt{Sect} is used everywhere.
%  \item We can provide a uniform LaTeX set of names for tags.
%  \end{itemize}
%  
%  To make it possible to adapt the tag names of a structure in document, the tag name
%  should be stored in a command. These three commands offer an interface to declare,
%  use and reassign such symbolic structure names. \verb+\NewStructureName+
%  takes one argument and 
%  declares the internal command, initially its value is \texttt{NonStruct}. 
%  The expandable command \verb+\UseStructureName+ takes one argument and allows to use
%  the stored value. \verb+\AssignStructureRole+ takes two
%  arguments. The first is a symbolic structure names, the second a role which 
%  should be a simply string allowed as a tag name. 
%  When the tagging code is loaded \verb+\AssignStructureRole+ is redefined
%  to setup the rolemapping, see the description in \texttt{latex-lab-namespace.dtx}. 
%  There is also a description of
%  the naming scheme and a list of the already predeclared names.
%  
%   
%  
% \MaybeStop{}
% \section{Implementation}
%
%
%
%  \begin{macro}{\tag_suspend:n,\tag_resume:n,\SuspendTagging,\ResumeTagging}
%
%    In the kernel, these commands get dummy definitions so that
%    they can be used without harm in packages. The real definition is
%    used when tagging gets enabled.
%    \begin{macrocode}
\cs_new_eq:NN \tag_suspend:n \use_none:n
\cs_new_eq:NN \tag_resume:n  \use_none:n
\cs_new_protected:Npn \SuspendTagging #1 { \tag_suspend:n {#1} }
\cs_new_protected:Npn \ResumeTagging #1  { \tag_resume:n {#1} }
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%  \begin{macro}{\NewTaggingSocket}
%    Initialize a new tagging socket and assign it a suitable plug.
% \changes{v1.0o}{2025/02/26}{Initialize tagging sockets with 1 or 2 arguments}
%    \begin{macrocode}
\cs_new_protected:Npn \NewTaggingSocket #1 #2 {
  \socket_new:nn { tagsupport / #1 } { #2 }
  \int_case:nnF
      { #2 }
         {
           0 \prg_do_nothing:
           1 { \socket_assign_plug:nn { tagsupport /  #1 } { noop } }
%    \end{macrocode}
%    Tagging sockets with two arguments use a special \texttt{transparent} plug that
%    just passes the second argument. Its already assigned so we only
%    have to alter it.
%    \begin{macrocode}
           2 { \socket_new_plug:nnn { tagsupport / #1 } { transparent }
                                    { ##2 }
               \socket_assign_plug:nn { tagsupport /  #1 } { transparent } }
         }
%    \end{macrocode}
%
%    \begin{macrocode}
         \ERRORnewtaggingsocket  % that should get a proper error message
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\NewTaggingSocketPlug,\AssignTaggingSocketPlug}
%    
% \changes{v1.0o}{2025/02/26}{Macro added}
%    \begin{macrocode}
\cs_new_protected:Npn \NewTaggingSocketPlug #1 {
  \NewSocketPlug { tagsupport/ #1 }
}
\cs_new_protected:Npn \AssignTaggingSocketPlug #1 {
  \AssignSocketPlug { tagsupport/ #1 }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\tag_socket_use:n,
%                \tag_socket_use:nn,
%                \tag_socket_use:nnn,
%                \tag_socket_use_expandable:n,
%                \UseTaggingSocket,
%                \UseExpandableTaggingSocket,
%               }
%    Again this is not the final definition for the kernel; it is just
%    a version to get going while some parts of the kernel support are
%    still missing.
% \changes{v1.0l}{2024/11/21}{Define \cs{tag_if_active:TF} conditionals here (github/1558)}
%    \begin{macrocode}
\prg_new_conditional:Npnn \tag_if_active: { p , T , TF, F }
     { \prg_return_false: }
%    \end{macrocode}
%    Dummy definitions in the kernel.
%    These definitions will get updated in \pkg{tagpdf}.
%    The default in the kernel is simply to get rid of the first argument, while
%    the second argument is preserved if present:
% \changes{v1.0k}{2024/10/21}{Changed behavior of two argument tagging sockets when disabled.}
% \changes{v1.0k}{2024/10/21}{Added expandable variants}
%    \begin{macrocode}
\cs_new:Npn \tag_socket_use_expandable:n #1 { }
\cs_new_protected:Npn \tag_socket_use:n #1 { }
\cs_new_protected:Npn \tag_socket_use:nn #1#2 { }
\cs_new_protected:Npn \tag_socket_use:nnn #1#2#3 { #3 }
\cs_new_protected:Npn \UseTaggingSocket #1 {
  \int_case:nnF
      { \int_use:c { c__socket_tagsupport/#1_args_int } }
         {
           0 \prg_do_nothing:
           1 \use_none:n
           2 \use_ii:nn
%    \end{macrocode}
%    We do not expect tagging sockets with more than one or two
%    arguments, so for now we only provide those.
%    \begin{macrocode}
         }
         \ERRORusetaggingsocket  % that should get a proper error message
}
%    \end{macrocode}
%    The same as an expandable command:
%    \begin{macrocode}
\cs_new:Npn \UseExpandableTaggingSocket #1 {
  \int_case:nnF
      { \int_use:c { c__socket_tagsupport/#1_args_int } }
         {
           0 \prg_do_nothing:
           1 \use_none:n
           2 \use_ii:nn
         }
         \ERRORusetaggingsocket  % that should get a proper error message
}
%    \end{macrocode}
%
%  \end{macro}
%
% \subsection{Math collection}
% The documentation is in latex-lab-math.
% 
% \begin{macro}{\MathCollectTrue,\MathCollectFalse}
%    \begin{macrocode}
\cs_new_protected:Npn\MathCollectTrue{}
\cs_new_protected:Npn\MathCollectFalse{}
%    \end{macrocode}
% \end{macro}
% 
% \subsection{Tagging sockets}
% This collects tagging sockets that should be generally available
% so that they can also be used even if the tagging code is not loaded.
%
% \subsection{Generic sockets}
% These sockets are used in various places and should not be reassigned globally.
% 
% \begin{taggingsocketdecl}{mc}
% At first a generic socket to surround content with the mc-commands. The first 
% argument can be used to pass options like \texttt{artifact}
%    \begin{macrocode}
\NewTaggingSocket{mc}{2}
\NewTaggingSocketPlug{mc}{kernel}
  {
    \tag_mc_begin:n {#1}
      #2
    \tag_mc_end:
  }
\AssignTaggingSocketPlug{mc}{kernel}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{struct-mc}
% A socket to surround content with a structure and an mc-command. With the first
% argument the tag and other options can be set.
%    \begin{macrocode}
\NewTaggingSocket{struct-mc}{2}
\NewTaggingSocketPlug{struct-mc}{kernel}
  {
    \tag_struct_begin:n{#1}
      \tag_mc_begin:n {}
          #2
      \tag_mc_end:
    \tag_struct_end:
  }
\AssignTaggingSocketPlug{struct-mc}{kernel}  
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \subsubsection{Tagging support for paragraph setup}
%
% Paragraphs are tagged through the code in the para/hooks. This code is sometimes
% adjusted, e.g. to produce a \enquote{flattened} paragraph or to use a different tag.
% Sockets related to such code parts are collected here.
%
%  \begin{macro}{\l__tag_block_flattened_level_int}
%    The block code needs to know if they are nested blockenvs inside
%    a flattened environment. For this it uses a counter. Inside some contexts,
%    e.g. at the begin of a minipage or a footnote this counter must be reset.
%    We therefore define the counter here so that we can use it in the following
%    socket.
%    \begin{macrocode}
\int_new:N \l__tag_block_flattened_level_int
%    \end{macrocode}
%  \end{macro}
%
%\begin{taggingsocketdecl}{para/on,para/off}
% These sockets allow paragraph tagging to be enabled/disabled.
%    \begin{macrocode}
\NewTaggingSocket{para/on}{0}
\NewTaggingSocketPlug{para/on}{kernel}{\bool_set_true:N \l__tag_para_bool}
\NewTaggingSocket{para/off}{0}
\NewTaggingSocketPlug{para/off}{kernel}{\bool_set_false:N \l__tag_para_bool}
\AssignTaggingSocketPlug{para/on}{kernel}
\AssignTaggingSocketPlug{para/off}{kernel}
%    \end{macrocode}
%\end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{para/restore}
% This socket restores the para related settings to their default. It
% should be used in places where ``normal'' paragraph tagging must be ensured, for example
% at the begin of a footnote.
%    \begin{macrocode}
\NewTaggingSocket{para/restore}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingplugdecl}{default}
% \changes{v1.0i}{2024/10/10}{Restore also paratagging (tagging/723)}
% \changes{v1.0t}{2025/08/21}{Use symbolic name instead of text-unit}
%    \begin{macrocode}
\NewTaggingSocketPlug{para/restore}{default}
 {
   \tl_set:Nn    \l__tag_para_main_tag_tl {\UseStructureName{para/semantic}}
   \tl_set_eq:NN \l__tag_para_tag_tl\l__tag_para_tag_default_tl
   \bool_set_false:N\l__tag_para_flattened_bool
   \int_zero:N   \l__tag_block_flattened_level_int
   \bool_set_true:N \l__tag_para_bool
 }
\AssignTaggingSocketPlug{para/restore}{default}
%    \end{macrocode}
% \end{taggingplugdecl}
%
% \begin{taggingsocketdecl}{para/begin,para/end}
% These sockets were previously defined in tagpdf. 
% There are the main sockets to handle the paragraph tagging when it is active 
% (i.e., when para/on or para/restore was executed earlier).
%    \begin{macrocode}
\NewTaggingSocket{para/begin}{0}
\NewTaggingSocket{para/end}{0}
%    \end{macrocode}
% Until tagpdf is updated we need to provide the plain and block plugs
%    \begin{macrocode}
\NewTaggingSocketPlug{para/begin}{plain}{}
\NewTaggingSocketPlug{para/end}{plain}{}
\NewTaggingSocketPlug{para/begin}{block}{}
\NewTaggingSocketPlug{para/end}{block}{}

%    \end{macrocode}

% \end{taggingsocketdecl}
% 
% \begin{taggingsocketdecl}{para/semantic/begin,para/semantic/end}
% These sockets handle the \UseStructureName{para/semantic} begin and end structure.
% These are stored in sockets of their own to be able to disable
% them globally.
% 
%    \begin{macrocode}
\NewTaggingSocket{para/semantic/begin}{1}
\NewTaggingSocket{para/semantic/end}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \begin{taggingplugdecl}{kernel (para/semantic/begin)}
% This tagging socket adds a \UseStructureName{para/semantic} structure.
% The argument allows to add additional commands like
% the command that puts the structure number of this command
% on a stack.
%    \begin{macrocode}
\tl_new:N \l__tag_para_attr_class_tl
\NewTaggingSocketPlug{para/semantic/begin}{kernel}
 {
    \__tag_gincr_para_main_begin_int:
    \tag_struct_begin:n
      {
        tag=\l__tag_para_main_tag_tl,
        attribute-class=\l__tag_para_main_attr_class_tl,
      }
    #1
 }
%    \end{macrocode}
% \end{taggingplugdecl}
% 
% \begin{taggingplugdecl}{kernel (para/semantic/end)}
% This socket should be used if a \UseStructureName{para/semantic}-structure  is closed.
% The argument allows e.g. to add debug info.
%    \begin{macrocode}
\NewTaggingSocketPlug{para/semantic/end}{kernel}
 {
   #1
   \__tag_gincr_para_main_end_int:
   \tag_struct_end:
 }
%    \end{macrocode}
% \end{taggingplugdecl}
% And now we assign these plugs:
%    \begin{macrocode}
\AssignTaggingSocketPlug{para/semantic/begin}{kernel}
\AssignTaggingSocketPlug{para/semantic/end}{kernel}
%    \end{macrocode}
% 
% \begin{taggingplugdecl}{kernel (para/begin)}
% This plug is similar to the block socket currently defined
% in tagpdf and should overwrite it. 
%    \begin{macrocode}
\NewTaggingSocketPlug{para/begin}{kernel}
  {
    \bool_if:NT \l__tag_para_bool
      {
        \legacy_if:nF { @inlabel }
          {
            \__tag_check_typeout_v:n
              {==>~ @endpe = \legacy_if:nTF { @endpe }{true}{false} \on@line }
            \legacy_if:nF { @endpe }
             {
               \bool_if:NF \l__tag_para_flattened_bool
                  {
                    \UseTaggingSocket{para/semantic/begin}
                     { \__tag_para_main_store_struct: }
                  }
              }
             \__tag_gincr_para_begin_int:
             \__tag_check_typeout_v:n {==>~increment~ P \on@line }
             \tag_struct_begin:n
               {
                 tag=\l__tag_para_tag_tl
                 ,attribute-class=\l__tag_para_attr_class_tl
               }
             \__tag_check_para_begin_show:nn {green}{\PARALABEL}
             \tag_mc_begin:n {}
       }
     }
  }
%    \end{macrocode}
% \end{taggingplugdecl}
% \begin{taggingplugdecl}{kernel (para/end)}
% This socket is used at the end of paragraphs.
%    \begin{macrocode}
\NewTaggingSocketPlug{para/end}{kernel}
  {
    \bool_if:NT \l__tag_para_bool
      {
        \__tag_gincr_para_end_int:
        \__tag_check_typeout_v:n {==>~increment~ /P \on@line }
        \tag_mc_end:
        \__tag_check_para_end_show:nn {red}{}
        \tag_struct_end:
        \bool_if:NF \l__tag_para_flattened_bool
         {
           \UseTaggingSocket{para/semantic/end}{}
         }
      }
  }
%    \end{macrocode}
% \end{taggingplugdecl}
% As tagpdf is currently assigning the sockets after the block code we assign
% if even later (for now):
%    \begin{macrocode}
\AddToHook{package/latex-lab-testphase-sec/after}
  {
    \AssignTaggingSocketPlug{para/begin}{kernel}
    \AssignTaggingSocketPlug{para/end}{kernel}
  }
%    \end{macrocode}

% \subsubsection{Tagging socket for targets}

% \begin{taggingsocketdecl}{refstepcounter}
% When tagging is active we want to track the current structure number
% when targets are set. This will be mostly used in \cs{refstepcounter}
% but also if targets are set manually.
%    \begin{macrocode}
\NewTaggingSocket{recordtarget}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingplugdecl}{kernel (recordtarget)}
%    \begin{macrocode}
%
\NewTaggingSocketPlug{recordtarget}{kernel}
  {
    \tl_if_blank:VF \@currentHref
    {
      \prop_gput:Nee
        \g__tag_struct_dest_num_prop
        {\@currentHref}
        {\tag_get:n{struct_num}}
    }
  }
\AssignTaggingSocketPlug{recordtarget}{kernel}
\ExplSyntaxOff
%    \end{macrocode}
% \end{taggingplugdecl}
%
% \subsubsection{Tagging Sockets for lists and blocks}
% \changes{v1.0s}{2025/08/03}{Add sockets for block code}
% \begin{taggingsocketdecl}{block/list/label}
%  A tagging socket around the label in a list. 
%    \begin{macrocode}
\NewTaggingSocket{block/list/label}{2}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{block/recipe}
%  A tagging socket to set the tagging recipe. 
%    \begin{macrocode}
\NewTaggingSocket{block/recipe}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \subsubsection{Tagging sockets for toc}

% \begin{taggingsocketdecl}{toc/contentsline/before,
%  toc/contentsline/after}
%  Tagging sockets at the begin and end of contentsline.
%  They receive \emph{all} contentsline arguments as one argument
%  in four brace groups. The socket code should then use the parts it needs.
%    \begin{macrocode}
\NewTaggingSocket{toc/contentsline/before}{1}
\NewTaggingSocket{toc/contentsline/after}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{toc/starttoc/before,
%                    toc/starttoc/after}
% Tagging sockets for the begin and end of start of \cs{@starttoc}.
% They take one argument, the extension.
%    \begin{macrocode}
\NewTaggingSocket{toc/starttoc/before}{1}
\NewTaggingSocket{toc/starttoc/after}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{toc/leaders/before,
%                    toc/leaders/after}
% Tagging sockets to make the dot leaders an artifact.
% They do not take an argument.
%    \begin{macrocode}
\NewTaggingSocket{toc/leaders/before}{0}
\NewTaggingSocket{toc/leaders/after}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \subsubsection{Tagging support for marginpar}
% 
% \begin{taggingsocketdecl}{marginpar/begin,marginpar/end}
% \changes{v1.0n}{2025/02/21}{move marginpar sockets}
%    \begin{macrocode}
\NewTaggingSocket{marginpar/begin}{0}
\NewTaggingSocket{marginpar/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}

%
% \subsubsection{Tagging support for table/tabular packages}
%
% The code uses a number of sockets to inject the tagging
% commands. These can be easily set to a noop-plug in case the
% automated tagging is not wanted.
%
% \begin{taggingsocketdecl}{tbl/cell/begin,
%                    tbl/cell/end,
%                    tbl/pcell/end,
%                    tbl/pcell/end,
%                    tbl/row/begin,
%                    tbl/row/end,
%                   }
%     At first sockets for the begin and end of cells and table rows:
%    \begin{macrocode}
\NewTaggingSocket{tbl/cell/begin}{0}
\NewTaggingSocket{tbl/cell/end}{0}
%    \end{macrocode}
%
%    \begin{macrocode}
\NewTaggingSocket{tbl/row/begin}{0}
\NewTaggingSocket{tbl/row/end}{0}
%    \end{macrocode}
%    Multi-line cells have their own sockets (as they start out in
%    vertical mode and need different treatment).
%    \begin{macrocode}
\NewTaggingSocket{tbl/pcell/begin}{0}
\NewTaggingSocket{tbl/pcell/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{tbl/init}
%    This socket should be at the begin of the table, inside a group.
%    It is used for settings such as disabling para-tagging inside the
%    table.  This socket
%    can perhaps be merged later into the begin-sockets.
%    \begin{macrocode}
\NewTaggingSocket{tbl/init}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{tbl/init/celldata}
%    This socket is used in \cs{tbl_init_cell_data_for_table}, the command
%    that stores and initialize cell data to handle nested tables.
%    It can be used to restore similar tagging related values
%    \begin{macrocode}
\NewTaggingSocket{tbl/init/celldata}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{tbl/finalize}
%    To fine tune the structure (change cells to header cells, remove
%    unwanted structures, move a foot to the end, etc.). We also need a
%    socket that is executed at the end of the table but \emph{before}
%    all the variables are restored to the outer or default values.
%    The code in the socket can make assignments, but probably
%    shouldn't do typesetting and not write whatsits.
%    \begin{macrocode}
\NewTaggingSocket{tbl/finalize}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{tbl/restore/celldata}
%    This socket is used in \cs{tbl_restore_outer_cell_data:}, the command
%    that restores cell data when quitting a nested table. It can be used to restore
%    similar tagging related values
%    \begin{macrocode}
\NewTaggingSocket{tbl/restore/celldata}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}

% \begin{taggingsocketdecl}{tbl/colspan}
%    This socket is used to manage spanning cells, e.g., a
%    \cs{multicolumn}. It expects one argument (the number of cells
%    spanned) and if tagging is enabled set appropriate tag attributes
%    in the background. We probably need a similar socket for row
%    spans eventually.
%    \begin{macrocode}
\NewTaggingSocket{tbl/colspan}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
%


% \begin{taggingsocketdecl}{tbl/hmode/begin,
%                    tbl/hmode/end,
%                    tbl/vmode/begin,
%                    tbl/vmode/end
%                   }
%
%    These sockets are used in the begin and end code of environments,
%    to allow a fast enabling and disabling of the tagging. We
%    distinguish between tables that can be used inside paragraphs and
%    standalone tables such as \env{longtable} that are always in
%    vertical mode.
%    \begin{macrocode}
\NewTaggingSocket{tbl/hmode/begin}{0}
\NewTaggingSocket{tbl/hmode/end}{0}
\NewTaggingSocket{tbl/vmode/begin}{0}
\NewTaggingSocket{tbl/vmode/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
%
% \begin{taggingsocketdecl}{tbl/longtable/init,
%                    tbl/longtable/finalize}
%    \env{longtable} needs its own sockets to fine tune the structure.
%    Simply switching the plug in the previous socket interferes with
%    enabling/disabling the tagging.
%    \begin{macrocode}
\NewTaggingSocket{tbl/longtable/init}{0}
\NewTaggingSocket{tbl/longtable/finalize}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{tbl/longtable/head,
%                    tbl/longtable/foot}
%    Header and footer boxes need special handling because they are repeatedly
%    used.
%    \begin{macrocode}
\NewTaggingSocket{tbl/longtable/head}{0}
\NewTaggingSocket{tbl/longtable/foot}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
% \begin{taggingsocketdecl}{tbl/leaders/begin,
%                    tbl/leaders/end}
%    Sockets around leaders such as rules or dotted lines, that should
%    be tagged as artifacts, used, for example, in \cs{cline}.
% \changes{v1.0c}{2024/07/13}{Sockets for \cs{cline} leaders added (tagging/134)}
%    \begin{macrocode}
\NewTaggingSocket{tbl/leaders/begin}{0}
\NewTaggingSocket{tbl/leaders/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \subsubsection{Tagging Support for floats}
%
% \begin{taggingsocketdecl}{float/hmode/begin,
%                    float/hmode/end}
%  These sockets are used if the float is called in
%  hmode.
% \changes{v1.0h}{2024/09/13}{Sockets for floats added}
%    \begin{macrocode}
\NewTaggingSocket{float/hmode/begin}{0}
\NewTaggingSocket{float/hmode/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{float/begin,
%                    float/end}
%  These sockets start and stop the float structure.
%    \begin{macrocode}
\NewTaggingSocket{float/begin}{0}
\NewTaggingSocket{float/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
% \begin{taggingsocketdecl}{caption/begin,
%                    caption/end}
%  These sockets are used in \cs{@makecaption}.
%  They open and close the \texttt{Caption} structure.
%  Their default plugs assume that they are used in
%  vmode. The argument of the begin socket is
%  the structure number of the parent float. If it is
%  empty the current structure number is used.
%    \begin{macrocode}
\NewTaggingSocket{caption/begin}{1}
\NewTaggingSocket{caption/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{caption/label/begin,
%                    caption/label/end}
%  These sockets are used in \cs{@makecaption} around the
%  label. Their default plugs ensure that
%  the label is outside the paragraph and that
%  the rest of the caption uses flattened para mode. If the
%  caption is not in a hbox, the \texttt{para/begin}
%  socket should follow to properly start the paragraph.
%    \begin{macrocode}
\NewTaggingSocket{caption/label/begin}{0}
\NewTaggingSocket{caption/label/end}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
% \subsection{Tagging support for output routines}
%
% \changes{v1.0m}{2025/02/14}{Tagging support for output routines added}
%
% \begin{taggingsocketdecl}{build/page/header}
% \changes{v1.0m}{2025/02/14}{Tagging socket added}
% \begin{taggingsocketdecl}{build/page/footer}
% \changes{v1.0m}{2025/02/14}{Tagging socket added}
%    These sockets receive the formatted running header/footer in its
%    second argument (the first is not used) following the convention
%    of tagging sockets, i.e., only the second argument is processed
%    if tagging is not active.
%    \begin{macrocode}
\NewTaggingSocket{build/page/header}{2}
\NewTaggingSocket{build/page/footer}{2}
%    \end{macrocode}
% \end{taggingsocketdecl}
% \end{taggingsocketdecl}
%
%
%
% \begin{taggingsocketdecl}{build/column/outputbox}
% \changes{v1.0m}{2025/02/14}{Tagging socket added}
%    This socket is used to add any missing tagging structures to the
%    \cs{@outputbox} box, if necessary.
%    \begin{macrocode}
\NewTaggingSocket{build/column/outputbox}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
%
% \begin{taggingsocketdecl}{build/column/footins}
% \changes{v1.0m}{2025/02/14}{Tagging socket added}
%    This socket is used to add any missing tagging structures to the
%    \cs{footins} box, if necessary.
%    \begin{macrocode}
\NewTaggingSocket{build/column/footins}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
%
%
%
%
% \begin{taggingsocketdecl}{page@sofar}
%
%  This socket is declared and used in the \pkg{multicol} output routines.
%  Only listed for reference.
%    \begin{macrocode}
%\NewTaggingSocket{page@sofar}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \subsection{Tagging support for math}
%
% \subsubsection{General sockets}
%
% The following sockets are the main math sockets.
%
% \changes{v1.0n}{2025/02/19}{Moved math sockets into lttagging}
%    \begin{macrocode}
\NewTaggingSocket{math/inline/begin}{0}
\NewTaggingSocket{math/inline/end}{0}
\NewTaggingSocket{math/inline/formula/begin}{2}
\NewTaggingSocket{math/inline/formula/end}{0}
\NewTaggingSocket{math/display/begin}{0}
\NewTaggingSocket{math/display/end}{0}
\NewTaggingSocket{math/display/formula/begin}{2}
\NewTaggingSocket{math/display/formula/end}{0}
\NewTaggingSocket{math/display/tag/begin}{0}
\NewTaggingSocket{math/display/tag/end}{0}
%    \end{macrocode}
%
% \subsubsection{Sockets specific for luamml}
% \paragraph{Save sockets}
%  These sockets are wrappers around the \cs{luamml_save:...} commands.
%  They take an argument which should contain the argument of the save command.
%
% \begin{taggingsocketdecl}{math/luamml/save/nn}
%  The argument should contain the two arguments of the command.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/save/nn}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{math/luamml/save/nNn}
%  The argument should contain the three arguments of the command.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/save/nNn}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \paragraph{Socket to annotate}
% 
% \begin{taggingsocketdecl}{math/luamml/annotate/false}
%  These socket can be used for content that should be annotated
%  with \texttt{core=false}
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/annotate/false}{2}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \paragraph{Array sockets} These sockets will be used in \pkg{array} to
% add luamml support to the array environment.
%
% \begin{taggingsocketdecl}{math/luamml/array/save}
%
%  This socket will be used in \cs{endarray}. The plug is set by luamml.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/array/save}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{math/luamml/array/finalize}
%
%  This socket will be used in \cs{endarray}. The plug is set by luamml.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/array/finalize}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{math/luamml/array/initcol}
%  This socket will be used in \cs{@classz}. The plug is set by luamml.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/array/initcol}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
% \begin{taggingsocketdecl}{math/luamml/array/finalizecol}
%  This socket will be used in \cs{@classz}. The plug is set by luamml.
% The argument sets the type of the column.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/array/finalizecol}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \paragraph{Alignment environments}
% Multiline environments like \texttt{align}, \texttt{multline} or \texttt{gather}
% are tagged as \texttt{mtable}.
%
% \begin{taggingsocketdecl}{math/luamml/mtable/finalizecol}
% This sockets is used at the end of alignment cells and adds them to
% the row. The argument passes a type like \texttt{last} or \texttt{box}.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/finalizecol}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% 
% \begin{taggingsocketdecl}{math/luamml/mtable/finalize}
% This sockets is used at the end of alignment environment to finalize the
% mtable code. It should be used normally with \cs{UseExpandableTaggingSocket}.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/finalize}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{math/luamml/mtable/aligncol}
% This sockets is used in multline to add attributes
% describing the alignment to the left and right.
% It takes an argument, the alignment.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/aligncol}{1}
%    \end{macrocode}
% \end{taggingsocketdecl}

% 
% \begin{taggingsocketdecl}{math/luamml/mtable/innertable/save}
% This socket is used in \cs{endaligned} to save the table. It takes no argument.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/innertable/save}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{math/luamml/mtable/smallmatrix/save}
% This socket is used in \cs{endsmallmatrix} to save the table. It takes no argument.
% TODO: Check if this socket and the innertable socket can/should be merged into a more
% generic version.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/smallmatrix/save}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \begin{taggingsocketdecl}{math/luamml/mtable/innertable/finalize}
% This socket is used e.g. in \cs{endsmallmatrix} and \cs{gathered} to finalize the table. 
% It takes no argument.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/innertable/finalize}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \begin{taggingsocketdecl}{math/luamml/mtable/tag/save}
% This socket is used to save a tag for later use.
% has been save before.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/tag/save}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}

% \begin{taggingsocketdecl}{math/luamml/mtable/tag/set}
% This socket should be used when a tag is placed. It inserts a tag that
% has been save before.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/mtable/tag/set}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
% 
% \paragraph{mbox socket}
%
% \begin{taggingsocketdecl}{math/luamml/hbox}
%  This socket is used around \cs{hbox}
%  inside an \cs{mbox}, \cs{makebox} and \cs{text} and annotates
%  the content if the \cs{hbox} is used inside math.
%  The real plug is set by luamml but a default plug is defined
%  here so that the socket can also be used if luamml is not used.
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/hbox}{2}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
%
% \paragraph{math phantom sockets}
% \changes{1.0m}{2025-01-27}{add sockets for math phantom commands}
% \begin{taggingsocketdecl}{math/luamml/finph@nt}
%  This socket handles the annotation of \cs{finph@nt}
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/finph@nt}{2}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \begin{taggingsocketdecl}{math/luamml/finph@nt}
%  This socket handles the annotation of \cs{finsm@sh}
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/finsm@sh}{2}
%    \end{macrocode}
% \end{taggingsocketdecl}
% \paragraph{Artifact root sign}
%
% \begin{taggingsocketdecl}{math/luamml/artifact}
% Unicode characters like a root sign should be marked as artifacts
% to avoid duplication, e.g., in derivation if mathml
% structure elements are used that imply the meaning.
%
%    \begin{macrocode}
\NewTaggingSocket{math/luamml/artifact}{0}
%    \end{macrocode}
% \end{taggingsocketdecl}
%
% \subsection{MathML intent attributes}
% \begin{macro}{\MathMLintent,\MathMLarg}
% Stub definitions here to allow these commands to be used in packages
% whether or not tagging is enabled.
%    \begin{macrocode}
\ExplSyntaxOn
\cs_new_protected:Npn\MathMLintent#1#2{#2}
\cs_new_protected:Npn\MathMLarg#1#2{#2}
\ExplSyntaxOff
%    \end{macrocode}
% \end{macro}
%
% \subsection{Symbolic structure names}
% \begin{macro}{\NewStructureName,\UseStructureName,\AssignStructureRole}
% Stub definitions here to allow these commands to be used in packages
% whether or not the tagging support code is loaded.
%    \begin{macrocode}
%<@@=tag>
\ExplSyntaxOn
\cs_new_protected:Npn\NewStructureName#1
 {
   \tl_new:c  {l_@@_name_#1_tl}
   \tl_set:cn {l_@@_name_#1_tl}{NonStruct}           
 }
\cs_new:Npn\UseStructureName#1
 {
   \cs:w l_@@_name_#1_tl\cs_end:
 }
\cs_new_protected:Npn\AssignStructureRole#1#2
 {
   \tl_set:cn { l_@@_name_#1_tl }{#2}
 }
\ExplSyntaxOff
%    \end{macrocode}
% \end{macro}
%
% \section{For lttab.dtx parked here for now}
%
%
%    \begin{macrocode}
%<@@=tbl>
\ExplSyntaxOn
%    \end{macrocode}
%
%
% \subsection{Variables for row, column and span counting}
%
%  This part needs a decision on names for various integer registers
%  as well as a decision if those should be also made available for
%  \LaTeXe{}-style packages in form of 2e names and or as
%  non-internals for the L3 programming layer.
%
%  At the moment they are all internal but this probably has to change.
%
%  \begin{macro}{
%     \g_@@_col_int,
%     \g_@@_row_int,
%     \g_@@_span_tl,
%     \g_@@_table_cols_tl}
%
%    \cs{g_@@_row_int} holds the current row number in the table. The
%    value \texttt{0} means we haven't yet processed the table
%    preamble (or in case of longtable are just in front of the next
%    chunk to be processed). It is incremented by every \cs{cr}
%    including the one ending the table preamble.
%
%    TODO: due to the gymnastics needed inside the longtable code the
%    row counter is directly exposed there rather than hidden by
%    interfaces. This needs changing when it is decided how to manage
%    these counters.
%
%    \cs{g_@@_col_int} holds the current column number. The value
%    \texttt{0} means we have not yet started the table or just finished a table row
%    (with \verb=\\= typically); any other positive value means we
%    are currently typesetting a cell in that column in some row
%    (denoted by the \cs{g_@@_row_int}).
%
%    In a \cs{multicolumn} it holds the column number of the first
%    spanned column and \cs{g_@@_span_tl} the info how many cells are
%    spanned.
%
%    \cs{g_@@_span_tl} is normally \texttt{1} except in a
%    \cs{multicolumn} cell.
%    \begin{macrocode}
\int_new:N \g_@@_col_int
\int_new:N \g_@@_row_int
\tl_new:N  \g_@@_span_tl
\tl_new:N  \g_@@_table_cols_tl

\tl_gset:Nn \g_@@_span_tl {1}
\tl_gset:Nn \g_@@_table_cols_tl {0}  % indicates outer level
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\l_@@_saved_col_tl,\l_@@_saved_row_tl,
%                \l_@@_saved_span_tl,\l_@@_saved_table_cols_tl}
%
%    Saving the outer values if we are nesting tables is necessary (as
%    the above variables are globally altered). For this we always use
%    token lists because they don't change and we do not need to blow
%    additional integer registers.
%    \begin{macrocode}
\tl_new:N \l_@@_saved_col_tl
\tl_new:N \l_@@_saved_row_tl
\tl_new:N \l_@@_saved_span_tl
\tl_new:N \l_@@_saved_table_cols_tl

\tl_set:Nn \l_@@_saved_col_tl{0}
\tl_set:Nn \l_@@_saved_row_tl{0}
\tl_set:Nn \l_@@_saved_span_tl{1}
\tl_set:Nn \l_@@_saved_table_cols_tl{0}  % indicates outer level
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\g_@@_missingcells_int}
% This will contain the number of missing cells in a row:
%    \begin{macrocode}
\int_new:N \g_@@_missing_cells_int
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
% \subsection{Tracing/debugging}
%
%  \begin{macro}{\DebugTablesOn,\DebugTablesOff}
%
%    \begin{macrocode}
\def\DebugTablesOn{
  \cs_set_eq:NN \@@_trace:n \typeout
}
\def\DebugTablesOff{
  \cs_set_eq:NN \@@_trace:n \use_none:n
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new_eq:NN \@@_trace:n \use_none:n
%    \end{macrocode}
%  \end{macro}
%
%
%
% \subsection{Interface commands}
%
% All interface commands for the cell number determination have to be
% public on some level because they are needed in other packages as
%  well, e.g., longtable. We may or may not also want to provide 2e
%  style names for them.
%
%  \begin{macro}{\tbl_update_cell_data:}
%    Updating cell data in columns after the first means we have to
%    increment the \cs{g_@@_col_int} by the span count of the previous
%    cell (in case it was a \cs{multicolumn}) and then reset the
%    \cs{g_@@_span_tl} to one (as the default).
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_update_cell_data: {
        \int_gadd:Nn \g_@@_col_int { \g_@@_span_tl }
        \tl_gset:Nn  \g_@@_span_tl {1}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\tbl_count_table_cols:}
%    Current implementation of \cs{@mkpream} uses the scratch counter
%    \cs{count@} to keep track of the number of toks registers it needs
%    (2 per column), but this can't be used as it counts also
%    insertions made with \verb+!{}+ and \verb+@{}+.
%    So similar as does longtable for \cs{LT@cols} we count the
%    numbers of ampersands instead.
%    \begin{macrocode}
\cs_new:Npn \tbl_count_table_cols:  {
  \seq_set_split:NnV\l_@@_tmpa_seq {&}\@preamble
  \tl_gset:Ne \g_@@_table_cols_tl { \seq_count:N \l_@@_tmpa_seq }
  \@@_trace:n { ==>~ Table~ has~ \g_@@_table_cols_tl \space columns }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\l_@@_tmpa_seq}
%
%    \begin{macrocode}
\seq_new:N \l_@@_tmpa_seq
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\tbl_count_missing_cells:n}
%
%    We might have the situation that some table package has not
%    implemented the \cs{tbl_count_table_cols:} in which case
%    \cs{g_@@_table_cols_tl} would always be zero and we would get an
%    error below when we try to determine the missing cells, so bypass
%    that calculation if we aren't doing tagging (there the packages
%    should have the proper code added). Recall that this is code,
%    that is called by \verb=\\= and an old table package might rely
%    on whatever the \LaTeX{} kernel offers here.
%    \begin{macrocode}
\cs_new:Npn \tbl_count_missing_cells:n #1 {
  \tag_if_active:T {
    \int_compare:nNnT \g_@@_col_int > 0
      {
        \int_gset:Nn \g_@@_missing_cells_int
            {
              \g_@@_table_cols_tl
            - \g_@@_col_int
            - \g_@@_span_tl
            + 1
            }
        \int_compare:nNnT \g_@@_missing_cells_int < 0 \ERRORmissingcells % should not happen
        \@@_trace:n{==>~
          (#1)~
          This~ row~ needs~
          \int_use:N \g_@@_missing_cells_int \space
          additional~ cell(s)
        }
      }
  }
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\tbl_init_cell_data_for_table:}
%
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_init_cell_data_for_table: {
  \tl_set:No \l_@@_saved_col_tl {\int_use:N \g_@@_col_int }
  \tl_set:No \l_@@_saved_row_tl {\int_use:N \g_@@_row_int }
  \tl_set_eq:NN \l_@@_saved_table_cols_tl  \g_@@_table_cols_tl
  \tl_set_eq:NN \l_@@_saved_span_tl  \g_@@_span_tl
%
  \@@_trace:n { ==>~ saved~cell~data:~
                \l_@@_saved_row_tl,
                \l_@@_saved_col_tl,
                \l_@@_saved_span_tl \space
                (
                \int_compare:nNnTF \l_@@_saved_table_cols_tl = 0
                    { outer~ level }
                    { max:~ \l_@@_saved_table_cols_tl }
                )
          }
%    \end{macrocode}
% Tagging has to initialize cell data too.
%    \begin{macrocode}
  \UseTaggingSocket{tbl/init/celldata}
%    \end{macrocode}
%    These are the initial values when starting a table:
%    \begin{macrocode}
  \int_gzero:N \g_@@_row_int
  \int_gzero:N \g_@@_col_int
  \tl_gset:Nn  \g_@@_span_tl {1}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%  \begin{macro}{\tbl_update_cell_data_for_next_row:}
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_update_cell_data_for_next_row: {
      \int_gincr:N \g_@@_row_int          % this row about to start
      \int_gzero:N \g_@@_col_int          % we are before first col
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\tbl_init_cell_data_for_row:}
%    If we start processing a cell in the first column  we set
%    \cs{g_@@_col_int} to \texttt{1} as we are no longer "at" but "in"
%    the first column. We also set \cs{g_@@_span_tl} to its default
%    value (not spanning cells).
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_init_cell_data_for_row: {
        \int_gset:Nn \g_@@_col_int {1}
        \tl_gset:Nn  \g_@@_span_tl {1}
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\tbl_if_row_was_started:T,
%                \tbl_if_row_was_started:TF}
%    We use \cs{g_@@_col_int} equal zero to indicate that we are just
%    after a TR (i.e.n between rows or at the very beginning of the
%    table). Using the row
%    count is not so good as longtable may split the table in chunks.
%
%    These conditionals have to be expandable (i.e., unprotected) as
%    they are sometimes executed when \TeX{} is scanning inside a table.
%    \begin{macrocode}
\cs_new:Npn \tbl_if_row_was_started:T {
      \int_compare:nNnT \g_@@_col_int > 0
}
\cs_new:Npn \tbl_if_row_was_started:TF {
      \int_compare:nNnTF \g_@@_col_int > 0
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\tbl_gzero_row_count:,\tbl_gincr_row_count:,\tbl_gdecr_row_count:}
%    This here is basically a temporary interface. What it will be in
%    the end depends on what we decide concerning exposing row and
%    column counters, if they stay internal we need something like
%    this here (perhaps using \texttt{gincr} etc, or perhaps some
%    other names in the first place).
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_gzero_row_count: {
  \int_gzero:N \g_@@_row_int
}
\cs_new_protected:Npn \tbl_gincr_row_count: {
  \int_gincr:N \g_@@_row_int
}
\cs_new_protected:Npn \tbl_gdecr_row_count: {
  \int_gdecr:N \g_@@_row_int
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\tbl_inbetween_rows:}
%    Again name is not really brilliant so far.
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_inbetween_rows: {
       \int_gzero:N  \g_@@_col_int
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%
%  \begin{macro}{\tbl_restore_outer_cell_data:}
%
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_restore_outer_cell_data: {
  \int_gset:Nn \g_@@_col_int { \l_@@_saved_col_tl }
  \int_gset:Nn \g_@@_row_int { \l_@@_saved_row_tl }
  \tl_gset_eq:NN \g_@@_span_tl \l_@@_saved_span_tl
  \tl_gset_eq:NN \g_@@_table_cols_tl   \l_@@_saved_table_cols_tl
  \UseTaggingSocket{tbl/restore/celldata}
  \@@_trace:n { ==>~ restored~cell~data:~
                \int_use:N \g_@@_row_int,
                \int_use:N \g_@@_col_int,
                \l_@@_saved_span_tl \space
                (
                \int_compare:nNnTF \g_@@_table_cols_tl = 0
                    { outer~ level }
                    { max:~ \g_@@_table_cols_tl }
                )
              }
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\tbl_update_multicolumn_cell_data:n}
%    This macro updates \cs{g_@@_col_int} and \cs{g_@@_span_tl} inside
%    a \cs{multicolumn} and possibly calls the tagging socket
%    \texttt{tbl/row/begin}.
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_update_multicolumn_cell_data:n #1 {
%    \end{macrocode}
%    We execute socket for tagging only if this \cs{multicolumn}
%    replaces the preamble of the first column. In that case we also have
%    to set \cs{g_@@_col_int} to 1 because this is no longer done in the
%    preamble for the cell either.
%    \begin{macrocode}
   \int_compare:nNnTF \g_@@_col_int = 0
       {
         \UseTaggingSocket{tbl/row/begin}
         \int_gset:Nn \g_@@_col_int {1}
       }
%    \end{macrocode}
%    If we are in a later column we use \cs{g_@@_span_tl} from the
%    previous column to update.
%    \begin{macrocode}
       {
         \int_gadd:Nn \g_@@_col_int { \g_@@_span_tl }
       }
%    \end{macrocode}
%    Then we set the span value so that it can be use in the next column.
%    \begin{macrocode}
   \tl_gset:Nn \g_@@_span_tl {#1}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\tbl_crcr:n}
%    This macro is used instead of the usual \cs{crcr} at the end of a
%    table. It is deliberately defined without protection because it
%    may get expanded by the scanning mechanism of low-level \TeX{}
%    after a final \cs{cr} (aka \verb=\\=) in the table. In that case
%    it shouldn't stop the expansion and the conditional inside will
%    be false, thus it just vanishes without doing anything. If there
%    are missing cells (in which case we also haven't see \cs{cr} yet)
%    the macro \cs{tbl_count_missing_cells:n} is executed and
%    then the row is finished with a final \cs{cr}.
%    \begin{macrocode}
\cs_new:Npn \tbl_crcr:n #1 {
    \int_compare:nNnT \g_@@_col_int > 0
        {
          \tbl_count_missing_cells:n {#1}
        }
%    \end{macrocode}
%    Even if we are at the start of a row we my have to do a \cs{cr},
%    so we do a \cs{crcr} always at the end.
% \changes{v1.0b}{2024/06/10}
%         {Always issue a \cs{crcr} even if we are at the start of a
%          row to avoid problems with tabulary and similar code}
%    \begin{macrocode}
    \crcr
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%    \begin{macrocode}
\ExplSyntaxOff
%<@@=>
%    \end{macrocode}
%
% \changes{v1.0h}{2024/09/20}{moved \cs{@kernel@refstepcounter} into ltxref}
%    This is needed for \pkg{longtable} because \cs{refstepcounter} is
%    setting up a target when \pkg{hyperref} is loaded and we don't
%    want that in \pkg{longtable}.%%
%    Prevent longtable patching by hyperref until hyperref does so automatically:
%    \begin{macrocode}
\def\hyper@nopatch@longtable{}
%    \end{macrocode}
%
%
% Should there be a module?
%
%    \begin{macrocode}
%<latexrelease>\NewModuleRelease{2024/06/01}{lttagging}
%<latexrelease>                 {Tagging support}
%    \end{macrocode}
%
%
%
%
%    \begin{macrocode}
%<latexrelease>\IncludeInRelease{0000/00/00}{lttagging}%
%<latexrelease>                 {Undo tagging support}
%<latexrelease>
%<latexrelease>
%<latexrelease>
%<latexrelease>\EndModuleRelease
%    \end{macrocode}
%
%    \begin{macrocode}
%</2ekernel|latexrelease>
%    \end{macrocode}
%
% \Finale
%
