%%%============================================================================== %% Copyright 2025-present by Alceu Frigeri %% %% This work may be distributed and/or modified under the conditions of %% %% * The [LaTeX Project Public License](http://www.latex-project.org/lppl.txt), %% version 1.3c (or later), and/or %% * The [GNU Affero General Public License](https://www.gnu.org/licenses/agpl-3.0.html), %% version 3 (or later) %% %% This work has the LPPL maintenance status *maintained*. %% %% The Current Maintainer of this work is Alceu Frigeri %% %% This is version {1.0} {2025/10/21} %% %% The list of files that compose this work can be found in the README.md file at %% https://ctan.org/pkg/pkginfograb %% %%%============================================================================== \NeedsTeXFormat{LaTeX2e}[2022/06/01] \ProvidesExplPackage {pkginfograb} {2025/10/21} {1.0} {Collecting~ package's~ info~ in~ a~ regular~ way} %%%%%%% %%% %%% Just an attempt of having packages info in a regular way %%% \pkginfograb_set:nn {} { props} for each and all. %%% %%%%%%% \cs_new_protected:Npn \pkginfograb_set:nn #1#2 { \prop_new_linked:c {l__pkginfograb_ #1 _prop} \prop_set_from_keyval:cn {l__pkginfograb_ #1 _prop} { #2 } } %%%%%%%%% %%% %%% self info %%% %%%%%%%%% \pkginfograb_set:nn {pkginfograb} { name = {pkginfograb} , prefix = {pkginfograb} , date = {2025/10/21}, version = {1.0} , description = {Collecting~ package's~ info~ in~ a~ regular~ way} } %%%%%%%%% %%%%%%%%% \cs_new_protected:Npn \pkginfograb_get:nn #1#2 { \prop_if_exist:cT { l__pkginfograb_ #1 _prop } { \prop_item:cn { l__pkginfograb_ #1 _prop } {#2} } } \cs_new_protected:Npn \pkginfograb_get:nnN #1#2#3 { \prop_if_exist:cTF { l__pkginfograb_ #1 _prop } { \prop_get:cnNF { l__pkginfograb_ #1 _prop } { #2 } #3 { \tl_clear:N #3 } } { \tl_clear:N #3 } } \cs_new_protected:Npn \pkginfograb_description:n #1 { \prop_if_exist:cTF { l__pkginfograb_ #1 _prop } { \par\noindent Package~ \textbf{\pkginfograb_get:nn{#1}{name}}~ Version:~\pkginfograb_get:nn{#1}{version}~ -~ \pkginfograb_get:nn{#1}{date} \par \emph{\pkginfograb_get:nn{#1}{description}}~\par } { \par \textbf{#1}'s~info~not~defined.\par } } %%%%%%%%%% %%%%%%%%%% ARGH... below follows version testing... %%%%%%%%%% \msg_new:nnnn {pkginfograb} {requires} { #1~requires~ #2~ version ~ #3~ or~ newer } { Package~#1~ requires~ at~ least~ version ~#3 ~ from ~ package ~ #2. } \msg_new:nnnn {pkginfograb} {version format} { Invalid~ version~ format:~ #1.~ Should~be~[v]digits[~.~digits[~.~digits]][letters] } { Invalid~ version~ format:~ #1.~ Should~be~[v]digits[~.~digits[~.~digits]][letters] } \msg_new:nnnn {pkginfograb} {date format} { Invalid~ date~ format:~ #1.~ Should~be~YYYY/MM/DD~or~YYYY-MM-DD~or~YYYY.MM.DD } { Invalid~ date~ format:~ #1.~ Should~be~YYYY/MM/DD~or~YYYY-MM-DD~or~YYYY.MM.DD } \tl_new:N \l__pkginfograb_tmpa_tl \tl_new:N \l__pkginfograb_tmpb_tl \tl_new:N \l__pkginfograb_tmpc_tl \tl_new:N \l__pkginfograb_tmpd_tl \seq_new:N \l__pkginfograb_tmpa_seq \seq_new:N \l__pkginfograb_tmpb_seq \cs_new_protected:Npn \pkginfograb_req_version:nnn #1#2#3 { \prop_if_exist:cTF { l__pkginfograb_ #2 _prop } { \pkginfograb_get:nnN {#2}{version}\l__pkginfograb_tmpa_tl \__pkginfograb_regex_split:VNTF \l__pkginfograb_tmpa_tl \l__pkginfograb_tmpa_seq { \__pkginfograb_regex_split:nNTF {#3} \l__pkginfograb_tmpb_seq { \__pkginfograb_req_version:TF {} % OK, nothing to be done { \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3} } } { \msg_error:nnn {pkginfograb}{version format}{#3} } } { \msg_error:nnV {pkginfograb}{version format} \l__pkginfograb_tmpa_tl } } { \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3} } } %% %% This will match %% versionA: [v]{digit]}[letters] %% versionB: [v]{digit.digit}[letters] %% versionC: [v]{digit.digit.digit}[letters] %% so that each regex has 5 capturing groups %% %% \regex_const:Nn \l__pkginfograb_versionA_regex {\A(v?)(\d+)(\d*)(\d*)([a-zA-Z]*)\Z} \regex_const:Nn \l__pkginfograb_versionB_regex {\A(v?)(\d+)\.(\d+)(\d*)([a-zA-Z]*)\Z} \regex_const:Nn \l__pkginfograb_versionC_regex {\A(v?)(\d+)\.(\d+)\.(\d+)([a-zA-Z]*)\Z} \prg_new_protected_conditional:Npnn \__pkginfograb_regex_split:nN #1#2 {TF} { \regex_split:NnNTF \l__pkginfograb_versionA_regex {#1} #2 { \prg_return_true: } { \regex_split:NnNTF \l__pkginfograb_versionB_regex {#1} #2 { \prg_return_true: } { \regex_split:NnNTF \l__pkginfograb_versionC_regex {#1} #2 { \prg_return_true: } { \prg_return_false: } } } } \prg_generate_conditional_variant:Nnn \__pkginfograb_regex_split:nN {V} {TF} \prg_generate_conditional_variant:Nnn \fp_compare:nNn {VNV}{TF} \prg_generate_conditional_variant:Nnn \str_compare:nNn {VNV}{TF} \prg_new_protected_conditional:Npnn \__pkginfograb_req_version: {TF} { \__pkginfograb_build_version:NNN \l__pkginfograb_tmpa_seq \l__pkginfograb_tmpc_tl \l__pkginfograb_tmpa_tl \__pkginfograb_build_version:NNN \l__pkginfograb_tmpb_seq \l__pkginfograb_tmpd_tl \l__pkginfograb_tmpb_tl \fp_compare:VNVTF \l__pkginfograb_tmpc_tl < \l__pkginfograb_tmpd_tl { \prg_return_false: } { \fp_compare:VNVTF \l__pkginfograb_tmpc_tl = \l__pkginfograb_tmpd_tl { \str_compare:VNVTF \l__pkginfograb_tmpa_tl < \l__pkginfograb_tmpb_tl { \prg_return_false: } { \prg_return_true: } } { \prg_return_true: } } } \tl_new:N \l__pkginfograb_tmpx_tl \cs_new_protected:Npn \__pkginfograb_build_version:NNN #1#2#3 { \seq_pop_left:NN #1 \l__pkginfograb_tmpx_tl \seq_pop_left:NN #1 \l__pkginfograb_tmpx_tl \seq_pop_right:NN #1 \l__pkginfograb_tmpx_tl \seq_pop_right:NN #1 #3 \tl_set:Ne #2 { \seq_format:Nn #1 {0>5} } } \prg_new_protected_conditional:Npnn \__pkginfograb_req_date: {TF} { \__pkginfograb_build_date:NN \l__pkginfograb_tmpa_seq \l__pkginfograb_tmpc_tl \__pkginfograb_build_date:NN \l__pkginfograb_tmpb_seq \l__pkginfograb_tmpd_tl \fp_compare:VNVTF \l__pkginfograb_tmpc_tl < \l__pkginfograb_tmpd_tl { \prg_return_false: } { \prg_return_true: } } \cs_new_protected:Npn \__pkginfograb_build_date:NN #1#2 { \seq_pop_left:NN #1 \l__pkginfograb_tmpx_tl \seq_pop_right:NN #1 \l__pkginfograb_tmpx_tl \tl_set:Ne #2 { \seq_format:Nn #1 {0>2} } } \regex_const:Nn \l__pkginfograb_date_regex {\A(\d\d\d\d)[/\-\.](\d\d?)[/\-\.](\d\d?)\Z} \cs_new_protected:Npn \pkginfograb_req_date:nnn #1#2#3 { \prop_if_exist:cTF { l__pkginfograb_ #2 _prop } { \pkginfograb_get:nnN {#2}{date}\l__pkginfograb_tmpa_tl \regex_split:NVNTF \l__pkginfograb_date_regex \l__pkginfograb_tmpa_tl \l__pkginfograb_tmpa_seq { \regex_split:NnNTF \l__pkginfograb_date_regex {#3} \l__pkginfograb_tmpb_seq { \__pkginfograb_build_date:NN \l__pkginfograb_tmpa_seq \l__pkginfograb_tmpc_tl \__pkginfograb_build_date:NN \l__pkginfograb_tmpb_seq \l__pkginfograb_tmpd_tl \fp_compare:VNVTF \l__pkginfograb_tmpc_tl < \l__pkginfograb_tmpd_tl { \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3} } {} % OK, nothing to be done } { \msg_error:nnn {pkginfograb}{date format}{#3} } } { \msg_error:nnV {pkginfograb}{date format} \l__pkginfograb_tmpa_tl } } { \msg_error:nnnnn {pkginfograb}{requires}{#1}{#2}{#3} } } %% just in case one wishes to use this in a LaTeX2e context. \cs_new_protected:Npn \pkginfograb_set_aliases: { \cs_set_eq:NN \PkgInfoSet \pkginfograb_set:nn \cs_set_eq:NN \PkgInfo \pkginfograb_get:nn \cs_set_eq:NN \PkgInfoGet \pkginfograb_get:nnN \cs_set_eq:NN \PkgInfoDescription \pkginfograb_description:n \cs_set_eq:NN \PkgInfoReqVersion \pkginfograb_req_version:nnn \cs_set_eq:NN \PkgInfoReqDate \pkginfograb_req_date:nnn } \cs_new_eq:NN \PkgInfoSetAliases \pkginfograb_set_aliases: