diff options
Diffstat (limited to 'Master/texmf-dist/tex/latex/datatool/datatool.sty')
-rw-r--r-- | Master/texmf-dist/tex/latex/datatool/datatool.sty | 3419 |
1 files changed, 2401 insertions, 1018 deletions
diff --git a/Master/texmf-dist/tex/latex/datatool/datatool.sty b/Master/texmf-dist/tex/latex/datatool/datatool.sty index 099417295be..6925836a74c 100644 --- a/Master/texmf-dist/tex/latex/datatool/datatool.sty +++ b/Master/texmf-dist/tex/latex/datatool/datatool.sty @@ -7,7 +7,7 @@ %% datatool.dtx (with options: `datatool.sty,package') %% %% datatool.dtx -%% Copyright 2007 Nicola Talbot +%% Copyright 2009 Nicola Talbot %% %% This work may be distributed and/or modified under the %% conditions of the LaTeX Project Public License, either version 1.3 @@ -39,12 +39,13 @@ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{datatool}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{datatool}[2009/02/27 v2.0 (NLCT)] \RequirePackage{xkeyval} \RequirePackage{ifthen} \RequirePackage{xfor} \RequirePackage{fp} \RequirePackage{substr} +\RequirePackage{etex} \newcommand*{\@dtl@separator}{,} \newcommand*{\DTLsetseparator}[1]{% \renewcommand*{\@dtl@separator}{#1}% @@ -1220,32 +1221,16 @@ \@dtl@dovalue } \newcommand{\DTLiffirstrow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLiffirstrow\space can only - be used inside \string\DTLforeach}{}% -\else -\expandafter\ifnum\csname c@DTLrow\romannumeral -\dtlforeachlevel\endcsname -=1\relax#1\else#2\fi -\fi} + \PackageError{datatool}{\string\DTLiffirstrow\space can only + be used inside \string\DTLforeach}{}% +} \newcommand{\DTLiflastrow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLiflastrow\space can only - be used inside \string\DTLforeach}{}% -\else -\ifx\@dtl@nextrow\@nnil -#1\else #2\fi -\fi + \PackageError{datatool}{\string\DTLiflastrow\space can only + be used inside \string\DTLforeach}{}% } \newcommand{\DTLifoddrow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLifoddrow\space can only - be used inside \string\DTLforeach}{}% -\else -\expandafter\ifodd\csname c@DTLrow\romannumeral -\dtlforeachlevel\endcsname -#1\else #2\fi -\fi + \PackageError{datatool}{\string\DTLifoddrow\space can only + be used inside \string\DTLforeach}{}% } \newif\if@dtl@condition \newcommand*{\dtl@testlt}[2]{% @@ -1373,145 +1358,808 @@ \TE@throw\noexpand\dtl@testcurrencyunit{#1}{#2}% \noexpand\if@dtl@condition} \newcommand*{\DTLnewdb}[1]{% -\DTLifdbexists{#1}{% -\PackageError{datatool}{Database `#1' already exists}{}}{% -\dtl@message{Creating database `#1'}% -\expandafter\gdef\csname dtldb@#1\endcsname{}% -\expandafter\gdef\csname dtlkeys@#1\endcsname{}% -\expandafter\global\expandafter\newcount\csname dtlrows@#1\endcsname}} + \DTLifdbexists{#1}% + {% + \PackageError{datatool}{Database `#1' already exists}{}% + }% + {% + \dtl@message{Creating database `#1'}% + \expandafter\newtoks\csname dtldb@#1\endcsname + \expandafter\newtoks\csname dtlkeys@#1\endcsname{}% + \expandafter\newcount\csname dtlrows@#1\endcsname + \expandafter\newcount\csname dtlcols@#1\endcsname + }% +} \newcommand*{\DTLrowcount}[1]{% \expandafter\number\csname dtlrows@#1\endcsname} +\newcommand*{\DTLcolumncount}[1]{% +\expandafter\number\csname dtlcols@#1\endcsname} \newcommand{\DTLifdbempty}[3]{% -\DTLifdbexists{#1}{% -\expandafter\ifx\csname dtldb@#1\endcsname\@empty - #2% -\else - #3% -\fi}{% -\PackageError{Database `#1' doesn't exist}{}{}}} -\newcommand*{\DTLnewrow}[1]{% -\DTLifdbempty{#1}{% - \expandafter\gdef\csname dtldb@#1\endcsname{{}}% - \expandafter\global\expandafter\advance - \csname dtlrows@#1\endcsname by 1\relax - \dtl@message{New row added to database `#1'}% -}{% - \expandafter\let\expandafter\@dtl@olddb\csname dtldb@#1\endcsname% - \expandafter\toks@\expandafter{\@dtl@olddb,{}}% - \expandafter\xdef\csname dtldb@#1\endcsname{\the\toks@}% - \expandafter\global\expandafter\advance - \csname dtlrows@#1\endcsname by 1\relax + \DTLifdbexists{#1}% + {\@DTLifdbempty{#1}{#2}{#3}}% + {\PackageError{Can't check if database `#1' is empty: + database doesn't exist}{}{}}% +} +\newcommand{\@DTLifdbempty}[3]{% + \expandafter\ifnum\csname dtlrows@#1\endcsname=0\relax + #2% + \else + #3% + \fi +} +\newcommand*{\DTLnewrow}{% + \@ifstar\@sDTLnewrow\@DTLnewrow +} +\newcommand*{\@DTLnewrow}[1]{% +\DTLifdbexists{#1}% + {\@sDTLnewrow{#1}}% + {\PackageErrors{datatool}{Can't add new row to database `#1': + database doesn't exist}{}}% +} +\newcommand*{\@sDTLnewrow}[1]{% + \global\advance\csname dtlrows@#1\endcsname by 1\relax + \toks@gput@right@cx{dtldb@#1}{% + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname + \noexpand\db@row@id@end@% + \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname + \noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + }% \dtl@message{New row added to database `#1'}% -}} -\newcommand{\DTLnewdbentry}[3]{% -\@dtl@toks{#3}% -\edef\@dtl@dbvalue{\the\@dtl@toks}% -\edef\@dtl@dbid{#2}% -\edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% -\DTLifdbempty{#1}{\DTLnewrow{#1}}{}% -\expandafter\dtl@choplast\expandafter{% -\csname dtldb@#1\endcsname}{\@dtl@dbrest}{\@dtl@dblastrow}% -\dtl@ifrowcontains{#2}{\@dtl@dblastrow}{% -\PackageError{datatool}{Can't add entry with ID `#2' to current -row of database `#1'}{There is already an entry with this ID on -the current row}}{% -\expandafter\@dtl@toks\expandafter{\@dtl@dbentry}% -\ifthenelse{\equal{}{\@dtl@dblastrow}}{% - \edef\@dtl@dblastrow{\the\@dtl@toks}% -}{% - \expandafter\toks@\expandafter{\@dtl@dblastrow}% - \edef\@dtl@dblastrow{\the\toks@,\the\@dtl@toks}% -}% -\expandafter\@dtl@toks\expandafter{\@dtl@dblastrow}% -\ifthenelse{\equal{}{\@dtl@dbrest}}{% - \expandafter\long\expandafter\xdef\csname dtldb@#1\endcsname{% - {\the\@dtl@toks}}% -}{% - \expandafter\toks@\expandafter{\@dtl@dbrest}% - \expandafter\long\expandafter\xdef\csname dtldb@#1\endcsname{% - \the\toks@,{\the\@dtl@toks}}% -}% -\@dtl@setidtype{#1}{#2}{#3}% -\expandafter\@dtl@setkeys\expandafter{#2}{#1}% -}% -\dtl@message{Added #2\space -> #3\space to database `#1'}% } -\newcommand{\@dtl@setidtype}[3]{% -\@dtl@checknumerical{#3}% -\def\@dtl@value{#3}% -\@ifundefined{@dtl@idtype@#1@#2}{% -\ifx\@dtl@value\@empty - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{}% -\else - \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% - \the\@dtl@datatype}% -\fi -}{% -\ifx\@dtl@value\@empty -\else - \expandafter\ifx\csname @dtl@idtype@#1@#2\endcsname\@empty - \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% - \the\@dtl@datatype}% - \else - \expandafter\@dtl@tmpcount\expandafter= - \csname @dtl@idtype@#1@#2\endcsname\relax - \ifcase\@dtl@tmpcount - \or - \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% - \the\@dtl@datatype}% - \or - \ifnum\@dtl@datatype=0\relax - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{0}% +\newcount\dtlcolumnnum +\newcount\dtlrownum +\newcommand*{\DTLifhaskey}{\@ifstar\@sDTLifhaskey\@DTLifhaskey} +\newcommand{\@DTLifhaskey}[4]{% + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}{#3}{#4}% + }% + {% + \PackageError{datatool}{Database `#1' doesn't exist}{}% + }% +} +\newcommand{\@sDTLifhaskey}[4]{% + \@ifundefined{dtl@ci@#1@#2}% + {% + #4% + }% + {% + #3% + }% +} +\newcommand*{\DTLgetcolumnindex}{% + \@ifstar\@sdtl@getcolumnindex\@dtl@getcolumnindex +} +\newcommand*{\@dtl@getcolumnindex}[3]{% + \DTLifdbexists{#2}% + {% + \@sDTLifhaskey{#2}{#3}% + {% + \@sdtl@getcolumnindex{#1}{#2}{#3}% + }% + {% + \PackageError{datatool}{Database `#2' doesn't contain + key `#3'}{}% + }% + }% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} +\newcommand*{\@sdtl@getcolumnindex}[3]{% + \expandafter\let\expandafter#1\csname dtl@ci@#2@#3\endcsname +} +\newcommand*{\dtl@columnindex}[2]{% + \csname dtl@ci@#1@#2\endcsname +} +\newcommand*{\DTLgetkeyforcolumn}{% + \@ifstar\@sdtlgetkeyforcolumn\@dtlgetkeyforcolumn} +\newcommand*{\@dtlgetkeyforcolumn}[3]{% + \DTLifdbexists{#2}% + {% + \ifnum#3<1\relax + \PackageError{datatool}{Invalid column index \number#3}{% + Column indices start at 1}% + \else + \expandafter\ifnum\csname dtlcols@#2\endcsname<#3\relax + \PackageError{datatool}{Index \number#3\space out of + range for database `#2'}{Database `#2' only has + \expandafter\number\csname dtlcols@#2\endcsname\space + columns}% \else - \ifnum\@dtl@datatype=3\relax - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{3}% - \else - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{2}% + \@sdtlgetkeyforcolumn{#1}{#2}{#3}% + \fi + \fi + }% + {% + \PackageError{datatool}{Database `#2' doesn't exists}{}% + }% +} +\newcommand*{\@sdtlgetkeyforcolumn}[3]{% + \edef\@dtl@dogetkeyforcolumn{\noexpand\@dtl@getkeyforcolumn + {\noexpand#1}{#2}{\number#3}}% + \@dtl@dogetkeyforcolumn +} +\newcommand*{\@dtl@getkeyforcolumn}[3]{% + \def\@dtl@get@keyforcolumn##1% before stuff + \db@plist@elt@w% start of block + \db@col@id@w #3\db@col@id@end@% index + \db@key@id@w ##2\db@key@id@end@% key + \db@type@id@w ##3\db@type@id@end@% data type + \db@header@id@w ##4\db@header@id@end@% header + \db@col@id@w #3\db@col@id@end@% index + \db@plist@elt@end@% end of block + ##5\q@nil{\def#1{##2}}% + \edef\@dtl@tmp{\expandafter\the\csname dtldb@#2\endcsname}% + \expandafter\@dtl@getkeyforcolumn\@dtl@tmp + \db@plist@elt@w% start of block + \db@col@id@w #3\db@col@id@end@ index + \db@key@id@w \@nil\db@key@id@end@% key + \db@type@id@w \db@type@id@end@% data type + \db@header@id@w \db@header@id@end@% header + \db@col@id@w #3\db@col@id@end@% index + \db@plist@elt@end@% end of block + \q@nil +} +\def\DTLunsettype{} +\def\DTLstringtype{0} +\def\DTLinttype{1} +\def\DTLrealtype{2} +\def\DTLcurrencytype{3} +\newcommand*{\DTLgetdatatype}{% + \@ifstar\@sdtlgetdatatype\@dtlgetdatatype +} +\newcommand*{\@dtlgetdatatype}[3]{% + \DTLifdbexists{#2}% + {% + \@sDTLifhaskey{#2}{#3}% + {% + \@sdtlgetdatatype{#1}{#2}{#3}% + }% + {% + \PackageError{datatool}{Key `#3' undefined in database `#2'}{}% + }% + }% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} +\newcommand*{\@sdtlgetdatatype}[3]{% + \edef\@dtl@dogetdata{\noexpand\@dtl@getdatatype{\noexpand#1}% + {\expandafter\the\csname dtlkeys@#2\endcsname}% + {\dtl@columnindex{#2}{#3}}}% + \@dtl@dogetdata +} +\newcommand*{\@dtl@getdatatype}[3]{% + \def\@dtl@get@keydata##1% stuff before + \db@plist@elt@w% start of key block + \db@col@id@w #3\db@col@id@end@% column index + \db@key@id@w ##2\db@key@id@end@% key id + \db@type@id@w ##3\db@type@id@end@% data type + \db@header@id@w ##4\db@header@id@end@% header + \db@col@id@w #3\db@col@id@end@% column index + \db@plist@elt@end@% end of key block + ##5% stuff afterwards + \q@nil{\def#1{##3}}% + \@dtl@get@keydata#2\q@nil +} +\newcommand*{\@dtl@getprops}[7]{% + \def\@dtl@get@keydata##1% stuff before + \db@plist@elt@w% start of key block + \db@col@id@w #7\db@col@id@end@% column index + \db@key@id@w ##2\db@key@id@end@% key id + \db@type@id@w ##3\db@type@id@end@% data type + \db@header@id@w ##4\db@header@id@end@% header + \db@col@id@w #7\db@col@id@end@% column index + \db@plist@elt@end@% end of key block + ##5% stuff afterwards + \q@nil{% + \def#1{##2}% key + \def#2{##3}% data type + #3={##4}% header + #4={##1}% before stuff + #5={##5}% after stuff + }% + \@dtl@get@keydata#6\q@nil +} +\newtoks\@dtl@before +\newtoks\@dtl@after +\newtoks\@dtl@colhead +\newcommand*{\@dtl@updatekeys}[3]{% + \@sDTLifhaskey{#1}{#2}% + {% + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{#1}{#2}\relax + \edef\@dtl@dogetprops{\noexpand\@dtl@getprops + {\noexpand\@dtl@key}{\noexpand\@dtl@type}% + {\noexpand\@dtl@colhead}{\noexpand\@dtl@before}% + {\noexpand\@dtl@after}{\the\csname dtlkeys@#1\endcsname}% + {\number\dtlcolumnnum}} + \@dtl@dogetprops + \def\@dtl@tmp{#3}% + \ifx\@dtl@tmp\@empty + \else + \let\@dtl@oldtype\@dtl@type + \@dtl@checknumerical{#3}% + \ifx\@dtl@type\@empty + \edef\@dtl@type{\number\@dtl@datatype}% + \else + \ifcase\@dtl@datatype % string + \def\@dtl@type{0}% + \or % int + \or % real + \ifnum\@dtl@type=1\relax + \def\@dtl@type{2}% + \fi + \or % currency + \ifnum\@dtl@type>0\relax + \def\@dtl@type{3}% + \fi \fi \fi - \or - \ifnum\@dtl@datatype=0\relax - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{0}% + \ifx\@dtl@oldtype\@dtl@type \else - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{3}% + \toks@gconcat@middle@cx{dtlkeys@#1}% + {\@dtl@before}% + {% + \noexpand\db@plist@elt@w% start of key block + \noexpand\db@col@id@w \the\dtlcolumnnum + \noexpand\db@col@id@end@% column index + \noexpand\db@key@id@w #2\noexpand\db@key@id@end@% key id + \noexpand\db@type@id@w \@dtl@type + \noexpand\db@type@id@end@% data type + \noexpand\db@header@id@w \the\@dtl@colhead + \noexpand\db@header@id@end@% header + \noexpand\db@col@id@w \the\dtlcolumnnum + \noexpand\db@col@id@end@% column index + \noexpand\db@plist@elt@end@% end of key block + }% + {\@dtl@after}% \fi \fi - \fi -\fi -}% + }% + {% + \expandafter\global\expandafter\advance + \csname dtlcols@#1\endcsname by 1\relax + \dtlcolumnnum=\csname dtlcols@#1\endcsname\relax + \expandafter\xdef\csname dtl@ci@#1@#2\endcsname{% + \number\dtlcolumnnum}% + \def\@dtl@tmp{#3}% + \ifx\@dtl@tmp\@empty + \edef\@dtl@type{}% don't know data type yet + \else + \@dtl@checknumerical{#3}% + \edef\@dtl@type{\number\@dtl@datatype}% + \fi + \toks@gput@right@cx{dtlkeys@#1}% + {% + \noexpand\db@plist@elt@w + \noexpand\db@col@id@w \the\dtlcolumnnum + \noexpand\db@col@id@end@ + \noexpand\db@key@id@w #2\noexpand\db@key@id@end@ + \noexpand\db@type@id@w \@dtl@type + \noexpand\db@type@id@end@ + \noexpand\db@header@id@w #2\noexpand\db@header@id@end@ + \noexpand\db@col@id@w \the\dtlcolumnnum + \noexpand\db@col@id@end@ + \noexpand\db@plist@elt@end@ + }% + }% } -\newcommand*{\@dtl@setkeys}[2]{% -\edef\@dtl@tmp{\csname dtlkeys@#2\endcsname}% -\expandafter\@dtl@toks\expandafter{\@dtl@tmp}% -\expandafter\ifx\csname dtlkeys@#2\endcsname\@empty - \expandafter\gdef\csname dtlkeys@#2\endcsname{#1}% -\else - \@for\dtl@key:=\@dtl@tmp\do{% - \ifthenelse{\equal{\dtl@key}{#1}}{\@endfortrue}{}% +\newcommand*{\DTLsetheader}{\@ifstar\@sDTLsetheader\@DTLsetheader} +\newcommand*{\@DTLsetheader}[3]{% + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}% + {% + \@sDTLsetheader{#1}{#2}{#3}% + }% + {% + \PackageError{datatool}{Database `#1' doesn't contain key + `#2'}{}% + }% + }% + {% + \PackageError{datatool}{Database `#1' doesn't exist}{}% + }% +} +\newcommand*{\@sDTLsetheader}[3]{% + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{#1}{#2}\relax + \@dtl@setheaderforindex{#1}{\dtlcolumnnum}{#3}% +} +\newcommand*{\@dtl@setheaderforindex}[3]{% + \edef\@dtl@dogetprops{\noexpand\@dtl@getprops + {\noexpand\@dtl@key}{\noexpand\@dtl@type}% + {\noexpand\@dtl@colhead}{\noexpand\@dtl@before}% + {\noexpand\@dtl@after}{\the\csname dtlkeys@#1\endcsname}% + {\number#2}} + \@dtl@dogetprops + \@dtl@colhead={#3}% + \edef\@dtl@colnum{\number#2}\relax + \toks@gconcat@middle@cx{dtlkeys@#1}% + {\@dtl@before}% + {% + \noexpand\db@plist@elt@w% start of block + \noexpand\db@col@id@w \@dtl@colnum + \noexpand\db@col@id@end@% index + \noexpand\db@key@id@w \@dtl@key\noexpand\db@key@id@end@% key + \noexpand\db@type@id@w \@dtl@type + \noexpand\db@type@id@end@% data type + \noexpand\db@header@id@w \the\@dtl@colhead + \noexpand\db@header@id@end@% header + \noexpand\db@col@id@w \@dtl@colnum + \noexpand\db@col@id@end@% index + \noexpand\db@plist@elt@end@% end of block }% - \if@endfor + {\@dtl@after}% +} +\newcommand{\DTLnewdbentry}{% + \@ifstar\@sDTLnewdbentry\@DTLnewdbentry +} +\newcommand{\@DTLnewdbentry}[3]{% + \DTLifdbexists{#1}% + {\@sDTLnewdbentry{#1}{#2}{#3}}% + {\PackageError{datatool}{Can't add new entry to database `#1': + database doesn't exist}{}}% +} +\newcommand*{\@sDTLnewdbentry}[3]{% + \@dtl@updatekeys{#1}{#2}{#3}% + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{#1}{#2}\relax + \edef\dtl@dogetrow{\noexpand\dtlgetrow{#1}% + {\number\csname dtlrows@#1\endcsname}}% + \dtl@dogetrow + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% + }% + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue + \@dtl@toks{#3}% + \toks@gconcat@middle@cx{dtldb@#1}% + {\dtlbeforerow}% + {% + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname + \noexpand\db@row@id@end@% + \the\dtlcurrentrow + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@% + \noexpand\db@col@elt@w \the\@dtl@toks + \noexpand\db@col@elt@end@% + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@% + \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname + \noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + }% + {\dtlafterrow}% + \dtl@message{Added #2\space -> #3\space to database `#1'}% \else - \expandafter\xdef\csname dtlkeys@#2\endcsname{\the\@dtl@toks,#1}% + \PackageError{datatool}{Can't add entry with ID `#2' to + current row of database `#1'}{There is already an entry with + this ID in the current row}% \fi -\fi } -\newcommand*{\@dtl@getidtype}[2]{% -\csname @dtl@idtype@#1@#2\endcsname} \newcommand{\DTLifdbexists}[3]{% -\@ifundefined{dtldb@#1}{#3}{#2}} -\newcommand{\dtl@ifrowcontains}[4]{% -\@for\@dtl@element:=#2\do{% -\dtl@getentryid{\@dtl@element}{\@dtl@entryid}% -\ifthenelse{\equal{#1}{\@dtl@entryid}}{\@endfortrue}{}% -}% -\if@endfor #3\else #4\fi -} -\newcommand*{\dtl@getentryid}[2]{\expandafter\@dtl@getentryid#1#2} -\long\def\@dtl@getentryid#1#2#3{\def#3{#1}} -\newcommand*{\dtl@getentryvalue}[2]{% -\expandafter\@dtl@getentryvalue#1#2} -\long\def\@dtl@getentryvalue#1#2#3{\gdef#3{#2}} -\global\newcount\dtlforeachlevel + \@ifundefined{dtldb@#1}{#3}{#2}} +\newcommand*{\@dtl@assign}[2]{% + \@dtl@assigncmd#1,\@nil\@@{#2}% +} +\def\@dtl@assigncmd#1=#2,#3\@@#4{% + \@sDTLifhaskey{#4}{#2}% + {% + \edef\@dtl@dogetentry{% + \noexpand\dtlgetentryfromcurrentrow + {\noexpand#1}{\dtl@columnindex{#4}{#2}}}% + \@dtl@dogetentry + \ifx#1\dtlnovalue + \@@dtl@setnull{#1}{#2}% + \fi + \global\let#1=#1\relax + }% + {% + \PackageError{datatool}{Can't assign \string#1\space: there + is no key `#2' in data base `#4'}{}% + \global\let#1\DTLstringnull + }% + \def\dtl@tmp{#3}% + \ifx\@nnil\dtl@tmp + \let\@dtl@next\@dtl@assigncmdnoop + \else + \let\@dtl@next\@dtl@assigncmd + \fi + \@dtl@next#3\@@{#4}% +} +\def\@dtl@assigncmdnoop#1\@@#2{} +\newcommand*{\@dtl@setnull}[2]{% + \@sDTLifhaskey{\@dtl@dbname}{#2}% + {% + \@@dtl@setnull{#1}{#2}% + }% + {% + \global\let#1=\DTLstringnull + }% +} +\newcommand*{\@@dtl@setnull}[2]{% + \@sdtlgetdatatype{\@dtl@type}{\@dtl@dbname}{#2}% + \ifnum0\@dtl@type=0\relax + \global\let#1=\DTLstringnull + \else + \global\let#1=\DTLnumbernull + \fi +} +\newcommand*{\DTLstringnull}{NULL} +\newcommand*{\DTLnumbernull}{0} +\newcommand*{\DTLifnull}[3]{% + \ifx\DTLstringnull#1\relax + #2% + \else + \ifx\DTLnumbernull#1\relax + #2% + \else + #3% + \fi + \fi +} +\def\@dtlnovalue{Undefined Value} +\def\dtlnovalue{\@dtlnovalue} +\newcommand*{\DTLgetkeydata}{% + \@ifstar\@sdtlgetkeydata\@dtlgetkeydata +} +\newcommand*{\@dtlgetkeydata}[5]{% + \DTLifdbexists{#2}% + {% + \@sDTLifhaskey{#2}{#1}% + {% + \@sdtlgetkeydata{#1}{#2}{#3}{#4}{#5}% + }% + {% + \PackageError{datatool}{Key `#1' not defined in database + `#2'}{}% + }% + }% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} +\newcommand*{\@sdtlgetkeydata}[5]{% + \@sdtl@getcolumnindex{#3}{#2}{#1}% + \edef\@dtl@dogetkeydata{\noexpand\@dtl@getprops + {\noexpand\@dtl@key}{\noexpand#4}{\noexpand\@dtl@colhead}% + {\noexpand\@dtl@before}{\noexpand\@dtl@after}% + {\expandafter\the\csname dtlkeys@#2\endcsname}% + {#3}}% + \@dtl@dogetkeydata + \edef#5{\the\@dtl@toks}% +} +\newcommand{\dtl@gathervalues}[3][key]{% + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#2}\do + {% + \dtlgetentryfromrow{\@dtl@tmp}{\@dtl@col}{\dtlcurrentrow}% + \ifx\@dtl@tmp\dtlnovalue + \@dtl@setnull{\@dtl@tmp}{\@dtl@key}% + \fi + \expandafter\let\csname @dtl@#1@\@dtl@key\endcsname\@dtl@tmp + }% +} +\newtoks\dtlcurrentrow +\newtoks\dtlbeforerow +\newtoks\dtlafterrow +\newcommand*{\dtlgetrow}[2]{% + \expandafter\toks@\expandafter=\csname dtldb@#1\endcsname + \edef\@dtl@dogetrow{\noexpand\@dtlgetrow{\the\toks@}{\number#2}}% + \@dtl@dogetrow +} +\newcommand*{\@dtlgetrow}[2]{% + \def\@dtl@getrow##1% before stuff + \db@row@elt@w% start of the row + \db@row@id@w #2\db@row@id@end@% row id + ##2% + \db@row@id@w #2\db@row@id@end@% row id + \db@row@elt@end@% end of the row + ##3% after stuff + \q@nil{\dtlbeforerow={##1}\dtlcurrentrow={##2}\dtlafterrow={##3}}% + \@dtl@getrow#1\q@nil +} +\newcommand*{\dtlgetentryfromcurrentrow}[2]{% + \dtlgetentryfromrow{#1}{#2}{\dtlcurrentrow}% +} +\newcommand*{\dtlgetentryfromrow}[3]{% + \edef\@dtl@do@getentry{\noexpand\dtl@getentryfromrow + {\noexpand#1}{\number#2}{\the#3}}% + \@dtl@do@getentry +} +\newcommand*{\dtl@getentryfromrow}[3]{% + \def\dtl@dogetentry##1% before stuff + \db@col@id@w #2\db@col@id@end@% Column id + \db@col@elt@w ##2\db@col@elt@end@% Value + \db@col@id@w #2\db@col@id@end@% Column id + ##3% Remaining stuff + \q@nil{\def#1{##2}}% + \dtl@dogetentry#3% + \db@col@id@w #2\db@col@id@end@% + \db@col@elt@w \@dtlnovalue\db@col@elt@end@% + \db@col@id@w #2\db@col@id@end@% + \q@nil +} +\newcommand*{\DTLgetvalue}[4]{% + \edef\dtl@dogetvalue{\noexpand\dtl@getvalue{\noexpand#1}{#2}% + {\number#3}{\number#4}}% + \dtl@dogetvalue +} +\newcommand*{\dtl@getvalue}[4]{% + \def\@dtl@getvalue ##1% stuff before row <r> + \db@row@id@w #3\db@row@id@end@% row <r> id + ##2% stuff in row <r> before column <c> + \db@col@id@w #4\db@col@id@end@% column <c> id + \db@col@elt@w ##3\db@col@elt@end@% value + ##4% stuff after value + \q@nil{\def#1{##3}}% + \toks@=\csname dtldb@#2\endcsname + \expandafter\@dtl@getvalue\the\toks@% contents of data base + \db@row@id@w #3\db@row@id@end@% + \db@col@id@w #4\db@col@id@end@% + \db@col@elt@w \@dtlnovalue\db@col@elt@end@% undefined value + \q@nil + \ifx#1\dtlnovalue + \PackageError{datatool}{There is no element at (row=#3, + column=#4) in database `#2'}{}% + \fi +} +\newcommand*{\DTLgetlocation}[4]{% + \def\@dtl@getlocation##1% stuff before value + \db@col@elt@w #4\db@col@elt@end@% value + \db@col@id@w ##2\db@col@id@end@% column id + ##3% stuff after this column + \db@row@id@w ##4\db@row@id@end@% row id + ##5% stuff after row + \q@nil{\def#1{##4}\def#2{##2}}% + \toks@=\csname dtldb@#3\endcsname + \expandafter\@dtl@getlocation\the\toks@% contents of data base + \db@col@elt@w #4\db@col@elt@end@% value + \db@col@id@w \@dtlnovalue\db@col@id@end@% undefined column id + \db@row@id@w \@dtlnovalue\db@row@id@end@% undefined row id + \q@nil + \ifx#1\dtlnovalue + \PackageError{datatool}{There is no element `#4' in + database `#3'}{}% + \fi +} + +\newcommand*{\dtlbreak}{% + \PackageError{datatool}{Can't break out of anything}{}% +} +\long\def\dtlforint#1=#2\to#3\step#4\do#5{% + \let\@dtl@orgbreak\dtlbreak + \def\@dtl@endloophook{}% + \def\dtlbreak{\def\@dtl@endloophook{#1=#3}}% + #1=#2\relax + \ifnum#4<0\relax + \whiledo{\(#1>#3\)\TE@or\(#1=#3\)}% + {% + #5% + \@dtl@endloophook + \advance#1 by #4\relax + }% + \else + \whiledo{\(#1<#3\)\TE@or\(#1=#3\)}% + {% + #5% + \@dtl@endloophook + \advance#1 by #4\relax + }% + \fi + \let\dtlbreak\@dtl@orgbreak +} +\newcount\@dtl@foreach@level +\long\def\dtlgforint#1=#2\to#3\step#4\do#5{% + \global#1=#2\relax + \global\advance\@dtl@foreach@level by 1\relax + \expandafter\global\expandafter + \let\csname @dtl@endhook@\the\@dtl@foreach@level\endcsname + \relax + \expandafter\global\expandafter + \let\csname @dtl@break@\the\@dtl@foreach@level\endcsname + \dtlbreak + \gdef\dtlbreak{\expandafter + \gdef\csname @dtl@endhook@\the\@dtl@foreach@level\endcsname{% + #1=#3}}% + \ifnum#4<0\relax + \whiledo{\(#1>#3\)\TE@or\(#1=#3\)}% + {% + #5% + \csname @dtl@endhook@\the\@dtl@foreach@level\endcsname + \global\advance#1 by #4\relax + }% + \else + \whiledo{\(#1<#3\)\TE@or\(#1=#3\)}% + {% + #5% + \csname @dtl@endhook@\the\@dtl@foreach@level\endcsname + \global\advance#1 by #4\relax + }% + \fi + \expandafter\global\expandafter\let\expandafter\dtlbreak + \csname @dtl@break@\the\@dtl@foreach@level\endcsname + \global\advance\@dtl@foreach@level by -1\relax +} +\long\def\@dtlforeachrow(#1,#2)\in#3\do#4{% + \edef\dtl@tmp{\expandafter\the\csname dtldb@#3\endcsname}% + \expandafter\@dtl@foreachrow\dtl@tmp + \db@row@elt@w% + \db@row@id@w \@nil\db@row@id@end@% + \db@row@id@w \@nil\db@row@id@end@% + \db@row@elt@end@% + \@@{#1}{#2}{#4}\q@nil +} +\long\def\@dtl@foreachrow\db@row@elt@w% +\db@row@id@w #1\db@row@id@end@% +#2\db@row@id@w #3\db@row@id@end@% +\db@row@elt@end@#4\@@#5#6#7\q@nil{% + \gdef#5{#1}% + \gdef\@dtl@loopbody{#7}% + \global\advance\@dtl@foreach@level by 1\relax + \ifx#5\@nnil + \expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachnoop + \else + \gdef#6{#2}% + \expandafter\let + \csname @dtl@break@\the\@dtl@foreach@level\endcsname + \dtlbreak + \gdef\dtlbreak{\expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachnoop}% + \expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachrow + \@dtl@loopbody + \expandafter\let\expandafter\dtlbreak + \csname @dtl@break@\the\@dtl@foreach@level\endcsname + \fi + \expandafter\let\expandafter\@dtl@foreachnext + \csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + \global\advance\@dtl@foreach@level by -1\relax + \@dtl@foreachnext#4\@@{#5}{#6}{#7}\q@nil +} +\long\def\@dtl@foreachnoop#1\@@#2\q@nil{} +\long\def\dtlforeachkey(#1,#2,#3,#4)\in#5\do#6{% + \gdef\@dtl@loopbody{#6}% + \edef\@dtl@keys{\expandafter\the\csname dtlkeys@#5\endcsname}% + \expandafter\@dtl@foreachkey\@dtl@keys + \db@plist@elt@w% + \db@col@id@w -1\db@col@id@end@% + \db@key@id@w \db@key@id@end@% + \db@type@id@w \db@type@id@end@% + \db@header@id@w \db@header@id@end@% + \db@col@id@w -1\db@col@id@end@% + \db@plist@elt@end@% + \@@{\@dtl@updatefkcs{#1}{#2}{#3}{#4}}\q@nil +} +\newcommand*{\@dtl@updatefkcs}[8]{% + \gdef#1{#5}% + \gdef#2{#6}% + \gdef#3{#7}% + \gdef#4{#8}% +} +\long\def\@dtl@foreachkey\db@plist@elt@w% +\db@col@id@w #1\db@col@id@end@% +\db@key@id@w #2\db@key@id@end@% +\db@type@id@w #3\db@type@id@end@% +\db@header@id@w #4\db@header@id@end@% +\db@col@id@w #5\db@col@id@end@% +\db@plist@elt@end@#6\@@#7\q@nil{% + \ifnum#1=-1\relax + \let\@dtl@foreachnext\@dtl@foreachnoop + \else + #7{#2}{#1}{#3}{#4}% + \global\advance\@dtl@foreach@level by 1\relax + \expandafter\let + \csname @dtl@break@\the\@dtl@foreach@level\endcsname + \dtlbreak + \gdef\dtlbreak{\expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachnoop}% + \expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachkey + \@dtl@loopbody + \expandafter\let\expandafter\@dtl@foreachnext + \csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + \expandafter\let\expandafter\dtlbreak + \csname @dtl@break@\the\@dtl@foreach@level\endcsname + \global\advance\@dtl@foreach@level by -1\relax + \fi + \@dtl@foreachnext#6\@@{#7}\q@nil +} +\newcommand*{\dtlforcolumn}{\@ifstar\@sdtlforcolumn\@dtlforcolumn} +\newcommand{\@dtlforcolumn}[4]{% + \DTLifdbexists{#2}% + {% + \@dtlifhaskey{#2}{#3}% + {% + \@sdtlforcolumn{#1}{#2}{#3}{#4}% + }% + {% + \PackageError{datatool}{Database `#2' doesn't contain + key `#3'}{}% + }% + }% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} +\newcommand{\@sdtlforcolumn}[4]{% + \toks@{#4}% + \edef\@dtl@doforcol{\noexpand\dtl@forcolumn{\noexpand#1}% + {\expandafter\the\csname dtldb@#2\endcsname}% + {\dtl@columnindex{#2}{#3}}{\the\toks@}% + }% + \@dtl@doforcol% +} +\newcommand*{\dtlforcolumnidx}{% + \@ifstar\@sdtlforcolumnidx\@dtlforcolumnidx +} +\newcommand{\@dtlforcolumnidx}[4]{% + \DTLifdbexists{#2}% + {% + \expandafter\ifnum\csname dtlcols@#2\endcsname<#3\relax + \PackageError{datatool}{Column index \number#3\space out of + bounds for database `#2'}{Database `#2' only has + \expandafter\number\csname dtlcols@#2\endcsname\space + columns}% + \else + \ifnum#3<1\relax + \PackageError{datatool}{Column index \number#3\space out of + bounds for database `#2'}{Indices start from 1}% + \else + \@sdtlforcolumnidx{#1}{#2}{#3}{#4}% + \fi + \fi + }% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} +\newcommand{\@sdtlforcolumnidx}[4]{% + \toks@{#4}% + \edef\@dtl@doforcol{\noexpand\dtl@forcolumn{\noexpand#1}% + {\expandafter\the\csname dtldb@#2\endcsname}% + {\number#3}{\the\toks@}% + }% + \@dtl@doforcol +} +\newcommand{\dtl@forcolumn}[4]{% + \let\@dtl@oldbreak\dtlbreak + \def\dtlbreak{\let\@dtl@forcolnext=\@dtl@forcolnoop}% + \def\@dtl@forcolumn##1% before stuff + \db@col@id@w #3\db@col@id@end@% column index + \db@col@elt@w ##2\db@col@elt@end@% entry + \db@col@id@w #3\db@col@id@end@% column index + ##3% after stuff + \q@nil{% + \def#1{##2}% assign value to <cs> + \ifx#1\@nnil + \let\@dtl@forcolnext=\@dtl@forcolnoop + \else + #4% + \let\@dtl@forcolnext=\@dtl@forcolumn + \fi + \@dtl@forcolnext##3\q@nil + }% + \@dtl@forcolumn#2% + \db@col@id@w #3\db@col@id@end@% + \db@col@elt@w \@nil\db@col@elt@end@% + \db@col@id@w #3\db@col@id@end@\q@nil + \let\dtlbreak\@dtl@oldbreak +} +\def\@dtl@forcolnoop#1\q@nil{} + +\newcount\dtlforeachlevel \newcounter{DTLrowi} \newcounter{DTLrowii} \newcounter{DTLrowiii} @@ -1520,6 +2168,18 @@ the current row}}{% \def\theHDTLrowi{\theHDTLrow.\arabic{DTLrowi}} \def\theHDTLrowii{\theHDTLrowi.\arabic{DTLrowii}} \def\theHDTLrowiii{\theHDTLrowii.\arabic{DTLrowiii}} +\newcount\dtl@rowi +\newcount\dtl@rowii +\newcount\dtl@rowiii +\newtoks\@dtl@curi +\newtoks\@dtl@previ +\newtoks\@dtl@nexti +\newtoks\@dtl@curii +\newtoks\@dtl@previi +\newtoks\@dtl@nextii +\newtoks\@dtl@curiii +\newtoks\@dtl@previii +\newtoks\@dtl@nextiii \newcommand*{\DTLsavelastrowcount}[1]{% \ifnum\dtlforeachlevel>2\relax \def#1{0}% @@ -1535,492 +2195,1098 @@ the current row}}{% \fi} \newcommand*{\DTLforeach}{\@ifstar\@sDTLforeach\@DTLforeach} \newcommand{\@DTLforeach}[4][\boolean{true}]{% -\DTLifdbexists{#2}{% -\refstepcounter{DTLrow}% -\global\c@DTLrow=\c@DTLrow -\gdef\@dtl@dbname{#2}% -\global\advance\dtlforeachlevel by 1\relax -\ifnum\dtlforeachlevel>3\relax - \PackageError{datatool}{\string\DTLforeach\space nested too -deeply}{}% -\else - \expandafter\global - \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname = 0\relax - \expandafter\global\expandafter\let - \csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname - =\@empty - \expandafter\global\expandafter\let - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname - =\@dtl@dbname - \expandafter\let\expandafter\@dtl@db\csname dtldb@#2\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% - \expandafter\global\expandafter - \let\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel - \endcsname=\@dtl@currentrow - \global\let\@dtl@nextrow\@xfor@nextelement - \ifx\relax#3\relax - \else - \@dtl@assign{#3}% - \fi - \ifthenelse{#1}{% - \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% - \expandafter\edef\expandafter\DTLcurrentindex\expandafter - {\arabic{DTLrow\romannumeral\dtlforeachlevel}}% - #4% - }{}% - \expandafter\let\expandafter\@dtl@thiscurrentrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - \ifx\@dtl@thiscurrentrow\@empty - \else - \expandafter\@dtl@toks\expandafter{\@dtl@thiscurrentrow}% - \expandafter - \ifx - \csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname - \@empty - \expandafter - \xdef\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname{% - {\the\@dtl@toks}}% + \DTLifdbexists{#2}% + {% + \refstepcounter{DTLrow}% + \global\c@DTLrow=\c@DTLrow\relax + \gdef\@dtl@dbname{#2}% + \global\advance\dtlforeachlevel by 1\relax + \ifnum\dtlforeachlevel>3\relax + \PackageError{datatool}{\string\DTLforeach\space nested too + deeply}{Only 3 levels are allowed}% \else - \expandafter\let\expandafter\@dtl@foreachrows\expandafter - =\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname - \expandafter\toks@\expandafter{\@dtl@foreachrows}% - \expandafter - \xdef\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname{% - \the\toks@,{\the\@dtl@toks}}% + \@DTLifdbempty{#2}% + {}% + {% + \expandafter\global + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + = 0\relax + \expandafter\global\expandafter\let% + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname + \DTLiffirstrow + \gdef\DTLiffirstrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =1\relax + ##1% + \else + ##2% + \fi}% + \expandafter\global\expandafter\let% + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname + \DTLiflastrow + \gdef\DTLiflastrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =\csname dtlcols@#2\endcsname\relax + ##1% + \else + ##2% + \fi}% + \expandafter\global\expandafter\let% + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + \DTLifoddrow + \gdef\DTLifoddrow##1##2{% + \expandafter\ifodd + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + ##1% + \else + ##2% + \fi}% + \expandafter\global\expandafter\let + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + =\@dtl@dbname + \expandafter\global\expandafter\let + \csname @dtl@ro@\romannumeral\dtlforeachlevel\endcsname + = 0\relax + \dtlgforint + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname + =1\to\csname dtlrows@#2\endcsname\step1\do + {% + \@dtl@tmpcount= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname + \edef\dtl@dogetrow{\noexpand\dtlgetrow{#2}% + {\number\@dtl@tmpcount}}% + \dtl@dogetrow + \expandafter\global + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + = \dtlcurrentrow + \expandafter\global + \csname @dtl@prev\romannumeral\dtlforeachlevel\endcsname + = \dtlbeforerow + \expandafter\global + \csname @dtl@next\romannumeral\dtlforeachlevel\endcsname + = \dtlafterrow + \ifx\relax#3\relax + \else + \@dtl@assign{#3}{#2}% + \fi + \ifthenelse{#1}% + {% + \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% + \expandafter\edef\expandafter\DTLcurrentindex% + \expandafter{% + \arabic{DTLrow\romannumeral\dtlforeachlevel}}% + #4% + \edef\@dtl@tmp{\expandafter\the + \csname @dtl@cur\romannumeral + \dtlforeachlevel\endcsname}% + \ifx\@dtl@tmp\@nnil + \expandafter\dtl@decrementrows\expandafter + {\csname @dtl@prev\romannumeral + \dtlforeachlevel\endcsname + }{\csname dtl@row\romannumeral + \dtlforeachlevel\endcsname}% + \expandafter\dtl@decrementrows\expandafter + {\csname @dtl@next\romannumeral + \dtlforeachlevel\endcsname + }{\csname dtl@row\romannumeral + \dtlforeachlevel\endcsname}% + \edef\@dtl@tmp{% + \expandafter\the + \csname @dtl@prev\romannumeral + \dtlforeachlevel\endcsname + \expandafter\the + \csname @dtl@next\romannumeral + \dtlforeachlevel\endcsname + }% + \expandafter\global\expandafter + \csname dtldb@#2\endcsname\expandafter{\@dtl@tmp}% + \expandafter\global\expandafter + \advance\csname dtlrows@#2\endcsname by -1\relax + \expandafter\global\expandafter + \advance\csname dtl@row\romannumeral + \dtlforeachlevel\endcsname by -1\relax + \else + \@dtl@before=\csname @dtl@prev\romannumeral + \dtlforeachlevel\endcsname + \@dtl@after=\csname @dtl@next\romannumeral + \dtlforeachlevel\endcsname + \toks@gconcat@middle@cx{dtldb@#2}% + {\@dtl@before}% + {% + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \expandafter\number + \csname dtl@row\romannumeral + \dtlforeachlevel\endcsname + \noexpand\db@row@id@end@% + \expandafter\the + \csname @dtl@cur\romannumeral + \dtlforeachlevel\endcsname + \noexpand\db@row@id@w \expandafter\number + \csname dtl@row\romannumeral + \dtlforeachlevel\endcsname + \noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + }% + {\@dtl@after}% + \fi + }% + {}% + }% + \expandafter\global\expandafter\let\expandafter\DTLiffirstrow + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname + \expandafter\global\expandafter\let\expandafter\DTLiflastrow + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname + \expandafter\global\expandafter\let\expandafter\DTLifoddrow + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + }% \fi - \fi -\@endforfalse -}% -\expandafter\let\expandafter\@dtl@foreachrows\expandafter - =\csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname -\expandafter\global - \expandafter\let\csname dtldb@#2\endcsname=\@dtl@foreachrows -\fi -\global\advance\dtlforeachlevel by -1\relax -}{% -\PackageError{datatool}{Database `#2' doesn't exist}{}}% + \global\advance\dtlforeachlevel by -1\relax + }% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% } \newcommand{\@sDTLforeach}[4][\boolean{true}]{% -\DTLifdbexists{#2}{% -\refstepcounter{DTLrow}% -\global\c@DTLrow=\c@DTLrow -\gdef\@dtl@dbname{#2}% -\global\advance\dtlforeachlevel by 1\relax -\ifnum\dtlforeachlevel>3\relax - \PackageError{datatool}{\string\DTLforeach\space nested too -deeply}{}% -\else - \expandafter\global - \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname = 0\relax - \expandafter\global\expandafter\let - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname - =\@nnil - \expandafter\let\expandafter\@dtl@db\csname dtldb@#2\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% - \expandafter\global\expandafter - \let\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel - \endcsname=\@dtl@currentrow - \global\let\@dtl@nextrow\@xfor@nextelement - \ifx\relax#3\relax + \DTLifdbexists{#2}% + {% + \refstepcounter{DTLrow}% + \global\c@DTLrow=\c@DTLrow + \global\advance\dtlforeachlevel by 1\relax + \ifnum\dtlforeachlevel>3\relax + \PackageError{datatool}{\string\DTLforeach\space nested too + deeply}{Only 3 levels are allowed}% + \else + \@DTLifdbempty{#2}% + {}% + {% + \expandafter\global + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + = 0\relax + \expandafter\global\expandafter\let% + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname + \DTLiffirstrow + \gdef\DTLiffirstrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =1\relax + ##1% + \else + ##2% + \fi}% + \expandafter\global\expandafter\let% + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname + \DTLiflastrow + \gdef\DTLiflastrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =\csname dtlcols@#2\endcsname\relax + ##1% + \else + ##2% + \fi}% + \expandafter\global\expandafter\let% + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + \DTLifoddrow + \gdef\DTLifoddrow##1##2{% + \expandafter\ifodd + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + ##1% + \else + ##2% + \fi}% + \expandafter\gdef\csname @dtl@dbname@\romannumeral + \dtlforeachlevel\endcsname{#2}% + \expandafter\global\expandafter\let + \csname @dtl@ro@\romannumeral\dtlforeachlevel\endcsname + = 1\relax + \@dtlforeachrow(\dtl@thisidx,\dtl@thisrow)\in{#2}\do% + {% + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname + = \dtl@thisidx\relax + \expandafter\global + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + = \expandafter{\dtl@thisrow}% + \ifx\relax#3\relax + \else + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \@dtl@assign{#3}{#2}% + \fi + \ifthenelse{#1}% + {% + \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% + \expandafter\edef\expandafter\DTLcurrentindex% + \expandafter{% + \arabic{DTLrow\romannumeral\dtlforeachlevel}}% + #4% + }% + {}% + }% + \expandafter\global\expandafter\let\expandafter\DTLiffirstrow + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname + \expandafter\global\expandafter\let\expandafter\DTLiflastrow + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname + \expandafter\global\expandafter\let\expandafter\DTLifoddrow + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + }% + \fi + \global\advance\dtlforeachlevel by -1\relax + }% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} +\newcommand*{\@dtlifreadonly}[2]{% + \expandafter\ifx + \csname @dtl@ro@\romannumeral\dtlforeachlevel\endcsname1\relax + #1% \else - \@dtl@assign{#3}% + #2% \fi - \ifthenelse{#1}{% - \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% - \expandafter\edef\expandafter\DTLcurrentindex\expandafter - {\arabic{DTLrow\romannumeral\dtlforeachlevel}}% - #4% - }{}% -\@endforfalse -}% -\fi -\global\advance\dtlforeachlevel by -1\relax -}{% -\PackageError{datatool}{Database `#2' doesn't exist}{}}% } \newcommand*{\DTLappendtorow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLappendtorow\space can only - be used inside \string\DTLforeach}{}% -\else - \expandafter\let\expandafter\@dtl@thisdb - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname - \ifx\@dtl@thisdb\@nnil - \PackageError{datatool}{\string\DTLappendtorow\space can't - be used inside \string\DTLforeach*}{The starred version of - \string\DTLforeach\space is read only}% - \else - \expandafter\@dtl@toks\expandafter{#2}% - \edef\@dtl@dbvalue{\the\@dtl@toks}% - \edef\@dtl@dbid{#1}% - \edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% - \PackageError{datatool}{Can't add entry with ID `#1' to current - row of database `\@dtl@thisdb'}{There is already an entry with - this ID on the current row}}{% - \expandafter\@dtl@toks\expandafter{\@dtl@dbentry}% - \ifx\@dtl@thisrow\@empty - \expandafter - \xdef\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname{% - \the\@dtl@toks}% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLappendrow\space can only be + used inside \string\DTLforeach}{}% \else - \expandafter\toks@\expandafter{\@dtl@thisrow}% - \expandafter - \xdef\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname{% - \the\toks@,\the\@dtl@toks}% + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLappendtorow\space can't + be used inside \DTLforeach*}{The starred version of + \string\DTLforeach\space is read only}% + }% + {% + \dtlrownum= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname\relax + \@dtl@updatekeys{\@dtl@thisdb}{#1}{#2}% + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{\@dtl@thisdb}{#1}\relax + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% + }% + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue + \expandafter\@dtl@toks\expandafter{#2}% + \toks@gput@right@cx{@dtl@cur\romannumeral\dtlforeachlevel}% + {% + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@ + \noexpand\db@col@elt@w \the\@dtl@toks + \noexpand\db@col@elt@end@ + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@ + }% + \dtl@message{Appended #1\space -> #2\space to database + `\@dtl@thisdb'}% + \else + \PackageError{datatool}{Can't append entry to row: + there is already an entry for key `#1' in this row}{}% + \fi + }% \fi - } - \@dtl@setidtype{\@dtl@thisdb}{#1}{#2}% - \expandafter\@dtl@setkeys\expandafter{#1}{\@dtl@thisdb}% - \fi -\fi } \newcommand*{\DTLremoveentryfromrow}[1]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLremoveentryfromrow\space can only - be used inside \string\DTLforeach}{}% -\else - \expandafter\let\expandafter\@dtl@thisdb - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname - \ifx\@dtl@thisdb\@nnil - \PackageError{datatool}{\string\DTLremoveentryfromrow\space can't - be used inside \string\DTLforeach*}{The starred version of - \string\DTLforeach\space is read only}% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLremoventryfromrow\space + can only be used inside \string\DTLforeach}{}% \else - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% - \let\@dtl@pre=\@empty - \@for\dtl@thisentry:=\@dtl@thisrow\do{% - \dtl@getentryid\dtl@thisentry\@dtl@id - \ifthenelse{\equal{\@dtl@id}{#1}}{% - }{% - \expandafter\@dtl@toks\expandafter{\dtl@thisentry}% - \ifx\@dtl@pre\@empty - \edef\@dtl@pre{{\the\@dtl@toks}}% - \else - \expandafter\toks@\expandafter{\@dtl@pre}% - \edef\@dtl@pre{\the\toks@,{\the\@dtl@toks}}% - \fi - } - }% - \expandafter\let - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - =\@dtl@pre - }{% - \PackageError{datatool}{Can't remove entry given by key `#1' - from current row in database `\@dtl@thisdb', no such entry}{}% - }% + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLremoveentryfromrow\space + can't be used inside \string\DTLforeach*}{The starred + version of \string\DTLforeach\space is read only}% + }% + {% + \dtlrownum= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname\relax + \@dtlifhaskey{\@dtl@thisdb}{#1}% + {% + \dtl@getcolumnindex{\thiscol}{\@dtl@thisdb}{#1}\relax + \dtlcolumnnum=\thiscol\relax + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% + }% + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue + \PackageError{datatool}{Can't remove entry given by `#1' + from current row in database `\@dtl@thisdb': no such + entry}{The current row doesn't contain an entry for + key `#1'}% + \else + \edef\@dtl@dosplitrow{% + \noexpand\dtlsplitrow{\the\dtlcurrentrow}% + {\number\dtlcolumnnum}{\noexpand\dtl@pre}% + {\noexpand\dtl@post}% + }% + \@dtl@dosplitrow + \expandafter\@dtl@toks\expandafter{\dtl@pre}% + \expandafter\toks@\expandafter{\dtl@post}% + \edef\@dtl@tmp{\the\@dtl@toks \the\toks@}% + \dtlcurrentrow=\expandafter{\@dtl@tmp}% + \expandafter\global + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + = \dtlcurrentrow + \dtl@message{Removed entry given by #1\space from current + row of database `\@dtl@thisdb'}% + \fi + }% + {% + \PackageError{datatool}{Can't remove entry given by + `#1' - no such key exists}{}% + }% + }% \fi -\fi } \newcommand*{\DTLreplaceentryforrow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLreplaceentryforrow\space can only - be used inside \string\DTLforeach}{}% -\else - \expandafter\let\expandafter\@dtl@thisdb - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname - \ifx\@dtl@thisdb\@nnil - \PackageError{datatool}{\string\DTLreplaceentryforrow\space can't - be used inside \string\DTLforeach*}{The starred version of - \string\DTLforeach\space is read only}% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLreplaceentryforrow\space + can only be used inside \string\DTLforeach}{}% \else - \expandafter\@dtl@toks\expandafter{#2}% - \edef\@dtl@dbvalue{\the\@dtl@toks}% - \edef\@dtl@dbid{#1}% - \edef\dtl@newentry{{\@dtl@dbid}{\the\@dtl@toks}}% - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% - \let\@dtl@pre=\@empty - \@for\dtl@thisentry:=\@dtl@thisrow\do{% - \dtl@getentryid\dtl@thisentry\@dtl@id - \ifthenelse{\equal{\@dtl@id}{#1}}{% - \expandafter\@dtl@toks\expandafter{\dtl@newentry}% - }{% - \expandafter\@dtl@toks\expandafter{\dtl@thisentry}% - } - \ifx\@dtl@pre\@empty - \edef\@dtl@pre{{\the\@dtl@toks}}% - \else - \expandafter\toks@\expandafter{\@dtl@pre}% - \edef\@dtl@pre{\the\toks@,{\the\@dtl@toks}}% - \fi - }% - \expandafter\let - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - =\@dtl@pre - }{% - \PackageError{datatool}{Can't remove entry given by key `#1' - from current row in database `\@dtl@thisdb', no such entry}{}% - }% + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLreplaceentryforrow\space + can't be used inside \string\DTLforeach*}{The starred version + of \string\DTLforeach\space is read only}% + }% + {% + \dtlrownum= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname\relax + \@dtlifhaskey{\@dtl@thisdb}{#1}% + {% + \dtl@getcolumnindex{\thiscol}{\@dtl@thisdb}{#1}\relax + \dtlcolumnnum=\thiscol\relax + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% + }% + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue + \PackageError{datatool}{Can't replace entry given by `#1' + from current row in database `\@dtl@thisdb': no such + entry}{The current row doesn't contain an entry for + key `#1'}% + \else + \edef\@dtl@dosplitrow{% + \noexpand\dtlsplitrow{\the\dtlcurrentrow}% + {\number\dtlcolumnnum}{\noexpand\dtl@pre}% + {\noexpand\dtl@post}% + }% + \@dtl@dosplitrow + \@dtl@toks{#2}% new value + \expandafter\@dtl@before\expandafter{\dtl@pre}% + \expandafter\@dtl@after\expandafter{\dtl@post}% + \toks@gconcat@middle@cx + {@dtl@cur\romannumeral\dtlforeachlevel}% + {\@dtl@before}% + {% + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@% + \noexpand\db@col@elt@w \the\@dtl@toks + \noexpand\db@col@elt@end@% + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@% + }% + {\@dtl@after}% + \dtl@message{Updated #1\space -> #2\space in database + `\@dtl@thisdb'}% + \fi + }% + {% + \PackageError{datatool}{Can't replace key `#1' - no such + key in database `\@dtl@thisdb'}{}% + }% + }% \fi -\fi } \newcommand*{\DTLremovecurrentrow}{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLremovecurrentrow\space can only - be used inside \string\DTLforeach}{}% -\else - \expandafter\ifx - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname\@nnil - \PackageError{datatool}{\string\DTLremovecurrentrow\space can't - be used inside \string\DTLforeach*}{The starred version of - \string\DTLforeach\space is read only}% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLremovecurrentrow\space can + only be used inside \string\DTLforeach}{}% \else - \expandafter\let - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - =\@empty + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLreplaceentryforrow\space + can't be used inside \string\DTLforeach*}{The starred version + of \string\DTLforeach\space is read only}% + }% + {% + \expandafter\global + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + ={\@nil}% + }% \fi -\fi +} +\newcommand{\DTLaddentryforrow}[5]{% + \DTLifdbexists{#1}% + { + \def\@dtl@notdone{\PackageError{datatool}{Unable to add entry + given by key `#4': condition not met for any row in database + `#1'}{}}% + \DTLforeach[#3]{#1}{#2}% + {% + \DTLappendtorow{#4}{#5}% + \let\@dtl@notdone\relax + \dtlbreak + }% + \@dtl@notdone + }% + {% + \PackageError{datatool}{Unable to add entry given by key `#4': + database `#1' doesn't exist}{}% + }% } \newcommand*{\DTLforeachkeyinrow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLforeachkeyinrow\space can only - be used inside \string\DTLforeach}{}% -\else - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - \@for\dtl@thisentry:=\@dtl@thisrow\do{% - \dtl@getentryvalue\dtl@thisentry{#1}% - #2% - }% -\fi + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLforeachkeyinrow\space can only + be used inside \string\DTLforeach}{}% + \else + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + \dtlforeachkey(\dtlkey,\dtlcol,\dtltype,\dtlheader)\in + \@dtl@thisdb\do{% + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand#1}{\dtlcol}}% + \dtl@dogetentry + \ifx#1\dtlnovalue + \ifnum0\dtltype=0\relax + \let#1=\DTLstringnull + \else + \let#1=\DTLnumbernull + \fi + \fi + \global\let#1#1% + \def\@dtl@loop@body{#2}% + \@dtl@loop@body + }% + \fi } -\newcommand{\DTLaddentryforrow}[5]{% -\gdef\@dtl@dbname{#1}% -\DTLifdbexists{#1}{% - \expandafter\@dtl@toks\expandafter{#5}% - \edef\@dtl@dbvalue{\the\@dtl@toks}% - \edef\@dtl@dbid{#4}% - \edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% - \expandafter - \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% - \let\@dtl@prerow=\@empty - \@for\@dtl@currentrow:=\@dtl@db\do{% - \@dtl@assign{#2}% - \ifthenelse{#3}{% - \expandafter\@dtl@toks\expandafter{\@dtl@dbentry}% - \ifx\@dtl@currentrow\@empty - \edef\@dtl@currentrow{{\the\@dtl@toks}}% +\newcommand*{\dtlbetweencols}{} +\newcommand*{\dtlbeforecols}{} +\newcommand*{\dtlaftercols}{} +\newcommand*{\dtlstringalign}{l} +\newcommand*{\dtlintalign}{r} +\newcommand*{\dtlrealalign}{r} +\newcommand*{\dtlcurrencyalign}{r} +\newcommand*{\dtladdalign}[4]{% + \ifnum#3=1\relax + \protected@edef#1{\dtlbeforecols}% + \else + \protected@edef#1{#1\dtlbetweencols}% + \fi + \ifx\@empty#2\@empty + \protected@edef#1{#1c}% + \else + \ifcase#2\relax + \protected@edef#1{#1\dtlstringalign}% + \or + \protected@edef#1{#1\dtlintalign}% + \or + \protected@edef#1{#1\dtlrealalign}% + \or + \protected@edef#1{#1\dtlcurrencyalign}% \else - \expandafter\toks@\expandafter{\@dtl@currentrow}% - \edef\@dtl@currentrow{\the\toks@,{\the\@dtl@toks}}% + \protected@edef#1{#1c}% + \PackageError{datatool}{Unknown data type `#2'}{}% \fi - \@endfortrue - }{% + \fi + \ifnum#3=#4\relax + \protected@edef#1{#1\dtlaftercols}% + \fi +} +\newcommand*{\dtlheaderformat}[1]{\null\hfil\textbf{#1}\hfil\null} +\newcommand*{\dtlstringformat}[1]{#1} +\newcommand*{\dtlintformat}[1]{#1} +\newcommand*{\dtlrealformat}[1]{#1} +\newcommand*{\dtlcurrencyformat}[1]{#1} +\newcommand*{\dtldisplaystarttab}{} +\newcommand*{\dtldisplayendtab}{} +\newcommand*{\dtldisplayafterhead}{} +\newcommand*{\dtldisplaystartrow}{} + +\newcommand*{\DTLdisplaydb}[1]{% + \def\@dtl@doamp{\gdef\@dtl@doamp{&}} + \def\@dtl@resetdoamp{\gdef\@dtl@doamp{\gdef\@dtl@doamp{&}}} + \edef\@dtl@maxcols{\expandafter\number + \csname dtlcols@#1\endcsname}% + \def\@dtl@tabargs{}% + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#1}\do + {% + \dtladdalign\@dtl@tabargs\@dtl@type\@dtl@idx\@dtl@maxcols + }% + \edef\@dtl@dobegintab{\noexpand\begin{tabular}{\@dtl@tabargs}}% + \@dtl@dobegintab + \dtldisplaystarttab + \@dtl@resetdoamp + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#1}\do + {% + \@dtl@doamp + \dtlheaderformat{\@dtl@head}% + }% + \\% + \dtldisplayafterhead + \@dtl@resetdoamp + \DTLforeach*{#1}{}{% + \DTLiffirstrow{}{\\\dtldisplaystartrow}% + \@dtl@resetdoamp + \DTLforeachkeyinrow{\@dtl@val}% + {% + \global\let\@dtl@val\@dtl@val + \@dtl@doamp + \@dtl@datatype=0\dtltype\relax + \ifcase\@dtl@datatype + \dtlstringformat\@dtl@val + \or + \dtlintformat\@dtl@val + \or + \dtlrealformat\@dtl@val + \or + \dtlcurrencyformat\@dtl@val + \else + \@dtl@val + \fi + }% + }% + \dtldisplayendtab + \end{tabular}% +} +\define@key{displaylong}{caption}{\def\@dtl@cap{#1}} +\define@key{displaylong}{contcaption}{\def\@dtl@contcap{#1}} +\define@key{displaylong}{shortcaption}{\def\@dtl@shortcap{#1}} +\define@key{displaylong}{label}{\def\@dtl@label{#1}} +\define@key{displaylong}{foot}{\def\@dtl@foot{#1}} +\define@key{displaylong}{lastfoot}{\def\@dtl@lastfoot{#1}} +\newcommand*{\@dtl@resetdostartrow}{% + \gdef\@dtl@dostartrow{% + \gdef\@dtl@dostartrow{\\\dtldisplaystartrow}}% +} +\newcommand*{\DTLdisplaylongdb}[2][]{% + \def\@dtl@cap{\@nil}% + \def\@dtl@contcap{\@nil}% + \def\@dtl@label{\@nil}% + \def\@dtl@shortcap{\@dtl@cap}% + \def\@dtl@foot{\@nil}% + \def\@dtl@lastfoot{\@nil}% + \setkeys{displaylong}{#1}% + \def\@dtl@doamp{\gdef\@dtl@doamp{&}} + \def\@dtl@resetdoamp{\gdef\@dtl@doamp{\gdef\@dtl@doamp{&}}} + \@dtl@resetdostartrow + \edef\@dtl@maxcols{\expandafter\number + \csname dtlcols@#2\endcsname}% + \def\@dtl@tabargs{}% + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {% + \dtladdalign\@dtl@tabargs\@dtl@type\@dtl@idx\@dtl@maxcols }% - \expandafter\@dtl@toks\expandafter{\@dtl@currentrow}% - \ifx\@dtl@prerow\@empty - \edef\@dtl@prerow{{\the\@dtl@toks}}% + \edef\@dtl@dobegintab{\noexpand\begin{longtable}{\@dtl@tabargs}}% + \@dtl@dobegintab + \dtldisplaystarttab + \ifx\@dtl@foot\@nnil \else - \expandafter\toks@\expandafter{\@dtl@prerow}% - \edef\@dtl@prerow{\the\toks@,{\the\@dtl@toks}}% + \@dtl@foot\endfoot \fi -}% -\if@endfor - \expandafter\@dtl@toks\expandafter{\@forremainder}% - \expandafter\toks@\expandafter{\@dtl@prerow}% - \edef\@dtl@prerow{\the\toks@,{\the\@dtl@toks}}% - \expandafter\global\expandafter - \let\csname dtldb@\@dtl@dbname\endcsname=\@dtl@prerow -\else - \PackageError{datatool}{Unable to add `#5' for key `#4' - condition - not met for any row in database `#1'}{}% -\fi -\@endforfalse -}{% -\PackageError{datatool}{Database `#1' doesn't exist}{}}% + \ifx\@dtl@lastfoot\@nnil + \else + \@dtl@lastfoot\endlastfoot + \fi + \ifx\@dtl@cap\@nnil + \@dtl@resetdoamp + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {\@dtl@doamp{\dtlheaderformat{\@dtl@head}}}% + \@dtl@resetdoamp + \@dtl@resetdostartrow + \endhead\dtldisplayafterhead + \else + \caption[\@dtl@shortcap]{\@dtl@cap}% + \ifx\@dtl@label\@nnil + \else + \label{\@dtl@label}% + \fi + \\% + \@dtl@resetdoamp + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {\@dtl@doamp{\dtlheaderformat{\@dtl@head}}}% + \@dtl@resetdoamp + \@dtl@resetdostartrow + \endfirsthead + \ifx\@dtl@contcap\@nnil + \caption{\@dtl@cap}% + \else + \caption{\@dtl@contcap}% + \fi + \\% + \@dtl@resetdoamp + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {\@dtl@doamp{\dtlheaderformat{\@dtl@head}}}% + \@dtl@resetdoamp + \@dtl@resetdostartrow + \endhead\dtldisplayafterhead + \fi + \DTLforeach*{#2}{}{% + \@dtl@dostartrow + \@dtl@resetdoamp + \DTLforeachkeyinrow{\@dtl@val}% + {% + \global\let\@dtl@val\@dtl@val + \@dtl@doamp + \@dtl@datatype=0\dtltype\relax + \ifcase\@dtl@datatype + \dtlstringformat\@dtl@val + \or + \dtlintformat\@dtl@val + \or + \dtlrealformat\@dtl@val + \or + \dtlcurrencyformat\@dtl@val + \fi + }% + }% + \dtldisplayendtab + \end{longtable}% } -\newcommand*{\@dtl@assign}[2][\@dtl@currentrow]{% -\@dtl@assigncmd#2,\relax\@@{#1}% +\newcommand*{\dtlswaprows}[3]{% + \ifnum#2=#3\relax + \else + \ifnum#2<#3\relax + \edef\@dtl@rowAidx{\number#2}% + \edef\@dtl@rowBidx{\number#3}% + \else + \edef\@dtl@rowAidx{\number#3}% + \edef\@dtl@rowBidx{\number#2}% + \fi + \edef\@dtl@dosplit{\noexpand\dtlgetrow{#1}{\@dtl@rowAidx}}% + \@dtl@dosplit + \expandafter\def\expandafter\@dtl@firstpart\expandafter + {\the\dtlbeforerow}% + \@dtl@toksA=\dtlcurrentrow + \edef\@dtl@dosplit{\noexpand\@dtlgetrow + {\the\dtlafterrow}{\@dtl@rowBidx}}% + \@dtl@dosplit + \expandafter\def\expandafter\@dtl@secondpart\expandafter + {\the\dtlbeforerow}% + \@dtl@toksB=\dtlcurrentrow + \expandafter\def\expandafter\@dtl@thirdpart\expandafter + {\the\dtlafterrow}% + \toks@=\expandafter{\@dtl@firstpart}% + \@dtl@toks=\expandafter{\@dtl@secondpart}% + \edef\@dtl@tmp{\the\toks@ + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \@dtl@rowAidx\noexpand\db@row@id@end@% + \the\@dtl@toksB + \noexpand\db@row@id@w \@dtl@rowAidx\noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + \the\@dtl@toks}% + \toks@=\expandafter{\@dtl@tmp}% + \@dtl@toks=\expandafter{\@dtl@thirdpart}% + \edef\@dtl@tmp{\the\toks@ + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \@dtl@rowBidx\noexpand\db@row@id@end@% + \the\@dtl@toksA + \noexpand\db@row@id@w \@dtl@rowBidx\noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + \the\@dtl@toks}% + \expandafter\global\csname dtldb@#1\endcsname=\expandafter + {\@dtl@tmp}% + \fi } -\def\@dtl@assigncmd#1=#2,#3\@@#4{% -\@for\@dtl@entry:=#4\do{% -\dtl@getentryid\@dtl@entry\@dtl@id -\ifthenelse{\equal{\@dtl@id}{#2}}{% -\dtl@getentryvalue\@dtl@entry#1% -\@endfortrue}{}% -}% -\if@endfor -\else - \@dtl@setnull{#1}{#2}% -\fi -\@endforfalse -\ifx\relax#3% - \let\@dtl@next=\@dtl@assigncmdnoop -\else - \let\@dtl@next=\@dtl@assigncmd -\fi -\@dtl@next#3\@@{#4}% +\newcommand*{\dtl@decrementrows}[2]{% + \def\@dtl@newlist{}% + \edef\@dtl@min{\number#2}% + \expandafter\@dtl@decrementrows\the#1% + \db@row@elt@w% + \db@row@id@w \@nil\db@row@id@end@% + \db@row@id@w \@nil\db@row@id@end@% + \db@row@elt@end@% + \@nil + #1=\expandafter{\@dtl@newlist}% +} +\def\@dtl@decrementrows\db@row@elt@w\db@row@id@w #1\db@row@id@end@% +#2\db@row@id@w #3\db@row@id@end@\db@row@elt@end@#4\@nil{% + \def\@dtl@thisrow{#1}% + \ifx\@dtl@thisrow\@nnil + \let\@dtl@donextdec=\@dtl@gobbletonil + \else + \ifnum\@dtl@thisrow>\@dtl@min + \@dtl@tmpcount=\@dtl@thisrow\relax + \advance\@dtl@tmpcount by -1\relax + \toks@{#2}% + \@dtl@toks=\expandafter{\@dtl@newlist}% + \edef\@dtl@newlist{\the\@dtl@toks + \noexpand\db@row@elt@w% row header + \noexpand\db@row@id@w \number\@dtl@tmpcount + \noexpand\db@row@id@end@% row id + \the\toks@ % row contents + \noexpand\db@row@id@w \number\@dtl@tmpcount + \noexpand\db@row@id@end@% row id + \noexpand\db@row@elt@end@% row end + }% + \else + \toks@{#2}% + \@dtl@toks=\expandafter{\@dtl@newlist}% + \edef\@dtl@newlist{\the\@dtl@toks + \noexpand\db@row@elt@w% row header + \noexpand\db@row@id@w #1% + \noexpand\db@row@id@end@% row id + \the\toks@ % row contents + \noexpand\db@row@id@w #3% + \noexpand\db@row@id@end@% row id + \noexpand\db@row@elt@end@% row end + }% + \fi + \let\@dtl@donextdec=\@dtl@decrementrows + \fi + \@dtl@donextdec#4\@nil +} +\newcommand*{\DTLremoverow}[2]{% + \DTLifdbexists{#1}% + {% + \ifnum#2>0\relax + \expandafter\ifnum\csname dtlrows@#1\endcsname<#2\relax + \expandafter\ifnum\csname dtlrows@#1\endcsname=1\relax + \PackageError{datatool}{Can't remove row `\number#2' from + database `#1': no such row}{Database `#1' only has + 1 row}% + \else + \PackageError{datatool}{Can't remove row `\number#2' from + database `#1': no such row}{Database `#1' only has + \expandafter\number\csname dtlrows@#1\endcsname\space + rows}% + \fi + \else + \@DTLremoverow{#1}{#2}% + \fi + \else + \PackageError{datatool}{Can't remove row \number#2: index + out of bounds}{Row indices start at 1}% + \fi + }% + {% + \PackageError{datatool}{Can't remove row: database `#1' doesn't + exist}{}% + }% } -\def\@dtl@assigncmdnoop#1\@@#2{} -\newcommand*{\@dtl@setnull}[2]{% -\@ifundefined{@dtl@idtype@\@dtl@dbname @#2}{% -\global\let#1=\DTLstringnull}{% -\edef\@dtl@tmp{0\@dtl@getidtype{\@dtl@dbname}{#2}}% -\expandafter\ifnum\@dtl@tmp=0\relax - \global\let#1=\DTLstringnull -\else - \global\let#1=\DTLnumbernull -\fi -}} -\newcommand*{\DTLstringnull}{NULL} -\newcommand*{\DTLnumbernull}{0} -\newcommand*{\DTLifnull}[3]{% -\ifx\DTLstringnull#1\relax - #2% -\else - \ifx\DTLnumbernull#1\relax - #2% - \else - #3% - \fi -\fi} -\newcommand{\dtl@gathervalues}[3][key]{% -\expandafter\let\expandafter\@dtl@tmp\expandafter - =\csname dtlkeys@#2\endcsname% -\def\@dtl@list{}% -\@for\dtl@key:=\@dtl@tmp\do{% - \expandafter\@dtl@setnull\expandafter{% - \csname @dtl@#1@\dtl@key\endcsname}{\dtl@key}% - \@for\dtl@thiselement:=#3\do{% - \dtl@getentryid\dtl@thiselement\@dtl@id - \ifthenelse{\equal{\@dtl@id}{\dtl@key}}{% - \dtl@getentryvalue\dtl@thiselement\@dtl@value% - \expandafter\toks@\expandafter{\@dtl@value}% - \expandafter\edef\csname @dtl@#1@\dtl@key\endcsname{% - \the\toks@}% - \@endfortrue}{}% - }% -\@endforfalse -}% +\newcommand*{\@DTLremoverow}[2]{% + \edef\dtl@dogetrow{\noexpand\dtlgetrow{#1}{\number#2}}% + \dtl@dogetrow + \expandafter\dtl@decrementrows\expandafter + {\dtlbeforerow}{#2}% + \expandafter\dtl@decrementrows\expandafter + {\dtlafterrow}{#2}% + \edef\dtl@tmp{\the\dtlbeforerow \the\dtlafterrow}% + \expandafter\global\csname dtldb@#1\endcsname + =\expandafter{\dtl@tmp}% + \expandafter\global\expandafter\advance + \csname dtlrows@#1\endcsname by -1\relax +} +\newcommand*{\DTLsumforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlsumforkeys +} +\newcommand*{\@dtlsumforkeys}[4][]{% + \def#4{0}% + \@for\@dtl@dbname:=#2\do{% + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@key}% + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \dtlgetentryfromrow{\DTLthisval}{\@dtl@col}{\dtlcurrentrow}% + \expandafter\ifthenelse\expandafter{\@dtl@cond}% + {\DTLadd{#4}{#4}{\DTLthisval}}{}% + }% + }% + }% } -\newcommand*{\DTLsumforkeys}[4][\boolean{true}\and -\DTLisnumerical{\DTLthisval}]{% -\def#4{0}% -\@for\@dtl@dbname:=#2\do{% - \DTLifdbexists{\@dtl@dbname}{% - \expandafter - \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% - \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% - \@for\@dtl@key:=#3\do{% - \protected@edef\DTLthisval{% - \csname @dtl@key@\@dtl@key\endcsname}% - \ifthenelse{#1}{\DTLadd{#4}{#4}{\DTLthisval}}{}% - }}% - }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% +\newcommand*{\DTLsumcolumn}[3]{% + \def#3{0}% + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \DTLadd{#3}{#3}{\DTLthisval}% + }% + }% + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% }% -}% } -\newcommand*{\DTLmeanforkeys}[4][\boolean{true}\and -\DTLisnumerical{\DTLthisval}]{% -\def#4{0}% -\def\dtl@n{0}% -\@for\@dtl@dbname:=#2\do{% -\DTLifdbexists{\@dtl@dbname}{% - \expandafter - \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% - \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% - \@for\@dtl@key:=#3\do{% - \protected@edef\DTLthisval{% - \csname @dtl@key@\@dtl@key\endcsname}% - \ifthenelse{#1}{% - \DTLadd{#4}{#4}{\DTLthisval}% - \DTLadd{\dtl@n}{\dtl@n}{1}% - }{}% - }}% -}{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}}}% -\ifnum\dtl@n=0\relax - \PackageError{datatool}{Can't compute mean, no data!}{}% -\else - \DTLdiv{#4}{#4}{\dtl@n}% -\fi -} -\newcommand*{\DTLvarianceforkeys}[4][\boolean{true}\and -\DTLisnumerical{\DTLthisval}]{% -\DTLmeanforkeys[#1]{#2}{#3}{\dtl@mean}% -\def#4{0}% -\@for\@dtl@dbname:=#2\do{% - \DTLifdbexists{\@dtl@dbname}{% - \expandafter - \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname - \@for\@dtl@currentrow:=\@dtl@db\do{% - \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% - \@for\@dtl@key:=#3\do{% - \protected@edef\DTLthisval{% - \csname @dtl@key@\@dtl@key\endcsname}% - \ifthenelse{#1}{% - \DTLsub{\dtl@diff}{\DTLthisval}{\dtl@mean}% - \DTLmul{\dtl@diff}{\dtl@diff}{\dtl@diff}% - \DTLadd{#4}{#4}{\dtl@diff}% - }{}% - }}% - }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% +\newcommand*{\DTLmeanforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlmeanforkeys +} +\newcount\@dtl@elements +\newcommand*{\@dtlmeanforkeys}[4][]{% + \def#4{0}% + \@dtl@elements=0\relax + \@for\@dtl@dbname:=#2\do{% + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@key}% + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \dtlgetentryfromrow{\DTLthisval}{\@dtl@col}{\dtlcurrentrow}% + \expandafter\ifthenelse\expandafter{\@dtl@cond}% + {% + \DTLadd{#4}{#4}{\DTLthisval}% + \advance\@dtl@elements by 1\relax + }{}% + }% + }% }% -}% -\ifnum\dtl@n=0\relax - \PackageError{datatool}{Can't compute variance, no data!}{}% -\else - \DTLdiv{#4}{#4}{\dtl@n}% -\fi + \ifnum\@dtl@elements=0\relax + \PackageError{datatool}{Unable to evaluate mean: no data}{}% + \else + \edef\@dtl@n{\number\@dtl@elements}% + \DTLdiv{#4}{#4}{\@dtl@n}% + \fi } -\newcommand*{\DTLsdforkeys}[4][\boolean{true}\and -\DTLisnumerical{\DTLthisval}]{% -\DTLvarianceforkeys[#1]{#2}{#3}{#4}% -\DTLsqrt{#4}{#4}% +\newcommand*{\DTLmeanforcolumn}[3]{% + \def#3{0}% + \@dtl@elements=0\relax + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \DTLadd{#3}{#3}{\DTLthisval}% + \advance\@dtl@elements by 1\relax + }% + \ifnum\@dtl@elements=0\relax + \PackageError{datatool}{Can't compute mean for + column `#2' in database `#1': no data}{}% + \else + \edef\@dtl@n{\number\@dtl@elements}% + \DTLdiv{#3}{#3}{\@dtl@n}% + \fi + }% + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% } -\newcommand*{\DTLminforkeys}[4][\boolean{true}\and -\DTLisnumerical{\DTLthisval}]{% -\def#4{}% -\@for\@dtl@dbname:=#2\do{% -\DTLifdbexists{\@dtl@dbname}{% - \expandafter - \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% - \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% - \@for\@dtl@key:=#3\do{% - \protected@edef\DTLthisval{% - \csname @dtl@key@\@dtl@key\endcsname}% - \ifthenelse{#1}{% - \ifx#4\@empty - \let#4=\DTLthisval - \else - \DTLmin{#4}{#4}{\DTLthisval}% - \fi - }{}% -}}% - }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% +\newcommand*{\DTLvarianceforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlvarianceforkeys +} +\newcommand*{\@dtlvarianceforkeys}[4][]{% + \@dtlmeanforkeys[#1]{#2}{#3}{\dtl@mean}% + \def#4{0}% + \@dtl@elements=0\relax + \@for\@dtl@dbname:=#2\do{% + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@key}% + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \dtlgetentryfromrow{\DTLthisval}{\@dtl@col}{\dtlcurrentrow}% + \expandafter\ifthenelse\expandafter{\@dtl@cond}% + {% + \DTLsub{\dtl@diff}{\DTLthisval}{\dtl@mean}% + \DTLmul{\dtl@diff}{\dtl@diff}{\dtl@diff}% + \DTLadd{#4}{#4}{\dtl@diff}% + \advance\@dtl@elements by 1\relax + }{}% + }% + }% }% -}} -\newcommand*{\DTLmaxforkeys}[4][\boolean{true}\and + \ifnum\@dtl@elements=0\relax + \PackageError{datatool}{Unable to evaluate variance: no data}{}% + \else + \edef\@dtl@n{\number\@dtl@elements}% + \DTLdiv{#4}{#4}{\@dtl@n}% + \fi +} +\newcommand*{\DTLvarianceforcolumn}[3]{% + \DTLmeanforcolumn{#1}{#2}{\dtl@mean}% + \def#3{0}% + \@dtl@elements=0\relax + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \DTLsub{\dtl@diff}{\DTLthisval}{\dtl@mean}% + \DTLmul{\dtl@diff}{\dtl@diff}{\dtl@diff}% + \DTLadd{#3}{#3}{\dtl@diff}% + \advance\@dtl@elements by 1\relax + }% + \ifnum\@dtl@elements=0\relax + \PackageError{datatool}{Can't compute variance for + column `#2' in database `#1': no data}{}% + \else + \edef\@dtl@n{\number\@dtl@elements}% + \DTLdiv{#3}{#3}{\@dtl@n}% + \fi + }% + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} +\newcommand*{\DTLsdforkeys}[1][\boolean{true}\and \DTLisnumerical{\DTLthisval}]{% -\def#4{}% -\@for\@dtl@dbname:=#2\do{% -\DTLifdbexists{\@dtl@dbname}{% - \expandafter - \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% - \dtl@gathervalues{\@dtl@dbname}{\@dtl@currentrow}% - \@for\@dtl@key:=#3\do{% - \protected@edef\DTLthisval{% - \csname @dtl@key@\@dtl@key\endcsname}% - \ifthenelse{#1}{% - \ifx#4\@empty - \let#4=\DTLthisval - \else - \DTLmax{#4}{#4}{\DTLthisval}% - \fi - }{}% -}}% - }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% + \def\@dtl@cond{#1}% + \@dtlsdforkeys +} +\newcommand*{\@dtlsdforkeys}[4][]{% + \@dtlvarianceforkeys[#1]{#2}{#3}{#4}% + \DTLsqrt{#4}{#4}% +} +\newcommand*{\DTLsdforcolumn}[3]{% + \DTLvarianceforcolumn{#1}{#2}{#3}% + \DTLsqrt{#3}{#3}% +} +\newcommand*{\DTLminforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlminforkeys +} +\newcommand*{\@dtlminforkeys}[4][]{% + \def#4{}% + \@for\@dtl@dbname:=#2\do{% + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@key}% + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \dtlgetentryfromrow{\DTLthisval}{\@dtl@col}{\dtlcurrentrow}% + \expandafter\ifthenelse\expandafter{\@dtl@cond}% + {% + \ifx#4\@empty + \let#4\DTLthisval + \else + \DTLmin{#4}{#4}{\DTLthisval}% + \fi + }{}% + }% + }% }% -}} +} +\newcommand*{\DTLminforcolumn}[3]{% + \def#3{}% + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \ifx#3\@empty + \let#3\DTLthisval + \else + \DTLmin{#3}{#3}{\DTLthisval}% + \fi + }% + }% + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} +\newcommand*{\DTLmaxforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlmaxforkeys +} +\newcommand*{\@dtlmaxforkeys}[4][]{% + \def#4{}% + \@for\@dtl@dbname:=#2\do{% + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@key}% + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \dtlgetentryfromrow{\DTLthisval}{\@dtl@col}{\dtlcurrentrow}% + \expandafter\ifthenelse\expandafter{\@dtl@cond}% + {% + \ifx#4\@empty + \let#4\DTLthisval + \else + \DTLmax{#4}{#4}{\DTLthisval}% + \fi + }{}% + }% + }% + }% +} +\newcommand*{\DTLmaxforcolumn}[3]{% + \def#3{}% + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \ifx#3\@empty + \let#3\DTLthisval + \else + \DTLmax{#3}{#3}{\DTLthisval}% + \fi + }% + }% + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} \newcommand*{\DTLcomputebounds}[8][\boolean{true}]{% \let#5=\relax \let#6=\relax @@ -2045,228 +3311,266 @@ deeply}{}% }% } \newcommand*{\DTLgetvalueforkey}[5]{% -{% -\global\let#1=\DTLstringnull -\@sDTLforeach{#3}{\dtl@valueA=#2,\dtl@refvalue=#4}{% -\DTLifnull{\dtl@refvalue}{}{% -\ifthenelse{\equal{\dtl@refvalue}{#5}}{% -\global\let#1=\dtl@valueA -\@endfortrue -}{}}}% -}} + \DTLgetrowforkey{\@dtl@row}{#3}{#4}{#5}% + \@sdtl@getcolumnindex{\@dtl@col}{#3}{#2}% + {% + \dtlcurrentrow=\expandafter{\@dtl@row}% + \edef\@dtl@dogetval{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\@dtl@val}{\@dtl@col}}% + \@dtl@dogetval + \global\let#1=\@dtl@val + }% +} \newcommand*{\DTLgetrowforkey}[4]{% -{% -\global\let#1=\@empty -\@sDTLforeach{#2}{\dtl@refvalue=#3}{% -\DTLifnull{\dtl@refvalue}{}{% -\ifthenelse{\equal{\dtl@refvalue}{#4}}{% -\expandafter\global\expandafter\let\expandafter#1 - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname -\@endfortrue -}{}}}% -}} + \global\let#1=\@empty + \@sDTLforeach{#2}{\dtl@refvalue=#3}{% + \DTLifnull{\dtl@refvalue}% + {}% + {% + \ifthenelse{\equal{\dtl@refvalue}{#4}}% + {% + \xdef#1{\the\dtlcurrentrow}% + \dtlbreak + }% + {}% + }% + }% +} +\newcommand*{\dtlsplitrow}[4]{% + \def\@dtlsplitrow##1%before stuff + \db@col@id@w #2\db@col@id@end@% column id + ##2% unwanted stuff + \db@col@id@w #2\db@col@id@end@% column id + ##3% after stuff + \q@nil{\def#3{##1}\def#4{##3}}% + \@dtlsplitrow#1\q@nil +} +\newtoks\@dtl@list \newcommand*{\DTLsort}{\@ifstar\@sDTLsort\@DTLsort} -\newcommand*{\@DTLsort}[3][]{% -\edef\@dtl@replacementkeys{#1}% -\edef\@dtl@sortorder{#2}% -\edef\@dtl@dbname{#3}% -\let\@dtl@comparecs=\dtlcompare -\expandafter\let\expandafter\@dtl@list\csname dtldb@#3\endcsname -\dtl@sortlist{\@dtl@list}{\@dtl@sortcriteria}% -\expandafter\global\expandafter - \let\csname dtldb@#3\endcsname=\@dtl@list} -\newcommand*{\@sDTLsort}[3][]{% -\edef\@dtl@replacementkeys{#1}% -\edef\@dtl@sortorder{#2}% -\edef\@dtl@dbname{#3}% -\let\@dtl@comparecs=\dtlicompare -\expandafter\let\expandafter\@dtl@list\csname dtldb@#3\endcsname -\dtl@sortlist{\@dtl@list}{\@dtl@sortcriteria}% -\expandafter\global\expandafter - \let\csname dtldb@#3\endcsname=\@dtl@list} +\newcommand{\@DTLsort}[3][]{% + \DTLifdbexists{#3}% + {% + \edef\@dtl@replacementkeys{#1}% + \edef\@dtl@sortorder{#2}% + \let\@dtl@comparecs=\dtlcompare + \dtl@sortdata{#3}% + }% + {% + \PackageError{datatool}{Database `#3' doesn't exist}{}% + }% +} +\newcommand{\@sDTLsort}[3][]{% + \DTLifdbexists{#3}% + {% + \edef\@dtl@replacementkeys{#1}% + \edef\@dtl@sortorder{#2}% + \let\@dtl@comparecs=\dtlicompare + \dtl@sortdata{#3}% + }% + {% + \PackageError{datatool}{Database `#3' doesn't exist}{}% + }% +} +\newtoks\@dtl@rowa +\newtoks\@dtl@rowb +\newcommand*{\dtl@sortdata}[1]{% + \def\@dtl@sortedlist{}% + \edef\@dtl@dbname{#1}% + \@dtlforeachrow(\@dtl@rowAnum,\@dtl@rowAcontents)\in{#1}\do{% + \@dtl@rowa=\expandafter{\@dtl@rowAcontents}% + \def\@dtl@newlist{}% + \@dtl@insertdonefalse + \dtlrownum=0\relax + \expandafter\@dtl@foreachrow\@dtl@sortedlist + \db@row@elt@w% + \db@row@id@w \@nil\db@row@id@end@% + \db@row@id@w \@nil\db@row@id@end@% + \db@row@elt@end@% + \@@{\@dtl@rowBnum}{\@dtl@rowBcontents}{% + \@dtl@rowb=\expandafter{\@dtl@rowBcontents}% + \dtlrownum=\@dtl@rowBnum + \if@dtl@insertdone + \advance\dtlrownum by 1\relax + \else + \@dtl@sortcriteria{\@dtl@rowa}{\@dtl@rowb}% + \ifnum\dtl@sortresult<0\relax + \toks@=\expandafter{\@dtl@newlist}% + \edef\@dtl@newlist{% + \the\toks@ + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \number\dtlrownum + \noexpand\db@row@id@end@% + \the\@dtl@rowa + \noexpand\db@row@id@w \number\dtlrownum + \noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + }% + \advance\dtlrownum by 1\relax + \@dtl@insertdonetrue + \fi + \fi + \toks@=\expandafter{\@dtl@newlist}% + \edef\@dtl@newlist{\the\toks@ + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \number\dtlrownum + \noexpand\db@row@id@end@% + \the\@dtl@rowb + \noexpand\db@row@id@w \number\dtlrownum + \noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + }% + }\q@nil + \if@dtl@insertdone + \else + \advance\dtlrownum by 1\relax + \toks@=\expandafter{\@dtl@newlist}% + \edef\@dtl@newlist{\the\toks@ + \noexpand\db@row@elt@w% + \noexpand\db@row@id@w \number\dtlrownum + \noexpand\db@row@id@end@% + \the\@dtl@rowa + \noexpand\db@row@id@w \number\dtlrownum + \noexpand\db@row@id@end@% + \noexpand\db@row@elt@end@% + }% + \fi + \let\@dtl@sortedlist=\@dtl@newlist + }% + \expandafter\global\csname dtldb@#1\endcsname=\expandafter + {\@dtl@sortedlist}% +} \newcommand{\@dtl@sortcriteria}[2]{% -\@for\@dtl@level:=\@dtl@sortorder\do{% - \expandafter\@dtl@getsortdirection\@dtl@level=\relax% - \@ifundefined{@dtl@idtype@\@dtl@dbname @\@dtl@key}{% - \ifx\@dtl@replacementkeys\@empty - \PackageError{datatool}{Unknown key `\@dtl@key' for database - `\@dtl@dbname'}{}% - \else - \dtl@gathervalues[keya]{\@dtl@dbname}{#1}% - \dtl@gathervalues[keyb]{\@dtl@dbname}{#2}% - \@ifundefined{@dtl@keya@\@dtl@key}{% - \@dtl@setnull{\@dtl@tmpa}{\@dtl@key}% - }{% - \expandafter\let\expandafter\@dtl@tmpa\expandafter - =\csname @dtl@keya@\@dtl@key\endcsname}% - \@ifundefined{@dtl@keyb@\@dtl@key}{% - \@dtl@setnull{\@dtl@tmpb}{\@dtl@key}% - }{% - \expandafter\let\expandafter\@dtl@tmpb\expandafter - =\csname @dtl@keyb@\@dtl@key\endcsname}% - \let\@dtl@keya=\@dtl@key - \let\@dtl@keyb=\@dtl@key - \DTLifnull{\@dtl@tmpa}{% - % find first non null key in list of replacement keys - \@for\@dtl@keya:=\@dtl@replacementkeys\do{% - \@ifundefined{@dtl@keya@\@dtl@keya}{}{% - \expandafter\let\expandafter\@dtl@tmpa\expandafter - =\csname @dtl@keya@\@dtl@keya\endcsname - \DTLifnull{\@dtl@tmpa}{}{\@endfortrue}}% - }% - \if@endfor \else\let\@dtl@keya=\@dtl@key \fi - \@endforfalse - }{}% - \DTLifnull{\@dtl@tmpb}{% - % find first non null key in list of replacement keys - \@for\@dtl@keyb:=\@dtl@replacementkeys\do{% - \@ifundefined{@dtl@keyb@\@dtl@keyb}{}{% - \expandafter\let\expandafter\@dtl@tmpb\expandafter - =\csname @dtl@keyb@\@dtl@keyb\endcsname - \DTLifnull{\@dtl@tmpb}{}{\@endfortrue}}% - }% - \if@endfor \else\let\@dtl@keyb=\@dtl@key \fi - \@endforfalse - }{}% - \@ifundefined{@dtl@idtype@\@dtl@dbname @\@dtl@keya}{% - \@ifundefined{@dtl@idtype@\@dtl@dbname @\@dtl@keyb}{% - \dtl@sortresult=0\relax}{\dtl@sortresult=-1\relax}% - }{% - \@ifundefined{@dtl@idtype@\@dtl@dbname @\@dtl@keyb}{% - \dtl@sortresult=1\relax}{% - \dtl@compare@{\@dtl@keya}{\@dtl@keyb}{#1}{#2}% - }% - }% - \fi - }{% - \ifx\@dtl@replacementkeys\@empty - \dtl@compare{\@dtl@key}{#1}{#2}% - \else - \dtl@gathervalues[keya]{\@dtl@dbname}{#1}% - \dtl@gathervalues[keyb]{\@dtl@dbname}{#2}% - \@ifundefined{@dtl@keya@\@dtl@key}{% - \@dtl@setnull{\@dtl@tmpa}{\@dtl@key}% - }{% - \expandafter\let\expandafter\@dtl@tmpa\expandafter - =\csname @dtl@keya@\@dtl@key\endcsname}% - \@ifundefined{@dtl@keyb@\@dtl@key}{% - \@dtl@setnull{\@dtl@tmpb}{\@dtl@key}% - }{% - \expandafter\let\expandafter\@dtl@tmpb\expandafter - =\csname @dtl@keyb@\@dtl@key\endcsname}% - \let\@dtl@keya=\@dtl@key - \let\@dtl@keyb=\@dtl@key - \DTLifnull{\@dtl@tmpa}{% - % find first non null key in list of replacement keys - \@for\@dtl@keya:=\@dtl@replacementkeys\do{% - \@ifundefined{@dtl@keya@\@dtl@keya}{}{% - \expandafter\let\expandafter\@dtl@tmpa\expandafter - =\csname @dtl@keya@\@dtl@keya\endcsname - \DTLifnull{\@dtl@tmpa}{}{\@endfortrue}}% - }% - \if@endfor \else\let\@dtl@keya=\@dtl@key \fi - \@endforfalse - }{}% - \DTLifnull{\@dtl@tmpb}{% - % find first non null key in list of replacement keys - \@for\@dtl@keyb:=\@dtl@replacementkeys\do{% - \@ifundefined{@dtl@keyb@\@dtl@keyb}{}{% - \expandafter\let\expandafter\@dtl@tmpb\expandafter - =\csname @dtl@keyb@\@dtl@keyb\endcsname - \DTLifnull{\@dtl@tmpb}{}{\@endfortrue}}% - }% - \if@endfor \else\let\@dtl@keyb=\@dtl@key \fi - \@endforfalse - }{}% - \dtl@compare@{\@dtl@keya}{\@dtl@keyb}{#1}{#2}% - \fi - \multiply\dtl@sortresult by \@dtl@sortdirection\relax - \ifnum\dtl@sortresult=0\relax - \else - \@endfortrue - \fi - }% -}% + \@for\@dtl@level:=\@dtl@sortorder\do{% + \expandafter\@dtl@getsortdirection\@dtl@level=\relax + \let\@dtl@keya=\@dtl@key + \let\@dtl@keyb=\@dtl@key + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@key}% + \dtlgetentryfromrow{\@dtl@a}{\@dtl@col}{#1}% + \dtlgetentryfromrow{\@dtl@b}{\@dtl@col}{#2}% + \ifx\@dtl@a\dtlnovalue + \@dtl@setnull{\@dtl@a}{\@dtl@key}% + \fi + \ifx\@dtl@b\dtlnovalue + \@dtl@setnull{\@dtl@b}{\@dtl@key}% + \fi + \DTLifnull{\@dtl@a}% + {% + \@for\@dtl@keya:=\@dtl@replacementkeys\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@keya}% + \dtlgetentryfromrow{\@dtl@a}{\@dtl@col}{#1}% + \ifx\@dtl@a\dtlnovalue + \@dtl@setnull{\@dtl@a}{\@dtl@key}% + \fi + \DTLifnull{\@dtl@a}{}{\@endfortrue}% + }% + \ifx\@dtl@keya\@nnil + \let\@dtl@keya\@dtl@key + \@dtl@setnull{\@dtl@a}{\@dtl@key}% + \fi + }% + {}% + \DTLifnull{\@dtl@b}% + {% + \@for\@dtl@keyb:=\@dtl@replacementkeys\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@keyb}% + \dtlgetentryfromrow{\@dtl@b}{\@dtl@col}{#2}% + \ifx\@dtl@b\dtlnovalue + \@dtl@setnull{\@dtl@b}{\@dtl@key}% + \fi + \DTLifnull{\@dtl@b}{}{\@endfortrue}% + }% + \ifx\@dtl@keyb\@nnil + \let\@dtl@keyb\@dtl@key + \@dtl@setnull{\@dtl@b}{\@dtl@key}% + \fi + }% + {}% + \@dtl@toksA=\expandafter{\@dtl@a}% + \@dtl@toksB=\expandafter{\@dtl@b}% + \edef\@dtl@docompare{\noexpand\dtl@compare@ + {\@dtl@keya}{\@dtl@keyb}% + {\noexpand\@dtl@toksA}{\noexpand\@dtl@toksB}}% + \@dtl@docompare + \ifnum\dtl@sortresult=0\relax + \@endforfalse + \else + \@endfortrue + \fi + }% } \def\@dtl@getsortdirection#1=#2\relax{% -\def\@dtl@key{#1}% -\def\@dtl@sortdirection{#2}% -\ifx\@dtl@sortdirection\@empty - \def\@dtl@sortdirection{-1}% -\else - \@dtl@get@sortdirection#2% - \ifthenelse{\equal{\@dtl@sortdirection}{ascending}}{% - \def\@dtl@sortdirection{-1}}{% - \ifthenelse{\equal{\@dtl@sortdirection}{descending}}{% - \def\@dtl@sortdirection{1}}{% - \PackageError{datatool}{Invalid sort direction - `\@dtl@sortdirection'}{% - The sort direction can only be one of `ascending' or - `descending'}\def\@dtl@sortdirection{-1}}}% -\fi + \def\@dtl@key{#1}% + \def\@dtl@sortdirection{#2}% + \ifx\@dtl@sortdirection\@empty + \def\@dtl@sortdirection{-1}% + \else + \@dtl@get@sortdirection#2% + \def\@dtl@dir{ascending}% + \ifx\@dtl@sortdirection\@dtl@dir + \def\@dtl@sortdirection{-1}% + \else + \def\@dtl@dir{descending}% + \ifx\@dtl@sortdirection\@dtl@dir + \def\@dtl@sortdirection{1}% + \else + \PackageError{datatool}{Invalid sort direction + `\@dtl@sortdirection'}{The sort direction can only be + one of `ascending' or `descending'}% + \def\@dtl@sortdirection{-1} + \fi + \fi + \fi } \def\@dtl@get@sortdirection#1={\def\@dtl@sortdirection{#1}} -\newtoks\@dtl@toksA\newtoks\@dtl@toksB +\newtoks\@dtl@toksA +\newtoks\@dtl@toksB +\newtoks\@dtl@toks \newcommand{\dtl@compare}[3]{% -\dtl@gathervalues{\@dtl@dbname}{#2}% -\expandafter\let\expandafter\@dtl@tmp\expandafter - =\csname @dtl@key@#1\endcsname -\expandafter\@dtl@toksA\expandafter{\@dtl@tmp}% -\edef\@dtl@a{\the\@dtl@toksA}% -\dtl@gathervalues{\@dtl@dbname}{#3}% -\expandafter\let\expandafter\@dtl@tmp\expandafter - =\csname @dtl@key@#1\endcsname -\expandafter\@dtl@toksB\expandafter{\@dtl@tmp}% -\edef\@dtl@b{\the\@dtl@toksB}% -\expandafter\@dtl@datatype\expandafter= - \csname @dtl@idtype@\@dtl@dbname @#1\endcsname\relax -\ifnum\@dtl@datatype=0\relax - \edef\@dtl@tmpcmp{% - \noexpand\@dtl@comparecs{\noexpand\dtl@sortresult}% - {\the\@dtl@toksA}{\the\@dtl@toksB}}% - \@dtl@tmpcmp -\else - \DTLifnumlt{\@dtl@a}{\@dtl@b}{\dtl@sortresult=-1\relax}{% - \DTLifnumgt{\@dtl@a}{\@dtl@b}{\dtl@sortresult=1\relax}{% - \dtl@sortresult=0\relax}}% -\fi -\ifdtlverbose -\@onelevel@sanitize\@dtl@a -\@onelevel@sanitize\@dtl@b -\fi -\dtl@message{`\@dtl@a' <=> `\@dtl@b' = \number\dtl@sortresult}% + \dtl@compare@{#1}{#1}{#2}{#3}% } \newcommand{\dtl@compare@}[4]{% -\dtl@gathervalues{\@dtl@dbname}{#3}% -\expandafter\let\expandafter\@dtl@tmp\expandafter - =\csname @dtl@key@#1\endcsname -\expandafter\@dtl@toksA\expandafter{\@dtl@tmp}% -\edef\@dtl@a{\the\@dtl@toksA}% -\dtl@gathervalues{\@dtl@dbname}{#4}% -\expandafter\let\expandafter\@dtl@tmp\expandafter - =\csname @dtl@key@#2\endcsname -\expandafter\@dtl@toksB\expandafter{\@dtl@tmp}% -\edef\@dtl@b{\the\@dtl@toksB}% -\expandafter\@dtl@tmpcount\expandafter= - \csname @dtl@idtype@\@dtl@dbname @#1\endcsname\relax -\expandafter\@dtl@datatype\expandafter= - \csname @dtl@idtype@\@dtl@dbname @#2\endcsname\relax -\multiply\@dtl@datatype by \@dtl@tmpcount\relax -\ifnum\@dtl@datatype=0\relax - \edef\@dtl@tmpcmp{% - \noexpand\@dtl@comparecs{\noexpand\dtl@sortresult}% - {\the\@dtl@toksA}{\the\@dtl@toksB}}% - \@dtl@tmpcmp -\else - \DTLifnumlt{\@dtl@a}{\@dtl@b}{\dtl@sortresult=-1\relax}{% - \DTLifnumgt{\@dtl@a}{\@dtl@b}{\dtl@sortresult=1\relax}{% - \dtl@sortresult=0\relax}}% -\fi -\ifdtlverbose -\@onelevel@sanitize\@dtl@a -\@onelevel@sanitize\@dtl@b -\fi -\dtl@message{`\@dtl@a' <=> `\@dtl@b' = \number\dtl@sortresult}% + \DTLgetdatatype{\@dtl@typeA}{\@dtl@dbname}{#1}% + \ifx\@dtl@typeA\DTLunsettype + \let\@dtl@typeA\DTLstringtype + \fi + \DTLgetdatatype{\@dtl@typeB}{\@dtl@dbname}{#2}% + \ifx\@dtl@typeB\DTLunsettype + \let\@dtl@typeB\DTLstringtype + \fi + \@dtl@tmpcount=\@dtl@typeA\relax + \multiply\@dtl@tmpcount by \@dtl@typeB\relax + \ifnum\@dtl@tmpcount=0\relax + \edef\@dtl@tmpcmp{% + \noexpand\@dtl@comparecs{\noexpand\dtl@sortresult}% + {\the#3}{\the#4}% + }% + \@dtl@tmpcmp + \ifdtlverbose + \edef\@dtl@a{\the#3}% + \edef\@dtl@b{\the#4}% + \fi + \else + \edef\@dtl@a{\the#3}% + \edef\@dtl@b{\the#4}% + \DTLifnumlt{\@dtl@a}{\@dtl@b}% + {% + \dtl@sortresult=-1\relax + }% + {% + \DTLifnumgt{\@dtl@a}{\@dtl@b}% + {% + \dtl@sortresult=1\relax + }% + {% + \dtl@sortresult=0\relax + }% + }% + \fi + \ifdtlverbose + \@onelevel@sanitize\@dtl@a + \@onelevel@sanitize\@dtl@b + \dtl@message{`\@dtl@a' <=> `\@dtl@b' = \number\dtl@sortresult}% + \fi } \newcommand*{\dtl@choplast}[3]{% \let#2\@empty @@ -2306,7 +3610,6 @@ deeply}{}% \@endforfalse}% \let#1=\@dtl@sortedlist } -\newtoks\@dtl@toks \newcommand{\dtl@insertinto}[3]{% \def\@dtl@newsortedlist{}% \@dtl@insertdonefalse @@ -2351,6 +3654,22 @@ deeply}{}% } \newif\if@dtl@insertdone \newcount\dtl@sortresult +\newcommand{\toks@gput@right@cx}[2]{% + \def\@toks@name{#1}% + \edef\@dtl@stuff{#2}% + \global\csname\@toks@name\endcsname\expandafter + \expandafter\expandafter{\expandafter\the + \csname\expandafter\@toks@name\expandafter\endcsname\@dtl@stuff}% +} +\newcommand{\toks@gconcat@middle@cx}[4]{% + \def\@toks@name{#1}% + \edef\@dtl@stuff{#3}% + \global\csname\@toks@name\endcsname\expandafter\expandafter + \expandafter\expandafter\expandafter + \expandafter\expandafter{\expandafter\expandafter\expandafter + \the\expandafter\expandafter\expandafter#2% + \expandafter\@dtl@stuff\the#4}% +} \newcommand*{\DTLadd}[3]{% \DTLconverttodecimal{#2}{\@dtl@numi}% \DTLconverttodecimal{#3}{\@dtl@numii}% @@ -2909,155 +4228,270 @@ deeply}{}% }}} \newwrite\@dtl@write \newcommand*{\DTLsavedb}[2]{% -\DTLifdbexists{#1}{% -\openout\@dtl@write=#2% -\edef\@dtl@keys{\csname dtlkeys@#1\endcsname}% -\def\@dtl@header{}% -\@for\@dtl@key:=\@dtl@keys\do{% -\expandafter\@dtl@toks\expandafter{\@dtl@header}% -\ifx\@dtl@header\@empty - \IfSubStringInString{\@dtl@separator}{\@dtl@key}{% - \protected@edef\@dtl@header{% - \@dtl@delimiter\@dtl@key\@dtl@delimiter}% - }{% - \protected@edef\@dtl@header{\@dtl@key}% - }% -\else - \IfSubStringInString{\@dtl@separator}{\@dtl@key}{% - \protected@edef\@dtl@header{\the\@dtl@toks\@dtl@separator - \@dtl@delimiter\@dtl@key\@dtl@delimiter}% - }{% - \protected@edef\@dtl@header{\the\@dtl@toks\@dtl@separator - \@dtl@key}% - }% -\fi -}% -\protected@write\@dtl@write{}{\@dtl@header}% -\expandafter\let\expandafter\@dtl@db\csname dtldb@#1\endcsname% -\@for\@dtl@currentrow:=\@dtl@db\do{% -\dtl@gathervalues{#1}{\@dtl@currentrow}% -\def\@dtl@outputrow{}% -\@for\@dtl@key:=\@dtl@keys\do{% -\protected@edef\@dtl@element{\csname @dtl@key@\@dtl@key\endcsname}% -\expandafter\@dtl@toks\expandafter{\@dtl@outputrow}% -\ifx\@dtl@outputrow\@empty - \IfSubStringInString{\@dtl@separator}{\@dtl@element}{% - \protected@edef\@dtl@outputrow{% - \@dtl@delimiter\@dtl@element\@dtl@delimiter}% - }{% - \protected@edef\@dtl@outputrow{\@dtl@element}% - }% -\else - \IfSubStringInString{\@dtl@separator}{\@dtl@element}{% - \protected@edef\@dtl@outputrow{\the\@dtl@toks\@dtl@separator - \@dtl@delimiter\@dtl@element\@dtl@delimiter}% - }{% - \protected@edef\@dtl@outputrow{\the\@dtl@toks\@dtl@separator - \@dtl@element}% - }% -\fi -}% -\protected@write\@dtl@write{}{\@dtl@outputrow}% -}% -\closeout\@dtl@write -}{% -\PackageError{datatool}{Database `#1' doesn't exist}{}% -}} + \DTLifdbexists{#1}% + {% + \openout\@dtl@write + \def\@dtl@header{}% + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)% + \in{#1}\do + {% + \IfSubStringInString{\@dtl@separator}{\@dtl@key}% + {% + \ifx\@dtl@header\@empty + \protected@edef\@dtl@header{% + \@dtl@delimiter\@dtl@key\@dtl@delimiter}% + \else + \toks@=\expandafter{\@dtl@header}% + \protected@edef\@dtl@header{% + \the\toks@\@dtl@separator + \@dtl@delimiter\@dtl@key\@dtl@delimiter}% + \fi + }% + {% + \ifx\@dtl@header\@empty + \protected@edef\@dtl@header{\@dtl@key}% + \else + \toks@=\expandafter{\@dtl@header}% + \protected@edef\@dtl@header{\the\toks@ + \@dtl@separator\@dtl@key}% + \fi + }% + }% + \protected@write\@dtl@write{}{\@dtl@header}% + \@sDTLforeach{#1}{}% + {% + \def\@dtl@row{}% + \DTLforeachkeyinrow{\@dtl@val}% + {% + \IfSubStringInString{\@dtl@separator}{\@dtl@val}% + {% + \ifx\@dtl@row\@empty + \protected@edef\@dtl@row{% + \@dtl@delimiter\@dtl@val\@dtl@delimiter}% + \else + \toks@=\expandafter{\@dtl@row}% + \protected@edef\@dtl@row{\the\toks@\@dtl@separator + \@dtl@delimiter\@dtl@val\@dtl@delimiter}% + \fi + }% + {% + \ifx\@dtl@row\@empty + \protected@edef\@dtl@row{\@dtl@val}% + \else + \toks@=\expandafter{\@dtl@row}% + \protected@edef\@dtl@row{\the\toks@\@dtl@separator + \@dtl@val}% + \fi + }% + \protected@write\@dtl@write{}{\@dtl@row}% + }% + }% + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} \newcommand*{\DTLsavetexdb}[2]{% -\DTLifdbexists{#1}{% -\def\@dtl@dbname{#1}% -\openout\@dtl@write=#2% -\edef\@dtl@keys{\csname dtlkeys@#1\endcsname}% -\protected@write\@dtl@write{}{\string\DTLnewdb{#1}}% -\expandafter\let\expandafter\@dtl@db\csname dtldb@#1\endcsname% -\@for\@dtl@currentrow:=\@dtl@db\do{% -\dtl@gathervalues{#1}{\@dtl@currentrow}% -\protected@write\@dtl@write{}{\string\DTLnewrow{#1}}% -\@for\@dtl@key:=\@dtl@keys\do{% -\expandafter\DTLifnull\csname @dtl@key@\@dtl@key\endcsname -{}{% -\protected@edef\@dtl@element{\csname @dtl@key@\@dtl@key\endcsname}% -\protected@write\@dtl@write{}{\string\DTLnewdbentry - {#1}{\@dtl@key}{\@dtl@element}}% -}% -}% -}% -\closeout\@dtl@write -}{% -\PackageError{datatool}{Database `#1' doesn't exist}{}% -}} + \DTLifdbexists{#1}% + {% + \openout\@dtl@write=#2\relax + \protected@write\@dtl@write{}{\string\DTLnewdb{#1}}% + \@sDTLforeach{#1}{}% + {% + \protected@write\@dtl@write{}{\string\DTLnewrow*{#1}}% + \DTLforeachkeyinrow{\@dtl@val}% + {% + \DTLifnull{\@dtl@val}% + {\def\@dtl@val{}}% + {}% + \protected@write\@dtl@write{}{% + \string\DTLnewdbentry*{#1}{\dtlkey}{\@dtl@val}}% + }% + }% + \dtlforeachkey(\@dtl@k,\@dtl@c,\@dtl@t,\@dtl@h)\in{#1}\do + {% + \@onelevel@sanitize\@dtl@h + \protected@write\@dtl@write{}{% + \string\DTLsetheader*{#1}{\@dtl@k}{\@dtl@h}}% + }% + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} +\newcommand{\@longempty}{} \newread\@dtl@read \newcount\dtl@entrycr -\gdef\DTLloaddb#1#2{% -\IfFileExists{#2}{% -\begingroup -\catcode`\"12\relax -\openin\@dtl@read=#2% -\dtl@message{Reading `#2'}% -\DTLnewdb{#1}% -\ifeof\@dtl@read -\else - \loop - \@dtl@conditionfalse +\define@boolkey{loaddb}[dtl]{noheader}[true]{} +\define@key{loaddb}{keys}{% + \dtl@entrycr=0\relax + \@for\@dtl@key:=#1\do + {% + \advance\dtl@entrycr by 1\relax + \expandafter + \edef\csname @dtl@inky@\romannumeral\dtl@entrycr\endcsname{% + \@dtl@key}% + }% +} +\define@key{loaddb}{headers}{% + \dtl@entrycr=0\relax + \@for\@dtl@head:=#1\do + {% + \advance\dtl@entrycr by 1\relax + \toks@=\expandafter{\@dtl@head}% + \expandafter + \edef\csname @dtl@inhd@\romannumeral\dtl@entrycr\endcsname{% + \the\toks@}% + }% +} +\newcommand*{\dtldefaultkey}{Column} +\newcommand*{\@dtl@readline}[2]{% + \read#1 to #2% + \dtl@trim#2% +} +\newcommand*{\@dtl@readrawline}[2]{% + \@dtl@rawread#1 to #2% + \dtl@trim#2% + \dtl@domappings\@dtl@line +} + +\newcommand*{\DTLloaddb}{% + \let\@dtl@doreadline\@dtl@readline + \@dtlloaddb +} +\newcommand*{\@dtlloaddb}[3][]{% + \IfFileExists{#3}{% + \begingroup + \catcode`\"12\relax + \dtlnoheaderfalse + \setkeys{loaddb}{#1}% + \openin\@dtl@read=#3% + \dtl@message{Reading `#3'}% + \DTLnewdb{#2}% \ifeof\@dtl@read + \PackageWarning{datatool}{File `#3' has no data}% \else - \read\@dtl@read to \@dtl@line - \dtl@trim\@dtl@line - \if\@dtl@line\par - \@dtl@conditiontrue + \ifdtlnoheader + \else + \loop + \@dtl@conditionfalse + \ifeof\@dtl@read + \else + \@dtl@doreadline\@dtl@read\@dtl@line + \ifx\@dtl@line\@longempty + \@dtl@conditiontrue + \fi + \fi + \if@dtl@condition + \repeat + \protected@edef\@dtl@lin@{% + \@dtl@separator\@dtl@line\@dtl@separator}% + \dtl@entrycr=0\relax + \loop + \expandafter\@dtl@lopoff\@dtl@lin@\to\@dtl@lin@\@dtl@key + \advance\dtl@entrycr by 1\relax + \expandafter\@dtl@toks\expandafter{\@dtl@key}% + \@ifundefined{@dtl@inky@\romannumeral\dtl@entrycr}% + {% + \expandafter + \edef\csname @dtl@inky@\romannumeral + \dtl@entrycr\endcsname{\the\@dtl@toks}% + }% + {% + \@ifundefined{@dtl@inhd@\romannumeral\dtl@entrycr}% + {% + \expandafter + \edef\csname @dtl@inhd@\romannumeral + \dtl@entrycr\endcsname{\the\@dtl@toks}% + }% + {}% + }% + \ifx\@dtl@lin@\@dtl@separator + \@dtl@conditionfalse + \else + \@dtl@conditiontrue + \fi + \if@dtl@condition + \repeat \fi + \ifeof\@dtl@read + \ifdtlnoheader + \PackageWarning{datatool}{No data in `#3'}% + \else + \PackageWarning{datatool}{Only header row found in `#3'}% + \fi + \else + \@dtl@conditiontrue + \loop + \@dtl@doreadline\@dtl@read\@dtl@line + \ifx\@dtl@line\@longempty + \else + \@sDTLnewrow{#2}% + \expandafter\@dtl@toks\expandafter{\@dtl@line}% + \edef\@dtl@lin@{\@dtl@separator\the\@dtl@toks + \@dtl@separator}% + \dtl@entrycr=0\relax + {% + \@dtl@conditiontrue + \loop + \expandafter\@dtl@lopoff\@dtl@lin@\to + \@dtl@lin@\@dtl@thisentry + \advance\dtl@entrycr by 1\relax + \@ifundefined{@dtl@inky@\romannumeral\dtl@entrycr}% + {% + \edef\@dtl@thiskey{\dtldefaultkey + \number\dtl@entrycr}% + \expandafter\let + \csname @dtl@inky@\romannumeral + \dtl@entrycr\endcsname\@dtl@thiskey + }% + {% + \edef\@dtl@thiskey{% + \csname @dtl@inky@\romannumeral + \dtl@entrycr\endcsname}% + }% + \expandafter\@dtl@toks\expandafter{\@dtl@thisentry}% + \edef\@do@dtlnewentry{\noexpand\@sDTLnewdbentry + {#2}{\@dtl@thiskey}{\the\@dtl@toks}}% + \@do@dtlnewentry + \ifx\@dtl@lin@\@dtl@separator + \@dtl@conditionfalse + \fi + \if@dtl@condition + \repeat + }% + \fi + \ifeof\@dtl@read \@dtl@conditionfalse\fi + \if@dtl@condition + \repeat + \fi \fi - \if@dtl@condition - \repeat - \ifeof\@dtl@read - \else - \protected@edef\@dtl@lin@{\@dtl@separator\@dtl@line\@dtl@separator}% - \@dtl@tmpcount=0\relax - \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% - \expandafter\@dtl@lopoff\@dtl@lin@\to\@dtl@lin@\@dtl@key - \advance\@dtl@tmpcount by 1\relax - \expandafter\@dtl@toks\expandafter{\@dtl@key}% - \expandafter - \edef\csname @dtl@inky@\romannumeral\@dtl@tmpcount\endcsname{% - \the\@dtl@toks}% - }% - \ifeof\@dtl@read - \else - \@dtl@conditiontrue - \loop - \read\@dtl@read to \@dtl@line - \dtl@trim\@dtl@line - \ifthenelse{\equal{\@dtl@line}{}}{}% - {% - \DTLnewrow{#1}% - \expandafter\@dtl@toks\expandafter{\@dtl@line}% - \edef\@dtl@lin@{\@dtl@separator\the\@dtl@toks - \@dtl@separator}% - \dtl@entrycr=0\relax - \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% - \expandafter\@dtl@lopoff\@dtl@lin@\to - \@dtl@lin@\@dtl@thisentry - \advance\dtl@entrycr by 1\relax - \edef\@dtl@thiskey{% - \csname @dtl@inky@\romannumeral\dtl@entrycr\endcsname}% - \expandafter\@dtl@toks\expandafter{\@dtl@thisentry}% - \edef\@do@dtlnewentry{\noexpand\DTLnewdbentry - {#1}{\@dtl@thiskey}{\the\@dtl@toks}}% - \@do@dtlnewentry - }% - }% - \ifeof\@dtl@read \@dtl@conditionfalse\fi - \if@dtl@condition - \repeat - \fi - \fi -\fi -\closein\@dtl@read -\endgroup -}{% -\PackageError{datatool}{Can't load database `#1' (file `#2' -doesn't exist)}{}% -}} + \closein\@dtl@read + \edef\@dtl@maxcols{\expandafter + \number\csname dtlcols@#2\endcsname}% + \dtlgforint\dtl@entrycr=1\to\@dtl@maxcols\step1\do + {% + \@ifundefined{@dtl@inhd@\romannumeral\dtl@entrycr}% + {}% + {% + \expandafter\let\expandafter\@dtl@head + \csname @dtl@inhd@\romannumeral\dtl@entrycr\endcsname + \@dtl@toks=\expandafter{\@dtl@head}% + \edef\@dtl@dosetheader{\noexpand\@dtl@setheaderforindex + {#2}{\number\dtl@entrycr}{\the\@dtl@toks}}% + \@dtl@dosetheader + }% + }% + \endgroup + }{% + \PackageError{datatool}{Can't load database `#2' (file `#3' + doesn't exist)}{}% + }% +} \newcommand{\dtl@trim}[1]{% \def\@dtl@trmstr{}% \expandafter\@dtl@starttrim#1\@nil% @@ -3072,75 +4506,10 @@ doesn't exist)}{}% \@dtl@dotrim% } \long\def\@dtl@trim#1 \@nil{\long\def\@dtl@trmstr{#1}} -\gdef\DTLloadrawdb#1#2{% -\IfFileExists{#2}{% -\openin\@dtl@read=#2% -\dtl@message{Reading `#2'}% -\DTLnewdb{#1}% -\ifeof\@dtl@read -\else - \loop - \@dtl@conditionfalse - \ifeof\@dtl@read - \else - \@dtl@rawread\@dtl@read to\@dtl@line - \dtl@trim\@dtl@line - \if\@dtl@line\par - \@dtl@conditiontrue - \fi - \fi - \if@dtl@condition - \repeat - \ifeof\@dtl@read - \else - \dtl@domappings\@dtl@line - \protected@edef\@dtl@lin@{\@dtl@separator\@dtl@line\@dtl@separator}% - \@dtl@tmpcount=0\relax - \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% - \expandafter\@dtl@lopoff\@dtl@lin@\to\@dtl@lin@\@dtl@key - \advance\@dtl@tmpcount by 1\relax - \expandafter\@dtl@toks\expandafter{\@dtl@key}% - \expandafter - \edef\csname @dtl@inky@\romannumeral\@dtl@tmpcount\endcsname{% - \the\@dtl@toks}% - }% - \ifeof\@dtl@read - \else - \@dtl@conditiontrue - \loop - \@dtl@rawread\@dtl@read to\@dtl@line - \dtl@trim\@dtl@line - \ifthenelse{\equal{\@dtl@line}{}}{}% - {% - \DTLnewrow{#1}% - \dtl@domappings\@dtl@line - \expandafter\@dtl@toks\expandafter{\@dtl@line}% - \edef\@dtl@lin@{\@dtl@separator\the\@dtl@toks - \@dtl@separator}% - \dtl@entrycr=0\relax - \whiledo{\not\equal{\@dtl@lin@}{\@dtl@separator}}{% - \expandafter\@dtl@lopoff\@dtl@lin@\to - \@dtl@lin@\@dtl@thisentry - \advance\dtl@entrycr by 1\relax - \edef\@dtl@thiskey{% - \csname @dtl@inky@\romannumeral\dtl@entrycr\endcsname}% - \expandafter\@dtl@toks\expandafter{\@dtl@thisentry}% - \edef\@do@dtlnewentry{\noexpand\DTLnewdbentry - {#1}{\@dtl@thiskey}{\the\@dtl@toks}}% - \@do@dtlnewentry - }% - }% - \ifeof\@dtl@read \@dtl@conditionfalse\fi - \if@dtl@condition - \repeat - \fi - \fi -\fi -\closein\@dtl@read -}{% -\PackageError{datatool}{Can't load database `#1' (file `#2' -doesn't exist)}{}% -}} +\newcommand*\DTLloadrawdb{% + \let\@dtl@doreadline\@dtl@readrawline + \@dtlloaddb +} \begingroup \catcode`\%=\active \catcode`$=\active @@ -3258,6 +4627,19 @@ doesn't exist)}{}% \@dtl@dosubstnext{#1}{#2}% } \def\@dtl@dosubstitutenoop#1#2{} +\newcommand*{\DTLifinlist}[4]{% + \def\@dtl@doifinlist##1,#1,##2\end@dtl@doifinlist{% + \def\@before{##1}% + \def\@after{##2}% + }% + \expandafter\@dtl@doifinlist\expandafter,#2,#1,\@nil + \end@dtl@doifinlist + \ifx\@after\@nnil + #4% + \else + #3% + \fi +} \newcommand*{\@dtl@currencies}{\$,\pounds} \newcommand*{\DTLnewcurrencysymbol}[1]{% \expandafter\toks@\expandafter{\@dtl@currencies}% @@ -3308,11 +4690,12 @@ doesn't exist)}{}% \fi } \newcommand*{\dtlshowdb}[1]{% -\expandafter\show\csname dtldb@#1\endcsname} +\expandafter\showthe\csname dtldb@#1\endcsname} \newcommand*{\dtlshowdbkeys}[1]{% -\expandafter\show\csname dtlkeys@#1\endcsname} +\expandafter\showthe\csname dtlkeys@#1\endcsname} \newcommand*{\dtlshowtype}[2]{% -\expandafter\show\csname @dtl@idtype@#1@#2\endcsname} + \DTLgetdatatype{\@dtl@type}{#1}{#2}\show\@dtl@type +} \endinput %% %% End of file `datatool.sty'. |