%% LaTeX package xassoccnt - version 2.0 (2021/11/21 -- 12:14:58) %% Source file for xassoccnt.sty %% %% %% ------------------------------------------------------------------------------------------- %% Copyright (c) 2017 -- 2021 by Dr. Christian Hupfer <> %% ------------------------------------------------------------------------------------------- %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 %% of this license or (at your option) any later version. %% The latest version of this license is in %% http://www.latex-project.org/lppl.txt %% and version 1.3 or later is part of all distributions of LaTeX %% version 2005/12/01 or later. %% %% %% This work has the LPPL maintenance status `unmaintained` %% %% \def\xassoccntpackageversion{2.0} \NeedsTeXFormat{LaTeX2e}[1995/12/01] \ProvidesPackage{xassoccnt}[2021/11/21 - v\xassoccntpackageversion] \RequirePackage{etoolbox} \RequirePackage{letltxmacro} \RequirePackage{xcolor} \RequirePackage{xparse} \RequirePackage{l3keys2e} \ExplSyntaxOn \newif\ifexplversionnew \explversionnewtrue % Some variants of standard expl3 contributions \cs_generate_variant:Nn \seq_set_from_clist:Nn { Nx, cx } \cs_generate_variant:Nn \seq_gset_from_clist:Nn { Nx, cx } \cs_generate_variant:Nn \seq_item:Nn { Nx, cx,NV,cV} \cs_generate_variant:Nn \seq_set_split:Nnn {Nxn,cxn,Nxx,cxx,cox,Nox,Non,con} \cs_generate_variant:Nn \seq_remove_all:Nn { cV, NV } \cs_generate_variant:Nn \seq_gremove_all:Nn { cV, NV } \cs_generate_variant:Nn \prop_put:Nnn {cxx,cxn,Nxx,Nxn} \cs_generate_variant:Nn \prop_gput:Nnn {cxx,cxn,Nxx,Nxn,NVx,Nvn,cVn,cVx} \cs_generate_variant:Nn \prop_remove:Nn {cx,Nx} \cs_generate_variant:Nn \prop_gremove:Nn {Nx,cx,No,co,NV,cV} \cs_generate_variant:Nn \prop_item:Nn {NV,cV,cx,No,co,Nx} \cs_generate_variant:Nn \int_set:Nn {NV,Nx,Nx,cx} \cs_generate_variant:Nn \cs_gset:Npn {NpV,Npv,cpV,cpv,cpo,Npo} \cs_generate_variant:Nn \tl_set:Nn {No,Nx,NV} % First some local or global values % global/local scratch variables \seq_new:N \l__xassoccnt_tmpa_seq \seq_new:N \l__xassoccnt_tmpb_seq \seq_new:N \l__xassoccnt_tmpc_seq \tl_new:N \l__xassoccnt_tmpa_tl \tl_new:N \l__xassoccnt_tmpb_tl \tl_new:N \g__xassoccnt_tmpa_tl \tl_new:N \g__xassoccnt_tmpb_tl \prop_new:N \l__xassoccnt_tmpa_prop \prop_new:N \g__xassoccnt_tmpa_prop \int_new:N \g__xassoccnt_tmpa_int \int_new:N \l__xassoccnt_tmpa_int \bool_new:N \l__xassoccnt_alphalphpackage_loaded_bool \bool_new:N \l__xassoccnt_hyperrefpackage_loaded_bool \bool_new:N \l__xassoccnt_cleverefpackage_loaded_bool \prop_new:N \g__xassoccnt_loadedpackages_prop \ifexplversionnew \str_const:Nn \c__xassoccnt_modulename_str {xassoccnt} \else \tl_const:Nn \c__xassoccnt_modulename_str {xassoccnt} % Only a wrapper \fi \bool_new:N \l__xassoccnt_calcpackage_loaded \int_const:Nn \c_xassoccnt_false_int {0} \int_const:Nn \c_xassoccnt_true_int {1} \int_new:N \l__xassoccnt_initialcountervalue_int \int_new:N \g__xassoccnt_lastcountervalue_int \bool_new:N \g__xassoccnt_autodefine_counters % --> global document option \bool_new:N \g__xassoccnt_nonumberofruns_bool % --> global document option \clist_new:N \l__xassoccnt_exclude_clist % clist for \clist_new:N \l__xassoccnt_onlycounters_clist % clist for the \SetDocumentCounter command \bool_new:N \l__xassoccnt_autodefine_none \bool_new:N \l__xassoccnt_autodefine_drivercounter \bool_new:N \l__xassoccnt_autodefine_allcounters \bool_new:N \l__xassoccnt_autodefine_associatedcounter \bool_new:N \l__xassoccnt_cascade_suspension_bool \bool_new:N \l__xassoccnt_countertype_general \bool_new:N \l__xassoccnt_countertype_driver \bool_new:N \l__xassoccnt_countertype_associated \bool_new:N \l__xassoccnt_countertype_total \bool_new:N \l__xassoccnt_is_supertotalcounter_bool \bool_new:N \l_xassoccnt_resetperiodiccounters_bool \bool_new:N \l_xassoccnt_wrapperiodiccounters_bool % Reset of counters related 'variables' \seq_new:N \g_xassoccnt_reset_seq \seq_new:N \l__xassoccnt_counterreset_seq % All counters \seq_new:N \g_xassoccnt_all_latex_counters_seq \prop_new:N \g_xassoccnt_latex_parentcounters_prop % Counter formats \prop_new:N \l_xassoccnt_counter_format_prop \prop_new:N \g_xassoccnt_counter_formatdata_prop %%% \int_new:N \g__xassoccnt_backupcalls_int \int_new:N \l__xassoccnt_backuptmpa_int \seq_new:N \l__xassoccnt_counternamesbackup_seq \seq_new:N \l__xassoccnt_countervaluesbackup_seq \seq_new:N \l__xassoccnt_backupresetlist_seq \bool_new:N \l__xassoccnt_counternamestarred_bool % Not needed actually \seq_new:N \g__xassoccnt_counternamesbackuplist_seq \cs_new:Nn \__xassoccnt_toggle_bool:N {% \bool_if:NTF #1 {\bool_set_false:n {#1}}{\bool_set_false:n {#1}} % \bool_if:nTF{#1}{\bool_set_false:n {#1}}{\bool_set_false:n {#1}} } \cs_new:Nn \__xassoccnt_toggle_bool:n {% \bool_if:nTF{#1}{\bool_set_false:n {#1}}{\bool_set_false:n {#1}} } \cs_generate_variant:Nn \__xassoccnt_toggle_bool:N { c } \cs_new:Nn \__xassoccnt_toggle_autodefine:n {% \clist_set:Nn \l_tmpa_clist {#1} \clist_map_inline:Nn \l_tmpa_clist {\__xassoccnt_toggle_bool:c {l__xassoccnt_autodefine_##1} } } \cs_new:Nn \__xassoccnt_set_false:n {% \clist_set:Nn \l_tmpa_clist {#1} \clist_map_inline:Nn \l_tmpa_clist {\bool_set_false:c {##1} } } \cs_new:Nn \__xassoccnt_set_true:n {% \clist_set:Nn \l_tmpa_clist {#1} \clist_map_inline:Nn \l_tmpa_clist {\bool_set_true:c {##1} } } \prop_new:N \g_xassoccnt_module_data_prop \prop_gput:Nnn \g_xassoccnt_module_data_prop {scratchname} {scratch} \prop_gput:Nnn \g_xassoccnt_module_data_prop {backupfeaturename} {backupcounters} \prop_gput:NnV \g_xassoccnt_module_data_prop {standardcounterformats} {\c_xassoccnt_true_int} \prop_gput:Nnn \g_xassoccnt_module_data_prop {prefix-sep} {::} \cs_new:Nn \xassoccnt_extract_moduledata:n {% \prop_item:Nn \g_xassoccnt_module_data_prop {#1} } \cs_new:Npn \xasdata #1{% \xassoccnt_extract_moduledata:n {#1}% } \keys_define:nn {xassoccnt} { initial .code:n={ \int_set:Nn \l__xassoccnt_initialcountervalue_int {#1}}, sloppy .bool_set:N=\l__xassoccnt_sloppy_newcounter, autodefinecounters .bool_set:N=\g__xassoccnt_autodefine_counters, nonumberofruns .code:n={\bool_gset_true:N \g__xassoccnt_nonumberofruns_bool}, nonumberofruns .value_forbidden:n = true, % Choice keys autodefine .choice:, autodefine / all .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_allcounters \__xassoccnt_set_true:n {l__xassoccnt_autodefine_drivercounter, l__xassoccnt_autodefine_associateddrivercounter } \bool_set_false:N \l__xassoccnt_autodefine_none }, autodefine / driver .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_drivercounter}, autodefine / associated .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_associatedcounter \__xassoccnt_set_false:n {l__xassoccnt_autodefine_allcounters,l__xassoccnt_autodefine_none}}, autodefine / none .code:n= {\bool_set_true:N \l__xassoccnt_autodefine_none \__xassoccnt_set_false:n {l__xassoccnt_autodefine_allcounters, l__xassoccnt_autodefine_associatedcounter, l__xassoccnt_autodefine_drivercounter}}, autodefine .initial:n= {none}, % No autodefinition by default associatedtoo .code:n={ \clist_clear:N \l__xassoccnt_onlycounters_clist}, associatedtoo .bool_set:N={\l__xassoccnt_setcounter_associated}, associatedtoo .initial:n={false}, onlycounters .code:n={\bool_set_false:N \l__xassoccnt_setcounter_associated \clist_set:Nn \l__xassoccnt_onlycounters_clist {#1} }, exclude .clist_set:N=\l__xassoccnt_exclude_clist, cascade .bool_set:N={\l__xassoccnt_cascade_suspension_bool}, %% For later purposes countertype .choice:, countertype / general .code:n= {\bool_set_true:N \l__xassoccnt_countertype_general \__xassoccnt_set_false:n {l__xassoccnt_countertype_driver, l__xassoccnt_countertype_total, l__xassoccnt_countertype_associated } }, %\bool_set_false:N \l__xassoccnt_countertype_driver \bool_set_false:N \l__xassoccnt_countertype_associated }, countertype / driver .code:n= {\bool_set_true:N \l__xassoccnt_countertype_driver \__xassoccnt_set_false:n {l__xassoccnt_countertype_general, l__xassoccnt_countertype_total, l__xassoccnt_countertype_associated } }, % \bool_set_false:N \l__xassoccnt_countertype_assocciated \bool_set_false:N \l__xassoccnt_countertype_general }, countertype / associated .code:n= {\bool_set_true:N \l__xassoccnt_countertype_associated \__xassoccnt_set_false:n {l__xassoccnt_countertype_general, l__xassoccnt_countertype_total, l__xassoccnt_countertype_driver } }, countertype / total .code:n= {\bool_set_true:N \l__xassoccnt_countertype_total \__xassoccnt_set_false:n {l__xassoccnt_countertype_driver, l__xassoccnt_countertype_general, l__xassoccnt_countertype_associated } }, countertype .initial:n={ general }, supertotal .bool_set:N={\l__xassoccnt_is_supertotalcounter_bool }, resetbackup .bool_set:N=\l__xassoccnt_resetbackupcounters_bool , standardcounterformats .choice:, standardcounterformats /on .code:n={\prop_gput:NnV \g_xassoccnt_module_data_prop {standardcounterformats} {\c_xassoccnt_true_int}}, standardcounterformats /off .code:n={\prop_gput:NnV \g_xassoccnt_module_data_prop {standardcounterformats} {\c_xassoccnt_false_int}}, redefinelabel .bool_set:N= { \g__xassoccnt_redefinelabel_bool }, map-name .code:n= { \prop_put:Nnn \g_xassoccnt_module_data_prop {map-name} {#1}}, counter-name .code:n= { \prop_put:Nnn \g_xassoccnt_module_data_prop {counter-name} {#1}} } \keys_define:nn {xassoccnt_periodiccounter} {% reset .bool_set:N={ \l_xassoccnt_resetperiodiccounters_bool }, wrap .bool_set:N={ \l_xassoccnt_wrapperiodiccounters_bool } } \cs_new:Nn \generate_unique_countergroup_value:n {% \seq_set_from_clist:Nn \l_tmpa_seq {#1} \tl_clear:N \l_tmpa_tl% \seq_map_inline:Nn \l_tmpa_seq {% \tl_put_right:Nn \l_tmpa_tl {\use:c{the##1}:}% }% \prop_put:NnV \g_xassoccnt_module_data_prop {currentid} {\l_tmpa_tl} } \keys_set:nn{xassoccnt}{nonumberofruns, redefinelabel=true,standardcounterformats=on} \ProcessKeysOptions{xassoccnt} \msg_new:nnn{xassoccnt}{counteralreadyexists}{% Error:~Counter~#1~already~exists\\ } \msg_new:nnn{xassoccnt}{nameisnocounter}{% Error:~Entity~#1~does~not~name~a~counter\\ } %Messages related to Counter formats \msg_new:nnn {xassoccnt} {counterformatnotdefined} {The~counter~format~"#1"~is~not~defined~for~counter~"#2"} \msg_new:nnn {xassoccnt} {counterformatwrongortooshort} {The~counter~format~for~"#1"~is~wrong~or~the~separator~is~missing} \msg_new:nnn{xassoccnt}{crossassociation}{% Error:~You~can't~cross-associate~two~counters\\ Here:~The~counters~#1~and~#2~should~not~be~associated~to~each~other~since~one~is~already~associated~to~the~other~one% } \msg_new:nnn{xassoccnt}{selfassociation}{% Warning:~An~accidental(?)~self-association~of~counter~"#1"~was~detected\\ This~will~be~ignored! } \msg_new:nnn{xassoccnt}{addwithoutdeclaration}{% Warning:~An~accidental(?)~addition~of~associated~counter(s)~without~DeclareAssociatedCounters~was~detected~for\\ the~driver~counter~"#1"~and~following~driven~counters:\\ ---~#2~--- } \msg_new:nnn{xassoccnt}{addcoupledcountergroupundefined}{% Warning:~There~is~no~coupled~counter~group~named~#2~\\ The~addition~operation~is~ignored!\\ ---~#1~--- } \msg_new:nnn{xassoccnt}{clearcoupledcountergroupundefined}{% Warning:~There~is~no~coupled~counter~group~named~#2~\\ The~clearing~operation~is~ignored!\\ ---~#1~--- } \msg_new:nnn{xassoccnt}{removingcoupledcountergroupundefined}{% Warning:~There~is~no~coupled~counter~group~named~#2~\\ The~removing~operation~is~ignored!\\ ---~#1~--- } \msg_new:nnn{xassoccnt}{emptybackupcountergroup}{% Warning:~The~backup~counter~group~name~is~empty!\\ Using~the~default~name:~"\xassoccnt_extract_moduledata:n{scratchname}"!\\ ---~#1~--- } \msg_new:nnn{xassoccnt}{addbackupcountergroupundefined}{% Warning:~There~is~no~backup~counter~group~named~#2~\\ The~addition~operation~is~ignored!\\ ---~#1~--- } \msg_new:nnn{xassoccnt}{backupcountergroupundefined}{% Warning:~There~is~no~backup~counter~group~named~#2~\\ The~restore~operation~is~ignored!\\ ---~#1~--- } \msg_new:nnn{xassoccnt}{restorebackupcountergroupundefined}{% Warning:~There~is~no~backup~counter~group~named~#2~\\ The~restoring~operation~is~ignored!\\ ---~#1~--- } \msg_new:nnn{xassoccnt}{nobackupid}{% Error:~Backup~ID~for~group~"#1"~not~given!\\ ---~#2~--- } \msg_new:nnn{xassoccnt}{norestoreid}{% Error:~Restore~ID~for~group~"#1"~not~given!\\ ---~#2~--- } \msg_new:nnn{xassoccnt}{duplicatebackupid}{% Error:~Backup~ID~"#1"~for~group~"#2"~is~already~defined!\\ ---~#3~--- } \msg_new:nnn{xassoccnt}{backupcollectionundefined}{% Error:~Backup~collection~#1~not~defined\\ Use~\DeclareBackupCollection~to~define~the~collection } \msg_new:nnn{xassoccnt}{incompatiblepackagenonfatal}{% Warning:~Package~"#1"~is~loaded~--~this~is~not~recommended~for~\c__xassoccnt_modulename_str\\ } \msg_new:nnn{xassoccnt}{packageloadedafterfatal}{% Error:~Package~"#1"~is~loaded~after~\c__xassoccnt_modulename_str~\\ This~is~an~error! } \msg_new:nnn{xassoccnt}{packagenotloadedfatal}{% Error:~Package~"#1"~is~not~loaded~but~required~\\ This~is~an~error! } \msg_new:nnn{xassoccnt}{containeralreadyexists}{% Error:~Container~named~#1~already~exists\\ } \msg_new:nnn{xassoccnt}{languagemappingalreadyexists}{% Warning:~Language~mapping~#1~already~exists!\\ } \msg_new:nnn{xassoccnt}{undefinedlanguagemapping}{% Error:~Language~mapping~#1~is~undefined!\\ } %%%%%%%%%%%%%%%%%%% \cs_new:Nn \xassoccnt_trackloadedpackages:n {% \seq_set_from_clist:Nn \l_tmpa_seq {#1} \seq_map_inline:Nn \l_tmpa_seq {% \@ifpackageloaded{##1}{% \prop_gput:Nnn \g__xassoccnt_loadedpackages_prop {##1} {\c_one_int} }{% \prop_gput:Nnn \g__xassoccnt_loadedpackages_prop {##1} {\c_zero_int} } } } \prg_new_conditional:Nnn \xassoccnt_package_loaded:n {T,F,TF}{% \prop_if_in:NnTF \g__xassoccnt_loadedpackages_prop {#1} {% \int_compare:nNnTF {\prop_item:Nn \g__xassoccnt_loadedpackages_prop {#1}} = {\c_zero_int } {\prg_return_false:} {\prg_return_true:}% }{% \prg_return_false: } } \prg_new_conditional:Nnn \xassoccnt_package_notloaded:n {T,F,TF}{% \prop_if_in:NnTF \g__xassoccnt_loadedpackages_prop {#1} {% \int_compare:nNnTF {\prop_item:Nn \g__xassoccnt_loadedpackages_prop {#1}} = {\c_zero_int } {\prg_return_true:} {\prg_return_false:}% }{% \prg_return_true: } } \prg_new_conditional:Nnn \__xassoccnt_package_notloaded_fatal:n {T,F,TF}{% \xassoccnt_package_notloaded:nTF{#1}{% \msg_error:nnn{xassoccnt}{packagenotloadedfatal}{#1} }{% \prg_return_true: } } \cs_new:Nn \xassoccnt_package_notloaded_fatal:nn {% \__xassoccnt_package_notloaded_fatal:nF {#1} {#2} } \NewDocumentCommand{\CheckIfPackageLoadedT}{m+m}{% \xassoccnt_package_loaded:nT {#1}{#2} } \NewDocumentCommand{\CheckIfPackageLoadedF}{m+m}{% \xassoccnt_package_loaded:nF {#1}{#2} } \NewDocumentCommand{\CheckIfPackageLoadedTF}{m+m+m}{% \xassoccnt_package_loaded:nTF {#1}{#2}{#3} } \NewDocumentCommand{\CheckIfNotPackageLoadedTF}{m+m+m}{% \xassoccnt_package_notloaded:nTF {#1}{#2}{#3} } \NewDocumentCommand{\CheckIfNotPackageLoadedT}{m+m}{% \xassoccnt_package_notloaded:nT {#1}{#2} } \NewDocumentCommand{\CheckIfNotPackageLoadedF}{m+m}{% \xassoccnt_package_notloaded:nF {#1}{#2} } %%%%%%%%%%%%%%%%%%%%%%%% \cs_new:Nn \__xassoccnt_intinc:n {\int_gincr:N \l_xassoccnt_resetlist_counter}% \int_new:N \l_xassoccnt_resetlist_counter \cs_new:Nn \xassoccnt_countersinresetlist:n {% \begingroup \int_zero:N \l_xassoccnt_resetlist_counter \cs_set_eq:NN \@elt \__xassoccnt_intinc:n \use:c{ cl@#1 } \endgroup } \cs_new:Nn \xassoccnt_report_resetlist:n {% \__xassoccnt_getresetlist:n {#1} \seq_show:N \l__xassoccnt_counterreset_seq% } \cs_new:Nn \xassoccnt_bootstrap_fullreset_list:n {% \group_begin: \def\@elt##1{\seq_gput_right:cn {#1_fullresetlist_seq} {##1}} \use:c{cl@#1} \group_end: } \cs_new:Nn \xassoccnt_local_list:nn {% \group_begin: \def\@elt##1{\seq_gput_right:cn {#1} {##1}} \use:c{cl@#2} \group_end: } \cs_new:Nn \xassoccnt_full_reset_list_recursive:nn { \seq_clear:N \l_tmpa_seq \xassoccnt_local_list:nn {l_tmpa_seq} {#2} \seq_map_inline:Nn \l_tmpa_seq {% \seq_gput_right:cn {#1_fullresetlist_seq} {##1}% \seq_remove_duplicates:c {#1_fullresetlist_seq } % Remove the duplicates \xassoccnt_full_reset_list_recursive:nn {#1} {##1}% Recursive call } } \cs_new:Nn \__xassoccnt_get_full_reset_list:n{% \cs_if_exist:cTF {c@#1} {% \seq_if_exist:cTF {#1_fullresetlist_seq} {% \seq_gclear:c {#1_fullresetlist_seq} }{% \seq_new:c {#1_fullresetlist_seq}% }% \xassoccnt_bootstrap_fullreset_list:n {#1} \seq_map_inline:cn {#1_fullresetlist_seq} {% \xassoccnt_full_reset_list_recursive:nn {#1}{##1}% }% }{% \msg_fatal:nnn{xassoccnt}{nameisnocounter}{#1}% }% } \NewDocumentCommand{\CounterFullResetList}{m}{% \__xassoccnt_get_full_reset_list:n{#1}% } \NewDocumentCommand{\ClearCounterResetList}{sm}{% \cs_if_exist:cT {cl@#2} {% \seq_clear:N \l__xassoccnt_tmpa_seq \xassoccnt_local_list:nn {l__xassoccnt_tmpa_seq} {#2} \seq_map_inline:Nn \l__xassoccnt_tmpa_seq { \IfBooleanTF{#1}{% \CounterWithout*{##1}{#2}% }{% \CounterWithout{##1}{#2}% }% } \IfBooleanF{#1}{% \xassoccnt_default_counterformat:n{#2} }% \cs_gset_eq:cc {cl@#2} {relax}% } } \NewDocumentCommand{\RemoveFromReset}{mm}{% \seq_clear:N \l_tmpa_seq \xassoccnt_local_list:nn {l_tmpa_seq} {#2} \seq_set_from_clist:Nn \l_tmpb_seq {#1} \seq_map_inline:Nn \l_tmpb_seq {% \seq_remove_all:Nn \l_tmpa_seq {##1}% }% \expandafter\xdef\csname cl@#2\endcsname{\empty}% \seq_map_inline:Nn \l_tmpa_seq {% \@addtoreset{##1}{#2}% } } \NewDocumentCommand{\RemoveFromFullReset}{mm}{% \__xassoccnt_get_full_reset_list:n{#2}% \seq_set_from_clist:Nn \l_tmpb_seq {#1} \seq_map_inline:Nn \l_tmpb_seq {% \__xassoccnt_get_full_reset_list:n{##1}% \seq_map_inline:cn {##1_fullresetlist_seq } {% \seq_gremove_all:cn {#2_fullresetlist_seq} {####1}% } \seq_gremove_all:cn {#2_fullresetlist_seq} {##1}% }% \expandafter\xdef\csname cl@#2\endcsname{\empty}% \seq_map_inline:cn {#2_fullresetlist_seq} {% \@addtoreset{##1}{#2}% }% } \NewDocumentCommand{\AddToReset}{mm}{% \__xassoccnt_latexcounter_exists:nTF {#2} { \seq_set_from_clist:Nn \l_tmpa_seq {#1} \seq_map_inline:Nn \l_tmpa_seq {% \__xassoccnt_ifinresetlist:nnF{##1}{#2}{% % Do not add the master counter to its own reset list! \tl_if_eq:nnF { ##1 } {#2} {% \@addtoreset{##1}{#2}% }% } }% End of \seq_map_inline }{% \msg_fatal:nnn{xassoccnt}{nameisnocounter}{#1}% }% } %%%% CounterWithin - Features \NewDocumentCommand{\CounterWithin}{smm}{% \__xassoccnt_latexcounter_exists:nTF {#3} {% \seq_set_from_clist:Nn \l_tmpa_seq {#2} % \seq_map_inline:Nn \l_tmpa_seq {% \__xassoccnt_ifinresetlist:nnF{##1}{#3}{% % Do not add the master counter to its own reset list! \tl_if_eq:nnF { ##1 } {#3} {% \@addtoreset{##1}{#3}% }% \IfBooleanF{#1}{% % Needs overhaul! \cs_set:cpn {the##1} {\csname the#3\endcsname.\arabic{##1}} } } }% End of \seq_map_inline }{% \msg_fatal:nnn{xassoccnt}{nameisnocounter}{#2}% }% } \NewDocumentCommand{\CounterWithout}{smm}{% \seq_clear:N \l_tmpa_seq \xassoccnt_local_list:nn {l_tmpa_seq} {#3} \seq_set_from_clist:Nn \l_tmpb_seq {#2} \seq_map_inline:Nn \l_tmpb_seq {% \IfBooleanF{#1}{% \cs_set:cpn {the##1} {\arabic{##1}}% } \seq_remove_all:Nn \l_tmpa_seq {##1}% }% \cs_set:cpx {cl@#3}{\empty} \seq_map_inline:Nn \l_tmpa_seq {% \@addtoreset{##1}{#3}% } } %%%% The original counter related routines! \cs_set_eq:NN \xassoccnt_standardstepcounter \stepcounter \cs_set_eq:NN \xassoccnt_standardrefstepcounter \refstepcounter \cs_set_eq:NN \xassoccnt_standardaddtocounter \addtocounter \cs_set_eq:NN \xassoccnt_standardsetcounter \setcounter % Needed for Backup/Restore features \AtEndPreamble{ \@ifpackageloaded{alphalph}{% \bool_gset_true:N \l__xassoccnt_alphalphpackage_loaded_bool% }{}% \@ifpackageloaded{hyperref}{% \bool_gset_true:N \l__xassoccnt_hyperrefpackage_loaded_bool% }{}% \@ifpackageloaded{cleveref}{% \bool_gset_true:N \l__xassoccnt_cleverefpackage_loaded_bool% }{} \xassoccnt_trackloadedpackages:n{alphalph,calc,cleveref,hyperref} } \AtEndOfPackage{% \@ifpackageloaded{alphalph}{% \bool_gset_true:N \l__xassoccnt_alphalphpackage_loaded_bool% }{}% } % A little patch for perpage \@ifpackageloaded{perpage}{% \msg_warning:nnn{xassoccnt}{incompatiblepackagenonfatal}{perpage}% Warning \def\pp@cl@end@iii\xassoccnt_standardstepcounter#1{} }{} \AtEndOfPackage{ \PackageInfo{xassoccnt}{2021/11/21 - v\xassoccntpackageversion -- stepping counters simultaneously and other features} \xassoccnt_trackloadedpackages:n{alphalph,calc,cleveref,hyperref} \@ifpackageloaded{calc}{% \msg_warning:nnn{xassoccnt}{incompatiblepackagenonfatal}{calc}% Warning \bool_set_true:N \l__xassoccnt_calcpackage_loaded }{}% } \AtBeginDocument{% % Recheck if `calc` isn't loaded after this package \@ifpackageloaded{calc}{% \bool_if:nF { \l__xassoccnt_calcpackage_loaded } {% \msg_error:nnn{xassoccnt}{packageloadedafterfatal}{calc}% Error! }% }{}% } \cs_new_nopar:Nn \__xassoccnt_laststeppedcounter: {} \cs_new_nopar:Nn \__xassoccnt_lastrefsteppedcounter: {} \cs_new_nopar:Nn \__xassoccnt_lastaddtocounter: {} \cs_new_nopar:Nn \__xassoccnt_lastsetcounter: {} \cs_new_nopar:Nn \__xassoccnt_lastsetdocumentcounter: {} \cs_new:Nn \xassoccnt_counter_container:n {% \seq_new:c{\__xassoccnt_generate_countercontainername:n{#1}}% \cs_new_nopar:cn {__xassoccnt_#1container:} {\__xassoccnt_generate_countercontainername:n{#1}}% } \cs_new:Nn \__xassoccnt_generate_countercontainername:n {% g_xassoccnt_#1cnt_seq% } \clist_new:N \__g_xassoccnt_countercontainer_clist \ifexplversionnew \str_const:Nn \c_xassoccnt_undefined_str {undefined} \str_const:Nn \c_xassoccnt_mastername_str {master} \str_const:Nn \c_xassoccnt_associatedname_str {associated} \str_const:Nn \c_xassoccnt_suspendedname_str {suspended} \else \tl_const:Nn \c_xassoccnt_mastername_str {master}% \tl_const:Nn \c_xassoccnt_associatedname_str {associated}% \tl_const:Nn \c_xassoccnt_suspendedname_str {suspended}% \tl_const:Nn \c_xassoccnt_undefined_str {undefined}% \fi \clist_gset:Nn \__g_xassoccnt_countercontainer_clist {% \c_xassoccnt_undefined_str, \c_xassoccnt_mastername_str, \c_xassoccnt_associatedname_str, \c_xassoccnt_suspendedname_str } % Now generate the containers and the accessing functions \clist_map_function:NN \__g_xassoccnt_countercontainer_clist \xassoccnt_counter_container:n \cs_new:Nn \__xassoccnt_drivercontainer:n {g_xassoccnt_#1cnt_seq} \cs_new:Nn \__xassoccnt_containerremoveduplicates:N { \seq_gremove_duplicates:N #1 } \cs_generate_variant:Nn \__xassoccnt_containerremoveduplicates:N { c } \cs_new_nopar:Nn \__xassoccnt_container_removeduplicates:n { \seq_gremove_duplicates:c{\__xassoccnt_generate_countercontainername:n{#1}}} \cs_new_nopar:Nn \__xassoccnt_container_removecounter:nn { \seq_gremove_all:cn{\__xassoccnt_generate_countercontainername:n{#1}}{#2} } \cs_new_nopar:Nn \__xassoccnt_container_putright:nn { \seq_put_right:cn{\__xassoccnt_generate_countercontainername:n{#1}}{#2} } \cs_new_nopar:Nn \__xassoccnt_container_gputright:nn { \seq_gput_right:cn{\__xassoccnt_generate_countercontainername:n{#1}}{#2} } \cs_new_nopar:Nn \__xassoccnt_container_removeassociated:nn { \seq_gremove_all:cn{\__xassoccnt_drivercontainer:n{#1}}{#2}} \cs_new_nopar:Nn \__xassoccnt_container_gclear:n {\seq_gclear:N #1 } \cs_new_nopar:Nn \__xassoccnt_container_clear:n {\seq_clear:N #1 } \seq_new:N \g__xassoccnt_totalcounter_container \prop_new:N \g_xassoccnt_totalcounter_prop \seq_new:N \g__xassoccnt_supertotalcounter_container \seq_new:N \g_xassoccnt_periodiccounter_container_seq \prop_new:N \g_xassoccnt_periodiccounter_prop \cs_new_nopar:Nn \__xassoccnt_container_perdriver_new:n { \seq_if_exist:cF{ \__xassoccnt_drivercontainer:n {#1} } { % Generate only if there is no driver container sequence so far! \seq_new:c{\__xassoccnt_drivercontainer:n{#1} } } } \cs_generate_variant:Nn \__xassoccnt_container_gclear:N { c } \cs_generate_variant:Nn \__xassoccnt_container_clear:N { c } \cs_new:Nn \__xassoccnt_container_set_from_clist:NN {\seq_set_from_clist:NN #1 #2} \cs_generate_variant:Nn \__xassoccnt_container_set_from_clist:NN { cN, cc, Nc } \cs_new:Nn \__xassoccnt_gcombine_container:NN {% \seq_concat:NNN \l_tmpb_seq #1 #2 \seq_gset_eq:NN #1 \l_tmpb_seq } \cs_generate_variant:Nn \__xassoccnt_gcombine_container:NN { cc } \cs_new:Nn \__xassoccnt_gcombineunique_container:NN {% \__xassoccnt_gcombine_container:NN #1 #2 \__xassoccnt_containerremoveduplicates:N #1 } \cs_generate_variant:Nn \__xassoccnt_gcombineunique_container:NN { cc } \cs_new:Nn \__xassoccnt_adddrivercounter:nn{ % \__xassoccnt_setupcontainers:n{#2}% } \cs_new:Nn \__xassoccnt_removedrivercounter:nn{% \__xassoccnt_container_gclear:c{\__xassoccnt_drivercontainer:n{#2}} % Clear the per-counter container first \__xassoccnt_container_removecounter:nn{\c_xassoccnt_mastername_str}{#2} % Remove the counter #2 from the master container \cs_undefine:c{\__xassoccnt_drivercontainer:n{#2}} } \cs_new:Nn \__xassoccnt_autodefine_associatedcounters:nn {% \bool_if:NTF \g__xassoccnt_autodefine_counters {% \seq_map_inline:Nn #2 { \__xassoccnt_newcounter_ltx:nnn {sloppy}{##1}{} } }{% \keys_set:nn{xassoccnt}{#1} \bool_if:nF{ \l__xassoccnt_autodefine_none }{% % No, some autodefine key has been specified \bool_if:nTF { \l__xassoccnt_autodefine_allcounters } {% \seq_map_inline:Nn #2 { \__xassoccnt_newcounter_ltx:nnn {sloppy}{##1}{} } %loop through the list and do not complain if the counter ##1 already exists }{% \bool_if:nT { \l__xassoccnt_autodefine_associatedcounter }{% \seq_map_inline:Nn #2 { \__xassoccnt_newcounter_ltx:nnn {sloppy}{##1}{}} } } } } } \cs_new:Nn \__xassoccnt_autodefine_drivercounter:nn {% \keys_set:nn{ xassoccnt } {#1} \bool_if:nTF{ \g__xassoccnt_autodefine_counters }{% \__xassoccnt_newcounter_ltx:nnn{#1,sloppy}{#2}{}% }{% \bool_if:nT {\l__xassoccnt_autodefine_drivercounter || \l__xassoccnt_autodefine_allcounters } {% \__xassoccnt_newcounter_ltx:nnn{#1}{#2}{} } } } \cs_new_nopar:Nn \__xassoccnt_expand_totalcountername:n {% xassoccnt@total@#1% } \cs_new:Nn \__xassoccnt_translate_counterlist:n {% \clist_clear:N \l_tmpb_clist \clist_set:Nx \l_tmpa_clist {#1}% \clist_map_inline:Nn \l_tmpa_clist {% \__xassoccnt_is_totalcounter:nTF { ##1 } { \clist_gput_right:Nx \l_tmpb_clist { \__xassoccnt_expand_totalcountername:n {##1} } } { \clist_gput_right:Nn \l_tmpb_clist {##1} } } \clist_set_eq:NN \l_tmpa_clist \l_tmpb_clist } \cs_new:Nn \__xassoccnt_addassociatedcounters:nnn {% \keys_set:nn{xassoccnt}{#1} \clist_set:Nx \l_tmpa_clist {#3} \clist_if_in:NnT \l_tmpa_clist {#2} {% Prevent self-association \msg_warning:nnn{xassoccnt}{selfassociation}{#2}% Warning \clist_gremove_all:Nn \l_tmpa_clist {#2}% }% \clist_remove_duplicates:N \l_tmpa_clist% \__xassoccnt_container_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist \seq_if_in:cnF{\__xassoccnt_mastercontainer:}{#2}{% \__xassoccnt_adddrivercounter:nn{#1}{#2}% Generate the driver counter container \msg_warning:nnnn{xassoccnt}{addwithoutdeclaration}{#2}{#3} % Warning --> associated some counter without declaring in the preamble }% \__xassoccnt_gcombineunique_container:cc{\__xassoccnt_drivercontainer:n{#2}}{l_tmpa_seq} \__xassoccnt_gcombineunique_container:cc{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_associatedname_str}}{l_tmpa_seq} % Do only define if really needed \__xassoccnt_autodefine_associatedcounters:nn {#1} {\l_tmpa_seq } } \cs_new:Nn \xassoccnt_removesuspendedcounters:nn{% \seq_if_exist:cTF{\__xassoccnt_suspendedcontainer:}{% \seq_if_in:cnT{\__xassoccnt_suspendedcontainer:}{#2}{% \__xassoccnt_container_removecounters:nn{suspended}{#2} }% }% } \cs_new:Nn \__xassoccnt_setupcontainers:n{% \__xassoccnt_container_putright:nn{master}{#1} \__xassoccnt_container_removeduplicates:n{master}% \__xassoccnt_container_perdriver_new:n{#1}% } \cs_new:Nn \__xassoccnt_newcounter_ltx:nn{% \group_begin: \keys_set:nn {xassoccnt}{sloppy=false,initial=\c_zero_int,#1} % \__xassoccnt_declare_language_map:nn {\prop_item:Nn \g_xassoccnt_module_data_prop {map-name} }{#2;;\prop_item:Nn \g_xassoccnt_module_data_prop {counter-name}} \cs_if_exist:cTF{c@#2}{% \bool_if:nF {\l__xassoccnt_sloppy_newcounter }{ \msg_error:nnn{xassoccnt}{counteralreadyexists}{#2}% Warning } }{% \newcounter{#2}% \xassoccnt_standardsetcounter{#2}{\l__xassoccnt_initialcountervalue_int} }% \group_end: } \ifexplversionnew \cs_new:Nn \__xassoccnt_newcounter_ltx:nnn{% \group_begin: \keys_set:nn {xassoccnt}{map-name=default,counter-name=#2,sloppy=false,initial=\c_zero_int,#1} \str_set:Nx \l_tmpa_str {#3}% \__xassoccnt_latexcounter_exists:nTF{#2}{% \bool_if:nF {\l__xassoccnt_sloppy_newcounter }{% \msg_error:nnn{xassoccnt}{counteralreadyexists}{#2}% Warning } }{% \str_if_empty:NTF \l_tmpa_str {% \newcounter{#2}% }{% \newcounter{#2}[#3]% }% \xassoccnt_standardsetcounter{#2}{\l__xassoccnt_initialcountervalue_int}% } \group_end: } \else \cs_new:Nn \__xassoccnt_newcounter_ltx:nnn{% \keys_set:nn {xassoccnt}{sloppy=false,initial=\c_zero_int,#1} \tl_set:Nx \l_tmpa_tl {#3} \__xassoccnt_latexcounter_exists:nTF{#2}{% \bool_if:nF {\l__xassoccnt_sloppy_newcounter }{ \msg_error:nnn{xassoccnt}{counteralreadyexists}{#2}% Warning } }{% \tl_if_empty:NTF \l_tmpa_tl {% \newcounter{#2}% }{% \newcounter{#2}[#3]% }% \xassoccnt_standardsetcounter{#2}{\l__xassoccnt_initialcountervalue_int} } } \fi \cs_generate_variant:Nn \__xassoccnt_newcounter_ltx:nnn {nVn} \cs_new:Nn \xassoccnt_declareassociatedcounters:nnn {% \__xassoccnt_container_if_in:cnTF{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_mastername_str}:}{#2}{% % Not contained in the driver counter list \__xassoccnt_addassociatedcounters:nnn{#1}{#2}{#3}% }{% % Check first if there is a potential cross association \__xassoccnt_adddrivercounter:nn{#1}{#2}% \xassoccnt_is_associatedtocounter:nnTF{#3}{#2}{% \msg_fatal:nnnn{xassoccnt}{crossassociation}{#2}{#3}% Fatal message % Not necessary unless the fatal message above is removed \__xassoccnt_container_removecounter:cn{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_mastername_str}:}{#2} }{% No, we don't try to cross-associate two counters \__xassoccnt_addassociatedcounters:nnn{#1}{#2}{#3}% }% }% \__xassoccnt_container_removeduplicates:n{\__xassoccnt_drivercontainer:n{#2}} \__xassoccnt_autodefine_drivercounter:nn { }{#2} } \prg_new_conditional:Nnn \xassoccnt_is_drivercounter:n {T,F,TF} { \seq_if_in:cnTF{\__xassoccnt_mastercontainer:}{#1}{% \prg_return_true: }{ \prg_return_false: } } \prg_new_conditional:Nnn \__xassoccnt_container_if_in:Nn { T, F, TF } { \seq_if_in:NnTF #1 {#2}{% \prg_return_true: }{ \prg_return_false: } } \cs_generate_variant:Nn \__xassoccnt_container_if_in:NnTF { NxTF, cnTF,cxTF } \cs_generate_variant:Nn \__xassoccnt_container_if_in:NnT { NxT,cnT,cxT } \cs_generate_variant:Nn \__xassoccnt_container_if_in:NnF { NxF,cnF,cxF } \prg_new_conditional:Nnn \xassoccnt_is_associatedcounter:n {T,F,TF} { \__xassoccnt_container_if_in:cnTF{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_associatedname_str}}{#1}{% \prg_return_true: }{ \prg_return_false: } } \prg_new_conditional:Nnn \xassoccnt_is_suspendedcounter:n {TF,T,F} {% \__xassoccnt_container_if_in:cxTF{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_suspendedname_str}}{#1}{% \prg_return_true: }{% \prg_return_false: }% } \prg_new_conditional:Nnn \xassoccnt_is_associatedtocounter:nn {T,F,TF} { \xassoccnt_is_drivercounter:nTF{#1}{% \seq_if_in:cnTF{\__xassoccnt_drivercontainer:n{#1}}{#2}{% \prg_return_true: }{% \prg_return_false: }% }{% \prg_return_false: }% } %% Clearing functions \cs_new:Nn \xassoccnt_remove_associatedcounter:nnn { \__xassoccnt_container_removeassociated:nn{#2}{#3} \__xassoccnt_container_removecounter:nn{\c_xassoccnt_associatedname_str}{#3}% } \cs_new:Nn \xassoccnt_remove_associatedcounters:nnn {% \clist_set:Nx \l_tmpa_clist {#3} \seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist \seq_map_inline:Nn \l_tmpa_seq { \xassoccnt_remove_associatedcounter:nnn{#1}{#2}{##1} } % Remove one counter after another one! } \cs_new:Nn \xassoccnt_gclear_associatedcounters:nn {% \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#2}} { \__xassoccnt_container_removecounter:nn{\c_xassoccnt_associatedname_str}{##1} }% Remove from associated list container \__xassoccnt_container_gclear:c {\__xassoccnt_drivercontainer:n{#2} } } %%%%%%%%%%%%%%%%%%%%% User interface routines \NewDocumentCommand{\SuspendCounters}{O{}m}{% \keys_set:nn { xassoccnt }{#1}% \clist_set:Nx \l_tmpa_clist {#2}% \clist_map_inline:Nn \l_tmpa_clist { \__xassoccnt_container_gputright:nn{\c_xassoccnt_suspendedname_str}{##1} } % Code for removal of duplicates \__xassoccnt_container_removeduplicates:n{\c_xassoccnt_suspendedname_str} } \cs_new_protected:Nn \xassoccnt_cascade_suspendcounters:nn {% \keys_set:nn { xassoccnt }{#1}% \clist_set:Nx \l_tmpa_clist {#2}% % Loop through the several counters! \clist_map_inline:Nn \l_tmpa_clist {% % Cascading requires knowledge of the counter reset list, so get this! \xassoccnt_countersinresetlist:n {##1} \int_compare:nNnT {\l_xassoccnt_resetlist_counter} > {0} {% \__xassoccnt_getresetlist:n {##1}% \seq_map_inline:Nn \l__xassoccnt_counterreset_seq {% \__xassoccnt_container_gputright:nn{\c_xassoccnt_suspendedname_str}{####1} % Recursively suspend all other counters that are on the reset list of #2 and hunt down their reset lists as well. \xassoccnt_cascade_suspendcounters:nn{#1}{####1}% }% }% End \int_compare: % Now add ##1 \__xassoccnt_container_gputright:nn{\c_xassoccnt_suspendedname_str}{##1} }% End \clist_map_inline: % Remove duplicates \__xassoccnt_container_removeduplicates:n{\c_xassoccnt_suspendedname_str} \bool_set_false:N \l__xassoccnt_cascade_suspension_bool } \NewDocumentCommand{\CascadeSuspendCounters}{O{}m}{% \xassoccnt_cascade_suspendcounters:nn {#1}{#2}% } \NewDocumentCommand{\ShowSuspendedCounters}{}{% \seq_use:cn { \__xassoccnt_generate_countercontainername:n{\c_xassoccnt_suspendedname_str}} {\par} } \NewDocumentCommand{\ResumeSuspendedCounters}{O{}m}{% \clist_set:Nx \l_tmpa_clist {#2}% \clist_map_inline:Nn \l_tmpa_clist { \__xassoccnt_container_removecounter:nn{\c_xassoccnt_suspendedname_str}{##1}% } } \NewDocumentCommand{\ResumeAllSuspendedCounters}{O{}}{% \seq_if_exist:cTF{\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_suspendedname_str}} {% \seq_gclear:c {\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_suspendedname_str}}% }{% % A warning message later on here! \typeout{Container\space\__xassoccnt_generate_countercontainername:n{\c_xassoccnt_suspendedname_str}\space does\space not\space exist}% }% } %%%% Associated counters section \NewDocumentCommand{\DeclareAssociatedCounters}{omm}{% \IfValueTF{#1}{% \keys_set:nn {xassoccnt} {#1} \xassoccnt_declareassociatedcounters:nnn{#1}{#2}{#3}% }{% % Disable the automated definition of counters explicitly \xassoccnt_declareassociatedcounters:nnn{autodefine=none}{#2}{#3}% } } \NewDocumentCommand{\AddDriverCounter}{O{}m}{% \xassoccnt_adddrivercounter:nn{#1}{#2} } \NewDocumentCommand{\AddAssociatedCounters}{O{}mm}{% %Check first if we are in document or in preamble: \ifx\@onlypreamble\@notprerr % Explicitly disable autodefinition of counters \__xassoccnt_addassociatedcounters:nnn{#1,autodefine=none}{#2}{#3}% \else % No, it's the preamble, fall back to `\DeclareAssociatedCounters \DeclareAssociatedCounters[#1]{#2}{#3} \fi } \NewDocumentCommand{\RemoveDriverCounter}{O{}m}{% \__xassoccnt_removedrivercounter:nn{#1}{#2}% } \NewDocumentCommand{\GetDriverCounter}{O{,}m}{% \seq_clear:N \l_tmpa_seq \seq_map_inline:cn {\__xassoccnt_mastercontainer:}{% \seq_if_in:cnT{\__xassoccnt_drivercontainer:n{##1}}{#2}{% \seq_put_right:Nn \l_tmpa_seq {##1} }% }% \seq_if_empty:NTF \l_tmpa_seq{--}{\seq_use:Nn \l_tmpa_seq {#1}} } \prg_new_conditional:Nnn \__xassoccnt_ifis_latexcounter:n {T,F,TF} {% \cs_if_exist:cTF {c@#1}{% \prg_return_true: }{% \prg_return_false: }% } \prg_new_conditional:Nnn \__xassoccnt_latexcounter_exists:n {T,F,TF} {% \cs_if_exist:cTF {c@#1}{% \prg_return_true: }{% \prg_return_false: }% } \NewDocumentCommand{\IfIsDocumentCounterTF}{om+m+m}{% \__xassoccnt_ifis_latexcounter:nTF {#2}{ #3 } { #4 } } \NewDocumentCommand{\IfIsDocumentCounterT}{om+m}{% \__xassoccnt_ifis_latexcounter:nT {#2}{ #3 } } \NewDocumentCommand{\IfIsDocumentCounterF}{om+m}{% \__xassoccnt_ifis_latexcounter:nF {#2}{ #3 } } \NewDocumentCommand{\IsDriverCounter}{O{}mmm}{% \xassoccnt_is_drivercounter:nTF{#2}{#3}{#4}% } \NewDocumentCommand{\IsAssociatedToCounter}{O{}mmmm}{% \xassoccnt_is_associatedtocounter:nnTF{#2}{#3}{% #4% }{% #5% }% } \NewDocumentCommand{\IsAssociatedCounter}{O{}mmm}{% \xassoccnt_is_associatedcounter:nTF{#2}{#3}{#4}% } \NewDocumentCommand{\IsSuspendedCounter}{O{}mmm}{% \xassoccnt_is_suspendedcounter:nTF{#2}{#3}{#4}% } \NewDocumentCommand{\IfExistsDriverCounterList}{mmm}{% \seq_if_exist:cTF{\__xassoccnt_drivercontainer:n{#1}}{% #2% }{% #3% }% } \NewDocumentCommand{\RemoveAssociatedCounters}{O{}mm}{% \xassoccnt_remove_associatedcounters:nnn{#1}{#2}{#3} } \NewDocumentCommand{\RemoveAssociatedCounter}{O{}mm}{% \xassoccnt_remove_associatedcounter:nnn{#1}{#2}{#3} } \NewDocumentCommand{\ClearAssociatedCounters}{O{}m}{% \xassoccnt_gclear_associatedcounters:nn{#1}{#2}% } \NewDocumentCommand{\ShowAssociatedCountersList}{m}{% {\color{red}% \fbox{#1}~has~\seq_use:cn {\__xassoccnt_drivercontainer:n{#1}}{\par\noindent} } } \NewDocumentCommand{\ShowAllAssociatedCounters}{}{% {\color{brown}% \seq_use:cn {\__xassoccnt_associatedcontainer:}{\par\noindent} } } \NewDocumentCommand{\ShowDriverCounterList}{}{% {\color{blue}% \seq_use:cn{\__xassoccnt_mastercontainer:}{\par\bigskip\noindent} }% } \cs_new:Nn \__xassoccnt_step_associatedcounters:n {% \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#1} } { \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#1} } {% \xassoccnt_addtocounter{##1}{\c_one_int} }% }% % End of \seq_if_exist } \prg_new_conditional:Nnn \__xassoccnt_is_totalcounter:n {T,F,TF} {% \seq_if_in:NxTF \g__xassoccnt_totalcounter_container { \__xassoccnt_expand_totalcountername:n {#1} } { \prg_return_true: }{% \prg_return_false: }% } \cs_new_nopar:Nn \__xassoccnt_translate_countername:Nn {% \tl_set:Nn #1 {#2}% \seq_if_in:NxTF \g__xassoccnt_supertotalcounter_container {#2} {% \tl_set:Nn #1 {\__xassoccnt_expand_totalcountername:n {#2} }% }{% } } \cs_generate_variant:Nn \__xassoccnt_translate_countername:Nn {cn} %% More generic macros (hidding the internal features of the lists) \prop_new:N \g_xassoccnt_feature_prop \cs_new_nopar:Nn \xassoccnt_container_property: {prop} \cs_new_nopar:Nn \xassoccnt_container_datatype: {seq} \cs_new:Nn \__xassoccnt_construct_cs:n {% \use:c{\xassoccnt_container_datatype:#1} } \cs_new:Nn \xassoccnt_container_new:N {% \__xassoccnt_construct_cs:n{_new:N} #1 } \cs_new:Nn \xassoccnt_container_clear:N {% \__xassoccnt_construct_cs:n{_clear:N} #1 } \cs_new:Nn \xassoccnt_container_gclear:N {% \__xassoccnt_construct_cs:n{_gclear:N} #1 } \cs_new:Nn \xassoccnt_container_set_eq:NN {% \__xassoccnt_construct_cs:n{_set_eq:NN} #1 #2 } \cs_new:Nn \xassoccnt_container_gset_eq:NN {% \__xassoccnt_construct_cs:n{_gset_eq:NN} #1 #2 } \cs_new:Nn \xassoccnt_container_put_right:Nn {% \__xassoccnt_construct_cs:n{_put_right:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_gput_right:Nn {% \__xassoccnt_construct_cs:n{_gput_right:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_put_left:Nn {% \__xassoccnt_construct_cs:n{_put_left:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_gput_left:Nn {% \__xassoccnt_construct_cs:n{_gput_left:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_get_item:Nn {% \__xassoccnt_construct_cs:n{_get_item:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_remove_duplicates:N {% \__xassoccnt_construct_cs:n{_remove_duplicates:N} #1 } \cs_new:Nn \xassoccnt_container_gremove_duplicates:N {% \__xassoccnt_construct_cs:n{_gremove_duplicates:N} #1 } \cs_new:Nn \xassoccnt_container_remove_all:Nn {% \__xassoccnt_construct_cs:n{_remove_all:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_gremove_all:Nn {% \__xassoccnt_construct_cs:n{_gremove_all:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_map_inline:Nn {% \__xassoccnt_construct_cs:n{_map_inline:Nn} #1 {#2} } \cs_new:Nn \xassoccnt_container_count:N {% \__xassoccnt_construct_cs:n{_count:N} #1 } \cs_new:Nn \xassoccnt_container_set_from_clist:NN {% \__xassoccnt_construct_cs:n{_set_from_clist:NN} #1 #2 } \cs_new:Nn \xassoccnt_container_gset_from_clist:NN {% \__xassoccnt_construct_cs:n{_gset_from_clist:NN} #1 #2 } \cs_new:Nn \xassoccnt_container_remove_by_clist:Nn {% \clist_set:Nn \l_tmpa_tl {#2} \clist_map_inline:Nn \l_tmpa_tl {% \xassoccnt_container_remove_all:Nn #1 {##1} } } \cs_new:Nn \xassoccnt_container_use:Nn {% \__xassoccnt_construct_cs:n{_use:Nn} #1 {#2} } \cs_new_nopar:Nn \xassoccnt_container_map_break: {% \__xassoccnt_construct_cs:n{_map_break:} } \cs_new:Nn \xassoccnt_container_concat:NNN {% \__xassoccnt_construct_cs:n{_concat:NNN} #1 #2 #3 } \cs_new:Nn \xassoccnt_container_gconcat:NNN {% \__xassoccnt_construct_cs:n{_gconcat:NNN} #1 #2 #3 } \prg_new_conditional:Nnn \xassoccnt_container_if_exist:N {TF,T,F}% { \seq_if_exist:NTF #1 {\prg_return_true:} {\prg_return_false:} } \prg_new_conditional:Nnn \xassoccnt_container_if_exist:c {TF,T,F}% { \seq_if_exist:cTF {#1} {\prg_return_true:} {\prg_return_false:} } \prg_new_conditional:Nnn \xassoccnt_container_if_in:Nn {TF,T,F}% { \__xassoccnt_construct_cs:n{_if_in:NnTF} #1 {#2} {\prg_return_true:} {\prg_return_false:} } \prg_new_conditional:Nnn \xassoccnt_container_if_empty:N {TF,T,F}% { \__xassoccnt_construct_cs:n{_if_empty:NTF} {\prg_return_true:} {\prg_return_false:} } \prg_new_conditional:Nnn \xassoccnt_container_if_empty:c {T,F,TF} { \__xassoccnt_construct_cs:n{_if_empty:cTF} {\prg_return_true:} {\prg_return_false:} } \cs_generate_variant:Nn \xassoccnt_container_new:N {c} \cs_generate_variant:Nn \xassoccnt_container_clear:N {c} \cs_generate_variant:Nn \xassoccnt_container_gclear:N {c} \cs_generate_variant:Nn \xassoccnt_container_set_eq:NN {cN,Nc,cc} \cs_generate_variant:Nn \xassoccnt_container_gset_eq:NN {cN,Nc,cc} \cs_generate_variant:Nn \xassoccnt_container_put_right:Nn {NV,Nv,No,Nx,cn,cV,cv,co,cx} \cs_generate_variant:Nn \xassoccnt_container_gput_right:Nn {NV,Nv,No,Nx,cn,cV,cv,co,cx} \cs_generate_variant:Nn \xassoccnt_container_put_left:Nn {NV,Nv,No,Nx,cn,cV,cv,co,cx} \cs_generate_variant:Nn \xassoccnt_container_gput_left:Nn {NV,Nv,No,Nx,cn,cV,cv,co,cx} \cs_generate_variant:Nn \xassoccnt_container_get_item:Nn {cn} \cs_generate_variant:Nn \xassoccnt_container_remove_duplicates:N {c} \cs_generate_variant:Nn \xassoccnt_container_gremove_duplicates:N {c} \cs_generate_variant:Nn \xassoccnt_container_concat:NNN {ccc} \cs_generate_variant:Nn \xassoccnt_container_gconcat:NNN {ccc} \cs_generate_variant:Nn \xassoccnt_container_remove_all:Nn {cn} \cs_generate_variant:Nn \xassoccnt_container_gremove_all:Nn {cn} \cs_generate_variant:Nn \xassoccnt_container_remove_by_clist:Nn {cn} \cs_generate_variant:Nn \xassoccnt_container_map_inline:Nn {cn} \cs_generate_variant:Nn \xassoccnt_container_count:N {c} \cs_generate_variant:Nn \xassoccnt_container_set_from_clist:NN {cN,cc,Nc} \cs_generate_variant:Nn \xassoccnt_container_gset_from_clist:NN {cN,cc,Nc} \cs_generate_variant:Nn \xassoccnt_container_use:Nn {cn} \cs_generate_variant:Nn \xassoccnt_container_if_in:NnTF {NVTF,NvTF,NoTF,NxTF,cnTF,cVTF,cvTF,coTF,cxTF} \cs_generate_variant:Nn \xassoccnt_container_if_in:NnT {NVT,NvT,NoT,NxT,cnT,cVT,cvT,coT,cxT} \cs_generate_variant:Nn \xassoccnt_container_if_in:NnF {NVF,NvF,NoF,NxF,cnF,cVF,cvF,coF,cxF} \cs_generate_variant:Nn \xassoccnt_container_if_exist:NTF {cTF} \cs_generate_variant:Nn \xassoccnt_container_if_exist:NT {cT} \cs_generate_variant:Nn \xassoccnt_container_if_exist:NF {cF} \bool_new:N \l__xassoccnt_feature_bool \bool_new:N \l__xassoccnt_sublists_bool \bool_new:N \xassoccnt_cascading_bool \bool_new:N \xassoccnt_keep_after_restore_bool \tl_new:N \__xassoccnt_featurename_tl \tl_new:N \__xassoccnt_backup_id_tl \tl_new:N \__xassoccnt_restore_id_tl \cs_new_nopar:Nn \xassoccnt_featurename_prop:{% xassoccnt_feature_\__xassoccnt_featurename_tl _prop% } \cs_new:Nn \xassoccnt_feature_prop_setkey:nn {% \prop_gput:cnn {\xassoccnt_featurename_prop:} {#1} {#2}% } \keys_define:nn {xassoccnt_container} { feature .bool_set:N=\l__xassoccnt_feature_bool, sublists .bool_set:N=\l__xassoccnt_sublists_bool, name .tl_set:N=\l__xassoccnt_countergroup_name_tl, multiple .bool_set:N=\l__xassoccnt_multiple_bool, featurename .tl_set:N=\l__xassoccnt_feature_name_tl, .code:n={ \xassoccnt_feature_prop_setkey:nn{featurename}{##1}}, publicname .code:n={\xassoccnt_feature_prop_setkey:nn{publicname}{##1}}, cascading .bool_set:N={\xassoccnt_cascading_bool}, resetbackup .bool_set:N={ \l__xassoccnt_resetbackupcounters_bool }, backup-id .tl_set:N={ \__xassoccnt_backup_id_tl }, restore-id .tl_set:N={ \__xassoccnt_restore_id_tl }, keep-after-restore .bool_set:N= {\xassoccnt_keep_after_restore_bool } } \seq_new:N \g__xassoccnt_feature_seq % The master control !!!! \seq_new:N \g__xassoccnt_sublists_seq \cs_new:Nn \xassoccnt_create_featurename:n { xassoccnt_feature_#1 } \cs_new:Nn \xassoccnt_featurename:n { xassoccnt_feature_#1 } \cs_new:Nn \xassoccnt_feature_subcontainer:nn { \xassoccnt_featurename:n{#1}_#2 } \cs_new:Nn \xassoccnt_feature_group_container:n { \xassoccnt_featurename:n{#1}_group } % This holds the names of the several sub containers %% A feature is actually a super container that has sub containers (i.e. a list/seq of counters that have this feature ) %% Example the feature 'coupledcounters' will have a group countainer, that holds the name of the counter groups %% Each counter group (of a feature) itself will have a subcontainer where the counter names are stored. %% Multiple counters may occur in the per - feature - specific container list \cs_new:Nn \xassoccnt_create_container:nN { \keys_set:nn {xassoccnt_container} {#1} \xassoccnt_container_if_exist:NTF #2 {% % A existing container must not be redefined \msg_error:nnn{xassoccnt}{containeralreadyexists}{#2}% Error! }{ \xassoccnt_container_new:N {#2} } } \cs_generate_variant:Nn \xassoccnt_create_container:nN {nc} \cs_new:Nn \xassoccnt_add_feature:nn {% \tl_set:Nn \__xassoccnt_featurename_tl {#2}% \prop_clear_new:c {\xassoccnt_featurename_prop:}% \keys_set:nn {xassoccnt_container} {#1} \seq_if_exist:NT \g__xassoccnt_feature_seq {% Unique addition of a feature only! \seq_if_in:NnF \g__xassoccnt_feature_seq {#2} {% \seq_gput_right:Nn \g__xassoccnt_feature_seq {#2}% \xassoccnt_create_container:nc {feature=true} { \xassoccnt_featurename:n { #2 } } \bool_if:NTF \l__xassoccnt_sublists_bool { \xassoccnt_create_container:nc {feature=false} {\xassoccnt_feature_group_container:n{#2} } \seq_gput_right:NV \g__xassoccnt_sublists_seq {\c_one_int } } { \seq_gput_right:NV \g__xassoccnt_sublists_seq {\c_zero_int }} }% End of \seq_if_in } } \prg_new_conditional:Nnn \xassoccnt_feature_if_in:N {TF,T,F} { \seq_if_in:NnTF { \g__xassoccnt_feature_seq } {#1} {\prg_return_true:} {\prg_return_false:} } \cs_generate_variant:Nn \xassoccnt_feature_if_in:NTF {c} \cs_generate_variant:Nn \xassoccnt_feature_if_in:NT {c} \cs_generate_variant:Nn \xassoccnt_feature_if_in:NF {c} \cs_new:Nn \xassoccnt_remove_feature:nn {% % keys from #1 to be set \seq_if_exist:NTF \g__xassoccnt_feature_seq {% \seq_remove_all:Nn \g__xassoccnt_feature_seq {#2} \cs_undefine:c { \xassoccnt_featurename:n { #2 }} % Remove the sequence as a macro }{ % To be done! } } \cs_new:Nn \xassoccnt_add_container_to_feature:nn {% \xassoccnt_feature_if_in:nTF { #1 } {% \xassoccnt_add_to_containerlist:cn { \xassoccnt_featurename:n { feature#1 }} {#2 } }{% % To be done } } \cs_new:Nn \xassoccnt_add_to_containerlist:Nn {% \clist_set:Nx \l_tmpa_clist {#2} \xassoccnt_container_if_exist:NTF #1 {% \clist_map_inline:Nn \l_tmpa_clist {% \xassoccnt_container_put_right:Nn #1 {##1}% Append data } }{ \xassoccnt_create_container:nc {feature=false} {#1} \xassoccnt_container_set_from_clist:NN #1 \l_tmpa_clist } } \cs_new:Nn \xassoccnt_feature_add_to_subcontainer:nnn {% \keys_set:nn{xassoccnt_container} {multiple=false,#1} \clist_set:Nx \l_tmpa_clist {#3} \clist_map_inline:Nn \l_tmpa_clist {% \xassoccnt_container_if_in:cnTF {\xassoccnt_feature_subcontainer:nn{\l__xassoccnt_feature_name_tl}{#2}} {##1} {% \bool_if:NT \l__xassoccnt_multiple_bool {% Add only if `multiple=true` was specified \xassoccnt_container_put_right:cn {\xassoccnt_feature_subcontainer:nn{\l__xassoccnt_feature_name_tl}{#2}} {##1} } }{% \xassoccnt_container_put_right:cn {\xassoccnt_feature_subcontainer:nn{\l__xassoccnt_feature_name_tl}{#2}} {##1} } } % End of map_inline } \cs_new:Nn \xassoccnt_feature_add_to_group_container:nn {% \keys_set:nn{xassoccnt_container} {multiple=false,#1} \xassoccnt_add_to_containerlist:cn {\xassoccnt_feature_group_container:n{\l__xassoccnt_feature_name_tl}} {#2}% Create the container first. \bool_if:NF \l__xassoccnt_multiple_bool {% \xassoccnt_container_remove_duplicates:c { \xassoccnt_feature_group_container:n{\l__xassoccnt_feature_name_tl} }% } \xassoccnt_container_if_exist:cF {\xassoccnt_feature_subcontainer:nn{\l__xassoccnt_feature_name_tl}{#2}} { \xassoccnt_create_container:nc {feature=false} {\xassoccnt_feature_subcontainer:nn{\l__xassoccnt_feature_name_tl}{#2}} % Creating and filling of the subcontainer } } \cs_generate_variant:Nn \xassoccnt_add_to_containerlist:Nn {cn} \NewDocumentCommand{\AddFeature}{O{sublists=false}m}{% \xassoccnt_add_feature:nn {#1} {#2} } \NewDocumentCommand{\RemoveFeature}{O{}m}{% \xassoccnt_remove_feature:nn {#1} {#2} } \NewDocumentCommand{\NewContainer}{m}{% \xassoccnt_create_container:Nc {feature=false} {#1} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% New Backup Counter features \cs_new:Nn \__xassoccnt_declare_countergroupname:nn {% \xassoccnt_container_if_exist:cF { \xassoccnt_feature_group_container:n{#1}{#2} } {% \xassoccnt_feature_add_to_group_container:nn{multiple=false,featurename=#1}{#2}% \seq_new:c { l_#1_#2_id_seq}% \prop_new:c { l_#1_#2_prop }% Setup a feature property sub list for values } } %\input{xassoccnt_backupfeatures_example} \cs_new:Nn \xassoccnt_backup_id_seq:n {% l_backupcounters_#1_id_seq% } \cs_new:Nn \xassoccnt_declare_backupcountersgroupname:n {% \xassoccnt_container_if_exist:cF { \xassoccnt_feature_group_container:n{backupcounters}{#1} } { \prop_new:c { l_backupcounters_#1_prop } \seq_new:c { \xassoccnt_backup_id_seq:n{#1}} % \xassoccnt_feature_add_to_group_container:nn{multiple=false,featurename=backupcounters}{#1}% } } \NewDocumentCommand{\DeclareBackupCountersGroupName}{m}{% \__xassoccnt_declare_countergroupname:nn{backupcounters}{#1}% } \cs_new:Nn \xassoccnt_assign_backupcounters_to_group:nn {% \keys_set:nn {xassoccnt_container} {name={},multiple=false,#1} \tl_if_empty:NT \l__xassoccnt_countergroup_name_tl {% \msg_warning:nnn{xassoccnt}{emptybackupcountergroup}{xassoccnt_assign_backupcounters_to_group}{}% \keys_set:nn {xassoccnt_container} {multiple=false,#1,name={\xassoccnt_extract_moduledata:n{scratchname}}} } % Check first if the counter group name is already registered \xassoccnt_container_if_exist:cF { \xassoccnt_feature_subcontainer:nn{backupcounters}{\l__xassoccnt_countergroup_name_tl} } {% \xassoccnt_declare_backupcountersgroupname:n{\l__xassoccnt_countergroup_name_tl}% }% \xassoccnt_feature_add_to_subcontainer:nnn{multiple=false,#1,featurename=backupcounters}{\l__xassoccnt_countergroup_name_tl}{#2}% } % This macro assigns counters to a backup group% \NewDocumentCommand{\AssignBackupCounters}{O{}m}{% \keys_set:nn{xassoccnt_container} {#1} \xassoccnt_assign_backupcounters_to_group:nn {#1}{#2}% \bool_if:NTF \xassoccnt_cascading_bool {% % Set the starter counter name to the list defined by `name=...` \AddBackupCounters[#1]{#2}% % Ok, let's get the all counters in the reset list of #2 \CounterFullResetList{#2}% \seq_if_empty:cF {#2_fullresetlist_seq} {% \seq_map_inline:cn { #2_fullresetlist_seq} {\AddBackupCounters[#1]{##1} }% }% }{% \AddBackupCounters[#1]{#2}% } } \NewDocumentCommand{\AddBackupCounters}{O{}m}{% \keys_set:nn {xassoccnt_container} {multiple=false,#1} \xassoccnt_container_if_exist:cTF { \xassoccnt_feature_subcontainer:nn{backupcounters}{\l__xassoccnt_countergroup_name_tl } } {% \xassoccnt_feature_add_to_subcontainer:nnn{#1,featurename=backupcounters}{\l__xassoccnt_countergroup_name_tl}{#2}% }{% \msg_warning:nnxx{xassoccnt}{addbackupcountergroupundefined}{AddBackupCounters}{\l__xassoccnt_countergroup_name_tl}% Warning about undefined counter group }% } \bool_new:N \l__xassoccnt_is_backupcounter_bool \prg_new_conditional:Nnn \__xassoccnt_is_backupcounter:N {TF,T,F} {% \xassoccnt_container_map_inline:cn { \xassoccnt_feature_group_container:n{backupcounters} } {% \bool_set_false:N \l__xassoccnt_is_backupcounter_bool \xassoccnt_container_if_in:cxT { \xassoccnt_feature_subcontainer:nn{backupcounters}{##1} } {#1} { \bool_set_true:N \l__xassoccnt_is_backupcounter_bool \xassoccnt_container_map_break: } } \bool_if:NTF \l__xassoccnt_is_backupcounter_bool {\prg_return_true:} {\prg_return_false:} } \cs_generate_variant:Nn \__xassoccnt_is_backupcounter:NTF {c } \cs_generate_variant:Nn \__xassoccnt_is_backupcounter:NT { c } \cs_generate_variant:Nn \__xassoccnt_is_backupcounter:NF { c } \cs_new:Nn \xassoccnt_is_backupcounter:NTF { % \__xassoccnt_is_backupcounter:NTF {#1} {#2} {#3} } \cs_new:Nn \xassoccnt_is_backupcounter:NT { % \__xassoccnt_is_backupcounter:NT {#1} {#2}% } \cs_new:Nn \xassoccnt_is_backupcounter:NF { % \__xassoccnt_is_backupcounter:NF {#1} {#2}% } %%%% \cs_new:Nn \__xassoccnt_backup_renew_theHmacros:nn {% \bool_if:NT \l__xassoccnt_hyperrefpackage_loaded_bool {% \cs_if_exist:cT {theH#1} {% \cs_gset_eq:cc {xassoccnt_#2_theH#1} {theH#1}% \expandafter\renewcommand\csname theH#1\endcsname{xassoccnt.#1_#2.\use:c{the#1}}% }% } } \cs_new:Nn \__xassoccnt_backup_restore_theHmacros:NN {% \bool_if:NT \l__xassoccnt_hyperrefpackage_loaded_bool {% \cs_if_exist:cT {theH#1} {% \expandafter\renewcommand\csname theH#1\endcsname{xassoccnt.#1_#2.\use:c{the#1}}% }% }% } \cs_new:Nn \__xassoccnt_prepare_backupid:nn{% #1#2 } \cs_new:Nn \__xassoccnt_prepare_backupid:nnn{% #1#2#3 } \cs_new:Nn \xassoccnt_feature_subproplist:NN {% l_#1_#2_prop% } \cs_new:Nn \xassoccnt_backup_subproplist:n {% l_\xassoccnt_extract_moduledata:n{backupfeaturename}_#1_prop% } \cs_new:Nn \xassoccnt_backupstore_property:Nnn{% % \prop_gput:Nnx {\xassoccnt_feature_subproplist:NN {\xassoccnt_extract_moduledata:n{backupfeaturename}{#1}}} { #2 } {#3}% Must be expanded } \cs_generate_variant:Nn \xassoccnt_backupstore_property:Nnn {cnn,cxx,Nxx} \cs_generate_variant:Nn \xassoccnt_backup_subproplist:n {V} \cs_generate_variant:Nn \xassoccnt_backup_subproplist:NN {Nc,cc} \cs_generate_variant:Nn \__xassoccnt_backup_restore_theHmacros:NN {Nc,cc}%,cx} \NewDocumentCommand{\BackupCounterValues}{O{}m}{% \keys_set:nn {xassoccnt_container} { backup-id={}, restore-id={}, resetbackup=true, cascading=false, multiple=false, name={\xassoccnt_extract_moduledata:n {scratchname}}, #1 } \tl_if_empty:NT \__xassoccnt_backup_id_tl {% \msg_fatal:nnxx{xassoccnt}{nobackupid}{\l__xassoccnt_countergroup_name_tl}{BackupCounterValues}% Fatal Error } \tl_if_empty:NT \__xassoccnt_restore_id_tl {% \msg_fatal:nnxx{xassoccnt}{nobackupid}{\l__xassoccnt_countergroup_name_tl}{BackupCounterValues}% Fatal Error } % Prevent multiple usages of the same backup id per counter group \seq_if_in:cVTF {\xassoccnt_backup_id_seq:n{\l__xassoccnt_countergroup_name_tl}} { \__xassoccnt_backup_id_tl } {% \msg_fatal:nnxxx{xassoccnt}{duplicatebackupid}{\__xassoccnt_backup_id_tl}{\l__xassoccnt_countergroup_name_tl}{BackupCounterValues}% Fatal Error }{% \seq_put_right:cV {\xassoccnt_backup_id_seq:n{\l__xassoccnt_countergroup_name_tl}} { \__xassoccnt_backup_id_tl }% \seq_remove_duplicates:c {\xassoccnt_backup_id_seq:n{\l__xassoccnt_countergroup_name_tl}} } \bool_if:NTF \xassoccnt_cascading_bool {% % Set the starter counter name to the list defined by `name=...` \AddBackupCounters[#1]{#2}% % Ok, let's get the all counters in the reset list of #2 \CounterFullResetList{#2}% \seq_if_empty:cF {#2_fullresetlist_seq} {% \seq_map_inline:cn { #2_fullresetlist_seq} {\AddBackupCounters[#1]{##1} }% }% }{% \AddBackupCounters[#1]{#2}% } \seq_map_inline:cn {\xassoccnt_feature_subcontainer:nn{\xassoccnt_extract_moduledata:n{backupfeaturename}}{\l__xassoccnt_countergroup_name_tl }} {% \xassoccnt_backupstore_property:cxx {\l_xassoccnt_countergroup_name_tl}{\__xassoccnt_prepare_backupid:nn{##1}{\__xassoccnt_backup_id_tl}} {\number\value{##1}}% Must be expanded! \__xassoccnt_backup_renew_theHmacros:nn {##1}{\__xassoccnt_prepare_backupid:nn{##1}{\__xassoccnt_backup_id_tl}}% \bool_if:NT \l__xassoccnt_resetbackupcounters_bool {% \setcounter{##1}{\c_zero_int}% } }% } \NewDocumentCommand{\BackupCounterGroup}{O{}m}{% \keys_set:nn {xassoccnt_container} { backup-id={}, restore-id={}, resetbackup=true, cascading=false, multiple=false, name={}, #1 } \tl_if_empty:NT \__xassoccnt_backup_id_tl {% \msg_fatal:nnxx{xassoccnt}{nobackupid}{#2}{BackupCounterGroup}% Fatal Error } % Prevent multiple usages of the same backup id per counter group \seq_if_in:cVTF {\xassoccnt_backup_id_seq:n{#2}} { \__xassoccnt_backup_id_tl } {% \msg_fatal:nnxxx{xassoccnt}{duplicatebackupid}{\__xassoccnt_backup_id_tl}{#2}{BackupCounterGroup}% Fatal Error }{% \seq_put_right:cV {\xassoccnt_backup_id_seq:n{#2}} { \__xassoccnt_backup_id_tl }% \seq_remove_duplicates:c {\xassoccnt_backup_id_seq:n{#2}} } \seq_map_inline:cn {\xassoccnt_feature_subcontainer:nn{\xassoccnt_extract_moduledata:n{backupfeaturename}}{#2}} {% \xassoccnt_backupstore_property:Nnn {#2}{\__xassoccnt_prepare_backupid:nn{##1}{\__xassoccnt_backup_id_tl}} {\number\value{##1}}% Must be expanded! \__xassoccnt_backup_renew_theHmacros:nn {##1}{\__xassoccnt_prepare_backupid:nn{##1}{\__xassoccnt_backup_id_tl}}% \bool_if:NT \l__xassoccnt_resetbackupcounters_bool {% \setcounter{##1}{\c_zero_int}% }% }% } \NewDocumentCommand{\RestoreBackupCounterGroup}{O{}m}{% \keys_set:nn {xassoccnt_container} {keep-after-restore=false,backup-id={},restore-id={},multiple=false,#1} % % Test whether counter group #2 exists: \seq_if_in:cnTF {\xassoccnt_feature_group_container:n{\xassoccnt_extract_moduledata:n{backupfeaturename}}} {#2} {% \tl_if_empty:NT \__xassoccnt_backup_id_tl {% \msg_error:nnxx{xassoccnt}{nobackupid}{\l__xassoccnt_countergroup_name_tl}{RestoreBackupCounterGroup}% Fatal Error }% \tl_if_empty:NT \__xassoccnt_restore_id_tl {% \tl_set_eq:NN \__xassoccnt_restore_id_tl \__xassoccnt_backup_id_tl } % Test first if the backup id is valid! \seq_if_in:cVT {\xassoccnt_backup_id_seq:n{#2}} { \__xassoccnt_backup_id_tl } {% \seq_map_inline:cn {\xassoccnt_feature_subcontainer:nn{\xassoccnt_extract_moduledata:n{backupfeaturename}}{#2 }} {% % \__xassoccnt_backup_restore_theHmacros:Nx {##1}{\__xassoccnt_prepare_backupid:nn{##1}{\__xassoccnt_restore_id_tl}}%\__xassoccnt_restore_id_tl}}% \tl_set:Nx \l_tmpa_tl {\__xassoccnt_prepare_backupid:nn{##1}{\__xassoccnt_backup_id_tl}} \int_set:Nx \l_tmpa_int {\prop_item:cV {\xassoccnt_backup_subproplist:n{#2} } {\l_tmpa_tl}}% \setcounter{##1}{\int_use:N \l_tmpa_int}% } \bool_if:NF \xassoccnt_keep_after_restore_bool {% \seq_gremove_all:cV {\xassoccnt_backup_id_seq:n{#2}} { \__xassoccnt_backup_id_tl } \seq_map_inline:cn {\xassoccnt_feature_subcontainer:nn{\xassoccnt_extract_moduledata:n{backupfeaturename}}{#2}} {% \prop_remove:cx { \xassoccnt_backup_subproplist:n{#2} } {\__xassoccnt_prepare_backupid:nn{##1}{\__xassoccnt_backup_id_tl}}% } } } }{% \msg_warning:nnxx{xassoccnt}{backupcountergroupundefined}{RestoreBackupCounterGroup}{#2}% Warning, rest is ignored! }% } %%%% Clearing, removing counters from a group and deleting the counter group \cs_new:Nn \xassoccnt_backup_removecounter_from_group:nnn {% % Check whether the counter group #2 exists \seq_set_from_clist:Nn \l_tmpa_seq {#3}% \xassoccnt_container_if_in:cnT {\xassoccnt_feature_group_container:n{\xassoccnt_extract_moduledata:n{backupfeaturename}}} {#2} {% \seq_map_inline:Nn \l_tmpa_seq {% % Remove the property value(s) connected with this counter! -> must loop over all backup-ids \seq_if_exist:cT {\xassoccnt_backup_id_seq:n{#2}} {% \seq_map_inline:cn { \xassoccnt_backup_id_seq:n{#2} } {% \prop_remove:cx { \xassoccnt_backup_subproplist:n{#2}} {\__xassoccnt_prepare_backupid:nn{##1}{####1} } }% }% % Remove the name ##1 from the counter group #2 \xassoccnt_container_gremove_all:cn {\xassoccnt_feature_subcontainer:nn{\xassoccnt_extract_moduledata:n{backupfeaturename}}{#2}} {##1} }% }% } \cs_new:Nn \xassoccnt_backup_clear_countergroup:nn {% \seq_if_exist:cT {\xassoccnt_backup_id_seq:n{#2}} {% \seq_clear:c {\xassoccnt_backup_id_seq:n{#2}}% \cs_undefine:c {\xassoccnt_backup_id_seq:n{#2}}% } % Delete the property list connected to the current counter group \prop_clear:c { \xassoccnt_backup_subproplist:n{#2} } % Remove the names from the counter group% \xassoccnt_container_clear:c { \xassoccnt_feature_subcontainer:nn{\xassoccnt_extract_moduledata:n{backupfeaturename}}{#2} } } \cs_new:Nn \xassoccnt_backup_delete_countergroup:nn{% \xassoccnt_backup_clear_countergroup:nn{#1}{#2}% \xassoccnt_container_remove_all:cn {\xassoccnt_feature_group_container:n{backupcounters}}{#2}% } \cs_new:Nn \__xassoccnt_backup_remove_prop_value:nn { \prop_remove:Nn #1 {#2} } \cs_new:Nn \xassoccnt_backup_clear_counterbackupstate:nnn {% \xassoccnt_container_if_exist:cT { \xassoccnt_feature_subcontainer:nn{backupcounters}{#2} } {% Is it a valid backup-id at all? -> check \seq_if_exist:cT {\xassoccnt_backup_id_seq:n{#2} } {% \seq_if_in:cVT { \xassoccnt_backup_id_seq:n{#2}} {#1} {% \prop_remove:cx { \xassoccnt_backup_subproplist:n{#2} } {\__xassoccnt_prepare_backupid:nn{#3}{#1} }% }% }% }% } \cs_new:Nn \xassoccnt_backup_clear_backupstate:nn {% \xassoccnt_container_if_exist:cT { \xassoccnt_feature_subcontainer:nn{backupcounters}{#2} } {% Is it a valid backup-id at all? -> check \seq_if_exist:cT {\xassoccnt_backup_id_seq:n{#2} } {% \seq_if_in:cVT { \xassoccnt_backup_id_seq:n{#2}} {#1} {% \seq_map_inline:cn { \xassoccnt_feature_subcontainer:nn{backupcounters}{#2} } {% \prop_remove:cx { \xassoccnt_backup_subproplist:n{#2} } {\__xassoccnt_prepare_backupid:nn{##1}{#1} } }% \seq_remove_all:cV { \xassoccnt_backup_id_seq:n{#2} } {#1}% }% }% }% } \NewDocumentCommand{\ClearCounterBackupState}{O{}mm}{% \keys_set:nn {xassoccnt_container} {backup-id={},#1} \xassoccnt_backup_clear_counterbackupstate:nnn {\__xassoccnt_backup_id_tl} { #2 } { #3 } } \NewDocumentCommand{\ClearBackupState}{O{}m}{% \keys_set:nn {xassoccnt_container} {backup-id={},#1} \xassoccnt_backup_clear_backupstate:nn { \__xassoccnt_backup_id_tl } {#2} %\prop_map_inline:cn {\xassoccnt_backup_subproplist:n{#2}} {##1->##2\par}% } \NewDocumentCommand{\ClearBackupCounterGroups}{O{}m}{% \seq_set_from_clist:Nn \l_tmpa_seq {#2}% \seq_map_inline:Nn \l_tmpa_seq {% \xassoccnt_backup_clear_countergroup:nn{#1}{##1}% }% } \NewDocumentCommand{\RemoveCountersFromBackupGroup}{O{}mm}{% \xassoccnt_backup_removecounter_from_group:nnn {#1} {#2} {#3}% } \NewDocumentCommand{\DeleteBackupCounterGroups}{O{}m}{% \seq_set_from_clist:Nn \l_tmpa_seq {#2}% \seq_map_inline:Nn \l_tmpa_seq {% \xassoccnt_backup_delete_countergroup:nn {#1} {##1}% }% } %%% Query routines \prg_new_conditional:Nnn \__xassoccnt_is_backupcountergroup:n {TF,T,F} {% \xassoccnt_container_if_in:cnTF { \xassoccnt_feature_group_container:n{\xassoccnt_extract_moduledata:n{backupfeaturename}} } {#1} {\prg_return_true:} {\prg_return_false:} } \prg_new_conditional:Nnn \__xassoccnt_is_backupstate:nn {TF,T,F} {% \xassoccnt_container_if_exist:cTF { \xassoccnt_feature_subcontainer:nn{backupcounters}{#1} } {% Is it a valid backup-id at all? -> check \seq_if_exist:cTF {\xassoccnt_backup_id_seq:n{#1} } {% \seq_if_in:cnTF { \xassoccnt_backup_id_seq:n{#1}} {#2} {\prg_return_true:} {\prg_return_false:} }{\prg_return_false:} }{\prg_return_false:} } \NewDocumentCommand{\IsBackupCounterGroupTF}{m+m+m}{% \__xassoccnt_is_backupcountergroup:nTF {#1} {#2} {#3}% } \NewDocumentCommand{\IsBackupCounterGroupT}{m+m}{% \__xassoccnt_is_backupcountergroup:nT {#1} {#2} } \NewDocumentCommand{\IsBackupCounterGroupF}{m+m}{% \__xassoccnt_is_backupcountergroup:nF {#1} {#2}% } \NewDocumentCommand{\IsBackupStateTF}{mm+m+m}{% \__xassoccnt_is_backupstate:nnTF {#1} {#2} {#3} {#4}% } \NewDocumentCommand{\IsBackupStateT}{mm+m}{% \__xassoccnt_is_backupstate:nnT {#1} {#2} {#3}% } \NewDocumentCommand{\IsBackupStateF}{mm+m}{% \__xassoccnt_is_backupstate:nnF {#1} {#2} {#3}% } \NewDocumentCommand{\IsBackupCounterTF}{m+m+m}{% \xassoccnt_is_backupcounter:nTF {#1} {#2} {#3} } \NewDocumentCommand{\IsBackupCounterT}{m+m}{% \xassoccnt_is_backupcounter:nT {#1} {#2} } \NewDocumentCommand{\IsBackupCounterF}{m+m}{% \xassoccnt_is_backupcounter:nF {#1} {#2} } %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Coupled Counter features \bool_new:N \l__xassoccnt_is_coupledcounter_bool \prg_new_conditional:Nnn \__xassoccnt_is_coupledcounter:N {TF,T,F} { \xassoccnt_container_map_inline:cn { \xassoccnt_feature_group_container:n{coupledcounters} } {% \bool_set_false:N \l__xassoccnt_is_coupledcounter_bool \xassoccnt_container_if_in:cxT { \xassoccnt_feature_subcontainer:nn{coupledcounters}{##1} } {#1} { \bool_set_true:N \l__xassoccnt_is_coupledcounter_bool \xassoccnt_container_map_break: } } \bool_if:NTF \l__xassoccnt_is_coupledcounter_bool {\prg_return_true:} {\prg_return_false:} } \cs_generate_variant:Nn \__xassoccnt_is_coupledcounter:NTF {cTF } \cs_generate_variant:Nn \__xassoccnt_is_coupledcounter:NT { cT } \cs_generate_variant:Nn \__xassoccnt_is_coupledcounter:NF { cF } \cs_new:Nn \xassoccnt_is_coupledcounter:NTF { % \__xassoccnt_is_coupledcounter:NTF {#1} {#2} {#3} } \cs_new:Nn \xassoccnt_is_coupledcounter:NT { % \__xassoccnt_is_coupledcounter:NT {#1} {#2}% } \cs_new:Nn \xassoccnt_is_coupledcounter:NF { % \__xassoccnt_is_coupledcounter:NnF {#1} {#2}% } % Declaring a new coupled counters group \cs_new:Nn \xassoccnt_declare_coupledcountersgroup:n {% \xassoccnt_container_if_exist:cF { \xassoccnt_feature_group_container:n{coupledcounters}{#1} } { \xassoccnt_feature_add_to_group_container:nn{multiple=false,featurename=coupledcounters}{#1}% } } % The stepcounter branch for coupled counters \cs_new:Nn \xassoccnt_stepcounter_coupledcounters:n {% \xassoccnt_container_map_inline:cn { \xassoccnt_feature_group_container:n{coupledcounters} } {% \xassoccnt_container_if_in:cxT { \xassoccnt_feature_subcontainer:nn{coupledcounters}{##1} } {#1 } { \xassoccnt_container_map_inline:cn {\xassoccnt_feature_subcontainer:nn{coupledcounters}{##1}} { \xassoccnt_standardstepcounter{####1}% } } } } \NewDocumentCommand{\DeclareCoupledCountersGroup}{m}{% \xassoccnt_declare_coupledcountersgroup:n{#1} } \NewDocumentCommand{\DeclareCoupledCounters}{O{}m}{% \keys_set:nn {xassoccnt_container} {multiple=false,#1} % Check first if the counter group name is already registered \xassoccnt_container_if_exist:cF { \xassoccnt_feature_subcontainer:nn{coupledcounters}{\l__xassoccnt_countergroup_name_tl} } { \xassoccnt_declare_coupledcountersgroup:n{\l__xassoccnt_countergroup_name_tl} } \xassoccnt_feature_add_to_subcontainer:nnn{multiple=false,#1,featurename=coupledcounters}{\l__xassoccnt_countergroup_name_tl}{#2}% } \NewDocumentCommand{\AddCoupledCounters}{O{}m}{% \keys_set:nn {xassoccnt_container} {multiple=false,#1} \xassoccnt_container_if_exist:cTF { \xassoccnt_feature_subcontainer:nn{coupledcounters}{\l__xassoccnt_countergroup_name_tl } } { \xassoccnt_feature_add_to_subcontainer:nnn{#1,featurename=coupledcounters}{\l__xassoccnt_countergroup_name_tl}{#2}% }{% \msg_warning:nnxx{xassoccnt}{addcoupledcountergroupundefined}{AddCoupledCounters}{\l__xassoccnt_countergroup_name_tl}% Warning about undefined counter group }% } \NewDocumentCommand{\RemoveCoupledCounters}{O{}m}{% \keys_set:nn {xassoccnt_container} {#1} \xassoccnt_container_if_exist:cTF { \xassoccnt_feature_subcontainer:nn{coupledcounters}{\l__xassoccnt_countergroup_name_tl } } {% \xassoccnt_container_remove_by_clist:cn {\xassoccnt_feature_subcontainer:nn{coupledcounters}{\l__xassoccnt_countergroup_name_tl }} {#2} }{% \msg_warning:nnxx{xassoccnt}{removingcoupledcountergroupundefined}{RemoveCoupledCounters}{\l__xassoccnt_countergroup_name_tl}% Warning about undefined counter group } } \NewDocumentCommand{\ClearCoupledCounters}{m}{% \keys_set:nn {xassoccnt_container} {#1} \xassoccnt_container_if_exist:cTF { \xassoccnt_feature_subcontainer:nn{coupledcounters}{\l__xassoccnt_countergroup_name_tl } } {% \xassoccnt_container_clear:c {\xassoccnt_feature_subcontainer:nn{coupledcounters}{\l__xassoccnt_countergroup_name_tl }} }{% \msg_warning:nnxx{xassoccnt}{clearcoupledcountergroupundefined}{ClearCoupledCounters}{\l__xassoccnt_countergroup_name_tl}% Warning about undefined counter group } } \NewDocumentCommand{\ClearAllCoupledCounters}{}{% \xassoccnt_container_if_exist:cT { \xassoccnt_feature_group_container:n{coupledcounters} } {% \xassoccnt_container_map_inline:cn { \xassoccnt_feature_group_container:n{coupledcounters} } {% \ClearCoupledCounters{name=##1}% } } } \NewDocumentCommand{\IsCoupledCounterTF}{mmm}{% \xassoccnt_is_coupledcounter:NTF {#1} {#2} {#3} } \NewDocumentCommand{\IsCoupledCounterT}{mm}{% \xassoccnt_is_coupledcounter:NT {#1} {#2} } \NewDocumentCommand{\IsCoupledCounterF}{mm}{% \xassoccnt_is_coupledcounter:NF {#1} {#2} } %%%%%%%%%%%%%%%%%%%%%%%%%%% \NewDocumentCommand{\DeclarePeriodicCounter}{O{}mm}{% \xassoccnt_add_periodiccounter:nnn {#1} {#2} {#3}% } \prg_new_conditional:Nnn \xassoccnt_is_periodiccounter:n {TF,T,F} {% \seq_if_in:NnTF \g_xassoccnt_periodiccounter_container_seq {#1} {\prg_return_true:} {\prg_return_false:} } \cs_new:Nn \xassoccnt_stepcounter_periodiccounter:n {% \xassoccnt_is_periodiccounter:nT {#1}{% \int_compare:nNnT {\prop_item:Nn \g_xassoccnt_periodiccounter_prop {#1}} = {\use:c{c@#1}}% { \__xassoccnt_setdocumentcounter:nnn {} {#1}{\c_zero_int} } } } \cs_new:Nn \xassoccnt_addtocounter_periodiccounter:nnn {% \keys_set:nn {xassoccnt_periodiccounter} {wrap=true,#3} \int_set:Nn \l_tmpa_int { \int_eval:n {\number\value{#1}+#2 } } \bool_if:NTF \l_xassoccnt_wrapperiodiccounters_bool {% \int_set:Nn \l_tmpb_int { \int_mod:nn {\l_tmpa_int} {\prop_item:Nn \g_xassoccnt_periodiccounter_prop {#1}}}% \__xassoccnt_setdocumentcounter:nnn {} {#1}{\l_tmpb_int}% Wrap around!!!! }{% \__xassoccnt_setdocumentcounter:nnn {} {#1}{\l_tmpa_int}% Don't Wrap around!!!! }% } \cs_new:Nn \xassoccnt_reset_periodiccounter:nn {% \keys_set:nn {xassoccnt_periodiccounter} {reset=true,#1} % Reset the periodic counter if requested (by default this is true!) \bool_if:NT \l_xassoccnt_resetperiodiccounters_bool {% \__xassoccnt_setdocumentcounter:nnn {} {#2} {\c_zero_int}% } } \cs_new:Nn \xassoccnt_remove_periodiccounter:nn {% \seq_gremove_all:Nn \g_xassoccnt_periodiccounter_container_seq {#2}% \prop_remove:Nn \g_xassoccnt_periodiccounter_prop {#2}% \xassoccnt_reset_periodiccounter:nn {#1} {#2} } \cs_new:Nn \xassoccnt_add_periodiccounter:nnn {% \keys_set:nn {xassoccnt} {#1} \seq_put_right:Nn \g_xassoccnt_periodiccounter_container_seq {#2}% \seq_gremove_duplicates:N \g_xassoccnt_periodiccounter_container_seq \xassoccnt_changecondition_periodiccounter:nnn {reset=false} {#2} {#3} % Check the optional argument later on!!!! } \cs_new:Nn \xassoccnt_changecondition_periodiccounter:nnn {% \xassoccnt_is_periodiccounter:nTF {#2}{% \prop_put:Nnn \g_xassoccnt_periodiccounter_prop {#2} {#3}% \xassoccnt_reset_periodiccounter:nn {#1} {#2} } } \NewDocumentCommand{\ChangePeriodicCounterCondition}{O{}mm}{% \xassoccnt_changecondition_periodiccounter:nnn {#1}{#2}{#3}% } \NewDocumentCommand{\RemovePeriodicCounter}{O{}m}{% \xassoccnt_remove_periodiccounter:nn{#1} {#2} } \NewDocumentCommand{\RemoveAllPeriodicCounters}{O{}}{% \seq_map_inline:Nn \g_xassoccnt_periodiccounter_container_seq {\xassoccnt_remove_periodiccounter:nn {#1} {##1}} \seq_gclear:N \g_xassoccnt_periodiccounter_container_seq \prop_gclear:N \g_xassoccnt_periodiccounter_prop } \NewDocumentCommand{\AddPeriodicCounter}{O{}mm}{% \xassoccnt_add_periodiccounter:nnn {#1} {#2} {#3} } \NewDocumentCommand{\IsPeriodicCounterTF}{m+m+m}{% \xassoccnt_is_periodiccounter:nTF{#1}{#2}{#3}% } \NewDocumentCommand{\IsPeriodicCounterT}{m+m}{% \xassoccnt_is_periodiccounter:nT{#1}{#2} } \NewDocumentCommand{\IsPeriodicCounterF}{m+m}{% \xassoccnt_is_periodiccounter:nF{#1}{#2} } %%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% Redefinition of standard counter macros \cs_set:Npn \stepcounter #1{% %\def\stepcounter#1{% \__xassoccnt_translate_countername:cn {l_tmpa_tl} {#1}% \xassoccnt_is_suspendedcounter:nF{#1}{% \xassoccnt_stepcounter_periodiccounter:n {#1}% \xassoccnt_is_coupledcounter:NTF {#1} { \xassoccnt_stepcounter_coupledcounters:n{#1} } {% No, not a coupled counter! % \cs_gset_nopar:Nn \__xassoccnt_laststeppedcounter: {\l_tmpa_tl}% \cs_gset_nopar:Npx \LastSteppedCounter {\tl_use:N \l_tmpa_tl}% \xassoccnt_countersinresetlist:n{\l_tmpa_tl}% \__xassoccnt_getresetlist:n {\l_tmpa_tl}% \seq_if_empty:NTF \l__xassoccnt_counterreset_seq {% \xassoccnt_standardaddtocounter{\l_tmpa_tl}{\c_one_int}% Use the original one! \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{\l_tmpa_tl}}% \__xassoccnt_step_associatedcounters:n {\l_tmpa_tl} }{ % reset list is not empty! % This is the replacement of \csname cl@#1\endcsname \xassoccnt_standardaddtocounter{\l_tmpa_tl}{\c_one_int} \seq_map_inline:Nn \l__xassoccnt_counterreset_seq {% \xassoccnt_is_drivercounter:nTF{##1}{% \csname c@##1\endcsname\c_zero_int % Reset but do not increase }{% \csname c@##1\endcsname-1 \xassoccnt_standardstepcounter{##1}% } } \__xassoccnt_step_associatedcounters:n {\l_tmpa_tl} % step the remaining associated counters }% End of not empty reset list }% End of coupled counters } % end of not suspended counter \__xassoccnt_is_totalcounter:nT {#1} {% \__xassoccnt_store_totalcounter_value:n {#1}% } } \RenewDocumentCommand{\addtocounter}{mmO{}}{% \xassoccnt_is_periodiccounter:nTF {#1}{% \xassoccnt_addtocounter_periodiccounter:nnn {#1} {#2} {#3}% }{% \xassoccnt_standardaddtocounter{#1}{#2}% } } \NewDocumentCommand{\xassoccnt_addtocounterfoo}{mmO{}}{% % Only add to a counter if this counter isn't on the suspended counters list! \xassoccnt_is_suspendedcounter:nF{#1}{% \__xassoccnt_translate_countername:cn {l_tmpb_tl} {#1}% \xassoccnt_standardaddtocounter{\l_tmpb_tl}{#2}% \cs_gset_nopar:Nn \__xassoccnt_lastaddtocounter: {\l_tmpb_tl}% }% % Now check if #1 is a total counter and set the property correspondingly \__xassoccnt_is_totalcounter:nT {#1} {% \__xassoccnt_store_totalcounter_value:n {#1}% } } \NewDocumentCommand{\xassoccnt_addtocounter}{mmO{}}{% % Only add to a counter if this counter isn't on the suspended counters list! \xassoccnt_is_suspendedcounter:nF{#1}{% \__xassoccnt_translate_countername:cn {l_tmpb_tl} {#1}% \xassoccnt_standardaddtocounter{\l_tmpb_tl}{#2}% \cs_gset_nopar:Npx \LastAddedToCounter {\tl_use:N \l_tmpb_tl}% }% % Now check if #1 is a total counter and set the property correspondingly \__xassoccnt_is_totalcounter:nT {#1} {% \__xassoccnt_store_totalcounter_value:n {#1}% } } \cs_new:Nn \__xassoccnt_setdocumentcounter:nnn {% \__xassoccnt_translate_countername:cn {l_tmpa_tl} {#2}% \xassoccnt_standardsetcounter{\l_tmpa_tl}{#3}% \clist_clear:N \l__xassoccnt_onlycounters_clist \keys_set:nn {xassoccnt}{#1}% \bool_if:nTF {\l__xassoccnt_setcounter_associated } {% \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#2} } { \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#2} } { \__xassoccnt_translate_countername:cn {l_tmpb_tl} {##1}% \xassoccnt_standardsetcounter{\l_tmpb_tl}{#3} } }% End of \seq_if_exist }{% % Check whether the `onlycounters` - clist is empty -- if not, loop through the list \clist_if_empty:NF \l__xassoccnt_onlycounters_clist {% \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#2} } { \clist_map_inline:Nn \l__xassoccnt_onlycounters_clist { % Check first if ##1 is associated to #2 at all \__xassoccnt_translate_countername:cn {l_tmpb_tl} {##1}% \xassoccnt_is_associatedtocounter:nnT {#2} {\l_tmpb_tl} { \xassoccnt_standardsetcounter{\l_tmpb_tl}{#3} } } } } } \cs_gset_nopar:Nn \__xassoccnt_lastsetdocumentcounter: {#2}% \cs_gset_nopar:Npx \LastSetDocumentCounter {#2}% \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{\l_tmpa_tl}}% } \cs_new:Nn \__xassoccnt_synccounters:nn {% \int_set:Nn \l_tmpa_int {\value{#2}} \__xassoccnt_setdocumentcounter:nnn {associatedtoo=true,#1}{#2}{\l_tmpa_int} % copy the driver counter value to all associated counters \int_zero:N \l_tmpa_int } \cs_new:Nn \__xassoccnt_copycounters:nnn {% \xassoccnt_standardsetcounter{#3}{\value{#2}} } \cs_new:Nn \__xassoccnt_swapcounters:nnn {% \int_set:Nn \l_tmpa_int {\value{#2}}% \xassoccnt_standardsetcounter{#2}{\value{#3}} \xassoccnt_standardsetcounter{#3}{\l_tmpa_int} \int_zero:N \l_tmpa_int } \cs_new:Nn \__xassoccnt_getresetlist:n {% \begingroup \seq_gclear:N \l__xassoccnt_counterreset_seq \def\@elt##1{\seq_gput_right:Nn \l__xassoccnt_counterreset_seq {##1} } \use:c{cl@#1} \endgroup } \newcommand{\showresetlist}[1]{% \__xassoccnt_getresetlist:n {#1} \seq_use:Nn \l__xassoccnt_counterreset_seq {\par} } \NewDocumentCommand{\SetDocumentCounter}{O{associatedtoo=false}mm}{% \__xassoccnt_setdocumentcounter:nnn {#1}{#2}{#3} % copy the driver counter value to all associated counters } \NewDocumentCommand{\StepDownCounter}{O{}m}{% \SubtractFromCounter[#1]{#2}{1}% } \NewDocumentCommand{\SubtractFromCounter}{O{}mm}{% \xassoccnt_addtocounter{#2}{-#3}[#1]% } \NewDocumentCommand{\SyncCounters}{om}{% \IfValueTF{#1}{% \__xassoccnt_synccounters:nn {#1}{#2} }{% \__xassoccnt_synccounters:nn {}{#2} } } \RenewDocumentCommand{\setcounter}{mm}{% \__xassoccnt_translate_countername:cn {l_tmpb_tl}{#1}% % \cs_gset_nopar:Nn \__xassoccnt_lastsetcounter: {#1} \cs_gset_nopar:Npx \LastSetCounter {#1} \xassoccnt_standardsetcounter{\tl_use:N \l_tmpb_tl}{#2}% \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{\l_tmpb_tl}}% \__xassoccnt_is_totalcounter:nT {#1} {% \__xassoccnt_store_totalcounter_value:n {#1}% } } \cs_set:Npn \refstepcounter #1 {% \seq_if_in:NxF \g_xassoccnt_suspendedcnt_seq {#1} {% \cs_gset_nopar:Npx \LastRefSteppedCounter {#1} \xassoccnt_standardrefstepcounter{#1}% \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#1}}% } } \cs_gset_nopar:Npx \LastRefSteppedCounter {} \newcommand{\LastCounterValue}{% \int_use:N \g__xassoccnt_lastcountervalue_int } %%%%% Wrappers for \newcounter etc. \NewDocumentCommand{\NewDocumentCounter}{O{initial=\c_zero_int}mo}{% \group_begin: \seq_set_from_clist:Nx \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq {% \IfValueTF{#3}{% \__xassoccnt_newcounter_ltx:nnn{#1}{##1}{#3} }{% \__xassoccnt_newcounter_ltx:nnn{#1}{##1}{} } } \group_end: } \NewDocumentCommand{\CopyDocumentCounters}{O{}mm}{% \__xassoccnt_copycounters:nnn{#1}{#2}{#3}% } \NewDocumentCommand{\SwapDocumentCounters}{O{}mm}{% \__xassoccnt_swapcounters:nnn{#1}{#2}{#3}% } %%%%%%%%%%%%%%% Reset list related stuff \newcommand{\countersresetlistcount}[1]{% \int_zero:N \l_xassoccnt_resetlist_counter% \xassoccnt_countersinresetlist:n{#1}% } \newcommand{\getresetlistcount}{% \int_use:N \l_xassoccnt_resetlist_counter } \bool_new:N \l__xassoccnt_isinresetlist_bool \prg_new_conditional:Nnn \__xassoccnt_ifinresetlist:nn {T,F,TF} {% \bool_set_false:N \l__xassoccnt_isinresetlist_bool \cs_set:Nx \l__tmpa_cs: {#2} \def\@elt##1{% Can't use \cs_new:Nn here :-( \cs_set:Nn \l__tmpb_cs: {##1} % Check if \l__tmpa_cs: and \l__tmpb_cs: are equal \cs_if_eq:NNT \l__tmpa_cs: \l__tmpb_cs: { \bool_gset_true:N \l__xassoccnt_isinresetlist_bool } } \use:c{ cl@#1 } \bool_if:nTF {\l__xassoccnt_isinresetlist_bool}{% \prg_return_true: }{% \prg_return_false: } } \NewDocumentCommand{\IfInResetListTF}{omm+m+m}{% \bool_set_true:N \l__xassoccnt_isinresetlist_bool \__xassoccnt_ifinresetlist:nnTF{#2}{#3}{#4}{#5}% } \NewDocumentCommand{\IfInResetListT}{omm+m}{% \__xassoccnt_ifinresetlist:nnT{#2}{#3}{#4}% } \NewDocumentCommand{\IfInResetListF}{omm+m}{% \__xassoccnt_ifinresetlist:nnF{#2}{#3}{#4}% } \cs_new_nopar:Npn \GetAllResetLists {% \group_begin: \def\@elt##1{% \seq_gput_right:Nn \g_xassoccnt_all_latex_counters_seq {##1}% } \cl@@ckpt% \seq_map_inline:Nn \g_xassoccnt_all_latex_counters_seq {% \def\@elt####1{####1,} \seq_set_from_clist:cx { g_latex_cntr_##1_seq } { \use:c{cl@##1} } } % Now fill the parent counter lists \seq_map_inline:Nn \g_xassoccnt_all_latex_counters_seq {% \seq_map_inline:cn { g_latex_cntr_##1_seq }{ % \prop_gput:Nnn \g_xassoccnt_latex_parentcounters_prop {####1} {##1} } } % \prop_show:N \g_xassoccnt_latex_parentcounters_prop %\g_latex_cntr_subsubsection_seq \group_end: } \cs_new:Nn \xassoccnt_full_reset_list_recursive_other:nn { \seq_clear:N \l_tmpa_seq \xassoccnt_local_list:nn {l_tmpa_seq} {#2} \seq_map_inline:Nn \l_tmpa_seq {% \seq_gput_right:cn {#1_fullresetlist_seq} {##1}% \seq_remove_duplicates:c {#1_fullresetlist_seq } % Remove the duplicates \xassoccnt_full_reset_list_recursive:nn {#1} {##1}% Recursive call } } % Gives the parent counter of a specific counter (or nothing) \cs_new:Npn \GetParentCounter #1{% \prop_if_in:NoT \g_xassoccnt_latex_parentcounters_prop {#1} {% \prop_item:No \g_xassoccnt_latex_parentcounters_prop {#1} } } \cs_new:Nn \__xassoccnt_parent_counter_chain:n {% \int_gincr:N \g__xassoccnt_tmpa_int \tl_set:Nx \l_tmpa_tl {#1} \tl_set:Nx \l_tmpb_tl {\GetParentCounter{#1}} % \seq_show:N \l__xassoccnt_tmpa_seq \seq_gput_right:Nx \l__xassoccnt_tmpa_seq {\GetParentCounter{#1}} \seq_remove_duplicates:N \l__xassoccnt_tmpa_seq \tl_set:Nx \l_tmpb_tl {\GetParentCounter{\l_tmpa_tl}} \int_compare:nNnF{\tl_count:N \l_tmpb_tl } = {0} { \__xassoccnt_parent_counter_chain:V{\l_tmpb_tl} } } \cs_new:Nn \xassoccnt_parent_counter_chain:n {% \prop_if_exist:cTF {g_xassoccnt_#1_counter_chain_prop}{ \prop_gclear:c {g_xassoccnt_#1_counter_chain_prop} }{ \prop_new:c {g_xassoccnt_#1_counter_chain_prop} } \seq_if_exist:cTF {g_xassoccnt_#1_counter_chain_seq} { \seq_gclear:c {g_xassoccnt_#1_counter_chain_seq} }{ \seq_new:c {g_xassoccnt_#1_counter_chain_seq} } \prop_clear:N \g__xassoccnt_tmpa_prop \seq_clear:N \l__xassoccnt_tmpa_seq \int_gzero:N \g__xassoccnt_tmpa_int \prop_gput:NVx \g__xassoccnt_tmpa_prop {\g__xassoccnt_tmpa_int} {#1} \seq_gput_right:Nx \l__xassoccnt_tmpa_seq {#1}% \__xassoccnt_parent_counter_chain:x{#1} \seq_gset_eq:cN {g_xassoccnt_#1_counter_chain_seq} \l__xassoccnt_tmpa_seq \seq_pop_right:cN {g_xassoccnt_#1_counter_chain_seq} \l_tmpa_tl \prop_gset_eq:cN {g_xassoccnt_#1_counter_chain_prop} \l__xassoccnt_tmpa_prop } \cs_generate_variant:Nn \xassoccnt_parent_counter_chain:n {x,V} \cs_generate_variant:Nn \__xassoccnt_parent_counter_chain:n {x,V} \NewDocumentCommand{\GetParentCounterChain}{m}{% \xassoccnt_parent_counter_chain:n{#1} } %%%%%%%%%%%%% Counter hierarchies \seq_new:N \g_xassoccnt_counterhierarchies_seq \cs_new:Nn \__xassoccnt_add_counterhierarchy:n {% \seq_if_exist:cF { g_xassoccnt_ #1 _counterhierarchy_seq } { \seq_new:cn {g_xassoccnt_ #1 _counterhierarchy_seq} } \tl_set:Nx \l_tmpb_tl {#1} \seq_gput_right:Nx \g_xassoccnt_counterhierarchies_seq {#1} \seq_gremove_duplicates:N \g_xassoccnt_counterhierarchies_seq } \keys_define:nn {xassoccnt(COUNTERHIERARCHY)} {% hierarchy-name .code:n= {\__xassoccnt_add_counterhierarchy:n{#1}}, hierarchy-name .value_required:n=true } \seq_set_from_clist:cn {foo_seq} {einstein,feynman,newton,boltzmann} \cs_new:Nn \seq_insert_seq:nnnn { \group_begin: \int_zero:N \l_tmpa_int \seq_set_eq:NN \l_tmpa_seq #1 \seq_clear:N \l__xassoccnt_tmpb_seq % \seq_clear:N \l_tmpa_seq \int_do_while:nNnn {\l_tmpa_int } < {#3} {% \int_incr:N \l_tmpa_int \seq_put_right:Nx \l__xassoccnt_tmpb_seq {\seq_item:NV #1 {\l_tmpa_int}} } \seq_concat:NNN \l__xassoccnt_tmpa_seq \l__xassoccnt_tmpb_seq #2 \seq_clear:N \l__xassoccnt_tmpb_seq \int_do_while:nNnn {\l_tmpa_int } < {\seq_count:N {#1} + 1} {% \int_incr:N \l_tmpa_int \seq_put_right:Nx \l__xassoccnt_tmpa_seq {\seq_item:NV #1 {\l_tmpa_int}} } % \seq_concat:NNN \l__xassoccnt_tmpc_seq \l__xassoccnt_tmpa_seq \l__xassoccnt_ \seq_use:Nn \l__xassoccnt_tmpa_seq {\par} % \map_\seq_map_inline:Nn #1 {% %\l_tmpa_seq #1 \group_end: } \NewDocumentCommand{\NewCounterHierarchy}{O{}m}{% \group_begin: \keys_set:nn {xassoccnt(COUNTERHIERARCHY)}{ #1 } \seq_set_from_clist:Nx \l_tmpa_seq {#2} \seq_set_eq:NN \l_tmpb_seq \l_tmpa_seq \int_zero:N \l_tmpa_int \seq_pop_left:NN \l_tmpb_seq \l_tmpa_tl \__xassoccnt_newcounter_ltx:nVn{}{\l_tmpa_tl}{} \seq_map_inline:Nn \l_tmpa_seq {% \int_incr:N \l_tmpa_int \tl_clear:N \l_tmpa_tl \tl_set:Nx \l_tmpa_tl {\seq_item:Nn \l_tmpa_seq {\l_tmpa_int+1}} \tl_if_empty:NF \l_tmpa_tl {% \__xassoccnt_newcounter_ltx:nVn{}{\l_tmpa_tl}{##1} } } \seq_set_eq:NN \l_tmpb_seq \l_tmpa_seq \seq_insert_seq:nnnn {\l_tmpa_seq} {\foo_seq} {2} {} \group_end: } % Pretty printing counters \NewDocumentCommand{\PrettyPrintCounterName}{+mm}{% \keys_set:nn {xassoccnt} {countertype=general,#1}% \bool_if:nTF {\l__xassoccnt_countertype_general} { \fbox{\textcolor{\GeneralCounterInfoColor}{\textbf{#2}}} } { \bool_if:nTF {\l__xassoccnt_countertype_driver} { \fbox{\textcolor{\DriverCounterInfoColor}{\textbf{#2}}}% }{ \bool_if:nTF {\l__xassoccnt_countertype_associated } {% \fbox{\textcolor{\AssociatedCounterInfoColor}{\textbf{#2}}}% }{% \bool_if:nTF {\l__xassoccnt_countertype_total } {% \fbox{\textcolor{\TotalCounterInfoColor}{\textbf{#2}}}% }{ Error}% } }% }% } %%%%%%%%%%% Total counter features \NewDocumentCommand{\IsTotalCounterTF}{m+m+m}{% \__xassoccnt_is_totalcounter:nTF { #1 } { #2 } { #3 } } \NewDocumentCommand{\IsTotalCounterT}{m+m}{% \__xassoccnt_is_totalcounter:nT { #1 } { #2 } } \NewDocumentCommand{\IsTotalCounterF}{m+m}{% \__xassoccnt_is_totalcounter:nF { #1 } { #2 } } \NewDocumentCommand{\NewTotalDocumentCounter}{O{}m}{% \keys_set:nn {xassoccnt} {supertotal=false,#1} \seq_set_from_clist:Nn \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq { \__xassoccnt_ifis_latexcounter:nF {##1} {% Define the counter \xassoccnt_declaredocumentcounter:nn{sloppy=false}{##1}% }% \__xassoccnt_registertotaldocumentcounter:nn{#1}{##1} } } \NewDocumentCommand{\DeclareTotalDocumentCounter}{O{}m}{% \keys_set:nn {xassoccnt} {supertotal=false,#1} \seq_set_from_clist:Nn \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq { \__xassoccnt_ifis_latexcounter:nF {##1} {% Define the counter \xassoccnt_declaredocumentcounter:nn{sloppy=false}{##1}% }% \__xassoccnt_registertotaldocumentcounter:nn{#1}{##1} } } \cs_new:Nn \__xassoccnt_store_totalcounter_value:n {% \prop_gput:Nnn \g_xassoccnt_totalcounter_prop {#1} {\number\value{\__xassoccnt_expand_totalcountername:n{#1}}} \prop_gput:Nnn \g_xassoccnt_totalcounter_prop {#1name} {\__xassoccnt_expand_totalcountername:n{#1}} \prop_gput:Nxx \g_xassoccnt_totalcounter_prop {\__xassoccnt_expand_totalcountername:n{#1}} {#1}% back reference } \cs_new:Nn \__xassoccnt_registertotaldocumentcounter:nn {% \keys_set:nn {xassoccnt} {supertotal=false,#1} \__xassoccnt_ifis_latexcounter:nF {#2} {% Counter does not exist -- do not autodefine \msg_error:nnn{xassoccnt}{nameisnocounter}{#2}% }% % If the counter already exists -> check for the internal totalcounter name \cs_if_exist:cF { c@\__xassoccnt_expand_totalcountername:n{#2} } { \xassoccnt_declaredocumentcounter:nn{sloppy=false,initial={-1}}{\__xassoccnt_expand_totalcountername:n{#2}}% \seq_gput_right:Nx \g__xassoccnt_totalcounter_container {\__xassoccnt_expand_totalcountername:n{#2}}% \__xassoccnt_store_totalcounter_value:n {#2}% \bool_if:NT \l__xassoccnt_is_supertotalcounter_bool {% \__xassoccnt_add_supertotalcounter:n {#2} } % Removed on 2017/03/12 % \AtEndDocument{% % \__xassoccnt_writetotalcounters:nn {#2}{#2} % }% }% } \cs_generate_variant:Nn \__xassoccnt_registertotaldocumentcounter:nn {nx} \NewDocumentCommand{\RegisterTotalDocumentCounter}{O{}m}{% \__xassoccnt_registertotaldocumentcounter:nn{#1}{#2}% } % Expandable version \cs_new:Npn \TotalValue #1{% \prop_item:Nn \g_xassoccnt_totalcounter_prop {#1}% } \cs_new:Nn \__xassoccnt_writetotalcounters_old:nn {% \immediate\write\@mainaux {% \string\IfIsDocumentCounterF\expandafter{\__xassoccnt_expand_totalcountername:n{#1}}{\string\DeclareDocumentCounter\expandafter{\__xassoccnt_expand_totalcountername:n{#1}}} } \seq_if_in:NnTF \g__xassoccnt_supertotalcounter_container {#1} {% \immediate\write\@mainaux{% \string\setcounter{\__xassoccnt_expand_totalcountername:n{#1}}{\number\value{\__xassoccnt_expand_totalcountername:n{#1}}}% } }{ \immediate\write\@mainaux{% \string\setcounter{\__xassoccnt_expand_totalcountername:n{#1}}{\number\value{#2}}% } } } \cs_generate_variant:Nn \__xassoccnt_writetotalcounters_old:nn {nx,xx} \cs_new_nopar:Nn \__xassoccnt_writetotalcounters_atend: {% \seq_map_inline:Nn \g__xassoccnt_totalcounter_container { \immediate\write\@mainaux{% \string\IfIsDocumentCounterF{##1}{\string\DeclareDocumentCounter{##1}}^^J } \seq_if_in:NnTF \g__xassoccnt_supertotalcounter_container {##1} {% \immediate\write\@mainaux{% \string\setcounter{\__xassoccnt_expand_totalcountername:n{##1}}{\number\value{\__xassoccnt_expand_totalcountername:n{##1}}}% } }{% \immediate\write\@mainaux{% \string\setcounter{##1}{\number\value{\prop_item:Nn \g_xassoccnt_totalcounter_prop {##1}}} } } } } \NewDocumentCommand{\WriteCountersAtEnd}{}{% \__xassoccnt_writetotalcounters_atend:% } \NewDocumentCommand{\TotalCounterInternalNameExp}{m}{% \prop_item:Nn \g_xassoccnt_totalcounter_prop {#1name}% } \NewDocumentCommand{\TotalCounterInternalName}{m}{% \__xassoccnt_is_totalcounter:nTF { #1 } { \__xassoccnt_expand_totalcountername:n {#1} } { #1 } % } %%% Super total counter features \cs_new:Nn \__xassoccnt_add_supertotalcounter:n {% \cs_if_exist:cTF {c@#1} {% \seq_gput_right:Nx \g__xassoccnt_supertotalcounter_container {#1} }{% % Some warning/error message later on here! } } \cs_new:Nn \__xassoccnt_remove_supertotalcounter:n {% \seq_gremove_all:Nn \g__xassoccnt_supertotalcounter_container {#1} } \prg_new_conditional:Nnn \__xassoccnt_is_supertotalcounter:n {T,F,TF} {% \seq_if_in:NxTF \g__xassoccnt_supertotalcounter_container { #1 } { \prg_return_true: }{% \prg_return_false: }% } \NewDocumentCommand{\IsSuperTotalCounterTF}{m+m+m}{% \__xassoccnt_is_supertotalcounter:nTF { #1 } { #2 } { #3 } } \NewDocumentCommand{\IsSuperTotalCounterT}{m+m}{% \__xassoccnt_is_supertotalcounter:nT { #1 } { #2 } } \NewDocumentCommand{\IsSuperTotalCounterF}{m+m}{% \__xassoccnt_is_supertotalcounter:nF { #1 } { #2 } } \NewDocumentCommand{\DeclareTotalAssociatedCounters}{omm}{% \NewTotalDocumentCounter{#3}% \DeclareAssociatedCounters{#2}{#3}% } %%% Counter backup list features % Those macros all deal with the global reset list% \cs_new:Nn \__xassoccnt_renew_theHmacros:n {% \bool_if:NT \l__xassoccnt_hyperrefpackage_loaded_bool {% \cs_if_exist:cT {theH#1} {% \cs_gset_eq:cc {xassoccnt_theH#1} {theH#1}% \expandafter\renewcommand\csname theH#1\endcsname{xassoccnt.\int_use:N \g__xassoccnt_backupcalls_int.#1.\number\value{#1}}% }% } } \cs_new:Nn \__xassoccnt_restore_theHmacros:n {% \bool_if:NT \l__xassoccnt_hyperrefpackage_loaded_bool {% \cs_if_exist:cT {theH#1} {% \cs_gset_eq:cc {theH#1} {xassoccnt_theH#1} % }% }% } \cs_new:Nn \__xassoccnt_addcountertobackuplist_with_reset:nn {% % Prevent multiple addition of a counter name \seq_if_in:NnF #1 {#2} { \seq_gput_right:Nn \l__xassoccnt_backupresetlist_seq {\c_one_int} \seq_gput_right:Nn #1 { #2 } } } \cs_new:Nn \__xassoccnt_addcountertobackuplist_without_reset:nn {% % Prevent multiple addition of a counter name \seq_if_in:NnF #1 {#2} { \seq_gput_right:Nn \l__xassoccnt_backupresetlist_seq {\c_zero_int} \seq_gput_right:NV #1 {#2} } } \cs_new:Nn \__xassoccnt_removestar:n {% \tl_clear:N \l_tmpa_tl \clist_set:Nx \l_tmpa_clist {#1} \clist_map_inline:Nn \l_tmpa_clist {% \tl_clear:N \l_tmpa_tl% \tl_if_in:nnTF {##1} {*} { \tl_set:Nn \l_tmpa_tl {##1} \tl_remove_all:Nn \l_tmpa_tl {*} \__xassoccnt_addcountertobackuplist_without_reset:nn { \l__xassoccnt_counternamesbackup_seq } {\l_tmpa_tl } }{% \__xassoccnt_addcountertobackuplist_with_reset:nn {\l__xassoccnt_counternamesbackup_seq} {##1} } }% } \cs_new:Nn \__xassoccnt_removestarsinglevalue:n {% \tl_clear:N \l_tmpa_tl% \tl_if_in:nnTF {#1} {*} { \tl_set:Nn \l_tmpa_tl {#1} \tl_remove_all:Nn \l_tmpa_tl {*} \__xassoccnt_addcountertobackuplist_without_reset:nn { \l__xassoccnt_counternamesbackup_seq } {\l_tmpa_tl } }{% \__xassoccnt_addcountertobackuplist_with_reset:nn {\l__xassoccnt_counternamesbackup_seq} {#1} } } \cs_new:Nn \__xassoccnt_backupcountervalues:nnn {% \seq_map_inline:Nn \l__xassoccnt_counternamesbackup_seq {% \int_incr:N \l_tmpa_int \__xassoccnt_ifis_latexcounter:nTF {##1} {% Check whether this is a counter at all! % Store the old `\theH....` definition if preset \__xassoccnt_renew_theHmacros:n {##1 } \seq_gput_right:Nx \l__xassoccnt_countervaluesbackup_seq { \number\value{##1} } % Check first if the counter name is starred -> no resetting then \int_compare:nNnF { \seq_item:Nn \l__xassoccnt_backupresetlist_seq {\int_use:N \l_tmpa_int }} = { \c_zero_int } {% \bool_if:NT \l__xassoccnt_resetbackupcounters_bool {% \setcounter{##1}{\c_zero_int}% }% }% }{% \msg_error:nnn{xassoccnt}{nameisnocounter}{##1}% }% }% } \cs_new:Nn \__xassoccnt_backupsinglecountervalue:n {% \int_set:Nn \l_tmpa_int {\seq_count:N \l__xassoccnt_backupresetlist_seq}% \__xassoccnt_ifis_latexcounter:nTF {#1} {% Check whether this is a counter at all! % Store the old `\theH....` definition if preset \__xassoccnt_renew_theHmacros:n { #1 } \seq_gput_right:Nx \l__xassoccnt_countervaluesbackup_seq { \number\value{#1} } % Check first if the counter name is starred -> no resetting then \int_compare:nNnF { \seq_item:Nn \l__xassoccnt_backupresetlist_seq {\int_use:N \l_tmpa_int }} = { \c_zero_int } {% \bool_if:NT \l__xassoccnt_resetbackupcounters_bool {% \setcounter{#1}{\c_zero_int}% }% }% }{% \msg_error:nnn{xassoccnt}{nameisnocounter}{#1}% }% } \cs_new:Nn \__xassoccnt_restorecountervalues:n { \int_zero:N \l_tmpa_int % dummy 'counter' \seq_map_inline:cn {#1} {% \int_incr:N \l_tmpa_int % Increment the local 'counter' \setcounter{##1}{\seq_item:Nn \l__xassoccnt_countervaluesbackup_seq {\int_use:N \l_tmpa_int }} \__xassoccnt_restore_theHmacros:n {##1}% } } \NewDocumentCommand{\FormerBackupCounterValues}{O{resetbackup=true}m}{% \keys_set:nn{xassoccnt}{#1}% \int_incr:N \g__xassoccnt_backupcalls_int \int_zero:N \l_tmpa_int \seq_gclear:N \l__xassoccnt_countervaluesbackup_seq \seq_gclear:N \l__xassoccnt_backupresetlist_seq \__xassoccnt_addbackupcounter:nnn {#1}{}{#2}% \seq_gclear:N \l__xassoccnt_backupresetlist_seq% } \NewDocumentCommand{\FormerRemoveBackupCounterInternal}{sO{}m}{% \tl_set:Nn \l_tmpa_tl {#3} \int_zero:N \l_tmpa_int% \int_zero:N \l_tmpb_int% \seq_clear:N \l_tmpa_seq% \seq_if_in:NnT \l__xassoccnt_counternamesbackup_seq {#3} {% \seq_map_inline:Nn \l__xassoccnt_counternamesbackup_seq {% \int_incr:N \l_tmpa_int \tl_set:Nn \l_tmpb_tl {##1} % Get the value of the current counter \int_set:Nn \l_tmpb_int {\seq_item:Nn \l__xassoccnt_countervaluesbackup_seq {\l_tmpa_int }} \tl_if_eq:NNTF \l_tmpa_tl \l_tmpb_tl { % Restore the old \theH#3 definition \__xassoccnt_restore_theHmacros:n {#3}% \IfBooleanF{#1}{ \setcounter{#3}{\l_tmpb_int } } }{ \seq_put_right:NV \l_tmpa_seq { \l_tmpa_int } }% End of \tl_if_eq:NNTF }% End of \seq_map_inline } % No F - Branch needed here (most likely ;-)) } \NewDocumentCommand{\FormerRemoveBackupCounters}{sO{}m}{% \clist_set:Nn \l_tmpa_clist {#3} % Loop through the list \clist_map_inline:Nn \l_tmpa_clist {% \IfBooleanTF{#1}{% \FormerRemoveBackupCounterInternal*{##1}% }{% \FormerRemoveBackupCounterInternal{##1}% } } } \NewDocumentCommand{\FormerRestoreAllCounterValues}{O{}}{% \__xassoccnt_restorecountervalues:n {l__xassoccnt_counternamesbackup_seq } \seq_clear:N \l__xassoccnt_countervaluesbackup_seq % clear the value list \seq_clear:N \l__xassoccnt_counternamesbackup_seq % clear the name list } % \Restore is \Remove with restoring (of course) \NewDocumentCommand{\FormerRestoreCounterValues}{O{}m}{% \clist_set:Nn \l_tmpa_clist {#2} \clist_map_inline:Nn \l_tmpa_clist {% \RemoveBackupCounterInternal{##1}% } } \cs_new:Nn \__xassoccnt_addbackupcounter:nnn {% % Remove first the stars from the counter names that should not be reset! \__xassoccnt_removestar:n {#3} % Now backup the counter values \__xassoccnt_backupcountervalues:nnn {#3}{}{} } \NewDocumentCommand{\FormerAddBackupCounter}{O{}m}{% \clist_set:Nx \l_tmpa_clist {#2} \clist_map_inline:Nn \l_tmpa_clist {% \__xassoccnt_removestarsinglevalue:n{##1}% \__xassoccnt_backupsinglecountervalue:n{##1}% } } %%%% More simplifying macros for doing similar steps for all counters in the comma separated list \NewDocumentCommand{\LoopAddtoCounters}{+mm}{% \clist_set:Nx \l_tmpa_clist {#1}% \clist_map_inline:Nn \l_tmpa_clist { \addtocounter{##1}{#2} } } \NewDocumentCommand{\LoopRefstepCounters}{+mm}{% \clist_set:Nx \l_tmpa_clist {#1}% \clist_map_inline:Nn \l_tmpa_clist { \refstepcounter{##1}{#2} } } \NewDocumentCommand{\LoopResetCounters}{+m}{% \LoopSetCounters{#1}{0} } \NewDocumentCommand{\LoopStepCounters}{+m}{% \clist_set:Nx \l_tmpa_clist {#1}% \clist_map_inline:Nn \l_tmpa_clist { \stepcounter{##1} } } \NewDocumentCommand{\LoopSetCounters}{+mm}{% \clist_set:Nx \l_tmpa_clist {#1}% \clist_map_inline:Nn \l_tmpa_clist { \setcounter{##1}{#2} } } \NewDocumentCommand{\LoopCountersFunction}{+m+m}{% \clist_set:Nx \l_tmpa_clist {#1}% \clist_map_inline:Nn \l_tmpa_clist { #2{##1} } } \NewDocumentCommand{\LoopFullCounterResetList}{m+m}{% \__xassoccnt_get_full_reset_list:n {#1}% \seq_if_exist:cT {#1_fullresetlist_seq } { \seq_map_inline:cn {#1_fullresetlist_seq} {% #2{##1}% } }% } \NewDocumentCommand{\LoopCounterResetList}{mm}{% \seq_gclear:N \g_xassoccnt_reset_seq \group_begin: \cs_if_exist:cT {cl@#1} {% \def\@elt##1{% \seq_gput_right:Nn \g_xassoccnt_reset_seq {##1} } \use:c{cl@#1}% Fill the list } \group_end: \seq_map_inline:Nn \g_xassoccnt_reset_seq {% \use:c{\cs_to_str:N #2}{#1}{##1} } } %%%% %% Counter-Values-Mapping-To-Something-Different - Macros %%% To be done! %%%%%%%%%%%%%%%%%%%% %% Reporting Macros \NewDocumentCommand{\ShowResetList}{m}{% \xassoccnt_report_resetlist:n{#1}% } \NewDocumentCommand{\DisplayResetList}{O{,}m}{% \__xassoccnt_getresetlist:n {#2} \seq_use:Nn \l__xassoccnt_counterreset_seq {#1} } %%%%%%%%%%%%%%%%%%%% \cs_new:Nn \xassoccnt_declaredocumentcounteropt:nnn{% \seq_set_from_clist:Nx \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq { \__xassoccnt_newcounter_ltx:nnn{#1}{##1}{#3}% } } \cs_new:Nn \xassoccnt_declaredocumentcounter:nn{% \seq_set_from_clist:Nx \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq { \__xassoccnt_newcounter_ltx:nn{#1}{##1}{}% } } \cs_generate_variant:Nn \xassoccnt_declaredocumentcounter:nn {nx} %%% Counter Output \cs_new:Npn \BinaryValue#1{% \int_to_bin:n{\number\value{#1}}% } \cs_new:Npn \hexValue#1{% \int_to_hex:n{\number\value{#1}}% } \cs_new:Npn \HexValue#1{% \int_to_Hex:n{\number\value{#1}}% } \cs_new:Npn \OctalValue#1{% \int_to_oct:n{\number\value{#1}}% } \cs_new:Npn \xalphalph #1 {% \int_to_alph:n{\number\value{#1}} } \cs_new:Npn \xAlphAlph #1 {% \int_to_Alph:n{\number\value{#1}} } \cs_new:Nn \xassoccnt_default_counterformat:n{% \arabic{#1}% } \cs_new:Nn \xassoccnt_alphalph_wrapper:n{% \xassoccnt_package_notloaded:nTF {alphalph}{% \cs_set:cpn {the#1}{\int_to_alph:n{\number\value{#1}}} }{% \cs_set:cpn {the#1}{\alphalph{\value{#1}}} } } \cs_new:Nn \xassoccnt_AlphAlph_wrapper:n{% \xassoccnt_package_notloaded:nTF {alphalph}{% \cs_set:cpn {the#1}{\int_to_Alph:n{\number\value{#1}}} }{% \cs_set:cpn {the#1}{\AlphAlph{\value{#1}}} } } \NewDocumentCommand{\alphalphinternal}{m}{% \xassoccnt_alphalph_wrapper:n{#1} } \NewDocumentCommand{\AlphAlphinternal}{m}{% \xassoccnt_AlphAlph_wrapper:n{#1} } \keys_define:nn {xassoccnt(COUNTERFORMAT)} { separator .initial:n={!}, separator .code:n={\prop_put:Nnn \l__xassoccnt_tmpa_prop {counterformatseparator} {#1}}, recursive .bool_set:N=\l_tmpa_bool } \cs_new:Nn \__xassoccnt_add_counter_formats:nn {% \group_begin: \seq_set_from_clist:Nn \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq {% \seq_set_split:Nxn \l_tmpb_seq {#1} {##1} \int_compare:nNnTF {\seq_count:N \l_tmpb_seq } > {1} { \prop_gput:Nxx \g_xassoccnt_counter_formatdata_prop {\seq_item:Nn \l_tmpb_seq {1}} { \seq_item:Nn \l_tmpb_seq {2} } }{ \msg_fatal:nnx {xassoccnt}{counterformatwrongortooshort}{\seq_item:Nn \l_tmpb_seq {1}} } } \group_end: } \cs_new:Nn \__xassoccnt_remove_counter_formats:nn {% \seq_set_from_clist:Nn \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq { \prop_gremove:Nx \g_xassoccnt_counter_formatdata_prop {##1} } } \NewDocumentCommand{\StoreCounterFormats}{O{}m}{% \group_begin: \keys_set:nn {xassoccnt(COUNTERFORMAT)}{separator=!,#1} \__xassoccnt_add_counter_formats:nn {\prop_item:Nn \l__xassoccnt_tmpa_prop {counterformatseparator}}{#2} \group_end: } \NewDocumentCommand{\AddCounterFormats}{O{}m}{% \group_begin: \keys_set:nn {xassoccnt(COUNTERFORMAT)}{separator={!},#1} \__xassoccnt_add_counter_formats:nn {\prop_item:Nn \l__xassoccnt_tmpa_prop {counterformatseparator}}{#2} \group_end: } \NewDocumentCommand{\RemoveCounterFormats}{O{}m}{% % First optional arg is reserved for later purposes \__xassoccnt_remove_counter_formats:nn {}{#2} } \NewDocumentCommand{\ClearCounterFormats}{}{% \prop_gclear:N \g_xassoccnt_counter_formatdata_prop } \NewDocumentCommand{\ShowCounterFormats}{}{% \prop_map_inline:Nn \g_xassoccnt_counter_formatdata_prop {##1~uses~\cs_to_str:N ##2\par} } % \seq_item 1 / seq_item 2 \cs_new:Nn \__xassoccnt_set_counterformat:nnn{% \group_begin: \tl_clear:N \l_tmpb_tl \int_compare:nNnTF {#1} > {1} {% \tl_set:Nx \l_tmpb_tl {#3} }{% Only one or less arguments -> use \arabic as counter format} \tl_set:Nn \l_tmpb_tl {n} % Arabic counter format (ar) } \prop_if_in:NVTF \g_xassoccnt_counter_formatdata_prop {\l_tmpb_tl} {% \tl_clear:N \l_tmpa_tl \tl_put_right:Nx \l_tmpa_tl { \prop_item:NV \g_xassoccnt_counter_formatdata_prop {\l_tmpb_tl}{#2}} \cs_gset:cpV {the #2} {\l_tmpa_tl} }{% \msg_fatal:nnxx {xassoccnt}{counterformatnotdefined}{\tl_use:N \l_tmpb_tl}{#2} } \group_end: } \cs_new:Nn \xassoccnt_set_counterformat:n {% \seq_set_split:Nxn \l_tmpb_seq {\prop_item:Nn \l__xassoccnt_tmpa_prop {counterformatseparator}} {#1} \__xassoccnt_set_counterformat:nnn { \seq_count:N \l_tmpb_seq }{ \seq_item:Nn \l_tmpb_seq {1}} { \seq_item:Nn \l_tmpb_seq {2} } } \NewDocumentCommand{\CounterFormat}{O{}m}{% \group_begin: \keys_set:nn {xassoccnt(COUNTERFORMAT)}{recursive=false,separator={!},#1} \bool_if:NTF \l_tmpa_bool {% \xassoccnt_recursive_counter_format:n{#2} }{% \seq_set_from_clist:Nx \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq {% \xassoccnt_set_counterformat:n {##1} } } \group_end: } \cs_new:Nn \__xassoccnt_recursive_counter_format:nn {% \tl_set:Nx \l__xassoccnt_tmpb_tl {#2}% \xassoccnt_parent_counter_chain:n {#1} \seq_if_exist:cT {g_xassoccnt_#1_counter_chain_seq}{ \seq_map_inline:cn {g_xassoccnt_#1_counter_chain_seq } {% \int_incr:N \l__xassoccnt_tmpa_int \int_compare:nNnTF{ \l__xassoccnt_tmpa_int} < {\seq_count:c {g_xassoccnt_#1_counter_chain_seq}} {% \int_set:NV \l_tmpa_int { \l__xassoccnt_tmpa_int } \int_incr:N \l_tmpa_int \tl_set:Nn \l_tmpa_tl {\csname} \tl_put_right:Nx \l_tmpa_tl {the\seq_item:cn {g_xassoccnt_#1_counter_chain_seq} {\l_tmpa_int}} \tl_put_right:Nn \l_tmpa_tl {\endcsname.} \tl_put_right:NV \l_tmpa_tl {\l__xassoccnt_tmpb_tl{##1}} }{% % Last element of the list, must only have its own representation usually, say \arabic{ \tl_clear:N \l_tmpa_tl \tl_put_right:NV \l_tmpa_tl {\l__xassoccnt_tmpb_tl{##1}} } \cs_gset:cpV {the##1} {\l_tmpa_tl} } }% End of \seq_if_exist:cT } \cs_new:Nn \xassoccnt_recursive_counter_format:n {% \group_begin: \seq_set_split:Nxn \l_tmpb_seq {\prop_item:Nn \l__xassoccnt_tmpa_prop {counterformatseparator}} {#1} % Get format \tl_clear:N \l_tmpb_tl \int_compare:nNnTF {\seq_count:N \l_tmpb_seq} > {1} {% \tl_set:Nx \l_tmpb_tl {\seq_item:Nn \l_tmpb_seq {2}} }{% Only one or less arguments -> use \arabic as counter format} \tl_set:Nn \l_tmpb_tl {n} % Arabic counter format (n) } \__xassoccnt_recursive_counter_format:nn {\seq_item:Nn \l_tmpb_seq {1}}{\prop_item:NV \g_xassoccnt_counter_formatdata_prop {\l_tmpb_tl}} \group_end: } %%%%%%%%%%%%%%%%%%%% \NewDocumentCommand{\EnableNumberofrunsTF}{mm}{% \bool_if:NF \g__xassoccnt_nonumberofruns_bool { #1 }{#2} } \NewDocumentCommand{\DeclareDocumentCounter}{O{initial={0}}mo}{% \IfValueTF{#3}{% \xassoccnt_declaredocumentcounteropt:nnn{#1}{#2}{#3}% }{% \xassoccnt_declaredocumentcounter:nn{#1}{#2}% }% } \cs_new:Nn \__xassoccnt_generate_associated_counters_labels:Nn {% \seq_map_inline:Nn #1 {% \prop_set_eq:NN \l_tmpb_prop \l_tmpa_prop \prop_if_in:NnF \l_tmpb_prop {prefix } { \prop_put:Nnn \l_tmpb_prop {prefix} {##1} } \def\@tempa{##1}% \def\cref@result{2}% \protected@edef\cref@currentlabel{% [\@tempa][\arabic{##1}][\cref@result]% \csname p@##1\endcsname\csname the##1\endcsname}% \__xassoccnt_internal_label:nn {##1} {\prop_item:Nn \l_tmpb_prop {prefix}\prop_item:Nn\l_tmpb_prop {prefix-sep}#2} }% End of \seq_map_inline } %%%% %%% Label features --- Experimental --- from 2017/03/03 \seq_new:N \g_xassoccnt_pre_label_hooks_seq \seq_new:N \g_xassoccnt_post_label_hooks_seq \cs_new:Nn \__xassoccnt_register_label_hook:nn {% \group_begin: \seq_set_from_clist:Nn \l_tmpa_seq {#2} \seq_map_inline:Nn \l_tmpa_seq {% \seq_gput_right:cn {g_xassoccnt_#1_label_hooks_seq} {\cs_to_str:N ##1} } \seq_gremove_duplicates:c {g_xassoccnt_#1_label_hooks_seq} \group_end: } \cs_new:Nn \__xassoccnt_clear_label_hooks:n { \seq_gclear:c {g_xassoccnt_#1_label_hooks_seq } } \cs_new:Nn \__xassoccnt_remove_from_label_hook:nn {% \seq_gremove:cn {g_xassoccnt_#1_label_hooks_seq} {#2} } \NewDocumentCommand{\RegisterPreLabelHook}{m}{% \__xassoccnt_register_label_hook:nn {pre} {#1} } \NewDocumentCommand{\RegisterPostLabelHook}{m}{% \__xassoccnt_register_label_hook:nn {post} {#1} } \NewDocumentCommand{\ClearPostLabelHook}{}{% \__xassoccnt_clear_label_hooks:n {post} } \NewDocumentCommand{\ClearPreLabelHook}{}{% \__xassoccnt_clear_label_hooks:n {post} } \NewDocumentCommand{\RunLabelHooks}{mm}{% \seq_if_exist:cT {g_xassoccnt_#1_label_hooks_seq} { \seq_map_inline:cn {g_xassoccnt_#1_label_hooks_seq} {% \cs_if_exist:cT {##1} { \use:c{##1}{#2}% } } } } \NewDocumentCommand{\RunPreLabelHooks}{m}{% \seq_if_exist:NT \g_xassoccnt_pre_label_hooks_seq { \seq_map_inline:Nn \g_xassoccnt_pre_label_hooks_seq {% \cs_if_exist:cT {##1} { \use:c{##1}{#1}% } } } } \NewDocumentCommand{\RunPostLabelHooks}{m}{% \seq_if_exist:NT \g_xassoccnt_post_label_hooks_seq { \seq_map_inline:Nn \g_xassoccnt_post_label_hooks_seq {% \cs_if_exist:cT {##1} { \use:c{##1}{#1}% } } } } %%% \NewDocumentCommand{\ProvideOriginalLabelCommands}{}{% \cs_new:Nn \__xassoccnt_internal_label:n {% \xassoccntlatex@@label{##1}% } \cs_new:Nn \__xassoccnt_internal_label:nn {% \bool_if:NTF \l__xassoccnt_cleverefpackage_loaded_bool {% \xassoccntlatex@@label[##1]{##2}% }{ \xassoccntlatex@@label{##2}% } } } \NewDocumentCommand{\RedefineLabelCommand}{}{% % Do only if redefinelabel=true was set as package option \bool_if:NT \g__xassoccnt_redefinelabel_bool { \keys_define:nn {xassoccntlabel} {% all .bool_set:N = \l_xassoccnt_allassociatedcounters_labeled_bool, select .code:n= { \seq_set_from_clist:Nx \l_tmpa_seq { ##1 }\bool_set_false:N \l_xassoccnt_allassociatedcounters_labeled_bool }, prefix .code:n={ \prop_put:Nnx \l_tmpa_prop {prefix} {##1} }, prefix-sep .code:n={ \prop_put:Nnx \l_tmpa_prop {prefix-sep} {##1} } } \RenewDocumentCommand{\label}{omO{}}{% \group_begin: \prop_clear:N \l_tmpa_prop \seq_clear:N \l_tmpa_seq \keys_set:nn {xassoccntlabel} {all=true,prefix-sep={\xassoccnt_extract_moduledata:n{prefix-sep}},##3}% % \RunLabelHooks{pre}{##2}% \IfValueTF{##1}{% % Generate the regular label \__xassoccnt_internal_label:nn {##1} {##2} }{% \__xassoccnt_internal_label:n {##2} } \RunLabelHooks{post}{##2}% \bool_if:NT \l_xassoccnt_allassociatedcounters_labeled_bool {% % The prefix is made from the associated counter \prop_remove:Nn \l_tmpa_prop {prefix} \seq_set_eq:Nc \l_tmpa_seq {\__xassoccnt_drivercontainer:n{\LastRefSteppedCounter}} } \seq_if_empty:NF \l_tmpa_seq {% Check whether either the only - list or the driver container list is empty (i.e. it was no driver container at all % If non-empty -> generate the labels with the given naming scheme \__xassoccnt_generate_associated_counters_labels:Nn \l_tmpa_seq {##2} }% End of \seq_if_empty \group_end: }% End of \RenewDocumentCommand{\label} }% End of bool_if:NT \g__xassoccnt_redefinelabel_bool } \NewDocumentCommand{\LaTeXLabel}{om}{% \bool_if:NTF \l__xassoccnt_cleverefpackage_loaded_bool {% \IfValueTF{#1}{ \xassoccntlatex@@label[#1]{#2}% }{ \xassoccntlatex@@label{#2}% } }{% \xassoccntlatex@@label{#2}% } } %%%%%%%%%%%%%%%%%%%% %%% Counter names to human language maps \seq_new:N \g_xassoccnt_language_map_seq \cs_new:Nn \__xassoccnt_declare_language_map:n {% \seq_set_from_clist:Nx \l_tmpa_seq {#1} \seq_map_inline:Nn \l_tmpa_seq { \seq_gput_right:Nn \g_xassoccnt_language_map_seq {##1} \prop_if_exist:cF {g_xassoccnt_language_map_##1_prop } { \prop_new:c { g_xassoccnt_language_map_##1_prop } } } } \cs_new:Nn \__xassoccnt_new_language_mapping:n { \seq_if_in:NnTF \g_xassoccnt_language_map_seq {#1} { \msg_warning:nnn{xassoccnt}{languagemappingalreadyexists} {#1} }{ \__xassoccnt_declare_language_map:n {#1} } } \cs_new:Nn \__xassoccnt_declare_language_map:nn { \__xassoccnt_new_language_mapping:n {#1 } \__xassoccnt_add_language_mappings:nn {#1} {#2} % \seq_set_from_clist:Nx \l_tmpa_seq {#2} % \seq_new:c { g_xassoccnt_language_map_#1_seq } % \seq_map_inline:Nn \l_tmpa_seq { % \__xassoccnt_split_mapping_sequence:nn {#1} {##1} % } % \prop_log:c {g_xassoccnt_language_map_#1_prop } } \cs_new:Nn \__xassoccnt_add_language_mappings:nn {% \group_begin: \seq_set_from_clist:Nx \l_tmpa_seq {#2} \seq_if_exist:cF { g_xassoccnt_language_map_#1_seq } { \seq_new:c { g_xassoccnt_language_map_#1_seq } } \seq_map_inline:Nn \l_tmpa_seq { \__xassoccnt_split_mapping_sequence:nn {#1} {##1} } \group_end: } \cs_new:Nn \__xassoccnt_use_if_empty:nn {% \int_compare:nNnTF {\tl_count:n {#2} } = {0} { #1 }{% #2 } } \cs_generate_variant:Nn \__xassoccnt_use_if_empty:nn {nx,no,xx,xn} \cs_new:Nn \prop_put_uppercase_first:Nnn { \prop_put:Nnn #1 {#2} {\__xassoccnt_uppercase_first:n {#3}} } \cs_new:Nn \prop_gput_uppercase_first:Nnn {% \typeout{Content~is~#3} \tl_set:Nn \l_tmpa_tl {#3} %\__xassoccnt_uppercase_first:n { \typeout{Content is \tl_use:N \l_tmpa_tl} \prop_gput:NnV #1 {#2} {\l_tmpa_tl } } \cs_new:Nn \prop_gput_uppercase_first:Nnnn {% \tl_if_empty:nTF {#4} { \prop_gput:Nnx #1 {#2} {\__xassoccnt_uppercase_first:n {#3}} }{ \prop_gput:NnV #1 {#2} {\__xassoccnt_uppercase_first:n {#4}} } } \cs_new:Nn \__xassoccnt_uppercase_first:n {% \tl_upper_case:n {\tl_head:n{#1}}\tl_tail:n{#1} } \cs_generate_variant:Nn \__xassoccnt_uppercase_first:n {x,o,V} \cs_generate_variant:Nn \prop_put_uppercase_first:Nnn {Nxx,Nnx,Nno,Nxn, cxn, cno,cxx,cnn} \cs_generate_variant:Nn \prop_gput_uppercase_first:Nnn {Nxx,Nnx,Nno,Nxn, cxn, cno,cxx,cnn} \cs_generate_variant:Nn \prop_gput_uppercase_first:Nnnn {Nxxx,Nnxx,cxxx,cnnn} \cs_new:Nn \__xassoccnt_split_mapping_sequence:nn {% \group_begin: \seq_set_split:Nnn \l_tmpb_seq {;;} {#2} \seq_gput_right:cx {g_xassoccnt_language_map_#1_seq } { \seq_item:Nn \l_tmpb_seq {1}} \int_compare:nNnT { \seq_count:N \l_tmpb_seq } = { \c_one_int } { % Append the first element to be the reference entry \seq_put_right:Nx \l_tmpb_seq { \seq_item:Nn \l_tmpb_seq {1} } } \prop_gput:cxx { g_xassoccnt_language_map_#1_prop } {\seq_item:Nn \l_tmpb_seq {1}-singular} {\__xassoccnt_use_if_empty:xn{\seq_item:Nn \l_tmpb_seq {2}}{\seq_item:Nn \l_tmpb_seq {2}}} \prop_gput:cxx { g_xassoccnt_language_map_#1_prop } {\seq_item:Nn \l_tmpb_seq {1}-plural} {\__xassoccnt_use_if_empty:xn{\seq_item:Nn \l_tmpb_seq {2}}{\seq_item:Nn \l_tmpb_seq {3}}} \prop_gput_uppercase_first:cxxx { g_xassoccnt_language_map_#1_prop } {\seq_item:Nn \l_tmpb_seq {1}-uppercase-singular} {\seq_item:Nn \l_tmpb_seq {2}}{\seq_item:Nn \l_tmpb_seq {4}} \prop_gput_uppercase_first:cxxx { g_xassoccnt_language_map_#1_prop } {\seq_item:Nn \l_tmpb_seq {1}-uppercase-plural} {\seq_item:Nn \l_tmpb_seq {2}}{\seq_item:Nn \l_tmpb_seq {5}} \group_end: } \cs_generate_variant:Nn \__xassoccnt_declare_language_map:nn {nx,xx} \cs_generate_variant:Nn \__xassoccnt_declare_language_map:n {x} \NewDocumentCommand{\DeclareLanguageMap}{m}{% \__xassoccnt_declare_language_map:n {#1} } \NewDocumentCommand{\DeclareLanguageMappings}{m+m}{% \__xassoccnt_declare_language_map:nn {#1}{#2} } \NewDocumentCommand{\AddLanguageMappings}{m+m}{% \__xassoccnt_add_language_mappings:nn{#1}{#2}% } \cs_generate_variant:Nn \prop_map_inline:Nn {Nx,cx} \NewDocumentCommand{\ShowLanguageMappings}{m}{% \seq_map_inline:cn {g_xassoccnt_language_map_#1_seq }{% ##1 ~ \prop_item:cx { g_xassoccnt_language_map_#1_prop } { ##1-singular } ~ \prop_item:cx { g_xassoccnt_language_map_#1_prop } { ##1-plural } ~ \prop_item:cx { g_xassoccnt_language_map_#1_prop } { ##1-uppercase-singular } ~ \prop_item:cx { g_xassoccnt_language_map_#1_prop } { ##1-uppercase-plural } \par } %\prop_map_inline:cn {g_xassoccnt_language_map_#1_prop }{#1 ~ ##1 ~ ##2 \par} } \cs_new:Npn \RetrieveCounterSingularName #1#2{% \prop_item:cn {g_xassoccnt_language_map_#1_prop }{#2-singular} } \cs_new:Npn \SetLanguageMapping #1 {% \seq_if_in:NnTF \g_xassoccnt_language_map_seq {#1} { \prop_gput:Nnn \g_xassoccnt_module_data_prop {currentlanguage} {#1} }{% Begin of False \msg_error:nnn{xassoccnt}{undefinedlanguagemapping}{#1} }% End of False } \cs_new:Npn \GetLanguageMapping {% \prop_item:Nn \g_xassoccnt_module_data_prop {currentlanguage} } \cs_new:Npn \xassingularname #1#2 {% \prop_item:cn {g_xassoccnt_language_map_#1_prop }{#2-singular} } \cs_new:Npn \xaspluralname #1#2 {% \prop_item:cn {g_xassoccnt_language_map_#1_prop }{#2-plural} } %%%%%%%%%%%%%%%%%%% % This is ad-hoc code for a yet - to be defined bool <-> prop list matching code \cs_new:Npn \PropertyHasValueTF #1#2#3#4 {% \int_compare:nNnTF {\prop_item:Nn \g_xassoccnt_module_data_prop {#1}} = {#2} { #3 }{% #4 } } \ExplSyntaxOff \EnableNumberofrunsTF{% \NewTotalDocumentCounter[supertotal=true]{numberofruns} \AtBeginDocument{% \stepcounter{numberofruns}% } }{} %%%%%%%%%%% % Extended interface functions \@onlypreamble{\DeclareTotalDocumentCounter} \@onlypreamble{\RegisterTotalDocumentCounter} \@onlypreamble{\DeclareAssociatedCounters} \@onlypreamble{\DeclareTotalAssociatedCounters} \@onlypreamble{\DeclareDocumentCounter} \@onlypreamble{\DeclareCoupledCounters} \AtEndPreamble{% \AtBeginDocument{% \LetLtxMacro\xassoccntlatex@@label\label \ProvideOriginalLabelCommands% \RedefineLabelCommand% } } \AtBeginDocument{% \PropertyHasValueTF{standardcounterformats} {1} {% \StoreCounterFormats{n!\arabic, b!\BinaryValue,h!\hexValue,H!\HexValue,r!\roman,R!\Roman,A!\Alph,a!\alph,aa!\xalphalph,o!\OctalValue,AA!\xAlphAlph}% }{} \DeclareBackupCountersGroupName{scratch}% } \AtEndDocument{% \WriteCountersAtEnd% } %%% Colour output routines \newcommand{\GeneralCounterInfoColor}{orange} \newcommand{\DriverCounterInfoColor}{blue} \newcommand{\AssociatedCounterInfoColor}{red} \newcommand{\TotalCounterInfoColor}{violet} \AddFeature[sublists=true,publicname={Coupled Counters Feature}]{coupledcounters} \AddFeature[sublists=true,publicname={Backup Counters Feature}]{backupcounters} % New style, not fully implemented so far % Some more to be done \endinput