% \iffalse meta-comment
%
% Copyright (C) 2023-2024
% 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}
             [2024/08/10 v1.0g 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}
%
%
%
%    \begin{macrocode}
%<*2ekernel|latexrelease>
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
%
% \section{General support for tagged output}
%
%  \DescribeMacro\SuspendTagging
%  \DescribeMacro\ResumeTagging
%  
%  The are places in code where it is import top 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
%  allowed 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}. 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
%  both take 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
%  they two commands do nothing.
%
%  TODO: the corresponding L3 layer commands should also have a dummy
%  definition in the kernel!
%
% \DescribeMacro\UseTaggingSocket
% \DescribeMacro\tag_socket_use:n
% \DescribeMacro\tag_socket_use:nn
%  To support tagging in packages we use sockets with names starting
%  with \texttt{tagsupport/}. Usually, these sockets have exactly two
%  plugs defined:
%  \plug{noop} (when no tagging is requested or tagging is not wanted
%  for some reason) and a second plug that enables the tagging. There
%  may be more, e.g., tagging with special debugging, etc., but right
%  now it is usually just on or off.
%
%  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 the socket name is specified without
%  \texttt{tagsupport/}, 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 when tagging is
%  suspended with \cs{SuspendTagging} instead of changing the plugs of
%  the tagging support sockets back and forth.
%
%  This means that with \cs{SuspendTagging} in force all socket
%  arguments are ignored (including the case when there is a single
%  one), i.e., all sockets used with \cs{UseTaggingSocket} behave as
%  if the \text{noop} plug is assigned.
%
%  It is possible to use the tagging support sockets with
%  \cs{UseSocket} instead of \cs{UseTaggingSocket}, 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}.
%
%  The L3 programming layer versions \cs{tag_socket_use:n} and
%  \cs{tag_socket_use:nn} are slightly more efficient than
%  \cs{UseTaggingSocket} because they do not have to determine how
%  many arguments the socket takes when disabling it, so in code that
%  is using the L3 programming layer we recommend to use them instead
%  of the CamelCase command.
%                
%
% \MaybeStop{}
%
%
% \section{Implementation}
%
%
%
%  \begin{macro}{\SuspendTagging,\ResumeTagging}
%    
%    In the kernel, these two 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 \SuspendTagging \use_none:n  
\cs_new_eq:NN \ResumeTagging  \use_none:n
%    \end{macrocode}
%
%    A simplified version of this definition should move to
%    \pkg{tagpdf} and dropped here, eventually.
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \cs_if_exist:NT \tag_stop:n
  { 
    \cs_set:Npn \SuspendTagging #1 {
%    \end{macrocode}%
%    This stops tagging and also disables all tagging sockets so we are done.
%    \begin{macrocode}
      \tag_stop:n {#1} 
    }
%    \end{macrocode}
%
%    \begin{macrocode}
    \cs_set:Npn \ResumeTagging #1 { \tag_start:n {#1} }
  }
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\tag_socket_use:n,
%                \tag_socket_use:nn,
%                \UseTaggingSocket,
%               }
%    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.
%    \begin{macrocode}
\AddToHook{begindocument}[kernel]{
  \cs_if_exist:NF \tag_if_active:T
     {
       \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}.
%    \begin{macrocode}
\cs_new_protected:Npn \tag_socket_use:n #1 { }
\cs_new_protected:Npn \tag_socket_use:nn #1#2 { }
%    \end{macrocode}
%    The default in the kernel is just to get rid of the argument:
%    \begin{macrocode}
\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_none: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}
%
%  \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. 
% 
% \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{socketdecl}{tagsupport/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}
\NewSocket{tagsupport/para/restore}{0}
%    \end{macrocode}
% \end{socketdecl}
% 
% \begin{plugdecl}{default}
%    \begin{macrocode}
\NewSocketPlug{tagsupport/para/restore}{default}
 {
   \tl_set:Nn    \l__tag_para_main_tag_tl {text-unit}
   \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
 }
\AssignSocketPlug{tagsupport/para/restore}{default}
\ExplSyntaxOff 
%    \end{macrocode}
% \end{plugdecl}

% \subsubsection{Tagging sockets for toc}

% \begin{socketdecl}{tagsupport/toc/contentsline/before,
%  tagsupport/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}
\NewSocket{tagsupport/toc/contentsline/before}{1}
\NewSocket{tagsupport/toc/contentsline/after}{1}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{socketdecl}{tagsupport/toc/starttoc/before,
%                    tagsupport/toc/starttoc/after}
% Tagging sockets for the begin and end of start of \cs{@starttoc}.
% They take one argument, the extension.                   
%    \begin{macrocode}
\NewSocket{tagsupport/toc/starttoc/before}{1}
\NewSocket{tagsupport/toc/starttoc/after}{1}
%    \end{macrocode}
% \end{socketdecl}
% 
% \begin{socketdecl}{tagsupport/toc/leaders/before,
%                    tagsupport/toc/leaders/after}
% Tagging sockets to make the dot leaders an artifact.
% They do not take an argument.                    
%    \begin{macrocode}
\NewSocket{tagsupport/toc/leaders/before}{0}
\NewSocket{tagsupport/toc/leaders/after}{0}
%    \end{macrocode}
% \end{socketdecl}
% 
% \subsection{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{socketdecl}{tagsupport/tbl/cell/begin,
%                    tagsupport/tbl/cell/end,
%                    tagsupport/tbl/pcell/end,
%                    tagsupport/tbl/pcell/end,
%                    tagsupport/tbl/row/begin,
%                    tagsupport/tbl/row/end,
%                   }
%     At first sockets for the begin and end of cells and table rows:
%    \begin{macrocode}
\NewSocket{tagsupport/tbl/cell/begin}{0}
\NewSocket{tagsupport/tbl/cell/end}{0}
%    \end{macrocode}
%
%    \begin{macrocode}
\NewSocket{tagsupport/tbl/row/begin}{0}
\NewSocket{tagsupport/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}
\NewSocket{tagsupport/tbl/pcell/begin}{0}
\NewSocket{tagsupport/tbl/pcell/end}{0}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{socketdecl}{tagsupport/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}
\NewSocket{tagsupport/tbl/init}{0}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{socketdecl}{tagsupport/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}
\NewSocket{tagsupport/tbl/init/celldata}{0}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{socketdecl}{tagsupport/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}
\NewSocket{tagsupport/tbl/finalize}{0}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{socketdecl}{tagsupport/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}
\NewSocket{tagsupport/tbl/restore/celldata}{0}
%    \end{macrocode}
% \end{socketdecl}

% \begin{socketdecl}{tagsupport/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}
\NewSocket{tagsupport/tbl/colspan}{1}
%    \end{macrocode}
% \end{socketdecl}
%


% \begin{socketdecl}{tagsupport/tbl/hmode/begin,
%                    tagsupport/tbl/hmode/end,
%                    tagsupport/tbl/vmode/begin,
%                    tagsupport/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}
\NewSocket{tagsupport/tbl/hmode/begin}{0}
\NewSocket{tagsupport/tbl/hmode/end}{0}
\NewSocket{tagsupport/tbl/vmode/begin}{0}
\NewSocket{tagsupport/tbl/vmode/end}{0}
%    \end{macrocode}
% \end{socketdecl}
%
%
%
% \begin{socketdecl}{tagsupport/tbl/longtable/init,
%                    tagsupport/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}
\NewSocket{tagsupport/tbl/longtable/init}{0}
\NewSocket{tagsupport/tbl/longtable/finalize}{0}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{socketdecl}{tagsupport/tbl/longtable/head,
%                    tagsupport/tbl/longtable/foot}
%    Header and footer boxes need special handling because they are repeatedly
%    used.
%    \begin{macrocode}
\NewSocket{tagsupport/tbl/longtable/head}{0}
\NewSocket{tagsupport/tbl/longtable/foot}{0}
%    \end{macrocode}
% \end{socketdecl}
%
%
% \begin{socketdecl}{tagsupport/tbl/leaders/begin,
%                    tagsupport/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}
\NewSocket{tagsupport/tbl/leaders/begin}{0}
\NewSocket{tagsupport/tbl/leaders/end}{0}
%    \end{macrocode}
% \end{socketdecl}
%
%
%
%
%
% \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 packagee 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_save_outer_table_cols:}
%    
%    \begin{macrocode}
\cs_new_protected:Npn \tbl_save_outer_table_cols: {
  \tl_set_eq:NN \l_@@_saved_table_cols_tl  \g_@@_table_cols_tl
}
%    \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_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}
%
%    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}.
%
%    TODO: move to right .dtx file
%    \begin{macrocode}
\let\@kernel@refstepcounter\refstepcounter
%    \end{macrocode}
%    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
%
