% ---------------------------------------------------------------------------- % the XSIM package - auxfile module % % eXercise Sheets IMproved % % ---------------------------------------------------------------------------- % Clemens Niederberger % Web: https://github.com/cgnieder/xsim % E-Mail: contact@mychemistry.eu % ---------------------------------------------------------------------------- % Copyright 2017--2020 Clemens Niederberger % % 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 `maintained'. % % The Current Maintainer of this work is Clemens Niederberger. % ---------------------------------------------------------------------------- % If you have any ideas, questions, suggestions or bugs to report, please % feel free to contact me. % ---------------------------------------------------------------------------- \XSIMmodule{auxfile}{writing stuff to an auxiliary file} \prg_new_conditional:Npnn \xsim_if_use_aux: {p,T,F,TF} { \bool_if:NTF \g_xsim_use_aux_bool { \prg_return_true: } { \prg_return_false: } } \cs_new_protected:Npn \xsim_write_to_aux:n #1 { \legacy_if:nT {@filesw} { \xsim_if_use_aux:TF { \iow_now:Nn \@auxout {#1} } { \iow_now:Nn \l__xsim_aux_file_iow {#1} } } } \cs_generate_variant:Nn \xsim_write_to_aux:n {x} % -------------------------------------------------------------------------- \cs_new_protected:Npn \XSIM #1 { \use:c {XSIMaux#1} } \cs_new_protected:Npn \xsim_new_aux_property:cpn #1 { \cs_new_protected:cpn {XSIMaux#1} } \cs_new_protected:Npn \xsim_add_property_to_aux:nn #1#2 { \xsim_verbose:n { Writing~ command~ \XSIM {#1}~ to~ aux~ file } \xsim_write_to_aux:x { \token_to_str:N \XSIM {#1} #2 } } \xsim_at_begin_document:n { \iow_now:Nx \@auxout { \token_to_str:N \providecommand \token_to_str:N \XSIM [1] {} } } % ---------------------------------------------------------------------------- \xsim_if_use_aux:F { \iow_new:N \l__xsim_aux_file_iow \xsim_at_begin_document:n { \iow_open:Nn \l__xsim_aux_file_iow { \c_sys_jobname_str .xsim } } } \cs_new_protected:Npn \xsim_close_aux: { \xsim_if_use_aux:F { \iow_close:N \l__xsim_aux_file_iow \legacy_if:nT {@filesw} { \iow_now:Nx \@auxout { \token_to_str:N \XSIM {readaux} } } } } \xsim_new_aux_property:cpn {readaux} { \file_if_exist:nT { \c_sys_jobname_str .xsim } { \file_input:n { \c_sys_jobname_str .xsim } } } % ---------------------------------------------------------------------------- % list for recording values that need to be written to the aux file and % updated at begin document \str_new:N \l__xsim_split_aux_lists_str \keys_define:nn {xsim} { split-aux-lists .code:n = \str_set:Nn \l__xsim_split_aux_lists_str {#1} , split-aux-lists .initial:n = || } % define list: % #1: name \cs_new_protected:Npn \xsim_new_list:n #1 { \xsim_verbose:n { Defining~ new~ auxfile~ list~ `#1'. } \prop_new:c {g__xsim_list_#1_prop} \seq_new:c {g__xsim_list_#1_seq} \seq_new:c {g__xsim_list_recorded_#1_seq} \xsim_new_aux_property:cpn {#1} ##1 { \prop_gclear:c {g__xsim_list_#1_prop} \tl_if_blank:nF {##1} { \seq_gset_split:cVx {g__xsim_list_#1_seq} \l__xsim_split_aux_lists_str { \tl_to_str:n {##1} } \seq_map_inline:cn {g__xsim_list_#1_seq} { \prop_gput:cnn {g__xsim_list_#1_prop} {####1} {} } } } \xsim_at_begin_document:n { \seq_gclear:c {g__xsim_list_recorded_#1_seq} \seq_set_eq:Nc \l__xsim_tmpa_seq {g__xsim_list_#1_seq} \seq_map_inline:Nn \l__xsim_tmpa_seq { \str_set:Nn \l__xsim_tmpa_str {##1} \seq_gput_right:cV {g__xsim_list_recorded_#1_seq} \l__xsim_tmpa_str } \seq_gremove_duplicates:c {g__xsim_list_recorded_#1_seq} } } % add to or remove from list: % #1: name % #2: entry \cs_new_protected:Npn \xsim_add_to_list:nn #1#2 { \xsim_verbose:n { Adding~ `#2'~ to~ list~ `#1'. } \str_set:Nn \l__xsim_tmpa_str {#2} \prop_gput:cnn {g__xsim_list_#1_prop} {#2} {} \seq_if_in:cVT {g__xsim_list_#1_seq} \l__xsim_tmpa_str { \seq_gremove_all:cV {g__xsim_list_#1_seq} \l__xsim_tmpa_str } \seq_gput_right:cV {g__xsim_list_#1_seq} \l__xsim_tmpa_str } \cs_generate_variant:Nn \xsim_add_to_list:nn {nx} % #1: name % #2: entry \cs_new_protected:Npn \xsim_remove_from_list:nn #1#2 { \xsim_verbose:n { Removing~ `#2'~ to~ list~ `#1'. } \str_set:Nn \l__xsim_tmpa_str {#2} \prop_if_in:cnT {g__xsim_list_#1_prop} {#2} { \prop_gremove:cn {g__xsim_list_#1_prop} {#2} } \seq_if_in:cVT {g__xsim_list_#1_seq} \l__xsim_tmpa_str { \seq_gremove_all:cV {g__xsim_list_#1_seq} \l__xsim_tmpa_str } \seq_if_in:cVT {g__xsim_list_recorded#1_seq} \l__xsim_tmpa_str { \seq_gremove_all:cV {g__xsim_list_recorded_#1_seq} \l__xsim_tmpa_str } } \cs_generate_variant:Nn \xsim_remove_from_list:nn {nx} % check if in list: % #1: name % #2: entry \prg_new_conditional:Npnn \xsim_if_in_list:nn #1#2 {p,T,F,TF} { \prop_if_in:cnTF {g__xsim_list_#1_prop} {#2} { \prg_return_true: } { \prg_return_false: } } \cs_generate_variant:Nn \xsim_if_in_list:nnTF {nx} \cs_generate_variant:Nn \xsim_if_in_list:nnT {nx} \cs_new:Npn \xsim_list_show:n #1 { \prop_show:c {g__xsim_list_#1_prop} } \bool_new:N \l__xsim_empty_lists_bool \cs_new_protected:Npn \xsim_empty_lists: { \bool_set_true:N \l__xsim_empty_lists_bool } % update list (should be used inside \xsim_at_end_document:n): % #1: name \cs_new_protected:Npn \xsim_update_list:n #1 { \xsim_verbose:n { Updating~ list~ `#1'. } \seq_remove_duplicates:c {g__xsim_list_#1_seq} \seq_remove_duplicates:c {g__xsim_list_recorded_#1_seq} \str_set:Nx \l__xsim_tmpa_str { \seq_use:cn {g__xsim_list_#1_seq} {} } \str_set:Nx \l__xsim_tmpb_str { \seq_use:cn {g__xsim_list_recorded_#1_seq} {} } \str_if_eq:NNF \l__xsim_tmpa_str \l__xsim_tmpb_str { \xsim_rerun: } \bool_if:NF \l__xsim_empty_lists_bool { \xsim_add_property_to_aux:nn {#1} { { \seq_use:cV {g__xsim_list_#1_seq} \l__xsim_split_aux_lists_str } } } } % loop over list: % #1: name % #2: code \cs_new_protected:Npn \xsim_foreach_list_entry:nn #1#2 { \seq_map_inline:cn {g__xsim_list_recorded_#1_seq} {#2} } \cs_new_protected:Npn \xsim_foreach_new_list_entry:nn #1#2 { \seq_map_inline:cn {g__xsim_list_#1_seq} {#2} } % length of a list: % #1: name \cs_new:Npn \xsim_list_count:n #1 { \seq_count:c {g__xsim_list_recorded_#1_seq} } % item of a list: % #1: name % #2: integer \cs_new:Npn \xsim_list_item:nn #1#2 { \seq_item:cn {g__xsim_list_recorded_#1_seq} {#2} } % ---------------------------------------------------------------------------- \file_input_stop: