% \iffalse meta-comment % %% File: tagpdf-checks.dtx % % Copyright (C) 2019-2024 Ulrike Fischer % % It may be distributed and/or modified under the conditions of the % LaTeX Project Public License (LPPL), either version 1.3c of this % license or (at your option) any later version. The latest version % of this license is in the file % % https://www.latex-project.org/lppl.txt % % This file is part of the "tagpdf bundle" (The Work in LPPL) % and all files in that bundle must be distributed together. % % ----------------------------------------------------------------------- % % The development version of the bundle can be found at % % https://github.com/latex3/tagpdf % % for those people who are interested. % % %<*driver> \DocumentMetadata{} \documentclass{l3doc} \usepackage{array,booktabs,caption} \hypersetup{pdfauthor=Ulrike Fischer, pdftitle=tagpdf-checks module (tagpdf)} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % \title{^^A % The \pkg{tagpdf-checks} module\\ Messages and check code ^^A % \\ Part of the tagpdf package % } % % \author{^^A % Ulrike Fischer\thanks % {^^A % E-mail: % \href{mailto:fischer@troubleshooting-tex.de} % {fischer@troubleshooting-tex.de}^^A % }^^A % } % % \date{Version 0.99i, released 2024-11-19} % \maketitle % \begin{documentation} % \section{Commands} % \begin{function}[pTF,EXP]{\tag_if_active:} % This command tests if tagging is active. It only gives true if all tagging has % been activated, \emph{and} if tagging hasn't been stopped locally. % \end{function} % \begin{function}[EXP]{\tag_get:n} % \begin{syntax} % \cs{tag_get:n}\Arg{keyword} % \end{syntax} % This is a generic command to retrieve data for the current structure or % mc-chunk. Currently % the only sensible values for the argument \meta{keyword} % are |mc_tag|, |struct_tag|, |struct_id| and |struct_num|. % \end{function} % % \begin{function}[pTF,EXP]{\tag_if_box_tagged:N} % \begin{syntax} % \cs{tag_if_box_tagged:N}\Arg{box} % \end{syntax} % This tests if a box contains tagging commands. % It relies currently on that the code, that saved the box, correctly sets % the command \verb+\l_tag_box_\int_use:N #1_tl+ to a positive value. % The LaTeX commands will do that automatically % at some time but it is in the responsibility of the user to % ensure that when using low-level code. % If the internal command doesn't exist the box is assumed to be untagged. % \end{function} % \section{Description of log messages} % \subsection{\cs{ShowTagging} command} % \begin{tabular}{lll} % Argument & type & note\\ % \cs{ShowTagging}{mc-data = num} & log+term & lua-only\\ % \cs{ShowTagging}{mc-current} & log+term & \\ % \cs{ShowTagging}{struck-stack= [log\verb+|+show]} & log or term+stop \\ % \cs{ShowTagging}{debug/structures = num} & log+termn & debug mode only % \end{tabular} % % \subsection{Messages in checks and commands} % \scriptsize % \begin{tabular}{llll} % command & message & action & remark\\ % |\@@_check_structure_has_tag:n| % & |struct-missing-tag| % & error % \\ % |\@@_check_structure_tag:N| % & |role-unknown-tag| % & warning % \\ % |\@@_check_info_closing_struct:n| % & |struct-show-closing| % & info % & log-level>0 % \\ % |\@@_check_no_open_struct:| % & struct-faulty-nesting % & error % & TODO: error only with 1? % \\ % |\@@_check_struct_used:n| % & |struct-used-twice| % & warning % \\ % |\@@_check_add_tag_role:nn| % & |role-missing|, |role-tag|, |role-unknown| % & warning, info (>0), warning % \\ % |\@@_check_mc_if_nested:|, % & |mc-nested| % & warning % \\ % |\@@_check_mc_if_open:| % & |mc-not-open| % & warning % & only generic (?) % \\ % |\@@_check_mc_pushed_popped:nn| % & |mc-pushed|, |mc-popped| % & info (2), info+|seq_log| (>2) % \\ % |\@@_check_mc_tag:N| % & |mc-tag-missing|, |role-unknown-tag| % & error (missing), warning (unknown). % \\ % |\@@_check_mc_used:n| % & |mc-used-twice| % & warning % & TODO: review the sense of this test! % \\ % |\@@_check_show_MCID_by_page:| % & % & % & currently unused % \\ % |\tag_mc_use:n| % & |mc-label-unknown|, |mc-used-twice| % & warning % & in mc-shared % \\ % |\role_add_tag:nn| % & |new-tag| % & info (>0) % & in roles % \\ % & |sys-no-interwordspace| % & warning % & space module, only xetex/dvi % \\ % |\@@_struct_write_obj:n| % & |struct-no-objnum| % & error % & in struct module % \\ % |\@@_struct_write_obj:n| % & |struct-orphan| % & warning % & in struct module % \\ % |\tag_struct_begin:n| % & |struct-faulty-nesting| % & error % \\ % |\@@_struct_insert_annot:nn| % & |struct-faulty-nesting| % & error % \\ % |tag_struct_use:n| % & |struct-label-unknown| % & warning % \\ % |attribute-class|, |attribute| % & |attr-unknown| % & error % \\ % |\@@_tree_fill_parenttree:| % & |tree-mcid-index-wrong| % & warning % TODO: should trigger a standard rerun message. % \\ % in |enddocument/info|-hook % & |para-hook-count-wrong| % & error (warning?) % \end{tabular} % % \normalsize % \subsection{Messages from the ptagging code} % A few messages are issued in generic % mode from the code which reinserts missing TMB/TME. % This is currently done if log-level is larger than zero. % TODO: reconsider log-level and messages when this code % settles down. % % % \subsection{Warning messages from the lua-code} % The messages are triggered if the log-level is at least equal to the number. % % \begin{tabular}[t]{>{\ttfamily}lll} % message & log-level & remark \\\hline % WARN TAG-NOT-TAGGED: &1 \\ % WARN TAG-OPEN-MC: &1 \\ % WARN SHIPOUT-MC-OPEN: &1 \\ % WARN SHIPOUT-UPS: &0 & shouldn't happen \\ % WARN TEX-MC-INSERT-MISSING:&0 & shouldn't happen \\ % WARN TEX-MC-INSERT-NO-KIDS:&2 & e.g. from empty hbox % \end{tabular} % % \subsection{Info messages from the lua-code} % The messages are triggered if the log-level is at least equal to the number. % |TAG| messages are from the traversing function, |TEX| from code used in the tagpdf-mc module. % |PARENTREE| is the code building the parenttree. % % \begin{longtable}{>{\ttfamily}lll} % message & log-level & remark \\\hline\endhead % INFO SHIPOUT-INSERT-LAST-EMC & 3 & finish of shipout code \\ % INFO SPACE-FUNCTION-FONT & 3 & interwordspace code \\ % INFO TAG-ABSPAGE & 3 \\ % INFO TAG-ARGS & 4 \\ % INFO TAG-ENDHEAD & 4 \\ % INFO TAG-ENDHEAD & 4 \\ % INFO TAG-HEAD & 3 \\ % INFO TAG-INSERT-ARTIFACT & 3 \\ % INFO TAG-INSERT-BDC & 3 \\ % INFO TAG-INSERT-EMC & 3 \\ % INFO TAG-INSERT-TAG & 3 \\ % INFO TAG-KERN-SUBTYPE & 4\\ % INFO TAG-MATH-SUBTYPE & 4 \\ % INFO TAG-MC-COMPARE & 4 \\ % INFO TAG-MC-INTO-PAGE & 3 \\ % INFO TAG-NEW-MC-NODE & 4 \\ % INFO TAG-NODE & 3 \\ % INFO TAG-NO-HEAD & 3 \\ % INFO TAG-NOT-TAGGED & 2 & replaced by artifact\\ % INFO TAG-QUITTING-BOX & 4 \\ % INFO TAG-STORE-MC-KID & 4 \\ % INFO TAG-TRAVERSING-BOX 3 \\ % INFO TAG-USE-ACTUALTEXT & 3 \\ % INFO TAG-USE-ALT & 3 \\ % INFO TAG-USE-RAW & 3 \\ % INFO TEX-MC-INSERT-KID & 3 \\ % INFO TEX-MC-INSERT-KID-TEST & 4 \\ % INFO TEX-MC-INTO-STRUCT & 3 \\ % INFO TEX-STORE-MC-DATA & 3 \\ % INFO TEX-STORE-MC-KID & 3 \\ % INFO PARENTTREE-CHUNKS & 3 \\ % INFO PARENTTREE-NO-DATA & 3\\ % INFO PARENTTREE-NUM & 3 \\ % INFO PARENTTREE-NUMENTRY & 3 \\ % INFO PARENTTREE-STRUCT-OBJREF & 4 % \end{longtable} % % \subsection{Debug mode messages and code} % If the package tagpdf-debug is loaded a number of commands are redefined and % enhanced with additional commands which can be used to output debug messages or % collect statistics. The commands are present but do nothing if the log-level is zero. % \begin{tabular}{llll} % command & name & action & remark\\\hline % |\tag_mc_begin:n| & mc-begin-insert & msg \\ % & mc-begin-ignore & msg & if inactive \\ % \end{tabular} % % \subsection{Messages} % \begin{function}{ % mc-nested, % mc-tag-missing, % mc-label-unknown, % mc-used-twice, % mc-used-twice, % mc-not-open, % mc-pushed, % mc-popped, % mc-current} % Various messages related to mc-chunks. TODO document their meaning. % \end{function} % \begin{function}{struct-unknown,struct-no-objnum,struct-orphan,struct-faulty-nesting, % struct-missing-tag,struct-used-twice,struct-label-unknown,struct-show-closing} % Various messages related to structure. Check the definition in the code for their % meaning and the arguments they take. % \end{function} % % \begin{function}{tree-struct-still-open} % Message issued at the end of the compilation % if there are (beside Root) other open structures on the stack. % \end{function} % % \begin{function}{tree-statistic} % Message issued at the end of the compilation % showing the number of objects to write % \end{function} % % \begin{function}{show-struct,show-kids} % These two messages are used in debug mode % to show the current structures in the log and terminal. % \end{function} % % \begin{function}{attr-unknown} % Message if an attribute i sunknown. % \end{function} % % \begin{function}{role-missing,role-unknown,role-unknown-tag,role-unknown-NS,role-tag,new-tag, % role-parent-child,role-remapping} % Messages related to role mapping. % \end{function} % % \begin{function}{tree-mcid-index-wrong} % Used in the tree code, typically indicates the document must be rerun. % \end{function} % % \begin{function}{sys-no-interwordspace} % Message if an engine doesn't support inter word spaces % \end{function} % % \begin{function}{para-hook-count-wrong} % Message if the number of begin paragraph and end paragraph differ. This normally means faulty structure. % \end{function} % \end{documentation} % \begin{implementation} % \begin{macrocode} %<@@=tag> %<*header> \ProvidesExplPackage {tagpdf-checks-code} {2024-11-19} {0.99i} {part of tagpdf - code related to checks, conditionals, debugging and messages} % % \end{macrocode} % \section{Messages} % % \subsection{Messages related to mc-chunks} % \begin{macro}{mc-nested} % This message is issue is a mc is opened before the previous has been closed. % This is not relevant for luamode, as the attributes don't care about this. % It is used in the |\@@_check_mc_if_nested:| test. % \begin{macrocode} %<*package> \msg_new:nnn { tag } {mc-nested} { nested~marked~content~found~-~mcid~#1 } % \end{macrocode} % \end{macro} % \begin{macro}{mc-tag-missing} % If the tag is missing % \begin{macrocode} \msg_new:nnn { tag } {mc-tag-missing} { required~tag~missing~-~mcid~#1 } % \end{macrocode} % \end{macro} % \begin{macro}{mc-label-unknown} % If the label of a mc that is used in another place is not known (yet) % or has been undefined as the mc was already used. % \begin{macrocode} \msg_new:nnn { tag } {mc-label-unknown} { label~#1~unknown~or~has~been~already~used.\\ Either~rerun~or~remove~one~of~the~uses. } % \end{macrocode} % \end{macro} % \begin{macro}{mc-used-twice} % An mc-chunk can be inserted only in one structure. This indicates wrong coding % and so should at least give a warning. % \begin{macrocode} \msg_new:nnn { tag } {mc-used-twice} { mc~#1~has~been~already~used } % \end{macrocode} % \end{macro} % \begin{macro}{mc-not-open} % This is issued if a |\tag_mc_end:| is issued wrongly, wrong coding. % \begin{macrocode} \msg_new:nnn { tag } {mc-not-open} { there~is~no~mc~to~end~at~#1 } % \end{macrocode} % \end{macro} % \begin{macro}{mc-pushed,mc-popped} % Informational messages about mc-pushing. % \begin{macrocode} \msg_new:nnn { tag } {mc-pushed} { #1~has~been~pushed~to~the~mc~stack} \msg_new:nnn { tag } {mc-popped} { #1~has~been~removed~from~the~mc~stack } % \end{macrocode} % \end{macro} % \begin{macro}{mc-current} % Informational messages about current mc state. % \begin{macrocode} \msg_new:nnn { tag } {mc-current} { current~MC:~ \bool_if:NTF\g_@@_in_mc_bool {abscnt=\@@_get_mc_abs_cnt:,~tag=\g_@@_mc_key_tag_tl} {no~MC~open,~current~abscnt=\@@_get_mc_abs_cnt:"} } % \end{macrocode} % \end{macro} % \subsection{Messages related to structures} % \begin{macro}{struct-unknown} % if for example a parent key value points to structure that doesn't exist (yet) % \begin{macrocode} \msg_new:nnn { tag } {struct-unknown} { structure~with~number~#1~doesn't~exist\\ #2 } % \end{macrocode} % \end{macro} % \begin{macro}{struct-no-objnum} % Should not happen \ldots % \begin{macrocode} \msg_new:nnn { tag } {struct-no-objnum} { objnum~missing~for~structure~#1 } % \end{macrocode} % \end{macro} % \begin{macro}{struct-orphan} % This indicates that there is a structure which has kids but no parent. % This can happen if a structure is stashed but then not used. % \begin{macrocode} \msg_new:nnn { tag } {struct-orphan} { Structure~#1~has~#2~kids~but~no~parent.\\ It~is~turned~into~an~artifact.\\ Did~you~stashed~a~structure~and~then~didn't~use~it? } % \end{macrocode} % \end{macro} % \begin{macro}{struct-faulty-nesting} % This indicates that there is somewhere one |\tag_struct_end:| too much. % This should be normally an error. % \begin{macrocode} \msg_new:nnn { tag } {struct-faulty-nesting} { there~is~no~open~structure~on~the~stack } % \end{macrocode} % \end{macro} % \begin{macro}{struct-missing-tag} % A structure must have a tag. % \begin{macrocode} \msg_new:nnn { tag } {struct-missing-tag} { a~structure~must~have~a~tag! } % \end{macrocode} % \end{macro} % \begin{macro}{struct-used-twice} % \begin{macrocode} \msg_new:nnn { tag } {struct-used-twice} { structure~with~label~#1~has~already~been~used} % \end{macrocode} % \end{macro} % \begin{macro}{struct-label-unknown} % label is unknown, typically needs a rerun. % \begin{macrocode} \msg_new:nnn { tag } {struct-label-unknown} { structure~with~label~#1~is~unknown~rerun} % \end{macrocode} % \end{macro} % \begin{macro}{struct-show-closing} % Informational message shown if log-mode is high enough % \begin{macrocode} \msg_new:nnn { tag } {struct-show-closing} { closing~structure~#1~tagged~\use:e{\prop_item:cn{g_@@_struct_#1_prop}{S}} } % \end{macrocode} % \end{macro} % % \begin{macro}{struct-Ref-unknown} % This message is issued at the end, when the Ref keys are updated. % TODO: in debug mode it should report more info about the structure. % \begin{macrocode} \msg_new:nnn { tag } {struct-Ref-unknown} { #1~has~no~related~structure.\\ /Ref~not~updated. } % \end{macrocode} % \end{macro} % \begin{macro}{tree-struct-still-open} % Message issued at the end if there are beside Root other % open structures on the stack. % \begin{macrocode} \msg_new:nnn { tag } {tree-struct-still-open} { There~are~still~open~structures~on~the~stack!\\ The~stack~contains~\seq_use:Nn\g_@@_struct_tag_stack_seq{,}.\\ The~structures~are~automatically~closed,\\ but~their~nesting~can~be~wrong. } % \end{macrocode} % \end{macro} % % \begin{macro}{tree-statistic} % Message issued at the end showing the estimated number of % structures and MC-childs % \begin{macrocode} \msg_new:nnn { tag } {tree-statistic} { Finalizing~the~tagging~structure:\\ Writing~out~\c_tilde_str \int_use:N\c@g_@@_struct_abs_int\c_space_tl~structure~objects\\ with~\c_tilde_str \int_use:N\c@g_@@_MCID_abs_int\c_space_tl'MC'~leaf~nodes.\\ Be~patient~if~there~are~lots~of~objects! } % % \end{macrocode} % \end{macro} % The following messages are only needed in debug mode. % \begin{macro}{show-struct,show-kids} % This two messages are used to show the current structures in the log and terminal. % \begin{macrocode} %<*debug> \msg_new:nnn { tag/debug } { show-struct } { =========================\\ The~structure~#1~ \tl_if_empty:nTF {#2} { is~empty \\>~ . } { contains: #2 } \\ } \msg_new:nnn { tag/debug } { show-kids } { The~structure~has~the~following~kids: \tl_if_empty:nTF {#2} { \\>~ NONE } { #2 } \\ ========================= } % % \end{macrocode} % \end{macro} % \subsection{Attributes} % Not much yet, as attributes aren't used so much. % \begin{macro}{attr-unknown} % \begin{macrocode} %<*package> \msg_new:nnn { tag } {attr-unknown} { attribute~#1~is~unknown} % \end{macrocode} % \end{macro} % % \subsection{Roles} % \begin{macro}{role-missing,role-unknown,role-unknown-tag,role-unknown-NS} % Warning message if either the tag or the role is missing % \begin{macrocode} \msg_new:nnn { tag } {role-missing} { tag~#1~has~no~role~assigned } \msg_new:nnn { tag } {role-unknown} { role~#1~is~not~known } \msg_new:nnn { tag } {role-unknown-tag} { tag~#1~is~not~known } \msg_new:nnn { tag } {role-unknown-NS} { \tl_if_empty:nTF{#1}{Empty~NS}{NS~#1~is~not~known} } % \end{macrocode} % \end{macro} % \begin{macro}{role-parent-child} % This is info and warning message about the containment rules between child and % parent tags. % \begin{macrocode} \msg_new:nnn { tag } {role-parent-child} { Parent-Child~'#1'~-->~'#2'.\\Relation~is~#3~\msg_line_context:} % \end{macrocode} % \end{macro} % \begin{macro}{role-remapping} % This is info and warning message about role-remapping % \begin{macrocode} \msg_new:nnn { tag } {role-remapping} { remapping~tag~to~#1 } % \end{macrocode} % \end{macro} % \begin{macro}{role-tag,new-tag} % Info messages. % \begin{macrocode} \msg_new:nnn { tag } {role-tag} { mapping~tag~#1~to~role~#2 } \msg_new:nnn { tag } {new-tag} { adding~new~tag~#1 } \msg_new:nnn { tag } {read-namespace} { reading~namespace~definitions~tagpdf-ns-#1.def } \msg_new:nnn { tag } {namespace-missing}{ namespace~definitions~tagpdf-ns-#1.def~not~found } \msg_new:nnn { tag } {namespace-unknown}{ namespace~#1~is~not~declared } % \end{macrocode} % \end{macro} % % \subsection{Miscellaneous} % \begin{macro}{tree-mcid-index-wrong} % Used in the tree code, typically indicates the document must be rerun. % \begin{macrocode} \msg_new:nnn { tag } {tree-mcid-index-wrong} {something~is~wrong~with~the~mcid--rerun} % \end{macrocode} % \end{macro} % \begin{macro}{sys-no-interwordspace} % Currently only pdflatex and lualatex have some support for real spaces. % \begin{macrocode} \msg_new:nnn { tag } {sys-no-interwordspace} {engine/output~mode~#1~doesn't~support~the~interword~spaces} % \end{macrocode} % \end{macro} % % \begin{macro}{\@@_check_typeout_v:n} % A simple logging function. By default is gobbles its argument, but % the log-keys sets it to typeout. % \begin{macrocode} \cs_set_eq:NN \@@_check_typeout_v:n \use_none:n % \end{macrocode} % \end{macro} % % \begin{macro}{para-hook-count-wrong} % At the end of the document we check if the count of para-begin and para-end is % identical. If not we issue a warning: this is normally a coding error and % and breaks the structure. % \begin{macrocode} \msg_new:nnnn { tag } {para-hook-count-wrong} {The~number~of~automatic~begin~(#1)~and~end~(#2)~#3~para~hooks~differ!} {This~quite~probably~a~coding~error~and~the~structure~will~be~wrong!} % % \end{macrocode} % \end{macro} % \section{Retrieving data} % \begin{macro}[EXP]{\tag_get:n} % This retrieves some data. % This is a generic command to retrieve data. Currently % the only sensible values for the argument are |mc_tag|, |struct_tag| % and |struct_num|. % \begin{macrocode} %\cs_new:Npn \tag_get:n #1 { \use:c {@@_get_data_#1: } } % \end{macrocode} % \end{macro} % % \section{User conditionals} % \begin{macro}[pTF]{\tag_if_active:} % This tests if tagging is active. This allows packages % to add conditional code. % The test is true if all booleans, the global and the two local one are true. % % \begin{macrocode} %<*base> \prg_new_conditional:Npnn \tag_if_active: { p , T , TF, F } { \prg_return_false: } % %<*package> \prg_set_conditional:Npnn \tag_if_active: { p , T , TF, F } { \bool_lazy_all:nTF { {\g_@@_active_struct_bool} {\g_@@_active_mc_bool} {\g_@@_active_tree_bool} {\l_@@_active_struct_bool} {\l_@@_active_mc_bool} } { \prg_return_true: } { \prg_return_false: } } % % \end{macrocode} % \end{macro} % % \begin{macro}[pTF]{\tag_if_box_tagged:N} % This tests if a box contains tagging commands. % It relies on that the code that saved the box correctly set % \verb+\l_tag_box__tl+ to a positive value. % The LaTeX commands will do that automatically % at some time but it is in the responsibility of the user to % ensure that when using low-level code. % If the internal command doesn't exist the box is assumed to be untagged. % \begin{macrocode} %<*base> \prg_new_conditional:Npnn \tag_if_box_tagged:N #1 {p,T,F,TF} { \tl_if_exist:cTF {l_tag_box_\int_use:N #1_tl} { \int_compare:nNnTF {0\tl_use:c{l_tag_box_\int_use:N #1_tl}}>{0} { \prg_return_true: } { \prg_return_false: } } { \prg_return_false: % warning?? } } % % \end{macrocode} % \end{macro} % % \section{Internal checks} % These are checks used in various places in the code. % % \subsection{checks for active tagging} % \begin{macro}[TF]{\@@_check_if_active_mc:,\@@_check_if_active_struct:} % This checks if mc are active. % \begin{macrocode} %<*package> \prg_new_conditional:Npnn \@@_check_if_active_mc: {T,F,TF} { \bool_lazy_and:nnTF { \g_@@_active_mc_bool } { \l_@@_active_mc_bool } { \prg_return_true: } { \prg_return_false: } } \prg_new_conditional:Npnn \@@_check_if_active_struct: {T,F,TF} { \bool_lazy_and:nnTF { \g_@@_active_struct_bool } { \l_@@_active_struct_bool } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \subsection{Checks related to structures} % \begin{macro}{\@@_check_structure_has_tag:n} % Structures must have a tag, so we check if the S entry is in the property. % It is an error if this is missing. The argument is a number. % The tests for existence and type is split in structures, % as the tags are stored differently to the mc case. % \begin{macrocode} \cs_new_protected:Npn \@@_check_structure_has_tag:n #1 %#1 struct num { \prop_if_in:cnF { g_@@_struct_#1_prop } {S} { \msg_error:nn { tag } {struct-missing-tag} } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_check_structure_tag:N} % This checks if the name of the tag is known, % either because it is a standard type or has been rolemapped. % \begin{macrocode} \cs_new_protected:Npn \@@_check_structure_tag:N #1 { \prop_if_in:NoF \g_@@_role_tags_NS_prop {#1} { \msg_warning:nne { tag } {role-unknown-tag} {#1} } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_check_info_closing_struct:n} % This info message is issued at a closing structure, the use should be guarded by % log-level. % \begin{macrocode} \cs_new_protected:Npn \@@_check_info_closing_struct:n #1 %#1 struct num { \int_compare:nNnT {\l_@@_loglevel_int} > { 0 } { \msg_info:nnn { tag } {struct-show-closing} {#1} } } \cs_generate_variant:Nn \@@_check_info_closing_struct:n {o,e} % \end{macrocode} % \end{macro} % \begin{macro}{\@@_check_no_open_struct:} % This checks if there is an open structure. It should be used when trying to % close a structure. It errors if false.% % \begin{macrocode} \cs_new_protected:Npn \@@_check_no_open_struct: { \msg_error:nn { tag } {struct-faulty-nesting} } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_check_struct_used:n} % This checks if a stashed structure has already been used. % \begin{macrocode} \cs_new_protected:Npn \@@_check_struct_used:n #1 %#1 label { \prop_get:cnNT {g_@@_struct_\property_ref:enn{tagpdfstruct-#1}{tagstruct}{unknown}_prop} {P} \l_@@_tmpa_tl { \msg_warning:nnn { tag } {struct-used-twice} {#1} } } % \end{macrocode} % \end{macro} % % \subsection{Checks related to roles} % \begin{macro}{\@@_check_add_tag_role:nn} % This check is used when defining a new role mapping. % \begin{macrocode} \cs_new_protected:Npn \@@_check_add_tag_role:nn #1 #2 %#1 tag, #2 role { \tl_if_empty:nTF {#2} { \msg_error:nnn { tag } {role-missing} {#1} } { \prop_get:NnNTF \g_@@_role_tags_NS_prop {#2} \l_@@_tmpa_tl { \int_compare:nNnT {\l_@@_loglevel_int} > { 0 } { \msg_info:nnnn { tag } {role-tag} {#1} {#2} } } { \msg_error:nnn { tag } {role-unknown} {#2} } } } % \end{macrocode} % Similar with a namespace % \begin{macrocode} \cs_new_protected:Npn \@@_check_add_tag_role:nnn #1 #2 #3 %#1 tag/NS, #2 role #3 namespace { \tl_if_empty:nTF {#2} { \msg_error:nnn { tag } {role-missing} {#1} } { \prop_get:cnNTF { g_@@_role_NS_#3_prop } {#2} \l_@@_tmpa_tl { \int_compare:nNnT {\l_@@_loglevel_int} > { 0 } { \msg_info:nnnn { tag } {role-tag} {#1} {#2/#3} } } { \msg_error:nnn { tag } {role-unknown} {#2/#3} } } } % \end{macrocode} % \end{macro} % \subsection{Check related to mc-chunks} % % \begin{macro}{\@@_check_mc_if_nested:,\@@_check_mc_if_open:} % Two tests if a mc is currently open. One for the true (for begin % code), one for the false part (for end code). % \begin{macrocode} \cs_new_protected:Npn \@@_check_mc_if_nested: { \@@_mc_if_in:T { \msg_warning:nne { tag } {mc-nested} { \@@_get_mc_abs_cnt: } } } \cs_new_protected:Npn \@@_check_mc_if_open: { \@@_mc_if_in:F { \msg_warning:nne { tag } {mc-not-open} { \@@_get_mc_abs_cnt: } } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_check_mc_pushed_popped:nn} % This creates an information message if mc's are pushed or popped. % The first argument is a word (pushed or popped), the second the tag name. % With larger log-level the stack is shown too. % \begin{macrocode} \cs_new_protected:Npn \@@_check_mc_pushed_popped:nn #1 #2 { \int_compare:nNnT { \l_@@_loglevel_int } ={ 2 } { \msg_info:nne {tag}{mc-#1}{#2} } \int_compare:nNnT { \l_@@_loglevel_int } > { 2 } { \msg_info:nne {tag}{mc-#1}{#2} \seq_log:N \g_@@_mc_stack_seq } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_check_mc_tag:N} % This checks if the mc has a (known) tag. % \begin{macrocode} \cs_new_protected:Npn \@@_check_mc_tag:N #1 %#1 is var with a tag name in it { \tl_if_empty:NT #1 { \msg_error:nne { tag } {mc-tag-missing} { \@@_get_mc_abs_cnt: } } \prop_if_in:NoF \g_@@_role_tags_NS_prop {#1} { \msg_warning:nne { tag } {role-unknown-tag} {#1} } } % \end{macrocode} % \end{macro} % % \begin{variable}{\g_@@_check_mc_used_intarray, \@@_check_init_mc_used:} % This variable holds the list of used mc numbers. % Everytime we store a mc-number we will add one the relevant array index % If everything is right at the end there should be only 1 until the max count % of the mcid. 2 indicates that one mcid was used twice, 0 that we lost one. % In engines other than luatex the total number of all intarray entries % are restricted so we use only a rather small value of 65536, and we initialize % the array only at first used, guarded by the log-level. % This check is probably only needed for debugging. % TODO does this really make sense to check? When can it happen?? % \begin{macrocode} \cs_new_protected:Npn \@@_check_init_mc_used: { \intarray_new:Nn \g_@@_check_mc_used_intarray { 65536 } \cs_gset_eq:NN \@@_check_init_mc_used: \prg_do_nothing: } % \end{macrocode} % \end{variable} % % \begin{macro}{\@@_check_mc_used:n} % This checks if a mc is used twice. % \begin{macrocode} \cs_new_protected:Npn \@@_check_mc_used:n #1 %#1 mcid abscnt { \int_compare:nNnT {\l_@@_loglevel_int} > { 2 } { \@@_check_init_mc_used: \intarray_gset:Nnn \g_@@_check_mc_used_intarray {#1} { \intarray_item:Nn \g_@@_check_mc_used_intarray {#1} + 1 } \int_compare:nNnT { \intarray_item:Nn \g_@@_check_mc_used_intarray {#1} } > { 1 } { \msg_warning:nnn { tag } {mc-used-twice} {#1} } } } % \end{macrocode} % \end{macro} % \begin{macro}{\@@_check_show_MCID_by_page:} % This allows to show the mc on a page. Currently unused. % \begin{macrocode} \cs_new_protected:Npn \@@_check_show_MCID_by_page: { \tl_set:Ne \l_@@_tmpa_tl { \@@_property_ref_lastpage:nn {abspage} {-1} } \int_step_inline:nnnn {1}{1} { \l_@@_tmpa_tl } { \seq_clear:N \l_@@_tmpa_seq \int_step_inline:nnnn {1} {1} { \@@_property_ref_lastpage:nn {tagmcabs} {-1} } { \int_compare:nT { \property_ref:enn {mcid-####1} {tagabspage} {-1} = ##1 } { \seq_gput_right:Ne \l_@@_tmpa_seq { Page##1-####1- \property_ref:enn {mcid-####1} {tagmcid} {-1} } } } \seq_show:N \l_@@_tmpa_seq } } % \end{macrocode} % \end{macro} % % \subsection{Checks related to the state of MC on a page or in a split stream} % The following checks are currently only usable in generic mode as they % rely on the marks defined in the mc-generic module. They are used to detect % if a mc-chunk has been split by a page break or similar and additional % end/begin commands are needed. % % \begin{macro}[pTF]{\@@_check_mc_in_galley:} % At first we need a test to decide if |\tag_mc_begin:n| (tmb) and |\tag_mc_end:| % (tme) has been used at all on the current galley. As each command issues % two slightly different marks we can do it by comparing firstmarks and botmarks. % The test assumes that the marks have been already mapped into the sequence with % |\@@_mc_get_marks:|. As |\seq_if_eq:NNTF| doesn't exist we use the tl-test. % \begin{macrocode} \prg_new_conditional:Npnn \@@_check_if_mc_in_galley: { T,F,TF } { \tl_if_eq:NNTF \l_@@_mc_firstmarks_seq \l_@@_mc_botmarks_seq { \prg_return_false: } { \prg_return_true: } } % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{\@@_check_if_mc_tmb_missing:} % This checks if a extra top mark (\enquote{extra-tmb}) is needed. % According to the analysis this the case if the firstmarks start with % |e-| or |b+|. % Like above we assume that the marks content is already in the seq's. % \begin{macrocode} \prg_new_conditional:Npnn \@@_check_if_mc_tmb_missing: { T,F,TF } { \bool_if:nTF { \str_if_eq_p:ee {\seq_item:Nn \l_@@_mc_firstmarks_seq {1}}{e-} || \str_if_eq_p:ee {\seq_item:Nn \l_@@_mc_firstmarks_seq {1}}{b+} } { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macro}[pTF]{\@@_check_if_mc_tme_missing:} % This checks if a extra bottom mark (\enquote{extra-tme}) is needed. % According to the analysis this the case if the botmarks starts with % |b+|. % Like above we assume that the marks content is already in the seq's. % \begin{macrocode} \prg_new_conditional:Npnn \@@_check_if_mc_tme_missing: { T,F,TF } { \str_if_eq:eeTF {\seq_item:Nn \l_@@_mc_botmarks_seq {1}}{b+} { \prg_return_true: } { \prg_return_false: } } % \end{macrocode} % \end{macro} % \begin{macrocode} % % \end{macrocode} % \begin{macrocode} %<*debug> % \end{macrocode} % Code for tagpdf-debug. This will probably change over time. % At first something for the mc commands. % \begin{macrocode} \msg_new:nnn { tag / debug } {mc-begin} { MC~begin~#1~with~options:~\tl_to_str:n{#2}~[\msg_line_context:] } \msg_new:nnn { tag / debug } {mc-end} { MC~end~#1~[\msg_line_context:] } \cs_new_protected:Npn \@@_debug_mc_begin_insert:n #1 { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnnn { tag / debug } {mc-begin} {inserted} { #1 } } } \cs_new_protected:Npn \@@_debug_mc_begin_ignore:n #1 { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnnn { tag / debug } {mc-begin } {ignored} { #1 } } } \cs_new_protected:Npn \@@_debug_mc_end_insert: { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnn { tag / debug } {mc-end} {inserted} } } \cs_new_protected:Npn \@@_debug_mc_end_ignore: { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnn { tag / debug } {mc-end } {ignored} } } % \end{macrocode} % And now something for the structures % \begin{macrocode} \msg_new:nnn { tag / debug } {struct-begin} { Struct~\tag_get:n{struct_num}~begin~#1~with~options:~\tl_to_str:n{#2}~\\[\msg_line_context:] } \msg_new:nnn { tag / debug } {struct-end} { Struct~end~#1~[\msg_line_context:] } \msg_new:nnn { tag / debug } {struct-end-wrong} { Struct~end~'#1'~doesn't~fit~start~'#2'~[\msg_line_context:] } \cs_new_protected:Npn \@@_debug_struct_begin_insert:n #1 { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnnn { tag / debug } {struct-begin} {inserted} { #1 } \seq_log:N \g_@@_struct_tag_stack_seq } } \cs_new_protected:Npn \@@_debug_struct_begin_ignore:n #1 { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnnn { tag / debug } {struct-begin } {ignored} { #1 } } } \cs_new_protected:Npn \@@_debug_struct_end_insert: { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnn { tag / debug } {struct-end} {inserted} \seq_log:N \g_@@_struct_tag_stack_seq } } \cs_new_protected:Npn \@@_debug_struct_end_ignore: { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \msg_note:nnn { tag / debug } {struct-end } {ignored} } } \cs_new_protected:Npn \@@_debug_struct_end_check:n #1 { \int_compare:nNnT { \l_@@_loglevel_int } > {0} { \seq_get:NNT \g_@@_struct_tag_stack_seq \l_@@_tmpa_tl { \str_if_eq:eeF {#1} {\exp_last_unbraced:NV\use_i:nn \l_@@_tmpa_tl} { \msg_warning:nnee { tag/debug }{ struct-end-wrong } {#1} {\exp_last_unbraced:NV\use_i:nn \l_@@_tmpa_tl} } } } } % \end{macrocode} % This tracks tag suspend and resume. % The tag-suspend message should go before the int is increased. % The tag-resume message after the int is decreased. % \begin{macrocode} \msg_new:nnn { tag / debug } {tag-suspend} { \int_if_zero:nTF {#1} {Tagging~suspended} {Tagging~(not)~suspended~(already~inactive)}\\ level:~#1~==>~\int_eval:n{#1+1}\tl_if_empty:nF{#2}{,~label:~#2}~[\msg_line_context:] } \msg_new:nnn { tag / debug } {tag-resume} { \int_if_zero:nTF {#1} {Tagging~resumed} {Tagging~(not)~resumed}\\ level:~\int_eval:n{#1+1}~==>~#1\tl_if_empty:nF{#2}{,~label:~#2}~[\msg_line_context:] } % \end{macrocode} % \begin{macrocode} % % \end{macrocode} % % \subsection{Benchmarks} % It doesn't make much sense to do benchmarks in debug mode or in combination % with a log-level as this would slow down the compilation. % So we add simple commands that can be activated if l3benchmark has been loaded. % TODO: is a warning needed? % \begin{macrocode} %<*package> \cs_new_protected:Npn \@@_check_benchmark_tic:{} \cs_new_protected:Npn \@@_check_benchmark_toc:{} \cs_new_protected:Npn \tag_check_benchmark_on: { \cs_if_exist:NT \benchmark_tic: { \cs_set_eq:NN \@@_check_benchmark_tic: \benchmark_tic: \cs_set_eq:NN \@@_check_benchmark_toc: \benchmark_toc: } } % % \end{macrocode} % \end{implementation} % \PrintIndex