summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/latex/xassoccnt
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2015-11-07 23:20:16 +0000
committerKarl Berry <karl@freefriends.org>2015-11-07 23:20:16 +0000
commit62343452c8e0aff0f46aa81463462fa3fa98f579 (patch)
treeffe7f69205ac58ca166847e9719c0147df350013 /Master/texmf-dist/tex/latex/xassoccnt
parent7997142fbde257d4323fb42fbd6704735854bd8c (diff)
xassoccnt (7nov15)
git-svn-id: svn://tug.org/texlive/trunk@38795 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex/xassoccnt')
-rw-r--r--Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty835
1 files changed, 835 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty b/Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty
new file mode 100644
index 00000000000..af5d532a123
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/xassoccnt/xassoccnt.sty
@@ -0,0 +1,835 @@
+\def\xassoccntpackageversion{0.1}
+\NeedsTeXFormat{LaTeX2e}
+
+\ProvidesPackage{xassoccnt}[2015/11/07 - v\xassoccntpackageversion]
+
+\RequirePackage{xcolor}
+\RequirePackage{xparse}
+\RequirePackage{l3keys2e}
+
+\ExplSyntaxOn
+
+% First some local or global values
+
+\int_new:N \l__xassoccnt_initialcountervalue_int
+\int_new:N \g__xassoccnt_lastcountervalue_int
+
+\bool_new:N \g__xassoccnt_autodefine_counters % --> 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_countertype_general
+\bool_new:N \l__xassoccnt_countertype_driver
+\bool_new:N \l__xassoccnt_countertype_associated
+
+
+
+\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} }
+}
+
+
+
+\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,
+ % 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,
+
+%% For later purposes
+ countertype .choice:,
+ countertype / general .code:n= {\bool_set_true:N \l__xassoccnt_countertype_general },
+ countertype / driver .code:n= {\bool_set_true:N \l__xassoccnt_countertype_driver },
+ countertype / associated .code:n= {\bool_set_true:N \l__xassoccnt_countertype_associated },
+ countertype .initial:n={ general }
+}
+
+\ProcessKeysOptions{xassoccnt}
+
+
+\msg_new:nnn{xassoccnt}{counteralreadyexists}{%
+ Error:~Counter~#1~already~exists\\
+}
+
+
+\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~---
+}
+
+\cs_new:Nn \__xassoccnt_stpelt:n{\global\csname c@#1\endcsname \c_minus_one\xassoccnt_addtocounter{#1}{\c_one}}%
+
+
+\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
+% \def\@elt##1{\int_gincr:N \l_xassoccnt_resetlist_counter}% Increase the 'counter' globally
+ \use:c{ cl@#1 }
+ \endgroup
+}
+
+
+
+\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
+
+\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%
+}
+
+\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}
+
+\clist_new:N \__g_xassoccnt_countercontainer_clist
+\clist_set: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_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 }
+
+
+
+\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: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{%
+ \keys_set:nn {xassoccnt}{sloppy=false,initial=\c_zero,#1}
+ \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}
+ }%
+}
+
+\cs_new:Nn \__xassoccnt_newcounter_ltx:nnn{%
+ \keys_set:nn {xassoccnt}{sloppy=false,initial=\c_zero,#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}
+ }
+}
+
+
+
+
+\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 { cnTF }
+\cs_generate_variant:Nn \__xassoccnt_container_if_in:NnT { cnT }
+\cs_generate_variant:Nn \__xassoccnt_container_if_in:NnF { cnF }
+
+\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:cnTF{\__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_if_empty:NF \l__xassoccnt_onlycounters_clist {%
+ \__xassoccnt_container_putright:nn{\c_xassoccnt_suspendedname_str}{#2}
+}
+
+
+\NewDocumentCommand{\ResumeSuspendedCounters}{O{}m}{%
+ \__xassoccnt_container_removecounter:nn{\c_xassoccnt_suspendedname_str}{#2}
+}
+
+
+\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}
+ }%
+}
+
+
+
+\RenewDocumentCommand{\stepcounter}{m}{%
+ \xassoccnt_is_suspendedcounter:nF{#1}{%
+ \cs_gset_nopar:Nn \__xassoccnt_laststeppedcounter: {#1}%
+ \xassoccnt_countersinresetlist:n{#1}%
+ \int_compare:nTF{%
+ \l_xassoccnt_resetlist_counter > \c_zero
+ }{%
+ \xassoccnt_standardaddtocounter{#1}{\c_one}%
+ \begingroup
+ \cs_set_eq:NN \@elt \__xassoccnt_stpelt:n
+ \use:c{cl@#1}
+ \endgroup
+ }{%
+ \xassoccnt_standardaddtocounter{#1}{\c_one}
+ }
+ \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#1}}%
+ \seq_if_exist:cT { \__xassoccnt_drivercontainer:n{#1} }
+ { \seq_map_inline:cn {\__xassoccnt_drivercontainer:n{#1} }
+ { \xassoccnt_addtocounter{##1}{\c_one} }
+ }% End of \seq_if_exist
+ }%
+}
+
+
+
+\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_standardaddtocounter{#1}{#2}%
+ \cs_gset_nopar:Nn \__xassoccnt_lastaddtocounter: {#1}%
+ }%
+}
+
+
+\cs_new:Nn \__xassoccnt_setdocumentcounter:nnn {
+ \xassoccnt_standardsetcounter{#2}{#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_standardsetcounter{##1}{#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_is_associatedtocounter:nnT {#2} {##1} { \xassoccnt_standardsetcounter{##1}{#3} }
+ }
+ }
+ }
+ }
+ \cs_gset_nopar:Nn \__xassoccnt_lastsetdocumentcounter: {#2}%
+ \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#2}}%
+}
+
+
+\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
+}
+
+
+
+
+
+% Extended support layer for counters
+\NewDocumentCommand{\SetDocumentCounterOld}{O{associatedtoo=false}mm}{%
+ \xassoccnt_standardsetcounter{#2}{#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_standardsetcounter{##1}{#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_is_associatedtocounter:nnT {#2} {##1} { \xassoccnt_standardsetcounter{##1}{#3} }
+ }
+ }
+ }
+ }
+ \cs_gset_nopar:Nn \__xassoccnt_lastsetdocumentcounter: {#2}%
+ \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#2}}%
+}
+
+
+\NewDocumentCommand{\SetDocumentCounter}{O{associatedtoo=false}mm}{%
+ \__xassoccnt_setdocumentcounter:nnn {#1}{#2}{#3} % copy the driver counter value to all associated counters
+}
+
+\NewDocumentCommand{\SyncCounters}{om}{%
+ \IfValueTF{#1}{%
+ \__xassoccnt_synccounters:nn {#1}{#2}
+ }{%
+ \__xassoccnt_synccounters:nn {}{#2}
+ }
+}
+
+
+\RenewDocumentCommand{\setcounter}{mm}{%
+ \cs_gset_nopar:Nn \__xassoccnt_lastsetcounter: {#1}
+ \xassoccnt_standardsetcounter{#1}{#2}%
+ \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#1}}%
+}
+
+
+\RenewDocumentCommand{\refstepcounter}{m}{%
+ \cs_gset_nopar:Nn \__xassoccnt_lastrefsteppedcounter: {#1}
+ \xassoccnt_standardrefstepcounter{#1}%
+ \int_gset:Nn \g__xassoccnt_lastcountervalue_int {\number\value{#1}}%
+}
+
+%%%% Now some wrapper macros for information on the last counter changed
+
+\newcommand{\LastSteppedCounter}{%
+ \__xassoccnt_laststeppedcounter:
+}
+
+
+\newcommand{\LastRefSteppedCounter}{%
+ \__xassoccnt_lastrefsteppedcounter:
+}
+
+\newcommand{\LastAddedToCounter}{%
+ \__xassoccnt_lastaddtocounter:
+}
+
+\newcommand{\LastSetCounter}{%
+ \__xassoccnt_lastsetcounter:
+}
+
+\newcommand{\LastSetDocumentCounter}{%
+ \__xassoccnt_lastsetdocumentcounter:
+}
+
+
+%%%%%%%%%
+
+
+\newcommand{\LastCounterValue}{%
+%\NewDocumentCommand{\LastCounterValue}{}{%
+ \int_use:N \g__xassoccnt_lastcountervalue_int
+}
+
+
+
+\NewDocumentCommand{\NewDocumentCounter}{O{initial=\c_zero}mo}{%
+ \IfValueTF{#3}{%
+ \__xassoccnt_newcounter_ltx:nnn{#1}{#2}{#3}
+ }{%
+ \__xassoccnt_newcounter_ltx:nnn{#1}{#2}{}
+ }
+}
+
+
+
+\NewDocumentCommand{\CopyDocumentCounters}{O{}mm}{%
+ \__xassoccnt_copycounters:nnn{#1}{#2}{#3}%
+}
+
+\NewDocumentCommand{\SwapDocumentCounters}{O{}mm}{%
+ \__xassoccnt_swapcounters:nnn{#1}{#2}{#3}%
+}
+
+
+\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:Nn \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_set_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}%
+}
+
+
+\ExplSyntaxOff
+
+
+%%%%%%%%%%%
+
+% Extended interface functions
+
+
+\NewDocumentCommand{\DeclareDocumentCounter}{O{initial={0}}mo}{%
+ \IfValueTF{#3}{%
+ \NewDocumentCounter[#1]{#2}[#3]%
+ }{%
+ \NewDocumentCounter[#1]{#2}%
+ }%
+}
+
+\@onlypreamble{\DeclareAssociatedCounters}
+\@onlypreamble{\DeclareDocumentCounter}
+
+\endinput \ No newline at end of file