From de3f0b6a3f872b5de7a6efb9d84a368e5c059f61 Mon Sep 17 00:00:00 2001 From: "Dr. Clea F. Rees" Date: Sun, 1 Mar 2009 20:35:54 +0000 Subject: datatool new version git-svn-id: svn://tug.org/texlive/trunk@12277 c570f23f-e606-0410-a88d-b1316a301751 --- Master/texmf-dist/bibtex/bst/datatool/databib.bst | 26 +- Master/texmf-dist/doc/latex/datatool/CHANGES | 80 + Master/texmf-dist/doc/latex/datatool/README | 206 +- Master/texmf-dist/doc/latex/datatool/datatool.pdf | Bin 0 -> 1455516 bytes Master/texmf-dist/doc/latex/datatool/doc/CHANGES | 32 - .../texmf-dist/doc/latex/datatool/doc/datatool.pdf | Bin 1180800 -> 0 bytes .../texmf-dist/source/latex/datatool/datatool.dtx | 11353 +++++++++++++------ .../texmf-dist/source/latex/datatool/datatool.ins | 4 +- Master/texmf-dist/tex/latex/datatool/databar.sty | 20 +- Master/texmf-dist/tex/latex/datatool/databib.sty | 149 +- Master/texmf-dist/tex/latex/datatool/datapie.sty | 4 +- Master/texmf-dist/tex/latex/datatool/dataplot.sty | 71 +- Master/texmf-dist/tex/latex/datatool/datatool.sty | 3419 ++++-- 13 files changed, 10963 insertions(+), 4401 deletions(-) create mode 100644 Master/texmf-dist/doc/latex/datatool/CHANGES create mode 100644 Master/texmf-dist/doc/latex/datatool/datatool.pdf delete mode 100644 Master/texmf-dist/doc/latex/datatool/doc/CHANGES delete mode 100644 Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf (limited to 'Master') diff --git a/Master/texmf-dist/bibtex/bst/datatool/databib.bst b/Master/texmf-dist/bibtex/bst/datatool/databib.bst index c114335a843..7999f9f6c08 100644 --- a/Master/texmf-dist/bibtex/bst/datatool/databib.bst +++ b/Master/texmf-dist/bibtex/bst/datatool/databib.bst @@ -7,7 +7,7 @@ %% datatool.dtx (with options: `databib.bst') %% %% 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 @@ -52,6 +52,7 @@ ENTRY pubmed url abstract + file } {} { label } @@ -378,6 +379,16 @@ FUNCTION {format.url} if$ } +FUNCTION {format.file} +{ file empty$ + { "" } + { + file + "\DTLnewbibitem {File}" swap$ group * + } + if$ +} + FUNCTION {format.address} { address empty$ { "" } @@ -758,6 +769,7 @@ FUNCTION {article} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -799,6 +811,7 @@ FUNCTION {book} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -821,6 +834,7 @@ FUNCTION {booklet} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -863,6 +877,7 @@ FUNCTION {inbook} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -894,6 +909,7 @@ FUNCTION {incollection} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -933,6 +949,7 @@ FUNCTION {inproceedings} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -977,6 +994,7 @@ FUNCTION {manual} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -1001,6 +1019,7 @@ FUNCTION {mastersthesis} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -1022,6 +1041,7 @@ FUNCTION {misc} format.pubmed output format.url output format.abstract output + format.file output fin.entry empty.misc.check } @@ -1047,6 +1067,7 @@ FUNCTION {phdthesis} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -1090,6 +1111,7 @@ FUNCTION {proceedings} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -1113,6 +1135,7 @@ FUNCTION {techreport} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -1131,6 +1154,7 @@ FUNCTION {unpublished} format.pubmed output format.url output format.abstract output + format.file output format.date output fin.entry } diff --git a/Master/texmf-dist/doc/latex/datatool/CHANGES b/Master/texmf-dist/doc/latex/datatool/CHANGES new file mode 100644 index 00000000000..4b9d5b36183 --- /dev/null +++ b/Master/texmf-dist/doc/latex/datatool/CHANGES @@ -0,0 +1,80 @@ +v2.0 (2009/02/27): + datatool.sty: + + * Rewritten database internal representation to make the code + faster (thanks to Morten H\o gholm for the suggestion) + * added etex as a required package + * Database columns can now have an associated header (in addition + to the key) + * added \DTLdisplaydb and \DTLdisplaylongdb + * added \DTLremoverow + * \DTLloaddb, \DTLloadrawdb: + - removed unnecessary checks to determine if database + exists when adding entries. + - added optional argument + - can now also load files without header row + * \DTLsumforkeys, \DTLmeanforkeys, \DTLvarianceforkeys, + \DTLsdforkeys, \DTLminforkeys and \DTLmaxforkeys now have a + second optional argument + * added \DTLsumcolumn, \DTLmeanforcolumn, \DTLvarianceforcolumn, + \DTLsdforcolumn, \DTLminforcolumn and \DTLmaxforcolumn + * added \dtlforeachkey + * added \dtlforint and \dtlgforint + * added \dtlforcolumn and \dtlforcolumnidx + * added \DTLcolumncount + * added starred versions of: + - \DTLifdbempty + - \DTLnewrow + * added \DTLifhaskey + * added \DTLgetcolumnindex + * added \DTLunsettype, \DTLstringtype, \DTLinttype, \DTLrealtype + and \DTLcurrencytype + * added \DTLgetdatatype + * removed \@dtl@setidtype + * removed \@dtl@setkeys + * removed \@dtl@getidtype + * removed \@dtl@ifrowcontains + * removed \dtl@getentryvalue + * removed \dtl@getentryid + * added \dtlgetentryfromcurrentrow + * added \dtlforcolumnindex + + dataplot.sty + * fixed bug causing ! Argument of \pgfmath@afterquick has an extra } + error + + databar.sty + * added \DTLeverybarhook + +v1.01 (2007/08/17) : + * Added databib package. + + * datatool.sty: + + - Fixed bug in datatool caused when certain commands occur + in database entries or when the data type is tested. + - Fixed bug in \DTLsubstituteall (caused problems when certain + - commands occurred in string) + - Added \DTLsplitstring + - Added \DTLifSubString and \DTLisSubString + - Added \DTLifStartsWith and \DTLisPrefix + - Added case insensitive string tests + - \DTLinitials and \DTLstoreinitials now work with ~ and \space + - \DTLinitials and \DTLstoreinitials now use \DTLinitialhyphen + - Added \dtlcompare (no longer using compare.tex) + - Added \DTLgetvalueforkey + - Added \DTLgetrowforkey + - Added optional argument to \DTLsort + - Fixed bug causing expansion in \DTLsort + - Fixed bug in \DTLsdforall and \DTLvarianceforall + - Removed extraneous spaces in \DTLaddall, \DTLminall, + \DTLmaxall, \DTLmeanforall, \DTLsdforall and \DTLvarianceforall + - Fixed bug in \DTLiflastrow + - Fixed bug in \DTLremovecurrentrow + + * Manual: + - added code that produces fig "Student Marks (with average scores". + - fixed typos in examples "Editing Database Rows" & "Mail Merging" + - added section on null values + +v1.0 (2007/07/23) : Initial Release diff --git a/Master/texmf-dist/doc/latex/datatool/README b/Master/texmf-dist/doc/latex/datatool/README index 581ed50375f..ad9f718294a 100644 --- a/Master/texmf-dist/doc/latex/datatool/README +++ b/Master/texmf-dist/doc/latex/datatool/README @@ -1,101 +1,105 @@ -LaTeX Bundle : datatool v1.01 (datatool.sty, datapie.sty, dataplot.sty, databar.sty, databib.sty) - -Last Modified : 17 Aug 2007 - -Author : Nicola Talbot - -datatool.sty: - - Databases can be created using LaTeX commands or loaded - from external ASCII files, such as comma or tab separated - variable files. - - Databases can be sorted numerically or alphabetically - (descending or ascending.) - - Repetitive operations can be performed on each row of - data in a database (such as mail merging.) Conditions - can be imposed to exclude rows. - - Commands are provided to determine if an argument is - an integer, a real number, currency or a string. - (Scientific notation is currently not supported.) - - Locale dependent number settings are supported - (such as a comma as a decimal character and full stop as - a number group character.) - - Commands are provided to convert between locale dependent - numbers/currency and the standard decimal format required - by the fp package enabling fixed point arithmetic to be - performed on elements of the database. - - Strings can be tested to determine if they are all upper - or all lower case. - - Names can be converted to initials using \DTLinitials. - -datapie.sty: - - A database defined by datatool.sty can be converted into a - pie chart. - - Segments can be separated from the rest of the chart to make - them stand out. - - Colour/grey scale options. - - Predefined segment colours can be changed. - - Hooks provided to annotate chart. - -dataplot.sty: - - A database defined by datatool.sty may be plotted as a 2D - scatter or line plot - - Settings provided to govern the appearance of the chart. - (e.g. show/hide axes, legend, grid, major/minor tick marks.) - - Hooks provided to add extra information to the plot - -databar.sty: - - A database defined by datatool.sty can be converted into a - bar chart. - - Colour/grey scale options. - - Predefined bar colours can be changed. - - Horizontal or vertical formats provided. - - Hooks provided to annotate chart. - -databib.sty: - - Provides commands to convert a BibTeX database into a datatool - database. - -*The datatool bundle replaces the csvtools bundle which is now obsolete.* - -The datatool.sty package requires the following packages/files: - -xkeyval -xfor -fp -substr - -The datapie.sty, dataplot.sty and databar.sty packages requires -the tikz/pgf package. - -*Remember to refresh TeX's database* - -The package and documentation source code is also supplied as a -dtx and ins file located in texmf/source. - -This material is subject to the LaTeX Project Public License. -See http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html for the details of that license. - -http://theoval.cmp.uea.ac.uk/~nlct/ - +LaTeX Bundle : datatool v2.0 (datatool.sty, datapie.sty, dataplot.sty, databar.sty, databib.sty) + +Last Modified : 27 February 2009 + +Author : Nicola Talbot + +datatool.sty: + + Databases can be created using LaTeX commands or loaded + from external ASCII files, such as comma or tab separated + variable files. + + Databases can be sorted numerically or alphabetically + (descending or ascending.) + + Repetitive operations can be performed on each row of + data in a database (such as mail merging.) Conditions + can be imposed to exclude rows. + + Commands are provided to determine if an argument is + an integer, a real number, currency or a string. + (Scientific notation is currently not supported.) + + Locale dependent number settings are supported + (such as a comma as a decimal character and full stop as + a number group character.) + + Commands are provided to convert between locale dependent + numbers/currency and the standard decimal format required + by the fp package enabling fixed point arithmetic to be + performed on elements of the database. + + Strings can be tested to determine if they are all upper + or all lower case. + + Names can be converted to initials using \DTLinitials. + +datapie.sty: + + A database defined by datatool.sty can be converted into a + pie chart. + + Segments can be separated from the rest of the chart to make + them stand out. + + Colour/grey scale options. + + Predefined segment colours can be changed. + + Hooks provided to annotate chart. + +dataplot.sty: + + A database defined by datatool.sty may be plotted as a 2D + scatter or line plot + + Settings provided to govern the appearance of the chart. + (e.g. show/hide axes, legend, grid, major/minor tick marks.) + + Hooks provided to add extra information to the plot + +databar.sty: + + A database defined by datatool.sty can be converted into a + bar chart. + + Colour/grey scale options. + + Predefined bar colours can be changed. + + Horizontal or vertical formats provided. + + Hooks provided to annotate chart. + +databib.sty: + + Provides commands to convert a BibTeX database into a datatool + database. + +*The datatool bundle replaces the csvtools bundle which is now obsolete.* + +REQUIRED PACKAGES: + +The datatool.sty package requires the following packages/files: + +xkeyval +ifthen +xfor +fp +substr +etex + +The datapie.sty, dataplot.sty and databar.sty packages +additionally require the tikz/pgf bundle. + +*Remember to refresh TeX's database* + +The package and documentation source code is also supplied as a +dtx and ins file located in texmf/source. + +This material is subject to the LaTeX Project Public License. +See http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html for the details of that license. + +http://theoval.cmp.uea.ac.uk/~nlct/ + diff --git a/Master/texmf-dist/doc/latex/datatool/datatool.pdf b/Master/texmf-dist/doc/latex/datatool/datatool.pdf new file mode 100644 index 00000000000..d45aac71de9 Binary files /dev/null and b/Master/texmf-dist/doc/latex/datatool/datatool.pdf differ diff --git a/Master/texmf-dist/doc/latex/datatool/doc/CHANGES b/Master/texmf-dist/doc/latex/datatool/doc/CHANGES deleted file mode 100644 index a898c349e78..00000000000 --- a/Master/texmf-dist/doc/latex/datatool/doc/CHANGES +++ /dev/null @@ -1,32 +0,0 @@ -v1.01 (2007/08/17) : - * Added databib package. - - * datatool.sty: - - - Fixed bug in datatool caused when certain commands occur - in database entries or when the data type is tested. - - Fixed bug in \DTLsubstituteall (caused problems when certain - - commands occurred in string) - - Added \DTLsplitstring - - Added \DTLifSubString and \DTLisSubString - - Added \DTLifStartsWith and \DTLisPrefix - - Added case insensitive string tests - - \DTLinitials and \DTLstoreinitials now work with ~ and \space - - \DTLinitials and \DTLstoreinitials now use \DTLinitialhyphen - - Added \dtlcompare (no longer using compare.tex) - - Added \DTLgetvalueforkey - - Added \DTLgetrowforkey - - Added optional argument to \DTLsort - - Fixed bug causing expansion in \DTLsort - - Fixed bug in \DTLsdforall and \DTLvarianceforall - - Removed extraneous spaces in \DTLaddall, \DTLminall, - \DTLmaxall, \DTLmeanforall, \DTLsdforall and \DTLvarianceforall - - Fixed bug in \DTLiflastrow - - Fixed bug in \DTLremovecurrentrow - - * Manual: - - added code that produces fig "Student Marks (with average scores". - - fixed typos in examples "Editing Database Rows" & "Mail Merging" - - added section on null values - -v1.0 (2007/07/23) : Initial Release diff --git a/Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf b/Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf deleted file mode 100644 index eb622488c8e..00000000000 Binary files a/Master/texmf-dist/doc/latex/datatool/doc/datatool.pdf and /dev/null differ diff --git a/Master/texmf-dist/source/latex/datatool/datatool.dtx b/Master/texmf-dist/source/latex/datatool/datatool.dtx index f2afe8ec4b3..fe88d5377eb 100644 --- a/Master/texmf-dist/source/latex/datatool/datatool.dtx +++ b/Master/texmf-dist/source/latex/datatool/datatool.dtx @@ -2,12 +2,12 @@ % datatool.dtx generated using makedtx version 0.94b (c) Nicola Talbot % Command line args: % -macrocode "databib.bst" -% -src "datatool.sty=>datatool.sty" -% -src "datapie.sty=>datapie.sty" -% -src "dataplot.sty=>dataplot.sty" -% -src "databar.sty=>databar.sty" -% -src "databib.sty=>databib.sty" -% -src "databib.bst=>databib.bst" +% -src "datatool.sty\Z=>datatool.sty" +% -src "datapie.sty\Z=>datapie.sty" +% -src "dataplot.sty\Z=>dataplot.sty" +% -src "databar.sty\Z=>databar.sty" +% -src "databib.sty\Z=>databib.sty" +% -src "databib.bst\Z=>databib.bst" % -author "Nicola Talbot" % -dir "source" % -setambles ".*\.bst=>\nopreamble\usepreamble\defaultpreamble\nopostamble" @@ -15,7 +15,7 @@ % -doc "manual.tex" % -codetitle "datatool.sty" % datatool -% Created on 2007/8/19 14:27 +% Created on 2009/2/27 13:27 %\fi %\iffalse %<*package> @@ -38,7 +38,7 @@ %\fi % \iffalse % Doc-Source file to use with LaTeX2e -% Copyright (C) 2007 Nicola Talbot, all rights reserved. +% Copyright (C) 2009 Nicola Talbot, all rights reserved. % \fi % \iffalse %<*driver> @@ -49,6 +49,9 @@ \usepackage{textcomp} \usepackage{graphicx} \usepackage{colortbl} +\usepackage{cmap} +\usepackage[T1]{fontenc} +\usepackage[utf8]{inputenc} \usepackage[colorlinks, bookmarks, hyperindex=false, @@ -77,7 +80,7 @@ \makeatother \RecordChanges \PageIndex -\CheckSum{13202} +\CheckSum{15413} \newcommand*{\sty}[1]{\textsf{#1}} \newcommand*{\env}[1]{\textsf{#1}} @@ -100,7 +103,8 @@ \newsavebox\defsbox \newlength\defwidth -\newenvironment{definition}{% +\newenvironment{definition}[1][]{% +\def\defarg{#1}% \setlength{\fboxsep}{4pt}\setlength{\fboxrule}{1.25pt}% \begin{lrbox}{\defsbox}% \setlength\defwidth\linewidth @@ -112,7 +116,7 @@ \end{lrbox}% \vskip10pt \noindent -\fcolorbox{black}{defbackground}{\usebox\defsbox}% +\defarg\fcolorbox{black}{defbackground}{\usebox\defsbox}% \vskip10pt } @@ -132,6 +136,9 @@ \newcommand*{\pkgopt}[2][datatool]{\textsf{#2}\index {#1 package options=\textsf{#1} package options>#2=\textsf{#2}|hyperpage}} +\newcommand*{\cmdopt}[2]{\textsf{#2}\index{#1 options=\cs{#1} +options>#2=\textsf{#2}|hyperpage}} + \newcounter{example} \newcommand*{\examplename}{example} \makeatletter @@ -166,7 +173,7 @@ %\MakeShortVerb{"} %\DeleteShortVerb{\|} % -% \title{datatool v 1.01: Databases and data manipulation} +% \title{datatool v 2.0: Databases and data manipulation} % \author{Nicola L.C. Talbot\\[10pt] %School of Computing Sciences\\ %University of East Anglia\\ @@ -174,7 +181,7 @@ %NR4 7TJ. United Kingdom.\\ %\url{http://theoval.cmp.uea.ac.uk/~nlct/}} % -% \date{17th August 2007} +% \date{27th February 2009} % \maketitle %\tableofcontents %\listofexamples @@ -192,14 +199,14 @@ %\begin{itemize} %\item Create or load databases. %\item Sort rows of a database (either numerically or alphabetically, -%ascending or descending.) +%ascending or descending). %\item Perform repetitive operations on each row of a database -%(e.g.\ mail merging.) Conditions may be imposed to exclude rows. +%(e.g.\ mail merging). Conditions may be imposed to exclude rows. %\item Determine whether an argument is an integer, a real number, %currency or a string. (Scientific notation is currently not %supported.) Locale dependent number settings are supported (such %as a comma as a decimal character and a full stop as a number -%group character.) +%group character). %\item Convert locale dependent numbers/currency to the decimal %format required by the \sty{fp} package, enabling fixed point %arithmetic to be performed on elements of the database. @@ -233,7 +240,8 @@ %later date. The use of 3D charts should be discouraged. They may look %pretty, but the purpose of a chart is to be informative. Three %dimensional graphics cause distortion, which can result in misleading -%impressions.) +%impressions. The \sty{pgf} manual provides a more in-depth +%discussion on the matter.) % %The \sty{dataplot} package can be used to convert a database into %a two dimensional plot using markers and/or lines. Three dimensional @@ -252,14 +260,13 @@ %\item[Integers] An integer is a sequence of digits, optionally %groups of three digits may be separated by the number group character. %The default number group character is a comma (,) but may be -%changed using \cs{DTLsetnumberchars} (see below.) +%changed using \cs{DTLsetnumberchars} (see below). % %\item[Real Numbers] A real number is an integer followed by the %decimal character followed by one or more digits. The decimal %character is a full stop (.) by default. The number group %and decimal characters may be changed using -%\DescribeMacro{\DTLsetnumberchars} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsetnumberchars}]% %\cs{DTLsetnumberchars}\marg{number group character}\marg{decimal character} %\end{definition} %Note that scientific notation is not supported, and the number group @@ -273,8 +280,7 @@ %symbol: \cs{texteuro}, \cs{textdollar}, \cs{textstirling}, %\cs{textyen}, \cs{textwon}, \cs{textcurrency}, \cs{euro} %and \cs{yen}. Additional currency symbols can be defined using -%\DescribeMacro{\DTLnewcurrencysymbol} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLnewcurrencysymbol}]% %\cs{DTLnewcurrencysymbol}\marg{symbol} %\end{definition} % @@ -288,9 +294,7 @@ % %The following conditionals are provided by the \sty{datatool} %package: -% -%\DescribeMacro{\DTLifint} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifint}]% %\cs{DTLifint}\marg{text}\marg{true part}\marg{false part} %\end{definition} %If \meta{text} is an integer then do \meta{true part}, otherwise @@ -334,8 +338,7 @@ %\DTLsetnumberchars{,}{.}\relax %\DTLifint{2,536m}{integer}{not an integer}. % -%\DescribeMacro{\DTLifreal} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifreal}]% %\cs{DTLifreal}\marg{text}\marg{true part}\marg{false part} %\end{definition} %If \meta{text} is a real number then do \meta{true part}, otherwise @@ -379,8 +382,7 @@ %\DTLsetnumberchars{,}{.}\relax %\DTLifreal{\$1.00}{real}{not real}. % -%\DescribeMacro{\DTLifcurrency} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifcurrency}]% %\cs{DTLifcurrency}\marg{text}\marg{true part}\marg{false part} %\end{definition} %If \meta{text} is currency, then do \meta{true part}, otherwise @@ -448,8 +450,7 @@ %\DTLnewcurrencysymbol{\euro}\relax %\DTLifcurrency{\euro5.99}{currency}{not currency}. % -%\DescribeMacro{\DTLifcurrencyunit} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifcurrencyunit}]% %\cs{DTLifcurrencyunit}\marg{text}\marg{symbol}\marg{true part}\marg{false part} %\end{definition} %If \meta{text} is currency, and uses \meta{symbol} as the unit of @@ -469,8 +470,7 @@ %\def\cost{\euro10.50}\relax %\DTLifcurrencyunit{\cost}{\euro}{euros}{not euros}. % -%\DescribeMacro{\DTLifnumerical} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifnumerical}]% %\cs{DTLifnumerical}\marg{text}\marg{true part}\marg{false part} %\end{definition} %If \meta{text} is numerical (either an integer, real number or @@ -502,15 +502,13 @@ %\DTLsetnumberchars{,}{.}\relax %\DTLifnumerical{\$1,000.0}{number}{string}. % -%\DescribeMacro{\DTLifstring} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstring}]% %\cs{DTLifstring}\marg{text}\marg{true part}\marg{false part} %\end{definition} %This is the opposite of \cs{DTLifnumerical}. If \meta{text} is %not numerical, do \meta{true part}, otherwise do \meta{false part}. % -%\DescribeMacro{\DTLifcasedatatype} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifcasedatatype}]% %\cs{DTLifcasedatatype}\marg{text}\marg{string case}\marg{int case}\marg{real case}\marg{currency case} %\end{definition} %If \meta{text} is a string do \meta{string case}, if \meta{text} @@ -523,14 +521,13 @@ %produces: %\DTLifcasedatatype{1,000}{string}{integer}{real}{currency}. % -%\DescribeMacro{\DTLifnumeq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifnumeq}]% %\cs{DTLifnumeq}\marg{num1}\marg{num2}\marg{true part}\marg{false part} %\end{definition} %If \meta{num1} is equal to \meta{num2}, then do \meta{true part}, %otherwise do \meta{false part}. Note that both \meta{num1} and %\meta{num2} must be numerical (either integers, real numbers or -%currency.) The currency symbol is ignored when determining +%currency). The currency symbol is ignored when determining %equality. For example %\begin{verbatim} %\DTLifnumeq{\pounds10.50}{10.5}{true}{false} @@ -544,12 +541,10 @@ %produces: %\DTLifnumeq{\pounds10.50}{\$10.50}{true}{false}. % -%\DescribeMacro{\DTLifstringeq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringeq}]% %\cs{DTLifstringeq}\marg{string1}\marg{string2}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifstringeq*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringeq*}]% %\cs{DTLifstringeq*}\marg{string1}\marg{string2}\marg{true part}\marg{false part} %\end{definition} %If \meta{string1} and \meta{string2} are the same, then do @@ -596,12 +591,10 @@ %produces: %\DTLifstringeq{an apple}{an apple}{true}{false}. % -%\DescribeMacro{\DTLifeq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifeq}]% %\cs{DTLifeq}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifeq*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifeq*}]% %\cs{DTLifeq*}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} %If both \meta{arg1} and \meta{arg2} are numerical, then this is @@ -609,22 +602,19 @@ %\cs{DTLifstringeq} (when using \cs{DTLifeq}) or \cs{DTLifstringeq*} %(when using \cs{DTLifeq*}). % -%\DescribeMacro{\DTLifnumlt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifnumlt}]% %\cs{DTLifnumlt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} %\end{definition} %If \meta{num1} is less than \meta{num2}, then do \meta{true part}, %otherwise do \meta{false part}. Note that both \meta{num1} and %\meta{num2} must be numerical (either integers, real numbers or -%currency.) +%currency). % -%\DescribeMacro{\DTLifstringlt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringlt}]% %\cs{DTLifstringlt}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifstringlt*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringlt*}]% %\cs{DTLifstringlt*}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} @@ -661,12 +651,10 @@ %produces: %\DTLifstringlt*{B}{a}{less}{not less}. % -%\DescribeMacro{\DTLiflt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLiflt}]% %\cs{DTLiflt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLiflt*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLiflt*}]% %\cs{DTLiflt*}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} %If \meta{arg1} and \meta{arg2} are both numerical, then this @@ -674,22 +662,19 @@ %to \cs{DTLstringlt} (when using \cs{DTLiflt}) or %\cs{DTLstringlt*} (when using \cs{DTLiflt*}). % -%\DescribeMacro{\DTLifnumgt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifnumgt}]% %\cs{DTLifnumgt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} %\end{definition} %If \meta{num1} is greater than \meta{num2}, then do \meta{true part}, %otherwise do \meta{false part}. Note that both \meta{num1} and %\meta{num2} must be numerical (either integers, real numbers or -%currency.) +%currency). % -%\DescribeMacro{\DTLifstringgt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringgt}]% %\cs{DTLifstringgt}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifstringgt*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringgt*}]% %\cs{DTLifstringgt*}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} @@ -726,12 +711,10 @@ %produces: %\DTLifstringgt*{B}{a}{greater}{not greater}. % -%\DescribeMacro{\DTLifgt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifgt}]% %\cs{DTLifgt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifgt*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifgt*}]% %\cs{DTLifgt*}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} %If \meta{arg1} and \meta{arg2} are both numerical, then this @@ -739,14 +722,13 @@ %to \cs{DTLstringgt} (when using \cs{DTLifgt}) or %\cs{DTLstringgt*} (when using \cs{DTLifgt*}). % -%\DescribeMacro{\DTLifnumclosedbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifnumclosedbetween}]% %\cs{DTLifnumclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %If \meta{min} $\leq$ \meta{num} $\leq$ \meta{max} then do \meta{true part}, %otherwise do \meta{false part}. Note that \meta{num}, \meta{min} and %\meta{max} must be numerical (either integers, real numbers or -%currency.) The currency symbol is ignored when determining +%currency). The currency symbol is ignored when determining %equality. For example: %\begin{verbatim} %\DTLifnumclosedbetween{5.4}{5}{7}{inside}{outside} @@ -760,12 +742,10 @@ %produces: %\DTLifnumclosedbetween{5}{5}{7}{inside}{outside}. % -%\DescribeMacro{\DTLifstringclosedbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringclosedbetween}]% %\cs{DTLifstringclosedbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifstringclosedbetween*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringclosedbetween*}]% %\cs{DTLifstringclosedbetween*}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %This determines if \meta{string} is between \meta{min} and @@ -773,12 +753,10 @@ %\meta{min} or \meta{max}. The starred version ignores the case, %the unstarred version is case sensitive. % -%\DescribeMacro{\DTLifclosedbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifclosedbetween}]% %\cs{DTLifclosedbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifclosedbetween*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifclosedbetween*}]% %\cs{DTLifclosedbetween*}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %If \meta{arg}, \meta{min} and \meta{max} are numerical, then this is @@ -787,14 +765,13 @@ %or %\cs{DTLifstringclosedbetween*} (when using \cs{DTLifclosedbetween*}). % -%\DescribeMacro{\DTLifnumopenbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifnumopenbetween}]% %\cs{DTLifnumopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %If \meta{min} $<$ \meta{num} $<$ \meta{max} then do \meta{true part}, %otherwise do \meta{false part}. Note that \meta{num}, \meta{min} and %\meta{max} must be numerical (either integers, real numbers or -%currency.) Again, the currency symbol is ignored when determining +%currency). Again, the currency symbol is ignored when determining %equality. For example: %\begin{verbatim} %\DTLifnumopenbetween{5.4}{5}{7}{inside}{outside} @@ -808,12 +785,10 @@ %produces: %\DTLifnumopenbetween{5}{5}{7}{inside}{outside}. % -%\DescribeMacro{\DTLifstringopenbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringopenbetween}]% %\cs{DTLifstringopenbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifstringopenbetween*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifstringopenbetween*}]% %\cs{DTLifstringopenbetween*}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %This determines if \meta{string} is between \meta{min} and @@ -821,12 +796,10 @@ %The starred version ignores the case, %the unstarred version is case sensitive. % -%\DescribeMacro{\DTLifopenbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifopenbetween}]% %\cs{DTLifopenbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} -%\DescribeMacro{\DTLifopenbetween*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifopenbetween*}]% %\cs{DTLifopenbetween*}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %If \meta{arg}, \meta{min} and \meta{max} are numerical, then this is @@ -834,28 +807,25 @@ %\cs{DTLifstringopenbetween} (when using \cs{DTLifopenbetween}) %\cs{DTLifstringopenbetween*} (when using \cs{DTLifopenbetween*}). % -%\DescribeMacro{\DTLifFPclosedbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifFPclosedbetween}]% %\cs{DTLifFPclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %If \meta{min} $\leq$ \meta{num} $\leq$ \meta{max} then do \meta{true part}, %otherwise do \meta{false part} where \meta{num}, \meta{min} %and \meta{max} are all in standard fixed point notation (i.e.\ %no number group separator, no currency symbols and a full stop as -%a decimal point.) +%a decimal point). % -%\DescribeMacro{\DTLifFPopenbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifFPopenbetween}]% %\cs{DTLifFPopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} %If \meta{min} $<$ \meta{num} $<$ \meta{max} then do \meta{true part}, %otherwise do \meta{false part} where \meta{num}, \meta{min} %and \meta{max} are all in standard fixed point notation (i.e.\ %no number group separator, no currency symbols and a full stop as -%a decimal point.) +%a decimal point). % -%\DescribeMacro{\DTLifAllUpperCase} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifAllUpperCase}]% %\cs{DTLifAllUpperCase}\marg{string}\marg{true part}\marg{false part} %\end{definition} %Tests if \meta{string} is all upper case. For example: @@ -886,8 +856,7 @@ %produces: %\DTLifAllUpperCase{MAN{\OE}UVRE}{all upper}{not all upper}. % -%\DescribeMacro{\DTLifAllLowerCase} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifAllLowerCase}]% %\cs{DTLifAllLowerCase}\marg{string}\marg{true part}\marg{false part} %\end{definition} %Tests if \meta{string} is all lower case. For example: @@ -918,8 +887,7 @@ %produces: %\DTLifAllLowerCase{man{\oe}uvre}{all lower}{not all lower}. % -%\DescribeMacro{\DTLifSubString} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifSubString}]% %\cs{DTLifSubString}\marg{string}\marg{substring}\marg{true %part}\marg{false part} %\end{definition} @@ -959,8 +927,7 @@ %produces: %\DTLifSubString{An Apple}{app}{is substring}{isn't substring}. % -%\DescribeMacro{\DTLifStartsWith} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifStartsWith}]% %\cs{DTLifStartsWith}\marg{string}\marg{substring}\marg{true %part}\marg{false part} %\end{definition} @@ -995,10 +962,11 @@ %\cs{whiledo} commands provided by the \sty{ifthen} package. %This section describes analogous commands which may only be %used in the conditional argument of \cs{ifthenelse} and -%\cs{whiledo}. +%\cs{whiledo}. These may be used with the boolean operations +%\cs{not}, \cs{and} and \cs{or} provided by the \sty{ifthen} package. +%See the \sty{ifthen} documentation for further details. % -%\DescribeMacro{\DTLisstring} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisstring}]% %\cs{DTLisstring}\marg{text} %\end{definition} %Tests if \meta{text} is a string. For example: @@ -1008,11 +976,10 @@ %produces: %\ifthenelse{\DTLisstring{some text}}{string}{not a string}. % -%\DescribeMacro{\DTLisnumerical} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisnumerical}]% %\cs{DTLisnumerical}\marg{text} %\end{definition} -%Tests if \meta{text} is numerical (i.e.\ not a string.) For example: +%Tests if \meta{text} is numerical (i.e.\ not a string). For example: %\begin{verbatim} %\ifthenelse{\DTLisnumerical{\$10.95}}{numerical}{not numerical} %\end{verbatim} @@ -1031,7 +998,7 @@ %\begin{verbatim} %\ifthenelse{\DTLisnumerical{\pounds10.95}}{numerical}{not numerical} %\end{verbatim} -%produces +%produces: %\ifthenelse{\DTLisnumerical{\pounds10.95}}{numerical}{not numerical}. %This is due to the expansion that occurs within \cs{ifthenelse}. %This can be prevented using \cs{noexpand}, for example: @@ -1046,12 +1013,11 @@ %\def\cost{\pounds10.95}% %\ifthenelse{\DTLisnumerical{\noexpand\cost}}{numerical}{not numerical} %\end{verbatim} -%produces +%produces: %\def\cost{\pounds10.95}\relax %\ifthenelse{\DTLisnumerical{\noexpand\cost}}{numerical}{not numerical}. % -%\DescribeMacro{\DTLiscurrency} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLiscurrency}]% %\cs{DTLiscurrency}\marg{text} %\end{definition} %Tests if \meta{text} is currency. For example: @@ -1064,18 +1030,17 @@ %The same warning given above for \cs{DTLisnumerical} also applies %here. % -%\DescribeMacro{\DTLiscurrencyunit} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLiscurrencyunit}]% %\cs{DTLiscurrencyunit}\marg{text}\marg{symbol} %\end{definition} -%Tests if \meta{text} is currency, and uses \meta{symbol} as the unit +%Tests if \meta{text} is currency and that currency uses \meta{symbol} as the unit %of currency. %For example: %\begin{verbatim} %\ifthenelse{\DTLiscurrencyunit{\$6.99}{\$}}{dollars}{not dollars} %\end{verbatim} %produces: -%\ifthenelse{\DTLiscurrencyunit{\$6.99}{\$}}{dollars}{not dollars} +%\ifthenelse{\DTLiscurrencyunit{\$6.99}{\$}}{dollars}{not dollars}. %Another example: %\begin{verbatim} %\def\cost{\euro10.50}% @@ -1087,20 +1052,18 @@ %\ifthenelse{\DTLiscurrencyunit{\noexpand\cost}{\noexpand\euro}}% %{euros}{not euros}. Again note the use of \cs{noexpand}. % -%\DescribeMacro{\DTLisreal} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisreal}]% %\cs{DTLisreal}\marg{text} %\end{definition} %Tests if \meta{text} is a fixed point number (again, an integer is -%not considered to be a fixed point number.) For example: +%not considered to be a fixed point number). For example: %\begin{verbatim} %\ifthenelse{\DTLisreal{1.5}}{real}{not real} %\end{verbatim} %produces: %\ifthenelse{\DTLisreal{1.5}}{real}{not real}. % -%\DescribeMacro{\DTLisint} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisint}]% %\cs{DTLisint}\marg{text} %\end{definition} %Tests if \meta{text} is an integer. For example: @@ -1110,8 +1073,7 @@ %produces: %\ifthenelse{\DTLisint{153}}{integer}{not an integer}. % -%\DescribeMacro{\DTLislt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLislt}]% %\cs{DTLislt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is less than \meta{arg2}. As with @@ -1121,8 +1083,7 @@ %version of this command, but you can instead use \cs{DTLisilt} %to ignore the case.) % -%\DescribeMacro{\DTLisilt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisilt}]% %\cs{DTLisilt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is less than \meta{arg2}. As with @@ -1130,8 +1091,7 @@ %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % -%\DescribeMacro{\DTLisgt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisgt}]% %\cs{DTLisgt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is greater than \meta{arg2}. As with @@ -1141,8 +1101,7 @@ %version of this command, instead use \cs{DTLisigt} to %ignore the case.) % -%\DescribeMacro{\DTLisigt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisigt}]% %\cs{DTLisigt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is greater than \meta{arg2}. As with @@ -1150,8 +1109,7 @@ %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % -%\DescribeMacro{\DTLiseq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLiseq}]% %\cs{DTLiseq}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is equal to \meta{arg2}. As with @@ -1160,8 +1118,7 @@ %alphabetical comparison is used. (Note that there is no starred %version of this command, instead use \cs{DTLisieq}.) % -%\DescribeMacro{\DTLisieq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisieq}]% %\cs{DTLisieq}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is equal to \meta{arg2}. As with @@ -1169,108 +1126,96 @@ %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % -%\DescribeMacro{\DTLisclosedbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisclosedbetween}]% %\cs{DTLisclosedbetween}\marg{arg}\marg{min}\marg{max} %\end{definition} %This checks if \meta{arg} lies between \meta{min} and -%\meta{max} (end points included.) As with +%\meta{max} (end points included). As with %\cs{DTLifclosedbetween}, if the arguments are numerical, %a numerical comparison is used, otherwise a case sensitive %alphabetical comparison is used. (Note that there is no starred %version of this command, instead use \cs{DTLisiclosedbetween}.) % -%\DescribeMacro{\DTLisiclosedbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisiclosedbetween}]% %\cs{DTLisiclosedbetween}\marg{arg}\marg{min}\marg{max} %\end{definition} %This checks if \meta{arg} lies between \meta{min} and -%\meta{max} (end points included.) As with +%\meta{max} (end points included). As with %\cs{DTLifclosedbetween*}, if the arguments are numerical, %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % -%\DescribeMacro{\DTLisopenbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisopenbetween}]% %\cs{DTLisopenbetween}\marg{arg}\marg{min}\marg{max} %\end{definition} %This checks if \meta{arg} lies between \meta{min} and -%\meta{max} (end points excluded.) As with +%\meta{max} (end points excluded). As with %\cs{DTLifopenbetween}, if the arguments are numerical, %a numerical comparison is used, otherwise a case sensitive %alphabetical comparison is used. (Note that there is no starred %version of this command, instead use \cs{DTLisiopenbetween}.) % -%\DescribeMacro{\DTLisiopenbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisiopenbetween}]% %\cs{DTLisiopenbetween}\marg{arg}\marg{min}\marg{max} %\end{definition} %This checks if \meta{arg} lies between \meta{min} and -%\meta{max} (end points excluded.) As with +%\meta{max} (end points excluded). As with %\cs{DTLifopenbetween*}, if the arguments are numerical, %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % -%\DescribeMacro{\DTLisFPlt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisFPlt}]% %\cs{DTLisFPlt}\marg{num1}\marg{num2} %\end{definition} %This checks if \meta{num1} is less than \meta{num2}, where both %numbers are in standard fixed point format (i.e.\ no number group -%separators, no currency and a full stop as a decimal point.) +%separators, no currency and a full stop as a decimal point). % -%\DescribeMacro{\DTLisFPlteq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisFPlteq}]% %\cs{DTLisFPlteq}\marg{num1}\marg{num2} %\end{definition} %This checks if \meta{num1} is less than or equal to \meta{num2}, where both %numbers are in standard fixed point format (i.e.\ no number group -%separators, no currency and a full stop as a decimal point.) +%separators, no currency and a full stop as a decimal point). % -%\DescribeMacro{\DTLisFPgt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisFPgt}]% %\cs{DTLisFPgt}\marg{num1}\marg{num2} %\end{definition} %This checks if \meta{num1} is greater than \meta{num2}, where both %numbers are in standard fixed point format (i.e.\ no number group -%separators, no currency and a full stop as a decimal point.) +%separators, no currency and a full stop as a decimal point). % -%\DescribeMacro{\DTLisFPgteq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisFPgteq}]% %\cs{DTLisFPgteq}\marg{num1}\marg{num2} %\end{definition} %This checks if \meta{num1} is greater than or equal to \meta{num2}, where both %numbers are in standard fixed point format (i.e.\ no number group -%separators, no currency and a full stop as a decimal point.) +%separators, no currency and a full stop as a decimal point). % -%\DescribeMacro{\DTLisFPeq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisFPeq}]% %\cs{DTLisFPeq}\marg{num1}\marg{num2} %\end{definition} %This checks if \meta{num1} is equal to \meta{num2}, where both %numbers are in standard fixed point format (i.e.\ no number group -%separators, no currency and a full stop as a decimal point.) +%separators, no currency and a full stop as a decimal point). % -%\DescribeMacro{\DTLisFPclosedbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisFPclosedbetween}]% %\cs{DTLisFPclosedbetween}\marg{num}\marg{min}\marg{max} %\end{definition} %This checks if \meta{num} lies between \meta{min} and -%\meta{max} (end points included.) All arguments must be +%\meta{max} (end points included). All arguments must be %numbers in standard fixed point format (i.e.\ no number group -%separators, no currency and a full stop as a decimal point.) +%separators, no currency and a full stop as a decimal point). % -%\DescribeMacro{\DTLisFPopenbetween} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisFPopenbetween}]% %\cs{DTLisFPopenbetween}\marg{num}\marg{min}\marg{max} %\end{definition} %This checks if \meta{num} lies between \meta{min} and -%\meta{max} (end points excluded.) All arguments must be +%\meta{max} (end points excluded). All arguments must be %numbers in standard fixed point format (i.e.\ no number group -%separators, no currency and a full stop as a decimal point.) +%separators, no currency and a full stop as a decimal point). % -%\DescribeMacro{\DTLisSubString} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisSubString}]% %\cs{DTLisSubString}\marg{string}\marg{substring} %\end{definition} %This checks if \meta{substring} is contained in \meta{string}. @@ -1278,8 +1223,7 @@ %\cs{DTLisSubString}. This command performs a case sensitive %match. % -%\DescribeMacro{\DTLisPrefix} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLisPrefix}]% %\cs{DTLisPrefix}\marg{string}\marg{prefix} %\end{definition} %This checks if \meta{string} starts with \meta{prefix}. @@ -1295,8 +1239,7 @@ %from the locale dependent format into the format required by the %\sty{fp} package. A numerical value (i.e.\ an integer, a real %or currency) can be converted into a plain decimal number using -%\DescribeMacro{\DTLconverttodecimal} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLconverttodecimal}]% %\cs{DTLconverttodecimal}\marg{num}\marg{cmd} %\end{definition} %The decimal number will be stored in \meta{cmd} which must be @@ -1305,12 +1248,11 @@ %\DTLconverttodecimal{1,563.54}{\mynum} %\end{verbatim} %\DTLconverttodecimal{1,563.54}{\mynum}\relax -%will define \cs{mynum} to be \texttt{\mynum}. The command +%will define \cs{mynum} to be \texttt{\mynum}. The command \cs{mynum} %can then be used in any of the arithmetic macros provided by the %\sty{fp} package. There are two commands provided to perform %the reverse: -%\DescribeMacro{\DTLdecimaltolocale} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdecimaltolocale}]% %\cs{DTLdecimaltolocale}\marg{number}\marg{cmd} %\end{definition} %This converts a plain decimal number \meta{number} (that uses a full @@ -1323,8 +1265,7 @@ %\DTLdecimaltolocale{6795.3}{\mynum} %will define \cs{mynum} to be \texttt{\mynum}. % -%\DescribeMacro{\DTLdecimaltocurrency} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdecimaltocurrency}]% %\cs{DTLdecimaltocurrency}\marg{number}\marg{cmd} %\end{definition} %This will convert a plain decimal number \meta{number} into a @@ -1347,8 +1288,7 @@ %\DTLdecimaltocurrency{267.5}{\price}\price. This is because %the last currency symbol to be encountered was \cs{texteuro}. %You can reset the currency symbol using the command: -%\DescribeMacro{\DTLsetdefaultcurrency} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsetdefaultcurrency}]% %\cs{DTLsetdefaultcurrency}\marg{symbol} %\end{definition} %For example: @@ -1366,12 +1306,11 @@ %back into the locale format using %\cs{DTLdecimaltolocale} or \cs{DTLdecimaltocurrency}. % -%\DescribeMacro{\DTLadd} -%\begin{definition} +% +%\begin{definition}[\DescribeMacro{\DTLadd}]% %\cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} -%\DescribeMacro{\DTLgadd} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgadd}]% %\cs{DTLgadd}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to \meta{num1}+\meta{num2}. @@ -1384,8 +1323,8 @@ %\end{verbatim} %will produce: %\DTLadd{\result}{3,562.65}{412.2}\result. Since -%\cs{DTLconverttodecimal} can also convert currency, you can -%also add prices. For example: +%\cs{DTLconverttodecimal} can convert currency to a real +%number, you can also add prices. For example: %\begin{verbatim} %\DTLadd{\result}{\pounds3,562.65}{\pounds452.2}\result %\end{verbatim} @@ -1410,12 +1349,10 @@ %produces: %\DTLadd{\result}{3,562.65}{\$452.2}\result. % -%\DescribeMacro{\DTLaddall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLaddall}]% %\cs{DTLaddall}\marg{cmd}\marg{number list} %\end{definition} -%\DescribeMacro{\DTLgaddall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgaddall}]% %\cs{DTLgaddall}\marg{cmd}\marg{number list} %\end{definition} %This sets the control sequence \meta{cmd} to the sum of all @@ -1435,12 +1372,10 @@ %produces: %\DTLaddall{\total}{{1,525},{2,340},500}\total. % -%\DescribeMacro{\DTLsub} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsub}]% %\cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} -%\DescribeMacro{\DTLgsub} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgsub}]% %\cs{DTLgsub}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to @@ -1456,12 +1391,10 @@ %\DTLsub{\result}{3,562.65}{412.2}\result. As with \cs{DTLadd}, %\meta{num1} and \meta{num2} may be currency. % -%\DescribeMacro{\DTLmul} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmul}]% %\cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} -%\DescribeMacro{\DTLgmul} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgmul}]% %\cs{DTLgmul}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to @@ -1494,12 +1427,10 @@ %which will produce: %\DTLmul{\result}{\$2}{\pounds568.95}\result. % -%\DescribeMacro{\DTLdiv} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdiv}]% %\cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} -%\DescribeMacro{\DTLgdiv} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgdiv}]% %\cs{DTLgdiv}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to @@ -1527,12 +1458,10 @@ %will produce: %\DTLdiv{\result}{\$501}{2}\result. % -%\DescribeMacro{\DTLabs} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLabs}]% %\cs{DTLabs}\marg{cmd}\marg{num} %\end{definition} -%\DescribeMacro{\DTLgabs} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgabs}]% %\cs{DTLgabs}\marg{cmd}\marg{num} %\end{definition} %This sets \meta{cmd} to the absolute value of \meta{num}. @@ -1544,12 +1473,10 @@ %produces: %\DTLabs{\result}{-\pounds2.50}\result. % -%\DescribeMacro{\DTLneg} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLneg}]% %\cs{DTLneg}\marg{cmd}\marg{num} %\end{definition} -%\DescribeMacro{\DTLgneg} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgneg}]% %\cs{DTLgneg}\marg{cmd}\marg{num} %\end{definition} %This sets \meta{cmd} to the negative of \meta{num}. @@ -1561,12 +1488,10 @@ %produces: %\DTLneg{\result}{\pounds2.50}\result. % -%\DescribeMacro{\DTLsqrt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsqrt}]% %\cs{DTLsqrt}\marg{cmd}\marg{num} %\end{definition} -%\DescribeMacro{\DTLgsqrt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgsqrt}]% %\cs{DTLgsqrt}\marg{cmd}\marg{num} %\end{definition} %This sets \meta{cmd} to the sqrt root of \meta{num}. @@ -1578,12 +1503,10 @@ %produces: %\DTLsqrt{\result}{2}\result. % -%\DescribeMacro{\DTLmin} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmin}]% %\cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} -%\DescribeMacro{\DTLgmin} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgmin}]% %\cs{DTLgmin}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to the minimum of @@ -1616,12 +1539,10 @@ %\DTLmin{\result}{\pounds5}{\$6}\result, which may not necessarily %be true! % -%\DescribeMacro{\DTLminall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLminall}]% %\cs{DTLminall}\marg{cmd}\marg{number list} %\end{definition} -%\DescribeMacro{\DTLgminall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgminall}]% %\cs{DTLgminall}\marg{cmd}\marg{number list} %\end{definition} %This sets the control sequence \meta{cmd} to the minimum of all @@ -1641,12 +1562,10 @@ %produces: %\DTLminall{\theMin}{{1,525},{2,340},500}\theMin. % -%\DescribeMacro{\DTLmax} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmax}]% %\cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} -%\DescribeMacro{\DTLgmax} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgmax}]% %\cs{DTLgmax}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to the maximum of @@ -1661,12 +1580,10 @@ %Again, \meta{num1} and \meta{num2} may %be currency, but the same warnings for \cs{DTLmin} apply. % -%\DescribeMacro{\DTLmaxall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmaxall}]% %\cs{DTLmaxall}\marg{cmd}\marg{number list} %\end{definition} -%\DescribeMacro{\DTLgmaxall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgmaxall}]% %\cs{DTLgmaxall}\marg{cmd}\marg{number list} %\end{definition} %This sets the control sequence \meta{cmd} to the maximum of all @@ -1686,12 +1603,10 @@ %produces: %\DTLmaxall{\theMax}{{1,525},{2,340},500}\theMax. % -%\DescribeMacro{\DTLmeanforall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmeanforall}]% %\cs{DTLmeanforall}\marg{cmd}\marg{number list} %\end{definition} -%\DescribeMacro{\DTLgmeanall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgmeanall}]% %\cs{DTLgmeanforall}\marg{cmd}\marg{number list} %\end{definition} %This sets the control sequence \meta{cmd} to the arithmetic mean of all @@ -1711,12 +1626,10 @@ %produces: %\DTLmeanforall{\theMean}{{1,525},{2,340},500}\theMean. % -%\DescribeMacro{\DTLvarianceforall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLvarianceforall}]% %\cs{DTLvarianceforall}\marg{cmd}\marg{number list} %\end{definition} -%\DescribeMacro{\DTLgvarianceforall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgvarianceforall}]% %\cs{DTLgvarianceforall}\marg{cmd}\marg{number list} %\end{definition} %This sets the control sequence \meta{cmd} to the variance of all @@ -1731,12 +1644,10 @@ %Again note that if any of the numbers in \meta{number list} %contain a comma, you must group the number. % -%\DescribeMacro{\DTLsdforall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsdforall}]% %\cs{DTLsdforall}\marg{cmd}\marg{number list} %\end{definition} -%\DescribeMacro{\DTLgsdforall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgsdforall}]% %\cs{DTLgsdforall}\marg{cmd}\marg{number list} %\end{definition} %This sets the control sequence \meta{cmd} to the standard deviation of all @@ -1756,38 +1667,40 @@ %produces: %\DTLsdforall{\theSD}{{1,525},{2,340},500}\theSD. % -%\DescribeMacro{\DTLround} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLround}]% %\cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} %\end{definition} -%\DescribeMacro{\DTLground} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLground}]% %\cs{DTLground}\marg{cmd}\marg{num}\marg{num digits} %\end{definition} %This sets \meta{cmd} to \meta{num} rounded to \meta{num digits} %after the decimal character. %\cs{DLTround} sets \meta{cmd} locally, while \cs{DTLground} sets -%\meta{cmd} globally. +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLround{\result}{3.135276}{2}\result +%\end{verbatim} +%produces: \DTLround{\result}{3.135276}{2}\result. % -%\DescribeMacro{\DTLtrunc} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLtrunc}]% %\cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} %\end{definition} -%\DescribeMacro{\DTLgtrunc} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgtrunc}]% %\cs{DTLgtrunc}\marg{cmd}\marg{num}\marg{num digits} %\end{definition} %This sets \meta{cmd} to \meta{num} truncated to \meta{num digits} %after the decimal character. %\cs{DLTtrunc} sets \meta{cmd} locally, while \cs{DTLgtrunc} sets -%\meta{cmd} globally. +%\meta{cmd} globally. Example: +%\begin{verbatim} +%\DTLtrunc{\result}{3.135276}{2}\result +%\end{verbatim} +%produces: \DTLtrunc{\result}{3.135276}{2}\result. % -%\DescribeMacro{\DTLclip} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLclip}]% %\cs{DTLclip}\marg{cmd}\marg{num} %\end{definition} -%\DescribeMacro{\DTLgclip} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLgclip}]% %\cs{DTLgclip}\marg{cmd}\marg{num} %\end{definition} %This sets \meta{cmd} to \meta{num} with all unnecessary 0's @@ -1804,8 +1717,7 @@ %if one string is contained in another string. In addition, %the \sty{datatool} provides the following macros: % -%\DescribeMacro{\DTLsubstitute} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsubstitute}]% %\cs{DTLsubstitute}\marg{cmd}\marg{original}\marg{replacement} %\end{definition} %This replaces the first occurrence of \meta{original} in @@ -1817,8 +1729,7 @@ %produces: %\def\mystr{abcdce}\DTLsubstitute{\mystr}{c}{z}\mystr. % -%\DescribeMacro{\DTLsubstituteall} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsubstituteall}]% %\cs{DTLsubstituteall}\marg{cmd}\marg{original}\marg{replacement} %\end{definition} %This replaces all occurrences of \meta{original} in @@ -1830,8 +1741,7 @@ %produces: %\def\mystr{abcdce}\DTLsubstituteall{\mystr}{c}{z}\mystr. % -%\DescribeMacro{\DTLsplitstring} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsplitstring}]% %\cs{DTLsplitstring}\marg{string}\marg{split text}\marg{before %cmd}\marg{after cmd} %\end{definition} @@ -1869,8 +1779,7 @@ %{\mystr}{c}{\beforepart}{\afterpart}\relax %Before part: ``\beforepart''. After part: ``\afterpart''. % -%\DescribeMacro{\DTLinitials} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLinitials}]% %\cs{DTLinitials}\marg{string} %\end{definition} %This converts \meta{string} (typically a name) into initials. @@ -1879,12 +1788,12 @@ %\DTLinitials{Mary Ann} %\end{verbatim} %produces: -%\DTLinitials{Mary Ann} (including the final full stop.) Note that +%\DTLinitials{Mary Ann} (including the final full stop). Note that %\begin{verbatim} %\DTLinitials{Mary-Ann} %\end{verbatim} %produces: -%\DTLinitials{Mary-Ann} (including the final full stop.) +%\DTLinitials{Mary-Ann} (including the final full stop). %Be careful if the initial letter has an %accent. The accented letter needs to be placed in a group, if %you want the initial to also have an accent, otherwise the @@ -1917,8 +1826,7 @@ %produces: %\DTLinitials{\MakeUppercase{mary ann}} % -%\DescribeMacro{\DTLstoreinitials} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLstoreinitials}]% %\cs{DTLstoreinitials}\marg{string}\marg{cmd} %\end{definition} %This converts \meta{string} into initials and stores the @@ -1933,30 +1841,26 @@ % %Both the above commands rely on the following to format the %initials: -%\DescribeMacro{\DTLafterinitials} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLafterinitials}]% %\cs{DTLafterinitials} %\end{definition} %This indicates what to do at the end of the initials. This %simply does a full stop by default. % -%\DescribeMacro{\DTLbetweeninitials} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbetweeninitials}]% %\cs{DTLbetweeninitials} %\end{definition} %This indicates what to do between initials. This does a %full stop by default. % -%\DescribeMacro{\DTLinitialhyphen} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLinitialhyphen}]% %\cs{DTLinitialhyphen} %\end{definition} %This indicates what to do at a hyphen. This simply does a hyphen %by default, but can be redefined to do nothing to prevent the %hyphen appearing in the initials. % -%\DescribeMacro{\DTLafterinitialbeforehyphen} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLafterinitialbeforehyphen}]% %\cs{DTLafterinitialbeforehyphen} %\end{definition} %This indicates what to do between an initial and a hyphen. @@ -1993,31 +1897,40 @@ %it is possible to iterate through each row of data, to make it %easier to perform repetitive actions, such as mail merging. % +%\importantpar Whilst \TeX\ is an excellent typesetting language, +%it is not designed as a database management system, and +%attempting to use it as such is like trying to fasten a screw +%with a knife instead of a screwdriver: it can be done, but requires +%great care and is more time consuming. Version 2.0 of the +%\sty{datatool} package uses a completely different method of storing +%the data to previous versions.\footnote{Thanks to Morten H\o gholm +%for the suggestion.} As a result, the code is much more efficient, +%however, large databases and complex operations will still slow the +%time taken to process your document. Therefore, if you can, it is +%better to do the complex operations using whatever system created +%the data in the first place. +% %\subsection{Creating a New Database} %\label{sec:newdb} % -%\DescribeMacro{\DTLnewdb} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLnewdb}]% %\cs{DTLnewdb}\marg{db name} %\end{definition} %This command creates a new empty database called \meta{db name}. You %can test if a database is empty using: -%\DescribeMacro{\DTLifdbempty} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifdbempty}]% %\cs{DTLifdbempty}\marg{db name}\marg{true part}\marg{false part} %\end{definition} %If the database called \meta{db name} is empty, do \meta{true part}, %otherwise do \meta{false part}. % -%\DescribeMacro{\DTLrowcount} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLrowcount}]% %\cs{DTLrowcount}\marg{db name} %\end{definition} %This command displays the number of rows in the database called %\meta{db name}. % -%\DescribeMacro{\DTLnewrow} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLnewrow}]% %\cs{DTLnewrow}\marg{db name} %\end{definition} %This command starts a new row in the database called \meta{db name}. @@ -2056,8 +1969,7 @@ %which produces: %\DTLrowcount{mydata}. % -%\DescribeMacro{\DTLnewdbentry} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLnewdbentry}]% %\cs{DTLnewdbentry}\marg{db name}\marg{key}\marg{value} %\end{definition} %This creates a new entry with the identifier \meta{key} whose value @@ -2070,29 +1982,53 @@ %Adds an entry with identifier \texttt{Surname} and value %\texttt{Smith} to the last row of the database named %\texttt{mydata}, and then adds an entry with identifier -%\texttt{FirstName} and value \texttt{John}. +%\texttt{FirstName} and value \texttt{John}. Note that the +%key should not contain any fragile commands. It is generally +%best to only use non-active characters in the key. % %\importantpar Note that database entries can't contain paragraph %breaks as many of the macros used by \sty{datatool} are short %commands. If you do need a paragraph break in an entry, you can %instead use the command: -%\DescribeMacro{\DTLpar} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpar}]% %\cs{DTLpar} %\end{definition} % -%\DescribeMacro{\DTLaddentryforrow} -%\begin{definition} -%\cs{DTLaddentryforrow}\marg{db name}\marg{assign list}\marg{condition}\marg{key}\marg{value} +%For example: +%\begin{verbatim} +%\DTLnewdbentry{mydata}{Description}{First paragraph.\DTLpar +%Second paragraph.} +%\end{verbatim} +% +%\begin{definition}[\DescribeMacro{\DTLaddentryforrow}]% +%\cs{DTLaddentryforrow}\marg{db}\marg{assign list}\marg{condition}\marg{key}\marg{value} %\end{definition} %This adds the entry with the key given by \meta{key} and value %given by \meta{value} to the first row in the database -%\meta{db name} which satisfies the condition given by +%\meta{db} which satisfies the condition given by %\meta{condition}. The \meta{assign list} argument is the same %as for \cs{DTLforeach} (described in \autoref{sec:dbforeach}) %and may be used to set the values which are to be tested in %\meta{condition} (where, again, \meta{condition} is the same -%as for \cs{DTLforeach}). +%as for \cs{DTLforeach}). For example: +%\begin{verbatim} +%\DTLaddentryforrow{mydata}{\firstname=FirstName,\surname=Surname}% +%{\DTLiseq{\firstname}{John}\and\DTLiseq{\surname}{Smith}}% +%{Score}{75} +%\end{verbatim} +% +%\begin{definition}[\DescribeMacro{\DTLsetheader}]% +%\cs{DTLsetheader}\marg{db}\marg{key}\marg{header} +%\end{definition} +%This assigns a header for a given key in the database named +%\meta{db}. This is used by \cs{DTLdisplaydb} and +%\cs{DTLdisplaylongdb} in the header row (see +%\autoref{sec:displaydb}). If you don't assign +%a header, the header will be given by the key. +%For example: +%\begin{verbatim} +%\DTLsetheader{mydata}{Price}{Price (\$)} +%\end{verbatim} % %\subsection{Loading a Database from an External ASCII File} %\label{sec:loaddb} @@ -2100,30 +2036,61 @@ %Instead of using the commands described in \autoref{sec:newdb} %to create a new database, you can load a database from an %external ASCII file using: -%\DescribeMacro{\DTLloaddb} -%\begin{definition} -%\cs{DTLloaddb}\marg{db name}\marg{filename} +%\begin{definition}[\DescribeMacro{\DTLloaddb}]% +%\cs{DTLloaddb}\oarg{options}\marg{db name}\marg{filename} %\end{definition} %This creates a new database called \meta{db name}, and fills %it with the entries given in the file \meta{filename}. -%The filename must have a header row at the start of the file, +%The filename may have a header row at the start of the file, %which provides the \meta{key} when creating a new database entry -%using \ics{DTLnewdbentry}. By default, the entries in the database +%using \ics{DTLnewdbentry}. The optional argument \meta{options} +%is a key=value list of options. Available options are: +%\begin{description} +%\item[\cmdopt{DTLloaddb}{noheader}] This is a boolean value and +%indicates if the file does not contain a header. If no value is +%supplied, "true" is assumed (i.e.\ the file doesn't contain a header +%row). If this option is omitted, it is assumed that the file +%contains a header row. +% +%\item[\cmdopt{DTLloaddb}{keys}] This is a comma-separated list of +%keys to use, where the keys are listed in the same order as the +%columns. If the file has a header, these keys will override the +%values given in the header row. If the file has no header row and no +%keys are supplied in \meta{options}, then the keys will be given by +%\cs{dtldefaultkey}\meta{n}, where \meta{n} is the column number and +%\DescribeMacro{\dtldefaultkey}\cs{dtldefaultkey} defaults to +%``\dtldefaultkey''. Note that the list of keys must be delimited by +%braces since they contain commas. For example: +%\begin{verbatim} +%\DTLloaddb[noheader,keys={Temperature,Time,T2G}]{data}{data.csv} +%\end{verbatim} +% +%\item[\cmdopt{DTLloaddb}{headers}] This is a comma-separated list of +%headers. If not supplied, the header will be the same as that given +%in the header row, or the key if there is no header row. Note that +%the list of headers must be delimited by braces since they contain +%commas. For example: +%\begin{verbatim} +%\DTLloaddb[noheader,keys={Temperature,Time,T2G},% +%headers={\shortstack{Incubation\\Temperature},% +%\shortstack{Incubation\\Time},% +%\shortstack{Time to\\Growth}}]{data}{data.csv} +%\end{verbatim} +%\end{description} +% +%By default, the entries in the database %must be separated by a comma, and optionally delimited by the %double quote character (\verb|"|). The separator can be changed %to a tab separator using the command: -%\DescribeMacro{\DTLsettabseparator} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsettabseparator}]% %\cs{DTLsettabseparator} %\end{definition} %To set the separator to a character other than a tab, you need to use -%\DescribeMacro{\DTLsetseparator} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsetseparator}]% %\cs{DTLsetseparator}\marg{character} %\end{definition} %The delimiter can be changed using -%\DescribeMacro{\DTLsetdelimiter} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsetdelimiter}]% %\cs{DTLsetdelimiter}\marg{character} %\end{definition} % @@ -2181,9 +2148,8 @@ %"&" and \verb|$|. In this case, if you try to load the file %using \ics{DTLloaddb}, you will encounter errors. Instead you %can use: -%\DescribeMacro{\DTLloadrawdb} -%\begin{definition} -%\cs{DTLloadrawdb}\marg{db name}\marg{filename} +%\begin{definition}[\DescribeMacro{\DTLloadrawdb}]% +%\cs{DTLloadrawdb}\oarg{options}\marg{db name}\marg{filename} %\end{definition} %This is the same as \ics{DTLloaddb} except that it maps nine of %the ten special characters onto commands which produce that @@ -2212,7 +2178,7 @@ %\cs{DTLloadrawdb} (note that the backslash retains its active state)} %\label{tab:rawmappings} %\begin{center} -%\begin{tabular}{ll} +%\begin{tabular}{cl} %Character & Mapping\\ %\verb|%| & \verb|\%|\\ %\verb|$| & \verb|\$|\\ @@ -2241,8 +2207,7 @@ %in a \LaTeX\ document. It will therefore be necessary to convert %this symbol to an appropriate control sequence. This can be done %using the command: -%\DescribeMacro{\DTLrawmap} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLrawmap}]% %\cs{DTLrawmap}\marg{string}\marg{replacement} %\end{definition} %For example:\par @@ -2251,8 +2216,8 @@ %\cs{DTLrawmap}\char`\{\pounds\char`\}\char`\{\cs{pounds}\char`\} %\end{ttfamily} %\vskip\baselineskip\noindent -%will convert all occurrences\footnote{when it is loaded into the -%\LaTeX\ database, it does not modify the data file!} of +%will replace all occurrences\footnote{when it is loaded into the +%\LaTeX\ database, it does not modify the data file!}\ of %\texttt{\pounds} with \cs{pounds}. Naturally, the mappings must be %set \emph{prior} to loading the data with \cs{DTLloadrawdb}. % @@ -2262,6 +2227,330 @@ %of \cs{par}, but remember that each row of data in an external data %file must not have a line break. % +%\subsection{Displaying the Contents of a Database} +%\label{sec:displaydb} +% +%Once you have created a database, either loading it from an +%external file, as described in \autoref{sec:loaddb}, or using the +%commands described in \autoref{sec:newdb}, you can display the +%entire database in a \env{tabular} or \env{longtable} +%environment. +% +%\begin{definition}[\DescribeMacro{\DTLdisplaydb}]% +%\cs{DTLdisplaydb}\marg{db} +%\end{definition} +%This displays the database given by \meta{db} in a \env{tabular} +%environment. The first row displays the headers for the database +%in bold, the subsequent rows display the values for each key +%in each row of the database. +% +%\begin{definition}[\DescribeMacro{\DTLdisplaylongdb}]% +%\cs{DTLdisplaylongdb}\oarg{options}\marg{db} +%\end{definition} +%This is like \cs{DTLdisplaydb} except that it uses the +%\env{longtable} environment instead of the \env{tabular} +%environment. Note that if you use this command, you must load +%\sty{longtable}, as it is not loaded by \sty{datatool}. +%The optional argument \meta{options} is a comma-separated list +%of key=value pairs. The following keys are available: +%\begin{description} +%\item[caption] The caption for the \env{longtable}. +% +%\item[contcaption] The continuation caption. +% +%\item[shortcaption] The caption to be used in the list of figures. +% +%\item[label] The label for this table. +% +%\item[foot] The \env{longtable}'s foot. +% +%\item[lastfoot] The foot for the last page of the \env{longtable}. +%\end{description} +%For example, suppose I have a database called "iris", then I can +%display the contents in a \env{longtable} using: +%\begin{verbatim} +%\DTLdisplaylongdb[% +%caption={Iris Data},% +%label={tab:iris},% +%contcaption={Iris Data (continued)},% +%foot={\em Continued overleaf},% +%lastfoot={}% +%]{iris} +%\end{verbatim} +%I can then reference the table using \verb|\ref{tab:iris}|. +% +%See the \sty{longtable} documentation for details on how to +%change the \env{longtable} settings, such as how to change the +%table so that it is left aligned instead of centred on the page. +% +%Note that if you want more control over the way the data is +%displayed, for example, you want to filter rows or columns, you will +%need to use \cs{DTLforeach}, described in \autoref{sec:dbforeach}. +% +%\begin{example}{Displaying the Contents of a Database}{ex:displaydb} +%Suppose I have a file called \texttt{t2g.csv} that contains the +%following: +%\begin{verbatim} +%40,120,40 +%40,90,60 +%35,180,20 +%55,190,40 +%\end{verbatim} +%This represents time to growth data, where the first column +%is the incubation temperature, the second column is the incubation +%time and the third column is the time to growth. This file has no +%header row, so when it is loaded, the \cmdopt{DTLloaddb}{noheaders} +%option is required. Note that \cs{DTLdisplaydb} only puts the data +%in a \env{tabular} environment, so \cs{DTLdisplaydb} needs to be +%put in a \env{table} environment with a caption to make it a float. +% +%First load the data base, setting the keys and headers: +%\begin{verbatim} +%\DTLloaddb[noheader,% +%keys={Temperature,Time,T2G},% +%headers={\shortstack{Incubation\\Temperature},% +%\shortstack{Incubation\\Time},\shortstack{Time to\\Growth}}% +%]{t2g}{t2g.csv} +%\end{verbatim} +%\DTLnewdb{t2g}\relax +%\DTLnewrow*{t2g}\relax +%\DTLnewdbentry*{t2g}{Temperature}{40}\relax +%\DTLnewdbentry*{t2g}{Time}{120}\relax +%\DTLnewdbentry*{t2g}{T2G}{40}\relax +%\DTLnewrow*{t2g}\relax +%\DTLnewdbentry*{t2g}{Temperature}{40}\relax +%\DTLnewdbentry*{t2g}{Time}{90}\relax +%\DTLnewdbentry*{t2g}{T2G}{60}\relax +%\DTLnewrow*{t2g}\relax +%\DTLnewdbentry*{t2g}{Temperature}{35}\relax +%\DTLnewdbentry*{t2g}{Time}{180}\relax +%\DTLnewdbentry*{t2g}{T2G}{20}\relax +%\DTLnewrow*{t2g}\relax +%\DTLnewdbentry*{t2g}{Temperature}{55}\relax +%\DTLnewdbentry*{t2g}{Time}{190}\relax +%\DTLnewdbentry*{t2g}{T2G}{40}\relax +%\DTLsetheader*{t2g}{Temperature}{\shortstack{Incubation\\Temperature}}\relax +%\DTLsetheader*{t2g}{Time}{\shortstack {Incubation\\Time}}\relax +%\DTLsetheader*{t2g}{T2G}{\shortstack {Time to\\Growth}}\relax +% +%Now display the data in a table: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Time to Growth Data} +%\vspace{\baselineskip} +%\centering +%\DTLdisplaydb{t2g} +%\end{table} +%\end{verbatim} +%The result is shown in \autoref{tab:t2g}. +%\begin{table}[htbp] +%\caption{Time to Growth Data} +%\label{tab:t2g} +%\vspace{\baselineskip} +%\centering +%\DTLdisplaydb{t2g} +%\end{table} +%\end{example} +% +%Each column in the database has an associated data type which +%indicates what type of data is in that column. This may be one +%of: string, integer, real number or currency. If a column contains +%more than one type, the data type is determined as follows: +%\begin{itemize} +%\item If the column contains at least one string, then the column +%data type is string. +% +%\item If the column doesn't contain a string, but contains at least +%one currency, then the column data type is currency. +% +%\item If the column contains only real numbers and integers, the +%column data type is real number. +% +%\item The column data type is integer if the column only +%contains integers. +%\end{itemize} +%The column data type is updated whenever a new entry is added +%to the database. Note that the column data type is not adjusted +%when an entry is removed from the database. +% +%The column alignments used by \cs{DTLdisplaydb} are given by: +%\begin{definition}[\DescribeMacro{\dtlstringalign}]% +%\cs{dtlstringalign} +%\end{definition}\noindent +%The string alignment defaults to \texttt{l} (left aligned). +% +%\begin{definition}[\DescribeMacro{\dtlintalign}]% +%\cs{dtlintalign} +%\end{definition}\noindent +%The integer alignment defaults to \texttt{r} (right aligned). +% +%\begin{definition}[\DescribeMacro{\dtlrealalign}]% +%\cs{dtlrealalign} +%\end{definition}\noindent +%The alignment for real numbers defaults to \texttt{r} (right +%aligned). +% +%\begin{definition}[\DescribeMacro{\dtlcurrencyalign}]% +%\cs{dtlcurrencyalign} +%\end{definition}\noindent +%The currency alignment defaults to \texttt{r} (right aligned). +% +%You can redefine these to change the column alignments. For +%example, if you want columns containing strings to have the +%alignment "p{2in}", then you can redefine \cs{dtlstringalign} as +%follows: +%\begin{verbatim} +%\renewcommand{\dtlstringalign}{p{2in}} +%\end{verbatim} +% +%\importantpar You can't use \sty{siunitx}'s "S" column alignment +%with either \cs{DTLdisplaydb} or \cs{DTLdisplaylongdb}. Instead, you +%will need to use \cs{DTLforeach}. The \sty{siunitx} documentation +%provides an example. +% +%In addition to the \cs{dtl}\meta{type}"align" commands above, you +%can also modify the \env{tabular} column styles by redefining +%\DescribeMacro{\dtlbeforecols}\cs{dtlbeforecols}, +%\DescribeMacro{\dtlbetweencols}\cs{dtlbetweencols} and +%\DescribeMacro{\dtlaftercols}\cs{dtlaftercols}. For example, to +%place a vertical line before the start of the first column and +%after the last column, do: +%\begin{verbatim} +%\renewcommand{\dtlbeforecols}{|} +%\renewcommand{\dtlaftercols}{|} +%\end{verbatim} +%If you additionally want vertical lines between columns, do: +%\begin{verbatim} +%\renewcommand{\dtlbetweencols}{|} +%\end{verbatim} +% +%Limited modifications can be made to the way the data is displayed +%with \cs{DTLdisplaydb} and \cs{DTLdisplaylongdb}. +%The commands controlling the formatting are described below. +%If a more complicated layout is required, you will need to use +%\cs{DTLforeach} described in \autoref{sec:dbforeach}. +% +%\begin{definition}[\DescribeMacro{\dtlheaderformat}]% +%\cs{dtlheaderformat}\marg{header} +%\end{definition} +%This indicates how to format a column header, where the header is +%given by \meta{header}. This defaults to +%\cs{null}\cs{hfil}\cs{textbf}\marg{header}\cs{hfil}\cs{null}. +% +%\begin{definition}[\DescribeMacro{\dtlstringformat}]% +%\cs{dtlstringformat}\marg{text} +%\end{definition} +%This specifies how to format each entry in the columns that contain +%strings. This defaults to just displaying \meta{text}. +% +%\begin{definition}[\DescribeMacro{\dtlintformat}]% +%\cs{dtlintformat}\marg{text} +%\end{definition} +%This specifies how to format each entry in the columns that contain +%only integers. This defaults to just displaying \meta{text}. +% +%\begin{definition}[\DescribeMacro{\dtlrealformat}]% +%\cs{dtlrealformat}\marg{text} +%\end{definition} +%This specifies how to format each entry in the columns that contain +%only real numbers or a mixture of real numbers and integers. This +%defaults to just displaying \meta{text}. +% +%\begin{definition}[\DescribeMacro{\dtlcurrencyformat}]% +%\cs{dtlcurrencyformat}\marg{text} +%\end{definition} +%This specifies how to format each entry in the columns that contain +%only currency or currency mixed with real numbers and/or integers. +%This defaults to just displaying \meta{text}. +% +%\begin{definition}[\DescribeMacro{\dtldisplaystarttab}]% +%\cs{dtldisplaystarttab} +%\end{definition} +%This is a hook to add something at the beginning of the +%\env{tabular} environment. This defaults to nothing. +% +%\begin{definition}[\DescribeMacro{\dtldisplayendtab}]% +%\cs{dtldisplayendtab} +%\end{definition} +%This is a hook to add something at the end of the +%\env{tabular} environment. This defaults to nothing. +% +%\begin{definition}[\DescribeMacro{\dtldisplayafterhead}]% +%\cs{dtldisplayafterhead} +%\end{definition} +%This is a hook to add something after the header row, before +%the first row of data. This defaults to nothing. +% +%\begin{definition}[\DescribeMacro{\dtldisplaystartrow}]% +%\cs{dtldisplaystartrow} +%\end{definition} +%This is a hook to add something at the start of each row, but +%not including the header row or the first row of data. This +%defaults to nothing. +% +%\begin{example}{Balance Sheet}{ex:balance} +%Suppose you have a file called "balance.csv" that contains +%the following: +%\begin{verbatim} +%Description,In,Out,Balance +%Travel expenses,,230,-230 +%Conference fees,,400,-630 +%Grant,700,,70 +%Train fare,,70,0 +%\end{verbatim} +%\DTLnewdb{balance}\relax +%\DTLnewrow{balance}\relax +%\DTLnewdbentry{balance}{Description}{Travel expenses}\relax +%\DTLnewdbentry{balance}{In}{}\relax +%\DTLnewdbentry{balance}{Out}{230.00}\relax +%\DTLnewdbentry{balance}{Balance}{-230.00}\relax +%\DTLnewrow{balance}\relax +%\DTLnewdbentry{balance}{Description}{Conference fees}\relax +%\DTLnewdbentry{balance}{In}{}\relax +%\DTLnewdbentry{balance}{Out}{400.00}\relax +%\DTLnewdbentry{balance}{Balance}{-630.00}\relax +%\DTLnewrow{balance}\relax +%\DTLnewdbentry{balance}{Description}{Grant}\relax +%\DTLnewdbentry{balance}{In}{700.00}\relax +%\DTLnewdbentry{balance}{Out}{}\relax +%\DTLnewdbentry{balance}{Balance}{70.00}\relax +%\DTLnewrow{balance}\relax +%\DTLnewdbentry{balance}{Description}{Train Fare}\relax +%\DTLnewdbentry{balance}{In}{}\relax +%\DTLnewdbentry{balance}{Out}{70.00}\relax +%\DTLnewdbentry{balance}{Balance}{0.00}\relax +%\DTLsetheader{balance}{In}{In (\pounds)}\relax +%\DTLsetheader{balance}{Out}{Out (\pounds)}\relax +%\DTLsetheader{balance}{Balance}{Balance (\pounds)}\relax +%The data can be loaded using: +%\begin{verbatim} +%\DTLloaddb[headers={Description,In (\pounds),Out (pounds),Balance +%(pounds)}]{balance}{balance.csv} +%\end{verbatim} +% +%Suppose I want negative numbers to be displayed in red. I can do +%this by redefining \cs{dtlrealformat} to check if the entry +%is negative. For example: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Balance Sheet} +%\renewcommand*{\dtlrealformat}[1]{\DTLiflt{#1}{0}{\color{red}}{}#1} +%\vspace{\baselineskip} +%\centering +%\DTLdisplaydb{balance} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:balance}. +%\begin{table}[htbp] +%\caption{Balance Sheet} +%\label{tab:balance} +%\renewcommand*{\dtlrealformat}[1]{\DTLiflt{#1}{0}{\color{red}}{}#1} +%\vspace{\baselineskip} +%\centering +%\DTLdisplaydb{balance} +%\end{table} +%\end{example} +% %\subsection{Iterating Through a Database} %\label{sec:dbforeach} % @@ -2270,12 +2559,10 @@ %commands described in \autoref{sec:newdb}, you can then iterate %through each row of the database and access elements in that row. % -%\DescribeMacro{\DTLforeach} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLforeach}]% %\cs{DTLforeach}\oarg{condition}\marg{db name}\marg{assign list}\marg{text} %\end{definition} -%\DescribeMacro{\DTLforeach*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLforeach*}]% %\cs{DTLforeach*}\oarg{condition}\marg{db name}\marg{assign list}\marg{text} %\end{definition} %This will iterate through each row of the database called @@ -2295,16 +2582,15 @@ % %The optional argument \meta{condition} is a condition in the %form allowed by \cs{ifthenelse}. This includes the commands -%provided by the \sty{ifthen} package, as well as the commands +%provided by the \sty{ifthen} package (such as \cs{not}, \cs{and}, +%\cs{or}), as well as the commands %described in \autoref{sec:ifthen}. The default value of %\meta{condition} is "\boolean{true}". % %The starred version \cs{DTLforeach*} is a read-only version. %If you want to modify the database using any of the commands %described in \autoref{sec:editdb}, you must use the unstarred -%version. The starred version is slightly quicker, however the -%difference will probably only be noticeable for very large -%databases. +%version. The starred version is faster. % %\begin{example}{Student scores}{ex:scores} %Suppose you have a data file called \texttt{studentscores.csv} that @@ -2393,39 +2679,110 @@ %\counterfmt{DTLrowi}, %\counterfmt{DTLrowii} and %\counterfmt{DTLrowiii} which keep track of -%the current row. +%the current row. % -%\importantpar Note that these counters are only incremented -%when \meta{condition} is satisfied. These counters are incremented +%\importantpar Note that these counters are only incremented when +%\meta{condition} is satisfied, therefore they will not have the +%correct value in \meta{condition}. These counters are incremented %using \cs{refstepcounter} before the start of \meta{text}, so they %may be referenced using \cs{label}, however remember that \cs{label} -%references the last counter to be incremented using +%references the last counter to be incremented using %\cs{refstepcounter} \emph{in the current scope}. The \cs{label} -%should therefore be the first command in \meta{text} to ensure -%that it references the current row counter. +%should therefore be the first command in \meta{text} to ensure that +%it references the current row counter. % -%\DescribeMacro{\DTLcurrentindex} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLcurrentindex}]% %\cs{DTLcurrentindex} %\end{definition} -%At the start of each iteration, \cs{DTLcurrentindex} is set -%to the arabic value of the current row counter. +%At the start of each iteration in \cs{DTLforeach}, +%\cs{DTLcurrentindex} is set to the arabic value of the current row +%counter. Note that this is only set after the condition is tested, +%so it should only be used in the body of \cs{DTLforeach} not in +%the condition. It is also only set locally, so if you use it in +%a tabular environment, it can only be used before the first instance +%of \verb|\\| or \verb|&| in the current iteration. % -%\DescribeMacro{\DTLforeachkeyinrow} -%\begin{definition} -%\cs{DTLforeachkeyinrow}\marg{cmd}\marg{text} +%Within the body of \ics{DTLforeach} (i.e.\ within \meta{text}) +%the following conditionals may be used: +%\begin{definition}[\DescribeMacro{\DTLiffirstrow}]% +%\cs{DTLiffirstrow}\marg{true part}\marg{false part} %\end{definition} -%This iterates through each key in the current row, assigns -%\meta{cmd} to the value of that key, and does \meta{text}. -%(\meta{cmd} must be a control sequence.) +%If the current row is the first row, then do \meta{true part}, +%otherwise do \meta{false part}. % -%\begin{example}{Student Scores---Labelling}{ex:label} -%In the previous example, the student scores, stored in the -%database "scores" were placed in a table. In this example the -%table will be modified slightly to number each student according -%to the row. Suppose I also want to identify which row Jane Brown -%is in, and reference it in the text. The easiest way to do this -%is to construct a label on each row which uniquely identifies +%\begin{definition}[\DescribeMacro{\DTLifoddrow}]% +%\cs{DTLifoddrow}\marg{true part}\marg{false part} +%\end{definition} +%If the current row number is an odd number, then do \meta{true part}, +%otherwise do \meta{false part}. +% +%\begin{definition}[\DescribeMacro{\DTLsavelastrowcount}]% +%\cs{DTLsavelastrowcount}\marg{cmd} +%\end{definition} +%This command will store the value of the row counter used in +%the last occurrence of \ics{DTLforeach} in the control sequence +%\meta{cmd}. +% +%\begin{definition}[\DescribeMacro{\DTLforeachkeyinrow}]% +%\cs{DTLforeachkeyinrow}\marg{cmd}\marg{text} +%\end{definition} +%This iterates through each key in the current row, (globally) assigns +%\meta{cmd} to the value of that key, and does \meta{text} +%(\meta{cmd} must be a control sequence and may be used in +%\meta{text}). This command may only be used in the body of +%\cs{DTLforeach}. At each iteration, \cs{DTLforeachkeyinrow} sets +%\cs{dtlkey} to the current key, \cs{dtlcol} to the current column +%index, \cs{dtltype} to the data type for the current column, +%and \cs{dtlheader} to the header for the current column. Note that +%\cs{dtltype} corresponds to the column type but if the entries in +%the column have mixed types, it may not correspond to the type +%of the current entry. +% +%\begin{definition}[\DescribeMacro{\dtlforeachkey}]% +%\cs{dtlforeachkey}(\meta{key cs},\meta{col cs},\meta{type +%cs},\meta{header cs})\cs{in}\marg{db}\cs{do}\marg{body} +%\end{definition} +%This iterates through all the keys in the database given by +%\meta{db}. In each iteration, \meta{key cs} is set to the key, +%\meta{col cs} is set to the column index, \meta{type cs} is +%set to the data type, \meta{header cs} is set to the header +%for that column, and then \meta{body} is done. Note that +%\meta{key cs}, \meta{col cs}, \meta{type cs} and \meta{header cs} +%must all be control sequences. No check is performed to determine +%if that control sequence already exists, and the control +%sequences are defined globally (since it's likely that +%\cs{dtlforeachkey} may be used within a \env{tabular} +%environment), so you need to make sure you don't override an +%existing command of the same name. The data type may have the +%following values: 0 (string), 1 (integer), 2 (real number), 3 +%(currency) or it will be empty if the column has no entries. +% +%\begin{definition}[\DescribeMacro{\dtlforcolumn}]% +%\cs{dtlforcolumn}\marg{cs}\marg{db}\marg{key}\marg{body} +%\end{definition} +%This iterates through the column given by \meta{key} in the +%database given by \meta{db} and applies \meta{body}. In each +%iteration, \meta{cs} (which must be a control sequence) is set to +%the current element in the column and may be used in \meta{body}. +% +%\begin{definition}[\DescribeMacro{\dtlbreak}]% +%\cs{dtlbreak} +%\end{definition} +%You can break out of most of the loops provided by \sty{datatool} +%using \cs{dtlbreak}. Note, however, that it doesn't break the loop +%until the end of the current iteration. There is no provision for +%a "next" or "continue" style command. +% +%Additional loop commands provided by \sty{datatool} are +%described in \autoref{sec:code:loops}. +% +%\begin{example}{Student Scores---Labelling}{ex:label} +%In the previous example, the student scores, stored in the +%database "scores" were placed in a table. In this example the +%table will be modified slightly to number each student according +%to the row. Suppose I also want to identify which row Jane Brown +%is in, and reference it in the text. The easiest way to do this +%is to construct a label on each row which uniquely identifies %that student. The label can't simply be constructed from the %surname, as there are two students with the same surname. In order %to create a unique label, I can either construct a label from @@ -2444,7 +2801,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% -%\DTLforeach{scores}{% +%\DTLforeach*{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\label{row:\score}\\\theDTLrowi & %\firstname & \surname & \score}% @@ -2458,10 +2815,16 @@ %Jane Brown scored the highest (75\%), her score can be seen on %row~\ref*{row:75}. % -%\textbf{Note:} the \cs{label} command is placed before +%Notes: +%\begin{itemize} +%\item the \cs{label} command is placed before %"\\" to ensure that it is in the same scope as the command %"\refstepcounter{DTLrowi}". % +%\item To avoid unwanted spaces the end of line characters are +%commented out with the percent (\texttt{\%}) symbol. +%\end{itemize} +% %\begin{table}[htbp] %\caption[Student scores (labelling rows)]{Student %scores}\label{tab:scoreslab} @@ -2471,21 +2834,13 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax -%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\DTLforeach*{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\label{row:\score}\\\theDTLrowi & %\firstname & \surname & \score}\relax %\end{tabular} %\end{table} %\end{example} % -%\DescribeMacro{\DTLsavelastrowcount} -%\begin{definition} -%\cs{DTLsavelastrowcount}\marg{cmd} -%\end{definition} -%This command will store the value of the row counter used in -%the last occurrence of \ics{DTLforeach} in the control sequence -%\meta{cmd}. -% %\begin{example}{Filtering Rows}{ex:filter} %As mentioned earlier, the optional argument \meta{condition} of %\ics{DTLforeach} provides a means to exclude certain rows. @@ -2502,7 +2857,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% -%\DTLforeach[\DTLisgt{\score}{60}]{scores}{% +%\DTLforeach*[\DTLisgt{\score}{60}]{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\firstname & \surname & \score} @@ -2525,7 +2880,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax -%\DTLforeach[\DTLisgt{\score}{60}]{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\DTLforeach*[\DTLisgt{\score}{60}]{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\firstname & \surname & \score} %\end{tabular} @@ -2544,7 +2899,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% -%\DTLforeach[\DTLisopenbetween{\surname}{B}{C}]{scores}{% +%\DTLforeach*[\DTLisopenbetween{\surname}{B}{C}]{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\firstname & \surname & \score} @@ -2561,7 +2916,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax -%\DTLforeach[\DTLisopenbetween{\surname}{B}{C}]{scores} +%\DTLforeach*[\DTLisopenbetween{\surname}{B}{C}]{scores} %{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\firstname & \surname & \score} @@ -2570,21 +2925,68 @@ % %\end{example} % -%Within the body of \ics{DTLforeach} (i.e.\ within \meta{text}) -%the following conditionals may be used: -%\DescribeMacro{\DTLiffirstrow} -%\begin{definition} -%\cs{DTLiffirstrow}\marg{true part}\marg{false part} -%\end{definition} -%If the current row is the first row, then do \meta{true part}, -%otherwise do \meta{false part}. +%\begin{example}{Breaking Out of a Loop}{ex:dtlbreak} +%Suppose I only want to display the first three rows of a database. +%I could do:\footnote{Recall that \counterfmt{DTLrowi} is incremented +%after the condition is tested, so it will be out by 1 when the +%condition is tested which is why \texttt{<3} is used instead of +%\texttt{<4}.} +%\begin{verbatim} +%\DTLforeach*[\value{DTLrowi}<3]{scores}% +%{\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\\firstname & \surname & \score +%} +%\end{verbatim} +%However, this isn't very efficient, as it still has to iterate +%through the entire database, checking if the condition is met. If +%the database has over 100 entries, this will slow the time taken +%to create the table. It would therefore be much more efficient +%to break out of the loop when row count exceeds 3: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{First Three Rows} +%\centering +%\vskip\baselineskip +%\begin{tabular}{llr} +%\bfseries First Name & \bfseries Surname & \bfseries Score (\%)% +%\DTLforeach*{scores}% +%{\firstname=FirstName,\surname=Surname,\score=Score}{% +%\ifthenelse{\DTLcurrentindex=3}{\dtlbreak}{}% +%\\\firstname & \surname & \score +%}% +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:dtlbreak}. Note that the loop is not +%broken until the end of the current iteration, so even though +%\cs{dtlbreak} occurs at the start of the third row, the loop isn't +%finished until the third row is completed. (Recall that +%\cs{DTLcurrentindex} must be used before the first instance of +%\verb|\\| or \verb|&|.) Alternatively, you can use +%\counterfmt{DTLrowi} instead: +%\begin{verbatim} +%\DTLforeach{scores}% +%{\firstname=FirstName,\surname=Surname,\score=Score}{% +%\\\firstname & \surname & \score +%\ifthenelse{\value{DTLrowi}=3}{\dtlbreak}{}% +%}% +%\end{verbatim} % -%\DescribeMacro{\DTLifoddrow} -%\begin{definition} -%\cs{DTLifoddrow}\marg{true part}\marg{false part} -%\end{definition} -%If the current row number is an odd number, then do \meta{true part}, -%otherwise do \meta{false part}. +%\begin{table}[htbp] +%\caption{First Three Rows} +%\label{tab:dtlbreak}% +%\centering +%\vskip\baselineskip +%\begin{tabular}{llr} +%\bfseries First Name & \bfseries Surname & \bfseries Score (\%)\relax +%\DTLforeach*{scores}% +%{\firstname=FirstName,\surname=Surname,\score=Score}{% +%\ifthenelse{\DTLcurrentindex=3}{\dtlbreak}{}\relax +%\\\firstname & \surname & \score +%}% +%\end{tabular} +%\end{table} +%\end{example} % %\begin{example}{Stripy Tables}{ex:stripy} %This example uses the same database as in the previous examples. @@ -2599,7 +3001,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% -%\DTLforeach{scores}{% +%\DTLforeach*{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\\DTLifoddrow{\rowcolor{blue}}{\rowcolor{green}}% %\firstname & \surname & \score}% @@ -2616,7 +3018,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax -%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\DTLforeach*{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\\DTLifoddrow{\rowcolor{blue}}{\rowcolor{green}}\relax %\firstname & \surname & \score}\relax %\end{tabular} @@ -2639,7 +3041,7 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% -%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{% +%\DTLforeach*{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{% %\DTLifoddrow{\\}{&}% %\firstname & \surname & \score}% %\end{tabular} @@ -2659,13 +3061,196 @@ %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax -%\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax +%\DTLforeach*{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\DTLifoddrow{\\}{&}\relax %\firstname & \surname & \score}\relax %\end{tabular} %\end{table} %\end{example} % +%\begin{example}{Iterating Through Keys in a Row}{ex:foreachkey} +%Suppose you have lots of columns in your database, and you +%want to display them all without having to set a variable for +%each column. You can leave the assignment list in \cs{DTLforeach} +%blank, and iterate through the keys using \cs{DTLforeachkeyinrow}. +%For example: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores (Iterating Through Keys)} +%\vskip\baselineskip +%\centering +%\begin{tabular}{llll} +%\bfseries First Name & \bfseries Surname & +%\bfseries Registration No. & +%\bfseries Score (\%)% +%\DTLforeach*{scores}{}{% +%\\\gdef\doamp{\gdef\doamp{&}}% +%\DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}% +%\end{tabular} +%\end{table} +%\end{verbatim} +%This produces \autoref{tab:foreachkey}. +%\begin{table}[htbp] +%\caption{Student Scores (Iterating Through Keys)} +%\label{tab:foreachkey} +%\vskip\baselineskip +%\centering +%\begin{tabular}{llll} +%\bfseries First Name & \bfseries Surname & +%\bfseries Registration No. & +%\bfseries Score (\%)\relax +%\DTLforeach*{scores}{}{% +%\\\gdef\doamp{\gdef\doamp{&}}\relax +%\DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}\relax +%\end{tabular} +%\end{table} +% +%Note that the "&" must be between columns, so I have defined +%a command called \cs{doamp} that on first use redefines +%itself to do "&". So, for each row, at the start of +%the key iteration, \cs{doamp} does nothing, and on subsequent +%iterations it does "&". This ensures that the correct number of +%"&"s are used. Since each cell in the \env{tabular} environment +%is scoped, \cs{gdef} is needed instead of \cs{def}. +% +%In the above, I needed to know how many columns are in the +%database, and the order that the headings should appear. If you +%are unsure, you can use \cs{dtlforeachkey} to determine the +%number of columns and to display the header row. For example: +%\begin{verbatim} +% \begin{table}[htbp] +% \caption{Student Scores} +% \vskip\baselineskip +% \centering +% % Work out the column alignments. +% \def\colalign{}% +% \dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +% {\edef\colalign{\colalign l}}% +% % Begin the tabular environment. +% \edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}% +% \dobegintabular +% % Do the header row. +% \gdef\doamp{\gdef\doamp{&}}% +% \dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +% {\doamp\bfseries \theHead}% +% % Iterate through the data. +% \DTLforeach*{scores}{}{% +% \\\gdef\doamp{\gdef\doamp{&}}% +% \DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}% +% \end{tabular} +% \end{table} +%\end{verbatim} +% +%\begin{table}[htbp] +%\caption{Student Scores (Using \cs{dtlforeachkey} and +%\cs{DTLforeachkeyinrow})} +%\label{tab:foreachkey2} +%\vskip\baselineskip +%\centering +%\def\colalign{}% +%\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +%{\edef\colalign{\colalign l}}% +%\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}\relax +%\dobegintabular +%\gdef\doamp{\gdef\doamp{&}}\relax +%\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +%{\doamp\bfseries \theHead}\relax +%\DTLforeach*{scores}{}{% +%\\\gdef\doamp{\gdef\doamp{&}}\relax +%\DTLforeachkeyinrow{\thisValue}{\doamp\thisValue}}\relax +%\end{tabular} +%\end{table} +% +%Notes: +%\begin{itemize} +%\item In order to determine the column alignment for the +%\env{tabular} environment, I first define \cs{colalign} to +%nothing, and then I iterate through the keys appending +%\texttt{l} to \cs{colalign}. Since \cs{colalign} only contains +%alphabetical characters, I can just use \cs{edef} for this. I +%could modify this to check the data type and, say, use \texttt{l} +%(left alignment) for columns containing strings and \texttt{c} +%(centred) for the other columns: +%\begin{verbatim} +%\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +%{\ifnum\theType=0\relax +% \edef\colalign{\colalign l}% column contains strings +% \else +% \edef\colalign{\colalign c}% column contains numerical values +% \fi +%}% +%\end{verbatim} +% +%\item To ensure \cs{colalign} gets correct expanded when passed +%to the \env{tabular} environment I temporarily define +%\cs{dobegintabular} to the code required to start the +%\env{tabular} environment: +%\begin{verbatim} +%\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}% +%\end{verbatim} +%This sets \cs{dobegintabular} to \verb|\begin{tabular}{llll}|. +%After defining \cs{dobegintabular}, I then need to use it. +% +%\item As before, I use \cs{doamp} to put the ampersands between +%columns. +% +%\item Recall that I can set the headers using \cs{DTLsetheader} +%or using the \cmdopt{DTLloaddb}{headers} key when loading the data +%from an external file. For example: +%\begin{verbatim} +%\DTLsetheaders{scores}{FirstName}{First Name} +%\DTLsetheaders{scores}{Score}{Score (\%)} +%\end{verbatim} +%\end{itemize} +% +%Recall that \cs{DTLforeachkeyinrow} sets \cs{dtlkey} to the +%current key. This can be used to filter out columns. Alternatively, +%if you know the column index, you can test \cs{dtlcol} instead. +%The following code modifies the above example so that it filters +%out the column whose key is \texttt{StudentNo}: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Student Scores (Filtering Out a Column)} +%\vskip\baselineskip +%\centering +%\def\colalign{}% +%\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +%{\DTLifeq{\theKey}{StudentNo}{}{\edef\colalign{\colalign l}}}% +%\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}% +%\dobegintabular +%\gdef\doamp{\gdef\doamp{&}}% +%\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +%{\DTLifeq{\theKey}{StudentNo}{}{\doamp\bfseries \theHead}}% +%\DTLforeach*{scores}{}{% +%\\\gdef\doamp{\gdef\doamp{&}}% +%\DTLforeachkeyinrow{\thisValue}{% +% \DTLifeq{\dtlkey}{StudentNo}{}{\doamp\thisValue}}}% +%\end{tabular} +%\end{table} +%\end{verbatim} +%The result is shown in \autoref{tab:foreachkey3}. +% +%\begin{table}[htbp] +%\caption{Student Scores (Filtering Out a Column)} +%\label{tab:foreachkey3} +%\vskip\baselineskip +%\centering +%\def\colalign{}% +%\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +%{\DTLifeq{\theKey}{StudentNo}{}{\edef\colalign{\colalign l}}}% +%\edef\dobegintabular{\noexpand\begin{tabular}{\colalign}}\relax +%\dobegintabular +%\gdef\doamp{\gdef\doamp{&}}\relax +%\dtlforeachkey(\theKey,\theCol,\theType,\theHead)\in{scores}\do +%{\DTLifeq{\theKey}{StudentNo}{}{\doamp\bfseries \theHead}}\relax +%\DTLforeach*{scores}{}{% +%\\\gdef\doamp{\gdef\doamp{&}}\relax +%\DTLforeachkeyinrow{\thisValue}{\relax +%\DTLifeq{\dtlkey}{StudentNo}{}{\doamp\thisValue}}}\relax +%\end{tabular} +%\end{table} +%\end{example} +% %\begin{example}{Nested \cs{DTLforeach}}{ex:nested} %In this example I have a CSV file called "index.csv" which %contains: @@ -2791,11 +3376,101 @@ %} %\end{example} % +%\begin{example}{Dynamically Allocating Field Name}{ex:dyn} +%(This example was suggested by Bill~Hobbs.) Suppose you have a +%directory containing members of multiple clubs. The CSV file +%(say, \texttt{clubs.csv}) may look something like: +%\begin{verbatim} +%First Name,Surname,Rockin,Single +%John,"Smith, Jr",member, +%Jane,Brown,,friend +%Andy,Brown,friend,member +%Z\"oe,Adams,member,member +%Roger,Brady,friend,friend +%Clare,Verdon,member, +%\end{verbatim} +%\DTLnewdb{clubs}\relax +%\DTLnewrow{clubs}\relax +%\DTLnewdbentry{clubs}{First Name}{John}\relax +%\DTLnewdbentry{clubs}{Surname}{Smith, Jr}\relax +%\DTLnewdbentry{clubs}{Rockin}{member}\relax +%\DTLnewdbentry{clubs}{Single}{}\relax +%\DTLnewrow{clubs}\relax +%\DTLnewdbentry{clubs}{First Name}{Jane}\relax +%\DTLnewdbentry{clubs}{Surname}{Brown}\relax +%\DTLnewdbentry{clubs}{Rockin}{}\relax +%\DTLnewdbentry{clubs}{Single}{friend}\relax +%\DTLnewrow{clubs}\relax +%\DTLnewdbentry{clubs}{First Name}{Andy}\relax +%\DTLnewdbentry{clubs}{Surname}{Brown}\relax +%\DTLnewdbentry{clubs}{Rockin}{friend}\relax +%\DTLnewdbentry{clubs}{Single}{member}\relax +%\DTLnewrow{clubs}\relax +%\DTLnewdbentry{clubs}{First Name}{Z\"oe}\relax +%\DTLnewdbentry{clubs}{Surname}{Adams}\relax +%\DTLnewdbentry{clubs}{Rockin}{member}\relax +%\DTLnewdbentry{clubs}{Single}{member}\relax +%\DTLnewrow{clubs}\relax +%\DTLnewdbentry{clubs}{First Name}{Roger}\relax +%\DTLnewdbentry{clubs}{Surname}{Brady}\relax +%\DTLnewdbentry{clubs}{Rockin}{friend}\relax +%\DTLnewdbentry{clubs}{Single}{friend}\relax +%\DTLnewrow{clubs}\relax +%\DTLnewdbentry{clubs}{First Name}{Clare}\relax +%\DTLnewdbentry{clubs}{Surname}{Verdon}\relax +%\DTLnewdbentry{clubs}{Rockin}{member}\relax +%\DTLnewdbentry{clubs}{Single}{}\relax +%(Blank entries indicate that the person is not a member of that +%club.) The data can be loaded as follows: +%\begin{verbatim} +%\DTLloaddb{clubs}{clubs.csv} +%\end{verbatim} +%Suppose at the beginning of your document you have specified +%which club you are interested in ("Rockin" or "Single") and +%store it in \cs{DIdent}: +%\begin{verbatim} +%\newcommand{\DIdent}{Rockin} +%\end{verbatim} +%\newcommand{\DIdent}{Rockin}\relax +%You can now display the members for this particular club as +%follows: +%\begin{verbatim} +%\begin{table}[htbp] +%\caption{Club Membership} +%\vskip\baselineskip +%\centering +%\begin{tabular}{lll} +%\bfseries First Name & \bfseries Surname & \bfseries Status +%\DTLforeach*[\not\DTLiseq{\status}{}]{clubs} +%{\firstname=First Name,\surname=Surname,\status=\DIdent}{% +%\\\firstname & \surname & \status +%}% +%\end{tabular} +%\end{table} +%\end{verbatim} +%The result is shown in \autoref{tab:dyn}. +% +%\begin{table}[htbp] +%\caption{Club Membership} +%\label{tab:dyn} +%\vskip\baselineskip +%\centering +%\begin{tabular}{lll} +%\bfseries First Name & \bfseries Surname & \bfseries Status +%\DTLforeach*[\not\DTLiseq{\status}{}]{clubs} +%{\firstname=First Name,\surname=Surname,\status=\DIdent}{\relax +%\\\firstname & \surname & \status +%}\relax +%\end{tabular} +%\end{table} +%\end{example} +% %\subsection{Null Values} %If a database is created using \cs{DTLnewdb}, \cs{DTLnewrow} %and \cs{DTLnewdbentry} (rather than loading it from an ASCII %file), it is possible for some of the entries to have null values %when a value is not assigned to a given key for a given row. +%(Note that a null value is not the same as an empty value.) % %When you iterate through the database using \cs{DTLforeach} %(described in \autoref{sec:dbforeach}), @@ -2803,20 +3478,17 @@ %in the \meta{values} argument will be set to a null value. This %value depends on the data type associated with the given key. % -%\DescribeMacro{\DTLstringnull} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLstringnull}]% %\cs{DTLstringnull} %\end{definition} %This is the null value for a string. % -%\DescribeMacro{\DTLnumbernull} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLnumbernull}]% %\cs{DTLnumbernull} %\end{definition} %This is the null value for a number. % -%\DescribeMacro{\DTLifnull} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifnull}]% %\cs{DTLifnull}\marg{cmd}\marg{true part}\marg{false part} %\end{definition} %This checks if \meta{cmd} is null where \meta{cmd} is a command name, @@ -2991,29 +3663,26 @@ %\subsection{Editing Database Rows} %\label{sec:editdb} % -%In the body of the \ics{DTLforeach} loop, you can use the following -%to edit the current row: -%\DescribeMacro{\DTLappendtorow} -%\begin{definition} +%In the body of the \ics{DTLforeach} loop,\footnote{Only the +%unstarred version of \cs{DTLforeach}; the starred version is +%read-only.}\ you can use the following to edit the current row: +%\begin{definition}[\DescribeMacro{\DTLappendtorow}]% %\cs{DTLappendtorow}\marg{key}\marg{value} %\end{definition} %This appends a new entry with the given \meta{key} and \meta{value} %to the current row. % -%\DescribeMacro{\DTLreplaceentryforrow} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLreplaceentryforrow}]% %\cs{DTLreplaceentryforrow}\marg{key}\marg{value} %\end{definition} %This replaces the entry for \meta{key} with \meta{value}. % -%\DescribeMacro{\DTLremoveentryfromrow} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLremoveentryfromrow}]% %\cs{DTLremoveentryfromrow}\marg{key} %\end{definition} -%This the entry for \meta{key} from the current row. +%This removes the entry for \meta{key} from the current row. % -%\DescribeMacro{\DTLremovecurrentrow} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLremovecurrentrow}]% %\cs{DTLremovecurrentrow} %\end{definition} %This removes the current row from the database. @@ -3100,7 +3769,7 @@ %\begin{table}[htbp] %\caption{Student marks} %\centering -%\begin{tabular}{llrrrr} +%\begin{tabular}{llcccc} %\bfseries Surname & \bfseries First Name & %\bfseries Assign 1 & %\bfseries Assign 2 & @@ -3127,7 +3796,7 @@ %\caption[Student marks (with averages)]{Student %marks}\label{tab:meanmarks} %\centering -%\begin{tabular}{llrrrr} +%\begin{tabular}{llcccc} %\bfseries Surname & \bfseries First Name & %\bfseries Assign 1 & %\bfseries Assign 2 & @@ -3223,29 +3892,40 @@ %\end{table} %\end{example} % -%\DescribeMacro{\DTLsumforkeys} -%\begin{definition} -%\cs{DTLsumforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\begin{definition}[\DescribeMacro{\DTLsumforkeys}]% +%\cs{DTLsumforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} %\end{definition} -%This command sums all the entries over all the databases listed in -%the comma separated list of database names \meta{db list} for each key in -%\meta{key list} where the condition given by -%\meta{condition} is true. The result is stored in \meta{cmd} -%which must be a control sequence. For example: +%This command sums all the entries over all the databases listed in +%the comma separated list of database names \meta{db list} for each +%key in \meta{key list} where the condition given by \meta{condition} +%is true. The second optional argument \meta{assign list} is the same +%as the assignment list used by \ics{DTLforeach}, so that you can use +%the information in \meta{condition}. The result is stored in +%\meta{cmd} which must be a control sequence. For example: %\begin{verbatim} %\DTLsumforkeys{scores}{Score}{\total} %\end{verbatim} %sets \cs{total} to the sum of all the scores in the database %called "scores". % -%\DescribeMacro{\DTLmeanforkeys} -%\begin{definition} -%\cs{DTLmeanforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\begin{definition}[\DescribeMacro{\DTLsumcolumn}]% +%\cs{DTLsumcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +%This is a faster version of \cs{DTLsumforkeys} that only sums +%the entries in a single column (specified by \meta{key}) for +%a single database (specified by \meta{db}) and doesn't provide any +%filtering. The result is stored in \meta{cmd} which must be +%a control sequence. +% +%\begin{definition}[\DescribeMacro{\DTLmeanforkeys}]% +%\cs{DTLmeanforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} %\end{definition} %This command computes the arithmetic mean of all the entries over -%all the databases listed in \meta{db list} for all keys in \meta{key list} where -%the condition -%given by \meta{condition} is true. The result is stored in \meta{cmd} +%all the databases listed in \meta{db list} for all keys in \meta{key +%list} where the condition given by \meta{condition} is true. The +%second optional argument \meta{assign list} is the same as the +%assignment list used by \ics{DTLforeach}, so that you can use the +%information in \meta{condition}. The result is stored in \meta{cmd} %which must be a control sequence. For example: %\begin{verbatim} %\DTLmeanforkeys{scores}{Score}{\average} @@ -3253,55 +3933,105 @@ %sets \cs{average} to the mean of all the scores in the database %called "scores". % -%\DescribeMacro{\DTLvarianceforkeys} -%\begin{definition} -%\cs{DTLvarianceforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\begin{definition}[\DescribeMacro{\DTLmeanforcolumn}]% +%\cs{DTLmeanforcolumn}\marg{db}\marg{key}\marg{cmd} %\end{definition} -%This command computes the variance of all the entries over -%all the databases listed in \meta{db list} for all keys in \meta{key list} where -%the condition -%given by \meta{condition} is true. The result is stored in \meta{cmd} -%which must be a control sequence. +%This is a faster version of \cs{DTLmeanforkeys} that only computes +%the mean for a single column (specified by \meta{key}) for +%a single database (specified by \meta{db}) and doesn't provide any +%filtering. The result is stored in \meta{cmd} which must be +%a control sequence. % -%\DescribeMacro{\DTLsdforkeys} -%\begin{definition} -%\cs{DTLsdforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\begin{definition}[\DescribeMacro{\DTLvarianceforkeys}]% +%\cs{DTLvarianceforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +%This command computes the variance of all the entries over all the +%databases listed in \meta{db list} for all keys in \meta{key list} +%where the condition given by \meta{condition} is true. The second +%optional argument \meta{assign list} is the same as the assignment +%list used by \ics{DTLforeach}, so that you can use the information +%in \meta{condition}. The result is stored in \meta{cmd} which must +%be a control sequence. +% +%\begin{definition}[\DescribeMacro{\DTLvarianceforcolumn}]% +%\cs{DTLvarianceforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +%This is a faster version of \cs{DTLvarianceforkeys} that only +%computes the variance for a single column (specified by \meta{key}) +%for a single database (specified by \meta{db}) and doesn't provide +%any filtering. The result is stored in \meta{cmd} which must be a +%control sequence. +% +%\begin{definition}[\DescribeMacro{\DTLsdforkeys}]% +%\cs{DTLsdforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} %\end{definition} %This command computes the standard deviation of all the entries over -%all the databases listed in \meta{db list} for all keys in \meta{key list} where -%the condition -%given by \meta{condition} is true. The result is stored in \meta{cmd} +%all the databases listed in \meta{db list} for all keys in \meta{key +%list} where the condition given by \meta{condition} is true. The +%second optional argument \meta{assign list} is the same as the +%assignment list used by \ics{DTLforeach}, so that you can use the +%information in \meta{condition}. The result is stored in \meta{cmd} %which must be a control sequence. % -%\DescribeMacro{\DTLminforkeys} -%\begin{definition} -%\cs{DTLminforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\begin{definition}[\DescribeMacro{\DTLsdforcolumn}]% +%\cs{DTLsdforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +%This is a faster version of \cs{DTLsdforkeys} that only computes the +%standard deviation for a single column (specified by \meta{key}) for +%a single database (specified by \meta{db}) and doesn't provide any +%filtering. The result is stored in \meta{cmd} which must be a +%control sequence. +% +%\begin{definition}[\DescribeMacro{\DTLminforkeys}]% +%\cs{DTLminforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} %\end{definition} -%This command determines the minimum value over all entries -%for all keys in \meta{key list} over all the databases listed in \meta{db list} -%and stores -%in \meta{cmd}, which must be a control sequence. For example +%This command determines the minimum value over all entries for all +%keys in \meta{key list} over all the databases listed in \meta{db +%list} where \meta{condition} is true. The second optional argument +%\meta{assign list} is the same as the assignment list used by +%\ics{DTLforeach}, so that you can use the information in +%\meta{condition}. The result is stored in \meta{cmd}, which must be +%a control sequence. For example %\begin{verbatim} %\DTLminforkeys{scores}{Score}{\theMin} %\end{verbatim} %sets \cs{theMin} to the minimum score in the database. % -%\DescribeMacro{\DTLmaxforkeys} -%\begin{definition} -%\cs{DTLmaxforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\begin{definition}[\DescribeMacro{\DTLminforcolumn}]% +%\cs{DTLminforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +%This is a faster version of \cs{DTLminforkeys} that only computes +%the minimum for a single column (specified by \meta{key}) for +%a single database (specified by \meta{db}) and doesn't provide any +%filtering. The result is stored in \meta{cmd} which must be +%a control sequence. +% +%\begin{definition}[\DescribeMacro{\DTLmaxforkeys}]% +%\cs{DTLmaxforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} %\end{definition} -%This command determines the maximum value over all entries -%for all keys in \meta{key list} over all the databases listed in \meta{db list} -%and stores -%in \meta{cmd}, which must be a control sequence. For example +%This command determines the maximum value over all entries for all +%keys in \meta{key list} over all the databases listed in \meta{db +%list} where \meta{condition} is true. The second optional argument +%\meta{assign list} is the same as the assignment list used by +%\ics{DTLforeach}, so that you can use the information in +%\meta{condition}. The result is stored in \meta{cmd}, which must be +%a control sequence. For example %\begin{verbatim} %\DTLminforkeys{scores}{Score}{\theMax} %\end{verbatim} %sets \cs{theMax} to the minimum score in the database. % -%\DescribeMacro{\DTLcomputebounds} -%\begin{definition} -%\cs{DTLcomputebounds}\marg{condition}\marg{db list}\marg{x key}\marg{y key}\marg{minX cmd}\marg{minY cmd}\marg{maxX cmd}\marg{maxY cmd} +%\begin{definition}[\DescribeMacro{\DTLmaxforcolumn}]% +%\cs{DTLmaxforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +%This is a faster version of \cs{DTLmaxforkeys} that only computes +%the maximum for a single column (specified by \meta{key}) for +%a single database (specified by \meta{db}) and doesn't provide any +%filtering. The result is stored in \meta{cmd} which must be +%a control sequence. +% +%\begin{definition}[\DescribeMacro{\DTLcomputebounds}]% +%\cs{DTLcomputebounds}\marg{db list}\marg{x key}\marg{y key}\marg{minX cmd}\marg{minY cmd}\marg{maxX cmd}\marg{maxY cmd} %\end{definition} %Computes the maximum and minimum $x$ and $y$ values over all %the databases listed in \meta{db list} where the $x$ value @@ -3350,12 +4080,10 @@ %\subsection{Sorting a Database} %\label{sec:sort} % -%\DescribeMacro{\DTLsort} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsort}]% %\cs{DTLsort}\oarg{replacement key list}\marg{sort criteria}\marg{db name} %\end{definition} -%\DescribeMacro{\DTLsort*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsort*}]% %\cs{DTLsort*}\oarg{replacement key list}\marg{sort criteria}\marg{db name} %\end{definition} %This will sort the database called \meta{db name} according to @@ -3644,8 +4372,7 @@ %\subsection{Saving a Database to an External File} %\label{sec:savedb} % -%\DescribeMacro{\DTLsavedb} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsavedb}]% %\cs{DTLsavedb}\marg{db name}\marg{filename} %\end{definition} %This writes the database called \meta{db name} to a file called @@ -3656,12 +4383,11 @@ %\DTLsettabdelimiter %\DTLsavedb{scores}{scores.txt} %\end{verbatim} -%will create a file called "scores.txt", and save the data in a +%will create a file called "scores.txt" and will save the data in a %tab separated format. (The delimiters will only be used if a %given entry contains the separator character.) % -%\DescribeMacro{\DTLsavetexdb} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsavetexdb}]% %\cs{DTLsavetexdb}\marg{db name}\marg{filename} %\end{definition} %This writes the database called \meta{db name} to a \LaTeX\ file @@ -3672,29 +4398,28 @@ %\section{Pie Charts (\texorpdfstring{\sty{datapie}}{datapie} package)} % %The \sty{datapie} package is not loaded by the \sty{datatool} package, -%so you need to load \sty{datapie} if you want to use any of the -%commands defined in this section. You will need to have the +%so you need to explicitly load \sty{datapie} if you want to use any of the +%commands defined in this section. You will also need to have the %\sty{pgf}/\sty{tikz} packages installed. The \sty{datapie} package %may be given the following options: %\begin{description} -%\item[{\pkgopt[datapie]{color}}] Colour option (default.) +%\item[{\pkgopt[datapie]{color}}] Colour option (default). %\item[{\pkgopt[datapie]{monochrome}}] Monochrome option. %\item[{\pkgopt[datapie]{rotateinner}}] %Rotate inner labels so that they are aligned %with the pie chart radial axis. %\item[{\pkgopt[datapie]{norotateinner}}] -%Don't rotate inner labels (default.) +%Don't rotate inner labels (default). %\item[{\pkgopt[datapie]{rotateouter}}] %Rotate outer labels so that they are aligned %with the pie chart radial axis. %\item[{\pkgopt[datapie]{norotateouter}}] -%Don't rotate outer labels (default.) +%Don't rotate outer labels (default). %\end{description} % %Numerical information contained in a database created by the %\sty{datatool} package can be converted into a pie chart using -%\DescribeMacro{\DTLpiechart} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpiechart}]% %\cs{DTLpiechart}\oarg{condition}\marg{settings list}\marg{db name}\marg{values} %\end{definition}\noindent %where \meta{db name} is the name of the database, and @@ -3771,7 +4496,7 @@ %\item[\setting{DTLpiechart}{cutaway}] %This is a list of cutaway segments. This should be %a comma separated list of individual numbers, or number ranges -%(separated by a dash.) For example "cutaway={1,3}" will separate +%(separated by a dash). For example "cutaway={1,3}" will separate %the first and third segments from the rest of the pie chart, offset %by the value of the \setting{DTLpiechart}{cutawayoffset} setting, %whereas "cutaway={1-3}" will separate the @@ -3968,8 +4693,7 @@ % %\subsection{Pie Chart Variables} % -%\DescribeMacro{\DTLpievariable} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpievariable}]% %\cs{DTLpievariable} %\end{definition} %This command is set to the variable given by the @@ -3977,8 +4701,7 @@ %argument of \cs{DTLpiechart}. The \setting{DTLpiechart}{innerlabel} %is set to \cs{DTLpievariable} by default. % -%\DescribeMacro{\DTLpiepercent} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpiepercent}]% %\cs{DTLpiepercent} %\end{definition} %This command is set to the percentage value of \cs{DTLpievariable}. @@ -4006,8 +4729,7 @@ %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent -%\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{% -%\name=Name,\quantity=Quantity} +%\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart (changing the labels)} %\label{fig:piechartlabels} %\end{figure} @@ -4015,15 +4737,13 @@ % %\subsection{Pie Chart Label Formatting} % -%\DescribeMacro{\DTLdisplayinnerlabel} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdisplayinnerlabel}]% %\cs{DTLdisplayinnerlabel}\marg{text} %\end{definition} %This governs how the inner label is formatted, where \meta{text} %is the text of the inner label. The default is to just do \meta{text}. % -%\DescribeMacro{\DTLdisplayouterlabel} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdisplayouterlabel}]% %\cs{DTLdisplayouterlabel}\marg{text} %\end{definition} %This governs how the outer label is formatted, where \meta{text} @@ -4053,8 +4773,7 @@ %\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} %\renewcommand*{\DTLdisplayouterlabel}[1]{\textsf{#1}} %\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent -%\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{% -%\name=Name,\quantity=Quantity} +%\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart (changing the label format)} %\label{fig:piechartlabelformat} %\end{figure} @@ -4063,42 +4782,43 @@ %\subsection{Pie Chart Colours} % %The \sty{datapie} package predefines colours for the first -%eight segments of the pie chart. If you require more than -%eight segments, you will need to use -%\DescribeMacro{\DTLsetpiesegmentcolor} -%\begin{definition} +%eight segments of the pie chart. If you require more than +%eight segments or if you want to change the default colours, you +%will need to use +%\begin{definition}[\DescribeMacro{\DTLsetpiesegmentcolor}]% %\cs{DTLsetpiesegmentcolor}\marg{n}\marg{color} %\end{definition}\noindent -%to set the colours for any additional segments, or you can use -%it to change the default colours. The first argument \meta{n} -%is the segment index (starting from 1), and the second argument -%\meta{color} is a colour specifier as used in commands such as -%\cs{color}. -% -%\DescribeMacro{\DTLdopiesegmentcolor} -%\begin{definition} +%The first argument \meta{n} is the segment index (starting from 1), +%and the second argument \meta{color} is a colour specifier as used +%in commands such as \cs{color}. +% +%It is a good idea to set the colours so that each segment colour +%is somehow relevant to whatever the segment represents. For +%example, in the previous examples of pie charts depicting fruit, +%some of default colours were inappropriate. Whilst red is +%appropriate for apples and green is appropriate for pears, blue +%doesn't really correspond to lemons or limes. +% +%\begin{definition}[\DescribeMacro{\DTLdopiesegmentcolor}]% %\cs{DTLdopiesegmentcolor}\meta{n} %\end{definition} %This sets the current text colour to that of the \meta{n}th %segment. % -%\DescribeMacro{\DTLdocurrentpiesegmentcolor} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdocurrentpiesegmentcolor}]% %\cs{DTLdocurrentpiesegmentcolor} %\end{definition} %This sets the current text colour to that of the current pie %segment. This command may only be used within a pie chart, or %within the body of \ics{DTLforeach}. % -%\DescribeMacro{\DTLpieoutlinecolor} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpieoutlinecolor}]% %\cs{DTLpieoutlinecolor} %\end{definition} %This sets the outline colour for the pie chart. The default is %black. % -%\DescribeMacro{\DTLpieoutlinewidth} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpieoutlinewidth}]% %\cs{DTLpieoutlinewidth} %\end{definition} %This is a length that governs the line width of the outline. The @@ -4110,13 +4830,15 @@ %This example extends \autoref{ex:pielabelformat}. %It sets the outline thickness to 2pt, and %the outer label is now set in the same colour as the fill colour -%of the segment to which it belongs. -%In addition, a legend is created using -%\ics{DTLforeach}. +%of the segment to which it belongs. The third segment (lemons and +%limes) is set to yellow and the fourth segment (peaches) is set +%to pink. In addition, a legend is created using \ics{DTLforeach}. %\begin{verbatim} %\begin{figure}[htbp] %\centering %\setlength{\DTLpieoutlinewidth}{2pt} +%\DTLsetpiesegmentcolor{3}{yellow} +%\DTLsetpiesegmentcolor{4}{pink} %\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} %\renewcommand*{\DTLdisplayouterlabel}[1]{% %\DTLdocurrentpiesegmentcolor @@ -4144,13 +4866,14 @@ %\begin{figure}[htbp] %\centering %\setlength{\DTLpieoutlinewidth}{2pt} +%\DTLsetpiesegmentcolor{3}{yellow} +%\DTLsetpiesegmentcolor{4}{pink} %\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} %\renewcommand*{\DTLdisplayouterlabel}[1]{\relax %\DTLdocurrentpiesegmentcolor %\textsf{\shortstack{#1}}} %\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent -%\%},outerlabel={\name\\(\DTLpievariable)}}{fruit}{% -%\name=Name,\quantity=Quantity} +%\%},outerlabel={\name\\(\DTLpievariable)}}{fruit}{\name=Name,\quantity=Quantity} %\begin{tabular}[b]{ll} %\DTLforeach{fruit}{\name=Name}{\DTLiffirstrow{}{\\}\relax %\DTLdocurrentpiesegmentcolor\rule{10pt}{10pt} & @@ -4165,20 +4888,18 @@ %\subsection{Adding Extra Commands Before and After the Pie Chart} % %The pie charts created using \ics{DTLpiechart} are placed inside -%a \env{tikzpicture} environment (defined by the \sty{tikz} package.) +%a \env{tikzpicture} environment (defined by the \sty{tikz} package). % -%\DescribeMacro{\DTLpieatbegintikz} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpieatbegintikz}]% %\cs{DTLpieatbegintikz} %\end{definition} %The macro \cs{DTLpieatbegintikz} is called at the start of the %\env{tikzpicture} environment, allowing you to change the %\env{tikzpicture} settings. By default \cs{DTLpieatbegintikz} %does nothing, but you can redefine it to, say, scale the pie -%chart. +%chart (but be careful not to distort the chart). % -%\DescribeMacro{\DTLpieatendtikz} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLpieatendtikz}]% %\cs{DTLpieatendtikz} %\end{definition} %The macro \cs{DTLpieatendtikz} is called at the end of the @@ -4191,6 +4912,8 @@ %\begin{verbatim} %\begin{figure}[htbp] %\centering +%\renewcommand*{\DTLpieatendtikz}{% +%\draw[<-] (45:1.5cm) -- (40:2.5cm)node[right]{Apples};} %\DTLpiechart{variable=\quantity}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{An annotated pie chart} @@ -4219,8 +4942,8 @@ %package is not loaded by \sty{datatool} so if you want to use %it you need to load it explicitly using "\usepackage{dataplot}". % -%\DescribeMacro{\DTLplot} -%\begin{definition} +% +%\begin{definition}[\DescribeMacro{\DTLplot}]% %\cs{DTLplot}\oarg{condition}\marg{db list}\marg{settings} %\end{definition} %This command creates a plot (inside a \env{tikzpicture} environment) @@ -4236,7 +4959,7 @@ %a number, or list of numbers (such as \setting{DTLplot}{bounds}) %the number must be supplied in standard decimal notation (i.e.\ %no currency, no number groups, and a full stop as the decimal -%point.) Available settings are as follows: +%point). Available settings are as follows: %\begin{description} %\item[\setting{DTLplot}{x}] The database key %that specifies the $x$ co-ordinates. This setting is required. @@ -4284,7 +5007,7 @@ %\item[\setting{DTLplot}{style}] This setting governs whether %to use lines or markers in the plot, and may take one of %the following values: "both" (lines and markers), -%"lines" (only lines) or "markers" (only markers.) The default is +%"lines" (only lines) or "markers" (only markers). The default is %"markers". % %\item[\setting{DTLplot}{axes}] This setting governs whether @@ -4587,13 +5310,11 @@ % %The \sty{datatool} package provides two hooks used at the beginning %and end of the \env{tikzpicture} environment: -%\DescribeMacro{\DTLplotatbegintikz} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotatbegintikz}]% %\cs{DTLplotatbegintikz} %\end{definition}\noindent %and -%\DescribeMacro{\DTLplotatendtikz} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotatendtikz}]% %\cs{DTLplotatendtikz} %\end{definition} %They are both defined to do nothing by default, but can be redefined @@ -4601,8 +5322,7 @@ %using these hooks, so you can use the same co-ordinates as those %in the data sets. % -%\DescribeMacro{\DTLaddtoplotlegend} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLaddtoplotlegend}]% %\cs{DTLaddtoplotlegend}\marg{marker}\marg{line style}\marg{text} %\end{definition} %This adds a new row to the plot legend where \meta{marker} is @@ -4656,45 +5376,39 @@ %the plot created using \ics{DTLplot}. These lengths can be %changed using \cs{setlength}. % -%\DescribeMacro{\DTLplotwidth} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotwidth}]% %\cs{DTLplotwidth} %\end{definition} %This length governs the length of the $x$ axis. Note that the plot %width does not include any outer tick marks or labels. The default %value is 4in. % -%\DescribeMacro{\DTLplotheight} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotheight}]% %\cs{DTLplotheight} %\end{definition} %This length governs the length of the $y$ axis. Note that the plot %height does not include any outer tick marks or labels. The default %value is 4in % -%\DescribeMacro{\DTLticklength} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLticklength}]% %\cs{DTLticklength} %\end{definition} %This governs the length of the tick marks. The default value is %5pt. % -%\DescribeMacro{\DTLminorticklength} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLminorticklength}]% %\cs{DTLminorticklength} %\end{definition} %This governs the length of the minor tick marks. The default value is %2pt. % -%\DescribeMacro{\DTLticklabeloffset} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLticklabeloffset}]% %\cs{DTLticklabeloffset} %\end{definition} %This governs the distance from the axis to the tick labels. The %default value is 8pt. % -%\DescribeMacro{\DTLmintickgap} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmintickgap}]% %\cs{DTLmintickgap} %\end{definition} %This is the minimum distance allowed between tick marks. If the @@ -4702,15 +5416,13 @@ %be tick marks at either end of the axis. The default value is %20pt. % -%\DescribeMacro{\DTLlegendxoffset} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLlegendxoffset}]% %\cs{DTLlegendxoffset} %\end{definition} %This is the horizontal distance from the border of the plot to the %outer border of the legend. The default value is 10pt. % -%\DescribeMacro{\DTLlegendyoffset} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLlegendyoffset}]% %\cs{DTLlegendyoffset} %\end{definition} %This is the vertical distance from the border of the plot to the @@ -4741,8 +5453,7 @@ %These macros govern the appearance of plots created using %\ics{DTLplot}. They can be changed using \cs{renewcommand}. % -%\DescribeMacro{\DTLplotmarks} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotmarks}]% %\cs{DTLplotmarks} %\end{definition} %This must be a comma separated list of \sty{pgf} code to create the @@ -4751,8 +5462,7 @@ %for generating plots using \cs{pgfuseplotmark}. See the \sty{pgf} %manual for more details. % -%\DescribeMacro{\DTLplotmarkcolors} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotmarkcolors}]% %\cs{DTLplotmarkcolors} %\end{definition} %This must be a comma separated list of defined colours to apply to the @@ -4760,8 +5470,7 @@ %listed. If this macro is set to empty, the current colour will %be used instead. % -%\DescribeMacro{\DTLplotlines} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotlines}]% %\cs{DTLplotlines} %\end{definition} %This must be a comma separated list of \sty{pgf} code to set the @@ -4770,8 +5479,7 @@ %see the \sty{pgf} manual for more details. If \cs{DTLplotlines} is %set to empty the current line style will be used instead. % -%\DescribeMacro{\DTLplotlinecolors} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLplotlinecolors}]% %\cs{DTLplotlinecolors} %\end{definition} %This must be a comma separated list of defined colours to apply to the @@ -4779,9 +5487,8 @@ %listed. If this macro is set to empty, the current colour will %be used instead. The default is the same as \cs{DTLplotmarkcolors}. % -%\DescribeMacro{\DTLXAxisStyle} -%\begin{definition} -%\cs{DTLxaxisstyle} +%\begin{definition}[\DescribeMacro{\DTLXAxisStyle}]% +%\cs{DTLXAxisStyle} %\end{definition} %This governs the style of the $x$ axis. It is passed as the optional %argument to the TikZ \cs{draw} command. By default it is just "-" @@ -4793,15 +5500,13 @@ %\renewcommand*{\DTLXAxisStyle}{->} %\end{verbatim} % -%\DescribeMacro{\DTLYAxisStyle} -%\begin{definition} -%\cs{DTLyaxisstyle} +%\begin{definition}[\DescribeMacro{\DTLYAxisStyle}]% +%\cs{DTLYAxisStyle} %\end{definition} %This governs the style of the $y$ axis. It is analogous to -%\cs{DTLxaxisstyle} described above. +%\cs{DTLXAxisStyle} described above. % -%\DescribeMacro{\DTLmajorgridstyle} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmajorgridstyle}]% %\cs{DTLmajorgridstyle} %\end{definition} %This specifies the format of the major grid lines. @@ -4809,8 +5514,7 @@ %optional argument of \cs{draw}. The default value is %"color=gray,-" which indicates a grey solid line. % -%\DescribeMacro{\DTLminorgridstyle} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLminorgridstyle}]% %\cs{DTLminorgridstyle} %\end{definition} %This specifies the format of the minor grid lines. @@ -4818,8 +5522,7 @@ %optional argument of \cs{draw}. The default value is %"color=gray,loosely dotted" which indicates a grey dotted line. % -%\DescribeMacro{\DTLformatlegend} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatlegend}]% %\cs{DTLformatlegend}\marg{legend} %\end{definition} %This formats the entire legend, which is passed as the argument. @@ -4827,8 +5530,8 @@ %a white background, a black frame. % %\subsection{Adding to a Plot Stream} -%\DescribeMacro{\DTLplotstream} -%\begin{definition} +% +%\begin{definition}[\DescribeMacro{\DTLplotstream}]% %\cs{DTLplotstream}\oarg{condition}\marg{db name}\marg{x key}\marg{y key} %\end{definition} %This adds points to a stream from the database called \meta{db name} @@ -5009,7 +5712,8 @@ %The \sty{databar} package provides commands for creating bar charts. %It is not loaded by the \sty{datatool} package, so if you want to %use it you will need to load it explicitly using -%"\usepackage{databar}". +%"\usepackage{databar}". You must also have the \sty{pgf} package +%installed. % %Bar charts can either be vertical or horizontal, the default is %vertical. In this section the $x$ axis refers to the horizontal @@ -5033,23 +5737,22 @@ %The \sty{databar} package options are as follows: %\begin{description} %\item[{\pkgopt[databar]{color}}] Created coloured bar charts -%(default.) +%(default). % %\item[{\pkgopt[databar]{gray}}] Created grey scale bar charts. % %\item[{\pkgopt[databar]{vertical}}] Created vertical bar charts -%(default.) +%(default). % %\item[{\pkgopt[databar]{horizontal}}] Created horizontal bar charts. %\end{description} % % -%\DescribeMacro{\DTLbarchart} -%\begin{definition} +% +%\begin{definition}[\DescribeMacro{\DTLbarchart}]% %\cs{DTLbarchart}\oarg{condition}\marg{db name}\marg{settings}\marg{values} %\end{definition} -%\DescribeMacro{\DTLmultibarchart} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLmultibarchart}]% %\cs{DTLmultibarchart}\oarg{condition}\marg{db name}\marg{settings}\marg{values} %\end{definition} %These commands both create a bar chart from the information in @@ -5145,7 +5848,7 @@ %\item[\setting{DTLbarchart,DTLmultibarchart}{verticalbars}] %This is a boolean setting, so it can only take the values %"true" (do a vertical bar chart) or "false" (do a horizontal -%bar chart.) If the value is omitted, "true" is assumed. +%bar chart). If the value is omitted, "true" is assumed. %\end{description} % %\begin{example}{A Basic Bar Chart}{ex:barchart} @@ -5171,22 +5874,20 @@ % %\subsection{Changing the Appearance of a Bar Chart} % -%\DescribeMacro{\DTLbarchartlength} -%\begin{definition} +% +%\begin{definition}[\DescribeMacro{\DTLbarchartlength}]% %\cs{DTLbarchartlength} %\end{definition} %This specifies the total length of the $y$ axis. You must use %\cs{setlength} to change this value. The default value is 3in. % -%\DescribeMacro{\DTLbarwidth} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbarwidth}]% %\cs{DTLbarwidth} %\end{definition} %This specifies the width of each bar. You must use \cs{setlength} %to change this value. The default value is 1cm. % -%\DescribeMacro{\DTLbarlabeloffset} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbarlabeloffset}]% %\cs{DTLbarlabeloffset} %\end{definition} %This specifies the distance from the $x$ axis to the lower bar label. @@ -5201,58 +5902,75 @@ %counter \counterfmt{DTLbarroundvar}. You must use \cs{setcounter} %to change this value. % -%\DescribeMacro{\DTLsetbarcolor} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLsetbarcolor}]% %\cs{DTLsetbarcolor}\marg{n}\marg{color} %\end{definition} %This sets the \meta{n}th bar colour to \meta{color}. %Only the first eight bars have a colour defined by default. If you %need more than eight bars, you will need to define more bar colours. +%It is recommended that you set the colour of each bar to +%correspond with whatever the bar represents. % -%\DescribeMacro{\DTLdobarcolor} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdobarcolor}]% %\cs{DTLdobarcolor}\marg{n} %\end{definition} %This sets the current colour to the colour of the \meta{n}th bar. % -%\DescribeMacro{\DTLbaroutlinecolor} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbaroutlinecolor}]% %\cs{DTLbaroutlinecolor} %\end{definition} %This macro contains the colour of the bar outlines. This defaults %to "black". % -%\DescribeMacro{\DTLbaroutlinewidth} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbaroutlinewidth}]% %\cs{DTLbaroutlinewidth} %\end{definition} %This length specifies the line width for the bar outlines. If it %is 0pt, the outline is not drawn. The default value is 0pt. % -%\DescribeMacro{\DTLbaratbegintikz} -%\begin{definition} +% +%\begin{definition}[\DescribeMacro{\DTLbaratbegintikz}]% %\cs{DTLbaratbegintikz} %\end{definition} %This specifies any additional commands to add to the start of %the plot. It defaults to nothing, and is called after the %unit vectors are set. % -%\DescribeMacro{\DTLbaratendtikz} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbaratendtikz}]% %\cs{DTLbaratendtikz} %\end{definition} %This specifies any additional commands to add to the end of %the plot. It defaults to nothing. % -%\DescribeMacro{\ifDTLverticalbars} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLeverybarhook}]% +%\cs{DTLeverybarhook} +%\end{definition} +%The specifies code to apply at every bar. Within the definition +%of \cs{DTLeverybarhook} you can use the commands +%\DescribeMacro{\DTLstartpt}\cs{DTLstartpt} (the start +%of the bar), \DescribeMacro{\DTLmidpt}\cs{DTLmidpt} +%(the mid point of the bar) and +%\DescribeMacro{\DTLendpt}\cs{DTLendpt} (the end of the bar). For +%example (using the earlier "fruit" database): +%\begin{verbatim} +%\renewcommand*{\DTLeverybarhook}{% +%\pgftext[at=\DTLmidpt]{\insertName\space(\insertValue)}% +%} +%\DTLbarchart{variable=\insertValue,axes=both, +%ylabel=Quantity,max=50,verticalbars=false +%}% +%{fruit}{\insertValue=Value,\insertName=Name} +%\end{verbatim} +%This puts the name followed by the quantity in brackets in the +%middle of the bar. +% +%\begin{definition}[\DescribeMacro{\ifDTLverticalbars}]% %\cs{ifDTLverticalbars} %\end{definition} %This conditional governs whether the chart uses vertical or %horizontal bars. % -%\DescribeMacro{\DTLbarXlabelalign} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbarXlabelalign}]% %\cs{DTLbarXlabelalign} %\end{definition} %This specifies the text alignment of the lower bar labels. This @@ -5262,57 +5980,51 @@ %package option or the \setting{DTLbarchart}{verticalbars}"=false" %setting. % -%\DescribeMacro{\DTLbarYticklabelalign} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbarYticklabelalign}]% %\cs{DTLbarYlabelalign} %\end{definition} %This specifies the text alignment of the $y$ axis labels. This %defaults to "right" for vertical bar charts and "center" for %horizontal bar charts. % -%\DescribeMacro{\DTLbardisplayYticklabel} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbardisplayYticklabel}]% %\cs{DTLbardisplayYticklabel}\marg{text} %\end{definition} %This specifies how to display the $y$ tick label. The argument %is the tick label. % -%\DescribeMacro{\DTLdisplaylowerbarlabel} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdisplaylowerbarlabel}]% %\cs{DTLdisplaylowerbarlabel}\marg{text} %\end{definition} %This specifies how to display the lower bar label for %\cs{DTLbarchart} and the lower bar group label for %\cs{DTLmultibarchart}. The argument is the label. % -%\DescribeMacro{\DTLdisplaylowermultibarlabel} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdisplaylowermultibarlabel}]% %\cs{DTLdisplaylowermultibarlabel}\marg{text} %\end{definition} %This specifies how to display the lower bar label for %\cs{DTLmultibarchart}. The argument is the label. This %command is ignored by \cs{DTLbarchart}. % -%\DescribeMacro{\DTLdisplayupperbarlabel} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdisplayupperbarlabel}]% %\cs{DTLdisplayupperbarlabel}\marg{text} %\end{definition} %This specifies how to display the upper bar label for %\cs{DTLbarchart} and the upper bar group label for %\cs{DTLmultibarchart}. The argument is the label. % -%\DescribeMacro{\DTLdisplayuppermultibarlabel} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLdisplayuppermultibarlabel}]% %\cs{DTLdisplayuppermultibarlabel}\marg{text} %\end{definition} %This specifies how to display the upper bar label for %\cs{DTLmultibarchart}. The argument is the label. This %command is ignored by \cs{DTLbarchart}. % -%\begin{example}{An Labelled Bar Chart}{ex:annotebarchart} +%\begin{example}{A Labelled Bar Chart}{ex:annotebarchart} %This example extends \autoref{ex:barchart} so that the chart is %a bit more informative (which is after all the whole point of -%a chart.) This chart now has a label below each bar, as well +%a chart). This chart now has a label below each bar, as well %as a label above the bar. The lower label uses the value of the %"Name" key, and the upper label uses the quantity. I have also %set the outline width so each bar has a border. @@ -5332,8 +6044,7 @@ %\centering %\setlength{\DTLbaroutlinewidth}{1pt} %\DTLbarchart{variable=\theQuantity,barlabel=\theName, -%upperbarlabel=\theQuantity}{fruit}{% -%\theQuantity=Quantity,\theName=Name} +%upperbarlabel=\theQuantity}{fruit}{\theQuantity=Quantity,\theName=Name} %\caption[A bar chart (labelled)]{A bar chart} %\label{fig:annotebarchart} %\end{figure} @@ -5414,8 +6125,7 @@ %Both \cs{DTLbarchart} and \cs{DTLmultibarchart} set the following %macros, which may be used in \cs{DTLbaratbegintikz} and %\cs{DTLbaratendtikz}: -%\DescribeMacro{\DTLbarchartwidth} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbarchartwidth}]% %\cs{DTLbarchartwidth} %\end{definition} %This is the overall width of the bar chart. In the case of @@ -5428,18 +6138,16 @@ %of data), $n$ is the number of bars within a group (i.e.\ %the number of commands listed in the %\setting{DTLmultibarchart}{variables}) setting and $g$ is the -%group gap (as specified by the \setting{DTLmultibarchart}{groupgap} setting.) +%group gap (as specified by the \setting{DTLmultibarchart}{groupgap} setting). % -%\DescribeMacro{\DTLnegextent} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLnegextent}]% %\cs{DTLnegextent} %\end{definition} %This is set to the negative extent of the bar chart. (This value %may either be zero or negative, and corresponds to the %\setting{DTLbarchart,DTLmultibarchart}{maxdepth} setting.) % -%\DescribeMacro{\DTLbarmax} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbarmax}]% %\cs{DTLbarmax} %\end{definition} %This is set to the maximum extent of the bar chart. (This value @@ -5585,7 +6293,7 @@ %\end{example} % %\section{Converting a \texorpdfstring{\BibTeX}{BibTeX} database -%into a datatool database +%into a \texorpdfstring{\sty{datatool}}{datatool} database %(\texorpdfstring{\sty{databib}}{databib} package)} %\label{sec:databib} % @@ -5622,12 +6330,12 @@ % %\BibTeX\ is an external application used in conjunction with \LaTeX. %When you run \BibTeX, you need to specify the name of the document's -%auxiliary file (without the \ext{aux} extension.) \BibTeX\ then reads +%auxiliary file (without the \ext{aux} extension). \BibTeX\ then reads %this file and looks for the commands \cs{bibstyle} (which indicates %which bibliography style (\ext{bst}) file to load), \cs{bibdata} %(which indicates which bibliography database (\ext{bib}) files to %load) and \cs{citation} (produced by \cs{cite} and \cs{nocite}, which -%indicates which entries should be included in the bibliography.) +%indicates which entries should be included in the bibliography). %\BibTeX\ then creates a file with the extension \ext{bbl} which %contains the bibliography, formatted according to the layout defined %in the bibliography style file. @@ -5797,13 +6505,12 @@ %\label{sec:loadbbl} % %The \sty{databib} package always requires the \texttt{databib.bst} -%bibliography style file (which is supplied with this bundle.) +%bibliography style file (which is supplied with this bundle). %You need to use \cs{cite} or \cs{nocite} as usual. If you want to %add all entries in the \ext{bib} file to the \sty{datatool} database, %you can use "\nocite{*}". % -%\DescribeMacro{\DTLloadbbl} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLloadbbl}]% %\cs{DTLloadbbl}\oarg{bbl name}\marg{db name}\marg{bib list} %\end{definition} %This command performs several functions: @@ -5836,7 +6543,7 @@ %information will be added to \meta{db name}. % %\importantpar Note that -%\cs{DTLloaddb} doesn't generate any text. Once you have loaded +%\cs{DTLloadbbl} doesn't generate any text. Once you have loaded %the data, you can display the bibliography uses %\cs{DTLbibliography} (described below) or you can iterate %through it using \cs{DTLforeachbibentry} described in @@ -5846,18 +6553,18 @@ %the following additional fields: "isbn", "doi", "pubmed", "url" %and "abstract". %However these fields are ignored by the three predefined -%\sty{databib} styles ("plain", "abbrv" and "alpha".) If you +%\sty{databib} styles ("plain", "abbrv" and "alpha"). If you %want these fields to be displayed in the bibliography you will -%need to modify the bibliography style (see \autoref{sec:modbibstyle}.) +%need to modify the bibliography style (see \autoref{sec:modbibstyle}). % %\subsection{Displaying a \texorpdfstring{\sty{databib}}{databib} %database} %\label{sec:thebib} % %A \sty{databib} database which has been loaded using -%\cs{DTLloaddb} (described in \autoref{sec:loadbbl}) can be +%\cs{DTLloadbbl} (described in \autoref{sec:loadbbl}) can be %displayed using: -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibliography}] %\cs{DTLbibliography}\oarg{conditions}\marg{db name} %\end{definition}\noindent %where \meta{db name} is the name of the database. @@ -5867,8 +6574,7 @@ %\cs{DTLforeach} \emph{In addition}, you may use the following %commands: % -%\DescribeMacro{\DTLbibfieldexists} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfieldexists}]% %\cs{DTLbibfieldexists}\marg{field label} %\end{definition} %This tests whether the field with the given label exists for the @@ -5888,8 +6594,7 @@ %\DTLbibliography[\DTLbibfieldexists{Year}]{mybib} %\end{verbatim} % -%\DescribeMacro{\DTLbibfieldiseq} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfieldiseq}]% %\cs{DTLbibfieldiseq}\marg{field label}\marg{value} %\end{definition} %This tests whether the value of the field given by @@ -5901,8 +6606,7 @@ %\DTLbibliography[\DTLbibfieldiseq{Year}{2004}]{mybib} %\end{verbatim} % -%\DescribeMacro{\DTLbibfieldcontains} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfieldcontains}]% %\cs{DTLbibfieldcontains}\marg{field label}\marg{sub string} %\end{definition} %This tests whether the value of the field given by \meta{field label} @@ -5913,8 +6617,7 @@ %\DTLbibliography[\DTLbibfieldcontains{Author}{Knuth}]{mybib} %\end{verbatim} % -%\DescribeMacro{\DTLbibfieldislt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfieldislt}]% %\cs{DTLbibfieldislt}\marg{field label}\marg{value} %\end{definition} %This tests whether the value of the field given by \meta{field label} @@ -5926,8 +6629,7 @@ %\DTLbibliography[\DTLbibfieldislt{Year}{1983}]{mybib} %\end{verbatim} % -%\DescribeMacro{\DTLbibfieldisle} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfieldisle}]% %\cs{DTLbibfieldisle}\marg{field label}\marg{value} %\end{definition} %This tests whether the value of the field given by \meta{field label} @@ -5939,8 +6641,7 @@ %\DTLbibliography[\DTLbibfieldisle{Year}{1983}]{mybib} %\end{verbatim} % -%\DescribeMacro{\DTLbibfieldisgt} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfieldisgt}]% %\cs{DTLbibfieldisgt}\marg{field label}\marg{value} %\end{definition} %This tests whether the value of the field given by \meta{field label} @@ -5952,8 +6653,7 @@ %\DTLbibliography[\DTLbibfieldisgt{Year}{1983}]{mybib} %\end{verbatim} % -%\DescribeMacro{\DTLbibfieldisge} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfieldisge}]% %\cs{DTLbibfieldisge}\marg{field label}\marg{value} %\end{definition} %This tests whether the value of the field given by \meta{field label} @@ -5968,7 +6668,8 @@ %Note that \cs{DTLbibliography} uses \cs{DTLforeachbibentry} %(described in \autoref{sec:foreachbib}) so you may also use %test the value of the counter \counterfmt{DTLbibrow} within -%\meta{conditions}. +%\meta{conditions}. You may also use the boolean commands defined +%by the \sty{ifthen} package, such as \ics{not}. % %\begin{example}{Creating a list of publications since a given year}{ex:bibsince2000} %Suppose my boss has asked me to produce a list of my @@ -6012,7 +6713,7 @@ %\bibstyle{databib} %\end{verbatim} %to the auxiliary file. This tells \BibTeX\ to use "databib.bst" -%(which is supplied with this package.) You therefore shouldn't +%(which is supplied with this package). You therefore shouldn't %use \cs{bibliographystyle}. % %\item writes the line @@ -6032,7 +6733,7 @@ %\end{enumerate} % %\item In my \BibTeX\ database ("nlct.bib" in this example), I -%have remember to use the \BibTeX\ month macros: "jan", "feb" +%have remembered to use the \BibTeX\ month macros: "jan", "feb" %etc. This means that the months are stored in the database in %the form \cs{DTLmonthname}\marg{nn}, where \meta{nn} is a two %digit number from 01 to 12. \cs{DTLsort} ignores command names @@ -6085,7 +6786,7 @@ %The style of the bibliography produced using \cs{DTLbibliography} %depends on the \pkgopt[databib]{style} %package option, or can be set using -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibliographystyle}]% %\cs{DTLbibliographystyle}\marg{style} %\end{definition} %Note that this is \emph{not} the same as \cs{bibliographystyle}, @@ -6103,7 +6804,7 @@ %standard \BibTeX\ styles of the same name, but are by no means %identical. The most notable difference is that these styles %do not sort the bibliography. It is up to you to sort the -%bibliography using \cs{DTLsort} (described in \autoref{sec:sort}.) +%bibliography using \cs{DTLsort} (described in \autoref{sec:sort}). % %\subsubsection{Modifying an existing style} %\label{sec:modbibstyle} @@ -6116,12 +6817,10 @@ %\autoref{sec:src:bibnames}, \autoref{sec:src:displaybib} %and \autoref{sec:src:bibstyle}. % -%\DescribeMacro{\DTLformatauthor} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatauthor}]% %\cs{DTLformatauthor}\marg{von part}\marg{surname}\marg{jr part}\marg{forenames} %\end{definition} -%\DescribeMacro{\DTLformateditor} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformateditor}]% %\cs{DTLformateditor}\marg{von part}\marg{surname}\marg{jr part}\marg{forenames} %\end{definition} %These commands are used to format an author/editor's name, @@ -6134,8 +6833,7 @@ % %Within \cs{DTLformatauthor} and \cs{DTLformateditor}, you may %use the following commands: -%\DescribeMacro{\DTLformatforenames} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatforenames}]% %\cs{DTLformatforenames}\marg{forenames} %\end{definition} %This is used by the "plain" style to display the author's @@ -6144,12 +6842,11 @@ %\cs{DTLcheckendsperiod} to prevent a sentence ending full stop %from following an abbreviation full stop}. % -%\DescribeMacro{\DTLformatabbrvforenames} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatabbrvforenames}]% %\cs{DTLformatabbrvforenames}\marg{forenames} %\end{definition} %This is used by the "abbrv" style to display the author's -%initials (which are determined from \meta{forenames}.) +%initials (which are determined from \meta{forenames}). %Note that if any of the authors has a name starting with an %accent, the accented letter must be grouped in order for this %command to work. For example: @@ -6160,25 +6857,22 @@ %in \autoref{sec:strings}, so if you want to change the way the %initials are displayed (e.g.\ put a space between them) you will %need to redefine the commands used by \cs{DTLstoreinitials} (such -%as \cs{DTLbetweeninitials}.) +%as \cs{DTLbetweeninitials}). % -%\DescribeMacro{\DTLformatsurname} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatsurname}]% %\cs{DTLformatsurname}\marg{surname} %\end{definition} %This displays its argument by default\footnote{It also checks %whether the surname ends with a full stop using %\cs{DTLcheckendsperiod}}. % -%\DescribeMacro{\DTLformatvon} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatvon}]% %\cs{DTLformatvon}\marg{von part} %\end{definition} %If the \meta{von part} is empty, this command does nothing, %otherwise it displays its argument followed by a %non-breakable space. -%\DescribeMacro{\DTLformatjr} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatjr}]% %\cs{DTLformatjr}\marg{jr part} %\end{definition} %If the \meta{jr part} is empty, this command displays nothing, @@ -6284,7 +6978,7 @@ %\begin{example}{Highlighting a given author}{ex:highlightauthor} %Suppose my boss wants me to produce a list of all my publications %(which I have stored in the file "nlct.bib", as in -%\autoref{ex:bibsince2000}.) Most of my +%\autoref{ex:bibsince2000}). Most of my %publications have multiple co-authors, but suppose my boss would %like me to highlight my name so that when he skims through %the document, he can easily see my name in the list of @@ -6348,12 +7042,10 @@ %to list journal papers and conference proceedings in separate %sections. In which case, you may find it easier to iterate through %the bibliography using: -%\DescribeMacro{\DTLforeachbib} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLforeachbib}]% %\cs{DTLforeachbib}\oarg{condition}\marg{db name}\marg{text} %\end{definition} -%\DescribeMacro{\DTLforeachbib*} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLforeachbib*}]% %\cs{DTLforeachbib*}\oarg{condition}\marg{db name}\marg{text} %\end{definition} %This iterates through the \sty{databib} database called @@ -6364,7 +7056,7 @@ %\begin{itemize} %\item \cs{DBIBcitekey} \DescribeMacro{\DBIBcitekey}This is the %unique label which identifies the current entry (as used in the -%argument of \cs{cite} and \cs{nocite}.) +%argument of \cs{cite} and \cs{nocite}). % %\item \cs{DBIBentrytype} \DescribeMacro{\DBIBentrytype}This %is the current entry type, and will be one of: "article", "book", @@ -6372,12 +7064,11 @@ %"manual", "mastersthesis", "misc", "phdthesis", "proceedings", %"techreport" or "unpublished". (Note that even if you used the %entry type "conference" in your \ext{bib} file, its entry type -%will be set to "inproceedings".) +%will be set to "inproceedings"). %\end{itemize} % %The remaining fields may be accessed using: -%\DescribeMacro{\DTLbibfield} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLbibfield}]% %\cs{DTLbibfield}\marg{field label} %\end{definition}\noindent %where \meta{field label} may be one of: "Address", "Author", @@ -6388,8 +7079,7 @@ %"Abstract" or "Url". % %You can determine if a field exists for a given entry using -%\DescribeMacro{\DTLifbibfieldexists} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifbibfieldexists}]% %\cs{DTLifbibfieldexists}\marg{field label}\marg{true part}\marg{false %part} %\end{definition} @@ -6397,8 +7087,7 @@ %bibliography entry, it does \meta{true part}, otherwise it %does \meta{false part}. % -%\DescribeMacro{\DTLifbibanyfieldexists} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLifbibanyfieldexists}]% %\cs{DTLifanybibfieldexists}\marg{field label list}\marg{true %part}\marg{false part} %\end{definition} @@ -6408,8 +7097,7 @@ %current bibliography item, this does \meta{true part}, otherwise %it does \meta{false part}. % -%\DescribeMacro{\DTLformatbibentry} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLformatbibentry}]% %\cs{DTLformatbibentry} %\end{definition} %This formats the bibliography entry for the current row. It @@ -6418,8 +7106,7 @@ %is given by \cs{DBIBentrytype}. These commands are defined %by the bibliography style. % -%\DescribeMacro{\DTLcomputewidestbibentry} -%\begin{definition} +%\begin{definition}[\DescribeMacro{\DTLcomputewidestbibentry}]% %\cs{DTLcomputewidestbibentry}\marg{conditions}\marg{db %name}\marg{bib label}\marg{cmd} %\end{definition} @@ -6477,9 +7164,145 @@ %\end{verbatim} %\end{example} % +%\subsection{Multiple Bibliographies} +%\label{sec:multibib} +% +%It is possible to have more than one bibliography in a document, +%but it then becomes necessary to have a separate auxiliary file +%for each bibliography, and each auxiliary file must then be +%passed to \BibTeX. In order to do this, you need to use +%\begin{definition}[\DescribeMacro{\DTLmultibibs}]% +%\cs{DTLmultibibs}\marg{name list} +%\end{definition} +%where \meta{name list} is a comma separated list of names, +%\meta{name}. For each \meta{name}, this command creates an +%auxiliary file called \meta{name}".aux" (note that this +%command may only be used in the preamble). +% +%When you want to cite an entry for a given bibliography named +%in \cs{DTLmultibibs}, you must use: +%\begin{definition}[\DescribeMacro{\DTLcite}]% +%\cs{DTLcite}\oarg{text}\marg{mbib}\marg{cite key list} +%\end{definition}\noindent +%This is analogous to \cs{cite}\oarg{text}\marg{cite key list}, +%but writes the \cs{citation} command to \meta{mbib}".aux" instead +%of to the document's main auxiliary file. It also ensures that +%the cross-referencing labels are based on \meta{mbib}, to allow +%you to have the same reference in more than one bibliography +%without incurring a ``multiply defined'' warning message. Note +%that you can still use \cs{cite} to add citation information to +%the main auxiliary file. +% +%If you want to add an entry to the bibliography without producing +%any text, you can use +%\begin{definition}[\DescribeMacro{\DTLnocite}] +%\cs{DTLnocite}\marg{mbib}\marg{cite key list} +%\end{definition}\noindent +%which is analogous to \cs{nocite}\marg{cite key list}, where +%again the citation information is written to \meta{mbib}".aux" +%instead of the document's main auxiliary file. +% +%Note that for both \cs{DTLcite} and \cs{DTLnocite} the +%\meta{mbib} part must be one of the names listed in +%\cs{DTLmultibibs}. +% +%\begin{definition}[\DescribeMacro{\DTLloadmbbl}]% +%\cs{DTLloadmbbl}\marg{mbib}\marg{db name}\marg{bib list} +%\end{definition} +%This is analogous to \cs{DTLloadbbl}\marg{db name}\marg{bib list} +%described in \autoref{sec:loadbbl}. (Again \meta{mbib} must be +%one of the names listed in \cs{DTLmultibibs}.) This creates +%a new \sty{datatool} database called \meta{db name} and loads the +%bibliography information from \meta{mbib}".bbl" (if it exists). +% +%\begin{definition}[\DescribeMacro{\DTLmbibliography}]% +%\cs{DTLmbibliography}\oarg{condition}\marg{mbib}\marg{db name} +%\end{definition} +%This is analogous to \cs{DTLbibliography}\oarg{condition}\marg{db name}, +%but is required when displaying a bibliography in which elements have +%been cited using \cs{DTLcite} and \cs{DTLnocite}. +% +%\begin{example}{Multiple Bibliographies}{ex:multibib} +%Suppose I need to create a document which contains a section listing +%all my publications, but I also need to have separate sections +%covering each of my research topics, with a mini-bibliography +%at the end of each section. As in the earlier examples, all my +%publications are stored in the file "nlct.bib" which is somewhere +%on \TeX's path. Note that there will be some duplication as the +%references in the mini-bibliographies will also appear in the +%main bibliography at the end of the document, but using +%\cs{DTLcite} and \cs{DTLmbibliography} ensures that all the +%cross-referencing labels (and hyperlinks if they are enabled) +%are unique. +%\begin{verbatim} +%\documentclass{article} +%\usepackage{databib} +%\DTLmultibibs{kernel,food} +%\begin{document} +%\section{Kernel methods} +%In this section I'm going to describe some research work into +%kernel methods, and in the process I'm going to cite some related +%papers \DTLcite{kernel}{Cawley2007a,Cawley2006a}. +% +%\DTLloadmbbl{kernel}{kernelDB}{nlct} +%\DTLmbibliography{kernel}{kernelDB} +% +%\section{Food research} +% +%In this section I'm going to describe some research work +%in the area of food safety, and in the process, I'm going +%to cite some related papers \DTLcite{food}{Peck1999,Barker1999a} +% +%\DTLloadmbbl{food}{foodDB}{nlct} +%\DTLmbibliography{food}{foodDB} +% +%\cite{*} +%\renewcommand{\refname}{Complete List of Publications} +%\DTLloadbbl{fullDB}{nlct} +%\DTLbibliography{fullDB} +%\end{document} +%\end{verbatim} +%Notes: +%\begin{enumerate} +%\item This will create the files "kernel.aux" and "food.aux". +%These will have to be passed to \BibTeX, in addition to the +%documents main auxiliary file. So, if my document is called +%"researchwork.tex", then I need to do: +%\begin{verbatim} +%latex researchwork +%bibtex researchwork +%bibtex kernel +%bibtex food +%latex researchwork +%latex researchwork +%\end{verbatim} +% +%\item "\cite{*}" is used to add all the entries in the bib file +%to the main bibliography database. As before, \cs{DTLloadbbl} +%and \cs{DTLbibliography} are used to load and display the main +%bibliography. +%\end{enumerate} +%\end{example} +% +%\importantpar Don't try to directly input the ".bbl" file using +%\cs{input} (or \cs{include}) instead of using \cs{DTLloadbbl} +%or \cs{DTLloadmbbl} as these commands store the name of the required +%database and initialise the database before loading the +%\texttt{.bbl} file. Similarly, don't just copy the contents of +%the ".bbl" file into your document without first defining the +%database using \ics{DTLnewdb} and setting \ics{DTLBIBdbname} to +%the name of the database. +% % \StopEventually{\clearpage\phantomsection %\addcontentsline{toc}{section}{\refname} % \DTLbibliography{docbib} +%\section{Acknowledgements} +% +%Many thanks to Morten~H\o gholm for suggesting a much more +%efficient way of storing the information in databases which +%has significantly improved the time it takes to \LaTeX\ documents +%containing large databases. +% %\phantomsection %\addcontentsline{toc}{section}{Change History}\PrintChanges %\phantomsection @@ -6497,7 +7320,7 @@ %\subsection{Package Declaration} % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{datatool}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{datatool}[2009/02/27 v2.0 (NLCT)] % \end{macrocode} % Load required packages: % \begin{macrocode} @@ -6507,6 +7330,10 @@ \RequirePackage{fp} \RequirePackage{substr} % \end{macrocode} +%\changes{2.0}{2009 February 27}{added etex as a required package} +% \begin{macrocode} +\RequirePackage{etex} +% \end{macrocode} % %\subsection{Package Options} %\begin{macro}{\@dtl@separator} @@ -8565,17 +9392,15 @@ %\end{definition} % Test if the current row is the first row. (This takes % \meta{condition}, the optional argument of \cs{DTLforeach}, -% into account.) +% into account, so it may not correspond to row~1 of the +% database.) Can only be used in \cs{DTLforeachrow}. +%\changes{2.0}{2009 February 27}{modified to have different +% definition depending on location} % \begin{macrocode} \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}{}% +} % \end{macrocode} %\end{macro} % @@ -8595,17 +9420,13 @@ % have to iterate through the database to count up the number % of rows which meet the condition, and then do another pass, % checking if the current row has reached that number. -% This command requires at least v1.02 of the \sty{xfor} package. %\changes{1.01}{2007 Aug 17}{fixed bug} +%\changes{2.0}{2009 February 27}{modified to have different +% definition depending on location} % \begin{macrocode} \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}{}% } % \end{macrocode} %\end{macro} @@ -8616,16 +9437,12 @@ %\end{definition} % Determines whether the current row is odd (takes the optional % argument of \cs{DTLforeach} into account.) +%\changes{2.0}{2009 February 27}{modified to have different +% definition depending on location} % \begin{macrocode} \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}{}% } % \end{macrocode} %\end{macro} @@ -9078,26 +9895,85 @@ %\end{macro} % % \subsection{Defining New Databases} -% A database is stored internally as a list of lists, where each list -% is a row of data. The data is stored as a comma separated list of -% \marg{id}\marg{value} pairs, where \meta{id} is an -% identifier -% and \meta{value} is the value. +% As from v2.0, the internal structure of the database has changed +% to make it more efficient.\footnote{Thanks to Morten H\o gholm +% for the suggestion.} The database is now stored in a token +% register instead of a macro. Each row is represented as:\par +%\verb|\db@row@elt@w|% +%\verb|\db@row@id@w| \meta{row idx}\verb|\db@row@id@end@|% +%\meta{column data}% +%\verb|\db@row@id@w| \meta{row idx}\verb|\db@row@id@end@|% +%\verb|\db@row@elt@end@|\par +% where \meta{row idx} is the row index and \meta{column data} is +% the data for each column in the row. Each column for a given +% row is stored as:\par +%\verb|\db@col@id@w| \meta{column idx}\verb|\db@col@id@end@|% +%\verb|\db@col@elt@w| \meta{value}\verb|\db@col@elt@end@|% +%\verb|\db@col@id@w| \meta{column idx}\verb|\db@col@id@end@|\par +% where \meta{column idx} is the column index and \meta{value} +% is the entry for the given column and row. +% +% Each row only has an associated index, but columns have +% a unique identifying key as well as an associated index. Columns +% also have an associated data type which may be: 0 (column +% contains strings), 1 (column contains integers), 2 (column +% contains real numbers), 3 (column contains currency) or +% \meta{empty} (column contains no data). Since the key sometimes +% has to be expanded, a header is also available in the event +% that the user wants to use \cs{DTLdisplaydb} or +% \cs{DTLdisplaylongdb} and requires a column header that would +% cause problems if used as a key. The general column +% information is stored in a token register where each column +% has information stored in the form:\par +%\verb|\db@plist@elt@w|% +%\verb|\db@col@id@w| \meta{index}\verb|\db@col@id@end@|% +%\verb|\db@key@id@w| \meta{key}\verb|\db@key@id@end@|% +%\verb|\db@type@id@w| \meta{type}\verb|\db@type@id@end@|% +%\verb|\db@header@id@w| \meta{type}\verb|\db@header@id@end@|% +%\verb|\db@col@id@w| \meta{index}\verb|\db@col@id@end@|% +%\verb|\db@plist@elt@end@| +% +% The column name (\meta{key}) is mapped to the column index +% using \cs{dtl@ci@}\meta{db}"@"\meta{key} where \meta{db} is +% the database name. % %\begin{macro}{\DTLnewdb} +%\changes{2.0}{2009 February 27}{Changed way database is stored} % \cs{DTLnewdb}\marg{name} -% initialises a database called \meta{name}. The keys associated -% with this database are stored in \cs{dtlkeys@}\meta{name} -% A new count register \cs{dtlrows@}\meta{db name} is created. -% This stores the total number of rows in the data base. +% initialises a database called \meta{name}. % \begin{macrocode} \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}} +% \end{macrocode} +% Check if there is already a database with this name. +% \begin{macrocode} + \DTLifdbexists{#1}% + {% + \PackageError{datatool}{Database `#1' already exists}{}% + }% + {% +% \end{macrocode} +% Define new database. Add information message if in verbose +% mode. +% \begin{macrocode} + \dtl@message{Creating database `#1'}% +% \end{macrocode} +% Define token register used to store the contents of the database. +% \begin{macrocode} + \expandafter\newtoks\csname dtldb@#1\endcsname +% \end{macrocode} +% Define token register used to store the column header information. +% \begin{macrocode} + \expandafter\newtoks\csname dtlkeys@#1\endcsname{}% +% \end{macrocode} +% Define count register used to store the row count. +% \begin{macrocode} + \expandafter\newcount\csname dtlrows@#1\endcsname +% \end{macrocode} +% Define count register used to store the column count. +% \begin{macrocode} + \expandafter\newcount\csname dtlcols@#1\endcsname + }% +} % \end{macrocode} %\end{macro} % @@ -9106,26 +9982,55 @@ % \cs{DTLrowcount}\marg{db name} %\end{definition} % The number of rows in the database called \meta{db name}. +% (Doesn't check if database exists.) % \begin{macrocode} \newcommand*{\DTLrowcount}[1]{% \expandafter\number\csname dtlrows@#1\endcsname} % \end{macrocode} %\end{macro} % +%\begin{macro}{\DTLcolumncount} +%\begin{definition} +% \cs{DTLcolumncount}\marg{db name} +%\end{definition} +% The number of columns in the database called \meta{db name}. +% (Doesn't check if database exists.) +%\changes{2.0}{2009 February 27}{new}% +% \begin{macrocode} +\newcommand*{\DTLcolumncount}[1]{% +\expandafter\number\csname dtlcols@#1\endcsname} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\DTLifdbempty} %\begin{definition} -% \cs{DTLifempty}\marg{name}\marg{true part}\marg{false part} +% \cs{DTLifdbempty}\marg{name}\marg{true part}\marg{false part} %\end{definition} -% Check if named database is empty (i.e.\ no rows have been added.) +% Check if named database is empty (i.e.\ no rows have been added). % \begin{macrocode} \newcommand{\DTLifdbempty}[3]{% -\DTLifdbexists{#1}{% -\expandafter\ifx\csname dtldb@#1\endcsname\@empty - #2% -\else - #3% -\fi}{% -\PackageError{Database `#1' doesn't exist}{}{}}} + \DTLifdbexists{#1}% + {\@DTLifdbempty{#1}{#2}{#3}}% + {\PackageError{Can't check if database `#1' is empty: + database doesn't exist}{}{}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@DTLifdbempty} +%\begin{definition} +% \cs{@sDTLifdbempty}\marg{name}\marg{true part}\marg{false part} +%\end{definition} +% Check if named existing database is empty. (No check performed +% to determine if the database exists.) +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand{\@DTLifdbempty}[3]{% + \expandafter\ifnum\csname dtlrows@#1\endcsname=0\relax + #2% + \else + #3% + \fi +} % \end{macrocode} %\end{macro} % @@ -9133,981 +10038,921 @@ %\begin{definition} % \cs{DTLnewrow}\marg{db name} %\end{definition} -% Add a new row to named database. +% Add a new row to named database. The starred version doesn't +% check for the existence of the database. % \begin{macrocode} -\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 - \dtl@message{New row added to database `#1'}% -}} +\newcommand*{\DTLnewrow}{% + \@ifstar\@sDTLnewrow\@DTLnewrow +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLnewdbentry} +%\begin{macro}{\@DTLnewrow} %\begin{definition} -% \cs{DTLnewdbentry}\marg{db name}\marg{id}\marg{value}. +% \cs{@DTLnewrow}\marg{db name} %\end{definition} -% Adds an entry to the last row (adds new row if database is empty.) -% -% When a new entry is added, the control sequence -% \cs{@dtl@idtype@}\meta{db name}\texttt{@}\meta{id} is checked. -% This keeps track of the type of all the entries with the given ID -% for the given database. If this control -% sequence doesn't exist, a new one is created, and set to the -% relevant type: 0 (string), 1 (int) or 2 (real). If it exists, -% then it is set as follows: if has a value of 0 (string), it -% remains unchanged. If it has another value, then it is set to -% 2 (real) if it was either 1 or 2 and \meta{value} is 2, it is -% set to 1 if \meta{value} is 1, otherwise it remains unchanged. +% Add a new row to named database. (Checks for the existance +% of the database.) % \begin{macrocode} -\newcommand{\DTLnewdbentry}[3]{% -% \end{macrocode} -% Set \cs{@dtl@dbvalue} to the value of this entry. -% \begin{macrocode} -\@dtl@toks{#3}% -\edef\@dtl@dbvalue{\the\@dtl@toks}% -% \end{macrocode} -% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow -% for the ID to be stored in a control sequence. -% \begin{macrocode} -\edef\@dtl@dbid{#2}% -% \end{macrocode} -% Set up the correct entry format: -% \begin{macrocode} -\edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% +\newcommand*{\@DTLnewrow}[1]{% +\DTLifdbexists{#1}% + {\@sDTLnewrow{#1}}% + {\PackageErrors{datatool}{Can't add new row to database `#1': + database doesn't exist}{}}% +} % \end{macrocode} -% If database is empty, add new row. +%\end{macro} +% +%\begin{macro}{\@sDTLnewrow} +%\begin{definition} +% \cs{@DTLnewrow}\marg{db name} +%\end{definition} +% Add a new row to named existing database. (No check performed +% to determine if the database exists.) +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\DTLifdbempty{#1}{\DTLnewrow{#1}}{}% +\newcommand*{\@sDTLnewrow}[1]{% % \end{macrocode} -% Add the entry to the last row of the database: -% Split the database into the last row -% (\cs{@dtl@dblastrow}), and everything except the last row -% (\cs{@dtl@dbrest}.) +% Increment row count. % \begin{macrocode} -\expandafter\dtl@choplast\expandafter{% -\csname dtldb@#1\endcsname}{\@dtl@dbrest}{\@dtl@dblastrow}% + \global\advance\csname dtlrows@#1\endcsname by 1\relax % \end{macrocode} -% Check if the last row already contains an entry with this ID. -% If so, generate an error, otherwise append this entry to the -% row, and reconstruct database list. +% Append an empty row to the database % \begin{macrocode} -\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}}{% + \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@% + }% % \end{macrocode} -% Append entry to last row +% Display message on terminal and log file if in verbose mode. % \begin{macrocode} -\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}% -}% + \dtl@message{New row added to database `#1'}% +} % \end{macrocode} -% Reconstruct list. +%\end{macro} +% +%\begin{macro}{\dtlcolumnnum} +% Count register to keep track of column index. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\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}}% -}% +\newcount\dtlcolumnnum % \end{macrocode} -% Set the keys +%\end{macro} +%\begin{macro}{\dtlrownum} +% Count register to keep track of row index. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\@dtl@setidtype{#1}{#2}{#3}% -\expandafter\@dtl@setkeys\expandafter{#2}{#1}% -}% -\dtl@message{Added #2\space -> #3\space to database `#1'}% -} +\newcount\dtlrownum % \end{macrocode} %\end{macro} % -%\begin{macro}{\@dtl@setidtype} +%\begin{macro}{\DTLifhaskey} %\begin{definition} -% \cs{@dtl@setidtype}\marg{db name}\marg{id}\marg{value} +%\cs{DTLifhaskey}\meta{db name}\meta{key}\meta{true part}\meta{false +% part} %\end{definition} -% Set the type for \meta{id} according to \meta{value}. -% If \meta{value} is empty, leave \cs{@dtl@idtype}\meta{id} -% unchanged (if defined) or define as empty if not defined. -%\changes{1.01}{2007 Aug 17}{Added currency check} -%\changes{1.01}{2007 Aug 17}{Fixed bug when setting -% \cs{@dtl@tmpcount}} -% \begin{macrocode} -\newcommand{\@dtl@setidtype}[3]{% -% \end{macrocode} -% Check the data type of this value. +% Checks if the named database \meta{db name} has a column with label +% \meta{key}. If column exists, do \meta{true part} otherwise +% do \meta{false part}. The starred version doesn't check if +% the named database exists. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\@dtl@checknumerical{#3}% +\newcommand*{\DTLifhaskey}{\@ifstar\@sDTLifhaskey\@DTLifhaskey} % \end{macrocode} -% Store value if \cs{@dtl@value} to make it easier to test if it -% is empty. +%\end{macro} +% +%\begin{macro}{\@DTLifhaskey} +% Unstarred version of \cs{DTLifhaskey} % \begin{macrocode} -\def\@dtl@value{#3}% +\newcommand{\@DTLifhaskey}[4]{% + \DTLifdbexists{#1}% + {% + \@sDTLifhaskey{#1}{#2}{#3}{#4}% + }% + {% + \PackageError{datatool}{Database `#1' doesn't exist}{}% + }% +} % \end{macrocode} -% Determine if this key already has a data type assigned to it. +%\end{macro} +%\begin{macro}{\@sDTLifhaskey} +% Starred version of \cs{DTLifhaskey} % \begin{macrocode} -\@ifundefined{@dtl@idtype@#1@#2}{% +\newcommand{\@sDTLifhaskey}[4]{% + \@ifundefined{dtl@ci@#1@#2}% + {% % \end{macrocode} -% This key doesn't have an associated data type, so set it to -% this value's data type, unless the value is empty. +% Key not defined % \begin{macrocode} -\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 -}{% + #4% + }% + {% % \end{macrocode} -% This key already has an associated data type, but may need updating. +% Key defined % \begin{macrocode} -\ifx\@dtl@value\@empty + #3% + }% +} % \end{macrocode} -% The value is empty, so do nothing. +%\end{macro} +% +%\begin{macro}{\DTLgetcolumnindex} +%\begin{definition} +%\cs{DTLgetcolumnindex}\marg{cs}\marg{db}\marg{key} +%\end{definition} +% Gets index for column with label \meta{key} from database +% \meta{db} and stores in \meta{cs} which must be a control +% sequence. +% Unstarred version checks if database and key exist, unstarred +% version doesn't perform any checks. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\else - \expandafter\ifx\csname @dtl@idtype@#1@#2\endcsname\@empty +\newcommand*{\DTLgetcolumnindex}{% + \@ifstar\@sdtl@getcolumnindex\@dtl@getcolumnindex +} % \end{macrocode} -% The data type is currently unset (all previous values for this -% key were empty) so set the data type for this key to the data type -% of the given value. +%\end{macro} +% +%\begin{macro}{\@dtl@getcolumnindex} +% Unstarred version of \cs{DTLgetcolumnindex} +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% - \the\@dtl@datatype}% - \else +\newcommand*{\@dtl@getcolumnindex}[3]{% % \end{macrocode} -% Store the data type currently associated with this key in -% \cs{@dtl@tmpcount}. +% Check if database exists. % \begin{macrocode} - \expandafter\@dtl@tmpcount\expandafter= - \csname @dtl@idtype@#1@#2\endcsname\relax + \DTLifdbexists{#2}% + {% % \end{macrocode} -% Determine whether to update the data type associated with this key. +% Database exists. Now check if key exists. % \begin{macrocode} - \ifcase\@dtl@tmpcount + \@sDTLifhaskey{#2}{#3}% + {% % \end{macrocode} -% The current data type is a string, so leave as it is -% (string overrides all the other types.) +% Key exists so go ahead and get column index. % \begin{macrocode} - \or + \@sdtl@getcolumnindex{#1}{#2}{#3}% + }% + {% % \end{macrocode} -% The current data type is an int, so set the data type of the given -% value (all other data types override int.) +% Key doesn't exists in named database. % \begin{macrocode} - \expandafter\xdef\csname @dtl@idtype@#1@#2\endcsname{% - \the\@dtl@datatype}% - \or + \PackageError{datatool}{Database `#2' doesn't contain + key `#3'}{}% + }% + }% + {% % \end{macrocode} -% The current data type is a real, set to real unless the given value -% is a string or currency (real overrides int, but not string or -% currency.) +% Named database doesn't exist. % \begin{macrocode} - \ifnum\@dtl@datatype=0\relax - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{0}% - \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}% - \fi - \fi - \or + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} % \end{macrocode} -% The current data type is currency, so set to currency unless -% the given value is a string (currency overrides real and int, -% but not string.) +%\end{macro} +% +%\begin{macro}{\@dtl@getcolumnindex} +% Starred version of \cs{DTLgetcolumnindex}. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \ifnum\@dtl@datatype=0\relax - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{0}% - \else - \expandafter\gdef\csname @dtl@idtype@#1@#2\endcsname{3}% - \fi - \fi - \fi -\fi -}% +\newcommand*{\@sdtl@getcolumnindex}[3]{% + \expandafter\let\expandafter#1\csname dtl@ci@#2@#3\endcsname } % \end{macrocode} -%\end{macro} +%\end{macro} % -%\begin{macro}{\@dtl@setkeys} +%\begin{macro}{\dtl@columnindex} %\begin{definition} -%\cs{@dtl@setkeys}\marg{key}\marg{db name} +% \cs{dtl@columnindex}\marg{db}\marg{key} %\end{definition} -% Adds \marg{key} to \cs{dtlkeys@}\meta{db name} if not already -% in it. +% Column index corresponding to \meta{key} in database \meta{db}. +% (No check for existance of database or key.) +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\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}{}% - }% - \if@endfor - \else - \expandafter\xdef\csname dtlkeys@#2\endcsname{\the\@dtl@toks,#1}% - \fi -\fi +\newcommand*{\dtl@columnindex}[2]{% + \csname dtl@ci@#1@#2\endcsname } % \end{macrocode} %\end{macro} % -%\begin{macro}{\@dtl@getidtype} +%\begin{macro}{\DTLgetkeyforcolumn} %\begin{definition} -% \cs{@dtl@getidtype}\marg{db name}\marg{id} +%\cs{DTLgetkeyforcolumn}\marg{key cs}\marg{db}\marg{column index} %\end{definition} -% Gets the data type for \meta{id} in given database. +% Gets the key associated with the given column index and stores +% in \meta{key cs}. Unstarred version doesn't perform checks. % \begin{macrocode} -\newcommand*{\@dtl@getidtype}[2]{% -\csname @dtl@idtype@#1@#2\endcsname} +\newcommand*{\DTLgetkeyforcolumn}{% + \@ifstar\@sdtlgetkeyforcolumn\@dtlgetkeyforcolumn} % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLifdbexists} -%\begin{definition} -%\cs{DTLifdbexists}\marg{db name}\marg{true part}\marg{false part} -%\end{definition} -% Checks if a data base with the given name exists. +%\begin{macro}{\@dtlgetkeyforcolumn} % \begin{macrocode} -\newcommand{\DTLifdbexists}[3]{% -\@ifundefined{dtldb@#1}{#3}{#2}} +\newcommand*{\@dtlgetkeyforcolumn}[3]{% + \DTLifdbexists{#2}% + {% +% \end{macrocode} +% Check if index is in range. +% \begin{macrocode} + \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 + \@sdtlgetkeyforcolumn{#1}{#2}{#3}% + \fi + \fi + }% + {% + \PackageError{datatool}{Database `#2' doesn't exists}{}% + }% +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\dtl@ifrowcontains} +%\begin{macro}{\@sdtlgetkeyforcolumn} %\begin{definition} -% \cs{dtl@ifrowcontains}\meta{id}\meta{cmd}\meta{true part}\meta{false -%part} +%\cs{@sdtlgetkeyforcolumn}\marg{key cs}\marg{db}\marg{column index} %\end{definition} -% Checks to see if the row given by \meta{cmd} contains an -% entry with ID given by \meta{id}. If true, do \meta{true part}, -% otherwise do \meta{false part}. +% Gets the key associated with the given column index and stores +% in \meta{key cs} % \begin{macrocode} -\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*{\@sdtlgetkeyforcolumn}[3]{% + \edef\@dtl@dogetkeyforcolumn{\noexpand\@dtl@getkeyforcolumn + {\noexpand#1}{#2}{\number#3}}% + \@dtl@dogetkeyforcolumn } % \end{macrocode} %\end{macro} -% -%\begin{macro}{\dtl@getentryid} -%\begin{definition} -% \cs{dtl@getentryid}\meta{entry cmd}\meta{id cmd} -%\end{definition} -% Gets the ID for an entry given by \meta{entry cmd}, and stores in -% in \meta{id cmd}. +%\begin{macro}{\@dtl@getkeyforcolumn} +% Column index must be fully expanded before use. % \begin{macrocode} -\newcommand*{\dtl@getentryid}[2]{\expandafter\@dtl@getentryid#1#2} -\long\def\@dtl@getentryid#1#2#3{\def#3{#1}} +\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 +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\dtl@getentryvalue} -%\begin{definition} -% \cs{dtl@getentryvalue}\meta{entry cmd}\meta{cmd} -%\end{definition} -% Stores the entry value in \meta{cmd} for -% entry given by \meta{entry cmd}. +% Define some commands to indicate the various data types a database +% may contain. +%\begin{macro}{\DTLunsettype} +% Unknown data type. (All entries in the column are blank so the +% type can't be determined.) +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\newcommand*{\dtl@getentryvalue}[2]{% -\expandafter\@dtl@getentryvalue#1#2} -\long\def\@dtl@getentryvalue#1#2#3{\gdef#3{#2}} +\def\DTLunsettype{} % \end{macrocode} %\end{macro} -% -%\begin{macro}{\dtlforeachlevel} -%\cs{DTLforeach} can only be nested up to three levels. -% \cs{dtlforeachlevel} keeps track of the current level. +%\begin{macro}{\DTLstringtype} +% Data type representing strings. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\global\newcount\dtlforeachlevel +\def\DTLstringtype{0} % \end{macrocode} %\end{macro} -% -% The counter DTLrow\meta{n} keeps track of each row of data during -% the \meta{n} nested \cs{DTLforeach}. It is only incremented in the -% conditions (given by the optional argument) are met. +%\begin{macro}{\DTLinttype} +% Data type representing integers. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\newcounter{DTLrowi} -\newcounter{DTLrowii} -\newcounter{DTLrowiii} +\def\DTLinttype{1} % \end{macrocode} -% Keep \sty{hyperref} happy +%\end{macro} +%\begin{macro}{\DTLrealtype} +% Data type representing real numbers. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\newcounter{DTLrow} -\def\theHDTLrow{\arabic{DTLrow}} -\def\theHDTLrowi{\theHDTLrow.\arabic{DTLrowi}} -\def\theHDTLrowii{\theHDTLrowi.\arabic{DTLrowii}} -\def\theHDTLrowiii{\theHDTLrowii.\arabic{DTLrowiii}} +\def\DTLrealtype{2} % \end{macrocode} -% -%\begin{macro}{\DTLsaverowcount} -%\begin{definition} -%\cs{DTLsavelastrowcount}\marg{cmd} -%\end{definition} -% Stores the maximum row count for the last \cs{DTLforeach}. +%\end{macro} +%\begin{macro}{\DTLcurrencytype} +% Data type representing currency. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\newcommand*{\DTLsavelastrowcount}[1]{% -\ifnum\dtlforeachlevel>2\relax - \def#1{0}% -\else - \ifnum\dtlforeachlevel<0\relax - \def#1{0}% - \else - \@dtl@tmpcount=\dtlforeachlevel - \advance\@dtl@tmpcount by 1\relax - \edef#1{\expandafter\number - \csname c@DTLrow\romannumeral\@dtl@tmpcount\endcsname}% - \fi -\fi} +\def\DTLcurrencytype{3} % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLforeach} +%\begin{macro}{\DTLgetdatatype} %\begin{definition} -% \cs{DTLforeach}\oarg{conditions}\marg{db name}\marg{values}\marg{text} +%\cs{DTLgetdatatype}\marg{cs}\marg{db}\marg{key} %\end{definition} -% For each row of data in the database given by \meta{db name}, -% do \meta{text}, if the specified conditions are satisfied. -% The argument \marg{values} is a comma separated list of -% \meta{cmd}\texttt{=}\meta{key} pairs. At the start of each row, -% each of the commands in this list are set to the value of the -% entry with the corresponding key \meta{key}. -% (\cs{gdef} is used to ensure \cs{DTLforeach} works in a tabular -% environment.) The database may be edited in the unstarred -% version, in the starred version the database is read only. -%\changes{1.01}{2007 Aug 17}{added starred version} +% Gets data type associated with column labelled \meta{key} in +% database \meta{db} and stores in \meta{cs}. Type may be: +% \meta{empty} (unset), 0 (string), 1 (int), +% 2 (real), 3 (currency). Unstarred version checks if the database +% and key exist, starred version doesn't. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\newcommand*{\DTLforeach}{\@ifstar\@sDTLforeach\@DTLforeach} +\newcommand*{\DTLgetdatatype}{% + \@ifstar\@sdtlgetdatatype\@dtlgetdatatype +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\@DTLforeach} -% \cs{@DTLforeach} is the unstarred version of \cs{DTLforeach}. -% The database is reconstructed to allow for rows to be edited. +%\begin{macro}{\@dtlgetdatatype} +% Unstarred version of \cs{DTLgetdatatype}. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\newcommand{\@DTLforeach}[4][\boolean{true}]{% +\newcommand*{\@dtlgetdatatype}[3]{% % \end{macrocode} -% Check database exists +% Check if database exists. % \begin{macrocode} -\DTLifdbexists{#2}{% + \DTLifdbexists{#2}% + {% % \end{macrocode} -% Keep \sty{hyperref} happy +% Check if key exists in this database. % \begin{macrocode} -\refstepcounter{DTLrow}% -\global\c@DTLrow=\c@DTLrow + \@sDTLifhaskey{#2}{#3}% + {% % \end{macrocode} -% Store database name +% Get data type for this database and key. % \begin{macrocode} -\gdef\@dtl@dbname{#2}% + \@sdtlgetdatatype{#1}{#2}{#3}% + }% + {% % \end{macrocode} -% Increment level and check not exceeded 3 +% Key doesn't exist in this database. % \begin{macrocode} -\global\advance\dtlforeachlevel by 1\relax -\ifnum\dtlforeachlevel>3\relax - \PackageError{datatool}{\string\DTLforeach\space nested too -deeply}{}% -\else -% \end{macrocode} -% Set level dependent information (needs to be global to ensure -% it works in the \env{tabular} environment.) Row counter: + \PackageError{datatool}{Key `#3' undefined in database `#2'}{}% + }% + }% + {% +% \end{macrocode} +% Database doesn't exist. % \begin{macrocode} - \expandafter\global - \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname = 0\relax + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} % \end{macrocode} -% Construct updated database: +%\end{macro} +% +%\begin{macro}{\@sdtlgetdatatype} +% Starred version of \cs{DTLgetdatatype}. This ensures that +% the key is fully expanded before begin passed to +% \cs{@dtl@getdatatype}. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \expandafter\global\expandafter\let - \csname @dtl@foreachrows@\romannumeral\dtlforeachlevel\endcsname - =\@empty +\newcommand*{\@sdtlgetdatatype}[3]{% + \edef\@dtl@dogetdata{\noexpand\@dtl@getdatatype{\noexpand#1}% + {\expandafter\the\csname dtlkeys@#2\endcsname}% + {\dtl@columnindex{#2}{#3}}}% + \@dtl@dogetdata +} % \end{macrocode} -% Database name: +%\end{macro} +% +%\begin{macro}{\@dtl@getdatatype} +%\begin{definition} +%\cs{@dtl@getdatatype}\marg{cs}\marg{data specs}\marg{column index} +%\end{definition} +% Column index must be expanded. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \expandafter\global\expandafter\let - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname - =\@dtl@dbname +\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 +} % \end{macrocode} -% Iterate through each row +%\end{macro} +% +%\begin{macro}{\@dtl@getprops} +%\begin{definition} +%\cs{@dtl@getprops}\marg{key cs}\marg{type cs}\marg{header toks}\marg{before toks}\marg{after toks}\marg{data specs}\marg{column index} +%\end{definition} +% Column index must be expanded. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \expandafter\let\expandafter\@dtl@db\csname dtldb@#2\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% +\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 +} % \end{macrocode} -% Set current row macro for this level +%\end{macro} +% +%\begin{macro}{\@dtl@before} +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \expandafter\global\expandafter - \let\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel - \endcsname=\@dtl@currentrow +\newtoks\@dtl@before % \end{macrocode} -% Globally assign next element (note that there is no check to -% determine if the next element will be skipped.) -%\changes{1.01}{2007 Aug 17}{set \cs{@dtl@nextrow}} +%\end{macro} +%\begin{macro}{\@dtl@after} +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \global\let\@dtl@nextrow\@xfor@nextelement +\newtoks\@dtl@after % \end{macrocode} -% Assign commands to the required entries +%\end{macro} +%\begin{macro}{\@dtl@colhead} +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \ifx\relax#3\relax - \else - \@dtl@assign{#3}% - \fi +\newtoks\@dtl@colhead % \end{macrocode} -% Do the main body of text if condition is satisfied +%\end{macro} +% +%\begin{macro}{\@dtl@updatekeys} +%\begin{definition} +%\cs{@dtl@updatekeys}\marg{db}\marg{key}\marg{value} +%\end{definition} +% Adds key to database's key list if it doesn't exist. +% The value is used to update the data type associated with that key. +% Key must be fully expanded. Doesn't check if database exists. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} - \ifthenelse{#1}{% - \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% - \expandafter\edef\expandafter\DTLcurrentindex\expandafter - {\arabic{DTLrow\romannumeral\dtlforeachlevel}}% - #4% - }{}% +\newcommand*{\@dtl@updatekeys}[3]{% % \end{macrocode} -% Reconstruct database +% Check if key already exists % \begin{macrocode} - \expandafter\let\expandafter\@dtl@thiscurrentrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname + \@sDTLifhaskey{#1}{#2}% + {% % \end{macrocode} -% Don't add this row if it is now empty +% Key exists, may need to update data type. First get the +% column index. +% \begin{macrocode} + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{#1}{#2}\relax +% \end{macrocode} +% Get the properties for this column +% \begin{macrocode} + \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 +% \end{macrocode} +% Is the value empty? +% \begin{macrocode} + \def\@dtl@tmp{#3}% + \ifx\@dtl@tmp\@empty +% \end{macrocode} +% Leave data type as it is % \begin{macrocode} - \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}}% \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}}% - \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}{}}% -} % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\@sDTLforeach} -% \cs{@sDTLforeach} is the starred version of \cs{DTLforeach}. -% The database rows can't be edited. +% Make a copy of current data type % \begin{macrocode} -\newcommand{\@sDTLforeach}[4][\boolean{true}]{% + \let\@dtl@oldtype\@dtl@type % \end{macrocode} -% Check database exists +% Check the data type for this entry (stored in \cs{@dtl@datatype}) % \begin{macrocode} -\DTLifdbexists{#2}{% + \@dtl@checknumerical{#3}% % \end{macrocode} -% Keep \sty{hyperref} happy +% If this column currently has no data type assigned to it +% then use the new type. % \begin{macrocode} -\refstepcounter{DTLrow}% -\global\c@DTLrow=\c@DTLrow + \ifx\@dtl@type\@empty + \edef\@dtl@type{\number\@dtl@datatype}% + \else % \end{macrocode} -% Store database name +% This column already has an associated data type but it may +% need updating. % \begin{macrocode} -\gdef\@dtl@dbname{#2}% + \ifcase\@dtl@datatype % string % \end{macrocode} -% Increment level and check not exceeded 3 +% String overrides all other types % \begin{macrocode} -\global\advance\dtlforeachlevel by 1\relax -\ifnum\dtlforeachlevel>3\relax - \PackageError{datatool}{\string\DTLforeach\space nested too -deeply}{}% -\else + \def\@dtl@type{0}% + \or % int % \end{macrocode} -% Set level dependent information (needs to be global to ensure -% it works in the \env{tabular} environment.) Row counter: +% All other types override int, so leave it as it is % \begin{macrocode} - \expandafter\global - \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname = 0\relax + \or % real % \end{macrocode} -% Set database name to \cs{@nnil} to indicate that this is read only: +% Real overrides int, but not currency or string % \begin{macrocode} - \expandafter\global\expandafter\let - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname - =\@nnil + \ifnum\@dtl@type=1\relax + \def\@dtl@type{2}% + \fi + \or % currency % \end{macrocode} -% Iterate through each row +% Currency overrides int and real but not string % \begin{macrocode} - \expandafter\let\expandafter\@dtl@db\csname dtldb@#2\endcsname% - \@for\@dtl@currentrow:=\@dtl@db\do{% + \ifnum\@dtl@type>0\relax + \def\@dtl@type{3}% + \fi + \fi + \fi % \end{macrocode} -% Set current row macro for this level +% Has the data type been updated? % \begin{macrocode} - \expandafter\global\expandafter - \let\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel - \endcsname=\@dtl@currentrow + \ifx\@dtl@oldtype\@dtl@type % \end{macrocode} -% Globally assign next element (note that there is no check to -% determine if the next element will be skipped.) -%\changes{1.01}{2007 Aug 17}{set \cs{@dtl@nextrow}} +% No change needed % \begin{macrocode} - \global\let\@dtl@nextrow\@xfor@nextelement + \else % \end{macrocode} -% Assign commands to the required entries +% Update required +% \begin{macrocode} + \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 + }% + {% +% \end{macrocode} +% Key doesn't exist. Increment column count. % \begin{macrocode} - \ifx\relax#3\relax - \else - \@dtl@assign{#3}% - \fi + \expandafter\global\expandafter\advance + \csname dtlcols@#1\endcsname by 1\relax + \dtlcolumnnum=\csname dtlcols@#1\endcsname\relax % \end{macrocode} -% Do the main body of text if condition is satisfied +% Set column index for this key % \begin{macrocode} - \ifthenelse{#1}{% - \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% - \expandafter\edef\expandafter\DTLcurrentindex\expandafter - {\arabic{DTLrow\romannumeral\dtlforeachlevel}}% - #4% - }{}% + \expandafter\xdef\csname dtl@ci@#1@#2\endcsname{% + \number\dtlcolumnnum}% % \end{macrocode} +% Get data type for this entry (stored in \cs{@dtl@datatype}) % \begin{macrocode} -\@endforfalse -}% -\fi -\global\advance\dtlforeachlevel by -1\relax -}{% -\PackageError{datatool}{Database `#2' doesn't exist}{}}% + \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 +% \end{macrocode} +% Append to property list +% \begin{macrocode} + \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@ + }% + }% } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLappendtorow} +%\begin{macro}{\DTLsetheader} %\begin{definition} -%\cs{DTLappendtorow}\marg{key}\marg{value} +%\cs{DTLsetheader}\marg{db}\marg{key}\marg{header} %\end{definition} -% Appends entry to current row. (The current row is given by -% \cs{@dtl@thiscurrentrow@}\meta{n} where \meta{n} is roman -% numeral value of \cs{dtlforeachlevel}. -% \begin{macrocode} -\newcommand*{\DTLappendtorow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLappendtorow\space can only - be used inside \string\DTLforeach}{}% -\else -% \end{macrocode} -% Set \cs{@dtl@thisdb} to the current database name: -% \begin{macrocode} - \expandafter\let\expandafter\@dtl@thisdb - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname -% \end{macrocode} -% Check this isn't in \cs{DTLforeach*} +% Sets header for column given by \meta{key} in database \meta{db}. +% Starred version doesn't check for existance of database or key. % \begin{macrocode} - \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 +\newcommand*{\DTLsetheader}{\@ifstar\@sDTLsetheader\@DTLsetheader} % \end{macrocode} -% Set \cs{@dtl@dbvalue} to the value of this entry +%\end{macro} +% +%\begin{macro}{\@DTLsetheader} +% Unstarred version % \begin{macrocode} - \expandafter\@dtl@toks\expandafter{#2}% - \edef\@dtl@dbvalue{\the\@dtl@toks}% +\newcommand*{\@DTLsetheader}[3]{% % \end{macrocode} -% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow -% for the ID to be stored in a control sequence. +% Check if database exists % \begin{macrocode} - \edef\@dtl@dbid{#1}% + \DTLifdbexists{#1}% + {% % \end{macrocode} -% Set up the correct entry format: +% Check if key exists. % \begin{macrocode} - \edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% + \@sDTLifhaskey{#1}{#2}% + {% + \@sDTLsetheader{#1}{#2}{#3}% + }% + {% + \PackageError{datatool}{Database `#1' doesn't contain key + `#2'}{}% + }% + }% + {% + \PackageError{datatool}{Database `#1' doesn't exist}{}% + }% +} % \end{macrocode} -% Set \cs{@dtl@thisrow} to the current row. +%\end{macro} +% +%\begin{macro}{\@sDTLsetheader} +% Starred version % \begin{macrocode} - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname +\newcommand*{\@sDTLsetheader}[3]{% + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{#1}{#2}\relax + \@dtl@setheaderforindex{#1}{\dtlcolumnnum}{#3}% +} % \end{macrocode} -% Check if there is already an entry with this key +%\end{macro} +% +%\begin{macro}{\@dtl@setheaderforindex} +%\begin{definition} +%\cs{@dtl@setheaderforindex}\marg{db}\marg{column index}\marg{header} +%\end{definition} +% Sets the header for column given by \meta{column index} in +% database \meta{db}. The header must be expanded. % \begin{macrocode} - \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}}{% +\newcommand*{\@dtl@setheaderforindex}[3]{% % \end{macrocode} -% Append entry to last row +% Get the properties for this column % \begin{macrocode} - \expandafter\@dtl@toks\expandafter{\@dtl@dbentry}% - \ifx\@dtl@thisrow\@empty - \expandafter - \xdef\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname{% - \the\@dtl@toks}% - \else - \expandafter\toks@\expandafter{\@dtl@thisrow}% - \expandafter - \xdef\csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname{% - \the\toks@,\the\@dtl@toks}% - \fi - } + \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 % \end{macrocode} -% Update key list +% Store the header in \cs{@dtl@toks} % \begin{macrocode} - \@dtl@setidtype{\@dtl@thisdb}{#1}{#2}% - \expandafter\@dtl@setkeys\expandafter{#1}{\@dtl@thisdb}% + \@dtl@colhead={#3}% % \end{macrocode} -% end the \cs{ifx} and \cs{ifnum} +% Reconstruct property list % \begin{macrocode} - \fi -\fi + \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 + }% + {\@dtl@after}% } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLremoveentryfromrow} +%\begin{macro}{\DTLnewdbentry} %\begin{definition} -%\cs{DTLremoveentryfromrow}\marg{key} +% \cs{DTLnewdbentry}\marg{db name}\marg{id}\marg{value}. %\end{definition} -% Removes entry given by \meta{key} from current row. -% (The current row is given by -% \cs{@dtl@thiscurrentrow@}\meta{n} where \meta{n} is roman -% numeral value of \cs{dtlforeachlevel}. +% Adds an entry to the last row (adds new row if database is empty) +% and updates general column information if necessary. The +% starred version doesn't check if the database exists. % \begin{macrocode} -\newcommand*{\DTLremoveentryfromrow}[1]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLremoveentryfromrow\space can only - be used inside \string\DTLforeach}{}% -\else +\newcommand{\DTLnewdbentry}{% + \@ifstar\@sDTLnewdbentry\@DTLnewdbentry +} % \end{macrocode} -% Set \cs{@dtl@thisdb} to the current database name: +%\end{macro} +% +%\begin{macro}{\@DTLnewdbentry} +% Unstarred version of \cs{DTLnewdbentry}. % \begin{macrocode} - \expandafter\let\expandafter\@dtl@thisdb - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +\newcommand{\@DTLnewdbentry}[3]{% + \DTLifdbexists{#1}% + {\@sDTLnewdbentry{#1}{#2}{#3}}% + {\PackageError{datatool}{Can't add new entry to database `#1': + database doesn't exist}{}}% +} % \end{macrocode} -% Check this isn't in \cs{DTLforeach*} +%\end{macro} +%\begin{macro}{\@sDTLnewdbentry} +% Starred version of \cs{DTLnewdbentry} (doesn't check if the database exists). % \begin{macrocode} - \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}% - \else +\newcommand*{\@sDTLnewdbentry}[3]{% % \end{macrocode} -% Set \cs{@dtl@thisrow} to the current row. +% Update key list % \begin{macrocode} - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname + \@dtl@updatekeys{#1}{#2}{#3}% % \end{macrocode} -% Check row contains an entry with this key +% Get the column index % \begin{macrocode} - \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{#1}{#2}\relax % \end{macrocode} -% Split row list +% Get the current row: % \begin{macrocode} - \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}{}% + \edef\dtl@dogetrow{\noexpand\dtlgetrow{#1}% + {\number\csname dtlrows@#1\endcsname}}% + \dtl@dogetrow +% \end{macrocode} +% Check if this row already has an entry for the given column. +% \begin{macrocode} + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% }% - \fi -\fi -} + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLreplaceentryforrow} -%\begin{definition} -%\cs{DTLreplaceentryforrow}\marg{key}\marg{value} -%\end{definition} -% Replaces entry given by \meta{key} in current row with -% \meta{value}. -% (The current row is given by -% \cs{@dtl@thiscurrentrow@}\meta{n} where \meta{n} is roman -% numeral value of \cs{dtlforeachlevel}. +% Store the value of this entry in \cs{@dtl@toks} % \begin{macrocode} -\newcommand*{\DTLreplaceentryforrow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLreplaceentryforrow\space can only - be used inside \string\DTLforeach}{}% -\else + \@dtl@toks{#3}% % \end{macrocode} -% Set \cs{@dtl@thisdb} to the current database name: +% There are no entries in this row for the given column. +% Add this entry. % \begin{macrocode} - \expandafter\let\expandafter\@dtl@thisdb - \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + \toks@gconcat@middle@cx{dtldb@#1}% + {\dtlbeforerow}% + {% % \end{macrocode} -% Check this isn't in \cs{DTLforeach*} +% Start of this row: % \begin{macrocode} - \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}% - \else + \noexpand\db@row@elt@w% % \end{macrocode} -% Set \cs{@dtl@dbvalue} to the value of this entry +% Row ID: % \begin{macrocode} - \expandafter\@dtl@toks\expandafter{#2}% - \edef\@dtl@dbvalue{\the\@dtl@toks}% + \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname + \noexpand\db@row@id@end@% % \end{macrocode} -% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow -% for the ID to be stored in a control sequence. +% Current row so far % \begin{macrocode} - \edef\@dtl@dbid{#1}% + \the\dtlcurrentrow % \end{macrocode} -% Set up the correct entry format: +% New column: +% Column ID % \begin{macrocode} - \edef\dtl@newentry{{\@dtl@dbid}{\the\@dtl@toks}}% + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@% % \end{macrocode} -% Set \cs{@dtl@thisrow} to the current row. +% Value: % \begin{macrocode} - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname + \noexpand\db@col@elt@w \the\@dtl@toks + \noexpand\db@col@elt@end@% % \end{macrocode} -% Check row contains an entry with this key +% Column ID: % \begin{macrocode} - \dtl@ifrowcontains{#1}{\@dtl@thisrow}{% + \noexpand\db@col@id@w \number\dtlcolumnnum + \noexpand\db@col@id@end@% % \end{macrocode} -% Split row list +% Row ID: % \begin{macrocode} - \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}{}% - }% - \fi -\fi -} + \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname + \noexpand\db@row@id@end@% % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLremovecurrentrow} -%\begin{definition} -%\cs{DTLremovecurrentrow} -%\end{definition} -% Removes current row. This just sets the current row to empty -%\changes{1.01}{2007 Aug 17}{fix bug caused by missing \cs{fi} -% and unrequired argument} +% End of this row % \begin{macrocode} -\newcommand*{\DTLremovecurrentrow}{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLremovecurrentrow\space can only - be used inside \string\DTLforeach}{}% -\else + \noexpand\db@row@elt@end@% + }% % \end{macrocode} -% Check this isn't in \cs{DTLforeach*} +% Rest (this should be empty) % \begin{macrocode} - \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}% + {\dtlafterrow}% +% \end{macrocode} +% Print information message if in verbose mode. +% \begin{macrocode} + \dtl@message{Added #2\space -> #3\space to database `#1'}% \else % \end{macrocode} -% Set current row to empty. +% There's already an entry for the given column in this row % \begin{macrocode} - \expandafter\let - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname - =\@empty + \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 } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLforeachkeyinrow} +%\changes{2.0}{2009 February 27}{removed \cs{@dtl@setidtype}} +%\changes{2.0}{2009 February 27}{removed \cs{@dtl@setkeys}} +%\changes{2.0}{2009 February 27}{removed \cs{@dtl@getidtype}} +% +%\begin{macro}{\DTLifdbexists} %\begin{definition} -%\cs{DTLforeachkeyinrow}\marg{cmd}\marg{text} +%\cs{DTLifdbexists}\marg{db name}\marg{true part}\marg{false part} %\end{definition} -% Iterates through each key in the current row of \cs{DTLforeach}, -% and does \meta{text}. -% \begin{macrocode} -\newcommand*{\DTLforeachkeyinrow}[2]{% -\ifnum\dtlforeachlevel=0\relax - \PackageError{datatool}{\string\DTLforeachkeyinrow\space can only - be used inside \string\DTLforeach}{}% -\else -% \end{macrocode} -% Set \cs{@dtl@thisrow} to the current row. +% Checks if a data base with the given name exists. % \begin{macrocode} - \expandafter\let\expandafter\@dtl@thisrow - \csname @dtl@thiscurrentrow@\romannumeral\dtlforeachlevel\endcsname +\newcommand{\DTLifdbexists}[3]{% + \@ifundefined{dtldb@#1}{#3}{#2}} % \end{macrocode} -% Iterate through the row +%\end{macro} +% +%\changes{2.0}{2009 February 27}{removed \cs{@dtl@ifrowcontains}} +%\changes{2.0}{2009 February 27}{removed \cs{dtl@getentryvalue}} +%\changes{2.0}{2009 February 27}{removed \cs{dtl@getentryid}} +% +%\subsection{Accessing Data} +% +%\begin{macro}{\@dtl@assign} +%\begin{definition} +%\cs{@dtl@assign}\marg{list}\marg{db} +%\end{definition} +% Assigns commands according to the given keys. +% The current row must be stored in \cs{dtlcurrentrow}. +%\changes{2.0}{2009 February 27}{updated to use new database +% structure} % \begin{macrocode} - \@for\dtl@thisentry:=\@dtl@thisrow\do{% - \dtl@getentryvalue\dtl@thisentry{#1}% - #2% - }% -\fi +\newcommand*{\@dtl@assign}[2]{% + \@dtl@assigncmd#1,\@nil\@@{#2}% } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLaddentryforrow} +%\begin{macro}{\@dtl@assigncmd} %\begin{definition} -%\cs{DTLaddentryforrow}\marg{db name}\marg{assign list}\marg{condition}\marg{key}\marg{value} +% \cs{@dtl@assigncmd}\meta{cmd}=\meta{id}\cs{@nil} %\end{definition} -% Adds the entry with key given by \meta{key} and value given by -% \meta{value} to the first row in the database \meta{db name} -% which satisfies the condition given by \meta{condition}. The -% \meta{assign list} is the same as for \cs{DTLforeach} and may -% be used to set the values which are to be tested in \meta{condition}. % \begin{macrocode} -\newcommand{\DTLaddentryforrow}[5]{% -\gdef\@dtl@dbname{#1}% -\DTLifdbexists{#1}{% +\def\@dtl@assigncmd#1=#2,#3\@@#4{% % \end{macrocode} -% Set \cs{@dtl@dbvalue} to the value of this entry +% get entry for ID given by \#2 and store in \#1 % \begin{macrocode} - \expandafter\@dtl@toks\expandafter{#5}% - \edef\@dtl@dbvalue{\the\@dtl@toks}% + \@sDTLifhaskey{#4}{#2}% + {% + \edef\@dtl@dogetentry{% + \noexpand\dtlgetentryfromcurrentrow + {\noexpand#1}{\dtl@columnindex{#4}{#2}}}% + \@dtl@dogetentry % \end{macrocode} -% Set \cs{@dtl@dbid} to the entry ID. This uses \cs{edef} to allow -% for the ID to be stored in a control sequence. +% Set to null if required % \begin{macrocode} - \edef\@dtl@dbid{#4}% + \ifx#1\dtlnovalue + \@@dtl@setnull{#1}{#2}% + \fi % \end{macrocode} -% Set up the correct entry format: +% Make it global % \begin{macrocode} - \edef\@dtl@dbentry{{\@dtl@dbid}{\the\@dtl@toks}}% + \global\let#1=#1\relax + }% + {% + \PackageError{datatool}{Can't assign \string#1\space: there + is no key `#2' in data base `#4'}{}% % \end{macrocode} -% Store the database in \cs{@dtl@db} +% Set to null % \begin{macrocode} - \expandafter - \let\expandafter\@dtl@db\csname dtldb@\@dtl@dbname\endcsname% - \let\@dtl@prerow=\@empty + \global\let#1\DTLstringnull + }% % \end{macrocode} -% Iterate through each row of the database +% Recurse? % \begin{macrocode} - \@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}}% - \else - \expandafter\toks@\expandafter{\@dtl@currentrow}% - \edef\@dtl@currentrow{\the\toks@,{\the\@dtl@toks}}% - \fi - \@endfortrue - }{% - }% - \expandafter\@dtl@toks\expandafter{\@dtl@currentrow}% - \ifx\@dtl@prerow\@empty - \edef\@dtl@prerow{{\the\@dtl@toks}}% + \def\dtl@tmp{#3}% + \ifx\@nnil\dtl@tmp + \let\@dtl@next\@dtl@assigncmdnoop \else - \expandafter\toks@\expandafter{\@dtl@prerow}% - \edef\@dtl@prerow{\the\toks@,{\the\@dtl@toks}}% + \let\@dtl@next\@dtl@assigncmd \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}{}}% -} -% \end{macrocode} -%\end{macro} -% -%\begin{macro}{\@dtl@assign} -%\begin{definition} -%\cs{@dtl@assign}\oarg{row}\marg{values} -%\end{definition} -% Assigns each command in -% \meta{values} (see above) to the value of the corresponding -% ID for the row given by \meta{row} (which defaults to -% \cs{@dtl@currentrow} if absent.) -% \begin{macrocode} -\newcommand*{\@dtl@assign}[2][\@dtl@currentrow]{% -\@dtl@assigncmd#2,\relax\@@{#1}% -} -% \end{macrocode} -%\end{macro} -%\begin{macro}{\@dtl@assigncmd} -%\begin{definition} -% \cs{\@dtl@assigncmd}\meta{cmd}=\meta{id}\cs{@nil} -%\end{definition} -% Assign \meta{cmd} to value given by \meta{id} -% \begin{macrocode} -\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}% + \@dtl@next#3\@@{#4}% } % \end{macrocode} %\end{macro} @@ -10117,24 +10962,63 @@ deeply}{}% \def\@dtl@assigncmdnoop#1\@@#2{} % \end{macrocode} %\end{macro} +% %\begin{macro}{\@dtl@setnull} %\cs{@dtl@setnull}\marg{cmd}\marg{id} sets \meta{cmd} to either % \cs{DTLstringnull} or \cs{DTLnumbernull} depending on the data % type for \meta{id}. (Database -% name should be stored in \cs{@dtl@dbname} prior to use. +% name should be stored in \cs{@dtl@dbname} prior to use.) +%\changes{2.0}{2009 February 27}{modified to use new database +% structure} % \begin{macrocode} \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 -}} +% \end{macrocode} +% Check if database given by \cs{@dtl@dbname} has the required key. +% \begin{macrocode} + \@sDTLifhaskey{\@dtl@dbname}{#2}% + {% +% \end{macrocode} +% Set to null +% \begin{macrocode} + \@@dtl@setnull{#1}{#2}% + }% + {% +% \end{macrocode} +% Key not defined in database \cs{@dtl@dbname}. +% \begin{macrocode} + \global\let#1=\DTLstringnull + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@@dtl@setnull} +% As above, but doesn't check if key exists +% \begin{macrocode} +\newcommand*{\@@dtl@setnull}[2]{% +% \end{macrocode} +% Get the data type associated with this key and store in +% \cs{@dtl@type}. +% \begin{macrocode} + \@sdtlgetdatatype{\@dtl@type}{\@dtl@dbname}{#2}% +% \end{macrocode} +% Check data type. +% \begin{macrocode} + \ifnum0\@dtl@type=0\relax +% \end{macrocode} +% Data type is \meta{empty} or 0, so set to string null. +% \begin{macrocode} + \global\let#1=\DTLstringnull + \else +% \end{macrocode} +% Data type is numerical, so set to number null. +% \begin{macrocode} + \global\let#1=\DTLnumbernull + \fi +} % \end{macrocode} %\end{macro} +% %\begin{macro}{\DTLstringnull} % String null value: % \begin{macrocode} @@ -10156,1916 +11040,5763 @@ deeply}{}% % does \meta{false part}. % \begin{macrocode} \newcommand*{\DTLifnull}[3]{% -\ifx\DTLstringnull#1\relax - #2% -\else - \ifx\DTLnumbernull#1\relax - #2% - \else - #3% - \fi -\fi} + \ifx\DTLstringnull#1\relax + #2% + \else + \ifx\DTLnumbernull#1\relax + #2% + \else + #3% + \fi + \fi +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\dtl@gathervalues} +%\begin{macro}{\@dtlnovalue} +% \begin{macrocode} +\def\@dtlnovalue{Undefined Value} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlnovalue} +% \begin{macrocode} +\def\dtlnovalue{\@dtlnovalue} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgetkeydata} %\begin{definition} -%\cs{dtl@gathervalues}\oarg{label}\marg{db name}\marg{row} +%\cs{DTLgetkeydata}\marg{key}\marg{db}\marg{col cs}\marg{type cs}\marg{header cs} %\end{definition} -% Stores each element of \meta{row} in \meta{db name} into -% the command \cs{@dtl@}\meta{label}\texttt{@}\meta{key}, -% where \meta{key} is the -% key for that element, and \meta{label} defaults to "key". +% Gets data for given key in database \meta{db}: the column index is +% stored in \meta{col cs} and data type is stored in \meta{type cs}. +% The unstarred version checks for the existance of the database +% and key, the starred version doesn't. % \begin{macrocode} -\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*{\DTLgetkeydata}{% + \@ifstar\@sdtlgetkeydata\@dtlgetkeydata } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLsumforkeys} -%\begin{definition} -%\cs{DTLsumforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} -%\end{definition} -% Sums all entries for key \meta{key} over all databases listed -% in \meta{db list}, -% and stores in \meta{cmd}, which must be a control sequence. -% The optional argument \meta{condition} is the same as that -% for \cs{DTLforeach}. +%\begin{macro}{\@dtlgetkeydata} +% Unstarred version of \cs{DTLgetkeydata} % \begin{macrocode} -\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*{\@dtlgetkeydata}[5]{% +% \end{macrocode} +% Check if the database exists. +% \begin{macrocode} + \DTLifdbexists{#2}% + {% +% \end{macrocode} +% Check if the given key exists in the database. +% \begin{macrocode} + \@sDTLifhaskey{#2}{#1}% + {% +% \end{macrocode} +% Get the data. +% \begin{macrocode} + \@sdtlgetkeydata{#1}{#2}{#3}{#4}{#5}% + }% + {% +% \end{macrocode} +% Key not defined in the given database. +% \begin{macrocode} + \PackageError{datatool}{Key `#1' not defined in database + `#2'}{}% + }% + }% + {% +% \end{macrocode} +% Database not defined. +% \begin{macrocode} + \PackageError{datatool}{Database `#2' doesn't exist}{}% }% -}% } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLmeanforkeys} -%\begin{definition} -%\cs{DTLmeanforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} -%\end{definition} -% Computes the arithmetic mean of all entries for each key in -% \meta{key list} over all databases in \meta{db list}, -% and stores in \meta{cmd}, which must be a control sequence. -% The optional argument \meta{condition} is the same as that -% for \cs{DTLforeach}. +%\begin{macro}{\@sdtlgetkeydata} +%\cs{@sdtlgetkeydata}\marg{key}\marg{db}\marg{col cs}\marg{type cs}\marg{header cs} +% Starred verison of \cs{DTLgetkeydata}. % \begin{macrocode} -\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*{\@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}% } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLvarianceforkeys} +%\begin{macro}{\dtl@gathervalues} %\begin{definition} -%\cs{DTLvarianceforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\cs{dtl@gathervalues}\oarg{label}\marg{db name}\marg{row toks} %\end{definition} -% Computes the variance of all entries for each key in -% \meta{key list} over all databases in \meta{db list}, -% and stores in \meta{cmd}, which must be a control sequence. -% The optional argument \meta{condition} is the same as that -% for \cs{DTLforeach}. +% Stores each element of \meta{row} in \meta{db name} into +% the command \cs{@dtl@}\meta{label}\texttt{@}\meta{key}, +% where \meta{key} is the +% key for that element, and \meta{label} defaults to "key". +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} -\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{\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 }% -}% -\ifnum\dtl@n=0\relax - \PackageError{datatool}{Can't compute variance, no data!}{}% -\else - \DTLdiv{#4}{#4}{\dtl@n}% -\fi } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLsdforkeys} -%\begin{definition} -%\cs{DTLsdforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} -%\end{definition} -% Computes the standard deviation of all entries for each key in -% \meta{key list} over all databases in \meta{db list}, -% and stores in \meta{cmd}, which must be a control sequence. -% The optional argument \meta{condition} is the same as that -% for \cs{DTLforeach}. +%\begin{macro}{\dtlcurrentrow} +% Define token register to store current row. % \begin{macrocode} -\newcommand*{\DTLsdforkeys}[4][\boolean{true}\and -\DTLisnumerical{\DTLthisval}]{% -\DTLvarianceforkeys[#1]{#2}{#3}{#4}% -\DTLsqrt{#4}{#4}% -} +\newtoks\dtlcurrentrow % \end{macrocode} %\end{macro} -% -%\begin{macro}{\DTLminforkeys} -%\begin{definition} -%\cs{DTLminforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} -%\end{definition} -% Determines the minimum over all entries for each key in -% \meta{key list} over all databases in \meta{db list}, -% and stores in \meta{cmd}, which must be a control sequence. -% The optional argument \meta{condition} is the same as that -% for \cs{DTLforeach}. +%\begin{macro}{\dtlbeforerow} +% Define token register to store everything before the current row. % \begin{macrocode} -\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}{}% - }% -}} +\newtoks\dtlbeforerow +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlafterrow} +% Define token register to store everything after the current row. +% \begin{macrocode} +\newtoks\dtlafterrow % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLmaxforkeys} +%\begin{macro}{\dtlgetrow} %\begin{definition} -%\cs{DTLmaxforkeys}\oarg{condition}\marg{db list}\marg{key list}\marg{cmd} +%\cs{dtlgetrow}\marg{db}\marg{row idx} %\end{definition} -% Determines the maximum over all entries for each key in -% \meta{key list} over all databases in \meta{db list}, -% and stores in \meta{cmd}, which must be a control sequence. -% The optional argument \meta{condition} is the same as that -% for \cs{DTLforeach}. +% Gets row with index \meta{row idx} from database named \meta{db} +% and stores the row in \cs{dtlcurrentrow}, the preceding rows in +% \cs{dtlbeforerow} and the following rows in \cs{dtlafterrow}. +% This assumes that the given row exists. % \begin{macrocode} -\newcommand*{\DTLmaxforkeys}[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 - \DTLmax{#4}{#4}{\DTLthisval}% - \fi - }{}% -}}% - }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% - }% -}} +\newcommand*{\dtlgetrow}[2]{% + \expandafter\toks@\expandafter=\csname dtldb@#1\endcsname + \edef\@dtl@dogetrow{\noexpand\@dtlgetrow{\the\toks@}{\number#2}}% + \@dtl@dogetrow +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLcomputebounds} +%\begin{macro}{\@dtlgetrow} %\begin{definition} -%\cs{DTLcomputebounds}\oarg{condition}\marg{db list}\marg{x key}\marg{y key}\marg{minX cmd}\marg{minY cmd}\marg{maxX cmd}\marg{maxY cmd} +%\cs{@dtlgetrow}\marg{data specs}\marg{row idx} +% Gets the row specs from \meta{data specs} for row with index +% \meta{row idx} which must be fully expanded. %\end{definition} -% Computes the maximum and minimum $x$ and $y$ values over all -% the databases listed in \meta{db list} where the $x$ value -% is given by \meta{x key} and the $y$ value is given by -% \meta{y key}. The results are stored in \meta{minX cmd}, -% \meta{minY cmd}, \meta{maxX cmd} and \meta{maxY cmd} in -% standard decimal format. % \begin{macrocode} -\newcommand*{\DTLcomputebounds}[8][\boolean{true}]{% -\let#5=\relax -\let#6=\relax -\let#7=\relax -\let#8=\relax -\@for\dtl@thisdb:=#2\do{% - \@sDTLforeach[#1]{\dtl@thisdb}{\DTLthisX=#3,\DTLthisY=#4}{% - \DTLconverttodecimal{\DTLthisX}{\dtl@decx}% - \DTLconverttodecimal{\DTLthisY}{\dtl@decy}% - \ifx#5\relax - \let#5=\dtl@decx - \let#6=\dtl@decy - \let#7=\dtl@decx - \let#8=\dtl@decy - \else - \FPmin{#5}{#5}{\dtl@decx}% - \FPmin{#6}{#6}{\dtl@decy}% - \FPmax{#7}{#7}{\dtl@decx}% - \FPmax{#8}{#8}{\dtl@decy}% - \fi - }% -}% +\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 } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLgetvalueforkey} +%\begin{macro}{\dtlgetentryfromcurrentrow} %\begin{definition} -%\cs{DTLgetvalueforkey}\marg{cmd}\marg{key}\marg{db name}\marg{ref -% key}\marg{ref value} +%\cs{dtlgetentryfromcurrentrow}\marg{cs}\marg{col num} %\end{definition} -% This (globally) sets \meta{cmd} (a control sequence) to the -% value of the key specified by \meta{key} in the first row -% of the database called \meta{db name} which contains the key -% \meta{ref key} which has the value \meta{value}. -%\changes{1.01}{2007 Aug 17}{new} +% Gets value for column \meta{col num} from \cs{dtlcurrentrow} +% and stores in \meta{cs}. If not found, \meta{cs} is set to +% \cs{dtlnovalue}. +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\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 -}{}}}% -}} +\newcommand*{\dtlgetentryfromcurrentrow}[2]{% + \dtlgetentryfromrow{#1}{#2}{\dtlcurrentrow}% +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLgetrowforkey} +%\begin{macro}{\dtlgetentryfromrow} %\begin{definition} -%\cs{DTLgetrowforkey}\marg{cmd}\marg{db name}\marg{ref -% key}\marg{ref value} +%\cs{dtlgetentryfromrow}\marg{cs}\marg{col num}\marg{row toks} %\end{definition} -% This (globally) sets \meta{cmd} (a control sequence) to the -% first row -% of the database called \meta{db name} which contains the key -% \meta{ref key} which has the value \meta{value}. -%\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} -\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 -}{}}}% -}} +\newcommand*{\dtlgetentryfromrow}[3]{% + \edef\@dtl@do@getentry{\noexpand\dtl@getentryfromrow + {\noexpand#1}{\number#2}{\the#3}}% + \@dtl@do@getentry +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLsort} +%\begin{macro}{\dtl@getentryfromrow} %\begin{definition} -% \cs{DTLsort}\oarg{replacement keys}\marg{sort criteria}\marg{db name} +%\cs{dtl@getentryfromrow}\marg{cs}\marg{col num}\marg{row specs} %\end{definition} -% Sorts database \meta{db name} according to \marg{sort criteria}, -% which must be a comma separated list of keys, and optionally -% \texttt{=}\meta{order}, where \meta{order} is either -% "ascending" or "descending". The optional argument is a list of -% keys to uses if the given key has a null value. The starred -% version uses a case insensitive string comparison. -%\changes{1.01}{2007 Aug 17}{added optional argument} -%\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} -\newcommand*{\DTLsort}{\@ifstar\@sDTLsort\@DTLsort} -% \end{macrocode} +\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 +} +% \end{macrocode} %\end{macro} % -%\begin{macro}{\@DTLsort} -% Unstarred (case sensitive) version. +%\begin{macro}{\DTLgetvalue} +%\begin{definition} +%\cs{DTLgetvalue}\marg{cs}\marg{db}\marg{r}\marg{c} +%\end{definition} +% Gets the element in row \meta{r}, column \meta{c} from database +% \meta{db} and stores in \meta{cs}. % \begin{macrocode} -\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*{\DTLgetvalue}[4]{% + \edef\dtl@dogetvalue{\noexpand\dtl@getvalue{\noexpand#1}{#2}% + {\number#3}{\number#4}}% + \dtl@dogetvalue +} % \end{macrocode} %\end{macro} -%\begin{macro}{\@sDTLsort} -% Starred (case insensitive) version. +% +%\begin{macro}{\dtl@getvalue} % \begin{macrocode} -\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*{\dtl@getvalue}[4]{% + \def\@dtl@getvalue ##1% stuff before row + \db@row@id@w #3\db@row@id@end@% row id + ##2% stuff in row before column + \db@col@id@w #4\db@col@id@end@% column 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 +} % \end{macrocode} %\end{macro} % -%\begin{macro}{\@dtl@sortcriteria} +%\begin{macro}{\DTLgetlocation} %\begin{definition} -% \cs{@dtl@sortcriteria}\marg{a}\marg{b} +%\cs{DTLgetlocation}\marg{row cs}\marg{column cs}\marg{database}% +%\marg{value} %\end{definition} -% Sort criteria. \cs{@dtl@dbname} and -% \cs{@dtl@sortorder} must be set before use. +% Assigns \meta{row cs} and \meta{column cs} to the indices of the +% first entry in \meta{database} that matches \meta{value}. % \begin{macrocode} -\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}% +\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 - \multiply\dtl@sortresult by \@dtl@sortdirection\relax - \ifnum\dtl@sortresult=0\relax - \else - \@endfortrue - \fi - }% -}% } % \end{macrocode} %\end{macro} -%\begin{macro}{\@dtl@getsortdirection} -% Get the direction from either \meta{key} or -% \meta{key}=\meta{direction}. Sets \cs{@dtl@sortdirection} to -% either -1 (ascending) or 1 (descending). + +%\subsection{Iterating Through Databases} +%\label{sec:code:loops} +% +%\begin{macro}{\dtlbreak} +% Break out of loop at the end of current iteration. % \begin{macrocode} -\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 +\newcommand*{\dtlbreak}{% + \PackageError{datatool}{Can't break out of anything}{}% } % \end{macrocode} %\end{macro} -%\begin{macro}{\@dtl@get@sortdirection} -% Get direction -% \begin{macrocode} -\def\@dtl@get@sortdirection#1={\def\@dtl@sortdirection{#1}} -% \end{macrocode} -%\end{macro} % -%\begin{macro}{\dtl@compare} +%\begin{macro}{\dtlforint} %\begin{definition} -%\cs{dtl@compare}\marg{key}\marg{a}\marg{b} +%\cs{dtlforint}\meta{ct}=\meta{start}\cs{to}\meta{end}\cs{step}% +%\meta{inc}\cs{do}\marg{body} %\end{definition} -% Compares \meta{a} and \meta{b} according to \meta{key} of -% database given by \cs{@dtl@dbname}. Sets \cs{dtl@sortresult}. -% \cs{@dtl@comparecs} must be set to the required comparison macro. +% \meta{ct} is a count register, \meta{start}, \meta{end} and +% \meta{inc} are integers. +% Group if nested or use \cs{dtlgforint}. +% An infinite loop may result if \meta{inc}$=0$ and +% \meta{start} $\le$ \meta{end} and \cs{dtlbreak} isn't used. % \begin{macrocode} -\newtoks\@dtl@toksA\newtoks\@dtl@toksB -\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}% +\long\def\dtlforint#1=#2\to#3\step#4\do#5{% +% \end{macrocode} +% Make a copy of old version of break function +% \begin{macrocode} + \let\@dtl@orgbreak\dtlbreak + \def\@dtl@endloophook{}% +% \end{macrocode} +% Setup break function for the loop (sets \meta{ct} to \meta{end} +% at the end of the current iteration). +% \begin{macrocode} + \def\dtlbreak{\def\@dtl@endloophook{#1=#3}}% +% \end{macrocode} +% Initialise \meta{ct} +% \begin{macrocode} + #1=#2\relax +% \end{macrocode} +% Check if the steps are positive or negative. +% \begin{macrocode} + \ifnum#4<0\relax +% \end{macrocode} +% Counting down +% \begin{macrocode} + \whiledo{\(#1>#3\)\TE@or\(#1=#3\)}% + {% + #5% + \@dtl@endloophook + \advance#1 by #4\relax + }% + \else +% \end{macrocode} +% Counting up +% \begin{macrocode} + \whiledo{\(#1<#3\)\TE@or\(#1=#3\)}% + {% + #5% + \@dtl@endloophook + \advance#1 by #4\relax + }% + \fi +% \end{macrocode} +% Restore break function. +% \begin{macrocode} + \let\dtlbreak\@dtl@orgbreak } % \end{macrocode} %\end{macro} % -%\begin{macro}{\dtl@compare@} -%\begin{definition} -%\cs{dtl@compare@}\marg{keya}\marg{keyb}\marg{a}\marg{b} -%\end{definition} -% Compare \meta{a} and \meta{b} according to \meta{keya} -% and \meta{keyb} of -% database given by \cs{@dtl@dbname}. Sets \cs{dtl@sortresult}. -% \cs{@dtl@comparecs} must be set. +%\begin{macro}{\@dtl@foreach@level} +% Count register to keep track of global nested loops. % \begin{macrocode} -\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}% -} +\newcount\@dtl@foreach@level % \end{macrocode} %\end{macro} % -%\subsection{General List Utilities} -% -%\begin{macro}{\dtl@choplast} +%\begin{macro}{\dtlgforint} %\begin{definition} -% \cs{dtl@choplast}\marg{list}\marg{rest}\marg{last} +%\cs{dtlgforint}\meta{ct}=\meta{start}\cs{to}\meta{end}\cs{step}% +%\meta{inc}\cs{do}\marg{body} %\end{definition} -% Chops the last element off a comma separated list, putting the -% last element in the control sequence \meta{last} and putting -% the rest in the control sequence \meta{rest}. The control -% sequence \meta{list} is unchanged. If the list is empty, both -% \meta{last} and \meta{rest} will be empty. +% \meta{ct} is a count register, \meta{start}, \meta{end} and +% \meta{inc} are integers. +% An infinite loop may result if \meta{inc}=0 and \meta{start} $\le$ +% \meta{end} and \cs{dtlbreak} isn't used. % \begin{macrocode} -\newcommand*{\dtl@choplast}[3]{% +\long\def\dtlgforint#1=#2\to#3\step#4\do#5{% % \end{macrocode} -% Set \meta{rest} to empty: +% Initialise % \begin{macrocode} -\let#2\@empty + \global#1=#2\relax % \end{macrocode} -% Set \meta{last} to empty: +% Increment level counter to allow for nested loops % \begin{macrocode} -\let#3\@empty + \global\advance\@dtl@foreach@level by 1\relax % \end{macrocode} -% Iterate through \meta{list}: +% Set up end loop hook % \begin{macrocode} -\@for\@dtl@element:=#1\do{% -\ifx#3\@empty + \expandafter\global\expandafter + \let\csname @dtl@endhook@\the\@dtl@foreach@level\endcsname + \relax % \end{macrocode} -% First iteration, don't set \meta{rest}. +% Set up the break function: +% Copy current definition % \begin{macrocode} -\else - \ifx#2\@empty + \expandafter\global\expandafter + \let\csname @dtl@break@\the\@dtl@foreach@level\endcsname + \dtlbreak % \end{macrocode} -% Second iteration, set \meta{rest} to \meta{last} (which is -% currently set to the previous value: +% Set up definition for this level (sets to at the end +% of the current iteration). % \begin{macrocode} - \expandafter\toks@\expandafter{#3}% - \edef#2{{\the\toks@}}% - \else + \gdef\dtlbreak{\expandafter + \gdef\csname @dtl@endhook@\the\@dtl@foreach@level\endcsname{% + #1=#3}}% % \end{macrocode} -% Subsequent iterations, set \meta{rest} to \meta{rest},\meta{last} -% (\meta{last} is currently set to the previous value): +% check the direction % \begin{macrocode} - \expandafter\toks@\expandafter{#3}% - \expandafter\@dtl@toks\expandafter{#2}% - \edef#2{\the\@dtl@toks,{\the\toks@}}% - \fi -\fi + \ifnum#4<0\relax % \end{macrocode} -% Now set \meta{last} to current element. +% Counting down % \begin{macrocode} -\let#3=\@dtl@element% -}% -} + \whiledo{\(#1>#3\)\TE@or\(#1=#3\)}% + {% + #5% + \csname @dtl@endhook@\the\@dtl@foreach@level\endcsname + \global\advance#1 by #4\relax + }% + \else % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\dtl@chopfirst} -%\begin{definition} -% \cs{dtl@chopfirst}\marg{list}\marg{first}\marg{rest} -%\end{definition} -% Chops first element off \meta{list} and store in \meta{first}. -% The remainder of the list is stored in \meta{rest}. (\meta{list} -% remains unchanged.) +% Counting up (or 0 increments) % \begin{macrocode} -\newcommand*{\dtl@chopfirst}[3]{% -\let#2=\@empty -\let#3=\@empty -\@for\@dtl@element:=#1\do{% - \let#2=\@dtl@element - \@endfortrue -}% -\if@endfor - \let#3=\@forremainder -\fi -\@endforfalse + \whiledo{\(#1<#3\)\TE@or\(#1=#3\)}% + {% + #5% + \csname @dtl@endhook@\the\@dtl@foreach@level\endcsname + \global\advance#1 by #4\relax + }% + \fi +% \end{macrocode} +% Restore break function +% \begin{macrocode} + \expandafter\global\expandafter\let\expandafter\dtlbreak + \csname @dtl@break@\the\@dtl@foreach@level\endcsname +% \end{macrocode} +% Decrement level counter +% \begin{macrocode} + \global\advance\@dtl@foreach@level by -1\relax } % \end{macrocode} %\end{macro} % -%\begin{macro}{\dtl@sortlist} +%\begin{macro}{\@dtlforeachrow} %\begin{definition} -% \cs{dtl@sortlist}\marg{list}\marg{criteria cmd} +%\cs{@dtlforeachrow}(\meta{idx cs},\meta{row cs})\cs{in}\marg{db}% +%\cs{do}\marg{body} %\end{definition} -% Performs an insertion sort on \meta{list}, where \meta{criteria cmd} -% is a macro which takes two arguments \meta{a} and \meta{b}. -% \meta{criteria cmd} must set the count register \cs{dtl@sortresult} -% to either -1 (\meta{a} less than \meta{b}), 0 (\meta{a} is -% equal to \meta{b}) or 1 (\meta{a} is greater than \meta{b}.) +% Iterates through each row in database. Assigns the current row +% index to \meta{idx cs} and the row specs to \meta{row cs} % \begin{macrocode} -\newcommand{\dtl@sortlist}[2]{% -\def\@dtl@sortedlist{}% -\@for\@dtl@currentrow:=#1\do{% -\expandafter\dtl@insertinto\expandafter - {\@dtl@currentrow}{\@dtl@sortedlist}{#2}% -\@endforfalse}% -\let#1=\@dtl@sortedlist +\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 } % \end{macrocode} %\end{macro} % -%\begin{macro}{\dtl@insertinto} -%\begin{definition} -% \cs{dtl@insertinto}\marg{element}\marg{sorted-list}\marg{criteria cmd} -%\end{definition} -% Inserts \meta{element} into the sorted list \meta{sorted-list} -% according to the criteria given by \meta{criteria cmd} (see above.) +%\begin{macro}{\@dtl@foreachrow} % \begin{macrocode} -\newtoks\@dtl@toks -\newcommand{\dtl@insertinto}[3]{% -\def\@dtl@newsortedlist{}% -\@dtl@insertdonefalse -\@for\dtl@srtelement:=#2\do{% -\if@dtl@insertdone - \expandafter\toks@\expandafter{\dtl@srtelement}% - \edef\@dtl@newstuff{{\the\toks@}}% -\else - \expandafter#3\expandafter{\dtl@srtelement}{#1}% - \ifnum\dtl@sortresult<0\relax - \expandafter\toks@\expandafter{\dtl@srtelement}% - \@dtl@toks{#1}% - \edef\@dtl@newstuff{{\the\@dtl@toks},{\the\toks@}}% - \@dtl@insertdonetrue +\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{% +% \end{macrocode} +% Define control sequence given by "#5" +% \begin{macrocode} + \gdef#5{#1}% +% \end{macrocode} +% Hide the loop body in a macro +% \begin{macrocode} + \gdef\@dtl@loopbody{#7}% +% \end{macrocode} +% Increment level counter to allow for nested loops +% \begin{macrocode} + \global\advance\@dtl@foreach@level by 1\relax +% \end{macrocode} +% Check if we have reached the end of the loop +% \begin{macrocode} + \ifx#5\@nnil + \expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachnoop \else - \expandafter\toks@\expandafter{\dtl@srtelement}% - \edef\@dtl@newstuff{{\the\toks@}}% + \gdef#6{#2}% +% \end{macrocode} +% Set up the break function: +% Make a copy of current break function +% \begin{macrocode} + \expandafter\let + \csname @dtl@break@\the\@dtl@foreach@level\endcsname + \dtlbreak +% \end{macrocode} +% Setup break function for this level +% \begin{macrocode} + \gdef\dtlbreak{\expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachnoop}% +% \end{macrocode} +% Initialise +% \begin{macrocode} + \expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachrow +% \end{macrocode} +% Do body of loop +% \begin{macrocode} + \@dtl@loopbody +% \end{macrocode} +% Restore break function +% \begin{macrocode} + \expandafter\let\expandafter\dtlbreak + \csname @dtl@break@\the\@dtl@foreach@level\endcsname \fi -\fi -\ifx\@dtl@newsortedlist\@empty - \expandafter\toks@\expandafter{\@dtl@newstuff}% - \edef\@dtl@newsortedlist{\the\toks@}% -\else - \expandafter\toks@\expandafter{\@dtl@newsortedlist}% - \expandafter\@dtl@toks\expandafter{\@dtl@newstuff}% - \edef\@dtl@newsortedlist{\the\toks@,\the\@dtl@toks}% -\fi -\@endforfalse -}% - \ifx\@dtl@newsortedlist\@empty - \@dtl@toks{#1}% - \edef\@dtl@newsortedlist{{\the\@dtl@toks}}% - \else - \if@dtl@insertdone - \else - \expandafter\toks@\expandafter{\@dtl@newsortedlist}% - \@dtl@toks{#1}% - \edef\@dtl@newsortedlist{\the\toks@,{\the\@dtl@toks}}% - \fi - \fi -\global\let#2=\@dtl@newsortedlist -} % \end{macrocode} -%\end{macro} -%\begin{macro}{\if@dtl@insertdone} -% Define conditional to indicate whether the new entry has -% been inserted into the sorted list. +% Set up what to do next. % \begin{macrocode} -\newif\if@dtl@insertdone + \expandafter\let\expandafter\@dtl@foreachnext + \csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname % \end{macrocode} -%\end{macro} -%\begin{macro}{\dtl@sortresult} -% Define \cs{dtl@sortresult} to be set by comparision macro. +% Decrement level counter. % \begin{macrocode} -\newcount\dtl@sortresult + \global\advance\@dtl@foreach@level by -1\relax +% \end{macrocode} +% Repeat loop if necessary. +% \begin{macrocode} + \@dtl@foreachnext#4\@@{#5}{#6}{#7}\q@nil +} % \end{macrocode} %\end{macro} % -% \subsection{Floating Point Arithmetic} -% The commands defined in this section all use the equivalent -% commands provided by the \sty{fp} package, but first convert -% the decimal number into the required format. +%\begin{macro}{\@dtl@foreachnoop} +% \begin{macrocode} +\long\def\@dtl@foreachnoop#1\@@#2\q@nil{} +% \end{macrocode} +%\end{macro} % -%\begin{macro}{\DTLadd} +%\begin{macro}{\dtlforeachkey} %\begin{definition} -% \cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} +%\cs{dtlforeachkey}(\meta{key cs},\meta{col cs},\meta{type cs},\meta{header cs})% +%\cs{in}\marg{db}\cs{do}\marg{body} %\end{definition} -% Sets \meta{cmd} = \meta{num1} + \meta{num2} +% Iterates through all the keys in database \meta{db}. In each +% iteration, \meta{key cs} stores the key, \meta{col cs} stores the +% column index and \meta{type cs} stores the data type. % \begin{macrocode} -\newcommand*{\DTLadd}[3]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\DTLconverttodecimal{#3}{\@dtl@numii}% -\FPadd{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi +\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 } % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLgadd} -% Global version +% +%\begin{macro}{\@dtl@updatefkcs} % \begin{macrocode} -\newcommand*{\DTLgadd}[3]{% -\DTLadd{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii +\newcommand*{\@dtl@updatefkcs}[8]{% + \gdef#1{#5}% + \gdef#2{#6}% + \gdef#3{#7}% + \gdef#4{#8}% } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLaddall} -%\begin{definition} -%\cs{DTLaddall}\marg{cmd}\marg{num list} -%\end{definition} -% Sums all the values in \meta{num list} and stores in -% \meta{cmd} which must be a control sequence. -%\changes{1.01}{2007 Aug 17}{removed extraneous space} +%\begin{macro}{\@dtl@foreachkey} +% Sets everything globally in case it occurs in a tabular environment +% Loop body needs to be stored in \cs{@dtl@loopbody}. +% "#7" indicates an update macro. % \begin{macrocode} -\newcommand*{\DTLaddall}[2]{% -\def\@dtl@sum{0}% -\@for\dtl@thisval:=#2\do{% - \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% - \FPadd{\@dtl@sum}{\@dtl@sum}{\@dtl@num}% -}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@sum}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@sum}{#1}% -\fi -} +\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 % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgaddall} -%\begin{definition} -%\cs{DTLgaddall}\marg{cmd}\marg{num list} -%\end{definition} -% Global version +% Terminate loop % \begin{macrocode} -\newcommand*{\DTLgaddall}[2]{% -\DTLaddall{\@dtl@tmpi}{#2}% -\global\let#1=\@dtl@tmpi -} + \let\@dtl@foreachnext\@dtl@foreachnoop + \else % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLsub} -%\begin{definition} -% \cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} -%\end{definition} -% Sets \meta{cmd} = \meta{num1} - \meta{num2} +% Set up loop variables % \begin{macrocode} -\newcommand*{\DTLsub}[3]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\DTLconverttodecimal{#3}{\@dtl@numii}% -\FPsub{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi -} + #7{#2}{#1}{#3}{#4}% % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgsub} -% Global version +% Increment level counter to allow for nested loops % \begin{macrocode} -\newcommand*{\DTLgsub}[3]{% -\DTLsub{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii -} + \global\advance\@dtl@foreach@level by 1\relax % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLmul} -%\begin{definition} -% \cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} -%\end{definition} -% Sets \meta{cmd} = \meta{num1} $\times$ \meta{num2} +% Set up the break function % \begin{macrocode} -\newcommand*{\DTLmul}[3]{% -\let\@dtl@thisreplaced=\@empty -\DTLconverttodecimal{#2}{\@dtl@numi}% -\ifx\@dtl@replaced\@empty -\else - \let\@dtl@thisreplaced=\@dtl@replaced -\fi -\DTLconverttodecimal{#3}{\@dtl@numii}% -\ifx\@dtl@replaced\@empty -\else - \let\@dtl@thisreplaced=\@dtl@replaced -\fi -\FPmul{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% -\ifx\@dtl@thisreplaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi -} + \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}% % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgmul} -% Global version +% Initialise % \begin{macrocode} -\newcommand*{\DTLgmul}[3]{% -\DTLmul{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii -} + \expandafter\global\expandafter + \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname + =\@dtl@foreachkey % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLdiv} -%\begin{definition} -% \cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} -%\end{definition} -% Sets \meta{cmd} = \meta{num1} / \meta{num2} +% Do body of loop % \begin{macrocode} -\newcommand*{\DTLdiv}[3]{% -\let\@dtl@thisreplaced=\@empty -\DTLconverttodecimal{#2}{\@dtl@numi}% -\ifx\@dtl@replaced\@empty -\else - \let\@dtl@thisreplaced=\@dtl@replaced -\fi -\DTLconverttodecimal{#3}{\@dtl@numii}% -\FPdiv{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% -\ifx\@dtl@thisreplaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \ifx\@dtl@thisreplaced\@dtl@replaced - \DTLdecimaltolocale{\@dtl@tmp}{#1}% - \else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + \@dtl@loopbody +% \end{macrocode} +% Set up what to do next +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@foreachnext + \csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname +% \end{macrocode} +% Restore break function +% \begin{macrocode} + \expandafter\let\expandafter\dtlbreak + \csname @dtl@break@\the\@dtl@foreach@level\endcsname +% \end{macrocode} +% Decrement level counter +% \begin{macrocode} + \global\advance\@dtl@foreach@level by -1\relax \fi -\fi -} % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgdiv} -% Global version +% Recurse if necessary % \begin{macrocode} -\newcommand*{\DTLgdiv}[3]{% -\DTLdiv{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii + \@dtl@foreachnext#6\@@{#7}\q@nil } % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLabs} +%\begin{macro}{\dtlforcolumn} %\begin{definition} -% \cs{DTLabs}\marg{cmd}\marg{num} +%\cs{dtlforcolumn}\marg{cs}\marg{db}\marg{key}\marg{body} %\end{definition} -% Sets \meta{cmd} = abs(\meta{num}) +% Iterates through column given by \meta{key} in database \meta{db}. +% \meta{cs} is assign to the element of the column in the +% current iteration. Starred version doesn't check if data base +% exists % \begin{macrocode} -\newcommand*{\DTLabs}[2]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\FPabs{\@dtl@tmp}{\@dtl@numi}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi -} +\newcommand*{\dtlforcolumn}{\@ifstar\@sdtlforcolumn\@dtlforcolumn} % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLgabs} -% Global version +% +%\begin{macro}{\@dtlforcolumn} % \begin{macrocode} -\newcommand*{\DTLgabs}[2]{% -\DTLabs{\@dtl@tmpii}{#2}% -\global\let#1=\@dtl@tmpii -} +\newcommand{\@dtlforcolumn}[4]{% % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLneg} -%\begin{definition} -% \cs{DTLneg}\marg{cmd}\marg{num} -%\end{definition} -% Sets \meta{cmd} = -\meta{num} +% Check if data base exists % \begin{macrocode} -\newcommand*{\DTLneg}[2]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\FPneg{\@dtl@tmp}{\@dtl@numi}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi + \DTLifdbexists{#2}% + {% + \@dtlifhaskey{#2}{#3}% + {% + \@sdtlforcolumn{#1}{#2}{#3}{#4}% + }% +% \end{macrocode} +% key not in data base +% \begin{macrocode} + {% + \PackageError{datatool}{Database `#2' doesn't contain + key `#3'}{}% + }% + }% +% + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% } % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLgneg} -% Global version +% +%\begin{macro}{\@sdtlforcolumn} % \begin{macrocode} -\newcommand*{\DTLgneg}[2]{% -\DTLneg{\@dtl@tmpii}{#2}% -\global\let#1=\@dtl@tmpii +\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% } -% \end{macrocode} +% end{macrocode} %\end{macro} % -%\begin{macro}{\DTLsqrt} +%\begin{macro}{\dtlforcolumnidx} %\begin{definition} -% \cs{DTLsqrt}\marg{cmd}\marg{num} +%\cs{dtlforcolumnidx}\marg{cs}\marg{db}\marg{col num}\marg{body} %\end{definition} -% Sets \meta{cmd} = sqrt(\meta{num}) +% Iterates through the column with index in database . +% Starred version doesn't check if database exists. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlforcolumnidx}{% + \@ifstar\@sdtlforcolumnidx\@dtlforcolumnidx +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlforcolumnidx} % \begin{macrocode} -\newcommand*{\DTLsqrt}[2]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\FProot{\@dtl@tmpi}{\@dtl@numi}{2}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmpi}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmpi}{#1}% -\fi +\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 + }% +% \end{macrocode} +% data base doesn't exist +% \begin{macrocode} + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% } % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLgsqrt} -% Global version +% +%\begin{macro}{\@sdtlforcolumnidx} % \begin{macrocode} -\newcommand*{\DTLgsqrt}[2]{% -\DTLsqrt{\@dtl@tmpii}{#2}% -\global\let#1=\@dtl@tmpii +\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 } -% \end{macrocode} +% \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLmin} +%\begin{macro}{\dtl@forcolumn} %\begin{definition} -% \cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} +%\cs{dtl@forcolumn}\marg{cs}\marg{db specs}\marg{col num}\marg{body} %\end{definition} -% Sets \meta{cmd} = min(\meta{num1}, \meta{num2}) +% \meta{col num} needs to be fully expanded % \begin{macrocode} -\newcommand*{\DTLmin}[3]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\DTLconverttodecimal{#3}{\@dtl@numii}% -\FPiflt{\@dtl@numi}{\@dtl@numii}% - \dtl@ifsingle{#2}{% - \let#1=#2}{% - \def#1{#2}}% -\else - \dtl@ifsingle{#3}{% - \let#1=#3}{% - \def#1{#3}}% -\fi +\newcommand{\dtl@forcolumn}[4]{% +% \end{macrocode} +% make a copy of break function +% \begin{macrocode} + \let\@dtl@oldbreak\dtlbreak +% \end{macrocode} +% set up break function +% \begin{macrocode} + \def\dtlbreak{\let\@dtl@forcolnext=\@dtl@forcolnoop}% +% \end{macrocode} +% define loop macro for this column +% \begin{macrocode} + \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 +% \end{macrocode} +% check if end of loop +% \begin{macrocode} + \ifx#1\@nnil + \let\@dtl@forcolnext=\@dtl@forcolnoop + \else +% \end{macrocode} +% do body of loop +% \begin{macrocode} + #4% + \let\@dtl@forcolnext=\@dtl@forcolumn + \fi +% \end{macrocode} +% repeat if necessary +% \begin{macrocode} + \@dtl@forcolnext##3\q@nil + }% +% \end{macrocode} +% do loop +% \begin{macrocode} + \@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 +% \end{macrocode} +% restore break function +% \begin{macrocode} + \let\dtlbreak\@dtl@oldbreak } % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLgmin} -% Global version +%\begin{macro}{\@dtl@forcolnoop} % \begin{macrocode} -\newcommand*{\DTLgmin}[3]{% -\DTLmin{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii -} +\def\@dtl@forcolnoop#1\q@nil{} % \end{macrocode} %\end{macro} -% -%\begin{macro}{\DTLminall} -%\begin{definition} -%\cs{DTLminall}\marg{cmd}\marg{num list} -%\end{definition} -% Finds the minimum value in \meta{num list} and stores in -% \meta{cmd} which must be a control sequence. -%\changes{1.01}{2007 Aug 17}{removed extraneous space} + +%\begin{macro}{\dtlforeachlevel} +%\cs{DTLforeach} can only be nested up to three levels. +% \cs{dtlforeachlevel} keeps track of the current level. % \begin{macrocode} -\newcommand*{\DTLminall}[2]{% -\let\@dtl@min=\@empty -\@for\dtl@thisval:=#2\do{% - \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% - \ifx\@dtl@min\@empty - \let\@dtl@min=\@dtl@num - \else - \FPmin{\@dtl@min}{\@dtl@min}{\@dtl@num}% - \fi -}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@min}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@min}{#1}% -\fi -} +\newcount\dtlforeachlevel % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLgminall} -%\begin{definition} -%\cs{DTLgminall}\marg{cmd}\marg{num list} -%\end{definition} -% Global version +% +% The counter DTLrow\meta{n} keeps track of each row of data during +% the \meta{n} nested \cs{DTLforeach}. It is only incremented in the +% conditions (given by the optional argument) are met. % \begin{macrocode} -\newcommand*{\DTLgminall}[2]{% -\DTLminall{\@dtl@tmpi}{#2}% -\global\let#1=\@dtl@tmpi -} +\newcounter{DTLrowi} +\newcounter{DTLrowii} +\newcounter{DTLrowiii} +% \end{macrocode} +% Keep \sty{hyperref} happy +% \begin{macrocode} +\newcounter{DTLrow} +\def\theHDTLrow{\arabic{DTLrow}} +\def\theHDTLrowi{\theHDTLrow.\arabic{DTLrowi}} +\def\theHDTLrowii{\theHDTLrowi.\arabic{DTLrowii}} +\def\theHDTLrowiii{\theHDTLrowii.\arabic{DTLrowiii}} % \end{macrocode} -%\end{macro} % -%\begin{macro}{\DTLmax} -%\begin{definition} -% \cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} -%\end{definition} -% Sets \meta{cmd} = max(\meta{num1}, \meta{num2}) % \begin{macrocode} -\newcommand*{\DTLmax}[3]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\DTLconverttodecimal{#3}{\@dtl@numii}% -\FPmax{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% -\FPifgt{\@dtl@numi}{\@dtl@numii}% - \dtl@ifsingle{#2}{% - \let#1=#2}{% - \def#1{#2}}% -\else - \dtl@ifsingle{#3}{% - \let#1=#3}{% - \def#1{#3}}% -\fi -} +\newcount\dtl@rowi +\newcount\dtl@rowii +\newcount\dtl@rowiii % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgmax} -% Global version +% % \begin{macrocode} -\newcommand*{\DTLgmax}[3]{% -\DTLmax{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii -} +\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 % \end{macrocode} -%\end{macro} % -%\begin{macro}{\DTLmaxall} +%\begin{macro}{\DTLsaverowcount} %\begin{definition} -%\cs{DTLmaxall}\marg{cmd}\marg{num list} +%\cs{DTLsavelastrowcount}\marg{cmd} %\end{definition} -% Finds the maximum value in \meta{num list} and stores in -% \meta{cmd} which must be a control sequence. -%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% Stores the maximum row count for the last \cs{DTLforeach}. % \begin{macrocode} -\newcommand*{\DTLmaxall}[2]{% -\let\@dtl@max=\@empty -\@for\dtl@thisval:=#2\do{% - \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% - \ifx\@dtl@max\@empty - \let\@dtl@max\@dtl@num +\newcommand*{\DTLsavelastrowcount}[1]{% +\ifnum\dtlforeachlevel>2\relax + \def#1{0}% +\else + \ifnum\dtlforeachlevel<0\relax + \def#1{0}% \else - \FPmax{\@dtl@max}{\@dtl@max}{\@dtl@num}% + \@dtl@tmpcount=\dtlforeachlevel + \advance\@dtl@tmpcount by 1\relax + \edef#1{\expandafter\number + \csname c@DTLrow\romannumeral\@dtl@tmpcount\endcsname}% \fi -}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@max}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@max}{#1}% -\fi -} +\fi} % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLgmaxall} +% +%\begin{macro}{\DTLforeach} %\begin{definition} -%\cs{DTLgmaxall}\marg{cmd}\marg{num list} +% \cs{DTLforeach}\oarg{conditions}\marg{db name}\marg{values}\marg{text} %\end{definition} -% Global version +% For each row of data in the database given by \meta{db name}, +% do \meta{text}, if the specified conditions are satisfied. +% The argument \marg{values} is a comma separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. At the start of each row, +% each of the commands in this list are set to the value of the +% entry with the corresponding key \meta{key}. +% (\cs{gdef} is used to ensure \cs{DTLforeach} works in a tabular +% environment.) The database may be edited in the unstarred +% version, in the starred version the database is read only. +%\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} -\newcommand*{\DTLgmaxall}[2]{% -\DTLmaxall{\@dtl@tmpi}{#2}% -\global\let#1=\@dtl@tmpi -} +\newcommand*{\DTLforeach}{\@ifstar\@sDTLforeach\@DTLforeach} % \end{macrocode} %\end{macro} % -%\begin{macro}{\DTLmeanforall} -%\begin{definition} -%\cs{DTLmeanforall}\marg{cmd}\marg{num list} -%\end{definition} -% Computes the arithmetic mean of all the values in \meta{num list} -% and stores in \meta{cmd} which must be a control sequence. -%\changes{1.01}{2007 Aug 17}{removed extraneous space} +%\begin{macro}{\@DTLforeach} +% \cs{@DTLforeach} is the unstarred version of \cs{DTLforeach}. +% The database is reconstructed to allow for rows to be edited. +% Use the starred version for faster access. +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} -\newcommand*{\DTLmeanforall}[2]{% -\def\@dtl@mean{0}% -\def\@dtl@n{0}% -\@for\dtl@thisval:=#2\do{% - \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% - \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% - \FPadd{\@dtl@n}{\@dtl@n}{1}% -}% -\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@mean}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@mean}{#1}% -\fi -} +\newcommand{\@DTLforeach}[4][\boolean{true}]{% % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgmeanforall} -%\begin{definition} -%\cs{DTLgmeanforall}\marg{cmd}\marg{num list} -%\end{definition} -% Global version +% Check database exists % \begin{macrocode} -\newcommand*{\DTLgmeanforall}[2]{% -\DTLmeanforall{\@dtl@tmpi}{#2}% -\global\let#1=\@dtl@tmpi -} + \DTLifdbexists{#2}% + {% % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLvarianceforall} -%\begin{definition} -%\cs{DTLvarianceforall}\marg{cmd}\marg{num list} -%\end{definition} -% Computes the variance of all the values in \meta{num list} -% and stores in \meta{cmd} which must be a control sequence. -%\changes{1.01}{2007 Aug 17}{fixed bug} -%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% Keep \sty{hyperref} happy % \begin{macrocode} -\newcommand*{\DTLvarianceforall}[2]{% -\def\@dtl@mean{0}% -\def\@dtl@n{0}% -\let\@dtl@decvals=\@empty -\@for\dtl@thisval:=#2\do{% - \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% - \ifx\@dtl@decvals\@empty - \let\@dtl@decvals=\@dtl@num - \else - \expandafter\toks@\expandafter{\@dtl@decvals}% - \edef\@dtl@decvals{\the\toks@,\@dtl@num}% - \fi - \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% - \FPadd{\@dtl@n}{\@dtl@n}{1}% -}% -\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% -\def\@dtl@var{0}% -\@for\@dtl@num:=\@dtl@decvals\do{% - \FPsub{\@dtl@diff}{\@dtl@num}{\@dtl@mean}% - \FPmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% - \FPadd{\@dtl@var}{\@dtl@var}{\@dtl@diff}% -}% -\FPdiv{\@dtl@var}{\@dtl@var}{\@dtl@n}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@var}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@var}{#1}% -\fi -} + \refstepcounter{DTLrow}% % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgvarianceforall} -%\begin{definition} -%\cs{DTLgvarianceforall}\marg{cmd}\marg{num list} -%\end{definition} -% Global version +% Make it global (so that it works in tabular environment) % \begin{macrocode} -\newcommand*{\DTLgvarianceforall}[2]{% -\DTLvarianceforall{\@dtl@tmpi}{#2}% -\global\let#1=\@dtl@tmpi -} + \global\c@DTLrow=\c@DTLrow\relax % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLsdforall} -%\begin{definition} -%\cs{DTLsdforall}\marg{cmd}\marg{num list} -%\end{definition} -% Computes the standard deviation of all the values in \meta{num list} -% and stores in \meta{cmd} which must be a control sequence. -%\changes{1.01}{2007 Aug 17}{fixed bug} -%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% Store database name % \begin{macrocode} -\newcommand*{\DTLsdforall}[2]{% -\def\@dtl@mean{0}% -\def\@dtl@n{0}% -\let\@dtl@decvals=\@empty -\@for\dtl@thisval:=#2\do{% - \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% - \ifx\@dtl@decvals\@empty - \let\@dtl@decvals=\@dtl@num - \else - \expandafter\toks@\expandafter{\@dtl@decvals}% - \edef\@dtl@decvals{\the\toks@,\@dtl@num}% - \fi - \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% - \FPadd{\@dtl@n}{\@dtl@n}{1}% -}% -\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% -\def\@dtl@sd{0}% -\@for\@dtl@num:=\@dtl@decvals\do{% - \FPsub{\@dtl@diff}{\@dtl@num}{\@dtl@mean}% - \FPmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% - \FPadd{\@dtl@sd}{\@dtl@sd}{\@dtl@diff}% -}% -\FPdiv{\@dtl@sd}{\@dtl@sd}{\@dtl@n}% -\FProot{\@dtl@sd}{\@dtl@sd}{2}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@sd}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@sd}{#1}% -\fi -} + \gdef\@dtl@dbname{#2}% % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgsdforall} -%\begin{definition} -%\cs{DTLgsdforall}\marg{cmd}\marg{num list} -%\end{definition} -% Global version +% Increment level and check not exceeded 3 % \begin{macrocode} -\newcommand*{\DTLgsdforall}[2]{% -\DTLsdforall{\@dtl@tmpi}{#2}% -\global\let#1=\@dtl@tmpi -} + \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}% % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLround} -%\begin{definition} -% \cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} -%\end{definition} -% Sets \meta{cmd} to \meta{num} rounded to \meta{num digits} -% digits after the decimal character. +% Do nothing if database is empty % \begin{macrocode} -\newcommand*{\DTLround}[3]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\FPround{\@dtl@tmp}{\@dtl@numi}{#3}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi -} + {}% + {% % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLground} -% Global version +% Set level dependent information (needs to be global to ensure +% it works in the \env{tabular} environment). Row counter: % \begin{macrocode} -\newcommand*{\DTLground}[3]{% -\DTLround{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii -} + \expandafter\global + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + = 0\relax % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLtrunc} -%\begin{definition} -% \cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} -%\end{definition} -% Sets \meta{cmd} to \meta{num} truncated to \meta{num digits} -% digits after the decimal character. +% Store previous value of \cs{DTLiffirstrow} % \begin{macrocode} -\newcommand*{\DTLtrunc}[3]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\FPtrunc{\@dtl@tmp}{\@dtl@numi}{#3}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi -} + \expandafter\global\expandafter\let% + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname + \DTLiffirstrow % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgtrunc} -% Global version +% Define current \cs{DTLiffirstrow} % \begin{macrocode} -\newcommand*{\DTLgtrunc}[3]{% -\DTLtrunc{\@dtl@tmpii}{#2}{#3}% -\global\let#1=\@dtl@tmpii -} + \gdef\DTLiffirstrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =1\relax + ##1% + \else + ##2% + \fi}% % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLclip} -%\begin{definition} -% \cs{DTLclip}\marg{cmd}\marg{num} -%\end{definition} -% Sets \meta{cmd} to \meta{num} with all unnecessary 0's removed. +% Store previous value of \cs{DTLiflastrow} % \begin{macrocode} -\newcommand*{\DTLclip}[2]{% -\DTLconverttodecimal{#2}{\@dtl@numi}% -\FPclip{\@dtl@tmp}{\@dtl@numi}% -\ifx\@dtl@replaced\@empty - \DTLdecimaltolocale{\@dtl@tmp}{#1}% -\else - \DTLdecimaltocurrency{\@dtl@tmp}{#1}% -\fi -} + \expandafter\global\expandafter\let% + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname + \DTLiflastrow % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLgclip} -% Global version +% Define current \cs{DTLiflastrow} % \begin{macrocode} -\newcommand*{\DTLgclip}[3]{% -\DTLclip{\@dtl@tmpii}{#2}% -\global\let#1=\@dtl@tmpii -} + \gdef\DTLiflastrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =\csname dtlcols@#2\endcsname\relax + ##1% + \else + ##2% + \fi}% % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLinitials} -%\subsection{String Macros} -%\begin{definition} -%\cs{DTLinitials}\marg{string} -%\end{definition} -% Convert a string into initials. -% (Any "~" character found is first converted into a space.) -%\changes{1.01}{2007 Aug 17}{now works with unbreakable space symbol} -%\changes{1.01}{2007 Aug 17}{now uses \cs{DTLinitialhyphen}} +% Store previous value of \cs{DTLifoddrow} % \begin{macrocode} -\newcommand*\DTLinitials[1]{% -\def\dtl@initialscmd{}% -\dtl@subnobrsp{#1}{\dtl@string}% -\DTLsubstituteall{\dtl@string}{~}{ }% -\DTLsubstituteall{\dtl@string}{\ }{ }% -\DTLsubstituteall{\dtl@string}{\space}{ }% -\expandafter\dtl@initials\dtl@string{} \@nil% -\dtl@initialscmd}% + \expandafter\global\expandafter\let% + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + \DTLifoddrow % \end{macrocode} -%\end{macro} -% The following substitutes "\protect \nobreakspace {}" with -% a space. (Note that in this case the space following -% "\nobreakspace" forms part of the command.) +% Define current \cs{DTLifoddrow} % \begin{macrocode} -\edef\dtl@construct@subnobrsp{% -\noexpand\def\noexpand\@dtl@subnobrsp##1\noexpand\protect -\expandafter\noexpand\csname nobreakspace \endcsname ##2{% -\noexpand\toks@{##1}% -\noexpand\expandafter\noexpand\@dtl@toks\noexpand\expandafter{% -\noexpand\@dtl@string}% -\noexpand\edef\noexpand\@dtl@string{\noexpand\the\noexpand\@dtl@toks -\noexpand\the\noexpand\toks@}% -\noexpand\def\noexpand\@dtl@tmp{##2}% -\noexpand\ifx\noexpand\@dtl@tmp\noexpand\@nnil - \noexpand\let\noexpand\@dtl@subnobrspnext=\noexpand\relax -\noexpand\else - \noexpand\toks@{ }% - \noexpand\expandafter\noexpand\@dtl@toks\noexpand\expandafter{% - \noexpand\@dtl@string}% - \noexpand\edef\noexpand\@dtl@string{\noexpand\the\noexpand\@dtl@toks - \noexpand\the\noexpand\toks@}% - \noexpand\let\noexpand\@dtl@subnobrspnext=\noexpand\@dtl@subnobrsp -\noexpand\fi -\noexpand\@dtl@subnobrspnext -}% -\noexpand\def\noexpand\dtl@subnobrsp##1##2{% -\noexpand\def\noexpand\@dtl@string{}% -\noexpand\@dtl@subnobrsp ##1\noexpand\protect\expandafter\noexpand -\csname nobreakspace \endcsname \noexpand\@nil -\noexpand\let##2=\noexpand\@dtl@string -}} -\dtl@construct@subnobrsp + \gdef\DTLifoddrow##1##2{% + \expandafter\ifodd + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + ##1% + \else + ##2% + \fi}% % \end{macrocode} -% -%\begin{macro}{\DTLstoreinitials} -%\begin{definition} -%\cs{DTLstoreinitials}\marg{string}\marg{cmd} -%\end{definition} -% Convert a string into initials and store in \meta{cmd}. -% (Any "~" character found is first converted into a space.) -%\changes{1.01}{2007 Aug 17}{now works with unbreakable space symbol} -%\changes{1.01}{2007 Aug 17}{now uses \cs{DTLinitialhyphen}} +% Store data base name for current level % \begin{macrocode} -\newcommand*{\DTLstoreinitials}[2]{% -\def\dtl@initialscmd{}% -\dtl@subnobrsp{#1}{\dtl@string}% -\DTLsubstituteall{\dtl@string}{~}{ }% -\DTLsubstituteall{\dtl@string}{\ }{ }% -\DTLsubstituteall{\dtl@string}{\space}{ }% -\expandafter\dtl@initials\dtl@string{} \@nil -\let#2=\dtl@initialscmd -} + \expandafter\global\expandafter\let + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname + =\@dtl@dbname % \end{macrocode} -%\end{macro} -%\begin{macro}{\dtl@initials} +% Mark it as not read only % \begin{macrocode} -\def\dtl@initials#1#2 #3{% -\dtl@ifsingle{#1}{% -\ifcat\noexpand#1\relax\relax - \def\@dtl@donextinitials{\@dtl@initials#2 {#3}}% -\else - \def\@dtl@donextinitials{\@dtl@initials#1#2 {#3}}% -\fi -}{% - \def\@dtl@donextinitials{\@dtl@initials{#1}#2 {#3}}% -}% -\@dtl@donextinitials -} + \expandafter\global\expandafter\let + \csname @dtl@ro@\romannumeral\dtlforeachlevel\endcsname + = 0\relax % \end{macrocode} -%\end{macro} -%\begin{macro}{\@dtl@initials} +% Loop through each row. +% Loop counter given by \cs{dtl@row@}\meta{level} % \begin{macrocode} -\def\@dtl@initials#1#2 #3{% -\dtl@initialshyphen#2-{}\dtl@endhyp -\expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% -\toks@{#1}% -\ifx\dtl@inithyphen\@empty -\else - \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@}% - \expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% - \expandafter\toks@\expandafter{\dtl@inithyphen}% -\fi -\def\dtl@tmp{#3}% -\ifx\@nnil\dtl@tmp - \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLafterinitials}% - \let\dtl@initialsnext=\@gobble -\else - \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLbetweeninitials}% - \let\dtl@initialsnext=\dtl@initials -\fi -\dtl@initialsnext{#3}} + \dtlgforint + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname + =1\to\csname dtlrows@#2\endcsname\step1\do + {% % \end{macrocode} -%\end{macro} -%\begin{macro}{\dtl@initialshyphen} +% Get current row from the data base % \begin{macrocode} -\def\dtl@initialshyphen#1-#2#3\dtl@endhyp{% -\def\dtl@inithyphen{#2}% -\ifx\dtl@inithyphen\@empty -\else - \edef\dtl@inithyphen{% - \DTLafterinitialbeforehyphen\DTLinitialhyphen#2}% -\fi -} + \@dtl@tmpcount= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname + \edef\dtl@dogetrow{\noexpand\dtlgetrow{#2}% + {\number\@dtl@tmpcount}}% + \dtl@dogetrow % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLafterinitials} -% Defines what to do after the final initial. +% Store the current row for this level % \begin{macrocode} -\newcommand*{\DTLafterinitials}{.} + \expandafter\global + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + = \dtlcurrentrow % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLbetweeninitials} -% Defines what to do between initials. +% Store the previous rows for this level % \begin{macrocode} -\newcommand*{\DTLbetweeninitials}{.} + \expandafter\global + \csname @dtl@prev\romannumeral\dtlforeachlevel\endcsname + = \dtlbeforerow % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLafterinitialbeforehyphen} -% Defines what to do before a hyphen. +% Store the subsequent rows for this level % \begin{macrocode} -\newcommand*{\DTLafterinitialbeforehyphen}{.} + \expandafter\global + \csname @dtl@next\romannumeral\dtlforeachlevel\endcsname + = \dtlafterrow % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLinitialhyphen} -%Defines what to do at the hyphen -%\changes{1.01}{2007 Aug 17}{new} +% Assign commands to the required entries % \begin{macrocode} -\newcommand*{\DTLinitialhyphen}{-} + \ifx\relax#3\relax + \else + \@dtl@assign{#3}{#2}% + \fi % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLifAllUpperCase} -%\begin{definition} -%\cs{DTLifAllUpperCase}\marg{string}\marg{true part}\marg{false part} -%\end{definition} -% If \meta{string} only contains uppercase characters do \meta{true -%part}, otherwise do \meta{false part}. +% Do the main body of text if condition is satisfied % \begin{macrocode} -\newcommand*{\DTLifAllUpperCase}[3]{% -\protected@edef\dtl@tuc{#1}% -\expandafter\dtl@testifuppercase\dtl@tuc\@nil\relax -\if@dtl@condition#2\else#3\fi -} + \ifthenelse{#1}% + {% +% \end{macrocode} +% Increment user row counter +% \begin{macrocode} + \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% + \expandafter\edef\expandafter\DTLcurrentindex% + \expandafter{% + \arabic{DTLrow\romannumeral\dtlforeachlevel}}% + #4% +% \end{macrocode} +% Has this row been marked for deletion? +% \begin{macrocode} + \edef\@dtl@tmp{\expandafter\the + \csname @dtl@cur\romannumeral + \dtlforeachlevel\endcsname}% + \ifx\@dtl@tmp\@nnil +% \end{macrocode} +% Row needs to be deleted +% Decrement row indices for rows with a higher index than this one +% \begin{macrocode} + \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}% +% \end{macrocode} +% Reconstruct data base without this row +% \begin{macrocode} + \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}% +% \end{macrocode} +% Decrement the row count for this database: +% \begin{macrocode} + \expandafter\global\expandafter + \advance\csname dtlrows@#2\endcsname by -1\relax +% \end{macrocode} +% Decrement the counter for this loop +% \begin{macrocode} + \expandafter\global\expandafter + \advance\csname dtl@row\romannumeral + \dtlforeachlevel\endcsname by -1\relax + \else % \end{macrocode} -%\end{macro} -%\begin{macro}{\dtl@testifalluppercase} +% Reconstruct data base +% \begin{macrocode} + \@dtl@before=\csname @dtl@prev\romannumeral + \dtlforeachlevel\endcsname + \@dtl@after=\csname @dtl@next\romannumeral + \dtlforeachlevel\endcsname + \toks@gconcat@middle@cx{dtldb@#2}% + {\@dtl@before}% + {% +% \end{macrocode} +% This row +% \begin{macrocode} + \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 + }% +% \end{macrocode} +% Condition not met so ignore % \begin{macrocode} -\def\dtl@testifuppercase#1#2{% -\def\dtl@argi{#1}% -\def\dtl@argii{#2}% -\def\dtl@tc@rest{}% -\ifx\dtl@argi\@nnil - \let\dtl@testifuppernext=\@nnil -\else - \ifx#1\protect - \let\dtl@testifuppernext=\dtl@testifuppercase - \else - \ifx\uppercase#1\relax - \@dtl@conditiontrue - \def\dtl@tc@rest{}% - \let\dtl@testifuppernext=\relax - \else - \edef\dtl@tc@arg{\string#1}% - \expandafter\dtl@test@ifuppercase\dtl@tc@arg\end - \ifx\dtl@argii\@nnil - \let\dtl@testifuppernext=\@dtl@gobbletonil - \fi + {}% + }% +% \end{macrocode} +% Restore previous value of \cs{DTLiffirstrow} +% \begin{macrocode} + \expandafter\global\expandafter\let\expandafter\DTLiffirstrow + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname +% \end{macrocode} +% Restore previous value of \cs{DTLiflastrow} +% \begin{macrocode} + \expandafter\global\expandafter\let\expandafter\DTLiflastrow + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname +% \end{macrocode} +% Restore previous value of \cs{DTLifoddrow} +% \begin{macrocode} + \expandafter\global\expandafter\let\expandafter\DTLifoddrow + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + }% \fi - \fi -\fi -\ifx\dtl@testifuppernext\relax - \edef\dtl@dotestifuppernext{% - \noexpand\dtl@testifuppercase}% -\else - \ifx\dtl@testifuppernext\@nnil - \edef\dtl@dotestifuppernext{#2}% - \else - \expandafter\toks@\expandafter{\dtl@tc@rest}% - \@dtl@toks{#2}% - \edef\dtl@dotestifuppernext{% - \noexpand\dtl@testifuppernext\the\toks@\the\@dtl@toks}% - \fi -\fi -\dtl@dotestifuppernext +% \end{macrocode} +% Decrement level +% \begin{macrocode} + \global\advance\dtlforeachlevel by -1\relax + }% +% \end{macrocode} +% else part (data base doesn't exist): +% \begin{macrocode} + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% } % \end{macrocode} %\end{macro} -%\begin{macro}{\dtl@test@ifalluppercase} +% +%\begin{macro}{\@sDTLforeach} +% \cs{@sDTLforeach} is the starred version of \cs{DTLforeach}. +% The database rows can't be edited. +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} -\def\dtl@test@ifuppercase#1#2\end{% -\def\dtl@tc@rest{#2}% -\IfSubStringInString{\string\MakeUppercase}{#1#2}{% - \@dtl@conditiontrue - \def\dtl@tc@rest{}% - \let\dtl@testifuppernext=\relax -}{% - \IfSubStringInString{\string\MakeTextUppercase}{#1#2}{% - \@dtl@conditiontrue - \def\dtl@tc@rest{}% - \let\dtl@testifuppernext=\relax - }{% - \edef\dtl@uccode{\the\uccode`#1}% - \edef\dtl@code{\number`#1}% - \ifnum\dtl@code=\dtl@uccode\relax - \@dtl@conditiontrue - \let\dtl@testifuppernext=\dtl@testifuppercase - \else - \ifnum\dtl@uccode=0\relax - \@dtl@conditiontrue - \let\dtl@testifuppernext=\dtl@testifuppercase +\newcommand{\@sDTLforeach}[4][\boolean{true}]{% +% \end{macrocode} +% Check database exists +% \begin{macrocode} + \DTLifdbexists{#2}% + {% +% \end{macrocode} +% Keep \sty{hyperref} happy +% \begin{macrocode} + \refstepcounter{DTLrow}% +% \end{macrocode} +% Make it global (so that it works in tabular environment) +% \begin{macrocode} + \global\c@DTLrow=\c@DTLrow +% \end{macrocode} +% Increment level and check not exceeded 3 +% \begin{macrocode} + \global\advance\dtlforeachlevel by 1\relax + \ifnum\dtlforeachlevel>3\relax + \PackageError{datatool}{\string\DTLforeach\space nested too + deeply}{Only 3 levels are allowed}% \else - \@dtl@conditionfalse - \let\dtl@testifuppernext=\@dtl@gobbletonil + \@DTLifdbempty{#2}% +% \end{macrocode} +% Do nothing if database is empty +% \begin{macrocode} + {}% + {% +% \end{macrocode} +% Set level dependent information (needs to be global to ensure +% it works in the \env{tabular} environment). Row counter: +% \begin{macrocode} + \expandafter\global + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + = 0\relax +% \end{macrocode} +% Store previous value of \cs{DTLiffirstrow} +% \begin{macrocode} + \expandafter\global\expandafter\let% + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname + \DTLiffirstrow +% \end{macrocode} +% Define current \cs{DTLiffirstrow} +% \begin{macrocode} + \gdef\DTLiffirstrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =1\relax + ##1% + \else + ##2% + \fi}% +% \end{macrocode} +% Store previous value of \cs{DTLiflastrow} +% \begin{macrocode} + \expandafter\global\expandafter\let% + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname + \DTLiflastrow +% \end{macrocode} +% Define current \cs{DTLiflastrow} +% \begin{macrocode} + \gdef\DTLiflastrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =\csname dtlcols@#2\endcsname\relax + ##1% + \else + ##2% + \fi}% +% \end{macrocode} +% Store previous value of \cs{DTLifoddrow} +% \begin{macrocode} + \expandafter\global\expandafter\let% + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + \DTLifoddrow +% \end{macrocode} +% Define current \cs{DTLifoddrow} +% \begin{macrocode} + \gdef\DTLifoddrow##1##2{% + \expandafter\ifodd + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + ##1% + \else + ##2% + \fi}% +% \end{macrocode} +% Store data base name for current level +% \begin{macrocode} + \expandafter\gdef\csname @dtl@dbname@\romannumeral + \dtlforeachlevel\endcsname{#2}% +% \end{macrocode} +% Mark it as read only +% \begin{macrocode} + \expandafter\global\expandafter\let + \csname @dtl@ro@\romannumeral\dtlforeachlevel\endcsname + = 1\relax +% \end{macrocode} +% Iterate through each row. +% \begin{macrocode} + \@dtlforeachrow(\dtl@thisidx,\dtl@thisrow)\in{#2}\do% + {% +% \end{macrocode} +% Assign row number (not sure if this is needed here) +% \begin{macrocode} + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname + = \dtl@thisidx\relax +% \end{macrocode} +% Store the current row specs for this level +% \begin{macrocode} + \expandafter\global + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + = \expandafter{\dtl@thisrow}% +% \end{macrocode} +% Assign commands to the required entries +% \begin{macrocode} + \ifx\relax#3\relax + \else +% \end{macrocode} +% Need to set \cs{dtlcurrentrow} for \cs{@dtl@assign} +% \begin{macrocode} + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \@dtl@assign{#3}{#2}% + \fi +% \end{macrocode} +% Do the main body of text if condition is satisfied +% \begin{macrocode} + \ifthenelse{#1}% + {% +% \end{macrocode} +% Increment user row counter +% \begin{macrocode} + \refstepcounter{DTLrow\romannumeral\dtlforeachlevel}% + \expandafter\edef\expandafter\DTLcurrentindex% + \expandafter{% + \arabic{DTLrow\romannumeral\dtlforeachlevel}}% + #4% + }% +% \end{macrocode} +% Condition not met so ignore +% \begin{macrocode} + {}% + }% +% \end{macrocode} +% Restore previous value of \cs{DTLiffirstrow} +% \begin{macrocode} + \expandafter\global\expandafter\let\expandafter\DTLiffirstrow + \csname @dtl@iffirstrow\the\dtlforeachlevel\endcsname +% \end{macrocode} +% Restore previous value of \cs{DTLiflastrow} +% \begin{macrocode} + \expandafter\global\expandafter\let\expandafter\DTLiflastrow + \csname @dtl@iflastrow\the\dtlforeachlevel\endcsname +% \end{macrocode} +% Restore previous value of \cs{DTLifoddrow} +% \begin{macrocode} + \expandafter\global\expandafter\let\expandafter\DTLifoddrow + \csname @dtl@ifoddrow\the\dtlforeachlevel\endcsname + }% \fi - \fi -}}} +% \end{macrocode} +% Decrement level +% \begin{macrocode} + \global\advance\dtlforeachlevel by -1\relax + }% +% \end{macrocode} +% else part (data base doesn't exist): +% \begin{macrocode} + {% + \PackageError{datatool}{Database `#2' doesn't exist}{}% + }% +} % \end{macrocode} %\end{macro} -%\begin{macro}{\DTLifAllLowerCase} +% +%\begin{macro}{\@dtlifreadonly} %\begin{definition} -%\cs{DTLifAllLowerCase}\marg{string}\marg{true part}\marg{false part} +%\cs{@dtlifreadonly}\marg{true part}\marg{false part} %\end{definition} -% If \meta{string} only contains lowercase characters do \meta{true -%part}, otherwise do \meta{false part}. +% Checks if current loop level is read only +%\changes{2.0}{2009 February 27}{new} % \begin{macrocode} -\newcommand*{\DTLifAllLowerCase}[3]{% -\protected@edef\dtl@tlc{#1}% -\expandafter\dtl@testiflowercase\dtl@tlc\@nil\relax -\if@dtl@condition#2\else#3\fi +\newcommand*{\@dtlifreadonly}[2]{% + \expandafter\ifx + \csname @dtl@ro@\romannumeral\dtlforeachlevel\endcsname1\relax +% \end{macrocode} +% Read only +% \begin{macrocode} + #1% + \else +% \end{macrocode} +% Not read only +% \begin{macrocode} + #2% + \fi } % \end{macrocode} %\end{macro} -%\begin{macro}{\dtl@testifalllowercase} +% +%\begin{macro}{\DTLappendtorow} +%\begin{definition} +%\cs{DTLappendtorow}\marg{key}\marg{value} +%\end{definition} +% Appends entry to current row. (The current row is given by +% \cs{@dtl@cur}\meta{n} where \meta{n} is roman +% numeral value of \cs{dtlforeachlevel}. +% One level expansion is applied to \meta{value}. +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} -\def\dtl@testiflowercase#1#2{% -\def\dtl@argi{#1}% -\def\dtl@argii{#2}% -\ifx\dtl@argi\@nnil - \let\dtl@testiflowernext=\@nnil -\else - \ifx#1\protect - \let\dtl@testiflowernext=\dtl@testiflowercase +\newcommand*{\DTLappendtorow}[2]{% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLappendrow\space can only be + used inside \string\DTLforeach}{}% \else - \ifx\lowercase#1\relax - \@dtl@conditiontrue - \def\dtl@tc@rest{}% - \let\dtl@testiflowernext=\relax - \else - \edef\dtl@tc@arg{\string#1}% - \expandafter\dtl@test@iflowercase\dtl@tc@arg\end - \ifx\dtl@argii\@nnil - \let\dtl@testiflowernext=\@dtl@gobbletonil +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Check this isn't in \cs{DTLforeach*} +% \begin{macrocode} + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLappendtorow\space can't + be used inside \DTLforeach*}{The starred version of + \string\DTLforeach\space is read only}% + }% + {% +% \end{macrocode} +% Store current row number in \cs{dtlrownum} +% \begin{macrocode} + \dtlrownum= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname\relax +% \end{macrocode} +% Update information about this column (adding new column if +% necessary) +% \begin{macrocode} + \@dtl@updatekeys{\@dtl@thisdb}{#1}{#2}% +% \end{macrocode} +% Get column index and store in \cs{dtlcolumnnum} +% \begin{macrocode} + \expandafter\dtlcolumnnum\expandafter + =\dtl@columnindex{\@dtl@thisdb}{#1}\relax +% \end{macrocode} +% Set \cs{dtlcurrentrow} to the current row +% \begin{macrocode} + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Does this row already have an entry with this key? +% \begin{macrocode} + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% + }% + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue +% \end{macrocode} +% There are no entries in this row for the given key. +% Store value in \cs{@dtl@toks} with one level expansion. +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{#2}% +% \end{macrocode} +% Append this entry to the current row. +% \begin{macrocode} + \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@ + }% +% \end{macrocode} +% Print information to terminal and log file if in verbose mode. +% \begin{macrocode} + \dtl@message{Appended #1\space -> #2\space to database + `\@dtl@thisdb'}% + \else +% \end{macrocode} +% There is already an entry in this row for the given key +% \begin{macrocode} + \PackageError{datatool}{Can't append entry to row: + there is already an entry for key `#1' in this row}{}% \fi - \fi + }% \fi -\fi -\ifx\dtl@testiflowernext\relax - \edef\dtl@dotestiflowernext{% - \noexpand\dtl@testiflowercase}% -\else - \ifx\dtl@testiflowernext\@nnil - \edef\dtl@dotestiflowernext{#2}% - \else - \expandafter\toks@\expandafter{\dtl@tc@rest}% - \@dtl@toks{#2}% - \edef\dtl@dotestiflowernext{% - \noexpand\dtl@testiflowernext\the\toks@\the\@dtl@toks}% - \fi -\fi -\dtl@dotestiflowernext } % \end{macrocode} %\end{macro} -%\begin{macro}{\dtl@test@ifalllowercase} +% +%\begin{macro}{\DTLremoveentryfromrow} +%\begin{definition} +%\cs{DTLremoveentryfromrow}\marg{key} +%\end{definition} +% Removes entry given by \meta{key} from current row. +% (The current row is given by +% \cs{@dtl@cur}\meta{n} where \meta{n} is roman +% numeral value of \cs{dtlforeachlevel}. +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} -\def\dtl@test@iflowercase#1#2\end{% -\def\dtl@tc@rest{#2}% -\IfSubStringInString{\string\MakeLowercase}{#1#2}{% - \@dtl@conditiontrue - \def\dtl@tc@rest{}% - \let\dtl@testiflowernext=\relax -}{% - \IfSubStringInString{\string\MakeTextLowercase}{#1#2}{% - \@dtl@conditiontrue - \def\dtl@tc@rest{}% - \let\dtl@testiflowernext=\relax - }{% - \edef\dtl@lccode{\the\lccode`#1}% - \edef\dtl@code{\number`#1}% - \ifnum\dtl@code=\dtl@lccode\relax - \@dtl@conditiontrue - \let\dtl@testiflowernext=\dtl@testiflowercase +\newcommand*{\DTLremoveentryfromrow}[1]{% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLremoventryfromrow\space + can only be used inside \string\DTLforeach}{}% \else - \ifnum\dtl@lccode=0\relax - \@dtl@conditiontrue - \let\dtl@testiflowernext=\dtl@testiflowercase +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Check this isn't in \cs{DTLforeach*} +% \begin{macrocode} + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLremoveentryfromrow\space + can't be used inside \string\DTLforeach*}{The starred + version of \string\DTLforeach\space is read only}% + }% + {% +% \end{macrocode} +% Store current row number in \cs{dtlrownum} +% \begin{macrocode} + \dtlrownum= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname\relax +% \end{macrocode} +% Is there a column corresponding to this key? +% \begin{macrocode} + \@dtlifhaskey{\@dtl@thisdb}{#1}% + {% +% \end{macrocode} +% There exists a column for this key, so get the index: +% \begin{macrocode} + \dtl@getcolumnindex{\thiscol}{\@dtl@thisdb}{#1}\relax + \dtlcolumnnum=\thiscol\relax +% \end{macrocode} +% Set \cs{dtlcurrentrow} to the current row +% \begin{macrocode} + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Does this row have an entry with this key? +% \begin{macrocode} + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% + }% + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue +% \end{macrocode} +% This row doesn't contain an entry with this key +% \begin{macrocode} + \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 +% \end{macrocode} +% Split the current row around the unwanted entry +% \begin{macrocode} + \edef\@dtl@dosplitrow{% + \noexpand\dtlsplitrow{\the\dtlcurrentrow}% + {\number\dtlcolumnnum}{\noexpand\dtl@pre}% + {\noexpand\dtl@post}% + }% + \@dtl@dosplitrow +% \end{macrocode} +% Reconstruct row without unwanted entry +% \begin{macrocode} + \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 +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLreplaceentryforrow} +%\begin{definition} +%\cs{DTLreplaceentryforrow}\marg{key}\marg{value} +%\end{definition} +% Replaces entry given by \meta{key} in current row with +% \meta{value}. +% (The current row is given by the token register +% \cs{@dtl@cur}\meta{n} where \meta{n} is roman +% numeral value of \cs{dtlforeachlevel}. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\DTLreplaceentryforrow}[2]{% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLreplaceentryforrow\space + can only be used inside \string\DTLforeach}{}% + \else +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Check this isn't in \cs{DTLforeach*} +% \begin{macrocode} + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLreplaceentryforrow\space + can't be used inside \string\DTLforeach*}{The starred version + of \string\DTLforeach\space is read only}% + }% + {% +% \end{macrocode} +% Store current row number in \cs{dtlrownum} +% \begin{macrocode} + \dtlrownum= + \csname dtl@row\romannumeral\dtlforeachlevel\endcsname\relax +% \end{macrocode} +% Is there a column corresponding to this key? +% \begin{macrocode} + \@dtlifhaskey{\@dtl@thisdb}{#1}% + {% +% \end{macrocode} +% There exists a column for this key, so get the index: +% \begin{macrocode} + \dtl@getcolumnindex{\thiscol}{\@dtl@thisdb}{#1}\relax + \dtlcolumnnum=\thiscol\relax +% \end{macrocode} +% Set \cs{dtlcurrentrow} to the current row +% \begin{macrocode} + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Does this row have an entry with this key? +% \begin{macrocode} + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\dtl@entry}{\number\dtlcolumnnum}% + }% + \dtl@dogetentry + \ifx\dtl@entry\dtlnovalue +% \end{macrocode} +% This row doesn't contain an entry with this key +% \begin{macrocode} + \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 +% \end{macrocode} +% Split the current row around the requested entry +% \begin{macrocode} + \edef\@dtl@dosplitrow{% + \noexpand\dtlsplitrow{\the\dtlcurrentrow}% + {\number\dtlcolumnnum}{\noexpand\dtl@pre}% + {\noexpand\dtl@post}% + }% + \@dtl@dosplitrow +% \end{macrocode} +% Reconstruct row with new entry +% \begin{macrocode} + \@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}% +% \end{macrocode} +% Print information to terminal and log file if in verbose mode. +% \begin{macrocode} + \dtl@message{Updated #1\space -> #2\space in database + `\@dtl@thisdb'}% + \fi + }% + {% +% \end{macrocode} +% There doesn't exist a column for this key. +% \begin{macrocode} + \PackageError{datatool}{Can't replace key `#1' - no such + key in database `\@dtl@thisdb'}{}% + }% + }% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLremovecurrentrow} +%\begin{definition} +%\cs{DTLremovecurrentrow} +%\end{definition} +% Removes current row. This just sets the current row to empty +%\changes{1.01}{2007 Aug 17}{fix bug caused by missing \cs{fi} +% and unrequired argument} +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\DTLremovecurrentrow}{% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLremovecurrentrow\space can + only be used inside \string\DTLforeach}{}% + \else +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Check this isn't in \cs{DTLforeach*} +% \begin{macrocode} + \@dtlifreadonly + {% + \PackageError{datatool}{\string\DTLreplaceentryforrow\space + can't be used inside \string\DTLforeach*}{The starred version + of \string\DTLforeach\space is read only}% + }% + {% +% \end{macrocode} +% Set the current row to \cs{@nil} (\cs{DTLforeach} needs to check +% for this) +% \begin{macrocode} + \expandafter\global + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname + ={\@nil}% + }% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLaddentryforrow} +%\begin{definition} +%\cs{DTLaddentryforrow}\marg{db name}\marg{assign list}\marg{condition}\marg{key}\marg{value} +%\end{definition} +% Adds the entry with key given by \meta{key} and value given by +% \meta{value} to the first row in the database \meta{db name} +% which satisfies the condition given by \meta{condition}. The +% \meta{assign list} is the same as for \cs{DTLforeach} and may +% be used to set the values which are to be tested in \meta{condition}. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand{\DTLaddentryforrow}[5]{% +% \end{macrocode} +% Iterate through the data base until condition is met +% \begin{macrocode} + \DTLifdbexists{#1}% + { + \def\@dtl@notdone{\PackageError{datatool}{Unable to add entry + given by key `#4': condition not met for any row in database + `#1'}{}}% +% \end{macrocode} +% Iterate through each row +% \begin{macrocode} + \DTLforeach[#3]{#1}{#2}% + {% +% \end{macrocode} +% add entry to this row +% \begin{macrocode} + \DTLappendtorow{#4}{#5}% +% \end{macrocode} +% disable error message +% \begin{macrocode} + \let\@dtl@notdone\relax +% \end{macrocode} +% break out of loop +% \begin{macrocode} + \dtlbreak + }% + \@dtl@notdone + }% + {% + \PackageError{datatool}{Unable to add entry given by key `#4': + database `#1' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLforeachkeyinrow} +%\begin{definition} +%\cs{DTLforeachkeyinrow}\marg{cmd}\marg{text} +%\end{definition} +% Iterates through each key in the current row of \cs{DTLforeach}, +% and does \meta{text}. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\DTLforeachkeyinrow}[2]{% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLforeachkeyinrow\space can only + be used inside \string\DTLforeach}{}% + \else +% \end{macrocode} +% Set \cs{@dtl@thisdb} to the current database name: +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@thisdb + \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Iterate through key list +% \begin{macrocode} + \dtlforeachkey(\dtlkey,\dtlcol,\dtltype,\dtlheader)\in + \@dtl@thisdb\do{% +% \end{macrocode} +% store row in \cs{dtlcurrentrow} +% (This may get nested so need to do it here instead of +% outside this loop in case +% \meta{text} changes it.) +% \begin{macrocode} + \dtlcurrentrow = + \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname +% \end{macrocode} +% Get the value for this key and store in "#1" +% \begin{macrocode} + \edef\dtl@dogetentry{\noexpand\dtlgetentryfromcurrentrow + {\noexpand#1}{\dtlcol}}% + \dtl@dogetentry +% \end{macrocode} +% Check if null +% \begin{macrocode} + \ifx#1\dtlnovalue + \ifnum0\dtltype=0\relax +% \end{macrocode} +% Data type is \meta{empty} or 0, so set to string null. +% \begin{macrocode} + \let#1=\DTLstringnull + \else +% \end{macrocode} +% Data type is numerical, so set to number null. +% \begin{macrocode} + \let#1=\DTLnumbernull + \fi + \fi +% \end{macrocode} +% Make "#1" global in case this is in a tabular environment (or +% something similar) +% \begin{macrocode} + \global\let#1#1% +% \end{macrocode} +% Store loop body so that any scoping commands (such as "&") don't +% cause a problem for \cs{ifx} +% \begin{macrocode} + \def\@dtl@loop@body{#2}% + \@dtl@loop@body + }% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Displaying Database} +% This section defines commands to display the entire database +% in a \env{tabular} or \env{longtable} environment. +% +%\begin{macro}{\dtlbetweencols} +% This specifies what to put between the column alignment +% specifiers. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlbetweencols}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlbeforecols} +% This specifies what to put before the first column alignment +% specifier. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlbeforecols}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlaftercols} +% This specifies what to put after the last column alignment +% specifier. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlaftercols}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlstringalign} +% Alignment character for columns containing strings +% \begin{macrocode} +\newcommand*{\dtlstringalign}{l} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlintalign} +% Alignment character for columns containing integers +% \begin{macrocode} +\newcommand*{\dtlintalign}{r} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlrealalign} +% Alignment character for columns containing real numbers +% \begin{macrocode} +\newcommand*{\dtlrealalign}{r} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlcurrencyalign} +% Alignment character for columns containing currency numbers +% \begin{macrocode} +\newcommand*{\dtlcurrencyalign}{r} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtladdalign} +%\begin{definition} +%\cs{dtladdalign}\marg{cs}\marg{type}\marg{col num}\marg{max cols} +%\end{definition} +% Adds tabular column alignment character to \meta{cs} for column +% \meta{col num} which contains data type \meta{type}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\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 +% \end{macrocode} +% string +% \begin{macrocode} + \protected@edef#1{#1\dtlstringalign}% + \or +% \end{macrocode} +% integer +% \begin{macrocode} + \protected@edef#1{#1\dtlintalign}% + \or +% \end{macrocode} +% real number +% \begin{macrocode} + \protected@edef#1{#1\dtlrealalign}% + \or +% \end{macrocode} +% currency +% \begin{macrocode} + \protected@edef#1{#1\dtlcurrencyalign}% \else - \@dtl@conditionfalse - \let\dtl@testiflowernext=\@dtl@gobbletonil +% \end{macrocode} +% Unknown type +% \begin{macrocode} + \protected@edef#1{#1c}% + \PackageError{datatool}{Unknown data type `#2'}{}% \fi \fi -}}} + \ifnum#3=#4\relax + \protected@edef#1{#1\dtlaftercols}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlheaderformat} +%\begin{definition} +%\cs{dtlheaderformat}\marg{text} +%\end{definition} +% Specifies how to format the column title. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlheaderformat}[1]{\null\hfil\textbf{#1}\hfil\null} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlstringformat} +%\begin{definition} +%\cs{dtlstringformat}\marg{text} +%\end{definition} +% Specifies how to format entries in columns with string data type. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlstringformat}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlintformat} +%\begin{definition} +%\cs{dtlintformat}\marg{text} +%\end{definition} +% Specifies how to format entries in columns with integer data type. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlintformat}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlrealformat} +%\begin{definition} +%\cs{dtlrealformat}\marg{text} +%\end{definition} +% Specifies how to format entries in columns with real data type. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlrealformat}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtlcurrencyformat} +%\begin{definition} +%\cs{dtlcurrencyformat}\marg{text} +%\end{definition} +% Specifies how to format entries in columns with currency data type. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtlcurrencyformat}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldisplaystarttab} +% Indicates what to do just after "\begin{tabular}"\marg{column specs} +% (e.g.\ \cs{hline}). +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtldisplaystarttab}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldisplayendtab} +% Indicates what to do just before "\end{tabular}". +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtldisplayendtab}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldisplayafterhead} +% Indicates what to do after the header row, before the first row +% of data. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtldisplayafterhead}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldisplaystartrow} +% Indicates what to do at the start of each row (not including +% the header row or the first row of data). +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtldisplaystartrow}{} +% \end{macrocode} +%\end{macro} + +%\begin{macro}{\DTLdisplaydb} +%\begin{definition} +%\cs{DTLdisplaydb}\marg{db} +%\end{definition} +% Displays the database \meta{db} in a tabular environment. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLdisplaydb}[1]{% +% \end{macrocode} +% Initialise: +% only want "&" between columns +% \begin{macrocode} + \def\@dtl@doamp{\gdef\@dtl@doamp{&}} + \def\@dtl@resetdoamp{\gdef\@dtl@doamp{\gdef\@dtl@doamp{&}}} +% \end{macrocode} +% Store maximum number of columns +% \begin{macrocode} + \edef\@dtl@maxcols{\expandafter\number + \csname dtlcols@#1\endcsname}% +% \end{macrocode} +% Argument for tabular environment +% \begin{macrocode} + \def\@dtl@tabargs{}% + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#1}\do + {% + \dtladdalign\@dtl@tabargs\@dtl@type\@dtl@idx\@dtl@maxcols + }% +% \end{macrocode} +% Begin tabular environment +% \begin{macrocode} + \edef\@dtl@dobegintab{\noexpand\begin{tabular}{\@dtl@tabargs}}% + \@dtl@dobegintab +% \end{macrocode} +% Do start hook +% \begin{macrocode} + \dtldisplaystarttab +% \end{macrocode} +% Reset \cs{@dtl@doamp} so it doesn't do an ampersand at the +% start of the first column. +% \begin{macrocode} + \@dtl@resetdoamp +% \end{macrocode} +% Do the header row. +% \begin{macrocode} + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#1}\do + {% + \@dtl@doamp + \dtlheaderformat{\@dtl@head}% + }% + \\% +% \end{macrocode} +% Do the after header hook +% \begin{macrocode} + \dtldisplayafterhead +% \end{macrocode} +% Reset \cs{@dtl@doamp} so it doesn't do an ampersand at the +% start of the first column. +% \begin{macrocode} + \@dtl@resetdoamp +% \end{macrocode} +% Iterate through each row of the database +% \begin{macrocode} + \DTLforeach*{#1}{}{% +% \end{macrocode} +% Do the start row hook if not the first row +% \begin{macrocode} + \DTLiffirstrow{}{\\\dtldisplaystartrow}% +% \end{macrocode} +% Reset \cs{@dtl@doamp} so it doesn't do an ampersand at the +% start of the first column. +% \begin{macrocode} + \@dtl@resetdoamp +% \end{macrocode} +% Iterate through each column. +% \begin{macrocode} + \DTLforeachkeyinrow{\@dtl@val}% + {% +% \end{macrocode} +% Need to make value global as it needs to be used after the +% ampersand. +% \begin{macrocode} + \global\let\@dtl@val\@dtl@val + \@dtl@doamp +% \end{macrocode} +% \cs{DTLforeachkeyinrow} sets \cs{dtltype} to the data type +% for the current key. This can be used to determine which +% format to use for this entry. +% \begin{macrocode} + \@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}% +} +% \end{macrocode} +%\end{macro} +% +% Define keys to use in the optional argument of +% \cs{DTLdisplaylongdb}. +% +% The caption key sets the caption for the longtable. +% \begin{macrocode} +\define@key{displaylong}{caption}{\def\@dtl@cap{#1}} +% \end{macrocode} +% The contcaption key sets the continuation caption for the +% longtable. +% \begin{macrocode} +\define@key{displaylong}{contcaption}{\def\@dtl@contcap{#1}} +% \end{macrocode} +% The shortcaption key sets the lof caption for the longtable. +% \begin{macrocode} +\define@key{displaylong}{shortcaption}{\def\@dtl@shortcap{#1}} +% \end{macrocode} +% The label key sets the label for the longtable. +% \begin{macrocode} +\define@key{displaylong}{label}{\def\@dtl@label{#1}} +% \end{macrocode} +% The foot key sets the longtable foot +% \begin{macrocode} +\define@key{displaylong}{foot}{\def\@dtl@foot{#1}} +% \end{macrocode} +% The lastfoot key sets the longtable last foot +% \begin{macrocode} +\define@key{displaylong}{lastfoot}{\def\@dtl@lastfoot{#1}} +% \end{macrocode} +% +%\begin{macro}{\@dtl@resetdostartrow} +% Resets start row hook so that it skips the first row. +% \begin{macrocode} +\newcommand*{\@dtl@resetdostartrow}{% + \gdef\@dtl@dostartrow{% + \gdef\@dtl@dostartrow{\\\dtldisplaystartrow}}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLdisplaylongdb} +%\begin{definition} +%\cs{DTLdisplaylongdb}\oarg{options}\marg{db} +%\end{definition} +% Displays the database \meta{db} in a longtable environment. +% (User needs to load \sty{longtable}). +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLdisplaylongdb}[2][]{% +% \end{macrocode} +% Initialise. +% \begin{macrocode} + \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}% +% \end{macrocode} +% Set the options +% \begin{macrocode} + \setkeys{displaylong}{#1}% +% \end{macrocode} +% Only want "&" between columns +% \begin{macrocode} + \def\@dtl@doamp{\gdef\@dtl@doamp{&}} + \def\@dtl@resetdoamp{\gdef\@dtl@doamp{\gdef\@dtl@doamp{&}}} + \@dtl@resetdostartrow +% \end{macrocode} +% Store maximum number of columns +% \begin{macrocode} + \edef\@dtl@maxcols{\expandafter\number + \csname dtlcols@#2\endcsname}% +% \end{macrocode} +% Argument for \env{longtable} environment +% \begin{macrocode} + \def\@dtl@tabargs{}% + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {% + \dtladdalign\@dtl@tabargs\@dtl@type\@dtl@idx\@dtl@maxcols + }% +% \end{macrocode} +% Start the \env{longtable} environment. +% \begin{macrocode} + \edef\@dtl@dobegintab{\noexpand\begin{longtable}{\@dtl@tabargs}}% + \@dtl@dobegintab +% \end{macrocode} +% Do start hook. +% \begin{macrocode} + \dtldisplaystarttab +% \end{macrocode} +% Is a foot required? +% \begin{macrocode} + \ifx\@dtl@foot\@nnil + \else + \@dtl@foot\endfoot + \fi +% \end{macrocode} +% Is a last foot required? +% \begin{macrocode} + \ifx\@dtl@lastfoot\@nnil + \else + \@dtl@lastfoot\endlastfoot + \fi +% \end{macrocode} +% Is a caption required? +% \begin{macrocode} + \ifx\@dtl@cap\@nnil +% \end{macrocode} +% No caption required, just do header row. +% \begin{macrocode} + \@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 +% \end{macrocode} +% Caption is required +% \begin{macrocode} + \caption[\@dtl@shortcap]{\@dtl@cap}% +% \end{macrocode} +% Is a label required? +% \begin{macrocode} + \ifx\@dtl@label\@nnil + \else + \label{\@dtl@label}% + \fi + \\% +% \end{macrocode} +% Do header row. +% \begin{macrocode} + \@dtl@resetdoamp + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {\@dtl@doamp{\dtlheaderformat{\@dtl@head}}}% + \@dtl@resetdoamp + \@dtl@resetdostartrow + \endfirsthead +% \end{macrocode} +% Is a continuation caption required? +% \begin{macrocode} + \ifx\@dtl@contcap\@nnil + \caption{\@dtl@cap}% + \else + \caption{\@dtl@contcap}% + \fi + \\% +% \end{macrocode} +% Do header row. +% \begin{macrocode} + \@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 +% \end{macrocode} +% Iterate through each row of the database +% \begin{macrocode} + \DTLforeach*{#2}{}{% + \@dtl@dostartrow + \@dtl@resetdoamp +% \end{macrocode} +% Iterate through each column +% \begin{macrocode} + \DTLforeachkeyinrow{\@dtl@val}% + {% + \global\let\@dtl@val\@dtl@val + \@dtl@doamp +% \end{macrocode} +% \cs{DTLforeachkeyinrow} sets \cs{dtltype} to the data type +% for the current key. This can be used to determine which +% format to use for this entry. +% \begin{macrocode} + \@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}% +} +% \end{macrocode} +%\end{macro} +% +% +%\subsection{Editing Databases} +% +%\begin{macro}{\dtlswaprows} +%\begin{definition} +%\cs{dtlswaprows}\marg{db}\marg{row1 idx}\marg{row2 idx} +%\end{definition} +% Swaps the rows with indices \meta{row1 idx} and \meta{row2 idx} +% in the database \meta{db}. +% (Doesn't check if data base exists of if indices are out of +% bounds.) +% \begin{macrocode} +\newcommand*{\dtlswaprows}[3]{% + \ifnum#2=#3\relax +% \end{macrocode} +% Attempt to swap row with itself: do nothing. +% \begin{macrocode} + \else +% \end{macrocode} +% Let row A be the row with the lower index and row B be the +% row with ther higher index. +% \begin{macrocode} + \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 +% \end{macrocode} +% Split the database around row A. +% \begin{macrocode} + \edef\@dtl@dosplit{\noexpand\dtlgetrow{#1}{\@dtl@rowAidx}}% + \@dtl@dosplit +% \end{macrocode} +% Store first part of database in \cs{@dtl@firstpart}. +% \begin{macrocode} + \expandafter\def\expandafter\@dtl@firstpart\expandafter + {\the\dtlbeforerow}% +% \end{macrocode} +% Store row A in \cs{@dtl@toksA}. +% \begin{macrocode} + \@dtl@toksA=\dtlcurrentrow +% \end{macrocode} +% Split the second part (everything after row A). +% \begin{macrocode} + \edef\@dtl@dosplit{\noexpand\@dtlgetrow + {\the\dtlafterrow}{\@dtl@rowBidx}}% + \@dtl@dosplit +% \end{macrocode} +% Store the mid part (everything between row A and row B) +% \begin{macrocode} + \expandafter\def\expandafter\@dtl@secondpart\expandafter + {\the\dtlbeforerow}% +% \end{macrocode} +% Store row B in \cs{@dtl@toksB}. +% \begin{macrocode} + \@dtl@toksB=\dtlcurrentrow +% \end{macrocode} +% Store the last part (everything after row B). +% \begin{macrocode} + \expandafter\def\expandafter\@dtl@thirdpart\expandafter + {\the\dtlafterrow}% +% \end{macrocode} +% Reconstruct database: store first part in \cs{toks@} +% \begin{macrocode} + \toks@=\expandafter{\@dtl@firstpart}% +% \end{macrocode} +% Store mid part in \cs{dtl@toks} +% \begin{macrocode} + \@dtl@toks=\expandafter{\@dtl@secondpart}% +% \end{macrocode} +% Format data for first part, row B and mid part. +% \begin{macrocode} + \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}% +% \end{macrocode} +% Store data so far in \cs{toks@}. +% \begin{macrocode} + \toks@=\expandafter{\@dtl@tmp}% +% \end{macrocode} +% Store last part in \cs{dtl@toks}. +% \begin{macrocode} + \@dtl@toks=\expandafter{\@dtl@thirdpart}% +% \end{macrocode} +% Format row A and end part. +% \begin{macrocode} + \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}% +% \end{macrocode} +% Update the database +% \begin{macrocode} + \expandafter\global\csname dtldb@#1\endcsname=\expandafter + {\@dtl@tmp}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@decrementrows} +%\begin{definition} +%\cs{dtl@decrementrows}\marg{toks}\marg{n} +%\end{definition} +% decrement by 1 all rows in \meta{toks} with row index above +% \meta{n} +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\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}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@decrementrows} +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\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 +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLremoverow} +%\begin{definition} +%\cs{DTLremoverow}\marg{db}\marg{row index} +%\end{definition} +% Remove row with given index from database named \meta{db}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLremoverow}[2]{% +% \end{macrocode} +% Check database exists +% \begin{macrocode} + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Check index if index is out of bounds +% \begin{macrocode} + \ifnum#2>0\relax +% \end{macrocode} +% Check if data base has at least \meta{row index} rows +% \begin{macrocode} + \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}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@DTLremoverow} +%\begin{definition} +%\cs{@DTLremoverow}\marg{db}\marg{row index} +%\end{definition} +% Doesn't perform any checks for the existance of the database +% or if the index is in range. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\@DTLremoverow}[2]{% +% \end{macrocode} +% Get row from data base +% \begin{macrocode} + \edef\dtl@dogetrow{\noexpand\dtlgetrow{#1}{\number#2}}% + \dtl@dogetrow +% \end{macrocode} +% Update the row indices +% \begin{macrocode} + \expandafter\dtl@decrementrows\expandafter + {\dtlbeforerow}{#2}% + \expandafter\dtl@decrementrows\expandafter + {\dtlafterrow}{#2}% +% \end{macrocode} +% Reconstruct database +% \begin{macrocode} + \edef\dtl@tmp{\the\dtlbeforerow \the\dtlafterrow}% + \expandafter\global\csname dtldb@#1\endcsname + =\expandafter{\dtl@tmp}% +% \end{macrocode} +% decrement row counter +% \begin{macrocode} + \expandafter\global\expandafter\advance + \csname dtlrows@#1\endcsname by -1\relax +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Database Functions} +% +%\begin{macro}{\DTLsumforkeys} +%\begin{definition} +%\cs{DTLsumforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Sums all entries for key \meta{key} over all databases listed +% in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The first argument \meta{condition} is the same as that +% for \cs{DTLforeach}. The second optional argument provides +% an assignment list to pass to \cs{DTLforeach} in case extra +% information is need by \meta{condition}. +%\changes{2.0}{2009 February 27}{added second optional argument} +% \begin{macrocode} +\newcommand*{\DTLsumforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlsumforkeys +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlsumforkeys} +% \begin{macrocode} +\newcommand*{\@dtlsumforkeys}[4][]{% + \def#4{0}% +% \end{macrocode} +% Iterate over all the listed data bases +% \begin{macrocode} + \@for\@dtl@dbname:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@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}}{}% + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsumcolumn} +%\begin{definition} +%\cs{DTLsumcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +% Quicker version of \cs{DTLsumforkeys} that just sums over +% one column (specified by \meta{key}) for a single database +% (specified by \meta{db}) and stores the result in \meta{cmd}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLsumcolumn}[3]{% + \def#3{0}% +% \end{macrocode} +% Check data base exists +% \begin{macrocode} + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Check column exists +% \begin{macrocode} + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \DTLadd{#3}{#3}{\DTLthisval}% + }% + }% +% \end{macrocode} +% key not defined for this data base +% \begin{macrocode} + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% +% \end{macrocode} +% data base doesn't exist +% \begin{macrocode} + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmeanforkeys} +%\begin{definition} +%\cs{DTLmeanforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Computes the arithmetic mean of all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The first argument \meta{condition} is the same as that +% for \cs{DTLforeach}. The second optional argument allows an +% assignment list to be passed to \cs{DTLforeach}. +%\changes{2.0}{2009 February 27}{added second optional argument} +% \begin{macrocode} +\newcommand*{\DTLmeanforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlmeanforkeys +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@elements} +% Count register to keep track of number of elements +% \begin{macrocode} +\newcount\@dtl@elements +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlmeanforkeys} +% \begin{macrocode} +\newcommand*{\@dtlmeanforkeys}[4][]{% + \def#4{0}% + \@dtl@elements=0\relax +% \end{macrocode} +% Iterate over all the listed data bases +% \begin{macrocode} + \@for\@dtl@dbname:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@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 + }{}% + }% + }% + }% +% \end{macrocode} +% Divide total by number of elements summed. +% \begin{macrocode} + \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 +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmeanforcolumn} +%\begin{definition} +%\cs{DTLmeanforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +% Quicker version of \cs{DTLmeanforkeys} that just computes the +% mean over one column (specified by \meta{key}) for a single +% database (specified by \meta{db}) and stores the result in +% \meta{cmd}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLmeanforcolumn}[3]{% + \def#3{0}% + \@dtl@elements=0\relax +% \end{macrocode} +% Check data base exists +% \begin{macrocode} + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Check column exists +% \begin{macrocode} + \@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 + }% +% \end{macrocode} +% key not defined for this data base +% \begin{macrocode} + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% +% \end{macrocode} +% data base doesn't exist +% \begin{macrocode} + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLvarianceforkeys} +%\begin{definition} +%\cs{DTLvarianceforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Computes the variance of all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The first optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. The second optional argument is an assignment +% list to pass to \cs{DTLforeach} in case it is required for the +% condition. +%\changes{2.0}{2009 February 27}{added second optional argument} +% \begin{macrocode} +\newcommand*{\DTLvarianceforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlvarianceforkeys +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlmeanforkeys} +% \begin{macrocode} +\newcommand*{\@dtlvarianceforkeys}[4][]{% + \@dtlmeanforkeys[#1]{#2}{#3}{\dtl@mean}% + \def#4{0}% + \@dtl@elements=0\relax +% \end{macrocode} +% Iterate over all the listed data bases +% \begin{macrocode} + \@for\@dtl@dbname:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@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}% + {% +% \end{macrocode} +% compute $(x_i - \mu)^2$ +% \begin{macrocode} + \DTLsub{\dtl@diff}{\DTLthisval}{\dtl@mean}% + \DTLmul{\dtl@diff}{\dtl@diff}{\dtl@diff}% + \DTLadd{#4}{#4}{\dtl@diff}% + \advance\@dtl@elements by 1\relax + }{}% + }% + }% + }% +% \end{macrocode} +% Divide by number of elements. +% \begin{macrocode} + \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 +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLvarianceforcolumn} +%\begin{definition} +%\cs{DTLvarianceforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +% Quicker version of \cs{DTLvarianceforkeys} that just computes the +% variance over one column (specified by \meta{key}) for a single +% database (specified by \meta{db}) and stores the result in +% \meta{cmd}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLvarianceforcolumn}[3]{% + \DTLmeanforcolumn{#1}{#2}{\dtl@mean}% + \def#3{0}% + \@dtl@elements=0\relax +% \end{macrocode} +% Check data base exists +% \begin{macrocode} + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Check column exists +% \begin{macrocode} + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% +% \end{macrocode} +% compute $(x_i - \mu)^2$ +% \begin{macrocode} + \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 + }% +% \end{macrocode} +% key not defined for this data base +% \begin{macrocode} + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% +% \end{macrocode} +% data base doesn't exist +% \begin{macrocode} + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\DTLsdforkeys} +%\begin{definition} +%\cs{DTLsdforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Computes the standard deviation of all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The first optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. The second optional argument is an +% assignment list for \cs{DTLforeach} in case it is needed for +% the condition. +%\changes{2.0}{2009 February 27}{added second optional argument} +% \begin{macrocode} +\newcommand*{\DTLsdforkeys}[1][\boolean{true}\and +\DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlsdforkeys +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtlsdforkeys} +% \begin{macrocode} +\newcommand*{\@dtlsdforkeys}[4][]{% + \@dtlvarianceforkeys[#1]{#2}{#3}{#4}% + \DTLsqrt{#4}{#4}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsdforcolumn} +%\begin{definition} +%\cs{DTLsdforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +% Quicker version of \cs{DTLsdforkeys} that just computes the +% standard deviation over one column (specified by \meta{key}) for +% a single database (specified by \meta{db}) and stores the result +% in \meta{cmd}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLsdforcolumn}[3]{% + \DTLvarianceforcolumn{#1}{#2}{#3}% + \DTLsqrt{#3}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLminforkeys} +%\begin{definition} +%\cs{DTLminforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Determines the minimum over all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The first optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. The second optional argument is an +% assignment list for \cs{DTLforeach} in the event that extra +% information is need for the condition. +%\changes{2.0}{2009 February 27}{added second optional argument} +% \begin{macrocode} +\newcommand*{\DTLminforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlminforkeys +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlminforkeys} +% \begin{macrocode} +\newcommand*{\@dtlminforkeys}[4][]{% + \def#4{}% +% \end{macrocode} +% Iterate over all the listed data bases +% \begin{macrocode} + \@for\@dtl@dbname:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@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 + }{}% + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLminforcolumn} +%\begin{definition} +%\cs{DTLminforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +% Quicker version of \cs{DTLminforkeys} that just finds the +% minimum value in one column (specified by \meta{key}) for a +% single database (specified by \meta{db}) and stores the result +% in \meta{cmd}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLminforcolumn}[3]{% + \def#3{}% +% \end{macrocode} +% Check data base exists +% \begin{macrocode} + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Check column exists +% \begin{macrocode} + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \ifx#3\@empty + \let#3\DTLthisval + \else + \DTLmin{#3}{#3}{\DTLthisval}% + \fi + }% + }% +% \end{macrocode} +% key not defined for this data base +% \begin{macrocode} + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% +% \end{macrocode} +% data base doesn't exist +% \begin{macrocode} + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\DTLmaxforkeys} +%\begin{definition} +%\cs{DTLmaxforkeys}\oarg{condition}\oarg{assign list}\marg{db list}\marg{key list}\marg{cmd} +%\end{definition} +% Determines the maximum over all entries for each key in +% \meta{key list} over all databases in \meta{db list}, +% and stores in \meta{cmd}, which must be a control sequence. +% The first optional argument \meta{condition} is the same as that +% for \cs{DTLforeach}. The second optional argument is an +% assignment list to pass to \cs{DTLforeach} in the event that +% extra information is required in the condition. +%\changes{2.0}{2009 February 27}{added second optional argument} +% \begin{macrocode} +\newcommand*{\DTLmaxforkeys}[1][\boolean{true}\and + \DTLisnumerical{\DTLthisval}]{% + \def\@dtl@cond{#1}% + \@dtlmaxforkeys +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlmaxforkeys} +% \begin{macrocode} +\newcommand*{\@dtlmaxforkeys}[4][]{% + \def#4{}% +% \end{macrocode} +% Iterate over all the listed data bases +% \begin{macrocode} + \@for\@dtl@dbname:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@dbname}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@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 + }{}% + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmaxforcolumn} +%\begin{definition} +%\cs{DTLmaxforcolumn}\marg{db}\marg{key}\marg{cmd} +%\end{definition} +% Quicker version of \cs{DTLmaxforkeys} that just finds the +% maximum value in one column (specified by \meta{key}) for a +% single database (specified by \meta{db}) and stores the result +% in \meta{cmd}. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\DTLmaxforcolumn}[3]{% + \def#3{}% +% \end{macrocode} +% Check data base exists +% \begin{macrocode} + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Check column exists +% \begin{macrocode} + \@sDTLifhaskey{#1}{#2}% + {% + \@sdtlforcolumn{\DTLthisval}{#1}{#2}% + {% + \ifx#3\@empty + \let#3\DTLthisval + \else + \DTLmax{#3}{#3}{\DTLthisval}% + \fi + }% + }% +% \end{macrocode} +% key not defined for this data base +% \begin{macrocode} + {% + \PackageError{datatool}{Key `#2' doesn't + exist in database `#1'}{}% + }% + }% +% \end{macrocode} +% data base doesn't exist +% \begin{macrocode} + {% + \PackageError{datatool}{Data base `#1' doesn't + exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLcomputebounds} +%\begin{definition} +%\cs{DTLcomputebounds}\oarg{condition}\marg{db list}\marg{x key}\marg{y key}\marg{minX cmd}\marg{minY cmd}\marg{maxX cmd}\marg{maxY cmd} +%\end{definition} +% Computes the maximum and minimum $x$ and $y$ values over all +% the databases listed in \meta{db list} where the $x$ value +% is given by \meta{x key} and the $y$ value is given by +% \meta{y key}. The results are stored in \meta{minX cmd}, +% \meta{minY cmd}, \meta{maxX cmd} and \meta{maxY cmd} in +% standard decimal format. +% \begin{macrocode} +\newcommand*{\DTLcomputebounds}[8][\boolean{true}]{% +\let#5=\relax +\let#6=\relax +\let#7=\relax +\let#8=\relax +\@for\dtl@thisdb:=#2\do{% + \@sDTLforeach[#1]{\dtl@thisdb}{\DTLthisX=#3,\DTLthisY=#4}{% + \DTLconverttodecimal{\DTLthisX}{\dtl@decx}% + \DTLconverttodecimal{\DTLthisY}{\dtl@decy}% + \ifx#5\relax + \let#5=\dtl@decx + \let#6=\dtl@decy + \let#7=\dtl@decx + \let#8=\dtl@decy + \else + \FPmin{#5}{#5}{\dtl@decx}% + \FPmin{#6}{#6}{\dtl@decy}% + \FPmax{#7}{#7}{\dtl@decx}% + \FPmax{#8}{#8}{\dtl@decy}% + \fi + }% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgetvalueforkey} +%\begin{definition} +%\cs{DTLgetvalueforkey}\marg{cmd}\marg{key}\marg{db name}\marg{ref +% key}\marg{ref value} +%\end{definition} +% This (globally) sets \meta{cmd} (a control sequence) to the +% value of the key specified by \meta{key} in the first row +% of the database called \meta{db name} which contains the key +% \meta{ref key} which has the value \meta{value}. +%\changes{1.01}{2007 Aug 17}{new} +%\changes{2.0}{2009 February 27}{updated to use new database +% structure} +% \begin{macrocode} +\newcommand*{\DTLgetvalueforkey}[5]{% +% \end{macrocode} +% Get row containing referenced (key,value) pair +% \begin{macrocode} + \DTLgetrowforkey{\@dtl@row}{#3}{#4}{#5}% +% \end{macrocode} +% Get column number for \meta{key} +% \begin{macrocode} + \@sdtl@getcolumnindex{\@dtl@col}{#3}{#2}% +% \end{macrocode} +% Get value for given column +% \begin{macrocode} + {% + \dtlcurrentrow=\expandafter{\@dtl@row}% + \edef\@dtl@dogetval{\noexpand\dtlgetentryfromcurrentrow + {\noexpand\@dtl@val}{\@dtl@col}}% + \@dtl@dogetval + \global\let#1=\@dtl@val + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgetrowforkey} +%\begin{definition} +%\cs{DTLgetrowforkey}\marg{cmd}\marg{db name}\marg{ref +% key}\marg{ref value} +%\end{definition} +% This (globally) sets \meta{cmd} (a control sequence) to the +% first row +% of the database called \meta{db name} which contains the key +% \meta{ref key} that has the value \meta{value}. +%\changes{1.01}{2007 Aug 17}{new} +%\changes{2.0}{2009 February 27}{update to use new database +% structure} +% \begin{macrocode} +\newcommand*{\DTLgetrowforkey}[4]{% + \global\let#1=\@empty + \@sDTLforeach{#2}{\dtl@refvalue=#3}{% + \DTLifnull{\dtl@refvalue}% + {}% + {% + \ifthenelse{\equal{\dtl@refvalue}{#4}}% + {% + \xdef#1{\the\dtlcurrentrow}% + \dtlbreak + }% + {}% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsplitrow} +%\begin{definition} +%\cs{dtlsplitrow}\marg{row specs}\marg{col num}\marg{before +% cs}\marg{after cs} +%\end{definition} +% Splits the row around the entry given by \meta{col num}. The +% entries before the split are stored in \meta{before cs} and the +% entries after the split are stored in \meta{after cs}. +% \meta{row specs} and \meta{col num} need to be expanded before use. +% \begin{macrocode} +\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 +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Sorting Databases} +% +%\begin{macro}{\@dtl@list} +% Token register to store data when sorting. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newtoks\@dtl@list +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsort} +%\begin{definition} +% \cs{DTLsort}\oarg{replacement keys}\marg{sort criteria}\marg{db name} +%\end{definition} +% Sorts database \meta{db name} according to \marg{sort criteria}, +% which must be a comma separated list of keys, and optionally +% \texttt{=}\meta{order}, where \meta{order} is either +% "ascending" or "descending". The optional argument is a list of +% keys to uses if the given key has a null value. The starred +% version uses a case insensitive string comparison. +%\changes{1.01}{2007 Aug 17}{added optional argument} +%\changes{1.01}{2007 Aug 17}{added starred version} +%\changes{2.0}{2009 February 27}{updated to use new data structure} +% \begin{macrocode} +\newcommand*{\DTLsort}{\@ifstar\@sDTLsort\@DTLsort} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@DTLsort} +% Unstarred (case sensitive) version. +% \begin{macrocode} +\newcommand{\@DTLsort}[3][]{% +% \end{macrocode} +% Check the database exists +% \begin{macrocode} + \DTLifdbexists{#3}% + {% +% \end{macrocode} +% Store replacement keys in \cs{@dtl@replacementkeys}. +% \begin{macrocode} + \edef\@dtl@replacementkeys{#1}% +% \end{macrocode} +% Store sort order in \cs{@dtl@sortorder}. +% \begin{macrocode} + \edef\@dtl@sortorder{#2}% +% \end{macrocode} +% Set \cs{@dtl@comparecs} to the required string comparison +% function. (Using case sensitive comparison macro \cs{dtlcompare}.) +% \begin{macrocode} + \let\@dtl@comparecs=\dtlcompare +% \end{macrocode} +% Sort the database. +% \begin{macrocode} + \dtl@sortdata{#3}% + }% + {% + \PackageError{datatool}{Database `#3' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@sDTLsort} +% Starred (case insensitive) version. +% \begin{macrocode} +\newcommand{\@sDTLsort}[3][]{% +% \end{macrocode} +% Check the database exists +% \begin{macrocode} + \DTLifdbexists{#3}% + {% +% \end{macrocode} +% Store replacement keys in \cs{@dtl@replacementkeys}. +% \begin{macrocode} + \edef\@dtl@replacementkeys{#1}% +% \end{macrocode} +% Store sort order in \cs{@dtl@sortorder}. +% \begin{macrocode} + \edef\@dtl@sortorder{#2}% +% \end{macrocode} +% Set \cs{@dtl@comparecs} to the required string comparison +% function. (Using case insensitive comparison macro +% \cs{dtlicompare}.) +% \begin{macrocode} + \let\@dtl@comparecs=\dtlicompare +% \end{macrocode} +% Sort the database. +% \begin{macrocode} + \dtl@sortdata{#3}% + }% + {% + \PackageError{datatool}{Database `#3' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@rowa} +% Token register to store first row when sorting. +% \begin{macrocode} +\newtoks\@dtl@rowa +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@rowb} +% Token register to store comparison row when sorting. +% \begin{macrocode} +\newtoks\@dtl@rowb +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@sortdata} +%\begin{definition} +%\cs{dtl@sortdata}\marg{db} +%\end{definition} +% Sorts the data in named database using an insertion sort +% algorithm. +% \cs{@dtl@replacementkeys}, \cs{@dtl@sortorder} and +% \cs{@dtl@comparecs} must be set prior to use. +%\changes{2.0}{2009 February 27}{new} +% \begin{macrocode} +\newcommand*{\dtl@sortdata}[1]{% +% \end{macrocode} +% Initialise macro containing sorted data. +% \begin{macrocode} + \def\@dtl@sortedlist{}% +% \end{macrocode} +% Store database name. +% \begin{macrocode} + \edef\@dtl@dbname{#1}% +% \end{macrocode} +% Iterate through each row and insert into sorted list. +% \begin{macrocode} + \@dtlforeachrow(\@dtl@rowAnum,\@dtl@rowAcontents)\in{#1}\do{% + \@dtl@rowa=\expandafter{\@dtl@rowAcontents}% +% \end{macrocode} +% Create a temporary list +% \begin{macrocode} + \def\@dtl@newlist{}% +% \end{macrocode} +% Initialise the insertion for this iteration. Insertion hasn't +% been done yet. +% \begin{macrocode} + \@dtl@insertdonefalse +% \end{macrocode} +% Initialise row index to 0 +% \begin{macrocode} + \dtlrownum=0\relax +% \end{macrocode} +% Iterate through sorted list. +% \begin{macrocode} + \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}{% +% \end{macrocode} +% Store row B in a token register +% \begin{macrocode} + \@dtl@rowb=\expandafter{\@dtl@rowBcontents}% +% \end{macrocode} +% Get current row number of sorted list +% \begin{macrocode} + \dtlrownum=\@dtl@rowBnum +% \end{macrocode} +% Has the insertion been done? +% \begin{macrocode} + \if@dtl@insertdone +% \end{macrocode} +% New element has already been inserted, so just increment the row +% number to compensate for the inserted row. +% \begin{macrocode} + \advance\dtlrownum by 1\relax + \else +% \end{macrocode} +% Insertion hasn't been done yet. +% Compare row A and row B. +% \begin{macrocode} + \@dtl@sortcriteria{\@dtl@rowa}{\@dtl@rowb}% +% \end{macrocode} +% If \cs{dtl@sortresult} is negative insert A before B. +% \begin{macrocode} + \ifnum\dtl@sortresult<0\relax +% \end{macrocode} +% Insert row A into new list. First store \cs{@dtl@newlist} in +% \cs{toks@}. +% \begin{macrocode} + \toks@=\expandafter{\@dtl@newlist}% +% \end{macrocode} +% Update \cs{@dtl@newlist} to be the old value followed by +% row A. +% \begin{macrocode} + \edef\@dtl@newlist{% +% \end{macrocode} +% Old value: +% \begin{macrocode} + \the\toks@ +% \end{macrocode} +% Format row A +% \begin{macrocode} + \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@% + }% +% \end{macrocode} +% Increment row number to compensate for inserted row. +% \begin{macrocode} + \advance\dtlrownum by 1\relax +% \end{macrocode} +% Mark insertion done. +% \begin{macrocode} + \@dtl@insertdonetrue + \fi + \fi +% \end{macrocode} +% Insert row B +% \begin{macrocode} + \toks@=\expandafter{\@dtl@newlist}% + \edef\@dtl@newlist{\the\toks@ +% \end{macrocode} +% row B +% \begin{macrocode} + \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@% + }% +% \end{macrocode} +% Repeat loop. +% \begin{macrocode} + }\q@nil +% \end{macrocode} +% If row A hasn't been inserted, do so now. +% \begin{macrocode} + \if@dtl@insertdone + \else +% \end{macrocode} +% \cs{dtlrownum} contains the index of the last row in new list, +% So increment it to get the new index for row A. +% \begin{macrocode} + \advance\dtlrownum by 1\relax +% \end{macrocode} +% Insert row A. +% \begin{macrocode} + \toks@=\expandafter{\@dtl@newlist}% + \edef\@dtl@newlist{\the\toks@ +% \end{macrocode} +% row A +% \begin{macrocode} + \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 +% \end{macrocode} +% Set sorted list to new list. +% \begin{macrocode} + \let\@dtl@sortedlist=\@dtl@newlist + }% +% \end{macrocode} +% Update database. +% \begin{macrocode} + \expandafter\global\csname dtldb@#1\endcsname=\expandafter + {\@dtl@sortedlist}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@sortcriteria} +%\begin{definition} +% \cs{@dtl@sortcriteria}\marg{row a toks}\marg{row b toks} +%\end{definition} +% \cs{@dtl@dbname} and \cs{@dtl@sortorder} must be set before use +% \cs{@dtl@sortorder} is a comma separated list of either just keys +% or \meta{key}=\meta{direction}. +% (Check keys are valid before use.) +%\changes{2.0}{2009 February 27}{updated to take account of new +% database structure} +% \begin{macrocode} +\newcommand{\@dtl@sortcriteria}[2]{% +% \end{macrocode} +% Iterate through the sort order. +% \begin{macrocode} + \@for\@dtl@level:=\@dtl@sortorder\do{% +% \end{macrocode} +% Set \cs{@dtl@sortdirection} to $-1$ (ascending) or $+1$ +% (descending). Key is stored in \cs{@dtl@key}. +% \begin{macrocode} + \expandafter\@dtl@getsortdirection\@dtl@level=\relax +% \end{macrocode} +% Initially comparing on the same key +% \begin{macrocode} + \let\@dtl@keya=\@dtl@key + \let\@dtl@keyb=\@dtl@key +% \end{macrocode} +% Get values corresponding to key from both rows. +% First get column index corresponding to key. +% \begin{macrocode} + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@key}% +% \end{macrocode} +% Get entry for this column from row A and store in \cs{@dtl@a}. +% \begin{macrocode} + \dtlgetentryfromrow{\@dtl@a}{\@dtl@col}{#1}% +% \end{macrocode} +% Get entry for this column from row B and store in \cs{@dtl@b}. +% \begin{macrocode} + \dtlgetentryfromrow{\@dtl@b}{\@dtl@col}{#2}% +% \end{macrocode} +% Has value from row A been defined? +% \begin{macrocode} + \ifx\@dtl@a\dtlnovalue +% \end{macrocode} +% Value hasn't been defined so set to null +% \begin{macrocode} + \@dtl@setnull{\@dtl@a}{\@dtl@key}% + \fi +% \end{macrocode} +% Has value from row B been defined? +% \begin{macrocode} + \ifx\@dtl@b\dtlnovalue +% \end{macrocode} +% Value hasn't been defined so set to null +% \begin{macrocode} + \@dtl@setnull{\@dtl@b}{\@dtl@key}% + \fi +% \end{macrocode} +% Check if value for row A is null. +% \begin{macrocode} + \DTLifnull{\@dtl@a}% + {% +% \end{macrocode} +% Value for row A is null, so find the first non null key in list of +% replacement keys. +% \begin{macrocode} + \@for\@dtl@keya:=\@dtl@replacementkeys\do{% +% \end{macrocode} +% Get column corresponding to this key. +% \begin{macrocode} + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@keya}% + \dtlgetentryfromrow{\@dtl@a}{\@dtl@col}{#1}% +% \end{macrocode} +% Has value for row A been defined? +% \begin{macrocode} + \ifx\@dtl@a\dtlnovalue +% \end{macrocode} +% Value for row A hasn't been defined so set to null +% \begin{macrocode} + \@dtl@setnull{\@dtl@a}{\@dtl@key}% + \fi +% \end{macrocode} +% Is value for row A null? If not null end the loop. +% \begin{macrocode} + \DTLifnull{\@dtl@a}{}{\@endfortrue}% + }% +% \end{macrocode} +% No non-null value found. +% \begin{macrocode} + \ifx\@dtl@keya\@nnil + \let\@dtl@keya\@dtl@key + \@dtl@setnull{\@dtl@a}{\@dtl@key}% + \fi + }% + {}% +% \end{macrocode} +% Check if value for row B is null. +% \begin{macrocode} + \DTLifnull{\@dtl@b}% + {% +% \end{macrocode} +% Value for row B is null, so find the first non null key in list of +% replacement keys. +% \begin{macrocode} + \@for\@dtl@keyb:=\@dtl@replacementkeys\do{% +% \end{macrocode} +% Get column corresponding to this key. +% \begin{macrocode} + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@dbname}{\@dtl@keyb}% + \dtlgetentryfromrow{\@dtl@b}{\@dtl@col}{#2}% +% \end{macrocode} +% Has value for row B been defined? +% \begin{macrocode} + \ifx\@dtl@b\dtlnovalue +% \end{macrocode} +% Value for row B hasn't been defined so set to null. +% \begin{macrocode} + \@dtl@setnull{\@dtl@b}{\@dtl@key}% + \fi +% \end{macrocode} +% Is value for row B null? If not null end the loop. +% \begin{macrocode} + \DTLifnull{\@dtl@b}{}{\@endfortrue}% + }% +% \end{macrocode} +% No non-null value found. +% \begin{macrocode} + \ifx\@dtl@keyb\@nnil + \let\@dtl@keyb\@dtl@key + \@dtl@setnull{\@dtl@b}{\@dtl@key}% + \fi + }% + {}% +% \end{macrocode} +% Compare rows A and B. First store the values for row A and B +% in token registers so that they can be passed to +% \cs{dtl@compare@}. +% \begin{macrocode} + \@dtl@toksA=\expandafter{\@dtl@a}% + \@dtl@toksB=\expandafter{\@dtl@b}% +% \end{macrocode} +% Do comparison. +% \begin{macrocode} + \edef\@dtl@docompare{\noexpand\dtl@compare@ + {\@dtl@keya}{\@dtl@keyb}% + {\noexpand\@dtl@toksA}{\noexpand\@dtl@toksB}}% + \@dtl@docompare +% \end{macrocode} +% Repeat if the two values are considered identical and there +% are further sorting options. +% \begin{macrocode} + \ifnum\dtl@sortresult=0\relax +% \end{macrocode} +% Reset switch to prevent breaking out of outer loop. +% \begin{macrocode} + \@endforfalse + \else +% \end{macrocode} +% Break out of loop. +% \begin{macrocode} + \@endfortrue + \fi + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@getsortdirection} +% Get the direction from either \meta{key} or +% \meta{key}=\meta{direction}. Sets \cs{@dtl@sortdirection} to +% either -1 (ascending) or 1 (descending). +% \begin{macrocode} +\def\@dtl@getsortdirection#1=#2\relax{% +% \end{macrocode} +% Store key in \cs{@dtl@key}. +% \begin{macrocode} + \def\@dtl@key{#1}% +% \end{macrocode} +% Store sort direction. This will be empty if no direction was +% specified. +% \begin{macrocode} + \def\@dtl@sortdirection{#2}% +% \end{macrocode} +% Check if a direction was specified. +% \begin{macrocode} + \ifx\@dtl@sortdirection\@empty +% \end{macrocode} +% No direction specified so assume ascending. +% \begin{macrocode} + \def\@dtl@sortdirection{-1}% + \else +% \end{macrocode} +% Get the sort direction from the second argument (needs terminating +% equal sign removed) and store in \cs{@dtl@sortdirection}. +% \begin{macrocode} + \@dtl@get@sortdirection#2% +% \end{macrocode} +% Determine the direction. +% \changes{2.0}{2009 February 27}{modified to use \cs{ifx} instead +% of \cs{ifthenelse}} +% \begin{macrocode} + \def\@dtl@dir{ascending}% + \ifx\@dtl@sortdirection\@dtl@dir +% \end{macrocode} +% Ascending +% \begin{macrocode} + \def\@dtl@sortdirection{-1}% + \else +% \end{macrocode} +% Check if descending. +% \begin{macrocode} + \def\@dtl@dir{descending}% + \ifx\@dtl@sortdirection\@dtl@dir +% \end{macrocode} +% Descending +% \begin{macrocode} + \def\@dtl@sortdirection{1}% + \else +% \end{macrocode} +% Direction not valid. Generate error message. +% \begin{macrocode} + \PackageError{datatool}{Invalid sort direction + `\@dtl@sortdirection'}{The sort direction can only be + one of `ascending' or `descending'}% +% \end{macrocode} +% Assume ascending. +% \begin{macrocode} + \def\@dtl@sortdirection{-1} + \fi + \fi + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@get@sortdirection} +% Get direction (trims trailing = sign) +% \begin{macrocode} +\def\@dtl@get@sortdirection#1={\def\@dtl@sortdirection{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@toksA} +% \begin{macrocode} +\newtoks\@dtl@toksA +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@toksB} +% \begin{macrocode} +\newtoks\@dtl@toksB +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@toks} +% \begin{macrocode} +\newtoks\@dtl@toks +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@compare} +%\begin{definition} +%\cs{dtl@compare}\marg{key}\marg{a toks}\marg{b toks} +%\end{definition} +% Compares two values according to \meta{key} of database given by +% \cs{@dtl@dbname}. Sets \cs{dtl@sortresult}. \cs{@dtl@comparecs} +% must be set to the required comparison macro. +%\changes{2.0}{2009 February 27}{no longer used} +% \begin{macrocode} +\newcommand{\dtl@compare}[3]{% + \dtl@compare@{#1}{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@compare@} +%\begin{definition} +% \cs{dtl@compare@}\marg{keyA}\marg{keyB}\marg{A toks}\marg{B toks} +%\end{definition} +% Compare \meta{A} and \meta{B} according \meta{keyA} and +% \meta{keyB} for database given by \cs{@dtl@dbname}. Sets +% \cs{dtl@sortresult}. +% \cs{@dtl@comparecs} must be set before use. +%\changes{2.0}{2009 February 27}{updated to use new database +% structure} +% \begin{macrocode} +\newcommand{\dtl@compare@}[4]{% +% \end{macrocode} +% Get the data type for first key and store in \cs{@dtl@typeA}. +% \begin{macrocode} + \DTLgetdatatype{\@dtl@typeA}{\@dtl@dbname}{#1}% +% \end{macrocode} +% Is it unset? If so, assume string +% \begin{macrocode} + \ifx\@dtl@typeA\DTLunsettype + \let\@dtl@typeA\DTLstringtype + \fi +% \end{macrocode} +% Get the data type for the second key and store in \cs{@dtl@typeB} +% \begin{macrocode} + \DTLgetdatatype{\@dtl@typeB}{\@dtl@dbname}{#2}% +% \end{macrocode} +% Is it unset? If so, assume string +% \begin{macrocode} + \ifx\@dtl@typeB\DTLunsettype + \let\@dtl@typeB\DTLstringtype + \fi +% \end{macrocode} +% Multiply the two values together +% \begin{macrocode} + \@dtl@tmpcount=\@dtl@typeA\relax + \multiply\@dtl@tmpcount by \@dtl@typeB\relax +% \end{macrocode} +% If either type is 0 (a string) then the product will also be +% 0 (string) otherwise it will be one of the numerical types. +% \begin{macrocode} + \ifnum\@dtl@tmpcount=0\relax +% \end{macrocode} +% A string, so use comparison function +% \begin{macrocode} + \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 +% \end{macrocode} +% Store the first value +% \begin{macrocode} + \edef\@dtl@a{\the#3}% +% \end{macrocode} +% Store the second value +% \begin{macrocode} + \edef\@dtl@b{\the#4}% +% \end{macrocode} +% Compare +% \begin{macrocode} + \DTLifnumlt{\@dtl@a}{\@dtl@b}% + {% +% \end{macrocode} +% $A < B$ +% \begin{macrocode} + \dtl@sortresult=-1\relax + }% + {% + \DTLifnumgt{\@dtl@a}{\@dtl@b}% + {% +% \end{macrocode} +% $A > B$ +% \begin{macrocode} + \dtl@sortresult=1\relax + }% + {% +% \end{macrocode} +% $A = B$ +% \begin{macrocode} + \dtl@sortresult=0\relax + }% + }% + \fi +% \end{macrocode} +% Write comparison result to terminal/log if verbose mode. +% \begin{macrocode} + \ifdtlverbose + \@onelevel@sanitize\@dtl@a + \@onelevel@sanitize\@dtl@b + \dtl@message{`\@dtl@a' <=> `\@dtl@b' = \number\dtl@sortresult}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\subsection{General List Utilities} +% +%\begin{macro}{\dtl@choplast} +%\begin{definition} +% \cs{dtl@choplast}\marg{list}\marg{rest}\marg{last} +%\end{definition} +% Chops the last element off a comma separated list, putting the +% last element in the control sequence \meta{last} and putting +% the rest in the control sequence \meta{rest}. The control +% sequence \meta{list} is unchanged. If the list is empty, both +% \meta{last} and \meta{rest} will be empty. +% \begin{macrocode} +\newcommand*{\dtl@choplast}[3]{% +% \end{macrocode} +% Set \meta{rest} to empty: +% \begin{macrocode} +\let#2\@empty +% \end{macrocode} +% Set \meta{last} to empty: +% \begin{macrocode} +\let#3\@empty +% \end{macrocode} +% Iterate through \meta{list}: +% \begin{macrocode} +\@for\@dtl@element:=#1\do{% +\ifx#3\@empty +% \end{macrocode} +% First iteration, don't set \meta{rest}. +% \begin{macrocode} +\else + \ifx#2\@empty +% \end{macrocode} +% Second iteration, set \meta{rest} to \meta{last} (which is +% currently set to the previous value: +% \begin{macrocode} + \expandafter\toks@\expandafter{#3}% + \edef#2{{\the\toks@}}% + \else +% \end{macrocode} +% Subsequent iterations, set \meta{rest} to \meta{rest},\meta{last} +% (\meta{last} is currently set to the previous value): +% \begin{macrocode} + \expandafter\toks@\expandafter{#3}% + \expandafter\@dtl@toks\expandafter{#2}% + \edef#2{\the\@dtl@toks,{\the\toks@}}% + \fi +\fi +% \end{macrocode} +% Now set \meta{last} to current element. +% \begin{macrocode} +\let#3=\@dtl@element% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@chopfirst} +%\begin{definition} +% \cs{dtl@chopfirst}\marg{list}\marg{first}\marg{rest} +%\end{definition} +% Chops first element off \meta{list} and store in \meta{first}. +% The remainder of the list is stored in \meta{rest}. (\meta{list} +% remains unchanged.) +% \begin{macrocode} +\newcommand*{\dtl@chopfirst}[3]{% +\let#2=\@empty +\let#3=\@empty +\@for\@dtl@element:=#1\do{% + \let#2=\@dtl@element + \@endfortrue +}% +\if@endfor + \let#3=\@forremainder +\fi +\@endforfalse +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@sortlist} +%\begin{definition} +% \cs{dtl@sortlist}\marg{list}\marg{criteria cmd} +%\end{definition} +% Performs an insertion sort on \meta{list}, where \meta{criteria cmd} +% is a macro which takes two arguments \meta{a} and \meta{b}. +% \meta{criteria cmd} must set the count register \cs{dtl@sortresult} +% to either -1 (\meta{a} less than \meta{b}), 0 (\meta{a} is +% equal to \meta{b}) or 1 (\meta{a} is greater than \meta{b}.) +% \begin{macrocode} +\newcommand{\dtl@sortlist}[2]{% +\def\@dtl@sortedlist{}% +\@for\@dtl@currentrow:=#1\do{% +\expandafter\dtl@insertinto\expandafter + {\@dtl@currentrow}{\@dtl@sortedlist}{#2}% +\@endforfalse}% +\let#1=\@dtl@sortedlist +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@insertinto} +%\begin{definition} +% \cs{dtl@insertinto}\marg{element}\marg{sorted-list}\marg{criteria cmd} +%\end{definition} +% Inserts \meta{element} into the sorted list \meta{sorted-list} +% according to the criteria given by \meta{criteria cmd} (see above.) +% \begin{macrocode} +\newcommand{\dtl@insertinto}[3]{% +\def\@dtl@newsortedlist{}% +\@dtl@insertdonefalse +\@for\dtl@srtelement:=#2\do{% +\if@dtl@insertdone + \expandafter\toks@\expandafter{\dtl@srtelement}% + \edef\@dtl@newstuff{{\the\toks@}}% +\else + \expandafter#3\expandafter{\dtl@srtelement}{#1}% + \ifnum\dtl@sortresult<0\relax + \expandafter\toks@\expandafter{\dtl@srtelement}% + \@dtl@toks{#1}% + \edef\@dtl@newstuff{{\the\@dtl@toks},{\the\toks@}}% + \@dtl@insertdonetrue + \else + \expandafter\toks@\expandafter{\dtl@srtelement}% + \edef\@dtl@newstuff{{\the\toks@}}% + \fi +\fi +\ifx\@dtl@newsortedlist\@empty + \expandafter\toks@\expandafter{\@dtl@newstuff}% + \edef\@dtl@newsortedlist{\the\toks@}% +\else + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \expandafter\@dtl@toks\expandafter{\@dtl@newstuff}% + \edef\@dtl@newsortedlist{\the\toks@,\the\@dtl@toks}% +\fi +\@endforfalse +}% + \ifx\@dtl@newsortedlist\@empty + \@dtl@toks{#1}% + \edef\@dtl@newsortedlist{{\the\@dtl@toks}}% + \else + \if@dtl@insertdone + \else + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \@dtl@toks{#1}% + \edef\@dtl@newsortedlist{\the\toks@,{\the\@dtl@toks}}% + \fi + \fi +\global\let#2=\@dtl@newsortedlist +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\if@dtl@insertdone} +% Define conditional to indicate whether the new entry has +% been inserted into the sorted list. +% \begin{macrocode} +\newif\if@dtl@insertdone +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@sortresult} +% Define \cs{dtl@sortresult} to be set by comparision macro. +% \begin{macrocode} +\newcount\dtl@sortresult +% \end{macrocode} +%\end{macro} +% +% \subsection{General Token Utilities} +%\begin{macro}{\toks@gput@right@cx} +%\begin{definition} +%\cs{toks@gput@right@cx}\marg{toks name}\marg{stuff} +%\end{definition} +% Globally appends stuff to token register \cs{}\meta{toks name} +% \begin{macrocode} +\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}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\toks@gconcat@middle@cx} +%\begin{definition} +%\cs{toks@gconcat@middle@cx}\marg{toks name}\marg{before toks}\marg{stuff}\marg{after toks} +%\end{definition} +% Globally sets token register \cs{}\meta{toks name} to +% the contents of \meta{before toks} concatenated with +% \meta{stuff} (expanded) and the contents of \meta{after toks} +% \begin{macrocode} +\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}% +} +% \end{macrocode} +%\end{macro} +% +% \subsection{Floating Point Arithmetic} +% The commands defined in this section all use the equivalent +% commands provided by the \sty{fp} package, but first convert +% the decimal number into the required format. +% +%\begin{macro}{\DTLadd} +%\begin{definition} +% \cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} + \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLadd}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPadd{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgadd} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgadd}[3]{% +\DTLadd{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLaddall} +%\begin{definition} +%\cs{DTLaddall}\marg{cmd}\marg{num list} +%\end{definition} +% Sums all the values in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLaddall}[2]{% +\def\@dtl@sum{0}% +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \FPadd{\@dtl@sum}{\@dtl@sum}{\@dtl@num}% +}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@sum}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@sum}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgaddall} +%\begin{definition} +%\cs{DTLgaddall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgaddall}[2]{% +\DTLaddall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsub} +%\begin{definition} +% \cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} - \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLsub}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPsub{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgsub} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgsub}[3]{% +\DTLsub{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmul} +%\begin{definition} +% \cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} $\times$ \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLmul}[3]{% +\let\@dtl@thisreplaced=\@empty +\DTLconverttodecimal{#2}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty +\else + \let\@dtl@thisreplaced=\@dtl@replaced +\fi +\DTLconverttodecimal{#3}{\@dtl@numii}% +\ifx\@dtl@replaced\@empty +\else + \let\@dtl@thisreplaced=\@dtl@replaced +\fi +\FPmul{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@thisreplaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmul} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmul}[3]{% +\DTLmul{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLdiv} +%\begin{definition} +% \cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} / \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLdiv}[3]{% +\let\@dtl@thisreplaced=\@empty +\DTLconverttodecimal{#2}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty +\else + \let\@dtl@thisreplaced=\@dtl@replaced +\fi +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPdiv{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\ifx\@dtl@thisreplaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \ifx\@dtl@thisreplaced\@dtl@replaced + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + \else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + \fi +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgdiv} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgdiv}[3]{% +\DTLdiv{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLabs} +%\begin{definition} +% \cs{DTLabs}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = abs(\meta{num}) +% \begin{macrocode} +\newcommand*{\DTLabs}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPabs{\@dtl@tmp}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgabs} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgabs}[2]{% +\DTLabs{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLneg} +%\begin{definition} +% \cs{DTLneg}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = -\meta{num} +% \begin{macrocode} +\newcommand*{\DTLneg}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPneg{\@dtl@tmp}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgneg} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgneg}[2]{% +\DTLneg{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsqrt} +%\begin{definition} +% \cs{DTLsqrt}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = sqrt(\meta{num}) +% \begin{macrocode} +\newcommand*{\DTLsqrt}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FProot{\@dtl@tmpi}{\@dtl@numi}{2}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmpi}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmpi}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgsqrt} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgsqrt}[2]{% +\DTLsqrt{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmin} +%\begin{definition} +% \cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = min(\meta{num1}, \meta{num2}) +% \begin{macrocode} +\newcommand*{\DTLmin}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPiflt{\@dtl@numi}{\@dtl@numii}% + \dtl@ifsingle{#2}{% + \let#1=#2}{% + \def#1{#2}}% +\else + \dtl@ifsingle{#3}{% + \let#1=#3}{% + \def#1{#3}}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmin} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmin}[3]{% +\DTLmin{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLminall} +%\begin{definition} +%\cs{DTLminall}\marg{cmd}\marg{num list} +%\end{definition} +% Finds the minimum value in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLminall}[2]{% +\let\@dtl@min=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@min\@empty + \let\@dtl@min=\@dtl@num + \else + \FPmin{\@dtl@min}{\@dtl@min}{\@dtl@num}% + \fi +}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@min}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@min}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgminall} +%\begin{definition} +%\cs{DTLgminall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgminall}[2]{% +\DTLminall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmax} +%\begin{definition} +% \cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = max(\meta{num1}, \meta{num2}) +% \begin{macrocode} +\newcommand*{\DTLmax}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\DTLconverttodecimal{#3}{\@dtl@numii}% +\FPmax{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% +\FPifgt{\@dtl@numi}{\@dtl@numii}% + \dtl@ifsingle{#2}{% + \let#1=#2}{% + \def#1{#2}}% +\else + \dtl@ifsingle{#3}{% + \let#1=#3}{% + \def#1{#3}}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmax} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmax}[3]{% +\DTLmax{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmaxall} +%\begin{definition} +%\cs{DTLmaxall}\marg{cmd}\marg{num list} +%\end{definition} +% Finds the maximum value in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLmaxall}[2]{% +\let\@dtl@max=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@max\@empty + \let\@dtl@max\@dtl@num + \else + \FPmax{\@dtl@max}{\@dtl@max}{\@dtl@num}% + \fi +}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@max}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@max}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmaxall} +%\begin{definition} +%\cs{DTLgmaxall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmaxall}[2]{% +\DTLmaxall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmeanforall} +%\begin{definition} +%\cs{DTLmeanforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the arithmetic mean of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLmeanforall}[2]{% +\def\@dtl@mean{0}% +\def\@dtl@n{0}% +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \FPadd{\@dtl@n}{\@dtl@n}{1}% +}% +\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@mean}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@mean}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmeanforall} +%\begin{definition} +%\cs{DTLgmeanforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmeanforall}[2]{% +\DTLmeanforall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLvarianceforall} +%\begin{definition} +%\cs{DTLvarianceforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the variance of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{fixed bug} +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLvarianceforall}[2]{% +\def\@dtl@mean{0}% +\def\@dtl@n{0}% +\let\@dtl@decvals=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@decvals\@empty + \let\@dtl@decvals=\@dtl@num + \else + \expandafter\toks@\expandafter{\@dtl@decvals}% + \edef\@dtl@decvals{\the\toks@,\@dtl@num}% + \fi + \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \FPadd{\@dtl@n}{\@dtl@n}{1}% +}% +\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% +\def\@dtl@var{0}% +\@for\@dtl@num:=\@dtl@decvals\do{% + \FPsub{\@dtl@diff}{\@dtl@num}{\@dtl@mean}% + \FPmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% + \FPadd{\@dtl@var}{\@dtl@var}{\@dtl@diff}% +}% +\FPdiv{\@dtl@var}{\@dtl@var}{\@dtl@n}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@var}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@var}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgvarianceforall} +%\begin{definition} +%\cs{DTLgvarianceforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgvarianceforall}[2]{% +\DTLvarianceforall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsdforall} +%\begin{definition} +%\cs{DTLsdforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the standard deviation of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{fixed bug} +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLsdforall}[2]{% +\def\@dtl@mean{0}% +\def\@dtl@n{0}% +\let\@dtl@decvals=\@empty +\@for\dtl@thisval:=#2\do{% + \DTLconverttodecimal{\dtl@thisval}{\@dtl@num}% + \ifx\@dtl@decvals\@empty + \let\@dtl@decvals=\@dtl@num + \else + \expandafter\toks@\expandafter{\@dtl@decvals}% + \edef\@dtl@decvals{\the\toks@,\@dtl@num}% + \fi + \FPadd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \FPadd{\@dtl@n}{\@dtl@n}{1}% +}% +\FPdiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% +\def\@dtl@sd{0}% +\@for\@dtl@num:=\@dtl@decvals\do{% + \FPsub{\@dtl@diff}{\@dtl@num}{\@dtl@mean}% + \FPmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% + \FPadd{\@dtl@sd}{\@dtl@sd}{\@dtl@diff}% +}% +\FPdiv{\@dtl@sd}{\@dtl@sd}{\@dtl@n}% +\FProot{\@dtl@sd}{\@dtl@sd}{2}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@sd}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@sd}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgsdforall} +%\begin{definition} +%\cs{DTLgsdforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgsdforall}[2]{% +\DTLsdforall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLround} +%\begin{definition} +% \cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +% Sets \meta{cmd} to \meta{num} rounded to \meta{num digits} +% digits after the decimal character. +% \begin{macrocode} +\newcommand*{\DTLround}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPround{\@dtl@tmp}{\@dtl@numi}{#3}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLground} +% Global version +% \begin{macrocode} +\newcommand*{\DTLground}[3]{% +\DTLround{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtrunc} +%\begin{definition} +% \cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +% Sets \meta{cmd} to \meta{num} truncated to \meta{num digits} +% digits after the decimal character. +% \begin{macrocode} +\newcommand*{\DTLtrunc}[3]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPtrunc{\@dtl@tmp}{\@dtl@numi}{#3}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgtrunc} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgtrunc}[3]{% +\DTLtrunc{\@dtl@tmpii}{#2}{#3}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLclip} +%\begin{definition} +% \cs{DTLclip}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} to \meta{num} with all unnecessary 0's removed. +% \begin{macrocode} +\newcommand*{\DTLclip}[2]{% +\DTLconverttodecimal{#2}{\@dtl@numi}% +\FPclip{\@dtl@tmp}{\@dtl@numi}% +\ifx\@dtl@replaced\@empty + \DTLdecimaltolocale{\@dtl@tmp}{#1}% +\else + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgclip} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgclip}[3]{% +\DTLclip{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\subsection{String Macros} +%\begin{macro}{\DTLinitials} +%\begin{definition} +%\cs{DTLinitials}\marg{string} +%\end{definition} +% Convert a string into initials. +% (Any "~" character found is first converted into a space.) +%\changes{1.01}{2007 Aug 17}{now works with unbreakable space symbol} +%\changes{1.01}{2007 Aug 17}{now uses \cs{DTLinitialhyphen}} +% \begin{macrocode} +\newcommand*\DTLinitials[1]{% +\def\dtl@initialscmd{}% +\dtl@subnobrsp{#1}{\dtl@string}% +\DTLsubstituteall{\dtl@string}{~}{ }% +\DTLsubstituteall{\dtl@string}{\ }{ }% +\DTLsubstituteall{\dtl@string}{\space}{ }% +\expandafter\dtl@initials\dtl@string{} \@nil% +\dtl@initialscmd}% +% \end{macrocode} +%\end{macro} +% The following substitutes "\protect \nobreakspace {}" with +% a space. (Note that in this case the space following +% "\nobreakspace" forms part of the command.) +% \begin{macrocode} +\edef\dtl@construct@subnobrsp{% +\noexpand\def\noexpand\@dtl@subnobrsp##1\noexpand\protect +\expandafter\noexpand\csname nobreakspace \endcsname ##2{% +\noexpand\toks@{##1}% +\noexpand\expandafter\noexpand\@dtl@toks\noexpand\expandafter{% +\noexpand\@dtl@string}% +\noexpand\edef\noexpand\@dtl@string{\noexpand\the\noexpand\@dtl@toks +\noexpand\the\noexpand\toks@}% +\noexpand\def\noexpand\@dtl@tmp{##2}% +\noexpand\ifx\noexpand\@dtl@tmp\noexpand\@nnil + \noexpand\let\noexpand\@dtl@subnobrspnext=\noexpand\relax +\noexpand\else + \noexpand\toks@{ }% + \noexpand\expandafter\noexpand\@dtl@toks\noexpand\expandafter{% + \noexpand\@dtl@string}% + \noexpand\edef\noexpand\@dtl@string{\noexpand\the\noexpand\@dtl@toks + \noexpand\the\noexpand\toks@}% + \noexpand\let\noexpand\@dtl@subnobrspnext=\noexpand\@dtl@subnobrsp +\noexpand\fi +\noexpand\@dtl@subnobrspnext +}% +\noexpand\def\noexpand\dtl@subnobrsp##1##2{% +\noexpand\def\noexpand\@dtl@string{}% +\noexpand\@dtl@subnobrsp ##1\noexpand\protect\expandafter\noexpand +\csname nobreakspace \endcsname \noexpand\@nil +\noexpand\let##2=\noexpand\@dtl@string +}} +\dtl@construct@subnobrsp +% \end{macrocode} +% +%\begin{macro}{\DTLstoreinitials} +%\begin{definition} +%\cs{DTLstoreinitials}\marg{string}\marg{cmd} +%\end{definition} +% Convert a string into initials and store in \meta{cmd}. +% (Any "~" character found is first converted into a space.) +%\changes{1.01}{2007 Aug 17}{now works with unbreakable space symbol} +%\changes{1.01}{2007 Aug 17}{now uses \cs{DTLinitialhyphen}} +% \begin{macrocode} +\newcommand*{\DTLstoreinitials}[2]{% +\def\dtl@initialscmd{}% +\dtl@subnobrsp{#1}{\dtl@string}% +\DTLsubstituteall{\dtl@string}{~}{ }% +\DTLsubstituteall{\dtl@string}{\ }{ }% +\DTLsubstituteall{\dtl@string}{\space}{ }% +\expandafter\dtl@initials\dtl@string{} \@nil +\let#2=\dtl@initialscmd +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@initials} +% \begin{macrocode} +\def\dtl@initials#1#2 #3{% +\dtl@ifsingle{#1}{% +\ifcat\noexpand#1\relax\relax + \def\@dtl@donextinitials{\@dtl@initials#2 {#3}}% +\else + \def\@dtl@donextinitials{\@dtl@initials#1#2 {#3}}% +\fi +}{% + \def\@dtl@donextinitials{\@dtl@initials{#1}#2 {#3}}% +}% +\@dtl@donextinitials +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@initials} +% \begin{macrocode} +\def\@dtl@initials#1#2 #3{% +\dtl@initialshyphen#2-{}\dtl@endhyp +\expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% +\toks@{#1}% +\ifx\dtl@inithyphen\@empty +\else + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@}% + \expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% + \expandafter\toks@\expandafter{\dtl@inithyphen}% +\fi +\def\dtl@tmp{#3}% +\ifx\@nnil\dtl@tmp + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLafterinitials}% + \let\dtl@initialsnext=\@gobble +\else + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLbetweeninitials}% + \let\dtl@initialsnext=\dtl@initials +\fi +\dtl@initialsnext{#3}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@initialshyphen} +% \begin{macrocode} +\def\dtl@initialshyphen#1-#2#3\dtl@endhyp{% +\def\dtl@inithyphen{#2}% +\ifx\dtl@inithyphen\@empty +\else + \edef\dtl@inithyphen{% + \DTLafterinitialbeforehyphen\DTLinitialhyphen#2}% +\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLafterinitials} +% Defines what to do after the final initial. +% \begin{macrocode} +\newcommand*{\DTLafterinitials}{.} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLbetweeninitials} +% Defines what to do between initials. +% \begin{macrocode} +\newcommand*{\DTLbetweeninitials}{.} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLafterinitialbeforehyphen} +% Defines what to do before a hyphen. +% \begin{macrocode} +\newcommand*{\DTLafterinitialbeforehyphen}{.} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLinitialhyphen} +%Defines what to do at the hyphen +%\changes{1.01}{2007 Aug 17}{new} +% \begin{macrocode} +\newcommand*{\DTLinitialhyphen}{-} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLifAllUpperCase} +%\begin{definition} +%\cs{DTLifAllUpperCase}\marg{string}\marg{true part}\marg{false part} +%\end{definition} +% If \meta{string} only contains uppercase characters do \meta{true +%part}, otherwise do \meta{false part}. +% \begin{macrocode} +\newcommand*{\DTLifAllUpperCase}[3]{% +\protected@edef\dtl@tuc{#1}% +\expandafter\dtl@testifuppercase\dtl@tuc\@nil\relax +\if@dtl@condition#2\else#3\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testifalluppercase} +% \begin{macrocode} +\def\dtl@testifuppercase#1#2{% +\def\dtl@argi{#1}% +\def\dtl@argii{#2}% +\def\dtl@tc@rest{}% +\ifx\dtl@argi\@nnil + \let\dtl@testifuppernext=\@nnil +\else + \ifx#1\protect + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \ifx\uppercase#1\relax + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax + \else + \edef\dtl@tc@arg{\string#1}% + \expandafter\dtl@test@ifuppercase\dtl@tc@arg\end + \ifx\dtl@argii\@nnil + \let\dtl@testifuppernext=\@dtl@gobbletonil + \fi + \fi + \fi +\fi +\ifx\dtl@testifuppernext\relax + \edef\dtl@dotestifuppernext{% + \noexpand\dtl@testifuppercase}% +\else + \ifx\dtl@testifuppernext\@nnil + \edef\dtl@dotestifuppernext{#2}% + \else + \expandafter\toks@\expandafter{\dtl@tc@rest}% + \@dtl@toks{#2}% + \edef\dtl@dotestifuppernext{% + \noexpand\dtl@testifuppernext\the\toks@\the\@dtl@toks}% + \fi +\fi +\dtl@dotestifuppernext +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@test@ifalluppercase} +% \begin{macrocode} +\def\dtl@test@ifuppercase#1#2\end{% +\def\dtl@tc@rest{#2}% +\IfSubStringInString{\string\MakeUppercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax +}{% + \IfSubStringInString{\string\MakeTextUppercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax + }{% + \edef\dtl@uccode{\the\uccode`#1}% + \edef\dtl@code{\number`#1}% + \ifnum\dtl@code=\dtl@uccode\relax + \@dtl@conditiontrue + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \ifnum\dtl@uccode=0\relax + \@dtl@conditiontrue + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \@dtl@conditionfalse + \let\dtl@testifuppernext=\@dtl@gobbletonil + \fi + \fi +}}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLifAllLowerCase} +%\begin{definition} +%\cs{DTLifAllLowerCase}\marg{string}\marg{true part}\marg{false part} +%\end{definition} +% If \meta{string} only contains lowercase characters do \meta{true +%part}, otherwise do \meta{false part}. +% \begin{macrocode} +\newcommand*{\DTLifAllLowerCase}[3]{% +\protected@edef\dtl@tlc{#1}% +\expandafter\dtl@testiflowercase\dtl@tlc\@nil\relax +\if@dtl@condition#2\else#3\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testifalllowercase} +% \begin{macrocode} +\def\dtl@testiflowercase#1#2{% +\def\dtl@argi{#1}% +\def\dtl@argii{#2}% +\ifx\dtl@argi\@nnil + \let\dtl@testiflowernext=\@nnil +\else + \ifx#1\protect + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \ifx\lowercase#1\relax + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax + \else + \edef\dtl@tc@arg{\string#1}% + \expandafter\dtl@test@iflowercase\dtl@tc@arg\end + \ifx\dtl@argii\@nnil + \let\dtl@testiflowernext=\@dtl@gobbletonil + \fi + \fi + \fi +\fi +\ifx\dtl@testiflowernext\relax + \edef\dtl@dotestiflowernext{% + \noexpand\dtl@testiflowercase}% +\else + \ifx\dtl@testiflowernext\@nnil + \edef\dtl@dotestiflowernext{#2}% + \else + \expandafter\toks@\expandafter{\dtl@tc@rest}% + \@dtl@toks{#2}% + \edef\dtl@dotestiflowernext{% + \noexpand\dtl@testiflowernext\the\toks@\the\@dtl@toks}% + \fi +\fi +\dtl@dotestiflowernext +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@test@ifalllowercase} +% \begin{macrocode} +\def\dtl@test@iflowercase#1#2\end{% +\def\dtl@tc@rest{#2}% +\IfSubStringInString{\string\MakeLowercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax +}{% + \IfSubStringInString{\string\MakeTextLowercase}{#1#2}{% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax + }{% + \edef\dtl@lccode{\the\lccode`#1}% + \edef\dtl@code{\number`#1}% + \ifnum\dtl@code=\dtl@lccode\relax + \@dtl@conditiontrue + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \ifnum\dtl@lccode=0\relax + \@dtl@conditiontrue + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \@dtl@conditionfalse + \let\dtl@testiflowernext=\@dtl@gobbletonil + \fi + \fi +}}} +% \end{macrocode} +%\end{macro} +% +%\subsection{Saving a database to an external file} +% +%\begin{macro}{\@dtl@write} +% \begin{macrocode} +\newwrite\@dtl@write +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLsavedb} +%\begin{definition} +% \cs{DTLsavedb}\marg{db name}\marg{filename} +%\end{definition} +% Save a database as an ASCII data file using the separator +% and delimiter given by \cs{@dtl@separator} and \cs{@dtl@delimiter}. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\DTLsavedb}[2]{% + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Open output file +% \begin{macrocode} + \openout\@dtl@write +% \end{macrocode} +% Initialise header row +% \begin{macrocode} + \def\@dtl@header{}% +% \end{macrocode} +% Construct the header row +% \begin{macrocode} + \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 + }% + }% +% \end{macrocode} +% Print header +% \begin{macrocode} + \protected@write\@dtl@write{}{\@dtl@header}% +% \end{macrocode} +% Iterate through each row +% \begin{macrocode} + \@sDTLforeach{#1}{}% + {% +% \end{macrocode} +% Initialise row +% \begin{macrocode} + \def\@dtl@row{}% +% \end{macrocode} +% Iterate through each key +% \begin{macrocode} + \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 + }% +% \end{macrocode} +% Print row +% \begin{macrocode} + \protected@write\@dtl@write{}{\@dtl@row}% + }% + }% +% \end{macrocode} +% Close output file +% \begin{macrocode} + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsavetexdb} +%\begin{definition} +% \cs{DTLsavetexdb}\marg{db name}\marg{filename} +%\end{definition} +% Save a database as a \LaTeX\ file. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\DTLsavetexdb}[2]{% + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Open output file +% \begin{macrocode} + \openout\@dtl@write=#2\relax +% \end{macrocode} +% Write new data base definition +% \begin{macrocode} + \protected@write\@dtl@write{}{\string\DTLnewdb{#1}}% +% \end{macrocode} +% Iterate through each row +% \begin{macrocode} + \@sDTLforeach{#1}{}% + {% +% \end{macrocode} +% Start new row +% \begin{macrocode} + \protected@write\@dtl@write{}{\string\DTLnewrow*{#1}}% +% \end{macrocode} +% Iterate through each column +% \begin{macrocode} + \DTLforeachkeyinrow{\@dtl@val}% + {% +% \end{macrocode} +% Is this entry null? +% \begin{macrocode} + \DTLifnull{\@dtl@val}% + {\def\@dtl@val{}}% + {}% +% \end{macrocode} +% Add entry +% \begin{macrocode} + \protected@write\@dtl@write{}{% + \string\DTLnewdbentry*{#1}{\dtlkey}{\@dtl@val}}% + }% + }% +% \end{macrocode} +% Save the column headers. +% \begin{macrocode} + \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}}% + }% +% \end{macrocode} +% Close output file +% \begin{macrocode} + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Loading a database from an external file} +% +% \begin{macrocode} +\newcommand{\@longempty}{} +% \end{macrocode} +%\begin{macro}{\@dtl@read} +% \begin{macrocode} +\newread\@dtl@read +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@entrycr} +% Keep track of current column in data file +% \begin{macrocode} +\newcount\dtl@entrycr +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifdtlnoheader} +% The "noheader" option indicates that the file doesn't have a +% header row. +% \begin{macrocode} +\define@boolkey{loaddb}[dtl]{noheader}[true]{} +% \end{macrocode} +%\end{macro} +% The "keys" option specifies the list of keys in the same order +% as the columns in the data file. +% Each key is stored in \cs{@dtl@inky@}\meta{n} where \meta{n} is the +% roman numeral representation of the current column. +% \begin{macrocode} +\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}% + }% +} +% \end{macrocode} +% The "headers" option specifies the list of headers in the +% same order as the columns in the data file. +% \begin{macrocode} +\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@}% + }% +} +% \end{macrocode} +% +%\begin{macro}{\dtldefaultkey} +% Default key to use if none specified (column index will be +% appended). +% \begin{macrocode} +\newcommand*{\dtldefaultkey}{Column} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@readline} +%\begin{definition} +%\cs{@dtl@readline}\marg{file reg}\marg{cs} +%\end{definition} +% Reads line from \meta{file reg}, trims end of line character +% and stores in \meta{cs}. +% \begin{macrocode} +\newcommand*{\@dtl@readline}[2]{% +% Read a line from "#1" and store in "#2" +% \begin{macrocode} + \read#1 to #2% +% \end{macrocode} +% Trim the end of line character +% \begin{macrocode} + \dtl@trim#2% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@readrawline} +%\begin{definition} +%\cs{@dtl@readrawline}\marg{file register}\marg{cs} +%\end{definition} +% Reads line from \meta{file register}, trims end of line character, +% applies mappings and stores in \meta{cs}. +% \begin{macrocode} +\newcommand*{\@dtl@readrawline}[2]{% +% Read a line from "#1" and store in "#2" +% \begin{macrocode} + \@dtl@rawread#1 to #2% +% \end{macrocode} +% Trim the end of line character +% \begin{macrocode} + \dtl@trim#2% +% \end{macrocode} +% Apply mappings +% \begin{macrocode} + \dtl@domappings\@dtl@line +} +% \end{macrocode} +%\end{macro} + +%\begin{macro}{\DTLloaddb} +%\begin{definition} +% \cs{DTLloaddb}\oarg{options}\marg{db name}\marg{filename} +%\end{definition} +% Creates a new database called \meta{db name}, and loads the data +% in \meta{filename} into it. The separator and delimiter used in +% the file must match \cs{@dtl@separator} and \cs{@dtl@delimiter}. +% The optional argument is a comma-separated list. +%\changes{2.0}{2009 February 27}{removed checks to see if the +% database exists when adding to it} +%\changes{2.0}{2009 February 27}{added optional argument} +% \begin{macrocode} +\newcommand*{\DTLloaddb}{% + \let\@dtl@doreadline\@dtl@readline + \@dtlloaddb +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlloaddb} +% Loads database using \cs{@dtl@doreadline} to read and trim +% line from file. (\cs{@dtl@doreadline} must be set before use.) +% \begin{macrocode} +\newcommand*{\@dtlloaddb}[3][]{% +% \end{macrocode} +% Check if file exists +% \begin{macrocode} + \IfFileExists{#3}{% +% \end{macrocode} +% File exists. Locally change catcode of double quote character in +% case it has been made active. +% \begin{macrocode} + \begingroup + \catcode`\"12\relax +% \end{macrocode} +% Initialise default options +% \begin{macrocode} + \dtlnoheaderfalse +% \end{macrocode} +% Get the options +% \begin{macrocode} + \setkeys{loaddb}{#1}% +% \end{macrocode} +% Open the file for reading. +% \begin{macrocode} + \openin\@dtl@read=#3% + \dtl@message{Reading `#3'}% +% \end{macrocode} +% Create the new database. +% \begin{macrocode} + \DTLnewdb{#2}% +% \end{macrocode} +% Check if the file is empty. +% \begin{macrocode} + \ifeof\@dtl@read +% \end{macrocode} +% File is empty, so just issue a warning. +% \begin{macrocode} + \PackageWarning{datatool}{File `#3' has no data}% + \else +% \end{macrocode} +% Does the file have a header row? +% \begin{macrocode} + \ifdtlnoheader + \else +% \end{macrocode} +% Remove initial blank rows +% \begin{macrocode} + \loop +% \end{macrocode} +% Set repeat condition to false +% \begin{macrocode} + \@dtl@conditionfalse +% \end{macrocode} +% Do nothing if reached the end of file +% \begin{macrocode} + \ifeof\@dtl@read + \else +% \end{macrocode} +% Read a line from the file and store in \cs{@dtl@line} +% \begin{macrocode} + \@dtl@doreadline\@dtl@read\@dtl@line +% \end{macrocode} +% If this is a blank row, set repeat condition to true +% \begin{macrocode} + \ifx\@dtl@line\@longempty + \@dtl@conditiontrue + \fi + \fi +% \end{macrocode} +% Repeat loop if necessary +% \begin{macrocode} + \if@dtl@condition + \repeat +% \end{macrocode} +% Parse the header row. Store the row as +% \meta{sep}\meta{row}\meta{sep} in \cs{@dtl@lin@}. +% \begin{macrocode} + \protected@edef\@dtl@lin@{% + \@dtl@separator\@dtl@line\@dtl@separator}% +% \end{macrocode} +% Keep track of columns: +% \begin{macrocode} + \dtl@entrycr=0\relax +% \end{macrocode} +% Keep lopping off elements until the end of the row is reached. +% (That is, until \cs{@dtl@lin@} is \cs{@dtl@separator}.) +%\changes{2.0}{2009 February 27}{changed \cs{whiledo} to +% \cs{loop} to improve efficiency}% +% \begin{macrocode} + \loop +% \end{macrocode} +% Lopoff the first element and store in \cs{@dtl@key} +% \begin{macrocode} + \expandafter\@dtl@lopoff\@dtl@lin@\to\@dtl@lin@\@dtl@key +% \end{macrocode} +% Increment column count. +% \begin{macrocode} + \advance\dtl@entrycr by 1\relax +% \end{macrocode} +% Store key in \cs{@dtl@toks} +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{\@dtl@key}% +% \end{macrocode} +% Store the key in \cs{@dtl@inky@}\meta{n} where \meta{n} is the +% roman numeral representation of the current column, unless +% already defined. +% \begin{macrocode} + \@ifundefined{@dtl@inky@\romannumeral\dtl@entrycr}% + {% + \expandafter + \edef\csname @dtl@inky@\romannumeral + \dtl@entrycr\endcsname{\the\@dtl@toks}% + }% + {% +% \end{macrocode} +% If key has been specified in "#1", then use the header found in the +% file, unless a header has also been specified in "#1" +% \begin{macrocode} + \@ifundefined{@dtl@inhd@\romannumeral\dtl@entrycr}% + {% + \expandafter + \edef\csname @dtl@inhd@\romannumeral + \dtl@entrycr\endcsname{\the\@dtl@toks}% + }% + {}% + }% +% \end{macrocode} +% Check if the loop should be repeated +% \begin{macrocode} + \ifx\@dtl@lin@\@dtl@separator + \@dtl@conditionfalse + \else + \@dtl@conditiontrue + \fi +% \end{macrocode} +% Repeat loop if necessary. +% \begin{macrocode} + \if@dtl@condition + \repeat +% \end{macrocode} +% End if no header +% \begin{macrocode} + \fi +% \end{macrocode} +% Now for the rest of the data. If the end of file has been +% reached, then only the header row is available or file is empty. +% \begin{macrocode} + \ifeof\@dtl@read + \ifdtlnoheader + \PackageWarning{datatool}{No data in `#3'}% + \else + \PackageWarning{datatool}{Only header row found in `#3'}% + \fi + \else +% \end{macrocode} +% Iterate through the rest of the file. First set the repeat +% condition to true: +% \begin{macrocode} + \@dtl@conditiontrue + \loop +% \end{macrocode} +% Read in a line +% \begin{macrocode} + \@dtl@doreadline\@dtl@read\@dtl@line +% \end{macrocode} +% Check if the line is empty. +%\changes{2.0}{2009 February 27}{changed \cs{ifthenelse} to +%\cs{ifx} to improve efficiency} +% \begin{macrocode} + \ifx\@dtl@line\@longempty +% \end{macrocode} +% Do nothing if the row is empty. +% \begin{macrocode} + \else +% \end{macrocode} +% Add a new row to the database. (Don't need to check if the +% database exists, since it's just been created.) +% \begin{macrocode} + \@sDTLnewrow{#2}% +% \end{macrocode} +% Store the row as \meta{sep}\meta{row}\meta{sep} to make the +% lopping off easier +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{\@dtl@line}% + \edef\@dtl@lin@{\@dtl@separator\the\@dtl@toks + \@dtl@separator}% +% \end{macrocode} +% Reset the column counter. +% \begin{macrocode} + \dtl@entrycr=0\relax +% \end{macrocode} +%\changes{2.0}{2009 February 27}{changed \cs{whiledo} to \cs{loop} +% to improve efficiency} +% Iterate through each element in the row. Needs to be grouped +% since we're already inside a loop. +% \begin{macrocode} + {% +% \end{macrocode} +% Initialise repeat condition +% \begin{macrocode} + \@dtl@conditiontrue +% \end{macrocode} +% Iterate through the list +% \begin{macrocode} + \loop +% \end{macrocode} +% lop off first element and store in \cs{@dtl@thisentry} +% \begin{macrocode} + \expandafter\@dtl@lopoff\@dtl@lin@\to + \@dtl@lin@\@dtl@thisentry +% \end{macrocode} +% Increment the column count. +% \begin{macrocode} + \advance\dtl@entrycr by 1\relax +% \end{macrocode} +% Get the key for this column and store in \cs{@dtl@thiskey}. +% Use default value if not defined. +% \begin{macrocode} + \@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}% + }% +% \end{macrocode} +% Store this entry in \cs{@dtl@toks} +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{\@dtl@thisentry}% % \end{macrocode} -%\end{macro} -% -%\subsection{Saving a database to an external file} -% -%\begin{macro}{\@dtl@write} +% Add this entry to the database % \begin{macrocode} -\newwrite\@dtl@write + \edef\@do@dtlnewentry{\noexpand\@sDTLnewdbentry + {#2}{\@dtl@thiskey}{\the\@dtl@toks}}% + \@do@dtlnewentry % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLsavedb} -%\begin{definition} -% \cs{DTLsavedb}\marg{db name}\marg{filename} -%\end{definition} -% Save a database as an ASCII data file using the separator -% and delimiter given by \cs{@dtl@separator} and \cs{@dtl@delimiter}. +% Check if loop should be terminated % \begin{macrocode} -\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}{}% -}} + \ifx\@dtl@lin@\@dtl@separator + \@dtl@conditionfalse + \fi % \end{macrocode} -%\end{macro} -% -%\begin{macro}{\DTLsavetexdb} -%\begin{definition} -% \cs{DTLsavetexdb}\marg{db name}\marg{filename} -%\end{definition} -% Save a database as a \LaTeX\ file. +% Repeat loop if necessary % \begin{macrocode} -\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}{}% -}} + \if@dtl@condition + \repeat + }% % \end{macrocode} -%\end{macro} -% -%\subsection{Loading a database from an external file} -% -%\begin{macro}{\@dtl@read} +% End of parsing this row % \begin{macrocode} -\newread\@dtl@read + \fi % \end{macrocode} -%\end{macro} -%\begin{macro}{\dtl@entrycr} -% Keep track of current column in data file +% If the end of file has been reached, set the repeat condition +% to false. % \begin{macrocode} -\newcount\dtl@entrycr + \ifeof\@dtl@read \@dtl@conditionfalse\fi % \end{macrocode} -%\end{macro} -%\begin{macro}{\DTLloaddb} -%\begin{definition} -% \cs{DTLloaddb}\marg{db name}\marg{filename} -%\end{definition} -% Creates a new database called \meta{db name}, and load the data in -% \meta{filename} into it. The separator and delimiter used in -% the file must match \cs{@dtl@separator} and \cs{@dtl@delimiter}. +% Repeat if necessary +% \begin{macrocode} + \if@dtl@condition + \repeat + \fi +% \end{macrocode} +% End of first \cs{ifeof} % \begin{macrocode} -\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 - \ifeof\@dtl@read - \else - \read\@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 - \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)}{}% -}} +% \end{macrocode} +% Close the input file +% \begin{macrocode} + \closein\@dtl@read +% \end{macrocode} +% Set the headers if required +% \begin{macrocode} + \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 + }% + }% +% \end{macrocode} +% End current scope +% \begin{macrocode} + \endgroup +% \end{macrocode} +% End true part of if file exists +% \begin{macrocode} + }{% +% \end{macrocode} +% Requested file not found on TeX's path +% \begin{macrocode} + \PackageError{datatool}{Can't load database `#2' (file `#3' + doesn't exist)}{}% + }% +} % \end{macrocode} %\end{macro} % @@ -12110,75 +16841,10 @@ doesn't exist)}{}% % "~" $\to$ "\textasciitilde", "_" $\to$ "\_" % and "^" $\to$ "\textasciicircum".) % \begin{macrocode} -\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 +} % \end{macrocode} %\end{macro} % @@ -12380,6 +17046,31 @@ doesn't exist)}{}% % \end{macrocode} %\end{macro} % +%\begin{macro}{\DTLifinlist} +%\cs{DTLifinlist}\marg{element}\marg{list}\marg{true part}\marg{false part} +% If \meta{element} is contained in the comma-separated list given +% by \meta{list}, then do \meta{true part} otherwise do false +% part. (Does a one level expansion on \meta{list}) +% \begin{macrocode} +\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 +% not found + #4% + \else +% found + #3% + \fi +} +% \end{macrocode} +%\end{macro} +% +% %\subsection{Currencies} %\begin{macro}{\@dtl@currencies} % \cs{@dtl@currencies} stores all known currencies. @@ -12495,9 +17186,10 @@ doesn't exist)}{}% %\cs{dtlshowdb}\marg{db name} %\end{definition} % Shows the database. +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} \newcommand*{\dtlshowdb}[1]{% -\expandafter\show\csname dtldb@#1\endcsname} +\expandafter\showthe\csname dtldb@#1\endcsname} % \end{macrocode} %\end{macro} % @@ -12506,9 +17198,10 @@ doesn't exist)}{}% %\cs{dtlshowdbkeys}\marg{db name} %\end{definition} % Shows the key list for the named database. +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} \newcommand*{\dtlshowdbkeys}[1]{% -\expandafter\show\csname dtlkeys@#1\endcsname} +\expandafter\showthe\csname dtlkeys@#1\endcsname} % \end{macrocode} %\end{macro} % @@ -12518,9 +17211,11 @@ doesn't exist)}{}% %\end{definition} % Show the data type for given key in the named database. % This should be an integer from 0 to 3. +%\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} \newcommand*{\dtlshowtype}[2]{% -\expandafter\show\csname @dtl@idtype@#1@#2\endcsname} + \DTLgetdatatype{\@dtl@type}{#1}{#2}\show\@dtl@type +} % \end{macrocode} %\end{macro} %\iffalse @@ -12537,7 +17232,7 @@ doesn't exist)}{}% % Declare package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{datapie}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{datapie}[2007/02/27 v2.0 (NLCT)] % \end{macrocode} % Require \sty{xkeyval} package % \begin{macrocode} @@ -13213,7 +17908,7 @@ Try #2-#1 instead of #1-#2}% % Declare package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{dataplot}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{dataplot}[2009/02/27 v2.0 (NLCT)] % \end{macrocode} % Required packages % \begin{macrocode} @@ -13252,15 +17947,16 @@ Try #2-#1 instead of #1-#2}% %\cs{DTLplot}. % \begin{macrocode} \newcommand*{\DTLplotmarks}{% -\pgfuseplotmark{o},% -\pgfuseplotmark{x},% -\pgfuseplotmark{+},% -\pgfuseplotmark{square},% -\pgfuseplotmark{triangle},% -\pgfuseplotmark{diamond},% -\pgfuseplotmark{pentagon},% -\pgfuseplotmark{asterisk},% -\pgfuseplotmark{star}} + \pgfuseplotmark{o},% + \pgfuseplotmark{x},% + \pgfuseplotmark{+},% + \pgfuseplotmark{square},% + \pgfuseplotmark{triangle},% + \pgfuseplotmark{diamond},% + \pgfuseplotmark{pentagon},% + \pgfuseplotmark{asterisk},% + \pgfuseplotmark{star}% +} % \end{macrocode} %\end{macro} % @@ -13268,28 +17964,29 @@ Try #2-#1 instead of #1-#2}% %\cs{DTLplotmarkcolors} contains a list of the plot mark colours. % \begin{macrocode} \newcommand*{\DTLplotmarkcolors}{% -red,% -green,% -blue,% -yellow,% -magenta,% -cyan,% -orange,% -black,% -gray} + red,% + green,% + blue,% + yellow,% + magenta,% + cyan,% + orange,% + black,% + gray} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLplotlines} %\cs{DTLplotlines} contains a list of dash patterns used by %\cs{DLTplot}. +%\changes{1.03}{2009 January 27}{fixed error in solid line setting} % \begin{macrocode} \newcommand*{\DTLplotlines}{% -\pgfsetdash{}{{0pt}},% solid line -\pgfsetdash{{10pt}{5pt}}{0pt},% -\pgfsetdash{{5pt}{5pt}}{0pt},% -\pgfsetdash{{1pt}{5pt}}{0pt},% -\pgfsetdash{{5pt}{5pt}{1pt}{5pt}}{0pt},% -\pgfsetdash{{1pt}{3pt}}{0pt},% + \pgfsetdash{}{0pt},% solid line + \pgfsetdash{{10pt}{5pt}}{0pt},% + \pgfsetdash{{5pt}{5pt}}{0pt},% + \pgfsetdash{{1pt}{5pt}}{0pt},% + \pgfsetdash{{5pt}{5pt}{1pt}{5pt}}{0pt},% + \pgfsetdash{{1pt}{3pt}}{0pt},% } % \end{macrocode} %\end{macro} @@ -13297,15 +17994,15 @@ gray} %\cs{DTLplotlinecolors} contains a list of the plot line colours. % \begin{macrocode} \newcommand*{\DTLplotlinecolors}{% -red,% -green,% -blue,% -yellow,% -magenta,% -cyan,% -orange,% -black,% -gray} + red,% + green,% + blue,% + yellow,% + magenta,% + cyan,% + orange,% + black,% + gray} % \end{macrocode} %\end{macro} % @@ -14635,7 +19332,7 @@ east,southeast,south,southwest,west,northwest}[northeast]{% % Declare package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{databar}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{databar}[2009/02/27 v2.0 (NLCT)] % \end{macrocode} % Require \sty{xkeyval} package % \begin{macrocode} @@ -14924,6 +19621,16 @@ east,southeast,south,southwest,west,northwest}[northeast]{% \DTLsetbarcolor{8}{black!85} \fi % \end{macrocode} +%\begin{macro}{\DTLeverybarhook} +% Code to apply at every bar. The start point of the bar +% can be accessed via \cs{DTLstartpt}, the mid point of the bar +% can be accessed via \cs{DTLmidpt} and the end point of the +% bar can be accessed via \cs{DTLendpt} +%\changes{2.0}{2009 February 27}{new}% +% \begin{macrocode} +\newcommand*{\DTLeverybarhook}{} +% \end{macrocode} +%\end{macro} % % Define keys for \cs{DTLbarchart} optional argument. % Set the maximum value of the $y$ axis. @@ -15061,7 +19768,8 @@ east,southeast,south,southwest,west,northwest}[northeast]{% uppermultibarlabels,groupgap}% \setkeys{databar}{#2}% \ifx\DTLbarvariable\relax - \PackageError{databar}{\string\DTLbarchart\space missing variable}{}% + \PackageError{databar}{\string\DTLbarchart\space missing + variable}{You haven't use the "variable" key}% \else % \end{macrocode} % Compute the maximum bar height, unless \cs{DTLbarmax} has been @@ -15253,6 +19961,10 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, \DTLbarXlabelalign }% +% \end{macrocode} +% Set \cs{DTLstartpt} to the starting point. +% \begin{macrocode} + \edef\DTLstartpt{\noexpand\pgfpointxy{\@dtl@start.5}{0}}% \else \edef\dtl@textopt{% at={\noexpand\pgfpointadd @@ -15260,6 +19972,10 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, \DTLbarXlabelalign }% +% \end{macrocode} +% Set \cs{DTLstartpt} to the starting point. +% \begin{macrocode} + \edef\DTLstartpt{\noexpand\pgfpointxy{0}{\@dtl@start.5}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplaylowerbarlabel{\dtl@barlabel}} @@ -15267,6 +19983,9 @@ uppermultibarlabels,groupgap}% % Draw upper $x$ labels % \begin{macrocode} \ifDTLverticalbars +% \end{macrocode} +% Vertical bars +% \begin{macrocode} \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} { \edef\dtl@textopt{% @@ -15281,7 +20000,14 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} }% } +% \end{macrocode} +% Set \cs{DTLendpt} to the end point. +% \begin{macrocode} + \edef\DTLendpt{\noexpand\pgfpointxy{\@dtl@start.5}{\dtl@variable}}% \else +% \end{macrocode} +% Horizontal bars +% \begin{macrocode} \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} { \edef\dtl@textopt{right, @@ -15296,10 +20022,23 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} }% } +% \end{macrocode} +% Set \cs{DTLendpt} to the end point. +% \begin{macrocode} + \edef\DTLendpt{\noexpand\pgfpointxy{\dtl@variable}{\@dtl@start.5}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplayupperbarlabel{\dtl@upperbarlabel}} % \end{macrocode} +% Set the mid point +% \begin{macrocode} +\def\DTLmidpt{\pgfpointlineattime{0.5}{\DTLstartpt}{\DTLendpt}}% +% \end{macrocode} +% Do every bar hook +%\changes{2.0}{2009 February 27}{added \cs{DTLeverybarhook}}% +% \begin{macrocode} + \DTLeverybarhook +% \end{macrocode} % End of loop % \begin{macrocode} \edef\@dtl@start{\number\@dtl@bar}% @@ -15677,6 +20416,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, \DTLbarXlabelalign }% + \edef\DTLstartpt{\noexpand\pgfpointxy{\@dtl@midpt}{0}}% \else \edef\dtl@textopt{% at={\noexpand\pgfpointadd @@ -15684,6 +20424,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, \DTLbarXlabelalign }% + \edef\DTLstartpt{\noexpand\pgfpointxy{0}{\@dtl@midpt}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplaylowermultibarlabel{\dtl@thisbarlabel}} @@ -15705,6 +20446,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} }% } + \edef\DTLendpt{\noexpand\pgfpointxy{\@dtl@midpt}{\dtl@variable}}% \else \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} { @@ -15720,10 +20462,20 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} }% } + \edef\DTLendpt{\noexpand\pgfpointxy{\dtl@variable}{\@dtl@midpt}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplayuppermultibarlabel{\dtl@thisupperbarlabel}} % \end{macrocode} +% Set the mid point +% \begin{macrocode} +\def\DTLmidpt{\pgfpointlineattime{0.5}{\DTLstartpt}{\DTLendpt}}% +% \end{macrocode} +% Do every bar hook +%\changes{2.0}{2009 February 27}{added \cs{DTLeverybarhook}}% +% \begin{macrocode} +\DTLeverybarhook +% \end{macrocode} % End of loop increment loop variables % \begin{macrocode} \FPadd{\@dtl@start}{\@dtl@start}{1}% @@ -15865,7 +20617,7 @@ uppermultibarlabels,groupgap}% %\subsection{Package Declaration} % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{databib}[2007/08/17 v1.0 (NLCT)] +\ProvidesPackage{databib}[2009/02/27 v2.0 (NLCT)] % \end{macrocode} % Load required packages: % \begin{macrocode} @@ -15906,9 +20658,12 @@ uppermultibarlabels,groupgap}% %\begin{macro}{\DTLnewbibrow} % \cs{DTLnewbibrow} adds a new row to the bibliography database. % (\cs{DTLBIBdbname} must be set prior to use to the name -% of the \sty{datatool} database.) +% of the \sty{datatool} database which must exist. Any check +% to determine its existence should be performed when +% \cs{DTLBIBdbname} is set.) +%\changes{1.03}{2009 January 27}{removed check if database exists} % \begin{macrocode} -\newcommand*{\DTLnewbibrow}{\DTLnewrow{\DTLBIBdbname}} +\newcommand*{\DTLnewbibrow}{\@DTLnewrow{\DTLBIBdbname}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLnewbibitem} @@ -15916,9 +20671,10 @@ uppermultibarlabels,groupgap}% %\cs{DTLnewbibitem}\marg{key}\marg{value} %\end{definition} % Adds a new database entry with the given key and value. +%\changes{1.03}{2009 January 27}{removed check if database exists} % \begin{macrocode} \newcommand*{\DTLnewbibitem}[2]{% -\DTLnewdbentry{\DTLBIBdbname}{#1}{#2}} + \@DTLnewdbentry{\DTLBIBdbname}{#1}{#2}} % \end{macrocode} %\end{macro} %\subsection{Predefined text} @@ -16006,11 +20762,11 @@ uppermultibarlabels,groupgap}% %\begin{macro}{\DTLbibliography} % \begin{macrocode} \newcommand*{\DTLbibliography}[2][\boolean{true}]{% -\begin{DTLthebibliography}[#1]{#2}% -\DTLforeachbibentry[#1]{#2}{% -\DTLbibitem \DTLformatbibentry \DTLendbibitem -}% -\end{DTLthebibliography}% + \begin{DTLthebibliography}[#1]{#2}% + \DTLforeachbibentry[#1]{#2}{% + \DTLbibitem \DTLformatbibentry \DTLendbibitem + }% + \end{DTLthebibliography}% } % \end{macrocode} %\end{macro} @@ -16022,12 +20778,28 @@ uppermultibarlabels,groupgap}% % Formats the current bib entry. % \begin{macrocode} \newcommand*{\DTLformatbibentry}{% -\@ifundefined{DTLformat\DBIBentrytype}{% -\PackageError{databib}{Don't know how to format bibliography entries -of type `\DBIBentrytype'}{}}{% -\dtl@message{[\DBIBcitekey]}% -\DTLstartsentencefalse\DTLmidsentencefalse\DTLperiodfalse -\csname DTLformat\DBIBentrytype\endcsname}% +% \end{macrocode} +% Check format for this type is defined. +% \begin{macrocode} + \@ifundefined{DTLformat\DBIBentrytype}% + {% + \PackageError{databib}{Don't know how to format bibliography + entries of type `\DBIBentrytype'}{}% + }% + {% +% \end{macrocode} +% Print information to terminal and log file if in verbose mode. +% \begin{macrocode} + \dtl@message{[\DBIBcitekey]}% +% \end{macrocode} +% Initialise +% \begin{macrocode} + \DTLstartsentencefalse\DTLmidsentencefalse\DTLperiodfalse +% \end{macrocode} +% Format this entry +% \begin{macrocode} + \csname DTLformat\DBIBentrytype\endcsname + }% } % \end{macrocode} %\end{macro} @@ -16089,20 +20861,46 @@ of type `\DBIBentrytype'}{}}{% % Unstarred version % \begin{macrocode} \newcommand*{\@DTLforeachbibentry}[3][\boolean{true}]{% -\edef\DBIBname{#2}\setcounter{DTLbibrow}{0}% -\@DTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype -=EntryType}{\dtl@gathervalues{#2}{\@dtl@currentrow}% -\ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}}} +% \end{macrocode} +% Store database name. +% \begin{macrocode} + \edef\DBIBname{#2}% +% \end{macrocode} +% Reset row counter. +% \begin{macrocode} + \setcounter{DTLbibrow}{0}% +% \end{macrocode} +% Iterate through the database. +% \begin{macrocode} + \@DTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}% + }% +} % \end{macrocode} %\end{macro} %\begin{macro}{\@sDTLforeachbibentry} % Starred version % \begin{macrocode} \newcommand*{\@sDTLforeachbibentry}[3][\boolean{true}]{% -\edef\DBIBname{#2}\setcounter{DTLbibrow}{0}% -\@sDTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype -=EntryType}{\dtl@gathervalues{#2}{\@dtl@currentrow}% -\ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}}} +% \end{macrocode} +% Store database name. +% \begin{macrocode} + \edef\DBIBname{#2}% +% \end{macrocode} +% Reset row counter. +% \begin{macrocode} + \setcounter{DTLbibrow}{0}% +% \end{macrocode} +% Iterate through the database (read only). +% \begin{macrocode} + \@sDTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}% + }% +} % \end{macrocode} %\end{macro} % @@ -17113,6 +21911,13 @@ of type `\DBIBentrytype'}{}}{% % \end{macrocode} %\end{macro} % +%\begin{macro}{\DTLmbibitem} +% As \cs{DTLbibitem} but for \cs{DTLmbibliography} +% \begin{macrocode} +\newcommand*{\DTLmbibitem}[1]{\bibitem{#1@\DBIBcitekey}} +% \end{macrocode} +%\end{macro} +% %\begin{macro}{\DTLformatauthor} %\begin{definition} %\cs{DTLformatauthor}\marg{von part}\marg{surname}\marg{junior @@ -17384,6 +22189,7 @@ and Systems} % Set how to start the bibliography entry: % \begin{macrocode} \renewcommand*{\DTLbibitem}{\bibitem{\DBIBcitekey}}% +\renewcommand*{\DTLmbibitem}[1]{\bibitem{##1@\DBIBcitekey}}% % \end{macrocode} % Sets the author name format. % \begin{macrocode} @@ -18132,6 +22938,9 @@ Integrated Circuits} \renewcommand*{\DTLbibitem}{% \expandafter\bibitem\expandafter [\csname dtl@biblabel@\DBIBcitekey\endcsname]{\DBIBcitekey}}% +\renewcommand*{\DTLmbibitem}[1]{% +\expandafter\bibitem\expandafter + [\csname dtl@biblabel@\DBIBcitekey\endcsname]{##1@\DBIBcitekey}}% % \end{macrocode} % \begin{macrocode} % \end{macrocode} @@ -18342,6 +23151,157 @@ bibliography style `#1'}{}}{\csname dtlbst@#1\endcsname}} % \begin{macrocode} \DTLbibliographystyle{\dtlbib@style} % \end{macrocode} +% +%\subsection{Multiple Bibliographies} +% In order to have multiple bibliographies, there needs to be +% an aux file for each bibliography. The main bibliography is in +% \cs{jobname}.aux, but need to provide a means of creating +% additional aux files. +%\begin{macro}{\DTLmultibibs} +%\begin{definition} +%\cs{DTLmultibibs}\marg{list} +%\end{definition} +%\changes{1.01}{2007/08/22}{new} +% This creates an auxiliary file for each name in \meta{list}. +% For example, "\DTLmultibibs{foo,bar}" will create the files +% "foo.aux" and "bar.aux". +% \begin{macrocode} +\newcommand*{\DTLmultibibs}[1]{% +\@for\@dtl@af:=#1\do{% +\@ifundefined{dtl@aux@\@dtl@af}{% +\expandafter\newwrite\csname dtl@aux@\@dtl@af\endcsname +\expandafter\immediate +\expandafter\openout\csname dtl@aux@\@dtl@af\endcsname=\@dtl@af.aux +\expandafter\def\csname b@\@dtl@af @*\endcsname{}% +}{% +\PackageError{databib}{Can't create auxiliary file `\@dtl@af.aux', +\expandafter\string\csname dtl@aux@\@dtl@af\endcsname\space +already exists}{}}}} +% \end{macrocode} +% Can only be used in the preamble: +% \begin{macrocode} +\@onlypreamble{\DTLmultibibs} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLcite} +%\begin{definition} +%\cs{DTLcite}\oarg{text}\marg{mbib}\marg{labels} +%\end{definition} +% This is similar to \cs{cite}\oarg{text}\marg{labels}, except +% 1) the cite information is written to the auxiliary file +% associated with the multi-bib \meta{mbib} (which must be named +% in \cs{DTLmultibibs}) and 2) the cross referencing label is +% constructed from \meta{mbib} and \meta{label} to allow for +% the same citation to appear in multiple bibliographies. +% \begin{macrocode} +\newcommand*{\DTLcite}{\@ifnextchar[{\@tempswatrue \dtl@citex +}{\@tempswafalse \dtl@citex[]}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@citex} +% \begin{macrocode} +\def\dtl@citex[#1]#2#3{% +\leavevmode\let\@citea\@empty +\@cite{\@for\@citeb:=#3\do{\@citea + \def\@citea{,\penalty \@m \ }% + \edef\@citeb{\expandafter\@firstofone\@citeb\@empty}% + \if@filesw + \@ifundefined{dtl@aux@#2}{% + \PackageError{databib}{multibib `#2' not defined}{% + You need to define `#2' in \string\DTLmutlibibs}% + }{% + \expandafter\immediate + \expandafter\write\csname dtl@aux@#2\endcsname{% + \string\citation{\@citeb}}% + }% + \fi + \@ifundefined{b@#2@\@citeb}{% + \hbox{\reset@font\bfseries ?}% + \G@refundefinedtrue + \@latex@warning{Citation `\@citeb ' on page \thepage \space + undefined}% + }{% + \@cite@ofmt{\csname b@#2@\@citeb \endcsname }% + }% +}}{#1}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLnocite} +%\begin{definition} +%\cs{DTLnocite}\marg{mbib}\marg{key list} +%\end{definition} +% As \cs{nocite} but uses the aux file associated with \meta{mbib} +% which must have been defined using \cs{DTLmultibibs}. +% \begin{macrocode} +\newcommand*{\DTLnocite}[2]{% +\@ifundefined{dtl@aux@#1}{% + \PackageError{databib}{multibib `#1' not defined}{% + You need to define `#1' in \string\DTLmutlibibs}% +}{% + \@bsphack + \ifx\@onlypreamble\document + \@for\@citeb:=#2\do{% + \edef\@citeb{\expandafter\@firstofone\@citeb}% + \if@filesw + \expandafter\immediate + \expandafter\write\csname dtl@aux@#1\endcsname{% + \string\citation{\@citeb}}% + \fi + \@ifundefined{b@#1@\@citeb}{% + \G@refundefinedtrue + \@latex@warning{Citation `\@citeb ' undefined}}{}% + }% + \else + \@latex@error{Cannot be used in preamble}\@eha + \fi + \@esphack +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLloadmbbl} +%\begin{definition} +%\cs{DTLloadmbib}\marg{mbib}\marg{db name}\marg{bib list} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLloadmbbl}[3]{% +\@ifundefined{dtl@aux@#1}{% + \PackageError{databib}{multibib `#1' not defined}{% + You need to define `#1' in \string\DTLmutlibibs}% +}{% + \if@filesw + \expandafter\immediate\expandafter + \write\csname dtl@aux@#1\endcsname{\string\bibstyle{databib}}% + \expandafter\immediate\expandafter + \write\csname dtl@aux@#1\endcsname{\string\bibdata{#3}}% + \fi + \DTLnewdb{#2}% + \edef\DTLBIBdbname{#2}% + \@input@{#1.bbl}% +}% +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLmbibliography}\oarg{condition}\marg{mbib name}\marg{bib dbname} +%\end{definition} +% Displays the bibliography for the database \meta{bib dbname} +% which must have previously been loaded using +% \cs{DTLloadmbbl}, where \meta{mbib name} must be listed +% in \cs{DTLmultibibs}. +%\begin{macro}{\DTLmbibliography} +% \begin{macrocode} +\newcommand*{\DTLmbibliography}[3][\boolean{true}]{% +\begin{DTLthebibliography}[#1]{#3}% +\DTLforeachbibentry[#1]{#3}{% +\DTLmbibitem{#2} \DTLformatbibentry \DTLendbibitem +}% +\end{DTLthebibliography}% +} +% \end{macrocode} +%\end{macro} %\iffalse % \begin{macrocode} % @@ -18357,6 +23317,7 @@ bibliography style `#1'}{}}{\csname dtlbst@#1\endcsname}} % \begin{macrocode} % Bibliography style `databib' % This style is provided for use with the databib package. +% v1.01 (2007/08/22) - added "file" field ENTRY { address @@ -18386,6 +23347,7 @@ ENTRY pubmed url abstract + file } {} { label } @@ -18722,6 +23684,16 @@ FUNCTION {format.url} if$ } +FUNCTION {format.file} +{ file empty$ + { "" } + { + file + "\DTLnewbibitem {File}" swap$ group * + } + if$ +} + FUNCTION {format.address} { address empty$ { "" } @@ -19116,6 +24088,7 @@ FUNCTION {article} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19157,6 +24130,7 @@ FUNCTION {book} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19179,6 +24153,7 @@ FUNCTION {booklet} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19221,6 +24196,7 @@ FUNCTION {inbook} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19252,6 +24228,7 @@ FUNCTION {incollection} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19291,6 +24268,7 @@ FUNCTION {inproceedings} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19335,6 +24313,7 @@ FUNCTION {manual} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19359,6 +24338,7 @@ FUNCTION {mastersthesis} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19380,6 +24360,7 @@ FUNCTION {misc} format.pubmed output format.url output format.abstract output + format.file output fin.entry empty.misc.check } @@ -19405,6 +24386,7 @@ FUNCTION {phdthesis} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19448,6 +24430,7 @@ FUNCTION {proceedings} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19471,6 +24454,7 @@ FUNCTION {techreport} format.pubmed output format.url output format.abstract output + format.file output fin.entry } @@ -19489,6 +24473,7 @@ FUNCTION {unpublished} format.pubmed output format.url output format.abstract output + format.file output format.date output fin.entry } diff --git a/Master/texmf-dist/source/latex/datatool/datatool.ins b/Master/texmf-dist/source/latex/datatool/datatool.ins index 87c233613df..38bc0ad7fe9 100644 --- a/Master/texmf-dist/source/latex/datatool/datatool.ins +++ b/Master/texmf-dist/source/latex/datatool/datatool.ins @@ -1,10 +1,10 @@ -% datatool.ins generated using makedtx version 0.94b 2007/8/19 14:27 +% datatool.ins generated using makedtx version 0.94b 2009/2/27 13:27 \input docstrip \preamble 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 diff --git a/Master/texmf-dist/tex/latex/datatool/databar.sty b/Master/texmf-dist/tex/latex/datatool/databar.sty index 63b5f505912..ecf8ce763bf 100644 --- a/Master/texmf-dist/tex/latex/datatool/databar.sty +++ b/Master/texmf-dist/tex/latex/datatool/databar.sty @@ -7,7 +7,7 @@ %% datatool.dtx (with options: `databar.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,7 +39,7 @@ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{databar}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{databar}[2009/02/27 v2.0 (NLCT)] \RequirePackage{xkeyval} \RequirePackage{dataplot} \newif\ifDTLcolorbarchart @@ -128,6 +128,7 @@ \DTLsetbarcolor{7}{black!75} \DTLsetbarcolor{8}{black!85} \fi +\newcommand*{\DTLeverybarhook}{} \define@key{databar}{max}{\def\DTLbarmax{#1}} \define@key{databar}{length}{\DTLbarchartlength=#1\relax } @@ -199,7 +200,8 @@ uppermultibarlabels,groupgap}% \setkeys{databar}{#2}% \ifx\DTLbarvariable\relax - \PackageError{databar}{\string\DTLbarchart\space missing variable}{}% + \PackageError{databar}{\string\DTLbarchart\space missing + variable}{You haven't use the "variable" key}% \else \ifx\DTLbarmax\relax \@sDTLforeach[#1]{#3}{#4}{% @@ -342,6 +344,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, \DTLbarXlabelalign }% + \edef\DTLstartpt{\noexpand\pgfpointxy{\@dtl@start.5}{0}}% \else \edef\dtl@textopt{% at={\noexpand\pgfpointadd @@ -349,6 +352,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, \DTLbarXlabelalign }% + \edef\DTLstartpt{\noexpand\pgfpointxy{0}{\@dtl@start.5}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplaylowerbarlabel{\dtl@barlabel}} @@ -367,6 +371,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} }% } + \edef\DTLendpt{\noexpand\pgfpointxy{\@dtl@start.5}{\dtl@variable}}% \else \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} { @@ -382,9 +387,12 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} }% } + \edef\DTLendpt{\noexpand\pgfpointxy{\dtl@variable}{\@dtl@start.5}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplayupperbarlabel{\dtl@upperbarlabel}} +\def\DTLmidpt{\pgfpointlineattime{0.5}{\DTLstartpt}{\DTLendpt}}% + \DTLeverybarhook \edef\@dtl@start{\number\@dtl@bar}% } \ifDTLbarxaxis @@ -653,6 +661,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, \DTLbarXlabelalign }% + \edef\DTLstartpt{\noexpand\pgfpointxy{\@dtl@midpt}{0}}% \else \edef\dtl@textopt{% at={\noexpand\pgfpointadd @@ -660,6 +669,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, \DTLbarXlabelalign }% + \edef\DTLstartpt{\noexpand\pgfpointxy{0}{\@dtl@midpt}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplaylowermultibarlabel{\dtl@thisbarlabel}} @@ -678,6 +688,7 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} }% } + \edef\DTLendpt{\noexpand\pgfpointxy{\@dtl@midpt}{\dtl@variable}}% \else \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} { @@ -693,9 +704,12 @@ uppermultibarlabels,groupgap}% {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} }% } + \edef\DTLendpt{\noexpand\pgfpointxy{\dtl@variable}{\@dtl@midpt}}% \fi \expandafter\pgftext\expandafter[\dtl@textopt]{% \DTLdisplayuppermultibarlabel{\dtl@thisupperbarlabel}} +\def\DTLmidpt{\pgfpointlineattime{0.5}{\DTLstartpt}{\DTLendpt}}% +\DTLeverybarhook \FPadd{\@dtl@start}{\@dtl@start}{1}% \advance\@dtl@barcount by 1\relax }% diff --git a/Master/texmf-dist/tex/latex/datatool/databib.sty b/Master/texmf-dist/tex/latex/datatool/databib.sty index 2b168d64dd4..44160a138d9 100644 --- a/Master/texmf-dist/tex/latex/datatool/databib.sty +++ b/Master/texmf-dist/tex/latex/datatool/databib.sty @@ -7,7 +7,7 @@ %% datatool.dtx (with options: `databib.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,7 +39,7 @@ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{databib}[2007/08/17 v1.0 (NLCT)] +\ProvidesPackage{databib}[2009/02/27 v2.0 (NLCT)] \RequirePackage{datatool} \newcommand*{\dtlbib@style}{plain} \define@choicekey{databib.sty}{style}{plain,abbrv,alpha}{% @@ -53,9 +53,9 @@ \DTLnewdb{#2}% \edef\DTLBIBdbname{#2}% \@input@{#1}} -\newcommand*{\DTLnewbibrow}{\DTLnewrow{\DTLBIBdbname}} +\newcommand*{\DTLnewbibrow}{\@DTLnewrow{\DTLBIBdbname}} \newcommand*{\DTLnewbibitem}[2]{% -\DTLnewdbentry{\DTLBIBdbname}{#1}{#2}} + \@DTLnewdbentry{\DTLBIBdbname}{#1}{#2}} \providecommand*{\andname}{and} \providecommand*{\ofname}{of} \providecommand*{\inname}{in} @@ -71,19 +71,23 @@ \providecommand*{\mscthesisname}{Master's thesis} \providecommand*{\phdthesisname}{PhD thesis} \newcommand*{\DTLbibliography}[2][\boolean{true}]{% -\begin{DTLthebibliography}[#1]{#2}% -\DTLforeachbibentry[#1]{#2}{% -\DTLbibitem \DTLformatbibentry \DTLendbibitem -}% -\end{DTLthebibliography}% + \begin{DTLthebibliography}[#1]{#2}% + \DTLforeachbibentry[#1]{#2}{% + \DTLbibitem \DTLformatbibentry \DTLendbibitem + }% + \end{DTLthebibliography}% } \newcommand*{\DTLformatbibentry}{% -\@ifundefined{DTLformat\DBIBentrytype}{% -\PackageError{databib}{Don't know how to format bibliography entries -of type `\DBIBentrytype'}{}}{% -\dtl@message{[\DBIBcitekey]}% -\DTLstartsentencefalse\DTLmidsentencefalse\DTLperiodfalse -\csname DTLformat\DBIBentrytype\endcsname}% + \@ifundefined{DTLformat\DBIBentrytype}% + {% + \PackageError{databib}{Don't know how to format bibliography + entries of type `\DBIBentrytype'}{}% + }% + {% + \dtl@message{[\DBIBcitekey]}% + \DTLstartsentencefalse\DTLmidsentencefalse\DTLperiodfalse + \csname DTLformat\DBIBentrytype\endcsname + }% } \newcommand*{\DTLendbibitem}{} \newlength\dtl@widest @@ -101,15 +105,23 @@ of type `\DBIBentrytype'}{}}{% \newcommand*{\DTLforeachbibentry}{% \@ifstar\@DTLforeachbibentry\@DTLforeachbibentry} \newcommand*{\@DTLforeachbibentry}[3][\boolean{true}]{% -\edef\DBIBname{#2}\setcounter{DTLbibrow}{0}% -\@DTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype -=EntryType}{\dtl@gathervalues{#2}{\@dtl@currentrow}% -\ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}}} + \edef\DBIBname{#2}% + \setcounter{DTLbibrow}{0}% + \@DTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}% + }% +} \newcommand*{\@sDTLforeachbibentry}[3][\boolean{true}]{% -\edef\DBIBname{#2}\setcounter{DTLbibrow}{0}% -\@sDTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype -=EntryType}{\dtl@gathervalues{#2}{\@dtl@currentrow}% -\ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}}} + \edef\DBIBname{#2}% + \setcounter{DTLbibrow}{0}% + \@sDTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}% + }% +} \newcounter{DTLbibrow} \def\theHDTLbibrow{\theHDTLrow.bib.\arabic{DTLbibrow}}% \newcommand*{\DTLbibfield}[1]{\csname @dtl@key@#1\endcsname} @@ -667,6 +679,7 @@ of type `\DBIBentrytype'}{}}{% \or Dec.% \fi} \newcommand*{\DTLbibitem}{\bibitem{\DBIBcitekey}} +\newcommand*{\DTLmbibitem}[1]{\bibitem{#1@\DBIBcitekey}} \newcommand*{\DTLformatauthor}[4]{% \DTLformatforenames{#4} \DTLformatvon{#1}% @@ -721,6 +734,7 @@ and Systems} \begin{thebibliography}{\number\@dtl@tmpcount}% }{\end{thebibliography}}% \renewcommand*{\DTLbibitem}{\bibitem{\DBIBcitekey}}% +\renewcommand*{\DTLmbibitem}[1]{\bibitem{##1@\DBIBcitekey}}% \renewcommand*{\DTLformatauthor}[4]{% \DTLformatforenames{##4} \DTLformatvon{##1}% @@ -1366,6 +1380,9 @@ Integrated Circuits} \renewcommand*{\DTLbibitem}{% \expandafter\bibitem\expandafter [\csname dtl@biblabel@\DBIBcitekey\endcsname]{\DBIBcitekey}}% +\renewcommand*{\DTLmbibitem}[1]{% +\expandafter\bibitem\expandafter + [\csname dtl@biblabel@\DBIBcitekey\endcsname]{##1@\DBIBcitekey}}% } \newcommand*{\dtl@createalphabiblabels}[2]{% \dtl@message{Creating bib labels}% @@ -1524,6 +1541,92 @@ Integrated Circuits} \@ifundefined{dtlbst@#1}{\PackageError{databib}{Unknown bibliography style `#1'}{}}{\csname dtlbst@#1\endcsname}} \DTLbibliographystyle{\dtlbib@style} +\newcommand*{\DTLmultibibs}[1]{% +\@for\@dtl@af:=#1\do{% +\@ifundefined{dtl@aux@\@dtl@af}{% +\expandafter\newwrite\csname dtl@aux@\@dtl@af\endcsname +\expandafter\immediate +\expandafter\openout\csname dtl@aux@\@dtl@af\endcsname=\@dtl@af.aux +\expandafter\def\csname b@\@dtl@af @*\endcsname{}% +}{% +\PackageError{databib}{Can't create auxiliary file `\@dtl@af.aux', +\expandafter\string\csname dtl@aux@\@dtl@af\endcsname\space +already exists}{}}}} +\@onlypreamble{\DTLmultibibs} +\newcommand*{\DTLcite}{\@ifnextchar[{\@tempswatrue \dtl@citex +}{\@tempswafalse \dtl@citex[]}} +\def\dtl@citex[#1]#2#3{% +\leavevmode\let\@citea\@empty +\@cite{\@for\@citeb:=#3\do{\@citea + \def\@citea{,\penalty \@m \ }% + \edef\@citeb{\expandafter\@firstofone\@citeb\@empty}% + \if@filesw + \@ifundefined{dtl@aux@#2}{% + \PackageError{databib}{multibib `#2' not defined}{% + You need to define `#2' in \string\DTLmutlibibs}% + }{% + \expandafter\immediate + \expandafter\write\csname dtl@aux@#2\endcsname{% + \string\citation{\@citeb}}% + }% + \fi + \@ifundefined{b@#2@\@citeb}{% + \hbox{\reset@font\bfseries ?}% + \G@refundefinedtrue + \@latex@warning{Citation `\@citeb ' on page \thepage \space + undefined}% + }{% + \@cite@ofmt{\csname b@#2@\@citeb \endcsname }% + }% +}}{#1}% +} +\newcommand*{\DTLnocite}[2]{% +\@ifundefined{dtl@aux@#1}{% + \PackageError{databib}{multibib `#1' not defined}{% + You need to define `#1' in \string\DTLmutlibibs}% +}{% + \@bsphack + \ifx\@onlypreamble\document + \@for\@citeb:=#2\do{% + \edef\@citeb{\expandafter\@firstofone\@citeb}% + \if@filesw + \expandafter\immediate + \expandafter\write\csname dtl@aux@#1\endcsname{% + \string\citation{\@citeb}}% + \fi + \@ifundefined{b@#1@\@citeb}{% + \G@refundefinedtrue + \@latex@warning{Citation `\@citeb ' undefined}}{}% + }% + \else + \@latex@error{Cannot be used in preamble}\@eha + \fi + \@esphack +}% +} +\newcommand*{\DTLloadmbbl}[3]{% +\@ifundefined{dtl@aux@#1}{% + \PackageError{databib}{multibib `#1' not defined}{% + You need to define `#1' in \string\DTLmutlibibs}% +}{% + \if@filesw + \expandafter\immediate\expandafter + \write\csname dtl@aux@#1\endcsname{\string\bibstyle{databib}}% + \expandafter\immediate\expandafter + \write\csname dtl@aux@#1\endcsname{\string\bibdata{#3}}% + \fi + \DTLnewdb{#2}% + \edef\DTLBIBdbname{#2}% + \@input@{#1.bbl}% +}% +} +\newcommand*{\DTLmbibliography}[3][\boolean{true}]{% +\begin{DTLthebibliography}[#1]{#3}% +\DTLforeachbibentry[#1]{#3}{% +\DTLmbibitem{#2} \DTLformatbibentry \DTLendbibitem +}% +\end{DTLthebibliography}% +} \endinput %% %% End of file `databib.sty'. diff --git a/Master/texmf-dist/tex/latex/datatool/datapie.sty b/Master/texmf-dist/tex/latex/datatool/datapie.sty index 418f8a045a2..f1af8129159 100644 --- a/Master/texmf-dist/tex/latex/datatool/datapie.sty +++ b/Master/texmf-dist/tex/latex/datatool/datapie.sty @@ -7,7 +7,7 @@ %% datatool.dtx (with options: `datapie.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,7 +39,7 @@ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{datapie}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{datapie}[2007/02/27 v2.0 (NLCT)] \RequirePackage{xkeyval} \newif\ifDTLcolorpiechart \DTLcolorpiecharttrue diff --git a/Master/texmf-dist/tex/latex/datatool/dataplot.sty b/Master/texmf-dist/tex/latex/datatool/dataplot.sty index 83eaef56ebb..48500c6843c 100644 --- a/Master/texmf-dist/tex/latex/datatool/dataplot.sty +++ b/Master/texmf-dist/tex/latex/datatool/dataplot.sty @@ -7,7 +7,7 @@ %% datatool.dtx (with options: `dataplot.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,7 +39,7 @@ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} \NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{dataplot}[2007/08/17 v1.01 (NLCT)] +\ProvidesPackage{dataplot}[2009/02/27 v2.0 (NLCT)] \RequirePackage{xkeyval} \RequirePackage{tikz} \RequirePackage{datatool} @@ -51,43 +51,44 @@ \DTLconverttodecimal{\dtl@y}{\dtl@decy}% \pgfplotstreampoint{\pgfpointxy{\dtl@decx}{\dtl@decy}}}} \newcommand*{\DTLplotmarks}{% -\pgfuseplotmark{o},% -\pgfuseplotmark{x},% -\pgfuseplotmark{+},% -\pgfuseplotmark{square},% -\pgfuseplotmark{triangle},% -\pgfuseplotmark{diamond},% -\pgfuseplotmark{pentagon},% -\pgfuseplotmark{asterisk},% -\pgfuseplotmark{star}} + \pgfuseplotmark{o},% + \pgfuseplotmark{x},% + \pgfuseplotmark{+},% + \pgfuseplotmark{square},% + \pgfuseplotmark{triangle},% + \pgfuseplotmark{diamond},% + \pgfuseplotmark{pentagon},% + \pgfuseplotmark{asterisk},% + \pgfuseplotmark{star}% +} \newcommand*{\DTLplotmarkcolors}{% -red,% -green,% -blue,% -yellow,% -magenta,% -cyan,% -orange,% -black,% -gray} + red,% + green,% + blue,% + yellow,% + magenta,% + cyan,% + orange,% + black,% + gray} \newcommand*{\DTLplotlines}{% -\pgfsetdash{}{{0pt}},% solid line -\pgfsetdash{{10pt}{5pt}}{0pt},% -\pgfsetdash{{5pt}{5pt}}{0pt},% -\pgfsetdash{{1pt}{5pt}}{0pt},% -\pgfsetdash{{5pt}{5pt}{1pt}{5pt}}{0pt},% -\pgfsetdash{{1pt}{3pt}}{0pt},% + \pgfsetdash{}{0pt},% solid line + \pgfsetdash{{10pt}{5pt}}{0pt},% + \pgfsetdash{{5pt}{5pt}}{0pt},% + \pgfsetdash{{1pt}{5pt}}{0pt},% + \pgfsetdash{{5pt}{5pt}{1pt}{5pt}}{0pt},% + \pgfsetdash{{1pt}{3pt}}{0pt},% } \newcommand*{\DTLplotlinecolors}{% -red,% -green,% -blue,% -yellow,% -magenta,% -cyan,% -orange,% -black,% -gray} + red,% + green,% + blue,% + yellow,% + magenta,% + cyan,% + orange,% + black,% + gray} \newlength\DTLplotwidth \setlength\DTLplotwidth{4in} \newlength\DTLplotheight 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 + \db@row@id@w #3\db@row@id@end@% row id + ##2% stuff in row before column + \db@col@id@w #4\db@col@id@end@% column 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 + \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}% + \ifnum\dtlforeachlevel=0\relax + \PackageError{datatool}{\string\DTLappendrow\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@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}% - \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}% }% - \expandafter\@dtl@toks\expandafter{\@dtl@currentrow}% - \ifx\@dtl@prerow\@empty - \edef\@dtl@prerow{{\the\@dtl@toks}}% + \\% + \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 + }% + \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}{}% + }% +} +\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*{\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}[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@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*{\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*{\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 + }{}% + }% + }% + }% + \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 } -\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*{\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*{\DTLsumforkeys}[4][\boolean{true}\and +\newcommand*{\DTLsdforkeys}[1][\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}{}% + \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*{\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*{\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}{}% }% -}% -\ifnum\dtl@n=0\relax - \PackageError{datatool}{Can't compute variance, no data!}{}% -\else - \DTLdiv{#4}{#4}{\dtl@n}% -\fi } -\newcommand*{\DTLsdforkeys}[4][\boolean{true}\and -\DTLisnumerical{\DTLthisval}]{% -\DTLvarianceforkeys[#1]{#2}{#3}{#4}% -\DTLsqrt{#4}{#4}% +\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*{\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*{\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'}{}% + }% }% -}} -\newcommand*{\DTLmaxforkeys}[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 - \DTLmax{#4}{#4}{\DTLthisval}% - \fi - }{}% -}}% - }{\PackageError{datatool}{Database `\@dtl@dbname' doesn't exist}{}% + {% + \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'. -- cgit v1.2.3