diff options
author | Karl Berry <karl@freefriends.org> | 2021-06-29 19:53:39 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2021-06-29 19:53:39 +0000 |
commit | fbf2ab9fcc75e9134c6e0f67d21cf7b993e67d99 (patch) | |
tree | 9936b4ef85813b6d9fd9076c679851396960ac6c /Master/texmf-dist/tex/latex | |
parent | 48647527a4d38db34ffd7ef702866e54fa17de55 (diff) |
csvsimple (29jun21)
git-svn-id: svn://tug.org/texlive/trunk@59756 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/latex')
-rw-r--r-- | Master/texmf-dist/tex/latex/csvsimple/csvsimple-l3.sty | 1260 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/csvsimple/csvsimple-legacy.sty | 795 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/csvsimple/csvsimple.sty | 795 |
3 files changed, 2087 insertions, 763 deletions
diff --git a/Master/texmf-dist/tex/latex/csvsimple/csvsimple-l3.sty b/Master/texmf-dist/tex/latex/csvsimple/csvsimple-l3.sty new file mode 100644 index 00000000000..da7e62f47dd --- /dev/null +++ b/Master/texmf-dist/tex/latex/csvsimple/csvsimple-l3.sty @@ -0,0 +1,1260 @@ +%% The LaTeX package csvsimple - version 2.0.0 (2021/06/29) +%% csvsimple-l3.sty: Simple LaTeX CSV file processing (LaTeX3) +%% +%% ------------------------------------------------------------------------------------------- +%% Copyright (c) 2008-2021 by Prof. Dr. Dr. Thomas F. Sturm <thomas dot sturm at unibw dot de> +%% ------------------------------------------------------------------------------------------- +%% +%% 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'. +%% +%% This work consists of all files listed in README.md +%% +\ProvidesExplPackage{csvsimple-l3}{2021/06/29}{2.0.0} + {LaTeX3 CSV file processing} + + + +%---- check package + +\cs_if_exist:NT \c__csvsim_package_expl_bool + { + \msg_new:nnn { csvsimple }{ l3 / package-loaded } + { Package~'csvsimple-legacy'~seems~already~be~loaded!~ + 'csvsimple-l3'~cannot~be~loaded~simultaneously.~ + Therefore,~loading~of~'csvsimple-l3'~stops~now.} + \msg_warning:nn { csvsimple }{ l3 / package-loaded } + \tex_endinput:D + } +\bool_const:Nn \c__csvsim_package_expl_bool { 1 } + + + +%---- declarations and expl3 variants + +\bool_new:N \g__csvsim_check_column_count_bool +\bool_new:N \g__csvsim_firstline_bool +\bool_new:N \g__csvsim_head_bool +\bool_new:N \g__csvsim_head_to_colnames_bool +\bool_new:N \g__csvsim_line_accepted_bool +\bool_new:N \l__csvsim_respect_and_bool +\bool_new:N \l__csvsim_respect_backslash_bool +\bool_new:N \l__csvsim_respect_circumflex_bool +\bool_new:N \l__csvsim_respect_dollar_bool +\bool_new:N \l__csvsim_respect_leftbrace_bool +\bool_new:N \l__csvsim_respect_percent_bool +\bool_new:N \l__csvsim_respect_rightbrace_bool +\bool_new:N \l__csvsim_respect_sharp_bool +\bool_new:N \l__csvsim_respect_tab_bool +\bool_new:N \l__csvsim_respect_tilde_bool +\bool_new:N \l__csvsim_respect_underscore_bool + +\int_new:N \g__csvsim_col_int +\int_new:N \g__csvsim_colmax_int +\int_new:N \g_csvsim_inputline_int +\int_new:N \g_csvsim_row_int +\int_new:N \g_csvsim_columncount_int + +\seq_new:N \g__csvsim_colname_seq +\seq_new:N \g__csvsim_line_seq +\seq_new:N \g__csvsim_range_seq + +\str_new:N \g__csvsim_curfilename_str +\str_new:N \g__csvsim_filename_str +\str_new:N \l__csvsim_csvsorter_command_str +\str_new:N \l__csvsim_csvsorter_configpath_str +\str_new:N \l__csvsim_csvsorter_log_str +\str_new:N \l__csvsim_csvsorter_token_str +\str_new:N \l__csvsim_ppfilename_str +\str_new:N \l__csvsim_temp_filename_str + +\tl_const:Nn \c__csvsim_par_tl { \par } + +\tl_new:N \g__csvsim_after_table_tl +\tl_new:N \g__csvsim_before_table_tl +\tl_new:N \g__csvsim_body_tl +\tl_new:N \g__csvsim_catcode_tl + +\tl_new:N \g__csvsim_columnnames_tl +\tl_new:N \g__csvsim_filter_tl +\tl_new:N \g__csvsim_headname_prefix_tl +\tl_new:N \g__csvsim_hook_after_first_line_tl +\tl_new:N \g__csvsim_hook_after_head_tl +\tl_new:N \g__csvsim_hook_after_line_tl +\tl_new:N \g__csvsim_hook_after_reading_tl +\tl_new:N \g__csvsim_hook_before_filter_tl +\tl_new:N \g__csvsim_hook_before_first_line_tl +\tl_new:N \g__csvsim_hook_before_line_tl +\tl_new:N \g__csvsim_hook_before_reading_tl +\tl_new:N \g__csvsim_hook_columncounterror_tl +\tl_new:N \g__csvsim_hook_late_after_first_line_tl +\tl_new:N \g__csvsim_hook_late_after_head_tl +\tl_new:N \g__csvsim_hook_late_after_last_line_tl +\tl_new:N \g__csvsim_hook_late_after_line_tl +\tl_new:N \g__csvsim_hook_table_begin_tl +\tl_new:N \g__csvsim_hook_table_end_tl +\tl_new:N \g__csvsim_preprocessor_tl +\tl_new:N \g__csvsim_separator_tl +\tl_new:N \g__csvsim_table_foot_tl +\tl_new:N \g__csvsim_table_head_tl + +\group_begin: + \char_set_catcode_other:n { 9 } + \str_const:Nn \c__csvsim_tab_str { ^^I } +\group_end: + +\regex_const:Nn \c__csvsim_integer_regex {\A\d+\Z} + +\cs_generate_variant:Nn \seq_gset_split:Nnn { NVV } + + +%---- messages + +\msg_new:nnnn { csvsimple }{ column-name } + { Unknown~column~key~'#1'. } + { The~key~'#1'~you~used~in~'column~names'~is~unknown.\\ + Therefore,~the~macro~#2 is~not~defined. + } + +\msg_new:nnn { csvsimple }{ empty-head } + { File~'#1'~starts~with~an~empty~line~(empty~head)!.} + +\msg_new:nnn { csvsimple }{ file-error } + { File~'#1'~not~existent,~not~readable,~or~empty!} + +\msg_new:nnn { csvsimple }{ column-wrong-count } + { #1~instead~of~#2~columns~for~input~line~#3~of~file~'#4'} + +\msg_new:nnn { csvsimple }{ sort-info } + { Sort~'#1'~by~'#2' } + +\msg_new:nnn { csvsimple }{ sort-shell-escape } + { You~need~to~use~'-shell-escape'~to~run~CSV-Sorter } + +\msg_new:nnnn { csvsimple }{ sort-error } + { Call~of~CSV-Sorter~failed! } + { See~log~file~'\l__csvsim_csvsorter_log_str'. } + + + +%---- core loop processing + +\cs_new_protected_nopar:Npn \__csvsim_read_line: + { + \group_begin: + \g__csvsim_catcode_tl + \ior_get:NNTF \g__csvsim_ior \l_tmpa_tl + { + \tl_gset_eq:NN \csvline \l_tmpa_tl + \int_gincr:N \g_csvsim_inputline_int + } + { + \msg_error:nnx { csvsimple }{ file-error }{ \g__csvsim_curfilename_str } + } + \group_end: + } + + +\cs_new_protected_nopar:Npn \__csvsim_scan_line: + { + \int_gzero:N \g__csvsim_col_int + \seq_gset_split:NVV \g__csvsim_line_seq \g__csvsim_separator_tl \csvline + \seq_map_inline:Nn \g__csvsim_line_seq + { + \int_gincr:N \g__csvsim_col_int + \tl_gset:cn {csvcol \int_to_roman:n \g__csvsim_col_int}{##1} + } + \int_compare:nNnT \g__csvsim_colmax_int < \g__csvsim_col_int + { + \int_gset_eq:NN \g__csvsim_colmax_int \g__csvsim_col_int + } + \int_compare:nNnT \g_csvsim_columncount_int < \c_one_int + { + \int_gset_eq:NN \g_csvsim_columncount_int \g__csvsim_col_int + } + } + + +\cs_new_protected_nopar:Npn \__csvsim_process_head_name:n #1 + { + \tl_set:No \l_tmpa_tl {\cs:w csvcol\int_to_roman:n{#1} \cs_end:} + \exp_args:NnV \cs_set_nopar:cpn {__csvsim__/\l_tmpa_tl} \l_tmpa_tl + + \bool_if:NT \g__csvsim_head_to_colnames_bool + { + \tl_set:No \l_tmpb_tl {\cs:w \g__csvsim_headname_prefix_tl \l_tmpa_tl \cs_end:} + \tl_put_right:NV \l_tmpb_tl \l_tmpa_tl + \exp_args:NNV \seq_gput_right:Nn \g__csvsim_colname_seq \l_tmpb_tl + } + } + + +\cs_new_protected_nopar:Npn \__csvsim_read_head: + { + \__csvsim_read_line: + \tl_if_eq:NNTF \csvline \c__csvsim_par_tl + { + \msg_error:nnx { csvsimple }{ empty-head }{ \g__csvsim_filename_str } + } + { + \int_zero:N \g_csvsim_columncount_int + \__csvsim_scan_line: + \int_step_function:nN \g_csvsim_columncount_int \__csvsim_process_head_name:n + } + } + + +\cs_new_protected_nopar:Npn \__csvsim_process_colname:nn #1#2 + { + \cs_if_exist:cTF {__csvsim__/#1} + { + \tl_set:Nv \l_tmpa_tl {__csvsim__/#1} + \tl_put_left:Nn \l_tmpa_tl {#2} + \exp_args:NNV \seq_gput_right:Nn \g__csvsim_colname_seq \l_tmpa_tl + } + { + \regex_match:NnTF \c__csvsim_integer_regex {#1} + { + \tl_set:No \l_tmpa_tl {\cs:w csvcol\int_to_roman:n{#1} \cs_end:} + \tl_put_left:Nn \l_tmpa_tl {#2} + \exp_args:NNV \seq_gput_right:Nn \g__csvsim_colname_seq \l_tmpa_tl + } + { + \str_set:Nn \l_tmpb_str {#2} + \msg_error:nnxx { csvsimple }{ column-name }{ #1 }{ \l_tmpb_str } + } + } + } + + +\cs_new_protected_nopar:Npn \__csvsim_set_colnames: + { + \seq_map_inline:Nn \g__csvsim_colname_seq + { + \tl_gset_eq:NN ##1 + } + } + + +\cs_new_protected_nopar:Npn \__csvsim_loop: + { + % preprocess + \tl_if_empty:NTF \l__csvsim_preprocessor_tl + { + \str_gset_eq:NN \g__csvsim_curfilename_str \g__csvsim_filename_str + } + { + \l__csvsim_preprocessor_tl \g__csvsim_filename_str \l__csvsim_ppfilename_str + \str_gset_eq:NN \g__csvsim_curfilename_str \l__csvsim_ppfilename_str + } + + % initialize + \cs_if_exist:NF \g__csvsim_ior + { + \ior_new:N \g__csvsim_ior + } + \__csvsim_setup_catcode_list: + \seq_gclear:N \g__csvsim_colname_seq + \int_gzero:N \g_csvsim_inputline_int + \int_gzero:N \g_csvsim_row_int + \int_gset_eq:NN \g__csvsim_colmax_int \c_one_int + + % open file + \g__csvsim_hook_before_reading_tl + \g__csvsim_hook_table_begin_tl + \ior_open:Nn \g__csvsim_ior { \g__csvsim_curfilename_str } + + % read head line + \bool_if:NT \g__csvsim_head_bool + { + \__csvsim_read_head: + } + \exp_args:NNNV \keyval_parse:NNn \use_none:n + \__csvsim_process_colname:nn \g__csvsim_columnnames_tl + \bool_if:NT \g__csvsim_head_bool + { + \g__csvsim_hook_after_head_tl + } + + % read body lines + \bool_gset_true:N \g__csvsim_line_firstline_bool + \bool_until_do:nn {\ior_if_eof_p:N \g__csvsim_ior} + { + \__csvsim_read_line: + \tl_if_eq:NNF \csvline \c__csvsim_par_tl + { + \bool_gset_true:N \g__csvsim_line_accepted_bool + \__csvsim_scan_line: + \__csvsim_set_colnames: + \bool_if:NT \g__csvsim_check_column_count_bool + { + \int_compare:nNnF \g__csvsim_col_int = \g_csvsim_columncount_int + { + \bool_gset_false:N \g__csvsim_line_accepted_bool + \g__csvsim_hook_columncounterror_tl + } + } + \bool_if:NT \g__csvsim_line_accepted_bool + { + \g__csvsim_hook_before_filter_tl + \g__csvsim_filter_tl + \bool_if:NT \g__csvsim_line_accepted_bool + { + \int_gincr:N \g_csvsim_row_int + \__csvsim_check_range: + \bool_if:NT \g__csvsim_line_accepted_bool + { + \bool_if:NTF \g__csvsim_line_firstline_bool + { + \bool_if:NT \g__csvsim_head_bool + { + \g__csvsim_hook_late_after_head_tl + } + \g__csvsim_hook_before_first_line_tl + \g__csvsim_body_tl + \g__csvsim_hook_after_first_line_tl + \bool_gset_false:N \g__csvsim_line_firstline_bool + } + { + \g__csvsim_hook_late_after_line_tl + \g__csvsim_hook_before_line_tl + \g__csvsim_body_tl + \g__csvsim_hook_after_line_tl + } + } + } + } + } + } + + % close file + \ior_close:N \g__csvsim_ior + + % clear macros + \int_step_inline:nn \g__csvsim_colmax_int + { + \tl_set:No \l_tmpa_tl {\cs:w csvcol\int_to_roman:n{##1} \cs_end:} + \use:x + { + \exp_not:N\tl_gclear:N \exp_not:V\l_tmpa_tl + } + } + \__csvsim_set_colnames: + \seq_gclear:N \g__csvsim_colname_seq + \bool_if:NF \g__csvsim_line_firstline_bool + { + \g__csvsim_hook_late_after_last_line_tl + } + \g__csvsim_hook_table_end_tl + \g__csvsim_hook_after_reading_tl + } + + +\NewDocumentCommand \csvloop { +m } + { + \keys_set:nn { csvsim } { default, every~csv, #1} + \__csvsim_loop: + } + + +\NewDocumentCommand \csvreader { +O{} m m +m } + { + \keys_set:nn { csvsim } { default, every~csv, #1, file={#2}, column~names={#3} } + \tl_gset:Nn \g__csvsim_body_tl {#4} + \__csvsim_loop: + } + + + +%---- auxiliary user macros + +\NewDocumentCommand \csvlinetotablerow { } + { + \tl_clear:N \l_tmpa_tl + \bool_set_false:N \l_tmpa_bool + \seq_map_inline:Nn \g__csvsim_line_seq + { + \bool_if:NTF \l_tmpa_bool + { + \tl_put_right:Nn \l_tmpa_tl { & ##1 } + } + { + \tl_put_right:Nn \l_tmpa_tl { ##1 } + \bool_set_true:N \l_tmpa_bool + } + } + \l_tmpa_tl + } + + +\NewExpandableDocumentCommand \thecsvrow { } + { + \int_use:N \g_csvsim_row_int + } + + +\NewExpandableDocumentCommand \thecsvcolumncount { } + { + \int_use:N \g_csvsim_columncount_int + } + + +\NewExpandableDocumentCommand \thecsvinputline { } + { + \int_use:N \g_csvsim_inputline_int + } + + +\NewExpandableDocumentCommand \ifcsvfirstrow { } + { + \bool_if:NTF \g__csvsim_firstline_bool + } + +% deprecated +\NewExpandableDocumentCommand \csviffirstrow { } + { + \bool_if:NTF \g__csvsim_firstline_bool + } + + +\NewExpandableDocumentCommand \ifcsvoddrow { } + { + \int_if_odd:nTF {\g_csvsim_row_int} + } + +% deprecated +\NewExpandableDocumentCommand \csvifoddrow { } + { + \int_if_odd:nTF {\g_csvsim_row_int} + } + + +\NewExpandableDocumentCommand \ifcsvstrcmp { m m } + { + \str_compare:eNeTF {#1} = {#2} + } + + +\NewExpandableDocumentCommand \ifcsvnotstrcmp { m m +m +m } + { + \ifcsvstrcmp{#1}{#2}{#4}{#3} + } + + +\NewDocumentCommand \ifcsvstrequal { m m } + { + \tl_set:Nx \l_tmpa_tl {#1} + \tl_set:Nx \l_tmpb_tl {#2} + \tl_if_eq:NNTF \l_tmpa_tl \l_tmpb_tl + } + + +\NewDocumentCommand \ifcsvprostrequal { m m } + { + \protected@edef \l_tmpa_tl {#1} + \protected@edef \l_tmpb_tl {#2} + \tl_if_eq:NNTF \l_tmpa_tl \l_tmpb_tl + } + + +\NewExpandableDocumentCommand \ifcsvfpcmp { m } + { + \fp_compare:nTF {#1} + } + + +\NewExpandableDocumentCommand \ifcsvintcmp { m } + { + \int_compare:nTF {#1} + } + + +%---- filename functions + +\cs_new_protected_nopar:Npn \__csvsim_set_temp_filename:nnn #1#2#3 + { + \str_set:Nn \l__csvsim_temp_filename_str {#2#3} + \str_if_empty:NTF \l__csvsim_temp_filename_str + { + \str_set:Nn \l__csvsim_temp_filename_str {#1} + } + { + \str_set:Nn \l_tmpa_str {#1} + \str_if_empty:NF \l_tmpa_str + { + \str_compare:eNeF { \str_item:Nn \l_tmpa_str {-1} } = { / } + { + \str_put_right:Nn \l_tmpa_str {/} + } + \str_concat:NNN \l__csvsim_temp_filename_str + \l_tmpa_str \l__csvsim_temp_filename_str + } + } + } + + +\cs_new_protected_nopar:Npn \__csvsim_set_temp_filename:n #1 + { + \file_parse_full_name_apply:nN { #1 } \__csvsim_set_temp_filename:nnn + } + + +\cs_new_protected_nopar:Npn \__csvsim_set_filename:Nn #1#2 + { + \__csvsim_set_temp_filename:n { #2 } + \str_set_eq:NN #1 \l__csvsim_temp_filename_str + } + + +\cs_new_protected_nopar:Npn \__csvsim_gset_filename:Nn #1#2 + { + \__csvsim_set_temp_filename:n { #2 } + \str_gset_eq:NN #1 \l__csvsim_temp_filename_str + } + + + +%---- keys + +\NewDocumentCommand \csvset { +m } + { + \keys_set:nn { csvsim } { #1 } + } + + +\NewDocumentCommand \csvstyle { m +m } + { + \keys_define:nn { csvsim } + { + #1 .meta:n = { #2 } + } + } + + +\NewDocumentCommand \csvnames { m m } + { + \keys_define:nn { csvsim } + { + #1 .meta:n = { column~names={#2} } + } + } + + +\keys_define:nn { csvsim } + { + file .code:n = \__csvsim_gset_filename:Nn \g__csvsim_filename_str {#1}, + column~names~reset .code:n = \tl_gclear:N \g__csvsim_columnnames_tl, + column~names .code:n = + { + \tl_if_empty:NTF \g__csvsim_columnnames_tl + { + \tl_gset:Nn \g__csvsim_columnnames_tl {#1} + } + { + \tl_gput_right:Nn \g__csvsim_columnnames_tl {,#1} + } + }, + command .tl_gset:N = \g__csvsim_body_tl, + check~column~count .bool_gset:N = \g__csvsim_check_column_count_bool, + on~column~count~error .tl_gset:N = \g__csvsim_hook_columncounterror_tl, + head .bool_gset:N = \g__csvsim_head_bool, + head~to~column~names~prefix .tl_gset:N = \g__csvsim_headname_prefix_tl, + head~to~column~names .bool_gset:N = \g__csvsim_head_to_colnames_bool, + column~count .int_gset:N = \g_csvsim_columncount_int, + separator .choice:, + separator/comma .code:n = + { + \tl_gset:Nn \g__csvsim_separator_tl {,} + }, + separator/semicolon .code:n = + { + \tl_gset:Nn \g__csvsim_separator_tl {;} + }, + separator/pipe .code:n = + { + \tl_gset:Nn \g__csvsim_separator_tl {|} + }, + separator/tab .code:n = + { + \tl_gset:NV \g__csvsim_separator_tl \c__csvsim_tab_str + \csvset{respect~tab} + }, + every~csv .meta:n = {}, + no~head .meta:n = { head=false }, + no~check~column~count .meta:n = { check~column~count=false }, + warn~on~column~count~error .meta:n = { on~column~count~error= + { + \msg_warning:nnxxxx { csvsimple }{ column-wrong-count } + { \int_use:N\g__csvsim_col_int } + { \int_use:N\g_csvsim_columncount_int } + { \int_use:N\g_csvsim_inputline_int } + { \g__csvsim_filename_str } + }}, + } + + +%---- hooks + +\keys_define:nn { csvsim } + { + before~reading .tl_gset:N = \g__csvsim_hook_before_reading_tl, + after~head .tl_gset:N = \g__csvsim_hook_after_head_tl, + before~filter .tl_gset:N = \g__csvsim_hook_before_filter_tl, + late~after~head .tl_gset:N = \g__csvsim_hook_late_after_head_tl, + late~after~first~line .tl_gset:N = \g__csvsim_hook_late_after_first_line_tl, + late~after~last~line .tl_gset:N = \g__csvsim_hook_late_after_last_line_tl, + before~first~line .tl_gset:N = \g__csvsim_hook_before_first_line_tl, + after~first~line .tl_gset:N = \g__csvsim_hook_after_first_line_tl, + after~reading .tl_gset:N = \g__csvsim_hook_after_reading_tl, + late~after~line .code:n = + { + \tl_gset:Nn \g__csvsim_hook_late_after_line_tl {#1} + \tl_gset_eq:NN \g__csvsim_hook_late_after_first_line_tl \g__csvsim_hook_late_after_line_tl + \tl_gset_eq:NN \g__csvsim_hook_late_after_last_line_tl \g__csvsim_hook_late_after_line_tl + }, + before~line .code:n = + { + \tl_gset:Nn \g__csvsim_hook_before_line_tl {#1} + \tl_gset_eq:NN \g__csvsim_hook_before_first_line_tl \g__csvsim_hook_before_line_tl + }, + after~line .code:n = + { + \tl_gset:Nn \g__csvsim_hook_after_line_tl {#1} + \tl_gset_eq:NN \g__csvsim_hook_after_first_line_tl \g__csvsim_hook_after_line_tl + }, + } + + +%---- filter + +\cs_new_protected_nopar:Npn \__csvsim_set_filter:n #1 + { + \tl_gset:Nn \g__csvsim_filter_tl + { + #1 + } + } + + +\NewDocumentCommand \csvfilteraccept { } + { + \__csvsim_set_filter:n + { + \bool_gset_true:N \g__csvsim_line_accepted_bool + } + } + + +\NewDocumentCommand \csvfilterreject { } + { + \__csvsim_set_filter:n + { + \bool_gset_false:N \g__csvsim_line_accepted_bool + } + } + + +\keys_define:nn { csvsim } + { + no~filter .code:n = + { + \csvfilteraccept + }, + filter~reject~all .code:n = + { + \csvfilterreject + }, + filter~accept~all .code:n = + { + \csvfilteraccept + }, + full~filter. tl_gset:N = \g__csvsim_hook_before_filter_tl, + filter~test .code:n = + { + \__csvsim_set_filter:n + { + #1 + { \bool_gset_true:N \g__csvsim_line_accepted_bool } + { \bool_gset_false:N \g__csvsim_line_accepted_bool } + } + }, + filter~bool .code:n = + { + \__csvsim_set_filter:n + { + \bool_gset:Nn \g__csvsim_line_accepted_bool { #1 } + } + }, + filter~fp .code:n = + { + \__csvsim_set_filter:n + { + \bool_gset:Nn \g__csvsim_line_accepted_bool { \fp_compare_p:n{#1} } + } + }, + filter~strcmp .meta:n = { filter~test=\ifcsvstrcmp #1 }, + filter~not~strcmp .meta:n = { filter~test=\ifcsvnotstrcmp #1 }, + } + + +\NewDocumentCommand \csvfilterbool { m m } + { + \keys_define:nn { csvsim } + { + #1 .meta:n = { filter~bool={#2} } + } + } + + +% ifthen +\keys_define:nn { csvsim } + { + filter~ifthen .code:n = + { + \__csvsim_set_filter:n + { + \ifthenelse{#1} + { \bool_gset_true:N \g__csvsim_line_accepted_bool } + { \bool_gset_false:N \g__csvsim_line_accepted_bool } + } + }, + filter~equal .meta:n = { filter~ifthen=\equal #1 }, + filter~not~equal .meta:n = { filter~ifthen=\not\equal #1 }, + } + + +% etoolbox +\keys_define:nn { csvsim } + { + filter~expr .code:n = + { + \__csvsim_set_filter:n + { + \ifboolexpr{#1} + { \bool_gset_true:N \g__csvsim_line_accepted_bool } + { \bool_gset_false:N \g__csvsim_line_accepted_bool } + } + }, + } + + + +%---- range + + +\cs_new_protected_nopar:Npn \__csvsim_add_range:n #1 + { + \tl_if_in:nnTF {#1}{-} + { + \seq_set_split:Nnn \l_tmpa_seq {-} {#1} + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_tl + \tl_if_empty:NTF \l_tmpa_tl + { + \int_set_eq:NN \l_tmpa_int \c_one_int + } + { + \int_set:Nn \l_tmpa_int { \l_tmpa_tl } + } + \tl_if_empty:NTF \l_tmpb_tl + { + \int_set_eq:NN \l_tmpb_int \c_max_int + } + { + \int_set:Nn \l_tmpb_int { \l_tmpb_tl } + } + } + { + \tl_if_in:nnTF {#1}{+} + { + \seq_set_split:Nnn \l_tmpa_seq {+} {#1} + \seq_pop_left:NN \l_tmpa_seq \l_tmpa_tl + \seq_pop_left:NN \l_tmpa_seq \l_tmpb_tl + \tl_if_empty:NTF \l_tmpa_tl + { + \int_set:Nn \l_tmpa_int { 1 } + } + { + \int_set:Nn \l_tmpa_int { \l_tmpa_tl } + } + \tl_if_empty:NTF \l_tmpb_tl + { + \int_set_eq:NN \l_tmpb_int \l_tmpa_int + } + { + \int_set:Nn \l_tmpb_int { \l_tmpa_int + \l_tmpb_tl - 1 } + } + } + { + \int_set:Nn \l_tmpa_int {#1} + \int_set_eq:NN \l_tmpb_int \l_tmpa_int + } + } + \seq_gput_right:Nx \g__csvsim_range_seq {{\int_use:N \l_tmpa_int}{\int_use:N \l_tmpb_int}} + } + + +\cs_new_protected_nopar:Npn \__csvsim_set_range:n #1 + { + \seq_gclear:N \g__csvsim_range_seq + \keyval_parse:NNn + \__csvsim_add_range:n + \use_none:nn + { #1 } + } + + +\keys_define:nn { csvsim } + { + range .code:n = + { + \__csvsim_set_range:n {#1} + }, + } + + +\prg_new_conditional:Npnn \__csvsim_if_in_range:nn #1#2 { p , T } + { + \if_int_compare:w #1 > \g_csvsim_row_int + \prg_return_false: + \else: + \if_int_compare:w #2 < \g_csvsim_row_int + \prg_return_false: + \else: + \prg_return_true: + \fi: + \fi: + } + + +\cs_new_protected_nopar:Npn \__csvsim_check_range: + { + \seq_if_empty:NF \g__csvsim_range_seq + { + \bool_gset_false:N \g__csvsim_line_accepted_bool + \seq_map_inline:Nn \g__csvsim_range_seq + { + \__csvsim_if_in_range:nnT ##1 + { + \bool_gset_true:N \g__csvsim_line_accepted_bool + \seq_map_break: + } + } + } + } + + + +%---- catcodes + +\cs_new_protected_nopar:Npn \__csvsim_setup_catcode_list: + { + \tl_gclear:N \g__csvsim_catcode_tl + \bool_if:NT \l__csvsim_respect_tab_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 9 } } + } + \bool_if:NT \l__csvsim_respect_percent_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 37 } } + } + \bool_if:NT \l__csvsim_respect_sharp_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 35 } } + } + \bool_if:NT \l__csvsim_respect_dollar_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 36 } } + } + \bool_if:NT \l__csvsim_respect_and_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 38 } } + } + \bool_if:NT \l__csvsim_respect_backslash_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 92 } } + } + \bool_if:NT \l__csvsim_respect_underscore_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 95 } } + } + \bool_if:NT \l__csvsim_respect_tilde_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 126 } } + } + \bool_if:NT \l__csvsim_respect_circumflex_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 94 } } + } + \bool_if:NT \l__csvsim_respect_leftbrace_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 123 } } + } + \bool_if:NT \l__csvsim_respect_rightbrace_bool + { + \tl_gput_right:Nn \g__csvsim_catcode_tl { \char_set_catcode_other:n { 125 } } + } + } + + +\keys_define:nn { csvsim } + { + respect~tab .bool_set:N = \l__csvsim_respect_tab_bool, + respect~percent .bool_set:N = \l__csvsim_respect_percent_bool, + respect~sharp .bool_set:N = \l__csvsim_respect_sharp_bool, + respect~dollar .bool_set:N = \l__csvsim_respect_dollar_bool, + respect~and .bool_set:N = \l__csvsim_respect_and_bool, + respect~backslash .bool_set:N = \l__csvsim_respect_backslash_bool, + respect~underscore .bool_set:N = \l__csvsim_respect_underscore_bool, + respect~tilde .bool_set:N = \l__csvsim_respect_tilde_bool, + respect~circumflex .bool_set:N = \l__csvsim_respect_circumflex_bool, + respect~leftbrace .bool_set:N = \l__csvsim_respect_leftbrace_bool, + respect~rightbrace .bool_set:N = \l__csvsim_respect_rightbrace_bool, + respect~all .meta:n = + { + respect~tab, respect~percent, respect~sharp, respect~dollar, + respect~and, respect~backslash, respect~underscore, respect~tilde, + respect~circumflex, respect~leftbrace, respect~rightbrace + }, + respect~none .meta:n = + { + respect~tab=false, respect~percent=false, respect~sharp=false, + respect~dollar=false, respect~and=false, respect~backslash=false, + respect~underscore=false, respect~tilde=false, respect~circumflex=false, + respect~leftbrace=false, respect~rightbrace=false + }, + } + + + +%---- tables + +\cs_new_protected_nopar:Npn \__csvsim_key_table:nn #1#2 + { + \tl_gset:Nn \g__csvsim_hook_table_begin_tl {#1} + \tl_gset:Nn \g__csvsim_hook_table_end_tl {#2} + } + + +\keys_define:nn { csvsim } + { + before~table .tl_gset:N = \g__csvsim_before_table_tl, + after~table .tl_gset:N = \g__csvsim_after_table_tl, + table~head .tl_gset:N = \g__csvsim_table_head_tl, + table~foot .tl_gset:N = \g__csvsim_table_foot_tl, + _table_ .code:n = \__csvsim_key_table:nn #1, + no~table .meta:n = { _table_={}{} }, + tabular .meta:n = + { + _table_ = { \g__csvsim_before_table_tl\begin{tabular}{#1}\g__csvsim_table_head_tl } + { \g__csvsim_table_foot_tl\end{tabular}\g__csvsim_after_table_tl }, + late~after~line = \\ + }, + centered~tabular .meta:n = + { + _table_ = { \begin{center}\g__csvsim_before_table_tl\begin{tabular}{#1}\g__csvsim_table_head_tl } + { \g__csvsim_table_foot_tl\end{tabular}\g__csvsim_after_table_tl\end{center} }, + late~after~line = \\ + }, + longtable .meta:n = + { + _table_ = { \g__csvsim_before_table_tl\begin{longtable}{#1}\g__csvsim_table_head_tl } + { \g__csvsim_table_foot_tl\end{longtable}\g__csvsim_after_table_tl }, + late~after~line = \\ + }, + tabbing .meta:n = + { + _table_ = { \g__csvsim_before_table_tl\begin{tabbing}\g__csvsim_table_head_tl } + { \g__csvsim_table_foot_tl\end{tabbing}\g__csvsim_after_table_tl }, + late~after~line = \\, + late~after~last~line = + }, + centered~tabbing .meta:n = + { + _table_ = { \begin{center}\g__csvsim_before_table_tl\begin{tabbing}\g__csvsim_table_head_tl } + { \g__csvsim_table_foot_tl\end{tabbing}\g__csvsim_after_table_tl\end{center} }, + late~after~line = \\, + late~after~last~line = + }, + _autotab_ .meta:n = + { + file = #1, + late~after~line = \\, + command = \csvlinetotablerow + }, + _autotabular_ .meta:n = + { + _autotab_ = #1, + late~after~last~line = \g__csvsim_table_foot_tl + \end{tabular} + \g__csvsim_after_table_tl, + }, + autotabular .meta:n = + { + _autotabular_ = #1, + head, + after~head = \g__csvsim_before_table_tl + \begin{tabular}{|*{\int_use:N\g__csvsim_col_int}{l|}} + \g__csvsim_table_head_tl, + table~head = \hline\csvlinetotablerow\\\hline, + table~foot = \\\hline, + }, + autotabular* .meta:n = + { + _autotabular_ = #1, + no~head, + before~first~line = \g__csvsim_before_table_tl + \begin{tabular}{|*{\int_use:N\g__csvsim_col_int}{l|}} + \g__csvsim_table_head_tl, + table~head = \hline, + table~foot = \\\hline, + }, + autobooktabular .meta:n = + { + _autotabular_ = #1, + head, + after~head = \g__csvsim_before_table_tl + \begin{tabular}{*{\int_use:N\g__csvsim_col_int}{l}} + \g__csvsim_table_head_tl, + table~head = \toprule\csvlinetotablerow\\\midrule, + table~foot = \\\bottomrule, + }, + autobooktabular* .meta:n = + { + _autotabular_ = #1, + no~head, + before~first~line = \g__csvsim_before_table_tl + \begin{tabular}{*{\int_use:N\g__csvsim_col_int}{l}} + \g__csvsim_table_head_tl, + table~head = \toprule, + table~foot = \\\bottomrule, + }, + _autolongtable_ .meta:n = + { + _autotab_ = #1, + late~after~last~line = \end{longtable} + \g__csvsim_after_table_tl, + }, + autolongtable .meta:n = + { + _autolongtable_ = #1, + head, + after~head = \g__csvsim_before_table_tl + \begin{longtable}{|*{\int_use:N\g__csvsim_col_int}{l|}} + \g__csvsim_table_head_tl, + table~head = \hline\csvlinetotablerow\\\hline\endhead + \hline\endfoot, + }, + autolongtable* .meta:n = + { + _autolongtable_ = #1, + no~head, + before~first~line = \g__csvsim_before_table_tl + \begin{longtable}{|*{\int_use:N\g__csvsim_col_int}{l|}} + \g__csvsim_table_head_tl, + table~head = \hline\endhead + \hline\endfoot, + }, + autobooklongtable .meta:n = + { + _autolongtable_ = #1, + head, + after~head = \g__csvsim_before_table_tl + \begin{longtable}{*{\int_use:N\g__csvsim_col_int}{l}} + \g__csvsim_table_head_tl, + table~head = \toprule\csvlinetotablerow\\\midrule\endhead + \bottomrule\endfoot, + }, + autobooklongtable* .meta:n = + { + _autolongtable_ = #1, + no~head, + before~first~line = \g__csvsim_before_table_tl + \begin{longtable}{*{\int_use:N\g__csvsim_col_int}{l}} + \g__csvsim_table_head_tl, + table~head = \toprule\endhead + \bottomrule\endfoot, + }, + } + + +\NewDocumentCommand \csvautotabular { s +O{} m } + { + \IfBooleanTF {#1} + { + \keys_set:nn { csvsim } { default, every~csv, autotabular*={#3}, #2} + } + { + \keys_set:nn { csvsim } { default, every~csv, autotabular={#3}, #2} + } + \__csvsim_loop: + } + + +\NewDocumentCommand \csvautolongtable { s +O{} m } + { + \IfBooleanTF {#1} + { + \keys_set:nn { csvsim } { default, every~csv, autolongtable*={#3}, #2} + } + { + \keys_set:nn { csvsim } { default, every~csv, autolongtable={#3}, #2} + } + \__csvsim_loop: + } + + +\NewDocumentCommand \csvautobooktabular { s +O{} m } + { + \IfBooleanTF {#1} + { + \keys_set:nn { csvsim } { default, every~csv, autobooktabular*={#3}, #2} + } + { + \keys_set:nn { csvsim } { default, every~csv, autobooktabular={#3}, #2} + } + \__csvsim_loop: + } + + +\NewDocumentCommand \csvautobooklongtable { s +O{} m } + { + \IfBooleanTF {#1} + { + \keys_set:nn { csvsim } { default, every~csv, autobooklongtable*={#3}, #2} + } + { + \keys_set:nn { csvsim } { default, every~csv, autobooklongtable={#3}, #2} + } + \__csvsim_loop: + } + + + +%---- sorting + +\cs_new_protected_nopar:Npn \__csvsim_key_new_sorting_rule:nn #1#2 + { + \keys_define:nn { csvsim } + { + sort~by~#1 .meta:n = { sort~by={#2} }, + } + } + + +\NewDocumentCommand \csvsortingrule { } + { + \__csvsim_key_new_sorting_rule:nn + } + + +\keys_define:nn { csvsim } + { + preprocessor .tl_gset:N = \l__csvsim_preprocessor_tl, + preprocessed~file .code:n = \__csvsim_set_filename:Nn \l__csvsim_ppfilename_str {#1}, + csvsorter~command .code:n = \__csvsim_set_filename:Nn \l__csvsim_csvsorter_command_str {#1}, + csvsorter~configpath .code:n = \__csvsim_set_filename:Nn\l__csvsim_csvsorter_configpath_str {#1}, + csvsorter~log .code:n = \__csvsim_set_filename:Nn \l__csvsim_csvsorter_log_str {#1}, + csvsorter~token .code:n = \__csvsim_set_filename:Nn \l__csvsim_csvsorter_token_str {#1}, + no~preprocessing .meta:n = { preprocessor= }, + sort~by .meta:n = + { + preprocessor= + { + \__csvsim_processor_csvsorter:nnn {#1} + } + }, + new~sorting~rule .code:n = \__csvsim_key_new_sorting_rule:nn #1, + new~sorting~rule .value_required:n = true , +} + + +\keys_set:nn { csvsim } + { + preprocessed~file = \c_sys_jobname_str _sorted._csv, + csvsorter~command = csvsorter, + csvsorter~configpath = ., + csvsorter~log = csvsorter.log, + csvsorter~token = \c_sys_jobname_str.csvtoken, + } + + +\cs_new_protected_nopar:Npn \__csvsim_processor_csvsorter:nnn #1#2#3 + { + \sys_if_shell_unrestricted:TF + { + \__csvsim_set_temp_filename:n { #1 } + \msg_note:nnxx { csvsimple }{ sort-info }{ #2 }{ \l__csvsim_temp_filename_str } + \cs_if_exist:NF \g__csvsim_iow + { + \iow_new:N \g__csvsim_iow + } + \iow_open:Nn \g__csvsim_iow { \l__csvsim_csvsorter_token_str } + \iow_now:Nn \g__csvsim_iow { \ExplSyntaxOn \msg_error:nn { csvsimple }{ sort-error } \ExplSyntaxOff } + \iow_close:N \g__csvsim_iow + \sys_shell_now:x + { + "\l__csvsim_csvsorter_command_str" \c_space_tl + -c~ "\l__csvsim_csvsorter_configpath_str/\l__csvsim_temp_filename_str" \c_space_tl + -l~ "\l__csvsim_csvsorter_log_str" \c_space_tl + -t~ "\l__csvsim_csvsorter_token_str" \c_space_tl + -i~ "#2" \c_space_tl + -o~ "#3" \c_space_tl + -q~1 + } + \file_input:n { \l__csvsim_csvsorter_token_str } + } + { + \msg_error:nn { csvsimple }{ sort-shell-escape } + } + } + + + +%---- default + +\keys_define:nn { csvsim } + { + % default for reset + default .meta:n = + { + file = unknown.csv, + no~preprocessing, + command = \csvline, + column~names~reset, + head, + check~column~count, + head~to~column~names~prefix = , + head~to~column~names = false, + column~count = 0, + on~column~count~error =, + no~filter, + before~filter =, + before~line =, + after~line =, + late~after~line =, + after~head =, + late~after~head =, + before~reading =, + after~reading =, + before~table =, + after~table =, + table~head =, + table~foot =, + no~table, + separator = comma, + respect~none, + }, + } + +\keys_set:nn { csvsim } + { + default + } diff --git a/Master/texmf-dist/tex/latex/csvsimple/csvsimple-legacy.sty b/Master/texmf-dist/tex/latex/csvsimple/csvsimple-legacy.sty new file mode 100644 index 00000000000..53a30ab9e36 --- /dev/null +++ b/Master/texmf-dist/tex/latex/csvsimple/csvsimple-legacy.sty @@ -0,0 +1,795 @@ +%% The LaTeX package csvsimple - version 2.0.0 (2021/06/29) +%% csvsimple-legacy.sty: Simple LaTeX CSV file processing (LaTeX2e) +%% +%% ------------------------------------------------------------------------------------------- +%% Copyright (c) 2008-2021 by Prof. Dr. Dr. Thomas F. Sturm <thomas dot sturm at unibw dot de> +%% ------------------------------------------------------------------------------------------- +%% +%% 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'. +%% +%% This work consists of all files listed in README.md +%% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{csvsimple-legacy}[2021/06/29 version 2.0.0 LaTeX2e CSV file processing] + + +%---- check package +\ExplSyntaxOn +\cs_if_exist:NT \c__csvsim_package_expl_bool + { + \msg_new:nnn { csvsimple }{ legacy / package-loaded } + { Package~'csvsimple-l3'~seems~already~be~loaded!~ + 'csvsimple-legacy'~cannot~be~loaded~simultaneously.~ + Therefore,~loading~of~'csvsimple-legacy'~stops~now.} + \msg_warning:nn { csvsimple }{ legacy / package-loaded } + \tex_endinput:D + } +\bool_const:Nn \c__csvsim_package_expl_bool { 0 } +\ExplSyntaxOff + + + +\RequirePackage{pgfrcs,pgfkeys,ifthen,etoolbox,shellesc} + + +%---- general + +\def\csv@warning#1{\PackageWarning{csvsimple}{#1}} +\def\csv@error#1#2{\PackageError{csvsimple}{#1}{#2}} + +\newread\csv@file +\newcounter{csvinputline} +\newcounter{csvrow} +\newcounter{csvcol} + +\def\csv@empty{} + +\long\def\csviffirstrow#1#2{% + \ifnum\c@csvrow=1% + \long\def\csviffirstrow@doit{#1}% + \else% + \long\def\csviffirstrow@doit{#2}% + \fi% + \csviffirstrow@doit% +} + +\long\def\csvifoddrow#1#2{% + \ifodd\c@csvrow% + \long\def\csvifoddrow@doit{#1}% + \else% + \long\def\csvifoddrow@doit{#2}% + \fi% + \csvifoddrow@doit% +} + +\def\csv@assemble@csvlinetotablerow{% + \global\c@csvcol 1\relax% + \xdef\csvlinetotablerow{\expandonce{\csname csvcol\romannumeral\c@csvcol\endcsname}}% + \ifnum\c@csvcol<\csv@columncount\relax% + \loop% + \global\advance\c@csvcol 1\relax% + \xappto\csvlinetotablerow{\noexpand&\expandonce{\csname csvcol\romannumeral\c@csvcol\endcsname}}% + \ifnum\c@csvcol<\csv@columncount\relax\repeat% + \fi% + \csvlinetotablerow% +} + + +%---- breaking lines + +% This command removes leading and trailing spaces from <Token>. I found +% the original code on the web. The original author was Michael Downes, who +% provided the code as an answer to 'around the bend' question #15. +\catcode`\Q=3 +\def\csv@TrimSpaces#1{% + \begingroup% + \aftergroup\toks\aftergroup0\aftergroup{% + \expandafter\csv@trimb\expandafter\noexpand#1Q Q}% + \global\edef#1{\the\toks0}% +} +\def\csv@trimb#1 Q{\csv@trimc#1Q} +\def\csv@trimc#1Q#2{\afterassignment\endgroup \vfuzz\the\vfuzz#1} +\catcode`\Q=11 + +\def\csv@TrimBraces#1{\expandafter\csv@TrimBraces@#1\@nil{#1}} +\def\csv@TrimBraces@#1\@nil#2{\def#2{#1}} + +\def\csv@breakline@kernel#1{% + \ifx\csv@termination#1\let\nextcol=\relax\else% + \let\nextcol=\csv@breakline% + \global\advance\c@csvcol 1\relax% + \def\csv@col@body{#1}% + \csv@TrimSpaces\csv@col@body% + \csv@TrimBraces\csv@col@body% + \toks@\expandafter{\csv@col@body}% + \expandafter\xdef\csname csvcol\romannumeral\c@csvcol\endcsname{\the\toks@}% + \fi% + \nextcol% +} + +% comma +\def\csv@breakline@A#1,{\csv@breakline@kernel{#1}} + +\def\csv@scanline@A#1{% + \global\c@csvcol 0\relax% + \csv@breakline#1,\csv@termination,% +} + +% semi colon +\def\csv@breakline@B#1;{\csv@breakline@kernel{#1}} + +\def\csv@scanline@B#1{% + \global\c@csvcol 0\relax% + \csv@breakline#1;\csv@termination;% +} + +% pipe +\def\csv@breakline@C#1|{\csv@breakline@kernel{#1}} + +\def\csv@scanline@C#1{% + \global\c@csvcol 0\relax% + \csv@breakline#1|\csv@termination|% +} + +% tab +\catcode`\^^I=12 +\def\csv@breakline@D#1^^I{\csv@breakline@kernel{#1}} + +\def\csv@scanline@D#1{% + \global\c@csvcol 0\relax% + \csv@breakline#1^^I\csv@termination^^I% +} +\catcode`\^^I=10 + +% expands a CSV line and scans content +\def\csv@escanline#1{% + \toks@\expandafter{#1}% + \edef\@csv@scanline{\noexpand\csv@scanline{\the\toks@}}% + \@csv@scanline% +} + +{ + \catcode`\"=12% + \gdef\csv@passivquotes{"} +} + +\newwrite\csv@out + +\def\csv@preprocessor@csvsorter#1#2#3{% + \begingroup% + \typeout{<sort \csv@passivquotes#2\csv@passivquotes\space by \csv@passivquotes#1\csv@passivquotes>}% + \immediate\openout\csv@out=\csv@csvsorter@token% + \immediate\write\csv@out{\string\makeatletter\string\csv@error{Call of CSV-Sorter failed! Use '-shell-escape' option or check log file '\csv@csvsorter@log'.}{}}% + \immediate\closeout\csv@out% + \ShellEscape{\csv@csvsorter@command\space + -c \csv@passivquotes#1\csv@passivquotes\space + -l \csv@passivquotes\csv@csvsorter@log\csv@passivquotes\space + -t \csv@passivquotes\csv@csvsorter@token\csv@passivquotes\space + -i \csv@passivquotes#2\csv@passivquotes\space + -o \csv@passivquotes#3\csv@passivquotes\space -q 1}% + \input{\csv@csvsorter@token}% + \endgroup% +} + + +\def\csv@preprocss@none{% + \let\csv@input@filename=\csv@filename% +} + +\def\csv@preprocss@procedure{% + \csv@preprocessor{\csv@filename}{\csv@ppfilename}% + \let\csv@input@filename=\csv@ppfilename% +} + + +%---- the loop + +\def\csv@AtEndLoop{\gappto\@endloophook} +\let\@endloophook\csv@empty + +\def\csv@current@col{\csname csvcol\romannumeral\c@csvcol\endcsname} + +% auto head names +\def\set@csv@autohead{% + \toks0=\expandafter{\csname\csv@headnameprefix\csv@current@col\endcsname}% + \toks1=\expandafter{\csname csvcol\romannumeral\c@csvcol\endcsname}% + \begingroup\edef\csv@temp{\endgroup\noexpand\gdef\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\noexpand\gdef\the\toks0{}}}% + \csv@temp% +} + +% head names and numbers +\def\set@csv@head{% + \toks0={\gdef##1}% + \toks1=\expandafter{\csname csvcol\romannumeral\c@csvcol\endcsname}% + \begingroup\edef\csv@temp{\endgroup\noexpand\pgfkeysdef{/csv head/\csv@current@col}{\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\the\toks0{}}}}% + \csv@temp% + \begingroup\edef\csv@temp{\endgroup\noexpand\pgfkeysdef{/csv head/\thecsvcol}{\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\the\toks0{}}}}% + \csv@temp% +} + +% head line +\def\csv@processheadline{% + \csvreadnext% + \ifx\csv@par\csvline\relax% + \csv@error{File '\csv@input@filename' starts with an empty line!}{}% + \else\csv@escanline{\csvline}% + \fi% + \xdef\csv@columncount{\thecsvcol}% + \global\c@csvcol 0\relax% + \loop% + \global\advance\c@csvcol 1\relax% + \csv@opt@headtocolumnames% + \set@csv@head% + \ifnum\c@csvcol<\csv@columncount\repeat% + \toks@=\expandafter{\csv@columnnames}% + \edef\csv@processkeys{\noexpand\pgfkeys{/csv head/.cd,\the\toks@}}% + \csv@processkeys% + \csv@posthead% +} + +% head numbers for no head +\def\set@csv@nohead{% + \toks0={\gdef##1}% + \toks1=\expandafter{\csname csvcol\romannumeral\c@csvcol\endcsname}% + \begingroup\edef\csv@temp{\endgroup\noexpand\pgfkeysdef{/csv head/\thecsvcol}{\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\the\toks0{}}}}% + \csv@temp% +} + +% no head line +\def\csv@noheadline{% + \global\c@csvcol 0\relax% + \loop% + \global\advance\c@csvcol 1\relax% + \set@csv@nohead% + \ifnum\c@csvcol<\csv@columncount\repeat% + \toks@=\expandafter{\csv@columnnames}% + \edef\csv@processkeys{\noexpand\pgfkeys{/csv head/.cd,\the\toks@}}% + \csv@processkeys% +} + +% check filter +\def\csv@checkfilter{% + \csv@prefiltercommand% + \csv@iffilter{% + \stepcounter{csvrow}% + \let\csv@usage=\csv@do@linecommand% + }{}% +} + +\def\csv@truefilter#1#2{#1} + +\def\csv@falsefilter#1#2{#2} + +\def\csvfilteraccept{\global\let\csv@iffilter=\csv@truefilter} + +\def\csvfilterreject{\global\let\csv@iffilter=\csv@falsefilter} + +% check columns +\def\csv@checkcolumncount{% + \ifnum\c@csvcol=\csv@columncount\relax% + \csv@checkfilter% + \else% + \csv@columncounterror% + \fi% +} + +\def\csv@nocheckcolumncount{% + \csv@checkfilter% +} + +% normal line +\def\csv@do@linecommand{% + \csv@do@latepostline% + \csv@do@preline% + \csv@body\relax% + \csv@do@postline% +} + +\gdef\csvreadnext{% + \global\read\csv@file to\csvline% + \stepcounter{csvinputline}% +} + +\def\csv@par{\par} + +% reads and processes a CSV file +\long\def\csvloop#1{% + % reset + \global\let\@endloophook\csv@empty% + \global\let\csvlinetotablerow\csv@assemble@csvlinetotablerow% + % options + \csvset{default,every csv,#1}% + \csv@preprocss% + \csv@set@catcodes% + \csv@prereading% + \csv@table@begin% + \setcounter{csvinputline}{0}% + % start reading + \openin\csv@file=\csv@input@filename\relax% + \ifeof\csv@file% + \csv@error{File '\csv@input@filename' not existent, not readable, or empty!}{}% + \else% + % the head line + \csv@opt@processheadline% + \fi% + % + \setcounter{csvrow}{0}% + \gdef\csv@do@preline{% + \csv@prefirstline% + \global\let\csv@do@preline=\csv@preline% + }% + \gdef\csv@do@postline{% + \csv@postfirstline% + \global\let\csv@do@postline=\csv@postline% + }% + \gdef\csv@do@@latepostline{% + \csv@latepostfirstline% + \global\let\csv@do@latepostline=\csv@latepostline% + }% + \gdef\csv@do@latepostline{% + \csv@lateposthead% + \global\let\csv@do@latepostline=\csv@do@@latepostline% + }% + % command for the reading loop + \gdef\csv@iterate{% + \let\csv@usage=\csv@empty% + \csvreadnext% + \ifeof\csv@file% + \global\let\csv@next=\csv@empty% + \else% + \global\let\csv@next=\csv@iterate% + \ifx\csv@par\csvline\relax% + \else% + \csv@escanline{\csvline}% + % check and decide + \csv@opt@checkcolumncount% + \fi% + \fi% + % do or do not + \csv@usage% + \csv@next}% + \ifeof\csv@file% + \global\let\csv@next=\csv@empty% + \else% + \global\let\csv@next=\csv@iterate% + \fi% + \csv@next% + \closein\csv@file% + \@endloophook% + \csv@latepostlastline% + \csv@table@end% + \csv@postreading% + \csv@reset@catcodes% +} + +% user command +\long\def\csv@reader[#1]#2#3#4{% + \global\long\def\csv@@body{#4}% + \csvloop{#1,file={#2},column names={#3},command=\csv@@body}% +} + +\def\csvreader{% + \@ifnextchar[{\csv@reader}{\csv@reader[]}} + + +%---- keys + +\pgfkeys{/handlers/.gstore in/.code=\pgfkeysalso{\pgfkeyscurrentpath/.code=\gdef#1{##1}}} +\pgfkeys{/csv/.is family} +\pgfkeys{/csv head/.is family} + +\def\csvset{\pgfqkeys{/csv}} +\def\csvheadset{\pgfqkeys{/csv head}} + +\csvset{% + file/.gstore in=\csv@filename,% + preprocessed file/.gstore in=\csv@ppfilename,% + preprocessor/.code={\gdef\csv@preprocessor{#1}\let\csv@preprocss=\csv@preprocss@procedure},% + no preprocessing/.code={\let\csv@preprocss=\csv@preprocss@none}, + column names reset/.code={\gdef\csv@columnnames{}},% + column names/.code={% + \toks0=\expandafter{\csv@columnnames}% + \def\temp{#1}\toks1=\expandafter{\temp}% + \xdef\csv@columnnames{\the\toks0,\the\toks1}% + }, + command/.gstore in=\csv@body,% + check column count/.is choice,% + check column count/.default=true,% + check column count/true/.code={\global\let\csv@opt@checkcolumncount=\csv@checkcolumncount},% + check column count/false/.code={\global\let\csv@opt@checkcolumncount=\csv@nocheckcolumncount},% + on column count error/.gstore in=\csv@columncounterror, + head/.is choice,% + head/.default=true,% + head/true/.code={\global\let\csv@opt@processheadline=\csv@processheadline% + \pgfkeysalso{check column count}},% + head/false/.code={\global\let\csv@opt@processheadline=\csv@noheadline% + \pgfkeysalso{check column count=false,late after head=}},% + head to column names prefix/.store in=\csv@headnameprefix,% + head to column names/.is choice,% + head to column names/.default=true,% + head to column names/true/.code={\global\let\csv@opt@headtocolumnames=\set@csv@autohead},% + head to column names/false/.code={\global\let\csv@opt@headtocolumnames=\csv@empty},% + column count/.gstore in=\csv@columncount,% + filter/.code={\gdef\csv@iffilter{\ifthenelse{#1}}}, + filter ifthen/.code={\gdef\csv@iffilter{\ifthenelse{#1}}}, + filter test/.code={\gdef\csv@iffilter{#1}}, + filter expr/.code={\gdef\csv@iffilter{\ifboolexpr{#1}}}, + no filter/.code={\csvfilteraccept}, + filter reject all/.code={\csvfilterreject}, + filter accept all/.code={\csvfilteraccept}, + before filter/.gstore in=\csv@prefiltercommand, + full filter/.gstore in=\csv@prefiltercommand, + before first line/.gstore in=\csv@prefirstline, + before line/.code={\gdef\csv@preline{#1}\pgfkeysalso{before first line=#1}}, + after first line/.gstore in=\csv@postfirstline, + after line/.code={\gdef\csv@postline{#1}\pgfkeysalso{after first line=#1}}, + late after first line/.gstore in=\csv@latepostfirstline, + late after last line/.gstore in=\csv@latepostlastline, + late after line/.code={\gdef\csv@latepostline{#1}\pgfkeysalso{late after first line=#1,late after last line=#1}}, + after head/.gstore in=\csv@posthead, + late after head/.gstore in=\csv@lateposthead, + before reading/.gstore in=\csv@prereading, + after reading/.gstore in=\csv@postreading, + before table/.gstore in=\csv@pretable, + after table/.gstore in=\csv@posttable, + table head/.gstore in=\csv@tablehead, + table foot/.gstore in=\csv@tablefoot, + @table/.code 2 args={\gdef\csv@table@begin{#1}\gdef\csv@table@end{#2}}, + no table/.style={@table={}{}}, + separator/.is choice, + separator/comma/.code={\global\let\csv@scanline=\csv@scanline@A% + \global\let\csv@breakline\csv@breakline@A}, + separator/semicolon/.code={\global\let\csv@scanline=\csv@scanline@B% + \global\let\csv@breakline\csv@breakline@B}, + separator/pipe/.code={\global\let\csv@scanline=\csv@scanline@C% + \global\let\csv@breakline\csv@breakline@C}, + separator/tab/.code={\global\let\csv@scanline=\csv@scanline@D% + \global\let\csv@breakline\csv@breakline@D% + \csvset{respect tab}}, + % + csvsorter command/.store in=\csv@csvsorter@command, + csvsorter configpath/.store in=\csv@csvsorter@configpath, + sort by/.style={preprocessor={\csv@preprocessor@csvsorter{\csv@csvsorter@configpath/#1}}}, + new sorting rule/.style 2 args={sort by #1/.style={sort by={#2}}}, + csvsorter log/.store in=\csv@csvsorter@log, + csvsorter token/.store in=\csv@csvsorter@token, + csvsorter command=csvsorter, + csvsorter configpath=., + preprocessed file={\jobname_sorted._csv}, + csvsorter log={csvsorter.log}, + csvsorter token={\jobname.csvtoken}, + % + % default for reset + default/.style={ + file=unknown.csv, + no preprocessing, + command=\csvline, + column names reset, + head, + head to column names prefix=, + head to column names=false, + column count=10, + on column count error=, + no filter, + before filter=, + before line=, + after line=, + late after line=, + after head=, + late after head=, + before reading=, + after reading=, + before table=, + after table=, + table head=, + table foot=, + no table, + separator=comma, + }, + default, + % + % styles + every csv/.style={}, + no head/.style={head=false}, + no check column count/.style={check column count=false}, + warn on column count error/.style={on column count error={\csv@warning{>\thecsvcol< instead of >\csv@columncount< columns for input line >\thecsvinputline< of file >\csv@ppfilename<}}}, + filter equal/.style 2 args={filter ifthen=\equal{#1}{#2}}, + filter not equal/.style 2 args={filter ifthen=\not\equal{#1}{#2}}, + filter strcmp/.style 2 args={filter test=\ifcsvstrcmp{#1}{#2}}, + filter not strcmp/.style 2 args={filter test=\ifcsvnotstrcmp{#1}{#2}}, + tabular/.style={ + @table={\csv@pretable\begin{tabular}{#1}\csv@tablehead}{\csv@tablefoot\end{tabular}\csv@posttable}, + late after line=\\}, + centered tabular/.style={ + @table={\begin{center}\csv@pretable\begin{tabular}{#1}\csv@tablehead}{\csv@tablefoot\end{tabular}\csv@posttable\end{center}}, + late after line=\\}, + longtable/.style={ + @table={\csv@pretable\begin{longtable}{#1}\csv@tablehead}{\csv@tablefoot\end{longtable}\csv@posttable}, + late after line=\\}, + tabbing/.style={ + @table={\csv@pretable\begin{tabbing}\csv@tablehead}{\csv@tablefoot\end{tabbing}\csv@posttable}, + late after line=\\, + late after last line=}, + centered tabbing/.style={ + @table={\begin{center}\csv@pretable\begin{tabbing}\csv@tablehead}{\csv@tablefoot\end{tabbing}\csv@posttable\end{center}}, + late after line=\\, + late after last line=}, + autotabular/.style={ + file=#1, + after head=\csv@pretable\begin{tabular}{|*{\csv@columncount}{l|}}\csv@tablehead, + table head=\hline\csvlinetotablerow\\\hline, + late after line=\\, + table foot=\\\hline, + late after last line=\csv@tablefoot\end{tabular}\csv@posttable, + command=\csvlinetotablerow}, + autolongtable/.style={ + file=#1, + after head=\csv@pretable\begin{longtable}{|*{\csv@columncount}{l|}}\csv@tablehead, + table head=\hline\csvlinetotablerow\\\hline\endhead\hline\endfoot, + late after line=\\, + late after last line=\csv@tablefoot\end{longtable}\csv@posttable, + command=\csvlinetotablerow}, + autobooktabular/.style={ + file=#1, + after head=\csv@pretable\begin{tabular}{*{\csv@columncount}{l}}\csv@tablehead, + table head=\toprule\csvlinetotablerow\\\midrule, + late after line=\\, + table foot=\\\bottomrule, + late after last line=\csv@tablefoot\end{tabular}\csv@posttable, + command=\csvlinetotablerow}, + autobooklongtable/.style={ + file=#1, + after head=\csv@pretable\begin{longtable}{*{\csv@columncount}{l}}\csv@tablehead, + table head=\toprule\csvlinetotablerow\\\midrule\endhead\bottomrule\endfoot, + late after line=\\, + late after last line=\csv@tablefoot\end{longtable}\csv@posttable, + command=\csvlinetotablerow}, +} + +% deprecated keys +\csvset{ + nofilter/.style=no filter, + nohead/.style=no head, +} + +% catcodes +\def\csv@set@catcodes{% + \csv@catcode@tab@set% + \csv@catcode@tilde@set% + \csv@catcode@circumflex@set% + \csv@catcode@underscore@set% + \csv@catcode@and@set% + \csv@catcode@sharp@set% + \csv@catcode@dollar@set% + \csv@catcode@backslash@set% + \csv@catcode@leftbrace@set% + \csv@catcode@rightbrace@set% + \csv@catcode@percent@set} + +\def\csv@reset@catcodes{\csv@catcode@percent@reset% + \csv@catcode@rightbrace@reset% + \csv@catcode@leftbrace@reset% + \csv@catcode@backslash@reset% + \csv@catcode@dollar@reset% + \csv@catcode@sharp@reset% + \csv@catcode@and@reset% + \csv@catcode@underscore@reset% + \csv@catcode@circumflex@reset% + \csv@catcode@tilde@reset% + \csv@catcode@tab@reset% +} + + +\csvset{ + respect tab/.is choice, + respect tab/true/.code={% + \gdef\csv@catcode@tab@set{% + \xdef\csv@catcode@tab@value{\the\catcode`\^^I}% + \catcode`\^^I=12}% + \gdef\csv@catcode@tab@reset{\catcode`\^^I=\csv@catcode@tab@value}}, + respect tab/false/.code={% + \global\let\csv@catcode@tab@set\csv@empty% + \global\let\csv@catcode@tab@reset\csv@empty}, + respect tab/.default=true, + % + respect percent/.is choice, + respect percent/true/.code={% + \gdef\csv@catcode@percent@set{% + \xdef\csv@catcode@percent@value{\the\catcode`\%}% + \catcode`\%=12}% + \gdef\csv@catcode@percent@reset{\catcode`\%=\csv@catcode@percent@value}}, + respect percent/false/.code={% + \global\let\csv@catcode@percent@set\csv@empty% + \global\let\csv@catcode@percent@reset\csv@empty}, + respect percent/.default=true, + % + respect sharp/.is choice, + respect sharp/true/.code={% + \gdef\csv@catcode@sharp@set{% + \xdef\csv@catcode@sharp@value{\the\catcode`\#}% + \catcode`\#=12}% + \gdef\csv@catcode@sharp@reset{\catcode`\#=\csv@catcode@sharp@value}}, + respect sharp/false/.code={% + \global\let\csv@catcode@sharp@set\csv@empty% + \global\let\csv@catcode@sharp@reset\csv@empty}, + respect sharp/.default=true, + % + respect dollar/.is choice, + respect dollar/true/.code={% + \gdef\csv@catcode@dollar@set{% + \xdef\csv@catcode@dollar@value{\the\catcode`\$}% + \catcode`\$=12}% + \gdef\csv@catcode@dollar@reset{\catcode`\$=\csv@catcode@dollar@value}}, + respect dollar/false/.code={% + \global\let\csv@catcode@dollar@set\csv@empty% + \global\let\csv@catcode@dollar@reset\csv@empty}, + respect dollar/.default=true, + % + respect and/.is choice, + respect and/true/.code={% + \gdef\csv@catcode@and@set{% + \xdef\csv@catcode@and@value{\the\catcode`\&}% + \catcode`\&=12}% + \gdef\csv@catcode@and@reset{\catcode`\&=\csv@catcode@and@value}}, + respect and/false/.code={% + \global\let\csv@catcode@and@set\csv@empty% + \global\let\csv@catcode@and@reset\csv@empty}, + respect and/.default=true, + % + respect backslash/.is choice, + respect backslash/true/.code={% + \gdef\csv@catcode@backslash@set{% + \xdef\csv@catcode@backslash@value{\the\catcode`\\}% + \catcode`\\=12}% + \gdef\csv@catcode@backslash@reset{\catcode`\\=\csv@catcode@backslash@value}}, + respect backslash/false/.code={% + \global\let\csv@catcode@backslash@set\csv@empty% + \global\let\csv@catcode@backslash@reset\csv@empty}, + respect backslash/.default=true, + % + respect underscore/.is choice, + respect underscore/true/.code={% + \gdef\csv@catcode@underscore@set{% + \xdef\csv@catcode@underscore@value{\the\catcode`\_}% + \catcode`\_=12}% + \gdef\csv@catcode@underscore@reset{\catcode`\_=\csv@catcode@underscore@value}}, + respect underscore/false/.code={% + \global\let\csv@catcode@underscore@set\csv@empty% + \global\let\csv@catcode@underscore@reset\csv@empty}, + respect underscore/.default=true, + % + respect tilde/.is choice, + respect tilde/true/.code={% + \gdef\csv@catcode@tilde@set{% + \xdef\csv@catcode@tilde@value{\the\catcode`\~}% + \catcode`\~=12}% + \gdef\csv@catcode@tilde@reset{\catcode`\~=\csv@catcode@tilde@value}}, + respect tilde/false/.code={% + \global\let\csv@catcode@tilde@set\csv@empty% + \global\let\csv@catcode@tilde@reset\csv@empty}, + respect tilde/.default=true, + % + respect circumflex/.is choice, + respect circumflex/true/.code={% + \gdef\csv@catcode@circumflex@set{% + \xdef\csv@catcode@circumflex@value{\the\catcode`\^}% + \catcode`\^=12}% + \gdef\csv@catcode@circumflex@reset{\catcode`\^=\csv@catcode@circumflex@value}}, + respect circumflex/false/.code={% + \global\let\csv@catcode@circumflex@set\csv@empty% + \global\let\csv@catcode@circumflex@reset\csv@empty}, + respect circumflex/.default=true, + % + respect leftbrace/.is choice, + respect leftbrace/true/.code={% + \gdef\csv@catcode@leftbrace@set{% + \xdef\csv@catcode@leftbrace@value{\the\catcode`\{}% + \catcode`\{=12}% + \gdef\csv@catcode@leftbrace@reset{\catcode`\{=\csv@catcode@leftbrace@value}}, + respect leftbrace/false/.code={% + \global\let\csv@catcode@leftbrace@set\csv@empty% + \global\let\csv@catcode@leftbrace@reset\csv@empty}, + respect leftbrace/.default=true, + % + respect rightbrace/.is choice, + respect rightbrace/true/.code={% + \gdef\csv@catcode@rightbrace@set{% + \xdef\csv@catcode@rightbrace@value{\the\catcode`\}}% + \catcode`\}=12}% + \gdef\csv@catcode@rightbrace@reset{\catcode`\}=\csv@catcode@rightbrace@value}}, + respect rightbrace/false/.code={% + \global\let\csv@catcode@rightbrace@set\csv@empty% + \global\let\csv@catcode@rightbrace@reset\csv@empty}, + respect rightbrace/.default=true, + % + respect all/.style={respect tab,respect percent,respect sharp,respect dollar, + respect and,respect backslash,respect underscore,respect tilde,respect circumflex, + respect leftbrace,respect rightbrace}, + respect none/.style={respect tab=false,respect percent=false,respect sharp=false, + respect dollar=false,respect and=false,respect backslash=false, + respect underscore=false,respect tilde=false,respect circumflex=false, + respect leftbrace=false,respect rightbrace=false}, + respect none +} + + +\long\def\csv@autotabular[#1]#2{\csvloop{autotabular={#2},#1}} + +\def\csvautotabular{% + \@ifnextchar[{\csv@autotabular}{\csv@autotabular[]}} + +\long\def\csv@autolongtable[#1]#2{\csvloop{autolongtable={#2},#1}} + +\def\csvautolongtable{% + \@ifnextchar[{\csv@autolongtable}{\csv@autolongtable[]}} + +\long\def\csv@autobooktabular[#1]#2{\csvloop{autobooktabular={#2},#1}} + +\def\csvautobooktabular{% + \@ifnextchar[{\csv@autobooktabular}{\csv@autobooktabular[]}} + + +\long\def\csv@autobooklongtable[#1]#2{\csvloop{autobooklongtable={#2},#1}} + +\def\csvautobooklongtable{% + \@ifnextchar[{\csv@autobooklongtable}{\csv@autobooklongtable[]}} + + +\def\csvstyle#1#2{\csvset{#1/.style={#2}}} + +\def\csvnames#1#2{\csvset{#1/.style={column names={#2}}}} + +% string comparison + +\newrobustcmd{\ifcsvstrequal}[2]{% + \begingroup% + \edef\csv@tempa{#1}% + \edef\csv@tempb{#2}% + \ifx\csv@tempa\csv@tempb% + \aftergroup\@firstoftwo% + \else% + \aftergroup\@secondoftwo% + \fi% + \endgroup% +}% + +\newrobustcmd{\ifcsvprostrequal}[2]{% + \begingroup% + \protected@edef\csv@tempa{#1}% + \protected@edef\csv@tempb{#2}% + \ifx\csv@tempa\csv@tempb% + \aftergroup\@firstoftwo% + \else% + \aftergroup\@secondoftwo% + \fi% + \endgroup% +}% + +\AtBeginDocument{% + \ifdefined\pdfstrcmp% + \let\csv@strcmp\pdfstrcmp% + \else\ifdefined\pdf@strcmp% + \let\csv@strcmp\pdf@strcmp% + \fi\fi% + \ifdefined\csv@strcmp% + \newrobustcmd{\ifcsvstrcmp}[2]{% + \ifnum\csv@strcmp{#1}{#2}=\z@\relax% + \expandafter\@firstoftwo% + \else% + \expandafter\@secondoftwo% + \fi% + }% + \else% + \let\ifcsvstrcmp\ifcsvstrequal% + \fi% +} + +\newrobustcmd{\ifcsvnotstrcmp}[4]{\ifcsvstrcmp{#1}{#2}{#4}{#3}} diff --git a/Master/texmf-dist/tex/latex/csvsimple/csvsimple.sty b/Master/texmf-dist/tex/latex/csvsimple/csvsimple.sty index 98d1a328668..def091859f7 100644 --- a/Master/texmf-dist/tex/latex/csvsimple/csvsimple.sty +++ b/Master/texmf-dist/tex/latex/csvsimple/csvsimple.sty @@ -1,4 +1,4 @@ -%% The LaTeX package csvsimple - version 1.22 (2021/06/07) +%% The LaTeX package csvsimple - version 2.0.0 (2021/06/29) %% csvsimple.sty: Simple LaTeX CSV file processing %% %% ------------------------------------------------------------------------------------------- @@ -15,766 +15,35 @@ %% %% This work has the LPPL maintenance status `author-maintained'. %% -%% This work consists of all files listed in README +%% This work consists of all files listed in README.md %% -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{csvsimple}[2021/06/07 version 1.22 LaTeX CSV file processing] - -\RequirePackage{pgfrcs,pgfkeys,ifthen,etoolbox,shellesc} - - -%---- general - -\def\csv@warning#1{\PackageWarning{csvsimple}{#1}} -\def\csv@error#1#2{\PackageError{csvsimple}{#1}{#2}} - -\newread\csv@file -\newcounter{csvinputline} -\newcounter{csvrow} -\newcounter{csvcol} - -\def\csv@empty{} - -\long\def\csviffirstrow#1#2{% - \ifnum\c@csvrow=1% - \long\def\csviffirstrow@doit{#1}% - \else% - \long\def\csviffirstrow@doit{#2}% - \fi% - \csviffirstrow@doit% -} - -\long\def\csvifoddrow#1#2{% - \ifodd\c@csvrow% - \long\def\csvifoddrow@doit{#1}% - \else% - \long\def\csvifoddrow@doit{#2}% - \fi% - \csvifoddrow@doit% -} - -\def\csv@assemble@csvlinetotablerow{% - \global\c@csvcol 1\relax% - \xdef\csvlinetotablerow{\expandonce{\csname csvcol\romannumeral\c@csvcol\endcsname}}% - \ifnum\c@csvcol<\csv@columncount\relax% - \loop% - \global\advance\c@csvcol 1\relax% - \xappto\csvlinetotablerow{\noexpand&\expandonce{\csname csvcol\romannumeral\c@csvcol\endcsname}}% - \ifnum\c@csvcol<\csv@columncount\relax\repeat% - \fi% - \csvlinetotablerow% -} - - -%---- breaking lines - -% This command removes leading and trailing spaces from <Token>. I found -% the original code on the web. The original author was Michael Downes, who -% provided the code as an answer to 'around the bend' question #15. -\catcode`\Q=3 -\def\csv@TrimSpaces#1{% - \begingroup% - \aftergroup\toks\aftergroup0\aftergroup{% - \expandafter\csv@trimb\expandafter\noexpand#1Q Q}% - \global\edef#1{\the\toks0}% -} -\def\csv@trimb#1 Q{\csv@trimc#1Q} -\def\csv@trimc#1Q#2{\afterassignment\endgroup \vfuzz\the\vfuzz#1} -\catcode`\Q=11 - -\def\csv@TrimBraces#1{\expandafter\csv@TrimBraces@#1\@nil{#1}} -\def\csv@TrimBraces@#1\@nil#2{\def#2{#1}} - -\def\csv@breakline@kernel#1{% - \ifx\csv@termination#1\let\nextcol=\relax\else% - \let\nextcol=\csv@breakline% - \global\advance\c@csvcol 1\relax% - \def\csv@col@body{#1}% - \csv@TrimSpaces\csv@col@body% - \csv@TrimBraces\csv@col@body% - \toks@\expandafter{\csv@col@body}% - \expandafter\xdef\csname csvcol\romannumeral\c@csvcol\endcsname{\the\toks@}% - \fi% - \nextcol% -} - -% comma -\def\csv@breakline@A#1,{\csv@breakline@kernel{#1}} - -\def\csv@scanline@A#1{% - \global\c@csvcol 0\relax% - \csv@breakline#1,\csv@termination,% -} - -% semi colon -\def\csv@breakline@B#1;{\csv@breakline@kernel{#1}} - -\def\csv@scanline@B#1{% - \global\c@csvcol 0\relax% - \csv@breakline#1;\csv@termination;% -} - -% pipe -\def\csv@breakline@C#1|{\csv@breakline@kernel{#1}} - -\def\csv@scanline@C#1{% - \global\c@csvcol 0\relax% - \csv@breakline#1|\csv@termination|% -} - -% tab -\catcode`\^^I=12 -\def\csv@breakline@D#1^^I{\csv@breakline@kernel{#1}} - -\def\csv@scanline@D#1{% - \global\c@csvcol 0\relax% - \csv@breakline#1^^I\csv@termination^^I% -} -\catcode`\^^I=10 - -% expands a CSV line and scans content -\def\csv@escanline#1{% - \toks@\expandafter{#1}% - \edef\@csv@scanline{\noexpand\csv@scanline{\the\toks@}}% - \@csv@scanline% -} - -{ - \catcode`\"=12% - \gdef\csv@passivquotes{"} -} - -\newwrite\csv@out - -\def\csv@preprocessor@csvsorter#1#2#3{% - \begingroup% - \typeout{<sort \csv@passivquotes#2\csv@passivquotes\space by \csv@passivquotes#1\csv@passivquotes>}% - \immediate\openout\csv@out=\csv@csvsorter@token% - \immediate\write\csv@out{\string\makeatletter\string\csv@error{Call of CSV-Sorter failed! Use '-shell-escape' option or check log file '\csv@csvsorter@log'.}{}}% - \immediate\closeout\csv@out% - \ShellEscape{\csv@csvsorter@command\space - -c \csv@passivquotes#1\csv@passivquotes\space - -l \csv@passivquotes\csv@csvsorter@log\csv@passivquotes\space - -t \csv@passivquotes\csv@csvsorter@token\csv@passivquotes\space - -i \csv@passivquotes#2\csv@passivquotes\space - -o \csv@passivquotes#3\csv@passivquotes\space -q 1}% - \input{\csv@csvsorter@token}% - \endgroup% -} - - -\def\csv@preprocss@none{% - \let\csv@input@filename=\csv@filename% -} - -\def\csv@preprocss@procedure{% - \csv@preprocessor{\csv@filename}{\csv@ppfilename}% - \let\csv@input@filename=\csv@ppfilename% -} - - -%---- the loop - -\def\csv@AtEndLoop{\gappto\@endloophook} -\let\@endloophook\csv@empty - -\def\csv@current@col{\csname csvcol\romannumeral\c@csvcol\endcsname} - -% auto head names -\def\set@csv@autohead{% - \toks0=\expandafter{\csname\csv@headnameprefix\csv@current@col\endcsname}% - \toks1=\expandafter{\csname csvcol\romannumeral\c@csvcol\endcsname}% - \begingroup\edef\csv@temp{\endgroup\noexpand\gdef\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\noexpand\gdef\the\toks0{}}}% - \csv@temp% -} - -% head names and numbers -\def\set@csv@head{% - \toks0={\gdef##1}% - \toks1=\expandafter{\csname csvcol\romannumeral\c@csvcol\endcsname}% - \begingroup\edef\csv@temp{\endgroup\noexpand\pgfkeysdef{/csv head/\csv@current@col}{\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\the\toks0{}}}}% - \csv@temp% - \begingroup\edef\csv@temp{\endgroup\noexpand\pgfkeysdef{/csv head/\thecsvcol}{\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\the\toks0{}}}}% - \csv@temp% -} - -% head line -\def\csv@processheadline{% - \csvreadnext% - \ifx\csv@par\csvline\relax% - \csv@error{File '\csv@input@filename' starts with an empty line!}{}% - \else\csv@escanline{\csvline}% - \fi% - \xdef\csv@columncount{\thecsvcol}% - \global\c@csvcol 0\relax% - \loop% - \global\advance\c@csvcol 1\relax% - \csv@opt@headtocolumnames% - \set@csv@head% - \ifnum\c@csvcol<\csv@columncount\repeat% - \toks@=\expandafter{\csv@columnnames}% - \edef\csv@processkeys{\noexpand\pgfkeys{/csv head/.cd,\the\toks@}}% - \csv@processkeys% - \csv@posthead% -} - -% head numbers for no head -\def\set@csv@nohead{% - \toks0={\gdef##1}% - \toks1=\expandafter{\csname csvcol\romannumeral\c@csvcol\endcsname}% - \begingroup\edef\csv@temp{\endgroup\noexpand\pgfkeysdef{/csv head/\thecsvcol}{\the\toks0{\the\toks1}\noexpand\csv@AtEndLoop{\the\toks0{}}}}% - \csv@temp% -} - -% no head line -\def\csv@noheadline{% - \global\c@csvcol 0\relax% - \loop% - \global\advance\c@csvcol 1\relax% - \set@csv@nohead% - \ifnum\c@csvcol<\csv@columncount\repeat% - \toks@=\expandafter{\csv@columnnames}% - \edef\csv@processkeys{\noexpand\pgfkeys{/csv head/.cd,\the\toks@}}% - \csv@processkeys% -} - -% check filter -\def\csv@checkfilter{% - \csv@prefiltercommand% - \csv@iffilter{% - \stepcounter{csvrow}% - \let\csv@usage=\csv@do@linecommand% - }{}% -} - -\def\csv@truefilter#1#2{#1} - -\def\csv@falsefilter#1#2{#2} - -\def\csvfilteraccept{\global\let\csv@iffilter=\csv@truefilter} - -\def\csvfilterreject{\global\let\csv@iffilter=\csv@falsefilter} - -% check columns -\def\csv@checkcolumncount{% - \ifnum\c@csvcol=\csv@columncount\relax% - \csv@checkfilter% - \else% - \csv@columncounterror% - \fi% -} - -\def\csv@nocheckcolumncount{% - \csv@checkfilter% -} - -% normal line -\def\csv@do@linecommand{% - \csv@do@latepostline% - \csv@do@preline% - \csv@body\relax% - \csv@do@postline% -} - -\gdef\csvreadnext{% - \global\read\csv@file to\csvline% - \stepcounter{csvinputline}% -} - -\def\csv@par{\par} - -% reads and processes a CSV file -\long\def\csvloop#1{% - % reset - \global\let\@endloophook\csv@empty% - \global\let\csvlinetotablerow\csv@assemble@csvlinetotablerow% - % options - \csvset{default,every csv,#1}% - \csv@preprocss% - \csv@set@catcodes% - \csv@prereading% - \csv@table@begin% - \setcounter{csvinputline}{0}% - % start reading - \openin\csv@file=\csv@input@filename\relax% - \ifeof\csv@file% - \csv@error{File '\csv@input@filename' not existent, not readable, or empty!}{}% - \else% - % the head line - \csv@opt@processheadline% - \fi% - % - \setcounter{csvrow}{0}% - \gdef\csv@do@preline{% - \csv@prefirstline% - \global\let\csv@do@preline=\csv@preline% - }% - \gdef\csv@do@postline{% - \csv@postfirstline% - \global\let\csv@do@postline=\csv@postline% - }% - \gdef\csv@do@@latepostline{% - \csv@latepostfirstline% - \global\let\csv@do@latepostline=\csv@latepostline% - }% - \gdef\csv@do@latepostline{% - \csv@lateposthead% - \global\let\csv@do@latepostline=\csv@do@@latepostline% - }% - % command for the reading loop - \gdef\csv@iterate{% - \let\csv@usage=\csv@empty% - \csvreadnext% - \ifeof\csv@file% - \global\let\csv@next=\csv@empty% - \else% - \global\let\csv@next=\csv@iterate% - \ifx\csv@par\csvline\relax% - \else% - \csv@escanline{\csvline}% - % check and decide - \csv@opt@checkcolumncount% - \fi% - \fi% - % do or do not - \csv@usage% - \csv@next}% - \ifeof\csv@file% - \global\let\csv@next=\csv@empty% - \else% - \global\let\csv@next=\csv@iterate% - \fi% - \csv@next% - \closein\csv@file% - \@endloophook% - \csv@latepostlastline% - \csv@table@end% - \csv@postreading% - \csv@reset@catcodes% -} - -% user command -\long\def\csv@reader[#1]#2#3#4{% - \global\long\def\csv@@body{#4}% - \csvloop{#1,file={#2},column names={#3},command=\csv@@body}% -} - -\def\csvreader{% - \@ifnextchar[{\csv@reader}{\csv@reader[]}} - - -%---- keys - -\pgfkeys{/handlers/.gstore in/.code=\pgfkeysalso{\pgfkeyscurrentpath/.code=\gdef#1{##1}}} -\pgfkeys{/csv/.is family} -\pgfkeys{/csv head/.is family} - -\def\csvset{\pgfqkeys{/csv}} -\def\csvheadset{\pgfqkeys{/csv head}} - -\csvset{% - file/.gstore in=\csv@filename,% - preprocessed file/.gstore in=\csv@ppfilename,% - preprocessor/.code={\gdef\csv@preprocessor{#1}\let\csv@preprocss=\csv@preprocss@procedure},% - no preprocessing/.code={\let\csv@preprocss=\csv@preprocss@none}, - column names reset/.code={\gdef\csv@columnnames{}},% - column names/.code={% - \toks0=\expandafter{\csv@columnnames}% - \def\temp{#1}\toks1=\expandafter{\temp}% - \xdef\csv@columnnames{\the\toks0,\the\toks1}% - }, - command/.gstore in=\csv@body,% - check column count/.is choice,% - check column count/.default=true,% - check column count/true/.code={\global\let\csv@opt@checkcolumncount=\csv@checkcolumncount},% - check column count/false/.code={\global\let\csv@opt@checkcolumncount=\csv@nocheckcolumncount},% - on column count error/.gstore in=\csv@columncounterror, - head/.is choice,% - head/.default=true,% - head/true/.code={\global\let\csv@opt@processheadline=\csv@processheadline% - \pgfkeysalso{check column count}},% - head/false/.code={\global\let\csv@opt@processheadline=\csv@noheadline% - \pgfkeysalso{check column count=false,late after head=}},% - head to column names prefix/.store in=\csv@headnameprefix,% - head to column names/.is choice,% - head to column names/.default=true,% - head to column names/true/.code={\global\let\csv@opt@headtocolumnames=\set@csv@autohead},% - head to column names/false/.code={\global\let\csv@opt@headtocolumnames=\csv@empty},% - column count/.gstore in=\csv@columncount,% - filter/.code={\gdef\csv@iffilter{\ifthenelse{#1}}}, - filter ifthen/.code={\gdef\csv@iffilter{\ifthenelse{#1}}}, - filter test/.code={\gdef\csv@iffilter{#1}}, - filter expr/.code={\gdef\csv@iffilter{\ifboolexpr{#1}}}, - no filter/.code={\csvfilteraccept}, - filter reject all/.code={\csvfilterreject}, - filter accept all/.code={\csvfilteraccept}, - before filter/.gstore in=\csv@prefiltercommand, - full filter/.gstore in=\csv@prefiltercommand, - before first line/.gstore in=\csv@prefirstline, - before line/.code={\gdef\csv@preline{#1}\pgfkeysalso{before first line=#1}}, - after first line/.gstore in=\csv@postfirstline, - after line/.code={\gdef\csv@postline{#1}\pgfkeysalso{after first line=#1}}, - late after first line/.gstore in=\csv@latepostfirstline, - late after last line/.gstore in=\csv@latepostlastline, - late after line/.code={\gdef\csv@latepostline{#1}\pgfkeysalso{late after first line=#1,late after last line=#1}}, - after head/.gstore in=\csv@posthead, - late after head/.gstore in=\csv@lateposthead, - before reading/.gstore in=\csv@prereading, - after reading/.gstore in=\csv@postreading, - before table/.gstore in=\csv@pretable, - after table/.gstore in=\csv@posttable, - table head/.gstore in=\csv@tablehead, - table foot/.gstore in=\csv@tablefoot, - @table/.code 2 args={\gdef\csv@table@begin{#1}\gdef\csv@table@end{#2}}, - no table/.style={@table={}{}}, - separator/.is choice, - separator/comma/.code={\global\let\csv@scanline=\csv@scanline@A% - \global\let\csv@breakline\csv@breakline@A}, - separator/semicolon/.code={\global\let\csv@scanline=\csv@scanline@B% - \global\let\csv@breakline\csv@breakline@B}, - separator/pipe/.code={\global\let\csv@scanline=\csv@scanline@C% - \global\let\csv@breakline\csv@breakline@C}, - separator/tab/.code={\global\let\csv@scanline=\csv@scanline@D% - \global\let\csv@breakline\csv@breakline@D% - \csvset{respect tab}}, - % - csvsorter command/.store in=\csv@csvsorter@command, - csvsorter configpath/.store in=\csv@csvsorter@configpath, - sort by/.style={preprocessor={\csv@preprocessor@csvsorter{\csv@csvsorter@configpath/#1}}}, - new sorting rule/.style 2 args={sort by #1/.style={sort by={#2}}}, - csvsorter log/.store in=\csv@csvsorter@log, - csvsorter token/.store in=\csv@csvsorter@token, - csvsorter command=csvsorter, - csvsorter configpath=., - preprocessed file={\jobname_sorted._csv}, - csvsorter log={csvsorter.log}, - csvsorter token={\jobname.csvtoken}, - % - % default for reset - default/.style={ - file=unknown.csv, - no preprocessing, - command=\csvline, - column names reset, - head, - head to column names prefix=, - head to column names=false, - column count=10, - on column count error=, - no filter, - before filter=, - before line=, - after line=, - late after line=, - after head=, - late after head=, - before reading=, - after reading=, - before table=, - after table=, - table head=, - table foot=, - no table, - separator=comma, - }, - default, - % - % styles - every csv/.style={}, - no head/.style={head=false}, - no check column count/.style={check column count=false}, - warn on column count error/.style={on column count error={\csv@warning{>\thecsvcol< instead of >\csv@columncount< columns for input line >\thecsvinputline< of file >\csv@ppfilename<}}}, - filter equal/.style 2 args={filter ifthen=\equal{#1}{#2}}, - filter not equal/.style 2 args={filter ifthen=\not\equal{#1}{#2}}, - filter strcmp/.style 2 args={filter test=\ifcsvstrcmp{#1}{#2}}, - filter not strcmp/.style 2 args={filter test=\ifcsvnotstrcmp{#1}{#2}}, - tabular/.style={ - @table={\csv@pretable\begin{tabular}{#1}\csv@tablehead}{\csv@tablefoot\end{tabular}\csv@posttable}, - late after line=\\}, - centered tabular/.style={ - @table={\begin{center}\csv@pretable\begin{tabular}{#1}\csv@tablehead}{\csv@tablefoot\end{tabular}\csv@posttable\end{center}}, - late after line=\\}, - longtable/.style={ - @table={\csv@pretable\begin{longtable}{#1}\csv@tablehead}{\csv@tablefoot\end{longtable}\csv@posttable}, - late after line=\\}, - tabbing/.style={ - @table={\csv@pretable\begin{tabbing}\csv@tablehead}{\csv@tablefoot\end{tabbing}\csv@posttable}, - late after line=\\, - late after last line=}, - centered tabbing/.style={ - @table={\begin{center}\csv@pretable\begin{tabbing}\csv@tablehead}{\csv@tablefoot\end{tabbing}\csv@posttable\end{center}}, - late after line=\\, - late after last line=}, - autotabular/.style={ - file=#1, - after head=\csv@pretable\begin{tabular}{|*{\csv@columncount}{l|}}\csv@tablehead, - table head=\hline\csvlinetotablerow\\\hline, - late after line=\\, - table foot=\\\hline, - late after last line=\csv@tablefoot\end{tabular}\csv@posttable, - command=\csvlinetotablerow}, - autolongtable/.style={ - file=#1, - after head=\csv@pretable\begin{longtable}{|*{\csv@columncount}{l|}}\csv@tablehead, - table head=\hline\csvlinetotablerow\\\hline\endhead\hline\endfoot, - late after line=\\, - late after last line=\csv@tablefoot\end{longtable}\csv@posttable, - command=\csvlinetotablerow}, - autobooktabular/.style={ - file=#1, - after head=\csv@pretable\begin{tabular}{*{\csv@columncount}{l}}\csv@tablehead, - table head=\toprule\csvlinetotablerow\\\midrule, - late after line=\\, - table foot=\\\bottomrule, - late after last line=\csv@tablefoot\end{tabular}\csv@posttable, - command=\csvlinetotablerow}, - autobooklongtable/.style={ - file=#1, - after head=\csv@pretable\begin{longtable}{*{\csv@columncount}{l}}\csv@tablehead, - table head=\toprule\csvlinetotablerow\\\midrule\endhead\bottomrule\endfoot, - late after line=\\, - late after last line=\csv@tablefoot\end{longtable}\csv@posttable, - command=\csvlinetotablerow}, -} - -% deprecated keys -\csvset{ - nofilter/.style=no filter, - nohead/.style=no head, -} - -% catcodes -\def\csv@set@catcodes{% - \csv@catcode@tab@set% - \csv@catcode@tilde@set% - \csv@catcode@circumflex@set% - \csv@catcode@underscore@set% - \csv@catcode@and@set% - \csv@catcode@sharp@set% - \csv@catcode@dollar@set% - \csv@catcode@backslash@set% - \csv@catcode@leftbrace@set% - \csv@catcode@rightbrace@set% - \csv@catcode@percent@set} - -\def\csv@reset@catcodes{\csv@catcode@percent@reset% - \csv@catcode@rightbrace@reset% - \csv@catcode@leftbrace@reset% - \csv@catcode@backslash@reset% - \csv@catcode@dollar@reset% - \csv@catcode@sharp@reset% - \csv@catcode@and@reset% - \csv@catcode@underscore@reset% - \csv@catcode@circumflex@reset% - \csv@catcode@tilde@reset% - \csv@catcode@tab@reset% -} - - -\csvset{ - respect tab/.is choice, - respect tab/true/.code={% - \gdef\csv@catcode@tab@set{% - \xdef\csv@catcode@tab@value{\the\catcode`\^^I}% - \catcode`\^^I=12}% - \gdef\csv@catcode@tab@reset{\catcode`\^^I=\csv@catcode@tab@value}}, - respect tab/false/.code={% - \global\let\csv@catcode@tab@set\csv@empty% - \global\let\csv@catcode@tab@reset\csv@empty}, - respect tab/.default=true, - % - respect percent/.is choice, - respect percent/true/.code={% - \gdef\csv@catcode@percent@set{% - \xdef\csv@catcode@percent@value{\the\catcode`\%}% - \catcode`\%=12}% - \gdef\csv@catcode@percent@reset{\catcode`\%=\csv@catcode@percent@value}}, - respect percent/false/.code={% - \global\let\csv@catcode@percent@set\csv@empty% - \global\let\csv@catcode@percent@reset\csv@empty}, - respect percent/.default=true, - % - respect sharp/.is choice, - respect sharp/true/.code={% - \gdef\csv@catcode@sharp@set{% - \xdef\csv@catcode@sharp@value{\the\catcode`\#}% - \catcode`\#=12}% - \gdef\csv@catcode@sharp@reset{\catcode`\#=\csv@catcode@sharp@value}}, - respect sharp/false/.code={% - \global\let\csv@catcode@sharp@set\csv@empty% - \global\let\csv@catcode@sharp@reset\csv@empty}, - respect sharp/.default=true, - % - respect dollar/.is choice, - respect dollar/true/.code={% - \gdef\csv@catcode@dollar@set{% - \xdef\csv@catcode@dollar@value{\the\catcode`\$}% - \catcode`\$=12}% - \gdef\csv@catcode@dollar@reset{\catcode`\$=\csv@catcode@dollar@value}}, - respect dollar/false/.code={% - \global\let\csv@catcode@dollar@set\csv@empty% - \global\let\csv@catcode@dollar@reset\csv@empty}, - respect dollar/.default=true, - % - respect and/.is choice, - respect and/true/.code={% - \gdef\csv@catcode@and@set{% - \xdef\csv@catcode@and@value{\the\catcode`\&}% - \catcode`\&=12}% - \gdef\csv@catcode@and@reset{\catcode`\&=\csv@catcode@and@value}}, - respect and/false/.code={% - \global\let\csv@catcode@and@set\csv@empty% - \global\let\csv@catcode@and@reset\csv@empty}, - respect and/.default=true, - % - respect backslash/.is choice, - respect backslash/true/.code={% - \gdef\csv@catcode@backslash@set{% - \xdef\csv@catcode@backslash@value{\the\catcode`\\}% - \catcode`\\=12}% - \gdef\csv@catcode@backslash@reset{\catcode`\\=\csv@catcode@backslash@value}}, - respect backslash/false/.code={% - \global\let\csv@catcode@backslash@set\csv@empty% - \global\let\csv@catcode@backslash@reset\csv@empty}, - respect backslash/.default=true, - % - respect underscore/.is choice, - respect underscore/true/.code={% - \gdef\csv@catcode@underscore@set{% - \xdef\csv@catcode@underscore@value{\the\catcode`\_}% - \catcode`\_=12}% - \gdef\csv@catcode@underscore@reset{\catcode`\_=\csv@catcode@underscore@value}}, - respect underscore/false/.code={% - \global\let\csv@catcode@underscore@set\csv@empty% - \global\let\csv@catcode@underscore@reset\csv@empty}, - respect underscore/.default=true, - % - respect tilde/.is choice, - respect tilde/true/.code={% - \gdef\csv@catcode@tilde@set{% - \xdef\csv@catcode@tilde@value{\the\catcode`\~}% - \catcode`\~=12}% - \gdef\csv@catcode@tilde@reset{\catcode`\~=\csv@catcode@tilde@value}}, - respect tilde/false/.code={% - \global\let\csv@catcode@tilde@set\csv@empty% - \global\let\csv@catcode@tilde@reset\csv@empty}, - respect tilde/.default=true, - % - respect circumflex/.is choice, - respect circumflex/true/.code={% - \gdef\csv@catcode@circumflex@set{% - \xdef\csv@catcode@circumflex@value{\the\catcode`\^}% - \catcode`\^=12}% - \gdef\csv@catcode@circumflex@reset{\catcode`\^=\csv@catcode@circumflex@value}}, - respect circumflex/false/.code={% - \global\let\csv@catcode@circumflex@set\csv@empty% - \global\let\csv@catcode@circumflex@reset\csv@empty}, - respect circumflex/.default=true, - % - respect leftbrace/.is choice, - respect leftbrace/true/.code={% - \gdef\csv@catcode@leftbrace@set{% - \xdef\csv@catcode@leftbrace@value{\the\catcode`\{}% - \catcode`\{=12}% - \gdef\csv@catcode@leftbrace@reset{\catcode`\{=\csv@catcode@leftbrace@value}}, - respect leftbrace/false/.code={% - \global\let\csv@catcode@leftbrace@set\csv@empty% - \global\let\csv@catcode@leftbrace@reset\csv@empty}, - respect leftbrace/.default=true, - % - respect rightbrace/.is choice, - respect rightbrace/true/.code={% - \gdef\csv@catcode@rightbrace@set{% - \xdef\csv@catcode@rightbrace@value{\the\catcode`\}}% - \catcode`\}=12}% - \gdef\csv@catcode@rightbrace@reset{\catcode`\}=\csv@catcode@rightbrace@value}}, - respect rightbrace/false/.code={% - \global\let\csv@catcode@rightbrace@set\csv@empty% - \global\let\csv@catcode@rightbrace@reset\csv@empty}, - respect rightbrace/.default=true, - % - respect all/.style={respect tab,respect percent,respect sharp,respect dollar, - respect and,respect backslash,respect underscore,respect tilde,respect circumflex, - respect leftbrace,respect rightbrace}, - respect none/.style={respect tab=false,respect percent=false,respect sharp=false, - respect dollar=false,respect and=false,respect backslash=false, - respect underscore=false,respect tilde=false,respect circumflex=false, - respect leftbrace=false,respect rightbrace=false}, - respect none -} - - -\long\def\csv@autotabular[#1]#2{\csvloop{autotabular={#2},#1}} - -\def\csvautotabular{% - \@ifnextchar[{\csv@autotabular}{\csv@autotabular[]}} - -\long\def\csv@autolongtable[#1]#2{\csvloop{autolongtable={#2},#1}} - -\def\csvautolongtable{% - \@ifnextchar[{\csv@autolongtable}{\csv@autolongtable[]}} - -\long\def\csv@autobooktabular[#1]#2{\csvloop{autobooktabular={#2},#1}} - -\def\csvautobooktabular{% - \@ifnextchar[{\csv@autobooktabular}{\csv@autobooktabular[]}} - - -\long\def\csv@autobooklongtable[#1]#2{\csvloop{autobooklongtable={#2},#1}} - -\def\csvautobooklongtable{% - \@ifnextchar[{\csv@autobooklongtable}{\csv@autobooklongtable[]}} - - -\def\csvstyle#1#2{\csvset{#1/.style={#2}}} - -\def\csvnames#1#2{\csvset{#1/.style={column names={#2}}}} - -% string comparison - -\newrobustcmd{\ifcsvstrequal}[2]{% - \begingroup% - \protected@edef\csv@tempa{#1}% - \protected@edef\csv@tempb{#2}% - \edef\csv@tempa{#1}% - \edef\csv@tempb{#2}% - \ifx\csv@tempa\csv@tempb% - \aftergroup\@firstoftwo% - \else% - \aftergroup\@secondoftwo% - \fi% - \endgroup% -}% - -\newrobustcmd{\ifcsvprostrequal}[2]{% - \begingroup% - \protected@edef\csv@tempa{#1}% - \protected@edef\csv@tempb{#2}% - \ifx\csv@tempa\csv@tempb% - \aftergroup\@firstoftwo% - \else% - \aftergroup\@secondoftwo% - \fi% - \endgroup% -}% - -\AtBeginDocument{% - \ifdefined\pdfstrcmp% - \let\csv@strcmp\pdfstrcmp% - \else\ifdefined\pdf@strcmp% - \let\csv@strcmp\pdf@strcmp% - \fi\fi% - \ifdefined\csv@strcmp% - \newrobustcmd{\ifcsvstrcmp}[2]{% - \ifnum\csv@strcmp{#1}{#2}=\z@\relax% - \expandafter\@firstoftwo% - \else% - \expandafter\@secondoftwo% - \fi% - }% - \else% - \let\ifcsvstrcmp\ifcsvstrequal% - \fi% -} - -\newrobustcmd{\ifcsvnotstrcmp}[4]{\ifcsvstrcmp{#1}{#2}{#4}{#3}} +\RequirePackage{l3keys2e} + +\ProvidesExplPackage{csvsimple}{2021/06/29}{2.0.0} + {LaTeX CSV file processing} + +\cs_if_exist:NT \c__csvsim_package_expl_bool + { + \msg_new:nnn { csvsimple }{ package-loaded } + { Package~'#1'~seems~already~be~loaded! } + \bool_if:NTF \c__csvsim_package_expl_bool + { + \msg_warning:nn { csvsimple }{ package-loaded }{ csvsimple-l3 } + } + { + \msg_warning:nn { csvsimple }{ package-loaded }{ csvsimple-legacy } + } + \tex_endinput:D + } + +\keys_define:nn { csvsimple } + { + l3 .code:n = \tl_set:Nn \l__csvsim_package_expl_tl { l3 }, + legacy .code:n = \tl_set:Nn \l__csvsim_package_expl_tl { legacy }, + } + +\keys_set:nn { csvsimple } { legacy } + +\ProcessKeysPackageOptions { csvsimple } + +\RequirePackage{csvsimple-\l__csvsim_package_expl_tl} |