%\iffalse % datatool.dtx generated using makedtx version 0.94b (c) Nicola Talbot % Command line args: % -macrocode "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" % -src "person\.sty\Z=>person.sty" % -author "Nicola Talbot" % -dir "source" % -setambles ".*\.bst=>\nopreamble\usepreamble\defaultpreamble\nopostamble" % -comment "databib.bst" % -doc "datatool-manual.tex" % -codetitle "datatool.sty" % datatool % Created on 2009/11/15 15:10 %\fi %\iffalse %<*package> %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} % %\fi % \iffalse % Doc-Source file to use with LaTeX2e % Copyright (C) 2009 Nicola Talbot, all rights reserved. % \fi % \iffalse %<*driver> \documentclass[a4paper]{ltxdoc} \usepackage{dox} \usepackage{ifthen} \usepackage[verbose=false]{datatool} \usepackage{datapie,databar,databib,person} \usepackage{textcomp} \usepackage{graphicx} \usepackage{colortbl} \usepackage{cmap} \usepackage[T1]{fontenc} \usepackage[utf8]{inputenc} \usepackage{caption} \usepackage[colorlinks, bookmarks, hyperindex=false, pdfauthor={Nicola L.C. Talbot}, pdftitle={datatool: Databases and data manipulation}, pdfkeywords={LaTeX,package,database,data,chart,plot}]{hyperref} \usetikzlibrary{snakes} %hyperindex conflicts with doc %(end up with |usage|hyperpage in indexentry) %This unfortunately means that the changes section doesn't %have active links, but at least it will keep makeindex happy. \renewcommand{\usage}[1]{\textit{\hyperpage{#1}}} \renewcommand{\main}[1]{\hyperpage{#1}} \newcommand{\see}[2]{\emph{see} #1} \makeatletter \def\index@prologue{\section*{Index}} % commands are too wide for a 3 column index \def\theindex{\@restonecoltrue\if@twocolumn\@restonecolfalse\fi \columnseprule \z@ \columnsep 35\p@ \twocolumn[\index@prologue]% \IndexParms \let\item\@idxitem \ignorespaces} \def\endtheindex{\if@restonecol\onecolumn\else\clearpage\fi} \makeatother \RecordChanges \PageIndex \CheckSum{16375} \newcommand*{\sty}[1]{\textsf{#1}} \newcommand*{\env}[1]{\textsf{#1}} \newcommand*{\ext}[1]{\texttt{#1}} \definecolor{defbackground}{rgb}{0.8,1,1} \makeatletter \newcommand*{\setting}[2]{\textsf{#2}\relax \@for\thiscmd:=#1\do{% \edef\doindex{\noexpand\index {\thiscmd\space settings=\noexpand\cs{\thiscmd} settings>#2=\noexpand \textsf{#2}|hyperpage}}\doindex }} \makeatother \newsavebox\defsbox \newlength\defwidth \newenvironment{definition}[1][]{% \def\defarg{#1}% \setlength{\fboxsep}{4pt}\setlength{\fboxrule}{1.25pt}% \begin{lrbox}{\defsbox}% \setlength\defwidth\linewidth \addtolength\defwidth{-2\fboxrule}% \addtolength\defwidth{-2\fboxsep}% \begin{minipage}{\defwidth}\flushleft }{% \end{minipage} \end{lrbox}% \vskip10pt \noindent \defarg\fcolorbox{black}{defbackground}{\usebox\defsbox}% \vskip10pt \noindent \ignorespacesafterend } \newlength\tmplength \newcommand{\importantpar}{\relax \settowidth{\hangindent}{\bfseries\Huge$\bigtriangleup$\space}\relax \settoheight{\tmplength}{\bfseries\Huge$\bigtriangleup$}\relax \addtolength{\tmplength}{-0.5\baselineskip}\relax \hskip-\hangindent \smash{\raisebox{-\tmplength}{\bfseries \raisebox{3pt}{\large!}$\!$\makebox[0pt]{\Huge$\bigtriangleup$}\relax }}\relax \hskip0.5\hangindent \hangafter=-2\relax } \doxitem{Counter}{counter}{counters} \newcommand*{\ctrfmt}[1]{\texttt{#1}} \newcommand*{\ctr}[1]{\ctrfmt{#1}\SpecialMainCounterIndex{#1}} \newcommand*{\desctr}[1]{\ctrfmt{#1}\DescribeCounter{#1}} \newcommand*{\ics}[1]{\cs{#1}\SpecialMainIndex{#1}} \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 \newenvironment{example}[2]{\refstepcounter{example}\label{#2}% \par\vskip10pt\noindent \textbf{\large Example \theexample\ (#1)}% \addcontentsline{loe}{section}{\protect\numberline{\theexample}#1}% \nopagebreak\par\vskip10pt\nopagebreak }% {\begin{center}\rule{2in}{1pt}\end{center}} \newcommand*{\listofexamples}{\section*{List of Examples}% \@starttoc{loe}} \makeatother %bibliography database \DTLnewdb{docbib} \DTLnewrow{docbib} \DTLnewdbentry{docbib}{CiteKey}{Goossens} \DTLnewdbentry{docbib}{EntryType}{book} \DTLnewdbentry{docbib}{Author}{{}{Goossens}{}{Michel},{}{Mittelbach}{}{Frank},{}{Samarin}{}{Alexander}} \DTLnewdbentry{docbib}{Title}{The \LaTeX\ Companion} \DTLnewdbentry{docbib}{Publisher}{Addison-Wesley} \DTLnewdbentry{docbib}{Year}{1994} \begin{document} \DocInput{datatool.dtx} \end{document} % %\fi %\MakeShortVerb{"} %\DeleteShortVerb{\|} % % \title{datatool v 2.03: Databases and data manipulation} % \author{Nicola L.C. Talbot\\[10pt] %School of Computing Sciences\\ %University of East Anglia\\ %Norwich. Norfolk\\ %NR4 7TJ. United Kingdom.\\ %\url{http://theoval.cmp.uea.ac.uk/~nlct/}} % % \date{15th November 2009} % \maketitle % %\pdfbookmark[1]{Contents}{contents} %\tableofcontents %\pdfbookmark[1]{List of Examples}{examples} %\listofexamples %\pdfbookmark[1]{List of Figures}{figures} %\listoffigures %\pdfbookmark[1]{List of Tables}{tables} %\listoftables % % \section{Introduction} % % \changes{1.0}{2007 July 22}{Initial version} %The \sty{datatool} bundle consists of the following %packages: \sty{datatool}, \sty{datapie}, \sty{dataplot}, %\sty{databar} and \sty{databib}. % %The \sty{datatool} package can be used to: %\begin{itemize} %\item Create or load databases. %\item Sort rows of a database (either numerically or alphabetically, %ascending or descending). %\item Perform repetitive operations on each row of a database %(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). %\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. %\item Names can be converted to initials. %\item Strings can be tested to determine if they are all %upper or lower case. %\item String comparisons (both case sensitive and case insensitive) %can be performed. %\end{itemize} % %The \sty{datapie} package can be used to convert a database into %a pie chart: %\begin{itemize} %\item Segments can be separated from the rest of the chart to make %them stand out. %\item Colour/grey scale options. %\item Predefined segment colours can be changed. %\item Hooks provided to add extra information to the chart %\end{itemize} % %The \sty{databar} package can be used to convert a database into %a bar chart: %\begin{itemize} %\item Colour/grey scale options. %\item Predefined bar colours can be changed. %\item Hooks provided to add extra information to the chart %\end{itemize} % %(The \sty{datapie} and \sty{databar} packages do not support the %creation of 3D charts, and I have no plans to implement them at any %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. 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 %plots are currently not supported. % %The \sty{databib} package can be used to convert a \BibTeX\ database %into a \sty{datatool} database. % %\section{Data Types} %\label{sec:datatypes} % %The \sty{datatool} package recognises four data types: integers, %real numbers, currency and strings. % %\begin{description} %\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). % %\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 %\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 %character may not be used after the decimal character. % %\item[Currency] A currency symbol followed by an integer or %real number is considered to be the currency data type. %There are two predefined currency symbols, "\$" and \cs{pounds}. %In addition, if any of the following commands are defined at the %start of the document, they are also considered to be a currency %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 %\begin{definition}[\DescribeMacro{\DTLnewcurrencysymbol}]% %\cs{DTLnewcurrencysymbol}\marg{symbol} %\end{definition} % %\item[Strings] Anything that doesn't belong to the above three %types is considered to be a string. % %\end{description} % %\subsection{Conditionals} %\label{sec:ifconditions} % %The following conditionals are provided by the \sty{datatool} %package: %\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 %do \meta{false part}. For example %\begin{verbatim} %\DTLifint{2536}{integer}{not an integer} %\end{verbatim} %produces: %\DTLifint{2536}{integer}{not an integer}. % %The number group character may appear in the number, for example: %\begin{verbatim} %\DTLifint{2,536}{integer}{not an integer} %\end{verbatim} %produces: %\DTLifint{2,536}{integer}{not an integer}. %However, the number group character may only be followed by a group %of three digits. For example: %\begin{verbatim} %\DTLifint{2,5,3,6}{integer}{not an integer} %\end{verbatim} %produces: %\DTLifint{2,5,3,6}{integer}{not an integer}. %The number group character may be changed. For example: %\begin{verbatim} %\DTLsetnumberchars{.}{,}% %\DTLifint{2,536}{integer}{not an integer} %\end{verbatim} %this now produces: %\DTLsetnumberchars{.}{,}\relax %\DTLifint{2,536}{integer}{not an integer}, since 2,536 is now %a real number. % %Note that nothing else can be appended or prepended to the %number. For example: %\begin{verbatim} %\DTLsetnumberchars{,}{.}% %\DTLifint{2,536m}{integer}{not an integer} %\end{verbatim} %produces: %\DTLsetnumberchars{,}{.}\relax %\DTLifint{2,536m}{integer}{not an integer}. % %\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 %do \meta{false part}. For example %\begin{verbatim} %\DTLifreal{1000.0}{real}{not real} %\end{verbatim} %produces: %\DTLifreal{1000.0}{real}{not real}. % %Note that an integer is not a real number: %\begin{verbatim} %\DTLifreal{1,000}{real}{not real} %\end{verbatim} %produces: %\DTLifreal{1,000}{real}{not real}. % %Whereas %\begin{verbatim} %\DTLifreal{1,000.0}{real}{not real} %\end{verbatim} %produces: %\DTLifreal{1,000.0}{real}{not real}. % %However %\begin{verbatim} %\DTLsetnumberchars{.}{,}% %\DTLifreal{1,000}{real}{not real} %\end{verbatim} %produces: %\DTLsetnumberchars{.}{,}\relax %\DTLifreal{1,000}{real}{not real} since the comma is now %the decimal character. % %Currency is not considered to be real: %\begin{verbatim} %\DTLsetnumberchars{,}{.}% %\DTLifreal{\$1.00}{real}{not real} %\end{verbatim} %produces: %\DTLsetnumberchars{,}{.}\relax %\DTLifreal{\$1.00}{real}{not real}. % %\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 %do false part. For example: %\begin{verbatim} %\DTLifcurrency{\$5.99}{currency}{not currency} %\end{verbatim} %produces: %\DTLifcurrency{\$5.99}{currency}{not currency}. Similarly: %\begin{verbatim} %\DTLifcurrency{\pounds5.99}{currency}{not currency} %\end{verbatim} %produces: %\DTLifcurrency{\pounds5.99}{currency}{not currency}. %Note, however, that %\begin{verbatim} %\DTLifcurrency{US\$5.99}{currency}{not currency} %\end{verbatim} %produces: %\DTLifcurrency{US\$5.99}{currency}{not currency}. If you want %this to be considered currency, you will have to add the %sequence "US\$" to the set of currency symbols: %\begin{verbatim} %\DTLnewcurrencysymbol{US\$}% %\DTLifcurrency{US\$5.99}{currency}{not currency} %\end{verbatim} %this now produces: %\DTLnewcurrencysymbol{US\$}\relax %\DTLifcurrency{US\$5.99}{currency}{not currency}. % %This document has used the \sty{textcomp} package which defines %\cs{texteuro}, so this is also considered to be currency. For %example: %\begin{verbatim} %\DTLifcurrency{\texteuro5.99}{currency}{not currency} %\end{verbatim} %produces: %\DTLifcurrency{\texteuro5.99}{currency}{not currency}. % %The preferred method is to display the euro symbol in a sans-serif %font, but %\begin{verbatim} %\DTLifcurrency{\textsf{\texteuro}5.99}{currency}{not currency} %\end{verbatim} %will produce: %\DTLifcurrency{\textsf{\texteuro}5.99}{currency}{not currency}. % %It is better to define a new command, for example: %\begin{verbatim} %\DeclareRobustCommand*{\euro}{\textsf{\texteuro}} %\end{verbatim} %and add that command to the list of currency symbols. In fact, %in this case, if you define the command \cs{euro} in the %preamble, it will automatically be added to the list of known %currency symbols. If however you define \cs{euro} in the document, %you will have to add it using \ics{DTLnewcurrencysymbol}. For %example: %\begin{verbatim} %\newcommand*{\euro}{\textsf{\texteuro}}% %\DTLnewcurrencysymbol{\euro}% %\DTLifcurrency{\euro5.99}{currency}{not currency} %\end{verbatim} %produces: %\DeclareRobustCommand*{\euro}{\textsf{\texteuro}}\relax %\DTLnewcurrencysymbol{\euro}\relax %\DTLifcurrency{\euro5.99}{currency}{not currency}. % %\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 %currency, then do \meta{true part} otherwise do \meta{false part}. %For example: %\begin{verbatim} %\DTLifcurrencyunit{\$6.99}{\$}{dollars}{not dollars} %\end{verbatim} %produces: %\DTLifcurrencyunit{\$6.99}{\$}{dollars}{not dollars}. %Another example: %\begin{verbatim} %\def\cost{\euro10.50}% %\DTLifcurrencyunit{\cost}{\euro}{euros}{not euros} %\end{verbatim} %produces: %\def\cost{\euro10.50}\relax %\DTLifcurrencyunit{\cost}{\euro}{euros}{not euros}. % %\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 %currency) then do \meta{true part} otherwise do %\meta{false part}. %For example: %\begin{verbatim} %\DTLifnumerical{1,000.0}{number}{string}. %\end{verbatim} %produces: \DTLifnumerical{1,000.0}{number}{string}. %Whereas %\begin{verbatim} %\DTLsetnumberchars{.}{,}% %\DTLifnumerical{1,000.0}{number}{string}. %\end{verbatim} %produces: %\DTLsetnumberchars{.}{,}\relax %\DTLifnumerical{1,000.0}{number}{string}. %Since the number group character is now a full stop, and the %decimal character is now a comma. (The number group character %may only appear before the decimal character, not after it.) % %Currency is also considered to be numerical: %\begin{verbatim} %\DTLsetnumberchars{,}{.}% %\DTLifnumerical{\$1,000.0}{number}{string}. %\end{verbatim} %produces: %\DTLsetnumberchars{,}{.}\relax %\DTLifnumerical{\$1,000.0}{number}{string}. % %\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}. % %\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} %is an integer do \meta{int case}, if \meta{text} is a real number %do \meta{real case}, if \meta{text} is currency do %\meta{currency case}. For example: %\begin{verbatim} %\DTLifcasedatatype{1,000}{string}{integer}{real}{currency} %\end{verbatim} %produces: %\DTLifcasedatatype{1,000}{string}{integer}{real}{currency}. % %\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 %equality. For example %\begin{verbatim} %\DTLifnumeq{\pounds10.50}{10.5}{true}{false} %\end{verbatim} %produces: %\DTLifnumeq{\pounds10.50}{10.5}{true}{false}, since they are %considered to be numerically equivalent. Likewise: %\begin{verbatim} %\DTLifnumeq{\pounds10.50}{\$10.50}{true}{false} %\end{verbatim} %produces: %\DTLifnumeq{\pounds10.50}{\$10.50}{true}{false}. % %\begin{definition}[\DescribeMacro{\DTLifstringeq}]% %\cs{DTLifstringeq}\marg{string1}\marg{string2}\marg{true part}\marg{false part} %\end{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 %\meta{true part}, otherwise do \meta{false part}. The starred %version ignores the case, the unstarred version is case %sensitive. Both %\meta{string1} and \meta{string2} are considered to be strings, %so for example: %\begin{verbatim} %\DTLifstringeq{10.50}{10.5}{true}{false} %\end{verbatim} %produces: %\DTLifstringeq{10.50}{10.5}{true}{false}. % %Note that %\begin{verbatim} %\DTLifstringeq{Text}{text}{true}{false} %\end{verbatim} %produces: %\DTLifstringeq{Text}{text}{true}{false}, whereas %\begin{verbatim} %\DTLifstringeq*{Text}{text}{true}{false} %\end{verbatim} %produces: %\DTLifstringeq*{Text}{text}{true}{false}, however it should also be %noted that many commands will be ignored, so: %\begin{verbatim} %\DTLifstringeq{\uppercase{t}ext}{text}{true}{false} %\end{verbatim} %produces: %\DTLifstringeq{\uppercase{t}ext}{text}{true}{false}. % %Spaces are considered to be equivalent to \cs{space} and "~". For %example: %\begin{verbatim} %\DTLifstringeq{an apple}{an~apple}{true}{false} %\end{verbatim} %produces: %\DTLifstringeq{an apple}{an~apple}{true}{false}. Consecutive spaces %are treated as the same, for example: %\begin{verbatim} %\DTLifstringeq{an apple}{an apple}{true}{false} %\end{verbatim} %produces: %\DTLifstringeq{an apple}{an apple}{true}{false}. % %\begin{definition}[\DescribeMacro{\DTLifeq}]% %\cs{DTLifeq}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{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 %equivalent to \cs{DTLifnumeq}, otherwise it is equivalent to %\cs{DTLifstringeq} (when using \cs{DTLifeq}) or \cs{DTLifstringeq*} %(when using \cs{DTLifeq*}). % %\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). % %\begin{definition}[\DescribeMacro{\DTLifstringlt}]% %\cs{DTLifstringlt}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLifstringlt*}]% %\cs{DTLifstringlt*}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} %If \meta{string1} is alphabetically less than \meta{string2}, then do %\meta{true part}, otherwise do \meta{false part}. The starred %version ignores the case, the unstarred version is case %sensitive. %For example: %\begin{verbatim} %\DTLifstringlt{aardvark}{zebra}{less}{not less} %\end{verbatim} %produces: %\DTLifstringlt{aardvark}{zebra}{less}{not less}. % %Note that both \meta{string1} and \meta{string2} are considered to be %strings, so for example: %\begin{verbatim} %\DTLifstringlt{2}{10}{less}{not less} %\end{verbatim} %produces: %\DTLifstringlt{2}{10}{less}{not less}, since the string "2" %comes after the string "10" when arranged alphabetically. % %The case sensitive (unstarred) version considers uppercase characters %to be less than lowercase characters, so %\begin{verbatim} %\DTLifstringlt{B}{a}{less}{not less} %\end{verbatim} %produces: %\DTLifstringlt{B}{a}{less}{not less}, whereas %\begin{verbatim} %\DTLifstringlt*{B}{a}{less}{not less} %\end{verbatim} %produces: %\DTLifstringlt*{B}{a}{less}{not less}. % %\begin{definition}[\DescribeMacro{\DTLiflt}]% %\cs{DTLiflt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{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 %is equivalent to \cs{DTLifnumlt}, otherwise it is equivalent %to \cs{DTLstringlt} (when using \cs{DTLiflt}) or %\cs{DTLstringlt*} (when using \cs{DTLiflt*}). % %\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). % %\begin{definition}[\DescribeMacro{\DTLifstringgt}]% %\cs{DTLifstringgt}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLifstringgt*}]% %\cs{DTLifstringgt*}\marg{string1}\marg{string2}\marg{true %part}\marg{false part} %\end{definition} %If \meta{string1} is alphabetically greater than \meta{string2}, then %do \meta{true part}, otherwise do \meta{false part}. The %starred version ignores the case, the unstarred version is %case sensitive. For example: %\begin{verbatim} %\DTLifstringgt{aardvark}{zebra}{greater}{not greater} %\end{verbatim} %produces: %\DTLifstringgt{aardvark}{zebra}{greater}{not greater}. % %Note that both \meta{string1} and \meta{string2} are considered to be %strings, so for example: %\begin{verbatim} %\DTLifstringgt{2}{10}{greater}{not greater} %\end{verbatim} %produces: %\DTLifstringgt{2}{10}{greater}{not greater}, since the string "2" %comes after the string "10" when arranged alphabetically. % %As with \cs{DTLifstringlt}, uppercase characters are considered %to be less than lower case characters when performing a %case sensitive comparison so: %\begin{verbatim} %\DTLifstringgt{B}{a}{greater}{not greater} %\end{verbatim} %produces: %\DTLifstringgt{B}{a}{greater}{not greater}, whereas %\begin{verbatim} %\DTLifstringgt*{B}{a}{greater}{not greater} %\end{verbatim} %produces: %\DTLifstringgt*{B}{a}{greater}{not greater}. % %\begin{definition}[\DescribeMacro{\DTLifgt}]% %\cs{DTLifgt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{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 %is equivalent to \cs{DTLifnumgt}, otherwise it is equivalent %to \cs{DTLstringgt} (when using \cs{DTLifgt}) or %\cs{DTLstringgt*} (when using \cs{DTLifgt*}). % %\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 %equality. For example: %\begin{verbatim} %\DTLifnumclosedbetween{5.4}{5}{7}{inside}{outside} %\end{verbatim} %produces: %\DTLifnumclosedbetween{5.4}{5}{7}{inside}{outside}. %Note that the closed range includes end points: %\begin{verbatim} %\DTLifnumclosedbetween{5}{5}{7}{inside}{outside} %\end{verbatim} %produces: %\DTLifnumclosedbetween{5}{5}{7}{inside}{outside}. % %\begin{definition}[\DescribeMacro{\DTLifstringclosedbetween}]% %\cs{DTLifstringclosedbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{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 %\meta{max} in the alphabetical sense, or is equal to either %\meta{min} or \meta{max}. The starred version ignores the case, %the unstarred version is case sensitive. % %\begin{definition}[\DescribeMacro{\DTLifclosedbetween}]% %\cs{DTLifclosedbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{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 %equivalent to \cs{DTLifnumclosedbetween}, otherwise it is equivalent to %\cs{DTLifstringclosedbetween} (when using \cs{DTLifclosedbetween}) %or %\cs{DTLifstringclosedbetween*} (when using \cs{DTLifclosedbetween*}). % %\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 %equality. For example: %\begin{verbatim} %\DTLifnumopenbetween{5.4}{5}{7}{inside}{outside} %\end{verbatim} %produces: %\DTLifnumopenbetween{5.4}{5}{7}{inside}{outside}. %Note that end points are not included. For example: %\begin{verbatim} %\DTLifnumopenbetween{5}{5}{7}{inside}{outside} %\end{verbatim} %produces: %\DTLifnumopenbetween{5}{5}{7}{inside}{outside}. % %\begin{definition}[\DescribeMacro{\DTLifstringopenbetween}]% %\cs{DTLifstringopenbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{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 %\meta{max} in the alphabetical sense. %The starred version ignores the case, %the unstarred version is case sensitive. % %\begin{definition}[\DescribeMacro{\DTLifopenbetween}]% %\cs{DTLifopenbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{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 %equivalent to \cs{DTLifnumopenbetween}, otherwise it is equivalent to %\cs{DTLifstringopenbetween} (when using \cs{DTLifopenbetween}) %\cs{DTLifstringopenbetween*} (when using \cs{DTLifopenbetween*}). % %\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). % %\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). % %\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: %\begin{verbatim} %\DTLifAllUpperCase{WORD}{all upper}{not all upper} %\end{verbatim} %produces: %\DTLifAllUpperCase{WORD}{all upper}{not all upper}, %whereas %\begin{verbatim} %\DTLifAllUpperCase{Word}{all upper}{not all upper} %\end{verbatim} %produces: %\DTLifAllUpperCase{Word}{all upper}{not all upper}. %Note also that: %\begin{verbatim} %\DTLifAllUpperCase{\MakeUppercase{word}}{all upper}{not all upper} %\end{verbatim} %also produces: %\DTLifAllUpperCase{\MakeUppercase{word}}{all upper}{not all upper}. %\cs{MakeTextUppercase} (defined in David Carlisle's \sty{textcase} %package) and \cs{uppercase} are also detected, otherwise, if %a command is encountered, the case of the command is considered. %For example: %\begin{verbatim} %\DTLifAllUpperCase{MAN{\OE}UVRE}{all upper}{not all upper} %\end{verbatim} %produces: %\DTLifAllUpperCase{MAN{\OE}UVRE}{all upper}{not all upper}. % %\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: %\begin{verbatim} %\DTLifAllLowerCase{word}{all lower}{not all lower} %\end{verbatim} %produces: %\DTLifAllLowerCase{word}{all lower}{not all lower}, %whereas %\begin{verbatim} %\DTLifAllLowerCase{Word}{all lower}{not all lower} %\end{verbatim} %produces: %\DTLifAllLowerCase{Word}{all lower}{not all lower}. %Note also that: %\begin{verbatim} %\DTLifAllLowerCase{\MakeLowercase{WORD}}{all lower}{not all lower} %\end{verbatim} %also produces: %\DTLifAllLowerCase{\MakeLowercase{WORD}}{all lower}{not all lower}. %\cs{MakeTextLowercase} (defined in David Carlisle's \sty{textcase} %package) and \cs{lowercase} are also detected, otherwise, if %a command is encountered, the case of the command is considered. %For example: %\begin{verbatim} %\DTLifAllLowerCase{man{\oe}uvre}{all lower}{not all lower} %\end{verbatim} %produces: %\DTLifAllLowerCase{man{\oe}uvre}{all lower}{not all lower}. % %\begin{definition}[\DescribeMacro{\DTLifSubString}]% %\cs{DTLifSubString}\marg{string}\marg{substring}\marg{true %part}\marg{false part} %\end{definition} %This tests if \meta{substring} is a sub-string of \meta{string}. %This command performs a case sensitive match. For example: %\begin{verbatim} %\DTLifSubString{An apple}{app}{is substring}{isn't substring} %\end{verbatim} %produces: %\DTLifSubString{An apple}{app}{is substring}{isn't substring}. %Note that spaces are considered to be equivalent to \cs{space} %or "~", so %\begin{verbatim} %\DTLifSubString{An apple}{n~a}{is substring}{isn't substring} %\end{verbatim} %produces: %\DTLifSubString{An apple}{n~a}{is substring}{isn't substring}, %but other commands are skipped, so %\begin{verbatim} %\DTLifSubString{An \uppercase{a}pple}{app}{is substring}{isn't %substring} %\end{verbatim} %produces: %\DTLifSubString{An \uppercase{a}pple}{app}{is substring}{isn't %substring}, since the \cs{uppercase} command is ignored. Note also %that grouping is ignored, so: %\begin{verbatim} %\DTLifSubString{An {ap}ple}{app}{is substring}{isn't substring} %\end{verbatim} %produces: %\DTLifSubString{An {ap}ple}{app}{is substring}{isn't substring}. % %\cs{DTLifSubString} is case sensitive, so: %\begin{verbatim} %\DTLifSubString{An Apple}{app}{is substring}{isn't substring} %\end{verbatim} %produces: %\DTLifSubString{An Apple}{app}{is substring}{isn't substring}. % %\begin{definition}[\DescribeMacro{\DTLifStartsWith}]% %\cs{DTLifStartsWith}\marg{string}\marg{substring}\marg{true %part}\marg{false part} %\end{definition} %This is like \cs{DTLifSubString}, except that \meta{substring} must %occur at the start of \meta{string}. This command performs a case %sensitive match. For example, %\begin{verbatim} %\DTLifStartsWith{An apple}{app}{prefix}{not a prefix} %\end{verbatim} %produces: %\DTLifStartsWith{An apple}{app}{prefix}{not a prefix}. All the %above remarks for \cs{DTLifSubString} also applies to %\cs{DTLifStartsWith}. For example: %\begin{verbatim} %\DTLifStartsWith{\uppercase{a}n apple}{an~}{prefix}{not a prefix} %\end{verbatim} %produces: %\DTLifStartsWith{\uppercase{a}n apple}{an~}{prefix}{not a prefix}, %since \cs{uppercase} is ignored, and "~" is considered to be the %same as a space, whereas %\begin{verbatim} %\DTLifStartsWith{An apple}{an~}{prefix}{not a prefix} %\end{verbatim} %produces: %\DTLifStartsWith{An apple}{an~}{prefix}{not a prefix}. % %\subsection{\texorpdfstring{\sty{ifthen}}{ifthen} conditionals} %\label{sec:ifthen} % %The commands described in the previous section can not be %used as the conditional part of the \cs{ifthenelse} or %\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}. 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. % %\begin{definition}[\DescribeMacro{\DTLisstring}]% %\cs{DTLisstring}\marg{text} %\end{definition} %Tests if \meta{text} is a string. For example: %\begin{verbatim} %\ifthenelse{\DTLisstring{some text}}{string}{not a string} %\end{verbatim} %produces: %\ifthenelse{\DTLisstring{some text}}{string}{not a string}. % %\begin{definition}[\DescribeMacro{\DTLisnumerical}]% %\cs{DTLisnumerical}\marg{text} %\end{definition} %Tests if \meta{text} is numerical (i.e.\ not a string). For example: %\begin{verbatim} %\ifthenelse{\DTLisnumerical{\$10.95}}{numerical}{not numerical} %\end{verbatim} %produces: %\ifthenelse{\DTLisnumerical{\$10.95}}{numerical}{not numerical}. % %Note however that \cs{DTLisnumerical} requires more care than %\cs{DTLifnumerical} when used with some of the other currency %symbols. Consider: %\begin{verbatim} %\DTLifnumerical{\pounds10.95}{numerical}{not numerical} %\end{verbatim} %This produces: %\DTLifnumerical{\pounds10.95}{numerical}{not numerical}. %However %\begin{verbatim} %\ifthenelse{\DTLisnumerical{\pounds10.95}}{numerical}{not numerical} %\end{verbatim} %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: %\begin{verbatim} %\ifthenelse{\DTLisnumerical{\noexpand\pounds10.95}}{numerical}{not numerical} %\end{verbatim} %produces: %\ifthenelse{\DTLisnumerical{\noexpand\pounds10.95}}{numerical}{not numerical}. % %Likewise: %\begin{verbatim} %\def\cost{\pounds10.95}% %\ifthenelse{\DTLisnumerical{\noexpand\cost}}{numerical}{not numerical} %\end{verbatim} %produces: %\def\cost{\pounds10.95}\relax %\ifthenelse{\DTLisnumerical{\noexpand\cost}}{numerical}{not numerical}. % %\begin{definition}[\DescribeMacro{\DTLiscurrency}]% %\cs{DTLiscurrency}\marg{text} %\end{definition} %Tests if \meta{text} is currency. For example: %\begin{verbatim} %\ifthenelse{\DTLiscurrency{\$10.95}}{currency}{not currency} %\end{verbatim} %produces: %\ifthenelse{\DTLiscurrency{\$10.95}}{currency}{not currency}. % %The same warning given above for \cs{DTLisnumerical} also applies %here. % %\begin{definition}[\DescribeMacro{\DTLiscurrencyunit}]% %\cs{DTLiscurrencyunit}\marg{text}\marg{symbol} %\end{definition} %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}. %Another example: %\begin{verbatim} %\def\cost{\euro10.50}% %\ifthenelse{\DTLiscurrencyunit{\noexpand\cost}{\noexpand\euro}}% %{euros}{not euros} %\end{verbatim} %produces: %\def\cost{\euro10.50}\relax %\ifthenelse{\DTLiscurrencyunit{\noexpand\cost}{\noexpand\euro}}% %{euros}{not euros}. Again note the use of \cs{noexpand}. % %\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: %\begin{verbatim} %\ifthenelse{\DTLisreal{1.5}}{real}{not real} %\end{verbatim} %produces: %\ifthenelse{\DTLisreal{1.5}}{real}{not real}. % %\begin{definition}[\DescribeMacro{\DTLisint}]% %\cs{DTLisint}\marg{text} %\end{definition} %Tests if \meta{text} is an integer. For example: %\begin{verbatim} %\ifthenelse{\DTLisint{153}}{integer}{not an integer} %\end{verbatim} %produces: %\ifthenelse{\DTLisint{153}}{integer}{not an integer}. % %\begin{definition}[\DescribeMacro{\DTLislt}]% %\cs{DTLislt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is less than \meta{arg2}. As with %\cs{DTLiflt}, if \meta{arg1} and \meta{arg2} 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, but you can instead use \cs{DTLisilt} %to ignore the case.) % %\begin{definition}[\DescribeMacro{\DTLisilt}]% %\cs{DTLisilt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is less than \meta{arg2}. As with %\cs{DTLiflt*}, if \meta{arg1} and \meta{arg2} are numerical, %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % %\begin{definition}[\DescribeMacro{\DTLisgt}]% %\cs{DTLisgt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is greater than \meta{arg2}. As with %\cs{DTLifgt}, if \meta{arg1} and \meta{arg2} 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{DTLisigt} to %ignore the case.) % %\begin{definition}[\DescribeMacro{\DTLisigt}]% %\cs{DTLisigt}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is greater than \meta{arg2}. As with %\cs{DTLifgt*}, if \meta{arg1} and \meta{arg2} are numerical, %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % %\begin{definition}[\DescribeMacro{\DTLiseq}]% %\cs{DTLiseq}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is equal to \meta{arg2}. As with %\cs{DTLifeq}, if \meta{arg1} and \meta{arg2} 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{DTLisieq}.) % %\begin{definition}[\DescribeMacro{\DTLisieq}]% %\cs{DTLisieq}\marg{arg1}\marg{arg2} %\end{definition} %This checks if \meta{arg1} is equal to \meta{arg2}. As with %\cs{DTLifeq*}, if \meta{arg1} and \meta{arg2} are numerical, %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % %\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 %\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}.) % %\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 %\cs{DTLifclosedbetween*}, if the arguments are numerical, %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % %\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 %\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}.) % %\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 %\cs{DTLifopenbetween*}, if the arguments are numerical, %a numerical comparison is used, otherwise a case insensitive %alphabetical comparison is used. % %\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). % %\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). % %\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). % %\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). % %\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). % %\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 %numbers in standard fixed point format (i.e.\ no number group %separators, no currency and a full stop as a decimal point). % %\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 %numbers in standard fixed point format (i.e.\ no number group %separators, no currency and a full stop as a decimal point). % %\begin{definition}[\DescribeMacro{\DTLisSubString}]% %\cs{DTLisSubString}\marg{string}\marg{substring} %\end{definition} %This checks if \meta{substring} is contained in \meta{string}. %The remarks about \cs{DTLifSubString} also apply to %\cs{DTLisSubString}. This command performs a case sensitive %match. % %\begin{definition}[\DescribeMacro{\DTLisPrefix}]% %\cs{DTLisPrefix}\marg{string}\marg{prefix} %\end{definition} %This checks if \meta{string} starts with \meta{prefix}. %The remarks about \cs{DTLifStartsWith} also apply to %\cs{DTLisPrefix}. This command performs a case sensitive %match. % %\section{Fixed Point Arithmetic} %\label{sec:fp} % %The \sty{datatool} package uses the \sty{fp} package to perform %fixed point arithmetic, however all numbers must be converted %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 %\begin{definition}[\DescribeMacro{\DTLconverttodecimal}]% %\cs{DTLconverttodecimal}\marg{num}\marg{cmd} %\end{definition} %The decimal number will be stored in \meta{cmd} which must be %a control sequence. For example: %\begin{verbatim} %\DTLconverttodecimal{1,563.54}{\mynum} %\end{verbatim} %\DTLconverttodecimal{1,563.54}{\mynum}\relax %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: %\begin{definition}[\DescribeMacro{\DTLdecimaltolocale}]% %\cs{DTLdecimaltolocale}\marg{number}\marg{cmd} %\end{definition} %This converts a plain decimal number \meta{number} (that uses a full %stop as the decimal character and has no number group characters) %into a locale dependent format. The resulting number is stored %in \meta{cmd}, which must be a control sequence. For example: %\begin{verbatim} %\DTLdecimaltolocale{6795.3}{\mynum} %\end{verbatim} %\DTLdecimaltolocale{6795.3}{\mynum} %will define \cs{mynum} to be \texttt{\mynum}. % %\begin{definition}[\DescribeMacro{\DTLdecimaltocurrency}]% %\cs{DTLdecimaltocurrency}\marg{number}\marg{cmd} %\end{definition} %This will convert a plain decimal number \meta{number} into a %locale dependent currency format. For example: %\begin{verbatim} %\DTLdecimaltocurrency{267.5}{\price}\price %\end{verbatim} %will produce: %\DTLdecimaltocurrency{267.5}{\price}\price. % %The currency symbol used by \cs{DTLdecimaltocurrency} is %initially "\$", but will use the currency last encountered. %So, for example %\begin{verbatim} %\DTLifcurrency{\texteuro45.00}{}{}% %\DTLdecimaltocurrency{267.5}{\price}\price %\end{verbatim} %will produce: %\DTLifcurrency{\texteuro45.00}{}{}\relax %\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: %\begin{definition}[\DescribeMacro{\DTLsetdefaultcurrency}]% %\cs{DTLsetdefaultcurrency}\marg{symbol} %\end{definition} %For example: %\begin{verbatim} %\DTLsetdefaultcurrency{\textyen}% %\DTLdecimaltocurrency{267.5}{\price}\price %\end{verbatim} %will produce: %\DTLsetdefaultcurrency{\textyen}\relax %\DTLdecimaltocurrency{267.5}{\price}\price % %The \sty{datatool} package provides convenience commands which %use \cs{DTLconverttodecimal}, and then use the basic macros provided %by the \sty{fp} package. The resulting value is then converted %back into the locale format using %\cs{DTLdecimaltolocale} or \cs{DTLdecimaltocurrency}. % % %\begin{definition}[\DescribeMacro{\DTLadd}]% %\cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} %\end{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}. %\cs{DLTadd} sets \meta{cmd} locally, while \cs{DTLgadd} sets %\meta{cmd} globally. % %For example: %\begin{verbatim} %\DTLadd{\result}{3,562.65}{412.2}\result %\end{verbatim} %will produce: %\DTLadd{\result}{3,562.65}{412.2}\result. Since %\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} %produces: %\DTLadd{\result}{\pounds3,562.65}{\pounds452.2}\result. % %Note that \sty{datatool} isn't aware of exchange rates! If you %use different currency symbols, the last symbol will be used. %For example %\begin{verbatim} %\DTLadd{\result}{\pounds3,562.65}{\euro452.2}\result %\end{verbatim} %produces: %\DTLadd{\result}{\pounds3,562.65}{\euro452.2}\result. % %Likewise, if one value is a number and the other is a currency, %the type of the last value, \meta{num2}, will be used for the %result. For example: %\begin{verbatim} %\DTLadd{\result}{3,562.65}{\$452.2}\result %\end{verbatim} %produces: %\DTLadd{\result}{3,562.65}{\$452.2}\result. % %\begin{definition}[\DescribeMacro{\DTLaddall}]% %\cs{DTLaddall}\marg{cmd}\marg{number list} %\end{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 %the numbers in \meta{number list}. %\cs{DLTaddall} sets \meta{cmd} locally, while \cs{DTLgaddall} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLaddall{\total}{25.1,45.2,35.6}\total %\end{verbatim} %produces: %\DTLaddall{\total}{25.1,45.2,35.6}\total. %Note that if any of the numbers in \meta{number list} contain %a comma, you must group the number. Example: %\begin{verbatim} %\DTLaddall{\total}{{1,525},{2,340},500}\total %\end{verbatim} %produces: %\DTLaddall{\total}{{1,525},{2,340},500}\total. % %\begin{definition}[\DescribeMacro{\DTLsub}]% %\cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLgsub}]% %\cs{DTLgsub}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to %\meta{num1}$-$\meta{num2}. %\cs{DLTsub} sets \meta{cmd} locally, while \cs{DTLgsub} sets %\meta{cmd} globally. % %For example: %\begin{verbatim} %\DTLsub{\result}{3,562.65}{412.2}\result %\end{verbatim} %will produce: %\DTLsub{\result}{3,562.65}{412.2}\result. As with \cs{DTLadd}, %\meta{num1} and \meta{num2} may be currency. % %\begin{definition}[\DescribeMacro{\DTLmul}]% %\cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLgmul}]% %\cs{DTLgmul}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to %\meta{num1}$\times$\meta{num2}. %\cs{DLTmul} sets \meta{cmd} locally, while \cs{DTLgmul} sets %\meta{cmd} globally. % %For example: %\begin{verbatim} %\DTLmul{\result}{568.95}{2}\result %\end{verbatim} %will produce: %\DTLmul{\result}{568.95}{2}\result. Again, \meta{num1} or %\meta{num2} may be currency, but unlike \cs{DTLadd} and \cs{DTLsub}, %currency overrides integer/real. For example: %\begin{verbatim} %\DTLmul{\result}{\pounds568.95}{2}\result %\end{verbatim} %will produce: %\DTLmul{\result}{\pounds568.95}{2}\result. Likewise, %\begin{verbatim} %\DTLmul{\result}{2}{\pounds568.95}\result %\end{verbatim} %will produce: %\DTLmul{\result}{2}{\pounds568.95}\result. Although it doesn't make %sense to multiply two currencies, \sty{datatool} will allow %\begin{verbatim} %\DTLmul{\result}{\$2}{\pounds568.95}\result %\end{verbatim} %which will produce: %\DTLmul{\result}{\$2}{\pounds568.95}\result. % %\begin{definition}[\DescribeMacro{\DTLdiv}]% %\cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLgdiv}]% %\cs{DTLgdiv}\marg{cmd}\marg{num1}\marg{num2} %\end{definition} %This sets the control sequence \meta{cmd} to %\meta{num1}$\div$\meta{num2}. %\cs{DLTdiv} sets \meta{cmd} locally, while \cs{DTLgdiv} sets %\meta{cmd} globally. % %For example: %\begin{verbatim} %\DTLdiv{\result}{501}{2}\result %\end{verbatim} %will produce: %\DTLdiv{\result}{501}{2}\result. Again, \meta{num1} or \meta{num2} %may be currency, but the resulting type will be not be a currency %if both \meta{num1} and \meta{num2} use the same currency symbol. %For example: %\begin{verbatim} %\DTLdiv{\result}{\$501}{\$2}\result %\end{verbatim} %will produce: %\DTLdiv{\result}{\$501}{\$2}\result. Whereas %\begin{verbatim} %\DTLdiv{\result}{\$501}{2}\result %\end{verbatim} %will produce: %\DTLdiv{\result}{\$501}{2}\result. % %\begin{definition}[\DescribeMacro{\DTLabs}]% %\cs{DTLabs}\marg{cmd}\marg{num} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLgabs}]% %\cs{DTLgabs}\marg{cmd}\marg{num} %\end{definition} %This sets \meta{cmd} to the absolute value of \meta{num}. %\cs{DLTabs} sets \meta{cmd} locally, while \cs{DTLgabs} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLabs{\result}{-\pounds2.50}\result %\end{verbatim} %produces: %\DTLabs{\result}{-\pounds2.50}\result. % %\begin{definition}[\DescribeMacro{\DTLneg}]% %\cs{DTLneg}\marg{cmd}\marg{num} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLgneg}]% %\cs{DTLgneg}\marg{cmd}\marg{num} %\end{definition} %This sets \meta{cmd} to the negative of \meta{num}. %\cs{DLTneg} sets \meta{cmd} locally, while \cs{DTLgneg} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLneg{\result}{\pounds2.50}\result %\end{verbatim} %produces: %\DTLneg{\result}{\pounds2.50}\result. % %\begin{definition}[\DescribeMacro{\DTLsqrt}]% %\cs{DTLsqrt}\marg{cmd}\marg{num} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLgsqrt}]% %\cs{DTLgsqrt}\marg{cmd}\marg{num} %\end{definition} %This sets \meta{cmd} to the sqrt root of \meta{num}. %\cs{DLTsqrt} sets \meta{cmd} locally, while \cs{DTLgsqrt} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLsqrt{\result}{2}\result %\end{verbatim} %produces: %\DTLsqrt{\result}{2}\result. % %\begin{definition}[\DescribeMacro{\DTLmin}]% %\cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} %\end{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 %\meta{num1} and \meta{num2}. %\cs{DLTmin} sets \meta{cmd} locally, while \cs{DTLgmin} sets %\meta{cmd} globally. For example: %\begin{verbatim} %\DTLmin{\result}{256}{32}\result %\end{verbatim} %produces: %\DTLmin{\result}{256}{32}\result. %Again, \meta{num1} and \meta{num2} may %be currency. For example: %\begin{verbatim} %\DTLmin{\result}{256}{\pounds32}\result %\end{verbatim} %produces: %\DTLmin{\result}{256}{\pounds32}\result, whereas %\begin{verbatim} %\DTLmin{\result}{\pounds256}{32}\result %\end{verbatim} %produces: %\DTLmin{\result}{\pounds256}{32}\result. As mentioned above, %\sty{datatool} doesn't know about exchange rates, so be careful %about mixing currencies. For example: %\begin{verbatim} %\DTLmin{\result}{\pounds5}{\$6}\result %\end{verbatim} %produces: %\DTLmin{\result}{\pounds5}{\$6}\result, which may not necessarily %be true! % %\begin{definition}[\DescribeMacro{\DTLminall}]% %\cs{DTLminall}\marg{cmd}\marg{number list} %\end{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 %the numbers in \meta{number list}. %\cs{DLTminall} sets \meta{cmd} locally, while \cs{DTLgminall} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLminall{\theMin}{25.1,45.2,35.6}\theMin %\end{verbatim} %produces: %\DTLminall{\theMin}{25.1,45.2,35.6}\theMin. %Note that if any of the numbers in \meta{number list} contain %a comma, you must group the number. Example: %\begin{verbatim} %\DTLminall{\theMin}{{1,525},{2,340},500}\theMin %\end{verbatim} %produces: %\DTLminall{\theMin}{{1,525},{2,340},500}\theMin. % %\begin{definition}[\DescribeMacro{\DTLmax}]% %\cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} %\end{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 %\meta{num1} and \meta{num2}. %\cs{DLTmax} sets \meta{cmd} locally, while \cs{DTLgmax} sets %\meta{cmd} globally. For example: %\begin{verbatim} %\DTLmax{\result}{256}{32}\result %\end{verbatim} %produces: %\DTLmax{\result}{256}{32}\result. %Again, \meta{num1} and \meta{num2} may %be currency, but the same warnings for \cs{DTLmin} apply. % %\begin{definition}[\DescribeMacro{\DTLmaxall}]% %\cs{DTLmaxall}\marg{cmd}\marg{number list} %\end{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 %the numbers in \meta{number list}. %\cs{DLTmaxall} sets \meta{cmd} locally, while \cs{DTLgmaxall} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLmaxall{\theMax}{25.1,45.2,35.6}\theMax %\end{verbatim} %produces: %\DTLmaxall{\theMax}{25.1,45.2,35.6}\theMax. %Note that if any of the numbers in \meta{number list} contain %a comma, you must group the number. Example: %\begin{verbatim} %\DTLmaxall{\theMax}{{1,525},{2,340},500}\theMax %\end{verbatim} %produces: %\DTLmaxall{\theMax}{{1,525},{2,340},500}\theMax. % %\begin{definition}[\DescribeMacro{\DTLmeanforall}]% %\cs{DTLmeanforall}\marg{cmd}\marg{number list} %\end{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 %the numbers in \meta{number list}. %\cs{DLTmeanforall} sets \meta{cmd} locally, while \cs{DTLgmeanforall} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLmeanforall{\theMean}{25.1,45.2,35.6}\theMean %\end{verbatim} %produces: %\DTLmeanforall{\theMean}{25.1,45.2,35.6}\theMean. %Note that if any of the numbers in \meta{number list} contain %a comma, you must group the number. Example: %\begin{verbatim} %\DTLmeanforall{\theMean}{{1,525},{2,340},500}\theMean %\end{verbatim} %produces: %\DTLmeanforall{\theMean}{{1,525},{2,340},500}\theMean. % %\begin{definition}[\DescribeMacro{\DTLvarianceforall}]% %\cs{DTLvarianceforall}\marg{cmd}\marg{number list} %\end{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 %the numbers in \meta{number list}. %\cs{DLTvarianceforall} sets \meta{cmd} locally, while \cs{DTLgvarianceforall} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLvarianceforall{\theVar}{25.1,45.2,35.6}\theVar %\end{verbatim} %produces: %\DTLvarianceforall{\theVar}{25.1,45.2,35.6}\theVar. %Again note that if any of the numbers in \meta{number list} %contain a comma, you must group the number. % %\begin{definition}[\DescribeMacro{\DTLsdforall}]% %\cs{DTLsdforall}\marg{cmd}\marg{number list} %\end{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 %the numbers in \meta{number list}. %\cs{DLTsdforall} sets \meta{cmd} locally, while \cs{DTLgsdforall} sets %\meta{cmd} globally. Example: %\begin{verbatim} %\DTLsdforall{\theSD}{25.1,45.2,35.6}\theSD %\end{verbatim} %produces: %\DTLsdforall{\theSD}{25.1,45.2,35.6}\theSD. %Note that if any of the numbers in \meta{number list} contain %a comma, you must group the number. Example: %\begin{verbatim} %\DTLsdforall{\theSD}{{1,525},{2,340},500}\theSD %\end{verbatim} %produces: %\DTLsdforall{\theSD}{{1,525},{2,340},500}\theSD. % %\begin{definition}[\DescribeMacro{\DTLround}]% %\cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} %\end{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. Example: %\begin{verbatim} %\DTLround{\result}{3.135276}{2}\result %\end{verbatim} %produces: \DTLround{\result}{3.135276}{2}\result. % %\begin{definition}[\DescribeMacro{\DTLtrunc}]% %\cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} %\end{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. Example: %\begin{verbatim} %\DTLtrunc{\result}{3.135276}{2}\result %\end{verbatim} %produces: \DTLtrunc{\result}{3.135276}{2}\result. % %\begin{definition}[\DescribeMacro{\DTLclip}]% %\cs{DTLclip}\marg{cmd}\marg{num} %\end{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 %removed. %\cs{DLTclip} sets \meta{cmd} locally, while \cs{DTLgclip} sets %\meta{cmd} globally. % %\section{Strings} %\label{sec:strings} % %Strings are considered to be anything non-numerical. The %\sty{datatool} package loads the \sty{substr} package, so %you can use the commands defined in that package to determine %if one string is contained in another string. In addition, %the \sty{datatool} provides the following macros: % %\begin{definition}[\DescribeMacro{\DTLsubstitute}]% %\cs{DTLsubstitute}\marg{cmd}\marg{original}\marg{replacement} %\end{definition} %This replaces the first occurrence of \meta{original} in %\meta{cmd} with \meta{replacement}. Note that \meta{cmd} must %be the name of a command. For example: %\begin{verbatim} %\def\mystr{abcdce}\DTLsubstitute{\mystr}{c}{z}\mystr %\end{verbatim} %produces: %\def\mystr{abcdce}\DTLsubstitute{\mystr}{c}{z}\mystr. % %\begin{definition}[\DescribeMacro{\DTLsubstituteall}]% %\cs{DTLsubstituteall}\marg{cmd}\marg{original}\marg{replacement} %\end{definition} %This replaces all occurrences of \meta{original} in %\meta{cmd} with \meta{replacement}, where again, \meta{cmd} must %be the name of a command. For example: %\begin{verbatim} %\def\mystr{abcdce}\DTLsubstituteall{\mystr}{c}{z}\mystr %\end{verbatim} %produces: %\def\mystr{abcdce}\DTLsubstituteall{\mystr}{c}{z}\mystr. % %\begin{definition}[\DescribeMacro{\DTLsplitstring}]% %\cs{DTLsplitstring}\marg{string}\marg{split text}\marg{before %cmd}\marg{after cmd} %\end{definition} %This splits \meta{string} at the first occurrence of \meta{split text} %and stores the before part in the command \meta{before cmd} and %the after part in the command \meta{after cmd}. For example: %\begin{verbatim} %\DTLsplitstring{abcdce}{c}{\beforepart}{\afterpart}% %Before part: ``\beforepart''. After part: ``\afterpart'' %\end{verbatim} %produces: %\DTLsplitstring{abcdce}{c}{\beforepart}{\afterpart}\relax %Before part: ``\beforepart''. After part: ``\afterpart''. %Note that for \cs{DTLsplitstring}, \meta{string} is not %expanded, so %\begin{verbatim} %\def\mystr{abcdce}% %\DTLsplitstring{\mystr}{c}{\beforepart}{\afterpart}% %Before part: ``\beforepart''. After part: ``\afterpart'' %\end{verbatim} %produces: %\def\mystr{abcdce}\relax %\DTLsplitstring{\mystr}{c}{\beforepart}{\afterpart}% %Before part: ``\beforepart''. After part: ``\afterpart''. If you %want the string expanded, you will need to use \cs{expandafter}: %\begin{verbatim} %\def\mystr{abcdce}% %\expandafter\DTLsplitstring\expandafter %{\mystr}{c}{\beforepart}{\afterpart}% %Before part: ``\beforepart''. After part: ``\afterpart'' %\end{verbatim} %which produces: %\def\mystr{abcdce}\relax %\expandafter\DTLsplitstring\expandafter %{\mystr}{c}{\beforepart}{\afterpart}\relax %Before part: ``\beforepart''. After part: ``\afterpart''. % %\begin{definition}[\DescribeMacro{\DTLinitials}]% %\cs{DTLinitials}\marg{string} %\end{definition} %This converts \meta{string} (typically a name) into initials. %For example: %\begin{verbatim} %\DTLinitials{Mary Ann} %\end{verbatim} %produces: %\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). %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 %accent command will be ignored. For example: %\begin{verbatim} %\DTLinitials{{\'E}lise Adams} %\end{verbatim} %produces: %\DTLinitials{{\'E}lise Adams}, whereas %\begin{verbatim} %\DTLinitials{\'Elise Adams} %\end{verbatim} %produces: %\DTLinitials{\'Elise Adams} In fact, any command which appears %at the start of the name that is not enclosed in a group will %be ignored. For example: %\begin{verbatim} %\DTLinitials{\MakeUppercase{m}ary ann} %\end{verbatim} %produces: %\DTLinitials{\MakeUppercase{m}ary ann}, whereas %\begin{verbatim} %\DTLinitials{{\MakeUppercase{m}}ary ann} %\end{verbatim} %produces: %\DTLinitials{{\MakeUppercase{m}}ary ann}, but note that %\begin{verbatim} %\DTLinitials{\MakeUppercase{mary ann}} %\end{verbatim} %produces: %\DTLinitials{\MakeUppercase{mary ann}} % %\begin{definition}[\DescribeMacro{\DTLstoreinitials}]% %\cs{DTLstoreinitials}\marg{string}\marg{cmd} %\end{definition} %This converts \meta{string} into initials and stores the %result in \meta{cmd} which must be a command name. The remarks %about \cs{DTLinitials} also relate to \cs{DTLstoreinitials}. %For example %\begin{verbatim} %\DTLstoreinitials{Marie-{\'E}lise del~Rosario}{\theInitials}\theInitials %\end{verbatim} %produces: %\DTLstoreinitials{Marie-{\'E}lise del~Rosario}{\theInitials}\theInitials % %Both the above commands rely on the following to format the %initials: %\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. % %\begin{definition}[\DescribeMacro{\DTLbetweeninitials}]% %\cs{DTLbetweeninitials} %\end{definition} %This indicates what to do between initials. This does a %full stop by default. % %\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. % %\begin{definition}[\DescribeMacro{\DTLafterinitialbeforehyphen}]% %\cs{DTLafterinitialbeforehyphen} %\end{definition} %This indicates what to do between an initial and a hyphen. %This simply does a full stop by default. % %For example %\begin{verbatim} %\renewcommand*{\DTLafterinitialbeforehyphen}{}% %\DTLinitials{Marie-{\'E}lise del~Rosario} %\end{verbatim} %produces: %{\renewcommand*{\DTLafterinitialbeforehyphen}{}\relax %\DTLinitials{Marie-{\'E}lise del~Rosario}} %whereas %\begin{verbatim} %\renewcommand*{\DTLafterinitialbeforehyphen}{}% %\renewcommand*{\DTLafterinitials}{}% %\renewcommand*{\DTLbetweeninitials}{}% %\renewcommand*{\DTLinitialhyphen}{}% %\DTLinitials{Marie-{\'E}lise del~Rosario} %\end{verbatim} %produces: %{\renewcommand*{\DTLafterinitialbeforehyphen}{}\relax %\renewcommand*{\DTLafterinitials}{}\relax %\renewcommand*{\DTLbetweeninitials}{}\relax %\renewcommand*{\DTLinitialhyphen}{}\relax %\DTLinitials{Marie-{\'E}lise del~Rosario}} % %\section{Databases} %\label{sec:databases} % %The \sty{datatool} package provides a means of creating and %loading databases. Once a database has been created (or loaded), %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} % %\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: %\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}. % %\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}. % %\begin{definition}[\DescribeMacro{\DTLcolumncount}]% %\cs{DTLcolumncount}\marg{db name} %\end{definition} %This command displays the number of columns (or keys) in the %database called \meta{db name}. % %\begin{definition}[\DescribeMacro{\DTLnewrow}]% %\cs{DTLnewrow}\marg{db name} %\end{definition} %This command starts a new row in the database called \meta{db name}. %This new row becomes the current row when adding new entries. % %For example, the following creates an empty database called %\texttt{mydata}: %\begin{verbatim} %\DTLnewdb{mydata} %\end{verbatim} %\DTLnewdb{mydata}\relax %The following tests if the database is empty: %\begin{verbatim} %\DTLifdbempty{mydata}{empty}{not empty}! %\end{verbatim} %This produces: %\DTLifdbempty{mydata}{empty}{not empty}! % %The following adds an empty row to the database, this is the %first row of the database: %\begin{verbatim} %\DTLnewrow{mydata} %\end{verbatim} %\DTLnewrow{mydata}\relax %Note that even though the only row in the database is currently %empty, the database is no longer considered to be empty: %\begin{verbatim} %\DTLifdbempty{mydata}{empty}{not empty}! %\end{verbatim} %This now produces: %\DTLifdbempty{mydata}{empty}{not empty}! The row count is %given by %\begin{verbatim} %\DTLrowcount{mydata} %\end{verbatim} %which produces: %\DTLrowcount{mydata}. The column count is given by %\begin{verbatim} %\DTLcolumncount{mydata} %\end{verbatim} %which produces: \DTLcolumncount{mydata}. % %\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 %is \meta{value} and adds it to the last row of the database %called \meta{db name}. For example: %\begin{verbatim} %\DTLnewdbentry{mydata}{Surname}{Smith} %\DTLnewdbentry{mydata}{FirstName}{John} %\end{verbatim} %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}. Note that the %key should not contain any fragile commands. It is generally %best to only use non-active characters in the key. % %The value isn't expanded by default, but you can change this %using the declaration: %\begin{definition}[\DescribeMacro{\dtlexpandnewvalue}] %\cs{dtlexpandnewvalue} %\end{definition} %This can be localised by placing it in a group, or you can %switch back using: %\begin{definition}[\DescribeMacro{\dtlnoexpandnewvalue}] %\cs{dtlnoexpandnewvalue} %\end{definition} % %\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: %\begin{definition}[\DescribeMacro{\DTLpar}]% %\cs{DTLpar} %\end{definition} % %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} 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}). For example: %\begin{verbatim} %\DTLaddentryforrow{mydata}{\firstname=FirstName,\surname=Surname}% %{\DTLiseq{\firstname}{John}\and\DTLiseq{\surname}{Smith}}% %{Score}{75} %\end{verbatim} %Note that unlike \cs{DTLnewdbentry}, the value is always expanded %when adding an entry using \cs{DTLaddentryforrow}. % %\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} % %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: %\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 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}. 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: %\begin{definition}[\DescribeMacro{\DTLsettabseparator}]% %\cs{DTLsettabseparator} %\end{definition} %To set the separator to a character other than a tab, you need to use %\begin{definition}[\DescribeMacro{\DTLsetseparator}]% %\cs{DTLsetseparator}\marg{character} %\end{definition} %The delimiter can be changed using %\begin{definition}[\DescribeMacro{\DTLsetdelimiter}]% %\cs{DTLsetdelimiter}\marg{character} %\end{definition} % %For example, suppose you have a file called \texttt{mydata.csv} %which contains the following: %\begin{verbatim} %FirstName,Surname,Score %John,"Smith, Jr",68 %Jane,Brown,75 %Andy,Brown,42 %Z\"oe,Adams,52 %\end{verbatim} %then %\begin{verbatim} %\DTLloaddb{mydata}{mydata.csv} %\end{verbatim} %is equivalent to: %\begin{verbatim} %\DTLnewdb{mydata} %\DTLnewrow{mydata}% %\DTLnewdbentry{mydata}{FirstName}{John}% %\DTLnewdbentry{mydata}{Surname}{Smith, Jr}% %\DTLnewdbentry{mydata}{Score}{68}% %\DTLnewrow{mydata}% %\DTLnewdbentry{mydata}{FirstName}{Jane}% %\DTLnewdbentry{mydata}{Surname}{Brown}% %\DTLnewdbentry{mydata}{Score}{75}% %\DTLnewrow{mydata}% %\DTLnewdbentry{mydata}{FirstName}{Andy}% %\DTLnewdbentry{mydata}{Surname}{Brown}% %\DTLnewdbentry{mydata}{Score}{42}% %\DTLnewrow{mydata}% %\DTLnewdbentry{mydata}{FirstName}{Z\"oe}% %\DTLnewdbentry{mydata}{Score}{52}% %\DTLnewdbentry{mydata}{Surname}{Adams}% %\end{verbatim} %Note that the entry \texttt{Smith, Jr} had to be delimited in %\texttt{mydata.csv} using the double quote character since it %contained a comma which is used as the separator. % %The file used in the above example contained a \LaTeX\ command, %namely \verb|\"|. When using \ics{DTLloaddb} all the special %characters that appear in the command retain their \LaTeX\ meaning %when the file is loaded. It is likely however that the data file %may have been created by another application that is not \TeX-aware, %such as a spreadsheet application. For example, suppose you %have a file called, say, \texttt{products.csv} which looks %like: %\begin{verbatim} %Product,Cost %Fruit & Veg,$1.25 %Stationary,$0.80 %\end{verbatim} %This file contains two of \TeX's special characters, namely %"&" and \verb|$|. In this case, if you try to load the file %using \ics{DTLloaddb}, you will encounter errors. Instead you %can use: %\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 %symbol. The only character that retains its active state is the %backslash character, so you will still need to check the file %for backslash characters. The mappings used are listed in %\autoref{tab:rawmappings}. So using the file \texttt{products.csv}, %as described above, %\begin{verbatim} %\DTLloadrawdb{mydata}{products.csv} %\end{verbatim} %is equivalent to: %\begin{verbatim} %\DTLnewdb{mydata} %\DTLnewrow{mydata}% %\DTLnewdbentry{mydata}{Product}{Fruit \& Veg}% %\DTLnewdbentry{mydata}{Cost}{\$1.25}% %\DTLnewrow{mydata}% %\DTLnewdbentry{mydata}{Product}{Stationary}% %\DTLnewdbentry{mydata}{Cost}{\$0.80}% %\end{verbatim} % %\begin{table}[htbp] %\caption[Special character mappings used by %\cs{DTLloadrawdb}]{Special character mappings used by %\cs{DTLloadrawdb} (note that the backslash retains its active state)} %\label{tab:rawmappings} %\centering %\begin{tabular}{cl} %Character & Mapping\\ %\verb|%| & \verb|\%|\\ %\verb|$| & \verb|\$|\\ %\verb|&| & \verb|\&|\\ %\verb|#| & \verb|\#|\\ %\verb|_| & \verb|\_|\\ %\verb|{| & \verb|\{|\\ %\verb|}| & \verb|\}|\\ %\verb|~| & \cs{textasciitilde}\\ %\verb|^| & \cs{textasciicircum} %\end{tabular} %\end{table} % %It may be that there are other characters that require mapping. %For example, the file \texttt{products.csv} may instead look like:\par %\vskip\baselineskip %\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} %Product,Cost %Fruit \& Veg,\pounds1.25 %Stationary,\pounds0.80 %\end{ttfamily} %\vskip\baselineskip %The pound character is not an internationally standard keyboard %character, and does not generally achieve the desired effect when used %in a \LaTeX\ document. It may therefore be necessary to convert %this symbol to an appropriate control sequence. This can be done %using the command: %\begin{definition}[\DescribeMacro{\DTLrawmap}]% %\cs{DTLrawmap}\marg{string}\marg{replacement} %\end{definition} %For example:\par %\vskip\baselineskip %\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} %\cs{DTLrawmap}\char`\{\pounds\char`\}\char`\{\cs{pounds}\char`\} %\end{ttfamily} %\vskip\baselineskip\noindent %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}. % %\importantpar Note that the warning in the previous section about no %paragraph breaks in an entry also applies to entries loaded from a %database. If you do need a paragraph break, use \ics{DTLpar} instead %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 the %\sty{longtable} package, 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} %\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} %\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} %\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} %\centering %\DTLdisplaydb{balance} %\end{table} %\end{example} % %\subsection{Iterating Through a Database} %\label{sec:dbforeach} % %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 then iterate %through each row of the database and access elements in that row. % %\begin{definition}[\DescribeMacro{\DTLforeach}]% %\cs{DTLforeach}\oarg{condition}\marg{db name}\marg{assign list}\marg{text} %\end{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 %\meta{db name}, applying \meta{text} to each row of the database %where \meta{condition} is met. The argument \meta{assign list} is a %comma separated list of \meta{cmd}"="\meta{key} pairs. At the %start of each row, each command \meta{cmd} in \meta{assign list} %will be set to the value of the entry given by \meta{key}. %These commands may then be used in \meta{text}. % %\importantpar Note that this assignment is done globally to ensure %that \cs{DLTforeach} works correctly in a \env{tabular} environment. %Since you may want to use the same set of commands in a later %\cs{DTLforeach}, the commands are not checked to determine if they %already exist. It is therefore important that you check you are not %using an existing command whose value should not be changed. % %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 (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 faster. % %\begin{example}{Student scores}{ex:scores} %Suppose you have a data file called \texttt{studentscores.csv} that %contains the following: %\begin{verbatim} %FirstName,Surname,StudentNo,Score %John,"Smith, Jr",102689,68 %Jane,Brown,102647,75 %Andy,Brown,103569,42 %Z\"oe,Adams,105987,52 %Roger,Brady,106872,58 %Clare,Verdon,104356,45 %\end{verbatim} %\DTLnewdb{scores}\relax %\DTLnewrow{scores}\relax %\DTLnewdbentry{scores}{FirstName}{John}\relax %\DTLnewdbentry{scores}{Surname}{Smith, Jr}\relax %\DTLnewdbentry{scores}{StudentNo}{102689}\relax %\DTLnewdbentry{scores}{Score}{68}\relax %\DTLnewrow{scores}\relax %\DTLnewdbentry{scores}{FirstName}{Jane}\relax %\DTLnewdbentry{scores}{Surname}{Brown}\relax %\DTLnewdbentry{scores}{StudentNo}{102647}\relax %\DTLnewdbentry{scores}{Score}{75}\relax %\DTLnewrow{scores}\relax %\DTLnewdbentry{scores}{FirstName}{Andy}\relax %\DTLnewdbentry{scores}{Surname}{Brown}\relax %\DTLnewdbentry{scores}{StudentNo}{103569}\relax %\DTLnewdbentry{scores}{Score}{42}\relax %\DTLnewrow{scores}\relax %\DTLnewdbentry{scores}{FirstName}{Z\"oe}\relax %\DTLnewdbentry{scores}{Score}{52}\relax %\DTLnewdbentry{scores}{StudentNo}{105987}\relax %\DTLnewdbentry{scores}{Surname}{Adams}\relax %\DTLnewrow{scores}\relax %\DTLnewdbentry{scores}{FirstName}{Roger}\relax %\DTLnewdbentry{scores}{Score}{58}\relax %\DTLnewdbentry{scores}{StudentNo}{106872}\relax %\DTLnewdbentry{scores}{Surname}{Brady}\relax %\DTLnewrow{scores}\relax %\DTLnewdbentry{scores}{FirstName}{Clare}\relax %\DTLnewdbentry{scores}{Score}{45}\relax %\DTLnewdbentry{scores}{StudentNo}{104356}\relax %\DTLnewdbentry{scores}{Surname}{Verdon}\relax %and you load the data into a database called "scores" using: %\begin{verbatim} %\DTLloaddb{scores}{studentscores.csv} %\end{verbatim} %you can then display the database in a table as follows: %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores} %\centering %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\firstname & \surname & \score} %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:scores}. (Note that since I didn't %need the student registration number, I didn't bother to %assign a command to the key "StudentNo".) % %\begin{table}[htbp] %\caption[Student scores (displaying a database in a %table)]{Student scores}\label{tab:scores} %\centering %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax %\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\firstname & \surname & \score} %\end{tabular} %\end{table} %\end{example} % %The macro \ics{DTLforeach} may be nested up to three times. Each %level uses the corresponding counters: %\desctr{DTLrowi}, %\desctr{DTLrowii} and %\desctr{DTLrowiii} which keep track of %the current row. % %\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 %\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. % %\begin{definition}[\DescribeMacro{\DTLcurrentindex}]% %\cs{DTLcurrentindex} %\end{definition} %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. % %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} %If the current row is the first row, then do \meta{true part}, %otherwise do \meta{false part}. % %\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{\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 %both the surname and the first name, or I can use the student's %registration number, or I can use the student's score, since all %the scores are unique. The former method will cause a problem since %one of the names (Z\"oe) contains an accent command. Although %the registration numbers are all unique, they are not particularly %memorable, so I shall instead use the scores. %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores} %\centering %\begin{tabular}{cllc} %\bfseries Row & %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach*{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\label{row:\score}\\\theDTLrowi & %\firstname & \surname & \score}% %\end{tabular} %\end{table} % %Jane Brown scored the highest (75\%), her score can be seen on %row~\ref{row:75}. %\end{verbatim} %This produces \autoref{tab:scoreslab} and the following text: %Jane Brown scored the highest (75\%), her score can be seen on %row~\ref*{row:75}. % %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} %\centering %\begin{tabular}{cllc} %\bfseries Row & %\bfseries First Name & %\bfseries Surname & %\bfseries 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} % %\begin{example}{Filtering Rows}{ex:filter} %As mentioned earlier, the optional argument \meta{condition} of %\ics{DTLforeach} provides a means to exclude certain rows. %This example uses the database defined in \autoref{ex:scores}, %but only displays the information for students whose marks are %above 60. At the end of the table, \cs{DTLsavelastrowcount} %is used to store the number of rows in the table. (Note that %\cs{DTLsavelastrowcount} is outside of \ics{DTLforeach}.) %\begin{verbatim} %\begin{table}[htbp] %\caption{Top student scores} %\centering %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach*[\DTLisgt{\score}{60}]{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\firstname & \surname & \score} %\end{tabular} % %\DTLsavelastrowcount{\n}% %\n\ students scored above 60\%. %\end{table} %\end{verbatim} %This produces \autoref{tab:topscores}. Note that in this example, %I could have specified the condition as "\score>60" since all %the scores are integers, however, as it's possible that an entry %may feasibly have a decimal score I have used \ics{DTLisgt} instead. % %\begin{table}[htbp] %\caption[Top student scores (filtering rows using %\cs{DTLisgt})]{Top student scores}\label{tab:topscores} %\centering %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax %\DTLforeach*[\DTLisgt{\score}{60}]{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\firstname & \surname & \score} %\end{tabular} % %\DTLsavelastrowcount{\n}\relax %\n\ students scored above 60\%. %\end{table} % %Suppose now, I only want to display the scores for students whose %surname begins with `B'. I can do this as follows: %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores (B)} %\centering %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach*[\DTLisopenbetween{\surname}{B}{C}]{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\firstname & \surname & \score} %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:Bscores}. % %\begin{table}[htbp] %\caption[Student scores (B) --- filtering rows using %\cs{DTLisopenbetween}]{Student scores (B)}\label{tab:Bscores} %\centering %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax %\DTLforeach*[\DTLisopenbetween{\surname}{B}{C}]{scores} %{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\firstname & \surname & \score} %\end{tabular} %\end{table} % %\end{example} % %\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 \ctr{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 %\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 %\ctr{DTLrowi} instead: %\begin{verbatim} %\DTLforeach{scores}% %{\firstname=FirstName,\surname=Surname,\score=Score}{% %\\\firstname & \surname & \score %\ifthenelse{\value{DTLrowi}=3}{\dtlbreak}{}% %}% %\end{verbatim} % %\begin{table}[htbp] %\caption{First Three Rows} %\label{tab:dtlbreak}% %\centering %\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. %It requires the \sty{colortbl} package, which provides the %command \cs{rowcolor}. The command \cs{DTLifoddrow} is used %to produce a striped table. %\begin{verbatim} %\begin{table}[htbp] %\caption{A stripy table}\label{tab:stripy} %\centering %\begin{tabular}{llc} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach*{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\\DTLifoddrow{\rowcolor{blue}}{\rowcolor{green}}% %\firstname & \surname & \score}% %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:stripy}. % %\begin{table}[htbp] %\caption[A stripy table (illustrating the use of %\cs{DTLifoddrow})]{A stripy table}\label{tab:stripy} %\centering %\begin{tabular}{llc} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax %\DTLforeach*{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\\DTLifoddrow{\rowcolor{blue}}{\rowcolor{green}}\relax %\firstname & \surname & \score}\relax %\end{tabular} %\end{table} %\end{example} % %\begin{example}{Two Database Rows per Tabular Row}{ex:2rows} %In order to save space, you may want two database rows per %tabular row, when displaying a database in a \env{tabular} %environment. This can be accomplished using \ics{DTLifoddrow}. %For example %\begin{verbatim} %\begin{table}[htbp] %\caption{Two database rows per tabular row} %\centering %\begin{tabular}{llcllc} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%) & %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach*{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{% %\DTLifoddrow{\\}{&}% %\firstname & \surname & \score}% %\end{tabular} %\end{table} %\end{verbatim} %produces \autoref{tab:2rows} % %\begin{table}[htbp] %\caption[Two database rows per tabular row (illustrating the %use of\newline \cs{DTLifoddrow})]{Two database rows per tabular %row}\label{tab:2rows} %\centering %\begin{tabular}{llcllc} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%) & %\bfseries First Name & %\bfseries Surname & %\bfseries 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)} %\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} %\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} % \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} %\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)} %\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} %\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: %\begin{verbatim} %File,Temperature,NaCl,pH %exp25a.csv,25,4.7,0.5 %exp25b.csv,25,4.8,1.5 %exp30a.csv,30,5.12,4.5 %\end{verbatim} %\DTLnewdb{index}\relax %\DTLnewrow{index}\relax %\DTLnewdbentry{index}{File}{exp25a.csv}\relax %\DTLnewdbentry{index}{Temperature}{25}\relax %\DTLnewdbentry{index}{NaCl}{4.7}\relax %\DTLnewdbentry{index}{pH}{0.5}\relax %\DTLnewrow{index}\relax %\DTLnewdbentry{index}{File}{exp25b.csv}\relax %\DTLnewdbentry{index}{Temperature}{25}\relax %\DTLnewdbentry{index}{NaCl}{4.8}\relax %\DTLnewdbentry{index}{pH}{1.5}\relax %\DTLnewrow{index}\relax %\DTLnewdbentry{index}{File}{exp30a.csv}\relax %\DTLnewdbentry{index}{Temperature}{30}\relax %\DTLnewdbentry{index}{NaCl}{5.12}\relax %\DTLnewdbentry{index}{pH}{4.5}\relax %The first column of this file contains the name of another %CSV file which has the results of a time to growth experiment %performed at the given incubation temperature, salt concentration %and pH. The file "exp25a.csv" contains the following: %\begin{verbatim} %Time,Log Count %0,3.75 %23,3.9 %45,4.0 %\end{verbatim} %\DTLnewdb{exp25a.csv}\relax %\DTLnewrow{exp25a.csv}\relax %\DTLnewdbentry{exp25a.csv}{Time}{0}\relax %\DTLnewdbentry{exp25a.csv}{Log Count}{3.75}\relax %\DTLnewrow{exp25a.csv}\relax %\DTLnewdbentry{exp25a.csv}{Time}{23}\relax %\DTLnewdbentry{exp25a.csv}{Log Count}{3.9}\relax %\DTLnewrow{exp25a.csv}\relax %\DTLnewdbentry{exp25a.csv}{Time}{45}\relax %\DTLnewdbentry{exp25a.csv}{Log Count}{4.0}\relax %The file "exp25b.csv" contains the following: %\begin{verbatim} %Time,Log Count %0,3.6 %60,3.8 %120,4.0 %\end{verbatim} %\DTLnewdb{exp25b.csv}\relax %\DTLnewrow{exp25b.csv}\relax %\DTLnewdbentry{exp25b.csv}{Time}{0}\relax %\DTLnewdbentry{exp25b.csv}{Log Count}{3.6}\relax %\DTLnewrow{exp25b.csv}\relax %\DTLnewdbentry{exp25b.csv}{Time}{60}\relax %\DTLnewdbentry{exp25b.csv}{Log Count}{3.8}\relax %\DTLnewrow{exp25b.csv}\relax %\DTLnewdbentry{exp25b.csv}{Time}{120}\relax %\DTLnewdbentry{exp25b.csv}{Log Count}{4.0}\relax %The file "exp30a.csv" contains the following: %\begin{verbatim} %Time,Log Count %0,3.73 %23,3.67 %60,4.9 %\end{verbatim} %\DTLnewdb{exp30a.csv}\relax %\DTLnewrow{exp30a.csv}\relax %\DTLnewdbentry{exp30a.csv}{Time}{0}\relax %\DTLnewdbentry{exp30a.csv}{Log Count}{3.73}\relax %\DTLnewrow{exp30a.csv}\relax %\DTLnewdbentry{exp30a.csv}{Time}{23}\relax %\DTLnewdbentry{exp30a.csv}{Log Count}{3.67}\relax %\DTLnewrow{exp30a.csv}\relax %\DTLnewdbentry{exp30a.csv}{Time}{60}\relax %\DTLnewdbentry{exp30a.csv}{Log Count}{4.9}\relax %Suppose I now want to iterate through "index.csv", load the given %file, and create a table for that data. I can do this using %nested \ics{DTLforeach} as follows: %\begin{verbatim} % % load index data file %\DTLloaddb{index}{index.csv} % % % iterate through index database %\DTLforeach{index}{\theFile=File,\theTemp=Temperature,% %\theNaCl=NaCl,\thepH=pH}{% % % load results file into database of the same name %\DTLloaddb{\theFile}{\theFile}% % % Create a table %\begin{table}[htbp] %\caption{Temperature = \theTemp, NaCl = \theNaCl, %pH = \thepH}\label{tab:\theFile} %\centering %\begin{tabular}{rl} %\bfseries Time & \bfseries Log Count %\DTLforeach{\theFile}{\theTime=Time,\theLogCount=Log Count}{% %\\\theTime & \theLogCount}% %\end{tabular} %\end{table} %} %\end{verbatim} %This creates \autoref{tab:exp25a.csv} to \autoref{tab:exp30a.csv}. %(Note that each table is given a label that is based on the %database name, to ensure that it is unique.) % %\DTLforeach{index}{\theFile=File,\theTemp=Temperature,\theNaCl %=NaCl,\thepH=pH}{ %\begin{table}[htbp] %\caption[Temperature = \theTemp, NaCl = \theNaCl, %pH = \thepH\space (illustrating nested %\cs{DTLforeach})]{Temperature = \theTemp, NaCl = \theNaCl, %pH = \thepH}\label{tab:\theFile} %\centering %\begin{tabular}{rl} %\bfseries Time & \bfseries Log Count %\DTLforeach{\theFile}{\theTime=Time,\theLogCount=Log Count}{ %\\\theTime & \theLogCount}% %\end{tabular} %\end{table} %} %\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} %\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} %\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}), %if an entry is missing for a given row, the associated command given %in the \meta{values} argument will be set to a null value. This %value depends on the data type associated with the given key. % %\begin{definition}[\DescribeMacro{\DTLstringnull}]% %\cs{DTLstringnull} %\end{definition} %This is the null value for a string. % %\begin{definition}[\DescribeMacro{\DTLnumbernull}]% %\cs{DTLnumbernull} %\end{definition} %This is the null value for a number. % %\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, %if it is, then \meta{true part} %is done, otherwise \meta{false part} is done. This macro is %illustrated in \autoref{ex:null} below. % %\begin{example}{Null Values}{ex:null} %Consider the following (which creates a database called "emailDB"): %\begin{verbatim} %\DTLnewdb{emailDB} %\DTLnewrow{emailDB} %\DTLnewdbentry{emailDB}{Surname}{Jones} %\DTLnewdbentry{emailDB}{FirstName}{Mary} %\DTLnewdbentry{emailDB}{Email1}{mj@my.uni.ac.uk} %\DTLnewdbentry{emailDB}{Email2}{mj@somewhere.com} %\DTLnewrow{emailDB} %\DTLnewdbentry{emailDB}{Surname}{Smith} %\DTLnewdbentry{emailDB}{FirstName}{Adam} %\DTLnewdbentry{emailDB}{Email1}{as@my.uni.ac.uk} %\DTLnewdbentry{emailDB}{RegNum}{12345} %\end{verbatim} %\DTLnewdb{emailDB}\relax %\DTLnewrow{emailDB}\relax %\DTLnewdbentry{emailDB}{Surname}{Jones}\relax %\DTLnewdbentry{emailDB}{FirstName}{Mary}\relax %\DTLnewdbentry{emailDB}{Email1}{mj@my.uni.ac.uk}\relax %\DTLnewdbentry{emailDB}{Email2}{mj@somewhere.com}\relax %\DTLnewrow{emailDB}\relax %\DTLnewdbentry{emailDB}{Surname}{Smith}\relax %\DTLnewdbentry{emailDB}{FirstName}{Adam}\relax %\DTLnewdbentry{emailDB}{Email1}{as@my.uni.ac.uk}\relax %\DTLnewdbentry{emailDB}{RegNum}{12345}\relax %In the above example, the first row of the database contains %an entry with the key "Email2", but the second row doesn't. %Whereas the second row contains an entry with the key "RegNum", %but the first row doesn't. % %The following code puts the information in a \env{tabular} %environment: %\begin{verbatim} %\begin{tabular}{lllll} %\bfseries First Name & %\bfseries Surname & %\bfseries Email 1 & %\bfseries Email 2 & %\bfseries Reg Num% %\DTLforeach{emailDB}{\firstname=FirstName,\surname=Surname,% %\emailI=Email1,\emailII=Email2,\regnum=RegNum}{% %\\\firstname & \surname & \emailI & \emailII & \regnum}% %\end{tabular} %\end{verbatim} %This produces the following:\par\vskip\baselineskip\noindent %\begin{tabular}{lllll} %\bfseries First Name & %\bfseries Surname & %\bfseries Email 1 & %\bfseries Email 2 & %\bfseries Reg Num\relax %\DTLforeach{emailDB}{\firstname=FirstName,\surname %=Surname,\emailI=Email1,\emailII=Email2,\regnum=RegNum}{\relax %\\\firstname & \surname & \emailI & \emailII & \regnum}\relax %\end{tabular} %\par\vskip\baselineskip %Note that on the first row of data, the registration number appears as %0, while on the next row, the second email address appears as %NULL. The \sty{datatool} package has identified the key "RegNum" %for this database as a numerical key, since all elements in the %database with that key are numerical, whereas it has %identified the key "Email2" as a string, since there is at least %one element in this database with that key that is a string. Null %numerical values are set to \cs{DTLnumbernull} (\DTLnumbernull), and %null strings are set to \cs{DTLstringnull} (\DTLstringnull). % %The following code checks each value to determine whether it %is null using \cs{DTLifnull}. If it is, the text \emph{Missing} %is inserted, otherwise the value itself is used: %\begin{verbatim} %\begin{tabular}{lllll} %\bfseries First Name & %\bfseries Surname & %\bfseries Email 1 & %\bfseries Email 2 & %\bfseries Reg Num% %\DTLforeach{emailDB}{\firstname=FirstName,\surname=Surname,% %\emailI=Email1,\emailII=Email2,\regnum=RegNum}{% %\\\DTLifnull{\firstname}{\emph{Missing}}{\firstname} & %\DTLifnull{\surname}{\emph{Missing}}{\surname} & %\DTLifnull{\emailI}{\emph{Missing}}{\emailI} & %\DTLifnull{\emailII}{\emph{Missing}}{\emailII} & %\DTLifnull{\regnum}{\emph{Missing}}{\regnum}}% %\end{tabular} %\end{verbatim} %This produces the following:\par\vskip\baselineskip\noindent %\begin{tabular}{lllll} %\bfseries First Name & %\bfseries Surname & %\bfseries Email 1 & %\bfseries Email 2 & %\bfseries Reg Num\relax %\DTLforeach{emailDB}{\firstname=FirstName,\surname %=Surname,\emailI=Email1,\emailII=Email2,\regnum=RegNum}{\relax %\\\DTLifnull{\firstname}{\emph{Missing}}{\firstname} & %\DTLifnull{\surname}{\emph{Missing}}{\surname} & %\DTLifnull{\emailI}{\emph{Missing}}{\emailI} & %\DTLifnull{\emailII}{\emph{Missing}}{\emailII} & %\DTLifnull{\regnum}{\emph{Missing}}{\regnum}}\relax %\end{tabular} %\par\vskip\baselineskip\noindent %If you want to do this, you may find it easier to define a %convenience command that will display some appropriate text %if an entry is missing, for example: %\begin{verbatim} %\newcommand*{\checkmissing}[1]{\DTLifnull{#1}{---}{#1}} %\end{verbatim} %Then instead of typing, say, %\begin{verbatim} %\DTLifnull{\regnum}{---}{\regnum} %\end{verbatim} %you can instead type: %\begin{verbatim} %\checkmissing{\regnum} %\end{verbatim} % %Now suppose that instead of defining the database using \cs{DTLnewdb}, %\cs{DTLnewrow} and \cs{DTLnewdbentry}, you have a file with the %contents: %\begin{ttfamily}\setlength{\parindent}{0pt}\par\vskip\baselineskip %Surname,FirstName,RegNum,Email1,Email2 % %\DTLforeach{emailDB}{\surname=Surname,\firstname=FirstName,\regNo %=RegNum,\emailI=Email1,\emailII %=Email2}{\relax %\surname,\firstname,\DTLifnull{\regNo}{}{\regNo},\emailI,\DTLifnull{\emailII}{}{\emailII}\par %} %\end{ttfamily}\par\vskip\baselineskip\noindent %and you load the data from this file using \cs{DTLloaddb} %(defined in \autoref{sec:loaddb}). Now the %database has no null values, but has an empty value for the %key "RegNum" on the first row of the database, and an empty %value for the key "Email2" on the second row of the database. %Now, the following code %\begin{verbatim} %\begin{tabular}{lllll} %\bfseries First Name & %\bfseries Surname & %\bfseries Email 1 & %\bfseries Email 2 & %\bfseries Reg Number% %\DTLforeach{emailDB}{\firstname=FirstName,\surname=Surname,% %\emailI=Email1,\emailII=Email2,\regnum=RegNum}{% %\\\DTLifnull{\firstname}{\emph{Missing}}{\firstname} & %\DTLifnull{\surname}{\emph{Missing}}{\surname} & %\DTLifnull{\emailI}{\emph{Missing}}{\emailI} & %\DTLifnull{\emailII}{\emph{Missing}}{\emailII} & %\DTLifnull{\regnum}{\emph{Missing}}{\regnum}}% %\end{tabular} %\end{verbatim} %produces:\par\vskip\baselineskip\noindent %\begin{tabular}{lllll} %\bfseries First Name & %\bfseries Surname & %\bfseries Email 1 & %\bfseries Email 2 & %\bfseries Reg Number\relax %\DTLforeach{emailDB}{\firstname=FirstName,\surname %=Surname,\emailI=Email1,\emailII=Email2,\regnum=RegNum}{\relax %\\\firstname & \surname & \emailI & \DTLifnull{\emailII}{}{\emailII} & \DTLifnull{\regnum}{}{\regnum}}\relax %\end{tabular} %\end{example} % %\subsection{Editing Database Rows} %\label{sec:editdb} % %A row can be removed from a data base using: %\begin{definition}[\DescribeMacro{\DTLremoverow}]% %\cs{DTLremoverow}\marg{db name}\marg{row index} %\end{definition} %where \meta{row index} is the index of the unwanted row. For %example: %\begin{verbatim} %\DTLremoverow{scores}{2} %\end{verbatim} %will delete the second row in the database labelled ``scores''. %There is also a starred version that doesn't check for the %existence of the database. % %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. %(\meta{value} is expanded.) % %\begin{definition}[\DescribeMacro{\DTLreplaceentryforrow}]% %\cs{DTLreplaceentryforrow}\marg{key}\marg{value} %\end{definition} %This replaces the entry for \meta{key} with \meta{value}. %(\meta{value} is expanded.) % %\begin{definition}[\DescribeMacro{\DTLremoveentryfromrow}]% %\cs{DTLremoveentryfromrow}\marg{key} %\end{definition} %This removes the entry for \meta{key} from the current row. % %\begin{definition}[\DescribeMacro{\DTLremovecurrentrow}]% %\cs{DTLremovecurrentrow} %\end{definition} %This removes the current row from the database. % %\begin{example}{Editing Database Rows}{ex:editdb} %In this example I have a CSV file called "marks.csv" that contains %student marks for three assignments: %\DTLnewdb{marks}\relax %\DTLnewrow{marks}\relax %\DTLnewdbentry{marks}{FirstName}{John}\relax %\DTLnewdbentry{marks}{Surname}{Smith, Jr}\relax %\DTLnewdbentry{marks}{StudentNo}{102689}\relax %\DTLnewdbentry{marks}{Assignment 1}{68}\relax %\DTLnewdbentry{marks}{Assignment 2}{57}\relax %\DTLnewdbentry{marks}{Assignment 3}{72}\relax %\DTLnewrow{marks}\relax %\DTLnewdbentry{marks}{FirstName}{Jane}\relax %\DTLnewdbentry{marks}{Surname}{Brown}\relax %\DTLnewdbentry{marks}{StudentNo}{102647}\relax %\DTLnewdbentry{marks}{Assignment 1}{75}\relax %\DTLnewdbentry{marks}{Assignment 2}{84}\relax %\DTLnewdbentry{marks}{Assignment 3}{80}\relax %\DTLnewrow{marks}\relax %\DTLnewdbentry{marks}{FirstName}{Andy}\relax %\DTLnewdbentry{marks}{Surname}{Brown}\relax %\DTLnewdbentry{marks}{StudentNo}{103569}\relax %\DTLnewdbentry{marks}{Assignment 1}{42}\relax %\DTLnewdbentry{marks}{Assignment 2}{52}\relax %\DTLnewdbentry{marks}{Assignment 3}{54}\relax %\DTLnewrow{marks}\relax %\DTLnewdbentry{marks}{FirstName}{Z\"oe}\relax %\DTLnewdbentry{marks}{Surname}{Adams}\relax %\DTLnewdbentry{marks}{StudentNo}{105987}\relax %\DTLnewdbentry{marks}{Assignment 1}{52}\relax %\DTLnewdbentry{marks}{Assignment 2}{48}\relax %\DTLnewdbentry{marks}{Assignment 3}{57}\relax %\DTLnewrow{marks}\relax %\DTLnewdbentry{marks}{FirstName}{Roger}\relax %\DTLnewdbentry{marks}{Surname}{Brady}\relax %\DTLnewdbentry{marks}{StudentNo}{106872}\relax %\DTLnewdbentry{marks}{Assignment 1}{58}\relax %\DTLnewdbentry{marks}{Assignment 2}{60}\relax %\DTLnewdbentry{marks}{Assignment 3}{62}\relax %\DTLnewrow{marks}\relax %\DTLnewdbentry{marks}{FirstName}{Clare}\relax %\DTLnewdbentry{marks}{Surname}{Verdon}\relax %\DTLnewdbentry{marks}{StudentNo}{104356}\relax %\DTLnewdbentry{marks}{Assignment 1}{45}\relax %\DTLnewdbentry{marks}{Assignment 2}{50}\relax %\DTLnewdbentry{marks}{Assignment 3}{48}\relax %\begin{ttfamily}\setlength{\parindent}{0pt}\par %Surname,FirstName,StudentNo,Assignment 1,Assignment 2,Assignment 3 % %\DTLforeach{marks}{\surname=Surname,\firstname=FirstName,\regNo %=StudentNo,\assignI=Assignment 1,\assignII %=Assignment 2,\assignIII=Assignment 3}{\relax %\char`\"\surname\char`\",\DTLifstringeq{\firstname}{Zoe}{Z\string\"oe}{\firstname},\regNo,\assignI,\assignII,\assignIII\par %} %\end{ttfamily}\par\noindent %First load this into a database called "marks": %\begin{verbatim} %\DTLloaddb{marks}{marks.csv} %\end{verbatim} %Suppose now I want to compute the average mark for each %student, and append this to the database. I can do this as %follows: %\begin{verbatim} %\DTLforeach{marks}{% %\assignI=Assignment 1,% %\assignII=Assignment 2,% %\assignIII=Assignment 3}{% %\DTLmeanforall{\theMean}{\assignI,\assignII,\assignIII}% %\DTLappendtorow{Average}{\theMean}} %\end{verbatim} %\DTLforeach{marks}{\assignI=Assignment 1,\assignII %=Assignment 2,\assignIII=Assignment 3}{\relax %\DTLmeanforall{\theMean}{\assignI,\assignII,\assignIII}% %\DTLappendtorow{Average}{\theMean}}\relax %For each row in the "marks" database, I now have an extra key %called "Average" that contains the average mark over all three %assignments for a given student. I can now put this data into %a table: %\begin{verbatim} %\begin{table}[htbp] %\caption{Student marks} %\centering %\begin{tabular}{llcccc} %\bfseries Surname & \bfseries First Name & %\bfseries Assign 1 & %\bfseries Assign 2 & %\bfseries Assign 3 & %\bfseries Average Mark% %\DTLforeach{marks}{\surname=Surname,\firstname=FirstName,\average %=Average,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII %=Assignment 3}{\\\surname %& \firstname & \assignI & \assignII & \assignIII & %\DTLround{\average}{\average}{2}\average}\relax %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:meanmarks}. % %Note that if I only wanted the averages for the table and nothing %else, I could simply have computed the average in each row of the %table and displayed it without adding the information to the %database, however I am going to reuse this information in %\autoref{ex:multibar}, so adding it to the database means that %I don't need to recompute the mean. % %\begin{table}[htbp] %\caption[Student marks (with averages)]{Student %marks}\label{tab:meanmarks} %\centering %\begin{tabular}{llcccc} %\bfseries Surname & \bfseries First Name & %\bfseries Assign 1 & %\bfseries Assign 2 & %\bfseries Assign 3 & %\bfseries Average Mark\relax %\DTLforeach{marks}{\surname=Surname,\firstname=FirstName,\average %=Average,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII %=Assignment 3}{\\\surname %& \firstname & \assignI & \assignII & \assignIII & %\DTLround{\average}{\average}{2}\average}\relax %\end{tabular} %\end{table} % %\end{example} % %\subsection{Arithmetical Computations on Database Entries} % %The commands used in \autoref{sec:fp} can be used on database %entries. You can, of course, directly use the commands provided %by the \sty{fp} package if you know that the values are in the %correct format (i.e.\ no currency symbols, no number group %separators and a full stop as the decimal point) but if this is %not the case, then you should use the commands described in %\autoref{sec:fp}. If you want to use a command provided by the %\sty{fp} package, that does not have a wrapper function in %\sty{datatool}, then you will need to convert the value using %\ics{DTLconverttodecimal}, and convert it back using either %\ics{DTLdecimaltolocale} or \ics{DTLdecimaltocurrency}. % %\begin{example}{Arithmetical Computations}{ex:mean} %In this example, I am going to produce a table similar to %\autoref{tab:scores}, except that I want to add an extra row at the %end which contains the average score. %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores}\label{tab:mean} %\centering %\def\total{0}% %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\firstname & \surname & %\DTLgadd{\total}{\score}{\total}% %\score %}\\ %\multicolumn{2}{l}{\bfseries Average Score} & %\DTLsavelastrowcount{\n}% %\DTLdiv{\average}{\total}{\n}% %\DTLround{\average}{\average}{2}% %\average %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:mean}. %\textbf{Notes:} %\begin{itemize} %\item I had to use \ics{DTLgadd} rather than \ics{DTLadd} since it %occurs within a \env{tabular} environment which puts each entry %in a local scope. % %\item I used \ics{DTLsavelastrowcount} to store the number of %rows produced by \ics{DTLforeach} in the control sequence \cs{n}. % %\item I used \ics{DTLround} to round the average score to 2 decimal %places. %\end{itemize} % %\begin{table}[htbp] %\caption[Student scores (using arithmetic computations)]{Student %scores}\label{tab:mean} %\centering %\def\total{0}\relax %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax %\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\firstname & \surname & %\DTLgadd{\total}{\score}{\total}\relax %\score %}\\ %\multicolumn{2}{l}{\bfseries Average Score} & %\DTLsavelastrowcount{\n}\relax %\DTLdiv{\average}{\total}{\n}\relax %\DTLround{\average}{\average}{2}\relax %\average %\end{tabular} %\end{table} %\end{example} % %\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 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". % %\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 %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} %\end{verbatim} %sets \cs{average} to the mean of all the scores in the database %called "scores". % %\begin{definition}[\DescribeMacro{\DTLmeanforcolumn}]% %\cs{DTLmeanforcolumn}\marg{db}\marg{key}\marg{cmd} %\end{definition} %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. % %\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 %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{\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} 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. % %\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} 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. % %\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 %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}. % %\begin{example}{Mail Merging}{ex:mailmerging} %This example uses the database given in \autoref{ex:scores} and %uses \ics{DTLmeanforkeys} to determine the average score. A letter %is then created for each student to inform them of their score %and the class average. % %\begin{verbatim} %\documentclass{letter} % %\usepackage{datatool} % %\begin{document} % % load database %\DTLloaddb{scores}{studentscores.csv} % % compute arithmetic mean for key `Score' %\DTLmeanforkeys{scores}{Score}{\average} % % Round the average to 2 decimal places %\DTLround{\average}{\average}{2} % % Save the highest score in \maxscore %\DTLmaxforkeys{scores}{Score}{\maxscore} % %\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,% %\score=Score}{% %\begin{letter}{} %\opening{Dear \firstname\ \surname} % %\DTLifnumgt{\score}{60}{Congratulations you}{You} achieved a score %of \score\% which was \DTLifnumgt{\score}{\average}{above}{below} %the average of \average\%. \DTLifnumeq{\score}{\maxscore}{You %achieved the highest score}{The top score was \maxscore}. % %\closing{Yours Sincerely} %\end{letter} %} %\end{document} %\end{verbatim} % %To determine a person's gender when mail merging, see %\autoref{sec:person}. %\end{example} % %\subsection{Sorting a Database} %\label{sec:sort} % %\begin{definition}[\DescribeMacro{\DTLsort}]% %\cs{DTLsort}\oarg{replacement key list}\marg{sort criteria}\marg{db name} %\end{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 %the criteria given by \meta{sort criteria}, which must be a %comma separated list of keys and optionally "="\meta{order}, where %\meta{order} is either "ascending" or "descending". If the order %is omitted, "ascending" is assumed. The database keeps track of %the data type for a given key, and uses this to determine whether %an alphabetical or numerical sort is required. (String comparisons %are made using the command \cs{dtlcompare} or \cs{dtlicompare} %described in \autoref{src:dtlcompare}.) % %The optional argument \meta{replacement key list} is a list of %keys to use if the current key given in \meta{sort criteria} %is null for a given entry. Null keys are unlikely to occur if %you have loaded the database from an external ASCII file, but %may occur if the database is created using \cs{DTLnewdb}, %\cs{DTLnewrow} and \cs{DTLnewdbentry}. For example: %\begin{verbatim} %\DTLsort[Editor,Organization]{Author}{mydata} %\end{verbatim} %will sort according to the "Author" key, but if that key is missing %for a given row of the database, the "Editor" key will be used, %and if the "Editor" key is missing, it will use the "Organization" %key. Note that this is not the same as: %\begin{verbatim} %\DTLsort{Author,Editor,Organization}{mydata} %\end{verbatim} %which will first compare the "Author" keys, but if the author names %are the same, it will then compare the "Editor" keys, and if the %editor names are also the same, it will then compare the %"Organization" keys. % %The unstarred version uses a case sensitive comparison for strings, %whereas the starred version ignores the case when comparing strings. %Note that the case sensitive comparison orders uppercase characters %before lowercase characters, so the letter B is considered to be %lower than the letter a. % %\begin{example}{Sorting a Database}{ex:sort} %This example uses the database called "scores" defined in %\autoref{ex:scores}. First, I am going to sort the database %according to the student scores in descending order (highest to %lowest) and display the database in a table %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores (sorted by score)} %\centering %\DTLsort{Score=descending}{scores}% %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)% %\DTLforeach{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\firstname & \surname & \score} %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:sortscores}. % %\begin{table}[htbp] %\caption{Student scores (sorted by score)}\label{tab:sortscores} %\centering %\DTLsort{Score=descending}{scores}\relax %\begin{tabular}{llr} %\bfseries First Name & %\bfseries Surname & %\bfseries Score (\%)\relax %\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\firstname & \surname & \score} %\end{tabular} %\end{table} % %Now I am going to sort the database according to %surname and then first name, and display it in a table. Note that %since I want to sort in ascending order, I can omit the %"=ascending" part of the sort criteria. I have also decided to %reverse the first and second columns, so that the surname is %in the first column. %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores (sorted by name)} %\centering %\DTLsort{Surname,FirstName}{scores}% %\begin{tabular}{llr} %\bfseries Surname & %\bfseries First Name & %\bfseries Score (\%)% %\DTLforeach{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\surname & \firstname & \score} %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:sortname}. %\begin{table}[htbp] %\caption{Student scores (sorted by name)}\label{tab:sortname} %\centering %\DTLsort{Surname,FirstName}{scores}\relax %\begin{tabular}{llr} %\bfseries Surname & %\bfseries First Name & %\bfseries Score (\%)\relax %\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\surname & \firstname & \score} %\end{tabular} %\end{table} % %Now suppose I add two new students to the database: %\begin{verbatim} %\DTLnewrow{scores}% %\DTLnewdbentry{scores}{Surname}{van der Mere}% %\DTLnewdbentry{scores}{FirstName}{Henk}% %\DTLnewdbentry{scores}{Score}{71}% %\DTLnewrow{scores}% %\DTLnewdbentry{scores}{Surname}{de la Mere}% %\DTLnewdbentry{scores}{FirstName}{Jos}% %\DTLnewdbentry{scores}{Score}{58}% %\end{verbatim} %\DTLnewrow{scores} %\DTLnewdbentry{scores}{Surname}{van der Mere}\relax %\DTLnewdbentry{scores}{FirstName}{Henk}\relax %\DTLnewdbentry{scores}{Score}{71}\relax %\DTLnewrow{scores}\relax %\DTLnewdbentry{scores}{Surname}{de la Mere}\relax %\DTLnewdbentry{scores}{FirstName}{Jos}\relax %\DTLnewdbentry{scores}{Score}{58}\relax %and again I try sorting the database, and displaying the contents %as a table: %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores (case sensitive sort)} %\centering %\DTLsort{Surname,FirstName}{scores}% %\begin{tabular}{llr} %\bfseries Surname & %\bfseries First Name & %\bfseries Score (\%)% %\DTLforeach{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\surname & \firstname & \score} %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:sortname2}. Notice that the surnames %aren't correctly ordered. This is because a case-sensitive %sort was used. Changing \cs{DTLsort} to \cs{DTLsort*} in the %above code produces \autoref{tab:sortname3}. % %\begin{table}[htbp] %\caption{Student scores (case sensitive sort)}\label{tab:sortname2} %\centering %\DTLsort{Surname,FirstName}{scores}\relax %\begin{tabular}{llr} %\bfseries Surname & %\bfseries First Name & %\bfseries Score (\%)\relax %\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\surname & \firstname & \score} %\end{tabular} %\end{table} % %\begin{table}[htbp] %\caption{Student scores (case ignored when %sorting)}\label{tab:sortname3} %\centering %\DTLsort*{Surname,FirstName}{scores}\relax %\begin{tabular}{llr} %\bfseries Surname & %\bfseries First Name & %\bfseries Score (\%)\relax %\DTLforeach{scores}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\surname & \firstname & \score} %\end{tabular} %\end{table} % %\end{example} % %\begin{example}{Influencing the sort order}{ex:sortswitchargs} %Consider the data displayed in \autoref{tab:sortname3}, suppose that %you want the names ``van der Mere'' and ``de la Mere'' sorted %according to the actual surname ``Mere'' rather than by the ``von %part''. There are two ways you can do this: firstly, you could store %the von part in a separate field, and then sort by surname, then von %part, then first name, or you could define a command called, say, %\cs{switchargs}, as follows: %\begin{verbatim} %\newcommand*{\switchargs}[2]{#2#1} %\end{verbatim} %\newcommand*{\switchargs}[2]{#2#1}\relax %then store the data as: %\begin{verbatim} %FirstName,Surname,StudentNo,Score %John,"Smith, Jr",102689,68 %Jane,Brown,102647,75 %Andy,Brown,103569,42 %Z\"oe,Adams,105987,52 %Roger,Brady,106872,58 %Clare,Verdon,104356,45 %Henk,\switchargs{Mere}{van der },106789,71 %Jos,\switchargs{Mere}{de la },104256,58 %\end{verbatim} %\DTLnewdb{scores2}\relax %\DTLnewrow{scores2}\relax %\DTLnewdbentry{scores2}{FirstName}{John}\relax %\DTLnewdbentry{scores2}{Surname}{Smith, Jr}\relax %\DTLnewdbentry{scores2}{StudentNo}{102689}\relax %\DTLnewdbentry{scores2}{Score}{68}\relax %\DTLnewrow{scores2}\relax %\DTLnewdbentry{scores2}{FirstName}{Jane}\relax %\DTLnewdbentry{scores2}{Surname}{Brown}\relax %\DTLnewdbentry{scores2}{StudentNo}{102647}\relax %\DTLnewdbentry{scores2}{Score}{75}\relax %\DTLnewrow{scores2}\relax %\DTLnewdbentry{scores2}{FirstName}{Andy}\relax %\DTLnewdbentry{scores2}{Surname}{Brown}\relax %\DTLnewdbentry{scores2}{StudentNo}{103569}\relax %\DTLnewdbentry{scores2}{Score}{42}\relax %\DTLnewrow{scores2}\relax %\DTLnewdbentry{scores2}{FirstName}{Z\"oe}\relax %\DTLnewdbentry{scores2}{Score}{52}\relax %\DTLnewdbentry{scores2}{StudentNo}{105987}\relax %\DTLnewdbentry{scores2}{Surname}{Adams}\relax %\DTLnewrow{scores2}\relax %\DTLnewdbentry{scores2}{FirstName}{Roger}\relax %\DTLnewdbentry{scores2}{Score}{58}\relax %\DTLnewdbentry{scores2}{StudentNo}{106872}\relax %\DTLnewdbentry{scores2}{Surname}{Brady}\relax %\DTLnewrow{scores2}\relax %\DTLnewdbentry{scores2}{FirstName}{Clare}\relax %\DTLnewdbentry{scores2}{Score}{45}\relax %\DTLnewdbentry{scores2}{StudentNo}{104356}\relax %\DTLnewdbentry{scores2}{Surname}{Verdon}\relax %\DTLnewrow{scores2} %\DTLnewdbentry{scores2}{Surname}{\switchargs{Mere}{van der }}\relax %\DTLnewdbentry{scores2}{FirstName}{Henk}\relax %\DTLnewdbentry{scores2}{Score}{71}\relax %\DTLnewrow{scores2}\relax %\DTLnewdbentry{scores2}{Surname}{\switchargs{Mere}{de la }}\relax %\DTLnewdbentry{scores2}{FirstName}{Jos}\relax %\DTLnewdbentry{scores2}{Score}{58}\relax %Now sort the data, and put it in table (this is the same code %as in the previous example: %\begin{verbatim} %\begin{table}[htbp] %\caption{Student scores (influencing the sort order)} %\centering %\DTLsort*{Surname,FirstName}{scores}% %\begin{tabular}{llr} %\bfseries Surname & %\bfseries First Name & %\bfseries Score (\%)% %\DTLforeach{scores}{% %\firstname=FirstName,\surname=Surname,\score=Score}{% %\\ %\surname & \firstname & \score} %\end{tabular} %\end{table} %\end{verbatim} %This produces \autoref{tab:influencesort}. % %\begin{table}[htbp] %\caption{Student scores (influencing the sort order)}\label{tab:influencesort} %\centering %\DTLsort*{Surname,FirstName}{scores2}\relax %\begin{tabular}{llr} %\bfseries Surname & %\bfseries First Name & %\bfseries Score (\%)\relax %\DTLforeach{scores2}{\firstname=FirstName,\surname=Surname,\score=Score}{\relax %\\ %\surname & \firstname & \score} %\end{tabular} %\end{table} % %\end{example} % %\subsection{Saving a Database to an External File} %\label{sec:savedb} % %\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 %\meta{filename}. The separator and delimiter characters used %are as given by \ics{DTLsetseparator} (or \ics{DTLsettabseparator}) %and \ics{DTLsetdelimiter}. For example: %\begin{verbatim} %\DTLsettabdelimiter %\DTLsavedb{scores}{scores.txt} %\end{verbatim} %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.) % %\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 %called \meta{filename}, where the database is stored as %a combination of \ics{DTLnewdb}, \ics{DTLnewrow} and %\ics{DTLnewdbentry} commands. % %\subsection{Deleting or Clearing a Database}\label{sec:deletedb} % %A database can be cleared or deleted when its contents are no %longer required. %\begin{definition}[\DescribeMacro{\DTLcleardb}] %\cs{DTLcleardb}\marg{db name} %\end{definition} %Clears the database given by \meta{db name}. The database is emptied %but remains defined. % %\begin{definition}[\DescribeMacro{\DTLdeletedb}] %\cs{DTLdeletedb}\marg{db name} %\end{definition} %Deletes (undefines) the database given by \meta{db name}. % %\subsection{Advanced Database Commands} % %This section describes more advanced commands. Further details %can be found in \autoref{sec:code:datatool}. % %\begin{definition}[\DescribeMacro{\DTLgetdatatype}] %\cs{DTLgetdatatype}\marg{cs}\marg{db}\marg{key} %\end{definition} %Gets the data type for the given key \meta{key} for the database %given by \meta{db}. The data type is stored in \meta{cs} which %must be a command name. The type will be one of: %\begin{itemize} %\item\DescribeMacro{\DTLunsettype}\cs{DTLunsettype} (not set), %\item\DescribeMacro{\DTLstringtype}\cs{DTLstringtype} (string), %\item\DescribeMacro{\DTLinttype}\cs{DTLinttype} (integer), %\item\DescribeMacro{\DTLrealtype}\cs{DTLrealtype} (real number) or %\item\DescribeMacro{\DTLcurrencytype}\cs{DTLcurrenttype} (currency). %\end{itemize} % %\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 (as for \cs{DTLgetdatatype}), \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. % %\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}. %Alternatively, if you want to identify the column by its index %rather than its key, use: %\begin{definition}[\DescribeMacro{\dtlforcolumnindex}]% %\cs{dtlforcolumnindex}\marg{cs}\marg{db}\marg{col index}\marg{body} %\end{definition} % %\begin{definition}[\DescribeMacro{\DTLifdbexists}] %\cs{DTLifdbexists}\marg{db name}\marg{true part}\marg{false part} %\end{definition} %Determines if the database given by \meta{db name} exists. % %\begin{definition}[\DescribeMacro{\DTLifhaskey}] %\cs{DTLifhaskey}\marg{db name}\marg{key}\marg{true part}\marg{false part} %\end{definition} %This determines if the database given by \meta{db name} has %any entries with the key given by \meta{key}. If so, it does %\meta{true part} otherwise it does \meta{false part}. % %Each key has an associated column index. This can be obtained %using: %\begin{definition}[\DescribeMacro{\DTLgetcolumnindex}] %\cs{DTLgetcolumnindex}\marg{cs}\marg{db}\marg{key} %\end{definition} %where \meta{cs} is a command name, \meta{db} is the database label %and \meta{key} is the key. The column index is stored in %\meta{cs}. % %You can also do the reverse and find the key associated with a %given column index: %\begin{definition}[\DescribeMacro{\DTLgetkeyforcolumn}] %\cs{DTLgetkeyforcolumn}\marg{key cs}\marg{db}\marg{column index} %\end{definition} %The key is stored in \meta{key cs} (which must be a command name). % %There is also a full expandable way of obtaining the column %index, but note that no check is performed to determine %if the database exists, or if it contains the given key: %\begin{definition}[\DescribeMacro{\dtlcolumnindex}] %\cs{dtlcolumnindex}\marg{db name}\marg{key} %\end{definition} % %\begin{definition}[\DescribeMacro{\DTLgetkeydata}] %\cs{DTLgetkeydata}\marg{key}\marg{db}\marg{col cs}\marg{type cs}\marg{header cs} %\end{definition} %Gets data for given key in database \meta{db}: the column index is %stored in \meta{col cs} (as \cs{DTLgetcolumnindex}), the type is %stored in \meta{type cs} (as \cs{DTLgetdatatype}) and the header %is stored in \meta{header cs}. % %\begin{definition}[\DescribeMacro{\DTLgetvalue}] %\cs{DTLgetvalue}\marg{cs}\marg{db}\marg{r}\marg{c} %\end{definition} %This gets the value for row given by index \meta{r} and column %given by \meta{c} for the database \meta{db} and stores it in %\meta{cs} which must be a command name. If you want to get the %value by key rather than column index you can use %\cs{dtlcolumnindex}. For example, the following gets the value %for row~3 with key \texttt{Surname} from the database %\texttt{data} and stores in \cs{myval}: %\begin{verbatim} %\DTLgetvalue{\myval}{data}{3}{\dtlcolumnindex{data}{Surname}} %\end{verbatim} % %\begin{definition}[\DescribeMacro{\DTLgetlocation}] %\cs{DTLgetlocation}\marg{row cs}\marg{column cs}\marg{database}% %\marg{value} %\end{definition} %Assigns \meta{row cs} and \meta{column cs} to the indices of the %first entry in \meta{database} that matches \meta{value}. % %\begin{definition}[\DescribeMacro{\DTLgetvalueforkey}] %\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}. % %Two rows can be swapped using: %\begin{definition}[\DescribeMacro{\DTLswaprows}]% %\cs{DTLswaprows}\marg{db name}\marg{row1 index}\marg{row2 index} %\end{definition} %where \meta{row1 index} and \meta{row2 index} are the indices %of the rows to be swapped. For example: %\begin{verbatim} %\DTLswaprows{scores}{3}{5} %\end{verbatim} %will swap the third and fifth rows. % %\begin{definition}[\DescribeMacro{\DTLifinlist}] %\cs{DTLifinlist}\marg{element}\marg{list}\marg{true part}\marg{false part} %\end{definition} %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}, but no %expansion on \meta{element}.) % %\section{Pie Charts (\texorpdfstring{\sty{datapie}}{datapie} package)} % %The \sty{datapie} package is not loaded by the \sty{datatool} package, %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]{gray}}] Grey scale 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). %\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). %\end{description} % %Numerical information contained in a database created by the %\sty{datatool} package can be converted into a pie chart using %\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 %\meta{condition} has the same form as the optional argument %to \ics{DTLforeach} described in \autoref{sec:dbforeach}. If %\meta{condition} is false, that information is omitted from the %construction of the pie chart. The argument \meta{values} is a %comma separated list of \meta{cmd}"="\meta{key} pairs, the same %as that required by the penultimate argument of \ics{DTLforeach}. %The \meta{settings list} is a comma separated list of %\meta{setting}=\meta{value} pairs, where \meta{setting} can be any of %the following: %\begin{description} %\item[\setting{DTLpiechart}{variable}] %This specifies the control sequence to use that %contains the value used to construct the pie chart. The control %sequence must be one of the control sequences to appear in %the assignment list \meta{values}. This setting is required. % %\item[\setting{DTLpiechart}{start}] %This is the starting angle of the first segment. The %value is 0 by default. % %\item[\setting{DTLpiechart}{radius}] %This is the radius of the pie chart. The default value %is 2cm. % %\item[\setting{DTLpiechart}{innerratio}] %The distance from the centre of the %pie chart to the point where the inner labels are placed is given %by this value multiplied by the ratio. The default value is 0.5. % %\item[\setting{DTLpiechart}{outerratio}] %The distance from the centre of the %pie chart to the point where the outer labels are placed is given %by this value multiplied by the ratio. The default value is 1.25. % %\item[\setting{DTLpiechart}{cutawayratio}] %The distance from the centre of the pie chart %to the point of cutaway segments is given by this value multiplied %by the ratio. The default value is 0.2. % %\item[\setting{DTLpiechart}{inneroffset}] %This is the absolute distance from the centre %of the pie chart to the point where the inner labels are placed. %You should use only one or other of \setting{DTLpiechart}{innerratio} %and \setting{DTLpiechart}{inneroffset}, not both. If you also want to %specify the radius, you must use \setting{DTLpiechart}{ratio} %before \setting{DTLpiechart}{inneroffset}. If omitted, the inner %offset is obtained from the ratio multiplied by the %\setting{DTLpiechart}{innerratio} value. % %\item[\setting{DTLpiechart}{outeroffset}] %This is the absolute distance from the centre %of the pie chart to the point where the outer labels are placed. %You should use only one or other of \setting{DTLpiechart}{outerratio} %and \setting{DTLpiechart}{outeroffset}, not both. If you also want to %specify the radius, you must use \setting{DTLpiechart}{ratio} %before \setting{DTLpiechart}{outeroffset}. If omitted, the outer %offset is obtained from the ratio multiplied by the %\setting{DTLpiechart}{outerratio} value. % %\item[\setting{DTLpiechart}{cutawayoffset}] %This is the absolute distance from the centre of %the pie chart to the point of the cutaway segments. You should use %only one or other of \setting{DTLpiechart}{cutawayratio} and %\setting{DTLpiechart}{cutawayoffset}, not both. If %you also want to specify the radius, you must use %\setting{DTLpiechart}{ratio} before %\setting{DTLpiechart}{cutawayoffset}. If omitted, the cutaway offset %is obtained from the ratio multiplied by the %\setting{DTLpiechart}{cutawayratio} value. % %\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 %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 %first three segments from the rest of the pie chart. If omitted, %the pie chart will be whole. % %\item[\setting{DTLpiechart}{innerlabel}] %The value of this is positioned in the middle of each segment at a %distance of \setting{DTLpiechart}{inneroffset} from the centre %of the pie chart. The default is the same as the value of %\setting{DTLpiechart}{variable}. % %\item[\setting{DTLpiechart}{outerlabel}] %The value of this is positioned at a distance of %\setting{DTLpiechart}{outeroffset} from the centre of the pie chart. %The default is empty. % %\item[\setting{DTLpiechart}{rotateinner}] This is a boolean setting, %so it can only take the values "true" and "false". If the value is %omitted "true" is assumed. If true, the inner labels are rotated %along the spokes of the pie chart, otherwise the inner labels are not %rotated. There are analogous package options %\pkgopt[datapie]{rotateinner} and \pkgopt[datapie]{norotateinner}. % %\item[\setting{DTLpiechart}{rotateouter}] %This is a boolean setting, so it can only take %the values "true" and "false". If the value is omitted "true" is %assumed. If true, the outer labels are rotated along the spokes of %the pie chart, otherwise the outer labels are not rotated. %There are analogous package options %\pkgopt[datapie]{rotateouter} and \pkgopt[datapie]{norotateouter}. % %\end{description} % %\begin{example}{A Pie Chart}{ex:piechart} %This example loads data from a file called "fruit.csv" which contains %the following: %\begin{verbatim} %Name,Quantity %"Apples",30 %"Pears",25 %"Lemons,Limes",40.5 %"Peaches",34.5 %"Cherries",20 %\end{verbatim} %First load the data: %\begin{verbatim} %\DTLloaddb{fruit}{fruit.csv} %\end{verbatim} %\DTLnewdb{fruit}\relax %\DTLnewrow{fruit}\relax %\DTLnewdbentry{fruit}{Name}{Apples}\relax %\DTLnewdbentry{fruit}{Quantity}{30}\relax %\DTLnewrow{fruit}\relax %\DTLnewdbentry{fruit}{Name}{Pears}\relax %\DTLnewdbentry{fruit}{Quantity}{25}\relax %\DTLnewrow{fruit}\relax %\DTLnewdbentry{fruit}{Name}{Lemons,Limes}\relax %\DTLnewdbentry{fruit}{Quantity}{40.5}\relax %\DTLnewrow{fruit}\relax %\DTLnewdbentry{fruit}{Name}{Peaches}\relax %\DTLnewdbentry{fruit}{Quantity}{34.5}\relax %\DTLnewrow{fruit}\relax %\DTLnewdbentry{fruit}{Name}{Cherries}\relax %\DTLnewdbentry{fruit}{Quantity}{20}\relax %Now create a pie chart in a figure: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart} %\end{figure} %\end{verbatim} %This creates \autoref{fig:piechart}. % %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart} %\label{fig:piechart} %\end{figure} % %There are no outer labels by default, but they can be set %using the \setting{DTLpiechart}{outerlabel} setting. %The following sets the outer label to the value of the "Name" key: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{A pie chart (outer labels set)} %\end{figure} %\end{verbatim} %This creates \autoref{fig:piechartouter}. % %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name}{fruit} %{\name=Name,\quantity=Quantity} %\caption{A pie chart (outer labels set)} %\label{fig:piechartouter} %\end{figure} % %You may prefer the labels to be rotated. The following %switches on the rotation for the inner and outer labels: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name,% %rotateinner,rotateouter}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{A pie chart (rotation enabled)} %\end{figure} %\end{verbatim} %This creates \autoref{fig:piechartrot}. % %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name %,rotateinner,rotateouter}{fruit} %{\name=Name,\quantity=Quantity} %\caption{A pie chart (rotation enabled)} %\label{fig:piechartrot} %\end{figure} %\end{example} % %\begin{example}{Separating Segments from the Pie Chart}{ex:cutaway} %You may want to separate one or more segments from the pie chart, %perhaps to emphasize them. You can do this using the %\setting{DTLpiechart}{cutaway} %setting. The following separates the first and third segments %from the pie chart: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name,% %cutaway={1,3}}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{A pie chart with cutaway segments} %\end{figure} %\end{verbatim} %This produces \autoref{fig:piecutaway}. % %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name %,cutaway={1,3}}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart with cutaway segments} %\label{fig:piecutaway} %\end{figure} % %Alternatively I can specify a range of segments. The following %separates the first two segments: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name,% %cutaway={1-2}}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{A pie chart with cutaway segments (\texttt{cutaway=\{1-2\}})} %\end{figure} %\end{verbatim} %This produces \autoref{fig:piecutaway2}. % %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name %,cutaway={1-2}}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart with cutaway segments (\texttt{cutaway=\{1-2\}})} %\label{fig:piecutaway2} %\end{figure} % %Notice the difference between \autoref{fig:piecutaway2} and %\autoref{fig:piecutaway3} which was produced using: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name,% %cutaway={1,2}}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{A pie chart with cutaway segments (\texttt{cutaway=\{1,2\}})} %\end{figure} %\end{verbatim} % %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,outerlabel=\name %,cutaway={1,2}}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart with cutaway segments (\texttt{cutaway=\{1,2\}})} %\label{fig:piecutaway3} %\end{figure} % %\end{example} % %\subsection{Pie Chart Variables} % %\begin{definition}[\DescribeMacro{\DTLpievariable}]% %\cs{DTLpievariable} %\end{definition} %This command is set to the variable given by the %\setting{DTLpiechart}{variable} setting in the \meta{settings list} %argument of \cs{DTLpiechart}. The \setting{DTLpiechart}{innerlabel} %is set to \cs{DTLpievariable} by default. % %\begin{definition}[\DescribeMacro{\DTLpiepercent}]% %\cs{DTLpiepercent} %\end{definition} %This command is set to the percentage value of \cs{DTLpievariable}. %The percentage value is rounded to \meta{n} digits, where \meta{n} %is the value of the \LaTeX\ counter %\desctr{DTLpieroundvar}. % %\begin{example}{Changing the Inner and Outer Labels}{ex:pielabels} %This example uses the database defined in \autoref{ex:piechart}. %The inner label is now set to the percentage value, rather than %the actual value, and the outer label is set to the name with %the actual value in parentheses. %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,% %innerlabel={\DTLpiepercent\%},% %outerlabel={\name\ (\DTLpievariable)}}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{A pie chart (changing the labels)} %\end{figure} %\end{verbatim} %This produces \autoref{fig:piechartlabels}. % %\begin{figure}[htbp] %\centering %\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent %\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart (changing the labels)} %\label{fig:piechartlabels} %\end{figure} %\end{example} % %\subsection{Pie Chart Label Formatting} % %\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}. % %\begin{definition}[\DescribeMacro{\DTLdisplayouterlabel}]% %\cs{DTLdisplayouterlabel}\marg{text} %\end{definition} %This governs how the outer label is formatted, where \meta{text} %is the text of the outer label. The default is to just do \meta{text}. % %\begin{example}{Changing the Inner and Outer Label %Format}{ex:pielabelformat} %This example extends \autoref{ex:pielabels}. %The inner and outer labels are now both typeset in a sans-serif %font: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} %\renewcommand*{\DTLdisplayouterlabel}[1]{\textsf{#1}} %\DTLpiechart{variable=\quantity,% %innerlabel={\DTLpiepercent\%},% %outerlabel={\name\ (\DTLpievariable)}}{fruit}{% %\name=Name,\quantity=Quantity} %\caption{A pie chart (changing the label format)} %\end{figure} %\end{verbatim} %This produces \autoref{fig:piechartlabelformat}. % %\begin{figure}[htbp] %\centering %\renewcommand*{\DTLdisplayinnerlabel}[1]{\textsf{#1}} %\renewcommand*{\DTLdisplayouterlabel}[1]{\textsf{#1}} %\DTLpiechart{variable=\quantity,innerlabel={\DTLpiepercent %\%},outerlabel={\name\ (\DTLpievariable)}}{fruit}{\name=Name,\quantity=Quantity} %\caption{A pie chart (changing the label format)} %\label{fig:piechartlabelformat} %\end{figure} %\end{example} % %\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 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 %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. % %\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}. % %\begin{definition}[\DescribeMacro{\DTLpieoutlinecolor}]% %\cs{DTLpieoutlinecolor} %\end{definition} %This sets the outline colour for the pie chart. The default is %black. % %\begin{definition}[\DescribeMacro{\DTLpieoutlinewidth}]% %\cs{DTLpieoutlinewidth} %\end{definition} %This is a length that governs the line width of the outline. The %default value is 0pt, but can be changed using \cs{setlength}. %The outline is only drawn if \cs{DTLpieoutlinewidth} is greater %than 0pt. % %\begin{example}{Pie Segment Colours}{ex:piecolours} %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. 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 %\textsf{\shortstack{#1}}} %\DTLpiechart{variable=\quantity,% %innerlabel={\DTLpiepercent\%},% %outerlabel={\name\\(\DTLpievariable)}}{fruit}{% %\name=Name,\quantity=Quantity} %\begin{tabular}[b]{ll} %\DTLforeach{fruit}{\name=Name}{\DTLiffirstrow{}{\\}% %\DTLdocurrentpiesegmentcolor\rule{10pt}{10pt} & %\name %} %\end{tabular} %\caption{A pie chart (using segment colours and outline)} %\end{figure} %\end{verbatim} %This produces \autoref{fig:piesegcolour}. (The format of the %outer label has been changed to use \cs{shortstack} to %prevent the outer labels from taking up so much horizontal %space. The \setting{DTLpiechart}{outerlabel} setting has also been %modified to use "\\" after the name to move the percentage value onto %the next row.) % %\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} %\begin{tabular}[b]{ll} %\DTLforeach{fruit}{\name=Name}{\DTLiffirstrow{}{\\}\relax %\DTLdocurrentpiesegmentcolor\rule{10pt}{10pt} & %\name %} %\end{tabular} %\caption{A pie chart (using segment colours and outline)} %\label{fig:piesegcolour} %\end{figure} %\end{example} % %\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). % %\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 (but be careful not to distort the chart). % %\begin{definition}[\DescribeMacro{\DTLpieatendtikz}]% %\cs{DTLpieatendtikz} %\end{definition} %The macro \cs{DTLpieatendtikz} is called at the end of the %\env{tikzpicture} environment, allowing you add additional %graphics to the pie chart. This does nothing by default. % %\begin{example}{Adding Information to the Pie Chart}{ex:piescale} %This example modifies \autoref{ex:piechart}. It redefines %\cs{DTLpieatendtikz} to add an annotated arrow. %\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} %\end{figure} %\end{verbatim} %This produces \autoref{fig:pieannote}. (Note that the centre %of the pie chart is the origin of the TikZ picture.) % %\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} %\label{fig:pieannote} %\end{figure} %\end{example} % %\section{Scatter and Line Plots (\texorpdfstring{\sty{dataplot}}{dataplot} %package)} % %The \sty{dataplot} package provides commands for creating %scatter or line plots from databases. It uses the pgf/TikZ plot %handler library to create the plots. See the \sty{pgf} manual for %more detail on pgf streams and plot handles. The \sty{dataplot} %package is not loaded by \sty{datatool} so if you want to use %it you need to load it explicitly using "\usepackage{dataplot}". % % %\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) %of all the data given in the databases listed in \meta{db list}, %which should be a comma separated list of database names. %The optional argument \meta{condition} is the same as that for %\ics{DTLforeach}. The \meta{settings} argument is a comma separated %list of \meta{setting}"="\meta{value} pairs. There are two settings %that must be specified \setting{DTLplot}{x} and \setting{DTLplot}{y}. %The other settings are optional. Note that any value that contains %a comma, must be enclosed in braces. For example %"colors={red,cyan,blue}". Note where any setting requires %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: %\begin{description} %\item[\setting{DTLplot}{x}] The database key %that specifies the $x$ co-ordinates. This setting is required. % %\item[\setting{DTLplot}{y}] The database key that specifies %the $y$ co-ordinates. This setting is required. % %\item[\setting{DTLplot}{markcolors}] A comma separated list of colour %names for the markers. An empty value will use the current colour. % %\item[\setting{DTLplot}{linecolors}] A comma separated list of colour %names for the plot lines. An empty value will use the current colour. % %\item[\setting{DTLplot}{colors}] A comma separated list of colour %names for the lines and markers. % %\item[\setting{DTLplot}{marks}] A comma separated list of %code to generate plot marks. (This should typically be a list %of \cs{pgfuseplotmark} commands, see the \sty{pgf} manual for %further details.) You may use \cs{relax} as an element %of the list to suppress markers for the corresponding plot. %For example: "marks={\pgfuseplotmark{o},\relax}" will use an %open circle marker for the first database, and no markers for the %second database listed in \meta{db list}. % %\item[\setting{DTLplot}{lines}] A comma separated list of %line style settings. (This should typically be a list of %\cs{pgfsetdash} commands, see the \sty{pgf} manual for %further details on how to set the line style.) An empty value %will use the current line style. %You may use \cs{relax} as an element %of the list to suppress line for the corresponding plot. %For example: "lines={\relax,\pgfsetdash{}{0pt}}" %will have no lines for the first database, and a solid line %for the second database listed in \meta{db list}. % %\item[\setting{DTLplot}{width}] The width of the plot. This must %be a length. The plot width does not include outer tick marks or %labels. % %\item[\setting{DTLplot}{height}] The height of the plot. This must %be a length. The plot height does not include outer tick marks %or labels. % %\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 %"markers". % %\item[\setting{DTLplot}{axes}] This setting governs whether %to display the axes, and may take one of %the following values: "both", "x", "y" or "none". If no value %is specified, "both" is assumed. % %\item[\setting{DTLplot}{box}] This setting governs whether %or not to surround the plot in a box. It is a boolean setting, %taking only the values "true" and "false". If no value is %specified, "true" is assumed. % %\item[\setting{DTLplot}{xtics}] This setting governs whether %or not to display the $x$ tick marks. It is a boolean setting, %taking only the values "true" and "false". If no value is %specified "true" is assumed. If the \setting{DTLplot}{axes} %setting is set to "both" or "x", this value will automatically %be set to "true", otherwise it will be set to "false". % %\item[\setting{DTLplot}{ytics}] This setting governs whether %or not to display the $y$ ticks. It is a boolean setting, %taking only the values "true" and "false". If no value is %specified "true" is assumed. If the \setting{DTLplot}{axes} %setting is set to "both" or "y", this value will automatically %be set to "true", otherwise it will be set to "false". % % %\item[\setting{DTLplot}{xminortics}] This setting governs whether %or not to display the $x$ minor tick marks. It is a boolean %setting, taking only the values "true" and "false". If no value is %specified "true" is assumed. This setting also sets the %$x$ major tick marks on if the value is "true". % %\item[\setting{DTLplot}{yminortics}] This setting governs whether %or not to display the $y$ minor tick marks. It is a boolean %setting, taking only the values "true" and "false". If no value is %specified "true" is assumed. This setting also sets the %$y$ major tick marks on if the value is "true". % %\item[\setting{DTLplot}{xticdir}] This sets the $x$ tick direction, %and may only take the values "in" or "out". % %\item[\setting{DTLplot}{yticdir}] This sets the $y$ tick direction, %and may only take the values "in" or "out". % %\item[\setting{DTLplot}{ticdir}] This sets the $x$ and $y$ tick %direction, and may only take the values "in" or "out". % %\item[\setting{DTLplot}{bounds}] The value must be in the form %\meta{min x}","\meta{min y}","\meta{max x}","\meta{max y}. This %sets the graph bounds to the given values. If omitted the %bounds are computed from the maximum and minimum values of the %data. For example %\begin{verbatim} %\DTLplot{data1,data2}{x=Height,y=Weight,bounds={0,0,10,20}} %\end{verbatim} %Note that the \setting{DTLplot}{bounds} setting overrides %the \setting{DTLplot}{minx}, \setting{DTLplot}{maxx}, %\setting{DTLplot}{miny} and \setting{DTLplot}{maxy} settings. % %\item[\setting{DTLplot}{minx}] The value is the minimum value %of the $x$ axis. % %\item[\setting{DTLplot}{miny}] The value is the minimum value %of the $y$ axis. % %\item[\setting{DTLplot}{maxx}] The value is the maximum value %of the $x$ axis. % %\item[\setting{DTLplot}{maxy}] The value is the maximum value %of the $y$ axis. % %\item[\setting{DTLplot}{xticpoints}] The value must be a comma %separated list of decimal numbers indicating where to put the %$x$ tick marks. If omitted, the $x$ tick marks are placed at %equal intervals along the $x$ axis such that each interval is %not less than the length given by \ics{DTLmintickgap}. %This setting overrides \setting{DTLplot}{xticgap}. % %\item[\setting{DTLplot}{xticgap}] This value specifies the %gap between the $x$ tick marks. % %\item[\setting{DTLplot}{yticpoints}] The value must be a comma %separated list of decimal numbers indicating where to put the %$y$ tick marks. If omitted, the $y$ tick marks are placed at %equal intervals along the $y$ axis such that each interval is %not less than the length given by \ics{DTLmintickgap}. %This setting overrides \setting{DTLplot}{yticgap}. % %\item[\setting{DTLplot}{yticgap}] This value specifies the %gap between the $y$ tick marks. % %\item[\setting{DTLplot}{grid}] This is a boolean value that %specifies whether or not to display the grid. If no value %is given, "true" is assumed. The minor grid lines are only %displayed if the minor tick marks are set. % %\item[\setting{DTLplot}{xticlabels}] The value must be a comma %separated list of labels for each $x$ tick mark. If omitted, %the labels are the value of the $x$ tick position, rounded %\meta{n} digits after the decimal point, where \meta{n} is %given by the value of the counter \ctr{DTLplotroundXvar}. % %\item[\setting{DTLplot}{yticlabels}] The value must be a comma %separated list of labels for each $y$ tick mark. If omitted, %the labels are the value of the $y$ tick position, rounded %\meta{n} digits after the decimal point, where \meta{n} is %given by the value of the counter \ctr{DTLplotroundYvar}. % %\item[\setting{DTLplot}{xlabel}] The value is the label for %the $x$ axis. If omitted, the axis has no label. % %\item[\setting{DTLplot}{ylabel}] The value is the label for %the $y$ axis. If omitted, the axis has no label. % %\item[\setting{DTLplot}{legend}] This setting governs whether %or not to display the legend, and where it should be displayed. %It may take one of the following values "none" (don't display %the legend), "north", "northeast", "east", "southeast", "south", %"southwest", "west" or "northwest". If the value is omitted, %"northeast" is assumed. % %\item[\setting{DTLplot}{legendlabels}] The value must be a comma %separated list of labels for the legend. If omitted, the database %names are used. % %\end{description} % %\begin{example}{A Basic Graph}{ex:basicplot} %Suppose you have a file called "groupa.csv" that contains the %following: %\DTLnewdb{groupa}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.55}\relax %\DTLnewdbentry{groupa}{Weight}{45.4}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.54}\relax %\DTLnewdbentry{groupa}{Weight}{48.0}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.56}\relax %\DTLnewdbentry{groupa}{Weight}{58.0}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.56}\relax %\DTLnewdbentry{groupa}{Weight}{50.2}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.57}\relax %\DTLnewdbentry{groupa}{Weight}{46.0}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.58}\relax %\DTLnewdbentry{groupa}{Weight}{48.3}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.59}\relax %\DTLnewdbentry{groupa}{Weight}{56.5}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.59}\relax %\DTLnewdbentry{groupa}{Weight}{58.1}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.60}\relax %\DTLnewdbentry{groupa}{Weight}{60.9}\relax %\DTLnewrow{groupa}\relax %\DTLnewdbentry{groupa}{Height}{1.62}\relax %\DTLnewdbentry{groupa}{Weight}{56.3}\relax %\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} %Height,Weight %\DTLforeach{groupa}{\x=Height,\y=Weight}{\x,\y %}\end{ttfamily}\par\noindent %First load this into a database called "groupa": %\begin{verbatim} %\DTLloaddb{groupa}{groupa.csv} %\end{verbatim} %The data can now be converted into a scatter plot as follows: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLplot{groupa}{x=Height,y=Weight} %\caption{A scatter plot} %\end{figure} %\end{verbatim} %This produces \autoref{fig:basicplot}. % %\begin{figure}[htbp] %\centering %\DTLplot{groupa}{x=Height,y=Weight} %\caption{A scatter plot} %\label{fig:basicplot} %\end{figure} % %Alternatively, you can use the \setting{DTLplot}{style} setting %to change it into a line plot: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLplot{groupa}{x=Height,y=Weight,style=lines} %\caption{A line plot} %\end{figure} %\end{verbatim} %This produces \autoref{fig:basiclineplot}. % %\begin{figure}[htbp] %\centering %\DTLplot{groupa}{x=Height,y=Weight,style=lines} %\caption{A line plot} %\label{fig:basiclineplot} %\end{figure} %\end{example} % %\begin{example}{Plotting Multiple Data Sets}{ex:2db} %In this example, I shall use the database called "groupa" defined %in \autoref{ex:basicplot}, and another database called "groupb" %which is loaded from the file "groupb.csv" which contains the %following: %\DTLnewdb{groupb} %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.54}\relax %\DTLnewdbentry{groupb}{Weight}{48.4}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.54}\relax %\DTLnewdbentry{groupb}{Weight}{42.0}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.55}\relax %\DTLnewdbentry{groupb}{Weight}{64.0}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.56}\relax %\DTLnewdbentry{groupb}{Weight}{58.2}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.56}\relax %\DTLnewdbentry{groupb}{Weight}{49.0}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.57}\relax %\DTLnewdbentry{groupb}{Weight}{40.3}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.58}\relax %\DTLnewdbentry{groupb}{Weight}{51.5}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.58}\relax %\DTLnewdbentry{groupb}{Weight}{63.1}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.59}\relax %\DTLnewdbentry{groupb}{Weight}{74.9}\relax %\DTLnewrow{groupb}\relax %\DTLnewdbentry{groupb}{Height}{1.59}\relax %\DTLnewdbentry{groupb}{Weight}{59.3}\relax %\begin{ttfamily}\obeylines\setlength{\parindent}{0pt} %Height,Weight %\DTLforeach{groupb}{\x=Height,\y=Weight}{\x,\y %}\end{ttfamily}\par\noindent %First load this into a database called "groupb": %\begin{verbatim} %\DTLloaddb{groupb}{groupb.csv} %\end{verbatim} %I can now plot both groups in the same graph, but I want a smaller %graph than \autoref{fig:basicplot} and \autoref{fig:basiclineplot}, %so I am going to set the plot width and height to 3in: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLplot{groupa,groupb}{x=Height,y=Weight,width=3in,height=3in} %\caption{A scatter plot} %\end{figure} %\end{verbatim} %This produces \autoref{fig:2db}. % %\begin{figure}[htbp] %\centering %\DTLplot{groupa,groupb}{x=Height,y=Weight,width=3in,height=3in} %\caption[A scatter plot (multiple datasets)]{A scatter plot} %\label{fig:2db} %\end{figure} % %Now let's add a legend using the \setting{DTLplot}{legend} setting, %with the legend labels "Group A" and "Group B", %and set the $x$ tick intervals using \setting{DTLplot}{xticpoints} %setting. I am also going to set the $x$ axis label to %"Height (m)" and the $y$ axis label to "Weight (kg)", and place %a box around the plot. %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLplot{groupa,groupb}{x=Height,y=Weight, %width=3in,height=3in,legend,legendlabels={Group A,Group B}, %xlabel={Height (m)},ylabel={Weight (kg)},box, %xticpoints={1.54,1.55,1.56,1.57,1.58,1.59,1.60,1.61,1.62}} %\caption{A scatter plot} %\end{figure} %\end{verbatim} %This produces \autoref{fig:legend}. % %\begin{figure}[htbp] %\centering %\DTLplot{groupa,groupb}{x=Height,y=Weight,legend, %width=3in,height=3in,legendlabels={Group A,Group B}, %xlabel={Height (m)},ylabel={Weight (kg)},box, %xticpoints={1.54,1.55,1.56,1.57,1.58,1.59,1.60,1.61,1.62}} %\caption[A scatter plot (with a legend)]{A scatter plot} %\label{fig:legend} %\end{figure} %\end{example} % %\subsection{Adding Information to the Plot} % %The \sty{datatool} package provides two hooks used at the beginning %and end of the \env{tikzpicture} environment: %\begin{definition}[\DescribeMacro{\DTLplotatbegintikz}]% %\cs{DTLplotatbegintikz} %\end{definition}\noindent %and %\begin{definition}[\DescribeMacro{\DTLplotatendtikz}]% %\cs{DTLplotatendtikz} %\end{definition} %They are both defined to do nothing by default, but can be redefined %to add commands to the image. The unit vectors are set prior to %using these hooks, so you can use the same co-ordinates as those %in the data sets. % %\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 %code to produce the marker, \meta{line style} is code to set %the line style and \meta{text} is a textual label. You can %use \cs{relax} to suppress the marker or line. For example: %\begin{verbatim} %\DTLaddtoplotlegend{\pgfuseplotmark{x}}{\relax}{Some Data} %\end{verbatim} %Note that the legend is plotted before \cs{DTLplotatendtikz}, %so if you want to add information to the legend you will need %to do the in \cs{DTLplotatstarttikz}. % %\begin{example}{Adding Information to a Plot}{ex:addtoplot} %Returning to the plots created in \autoref{ex:2db}, suppose %I now want to annotate the plot, say I want to draw your notice %to a particular point, say the point (1.58,48.3), then I can %redefine \cs{DTLplotatendtikz} to draw an annotated arrow to %that point: %\begin{verbatim} %\renewcommand*{\DTLplotatendtikz}{% %\draw[<-,line width=1pt] (1.58,48.3) -- (1.6,43) % node[below]{interesting point}; %} %\end{verbatim} %So \autoref{fig:legend} now looks like \autoref{fig:annote}. %(Obviously, \cs{DTLplotatendtikz} needs to be redefined before %using \cs{DTLplot}.) % %\begin{figure}[htbp] %\renewcommand*{\DTLplotatendtikz}{% %\draw[<-,line width=1pt] (1.58,48.3) -- (1.6,43) % node[below]{interesting point}; %} %\centering %\DTLplot{groupa,groupb}{x=Height,y=Weight,legend, %width=3in,height=3in,legendlabels={Group A,Group B},box, %xlabel={Height (m)},ylabel={Weight (kg)}, %xticpoints={1.54,1.55,1.56,1.57,1.58,1.59,1.60,1.61,1.62}} %\caption[A scatter plot (using the end plot hook to annotate the %plot)]{A scatter plot} % %\label{fig:annote} %\end{figure} %\end{example} % %\subsection{Global Plot Settings} % %\subsubsection{Lengths} %This section describes the lengths that govern the appearance of %the plot created using \ics{DTLplot}. These lengths can be %changed using \cs{setlength}. % %\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. % %\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 % %\begin{definition}[\DescribeMacro{\DTLticklength}]% %\cs{DTLticklength} %\end{definition} %This governs the length of the tick marks. The default value is %5pt. % %\begin{definition}[\DescribeMacro{\DTLminorticklength}]% %\cs{DTLminorticklength} %\end{definition} %This governs the length of the minor tick marks. The default value is %2pt. % %\begin{definition}[\DescribeMacro{\DTLticklabeloffset}]% %\cs{DTLticklabeloffset} %\end{definition} %This governs the distance from the axis to the tick labels. The %default value is 8pt. % %\begin{definition}[\DescribeMacro{\DTLmintickgap}]% %\cs{DTLmintickgap} %\end{definition} %This is the minimum distance allowed between tick marks. If the %plot width or height is less than this distance there will only %be tick marks at either end of the axis. The default value is %20pt. % %\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. % %\begin{definition}[\DescribeMacro{\DTLlegendyoffset}]% %\cs{DTLlegendyoffset} %\end{definition} %This is the vertical distance from the border of the plot to the %outer border of the legend. The default value is 10pt. % %\subsubsection{Counters} %These counters govern the appearance of plots %created using \ics{DTLplot}. The value of the counters can be %changed using \cs{setcounter}. % %\begin{definition}[\DescribeCounter{DTLplotroundXvar}] %\ctrfmt{DTLplotroundXvar} %\end{definition} %Unless you specify your own tick labels, the $x$ tick labels will %be given by the tick points rounded to \meta{n} digits after the %decimal point, where \meta{n} is the value of the counter %\ctrfmt{DTLplotroundXvar}. % %\begin{definition}[\DescribeCounter{DTLplotroundYvar}] %\ctrfmt{DTLplotroundYvar} %\end{definition} %Unless you specify your own tick labels, the $y$ tick labels will %be given by the tick points rounded to \meta{n} digits after the %decimal point, where \meta{n} is the value of the counter %\ctrfmt{DTLplotroundYvar}. % %\subsubsection{Macros} %These macros govern the appearance of plots created using %\ics{DTLplot}. They can be changed using \cs{renewcommand}. % %\begin{definition}[\DescribeMacro{\DTLplotmarks}]% %\cs{DTLplotmarks} %\end{definition} %This must be a comma separated list of \sty{pgf} code to create the %plot marks. \ics{DTLplot} cycles through this list for each %database listed. The \sty{pgf} package provides convenient commands %for generating plots using \cs{pgfuseplotmark}. See the \sty{pgf} %manual for more details. % %\begin{definition}[\DescribeMacro{\DTLplotmarkcolors}]% %\cs{DTLplotmarkcolors} %\end{definition} %This must be a comma separated list of defined colours to apply to the %plot marks. \ics{DTLplot} cycles through this list for each database %listed. If this macro is set to empty, the current colour will %be used instead. % %\begin{definition}[\DescribeMacro{\DTLplotlines}]% %\cs{DTLplotlines} %\end{definition} %This must be a comma separated list of \sty{pgf} code to set the %style of the plot lines. \ics{DTLplot} cycles through this list for %each database listed. Dash patterns can be set using \cs{pgfsetdash}, %see the \sty{pgf} manual for more details. If \cs{DTLplotlines} is %set to empty the current line style will be used instead. % %\begin{definition}[\DescribeMacro{\DTLplotlinecolors}]% %\cs{DTLplotlinecolors} %\end{definition} %This must be a comma separated list of defined colours to apply to the %plot lines. \cs{DTLplot} cycles through this list for each database %listed. If this macro is set to empty, the current colour will %be used instead. The default is the same as \cs{DTLplotmarkcolors}. % %\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 "-" %which is a solid line style with no start or end arrows. The $x$ %axis line starts from the bottom left corner of the plot and extends %to the bottom right corner of the plot. So if you want the $x$ axis %to have an arrow head at the right end, you can do: %\begin{verbatim} %\renewcommand*{\DTLXAxisStyle}{->} %\end{verbatim} % %\begin{definition}[\DescribeMacro{\DTLYAxisStyle}]% %\cs{DTLYAxisStyle} %\end{definition} %This governs the style of the $y$ axis. It is analogous to %\cs{DTLXAxisStyle} described above. % %\begin{definition}[\DescribeMacro{\DTLmajorgridstyle}]% %\cs{DTLmajorgridstyle} %\end{definition} %This specifies the format of the major grid lines. %It may be set to any TikZ setting that you can pass to the %optional argument of \cs{draw}. The default value is %"color=gray,-" which indicates a grey solid line. % %\begin{definition}[\DescribeMacro{\DTLminorgridstyle}]% %\cs{DTLminorgridstyle} %\end{definition} %This specifies the format of the minor grid lines. %It may be set to any TikZ setting that you can pass to the %optional argument of \cs{draw}. The default value is %"color=gray,loosely dotted" which indicates a grey dotted line. % %\begin{definition}[\DescribeMacro{\DTLformatlegend}]% %\cs{DTLformatlegend}\marg{legend} %\end{definition} %This formats the entire legend, which is passed as the argument. %The default is to set the legend with %a white background, a black frame. % %\subsection{Adding to a Plot Stream} % %\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} %where the $x$ co-ordinates are given by the key \meta{x key} %and the $y$ co-ordinates are given by the key \meta{y key}. %(\ics{DTLconverttodecimal} is used to convert locale dependent %values to a standard decimal that is recognised by the %\sty{pgf} package.) %The optional argument \meta{condition} is the same as that %for \ics{DTLforeach}. % %\begin{example}{Adding to a Plot Stream}{ex:plotstream} %Suppose you have a CSV file called "data.csv" containing the %following: %\begin{verbatim} %x,y %0,0 %1,1 %2,0.5 %1.5,0.3 %\end{verbatim} %\DTLnewdb{data}\relax %\DTLnewrow{data}\relax %\DTLnewdbentry{data}{x}{0}\relax %\DTLnewdbentry{data}{y}{0}\relax %\DTLnewrow{data}\relax %\DTLnewdbentry{data}{x}{1}\relax %\DTLnewdbentry{data}{y}{1}\relax %\DTLnewrow{data}\relax %\DTLnewdbentry{data}{x}{2}\relax %\DTLnewdbentry{data}{y}{0.5}\relax %\DTLnewrow{data}\relax %\DTLnewdbentry{data}{x}{1.5}\relax %\DTLnewdbentry{data}{y}{0.3}\relax %First load the file into a database called "data": %\begin{verbatim} %\DTLloaddb{data}{data.csv} %\end{verbatim} %Now create a figure containing this data: %\begin{verbatim} %\begin{figure}[tbhp] %\centering %\begin{tikzpicture} %\pgfplothandlermark{\pgfuseplotmark{o}} %\pgfplotstreamstart %\DTLplotstream{data}{x}{y}% %\pgfplotstreamend %\pgfusepath{stroke} %\end{tikzpicture} %\caption{Adding to a plot stream} %\end{figure} %\end{verbatim} %This produces \autoref{fig:plotstream}. % %\begin{figure}[tbhp] %\centering %\begin{tikzpicture} %\pgfplothandlermark{\pgfuseplotmark{o}} %\pgfplotstreamstart %\DTLplotstream{data}{x}{y}% %\pgfplotstreamend %\pgfusepath{stroke} %\end{tikzpicture} %\caption{Adding to a plot stream} %\label{fig:plotstream} %\end{figure} %\end{example} % %\begin{example}{Plotting Multiple Keys in the Same %Database}{ex:multikey} %Suppose I have conducted two time to growth experiments. For each %experiment, I have recorded the log count at set times, and I have %recorded this information in the same data file called, say, %"growth.csv" which contains the following: %\begin{verbatim} %Time,Experiment 1,Experiment 2 %0,3.73,3.6 %23,3.67,3.7 %60,4.9,3.8 %\end{verbatim} %\DTLnewdb{growth}\DTLnewrow{growth}\relax %\DTLnewdbentry{growth}{Time}{0}\relax %\DTLnewdbentry{growth}{Experiment 1}{3.73}\relax %\DTLnewdbentry{growth}{Experiment 2}{3.6}\relax %\DTLnewrow{growth}\relax %\DTLnewdbentry{growth}{Time}{23}\relax %\DTLnewdbentry{growth}{Experiment 1}{3.67}\relax %\DTLnewdbentry{growth}{Experiment 2}{3.7}\relax %\DTLnewrow{growth}\relax %\DTLnewdbentry{growth}{Time}{60}\relax %\DTLnewdbentry{growth}{Experiment 1}{4.9}\relax %\DTLnewdbentry{growth}{Experiment 2}{3.8}\relax %I can load the data into a database using: %\begin{verbatim} %\DTLloaddb{growth}{growth.csv} %\end{verbatim} %However, I'd like to plot both results on the same graph. Since they %are contained in the same database, I can't use the method I used %in \autoref{ex:2db}. Instead I can use a combination of %\ics{DTLplot} and \ics{DTLplotstream}: %\begin{verbatim} %\begin{figure}[tbhp] %\centering % % computer bounds %\DTLminforkeys{growth}{Time}{\minX} %\DTLminforkeys{growth}{Experiment 1,Experiment 2}{\minY} %\DTLmaxforkeys{growth}{Time}{\maxX} %\DTLmaxforkeys{growth}{Experiment 1,Experiment 2}{\maxY} % % round x tick labels %\setcounter{DTLplotroundXvar}{0} % % redefine \DTLplotatbegintikz to plot the data for Experiment 1 %\renewcommand*{\DTLplotatbegintikz}{% % % set plot mark %\pgfplothandlermark{\color{green}\pgfuseplotmark{x}} % % start plot stream %\pgfplotstreamstart % % add data from Experiment 1 to plot stream %\DTLplotstream{growth}{Time}{Experiment 1}% % % end plot stream %\pgfplotstreamend % % stroke path %\pgfusepath{stroke} % % add information to legend (no line is require so use \relax) %\DTLaddtoplotlegend{\color{green}% %\pgfuseplotmark{x}}{\relax}{Experiment 1} %} % % now plot the data for Experiment 2 %\DTLplot{growth}{x=Time,y=Experiment 2,legend, %width=3in,height=3in,bounds={\minX,\minY,\maxX,\maxY}, %xlabel={Time},ylabel={Log Count}, %legendlabels={Experiment 2}} %\caption{Time to growth data} %\end{figure} %\end{verbatim} %This produces \autoref{fig:multikey}. %Notes: %\begin{itemize} %\item I redefined \ics{DTLplotatbegintikz} in order to add %the new plot to the legend, since \ics{DTLplotatendtikz} is %used after the legend is plotted. The $x$ and $y$ unit vectors %are set before \ics{DTLplotatbegintikz} so I don't need to %worry about the co-ordinates. %\item I set the counter \ctr{DTLplotroundXvar} to zero %otherwise the $x$ axis would have looked too cluttered. %\item I have used \ics{DTLminforkeys} and \ics{DTLmaxforkeys} to %determine the bounds since \ics{DTLplot} won't take the data %for Experiment 1 into account when computing the bounds. %\end{itemize} % %\begin{figure}[htbp] %\DTLminforkeys{growth}{Time}{\minX} %\DTLminforkeys{growth}{Experiment 1,Experiment 2}{\minY} %\DTLmaxforkeys{growth}{Time}{\maxX} %\DTLmaxforkeys{growth}{Experiment 1,Experiment 2}{\maxY} %\setcounter{DTLplotroundXvar}{0} %\renewcommand*{\DTLplotatbegintikz}{% %\pgfplothandlermark{\color{green}\pgfuseplotmark{x}} %\pgfplotstreamstart %\DTLplotstream{growth}{Time}{Experiment 1}% %\pgfplotstreamend %\pgfusepath{stroke} %\DTLaddtoplotlegend{\color{green}\pgfuseplotmark{x}}{\relax}{Experiment 1} %} %\centering %\DTLplot{growth}{x=Time,y=Experiment 2,legend, %width=3in,height=3in,bounds={\minX,\minY,\maxX,\maxY}, %xlabel={Time},ylabel={Log Count}, %legendlabels={Experiment 2}} %\caption[Time to growth data (plotting from the same database using %different keys)]{Time to growth data} %\label{fig:multikey} %\end{figure} %\end{example} % %\section{Bar Charts (\texorpdfstring{\sty{databar}}{databar} %package)} % %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}". 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 %axis when plotting a vertical bar chart and to the vertical axis %when plotting a horizontal bar chart. The $x$ axis units are in %increments of one bar. The $y$ axis refers to the vertical axis %when plotting a vertical bar chart and to the horizontal axis when %plotting a horizontal bar chart. The $y$ axis uses the same %co-ordinates as the data. The bars may have an upper and lower %label. In a vertical bar chart, the lower label is placed below %the $x$ axis and the upper label is placed above the top of the bar. %In a horizontal bar chart, the lower label is placed to the left of %the $x$ axis and the upper label is placed to the right of the %end of the bar. (This is actually a misnomer as it is possible %for the ``upper'' label to be below the ``lower'' label if a %bar has a negative value, however the bars are considered to %be anchored on the $x$ axis, and the other end of the bar is %considered to be the ``upper'' end, regardless of its %direction.) % %The \sty{databar} package options are as follows: %\begin{description} %\item[{\pkgopt[databar]{color}}] Created coloured bar charts %(default). % %\item[{\pkgopt[databar]{gray}}] Created grey scale bar charts. % %\item[{\pkgopt[databar]{vertical}}] Created vertical bar charts %(default). % %\item[{\pkgopt[databar]{horizontal}}] Created horizontal bar charts. %\end{description} % % % %\begin{definition}[\DescribeMacro{\DTLbarchart}]% %\cs{DTLbarchart}\oarg{condition}\marg{db name}\marg{settings}\marg{values} %\end{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 %the database \meta{db name}, where \meta{condition} is the same %as the optional argument for \ics{DTLforeach} described in %\autoref{sec:dbforeach}, and \meta{values} is the same as the %penultimate argument of \ics{DTLforeach}. The \meta{settings} %argument is a \meta{setting}"="\meta{value} list of settings. The %first command, \cs{DLTbarchart}, will draw a bar chart for a %given column of data in the database, whereas the second command, %\cs{DTLmultibarchart}, will draw a bar chart that is divided into %groups of bars where each bar within a group represents data from %several columns of a given row in the database. % %The \setting{DTLbarchart}{variable} setting is %required for \cs{DTLbarchart} and the %\setting{DTLmultibarchart}{variables}, the other settings are %optional (though some may only be used for one of %\cs{DTLbarchart} and \cs{DLTmultibarchart}), and are as follows: % %\begin{description} %\item[\setting{DTLbarchart}{variable}] %This specifies the control sequence to use that %contains the value used to construct the bar chart. The control %sequence must be one of the control sequences to appear in %the assignment list \meta{values}. This setting is required %for \cs{DTLbarchart}, and is unavailable for \cs{DTLmultibarchart}. % %\item[\setting{DTLmultibarchart}{variables}] %This specifies a list of control sequences to use which %contain the values used to construct the bar chart. Each control %sequence must be one of the control sequences to appear in %the assignment list \meta{values}. This setting is required %for \cs{DTLmultibarchart}, and is unavailable for %\cs{DTLbarchart}. % %\item[\setting{DTLbarchart,DTLmultibarchart}{max}] %This specifies the maximum value on the $y$ axis. (This should %be a standard decimal value.) % %\item[\setting{DTLbarchart,DTLmultibarchart}{length}] %This specifies the overall length of the $y$ axis, and must %be a dimension. % %\item[\setting{DTLbarchart,DTLmultibarchart}{maxdepth}] %This must be a zero or negative number. It specifies the maximum %depth of the $y$ axis. (This should be a standard decimal value.) % %\item[\setting{DTLbarchart,DTLmultibarchart}{axes}] %This setting specifies which axes to display. This may take one %of the following values: "both", "x", "y" or "none". % %\item[\setting{DTLbarchart,DTLmultibarchart}{barlabel}] %This setting specifies the lower bar label. When used with %\cs{DTLmultibarchart} it indicates the group label. % %\item[\setting{DTLmultibarchart}{multibarlabels}] %This setting should contain a comma separated list of labels %for each bar within a group for \cs{DTLmultibarchart}. This %setting is not available for \cs{DTLbarchart}. % %\item[\setting{DTLbarchart}{upperbarlabel}] %This setting specifies the upper bar label. This setting %is not available for \cs{DTLmultibarchart}. % %\item[\setting{DTLmultibarchart}{uppermultibarlabels}] %This setting must be a comma separated list of upper bar %labels for each bar within a group. This setting is not %available for \cs{DTLbarchart}. % %\item[\setting{DTLbarchart,DTLmultibarchart}{yticpoints}] %This must be a comma separated list of tick locations for the %$y$ axis. (These should be standard decimal values.) %This setting overrides \setting{DTLbarchart}{yticgap}. % %\item[\setting{DTLbarchart,DTLmultibarchart}{yticgap}] %This specifies the gap between the $y$ tick marks. (This should %be a standard decimal value.) % %\item[\setting{DTLbarchart,DTLmultibarchart}{yticlabels}] %This must be a comma separated list of tick labels for the %$y$ axis. % %\item[\setting{DTLbarchart,DTLmultibarchart}{ylabel}] %This specifies the label for the $y$ axis. % %\item[\setting{DTLmultibarchart}{groupgap}] This specifies %the gap between groups when using \cs{DTLmultibarchart}. %This value is given as a multiple of the bar width. The %default value is 1, which indicates a gap of one bar width. %This setting is not available for \cs{DTLbarchart}. % %\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. %\end{description} % %\begin{example}{A Basic Bar Chart}{ex:barchart} %Recall \autoref{ex:piechart} defined a database called "fruit". %This example will be using that database to plot a bar chart. %The following plots a basic vertical bar chart: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLbarchart{variable=\theQuantity}{fruit}{\theQuantity=Quantity} %\caption{A basic bar chart} %\end{figure} %\end{verbatim} %This produces \autoref{fig:barchart}. % %\begin{figure}[htbp] %\centering %\DTLbarchart{variable=\theQuantity}{fruit}{\theQuantity=Quantity} %\caption{A basic bar chart} %\label{fig:barchart} %\end{figure} %\end{example} % %\subsection{Changing the Appearance of a Bar Chart} % % %\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. % %\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. % %\begin{definition}[\DescribeMacro{\DTLbarlabeloffset}]% %\cs{DTLbarlabeloffset} %\end{definition} %This specifies the distance from the $x$ axis to the lower bar label. %You must use \cs{setlength} to change this value. The default value %is 10pt. % %\begin{definition}[\DescribeCounter{DTLbarroundvar}] %\ctrfmt{DTLbarroundvar} %\end{definition} %The $y$ tick labels are rounded to \meta{n} digits after the %decimal point, where \meta{n} is given by the value of the %counter \ctrfmt{DTLbarroundvar}. You must use \cs{setcounter} %to change this value. % %\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. % %\begin{definition}[\DescribeMacro{\DTLdobarcolor}]% %\cs{DTLdobarcolor}\marg{n} %\end{definition} %This sets the current colour to the colour of the \meta{n}th bar. % %\begin{definition}[\DescribeMacro{\DTLbaroutlinecolor}]% %\cs{DTLbaroutlinecolor} %\end{definition} %This macro contains the colour of the bar outlines. This defaults %to "black". % %\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. % % %\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. % %\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. % %\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. % %\begin{definition}[\DescribeMacro{\DTLbarXlabelalign}]% %\cs{DTLbarXlabelalign} %\end{definition} %This specifies the text alignment of the lower bar labels. This %defaults to "left,rotate=-90" if you use the \pkgopt[databar]{vertical} %package option or the \setting{DTLbarchart}{verticalbars} setting, %and defaults to "right" if you use the \pkgopt[databar]{horizontal} %package option or the \setting{DTLbarchart}{verticalbars}"=false" %setting. % %\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. % %\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. % %\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. % %\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}. % %\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. % %\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}{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 %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. %\begin{verbatim} %\begin{figure}[htbp] %\setlength{\DTLbaroutlinewidth}{1pt} %\centering %\DTLbarchart{variable=\theQuantity,barlabel=\theName,% %upperbarlabel=\theQuantity}{fruit}{% %\theQuantity=Quantity,\theName=Name} %\caption{A bar chart} %\end{figure} %\end{verbatim} %This produces \autoref{fig:annotebarchart}. % %\begin{figure}[htbp] %\centering %\setlength{\DTLbaroutlinewidth}{1pt} %\DTLbarchart{variable=\theQuantity,barlabel=\theName, %upperbarlabel=\theQuantity}{fruit}{\theQuantity=Quantity,\theName=Name} %\caption[A bar chart (labelled)]{A bar chart} %\label{fig:annotebarchart} %\end{figure} %\end{example} % %\begin{example}{Profit/Loss Bar Chart}{ex:profit} %Suppose I have a file called "profits.csv" that looks like: %\DTLnewdb{profits} %\DTLnewrow{profits} %\DTLnewdbentry{profits}{Year}{2000}\relax %\DTLnewdbentry{profits}{Profit}{\protect\pounds2,525}\relax %\DTLnewrow{profits} %\DTLnewdbentry{profits}{Year}{2001}\relax %\DTLnewdbentry{profits}{Profit}{\protect\pounds3,752}\relax %\DTLnewrow{profits} %\DTLnewdbentry{profits}{Year}{2002}\relax %\DTLnewdbentry{profits}{Profit}{-\protect\pounds1,520}\relax %\DTLnewrow{profits} %\DTLnewdbentry{profits}{Year}{2003}\relax %\DTLnewdbentry{profits}{Profit}{\protect\pounds1,270}\relax %\begin{verbatim} %Year,Profit %2000,\pounds2,535 %2001,\pounds3,752 %2002,-\pounds1,520 %2003,\pounds1,270 %\end{verbatim} %First I can load this file into a database called "profits": %\begin{verbatim} %\DTLloaddb{profits}{profits.csv} %\end{verbatim} %Now I can plot the data as a bar chart: %\begin{verbatim} %\begin{figure}[htbp] %\centering % % Set the width of each bar to 10pt %\setlength{\DTLbarwidth}{10pt} % % Set the outline width to 1pt %\setlength{\DTLbaroutlinewidth}{1pt} % % Round the $y$ tick labels to integers %\setcounter{DTLbarroundvar}{0} % % Adjust the tick label offset %\setlength{\DTLticklabeloffset}{20pt} % % Change the y tick label alignment %\renewcommand*{\DTLbarYticklabelalign}{left} % % Rotate the y tick labels %\renewcommand*{\DTLbardisplayYticklabel}[1]{\rotatebox{-45}{#1}} % % Set the bar colours depending on the value of \theProfit %\DTLforeach{profits}{\theProfit=Profit}{% %\ifthenelse{\DTLislt{\theProfit}{0}} %{\DTLsetbarcolor{\DTLcurrentindex}{red}} %{\DTLsetbarcolor{\DTLcurrentindex}{blue}}} % % Do the bar chart %\DTLbarchart{variable=\theProfit,upperbarlabel=\theYear, %ylabel={Profit/Loss (\pounds)},verticalbars=false, %maxdepth=-2000,max=4000}{profits} %{\theProfit=Profit,\theYear=Year} %\caption{Profits for 2000--2003} %\end{figure} %\end{verbatim} %This produces \autoref{fig:profits}. Notes: %\begin{enumerate} %\item This example uses \cs{rotatebox}, so the \sty{graphics} %or \sty{graphicx} package is required. %\item The $y$ tick labels are too wide to fit horizontally %so they have been rotated to avoid overlapping with their %neighbour. %\item Rotating the $y$ tick labels puts them too close to %the $y$ axis, so \ics{DTLticklabeloffset} is made larger to %compensate. %\item Remember not to use \cs{year} as an assignment command %as this command already exists! %\item Before the bar chart is created I have iterated through %the database, setting the bar colour to red or blue %depending on the value of \cs{theProfit}. %\end{enumerate} % %Both \cs{DTLbarchart} and \cs{DTLmultibarchart} set the following %macros, which may be used in \cs{DTLbaratbegintikz} and %\cs{DTLbaratendtikz}: %\begin{definition}[\DescribeMacro{\DTLbarchartwidth}]% %\cs{DTLbarchartwidth} %\end{definition} %This is the overall width of the bar chart. In the case of %\cs{DTLbarchart} this is just the number of bars. In the case %of \cs{DTLmultibarchart} it is computed as: %\begin{displaymath} %m \times n + (m-1)\times g %\end{displaymath} %where $m$ is the number of bar groups (i.e.\ the number of rows %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). % %\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.) % %\begin{definition}[\DescribeMacro{\DTLbarmax}]% %\cs{DTLbarmax} %\end{definition} %This is set to the maximum extent of the bar chart. (This value %corresponds to the %\setting{DTLbarchart,DTLmultibarchart}{max} setting.) % %\begin{figure}[htbp] %\centering %\setlength{\DTLbarwidth}{10pt} %\setlength{\DTLbaroutlinewidth}{1pt} %\setlength{\DTLticklabeloffset}{20pt} %\setcounter{DTLbarroundvar}{0} %\renewcommand*{\DTLbarYticklabelalign}{left} %\renewcommand*{\DTLbardisplayYticklabel}[1]{\rotatebox{-45}{#1}} %\DTLforeach{profits}{\theProfit=Profit}{\relax %\ifthenelse{\DTLislt{\theProfit}{0}} %{\DTLsetbarcolor{\DTLcurrentindex}{red}} %{\DTLsetbarcolor{\DTLcurrentindex}{blue}}} %\DTLbarchart{variable=\theProfit,upperbarlabel=\theYear, %ylabel={Profit/Loss (\pounds)},verticalbars=false, %maxdepth=-2000,max=4000 %}{profits} %{\theProfit=Profit,\theYear=Year} %\caption[Profits for 2000--2003 (a horizontal bar chart)]{Profits for %2000--2003} %\label{fig:profits} %\end{figure} % %\end{example} % %\begin{example}{A Multi-Bar Chart}{ex:multibar} %This example uses the "marks" database described in %\autoref{ex:editdb}. %Recall that this database stores student marks for three %assignments. The keys for the assignment marks are %\texttt{Assignment 1}, \texttt{Assignment 2} and %\texttt{Assignment 3}, respectively. I can convert this %data into a bar chart using the following: %\begin{verbatim} %\begin{figure}[htbp] %\centering %\DTLmultibarchart{variables={\assignI,\assignII,\assignIII}, %barwidth=10pt,uppermultibarlabels={\assignI,\assignII,\assignIII}, %barlabel={\firstname\ \surname}}{marks}{% %\surname=Surname,\firstname=FirstName,\assignI=Assignment 1,% %\assignII=Assignment 2,\assignIII=Assignment 3} %\caption{Student marks} %\end{figure} %\end{verbatim} %This produces \autoref{fig:multibar}. Notes: %\begin{enumerate} %\item I used "variables={\assignI,\assignII,\assignIII}" to %set the variable to use for each bar within a group. This means %that there will be three bars in each group. %\item I have set the bar width to 10pt, otherwise the chart %will be too wide. %\item I used "uppermultibarlabels={\assignI,\assignII,\assignIII}" %to set the upper labels for each bar within a group. This %will print the assignment mark above the relevant bar. %\item I used "barlabel={\firstname\ \surname}" to place the %student's name below the group corresponding to that student. %\end{enumerate} % %\begin{figure}[htbp] %\centering %\DTLmultibarchart{variables={\assignI,\assignII,\assignIII}, %barwidth=10pt,uppermultibarlabels={\assignI,\assignII,\assignIII}, %barlabel={\firstname\ \surname}}{marks} %{\surname=Surname,\firstname=FirstName,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII=Assignment 3} %\caption[Student marks (a multi-bar chart)]{Student %marks}\label{fig:multibar} %\end{figure} % %Recall that \autoref{ex:editdb} computed the average score over %for each student, and saved it with the key "Average". This %information can be added to the bar chart. It might also be %useful to compute the average over all students and add this %information to the chart. This is done as follows: %\begin{verbatim} % \begin{figure}[htbp] % \centering % % compute the overall mean % \DTLmeanforkeys{marks}{Average}{\overallmean} % % round it to 2 decimal places % \DTLround{\overallmean}{\overallmean}{2} % % draw a grey dotted line indicating the overall mean % % covering the entire width of the bar chart % \renewcommand*{\DTLbaratendtikz}{% % \draw[lightgray,loosely dotted] (0,\overallmean) -- % (\DTLbarchartwidth,\overallmean) % node[right,black]{Average (\overallmean)};} % % Set the lower bar labels to draw a brace across the current % % group, along with the student's name and average score % \renewcommand*{\DTLdisplaylowerbarlabel}[1]{% % \tikz[baseline=(current bounding box.center)]{ % \draw[snake=brace,rotate=-90](0,0) -- (\DTLbargroupwidth,0);} % \DTLround{\theMean}{\theMean}{2}% % \shortstack{#1\\(Average: \theMean)}} % % draw the bar chart % \DTLmultibarchart{variables={\assignI,\assignII,\assignIII}, % barwidth=10pt,uppermultibarlabels={\assignI,\assignII,\assignIII}, % barlabel={\firstname\ \surname}}{marks} % {\surname=Surname,\firstname=FirstName,\assignI=Assignment 1,% % \assignII=Assignment 2,\assignIII=Assignment 3,\theMean=Average} % \caption{Student marks} % \end{figure} %\end{verbatim} %which produces \autoref{fig:multibarmean}. Notes: %\begin{enumerate} %\item I've used the TikZ snake library to create a brace, so %I need to put %\begin{verbatim} %\usetikzlibrary{snakes} %\end{verbatim} %in the preamble. See the \sty{pgf} manual for more details on %how to use this library. % %\item I used \ics{DTLbargroupwidth} to indicate the width of %each bar group. % %\item I used \ics{DTLbarchartwidth} to indicate the width of the %entire bar chart %\end{enumerate} % %\begin{figure}[htbp] %\centering %\DTLmeanforkeys{marks}{Average}{\overallmean} %\DTLround{\overallmean}{\overallmean}{2} %\renewcommand*{\DTLbaratendtikz}{\draw[lightgray,loosely dotted] (0,\overallmean) -- %(\DTLbarchartwidth,\overallmean) node[right,black]{Average (\overallmean)};} %\renewcommand*{\DTLdisplaylowerbarlabel}[1]{\relax %\tikz[baseline=(current bounding box.center)]{ %\draw[snake=brace,rotate=-90](0,0) -- (\DTLbargroupwidth,0);} %\DTLround{\theMean}{\theMean}{2}\relax %\shortstack{#1\\(Average: \theMean)}} %\DTLmultibarchart{variables={\assignI,\assignII,\assignIII}, %barwidth=10pt,uppermultibarlabels={\assignI,\assignII,\assignIII}, %barlabel={\firstname\ \surname}}{marks} %{\surname=Surname,\firstname=FirstName,\assignI=Assignment 1,\assignII=Assignment 2,\assignIII=Assignment 3,\theMean=Average} %\caption[Student marks (annotating a bar chart)]{Student marks} %\label{fig:multibarmean} %\end{figure} %\end{example} % %\section{Converting a \texorpdfstring{\BibTeX}{BibTeX} database %into a \texorpdfstring{\sty{datatool}}{datatool} database %(\texorpdfstring{\sty{databib}}{databib} package)} %\label{sec:databib} % %The \sty{databib} package provides the means of converting a \BibTeX\ %database into a \sty{datatool} database. The database can then be %sorted using \cs{DTLsort}, described in \autoref{sec:sort}. %For example, you may want to sort the bibliography in %reverse chronological order. Once you have sorted the bibliography, %you can display it using \cs{DTLbibliography}, described in %\autoref{sec:thebib}, or you can iterate through the database %using \cs{DTLforeachbib}, described in \autoref{sec:foreachbib}. % %Note that the \sty{databib} %package is not automatically loaded by \sty{datatool}, so if %you want to use it, you must load it using %"\usepackage{databib}". % %\importantpar The purpose of this package is to provide a means for %authors to format their own bibliography style where there is no %bibliography style file available that produces the desired results. %The \cs{DTLsort} macro uses a much less efficient sorting algorithm %than \BibTeX, and loading the bibliography as a \sty{datatool} %database is much slower than loading a standard \ext{bbl} file. If %you have a large database, and you are worried that \LaTeX\ may have %become stuck, try using the \pkgopt{verbose} option to \sty{datatool} %or use the command \cs{dtlverbosetrue}. This will print informative %messages to the console and transcript file, to let you know what's %going on. % %\subsection{\texorpdfstring{\BibTeX}{BibTeX}: An Overview} %\label{sec:bibtex} %This document assumes that you have at least some passing %familiarity with \BibTeX, but here follows a brief refresher. % %\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 %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). %\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. % %In general, given a document called, say, \texttt{mydoc.tex}, you %will have to perform the following steps to ensure that the %bibliography and all citations are up-to-date: %\begin{enumerate} %\item %\begin{verbatim} %latex mydoc %\end{verbatim} %This writes the citation information to the auxiliary file. %The bibliography currently doesn't exists, so it isn't displayed. %Citations will appear in the document as ?? since the internal %cross-references don't exist yet. % %\item %\begin{verbatim} %bibtex mydoc %\end{verbatim} %This reads the auxiliary file, and creates a file with the extension %\ext{bbl} which typically contains the typeset bibliography. % %\item %\begin{verbatim} %latex mydoc %\end{verbatim} %Now that the \ext{bbl} file exists, the bibliography can be input %into the document. The internal cross-referencing information for the %bibliography can now be written to the auxiliary file. % %\item %\begin{verbatim} %latex mydoc %\end{verbatim} %The cross-referencing information can be read from the auxiliary %file. %\end{enumerate} % %\subsubsection{\texorpdfstring{\BibTeX}{BibTeX} database} % %The bibliographic data required by \BibTeX\ must be stored in %a file with the extension \ext{bib}, where each entry is stored %in the form:\par\vskip\baselineskip\noindent %{\obeylines %\noindent\texttt{@}\meta{entry\_type}\verb|{|\meta{cite\_key}\texttt, % \meta{field\_name} \texttt{=} \char`\"\meta{value}\char`\"\texttt, % \mbox{}\vdots % \meta{field\_name} \texttt{=} \char`\"\meta{value}\char`\" %\noindent\verb|}| %} %\par\vskip\baselineskip\noindent %Note that curly braces "{" and "}" may be used instead of \verb|"| %and \verb|"|. % %The entry type, given by \meta{entry\_type} above, indicates %the type of document. This may be one of: "article", "book", %"booklet", "inbook", "incollection", "inproceedings"\footnote %{Note that \texttt{conference} is a synonym for \texttt{inproceedings}.}, %"manual", %"mastersthesis", "misc", "phdthesis", "proceedings", \linebreak %"techreport" or "unpublished". % %The \meta{cite\_key} above is a unique label identifying this %entry, and is the label used in the argument of \cs{cite} or %\cs{nocite}. The available fields depends on the entry type, for %example, the field "journal" is required for the "article" entry %type, but is ignored for the "inproceedings" entry type. The standard %fields are: "address", "author", "booktitle", "chapter", "edition", %"editor", "howpublished", "institution", "journal", "key", "month", %"note", "number", "organization", "pages", "publisher", "school", %"series", "title", "type", "volume" and "year". % %Author and editor names must be entered in one of the following %ways: %\begin{enumerate} %\item \meta{First names} \meta{von part} \meta{Surname}, \meta{Jr part} % %The \meta{von part} is optional and is identified by the name(s) %starting with lowercase letters. The final comma followed by %\meta{Jr part} is also optional. Examples: %\begin{verbatim} %author = "Henry James de Vere" %\end{verbatim} %In the above, the first names are Henry James, the ``von part'' is %de and the surname is Vere. There is no ``junior part''. %\begin{verbatim} %author = "Mary-Jane Brown, Jr" %\end{verbatim} %In the above, the first name is Mary-Jane, there is no von part, %the surname is Brown and the junior part is Jr. %\begin{verbatim} %author = "Peter {Murphy Allen}" %\end{verbatim} %In the above, the first name is Peter, and the surname is Murphy %Allen. Note that in this case, the surname must be grouped, otherwise %Murphy would be considered part of the forename. %\begin{verbatim} %author = "Maria Eliza {\uppercase{d}e La} Cruz" %\end{verbatim} %In the above, the first name is Maria Eliza, the von part is %De La, and the surname is Cruz. In this case, the von part starts %with an uppercase letter, but specifying %\begin{verbatim} %author = "Maria Eliza De La Cruz" %\end{verbatim} %would make \BibTeX\ incorrectly classify ``Maria Eliza De La'' as %the first names, and the von part would be empty. Since \BibTeX\ %doesn't understand \LaTeX\ commands, using "{\uppercase{d}e La}" %will trick \BibTeX\ into thinking that it starts with a lower %case letter. % %\item \meta{von part} \meta{Surname}, \meta{Forenames} % %Again the \meta{von part} is optional, and is determined by the %case of the first letter. For example: %\begin{verbatim} %author = "de Vere, Henry James" %\end{verbatim} %\end{enumerate} % %Multiple authors or editors should be separated by the key word %"and", for example: %\begin{verbatim} %author = "Michel Goossens and Frank Mittlebach and Alexander Samarin" %\end{verbatim} % %Below is an example of a book entry: %\begin{verbatim} %@book{latexcomp, % title = "The \LaTeX\ Companion", % author = "Michel Goossens and Frank Mittlebach and % Alexander Samarin", % publisher = "Addison-Wesley", % year = 1994 %} %\end{verbatim} %Note that numbers may be entered without delimiters, as in "year = 1994". %There are also some predefined strings, including those for the month %names. You should always use these strings instead of the actual %month name, as the way the month name is displayed depends on the %bibliography style. For example: %\begin{verbatim} %@article{Cawley2007b, %author = "Gavin C. Cawley and Nicola L. C. Talbot", %title = "Preventing over-fitting in model selection via {B}ayesian % regularisation of the hyper-parameters", %journal = "Journal of Machine Learning Research", %volume = 8, %pages = "841--861", %month = APR, %year = 2007 %} %\end{verbatim} % %You can concatenate strings using the "#" character, for example: %\begin{verbatim} %month = JUL # "~31~--~" # AUG # "~4", %\end{verbatim} %Depending on the bibliography style, this may be displayed as: %July~31~--~August~4, or it may be displayed as: %Jul~31~--~Aug~4. For further information, see~\cite{Goossens}. % %\subsection{Loading a \texorpdfstring{\sty{databib}}{databib} %database} %\label{sec:loadbbl} % %The \sty{databib} package always requires the \texttt{databib.bst} %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{*}". % %\begin{definition}[\DescribeMacro{\DTLloadbbl}]% %\cs{DTLloadbbl}\oarg{bbl name}\marg{db name}\marg{bib list} %\end{definition} %This command performs several functions: % %\begin{enumerate} %\item it writes the following line in the auxiliary file: %\begin{verbatim} %\bibstyle{databib} %\end{verbatim} %which tells \BibTeX\ to use the \texttt{databib.bst} %\BibTeX\ style file, % %\item it writes \cs{bibdata}\marg{bib list} to the %auxiliary file, which tells \BibTeX\ which \ext{bib} files to use, % %\item it creates a \sty{datatool} database called \meta{db name}, % %\item it loads the file \meta{bbl name} if it exists. (The value %defaults to \cs{jobname}".bbl", which is the usual name for %a \ext{bbl} file.) If the \ext{bbl} file doesn't exist, the %database \meta{db name} will remain empty. %\end{enumerate} % %You then need to run your document through \LaTeX\ (or PDF\LaTeX) %and then run \BibTeX\ on the auxiliary file, as described in %\autoref{sec:bibtex}. This will create a \ext{bbl} file which %contains all the commands required to add the bibliography information %to the \sty{datatool} database called \meta{db name}. The next %time you \LaTeX\ your document, this file will be read, and the %information will be added to \meta{db name}. % %\importantpar Note that %\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 %\autoref{sec:foreachbib}. % %Note that the \texttt{databib.bst} \BibTeX\ style file provides %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 %want these fields to be displayed in the bibliography you will %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{DTLloadbbl} (described in \autoref{sec:loadbbl}) can be %displayed using: %\begin{definition}[\DescribeMacro{\DTLbibliography}] %\cs{DTLbibliography}\oarg{conditions}\marg{db name} %\end{definition}\noindent %where \meta{db name} is the name of the database. % %Within the optional argument \meta{condition}, you may use any of the %commands that may be used within the optional argument of %\cs{DTLforeach} \emph{In addition}, you may use the following %commands: % %\begin{definition}[\DescribeMacro{\DTLbibfieldexists}]% %\cs{DTLbibfieldexists}\marg{field label} %\end{definition} %This tests whether the field with the given label exists for the %current entry. %The field label may be one of: "Address", "Author", %"BookTitle", "Chapter", "Edition", "Editor", "HowPublished", %"Institution", "Journal", "Key", "Month", "Note", "Number", %"Organization", "Pages", "Publisher", "School", "Series", %"Title", "Type", "Volume", "Year", "ISBN", "DOI", "PubMed", %"Abstract" or "Url". % %For example, suppose you have loaded a \sty{databib} database %called "mybib" using \cs{DTLloadbbl} (described in %\autoref{sec:loadbbl}) then the following bibliography will only %include those entries which have a "Year" field: %\begin{verbatim} %\DTLbibliography[\DTLbibfieldexists{Year}]{mybib} %\end{verbatim} % %\begin{definition}[\DescribeMacro{\DTLbibfieldiseq}]% %\cs{DTLbibfieldiseq}\marg{field label}\marg{value} %\end{definition} %This tests whether the value of the field given by %\meta{field label} equals \meta{value}. If the field doesn't %exist for the current entry, this evaluates to false. %For example, the following will produce a bibliography which %only contains entries which have the "Year" field set to 2004: %\begin{verbatim} %\DTLbibliography[\DTLbibfieldiseq{Year}{2004}]{mybib} %\end{verbatim} % %\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} %contains \meta{sub string}. For example, the following will produce %a bibliography which only contains entries where the author field %contains the name "Knuth": %\begin{verbatim} %\DTLbibliography[\DTLbibfieldcontains{Author}{Knuth}]{mybib} %\end{verbatim} % %\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} %is less than \meta{value}. If the field doesn't exist for the %current entry, this evaluates to false. %For example, the following will produce a bibliography which only %contains entries whose "Year" field is less than 1983: %\begin{verbatim} %\DTLbibliography[\DTLbibfieldislt{Year}{1983}]{mybib} %\end{verbatim} % %\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} %is less than or equal to \meta{value}. If the field doesn't exist %for the current entry, this evaluates to false. %For example, the following will produce a bibliography which only %contains entries whose "Year" field is less than or equal to 1983: %\begin{verbatim} %\DTLbibliography[\DTLbibfieldisle{Year}{1983}]{mybib} %\end{verbatim} % %\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} %is greater than \meta{value}. If the field doesn't exist for the %current entry, this evaluates to false. %For example, the following will produce a bibliography which only %contains entries whose "Year" field is greater than 1983: %\begin{verbatim} %\DTLbibliography[\DTLbibfieldisgt{Year}{1983}]{mybib} %\end{verbatim} % %\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} %is greater than or equal to \meta{value}. If the field doesn't exist %for the current entry, this evaluates to false. %For example, the following will produce a bibliography which only %contains entries whose "Year" field is greater than or equal to 1983: %\begin{verbatim} %\DTLbibliography[\DTLbibfieldisge{Year}{1983}]{mybib} %\end{verbatim} % %Note that \cs{DTLbibliography} uses \cs{DTLforeachbibentry} %(described in \autoref{sec:foreachbib}) so you may also use %test the value of the counter \ctr{DTLbibrow} within %\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 %publications in reverse chronological order, but doesn't want any %publications published prior %to the year 2000. I have a file called "nlct.bib" which contains %all my publications which I keep in the directory %\verb!$HOME/texmf/bibtex/bib/!. I could look through this file, %work out the labels for all the publications whose year field %is greater or equal to 2000, and %create a file with a \cs{nocite} command containing all those labels %in a comma separated list in reverse chronological order, %but I really can't be bothered to do that. %Instead, I can create the following document: %\begin{verbatim} %\documentclass{article} %\usepackage{databib} %\begin{document} %\nocite{*} %\DTLloadbbl{mybib}{nlct} %\DTLsort{Year=descending,Month=descending}{mybib} %\DTLbibliography[\DTLbibfieldisge{Year}{2000}]{mybib} %\end{document} %\end{verbatim} %Suppose I save this file as "mypubs.tex", then I need to do: %\begin{verbatim} %latex mypubs %bibtex mypubs %latex mypubs %\end{verbatim} %Notes: %\begin{enumerate} %\item "\nocite{*}" is used to add all the citations in the %bibliography file ("nlct.bib" in this case) to the \sty{databib} %database. % %\item "\DTLloadbbl{mybib}{nlct}" does the following: %\begin{enumerate} %\item writes the line %\begin{verbatim} %\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 %use \cs{bibliographystyle}. % %\item writes the line %\begin{verbatim} %\bibdata{nlct} %\end{verbatim} %to the auxiliary file. This tells \BibTeX\ that the bibliography %data is stored in the file "nlct.bib". Since I have placed this %file in \TeX's search path, \BibTeX\ will be able to find it. % %\item creates a \sty{datatool} database called "mybib". % %\item if the \ext{bbl} file ("mypubs.bbl" in this example) exists, %it loads this file (which adds the bibliography data to the %database), otherwise it does nothing further. % %\end{enumerate} % %\item In my \BibTeX\ database ("nlct.bib" in this example), I %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 %when it compares strings, which means I can not only sort by %year, but also by month\footnote{as long as I haven't put anything %before the month name in the bibliography file, e.g.\ %\mbox{\texttt{month = "2~" \# apr}} will sort by 2~03, instead of %03}. % %\item Once I have loaded and sorted my database, I can then %display it using \cs{DTLbibliography}. This uses the style %given by the \sty{databib} \pkgopt[databib]{style} package option, %or the \cs{DTLbibliographystyle} command, both of which are %described in \autoref{sec:bibstyle}. % %\item I have filtered the bibliography using the optional %argument\linebreak "[\DTLbibfieldisge{Year}{2000}]", which checks if the %year field of the current entry is greater than or equal to %2000. (Note that if an entry has no year field, the condition %evaluates to false, and the entry will be omitted from the %bibliography.) % %\item If the bibliography database is large, sorting and creating %the bibliography may take a while. Using \sty{databib} is much %slower than using a standard \BibTeX\ style file. %\end{enumerate} %\end{example} % %\begin{example}{Creating a list of my 10 most recent %publications}{ex:top10bib} %Suppose now my boss has asked me to produce a list of my ten most %recent publications (in reverse chronological order). %As in the previous example, I have a file called "nlct.bib" %which contains all my publications. I can create the required %document as follows: %\begin{verbatim} %\documentclass{article} %\usepackage{databib} %\begin{document} %\nocite{*} %\DTLloadbbl{mybib}{nlct} %\DTLsort{Year=descending,Month=descending}{mybib} %\DTLbibliography[\value{DTLbibrow}<11]{mybib} %\end{document} %\end{verbatim} %\end{example} % %\subsection{Changing the bibliography style} %\label{sec:bibstyle} %The style of the bibliography produced using \cs{DTLbibliography} %depends on the \pkgopt[databib]{style} %package option, or can be set using %\begin{definition}[\DescribeMacro{\DTLbibliographystyle}]% %\cs{DTLbibliographystyle}\marg{style} %\end{definition} %Note that this is \emph{not} the same as \cs{bibliographystyle}, %as the \sty{databib} package uses its custom \texttt{databib.bst} %bibliography style file. % %Example: %\begin{verbatim} %\usepackage[style=plain]{databib} %\end{verbatim} %This sets the plain bibliography style. This is, in fact, the %default style, so it need not be specified. % %Available styles are: "plain", "abbrv" and "alpha". These are similar to the %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}). % %\subsubsection{Modifying an existing style} %\label{sec:modbibstyle} % %This section describes some of the commands which are used to %format the bibliography. You can choose whichever predefined %style best fits your required style, and then modify the commands %described in this section. A description of the remaining %commands not listed in this section can be found in %\autoref{sec:src:bibnames}, \autoref{sec:src:displaybib} %and \autoref{sec:src:bibstyle}. % %\begin{definition}[\DescribeMacro{\DTLformatauthor}]% %\cs{DTLformatauthor}\marg{von part}\marg{surname}\marg{jr part}\marg{forenames} %\end{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, %respectively. The list of authors and editors are stored in %the \sty{databib} database as a comma separated list of %\marg{von part}\marg{surname}\marg{jr part}\marg{forenames} %data. This ensures that when you sort on the Author or Editor %field, the names will be sorted by the first author or editor's %surname. % %Within \cs{DTLformatauthor} and \cs{DTLformateditor}, you may %use the following commands: %\begin{definition}[\DescribeMacro{\DTLformatforenames}]% %\cs{DTLformatforenames}\marg{forenames} %\end{definition} %This is used by the "plain" style to display the author's %forenames\footnote{It also checks %whether \meta{forenames} ends with a full stop using %\cs{DTLcheckendsperiod} to prevent a sentence ending full stop %from following an abbreviation full stop}. % %\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}). %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: %\begin{verbatim} %author = "{\'E}lise {\"E}awyn Edwards", %\end{verbatim} %The initials are formed using \cs{DTLstoreinitials} described %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}). % %\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}}. % %\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. %\begin{definition}[\DescribeMacro{\DTLformatjr}]% %\cs{DTLformatjr}\marg{jr part} %\end{definition} %If the \meta{jr part} is empty, this command displays nothing, %otherwise it displays a comma followed by its argument\footnote %{again, it also checks \meta{jr part} to determine if it ends %with a full stop}. % %For example, suppose you want the author's surname to appear %first in small capitals, followed by a comma and the forenames. This %can be achieved by redefining \cs{DTLformatauthor} as follows: %\begin{verbatim} %\renewcommand*{\DTLformatauthor}[4]{% %\textsc{\DTLformatvon{#1}% %\DTLformatsurname{#2}\DTLformatjr{#3}}, %\DTLformatforenames{#4}% %} %\end{verbatim} % %\begin{definition}[\DescribeCounter{DTLmaxauthors}] %\ctrfmt{DTLmaxauthors} %\end{definition} %The counter \ctrfmt{DTLmaxauthors} is used to determine the %maximum number of authors to display for a given entry. If the %entry's author list contains more than that number of authors, %\cs{etalname} is used, the definition of which is given in %\autoref{sec:src:bibnames}. The default value of %\ctrfmt{DTLmaxauthors} is \theDTLmaxauthors. % %\begin{definition}[\DescribeCounter{DTLmaxeditors}] %\ctrfmt{DTLmaxeditors} %\end{definition} %The \ctrfmt{DTLmaxeditors} counter is analogous to the %\ctrfmt{DTLmaxauthors} counter. It is used to determine the %maximum number of editor names to display. The default value %of \ctrfmt{DTLmaxeditors} is \theDTLmaxeditors. % %\DescribeMacro{\DTLandlast} %Within a list of author or editor names, \cs{DTLandlast} is %used between the last two names, otherwise %\DescribeMacro{\DTLandnotlast}\cs{DTLandnotlast} is used between %names. %However, if there are only two author or editor names, %\DescribeMacro{\DTLtwoand}\cs{DTLtwoand} %is used instead of \cs{DTLandlast}. % %\DescribeMacro{\DTLendbibitem} %The command \cs{DTLendbibitem} is a hook provided to add %additional information at the end of each bibliography item. %This does nothing by default, but if you want to display the %additional fields provided by the "databib.bst" style file, %you can redefine \cs{DTLendbibitem} so that it displays a %particular field, if it is defined. Within this command, you %may use the commands \cs{DTLbibfield}, \cs{DTLifbibfieldexist} %and \cs{DTLifanybibfieldexist}, which are described in %\autoref{sec:foreachbib}. For example, if you have used the %"abstract" field in any of your entries, you can display the %abstract as follows: %\begin{verbatim} %\renewcommand{\DTLendbibitem}{% %\DTLifbibfieldexists{Abstract}{\DTLpar\textbf{Abstract} %\begin{quote}\DTLbibfield{Abstract}\end{quote}}{}} %\end{verbatim} %(Note that \cs{DTLpar} needs to be used instead of %\cs{par}.) % %\begin{example}{Compact bibliography}{ex:compactbib} %Suppose I don't have much space in my document, and I need to %produce a compact bibliography. Firstly, I can use the %bibliography style "abbrv", either through the package option: %\begin{verbatim} %\usepackage[style=abbrv]{databib} %\end{verbatim} %or using: %\begin{verbatim} %\DTLbibliographystyle{abbrv} %\end{verbatim} %Once I have set the style, I can further modify it thus: %\begin{verbatim} %\renewcommand*{\andname}{\&} %\renewcommand*{\editorname}{ed.} %\renewcommand*{\editorsname}{eds.} %\renewcommand*{\pagesname}{pp.} %\renewcommand*{\pagename}{p.} %\renewcommand*{\volumename}{vol.} %\renewcommand*{\numbername}{no.} %\renewcommand*{\editionname}{ed.} %\renewcommand*{\techreportname}{T.R.} %\renewcommand*{\mscthesisname}{MSc thesis} %\end{verbatim} %Now I can load\footnote{I can load the bibliography earlier, but %obviously the bibliography should only be displayed after the %bibliography styles have been set, otherwise they will have no %effect} and display the bibliography: %\begin{verbatim} % % create a database called mybib from the information given % % in mybib1.bib and mybib2.bib % \DTLloadbbl{mybib}{mybib1,mybib2} % % display the bibliography % \DTLbibliography{mybib} %\end{verbatim} %\end{example} % %\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 %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 %co-authors. I can do this by redefining \cs{DTLformatauthor} %so that it checks if the given surname matches mine. (This %assumes that none of the other co-author's share my surname.) %\begin{verbatim} %\renewcommand*{\DTLformatauthor}[4]{% %{\DTLifstringeq{#2}{Talbot}{\bfseries }{}% %\DTLformatforenames{#4} %\DTLformatvon{#1}% %\DTLformatsurname{#2}% %\DTLformatjr{#3}}} %\end{verbatim} %Notes: %\begin{enumerate} %\item I have used \cs{DTLifstringeq} (described in %\autoref{sec:ifconditions}) to perform the string comparison. %\item If one or more of my co-authors shared the same surname as %me, I would also have had to check the first name, however there %is regrettably a lack of consistency in my \ext{bib} file when %it comes to my forenames. Sometimes my name is given as %\texttt{Nicola L. C. Talbot}, sometimes the middle initials %are omitted, \texttt{Nicola Talbot}, or sometimes, just initials %are used, \texttt{N. L. C. Talbot}. This can cause problems %when checking the forenames, but as long as the other authors %who share the same surname as me, don't also share the same %first initial, I can use \cs{DTLifStartsWith} or \cs{DTLisPrefix}, %which are described in \autoref{sec:ifconditions} and %\autoref{sec:ifthen}, respectively. Using the first approach %I can do: %\begin{verbatim} %\renewcommand*{\DTLformatauthor}[4]{% %{\DTLifstringeq{#2}{Talbot}{\DTLifStartsWith{#4}{N}{\bfseries }{}}{}% %\DTLformatforenames{#4} %\DTLformatvon{#1}% %\DTLformatsurname{#2}% %\DTLformatjr{#3}}} %\end{verbatim} %Using the second approach I can do: %\begin{verbatim} %\renewcommand*{\DTLformatauthor}[4]{% %{\ifthenelse{\DTLiseq{#2}{Talbot}\and %\DTLisPrefix{#4}{N}}{\bfseries }{}% %\DTLformatforenames{#4} %\DTLformatvon{#1}% %\DTLformatsurname{#2}% %\DTLformatjr{#3}}} %\end{verbatim} % %\item I have used a group to localise the effect of \cs{bfseries}. %\end{enumerate} %\end{example} % %\subsection{Iterating through a %\texorpdfstring{\sty{databib}}{databib} database} %\label{sec:foreachbib} % %\cs{DTLbibliography} (described in \autoref{sec:thebib}) may still %not meet your needs. For example, you may be required %to list journal papers and conference proceedings in separate %sections. In which case, you may find it easier to iterate through %the bibliography using: %\begin{definition}[\DescribeMacro{\DTLforeachbib}]% %\cs{DTLforeachbib}\oarg{condition}\marg{db name}\marg{text} %\end{definition} %\begin{definition}[\DescribeMacro{\DTLforeachbib*}]% %\cs{DTLforeachbib*}\oarg{condition}\marg{db name}\marg{text} %\end{definition} %This iterates through the \sty{databib} database called %\meta{db name} and does \meta{text} if \meta{condition} is met. %As with \cs{DTLforeach}, the starred version is read-only. % %For each row of the database, the following commands are set: %\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}). % %\item \cs{DBIBentrytype} \DescribeMacro{\DBIBentrytype}This %is the current entry type, and will be one of: "article", "book", %"booklet", "inbook", "incollection", "inproceedings", %"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"). %\end{itemize} % %The remaining fields may be accessed using: %\begin{definition}[\DescribeMacro{\DTLbibfield}]% %\cs{DTLbibfield}\marg{field label} %\end{definition}\noindent %where \meta{field label} may be one of: "Address", "Author", %"BookTitle", "Chapter", "Edition", "Editor", "HowPublished", %"Institution", "Journal", "Key", "Month", "Note", "Number", %"Organization", "Pages", "Publisher", "School", "Series", %"Title", "Type", "Volume", "Year", "ISBN", "DOI", "PubMed", %"Abstract" or "Url". % %You can determine if a field exists for a given entry using %\begin{definition}[\DescribeMacro{\DTLifbibfieldexists}]% %\cs{DTLifbibfieldexists}\marg{field label}\marg{true part}\marg{false %part} %\end{definition} %If the field given by \meta{field label} exists for the current %bibliography entry, it does \meta{true part}, otherwise it %does \meta{false part}. % %\begin{definition}[\DescribeMacro{\DTLifbibanyfieldexists}]% %\cs{DTLifanybibfieldexists}\marg{field label list}\marg{true %part}\marg{false part} %\end{definition} %This is similar to \cs{DTLifbibfieldexists} except that the %first argument is a list of field names. If one or more of %the fields given in \meta{field label list} exists for the %current bibliography item, this does \meta{true part}, otherwise %it does \meta{false part}. % %\begin{definition}[\DescribeMacro{\DTLformatbibentry}]% %\cs{DTLformatbibentry} %\end{definition} %This formats the bibliography entry for the current row. It %checks for the existence of the command %\cs{DTLformat}\meta{entry type}, where \meta{entry type} %is given by \cs{DBIBentrytype}. These commands are defined %by the bibliography style. % %\begin{definition}[\DescribeMacro{\DTLcomputewidestbibentry}]% %\cs{DTLcomputewidestbibentry}\marg{conditions}\marg{db %name}\marg{bib label}\marg{cmd} %\end{definition} %This computes the widest bibliography entry over all entries %satisfying \meta{conditions} in the database \meta{db name}, %where the label is given by \meta{bib label}, and the result %is stored in \meta{cmd}, which may then be used in the %argument of the \env{thebibliography} environment. % %The counter \desctr{DTLbibrow} keeps track of the current %bibliography entry. This is reset at the start of each %\cs{DTLforeachbib} and is incremented if \meta{conditions} %is met. % %Within the optional argument \meta{condition}, you may use any of the %commands that may be used within the optional argument of %\cs{DTLbibliography}, described in \autoref{sec:thebib}. % %\begin{example}{Separate List of Journals and Conference Papers}{ex:jcbib} %Suppose now my boss has decided that I need to produce a list %of all my publications, but they need to be separated so that %all the journal papers appear in one section, and all the %conference papers appear in another section. The journal papers %need to be labelled [J1], [J2] and so on, while the conference %papers need to be labelled [C1], [C2] and so on. (My boss isn't %interested in any of my other publications!) Again, all my %publications are stored in the \BibTeX\ database "nlct.bib". The %following creates the required document: %\begin{verbatim} %\documentclass{article} %\usepackage{databib} %\begin{document} %\nocite{*} %\DTLloadbbl{mybib}{nlct} % %\renewcommand*{\refname}{Journal Papers} %\DTLcomputewidestbibentry{\equal{\DBIBentrytype}{article}} %{mybib}{J\theDTLbibrow}{\widest} % %\begin{thebibliography}{\widest} %\DTLforeachbibentry[\equal{\DBIBentrytype}{article}]{mybib}{% %\bibitem[J\theDTLbibrow]{\DBIBcitekey} \DTLformatbibentry} %\end{thebibliography} % %\renewcommand*{\refname}{Conference Papers} %\DTLcomputewidestbibentry{\equal{\DBIBentrytype}{inproceedings}} %{mybib}{C\theDTLbibrow}{\widest} % %\begin{thebibliography}{\widest} %\DTLforeachbibentry[\equal{\DBIBentrytype}{inproceedings}]{mybib}{% %\bibitem[C\theDTLbibrow]{\DBIBcitekey} \DTLformatbibentry} %\end{thebibliography} % %\end{document} %\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. % %\section{Referencing People (\sty{person} package)} %\label{sec:person} % %Sometimes when mail-merging, it may be necessary to reference a %person by their pronoun which can lead to the cumbersome and %impersonal ``he/she'' construct. The \sty{person} package %allows you to define a person by their full name, familiar name and %gender. You can then use the commands described in %\autoref{sec:refperson} to produce the appropriate pronoun. % %This can also be useful for other types of documents, such as an %order of service for a baptism or funeral. Since the %document is much the same from one person to the next, documents of %this nature are frequently simply copied and a search and replace %edit is used to change the relevant text. However this can lead to %errors (especially if the previous person's name was Mary!) With %the \sty{person} package, you need only change the definition of %the person by modifying the arguments of \cs{newperson}. % %\subsection{Defining and Undefining People} % %A person is defined (globally) using the command: %\begin{definition}[\DescribeMacro{\newperson}] %\cs{newperson}\oarg{label}\marg{full name}\marg{familiar name}\marg{gender} %\end{definition} %The optional argument is a unique label identifying this person, %in the event that there is more than one person. If \meta{label} %is omitted \texttt{anon} is used. (This is also the case for %subsequent commands that take an optional label.) %The gender may be any of those given by %\begin{definition}[\DescribeMacro{\malelabels}] %\cs{malelabels} %\end{definition} %or %\begin{definition}[\DescribeMacro{\femalelabels}] %\cs{femalelabels} %\end{definition} %The default definition of \cs{malelabels} is \texttt{\malelabels} %and the default definition of \cs{femalelabels} is %\texttt{\femalelabels}. You can add extra identifiers using %\begin{definition}[\DescribeMacro{\addmalelabel}] %\cs{addmalelabel}\marg{identifier} %\end{definition} %or %\begin{definition}[\DescribeMacro{\addfemalelabel}] %\cs{addfemalelabel}\marg{identifier} %\end{definition} %For example: %\begin{verbatim} %\addmalelabel{boy} %\addfemalelabel{girl} %\end{verbatim} % %The total number of defined people is given by: %\begin{definition}[\DescribeMacro{\thepeople}] %\cs{thepeople} %\end{definition} % %A person can be undefined using: %\begin{definition}[\DescribeMacro{\removeperson}] %\cs{removeperson}\oarg{label} %\end{definition} %where the person is given by \meta{label}. % %If more than one person has been defined, they can all be %removed using: %\begin{definition}[\DescribeMacro{\removeallpeople}] %\cs{removeallpeople} %\end{definition} %or you can remove a subset using: %\begin{definition}[\DescribeMacro{\removepeople}] %\cs{removepeople}\marg{list} %\end{definition} %where \meta{list} is a comma-separated list of labels. % %\subsection{Displaying Information} %\label{sec:refperson} % %Once a person has been defined, you can display their name using: %\begin{definition}[\DescribeMacro{\personfullname}] %\cs{personfullname}\oarg{label} %\end{definition} %where \meta{label} is the unique label used in the optional %argument to \cs{newperson}. The person's familiar name is displayed %using: %\begin{definition}[\DescribeMacro{\personname}] %\cs{personname}\oarg{label} %\end{definition} %The person's pronoun (``he'' or ``she'') is displayed using: %\begin{definition}[\DescribeMacro{\personpronoun}] %\cs{personpronoun}\oarg{label} %\end{definition} %The objective pronoun (``him'' or ``her'') is displayed using: %\begin{definition}[\DescribeMacro{\personobjpronoun}] %\cs{personobjpronoun}\oarg{label} %\end{definition} %The possessive adjective (``his'' or ``her'') is displayed using: %\begin{definition}[\DescribeMacro{\personpossadj}] %\cs{personpossadj}\oarg{label} %\end{definition} %The possessive pronoun ``his'' or ``hers'' is displayed using: %\begin{definition}[\DescribeMacro{\personposspronoun}] %\cs{personposspronoun}\oarg{label} %\end{definition} %The person's relationship to their parent (``son'' or ``daughter'') %is displayed using: %\begin{definition}[\DescribeMacro{\personchild}] %\cs{personchild}\oarg{label} %\end{definition} %The person's relationship to their child (``mother'' or ``father'') %is displayed using: %\begin{definition}[\DescribeMacro{\personparent}] %\cs{personparent}\oarg{label} %\end{definition} %The person's relationship to their sibling (``brother'' or %``sister'') is displayed using: %\begin{definition}[\DescribeMacro{\personsibling}] %\cs{personsibling}\oarg{label} %\end{definition} % %If the word occurs at the start of a sentence, you will need one %of the following commands, which are as the above, except the %first letter is converted to upper case: %\begin{definition}[\DescribeMacro{\Personpronoun}] %\cs{Personpronoun}\oarg{label} %\end{definition} %\begin{definition}[\DescribeMacro{\Personobjpronoun}] %\cs{Personobjpronoun}\oarg{label} %\end{definition} %\begin{definition}[\DescribeMacro{\Personpossadj}] %\cs{Personpossadj}\oarg{label} %\end{definition} %\begin{definition}[\DescribeMacro{\Personposspronoun}] %\cs{Personposspronoun}\oarg{label} %\end{definition} %\begin{definition}[\DescribeMacro{\Personchild}] %\cs{Personchild}\oarg{label} %\end{definition} %\begin{definition}[\DescribeMacro{\Personparent}] %\cs{Personparent}\oarg{label} %\end{definition} %\begin{definition}[\DescribeMacro{\Personsibling}] %\cs{Personsibling}\oarg{label} %\end{definition} % %\begin{example}{Order of Service (Memorial)}{ex:memorial} %This example is for a memorial order of service. % %\begin{verbatim} %\documentclass{article} % %\usepackage{person} % %\newperson{Jane Doe}{Jane}{female} % %\begin{document} %\begin{center} %\Large %In Memory of \personfullname %\end{center} % %We are gathered here to remember our \personsibling\ \personname. %\Personpronoun\ will be much missed, and \personpossadj\ %family are in our prayers. %\end{document} %\end{verbatim} % %\newperson{Jane Doe}{Jane}{female} %\begin{center} %\Large %In Memory of \personfullname %\end{center} % %We are gathered here to remember our \personsibling\ \personname. %\Personpronoun\ will be much missed, and \personpossadj\ %family are in our prayers. %\removeperson % %\end{example} % %If there is more than one person, you will need to use the %optional argument \meta{label} to \cs{newperson} to uniquely %identify each person. You can then list all of the people's full %or familiar names using: %\begin{definition}[\DescribeMacro{\peoplefullname}] %\cs{peoplefullname} %\end{definition} %\begin{definition}[\DescribeMacro{\peoplename}] %\cs{peoplename} %\end{definition} %Note that if there is only one person defined, these commands behave %the same as \cs{personfullname}\oarg{label} and %\cs{personname}[\meta{label}]. % %Similarly for the pronouns: %\begin{definition}[\DescribeMacro{\peoplepronoun}] %\cs{peoplepronoun} %\end{definition} %\begin{definition}[\DescribeMacro{\Peoplepronoun}] %\cs{Peoplepronoun} %\end{definition} %\begin{definition}[\DescribeMacro{\peopleobjpronoun}] %\cs{peopleobjpronoun} %\end{definition} %\begin{definition}[\DescribeMacro{\Peopleobjpronoun}] %\cs{Peopleobjpronoun} %\end{definition} %\begin{definition}[\DescribeMacro{\peoplepossadj}] %\cs{peoplepossadj} %\end{definition} %\begin{definition}[\DescribeMacro{\Peoplepossadj}] %\cs{Peoplepossadj} %\end{definition} %\begin{definition}[\DescribeMacro{\peopleposspronoun}] %\cs{peopleposspronoun} %\end{definition} %\begin{definition}[\DescribeMacro{\Peopleposspronoun}] %\cs{Peopleposspronoun} %\end{definition} %where, again, if only one person has been defined, each of these %commands is equivalent to %\cs{person}\ldots\oarg{label} or %\cs{Person}\ldots\oarg{label}. If more than %one person has been defined, these commands will display %they/them/their/theirs or They/Them/Their/Theirs, as appropriate. % %Likewise for relationship commands: %\begin{definition}[\DescribeMacro{\peoplechild}] %\cs{peoplechild} %\end{definition} %\begin{definition}[\DescribeMacro{\Peoplechild}] %\cs{Peoplechild} %\end{definition} %\begin{definition}[\DescribeMacro{\peopleparent}] %\cs{peopleparent} %\end{definition} %\begin{definition}[\DescribeMacro{\Peopleparent}] %\cs{Peopleparent} %\end{definition} %\begin{definition}[\DescribeMacro{\peoplesibling}] %\cs{peoplesibling} %\end{definition} %\begin{definition}[\DescribeMacro{\Peoplesibling}] %\cs{Peoplesibling} %\end{definition} % %\begin{example}{Order of Service (Baptism)}{ex:baptism} %In this example two people are defined. %\begin{verbatim} %\documentclass{article} % %\usepackage{person} % %\newperson[john]{John Joseph}{John}{male} %\newperson[jane]{Jane Mary}{Jane}{female} % %\begin{document} %\begin{center} %\Large %Baptism of \peoplefullname. %\end{center} % %Today we welcome \peoplename\ into God's family, may He guide %and protect \peopleobjpronoun. %\end{document} %\end{verbatim} % %This is produces the following text: % %\newperson[john]{John Joseph}{John}{male} %\newperson[jane]{Jane Mary}{Jane}{female} % %\begin{center} %\Large %Baptism of \peoplefullname. %\end{center} % %Today we welcome \peoplename\ into God's family, may He guide %and protect \peopleobjpronoun. %\removeallpeople %\end{example} % %\begin{example}{Mail Merging Using Appropriate Gender}{ex:personmerge} %In this example I have a CSV file called \texttt{students.csv} %containing the following: %\begin{verbatim} %FirstName,Surname,Gender,Parent,Address %John,"Smith, Jr",M,Mr and Mrs Smith,1 The Street\\Newtown %Jane,Brown,F,Ms Brown,2 The Avenue\\Oldtown %Andy,Brown,male,Mr Brown and Miss Sepia,3 The Road\\Newtown %Z\"oe,Adams,f,Mr and Mrs Adams,5 The Street\\Newtown %Roger,Brady,m,Mrs Brady,6 The Avenue\\Oldtowm %Clare,Vernon,female,Mr Vernon,7 The Close\\Anytown %\end{verbatim} %Suppose I have to write to each student's parents regarding their %child. I can load the information using \ics{DTLloaddb} (described %in \autoref{sec:loaddb}). I can then iterate through the database %and define the student as a person and use the commands defined in %the \sty{person} package to display the correct gender related text. %I could give each person a unique label based on the row count %(\ics{DTLcurrentindex}), but since I don't need to reuse the %information, I can use the default "anon" label and undefine the %person when no longer required. % %Note that in the CSV file, the gender label isn't consistent. %For some students the gender is identified by a single letter %(``m'' or ``f'') and for others the gender is identified by a %complete word (``male'' or ``female''). There's also no regard %for case. This doesn't matter to \ics{newperson} as all the %identifiers used are listed in \ics{malelabels} and %\ics{femalelabels}. % %The following is an example letter sent to all parents: %\begin{verbatim} %\documentclass{letter} %\usepackage{person} % %% load student information from file "students.csv" %\DTLloaddb{students}{students.csv} %\begin{document} %% Iterate through the student database: %\DTLforeach{students}{\FirstName=FirstName,\Surname=Surname,% %\Gender=Gender,\Parent=Parent,\Address=Address}{% %% Define "anon": % \newperson{\FirstName\space\Surname}{\FirstName}{\Gender}% %% Do the letter: % \begin{letter}{\Parent\\\Address} % \opening{Dear \Parent} % Your \personchild\ \personname\ has been awarded a % place. We look forward to seeing \personobjpronoun\ % on \personpossadj\ arrival. % \closing{Yours Sincerely} % \end{letter} %% Undefine "anon": % \removeperson %} %\end{document} %\end{verbatim} % %The body of the first letter appears as follows: %\newperson{John Smith Jr}{John}{m} %\par\vskip\baselineskip % % Your \personchild\ \personname\ has been awarded a % place. We look forward to seeing \personobjpronoun\ % on \personpossadj\ arrival. % %\removeperson %\par\vskip\baselineskip %Whereas the body of the second letter appears as follows: %\newperson{Jane Brown}{Jane}{f} %\par\vskip\baselineskip % % Your \personchild\ \personname\ has been awarded a % place. We look forward to seeing \personobjpronoun\ % on \personpossadj\ arrival. % %\removeperson %\end{example} % %\subsection{Advanced Commands} % %This section describes additional commands provided by the %\sty{person} package. More detail can be found in %\autoref{sec:code:person}. % %\subsubsection{Conditionals} % %\begin{definition}[\DescribeMacro{\ifpersonexists}] %\cs{ifpersonexists}\marg{label}\marg{true part}\marg{false part} %\end{definition} %Tests if the person identified by \meta{label} has been defined. %If true, do \meta{true part} otherwise do \meta{false part}. % %\begin{definition}[\DescribeMacro{\ifmale}] %\cs{ifmale}\marg{label}\marg{true part}\marg{false part} %\end{definition} %Test if the person identified by \meta{label} is male. %If true, do \meta{true part} otherwise do \meta{false part}. % %\begin{definition}[\DescribeMacro{\iffemale}] %\cs{iffemale}\marg{label}\marg{true part}\marg{false part} %\end{definition} %Test if the person identified by \meta{label} is female. %If true, do \meta{true part} otherwise do \meta{false part}. % %\begin{definition}[\DescribeMacro{\ifallmale}] %\cs{ifallmale}\oarg{label list}\marg{true part}\marg{false part} %\end{definition} %Tests if all the people listed in \meta{label list} are male. %If true, do \meta{true part} otherwise do \meta{false part}. %If \meta{label list} is omitted, applied to all defined people. %\begin{definition}[\DescribeMacro{\ifallfemale}] %\cs{ifallfemale}\oarg{label list}\marg{true part}\marg{false part} %\end{definition} %Likewise to test if all the people tested are female. % %To determine if a string is an allowed male label: %\begin{definition}[\DescribeMacro{\ifmalelabel}] %\cs{ifmalelabel}\marg{identifier}\marg{true part}\marg{false part} %\end{definition} %where \meta{identifier} is the string to be tested. If true, do %\meta{true part} otherwise do \meta{false part}. %For example: %\begin{verbatim} %\def\gender{M} %\ifmalelabel{\gender}{male}{not male} %\end{verbatim} %Similarly to for an allowed female label: %\begin{definition}[\DescribeMacro{\iffemalelabel}] %\cs{iffemalelabel}\marg{identifier}\marg{true part}\marg{false part} %\end{definition} %For example: %\begin{verbatim} %\ifmalelabel{\gender}{Male}{% % \iffemalelabel{\gender}{Female}% % {Undefined Gender}% %} %\end{verbatim} % %\subsubsection{Iterating Through Defined People} % %You can iterate through all defined people using: %\begin{definition}[\DescribeMacro{\foreachperson}] %\cs{foreachperson}(\meta{name cs},\meta{full name cs},\meta{gender cs},\meta{label cs})\cs{do}\marg{body} %\end{definition} %At each iteration, \meta{name cs}, \meta{full name cs}, %\meta{gender cs} and \meta{label cs} are set to the current person's %name, full name, gender and label, respectively. (These arguments %must all be command names.) Note that the gender is set to %the definition of \DescribeMacro{\malename}\cs{malename} or %\DescribeMacro{\femalename}\cs{femalename}, as appropriate.\footnote{Predefined names provided by the \sty{person} package are described %in \autoref{sec:code:peoplenames}.} Once these %commands are set, \meta{body} is applied. % %If you only want to iterate through a subset of defined people, %you can use: %\begin{definition} %\cs{foreachperson}(\meta{name cs},\meta{full name cs},\meta{gender cs},\meta{label cs})\cs{in}\marg{list}\cs{do}\marg{body} %\end{definition} %where \meta{list} is a comma-separated list of labels. % %\subsubsection{Accessing Individual Information} % %\begin{definition}[\DescribeMacro{\getpersongender}] %\cs{getpersongender}\marg{cs}\marg{label} %\end{definition} %Gets the gender of the person identified by \meta{label} and %stores in \meta{cs} (which must be a command name). This %sets \meta{cs} to the definition of \ics{malename} or %\ics{femalename} as appropriate. % %\begin{definition}[\DescribeMacro{\getpersonname}] %\cs{getpersonname}\marg{cs}\marg{label} %\end{definition} %Gets the name of the person identified by \meta{label} and %stores in \meta{cs} (which must be a command name). % %\begin{definition}[\DescribeMacro{\getpersonfullname}] %\cs{getpersonfullname}\marg{cs}\marg{label} %\end{definition} %Gets the full name of the person identified by \meta{label} and %stores in \meta{cs} (which must be a command name). % % \StopEventually{\clearpage\phantomsection %\addcontentsline{toc}{section}{\refname} % \DTLbibliography{docbib} %\addcontentsline{toc}{section}{Acknowledgements} %\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 %\clearpage %\phantomsection %\addcontentsline{toc}{section}{Index}\PrintIndex %} % % % %\section{datatool.sty} %\iffalse % \begin{macrocode} %<*datatool.sty> % \end{macrocode} %\fi %\label{sec:code:datatool} %\subsection{Package Declaration} % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{datatool}[2009/11/15 v2.03 (NLCT)] % \end{macrocode} % Load required packages: % \begin{macrocode} \RequirePackage{xkeyval} \RequirePackage{ifthen} \RequirePackage{xfor} \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} % The data separator character (comma by default) is stored in % \cs{@dtl@separator}. % This is the separator used in external data files, not in the % \LaTeX\ code, which always uses a comma separator. % \begin{macrocode} \newcommand*{\@dtl@separator}{,} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLsetseparator} %\begin{definition} %\cs{DTLsetseparator}\marg{char} %\end{definition} % The sets \cs{@dtl@separator}, and constructs the relevent macros % that require this character to be hardcoded into their definition. % \begin{macrocode} \newcommand*{\DTLsetseparator}[1]{% \renewcommand*{\@dtl@separator}{#1}% \@dtl@construct@lopoffs } % \end{macrocode} %\end{macro} %\begin{macro}{\DTLsettabseparator} %\cs{DTLsettabseparator} makes it easier to set a tab separator. % \begin{macrocode} \begingroup \catcode`\ 12 \gdef\DTLsettabseparator{% \catcode`\ 12 \DTLsetseparator{ }% } \endgroup % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@delimiter} % The data delimiter character (double quote by default) is stored % in \cs{@dtl@delimiter}. This is used in external data files, not % in the \LaTeX\ code. % \begin{macrocode} \begingroup \catcode`\"12\relax \gdef\@dtl@delimiter{"} \endgroup % \end{macrocode} %\end{macro} %\begin{macro}{\DTLsetdelimiter} %\begin{definition} %\cs{DTLsetdelimiter}\marg{char} %\end{definition} % This sets the delimiter. % \begin{macrocode} \newcommand*\DTLsetdelimiter[1]{% \renewcommand*{\@dtl@delimiter}{#1}% \@dtl@construct@lopoffs} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@construct@lopoff} %\begin{definition} %\cs{@dtl@construct@lopoff}\meta{separator char}\meta{delimiter char} %\end{definition} % This defines %\begin{definition} % \cs{@dtl@lopoff}\meta{first element}\meta{sep}\meta{rest of list}\cs{to}\meta{cmd1}\meta{cmd2} %\end{definition}\noindent %for the current separator and delimiter. % \begin{macrocode} \edef\@dtl@construct@lopoff#1#2{% \noexpand\long\noexpand\def\noexpand\@dtl@lopoff#1##1##2\noexpand \to##3##4{% \noexpand\ifx#2##1\noexpand\relax \noexpand\@dtl@qlopoff#1##1##2\noexpand\to##3##4\relax \noexpand\else \noexpand\@dtl@lop@ff#1##1##2\noexpand\to##3##4\relax \noexpand\fi }} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@construct@qlopoff} %\begin{definition} % \cs{@dtl@construct@qlopoff}\meta{separator char}\meta{delimiter char} %\end{definition} % This constructs \cs{@dtl@qlopoff} to be used % when the entry is surrounded by the current delimiter value. % \begin{macrocode} \edef\@dtl@construct@qlopoff#1#2{% \noexpand\long\noexpand\def\noexpand\@dtl@qlopoff#1#2##1#2#1##2\noexpand \to##3##4{% \noexpand\def##4{##1}\noexpand\def##3{#1##2}% }} % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@construct@lop@ff} %\begin{definition} % \cs{@dtl@construct@lop@ff}\meta{separator char} %\end{definition} % This constructs \cs{@dtl@lop@ff} to be used when % the entry isn't surrouded by the delimiter. % \begin{macrocode} \edef\@dtl@construct@lop@ff#1{% \noexpand\long\noexpand\def\noexpand\@dtl@lop@ff#1##1#1##2\noexpand \to##3##4{% \noexpand\def##4{##1}\noexpand\def##3{#1##2}% }} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@construct@lopoffs} %\begin{definition} %\cs{@dtl@construct@lopoffs} %\end{definition} % This constructs all the lopoff macros % using the given separator and delimiter characters. % \begin{macrocode} \newcommand{\@dtl@construct@lopoffs}{% \edef\@dtl@chars{{\@dtl@separator}{\@dtl@delimiter}}% \expandafter\@dtl@construct@lopoff\@dtl@chars \expandafter\@dtl@construct@qlopoff\@dtl@chars \expandafter\@dtl@construct@lop@ff\expandafter{\@dtl@separator}% } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@decimal} % The current decimal character is stored in \cs{@dtl@decimal}. % \begin{macrocode} \newcommand*{\@dtl@decimal}{.} % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@numbergroupchar} % The current number group character is stored in % \cs{@dtl@numbergroupchar}. % \begin{macrocode} \newcommand*{\@dtl@numbergroupchar}{,} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLsetnumberchars} %\begin{definition} %\cs{DTLsetnumberchars}\marg{number group char}\marg{decimal char} %\end{definition} % This sets the decimal character and number group % characters. % \begin{macrocode} \newcommand*{\DTLsetnumberchars}[2]{% \renewcommand*{\@dtl@numbergroupchar}{#1}% \renewcommand*{\@dtl@decimal}{#2}% \@dtl@construct@getnums \@dtl@construct@stripnumgrpchar{#1}} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@construct@getintfrac} %\begin{definition} %\cs{@dtl@construct@getintfrac}\marg{char} %\end{definition} % This constructs the macros for extracting integer and % fractional parts from a real number using the decimal character % \meta{char}. % %\begin{definition} % \cs{DTLconverttodecimal}\marg{num}\marg{cmd} %\end{definition} % \cs{DTLconverttodecimal} will convert locale dependent \meta{num} % a decimal number in a form that can be used in the % macros defined in the \sty{fp} package. The resulting % number is stored in \meta{cmd}. This command has to be redefined % whenever the decimal and number group characters are changed % as they form part of the command definitions. % \begin{macrocode} \edef\@dtl@construct@getintfrac#1{% \noexpand\def\noexpand\@dtl@getintfrac##1#1##2\noexpand\relax{% \noexpand\@dtl@get@intpart{##1}% \noexpand\def\noexpand\@dtl@fracpart{##2}% \noexpand\ifx\noexpand\@empty\noexpand\@dtl@fracpart \noexpand\def\noexpand\@dtl@fracpart{0}% \noexpand\else \noexpand\@dtl@getfracpart##2\noexpand\relax \noexpand\@dtl@choptrailingzeroes{\noexpand\@dtl@fracpart}% \noexpand\fi }% \noexpand\def\noexpand\@dtl@getfracpart##1#1\noexpand\relax{% \noexpand\def\noexpand\@dtl@fracpart{##1}% }% \noexpand\def\noexpand\DTLconverttodecimal##1##2{% \noexpand\dtl@ifsingle{##1}% {\noexpand\expandafter\noexpand\toks@\noexpand\expandafter{##1}% \noexpand\edef\noexpand\@dtl@tmp{\noexpand\the\noexpand\toks@}}% {\noexpand\def\noexpand\@dtl@tmp{##1}}% \noexpand\@dtl@standardize@currency\noexpand\@dtl@tmp \noexpand\ifx\noexpand\@dtl@org@currency\noexpand\@empty \noexpand\else \noexpand\let\noexpand\@dtl@currency\noexpand\@dtl@org@currency \noexpand\fi \noexpand\expandafter \noexpand\@dtl@getintfrac\noexpand\@dtl@tmp#1\noexpand\relax \noexpand\edef##2{\noexpand\@dtl@intpart.\noexpand\@dtl@fracpart}}% } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@construct@getnums} % The following calls the above with the relevant % decimal character: % \begin{macrocode} \newcommand*{\@dtl@construct@getnums}{% \expandafter\@dtl@construct@getintfrac\expandafter{\@dtl@decimal}} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@get@intpart} % The following gets the integer part (adjusting for % repeating +/- signs if necessary.) % Sets \cs{@dtl@intpart}. % \begin{macrocode} \newcommand*{\@dtl@get@intpart}[1]{% \@dtl@tmpcount=1\relax \def\@dtl@intpart{#1}% \ifx\@dtl@intpart\@empty \def\@dtl@intpart{0}% \else \def\@dtl@intpart{}% \@dtl@get@int@part#1.\relax% \fi \ifnum\@dtl@tmpcount<0\relax \edef\@dtl@intpart{-\@dtl@intpart}% \fi \@dtl@strip@numgrpchar{\@dtl@intpart}% } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@get@int@part} % \begin{macrocode} \def\@dtl@get@int@part#1#2\relax{% \def\@dtl@argi{#1}% \def\@dtl@argii{#2}% \ifx\protect#1\relax% \let\@dtl@get@nextintpart=\@dtl@get@int@part \else \expandafter\ifx\@dtl@argi\$% \let\@dtl@get@nextintpart=\@dtl@get@int@part \else \ifx-#1% \multiply\@dtl@tmpcount by -1\relax \let\@dtl@get@nextintpart=\@dtl@get@int@part \else \if\@dtl@argi+% \let\@dtl@get@nextintpart=\@dtl@get@int@part \else \def\@dtl@intpart{#1}% \ifx.\@dtl@argii \let\@dtl@get@nextintpart=\@gobble \else \let\@dtl@get@nextintpart=\@dtl@get@next@intpart \fi \fi \fi \fi \fi \@dtl@get@nextintpart#2\relax } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@get@next@intpart} % \begin{macrocode} \def\@dtl@get@next@intpart#1.\relax{% \edef\@dtl@intpart{\@dtl@intpart#1}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@choptrailingzeroes} %\begin{definition} % \cs{@dtl@choptrailingzeroes}\marg{cmd} %\end{definition} % Chops trailing zeroes from number given by \meta{cmd}. % \begin{macrocode} \newcommand*{\@dtl@choptrailingzeroes}[1]{% \def\@dtl@tmpcpz{}% \expandafter\@dtl@chop@trailingzeroes#1\@nil% \let#1=\@dtl@tmpcpz } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@chop@trailingzeroes} % Trailing zeroes are chopped using a recursive algorithm. % \cs{@dtl@tmpcpz} needs to be set before using this. (The chopped % number is put in this control sequence.) % \begin{macrocode} \def\@dtl@chop@trailingzeroes#1#2\@nil{% \FPifeq{#2}{0}% \edef\@dtl@tmpcpz{\@dtl@tmpcpz#1}% \let\@dtl@chopzeroesnext=\@dtl@gobbletonil \else \edef\@dtl@tmpcpz{\@dtl@tmpcpz#1}% \let\@dtl@chopzeroesnext=\@dtl@chop@trailingzeroes \fi \@dtl@chopzeroesnext#2\@nil } % \end{macrocode} %\end{macro} % No-op macro to end recursion: %\begin{macro}{\@dtl@gobbletonil} % \begin{macrocode} \def\@dtl@gobbletonil#1\@nil{} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@truncatedecimal} %\begin{definition} %\cs{dtl@truncatedecimal}\meta{cmd} %\end{definition} %Truncates decimal given by \meta{cmd} to an integer (assumes the % number is in decimal format with full stop as decimal point.) % \begin{macrocode} \newcommand*{\dtl@truncatedecimal}[1]{% \expandafter\@dtl@truncatedecimal#1.\@nil#1} % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@truncatedecimal} % \begin{macrocode} \def\@dtl@truncatedecimal#1.#2\@nil#3{% \def#3{#1}} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@strip@numgrpchar} %\begin{definition} % \cs{@dtl@strip@numgrpchar}\marg{cmd} %\end{definition} % Strip the number group character from the number given by % \meta{cmd}. % \begin{macrocode} \newcommand*{\@dtl@strip@numgrpchar}[1]{% \def\@dtl@stripped{}% \edef\@dtl@do@stripnumgrpchar{% \noexpand\@@dtl@strip@numgrpchar#1\@dtl@numbergroupchar \noexpand\relax}% \@dtl@do@stripnumgrpchar \let#1=\@dtl@stripped } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@construct@stripnumgrpchar} % The following macro constructs \cs{@@dtl@strip@numgrpchar}. % \begin{macrocode} \edef\@dtl@construct@stripnumgrpchar#1{% \noexpand\def\noexpand\@@dtl@strip@numgrpchar##1#1##2\noexpand\relax{% \noexpand\expandafter\noexpand\toks@\noexpand\expandafter {\noexpand\@dtl@stripped}% \noexpand\edef\noexpand\@dtl@stripped{\noexpand\the\noexpand\toks@ ##1}% \noexpand\def\noexpand\@dtl@tmp{##2}% \noexpand\ifx\noexpand\@dtl@tmp\noexpand\@empty \noexpand\let\noexpand\@dtl@next=\noexpand\relax \noexpand\else \noexpand\let\noexpand\@dtl@next=\noexpand\@@dtl@strip@numgrpchar \noexpand\fi \noexpand\@dtl@next##2\noexpand\relax }% } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLdecimaltolocale} %\begin{definition} % \cs{DTLdecimaltolocale}\marg{number}\marg{cmd} %\end{definition} % Define command to convert a decimal number into the locale % dependent format. Stores result in \meta{cmd} which must be % a control sequence. % \begin{macrocode} \newcommand*{\DTLdecimaltolocale}[2]{% \edef\@dtl@tmpdtl{#1}% \expandafter\@dtl@decimaltolocale\@dtl@tmpdtl.\relax \FPifeq{\@dtl@fracpart}{0}% \edef#2{\@dtl@intpart}% \else \edef#2{\@dtl@intpart\@dtl@decimal\@dtl@fracpart}% \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@decimaltolocale} % Convert the integer part (store in \cs{@dtl@intpart}) % \begin{macrocode} \def\@dtl@decimaltolocale#1.#2\relax{% \@dtl@decimaltolocaleint{#1}% \def\@dtl@fracpart{#2}% \ifx\@dtl@fracpart\@empty \def\@dtl@fracpart{0}% \else \@dtl@decimaltolocalefrac#2\relax \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@decimaltolocaleint} % \begin{macrocode} \def\@dtl@decimaltolocaleint#1{% \@dtl@tmpcount=0\relax \@dtl@countdigits#1.\relax \@dtl@numgrpsepcount=\@dtl@tmpcount\relax \divide\@dtl@numgrpsepcount by 3\relax \multiply\@dtl@numgrpsepcount by 3\relax \advance\@dtl@numgrpsepcount by -\@dtl@tmpcount\relax \ifnum\@dtl@numgrpsepcount<0\relax \advance\@dtl@numgrpsepcount by 3\relax \fi \def\@dtl@intpart{}% \@dtl@decimal@to@localeint#1.\relax } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@countdigits} % Counts the number of digits until "#2" is a full stop. % (increments \cs{@dtl@tmpcount}.) % \begin{macrocode} \def\@dtl@countdigits#1#2\relax{% \advance\@dtl@tmpcount by 1\relax \ifx.#2\relax \let\@dtl@countnext=\@gobble \else \let\@dtl@countnext=\@dtl@countdigits \fi \@dtl@countnext#2\relax } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@decimal@to@localeint} % \begin{macrocode} \def\@dtl@decimal@to@localeint#1#2\relax{% \advance\@dtl@numgrpsepcount by 1\relax \ifx.#2\relax \edef\@dtl@intpart{\@dtl@intpart#1}% \let\@dtl@localeintnext=\@gobble \else \ifnum\@dtl@numgrpsepcount=3\relax \edef\@dtl@intpart{\@dtl@intpart#1\@dtl@numbergroupchar}% \@dtl@numgrpsepcount=0\relax \else \ifnum\@dtl@numgrpsepcount>3\relax \@dtl@numgrpsepcount=0\relax \fi \edef\@dtl@intpart{\@dtl@intpart#1}% \fi \let\@dtl@localeintnext=\@dtl@decimal@to@localeint \fi \@dtl@localeintnext#2\relax } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@decimaltolocalefrac} % Convert the fractional part (store in \cs{@dtl@fracpart}) % \begin{macrocode} % \end{macrocode} \def\@dtl@decimaltolocalefrac#1.\relax{% \def\@dtl@fracpart{#1}% \@dtl@choptrailingzeroes{\@dtl@fracpart}% } %\end{macro} % %\begin{macro}{\DTLdecimaltocurrency} %\begin{definition} % \cs{DTLdecimaltocurrency}\marg{number}\marg{cmd} %\end{definition} % This converts a decimal number into the locale % dependent currency format. Stores result in \meta{cmd} which must be % a control sequence. % \begin{macrocode} \newcommand*{\DTLdecimaltocurrency}[2]{% \edef\@dtl@tmpdtl{#1}% \expandafter\@dtl@decimaltolocale\@dtl@tmpdtl.\relax \dtl@truncatedecimal\@dtl@tmpdtl \@dtl@tmpcount=\@dtl@tmpdtl\relax \expandafter\@dtl@toks\expandafter{\@dtl@currency}% \FPifeq{\@dtl@fracpart}{0}% \ifnum\@dtl@tmpcount<0\relax \@dtl@tmpcount = -\@dtl@tmpcount\relax \edef#2{-\the\@dtl@toks\the\@dtl@tmpcount\@dtl@decimal00}% \else \edef#2{\the\@dtl@toks\@dtl@intpart\@dtl@decimal00}% \fi \else \ifnum\@dtl@tmpcount<0\relax \@dtl@tmpcount = -\@dtl@tmpcount\relax \ifnum\@dtl@fracpart<10\relax \edef#2{-\the\@dtl@toks\number\@dtl@tmpcount \@dtl@decimal\@dtl@fracpart0}% \else \edef#2{-\the\@dtl@toks\number\@dtl@tmpcount \@dtl@decimal\@dtl@fracpart}% \fi \else \ifnum\@dtl@fracpart<10\relax \edef#2{\the\@dtl@toks\@dtl@intpart\@dtl@decimal\@dtl@fracpart0}% \else \edef#2{\the\@dtl@toks\@dtl@intpart\@dtl@decimal\@dtl@fracpart}% \fi \fi \fi } % \end{macrocode} %\end{macro} % % Set the defaults: % \begin{macrocode} \@dtl@construct@lopoffs \@dtl@construct@getnums \expandafter\@dtl@construct@stripnumgrpchar\expandafter {\@dtl@numbergroupchar} % \end{macrocode} % Define key for package option \pkgopt{separator}. % \begin{macrocode} \define@key{datatool.sty}{separator}{% \DTLsetseparator{#1}} % \end{macrocode} % Define key for package option \pkgopt{delimiter}. % \begin{macrocode} \define@key{datatool.sty}{delimiter}{% \DTLsetdelimiter{#1}} % \end{macrocode} % Define key for package option \pkgopt{verbose}. (This also % switches the \sty{fp} messages on/off) % \begin{macrocode} \define@boolkey{datatool.sty}[dtl]{verbose}[true]{% \ifdtlverbose \FPmessagestrue\else \FPmessagesfalse\fi} % \end{macrocode} %\begin{macro}{\dtl@message} %\begin{definition} %\cs{dtl@message}\marg{message string} %\end{definition} % Displays message only if the verbose option is set. % \begin{macrocode} \newcommand*{\dtl@message}[1]{% \ifdtlverbose\typeout{#1}\fi} % \end{macrocode} %\end{macro} % Process package options: % \begin{macrocode} \ProcessOptionsX % \end{macrocode} % %\begin{macro}{\DTLpar} % Many of the commands used by this package are short commands. % This means that you can't use \cs{par} % in the data. To get around this, define the robust command % \cs{DTLpar} to use instead. % \begin{macrocode} \DeclareRobustCommand\DTLpar{\@par} % \end{macrocode} %\end{macro} % % \subsection{Determining Data Types} % The control sequence \cs{@dtl@checknumerical} checks the data % type of its argument, and sets \cs{@dtl@datatype} to 0 if % the argument is a string, 1 if the argument is an integer % or 2 if the argument is a real number. First define % \cs{@dtl@datatype}: %\begin{macro}{\@dtl@datatype} % \begin{macrocode} \newcount\@dtl@datatype % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@tmpcount} % Define temporary count register % \begin{macrocode} \newcount\@dtl@tmpcount % \end{macrocode} %\end{macro} %\begin{macro}{\dtl@tmplength} % Define temporary length register: % \begin{macrocode} \newlength\dtl@tmplength % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@numgrpsepcount} % Define count register to count the digits between the number % group separators. % \begin{macrocode} \newcount\@dtl@numgrpsepcount % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@checknumerical} %\begin{definition} %\cs{@dtl@checknumerical}\marg{arg} %\end{definition} % Checks if \meta{arg} is numerical % (includes decimal numbers, but not scientific notation.) % Sets \cs{@dtl@datatype}, as described above. % \begin{macrocode} \newcommand{\@dtl@checknumerical}[1]{% \@dtl@numgrpsepfalse \def\@dtl@tmp{#1}% \ifx\@empty#1\@empty \@dtl@datatype=0\relax \else \dtl@ifsingle{#1}% {\expandafter\toks@\expandafter{#1}% \edef\@dtl@tmp{\the\toks@}}% {\def\@dtl@tmp{#1}}% \@dtl@tmpcount=0\relax \@dtl@datatype=0\relax \@dtl@numgrpsepcount=2\relax \@dtl@standardize@currency\@dtl@tmp \ifx\@dtl@org@currency\@empty \else \let\@dtl@currency\@dtl@org@currency \fi \expandafter\@dtl@checknumericalstart\@dtl@tmp\@nil\@nil \fi \ifnum\@dtl@numgrpsepcount>-1\relax \if@dtl@numgrpsep \ifnum\@dtl@numgrpsepcount=3\relax \else \@dtl@datatype=0\relax \fi \fi \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@checknumericalstart} % Check first character for checknumerical process to see if % it's a plus or minus sign. % \begin{macrocode} \def\@dtl@checknumericalstart#1#2\@nil\@nil{% \ifx#1\protect \@dtl@checknumericalstart#2\@nil\@nil\relax \else \ifx-#1\relax \def\@dtl@tmp{#2}% \ifx\@empty\@dtl@tmp \@dtl@datatype=0\relax \else \ifnum\@dtl@datatype=0\relax \@dtl@datatype=1\relax \fi \@dtl@checknumericalstart#2\@nil\@nil\relax \fi \else \ifx+#1\relax \def\@dtl@tmp{#2}% \ifx\@empty\@dtl@tmp \@dtl@datatype=0\relax \else \ifnum\@dtl@datatype=0\relax \@dtl@datatype=1\relax \fi \@dtl@checknumericalstart#2\@nil\@nil\relax \fi \else \def\@dtl@tmp{#1}% \ifx#1\$\relax \@dtl@datatype=3\relax \@dtl@checknumericalstart#2\@nil\@nil\relax \else \ifx\@empty\@dtl@tmp \@dtl@datatype=0\relax \else \ifnum\@dtl@datatype=0\relax \@dtl@datatype=1\relax \fi \@dtl@checknumericalloop#1#2\@nil\@nil\relax \fi \fi \fi \fi \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\if@dtl@numgrpsep} % The conditional \cs{if@dtl@numgrpsep} is set the first time % \cs{@dtl@checknumericalloop} encounters the number group % separator. % \begin{macrocode} \newif\if@dtl@numgrpsep % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@ifDigitOrDecimalSep} % Check if argument is either a digit or the decimal separator. %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\@dtl@ifDigitOrDecimalSep}[3]{% \ifx0#1\relax #2% \else \ifx1#1\relax #2% \else \ifx2#1\relax #2% \else \ifx3#1\relax #2% \else \ifx4#1\relax #2% \else \ifx5#1\relax #2% \else \ifx6#1\relax #2% \else \ifx7#1\relax #2% \else \ifx8#1\relax #2% \else \ifx9#1\relax #2% \else \expandafter\ifx\@dtl@decimal#1\relax #2% \else #3% \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@checknumericalloop} % Check numerical loop. This iterates through each character % until \cs{@nil} is reached, or invalid character found. % Increments \cs{@dtl@tmpcount} each time it encounters a % decimal character.\changes{1.01}{2007 Aug 17}{fixed bug caused % by commands occuring within text being tested} % \begin{macrocode} \def\@dtl@checknumericalloop#1#2\@nil{% \def\@dtl@tmp{#1}% \ifx\@nnil\@dtl@tmp\relax \let\@dtl@chcknumnext=\@dtl@checknumericalnoop% \else \@dtl@ifDigitOrDecimalSep{#1}{% \let\@dtl@chcknumnext=\@dtl@checknumericalloop% \expandafter\ifx\@dtl@decimal#1\relax \if@dtl@numgrpsep \ifnum\@dtl@numgrpsepcount=3\relax \@dtl@numgrpsepcount=-1\relax \else \@dtl@datatype=0\relax \let\@dtl@chcknumnext=\@dtl@checknumericalnoop \fi \else \@dtl@numgrpsepcount=-1\relax \fi \else \ifnum\@dtl@numgrpsepcount=-1\relax \else \advance\@dtl@numgrpsepcount by 1\relax \fi \fi }{% \ifx\@dtl@numbergroupchar\@dtl@tmp\relax \@dtl@numgrpseptrue \ifnum\@dtl@numgrpsepcount<3\relax \@dtl@datatype=0\relax \let\@dtl@chcknumnext=\@dtl@checknumericalnoop \else \@dtl@numgrpsepcount=0\relax \fi \else \@dtl@datatype=0\relax \let\@dtl@chcknumnext=\@dtl@checknumericalnoop \fi }% \ifx\@dtl@decimal\@dtl@tmp\relax \ifnum\@dtl@datatype<3\relax \@dtl@datatype=2\relax \fi \advance\@dtl@tmpcount by 1\relax \ifnum\@dtl@tmpcount>1\relax \@dtl@datatype=0\relax \let\@dtl@chcknumnext=\@dtl@checknumericalnoop% \fi \fi \fi \@dtl@chcknumnext#2\@nil } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@checknumericalnoop} % End loop % \begin{macrocode} \def\@dtl@checknumericalnoop#1\@nil#2{} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifnumerical} %\begin{definition} %\cs{DTLifnumerical}\marg{arg}\marg{true part}\marg{false part} %\end{definition} % Tests the first argument, if % its numerical do second argument, otherwise do third argument. % \begin{macrocode} \newcommand{\DTLifnumerical}[3]{% \@dtl@checknumerical{#1}% \ifnum\@dtl@datatype=0\relax#3\else#2\fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifreal} %\begin{definition} %\cs{DTLifreal}\marg{arg}\marg{true part}\marg{false part} %\end{definition} % Tests the first argument, if % it's a real number (not an integer) do second argument, % otherwise do third argument. % \begin{macrocode} \newcommand{\DTLifreal}[3]{% \@dtl@checknumerical{#1}% \ifnum\@dtl@datatype=2\relax #2\else #3\fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifint} %\begin{definition} %\cs{DTLifint}\marg{arg}\marg{true part}\marg{false part} %\end{definition} % Tests the first argument, if % it's an integer do second argument, % otherwise do third argument. % \begin{macrocode} \newcommand{\DTLifint}[3]{% \@dtl@checknumerical{#1}% \ifnum\@dtl@datatype=1\relax #2\else #3\fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifstring} %\begin{definition} %\cs{DTLifstring}\marg{arg}\marg{true part}\marg{false part} %\end{definition} % Tests the first argument, if % it's a string do second argument, % otherwise do third argument. % \begin{macrocode} \newcommand{\DTLifstring}[3]{% \@dtl@checknumerical{#1}% \ifnum\@dtl@datatype=0\relax #2\else #3\fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifcurrency} %\begin{definition} %\cs{DTLifcurrency}\marg{arg}\marg{true part}\marg{false part} %\end{definition} % Tests the first argument, if % it starts with the currency symbol do second argument, % otherwise do third argument. % \begin{macrocode} \newcommand{\DTLifcurrency}[3]{% \@dtl@checknumerical{#1}% \ifnum\@dtl@datatype=3\relax #2\else #3\fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifcurrencyunit} %\begin{definition} %\cs{DTLifcurrencyunit}\marg{arg}\marg{symbol}\marg{true % part}\marg{false part} %\end{definition} % This tests if \meta{arg} is currency, and uses the currency unit % \meta{symbol}. If true do third argument, otherwise % do fourth argument. % \begin{macrocode} \newcommand*{\DTLifcurrencyunit}[4]{% \@dtl@checknumerical{#1}% \ifnum\@dtl@datatype=3\relax \ifthenelse{\equal{\@dtl@org@currency}{#2}}{#3}{#4}% \else #4% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifcasedatatype} %\begin{definition} %\cs{DTLifcasedatatype}\marg{arg}\marg{string case}\marg{int %case}\marg{real case}\marg{currency case} %\end{definition} % If \meta{arg} is a string, do \meta{string case}, if \meta{arg} % is an integer do \meta{int case}, if \meta{arg} is a real number, % do \meta{real case}, if \meta{arg} is currency, do \meta{curreny %case}. % \begin{macrocode} \newcommand{\DTLifcasedatatype}[5]{% \@dtl@checknumerical{#1}% \ifcase\@dtl@datatype #2% string \or #3% integer \or #4% number \or #5% currency \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testbothnumerical} %\begin{definition} %\cs{dtl@testbothnumerical}\marg{arg1}\marg{arg2} %\end{definition} % Tests if both arguments are numerical. This sets % the conditional \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testbothnumerical}[2]{% \dtl@ifsingle{#1}{% \edef\@dtl@tmp{#1}}{% \def\@dtl@tmp{#1}}% \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% \edef\@dtl@firsttype{\number\@dtl@datatype}% \dtl@ifsingle{#2}{% \edef\@dtl@tmp{#2}}{% \def\@dtl@tmp{#2}}% \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% \multiply\@dtl@datatype by \@dtl@firsttype\relax \ifnum\@dtl@datatype>0\relax \@dtl@conditiontrue \else \@dtl@conditionfalse \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifnumlt} %\begin{definition} %\cs{DTLifnumlt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} %\end{definition} % Determines if \marg{num1} $<$ \marg{num2}. Both numbers % need to have the decimal separator changed to a dot % to ensure that it works with \cs{FPiflt} % \begin{macrocode} \newcommand*{\DTLifnumlt}[4]{% \DTLconverttodecimal{#1}{\@dtl@numi}% \DTLconverttodecimal{#2}{\@dtl@numii}% \FPiflt{\@dtl@numi}{\@dtl@numii}% #3% \else #4% \fi } % \end{macrocode} %\end{macro} % %\label{src:dtlcompare} %\begin{macro}{\dtlcompare} %\begin{definition} %\cs{dtlcompare}\marg{count}\marg{string1}\marg{string2} %\end{definition} % Compares \meta{string1} and \meta{string2}, and stores the % result in the count register \meta{count}. The result may be % one of: %\par\vskip\baselineskip\noindent %\begin{tabular}{rl} %-1 & if \meta{string1} is considered to be less than %\meta{string2}\\ %0 & if \meta{string1} is considered to be the same as %\meta{string2}\\ %1 & if \meta{string1} is considered to be greater than %\meta{string2} %\end{tabular} %\par\vskip\baselineskip\noindent %Note that for the purposes of string comparisons, commands within %\meta{string1} and \meta{string2} are ignored, except for %\cs{space} and "~", which are both treated as a space (character %code 32.) The following %examples assume that the count register \cs{mycount} has been %defined as follows: %\begin{verbatim} %\newcount\mycount %\end{verbatim} %\newcount\mycount\par\noindent %\textbf{Examples:} %\begin{enumerate} %\item %\begin{verbatim} %\dtlcompare{\mycount}{Z\"oe}{Zoe}\number\mycount %\end{verbatim} %produces: %\dtlcompare{\mycount}{Z\"oe}{Zoe}\number\mycount, since the accent %command is ignored. % %\item %\begin{verbatim} %\dtlcompare{\mycount}{foo}{Foo}\number\mycount %\end{verbatim} %produces: %\dtlcompare{\mycount}{foo}{Foo}\number\mycount, since the comparison %is case sensitive, however, note the following example: %\item %\begin{verbatim} %\dtlcompare{\mycount}{foo}{\uppercase{f}oo}\number\mycount %\end{verbatim} %which produces: %\dtlcompare{\mycount}{foo}{\uppercase{f}oo}\number\mycount, since %the \cs{uppercase} command is ignored. % %\item You can ``trick'' \cs{dtlcompare} using a command which doesn't %output any text. Suppose you have defined the following command: %\begin{verbatim} %\newcommand*{\noopsort}[1]{} %\end{verbatim} %\providecommand*{\noopsort}[1]{} %then "\noopsort{a}foo" produces the text: \noopsort{a}foo, however %the following %\begin{verbatim} %\dtlcompare{\mycount}{\noopsort{a}foo}{bar}\number\mycount %\end{verbatim} %produces: %\dtlcompare{\mycount}{\noopsort{a}foo}{bar}\number\mycount, %since the command \cs{noopsort} is disregarded when the comparison %is made, so \cs{dtlcompare} just compares "{a}foo" with "bar", and %since "a" is less than "b", the first string is considered to be less %than the second string. % %\item Note that this also means that: %\begin{verbatim} %\def\mystr{abc}% %\dtlcompare{\mycount}{\mystr}{abc}\number\mycount %\end{verbatim} %produces: %\def\mystr{abc}\relax %\dtlcompare{\mycount}{\mystr}{abc}\number\mycount, since the command %\cs{mystr} is disregarded, which means that \cs{dtlcompare} is %comparing an empty string with the string "abc". % %\item Spaces count in the comparison: %\begin{verbatim} %\dtlcompare{\mycount}{ab cd}{abcd}\number\mycount %\end{verbatim} %produces: %\dtlcompare{\mycount}{ab cd}{abcd}\number\mycount, %but sequential spaces are treated as a single space: %\begin{verbatim} %\dtlcompare{\mycount}{ab cd}{ab cd}\number\mycount %\end{verbatim} %produces: %\dtlcompare{\mycount}{ab cd}{ab cd}\number\mycount. % %\item As usual, spaces following command names are ignored, so %\begin{verbatim} %\dtlcompare{\mycount}{ab\relax cd}{ab cd}\number\mycount %\end{verbatim} %produces: %\dtlcompare{\mycount}{ab\relax cd}{ab cd}\number\mycount. % %\item "~" and \cs{space} are considered to be the same as a % space: %\begin{verbatim} %\dtlcompare{\mycount}{ab cd}{ab~cd}\number\mycount %\end{verbatim} %produces: %\dtlcompare{\mycount}{ab cd}{ab~cd}\number\mycount. %\end{enumerate} %\changes{1.01}{2007 Aug 17}{replaces \cs{compare} (no % longer using compare.tex)} % \begin{macrocode} \newcommand*{\dtlcompare}[3]{% \dtl@subnobrsp{#2}{\@dtl@argA}% \dtl@subnobrsp{#3}{\@dtl@argB}% \ifx\@dtl@argA\@empty \ifx\@dtl@argB\@empty #1=0\relax \else #1=-1\relax \fi \else \ifx\@dtl@argB\@empty #1=1\relax \else \DTLsubstituteall{\@dtl@argA}{ }{\space }% \DTLsubstituteall{\@dtl@argB}{ }{\space }% \expandafter\dtl@getfirst\@dtl@argA\end \let\dtl@firstA=\dtl@first \let\dtl@restA=\dtl@rest \expandafter\dtl@getfirst\@dtl@argB\end \let\dtl@firstB=\dtl@first \let\dtl@restB=\dtl@rest \expandafter\dtl@ifsingle\expandafter{\dtl@firstA}{% \expandafter\dtl@ifsingle\expandafter{\dtl@firstB}{% \expandafter\dtl@setcharcode\expandafter{\dtl@firstA}{\dtl@codeA}% \expandafter\dtl@setcharcode\expandafter{\dtl@firstB}{\dtl@codeB}% \ifnum\dtl@codeA=-1\relax \ifnum\dtl@codeB=-1\relax \protected@edef\dtl@donext{% \noexpand\dtlcompare{\noexpand#1}{\dtl@restA}{\dtl@restB}}% \dtl@donext \else \protected@edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext \fi \else \ifnum\dtl@codeB=-1\relax \protected@edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\dtl@firstA\dtl@restA}{\dtl@restB}}% \dtl@donext \else \ifnum\dtl@codeA<\dtl@codeB #1=-1\relax \else \ifnum\dtl@codeA>\dtl@codeB #1=1\relax \else \ifx\dtl@restA\@empty \ifx\dtl@restB\@empty #1=0\relax \else #1=-1\relax \fi \else \ifx\restB\@empty #1=1\relax \else \protected@edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\dtl@restA}{\dtl@restB}}% \dtl@donext \fi \fi \fi \fi \fi \fi }{% \protected@edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\dtl@firstA\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext }}{% \protected@edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\dtl@firstA\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext }% \fi \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\dtl@getfirst} % Gets the first object, and stores in \cs{dtl@first}. The remainder % is stored in \cs{dtl@rest}. % \begin{macrocode} \def\dtl@getfirst#1#2\end{% \def\dtl@first{#1}% \ifx\dtl@first\@empty \def\dtl@rest{#2}% \else \dtl@ifsingle{#1}{\def\dtl@rest{#2}}{\dtl@getfirst#1#2\end}% \fi } % \end{macrocode} %\end{macro} % Count registers to store character codes: % \begin{macrocode} \newcount\dtl@codeA \newcount\dtl@codeB % \end{macrocode} %\begin{macro}{\dtl@setcharcode} %\begin{definition} %\cs{dtl@setcharcode}\marg{c}\marg{count register} %\end{definition} % Sets \meta{count register} to the character code of \meta{c}, or to % -1 if \meta{c} is a control sequence, unless \meta{c} is either % \cs{space} or |~| in which case it sets \meta{count register} % to the character code of the space character. % \begin{macrocode} \newcommand*{\dtl@setcharcode}[2]{% \def\@dtl@tmp{#1}% \ifx\@dtl@tmp\@empty #2=-1\relax \else \ifx#1\space\relax #2=`\ \relax \else \ifx#1~\relax #2=`\ \relax \else \ifcat\noexpand#1\relax% #2=-1\relax \else #2=`#1\relax \fi \fi \fi \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@setlccharcode} %\begin{definition} %\cs{dtl@setlccharcode}\marg{c}\marg{count register} %\end{definition} % As \cs{dtl@setlccharcode} except it sets \meta{count register} % to the lower case character code of \meta{c}, unless \meta{c} % is a control sequence, in which case it does the same as % \cs{dtl@setcharcode}. % \begin{macrocode} \newcommand*{\dtl@setlccharcode}[2]{% \def\@dtl@tmp{#1}% \ifx\@dtl@tmp\@empty #2=-1\relax \else \ifx#1\space\relax #2=`\ \relax \else \ifx#1~\relax #2=`\ \relax \else \ifcat\noexpand#1\relax% #2=-1\relax \else #2=\lccode`#1\relax \fi \fi \fi \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\dtlicompare} %\begin{definition} %\cs{dtlicompare}\marg{count}\marg{string1}\marg{string2} %\end{definition} % As \cs{dtlcompare} but ignores case. %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\dtlicompare}[3]{% \dtl@subnobrsp{#2}{\@dtl@argA}% \dtl@subnobrsp{#3}{\@dtl@argB}% \ifx\@dtl@argA\@empty \ifx\@dtl@argB\@empty #1=0\relax \else #1=-1\relax \fi \else \ifx\@dtl@argB\@empty #1=1\relax \else \DTLsubstituteall{\@dtl@argA}{ }{\space }% \DTLsubstituteall{\@dtl@argB}{ }{\space }% \expandafter\dtl@getfirst\@dtl@argA\end \let\dtl@firstA=\dtl@first \let\dtl@restA=\dtl@rest \expandafter\dtl@getfirst\@dtl@argB\end \let\dtl@firstB=\dtl@first \let\dtl@restB=\dtl@rest \expandafter\dtl@ifsingle\expandafter{\dtl@firstA}{% \expandafter\dtl@ifsingle\expandafter{\dtl@firstB}{% \expandafter\dtl@setlccharcode\expandafter{\dtl@firstA}{\dtl@codeA}% \expandafter\dtl@setlccharcode\expandafter{\dtl@firstB}{\dtl@codeB}% \ifnum\dtl@codeA=-1\relax \ifnum\dtl@codeB=-1\relax \protected@edef\dtl@donext{% \noexpand\dtlicompare{\noexpand#1}{\dtl@restA}{\dtl@restB}}% \dtl@donext \else \protected@edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext \fi \else \ifnum\dtl@codeB=-1\relax \protected@edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\dtl@firstA\dtl@restA}{\dtl@restB}}% \dtl@donext \else \ifnum\dtl@codeA<\dtl@codeB #1=-1\relax \else \ifnum\dtl@codeA>\dtl@codeB #1=1\relax \else \ifx\dtl@restA\@empty \ifx\dtl@restB\@empty #1=0\relax \else #1=-1\relax \fi \else \ifx\restB\@empty #1=1\relax \else \protected@edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\dtl@restA}{\dtl@restB}}% \dtl@donext \fi \fi \fi \fi \fi \fi }{% \protected@edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\dtl@firstA\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext }}{% \protected@edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\dtl@firstA\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext }% \fi \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifstringlt} %\begin{definition} %\cs{DTLifstringlt}\marg{string1}\marg{string2}\marg{true part}\marg{false part} %\end{definition} % String comparison (Starred version ignores case) %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifstringlt}{\@ifstar\@sDTLifstringlt\@DTLifstringlt} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifstringlt}[4]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlcompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount<0\relax #3% \else #4% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifstringlt}[4]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlicompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount<0\relax #3% \else #4% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLiflt} %\begin{definition} %\cs{DTLiflt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} % Does \cs{DTLifnumlt} if both \meta{arg1} and \meta{arg2} are % numerical, otherwise do \cs{DTLifstringlt} (unstarred version) % or \cs{DTLifstringlt*} (starred version). %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLiflt}{\@ifstar\@sDTLiflt\@DTLiflt} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLiflt}[4]{% \dtl@testbothnumerical{#1}{#2}% \if@dtl@condition \DTLifnumlt{#1}{#2}{#3}{#4}% \else \@DTLifstringlt{#1}{#2}{#3}{#4}% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLiflt}[4]{% \dtl@testbothnumerical{#1}{#2}% \if@dtl@condition \DTLifnumlt{#1}{#2}{#3}{#4}% \else \@sDTLifstringlt{#1}{#2}{#3}{#4}% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifnumgt} %\begin{definition} %\cs{DTLifnumgt}\marg{num1}\marg{num2}\marg{true part}\marg{false part} %\end{definition} % Determines if \marg{num1} $>$ \marg{num2}. Both numbers % need to have the decimal separator changed to a dot % to ensure that it works with \cs{FPifgt} % \begin{macrocode} \newcommand*{\DTLifnumgt}[4]{% \DTLconverttodecimal{#1}{\@dtl@numi}% \DTLconverttodecimal{#2}{\@dtl@numii}% \FPifgt{\@dtl@numi}{\@dtl@numii}% #3% \else #4% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifstringgt} %\begin{definition} %\cs{DTLifstringgt}\marg{string1}\marg{string2}\marg{true part}\marg{false part} %\end{definition} % String comparison (starred version ignores case) %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifstringgt}{\@ifstar\@sDTLifstringgt\@DTLifstringgt} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifstringgt}[4]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlcompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount>0\relax #3% \else #4% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifstringgt}[4]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlicompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount>0\relax #3% \else #4% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifgt} %\begin{definition} %\cs{DTLifgt}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} % Does \cs{DTLifnumgt} if both \meta{arg1} and \meta{arg2} are % numerical, otherwise do \cs{DTLifstringgt} or \cs{DTLifstringgt*}. %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifgt}{\@ifstar\@sDTLifgt\@DTLifgt} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifgt}[4]{% \dtl@testbothnumerical{#1}{#2}% \if@dtl@condition \DTLifnumgt{#1}{#2}{#3}{#4}% \else \@DTLifstringgt{#1}{#2}{#3}{#4}% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifgt}[4]{% \dtl@testbothnumerical{#1}{#2}% \if@dtl@condition \DTLifnumgt{#1}{#2}{#3}{#4}% \else \@sDTLifstringgt{#1}{#2}{#3}{#4}% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifnumeq} %\begin{definition} %\cs{DTLifnumeq}\marg{num1}\marg{num2}\marg{true part}\marg{false part} %\end{definition} % Determines if \marg{num1} = \marg{num2}. Both numbers % need to have the decimal separator changed to a dot % to ensure that it works with \cs{FPifeq} % \begin{macrocode} \newcommand*{\DTLifnumeq}[4]{% \DTLconverttodecimal{#1}{\@dtl@numi}% \DTLconverttodecimal{#2}{\@dtl@numii}% \FPifeq{\@dtl@numi}{\@dtl@numii}% #3% \else #4% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifstringeq} %\begin{definition} %\cs{DTLifstringeq}\marg{string1}\marg{string2}\marg{true part}\marg{false part} %\end{definition} % String comparison (starred version ignores case) %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifstringeq}{\@ifstar\@sDTLifstringeq\@DTLifstringeq} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifstringeq}[4]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlcompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount=0\relax #3% \else #4% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifstringeq}[4]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlicompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount=0\relax #3% \else #4% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifeq} %\begin{definition} %\cs{DTLifeq}\marg{arg1}\marg{arg2}\marg{true part}\marg{false part} %\end{definition} % Does \cs{DTLifnumeq} if both \meta{arg1} and \meta{arg2} are % numerical, otherwise do \cs{DTLifstringeq} or \cs{DTLifstringeq*}. %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifeq}{\@ifstar\@sDTLifeq\@DTLifeq} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifeq}[4]{% \dtl@testbothnumerical{#1}{#2}% \if@dtl@condition \DTLifnumeq{#1}{#2}{#3}{#4}% \else \@DTLifstringeq{#1}{#2}{#3}{#4}% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifeq}[4]{% \dtl@testbothnumerical{#1}{#2}% \if@dtl@condition \DTLifnumeq{#1}{#2}{#3}{#4}% \else \@sDTLifstringeq{#1}{#2}{#3}{#4}% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifSubString} %\begin{definition} %\cs{DTLifSubString}\marg{string}\marg{sub string}\marg{true %part}\marg{false part} %\end{definition} % If \meta{sub string} is contained in \meta{string} does %\meta{true part}, otherwise does \meta{false part}. %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLifSubString}[4]{% \protected@edef\@dtl@tmp{\noexpand\dtl@testifsubstring {#1}{#2}}% \@dtl@tmp \if@dtl@condition #3% \else #4% \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\dtl@testifsubstring} % \begin{macrocode} \newcommand*{\dtl@testifsubstring}[2]{% \dtl@subnobrsp{#1}{\@dtl@argA}% \dtl@subnobrsp{#2}{\@dtl@argB}% \ifx\@dtl@argB\@empty \@dtl@conditiontrue \else \ifx\@dtl@argA\@empty \@dtl@conditionfalse \else \dtl@teststartswith{#1}{#2}% \if@dtl@condition \else \DTLsubstituteall{\@dtl@argA}{ }{\space }% \expandafter\dtl@getfirst\@dtl@argA\end \expandafter\dtl@ifsingle\expandafter{\dtl@first}{% \expandafter\dtl@testifsubstring\expandafter{\dtl@rest}{#2}% }{% \protected@edef\@dtl@donext{\noexpand\dtl@testifsubstring {\dtl@first\dtl@rest}{\@dtl@argB}}% \@dtl@donext }% \fi \fi \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifStartsWith} %\begin{definition} %\cs{DTLifStartsWith}\marg{string}\marg{substring}\marg{true %part}\marg{false part} %\end{definition} %If \meta{string} starts with \meta{substring}, this does %\meta{true part}, otherwise it does \meta{false part}. %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLifStartsWith}[4]{% \@dtl@conditionfalse \protected@edef\@dtl@tmp{\noexpand\dtl@teststartswith{#1}{#2}}% \@dtl@tmp \if@dtl@condition #3% \else #4% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@teststartswith} %\begin{definition} %\cs{dtl@teststartswith}\marg{string}\marg{prefix} %\end{definition} % Tests if \meta{string} starts with \meta{prefix}. This sets % \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@teststartswith}[2]{% \dtl@subnobrsp{#1}{\@dtl@argA}% \dtl@subnobrsp{#2}{\@dtl@argB}% \ifx\@dtl@argA\@empty \ifx\@dtl@argB\@empty \@dtl@conditiontrue \else \@dtl@conditionfalse \fi \else \ifx\@dtl@argB\@empty \@dtl@conditiontrue \else \DTLsubstituteall{\@dtl@argA}{ }{\space }% \DTLsubstituteall{\@dtl@argB}{ }{\space }% \expandafter\dtl@getfirst\@dtl@argA\end \let\dtl@firstA=\dtl@first \let\dtl@restA=\dtl@rest \expandafter\dtl@getfirst\@dtl@argB\end \let\dtl@firstB=\dtl@first \let\dtl@restB=\dtl@rest \expandafter\dtl@ifsingle\expandafter{\dtl@firstA}{% \expandafter\dtl@ifsingle\expandafter{\dtl@firstB}{% \expandafter\dtl@setcharcode\expandafter{\dtl@firstA}{\dtl@codeA}% \expandafter\dtl@setcharcode\expandafter{\dtl@firstB}{\dtl@codeB}% \ifnum\dtl@codeA=-1\relax \ifnum\dtl@codeB=-1\relax \protected@edef\dtl@donext{% \noexpand\dtl@teststartswith{\dtl@restA}{\dtl@restB}}% \dtl@donext \else \protected@edef\dtl@donext{% \noexpand\dtl@teststartswith {\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext \fi \else \ifnum\dtl@codeB=-1\relax \protected@edef\dtl@donext{% \noexpand\dtl@teststartswith {\dtl@firstA\dtl@restA}{\dtl@restB}}% \dtl@donext \else \ifnum\dtl@codeA=\dtl@codeB \protected@edef\dtl@donext{% \noexpand\dtl@teststartswith{\dtl@restA}{\dtl@restB}}% \dtl@donext \else \@dtl@conditionfalse \fi \fi \fi }{% \protected@edef\dtl@donext{% \noexpand\dtl@teststartswith {\dtl@firstA\dtl@restA}{\dtl@firstB\dtl@restB}}% \dtl@donext }}{% \protected@edef\dtl@donext{% \noexpand\dtl@teststartswith {\dtl@firstA\dtl@restA}{\dtl@firstB\dtl@restB}}% }% \fi \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifnumclosedbetween} %\begin{definition} %\cs{DTLifnumclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % Determines if \meta{min} $\leq$ \meta{num} $\leq$ \meta{max}. % \begin{macrocode} \newcommand*{\DTLifnumclosedbetween}[5]{% \DTLconverttodecimal{#1}{\@dtl@numi}% \DTLconverttodecimal{#2}{\@dtl@numii}% \DTLconverttodecimal{#3}{\@dtl@numiii}% \DTLifFPclosedbetween{\@dtl@numi}{\@dtl@numii}{\@dtl@numiii}{#4}{#5}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifstringclosedbetween} %\begin{definition} %\cs{DTLifstringclosedbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % String comparison (starred version ignores case) %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifstringclosedbetween}{% \@ifstar\@sDTLifstringclosedbetween\@DTLifstringclosedbetween} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifstringclosedbetween}[5]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlcompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \let\@dtl@dovalue\relax \ifnum\@dtl@tmpcount<0\relax \def\@dtl@dovalue{#5}% \fi \ifx\@dtl@dovalue\relax \protected@edef\@dtl@tmpcmp{% \noexpand\dtlcompare{\noexpand\@dtl@tmpcount}{#1}{#3}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount>0\relax \def\@dtl@dovalue{#5}% \else \def\@dtl@dovalue{#4}% \fi \fi \@dtl@dovalue } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifstringclosedbetween}[5]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlicompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \let\@dtl@dovalue\relax \ifnum\@dtl@tmpcount<0\relax \def\@dtl@dovalue{#5}% \fi \ifx\@dtl@dovalue\relax \protected@edef\@dtl@tmpcmp{% \noexpand\dtlicompare{\noexpand\@dtl@tmpcount}{#1}{#3}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount>0\relax \def\@dtl@dovalue{#5}% \else \def\@dtl@dovalue{#4}% \fi \fi \@dtl@dovalue } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifclosedbetween} %\begin{definition} %\cs{DTLifclosedbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % Does \cs{DTLifnumclosedbetween} if \marg{arg}, \meta{min} and \meta{max} are % numerical, otherwise do \cs{DTLifstringclosedbetween} % or \cs{DTLifstringclosedbetween*}. %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifclosedbetween}{% \@ifstar\@sDTLifclosedbetween\@DTLifclosedbetween} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifclosedbetween}[5]{% \dtl@testbothnumerical{#2}{#3}% \if@dtl@condition \dtl@ifsingle{#1}{% \edef\@dtl@tmp{#1}}{% \def\@dtl@tmp{#1}}% \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% \ifnum\@dtl@datatype>0\relax \DTLifnumclosedbetween{#1}{#2}{#3}{#4}{#5}% \else \@DTLifstringclosedbetween{#1}{#2}{#3}{#4}{#5}% \fi \else \@DTLifstringclosedbetween{#1}{#2}{#3}{#4}{#5}% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifclosedbetween}[5]{% \dtl@testbothnumerical{#2}{#3}% \if@dtl@condition \dtl@ifsingle{#1}{% \edef\@dtl@tmp{#1}}{% \def\@dtl@tmp{#1}}% \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% \ifnum\@dtl@datatype>0\relax \DTLifnumclosedbetween{#1}{#2}{#3}{#4}{#5}% \else \@sDTLifstringclosedbetween{#1}{#2}{#3}{#4}{#5}% \fi \else \@sDTLifstringclosedbetween{#1}{#2}{#3}{#4}{#5}% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifnumopenbetween} %\begin{definition} %\cs{DTLifnumopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % Determines if \meta{min} $<$ \meta{num} $<$ \meta{max}. % \begin{macrocode} \newcommand*{\DTLifnumopenbetween}[5]{% \DTLconverttodecimal{#1}{\@dtl@numi}% \DTLconverttodecimal{#2}{\@dtl@numii}% \DTLconverttodecimal{#3}{\@dtl@numiii}% \DTLifFPopenbetween{\@dtl@numi}{\@dtl@numii}{\@dtl@numiii}{#4}{#5}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifstringopenbetween} %\begin{definition} %\cs{DTLifstringopenbetween}\marg{string}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % String comparison (starred version ignores case) %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifstringopenbetween}{% \@ifstar\@sDTLifstringopenbetween\@DTLifstringopenbetween} % \end{macrocode} % Unstarred version: % \begin{macrocode} \newcommand*{\@DTLifstringopenbetween}[5]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlcompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \let\@dtl@dovalue\relax \ifnum\@dtl@tmpcount>0\relax \else \def\@dtl@dovalue{#5}% \fi \ifx\@dtl@dovalue\relax \protected@edef\@dtl@tmpcmp{% \noexpand\dtlcompare{\noexpand\@dtl@tmpcount}{#1}{#3}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount<0\relax \def\@dtl@dovalue{#4}% \else \def\@dtl@dovalue{#5}% \fi \fi \@dtl@dovalue } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifstringopenbetween}[5]{% \protected@edef\@dtl@tmpcmp{% \noexpand\dtlicompare{\noexpand\@dtl@tmpcount}{#1}{#2}}% \@dtl@tmpcmp \let\@dtl@dovalue\relax \ifnum\@dtl@tmpcount>0\relax \else \def\@dtl@dovalue{#5}% \fi \ifx\@dtl@dovalue\relax \protected@edef\@dtl@tmpcmp{% \noexpand\dtlicompare{\noexpand\@dtl@tmpcount}{#1}{#3}}% \@dtl@tmpcmp \ifnum\@dtl@tmpcount<0\relax \def\@dtl@dovalue{#4}% \else \def\@dtl@dovalue{#5}% \fi \fi \@dtl@dovalue } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifopenbetween} %\begin{definition} %\cs{DTLifopenbetween}\marg{arg}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % Does \cs{DTLifnumopenbetween} if \marg{arg}, \meta{min} and \meta{max} are % numerical, otherwise do \cs{DTLifstringopenbetween} % or \cs{DTLifstringopenbetween*}. %\changes{1.01}{2007 Aug 17}{added starred version} % \begin{macrocode} \newcommand*{\DTLifopenbetween}{% \@ifstar\@sDTLifopenbetween\@DTLifopenbetween} % \end{macrocode} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLifopenbetween}[5]{% \dtl@testbothnumerical{#2}{#3}% \if@dtl@condition \dtl@ifsingle{#1}{% \edef\@dtl@tmp{#1}}{% \def\@dtl@tmp{#1}}% \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% \ifnum\@dtl@datatype>0\relax \DTLifnumopenbetween{#1}{#2}{#3}{#4}{#5}% \else \@DTLifstringopenbetween{#1}{#2}{#3}{#4}{#5}% \fi \else \@DTLifstringopenbetween{#1}{#2}{#3}{#4}{#5}% \fi } % \end{macrocode} % Starred version % \begin{macrocode} \newcommand*{\@sDTLifopenbetween}[5]{% \dtl@testbothnumerical{#2}{#3}% \if@dtl@condition \dtl@ifsingle{#1}{% \edef\@dtl@tmp{#1}}{% \def\@dtl@tmp{#1}}% \expandafter\@dtl@checknumerical\expandafter{\@dtl@tmp}% \ifnum\@dtl@datatype>0\relax \DTLifnumopenbetween{#1}{#2}{#3}{#4}{#5}% \else \@sDTLifstringopenbetween{#1}{#2}{#3}{#4}{#5}% \fi \else \@sDTLifstringopenbetween{#1}{#2}{#3}{#4}{#5}% \fi } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifFPopenbetween} %\begin{definition} %\cs{DTLifFPopenbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % Determines if \meta{min} $<$ \meta{num} $<$ \meta{max} where % all arguments are in standard fixed point notation. % \begin{macrocode} \newcommand*{\DTLifFPopenbetween}[5]{% \let\@dtl@dovalue\relax \FPifgt{#1}{#2}% \else \def\@dtl@dovalue{#5}% \fi \FPiflt{#1}{#3}% \ifx\@dtl@dovalue\relax \def\@dtl@dovalue{#4}% \fi \else \def\@dtl@dovalue{#5}% \fi \@dtl@dovalue } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifFPclosedbetween} %\begin{definition} %\cs{DTLifFPclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true part}\marg{false part} %\end{definition} % Determines if \meta{min} $\leq$ \meta{num} $\leq$ \meta{max}. % \begin{macrocode} \newcommand*{\DTLifFPclosedbetween}[5]{% \let\@dtl@dovalue\relax \FPifgt{#1}{#3}% \def\@dtl@dovalue{#5}% \fi \FPiflt{#1}{#2}% \ifx\@dtl@dovalue\relax \def\@dtl@dovalue{#5}% \fi \else \def\@dtl@dovalue{#4}% \fi \@dtl@dovalue } % \end{macrocode} %\end{macro} % % The following conditionals are only meant to be used within % \cs{DTLforeach} as they depend on the counter % \texttt{DTLrow}\meta{n}. % %\begin{macro}{\DTLiffirstrow} %\begin{definition} %\cs{DTLiffirstrow}\marg{true part}\marg{false part} %\end{definition} % Test if the current row is the first row. (This takes % \meta{condition}, the optional argument of \cs{DTLforeach}, % 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]{% \PackageError{datatool}{\string\DTLiffirstrow\space can only be used inside \string\DTLforeach}{}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLiflastrow} %\begin{definition} %\cs{DTLiflastrow}\marg{true part}\marg{false part} %\end{definition} % Checks if the current row is the last row of the database. % It doesn't take the condition (the optional argument of % \cs{DTLforeach}) into account, so its possible it may never % do \meta{true part}, as the last row of the database may not % meet the condition. It is therefore not very useful and is % confusing since it behaves differently to \cs{DTLiffirstrow} % which does take the condition into account, so I have removed % its description from the main part of the manual. If you need % to use the optional argument of \cs{DTLforeach}, you will first % 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. %\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]{% \PackageError{datatool}{\string\DTLiflastrow\space can only be used inside \string\DTLforeach}{}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifoddrow} %\begin{definition} %\cs{DTLifoddrow}\marg{true part}\marg{false part} %\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]{% \PackageError{datatool}{\string\DTLifoddrow\space can only be used inside \string\DTLforeach}{}% } % \end{macrocode} %\end{macro} % % \subsection{ifthen Conditionals} % The following commands provide conditionals \cs{DTLis}\ldots\ % which can be used in \cs{ifthenelse}. First need to define % a new conditional: %\begin{macro}{\if@dtl@condition} % \begin{macrocode} \newif\if@dtl@condition % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testlt} % Command to test if first argument is less than second argument. % If either argument is a string, a case sensitive string comparison % is used instead. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testlt}[2]{% \DTLiflt{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLislt} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLislt}[2]{% \TE@throw\noexpand\dtl@testlt{#1}{#2}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testiclt} % Command to test if first argument is less than second argument. % If either argument is a string, a case insensitive string comparison % is used instead. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testiclt}[2]{% \@sDTLiflt{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLisilt} % Provide conditional command for use in \cs{ifthenelse} %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLisilt}[2]{% \TE@throw\noexpand\dtl@testiclt{#1}{#2}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testgt} % Command to test if first number is greater than second number. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testgt}[2]{% \DTLifgt{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisgt} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisgt}[2]{% \TE@throw\noexpand\dtl@testgt{#1}{#2}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testicgt} % Command to test if first number is greater than second number % (ignores case). % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testicgt}[2]{% \@sDTLifgt{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisigt} % Provide conditional command for use in \cs{ifthenelse} %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLisigt}[2]{% \TE@throw\noexpand\dtl@testicgt{#1}{#2}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testeq} % Command to test if first number is equal to the second number. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testeq}[2]{% \DTLifeq{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLiseq} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLiseq}[2]{% \TE@throw\noexpand\dtl@testeq{#1}{#2}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testiceq} % Command to test if first number is equal to the second number % (ignores case). % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testiceq}[2]{% \@sDTLifeq{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisieq} % Provide conditional command for use in \cs{ifthenelse} %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLisieq}[2]{% \TE@throw\noexpand\dtl@testiceq{#1}{#2}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLisSubString} % Tests if second argument is contained in first argument. %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLisSubString}[2]{% \TE@throw\noexpand\dtl@testifsubstring{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLisPrefix} % Tests if first argument starts with second argument. %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLisPrefix}[2]{% \TE@throw\noexpand\dtl@teststartswith{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testclosedbetween} % Command to test if first value lies between second and third % values. (End points included, case sensitive.) % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testclosedbetween}[3]{% \DTLifclosedbetween{#1}{#2}{#3}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisclosedbetween} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisclosedbetween}[3]{% \TE@throw\noexpand\dtl@testclosedbetween{#1}{#2}{#3}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testiclosedbetween} % Command to test if first value lies between second and third % values. (End points included, case ignored.) % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testiclosedbetween}[3]{% \@sDTLifclosedbetween{#1}{#2}{#3}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisiclosedbetween} % Provide conditional command for use in \cs{ifthenelse} %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLisiclosedbetween}[3]{% \TE@throw\noexpand\dtl@testiclosedbetween{#1}{#2}{#3}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testopenbetween} % Command to test if first value lies between second and third % values. (End points excluded, case sensitive.) % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testopenbetween}[3]{% \DTLifopenbetween{#1}{#2}{#3}{\@dtl@conditiontrue }{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisopenbetween} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisopenbetween}[3]{% \TE@throw\noexpand\dtl@testopenbetween{#1}{#2}{#3}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testiopenbetween} % Command to test if first value lies between second and third % values. (End points excluded, case ignored.) % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testiopenbetween}[3]{% \@sDTLifopenbetween{#1}{#2}{#3}{\@dtl@conditiontrue }{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisiopenbetween} % Provide conditional command for use in \cs{ifthenelse} %\changes{1.01}{2007 Aug 17}{new} % \begin{macrocode} \newcommand*{\DTLisiopenbetween}[3]{% \TE@throw\noexpand\dtl@testiopenbetween{#1}{#2}{#3}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testclosedbetween} % Command to test if first number lies between second and third % numbers. (End points included, all arguments are fixed point % numbers in standard format.) This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testFPclosedbetween}[3]{% \DTLifFPclosedbetween{#1}{#2}{#3}% {\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} % Provide conditional command for use in \cs{ifthenelse} %\begin{macro}{\DTLisFPclosedbetween} % \begin{macrocode} \newcommand*{\DTLisFPclosedbetween}[3]{% \TE@throw\noexpand\dtl@testFPclosedbetween{#1}{#2}{#3}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testopenbetween} % Command to test if first number lies between second and third % numbers. (End points excluded, all arguments are fixed point % numbers in standard format.) This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testFPopenbetween}[3]{% \DTLifFPopenbetween{#1}{#2}{#3}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisFPopenbetween} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisFPopenbetween}[3]{% \TE@throw\noexpand\dtl@testFPopenbetween{#1}{#2}{#3}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testFPislt} % Command to test if first number is less than second % number where both numbers are in standard format. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testFPislt}[2]{% \FPiflt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisFPlt} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisFPlt}[2]{% \TE@throw\noexpand\dtl@testFPislt{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testFPisgt} % Command to test if first number is greater than second % number where both numbers are in standard format. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testFPisgt}[2]{% \FPifgt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisFPgt} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisFPgt}[2]{% \TE@throw\noexpand\dtl@testFPisgt{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testFPiseq} % Command to test if two numbers are equal, where both numbers % are in standard decimal format % \begin{macrocode} \newcommand*{\dtl@testFPiseq}[2]{% \FPifeq{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisFPeq} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisFPeq}[2]{% \TE@throw\noexpand\dtl@testFPiseq{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testFPislteq} % Command to test if first number is less than or equal to second % number where both numbers are in standard format. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testFPislteq}[2]{% \FPiflt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi \if@dtl@condition \else \dtl@testFPiseq{#1}{#2}% \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisFPlteq} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisFPlteq}[2]{% \TE@throw\noexpand\dtl@testFPislteq{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testFPisgteq} % Command to test if first number is greater than or equal to second % number where both numbers are in standard format. % This sets \cs{if@dtl@condition}. % \begin{macrocode} \newcommand*{\dtl@testFPisgteq}[2]{% \FPifgt{#1}{#2}\@dtl@conditiontrue\else\@dtl@conditionfalse\fi \if@dtl@condition \else \dtl@testFPiseq{#1}{#2}% \fi } % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisFPgteq} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisFPgteq}[2]{% \TE@throw\noexpand\dtl@testFPisgteq{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@teststring} % Command to test if argument is a string. This sets % \cs{if@dtl@condition} % \begin{macrocode} \newcommand*{\dtl@teststring}[1]{% \DTLifstring{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisstring} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisstring}[1]{% \TE@throw\noexpand\dtl@teststring{#1}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testnumerical} % Command to test if argument is a numerical. This sets % \cs{if@dtl@condition} % \begin{macrocode} \newcommand*{\dtl@testnumerical}[1]{% \DTLifnumerical{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}% } % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisnumerical} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisnumerical}[1]{% \TE@throw\noexpand\dtl@testnumerical{#1}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testint} % Command to test if argument is an integer. This sets % \cs{if@dtl@condition} % \begin{macrocode} \newcommand*{\dtl@testint}[1]{% \DTLifint{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisint} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisint}[1]{% \TE@throw\noexpand\dtl@testint{#1}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testreal} % Command to test if argument is a real. This sets % \cs{if@dtl@condition} % \begin{macrocode} \newcommand*{\dtl@testreal}[1]{% \DTLifreal{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLisreal} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLisreal}[1]{% \TE@throw\noexpand\dtl@testreal{#1}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testcurrency} % Command to test if argument is a currency. This sets % \cs{if@dtl@condition} % \begin{macrocode} \newcommand*{\dtl@testcurrency}[1]{% \DTLifcurrency{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLiscurrency} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLiscurrency}[1]{% \TE@throw\noexpand\dtl@testcurrency{#1}\noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@testcurrencyunit} % Command to test if argument is a currency with given unit. This sets % \cs{if@dtl@condition} % \begin{macrocode} \newcommand*{\dtl@testcurrencyunit}[2]{% \DTLifcurrencyunit{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLiscurrencyunit} % Provide conditional command for use in \cs{ifthenelse} % \begin{macrocode} \newcommand*{\DTLiscurrencyunit}[2]{% \TE@throw\noexpand\dtl@testcurrencyunit{#1}{#2}% \noexpand\if@dtl@condition} % \end{macrocode} %\end{macro} % % \subsection{Defining New Databases} % 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} %\begin{definition} % \cs{DTLnewdb}\marg{db name} %\end{definition} %\changes{2.0}{2009 February 27}{Changed way database is stored} % Initialises a database called \meta{name}. % \begin{macrocode} \newcommand*{\DTLnewdb}[1]{% % \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} % %\begin{macro}{\DTLcleardb} %\begin{definition} % \cs{DTLcleardb}\marg{db name} %\end{definition} % Clears the database. (Makes it empty, but still defined.) %\changes{2.03}{2009 November 15}{new} % \begin{macrocode} \newcommand*{\DTLcleardb}[1]{% \DTLifdbexists{#1}% {% \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do {% \expandafter\let\csname dtl@ci@#1@\@dtl@key\endcsname\undefined }% \csname dtldb@#1\endcsname{}% \csname dtlkeys@#1\endcsname{}% \csname dtlrows@#1\endcsname=0\relax \csname dtlcols@#1\endcsname=0\relax }% {% \PackageError{Can't clear database `#1': database doesn't exist}{}{}% }% } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLdeletedb} %\begin{definition} % \cs{DTLdeletedb}\marg{db name} %\end{definition} % Deletes a database. %\changes{2.03}{2009 November 15}{new} % \begin{macrocode} \newcommand*{\DTLdeletedb}[1]{% \DTLifdbexists{#1}% {% \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do {% \expandafter\let\csname dtl@ci@#1@\@dtl@key\endcsname\undefined }% \expandafter\let\csname dtldb@#1\endcsname\undefined \expandafter\let\csname dtlkeys@#1\endcsname\undefined \expandafter\let\csname dtlrows@#1\endcsname\undefined \expandafter\let\csname dtlcols@#1\endcsname\undefined }% {% \PackageError{Can't delete database `#1': database doesn't exist}{}{}% }% } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLrowcount} %\begin{definition} % \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{DTLifdbempty}\marg{name}\marg{true part}\marg{false part} %\end{definition} % Check if named database is empty (i.e.\ no rows have been added). % \begin{macrocode} \newcommand{\DTLifdbempty}[3]{% \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} % %\begin{macro}{\DTLnewrow} %\begin{definition} % \cs{DTLnewrow}\marg{db name} %\end{definition} % Add a new row to named database. The starred version doesn't % check for the existence of the database. % \begin{macrocode} \newcommand*{\DTLnewrow}{% \@ifstar\@sDTLnewrow\@DTLnewrow } % \end{macrocode} %\end{macro} % %\begin{macro}{\@DTLnewrow} %\begin{definition} % \cs{@DTLnewrow}\marg{db name} %\end{definition} % Add a new row to named database. (Checks for the existance % of the database.) % \begin{macrocode} \newcommand*{\@DTLnewrow}[1]{% \DTLifdbexists{#1}% {\@sDTLnewrow{#1}}% {\PackageErrors{datatool}{Can't add new row to database `#1': database doesn't exist}{}}% } % \end{macrocode} %\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} \newcommand*{\@sDTLnewrow}[1]{% % \end{macrocode} % Increment row count. % \begin{macrocode} \global\advance\csname dtlrows@#1\endcsname by 1\relax % \end{macrocode} % Append an empty row to the database % \begin{macrocode} \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} % Display message on terminal and log file if in verbose mode. % \begin{macrocode} \dtl@message{New row added to database `#1'}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlcolumnnum} % Count register to keep track of column index. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newcount\dtlcolumnnum % \end{macrocode} %\end{macro} %\begin{macro}{\dtlrownum} % Count register to keep track of row index. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newcount\dtlrownum % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLifhaskey} %\begin{definition} %\cs{DTLifhaskey}\meta{db name}\meta{key}\meta{true part}\meta{false % part} %\end{definition} % 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} \newcommand*{\DTLifhaskey}{\@ifstar\@sDTLifhaskey\@DTLifhaskey} % \end{macrocode} %\end{macro} % %\begin{macro}{\@DTLifhaskey} % Unstarred version of \cs{DTLifhaskey} % \begin{macrocode} \newcommand{\@DTLifhaskey}[4]{% \DTLifdbexists{#1}% {% \@sDTLifhaskey{#1}{#2}{#3}{#4}% }% {% \PackageError{datatool}{Database `#1' doesn't exist}{}% }% } % \end{macrocode} %\end{macro} %\begin{macro}{\@sDTLifhaskey} % Starred version of \cs{DTLifhaskey} % \begin{macrocode} \newcommand{\@sDTLifhaskey}[4]{% \@ifundefined{dtl@ci@#1@#2}% {% % \end{macrocode} % Key not defined % \begin{macrocode} #4% }% {% % \end{macrocode} % Key defined % \begin{macrocode} #3% }% } % \end{macrocode} %\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} \newcommand*{\DTLgetcolumnindex}{% \@ifstar\@sdtl@getcolumnindex\@dtl@getcolumnindex } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@getcolumnindex} % Unstarred version of \cs{DTLgetcolumnindex} %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newcommand*{\@dtl@getcolumnindex}[3]{% % \end{macrocode} % Check if database exists. % \begin{macrocode} \DTLifdbexists{#2}% {% % \end{macrocode} % Database exists. Now check if key exists. % \begin{macrocode} \@sDTLifhaskey{#2}{#3}% {% % \end{macrocode} % Key exists so go ahead and get column index. % \begin{macrocode} \@sdtl@getcolumnindex{#1}{#2}{#3}% }% {% % \end{macrocode} % Key doesn't exists in named database. % \begin{macrocode} \PackageError{datatool}{Database `#2' doesn't contain key `#3'}{}% }% }% {% % \end{macrocode} % Named database doesn't exist. % \begin{macrocode} \PackageError{datatool}{Database `#2' doesn't exist}{}% }% } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@getcolumnindex} % Starred version of \cs{DTLgetcolumnindex}. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newcommand*{\@sdtl@getcolumnindex}[3]{% \expandafter\let\expandafter#1\csname dtl@ci@#2@#3\endcsname } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlcolumnindex} %\begin{definition} % \cs{dtlcolumnindex}\marg{db}\marg{key} %\end{definition} % 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} %\changes{2.03}{2009 November 15}{renamed \cs{dtl@columnindex} to %\cs{dtlcolumnindex}} % \begin{macrocode} \newcommand*{\dtlcolumnindex}[2]{% \csname dtl@ci@#1@#2\endcsname } % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLgetkeyforcolumn} %\begin{definition} %\cs{DTLgetkeyforcolumn}\marg{key cs}\marg{db}\marg{column index} %\end{definition} % Gets the key associated with the given column index and stores % in \meta{key cs}. Unstarred version doesn't perform checks. % \begin{macrocode} \newcommand*{\DTLgetkeyforcolumn}{% \@ifstar\@sdtlgetkeyforcolumn\@dtlgetkeyforcolumn} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtlgetkeyforcolumn} % \begin{macrocode} \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}{\@sdtlgetkeyforcolumn} %\begin{definition} %\cs{@sdtlgetkeyforcolumn}\marg{key cs}\marg{db}\marg{column index} %\end{definition} % Gets the key associated with the given column index and stores % in \meta{key cs} % \begin{macrocode} \newcommand*{\@sdtlgetkeyforcolumn}[3]{% \edef\@dtl@dogetkeyforcolumn{\noexpand\@dtl@getkeyforcolumn {\noexpand#1}{#2}{\number#3}}% \@dtl@dogetkeyforcolumn } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@getkeyforcolumn} % Column index must be fully expanded before use. % \begin{macrocode} \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} % % 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} \def\DTLunsettype{} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLstringtype} % Data type representing strings. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \def\DTLstringtype{0} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLinttype} % Data type representing integers. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \def\DTLinttype{1} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLrealtype} % Data type representing real numbers. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \def\DTLrealtype{2} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLcurrencytype} % Data type representing currency. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \def\DTLcurrencytype{3} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLgetdatatype} %\begin{definition} %\cs{DTLgetdatatype}\marg{cs}\marg{db}\marg{key} %\end{definition} % 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*{\DTLgetdatatype}{% \@ifstar\@sdtlgetdatatype\@dtlgetdatatype } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtlgetdatatype} % Unstarred version of \cs{DTLgetdatatype}. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newcommand*{\@dtlgetdatatype}[3]{% % \end{macrocode} % Check if database exists. % \begin{macrocode} \DTLifdbexists{#2}% {% % \end{macrocode} % Check if key exists in this database. % \begin{macrocode} \@sDTLifhaskey{#2}{#3}% {% % \end{macrocode} % Get data type for this database and key. % \begin{macrocode} \@sdtlgetdatatype{#1}{#2}{#3}% }% {% % \end{macrocode} % Key doesn't exist in this database. % \begin{macrocode} \PackageError{datatool}{Key `#3' undefined in database `#2'}{}% }% }% {% % \end{macrocode} % Database doesn't exist. % \begin{macrocode} \PackageError{datatool}{Database `#2' doesn't exist}{}% }% } % \end{macrocode} %\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} \newcommand*{\@sdtlgetdatatype}[3]{% \edef\@dtl@dogetdata{\noexpand\@dtl@getdatatype{\noexpand#1}% {\expandafter\the\csname dtlkeys@#2\endcsname}% {\dtlcolumnindex{#2}{#3}}}% \@dtl@dogetdata } % \end{macrocode} %\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} \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} %\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} \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} %\end{macro} % %\begin{macro}{\@dtl@before} %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newtoks\@dtl@before % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@after} %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newtoks\@dtl@after % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@colhead} %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newtoks\@dtl@colhead % \end{macrocode} %\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} \newcommand*{\@dtl@updatekeys}[3]{% % \end{macrocode} % Check if key already exists % \begin{macrocode} \@sDTLifhaskey{#1}{#2}% {% % \end{macrocode} % Key exists, may need to update data type. First get the % column index. % \begin{macrocode} \expandafter\dtlcolumnnum\expandafter =\dtlcolumnindex{#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} \else % \end{macrocode} % Make a copy of current data type % \begin{macrocode} \let\@dtl@oldtype\@dtl@type % \end{macrocode} % Check the data type for this entry (stored in \cs{@dtl@datatype}) % \begin{macrocode} \@dtl@checknumerical{#3}% % \end{macrocode} % If this column currently has no data type assigned to it % then use the new type. % \begin{macrocode} \ifx\@dtl@type\@empty \edef\@dtl@type{\number\@dtl@datatype}% \else % \end{macrocode} % This column already has an associated data type but it may % need updating. % \begin{macrocode} \ifcase\@dtl@datatype % string % \end{macrocode} % String overrides all other types % \begin{macrocode} \def\@dtl@type{0}% \or % int % \end{macrocode} % All other types override int, so leave it as it is % \begin{macrocode} \or % real % \end{macrocode} % Real overrides int, but not currency or string % \begin{macrocode} \ifnum\@dtl@type=1\relax \def\@dtl@type{2}% \fi \or % currency % \end{macrocode} % Currency overrides int and real but not string % \begin{macrocode} \ifnum\@dtl@type>0\relax \def\@dtl@type{3}% \fi \fi \fi % \end{macrocode} % Has the data type been updated? % \begin{macrocode} \ifx\@dtl@oldtype\@dtl@type % \end{macrocode} % No change needed % \begin{macrocode} \else % \end{macrocode} % 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} \expandafter\global\expandafter\advance \csname dtlcols@#1\endcsname by 1\relax \dtlcolumnnum=\csname dtlcols@#1\endcsname\relax % \end{macrocode} % Set column index for this key % \begin{macrocode} \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} \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}{\DTLsetheader} %\begin{definition} %\cs{DTLsetheader}\marg{db}\marg{key}\marg{header} %\end{definition} % 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} \newcommand*{\DTLsetheader}{\@ifstar\@sDTLsetheader\@DTLsetheader} % \end{macrocode} %\end{macro} % %\begin{macro}{\@DTLsetheader} % Unstarred version % \begin{macrocode} \newcommand*{\@DTLsetheader}[3]{% % \end{macrocode} % Check if database exists % \begin{macrocode} \DTLifdbexists{#1}% {% % \end{macrocode} % Check if key exists. % \begin{macrocode} \@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} %\end{macro} % %\begin{macro}{\@sDTLsetheader} % Starred version % \begin{macrocode} \newcommand*{\@sDTLsetheader}[3]{% \expandafter\dtlcolumnnum\expandafter =\dtlcolumnindex{#1}{#2}\relax \@dtl@setheaderforindex{#1}{\dtlcolumnnum}{#3}% } % \end{macrocode} %\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} \newcommand*{\@dtl@setheaderforindex}[3]{% % \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#2}} \@dtl@dogetprops % \end{macrocode} % Store the header in \cs{@dtl@toks} % \begin{macrocode} \@dtl@colhead={#3}% % \end{macrocode} % Reconstruct property list % \begin{macrocode} \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}{\dtlexpandnewvalue} % Expand new value before adding to database % \begin{macrocode} \newcommand*{\dtlexpandnewvalue}{% \def\@dtl@setnewvalue##1{\protected@edef\@dtl@tmp{##1}% \expandafter\@dtl@toks\expandafter{\@dtl@tmp}}% } % \end{macrocode} %\end{macro} %\begin{macro}{\dtlnoexpandnewvalue} % Don't expand new value before adding to database % \begin{macrocode} \newcommand*{\dtlnoexpandnewvalue}{% \def\@dtl@setnewvalue##1{\@dtl@toks{##1}}% } % \end{macrocode} % Do this by default: % \begin{macrocode} \dtlnoexpandnewvalue % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLnewdbentry} %\begin{definition} % \cs{DTLnewdbentry}\marg{db name}\marg{id}\marg{value}. %\end{definition} % 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{\DTLnewdbentry}{% \@ifstar\@sDTLnewdbentry\@DTLnewdbentry } % \end{macrocode} %\end{macro} % %\begin{macro}{\@DTLnewdbentry} % Unstarred version of \cs{DTLnewdbentry}. % \begin{macrocode} \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} %\end{macro} %\begin{macro}{\@sDTLnewdbentry} % Starred version of \cs{DTLnewdbentry} (doesn't check if the database exists). % \begin{macrocode} \newcommand*{\@sDTLnewdbentry}[3]{% % \end{macrocode} % Update key list % \begin{macrocode} \@dtl@updatekeys{#1}{#2}{#3}% % \end{macrocode} % Get the column index % \begin{macrocode} \expandafter\dtlcolumnnum\expandafter =\dtlcolumnindex{#1}{#2}\relax % \end{macrocode} % Get the current row: % \begin{macrocode} \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}% }% \dtl@dogetentry \ifx\dtl@entry\dtlnovalue % \end{macrocode} % Store the value of this entry in \cs{@dtl@toks} %\changes{2.03}{2009 November 15}{value can be expanded before % adding to database}% % \begin{macrocode} \@dtl@setnewvalue{#3}% % \end{macrocode} % There are no entries in this row for the given column. % Add this entry. % \begin{macrocode} \toks@gconcat@middle@cx{dtldb@#1}% {\dtlbeforerow}% {% % \end{macrocode} % Start of this row: % \begin{macrocode} \noexpand\db@row@elt@w% % \end{macrocode} % Row ID: % \begin{macrocode} \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname \noexpand\db@row@id@end@% % \end{macrocode} % Current row so far % \begin{macrocode} \the\dtlcurrentrow % \end{macrocode} % New column: % Column ID % \begin{macrocode} \noexpand\db@col@id@w \number\dtlcolumnnum \noexpand\db@col@id@end@% % \end{macrocode} % Value: % \begin{macrocode} \noexpand\db@col@elt@w \the\@dtl@toks \noexpand\db@col@elt@end@% % \end{macrocode} % Column ID: % \begin{macrocode} \noexpand\db@col@id@w \number\dtlcolumnnum \noexpand\db@col@id@end@% % \end{macrocode} % Row ID: % \begin{macrocode} \noexpand\db@row@id@w \number\csname dtlrows@#1\endcsname \noexpand\db@row@id@end@% % \end{macrocode} % End of this row % \begin{macrocode} \noexpand\db@row@elt@end@% }% % \end{macrocode} % Rest (this should be empty) % \begin{macrocode} {\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} % There's already an entry for the given column in this row % \begin{macrocode} \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 } % \end{macrocode} %\end{macro} % %\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{DTLifdbexists}\marg{db name}\marg{true part}\marg{false part} %\end{definition} % Checks if a data base with the given name exists. % \begin{macrocode} \newcommand{\DTLifdbexists}[3]{% \@ifundefined{dtldb@#1}{#3}{#2}} % \end{macrocode} %\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} \newcommand*{\@dtl@assign}[2]{% \@dtl@assigncmd#1,\@nil\@@{#2}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtl@assigncmd} %\begin{definition} % \cs{@dtl@assigncmd}\meta{cmd}=\meta{id}\cs{@nil} %\end{definition} %\changes{2.03}{2009 November 15}{modified to ignore spaces after % commas} % \begin{macrocode} \def\@dtl@assigncmd#1#2=#3,#4\@@#5{% % \end{macrocode} % get entry for ID given by \#3 and store in \#2 % \begin{macrocode} \@sDTLifhaskey{#5}{#3}% {% \edef\@dtl@dogetentry{% \noexpand\dtlgetentryfromcurrentrow {\noexpand#1}{\dtlcolumnindex{#5}{#3}}}% \@dtl@dogetentry % \end{macrocode} % Set to null if required % \begin{macrocode} \ifx#1\dtlnovalue \@@dtl@setnull{#1}{#3}% \fi % \end{macrocode} % Make it global % \begin{macrocode} \global\let#1=#1\relax }% {% \PackageError{datatool}{Can't assign \string#1\space: there is no key `#3' in data base `#5'}{}% % \end{macrocode} % Set to null % \begin{macrocode} \global\let#1\DTLstringnull }% % \end{macrocode} % Recurse? % \begin{macrocode} \def\dtl@tmp{#4}% \ifx\@nnil\dtl@tmp \let\@dtl@next\@dtl@assigncmdnoop \else \let\@dtl@next\@dtl@assigncmd \fi \@dtl@next#4\@@{#5}% } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@assigncmdnoop} % End loop % \begin{macrocode} \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.) %\changes{2.0}{2009 February 27}{modified to use new database % structure} % \begin{macrocode} \newcommand*{\@dtl@setnull}[2]{% % \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} \newcommand*{\DTLstringnull}{NULL} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLnumbernull} % Number null value: % \begin{macrocode} \newcommand*{\DTLnumbernull}{0} % \end{macrocode} %\end{macro} %\begin{macro}{\DTLifnull} %\begin{definition} %\cs{DTLifnull}\marg{value}\marg{true part}\marg{false part} %\end{definition} % Checks if \meta{value} is null (either \cs{DTLstringnull} or % \cs{DTLnumbernull}) if true, does \meta{true part} otherwise % does \meta{false part}. % \begin{macrocode} \newcommand*{\DTLifnull}[3]{% \ifx\DTLstringnull#1\relax #2% \else \ifx\DTLnumbernull#1\relax #2% \else #3% \fi \fi } % \end{macrocode} %\end{macro} % %\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{DTLgetkeydata}\marg{key}\marg{db}\marg{col cs}\marg{type cs}\marg{header cs} %\end{definition} % 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*{\DTLgetkeydata}{% \@ifstar\@sdtlgetkeydata\@dtlgetkeydata } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtlgetkeydata} % Unstarred version of \cs{DTLgetkeydata} % \begin{macrocode} \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}{\@sdtlgetkeydata} %\cs{@sdtlgetkeydata}\marg{key}\marg{db}\marg{col cs}\marg{type cs}\marg{header cs} % Starred verison of \cs{DTLgetkeydata}. % \begin{macrocode} \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}{\dtl@gathervalues} %\begin{definition} %\cs{dtl@gathervalues}\oarg{label}\marg{db name}\marg{row toks} %\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". %\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} \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 }% } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlcurrentrow} % Define token register to store current row. % \begin{macrocode} \newtoks\dtlcurrentrow % \end{macrocode} %\end{macro} %\begin{macro}{\dtlbeforerow} % Define token register to store everything before the current row. % \begin{macrocode} \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}{\dtlgetrow} %\begin{definition} %\cs{dtlgetrow}\marg{db}\marg{row idx} %\end{definition} % 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*{\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}{\@dtlgetrow} %\begin{definition} %\cs{@dtlgetrow}\marg{data specs}\marg{row idx} %\end{definition} % Gets the row specs from \meta{data specs} for row with index % \meta{row idx} which must be fully expanded. % \begin{macrocode} \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}{\dtlgetentryfromcurrentrow} %\begin{definition} %\cs{dtlgetentryfromcurrentrow}\marg{cs}\marg{col num} %\end{definition} % 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*{\dtlgetentryfromcurrentrow}[2]{% \dtlgetentryfromrow{#1}{#2}{\dtlcurrentrow}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlgetentryfromrow} %\begin{definition} %\cs{dtlgetentryfromrow}\marg{cs}\marg{col num}\marg{row toks} %\end{definition} % \begin{macrocode} \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}{\dtl@getentryfromrow} %\begin{definition} %\cs{dtl@getentryfromrow}\marg{cs}\marg{col num}\marg{row specs} %\end{definition} % \begin{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}{\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*{\DTLgetvalue}[4]{% \edef\dtl@dogetvalue{\noexpand\dtl@getvalue{\noexpand#1}{#2}% {\number#3}{\number#4}}% \dtl@dogetvalue } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@getvalue} % \begin{macrocode} \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}{\DTLgetlocation} %\begin{definition} %\cs{DTLgetlocation}\marg{row cs}\marg{column cs}\marg{database}% %\marg{value} %\end{definition} % 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*{\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 } % \end{macrocode} %\end{macro} %\subsection{Iterating Through Databases} %\label{sec:code:loops} % %\begin{macro}{\dtlbreak} % Break out of loop at the end of current iteration. % \begin{macrocode} \newcommand*{\dtlbreak}{% \PackageError{datatool}{Can't break out of anything}{}% } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlforint} %\begin{definition} %\cs{dtlforint}\meta{ct}=\meta{start}\cs{to}\meta{end}\cs{step}% %\meta{inc}\cs{do}\marg{body} %\end{definition} % \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} \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@foreach@level} % Count register to keep track of global nested loops. % \begin{macrocode} \newcount\@dtl@foreach@level % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlgforint} %\begin{definition} %\cs{dtlgforint}\meta{ct}=\meta{start}\cs{to}\meta{end}\cs{step}% %\meta{inc}\cs{do}\marg{body} %\end{definition} % \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} \long\def\dtlgforint#1=#2\to#3\step#4\do#5{% % \end{macrocode} % Initialise % \begin{macrocode} \global#1=#2\relax % \end{macrocode} % Increment level counter to allow for nested loops % \begin{macrocode} \global\advance\@dtl@foreach@level by 1\relax % \end{macrocode} % Set up end loop hook % \begin{macrocode} \expandafter\global\expandafter \let\csname @dtl@endhook@\the\@dtl@foreach@level\endcsname \relax % \end{macrocode} % Set up the break function: % Copy current definition % \begin{macrocode} \expandafter\global\expandafter \let\csname @dtl@break@\the\@dtl@foreach@level\endcsname \dtlbreak % \end{macrocode} % Set up definition for this level (sets to at the end % of the current iteration). % \begin{macrocode} \gdef\dtlbreak{\expandafter \gdef\csname @dtl@endhook@\the\@dtl@foreach@level\endcsname{% #1=#3}}% % \end{macrocode} % check the direction % \begin{macrocode} \ifnum#4<0\relax % \end{macrocode} % Counting down % \begin{macrocode} \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} % Counting up (or 0 increments) % \begin{macrocode} \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}{\@dtlforeachrow} %\begin{definition} %\cs{@dtlforeachrow}(\meta{idx cs},\meta{row cs})\cs{in}\marg{db}% %\cs{do}\marg{body} %\end{definition} % 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} \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@foreachrow} % \begin{macrocode} \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 \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 % \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} % Decrement level counter. % \begin{macrocode} \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} % %\begin{macro}{\@dtl@foreachnoop} % \begin{macrocode} \long\def\@dtl@foreachnoop#1\@@#2\q@nil{} % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlforeachkey} %\begin{definition} %\cs{dtlforeachkey}(\meta{key cs},\meta{col cs},\meta{type cs},\meta{header cs})% %\cs{in}\marg{db}\cs{do}\marg{body} %\end{definition} % 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} \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}{\@dtl@updatefkcs} % \begin{macrocode} \newcommand*{\@dtl@updatefkcs}[8]{% \gdef#1{#5}% \gdef#2{#6}% \gdef#3{#7}% \gdef#4{#8}% } % \end{macrocode} %\end{macro} % %\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} \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} % Terminate loop % \begin{macrocode} \let\@dtl@foreachnext\@dtl@foreachnoop \else % \end{macrocode} % Set up loop variables % \begin{macrocode} #7{#2}{#1}{#3}{#4}% % \end{macrocode} % Increment level counter to allow for nested loops % \begin{macrocode} \global\advance\@dtl@foreach@level by 1\relax % \end{macrocode} % Set up the break function % \begin{macrocode} \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} % Initialise % \begin{macrocode} \expandafter\global\expandafter \let\csname @dtl@foreachnext\the\@dtl@foreach@level\endcsname =\@dtl@foreachkey % \end{macrocode} % Do body of loop % \begin{macrocode} \@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 % \end{macrocode} % Recurse if necessary % \begin{macrocode} \@dtl@foreachnext#6\@@{#7}\q@nil } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtlforcolumn} %\begin{definition} %\cs{dtlforcolumn}\marg{cs}\marg{db}\marg{key}\marg{body} %\end{definition} % 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*{\dtlforcolumn}{\@ifstar\@sdtlforcolumn\@dtlforcolumn} % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtlforcolumn} % \begin{macrocode} \newcommand{\@dtlforcolumn}[4]{% % \end{macrocode} % Check if data base exists % \begin{macrocode} \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}{\@sdtlforcolumn} % \begin{macrocode} \newcommand{\@sdtlforcolumn}[4]{% \toks@{#4}% \edef\@dtl@doforcol{\noexpand\dtl@forcolumn{\noexpand#1}% {\expandafter\the\csname dtldb@#2\endcsname}% {\dtlcolumnindex{#2}{#3}}{\the\toks@}% }% \@dtl@doforcol% } % end{macrocode} %\end{macro} % %\begin{macro}{\dtlforcolumnidx} %\begin{definition} %\cs{dtlforcolumnidx}\marg{cs}\marg{db}\marg{col num}\marg{body} %\end{definition} % 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{\@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}{\@sdtlforcolumnidx} % \begin{macrocode} \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{macro} % %\begin{macro}{\dtl@forcolumn} %\begin{definition} %\cs{dtl@forcolumn}\marg{cs}\marg{db specs}\marg{col num}\marg{body} %\end{definition} % \meta{col num} needs to be fully expanded % \begin{macrocode} \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}{\@dtl@forcolnoop} % \begin{macrocode} \def\@dtl@forcolnoop#1\q@nil{} % \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{macrocode} \newcount\dtlforeachlevel % \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{macrocode} \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} % % \begin{macrocode} \newcount\dtl@rowi \newcount\dtl@rowii \newcount\dtl@rowiii % \end{macrocode} % % \begin{macrocode} \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} % %\begin{macro}{\DTLsaverowcount} %\begin{definition} %\cs{DTLsavelastrowcount}\marg{cmd} %\end{definition} % Stores the maximum row count for the last \cs{DTLforeach}. % \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} % \end{macrocode} %\end{macro} % %\begin{macro}{\DTLforeach} %\begin{definition} % \cs{DTLforeach}\oarg{conditions}\marg{db name}\marg{values}\marg{text} %\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} % \begin{macrocode} \newcommand*{\DTLforeach}{\@ifstar\@sDTLforeach\@DTLforeach} % \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. % Use the starred version for faster access. %\changes{2.0}{2009 February 27}{updated to use new database structure} % \begin{macrocode} \newcommand{\@DTLforeach}[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\relax % \end{macrocode} % Store database name % \begin{macrocode} \gdef\@dtl@dbname{#2}% % \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 \@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\global\expandafter\let \csname @dtl@dbname@\romannumeral\dtlforeachlevel\endcsname =\@dtl@dbname % \end{macrocode} % Mark it as not read only % \begin{macrocode} \expandafter\global\expandafter\let \csname @dtl@ro@\romannumeral\dtlforeachlevel\endcsname = 0\relax % \end{macrocode} % Loop through each row. % Loop counter given by \cs{dtl@row@}\meta{level} % \begin{macrocode} \dtlgforint \csname dtl@row\romannumeral\dtlforeachlevel\endcsname =1\to\csname dtlrows@#2\endcsname\step1\do {% % \end{macrocode} % Get current row from the data base % \begin{macrocode} \@dtl@tmpcount= \csname dtl@row\romannumeral\dtlforeachlevel\endcsname \edef\dtl@dogetrow{\noexpand\dtlgetrow{#2}% {\number\@dtl@tmpcount}}% \dtl@dogetrow % \end{macrocode} % Store the current row for this level % \begin{macrocode} \expandafter\global \csname @dtl@cur\romannumeral\dtlforeachlevel\endcsname = \dtlcurrentrow % \end{macrocode} % Store the previous rows for this level % \begin{macrocode} \expandafter\global \csname @dtl@prev\romannumeral\dtlforeachlevel\endcsname = \dtlbeforerow % \end{macrocode} % Store the subsequent rows for this level % \begin{macrocode} \expandafter\global \csname @dtl@next\romannumeral\dtlforeachlevel\endcsname = \dtlafterrow % \end{macrocode} % Assign commands to the required entries % \begin{macrocode} \ifx\relax#3\relax \else \@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} % 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} % 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} {}% }% % \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 % \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}{\@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} \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 \@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 % \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}{\@dtlifreadonly} %\begin{definition} %\cs{@dtlifreadonly}\marg{true part}\marg{false part} %\end{definition} % Checks if current loop level is read only %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \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}{\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} \newcommand*{\DTLappendtorow}[2]{% \ifnum\dtlforeachlevel=0\relax \PackageError{datatool}{\string\DTLappendrow\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\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 =\dtlcolumnindex{\@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. % Expand entry value before storing. %\changes{2.03}{2009 November 15}{value expanded before storing} % \begin{macrocode} \protected@edef\@dtl@tmp{#2}% \expandafter\@dtl@toks\expandafter{\@dtl@tmp}% % \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 } % \end{macrocode} %\end{macro} % %\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} \newcommand*{\DTLremoveentryfromrow}[1]{% \ifnum\dtlforeachlevel=0\relax \PackageError{datatool}{\string\DTLremoventryfromrow\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\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 value (given by \verb|#2|). %\changes{2.03}{2009 November 15}{expand replacement entry} % \begin{macrocode} \protected@edef\@dtl@tmp{#2}% \expandafter\@dtl@toks\expandafter{\@dtl@tmp}% 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 % \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} % Apply sort direction %\changes{2.01}{2009 March 27}{fixed sort direction} % \begin{macrocode} \multiply\dtl@sortresult by -\@dtl@sortdirection\relax } % \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}\ma