%% LaTeX package xcntperchap - version 0.5 (2018/01/05 -- 22:04:12) %% Source file for xcntperchap.sty %% %% %% ------------------------------------------------------------------------------------------- %% Copyright (c) 2016 -- 2018 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 `author-maintained` %% %% \def\xcntperchappackageversion{0.5} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{xcntperchap}[2018/01/05 - v\xcntperchappackageversion] \RequirePackage[counter]{zref} \RequirePackage{l3keys2e} \RequirePackage{xparse} \RequirePackage{xassoccnt} \ExplSyntaxOn \cs_set_eq:NN \latex@@stepcounter \stepcounter \cs_set_eq:NN \latex@@addtocounter \addtocounter \cs_set_eq:NN \latex@@setcounter \setcounter \cs_generate_variant:Nn \int_set:Nn {NV, Nx} \cs_generate_variant:Nn \int_eval:n {V, x} \cs_generate_variant:Nn \seq_gremove_all:Nn {NV,Nx,cV,cx} \seq_new:N \g_xcntperchap_tracklevel_seq % This holds all counters which serve as a tracklevel \ior_new:N \g_trackfile_storage_read \iow_new:N \g_trackfile_storage_write \int_new:N \l_tracklevelunit_int \int_new:N \l_tracklevel_tracked_int \cs_new:Nn \xcntperchap_add_tracklevel:n {% \seq_if_in:NnF \g_xcntperchap_tracklevel_seq {#1} {% \seq_gput_right:Nn \g_xcntperchap_tracklevel_seq {#1} \seq_new:c {g_xcntperchap_tracklevel_#1_seq}% Creating a new container for the counter names to be tracked \prop_new:c {g_xcntperchap_tracklevel_#1_prop}% Creating a new property list for the counter names to be tracked \seq_new:c {g_xcntperchap_tracklevelstored_#1_seq}% Creating a new container for the stored counter values (used later on) \IfIsDocumentCounterF{cps@@#1trackleveltotal}{% \NewDocumentCounter{cps@@#1trackleveltotal}% } \DeclareAssociatedCounters{#1}{cps@@#1trackleveltotal} \zref@newprop{cps#1total}{\number\value{cps@@#1trackleveltotal}} }% } \NewDocumentCommand{\RegisterMultipleTrackCounters}{mm}{% \clist_set:Nn \l_tmpa_clist {#1}% \clist_map_inline:Nn \l_tmpa_clist {% \RegisterTrackCounter{##1}{#2}% } } \NewDocumentCommand{\RegisterTrackCounter}{mm}{% \xcntperchap_add_tracklevel:n {#1} \seq_set_from_clist:cn {g_xcntperchap_tracklevel_#1_seq} {#2} \seq_remove_duplicates:c {g_xcntperchap_tracklevel_#1_seq} \int_zero:N \l_tmpa_int \seq_map_inline:cn {g_xcntperchap_tracklevel_#1_seq} {% \int_incr:N \l_tmpa_int \IfIsDocumentCounterF{cps@@#1total##1}{% \NewDocumentCounter{cps@@#1total##1}% \AddAssociatedCounters{##1}{cps@@#1total##1}% Define associated counters } \prop_put:cnV {g_xcntperchap_tracklevel_#1_prop} {##1} \l_tmpa_int % New Version 0.2 } } \cs_new:Nn \xcntperchap_storetracked_values:n{% \group_begin: \tl_clear:N \l_tmpa_tl \int_zero:N \l_tmpa_int \int_zero:N \l_tmpb_int \seq_if_exist:cT {g_xcntperchap_tracklevel_#1_seq} { \seq_if_in:NnT \g_xcntperchap_tracklevel_seq {#1} {% \tl_put_right:Nn \l_tmpa_tl {#1,}% \int_set:Nx \l_tmpb_int {\seq_count:c {g_xcntperchap_tracklevel_#1_seq} } \int_compare:nNnT { \number\value{#1} } > {0 }{% \int_zero:N \l_tmpa_int \seq_map_inline:cn {g_xcntperchap_tracklevel_#1_seq} {% \int_incr:N \l_tmpa_int \int_compare:nNnTF {\l_tmpa_int } < { \l_tmpb_int } { \tl_gput_right:Nx \l_tmpa_tl { \number\value{cps@@#1total##1}, } } { \tl_gput_right:Nx \l_tmpa_tl { \number\value{cps@@#1total##1} } } } % Store the value list to the file \iow_now:Nx \g_trackfile_storage_write {\tl_use:N \l_tmpa_tl}% } \seq_map_inline:cn {g_xcntperchap_tracklevel_#1_seq} { \setcounter{cps@@#1total##1}{\c_zero}% Reset the total counter values } } } \group_end: } \NewDocumentCommand{\StoreCounterValues}{m}{% \xcntperchap_storetracked_values:n{#1}% } % Redefine again, to provide the storage feature \cs_set:Npn \xcntperchap_internal_stepcounter #1 {% % Must get reset list first \__xassoccnt_getresetlist:n{#1}% \seq_map_inline:Nn \g_xcntperchap_tracklevel_seq {% \seq_if_in:NnT \l__xassoccnt_counterreset_seq {##1} {% \StoreCounterValues{##1}% } } \StoreCounterValues{#1}% \latex@@stepcounter{#1}% } \cs_set:Npn \stepcounter #1{% \xcntperchap_internal_stepcounter{#1}% } % Added in Version 0.5 \cs_set:Npn \setcounter #1#2{% % This might be necessary later on -> check in next updates % \__xassoccnt_getresetlist:n{#1}% % \seq_map_inline:Nn \g_xcntperchap_tracklevel_seq {% % \seq_if_in:NnT \l__xassoccnt_counterreset_seq {##1} {% % \StoreCounterValues{##1}% % } % } \StoreCounterValues{#1}% \latex@@setcounter{#1}{#2}% } \NewDocumentCommand{\AddToTrackedCounters}{mm}{% \seq_set_from_clist:Nn \l_tmpa_seq {#1} \seq_map_inline:Nn \l_tmpa_seq {% \prg_replicate:nn {#2} {\stepcounter{##1}} } } \cs_new:Nn \xcntperchap_trackcounters: {% \seq_map_inline:cn {g_xcntperchap_tracklevel_seq} {% \xcntperchap_storetracked_values:n{##1}% } } \NewDocumentCommand{\TrackCounters}{}{% \xcntperchap_trackcounters: } \NewDocumentCommand{\cntperchapsetup}{}{% % Unused so far } \NewDocumentCommand{\LoadTrackedValues}{}{% \IfFileExists{\jobname.cpc}{% \xcntperchap_open_trackfile_for_read:n{\jobname.cpc} \GetStoredValues% \xcntperchap_close_trackfile_for_read: }{} } \cs_new:Nn \l_xcntperchap_numberoftracks:n {% \seq_if_exist:cTF { g_xcntperchap_tracklevelstored_#1_seq} {% \int_eval:n {\seq_count:c {g_xcntperchap_tracklevelstored_#1_seq} / \seq_count:c {g_xcntperchap_tracklevel_#1_seq}} }{ \c_zero } } \cs_new:Nn \xcntperchap_open_trackfile_for_read:n {% \ior_open:Nn \g_trackfile_storage_read {#1} } \cs_new_nopar:Nn \xcntperchap_close_trackfile_for_read: {% \ior_close:N \g_trackfile_storage_read } \cs_new:Nn \xcntperchap_open_trackfile_for_write:n {% \iow_open:Nn \g_trackfile_storage_write {#1} } \cs_new_nopar:Nn \xcntperchap_close_trackfile_for_write: {% \iow_close:N \g_trackfile_storage_write } \NewDocumentCommand{\CloseTrackFileForWrite}{}{% \xcntperchap_close_trackfile_for_write:% } \NewDocumentCommand{\OpenTrackFileForWrite}{m}{% \xcntperchap_open_trackfile_for_write:n{#1}% } \cs_new:Nn \l_xcntperchap_read_countervalues:n {% \clist_set:Nx \l_tmpa_clist {#1}% \tl_set:Nx \l_tmpa_tl {\clist_item:Nn \l_tmpa_clist {1}} \clist_map_inline:Nn \l_tmpa_clist {% \seq_gput_right:cn {g_xcntperchap_tracklevelstored_\l_tmpa_tl _seq} {##1} % Store the value in the tracklevel list for counter \l_tmpa_tl } % Kick the name of the tracklevel counter from the list \seq_gremove_all:cx {g_xcntperchap_tracklevelstored_\l_tmpa_tl _seq} {\tl_use:N \l_tmpa_tl}% } \cs_new_nopar:Nn \xcntperchap_gettrackedvalues_from_file:n {% \ior_map_inline:Nn #1 { \l_xcntperchap_read_countervalues:n{##1} } } % Unexpandable version! \cs_new:Nn \xcntperchap_obtaintrackedvalue:nnn {% \int_set:Nx \l_tracklevelunit_int {#1} \seq_if_in:cnTF {g_xcntperchap_tracklevel_#2_seq} {#3} { \int_set:Nx \l_tracklevel_tracked_int {\seq_count:c {g_xcntperchap_tracklevel_#2_seq}} \int_zero:N \l_tmpa_int \seq_map_inline:cn {g_xcntperchap_tracklevel_#2_seq} {% \int_incr:N \l_tmpa_int \tl_if_eq:nnT { ##1 } {#3 } { \seq_map_break: } } \int_set:NV \l_tmpb_int { \l_tmpa_int } \int_set:Nx \l_tmpa_int { \l_tracklevel_tracked_int * (\l_tracklevelunit_int -1) + \l_tmpb_int } }{% % Perhaps some error message here, for the moment only a screen message \typeout{#3~is~not~under~track~control~of~#2} } } \NewDocumentCommand{\ObtainTrackedValue}{omm}{% \IfValueTF{#1}{% \xcntperchap_obtaintrackedvalue:nnn {#1}{#2}{#3}% }{% \xcntperchap_obtaintrackedvalue:nnn {\number\value{#2}}{#2}{#3}% }% } %%%%% 0.2 Expandable Version \cs_new:Nn \xcntperchap_obtaintrackedvalue_exp:nnn {% Needs some error checking!!! \seq_if_exist:cTF {g_xcntperchap_tracklevel_#2_seq} { \seq_item:cn {g_xcntperchap_tracklevelstored_#2_seq} { \seq_count:c {g_xcntperchap_tracklevel_#2_seq} * \int_eval:n{#1-1}+\prop_item:cn {g_xcntperchap_tracklevel_#2_prop} {#3}} }{ \typeout{Error!}% } } \DeclareExpandableDocumentCommand{\ObtainTrackedValueExp}{omm}{% \IfValueTF{#1}{% \xcntperchap_obtaintrackedvalue_exp:nnn {#1}{#2}{#3}% }{% \xcntperchap_obtaintrackedvalue_exp:nnn {\number\value{#2}}{#2}{#3} } } \NewDocumentCommand{\GetStoredValues}{}{% \xcntperchap_gettrackedvalues_from_file:n {\g_trackfile_storage_read} } \ExplSyntaxOff \newif\if@cpscleverefloaded \AtBeginDocument{% \@ifpackageloaded{cleveref}{% \global\@cpscleverefloadedtrue }{% \global\@cpscleverefloadedfalse } } \NewDocumentCommand{\tracklabel}{som}{% \zref@labelbyprops{#3}{counter,cps\LastRefSteppedCounter total}% The counter property is for safety here! \IfBooleanF{#1}{% No starred version, generate the usual \label % Check first whether we're using cleveref \IfValueTF{#2}{% \@ifcleverefloadedtrue \label[#2]{#3}% \else % ignore the optional argument provided by tracklabel, it's of use since cleveref is not loaded. \label{#3}% \fi }{% No optional argument \label{#3}% }% }% End of checking for starred command } \DeclareExpandableDocumentCommand{\ObtainTrackedValueByLabel}{omm}{% \zref@ifrefundefined{#2}{??}{% \IfValueTF{#1}{% \ObtainTrackedValueExp[\zref@extract{#2}{cps#1total}]{#1}{#3}% }{% \ObtainTrackedValueExp[\zref@extract{#2}{cps\zref@extract{#2}{counter}total}]{\zref@extract{#2}{counter}}{#3}% }% }% } \NewDocumentCommand{\RegisterCounters}{mm}{% \RegisterTrackCounter{#1}{#2}% } \@onlypreamble\RegisterTrackCounter \@onlypreamble\RegisterMultipleTrackCounters \@onlypreamble\RegisterCounters \makeatother \AtBeginDocument{% \LoadTrackedValues% \OpenTrackFileForWrite{\jobname.cpc}% } \AtEndDocument{% \TrackCounters% \CloseTrackFileForWrite% } \endinput