diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/datatool/datatool.dtx |
Initial commit
Diffstat (limited to 'macros/latex/contrib/datatool/datatool.dtx')
-rw-r--r-- | macros/latex/contrib/datatool/datatool.dtx | 29468 |
1 files changed, 29468 insertions, 0 deletions
diff --git a/macros/latex/contrib/datatool/datatool.dtx b/macros/latex/contrib/datatool/datatool.dtx new file mode 100644 index 0000000000..9115c37a69 --- /dev/null +++ b/macros/latex/contrib/datatool/datatool.dtx @@ -0,0 +1,29468 @@ +%\iffalse +% datatool.dtx generated using makedtx version 1.2 (c) Nicola Talbot +% Command line args: +% -macrocode "databib\.bst" +% -codetitle "" +% -setambles "databib\.bst=>\nopreamble\nopostamble" +% -src "datatool-base.sty\Z=>datatool-base.sty" +% -src "datatool-fp.sty\Z=>datatool-fp.sty" +% -src "datatool-pgfmath.sty\Z=>datatool-pgfmath.sty" +% -src "datatool.sty\Z=>datatool.sty" +% -src "datagidx.sty\Z=>datagidx.sty" +% -src "databib.sty\Z=>databib.sty" +% -src "databar.sty\Z=>databar.sty" +% -src "datapie.sty\Z=>datapie.sty" +% -src "dataplot.sty\Z=>dataplot.sty" +% -src "person.sty\Z=>person.sty" +% -src "databib.bst\Z=>databib.bst" +% -doc "datatool-manual.tex" +% -author "Nicola Talbot" +% -comment "databib\.bst" +% datatool +% Created on 2018/12/7 15:44 +%\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 \~} +%</package> +%\fi +% \iffalse +% Doc-Source file to use with LaTeX2e +% Copyright (C) 2018 Nicola Talbot, all rights reserved. +% \fi +% \iffalse +%<*driver> +\documentclass[report,widecs]{nlctdoc} + +\iffalse +datatool-manual.tex is a stub file used by makedtx to create +datatool.dtx +\fi + +\DeleteShortVerb{|} + +\usepackage{datatool} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage[colorlinks, + bookmarks, + hyperindex=false, + pdfauthor={Nicola L. C. Talbot}, + pdftitle={datatool: Databases and data manipulation}, + pdfkeywords={LaTeX,package,database,data,chart,plot}]{hyperref} + +\doxitem{Counter}{counter}{counters} +\doxitem{Option}{option}{package options} + +\CheckSum{24081} + +\RecordChanges +\PageIndex +\setcounter{IndexColumns}{2} + +\begin{document} +\DocInput{datatool.dtx} +\end{document} +%</driver> +%\fi +%\MakeShortVerb{"} +% +%\title{Documented Code for datatool v2.31} +%\author{Nicola L. C. Talbot\\ +%\url{http://www.dickimaw-books.com/}} +% +%\date{2018-12-07} +%\maketitle +% +%\pagenumbering{roman} +% +%This is the documented code for the \styfmt{datatool} bundle. See +%\url{datatool-user.pdf} for the main user manual. +% +%\clearpage +%\pdfbookmark[0]{Contents}{contents} +%\tableofcontents +% +%\pagenumbering{arabic} +% +%\StopEventually{% +% \clearpage\phantomsection +% \addcontentsline{toc}{chapter}{Index}% +% \PrintIndex +% \clearpage\phantomsection +% \addcontentsline{toc}{chapter}{History}\PrintChanges +%} +% +% +% +%\iffalse +% \begin{macrocode} +%<*datatool-base.sty> +% \end{macrocode} +%\fi +%\chapter{datatool-base.sty} +%\label{sec:code:datatool-base} +% This package provides all the basic commands needed by various +% packages in the \styfmt{datatool} bundle. +% +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datatool-base}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{etoolbox} +\RequirePackage{amsmath} +\RequirePackage{xkeyval} +\RequirePackage{xfor} +\RequirePackage{ifthen} +% \end{macrocode} +% Version of \isty{substr} required that fixes +% \cs{su@IfSubStringInString} +% \begin{macrocode} +\RequirePackage{substr}[2009/10/20] +% \end{macrocode} +% +%\section{Package Options} +% +%\begin{option}{verbose} +% Define key for package option \pkgopt{verbose}. (This also +% switches the \sty{fp} messages on/off if \sty{datatool-fp} used.) +% This boolean may already have been defined if \sty{datatool} has +% been loaded. +% \begin{macrocode} +\ifundef{\ifdtlverbose} +{ + \define@boolkey{datatool-base.sty}[dtl]{verbose}[true]{} +}% +{} +% \end{macrocode} +%\end{option} +%\begin{option}{math} +% Determine whether to use \sty{fp} or \sty{pgfmath} for the +% arithmetic commands. The default is to use \sty{fp}. +% \begin{macrocode} +\define@choicekey{datatool-base.sty}{math}[\val\nr]{fp,pgfmath}{% + \renewcommand*\@dtl@mathprocessor{#1}% +} +% \end{macrocode} +%\end{option} +% +%\begin{option}{utf8} +%\changes{2.24}{2016-01-12}{new} +% Enable UTF-8 support in comparison handlers. This is still a bit +% experimental, so it needs to be explicitly switched on. +% \begin{macrocode} +\define@boolkey{datatool-base.sty}[@dtl@]{utf8}[true]{} +\ifdef\UTFviii@two@octets +{\booltrue{@dtl@utf8}}% +{\boolfalse{@dtl@utf8}} +% \end{macrocode} +%\end{option} +% +%\begin{macro}{\dtlenableUTFviii} +%\changes{2.24}{2016-01-12}{new} +% \begin{macrocode} +\newcommand*{\dtlenableUTFviii}{\booltrue{@dtl@utf8}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldisableUTFviii} +%\changes{2.24}{2016-01-12}{new} +% \begin{macrocode} +\newcommand*{\dtldisableUTFviii}{\boolfalse{@dtl@utf8}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@mathprocessor} +% \begin{macrocode} +\providecommand*{\@dtl@mathprocessor}{fp} +% \end{macrocode} +%\end{macro} +% +% Process options: +% \begin{macrocode} +\ProcessOptionsX +% \end{macrocode} +% +% Load package dealing with numerical processes: +% \begin{macrocode} +\RequirePackage{datatool-\@dtl@mathprocessor} +% \end{macrocode} +% +%\section{Utilities} +% +%\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} +% +%\begin{macro}{\@dtl@toks} +% \begin{macrocode} +\newtoks\@dtl@toks +% \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@ifsingle} +%\begin{definition} +%\cs{dtl@ifsingle}\marg{arg}\marg{true part}\marg{false part} +%\end{definition} +% If there is only one object in \meta{arg} (without expansion) +% do \meta{true part}, otherwise do false part. +% \begin{macrocode} +\newcommand{\dtl@ifsingle}[3]{% + \def\@dtl@arg{#1}% + \ifdefempty{\@dtl@arg}% + {% + #3% + }% + {% + \@dtl@ifsingle#1\@nil{#2}{#3}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@ifsingle} +% \begin{macrocode} +\def\@dtl@ifsingle#1#2\@nil#3#4{% + \def\dtl@sg@arg{#2}% + \ifdefempty{\dtl@sg@arg}% + {% + #3% + }% + {% + #4% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@ifsingleorUTFviii} +%\changes{2.24}{2016-01-12}{new} +% As above but also checks for UTF8. +% \begin{macrocode} +\newcommand{\dtl@ifsingleorUTFviii}[3]{% + \ifbool{@dtl@utf8} + {% + \def\@dtl@arg{#1}% + \ifdefempty{\@dtl@arg}% + {% + #3% + }% + {% + \expandafter\dtl@if@two@octets#1\relax\relax\dtl@end@if@two@octets + {% + \dtl@getfirst@UTFviii#1\@nil\end@dtl@getfirst@UTFviii + \ifdefempty\dtl@rest{#2}{#3}% + }% + {% + \@dtl@ifsingle#1\@nil{#2}{#3}% + }% + }% + }% + {% + \dtl@ifsingle{#1}{#2}{#3}% + }% +}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlifintopenbetween} +%\begin{definition} +%\cs{dtlifintopenbetween}\marg{num}\marg{min}\marg{max}\marg{true +%part}\marg{false part} +%\end{definition} +% If we're dealing with integers it's more efficient to use \TeX's +% \cs{ifnum}. +% \begin{macrocode} +\newcommand{\dtlifintopenbetween}[5]{% + \ifnum#1>#2\relax +% \end{macrocode} +% Greater than minimum value. Is it less than the maximum? +% \begin{macrocode} + \ifnum#1<#3\relax + #4% + \else + #5% + \fi + \else + #5% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlifintclosedbetween} +%\begin{definition} +%\cs{dtlifintclosedbetween}\marg{num}\marg{min}\marg{max}\marg{true +%part}\marg{false part} +%\end{definition} +% If we're dealing with integers it's more efficient to use \TeX's +% \cs{ifnum}. +% \begin{macrocode} +\newcommand{\dtlifintclosedbetween}[5]{% + \dtlifintopenbetween{#1}{#2}{#3}{#4}% + {% +% \end{macrocode} +% Check end points. +% \begin{macrocode} + \ifnum#1=#2\relax + #4% + \else + \ifnum#1=#3\relax + #4% + \else + #5% + \fi + \fi + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\long@collect@body} +% Need long versions of \isty{amsmath}'s \cs{collect@body}. These macros are +% adapted from the macros defined by \sty{amsmath}. +% \begin{macrocode} +\long\def\long@collect@body#1{% + \@envbody{\@xp#1\@xp{\the\@envbody}}% + \edef\process@envbody{\the\@envbody\@nx\end{\@currenvir}}% + \@envbody\@emptytoks \def\begin@stack{b}% + \begingroup + \@xp\let\csname\@currenvir\endcsname\long@collect@@body + \edef\process@envbody{\@xp\@nx\csname\@currenvir\endcsname}% + \process@envbody +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\long@addto@envbody} +%\changes{2.10}{2012-07-18}{new} +% Adapted from \isty{amsmath}'s \cs{addto@envbody} +% \begin{macrocode} +\long\def\long@addto@envbody#1{% + \toks@{#1}% + \edef\@dtl@tmp{\the\@envbody\the\toks@}% + \global\@envbody\@xp{\@dtl@tmp}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\long@collect@@body} +%\changes{2.10}{2012-07-18}{new} +% Adapted from \isty{amsmath}'s \cs{collect@body} +% \begin{macrocode} +\long\def\long@collect@@body#1\end#2{% + \protected@edef\begin@stack{% + \long@push@begins#1\begin\end \@xp\@gobble\begin@stack + }% + \ifx\@empty\begin@stack + \endgroup + \@checkend{#2}% + \long@addto@envbody{#1}% + \else + \long@addto@envbody{#1\end{#2}}% + \fi + \process@envbody +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\long@push@begins} +%\changes{2.10}{2012-07-18}{new} +%Adapted from \isty{amsmath}'s \cs{push@begins} +% \begin{macrocode} +\long\def\long@push@begins#1\begin#2{% + \ifx\end#2\else b\@xp\long@push@begins\fi +} +% \end{macrocode} +%\end{macro} +% +%\subsection{General List Utilities} +% +%\begin{macro}{\DTLifinlist} +%\begin{definition} +%\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}.) +% \begin{macrocode} +\newcommand*{\DTLifinlist}[4]{% + \def\@dtl@doifinlist##1,#1,##2\end@dtl@doifinlist{% + \def\@before{##1}% + \def\@after{##2}% + }% + \expandafter\@dtl@doifinlist\expandafter,#2,#1,\@nil + \end@dtl@doifinlist + \ifx\@after\@nnil +% not found + #4% + \else +% found + #3% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifDTLlistskipempty} +%\changes{2.31}{2018-12-07}{new} +%If true, skip empty elements in the list-related commands below. +% \begin{macrocode} +\newif\ifDTLlistskipempty +\DTLlistskipemptytrue +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLlistelement} +%\begin{definition} +%\cs{DTLlistelement}\marg{list}\marg{idx} +%\end{definition} +%Does the \meta{idx}th element in the list. The index +%should start from 1 for the first element. +% \begin{macrocode} +\newrobustcmd{\DTLlistelement}[2]{% +% \end{macrocode} +%The \cs{@for}-loop is scoped in case it's nested. +% \begin{macrocode} + \begingroup + \@dtl@tmpcount=0\relax + \@for\@dtl@element:=#1\do{% + \ifDTLlistskipempty + \ifdefempty{\@dtl@element}% + {}% + {% + \advance\@dtl@tmpcount by 1\relax% + \ifnum\@dtl@tmpcount=#2 \@dtl@element\@endfortrue\fi + }% + \else + \advance\@dtl@tmpcount by 1\relax% + \ifnum\@dtl@tmpcount=#2 \@dtl@element\@endfortrue\fi + \fi + }% + \if@endfor \else\@dtl@listelement@outofrange{#2}\fi + \endgroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLfetchlistelement} +%\begin{definition} +%\cs{DTLfetchlistelement}\marg{list}\marg{idx}\marg{cs} +%\end{definition} +%Fetches the \meta{idx}th element in the list and stores in \meta{cs}. The index +%should start from 1 for the first element. +% \begin{macrocode} +\newrobustcmd{\DTLfetchlistelement}[3]{% +% \end{macrocode} +%The \cs{@for}-loop is scoped in case it's nested. +% \begin{macrocode} + \begingroup + \@dtl@tmpcount=0\relax + \@for\@dtl@element:=#1\do{% + \ifDTLlistskipempty + \ifdefempty{\@dtl@element}% + {}% + {% + \advance\@dtl@tmpcount by 1\relax% + \ifnum\@dtl@tmpcount=#2 \@endfortrue\fi + }% + \else + \advance\@dtl@tmpcount by 1\relax% + \ifnum\@dtl@tmpcount=#2 \@endfortrue\fi + \fi + }% + \if@endfor \else\def\@dtl@element{\@dtl@listelement@outofrange{#2}}\fi + \edef\x{% + \endgroup + \noexpand\def\noexpand#3{\expandonce\@dtl@element}% + }\x +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@listelement@outofrange} +%\changes{2.31}{2018-12-07}{new} +% \begin{macrocode} +\newcommand{\@dtl@listelement@outofrange}[1]{% + \PackageWarning{datatool-base}{List index `\number#1' out of range}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLnumitemsinlist} +%\begin{definition} +%\cs{DTLnumitemsinlist}\marg{list}\marg{cmd} +%\end{definition} +% Counts number of non-empty elements in list and stores result in control +% sequence \meta{cmd}. +%\changes{2.31}{2018-12-07}{made robust} +% \begin{macrocode} +\newrobustcmd{\DTLnumitemsinlist}[2]{% + \@dtl@tmpcount=0\relax + \@for\@dtl@element:=#1\do{% + \ifDTLlistskipempty + \ifdefempty{\@dtl@element}% + {}% + {\advance\@dtl@tmpcount by 1\relax}% + \else + \advance\@dtl@tmpcount by 1\relax + \fi + }% + \edef#2{\number\@dtl@tmpcount}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@choplast} +%\begin{definition} +% \cs{dtl@choplast}\marg{list}\marg{rest}\marg{last} +%\end{definition} +% Chops the last element off a comma separated list, putting the +% last element in the control sequence \meta{last} and putting +% the rest in the control sequence \meta{rest}. The control +% sequence \meta{list} is unchanged. If the list is empty, both +% \meta{last} and \meta{rest} will be empty. +% \begin{macrocode} +\newcommand*{\dtl@choplast}[3]{% +% \end{macrocode} +% Set \meta{rest} to empty: +% \begin{macrocode} + \let#2\@empty +% \end{macrocode} +% Set \meta{last} to empty: +% \begin{macrocode} + \let#3\@empty +% \end{macrocode} +% Iterate through \meta{list}: +% \begin{macrocode} + \@for\@dtl@element:=#1\do{% + \ifdefempty{#3}% + {% +% \end{macrocode} +% First iteration, don't set \meta{rest}. +% \begin{macrocode} + }% + {% + \ifdefempty{#2}% + {% +% \end{macrocode} +% Second iteration, set \meta{rest} to \meta{last} (which is +% currently set to the previous value: +% \begin{macrocode} + \expandafter\toks@\expandafter{#3}% + \edef#2{{\the\toks@}}% + }% + {% +% \end{macrocode} +% Subsequent iterations, set \meta{rest} to \meta{rest},\meta{last} +% (\meta{last} is currently set to the previous value): +% \begin{macrocode} + \expandafter\toks@\expandafter{#3}% + \expandafter\@dtl@toks\expandafter{#2}% + \edef#2{\the\@dtl@toks,{\the\toks@}}% + }% + }% +% \end{macrocode} +% Now set \meta{last} to current element. +% \begin{macrocode} + \let#3=\@dtl@element% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@chopfirst} +%\begin{definition} +% \cs{dtl@chopfirst}\marg{list}\marg{first}\marg{rest} +%\end{definition} +% Chops first element off \meta{list} and store in \meta{first}. +% The remainder of the list is stored in \meta{rest}. (\meta{list} +% remains unchanged.) +% \begin{macrocode} +\newcommand*{\dtl@chopfirst}[3]{% + \let#2=\@empty + \let#3=\@empty + \@for\@dtl@element:=#1\do{% + \let#2=\@dtl@element + \@endfortrue + }% + \if@endfor + \let#3=\@forremainder + \fi + \@endforfalse +} +% \end{macrocode} +%\end{macro} +% +%I made a bit of a blunder here. \cs{dtl@sortlist} was supposed to +%work with commands like \cs{dtlcompare}, but those commands require +%three arguments, the first being the register in which to store the +%result. This contradicts the requirements of \cs{dtl@sortlist}. The +%\qt{bug fix} in v2.26 fixed it to work with commands like +%\cs{dtlcompare}, but that broke the documented design (which breaks +%the \sty{glossaries} package). The other problem is that +%\cs{dtl@insertinto} actually sorts in the reverse order. +%So v2.27 undoes the change from v2.26 to ensure backward +%compatibility and provides an alternative user-level command +%\cs{dltsortlist}, that's designed to work with the three-argument +%handler commands like \cs{dtlcompare}. +% +%\begin{macro}{\dtl@sortlist} +%\begin{definition} +% \cs{dtl@sortlist}\marg{list}\marg{criteria cmd} +%\end{definition} +% Performs an insertion sort on \meta{list}, where \meta{criteria cmd} +% is a macro which takes two arguments \meta{a} and \meta{b}. +% \meta{criteria cmd} must set the count register \cs{dtl@sortresult} +% to either $-1$ (\meta{b} less than \meta{a}), 0 (\meta{a} is +% equal to \meta{b}) or 1 (\meta{b} is greater than \meta{a}.) +% \begin{macrocode} +\newcommand{\dtl@sortlist}[2]{% +\def\@dtl@sortedlist{}% +\@for\@dtl@currentrow:=#1\do{% +\expandafter\dtl@insertinto\expandafter + {\@dtl@currentrow}{\@dtl@sortedlist}{#2}% +\@endforfalse}% +\let#1=\@dtl@sortedlist +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@insertinto} +%\begin{definition} +% \cs{dtl@insertinto}\marg{element}\marg{sorted-list}\marg{criteria cmd} +%\end{definition} +% Inserts \meta{element} into the sorted list \meta{sorted-list} +% according to the criteria given by \meta{criteria cmd} (see above.) +% \begin{macrocode} +\newcommand{\dtl@insertinto}[3]{% + \def\@dtl@newsortedlist{}% + \@dtl@insertdonefalse + \@for\dtl@srtelement:=#2\do{% + \if@dtl@insertdone + \expandafter\toks@\expandafter{\dtl@srtelement}% + \edef\@dtl@newstuff{{\the\toks@}}% + \else +% \end{macrocode} +%\changes{2.26}{2016-07-20}{fixed bug (missing \cs{dtl@sortresult})} +%\changes{2.27}{2016-07-28}{undone the incorrect change in v2.26} +% \begin{macrocode} + \expandafter#3\expandafter{\dtl@srtelement}{#1}% +% \end{macrocode} +%\changes{2.26}{2016-07-20}{fixed bug (incorrect inequality sign)} +%\changes{2.27}{2016-07-28}{undone the incorrect change in v2.26} +% \begin{macrocode} + \ifnum\dtl@sortresult<0\relax + \expandafter\toks@\expandafter{\dtl@srtelement}% + \@dtl@toks{#1}% + \edef\@dtl@newstuff{{\the\@dtl@toks},{\the\toks@}}% + \@dtl@insertdonetrue + \else + \expandafter\toks@\expandafter{\dtl@srtelement}% + \edef\@dtl@newstuff{{\the\toks@}}% + \fi + \fi + \ifdefempty{\@dtl@newsortedlist}% + {% + \expandafter\toks@\expandafter{\@dtl@newstuff}% + \edef\@dtl@newsortedlist{\the\toks@}% + }% + {% + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \expandafter\@dtl@toks\expandafter{\@dtl@newstuff}% + \edef\@dtl@newsortedlist{\the\toks@,\the\@dtl@toks}% + }% + \@endforfalse + }% + \ifdefempty{\@dtl@newsortedlist}% + {% + \@dtl@toks{#1}% + \edef\@dtl@newsortedlist{{\the\@dtl@toks}}% + }% + {% + \if@dtl@insertdone + \else + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \@dtl@toks{#1}% + \edef\@dtl@newsortedlist{\the\toks@,{\the\@dtl@toks}}% + \fi + }% + \global\let#2=\@dtl@newsortedlist +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsortlist} +%\changes{2.27}{2016-07-28}{new} +%\begin{definition} +% \cs{dtlsortlist}\marg{list}\marg{criteria cmd} +%\end{definition} +% As \cs{dtl@sortlist} but the \meta{criteria} command must take +% three arguments. +% \begin{macrocode} +\newcommand{\dtlsortlist}[2]{% +\def\@dtl@sortedlist{}% +\@for\@dtl@currentrow:=#1\do{% +\expandafter\dtlinsertinto\expandafter + {\@dtl@currentrow}{\@dtl@sortedlist}{#2}% +\@endforfalse}% +\let#1=\@dtl@sortedlist +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlinsertinto} +%\changes{2.27}{2016-07-28}{new} +%\begin{definition} +% \cs{dtlinsertinto}\marg{element}\marg{sorted-list}\marg{criteria cmd} +%\end{definition} +% Inserts \meta{element} into the sorted list \meta{sorted-list} +% according to the criteria given by \meta{criteria cmd}, which +% should be a command that takes three arguments +% \marg{reg}\marg{A}\marg{B}, where \meta{reg} is a count register +% in which to store the result, \meta{A} is the first element and +% \meta{B} is the second element to compare. +% \begin{macrocode} +\newcommand{\dtlinsertinto}[3]{% + \def\@dtl@newsortedlist{}% + \@dtl@insertdonefalse + \@for\dtl@srtelement:=#2\do{% + \expandafter\DTLifSubString\expandafter{\dtl@srtelement}{,} + {% + \expandafter\toks@\expandafter{\dtl@srtelement}% + \edef\dtl@srtelement{{\the\toks@}}% + }% + {% + } + \if@dtl@insertdone + \let\@dtl@newstuff\dtl@srtelement + \else + \expandafter#3\expandafter\dtl@sortresult + \expandafter{\dtl@srtelement}{#1}% + \ifnum\dtl@sortresult>0\relax + \DTLifSubString{#1}{,}% + {% + \@dtl@toks{{#1}}% + }% + {% + \@dtl@toks{#1}% + }% + \expandafter\toks@\expandafter{\dtl@srtelement}% + \edef\@dtl@newstuff{\the\@dtl@toks,\the\toks@}% + \@dtl@insertdonetrue + \else + \expandafter\toks@\expandafter{\dtl@srtelement}% + \edef\@dtl@newstuff{{\the\toks@}}% + \let\@dtl@newstuff\dtl@srtelement + \fi + \fi + \ifdefempty{\@dtl@newsortedlist}% + {% + \expandafter\toks@\expandafter{\@dtl@newstuff}% + \edef\@dtl@newsortedlist{\the\toks@}% + }% + {% + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \expandafter\@dtl@toks\expandafter{\@dtl@newstuff}% + \edef\@dtl@newsortedlist{\the\toks@,\the\@dtl@toks}% + }% + \@endforfalse + }% + \ifdefempty{\@dtl@newsortedlist}% + {% + \DTLifSubString{#1}{,}% + {% + \@dtl@toks{{#1}}% + }% + {% + \@dtl@toks{#1}% + }% + \edef\@dtl@newsortedlist{\the\@dtl@toks}% + }% + {% + \if@dtl@insertdone + \else + \DTLifSubString{#1}{,}% + {% + \@dtl@toks{{#1}}% + }% + {% + \@dtl@toks{#1}% + }% + \expandafter\toks@\expandafter{\@dtl@newsortedlist}% + \edef\@dtl@newsortedlist{\the\toks@,\the\@dtl@toks}% + \fi + }% + \global\let#2=\@dtl@newsortedlist +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\edtlinsertinto} +%\changes{2.27}{2016-07-28}{new} +%\begin{definition} +% \cs{edtlinsertinto}\marg{element}\marg{sorted-list}\marg{criteria cmd} +%\end{definition} +%First expands \meta{element} before inserting into the list. +% \begin{macrocode} +\newcommand*{\edtlinsertinto}[3]{% + \protected@edef\dtl@srtelement{#1}% + \expandafter\dtlinsertinto\expandafter{\dtl@srtelement}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\if@dtl@insertdone} +% Define conditional to indicate whether the new entry has +% been inserted into the sorted list. +% \begin{macrocode} +\newif\if@dtl@insertdone +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@sortresult} +% Define \cs{dtl@sortresult} to be set by comparison macro. +% \begin{macrocode} +\newcount\dtl@sortresult +% \end{macrocode} +%\end{macro} +% +%This next command is based on the list iteration exercise +%given at +%\url{http://www.dickimaw-books.com/latex/admin/html/foreachtips.shtml#oxfordcomma} +%It's designed to format a comma-separated list using +%\cs{DTLlistformatsep} +%between each item except for the last. The separator for the +%last pair is \cs{DTLlistformatlastsep} if the list only contains two +%items or \cs{DTLlistformatoxford}\cs{DTLlistformatlastsep} if the list contains three or +%more items. Each item is formatted according to +%\cs{DTLlistformatitem}. +%\begin{macro}{\DTLlistformatsep} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\DTLlistformatsep}{, } +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLlistformatoxford} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\DTLlistformatoxford}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLandname} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\ifdef\andname +{\newcommand*{\DTLandname}{\andname}} +{\newcommand*{\DTLandname}{\&}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLlistformatlastsep} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\DTLlistformatlastsep}{ \DTLandname\space} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLlistformatitem} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\DTLlistformatitem}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@formatlist@handler} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\@dtl@formatlist@handler}[1]{% + \@dtl@formatlist@itemsep + \@dtl@formatlist@lastitem + \renewcommand{\@dtl@formatlist@lastitem}{% + \renewcommand{\@dtl@formatlist@itemsep}{% + \DTLlistformatsep + \renewcommand*{\@dtl@formatlist@prelastitemsep}{% + \DTLlistformatoxford}}% + \renewcommand{\@dtl@formatlist@prelastitem}{% + \@dtl@formatlist@prelastitemsep + \DTLlistformatlastsep}% + \DTLlistformatitem{#1}% + }% +}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatlist} +%\changes{2.28}{2017-11-10}{new} +%Formats the comma-separated list supplied in its argument. +%The unstarred version adds grouping. +% \begin{macrocode} +\newrobustcmd*{\DTLformatlist}{% + \@ifstar{\s@dtlformatlist}{\@dtlformatlist}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\s@dtlformatlist} +%\changes{2.28}{2017-11-10}{new} +%Starred version of \cs{DTLformatlist} doesn't add grouping. +% \begin{macrocode} +\newcommand*{\s@dtlformatlist}[1]{% + \def\@dtl@formatlist@itemsep{}% + \def\@dtl@formatlist@lastitem{}% + \def\@dtl@formatlist@prelastitem{}% + \def\@dtl@formatlist@prelastitemsep{}% + \@for\@dtl@formatlist@item:=#1\do{% + \ifDTLlistskipempty + \ifdefempty{\@dtl@formatlist@item}% + {}% + {\expandafter\@dtl@formatlist@handler\expandafter{\@dtl@formatlist@item}}% + \else + \expandafter\@dtl@formatlist@handler\expandafter{\@dtl@formatlist@item}% + \fi + }% + \@dtl@formatlist@prelastitem\@dtl@formatlist@lastitem +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlformatlist} +%\changes{2.28}{2017-11-10}{new} +%Unstarred version of \cs{DTLformatlist} adds grouping. +% \begin{macrocode} +\newcommand*{\@dtlformatlist}[1]{{\s@dtlformatlist{#1}}} +% \end{macrocode} +%\end{macro} +% +% \subsection{General Token Utilities} +%\changes{2.28}{2017-11-10}{renamed \cs{toks@g...} to +%\cs{dtl@toks@g...}} +%\begin{macro}{\@dtl@toks@gput@right@cx} +%\begin{definition} +%\cs{dtl@toks@gput@right@cx}\marg{toks name}\marg{stuff} +%\end{definition} +% Globally appends stuff to token register \cs{}\meta{toks name} +% \begin{macrocode} +\newcommand{\@dtl@toks@gput@right@cx}[2]{% + \def\@dtl@toks@name{#1}% + \edef\@dtl@stuff{#2}% + \global\csname\@dtl@toks@name\endcsname\expandafter + \expandafter\expandafter{\expandafter\the + \csname\expandafter\@dtl@toks@name\expandafter\endcsname\@dtl@stuff}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@toks@gconcat@middle@cx} +%\begin{definition} +%\cs{dtl@toks@gconcat@middle@cx}\marg{toks name}\marg{before toks}\marg{stuff}\marg{after toks} +%\end{definition} +% Globally sets token register \cs{}\meta{toks name} to +% the contents of \meta{before toks} concatenated with +% \meta{stuff} (expanded) and the contents of \meta{after toks} +% \begin{macrocode} +\newcommand{\@dtl@toks@gconcat@middle@cx}[4]{% + \def\@dtl@toks@name{#1}% + \edef\@dtl@stuff{#3}% + \global\csname\@dtl@toks@name\endcsname\expandafter\expandafter + \expandafter\expandafter\expandafter + \expandafter\expandafter{\expandafter\expandafter\expandafter + \the\expandafter\expandafter\expandafter#2% + \expandafter\@dtl@stuff\the#4}% +} +% \end{macrocode} +%\end{macro} +% +%\section{Locale Dependent Information} +% +%\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@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}[\DescribeMacro{\DTLconverttodecimal}] +% \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. +%\changes{2.12}{2012-11-30}{switched to \cs{ifdefempty}} +% \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\ifdefempty{\noexpand\@dtl@fracpart} + {% + \noexpand\def\noexpand\@dtl@fracpart{0}% + }% + {% + \noexpand\@dtl@getfracpart##2\noexpand\relax + \noexpand\@dtl@choptrailingzeroes{\noexpand\@dtl@fracpart}% + }% + }% + \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\ifdefempty{\noexpand\@dtl@org@currency}% + {% + }% + {% + \noexpand\let\noexpand\@dtl@currency\noexpand\@dtl@org@currency + }% + \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{% + \dtlifnumeq{#2}{0}% + {% + \edef\@dtl@tmpcpz{\@dtl@tmpcpz#1}% + \let\@dtl@chopzeroesnext=\@dtl@gobbletonil + }% + {% + \edef\@dtl@tmpcpz{\@dtl@tmpcpz#1}% + \let\@dtl@chopzeroesnext=\@dtl@chop@trailingzeroes + }% + \@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 + \dtlifnumeq{\@dtl@fracpart}{0}% + {% + \edef#2{\@dtl@intpart}% + }% + {% + \edef#2{\@dtl@intpart\@dtl@decimal\@dtl@fracpart}% + }% +} +% \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}% + \ifdefempty\@dtl@fracpart + {% + \def\@dtl@fracpart{0}% + }% + {% + \@dtl@decimaltolocalefrac#2\relax + }% +} +% \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}). +%\changes{2.22}{2014-06-10}{removed \cs{@dtl@choptrailingzeroes} +% and added \cs{@dtl@chopexcessfrac}}% +%\cs{@dtl@choptrailingzeroes} was originally used, but this +%interfered with \cs{dtlround}. Removing +%\cs{@dtl@choptrailingzeroes} caused a `Number too big' error, +% so any fractional part over 2147483647 needs to be trimmed. +% Unfortunately \verb|\ifnum#1>2147483647| also causes the +% `Number too big' error, so count the digits, and if the digit +% count exceeds 9, trim the excess. +% \begin{macrocode} +\def\@dtl@decimaltolocalefrac#1.\relax{% + \count@=0\relax + \@dtl@digitcount#1\relax + \ifnum\count@>9\relax + \@dtl@chopexcessfrac#1000000000\@nil + \else + \def\@dtl@fracpart{#1}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@chopexcessfrac} +% Chop fractional part to just 9 digits. +%\changes{2.22}{2014-06-10}{new} +% \begin{macrocode} +\newcommand*{\@dtl@chopexcessfrac}[9]{% + \def\@dtl@fracpart{#1#2#3#4#5#6#7#8#9}% + \@dtl@gobbletonil +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@digitcount} +% Counts the number of digits in \#1. +%\changes{2.22}{2014-06-10}{new} +% \begin{macrocode} +\newcommand*{\@dtl@digitcount}[1]{% + \ifx\relax#1\relax + \let\@dtl@digitcountnext\relax + \else + \advance\count@ by \@ne + \let\@dtl@digitcountnext\@dtl@digitcount + \fi + \@dtl@digitcountnext +} +% \end{macrocode} +%\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}% + \dtlifnumeq{\@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 + }% + {% + \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 + }% +} +% \end{macrocode} +%\end{macro} +% +% Set the defaults: +% \begin{macrocode} +\@dtl@construct@getnums +\expandafter\@dtl@construct@stripnumgrpchar\expandafter + {\@dtl@numbergroupchar} +% \end{macrocode} +% +%\subsection{Currencies} +%\begin{macro}{\@dtl@currencies} +% \cs{@dtl@currencies} stores all known currencies. +% \begin{macrocode} +\newcommand*{\@dtl@currencies}{\$,\pounds} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLnewcurrencysymbol} +%\begin{definition} +% \cs{DTLaddcurrency}\marg{symbol} +%\end{definition} +% Adds \meta{symbol} to the list of known currencies +% \begin{macrocode} +\newcommand*{\DTLnewcurrencysymbol}[1]{% + \expandafter\toks@\expandafter{\@dtl@currencies}% + \@dtl@toks{#1}% + \edef\@dtl@currencies{\the\@dtl@toks,\the\toks@}% +} +% \end{macrocode} +%\end{macro} +% If any of the following currency commands have been defined, +% add them to the list: +% \begin{macrocode} +\AtBeginDocument{% + \@ifundefined{texteuro}{}{\DTLnewcurrencysymbol{\texteuro}}% + \@ifundefined{textdollar}{}{\DTLnewcurrencysymbol{\textdollar}}% + \@ifundefined{textstirling}{}{\DTLnewcurrencysymbol{\textstirling}}% + \@ifundefined{textyen}{}{\DTLnewcurrencysymbol{\textyen}}% + \@ifundefined{textwon}{}{\DTLnewcurrencysymbol{\textwon}}% + \@ifundefined{textcurrency}{}{\DTLnewcurrencysymbol{\textcurrency}}% + \@ifundefined{euro}{}{\DTLnewcurrencysymbol{\euro}}% + \@ifundefined{yen}{}{\DTLnewcurrencysymbol{\yen}}% +} +% \end{macrocode} +%\begin{macro}{\@dtl@standardize@currency} +%\begin{definition} +%\cs{@dtl@standardize@currency}\marg{cmd} +%\end{definition} +% Substitutes the first currency symbol found in \meta{cmd} +% with "\$". This is used when testing text to determine +% if it is currency. The original currency symbol is stored +% in \cs{@dtl@org@currency}, so that it can be replaced later. +% If no currency symbol is found, \cs{@dtl@org@currency} will +% be empty. +% \begin{macrocode} +\newcommand{\@dtl@standardize@currency}[1]{% + \def\@dtl@org@currency{}% + \@for\@dtl@thiscurrency:=\@dtl@currencies\do{% + \expandafter\toks@\expandafter{\@dtl@thiscurrency}% + \edef\@dtl@dosubs{\noexpand\DTLsubstitute{\noexpand#1}% + {\the\toks@}{\noexpand\$}}% + \@dtl@dosubs + \ifdefempty{\@dtl@replaced}% + {% + }% + {% + \let\@dtl@org@currency=\@dtl@replaced + \@endfortrue + }% + }% + \@endforfalse +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@currency} +%\cs{@dtl@currency} is set by \cs{DTLlocaltodecimal} and +%\cs{@dtl@checknumerical}. It is used by \cs{DTLdecimaltocurrency}. +% Set to "\$" by default. +% \begin{macrocode} +\newcommand*{\@dtl@currency}{\$} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLsetdefaultcurrency} +%\cs{DTLsetdefaultcurrency}\marg{symbol} sets the default currency. +% \begin{macrocode} +\newcommand*{\DTLsetdefaultcurrency}[1]{% + \renewcommand*{\@dtl@currency}{#1}% +} +% \end{macrocode} +%\end{macro} +% +% \section{Floating Point Arithmetic} +% The commands defined in this section all use the equivalent +% commands provided by the \sty{fp} or \sty{pgfmath} packages, but +% first convert the decimal number into the required format. +% +%\begin{macro}{\DTLadd} +%\begin{definition} +% \cs{DTLadd}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} + \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLadd}[3]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \DTLconverttodecimal{#3}{\@dtl@numii}% + \dtladd{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgadd} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgadd}[3]{% + \DTLadd{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLaddall} +%\begin{definition} +%\cs{DTLaddall}\marg{cmd}\marg{num list} +%\end{definition} +% Sums all the values in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLaddall}[2]{% + \def\@dtl@sum{0}% + \@for\dtl@thisval:=#2\do{% + \expandafter\DTLconverttodecimal\expandafter{\dtl@thisval}{\@dtl@num}% + \dtladd{\@dtl@sum}{\@dtl@sum}{\@dtl@num}% + }% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@sum}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@sum}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgaddall} +%\begin{definition} +%\cs{DTLgaddall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgaddall}[2]{% + \DTLaddall{\@dtl@tmpi}{#2}% + \global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsub} +%\begin{definition} +% \cs{DTLsub}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} - \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLsub}[3]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \DTLconverttodecimal{#3}{\@dtl@numii}% + \dtlsub{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgsub} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgsub}[3]{% + \DTLsub{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmul} +%\begin{definition} +% \cs{DTLmul}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} $\times$ \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLmul}[3]{% + \let\@dtl@thisreplaced=\@empty + \DTLconverttodecimal{#2}{\@dtl@numi}% + \ifdefempty{\@dtl@replaced}% + {% + }% + {% + \let\@dtl@thisreplaced=\@dtl@replaced + }% + \DTLconverttodecimal{#3}{\@dtl@numii}% + \ifdefempty{\@dtl@replaced}% + {% + }% + {% + \let\@dtl@thisreplaced=\@dtl@replaced + }% + \dtlmul{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% + \ifdefempty{\@dtl@thisreplaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmul} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmul}[3]{% + \DTLmul{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLdiv} +%\begin{definition} +% \cs{DTLdiv}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = \meta{num1} / \meta{num2} +% \begin{macrocode} +\newcommand*{\DTLdiv}[3]{% + \let\@dtl@thisreplaced=\@empty + \DTLconverttodecimal{#2}{\@dtl@numi}% + \ifdefempty{\@dtl@replaced}% + {% + }% + {% + \let\@dtl@thisreplaced=\@dtl@replaced + }% + \DTLconverttodecimal{#3}{\@dtl@numii}% + \dtldiv{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% + \ifdefempty{\@dtl@thisreplaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \ifdefequal{\@dtl@thisreplaced}{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgdiv} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgdiv}[3]{% + \DTLdiv{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLabs} +%\begin{definition} +% \cs{DTLabs}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = abs(\meta{num}) +% \begin{macrocode} +\newcommand*{\DTLabs}[2]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \dtlabs{\@dtl@tmp}{\@dtl@numi}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgabs} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgabs}[2]{% + \DTLabs{\@dtl@tmpii}{#2}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLneg} +%\begin{definition} +% \cs{DTLneg}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = -\meta{num} +% \begin{macrocode} +\newcommand*{\DTLneg}[2]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \dtlneg{\@dtl@tmp}{\@dtl@numi}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgneg} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgneg}[2]{% + \DTLneg{\@dtl@tmpii}{#2}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsqrt} +%\begin{definition} +% \cs{DTLsqrt}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} = sqrt(\meta{num}) +% \begin{macrocode} +\newcommand*{\DTLsqrt}[2]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \dtlroot{\@dtl@tmpi}{\@dtl@numi}{2}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmpi}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmpi}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgsqrt} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgsqrt}[2]{% +\DTLsqrt{\@dtl@tmpii}{#2}% +\global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmin} +%\begin{definition} +% \cs{DTLmin}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = min(\meta{num1}, \meta{num2}) +% \begin{macrocode} +\newcommand*{\DTLmin}[3]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \DTLconverttodecimal{#3}{\@dtl@numii}% + \dtlifnumlt{\@dtl@numi}{\@dtl@numii}% + {% + \dtl@ifsingle{#2}% + {\let#1=#2}% + {\def#1{#2}}% + }% + {% + \dtl@ifsingle{#3}% + {\let#1=#3}% + {\def#1{#3}}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmin} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmin}[3]{% + \DTLmin{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLminall} +%\begin{definition} +%\cs{DTLminall}\marg{cmd}\marg{num list} +%\end{definition} +% Finds the minimum value in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLminall}[2]{% + \let\@dtl@min=\@empty + \@for\dtl@thisval:=#2\do{% + \expandafter\DTLconverttodecimal\expandafter{\dtl@thisval}{\@dtl@num}% + \ifdefempty{\@dtl@min}% + {% + \let\@dtl@min=\@dtl@num + }% + {% + \dtlmin{\@dtl@min}{\@dtl@min}{\@dtl@num}% + }% + }% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@min}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@min}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgminall} +%\begin{definition} +%\cs{DTLgminall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgminall}[2]{% + \DTLminall{\@dtl@tmpi}{#2}% + \global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmax} +%\begin{definition} +% \cs{DTLmax}\marg{cmd}\marg{num1}\marg{num2} +%\end{definition} +% Sets \meta{cmd} = max(\meta{num1}, \meta{num2}) +% \begin{macrocode} +\newcommand*{\DTLmax}[3]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \DTLconverttodecimal{#3}{\@dtl@numii}% + \dtlmax{\@dtl@tmp}{\@dtl@numi}{\@dtl@numii}% + \dtlifnumgt{\@dtl@numi}{\@dtl@numii}% + {% + \dtl@ifsingle{#2}% + {\let#1=#2}% + {\def#1{#2}}% + }% + {% + \dtl@ifsingle{#3}% + {\let#1=#3}% + {\def#1{#3}}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmax} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmax}[3]{% + \DTLmax{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmaxall} +%\begin{definition} +%\cs{DTLmaxall}\marg{cmd}\marg{num list} +%\end{definition} +% Finds the maximum value in \meta{num list} and stores in +% \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLmaxall}[2]{% + \let\@dtl@max=\@empty + \@for\dtl@thisval:=#2\do{% + \expandafter\DTLconverttodecimal\expandafter{\dtl@thisval}{\@dtl@num}% + \ifdefempty{\@dtl@max}% + {% + \let\@dtl@max\@dtl@num + }% + {% + \dtlmax{\@dtl@max}{\@dtl@max}{\@dtl@num}% + }% + }% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@max}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@max}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmaxall} +%\begin{definition} +%\cs{DTLgmaxall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmaxall}[2]{% +\DTLmaxall{\@dtl@tmpi}{#2}% +\global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmeanforall} +%\begin{definition} +%\cs{DTLmeanforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the arithmetic mean of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLmeanforall}[2]{% + \def\@dtl@mean{0}% + \def\@dtl@n{0}% + \@for\dtl@thisval:=#2\do{% + \expandafter\DTLconverttodecimal\expandafter{\dtl@thisval}{\@dtl@num}% + \dtladd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \dtladd{\@dtl@n}{\@dtl@n}{1}% + }% + \dtldiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@mean}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@mean}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgmeanforall} +%\begin{definition} +%\cs{DTLgmeanforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgmeanforall}[2]{% + \DTLmeanforall{\@dtl@tmpi}{#2}% + \global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLvarianceforall} +%\begin{definition} +%\cs{DTLvarianceforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the variance of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{fixed bug} +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLvarianceforall}[2]{% + \def\@dtl@mean{0}% + \def\@dtl@n{0}% + \let\@dtl@decvals=\@empty + \@for\dtl@thisval:=#2\do{% + \expandafter\DTLconverttodecimal\expandafter{\dtl@thisval}{\@dtl@num}% + \ifdefempty{\@dtl@decvals}% + {% + \let\@dtl@decvals=\@dtl@num + }% + {% + \expandafter\toks@\expandafter{\@dtl@decvals}% + \edef\@dtl@decvals{\the\toks@,\@dtl@num}% + }% + \dtladd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \dtladd{\@dtl@n}{\@dtl@n}{1}% + }% + \dtldiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% + \def\@dtl@var{0}% + \@for\@dtl@num:=\@dtl@decvals\do{% + \dtlsub{\@dtl@diff}{\@dtl@num}{\@dtl@mean}% + \dtlmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% + \dtladd{\@dtl@var}{\@dtl@var}{\@dtl@diff}% + }% + \dtldiv{\@dtl@var}{\@dtl@var}{\@dtl@n}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@var}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@var}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgvarianceforall} +%\begin{definition} +%\cs{DTLgvarianceforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgvarianceforall}[2]{% + \DTLvarianceforall{\@dtl@tmpi}{#2}% + \global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsdforall} +%\begin{definition} +%\cs{DTLsdforall}\marg{cmd}\marg{num list} +%\end{definition} +% Computes the standard deviation of all the values in \meta{num list} +% and stores in \meta{cmd} which must be a control sequence. +%\changes{1.01}{2007 Aug 17}{fixed bug} +%\changes{1.01}{2007 Aug 17}{removed extraneous space} +% \begin{macrocode} +\newcommand*{\DTLsdforall}[2]{% + \def\@dtl@mean{0}% + \def\@dtl@n{0}% + \let\@dtl@decvals=\@empty + \@for\dtl@thisval:=#2\do{% + \expandafter\DTLconverttodecimal\expandafter{\dtl@thisval}{\@dtl@num}% + \ifdefempty{\@dtl@decvals}% + {% + \let\@dtl@decvals=\@dtl@num + }% + {% + \expandafter\toks@\expandafter{\@dtl@decvals}% + \edef\@dtl@decvals{\the\toks@,\@dtl@num}% + }% + \dtladd{\@dtl@mean}{\@dtl@mean}{\@dtl@num}% + \dtladd{\@dtl@n}{\@dtl@n}{1}% + }% + \dtldiv{\@dtl@mean}{\@dtl@mean}{\@dtl@n}% + \def\@dtl@sd{0}% + \@for\@dtl@num:=\@dtl@decvals\do{% + \dtlsub{\@dtl@diff}{\@dtl@num}{\@dtl@mean}% + \dtlmul{\@dtl@diff}{\@dtl@diff}{\@dtl@diff}% + \dtladd{\@dtl@sd}{\@dtl@sd}{\@dtl@diff}% + }% + \dtldiv{\@dtl@sd}{\@dtl@sd}{\@dtl@n}% + \dtlroot{\@dtl@sd}{\@dtl@sd}{2}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@sd}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@sd}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgsdforall} +%\begin{definition} +%\cs{DTLgsdforall}\marg{cmd}\marg{num list} +%\end{definition} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgsdforall}[2]{% + \DTLsdforall{\@dtl@tmpi}{#2}% + \global\let#1=\@dtl@tmpi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLround} +%\begin{definition} +% \cs{DTLround}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +% Sets \meta{cmd} to \meta{num} rounded to \meta{num digits} +% digits after the decimal character. +% \begin{macrocode} +\newcommand*{\DTLround}[3]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \dtlround{\@dtl@tmp}{\@dtl@numi}{#3}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLground} +% Global version +% \begin{macrocode} +\newcommand*{\DTLground}[3]{% + \DTLround{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtrunc} +%\begin{definition} +% \cs{DTLtrunc}\marg{cmd}\marg{num}\marg{num digits} +%\end{definition} +% Sets \meta{cmd} to \meta{num} truncated to \meta{num digits} +% digits after the decimal character. +% \begin{macrocode} +\newcommand*{\DTLtrunc}[3]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \dtltrunc{\@dtl@tmp}{\@dtl@numi}{#3}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgtrunc} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgtrunc}[3]{% + \DTLtrunc{\@dtl@tmpii}{#2}{#3}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLclip} +%\begin{definition} +% \cs{DTLclip}\marg{cmd}\marg{num} +%\end{definition} +% Sets \meta{cmd} to \meta{num} with all unnecessary 0's removed. +% \begin{macrocode} +\newcommand*{\DTLclip}[2]{% + \DTLconverttodecimal{#2}{\@dtl@numi}% + \dtlclip{\@dtl@tmp}{\@dtl@numi}% + \ifdefempty{\@dtl@replaced}% + {% + \DTLdecimaltolocale{\@dtl@tmp}{#1}% + }% + {% + \DTLdecimaltocurrency{\@dtl@tmp}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgclip} +% Global version +% \begin{macrocode} +\newcommand*{\DTLgclip}[3]{% + \DTLclip{\@dtl@tmpii}{#2}% + \global\let#1=\@dtl@tmpii +} +% \end{macrocode} +%\end{macro} +% +%\section{String Macros} +%\begin{macro}{\DTLinitials} +%\begin{definition} +%\cs{DTLinitials}\marg{string} +%\end{definition} +% Convert a string into initials. +% (Any "~" character found is first converted into a space.) +%\changes{1.01}{2007 Aug 17}{now works with unbreakable space symbol} +%\changes{1.01}{2007 Aug 17}{now uses \cs{DTLinitialhyphen}} +% \begin{macrocode} +\newcommand*\DTLinitials[1]{% + \def\dtl@initialscmd{}% + \dtl@subnobrsp{#1}{\dtl@string}% + \DTLsubstituteall{\dtl@string}{~}{ }% + \DTLsubstituteall{\dtl@string}{\ }{ }% + \DTLsubstituteall{\dtl@string}{\space}{ }% + \expandafter\dtl@initials\dtl@string{} \@nil% + \dtl@initialscmd +}% +% \end{macrocode} +%\end{macro} +% The following substitutes "\protect \nobreakspace {}" with +% a space. (Note that in this case the space following +% "\nobreakspace" forms part of the command.) +% \begin{macrocode} +\edef\dtl@construct@subnobrsp{% +% \end{macrocode} +% Define \ics{@dtl@subnobrsp} +% \begin{macrocode} + \noexpand\def\noexpand\@dtl@subnobrsp##1\noexpand\protect + \expandafter\noexpand\csname nobreakspace \endcsname ##2{% + \noexpand\toks@{##1}% + \noexpand\expandafter\noexpand\@dtl@toks\noexpand\expandafter{% + \noexpand\@dtl@string}% + \noexpand\edef\noexpand\@dtl@string{\noexpand\the\noexpand\@dtl@toks + \noexpand\the\noexpand\toks@}% + \noexpand\def\noexpand\@dtl@tmp{##2}% + \noexpand\ifx\noexpand\@dtl@tmp\noexpand\@nnil + \noexpand\let\noexpand\@dtl@subnobrspnext=\noexpand\relax + \noexpand\else + \noexpand\toks@{ }% + \noexpand\expandafter\noexpand\@dtl@toks\noexpand\expandafter{% + \noexpand\@dtl@string}% + \noexpand\edef\noexpand\@dtl@string{\noexpand\the\noexpand\@dtl@toks + \noexpand\the\noexpand\toks@}% + \noexpand\let\noexpand\@dtl@subnobrspnext=\noexpand\@dtl@subnobrsp + \noexpand\fi + \noexpand\@dtl@subnobrspnext + }% +% \end{macrocode} +% Define \ics{dtl@subnobrsp} +% \begin{macrocode} + \noexpand\def\noexpand\dtl@subnobrsp##1##2{% + \noexpand\def\noexpand\@dtl@string{}% + \noexpand\@dtl@subnobrsp ##1\noexpand\protect\expandafter\noexpand + \csname nobreakspace \endcsname \noexpand\@nil + \noexpand\let##2=\noexpand\@dtl@string + }% +} +\dtl@construct@subnobrsp +% \end{macrocode} +% +%\begin{macro}{\DTLstoreinitials} +%\begin{definition} +%\cs{DTLstoreinitials}\marg{string}\marg{cmd} +%\end{definition} +% Convert a string into initials and store in \meta{cmd}. +% (Any "~" character found is first converted into a space.) +%\changes{1.01}{2007 Aug 17}{now works with unbreakable space symbol} +%\changes{1.01}{2007 Aug 17}{now uses \cs{DTLinitialhyphen}} +% \begin{macrocode} +\newcommand*{\DTLstoreinitials}[2]{% + \def\dtl@initialscmd{}% + \dtl@subnobrsp{#1}{\dtl@string}% + \DTLsubstituteall{\dtl@string}{~}{ }% + \DTLsubstituteall{\dtl@string}{\ }{ }% + \DTLsubstituteall{\dtl@string}{\space}{ }% + \expandafter\dtl@initials\dtl@string{} \@nil + \let#2=\dtl@initialscmd +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@initials} +% \begin{macrocode} +\def\dtl@initials#1#2 #3{% + \dtl@ifsingle{#1}% + {% + \ifcat\noexpand#1\relax\relax + \def\@dtl@donextinitials{\@dtl@initials#2 {#3}}% + \else + \def\@dtl@donextinitials{\@dtl@initials#1#2 {#3}}% + \fi + }% + {% + \def\@dtl@donextinitials{\@dtl@initials{#1}#2 {#3}}% + }% + \@dtl@donextinitials +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@initials} +% \begin{macrocode} +\def\@dtl@initials#1#2 #3{% + \dtl@initialshyphen#2-{}\dtl@endhyp + \expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% + \toks@{#1}% + \ifdefempty{\dtl@inithyphen}% + {% + }% + {% + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@}% + \expandafter\@dtl@toks\expandafter{\dtl@initialscmd}% + \expandafter\toks@\expandafter{\dtl@inithyphen}% + }% + \def\dtl@tmp{#3}% + \ifx\@nnil\dtl@tmp + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLafterinitials}% + \let\dtl@initialsnext=\@gobble + \else + \edef\dtl@initialscmd{\the\@dtl@toks\the\toks@\DTLbetweeninitials}% + \let\dtl@initialsnext=\dtl@initials + \fi + \dtl@initialsnext{#3}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@initialshyphen} +% \begin{macrocode} +\def\dtl@initialshyphen#1-#2#3\dtl@endhyp{% + \def\dtl@inithyphen{#2}% + \ifdefempty{\dtl@inithyphen}% + {% + }% + {% + \edef\dtl@inithyphen{% + \DTLafterinitialbeforehyphen\DTLinitialhyphen#2}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLafterinitials} +% Defines what to do after the final initial. +% \begin{macrocode} +\newcommand*{\DTLafterinitials}{.} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLbetweeninitials} +% Defines what to do between initials. +% \begin{macrocode} +\newcommand*{\DTLbetweeninitials}{.} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLafterinitialbeforehyphen} +% Defines what to do before a hyphen. +% \begin{macrocode} +\newcommand*{\DTLafterinitialbeforehyphen}{.} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLinitialhyphen} +%Defines what to do at the hyphen +%\changes{1.01}{2007 Aug 17}{new} +% \begin{macrocode} +\newcommand*{\DTLinitialhyphen}{-} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLifAllUpperCase} +%\begin{definition} +%\cs{DTLifAllUpperCase}\marg{string}\marg{true part}\marg{false part} +%\end{definition} +% If \meta{string} only contains uppercase characters do \meta{true +%part}, otherwise do \meta{false part}. +% \begin{macrocode} +\newcommand*{\DTLifAllUpperCase}[3]{% + \protected@edef\dtl@tuc{#1}% + \expandafter\dtl@testifuppercase\dtl@tuc\@nil\relax + \if@dtl@condition#2\else#3\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testifalluppercase} +% \begin{macrocode} +\def\dtl@testifuppercase#1#2{% + \def\dtl@argi{#1}% + \def\dtl@argii{#2}% + \def\dtl@tc@rest{}% + \ifx\dtl@argi\@nnil + \let\dtl@testifuppernext=\@nnil + \else + \ifx#1\protect + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \ifx\uppercase#1\relax + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax + \else + \edef\dtl@tc@arg{\string#1}% + \expandafter\dtl@test@ifuppercase\dtl@tc@arg\end + \ifx\dtl@argii\@nnil + \let\dtl@testifuppernext=\@dtl@gobbletonil + \fi + \fi + \fi + \fi + \ifx\dtl@testifuppernext\relax + \edef\dtl@dotestifuppernext{% + \noexpand\dtl@testifuppercase}% + \else + \ifx\dtl@testifuppernext\@nnil + \edef\dtl@dotestifuppernext{#2}% + \else + \expandafter\toks@\expandafter{\dtl@tc@rest}% + \@dtl@toks{#2}% + \edef\dtl@dotestifuppernext{% + \noexpand\dtl@testifuppernext\the\toks@\the\@dtl@toks}% + \fi + \fi + \dtl@dotestifuppernext +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@test@ifalluppercase} +% \begin{macrocode} +\def\dtl@test@ifuppercase#1#2\end{% + \def\dtl@tc@rest{#2}% + \IfSubStringInString{\string\MakeUppercase}{#1#2}% + {% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax + }% + {% + \IfSubStringInString{\string\MakeTextUppercase}{#1#2}% + {% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testifuppernext=\relax + }% + {% + \edef\dtl@uccode{\the\uccode`#1}% + \edef\dtl@code{\number`#1}% + \ifnum\dtl@code=\dtl@uccode\relax + \@dtl@conditiontrue + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \ifnum\dtl@uccode=0\relax + \@dtl@conditiontrue + \let\dtl@testifuppernext=\dtl@testifuppercase + \else + \@dtl@conditionfalse + \let\dtl@testifuppernext=\@dtl@gobbletonil + \fi + \fi + }% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLifAllLowerCase} +%\begin{definition} +%\cs{DTLifAllLowerCase}\marg{string}\marg{true part}\marg{false part} +%\end{definition} +% If \meta{string} only contains lowercase characters do \meta{true +%part}, otherwise do \meta{false part}. +% \begin{macrocode} +\newcommand*{\DTLifAllLowerCase}[3]{% + \protected@edef\dtl@tlc{#1}% + \expandafter\dtl@testiflowercase\dtl@tlc\@nil\relax + \if@dtl@condition#2\else#3\fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testifalllowercase} +% \begin{macrocode} +\def\dtl@testiflowercase#1#2{% + \def\dtl@argi{#1}% + \def\dtl@argii{#2}% + \ifx\dtl@argi\@nnil + \let\dtl@testiflowernext=\@nnil + \else + \ifx#1\protect + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \ifx\lowercase#1\relax + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax + \else + \edef\dtl@tc@arg{\string#1}% + \expandafter\dtl@test@iflowercase\dtl@tc@arg\end + \ifx\dtl@argii\@nnil + \let\dtl@testiflowernext=\@dtl@gobbletonil + \fi + \fi + \fi + \fi + \ifx\dtl@testiflowernext\relax + \edef\dtl@dotestiflowernext{% + \noexpand\dtl@testiflowercase}% + \else + \ifx\dtl@testiflowernext\@nnil + \edef\dtl@dotestiflowernext{#2}% + \else + \expandafter\toks@\expandafter{\dtl@tc@rest}% + \@dtl@toks{#2}% + \edef\dtl@dotestiflowernext{% + \noexpand\dtl@testiflowernext\the\toks@\the\@dtl@toks}% + \fi + \fi + \dtl@dotestiflowernext +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@test@ifalllowercase} +% \begin{macrocode} +\def\dtl@test@iflowercase#1#2\end{% + \def\dtl@tc@rest{#2}% + \IfSubStringInString{\string\MakeLowercase}{#1#2}% + {% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax + }% + {% + \IfSubStringInString{\string\MakeTextLowercase}{#1#2}% + {% + \@dtl@conditiontrue + \def\dtl@tc@rest{}% + \let\dtl@testiflowernext=\relax + }% + {% + \edef\dtl@lccode{\the\lccode`#1}% + \edef\dtl@code{\number`#1}% + \ifnum\dtl@code=\dtl@lccode\relax + \@dtl@conditiontrue + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \ifnum\dtl@lccode=0\relax + \@dtl@conditiontrue + \let\dtl@testiflowernext=\dtl@testiflowercase + \else + \@dtl@conditionfalse + \let\dtl@testiflowernext=\@dtl@gobbletonil + \fi + \fi + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsubstitute} +%\begin{definition} +%\cs{DTLsubstitute}\marg{cmd}\marg{original}\marg{replacement} +%\end{definition} +% Substitutes first occurrence of \meta{original} with +% \marg{replacement} within the string given by \meta{cmd} +% \begin{macrocode} +\newcommand{\DTLsubstitute}[3]{% + \expandafter\DTLsplitstring\expandafter + {#1}{#2}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + }% + {% + \def#1{}% + \expandafter\@dtl@toks\expandafter{\@dtl@beforepart}% + \expandafter\toks@\expandafter{#1}% + \protected@edef#1{\the\toks@\the\@dtl@toks#3}% + \expandafter\@dtl@toks\expandafter{\@dtl@afterpart}% + \expandafter\toks@\expandafter{#1}% + \edef#1{\the\toks@\the\@dtl@toks}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLsplitstring} +%\begin{definition} +%\cs{DTLsplitstring}\marg{string}\marg{split text}\marg{before +%cmd}\marg{after cmd} +%\end{definition} +% Splits string at \meta{split text} stores the pre split text +% in \meta{before cmd} and the post split text in \meta{after cmd}. +%\changes{1.01}{2007 Aug 17}{new} +% \begin{macrocode} +\newcommand*{\DTLsplitstring}[4]{% + \def\dtl@splitstr##1#2##2\@nil{% + \def#3{##1}% + \def#4{##2}% + \ifdefempty{#4}% + {% + \let\@dtl@replaced=\@empty + }% + {% + \def\@dtl@replaced{#2}% + \dtl@split@str##2\@nil + }% + }% + \def\dtl@split@str##1#2\@nil{% + \def#4{##1}}% + \dtl@splitstr#1#2\@nil +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsubstituteall} +%\begin{definition} +%\cs{DTLsubstituteall}\marg{cmd}\marg{original}\marg{replacement} +%\end{definition} +% Substitutes all occurrences of \meta{original} with +% \marg{replacement} within the string given by \meta{cmd} +%\changes{1.01}{2007 Aug 17}{fixed bug caused when certain commands +% occur in the string} +%\changes{2.10}{2012-07-18}{added \cs{long}} +% \begin{macrocode} +\newcommand{\DTLsubstituteall}[3]{% + \def\@dtl@splitsubstr{}% + \let\@dtl@afterpart=#1\relax + \@dtl@dosubstitute{#2}{#3}% + \expandafter\toks@\expandafter{\@dtl@splitsubstr}% + \expandafter\@dtl@toks\expandafter{\@dtl@afterpart}% + \long\edef#1{\the\toks@\the\@dtl@toks}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@dosubstitute} +% Recursive substitution macro. +% \begin{macrocode} +\def\@dtl@dosubstitute#1#2{% + \expandafter\DTLsplitstring\expandafter + {\@dtl@afterpart}{#1}{\@dtl@beforepart}{\@dtl@afterpart}% + \expandafter\toks@\expandafter{\@dtl@splitsubstr}% + \expandafter\@dtl@toks\expandafter{\@dtl@beforepart}% + \edef\@dtl@splitsubstr{\the\toks@\the\@dtl@toks}% + \ifdefempty{\@dtl@replaced}% + {% + \let\@dtl@dosubstnext=\@dtl@dosubstitutenoop + }% + {% + \expandafter\toks@\expandafter{\@dtl@splitsubstr}% + \@dtl@toks{#2}% + \edef\@dtl@splitsubstr{\the\toks@\the\@dtl@toks}% + \let\@dtl@dosubstnext=\@dtl@dosubstitute + }% + \@dtl@dosubstnext{#1}{#2}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@dosubstitutenoop} +% Terminates recursive substitution macro. +% \begin{macrocode} +\def\@dtl@dosubstitutenoop#1#2{} +% \end{macrocode} +%\end{macro} +% +%\section{Conditionals} +% +%\begin{macro}{\if@dtl@condition} +% \begin{macrocode} +\newif\if@dtl@condition +% \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@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 + \dtl@ifsingle{#1}% + {% + \expandafter\toks@\expandafter{#1}% + \edef\@dtl@tmp{\the\toks@}% + }% + {% + \def\@dtl@tmp{#1}% + }% +% \end{macrocode} +%\changes{2.16}{2013-08-16}{Moved empty check} +% \begin{macrocode} + \ifdefempty\@dtl@tmp + {% + \@dtl@datatype=0\relax + }% + {% + \@dtl@tmpcount=0\relax + \@dtl@datatype=0\relax + \@dtl@numgrpsepcount=2\relax + \@dtl@standardize@currency\@dtl@tmp + \ifdefempty{\@dtl@org@currency}% + {% + }% + {% + \let\@dtl@currency\@dtl@org@currency + }% + \expandafter\@dtl@checknumericalstart\@dtl@tmp\@nil\@nil + }% + \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@protect} +%\changes{2.31}{2018-12-07}{new} +% \begin{macrocode} +\newcommand*{\@dtl@protect}{\protect} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@minus} +%\changes{2.31}{2018-12-07}{new} +% \begin{macrocode} +\newcommand*{\@dtl@minus}{-} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@plus} +%\changes{2.31}{2018-12-07}{new} +% \begin{macrocode} +\newcommand*{\@dtl@plus}{+} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@dollar} +%\changes{2.31}{2018-12-07}{new} +% \begin{macrocode} +\newcommand*{\@dtl@dollar}{\$} +% \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{% + \def\@dtl@tmp{#1}% + \ifx\@dtl@tmp\@dtl@protect + \@dtl@checknumericalstart#2\@nil\@nil\relax + \else + \ifx\@dtl@tmp\@dtl@minus + \def\@dtl@tmp{#2}% + \ifdefempty{\@dtl@tmp}% + {% + \@dtl@datatype=0\relax + }% + {% + \ifnum\@dtl@datatype=0\relax + \@dtl@datatype=1\relax + \fi + \@dtl@checknumericalstart#2\@nil\@nil\relax + }% + \else + \ifx\@dtl@tmp\@dtl@plus + \def\@dtl@tmp{#2}% + \ifdefempty{\@dtl@tmp}% + {% + \@dtl@datatype=0\relax + }% + {% + \ifnum\@dtl@datatype=0\relax + \@dtl@datatype=1\relax + \fi + \@dtl@checknumericalstart#2\@nil\@nil\relax + }% + \else + \def\@dtl@tmp{#1}% + \ifx\@dtl@tmp\@dtl@dollar + \def\@dtl@tmp{#2}% + \ifdefempty{\@dtl@tmp}% + {% + \@dtl@datatype=0\relax + }% + {% + \@dtl@datatype=3\relax + \@dtl@checknumericalstart#2\@nil\@nil\relax + }% + \else + \ifdefempty{\@dtl@tmp}% + {% + \@dtl@datatype=0\relax + }% + {% + \ifnum\@dtl@datatype=0\relax + \@dtl@datatype=1\relax + \fi + \@dtl@checknumericalloop#1#2\@nil\@nil\relax + }% + \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. +% Rewrite provided by Bruno Le Floch. +%\changes{1.01}{2007 Aug 17}{new} +%\changes{2.10}{2012-07-18}{Rewritten} +% \begin{macrocode} +\newcommand*{\@dtl@ifDigitOrDecimalSep}[3]{% + \ifnum 9<1\noexpand#1\relax + #2% + \else + \expandafter\ifx\@dtl@decimal#1\relax + #2% + \else + #3% + \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{dtlifnumlt} +%\changes{2.10}{2012-07-18}{changed \cs{FPiflt} to \cs{dtlifnumlt}} +% \begin{macrocode} +\newcommand*{\DTLifnumlt}[4]{% + \DTLconverttodecimal{#1}{\@dtl@numi}% + \DTLconverttodecimal{#2}{\@dtl@numii}% + \dtlifnumlt{\@dtl@numi}{\@dtl@numii}% + {% + #3% + }% + {% + #4% + }% +} +% \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}% + \ifdefempty{\@dtl@argA}% + {% + \ifdefempty{\@dtl@argB}% + {% + #1=0\relax + }% + {% + #1=-1\relax + }% + }% + {% + \ifdefempty{\@dtl@argB}% + {% + #1=1\relax + }% + {% + \DTLsubstituteall{\@dtl@argA}{ }{\space }% + \DTLsubstituteall{\@dtl@argB}{ }{\space }% + \expandafter\dtl@getfirst\@dtl@argA\end@dtl@getfirst + \let\dtl@firstA=\dtl@first + \let\dtl@restA=\dtl@rest + \expandafter\dtl@getfirst\@dtl@argB\end@dtl@getfirst + \let\dtl@firstB=\dtl@first + \let\dtl@restB=\dtl@rest + \expandafter\dtl@ifsingleorUTFviii\expandafter{\dtl@firstA}{% + \expandafter\dtl@ifsingleorUTFviii\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 +% \end{macrocode} +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +%\changes{2.25}{2016-01-18}{added \cs{expandonce}} +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlcompare + {\noexpand#1}{\expandonce\dtl@restA}{\expandonce\dtl@restB}}% + \dtl@donext + \else + \edef\dtl@donext{% + \noexpand\dtlcompare + {\noexpand#1}% + {\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + \fi + \else + \ifnum\dtl@codeB=-1\relax +% \end{macrocode} +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlcompare + {\noexpand#1}% + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@restB}}% + \dtl@donext + \else + \ifnum\dtl@codeA<\dtl@codeB + #1=-1\relax + \else + \ifnum\dtl@codeA>\dtl@codeB + #1=1\relax + \else + \ifdefempty{\dtl@restA}% + {% + \ifdefempty{\dtl@restB}% + {% + #1=0\relax + }% + {% + #1=-1\relax + }% + }% + {% + \ifdefempty{\restB}% + {% + #1=1\relax + }% + {% + \protected@edef\dtl@donext{% + \noexpand\dtlcompare + {\noexpand#1}{\dtl@restA}{\dtl@restB}}% + \dtl@donext + }% + }% + \fi + \fi + \fi + \fi + }{% +% \end{macrocode} +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlcompare + {\noexpand#1}% + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + }}{% + \edef\dtl@donext{% + \noexpand\dtlcompare + {\noexpand#1}% + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@if@two@octets} +%\changes{2.24}{2016-01-12}{new} +%Check if argument starts with \cs{UTFviii@two@octets} +% \begin{macrocode} +\def\dtl@if@two@octets#1#2\dtl@end@if@two@octets#3#4{% + \ifbool{@dtl@utf8} + {% + \ifx\UTFviii@two@octets#1\relax + #3% + \else + #4% + \fi + }% + {% + #4% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@getfirst@UTFviii} +%\changes{2.24}{2016-01-12}{new} +% \begin{macrocode} +\def\dtl@getfirst@UTFviii#1#2#3\end@dtl@getfirst@UTFviii{% + \def\dtl@first{#1#2}% + \ifx\@nil#3\relax + \def\dtl@rest{}% + \else + \expandafter\def\expandafter\dtl@rest\expandafter{\@dtl@firsttonil#3}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@firsttonil} +%\changes{2.24}{2016-01-12}{new} +% \begin{macrocode} +\def\@dtl@firsttonil#1\@nil{#1} +% \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}. +%\changes{2.23}{2015-07-11}{changed \cs{end} to \cs{end@dtl@getfirst}} +% \begin{macrocode} +\def\dtl@getfirst#1#2\end@dtl@getfirst{% + \def\dtl@first{#1}% + \ifdefempty{\dtl@first}% + {% + \def\dtl@rest{#2}% + }% + {% + \ifbool{@dtl@utf8} + {% + \expandafter\dtl@if@two@octets#1#2\relax\dtl@end@if@two@octets + {% + \dtl@getfirst@UTFviii#1#2\@nil\end@dtl@getfirst@UTFviii + }% + {% + \dtl@ifsingle{#1}{\def\dtl@rest{#2}}{\dtl@getfirst#1#2\end@dtl@getfirst}% + }% + }% + {% + \dtl@ifsingle{#1}{\def\dtl@rest{#2}}{\dtl@getfirst#1#2\end@dtl@getfirst}% + }% + }% +}% +% \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]{% + \ifstrempty{#1}% + {% +% \end{macrocode} +% Empty argument. Set code to $-1$. +% \begin{macrocode} + #2=-1\relax + }% + {% + \ifx\@dtl@wordbreak#1\relax +% \end{macrocode} +% Reached a word break. Set to character code of a space. +%\changes{2.13}{2013-01-15}{change from check for space and tilde to check +%for \cs{@dtl@wordbreak}} +% \begin{macrocode} + #2=`\ \relax + \else + \ifcat\noexpand#1\relax +% \end{macrocode} +% Argument is a control sequence, so set to 0. +% \begin{macrocode} + #2=0\relax + \else + \expandafter\dtl@if@two@octets#1\relax\relax\dtl@end@if@two@octets + {% +% \end{macrocode} +% Argument is a UTF8 character. +% \begin{macrocode} + \dtlsetUTFviiicharcode{#1}{#2}% + }% + {% +% \end{macrocode} +% Argument is a character, so set to the character code. +% \begin{macrocode} + \dtlsetcharcode{#1}{#2}% + }% + \fi + \fi + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsetcharcode} +%\changes{2.24}{2016-01-12}{new} +% Set the code for the given character. May be redefined by user +% for non-UTF8 encodings (e.g.\ Latin-1). +% \begin{macrocode} +\newcommand*{\dtlsetcharcode}[2]{#2=`#1\relax} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsetlccharcode} +%\changes{2.24}{2016-01-12}{new} +% Set the lowercase code for the given character. May be redefined by user +% for non-UTF8 encodings (e.g.\ Latin-1). +% \begin{macrocode} +\newcommand*{\dtlsetlccharcode}[2]{#2=\lccode`#1\relax} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsetUTFviiicharcode} +% Default behaviour is to set all UTF8 characters to code 64 (before +% A). This will need to be redefined according to the relevant alphabet. +%\changes{2.24}{2016-01-12}{new} +% \begin{macrocode} +\newcommand*\dtlsetUTFviiicharcode[2]{\dtlsetdefaultUTFviiicharcode{#1}{#2}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsetUTFviiilccharcode} +%\changes{2.24}{2016-01-12}{new} +% Default behaviour is to set all UTF8 characters to code 96 (before +% a). This will need to be redefined according to the relevant alphabet. +% \begin{macrocode} +\newcommand*\dtlsetUTFviiilccharcode[2]{\dtlsetdefaultUTFviiilccharcode{#1}{#2}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsetdefaultUTFviiicharcode} +%\changes{2.24}{2016-01-12}{new} +% Default codes for some supplemental Latin characters. +% \begin{macrocode} +\newcommand*\dtlsetdefaultUTFviiicharcode[2]{% + \ifboolexpr + { + test {\ifstrequal{#1}{À}} + or test {\ifstrequal{#1}{Á}} + or test {\ifstrequal{#1}{Á}} + or test {\ifstrequal{#1}{Ã}} + or test {\ifstrequal{#1}{Ä}} + }% + {% + #2=`A\relax + }% + {% + \ifstrequal{#1}{Ç}% + {% + #2=`C\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{È}} + or test {\ifstrequal{#1}{É}} + or test {\ifstrequal{#1}{Ê}} + or test {\ifstrequal{#1}{Ë}} + }% + {% + #2=`E\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{Ì}} + or test {\ifstrequal{#1}{Í}} + or test {\ifstrequal{#1}{Î}} + or test {\ifstrequal{#1}{Ï}} + }% + {% + #2=`I\relax + }% + {% + \ifstrequal{#1}{Ñ}% + {% + #2=`N\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{Ò}} + or test {\ifstrequal{#1}{Ó}} + or test {\ifstrequal{#1}{Ô}} + or test {\ifstrequal{#1}{Õ}} + or test {\ifstrequal{#1}{Ö}} + }% + {% + #2=`O\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{Ù}} + or test {\ifstrequal{#1}{Ú}} + or test {\ifstrequal{#1}{Û}} + or test {\ifstrequal{#1}{Ü}} + }% + {% + #2=`U\relax + }% + {% + \ifstrequal{#1}{Ý}% + {% + #2=`Y\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{à}} + or test {\ifstrequal{#1}{á}} + or test {\ifstrequal{#1}{á}} + or test {\ifstrequal{#1}{ã}} + or test {\ifstrequal{#1}{ä}} + }% + {% + #2=`a\relax + }% + {% + \ifstrequal{#1}{ç}% + {% + #2=`c\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{è}} + or test {\ifstrequal{#1}{é}} + or test {\ifstrequal{#1}{ê}} + or test {\ifstrequal{#1}{ë}} + }% + {% + #2=`e\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ì}} + or test {\ifstrequal{#1}{í}} + or test {\ifstrequal{#1}{î}} + or test {\ifstrequal{#1}{ï}} + }% + {% + #2=`i\relax + }% + {% + \ifstrequal{#1}{ñ}% + {% + #2=`n\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ò}} + or test {\ifstrequal{#1}{ó}} + or test {\ifstrequal{#1}{ô}} + or test {\ifstrequal{#1}{õ}} + or test {\ifstrequal{#1}{ö}} + }% + {% + #2=`o\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ù}} + or test {\ifstrequal{#1}{ú}} + or test {\ifstrequal{#1}{û}} + or test {\ifstrequal{#1}{ü}} + }% + {% + #2=`u\relax + }% + {% + \ifstrequal{#1}{ý}% + {% + #2=`y\relax + }% + {% + #2=64\relax + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsetdefaultUTFviiilccharcode} +%\changes{2.24}{2016-01-12}{new} +% As above but for case-insensitive comparison. +% \begin{macrocode} +\newcommand*\dtlsetdefaultUTFviiilccharcode[2]{% + \ifboolexpr + { + test {\ifstrequal{#1}{à}} + or test {\ifstrequal{#1}{á}} + or test {\ifstrequal{#1}{á}} + or test {\ifstrequal{#1}{ã}} + or test {\ifstrequal{#1}{ä}} + or test {\ifstrequal{#1}{À}} + or test {\ifstrequal{#1}{Á}} + or test {\ifstrequal{#1}{Á}} + or test {\ifstrequal{#1}{Ã}} + or test {\ifstrequal{#1}{Ä}} + }% + {% + #2=`a\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ç}} + or test {\ifstrequal{#1}{Ç}} + } + {% + #2=`c\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{è}} + or test {\ifstrequal{#1}{é}} + or test {\ifstrequal{#1}{ê}} + or test {\ifstrequal{#1}{ë}} + or test {\ifstrequal{#1}{È}} + or test {\ifstrequal{#1}{É}} + or test {\ifstrequal{#1}{Ê}} + or test {\ifstrequal{#1}{Ë}} + }% + {% + #2=`e\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ì}} + or test {\ifstrequal{#1}{í}} + or test {\ifstrequal{#1}{î}} + or test {\ifstrequal{#1}{ï}} + or test {\ifstrequal{#1}{Ì}} + or test {\ifstrequal{#1}{Í}} + or test {\ifstrequal{#1}{Î}} + or test {\ifstrequal{#1}{Ï}} + }% + {% + #2=`i\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ñ}} + or test {\ifstrequal{#1}{Ñ}} + } + {% + #2=`n\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ò}} + or test {\ifstrequal{#1}{ó}} + or test {\ifstrequal{#1}{ô}} + or test {\ifstrequal{#1}{õ}} + or test {\ifstrequal{#1}{ö}} + or test {\ifstrequal{#1}{Ò}} + or test {\ifstrequal{#1}{Ó}} + or test {\ifstrequal{#1}{Ô}} + or test {\ifstrequal{#1}{Õ}} + or test {\ifstrequal{#1}{Ö}} + }% + {% + #2=`o\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ù}} + or test {\ifstrequal{#1}{ú}} + or test {\ifstrequal{#1}{û}} + or test {\ifstrequal{#1}{ü}} + or test {\ifstrequal{#1}{Ù}} + or test {\ifstrequal{#1}{Ú}} + or test {\ifstrequal{#1}{Û}} + or test {\ifstrequal{#1}{Ü}} + }% + {% + #2=`u\relax + }% + {% + \ifboolexpr + { + test {\ifstrequal{#1}{ý}} + or test {\ifstrequal{#1}{Ý}} + }% + {% + #2=`y\relax + }% + {% + #2=96\relax + }% + }% + }% + }% + }% + }% + }% + }% +} +% \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]{% + \ifstrempty{#1}% + {% +% \end{macrocode} +% String is empty so set to $-1$. +% \begin{macrocode} + #2=-1\relax + }% + {% +% \end{macrocode} +% Do we have a word break? +%\changes{2.13}{2013-01-15}{changed to test for \cs{@dtl@wordbreak} instead +%of \cs{space} and tilde} +% \begin{macrocode} + \ifx#1\@dtl@wordbreak\relax + #2=`\ \relax + \else + \ifcat\noexpand#1\relax% +% \end{macrocode} +% Argument is a control sequence, so set to 0. +% \begin{macrocode} + #2=0\relax + \else + \expandafter\dtl@if@two@octets#1\relax\relax\dtl@end@if@two@octets + {% +% \end{macrocode} +% Argument is a UTF8 character. +% \begin{macrocode} + \dtlsetUTFviiilccharcode{#1}{#2}% + }% + {% +% \end{macrocode} +% Argument is a character, so set to the lower case code. +% \begin{macrocode} + \dtlsetlccharcode{#1}{#2}% + }% +% \end{macrocode} +% If the result is zero, which means the character doesn't have a lower case +% equivalent. So set to the character code. +%\changes{2.13}{2013-01-15}{fixed bug where characters without a lower case +%equivalent were all considered equal} +% \begin{macrocode} + \ifnum#2=0\relax + #2=`#1\relax + \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}% + \ifdefempty{\@dtl@argA}% + {% + \ifdefempty{\@dtl@argB}% + {% +% \end{macrocode} +% Both are empty, so they are equal. +% \begin{macrocode} + #1=0\relax + }% + {% +% \end{macrocode} +% The first string is empty, but the second isn't. Therefore the +% first string is less than the second string. +% \begin{macrocode} + #1=-1\relax + }% + }% + {% + \ifdefempty{\@dtl@argB}% + {% +% \end{macrocode} +% The second string is empty, but the first isn't. Therefore the +% first string is greater than the second string. +% \begin{macrocode} + #1=1\relax + }% + {% +% \end{macrocode} +% Identify all word breaks. +%\changes{2.13}{2013-01-15}{now using \cs{dtl@setwordbreaksnohyphens} to +%deal with spaces} +% \begin{macrocode} + \dtl@setwordbreaksnohyphens{\@dtl@argA}{\@dtl@wordbreak}% + \let\@dtl@argA\dtl@string + \dtl@setwordbreaksnohyphens{\@dtl@argB}{\@dtl@wordbreak}% + \let\@dtl@argB\dtl@string +% \end{macrocode} +% Get the first object and the remaining text. +% \begin{macrocode} + \expandafter\dtl@getfirst\@dtl@argA\end@dtl@getfirst + \let\dtl@firstA=\dtl@first + \let\dtl@restA=\dtl@rest + \expandafter\dtl@getfirst\@dtl@argB\end@dtl@getfirst + \let\dtl@firstB=\dtl@first + \let\dtl@restB=\dtl@rest +% \end{macrocode} +% Is the first object of \meta{string1} a single character or a group? +% \begin{macrocode} + \expandafter\dtl@ifsingleorUTFviii\expandafter{\dtl@firstA}% + {% +% \end{macrocode} +% It's a single character. Is the first object of \meta{string2} a +% single character or a group? +% \begin{macrocode} + \expandafter\dtl@ifsingleorUTFviii\expandafter{\dtl@firstB}% + {% +% \end{macrocode} +% Both are a single character. Get the lower case character code. +% \begin{macrocode} + \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 +% \end{macrocode} +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +%\changes{2.25}{2016-01-18}{added \cs{expandonce}} +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlicompare{\noexpand#1}% + {\expandonce\dtl@restA}{\expandonce\dtl@restB}}% + \dtl@donext + \else + \edef\dtl@donext{% + \noexpand\dtlicompare + {\noexpand#1}% + {\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + \fi + \else + \ifnum\dtl@codeB=-1\relax +% \end{macrocode} +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlicompare + {\noexpand#1}% + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@restB}}% + \dtl@donext + \else + \ifnum\dtl@codeA<\dtl@codeB + #1=-1\relax + \else + \ifnum\dtl@codeA>\dtl@codeB + #1=1\relax + \else + \ifdefempty{\dtl@restA}% + {% + \ifdefempty{\dtl@restB}% + {% + #1=0\relax + }% + {% + #1=-1\relax + }% + }% + {% + \ifdefempty{\restB}% + {% + #1=1\relax + }% + {% +% \end{macrocode} +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlicompare + {\noexpand#1}% + {\expandonce\dtl@restA}% + {\expandonce\dtl@restB}}% + \dtl@donext + }% + }% + \fi + \fi + \fi + \fi + }% + {% +% \end{macrocode} +% The first object in \meta{string1} is a single character, but the +% first object in \meta{string2} isn't a single character. +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlicompare + {\noexpand#1}% + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + }% + }% + {% +% \end{macrocode} +% Neither object is a single character. +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlicompare + {\noexpand#1}% + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlwordindexcompare} +% Word breaks come before all other letters of the alphabet. +% \begin{macrocode} +\newcommand*{\dtlwordindexcompare}[3]{% + \@dtldictcompare{#1}{#2}{#3}{\@dtl@wordbreak}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlletterindexcompare} +% Word breaks are ignored. +% \begin{macrocode} +\newcommand*{\dtlletterindexcompare}[3]{% + \@dtldictcompare{#1}{#2}{#3}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtldictcompare} +% Word or letter compare. Fourth argument should be +% \cs{@dtl@wordbreak} for word compare or empty for letter compare. +% \begin{macrocode} +\newcommand*{\@dtldictcompare}[4]{% + \dtl@subnobrsp{#2}{\@dtl@argA}% + \dtl@subnobrsp{#3}{\@dtl@argB}% + \ifdefempty{\@dtl@argA}% + {% + \ifdefempty{\@dtl@argB}% + {% + #1=0\relax + }% + {% + #1=-1\relax + }% + }% + {% + \ifdefempty{\@dtl@argB}% + {% + #1=1\relax + }% + {% +% \end{macrocode} +% Alphabetizing continues until a comma indicates inverted order. +% This assumes that an actual comma indicates that the comma forms part of +% the text (e.g.\ in a title of a play). Inversion commas should be +% indicated using commands such as \ics{datatoolpersoncomma}. +% There are three types of +% inverted order: people, places and subjects (concepts or objects). +% We also need to treat parenthetical material in a similar way. +% Find if the first string has an inverted order. +% \begin{macrocode} + \expandafter\DTLsplitstring\expandafter + {\@dtl@argA}{\datatoolpersoncomma}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \expandafter\DTLsplitstring\expandafter + {\@dtl@argA}{\datatoolplacecomma}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \expandafter\DTLsplitstring\expandafter + {\@dtl@argA}{\datatoolsubjectcomma}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \expandafter\DTLsplitstring\expandafter + {\@dtl@argA}{\datatoolparenstart}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \def\@dtl@A@comma{0}% + \let\@dtl@A@before\@dtl@argA + \def\@dtl@A@after{}% + }% + {% + \let\@dtl@A@comma\@dtl@replaced + \let\@dtl@A@before\@dtl@beforepart + \let\@dtl@A@after\@dtl@afterpart + }% + }% + {% + \let\@dtl@A@comma\@dtl@replaced + \let\@dtl@A@before\@dtl@beforepart + \let\@dtl@A@after\@dtl@afterpart + }% + }% + {% + \let\@dtl@A@comma\@dtl@replaced + \let\@dtl@A@before\@dtl@beforepart + \let\@dtl@A@after\@dtl@afterpart + }% + }% + {% + \let\@dtl@A@comma\@dtl@replaced + \let\@dtl@A@before\@dtl@beforepart + \let\@dtl@A@after\@dtl@afterpart + }% +% \end{macrocode} +% Now find if the second string has an inverted order. +% \begin{macrocode} + \expandafter\DTLsplitstring\expandafter + {\@dtl@argB}{\datatoolpersoncomma}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \expandafter\DTLsplitstring\expandafter + {\@dtl@argB}{\datatoolplacecomma}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \expandafter\DTLsplitstring\expandafter + {\@dtl@argB}{\datatoolsubjectcomma}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \expandafter\DTLsplitstring\expandafter + {\@dtl@argB}{\datatoolparenstart}{\@dtl@beforepart}{\@dtl@afterpart}% + \ifdefempty{\@dtl@replaced}% + {% + \def\@dtl@B@comma{0}% + \let\@dtl@B@before\@dtl@argB + \def\@dtl@B@after{}% + }% + {% + \let\@dtl@B@comma\@dtl@replaced + \let\@dtl@B@before\@dtl@beforepart + \let\@dtl@B@after\@dtl@afterpart + }% + }% + {% + \let\@dtl@B@comma\@dtl@replaced + \let\@dtl@B@before\@dtl@beforepart + \let\@dtl@B@after\@dtl@afterpart + }% + }% + {% + \let\@dtl@B@comma\@dtl@replaced + \let\@dtl@B@before\@dtl@beforepart + \let\@dtl@B@after\@dtl@afterpart + }% + }% + {% + \let\@dtl@B@comma\@dtl@replaced + \let\@dtl@B@before\@dtl@beforepart + \let\@dtl@B@after\@dtl@afterpart + }% +% \end{macrocode} +% Get the first letter and find out if it's a letter, digit or +% symbol. +% \begin{macrocode} + \expandafter\dtl@ifcasechargroup\@dtl@A@before\dtl@end@ifcasechargroup + {\def\@dtl@A@chargroup{2}}% + {\def\@dtl@A@chargroup{1}}% + {\def\@dtl@A@chargroup{0}}% + \expandafter\dtl@ifcasechargroup\@dtl@B@before\dtl@end@ifcasechargroup + {\def\@dtl@B@chargroup{2}}% + {\def\@dtl@B@chargroup{1}}% + {\def\@dtl@B@chargroup{0}}% +% \end{macrocode} +% Are they in the same group? +% \begin{macrocode} + \ifnum\@dtl@A@chargroup<\@dtl@B@chargroup + #1=-1\relax + \else + \ifnum\@dtl@A@chargroup>\@dtl@B@chargroup + #1=1\relax + \else +% \end{macrocode} +% In the same group. Which group are they in? +% \begin{macrocode} + \ifcase\@dtl@A@chargroup +% \end{macrocode} +% Symbol group +%v2.25: added \cs{expandonce} to prevent non-ASCII characters from being +%expanded. +%\changes{2.25}{2016-01-18}{added \cs{expandonce}} +% \begin{macrocode} + \edef\dtl@donext{% + \noexpand\dtlcompare + {\noexpand#1}% + {\expandonce\@dtl@A@before}% + {\expandonce\@dtl@B@before}}% + \dtl@donext +% \end{macrocode} +% Number. +% \begin{macrocode} + \or + \ifnum\@dtl@A@before<\@dtl@B@before\relax + #1=-1\relax + \else + \ifnum\@dtl@A@before>\@dtl@B@before\relax + #1=1\relax + \else + #1=0\relax + \fi + \fi + \or +% \end{macrocode} +% Word or phrase. +% \begin{macrocode} + \@dtlwordindexcompare{#1}{\@dtl@A@before}{\@dtl@B@before} + {\dtlicomparewords}{#4}% +% \end{macrocode} +% If they are equal, do we have an inverted order? +% \begin{macrocode} + \ifnum#1=0\relax +% \end{macrocode} +% Temporarily redefine the inversion commas to numbers to make the +% comparisons easier. +% \begin{macrocode} + \let\@org@dtl@person@comma\datatoolpersoncomma + \let\@org@dtl@place@comma\datatoolplacecomma + \let\@org@dtl@subject@comma\datatoolsubjectcomma + \let\@org@dtl@paren@start\datatoolparenstart +% \end{macrocode} +% People first, then places, then subjects, then no inversion, then +% parenthetical. +% \begin{macrocode} + \def\datatoolpersoncomma{3}% + \def\datatoolplacecomma{2}% + \def\datatoolsubjectcomma{1}% + \def\datatoolparenstart{-1}% +% \end{macrocode} +% Now compare: +% \begin{macrocode} + \ifnum\@dtl@A@comma>\@dtl@B@comma\relax + #1=-1\relax + \else + \ifnum\@dtl@A@comma<\@dtl@B@comma\relax + #1=1\relax + \else +% \end{macrocode} +% They are the same type. First do a reverse case sensitive comparison. +% \begin{macrocode} + \@dtlwordindexcompare{#1}{\@dtl@B@before}{\@dtl@A@before} + {\dtlcomparewords}{#4}% +% \end{macrocode} +% Are they still equal? +% \begin{macrocode} + \ifnum#1=0\relax +% \end{macrocode} +% So sort on inversion. +% \begin{macrocode} + \@dtlwordindexcompare{#1}{\@dtl@A@after}{\@dtl@B@after} + {\dtlicomparewords}{#4}% + \fi + \fi + \fi +% \end{macrocode} +% Restore original definitions. +% \begin{macrocode} + \let\datatoolpersoncomma\@org@dtl@person@comma + \let\datatoolplacecomma\@org@dtl@place@comma + \let\datatoolsubjectcomma\@org@dtl@subject@comma + \let\datatoolparenstart\@org@dtl@paren@start + \fi + \fi + \fi + \fi + }% + }% +}% +% \end{macrocode} +%\end{macro} +% +% Need to indicate type of inversion. +%\begin{macro}{\datatoolpersoncomma} +% \begin{macrocode} +\newcommand*{\datatoolpersoncomma}{,\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datatoolplacecomma} +% \begin{macrocode} +\newcommand*{\datatoolplacecomma}{,\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datatoolsubjectcomma} +% \begin{macrocode} +\newcommand*{\datatoolsubjectcomma}{,\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datatoolparenstart} +% \begin{macrocode} +\newcommand*{\datatoolparenstart}{\space} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\@dtlwordindexcompare} +%\begin{definition} +%\cs{@dtlwordindexcompare}\marg{count}\marg{cs A}\marg{cs +%B}\marg{word comparison handler}\marg{word break replacement} +%\end{definition} +% \begin{macrocode} +\newcommand*{\@dtlwordindexcompare}[5]{% +% \end{macrocode} +% Word or phrase. Replace word breaks. +% \begin{macrocode} + \dtl@setwordbreaks{#2}{#5}% + \let#2\dtl@string +% \end{macrocode} +% And again for the second string. +% \begin{macrocode} + \dtl@setwordbreaks{#3}{}% + \let#3\dtl@string +% \end{macrocode} +% Now compare both strings. +% \begin{macrocode} +% \@dtl@dict@compare{#1}{#2}{#3}{#4}% + \edef\@dtl@do@compare{% + \noexpand#4{\noexpand#1}% + {\expandonce#2}{\expandonce#3}% + }% + \@dtl@do@compare +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@dict@compare} +%\begin{definition} +%\cs{@dtl@dict@compare}\marg{count}\marg{cs A}\marg{cs +%B}\marg{word comparison handler} +%\end{definition} +% Now that all the word breaks have been identified with +% \cs{@dtl@wordbreak} compare both strings. +% \begin{macrocode} +\newcommand*{\@dtl@dict@compare}[4]{% +% \end{macrocode} +% Are either empty? +% \begin{macrocode} + \ifdefempty{#2}% + {% +% \end{macrocode} +% A is empty. Is B empty? +% \begin{macrocode} + \ifdefempty{#3}% + {% +% \end{macrocode} +% Both are empty. +% \begin{macrocode} + #1=0\relax + }% + {% +% \end{macrocode} +% A is empty but B isn't +% \begin{macrocode} + #1=-1\relax + }% + }% + {% +% \end{macrocode} +% A isn't empty. Is B empty? +% \begin{macrocode} + \ifdefempty{#3}% + {% +% \end{macrocode} +% B is empty but A isn't. +% \begin{macrocode} + #1=1\relax + }% + {% +% \end{macrocode} +% Neither are empty. Grab first word from A. +% \begin{macrocode} + \expandafter\dtl@grabword#2\@dtl@endgrabword\dtl@A@first\dtl@A@remain +% \end{macrocode} +% Grab first word from B. +% \begin{macrocode} + \expandafter\dtl@grabword#3\@dtl@endgrabword\dtl@B@first\dtl@B@remain +% \end{macrocode} +% Compare A and B. +% \begin{macrocode} + \edef\@dtl@do@compare{% + \noexpand#4{\noexpand#1}% + {\expandonce\dtl@A@first}{\expandonce\dtl@B@first}% + }% + \@dtl@do@compare +% \end{macrocode} +% Are they the same? +% \begin{macrocode} + \ifnum#1=0\relax +% \end{macrocode} +% They are, so compare on the next word. +% \begin{macrocode} + \@dtl@dict@compare{#1}{\dtl@A@remain}{\dtl@B@remain}{#4}% + \fi + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@grabword} +% Grab first word from phrase. +% \begin{macrocode} +\def\dtl@grabword#1\@dtl@wordbreak#2\@dtl@endgrabword#3#4{% + \def#3{#1}% + \def#4{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlicomparewords} +%\begin{definition} +%\cs{dtlicomparewords}\marg{count}\marg{word A}\marg{word B} +%\end{definition} +%This does a case insensitive comparison. +% \begin{macrocode} +\newcommand{\dtlicomparewords}[3]{% + \dtlicompare{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlcomparewords} +%\begin{definition} +%\cs{dtlcomparewords}\marg{count}\marg{word A}\marg{word B} +%\end{definition} +%This does a case sensitive comparison. +% \begin{macrocode} +\newcommand{\dtlcomparewords}[3]{% + \dtlcompare{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@setwordbreaks} +% Replace word breaks (space, \cs{space}, \cs{\space}, \verb|~| and +% hyphen \texttt{-}) with the second argument (either +% \cs{@dtl@wordbreak} for letter sort or nothing for word sort). Result is stored in +% \cs{dtl@string}. +% \begin{macrocode} +\newcommand*{\dtl@setwordbreaks}[2]{% + \expandafter\dtl@subnobrsp\expandafter{#1}{\dtl@string}% + \DTLsubstituteall{\dtl@string}{~}{#2}% + \DTLsubstituteall{\dtl@string}{\ }{#2}% + \DTLsubstituteall{\dtl@string}{\space}{#2}% + \DTLsubstituteall{\dtl@string}{-}{#2}% +% \end{macrocode} +% Now deal with actual spaces. +% \begin{macrocode} + \toks@{#2}% + \edef\dtl@do@setwordbreaks{% + \noexpand\@dtl@setwordbreaks{\the\toks@}\expandonce\dtl@string\space\noexpand\@nil}% + \def\dtl@string{}% + \dtl@do@setwordbreaks +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@setwordbreaks} +% \begin{macrocode} +\def\@dtl@setwordbreaks#1#2 #3{% + \def\dtl@tmp{#3}% + \ifx\@nnil\dtl@tmp +% \end{macrocode} +% Reached end of loop. +% \begin{macrocode} + \let\@dtl@setwordbreaks@next\@gobbletwo + \appto\dtl@string{#2}% + \else + \let\@dtl@setwordbreaks@next\@dtl@setwordbreaks + \appto\dtl@string{#2#1}% + \fi + \@dtl@setwordbreaks@next{#1}#3% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtl@setwordbreaksnohyphens} +% As \cs{dtl@setwordbreaks} but excludes hyphens. +% \begin{macrocode} +\newcommand*{\dtl@setwordbreaksnohyphens}[2]{% + \expandafter\dtl@subnobrsp\expandafter{#1}{\dtl@string}% + \DTLsubstituteall{\dtl@string}{~}{#2}% + \DTLsubstituteall{\dtl@string}{\ }{#2}% + \DTLsubstituteall{\dtl@string}{\space}{#2}% +% \end{macrocode} +% Now deal with actual spaces. +% \begin{macrocode} + \toks@{#2}% + \edef\dtl@do@setwordbreaks{% + \noexpand\@dtl@setwordbreaks{\the\toks@}\expandonce\dtl@string\space\noexpand\@nil}% + \def\dtl@string{}% + \dtl@do@setwordbreaks +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@wordbreak} +% \begin{macrocode} +\newcommand*{\@dtl@wordbreak}{ } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@ifcasechargroup} +% Determine if first character is a letter, a digit or a symbol. +% \begin{macrocode} +\def\dtl@ifcasechargroup#1#2\dtl@end@ifcasechargroup#3#4#5{% +% \end{macrocode} +% Does it start with a UTF8 character? +% \begin{macrocode} + \expandafter\dtl@if@two@octets#1#2\relax\relax\dtl@end@if@two@octets + {% +% \end{macrocode} +% Get the lower case character code. +%\changes{2.24}{2016-01-12}{added check for UTF8} +% \begin{macrocode} + \dtl@getfirst@UTFviii#1#2\@nil\end@dtl@getfirst@UTFviii + \expandafter\dtlsetUTFviiilccharcode\expandafter{\dtl@first}{\count@}% + \ifnum\count@<`a\relax #5\else#3\fi + }% + {% + \dtlifcasechargroup{#1}% + {#3}% + {% +% \end{macrocode} +% Starts with a digit. Is the whole thing an integer? +% \begin{macrocode} + \DTLifint{#1#2} + {% + #4% + }% + {% +% \end{macrocode} +% No, it isn't. Consider it a string. +% \begin{macrocode} + #3% + }% + }% + {#5}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{macro} +%\begin{definition} +%\cs{dtlifcasechargroup}\marg{char}\marg{case letter}\marg{case +%digit}\marg{case symbol} +%\end{definition} +% \begin{macrocode} +\newcommand*{\dtlifcasechargroup}[4]{% + \count@=`#1\relax + \dtlifintclosedbetween{\number\count@}{48}{57}% + {% +% \end{macrocode} +% It's a digit. +% \begin{macrocode} + #3% + }% + {% + \dtlifintclosedbetween{\number\count@}{97}{122}% + {% +% \end{macrocode} +% Lower case letter +% \begin{macrocode} + #2% + }% + {% + \dtlifintclosedbetween{\number\count@}{65}{90}% + {% +% \end{macrocode} +% Upper case letter +% \begin{macrocode} + #2% + }% + {% +% \end{macrocode} +% Other +% \begin{macrocode} + #4% + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlparsewords} +%\changes{2.13}{2013-01-15}{new} +%\begin{definition} +%\cs{dtlparsewords}\marg{phrase}\marg{handler cs} +%\end{definition} +% Iterates through the given phrase. Hyphens are considered word +% boundaries. +% \begin{macrocode} +\newcommand*{\dtlparsewords}[2]{% + \dtl@subnobrsp{#1}{\dtl@string}% + \DTLsubstituteall{\dtl@string}{~}{ }% + \DTLsubstituteall{\dtl@string}{\ }{ }% + \DTLsubstituteall{\dtl@string}{\space}{ }% + \DTLsubstituteall{\dtl@string}{-}{ }% + \let\dtl@parsewordshandler#2\relax + \edef\dtl@donext{% + \noexpand\@dtl@parse@words\expandonce\dtl@string\space\noexpand\@nil}% + \dtl@donext +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@parse@words} +% \begin{macrocode} +\def\@dtl@parse@words#1 #2{% + \def\dtl@tmp{#2}% + \ifx\@nnil\dtl@tmp + \let\parse@wordsnext=\@gobble + \else + \let\parse@wordsnext=\@dtl@parse@words + \fi + \dlt@parsewordshandler{#1}% + \parse@wordsnext#2% +} +% \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{dtlifnumgt} +%\changes{2.10}{2012-07-18}{changed \cs{FPifgt} to \cs{dtlifnumgt}} +% \begin{macrocode} +\newcommand*{\DTLifnumgt}[4]{% + \DTLconverttodecimal{#1}{\@dtl@numi}% + \DTLconverttodecimal{#2}{\@dtl@numii}% + \dtlifnumgt{\@dtl@numi}{\@dtl@numii}% + {% + #3% + }% + {% + #4% + }% +} +% \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{dtlifnumeq} +%\changes{2.10}{2012-07-18}{changed \cs{FPifeq} to \cs{dtlifnumeq}} +% \begin{macrocode} +\newcommand*{\DTLifnumeq}[4]{% + \DTLconverttodecimal{#1}{\@dtl@numi}% + \DTLconverttodecimal{#2}{\@dtl@numii}% + \dtlifnumeq{\@dtl@numi}{\@dtl@numii}% + {% + #3% + }% + {% + #4% + }% +} +% \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@dotestifsubstring{\noexpand\dtl@testifsubstring + {#1}{#2}}% + \@dtl@dotestifsubstring + \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}% +% \end{macrocode} +% Identify all word breaks. +%\changes{2.13}{2013-01-15}{now using \cs{dtl@setwordbreaksnohyphens} to +%deal with spaces} +% \begin{macrocode} + \dtl@setwordbreaksnohyphens{\@dtl@argA}{\@dtl@wordbreak}% + \let\@dtl@argA\dtl@string + \dtl@setwordbreaksnohyphens{\@dtl@argB}{\@dtl@wordbreak}% + \let\@dtl@argB\dtl@string + \edef\dtl@donext{% + \noexpand\@dtl@testifsubstring{\expandonce\@dtl@argA}{\expandonce\@dtl@argB}}% + \dtl@donext +} +\newcommand*{\@dtl@testifsubstring}[2]{% +% \end{macrocode} +%\changes{2.23}{2015-07-11}{bug fix: temp control sequences clash with +%\cs{@dtl@teststartswith}} +% \begin{macrocode} + \def\@dtl@subs@argA{#1}% + \def\@dtl@subs@argB{#2}% + \ifdefempty{\@dtl@subs@argB}% + {% + \@dtl@conditiontrue + }% + {% + \ifdefempty{\@dtl@subs@argA}% + {% + \@dtl@conditionfalse + }% + {% + \@dtl@teststartswith{#1}{#2}% + \if@dtl@condition + \else + \dtl@getfirst#1\end@dtl@getfirst + \expandafter\dtl@ifsingle\expandafter{\dtl@first}% + {% + \expandafter\@dtl@testifsubstring\expandafter{\dtl@rest}{#2}% + }% + {% + \protected@edef\@dtl@donext{\noexpand\@dtl@testifsubstring + {\expandonce\dtl@first\expandonce\dtl@rest}{\expandonce\@dtl@subs@argB}}% + \@dtl@donext + }% + \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}. First substitute all word breaks with +% \cs{dtl@setwordbreaksnohyphen} +% \begin{macrocode} +\newcommand*{\dtl@teststartswith}[2]{% + \dtl@subnobrsp{#1}{\@dtl@argA}% + \dtl@subnobrsp{#2}{\@dtl@argB}% +% \end{macrocode} +% Identify all word breaks. +%\changes{2.13}{2013-01-15}{now using \cs{dtl@setwordbreaksnohyphens} to +%deal with spaces} +% \begin{macrocode} + \dtl@setwordbreaksnohyphens{\@dtl@argA}{\@dtl@wordbreak}% + \let\@dtl@argA\dtl@string + \dtl@setwordbreaksnohyphens{\@dtl@argB}{\@dtl@wordbreak}% + \let\@dtl@argB\dtl@string + \edef\dtl@donext{% + \noexpand\@dtl@teststartswith{\expandonce\@dtl@argA}{\expandonce\@dtl@argB}}% + \dtl@donext +} + +\newcommand*{\@dtl@teststartswith}[2]{% + \def\@dtl@argA{#1}% + \def\@dtl@argB{#2}% + \ifdefempty{\@dtl@argA}% + {% + \ifdefempty{\@dtl@argB}% + {% + \@dtl@conditiontrue + }% + {% + \@dtl@conditionfalse + }% + }% + {% + \ifdefempty{\@dtl@argB}% + {% + \@dtl@conditiontrue + }% + {% + \expandafter\dtl@getfirst\@dtl@argA\end@dtl@getfirst +% \end{macrocode} +% Get the first object and the remaining text. +% \begin{macrocode} + \let\dtl@firstA=\dtl@first + \let\dtl@restA=\dtl@rest + \expandafter\dtl@getfirst\@dtl@argB\end@dtl@getfirst + \let\dtl@firstB=\dtl@first + \let\dtl@restB=\dtl@rest +% \end{macrocode} +% Is the first object of \meta{string1} a single character or a group? +% \begin{macrocode} + \expandafter\dtl@ifsingle\expandafter{\dtl@firstA}% + {% +% \end{macrocode} +% It's a single character. Is the first object of \meta{string2} a +% single character or a group? +% \begin{macrocode} + \expandafter\dtl@ifsingle\expandafter{\dtl@firstB}% + {% +% \end{macrocode} +% Both are a single character. Get the lower case character code. +% \begin{macrocode} + \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{\expandonce\dtl@restA}{\expandonce\dtl@restB}}% + \dtl@donext + \else + \protected@edef\dtl@donext{% + \noexpand\@dtl@teststartswith + {\expandonce\dtl@restA}{\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + \fi + \else + \ifnum\dtl@codeB=-1\relax + \protected@edef\dtl@donext{% + \noexpand\@dtl@teststartswith + {\expandonce\dtl@firstA\expandonce\dtl@restA}{\expandonce\dtl@restB}}% + \dtl@donext + \else + \ifnum\dtl@codeA=\dtl@codeB + \protected@edef\dtl@donext{% + \noexpand\@dtl@teststartswith{\expandonce\dtl@restA}{\expandonce\dtl@restB}}% + \dtl@donext + \else + \@dtl@conditionfalse + \fi + \fi + \fi + }% + {% +% \end{macrocode} +% The first object in \meta{string1} is a single character, but the +% first object in \meta{string2} isn't a single character. +% \begin{macrocode} + \protected@edef\dtl@donext{% + \noexpand\@dtl@teststartswith + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + \dtl@donext + }% + }% + {% +% \end{macrocode} +% Neither object is a single character. +% \begin{macrocode} + \protected@edef\dtl@donext{% + \noexpand\@dtl@teststartswith + {\expandonce\dtl@firstA\expandonce\dtl@restA}% + {\expandonce\dtl@firstB\expandonce\dtl@restB}}% + }% + }% + }% +} +% \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. +% (Command name maintained for backward compatibility.) +% \begin{macrocode} +\let\DTLifFPopenbetween\dtlifnumopenbetween +% \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}. +% (Command name maintained for backward compatibility.) +% \begin{macrocode} +\let\DTLifFPclosedbetween\dtlifnumclosedbetween +% \end{macrocode} +%\end{macro} +% +% +%\subsection{ifthen Conditionals} +% The following commands provide conditionals \cs{DTLis}\ldots\ +% which can be used in \cs{ifthenelse}. +% +%\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 argument is greater than second argument. +% 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 argument is greater than second argument +% (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 argument is equal to the second argument. +% 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}{\DTLisinlist} +% Tests if first argument starts with second argument. +%\changes{2.23}{2015-07-11}{new} +% \begin{macrocode} +\newcommand*{\DTLisinlist}[2]{% + \TE@throw\noexpand\dtl@testinlist{#1}{#2}% + \noexpand\if@dtl@condition +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@testinlist} +%\changes{2.23}{2015-07-11}{new} +% \begin{macrocode} +\newcommand*{\dtl@testinlist}[2]{% + \DTLifinlist{#1}{#2}{\@dtl@conditiontrue}{\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@testnumclosedbetween} +% 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@testnumclosedbetween}[3]{% + \DTLifnumclosedbetween{#1}{#2}{#3}% + {\@dtl@conditiontrue}{\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% +% Provide conditional command for use in \cs{ifthenelse} +%\begin{macro}{\DTLisnumclosedbetween} +% \begin{macrocode} +\newcommand*{\DTLisnumclosedbetween}[3]{% + \TE@throw\noexpand\dtl@testnumclosedbetween{#1}{#2}{#3}% + \noexpand\if@dtl@condition +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@testnumopenbetween} +% 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@testnumopenbetween}[3]{% + \DTLifnumopenbetween{#1}{#2}{#3}% + {\@dtl@conditiontrue}{\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLisnumopenbetween} +% Provide conditional command for use in \cs{ifthenelse} +% \begin{macrocode} +\newcommand*{\DTLisnumopenbetween}[3]{% + \TE@throw\noexpand\dtl@testnumopenbetween{#1}{#2}{#3}% + \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}{\DTLisFPclosedbetween} +% Keep old command name for backwards compatibility: +% \begin{macrocode} +\let\DTLisFPclosedbetween\DTLisnumclosedbetween +% \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]{% + \dtlifnumlt{#1}{#2}% + {% + \@dtl@conditiontrue + }% + {% + \@dtl@conditionfalse + }% +} +% \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]{% + \dtlifnumgt{#1}{#2}% + {% + \@dtl@conditiontrue + }% + {% + \@dtl@conditionfalse + }% +} +% \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]{% + \dtlifnumeq{#1}{#2}% + {% + \@dtl@conditiontrue + }% + {% + \@dtl@conditionfalse + }% +} +% \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]{% + \dtlifnumlt{#1}{#2}% + {% + \@dtl@conditiontrue + }% + {% + \@dtl@conditionfalse + }% + \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]{% + \dtlifnumgt{#1}{#2}% + {% + \@dtl@conditiontrue + }% + {% + \@dtl@conditionfalse + }% + \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} +% +%\section{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 <ct> to <end> 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{environment}{dtlenvgforint} +% Environment form (contents are gathered, so verbatim can't be +% used): +% \begin{macrocode} +\newenvironment{dtlenvgforint}[1]% +{% + \def\@dtlenvgforint@arg{#1}% + \long@collect@body\@do@dtlenvgforint +}% +{} +\newcommand{\@do@dtlenvgforint}[1]{% + \expandafter\dtlgforint\@dtlenvgforint@arg\do{#1}% +} +% \end{macrocode} +%\end{environment} +%\iffalse +% \begin{macrocode} +%</datatool-base.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*datatool-fp.sty> +% \end{macrocode} +%\fi +%\chapter{datatool-fp.sty}\label{sec:code:datatool-fp} +% Definitions of fixed-point commands that use the \sty{fp} package. +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datatool-fp}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{xkeyval} +\RequirePackage{fp} +\RequirePackage{datatool-base} +% \end{macrocode} +%\begin{option}{verbose} +% Switch \sty{fp} messages on or off +% \begin{macrocode} +\define@choicekey{datatool-fp}{verbose}[\val\nr]{true,false}[true]{% + \ifcase\nr\relax + \FPmessagestrue + \or + \FPmessagesfalse + \fi +} +\let\ifFPmessages\ifdtlverbose +% \end{macrocode} +%\end{option} +% +% Process package options: +% \begin{macrocode} +\ProcessOptionsX +% \end{macrocode} +% +% Define commands that are needed before loading +% \sty{datatool-base}: +% \begin{macrocode} +\providecommand*{\@dtl@mathprocessor}{fp} +% \end{macrocode} +%\begin{macro}{\dtlifnumeq} +%\begin{definition} +%\cs{dtlifnumeq}\marg{num1}\marg{num2}\marg{true part}\marg{false +%part} +%\end{definition} +% Does \meta{true part} if \meta{num1}=\meta{num2}, otherwise does +% \meta{false part}. The numbers must use a full stop as the decimal +% character and no number group separator. +% \begin{macrocode} +\newcommand*{\dtlifnumeq}[4]{% + \FPifeq{#1}{#2}% + #3% + \else + #4% + \fi +} +% \end{macrocode} +%\end{macro} +% +% If \pkgopt{verbose} option set, switch on \pkgopt{verbose} for +% \sty{datatool-base} as well: +% \begin{macrocode} +\let\ifdtlverbose\ifFPmessages +% \end{macrocode} +% +%\section{Comparison Commands} +% +%\begin{macro}{\dtlifnumlt} +%\begin{definition} +%\cs{dtlifnumlt}\marg{num1}\marg{num2}\marg{true part}\marg{false +%part} +%\end{definition} +% Does \meta{true part} if \meta{num1} \textless \meta{num2}, otherwise does +% \meta{false part}. The numbers must use a full stop as the decimal +% character and no number group separator. +% \begin{macrocode} +\newcommand*{\dtlifnumlt}[4]{% + \FPiflt{#1}{#2}% + #3% + \else + #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} +% Does \meta{true part} if \meta{num1} \textgreater \meta{num2}, otherwise does +% \meta{false part}. The numbers must use a full stop as the decimal +% character and no number group separator. +% \begin{macrocode} +\newcommand*{\dtlifnumgt}[4]{% + \FPifgt{#1}{#2}% + #3% + \else + #4% + \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} where +% all arguments are in standard fixed point notation. +% \begin{macrocode} +\newcommand*{\dtlifnumopenbetween}[5]{% + \let\@dtl@dovalue\relax + \dtlifnumgt{#1}{#2}% + {}% + {% + \def\@dtl@dovalue{#5}% + }% + \dtlifnumlt{#1}{#3}% + {% + \ifx\@dtl@dovalue\relax + \def\@dtl@dovalue{#4}% + \fi + }% + {% + \def\@dtl@dovalue{#5}% + }% + \@dtl@dovalue +} +% \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} where +% all arguments are in standard fixed point notation. +% \begin{macrocode} +\newcommand*{\dtlifnumclosedbetween}[5]{% + \let\@dtl@dovalue\relax + \dtlifnumgt{#1}{#2}% + {}% + {% + \dtlifnumeq{#1}{#2}% + {% + \def\@dtl@dovalue{#4}% + }% + {% + \def\@dtl@dovalue{#5}% + }% + }% + \dtlifnumlt{#1}{#3}% + {% + \ifx\@dtl@dovalue\relax + \def\@dtl@dovalue{#4}% + \fi + }% + {% + \dtlifnumeq{#1}{#3}% + {% + \def\@dtl@dovalue{#4}% + }% + {% + \def\@dtl@dovalue{#5}% + }% + }% + \@dtl@dovalue +} +% \end{macrocode} +%\end{macro} +% +%\section{Functions} +% +%\begin{macro}{\dtladd} +% Adds two numbers using fp. +% \begin{macrocode} +\newcommand*{\dtladd}[3]{% + \FPadd{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsub} +% Subtracts two numbers using fp. +% \begin{macrocode} +\newcommand*{\dtlsub}[3]{% + \FPsub{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlmul} +% Multiplies two numbers using fp. +% \begin{macrocode} +\newcommand*{\dtlmul}[3]{% + \FPmul{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldiv} +% Divides two numbers using fp. +% \begin{macrocode} +\newcommand*{\dtldiv}[3]{% + \FPdiv{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlroot} +% Square root using fp. +% \begin{macrocode} +\newcommand*{\dtlroot}[2]{% + \FProot{#1}{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlround} +% Rounds using fp. +% \begin{macrocode} +\newcommand*{\dtlround}[3]{% + \FPround{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtltrunc} +% Truncates using fp. +% (Third argument is the number of digits.) +% \begin{macrocode} +\newcommand*{\dtltrunc}[3]{% + \FPtrunc{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlclip} +% \begin{macrocode} +\newcommand*{\dtlclip}[2]{% + \FPclip{#1}{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlmin} +% Minimum of two numbers using fp. +% \begin{macrocode} +\newcommand*{\dtlmin}[3]{% + \FPmin{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlmax} +% Maximum of two numbers using fp. +% \begin{macrocode} +\newcommand*{\dtlmax}[3]{% + \FPmax{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlabs} +% Absolute value using fp. +% \begin{macrocode} +\newcommand*{\dtlabs}[2]{% + \FPabs{#1}{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlneg} +% Negative of a value using fp. +% \begin{macrocode} +\newcommand*{\dtlneg}[2]{% + \FPneg{#1}{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\iffalse +% \begin{macrocode} +%</datatool-fp.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*datatool-pgfmath.sty> +% \end{macrocode} +%\fi +%\chapter{datatool-pgfmath.sty}\label{sec:code:datatool-pgfmath} +% Definitions of fixed-point commands that use the \sty{pgfmath} package. +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datatool-pgfmath}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{xkeyval} +\RequirePackage{pgfrcs,pgfkeys,pgfmath} +% \end{macrocode} +% +% Process package options: +% \begin{macrocode} +\ProcessOptionsX +% \end{macrocode} +% +% Define commands that are needed before loading +% \sty{datatool-base}: +% \begin{macrocode} +\providecommand*{\@dtl@mathprocessor}{pgfmath} +% \end{macrocode} +%\begin{macro}{\dtlifnumeq} +%\begin{definition} +%\cs{dtlifnumeq}\marg{num1}\marg{num2}\marg{true part}\marg{false +%part} +%\end{definition} +% Does \meta{true part} if \meta{num1}=\meta{num2}, otherwise does +% \meta{false part}. The numbers must use a full stop as the decimal +% character and no number group separator. The \verb|\number0| part +% allows an empty argument to be treated as zero. (\cs{number} +% required to prevent a zero prefix indicating an octal number.) +%\changes{2.12}{2012-11-30}{fixed bug causing premature expansion} +%\changes{2.26}{2016-07-20}{added \cs{number}} +% \begin{macrocode} +\newcommand*{\dtlifnumeq}[4]{% + \def\@dtl@truepart{#3}% + \def\@dtl@falsepart{#4}% + \pgfmathifthenelse{\number0#1==\number0#2}% + {"\noexpand\@dtl@truepart"}{"\noexpand\@dtl@falsepart"}% + \pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +% Load base package: +% \begin{macrocode} +\RequirePackage{datatool-base} +% \end{macrocode} +% +%\section{Comparison Commands} +%\begin{macro}{\dtlifnumlt} +%\begin{definition} +%\cs{dtlifnumlt}\marg{num1}\marg{num2}\marg{true part}\marg{false +%part} +%\end{definition} +% Does \meta{true part} if \meta{num1} \textless \meta{num2}, otherwise does +% \meta{false part}. The numbers must use a full stop as the decimal +% character and no number group separator. +%\changes{2.12}{2012-11-30}{fixed bug causing premature expansion} +%\changes{2.26}{2016-07-20}{added \cs{number}} +% \begin{macrocode} +\newcommand*{\dtlifnumlt}[4]{% + \def\@dtl@truepart{#3}% + \def\@dtl@falsepart{#4}% + \pgfmathifthenelse{\number0#1 < \number0#2}% + {"\noexpand\@dtl@truepart"}{"\noexpand\@dtl@falsepart"}% + \pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlifnumgt} +%\begin{definition} +%\cs{dtlifnumgt}\marg{num1}\marg{num2}\marg{true part}\marg{false +%part} +%\end{definition} +% Does \meta{true part} if \meta{num1} \textgreater \meta{num2}, otherwise does +% \meta{false part}. The numbers must use a full stop as the decimal +% character and no number group separator. +%\changes{2.12}{2012-11-30}{fixed bug causing premature expansion} +%\changes{2.26}{2016-07-20}{added \cs{number}} +% \begin{macrocode} +\newcommand*{\dtlifnumgt}[4]{% + \def\@dtl@truepart{#3}% + \def\@dtl@falsepart{#4}% + \pgfmathifthenelse{\number0#1 > \number0#2}% + {"\noexpand\@dtl@truepart"}{"\noexpand\@dtl@falsepart"}% + \pgfmathresult +} +% \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} where +% all numerical arguments are in standard fixed point notation. +%\changes{2.12}{2012-11-30}{fixed bug causing premature expansion} +%\changes{2.26}{2016-07-20}{added \cs{number}} +% \begin{macrocode} +\newcommand*{\dtlifnumopenbetween}[5]{% + \def\@dtl@truepart{#4}% + \def\@dtl@falsepart{#5}% + \pgfmathifthenelse + {(\number0#2 < \number0#1) && (\number0#1 < \number0#3)}% + {"\noexpand\@dtl@truepart"}{"\noexpand\@dtl@falsepart"}% + \pgfmathresult +} +% \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} where +% all numerical arguments are in standard fixed point notation. +%\changes{2.12}{2012-11-30}{fixed bug causing premature expansion} +%\changes{2.26}{2016-07-20}{added \cs{number}} +% \begin{macrocode} +\newcommand*{\dtlifnumclosedbetween}[5]{% + \def\@dtl@truepart{#4}% + \def\@dtl@falsepart{#5}% + \pgfmathifthenelse + {(\number0#2 <= \number0#1) && (\number0#1 <= \number0#3)} + {"\noexpand\@dtl@truepart"}{"\noexpand\@dtl@falsepart"}% + \pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\section{Functions} +%\begin{macro}{\dtladd} +% Adds two numbers using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtladd}[3]{% + \pgfmathadd{#2}{#3}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsub} +% Subtracts two numbers using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtlsub}[3]{% + \pgfmathsubtract{#2}{#3}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlmul} +% Multiplies two numbers using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtlmul}[3]{% + \pgfmathmultiply{#2}{#3}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldiv} +% Divides two numbers using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtldiv}[3]{% + \pgfmathdivide{#2}{#3}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlroot} +% Square root using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtlroot}[2]{% + \pgfmathsqrt{#2}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlround} +% Rounds using PGF math engine. +%\changes{2.26}{2016-07-20}{fixed bug cause by rounding} +% \begin{macrocode} +\newcommand*{\dtlround}[3]{% + \ifnum#3=0\relax + \pgfmathparse{int(round(#2))}% + \let#1\pgfmathresult + \else + \pgfmathparse{int(10^#3)}% + \let\dtl@tmpshift\pgfmathresult +% \end{macrocode} +%Need to be careful not to trigger the dimension too large error, +%so this is a bit convoluted. +% \begin{macrocode} + \pgfmathparse{int(floor(#2))}% + \let\dtl@int@round\pgfmathresult + \pgfmathparse{int(round((#2-\dtl@int@round) * \dtl@tmpshift))}% +% \end{macrocode} +%\changes{2.26}{2016-07-20}{fixed bug caused by rounding errors} +% This bit is awkward because simply dividing by multiples +% of 10 in pgfmath can cause rounding errors, so need to +% employ another method. +% \begin{macrocode} + \@dtl@tmpcount=0\relax + \expandafter\@dtl@countdigits\pgfmathresult.\relax + \advance\@dtl@tmpcount by -#3\relax + \def\@dtl@intpart{}% + \def\@dtl@fracpart{}% + \expandafter\@dtl@gatherintfrac\pgfmathresult\relax + \edef\@dtl@intpart{\number\numexpr\dtl@int@round + +\number0\@dtl@intpart}% + \edef#1{\@dtl@intpart.\@dtl@fracpart}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@gatherintfrac} +%\changes{2.26}{2016-07-20}{new} +% \begin{macrocode} +\newcommand*{\@dtl@gatherintfrac}[1]{% + \ifx\relax#1\relax + \else + \advance\@dtl@tmpcount by -1\relax + \ifnum\@dtl@tmpcount<0\relax + \edef\@dtl@fracpart{\@dtl@fracpart#1}% + \else + \edef\@dtl@intpart{\@dtl@intpart#1}% + \fi + \expandafter\@dtl@gatherintfrac + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtltrunc} +% Truncates using PGF math engine. +% (Third argument is the number of digits.) +%\changes{2.26}{2016-07-20}{new} +%This suffers from the same problems as \cs{dtlround}. Can +% cause dimension too large error or rounding errors. +% \begin{macrocode} +\newcommand*{\dtltrunc}[3]{% + \ifnum#3=0\relax + \pgfmathparse{int(floor(#2))}% + \let#1\pgfmathresult + \else + \pgfmathparse{int(10^#3)}% + \let\dtl@tmpshift\pgfmathresult +% \end{macrocode} +%Need to be careful not to trigger the dimension too large error, +%so this is a bit convoluted. +% \begin{macrocode} + \pgfmathparse{int(floor(#2))}% + \let\dtl@int@trunc\pgfmathresult + \pgfmathparse{int(floor((#2-\dtl@int@trunc) * \dtl@tmpshift))}% +% \end{macrocode} +%\changes{2.26}{2016-07-20}{fixed bug caused by rounding errors} +% This bit is awkward because simply dividing by multiples +% of 10 in pgfmath can cause rounding errors, so need to +% employ another method. +% \begin{macrocode} + \@dtl@tmpcount=0\relax + \expandafter\@dtl@countdigits\pgfmathresult.\relax + \advance\@dtl@tmpcount by -#3\relax + \def\@dtl@intpart{}% + \def\@dtl@fracpart{}% + \expandafter\@dtl@gatherintfrac\pgfmathresult\relax + \edef\@dtl@intpart{\number\numexpr\dtl@int@trunc + +\number0\@dtl@intpart}% + \edef#1{\@dtl@intpart.\@dtl@fracpart}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlclip} +% There isn't a clip in pgfmath as it seems to automatically clip. +% \begin{macrocode} +\newcommand*{\dtlclip}[2]{% + \edef#1{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlmin} +% Minimum of two numbers using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtlmin}[3]{% + \pgfmathmin{#2}{#3}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlmax} +% Maximum of two numbers using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtlmax}[3]{% + \pgfmathmax{#2}{#3}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlabs} +% Absolute value using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtlabs}[2]{% + \pgfmathabs{#2}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlneg} +% Negative of a value using PGF math engine. +% \begin{macrocode} +\newcommand*{\dtlneg}[2]{% + \pgfmathmul{-1}{#2}% + \let#1\pgfmathresult +} +% \end{macrocode} +%\end{macro} +% +%\iffalse +% \begin{macrocode} +%</datatool-pgfmath.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*datatool.sty> +% \end{macrocode} +%\fi +%\chapter{datatool.sty} +%\label{sec:code:datatool} +%\section{Package Declaration} +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datatool}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Load required packages: +% \begin{macrocode} +\RequirePackage{xkeyval} +\RequirePackage{ifthen} +\RequirePackage{xfor} +\RequirePackage{substr} +\RequirePackage{etoolbox} +% \end{macrocode} +%\changes{2.0}{2009 February 27}{added etex as a required package} +%\changes{2.23}{2015-07-11}{removed etex as a required package} +% +%\section{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 relevant 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} +\begingroup +\catcode`\^^I12 +%\begin{macro}{\DTLsettabseparator} +%\cs{DTLsettabseparator} makes it easier to set a tab separator. +%\changes{2.10}{2012-07-18}{changed tab character to +%\texttt{\textasciicircum\textasciicircum I}} +% \begin{macrocode} +\gdef\DTLsettabseparator{% + \catcode`\^^I12 + \DTLsetseparator{^^I}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmaketabspace} +%\changes{2.23}{2015-07-11}{restores tab catcode to 10} +% \begin{macrocode} +\gdef\DTLmaketabspace{% + \catcode`\^^I10\relax +} +\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} +%for the current separator and delimiter. +%\changes{2.30}{2018-04-16}{removed spurious spaces} +% \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\ifstrempty{##1}% + {\noexpand\@dtl@qlopoff#1{}##2\noexpand\to##3##4\relax}% + {% + \noexpand\dtl@ifsingle{##1}% + {\noexpand\@dtl@qlopoff#1##1##2\noexpand\to##3##4\relax}% + {\noexpand\@dtl@qlopoff#1{##1}##2\noexpand\to##3##4\relax}% + }% + \noexpand\else + \noexpand\ifstrempty{##1}% + {\noexpand\@dtl@lop@ff#1{}##2\noexpand\to##3##4\relax}% + {% + \noexpand\dtl@ifsingle{##1}% + {\noexpand\@dtl@lop@ff#1##1##2\noexpand\to##3##4\relax}% + {\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}% +% \end{macrocode} +% Replace any escaped delimiters +%\changes{2.10}{2012-07-18}{Added code to replace escaped delimiters} +% \begin{macrocode} + \noexpand\DTLsubstituteall{##4}{#2#2}{#2}% + \noexpand\edef\noexpand\@dtl@dosubs{% + \noexpand\noexpand\noexpand\DTLsubstituteall{\noexpand\noexpand##4}% + {\noexpand\expandafter\noexpand\noexpand\noexpand\csname#2\noexpand\endcsname#2}% + {\noexpand\expandafter\noexpand\noexpand\noexpand\csname#2\noexpand\endcsname}% + }% + \noexpand\@dtl@dosubs + \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{option}{separator} +% Define separator used in external data files. +% \begin{macrocode} +\define@key{datatool.sty}{separator}{% + \DTLsetseparator{#1}% +} +% \end{macrocode} +%\end{option} +% +%\begin{option}{delimiter} +% Define delimiter used in external data files. +% \begin{macrocode} +\define@key{datatool.sty}{delimiter}{% + \DTLsetdelimiter{#1}% +} +% \end{macrocode} +%\end{option} +% +%\begin{option}{verbose} +% \begin{macrocode} +\define@boolkey{datatool.sty}[dtl]{verbose}[true]{} +% \end{macrocode} +%\end{option} +% +%\begin{option}{math} +% Determine whether to use \sty{fp} or \sty{pgfmath} for the +% arithmetic commands. The default is to use \sty{fp}. +%\changes{2.13}{2013-01-15}{changed \cs{newcommand} to +%\cs{providecommand}} +% \begin{macrocode} +\define@choicekey{datatool.sty}{math}[\val\nr]{fp,pgfmath}{% + \renewcommand*\@dtl@mathprocessor{#1}% +} +\providecommand*{\@dtl@mathprocessor}{fp} +% \end{macrocode} +%\end{option} +% +%\begin{macro}{\@dtl@set@options} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\@dtl@set@options}{} +% \end{macrocode} +%\end{macro} +%\begin{option}{utf8} +%\changes{2.28}{2017-11-10}{new} +%Pass to \sty{datatool-base} +% \begin{macrocode} +\define@choicekey{datatool.sty}{utf8}{true,false}[true]{% + \renewcommand*{\@dtl@set@options}{\setbool{@dtl@utf8}{#1}}% +} +% \end{macrocode} +%\end{option} +% Process package options: +% \begin{macrocode} +\ProcessOptionsX +% \end{macrocode} +% +% Set the defaults: +% \begin{macrocode} +\@dtl@construct@lopoffs +% \end{macrocode} +% +% Load base package: +% \begin{macrocode} +\RequirePackage{datatool-base} +% \end{macrocode} +%Set options that depend on \sty{datatool-base}: +% \begin{macrocode} +\@dtl@set@options +% \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. This command needs to be robust so it doesn't get +% expanded when written to a file. We also can't just use a synonym +% for \cs{@@par} because it may be used in a context where \cs{par} +% has a different meaning to \cs{@@par}. +%\changes{2.14}{2013-06-28}{changed to \cs{let}} +%\changes{2.18}{2013-09-06}{changed back to a robust command} +% \begin{macrocode} +\DeclareRobustCommand{\DTLpar}{\par} +% \end{macrocode} +%\end{macro} +% +% \section{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}{\DTLgnewdb} +%\begin{definition} +% \cs{DTLgnewdb}\marg{db name} +%\end{definition} +%\changes{2.13}{2013-01-15}{new} +% Initialises a database called \meta{name}. (Global version.) +% \begin{macrocode} +\newcommand*{\DTLgnewdb}[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\global\expandafter\newtoks\csname dtldb@#1\endcsname +% \end{macrocode} +% Define token register used to store the column header information. +% \begin{macrocode} + \expandafter\global\expandafter\newtoks\csname dtlkeys@#1\endcsname{}% +% \end{macrocode} +% Define count register used to store the row count. +% \begin{macrocode} + \expandafter\global\expandafter\newcount\csname dtlrows@#1\endcsname +% \end{macrocode} +% Define count register used to store the column count. +% \begin{macrocode} + \expandafter\global\expandafter\newcount\csname dtlcols@#1\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgdeletedb} +%\begin{definition} +% \cs{DTLgdeletedb}\marg{db name} +%\end{definition} +% Deletes a database. (Global version.) +%\changes{2.13}{2013-01-15}{new} +% \begin{macrocode} +\newcommand*{\DTLgdeletedb}[1]{% + \DTLifdbexists{#1}% + {% + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do + {% + \expandafter\global\expandafter\let\csname dtl@ci@#1@\@dtl@key\endcsname\undefined + }% + \expandafter\global\expandafter\let\csname dtldb@#1\endcsname\undefined + \expandafter\global\expandafter\let\csname dtlkeys@#1\endcsname\undefined + \expandafter\global\expandafter\let\csname dtlrows@#1\endcsname\undefined + \expandafter\global\expandafter\let\csname dtlcols@#1\endcsname\undefined + }% + {% + \PackageError{Can't delete database `#1': + database doesn't exist}{}{}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgcleardb} +%\begin{definition} +% \cs{DTLgcleardb}\marg{db name} +%\end{definition} +% Clears the database. (Global version.) +%\changes{2.13}{2013-01-15}{new} +% \begin{macrocode} +\newcommand*{\DTLgcleardb}[1]{% + \DTLifdbexists{#1}% + {% + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do + {% + \expandafter\global\expandafter\let\csname dtl@ci@#1@\@dtl@key\endcsname\undefined + }% + \expandafter\global\csname dtldb@#1\endcsname{}% + \expandafter\global\csname dtlkeys@#1\endcsname{}% + \expandafter\global\csname dtlrows@#1\endcsname=0\relax + \expandafter\global\csname dtlcols@#1\endcsname=0\relax + }% + {% + \PackageError{Can't clear 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 existence +% of the database.) +%\changes{2.13}{2013-01-15}{fixed typo in \cs{PackageError}} +% \begin{macrocode} +\newcommand*{\@DTLnewrow}[1]{% +\DTLifdbexists{#1}% + {\@sDTLnewrow{#1}}% + {\PackageError{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} + \@dtl@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. +%\changes{2.10}{2012-07-18}{fixed bug} +% \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 dtlkeys@#2\endcsname}% + \expandafter\@dtl@get@keyforcolumn\@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}{\DTLaddcolumn} +%\begin{definition} +%\cs{DTLaddcolumn}\marg{db}\marg{key} +%\end{definition} +% Adds a column with given key to given column. No data is added to +% the column. The starred version doesn't check for the existence of +% the database. +%\changes{2.11}{2012-09-25}{new} +% \begin{macrocode} +\newcommand*{\DTLaddcolumn}{% + \@ifstar\@sDTLaddcolumn\@DTLaddcolumn +} +\newcommand{\@DTLaddcolumn}[2]{% + \DTLifdbexists{#1}% + {\@dtl@updatekeys{#1}{#2}{}}% + {\PackageError{datatool}{Can't add new column to database `#1': + database doesn't exist}{}}% +} +\newcommand{\s@DTLaddcolumn}[2]{% + \@dtl@updatekeys{#1}{#2}{}% +} +% \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 +%\changes{2.11}{2012-09-25}{remove unwanted space} +% \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? +%\changes{2.14}{2013-06-28}{expand value before testing if it's +%empty} +%\changes{2.16}{2013-08-16}{reverted to not expanding value (2.14 change +%causes an error with fragile commands). Fix now in +%\cs{@dtl@checknumerical}} +% \begin{macrocode} + \ifstrempty{#3}% + {% +% \end{macrocode} +% Leave data type as it is +% \begin{macrocode} + }% + {% +% \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} + \ifdefempty{\@dtl@type}% + {% + \edef\@dtl@type{\number\@dtl@datatype}% + }% + {% +% \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 + }% +% \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} + \@dtl@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 + }% + }% + {% +% \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} + \ifstrempty{#2}% + {% + \edef\@dtl@type{}% don't know data type yet + }% + {% + \@dtl@checknumerical{#3}% + \edef\@dtl@type{\number\@dtl@datatype}% + }% +% \end{macrocode} +% Append to property list +% \begin{macrocode} + \@dtl@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 +%\changes{2.13}{2013-01-15}{removed spurious space} +% \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 + \@dtl@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} + \@dtl@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}} +% +%\section{Accessing Data} +% +%\begin{macro}{\DTLassign} +%\begin{definition} +%\cs{DTLassign}\marg{db}\marg{row idx}\marg{assign list} +%\end{definition} +% Assigns values given in \meta{assign list} for row \meta{row idx} in database +% \meta{db}. (Where \meta{assign list} is in the same form as in +% \cs{DTLforeach}) +%\changes{2.10}{2012-07-18}{new} +% \begin{macrocode} +\newcommand*{\DTLassign}[3]{% + \DTLifdbexists{#1} + {% +% \end{macrocode} +% Grouped in the event that \cs{dtlcurrentrow} is already in use. +% (Assignments in \cs{@dtl@assign} are global.) +% \begin{macrocode} + {% + \dtlgetrow{#1}{#2}% + \@dtl@assign{#3}{#1}% + }% + }% + {% + \PackageError{datatool}{Database `#1' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLassignfirstmatch} +%\begin{definition} +%\cs{DTLassignfirstmatch}\marg{db}\marg{col key}\marg{value}\marg{assign list} +%\end{definition} +% Applies the assignment list to the first row that has the given +% value in the given column. (Value must be expanded.) +%\changes{2.20}{2014-02-03}{new} +% \begin{macrocode} +\newcommand*{\DTLassignfirstmatch}[4]{% + \dtl@assignfirstmatch{#3}{#1}{#2}{#4}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\xDTLassignfirstmatch} +%\begin{definition} +%\cs{xDTLassignfirstmatch}\marg{db}\marg{col key}\marg{value}\marg{assign list} +%\end{definition} +% Applies the assignment list to the first row that has the given +% value in the given column. (Performs \emph{one level} expansion on +% \meta{value}.) +%\changes{2.20}{2014-02-03}{new} +% \begin{macrocode} +\newcommand*{\xDTLassignfirstmatch}[4]{% + \protected@edef\@dtl@asg@value{\expandonce{#3}}% + \expandafter\dtl@assignfirstmatch\expandafter + {\@dtl@asg@value}{#1}{#2}{#4}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@assignfirstmatch} +% Internal swaps the ordering around so the value is first. (This +% just makes it easier for \cs{xDTLassignfirstmatch} +% \begin{macrocode} +\newcommand*{\dtl@assignfirstmatch}[4]{% + \DTLifdbexists{#2}% + {% +% Grouped in the event that \cs{dtlcurrentrow} is already in use. +% (Assignments in \cs{@dtl@assign} are global.) +% \begin{macrocode} + {% +% \end{macrocode} +% Get row idx: +% \begin{macrocode} + \dtlgetrowindex{\dtl@asg@rowidx}{#2}{\dtlcolumnindex{#2}{#3}}{#1}% + \ifx\dtl@asg@rowidx\dtlnovalue + \PackageError{datatool}{No match found for + \string\DTLassignfirstmatch{#2}{#3}{#1}{#4}}{}% + \else + \dtlgetrow{#2}{\dtl@asg@rowidx}% + \@dtl@assign{#4}{#2}% + \fi + }% + }% + {% + \PackageError{datatool}{Data base `#2' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\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} +%\changes{2.20}{2014-02-03}{Added check for empty argument}% +% \begin{macrocode} +\newcommand*{\@dtl@assign}[2]{% + \ifstrempty{#1}{}% + {% + \@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} +% Store database label. (This may already have been done so \cs{edef} +% is used to prevent infinite recursion.) +%\changes{2.20}{2014-02-03}{Stored db label in \cs{@dtl@dbname}} +% \begin{macrocode} + \edef\@dtl@dbname{#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} + \ifdefequal{#1}{\dtlnovalue}% + {% + \@@dtl@setnull{#1}{#3}% + }% + {}% +% \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}{\@dtlstringnull} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtlstringnull} +%\changes{2.13}{2013-01-15}{new} +% String null value: +% \begin{macrocode} +\newcommand*{\@dtlstringnull}{NULL} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLnumbernull} +% Number null value: +% \begin{macrocode} +\newcommand*{\DTLnumbernull}{\@dtlnumbernull} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@dtlnumbernull} +%\changes{2.13}{2013-01-15}{new} +% Number null value: +% \begin{macrocode} +\newcommand*{\@dtlnumbernull}{0} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLifnull} +%\begin{definition} +%\cs{DTLifnull}\marg{command}\marg{true part}\marg{false part} +%\end{definition} +% Checks if \meta{command} 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#1\dtlnovalue + #2% + \else + \ifx#1\DTLstringnull + #2% + \else + \ifx#1\DTLnumbernull + #2% + \else + #3% + \fi + \fi + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLifnullorempty} +%\begin{definition} +%\cs{DTLifnullorempty}\marg{command}\marg{true part}\marg{false part} +%\end{definition} +%\changes{2.20}{2014-02-03}{new} +% \begin{macrocode} +\newcommand*{\DTLifnullorempty}[3]{% + \ifdefempty{#1}{#2}{\DTLifnull{#1}{#2}{#3}}% +} +% \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 + {% +% \end{macrocode} +%\changes{2.21}{2014-03-08}{fixed bug that ignore row tok argument} +% \begin{macrocode} + \dtlgetentryfromrow{\@dtl@tmp}{\@dtl@col}{#3}% + \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}{\dtl@g@gathervalues} +%\begin{definition} +%\cs{dtl@g@gathervalues}\oarg{label}\marg{db name}\marg{row toks} +%\end{definition} +% As above but makes global assignments +%\changes{2.21}{2014-03-08}{new} +% \begin{macrocode} +\newcommand{\dtl@g@gathervalues}[3][key]{% + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#2}\do + {% + \dtlgetentryfromrow{\@dtl@tmp}{\@dtl@col}{#3}% + \ifx\@dtl@tmp\dtlnovalue + \@dtl@setnull{\@dtl@tmp}{\@dtl@key}% + \fi + \expandafter\global + \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}. +% The row index, \meta{row idx}, is stored in \cs{dtlrownum} +% and the database name, \meta{db}, is stored in \cs{dtldbname}. +% This assumes that the given row exists. +% \begin{macrocode} +\newcommand*{\dtlgetrow}[2]{% + \dtlrownum=#2\relax + \edef\dtldbname{#1}% + \expandafter\toks@\expandafter=\csname dtldb@#1\endcsname + \edef\@dtl@dogetrow{\noexpand\@dtlgetrow{\the\toks@}{\number#2}}% + \@dtl@dogetrow +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\edtlgetrowforvalue} +%\changes{2.17}{2013-08-29}{new} +%\begin{definition} +%\cs{edtlgetrowforvalue}\marg{db}\marg{column idx}\marg{value} +%\end{definition} +% A version of \cs{dtlgetrowforvalue} that expands its arguments. +% \begin{macrocode} +\newcommand{\edtlgetrowforvalue}[3]{% + \protected@edef\@dtl@dogetrowforvalue{% + \noexpand\dtlgetrowforvalue{#1}{#2}{#3}}% + \@dtl@dogetrowforvalue +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLfetch} +%\changes{2.17}{2013-08-29}{new} +%\begin{definition} +%\cs{DTLfetch}\marg{db name}\marg{column1 name}\marg{column1 +%value}\marg{column2 name} +%\end{definition} +% Fetches and displays the value for \meta{column2 name} in the +% first row where the value of \meta{column1 name} is \meta{column1 +% value}. Note that all arguments are expanded. +% \begin{macrocode} +\newcommand{\DTLfetch}[4]{% + \edtlgetrowforvalue{#1}{\dtlcolumnindex{#1}{#2}}{#3}% + \dtlgetentryfromcurrentrow{\dtlcurrentvalue}{\dtlcolumnindex{#1}{#4}}% + \dtlcurrentvalue +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlgetrowforvalue} +%\begin{definition} +%\cs{dtlgetrowforvalue}\marg{db}\marg{column idx}\marg{value} +%\end{definition} +% Like \cs{dtlgetrow}, but gets the row where the entry in column +% \meta{column index} matches \meta{value}. Produces an error if row +% not found. +%\changes{2.11}{2012-09-25}{new} +% \begin{macrocode} +\newcommand*{\dtlgetrowforvalue}[3]{% + \dtlgetrowindex{\dtl@rowidx}{#1}{#2}{#3}% + \ifx\dtl@rowidx\dtlnovalue + \PackageError{datatool}{No row found in database `#1' for + column `\number#2' matching `#3'}{}% + \else + \dtlrownum=\dtl@rowidx\relax + \edef\dtldbname{#1}% + \expandafter\toks@\expandafter=\csname dtldb@#1\endcsname + \edef\@dtl@dogetrow{\noexpand\@dtlgetrow{\the\toks@}{\dtl@rowidx}}% + \@dtl@dogetrow + \fi +} +% \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}{\dtlrecombine} +%\begin{definition} +%\cs{dtlrecombine} +%\end{definition} +% Recombines database contents from \cs{dtlbeforerow}, +% \cs{dtlcurrentrow} and \cs{dtlafterrow} +% \begin{macrocode} +\newcommand*{\dtlrecombine}{% + \@dtl@toks@gconcat@middle@cx{dtldb@\dtldbname}% + {\dtlbeforerow}% + {% +% \end{macrocode} +% Start of row tag +% \begin{macrocode} + \noexpand\db@row@elt@w +% \end{macrocode} +% Row number +% \begin{macrocode} + \noexpand\db@row@id@w + \number\dtlrownum + \noexpand\db@row@id@end@ +% \end{macrocode} +% Current row specs: +% \begin{macrocode} + \the\dtlcurrentrow +% \end{macrocode} +% Row number +% \begin{macrocode} + \noexpand\db@row@id@w + \number\dtlrownum + \noexpand\db@row@id@end@ +% \end{macrocode} +% End of row tag +% \begin{macrocode} + \noexpand\db@row@elt@end@ + }% + {\dtlafterrow}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlrecombineomitcurrent} +%\begin{definition} +%\cs{dtlrecombineomitcurrent} +%\end{definition} +%Like \cs{dtlrecombine} but omits \cs{dtlcurrentrow} +%\changes{2.10}{2012-07-18}{new} +% \begin{macrocode} +\newcommand{\dtlrecombineomitcurrent}{% +% \end{macrocode} +% Decrement row indices in \cs{dtlafterrow}: +% \begin{macrocode} + \dtl@decrementrows{\dtlafterrow}{\dtlrownum} +% \end{macrocode} +% Reconstruct database contents by concatenating +% \cs{dtlbeforerow} and \cs{dtlafterrow} +% \begin{macrocode} + \csname dtldb@\dtldbname\endcsname=\dtlbeforerow + \@dtl@toks@gput@right@cx{dtldb@\dtldbname}{\the\dtlafterrow}% + \dtl@message{Removed row \number\dtlrownum\space in database + `\dtldbname'}% +} +% \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} +% +%\begin{macro}{\dtlreplaceentryincurrentrow} +%\begin{definition} +%\cs{dtlreplaceentryincurrentrow}\marg{new value}\marg{col num} +%\end{definition} +% Replaces entry for column \meta{col num} in \cs{dtlcurrentrow} +% with \meta{new value} +%\changes{2.10}{2012-07-18}{new} +% \begin{macrocode} +\newcommand*{\dtlreplaceentryincurrentrow}[2]{% +% \end{macrocode} +% Split row +% \begin{macrocode} + \edef\@dtl@do@splitrow{\noexpand\dtlsplitrow + {\the\dtlcurrentrow}% + {\number#2}% + {\noexpand\@dtl@before@cs}% + {\noexpand\@dtl@after@cs}}% + \@dtl@do@splitrow +% \end{macrocode} +% Recombine with new value +% \begin{macrocode} + \toks@{#1}% + \edef\@dtl@stuff{% + \expandonce\@dtl@before@cs +% \end{macrocode} +% Begin column index specs: +% \begin{macrocode} + \noexpand\db@col@id@w \number#2\noexpand + \noexpand\db@col@id@end@% column id +% \end{macrocode} +% New entry: +% \begin{macrocode} + \noexpand\db@col@elt@w + \the\toks@ + \noexpand\db@col@elt@end@ +% \end{macrocode} +% End column index specs: +% \begin{macrocode} + \noexpand\db@col@id@w \number#2\noexpand + \noexpand\db@col@id@end@% column id + \expandonce\@dtl@after@cs + }% +% \end{macrocode} +% Store in \cs{dtlcurrentrow} +% \begin{macrocode} + \expandafter\dtlcurrentrow\expandafter{\@dtl@stuff}% +% \end{macrocode} +% Update column specs +% \begin{macrocode} + \@sdtlgetkeyforcolumn{\@dtl@key}{\dtldbname}{#2}% + \@dtl@updatekeys{\dtldbname}{\@dtl@key}{#1}% + \dtl@message{Updated \@dtl@key\space -> #1\space in database + `\dtldbname'}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlremoveentryincurrentrow} +%\begin{definition} +%\cs{dtlremoveentryincurrentrow}\marg{col idx} +%\end{definition} +% Removes entry for column \meta{col idx} from \cs{dtlcurrentrow}. +%\changes{2.10}{2012-07-18}{new} +% \begin{macrocode} +\newcommand*{\dtlremoveentryincurrentrow}[1]{% +% \end{macrocode} +% Split row +% \begin{macrocode} + \edef\@dtl@do@splitrow{\noexpand\dtlsplitrow + {\the\dtlcurrentrow}% + {\number#1}% + {\noexpand\@dtl@before@cs}% + {\noexpand\@dtl@after@cs}}% + \@dtl@do@splitrow +% \end{macrocode} +% Combine row without given column: +% \begin{macrocode} + \edef\@dtl@stuff{% + \expandonce\@dtl@before@cs + \expandonce\@dtl@after@cs + }% +% \end{macrocode} +% Store in \cs{dtlcurrentrow} +% \begin{macrocode} + \expandafter\dtlcurrentrow\expandafter{\@dtl@stuff}% + \dtl@message{Removed entry from column \number#1\space\space in database + `\dtldbname'}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlswapentriesincurrentrow} +%\begin{definition} +%\cs{dtlswapentriesincurrentrow}\marg{col1 +%num}\marg{col2 num} +%\end{definition} +% Swaps columns \meta{col1 num} and \meta{col2 num} in \cs{dtlcurrentrow} +%\changes{2.10}{2012-07-18}{new} +% \begin{macrocode} +\newcommand*{\dtlswapentriesincurrentrow}[2]{% + \dtlgetentryfromcurrentrow{\@dtl@entryI}{#1}% + \dtlgetentryfromcurrentrow{\@dtl@entryII}{#2}% + \expandafter\dtlreplaceentryincurrentrow\expandafter + {\@dtl@entryII}{#1}% + \expandafter\dtlreplaceentryincurrentrow\expandafter + {\@dtl@entryI}{#2}% +} +% \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}{\dtlappendentrytocurrentrow} +%\begin{definition} +%\cs{dtlappendentrytocurrentrow}\marg{key}\marg{value} +%\end{definition} +% Appends entry to \cs{dtlcurrentrow} +%\changes{2.10}{2012-07-18}{new} +% \begin{macrocode} +\newcommand*{\dtlappendentrytocurrentrow}[2]{% +% \end{macrocode} +% Update information about this column (adding new column if +% necessary) +% \begin{macrocode} + \@dtl@updatekeys{\dtldbname}{#1}{#2}% +% \end{macrocode} +% Get column index and store in \cs{dtlcolumnnum} +% \begin{macrocode} + \expandafter\dtlcolumnnum\expandafter + =\dtlcolumnindex{\dtldbname}{#1}\relax +% \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. +% \begin{macrocode} + \protected@edef\@dtl@tmp{#2}% + \expandafter\@dtl@toks\expandafter{\@dtl@tmp}% +% \end{macrocode} +% Append this entry to the current row. +% \begin{macrocode} + \@dtl@toks@gput@right@cx{dtlcurrentrow}% + {% +% \end{macrocode} +% Begin column index specs: +% \begin{macrocode} + \noexpand\db@col@id@w + \number\dtlcolumnnum + \noexpand\db@col@id@end@ +% \end{macrocode} +% New entry: +% \begin{macrocode} + \noexpand\db@col@elt@w + \the\@dtl@toks + \noexpand\db@col@elt@end@ +% \end{macrocode} +% End column index specs: +% \begin{macrocode} + \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 + `\dtldbname'}% + \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 +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlupdateentryincurrentrow} +%\begin{definition} +%\cs{dtlupdateentryincurrentrow}\marg{key}\marg{value} +%\end{definition} +% Appends entry to \cs{dtlcurrentrow} if column with given key +% doesn't exist, otherwise updates the value. +%\changes{2.11}{2012-09-25}{new} +% \begin{macrocode} +\newcommand*{\dtlupdateentryincurrentrow}[2]{% +% \end{macrocode} +% Update information about this column (adding new column if +% necessary) +% \begin{macrocode} + \@dtl@updatekeys{\dtldbname}{#1}{#2}% +% \end{macrocode} +% Get column index and store in \cs{dtlcolumnnum} +% \begin{macrocode} + \expandafter\dtlcolumnnum\expandafter + =\dtlcolumnindex{\dtldbname}{#1}\relax +% \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. +% \begin{macrocode} + \protected@edef\@dtl@tmp{#2}% + \expandafter\@dtl@toks\expandafter{\@dtl@tmp}% +% \end{macrocode} +% Append this entry to the current row. +% \begin{macrocode} + \@dtl@toks@gput@right@cx{dtlcurrentrow}% + {% +% \end{macrocode} +% Begin column index specs: +% \begin{macrocode} + \noexpand\db@col@id@w + \number\dtlcolumnnum + \noexpand\db@col@id@end@ +% \end{macrocode} +% New entry: +% \begin{macrocode} + \noexpand\db@col@elt@w + \the\@dtl@toks + \noexpand\db@col@elt@end@ +% \end{macrocode} +% End column index specs: +% \begin{macrocode} + \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 + `\dtldbname'}% + \else +% \end{macrocode} +% There is already an entry in this row for the given key +% \begin{macrocode} + \toks@{#2}% + \edef\do@dtlreplaceincurrentrow{% + \noexpand\dtlreplaceentryincurrentrow{\the\toks@}{\number\dtlcolumnnum}% + }% + \do@dtlreplaceincurrentrow + \fi +} +% \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 <r> + \db@row@id@w #3\db@row@id@end@% row <r> id + ##2% stuff in row <r> before column <c> + \db@col@id@w #4\db@col@id@end@% column <c> id + \db@col@elt@w ##3\db@col@elt@end@% value + ##4% stuff after value + \q@nil{\def#1{##3}}% + \toks@=\csname dtldb@#2\endcsname + \expandafter\@dtl@getvalue\the\toks@% contents of data base + \db@row@id@w #3\db@row@id@end@% + \db@col@id@w #4\db@col@id@end@% + \db@col@elt@w \@dtlnovalue\db@col@elt@end@% undefined value + \q@nil + \ifx#1\dtlnovalue + \PackageError{datatool}{There is no element at (row=#3,\space + 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} +% +%\begin{macro}{\DTLgetrowindex} +%\begin{definition} +%\cs{DTLgetrowindex}\marg{row cs}\marg{database}\marg{column index}% +%\marg{value} +%\end{definition} +% Assigns \meta{row cs} to the row index of the +% first entry in \meta{database} where the entry in \meta{column +% index} matches \meta{value}. +%\changes{2.11}{2012-09-25}{new} +% \begin{macrocode} +\newcommand*{\DTLgetrowindex}[4]{% + \toks@{#4}% + \edef\dtl@dogetrowindex{\noexpand\@dtlgetrowindex{\noexpand#1}{#2}{\number#3}{\the\toks@}}% + \dtl@dogetrowindex + \ifx#1\dtlnovalue + \PackageError{datatool}{There is no element `#4' for column + \number#3\space in database `#2'}{}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlgetrowindex} +%\begin{definition} +%\cs{dtlgetrowindex}\marg{row cs}\marg{database}\marg{column index}% +%\marg{value} +%\end{definition} +% As above but doesn't produce an error if not found. +%\changes{2.11}{2012-09-25}{new} +% \begin{macrocode} +\newcommand*{\dtlgetrowindex}[4]{% + \toks@{#4}% + \edef\dtl@dogetrowindex{\noexpand\@dtlgetrowindex{\noexpand#1}{#2}{\number#3}{\the\toks@}}% + \dtl@dogetrowindex +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\xdtlgetrowindex} +%\begin{definition} +%\cs{xdtlgetrowindex}\marg{row cs}\marg{database}\marg{column index}% +%\marg{value} +%\end{definition} +% As above but expands the value. +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\xdtlgetrowindex}[4]{% + \protected@edef\dtl@dogetrowindex{\noexpand\@dtlgetrowindex{\noexpand#1}{#2}{\number#3}{#4}}% + \dtl@dogetrowindex +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlgetrowindex} +%\begin{definition} +%\cs{@dtlgetrowindex}\marg{row cs}\marg{database}\marg{column index}% +%\marg{value} +%\end{definition} +% Column index must be fully expanded. +%\changes{2.11}{2012-09-25}{new} +% \begin{macrocode} +\newcommand*{\@dtlgetrowindex}[4]{% + \def\@dtl@getrowindex##1% stuff before value + \db@col@elt@w #4\db@col@elt@end@% value + \db@col@id@w #3\db@col@id@end@% column id + ##2% stuff after this column + \db@row@id@w ##3\db@row@id@end@% row id + ##4% stuff after row + \q@nil{\def#1{##3}}% + \toks@=\csname dtldb@#2\endcsname + \expandafter\@dtl@getrowindex\the\toks@% contents of data base + \db@col@elt@w #4\db@col@elt@end@% value + \db@col@id@w #3\db@col@id@end@% column id + \db@row@id@w \@dtlnovalue\db@row@id@end@% undefined row id + \q@nil +} +% \end{macrocode} +%\end{macro} + + +%\section{Iterating Through Databases} +%\label{sec:code:loops} +% +%\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,\meta{type cs} stores the data type and \meta{header +% cs} stores the header. +% \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 <col num> in database <db>. +% 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 <cs> +% \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{environment}{DTLenvforeach} +% Environment form of \cs{DTLforeach} (contents are gathered, so +% verbatim can't be used). +% \begin{macrocode} +\newenvironment{DTLenvforeach}[3][\boolean{true}]% +{% + \def\@dtlenvforeach@args{[#1]{#2}{#3}}% + \long@collect@body\@do@dtlenvforeach +}% +{} +\newcommand{\@do@dtlenvforeach}[1]{% + \expandafter\@DTLforeach\@dtlenvforeach@args{#1}% +} +% \end{macrocode} +%\end{environment} +% +%\begin{environment}{DTLenvforeach*} +% Environment form of \cs{DTLforeach*} (contents are gathered, so +% verbatim can't be used). +% \begin{macrocode} +\newenvironment{DTLenvforeach*}[3][\boolean{true}]% +{% + \def\s@dtlenvforeach@args{[#1]{#2}{#3}}% + \long@collect@body\@do@sdtlenvforeach +}% +{} +\newcommand{\@do@sdtlenvforeach}[1]{% + \expandafter\@sDTLforeach\s@dtlenvforeach@args{#1}% +} +% \end{macrocode} +%\end{environment} +% +%\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 +%\changes{2.20}{2014-02-03}{change \cs{gdef} to \cs{xdef}} +% \begin{macrocode} + \xdef\@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} +%\changes{2.12}{2012-11-30}{fixed bug in \cs{DTLiflastrow}} +% \begin{macrocode} + \gdef\DTLiflastrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =\csname dtlrows@#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 + \@dtl@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} +% Store database name. +%\changes{2.20}{2014-02-03}{Added missing \cs{@dtl@dbname} assignment} +% \begin{macrocode} + \xdef\@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} +%\changes{2.12}{2012-11-30}{fixed bug in \cs{DTLiflastrow}} +% \begin{macrocode} + \gdef\DTLiflastrow##1##2{% + \expandafter\ifnum + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname + =\csname dtlrows@#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} + \@dtl@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}% + \@dtl@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 +%\changes{2.13}{2013-01-15}{removed spurious space} +% \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} +%\changes{2.13}{2013-01-15}{changed to use \cs{@dtlstringnull} and +%\cs{@dtlnumbernull}}% +% 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} +% +%\section{DTLforeach Conditionals} +% 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} +% +%\section{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 + \ifstrempty{#2}% + {% + \protected@edef#1{#1c}% + }% + {% + \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 + }% + \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}{\dtldisplayvalign} +%\changes{2.11}{2012-09-25}{new} +% Stores the vertical alignment specifier for the tabular +% environment used in \cs{DTLdisplaydb} +% \begin{macrocode} +\newcommand*{\dtldisplayvalign}{c} +% \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}{\dtldisplaycr} +%\changes{2.19}{2014-01-17}{new} +% \begin{macrocode} +\newcommand{\dtldisplaycr}{\tabularnewline} +% \end{macrocode} +%\end{macro} + +%\begin{macro}{\DTLdisplaydb} +%\begin{definition} +%\cs{DTLdisplaydb}\oarg{omit list}\marg{db} +%\end{definition} +% Displays the database \meta{db} in a tabular environment. +%\changes{2.0}{2009 February 27}{new} +%\changes{2.10}{2012-07-18}{added optional arg} +% \begin{macrocode} +\newcommand*{\DTLdisplaydb}[2][]{% +% \end{macrocode} +% Initialise: +% only want "&" between columns +%\changes{2.13}{2013-01-15}{removed spurious space} +% \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@#2\endcsname}% +% \end{macrocode} +% Subtract number of omitted columns +% \begin{macrocode} + \DTLnumitemsinlist{#1}{\@dtl@tmp}% + \dtlsub{\@dtl@maxcols}{\@dtl@maxcols}{\@dtl@tmp}% + \dtlclip{\@dtl@maxcols}{\@dtl@maxcols}% +% \end{macrocode} +% Argument for tabular environment +% \begin{macrocode} + \def\@dtl@tabargs{}% + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {% + \expandafter\DTLifinlist\expandafter{\@dtl@key}{#1}% + {}% + {% + \dtladdalign\@dtl@tabargs\@dtl@type\@dtl@idx\@dtl@maxcols +% \end{macrocode} +%\changes{2.13}{2013-01-15}{removed spurious space} +% \begin{macrocode} + }% + }% +% \end{macrocode} +% Begin tabular environment +% \begin{macrocode} + \edef\@dtl@dobegintab{\noexpand\begin{tabular}[\dtldisplayvalign]{\@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{#2}\do + {% + \expandafter\DTLifinlist\expandafter{\@dtl@key}{#1}% + {}% + {% + \@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} + \@sDTLforeach{#2}{}{% +% \end{macrocode} +% Do the start row hook if not the first row +%\changes{2.19}{2014-01-17}{switched to \cs{dtldisplaycr}} +% \begin{macrocode} + \DTLiffirstrow{}{\dtldisplaycr\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}% + {% + \expandafter\DTLifinlist\expandafter{\dtlkey}{#1}% + {}% + {% +% \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} +% List of omitted columns +% \begin{macrocode} +\define@key{displaylong}{omit}{\def\@dtl@omitlist{#1}} +% \end{macrocode} +% +%\begin{macro}{\@dtl@resetdostartrow} +% Resets start row hook so that it skips the first row. +%\changes{2.19}{2014-01-17}{switched to \cs{dtldisplaycr}} +% \begin{macrocode} +\newcommand*{\@dtl@resetdostartrow}{% + \gdef\@dtl@dostartrow{% + \gdef\@dtl@dostartrow{\dtldisplaycr\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} +%\changes{2.10}{2012-07-18}{added omit option} +% \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}% + \def\@dtl@omitlist{}% +% \end{macrocode} +% Set the options +% \begin{macrocode} + \setkeys{displaylong}{#1}% +% \end{macrocode} +% Only want "&" between columns +%\changes{2.13}{2013-01-15}{removed spurious space} +% \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} +% Subtract number of omitted columns +% \begin{macrocode} + \DTLnumitemsinlist{\@dtl@omitlist}{\@dtl@tmp}% + \dtlsub{\@dtl@maxcols}{\@dtl@maxcols}{\@dtl@tmp}% + \dtlclip{\@dtl@maxcols}{\@dtl@maxcols}% +% \end{macrocode} +% Argument for \env{longtable} environment +% \begin{macrocode} + \def\@dtl@tabargs{}% + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {% + \expandafter\DTLifinlist\expandafter{\@dtl@key}{\@dtl@omitlist}% + {}% + {% + \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} +% 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 + \dtldisplaystarttab + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {% + \expandafter\DTLifinlist\expandafter{\@dtl@key}{\@dtl@omitlist}% + {}% + {% + \@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 + \dtldisplaycr +% \end{macrocode} +%\changes{2.21}{2014-03-08}{fixed location of \cs{dtldisplaystarttab}} +% Do start hook. +% \begin{macrocode} + \dtldisplaystarttab +% \end{macrocode} +% Do header row. +% \begin{macrocode} + \@dtl@resetdoamp + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {% + \expandafter\DTLifinlist\expandafter{\@dtl@key}{\@dtl@omitlist}% + {}% + {% + \@dtl@doamp{\dtlheaderformat{\@dtl@head}}% + }% + }% + \@dtl@resetdoamp +% \end{macrocode} +%\changes{2.21}{2014-03-08}{added missing \cs{dtldisplayafterhead}} +% \begin{macrocode} + \dtldisplaycr\dtldisplayafterhead + \endfirsthead +% \end{macrocode} +% Is a continuation caption required? +% \begin{macrocode} + \ifx\@dtl@contcap\@nnil + \caption{\@dtl@cap}% + \else + \caption{\@dtl@contcap}% + \fi +% \end{macrocode} +%\changes{2.21}{2014-03-08}{fixed location of \cs{dtldisplaystarttab}} +% Do start hook. +% \begin{macrocode} + \dtldisplaycr\dtldisplaystarttab +% \end{macrocode} +% Do header row. +% \begin{macrocode} + \@dtl@resetdoamp + \dtlforeachkey(\@dtl@key,\@dtl@idx,\@dtl@type,\@dtl@head)% + \in{#2}\do + {% + \expandafter\DTLifinlist\expandafter{\@dtl@key}{\@dtl@omitlist}% + {}% + {% + \@dtl@doamp{\dtlheaderformat{\@dtl@head}}% + }% + }% + \@dtl@resetdoamp + \@dtl@resetdostartrow +% \end{macrocode} +%\changes{2.21}{2014-03-08}{moved misplaced \cs{dtldisplayafterhead}} +% \begin{macrocode} + \dtldisplaycr\dtldisplayafterhead + \endhead + \fi +% \end{macrocode} +% Iterate through each row of the database +% \begin{macrocode} + \@sDTLforeach{#2}{}{% + \@dtl@dostartrow + \@dtl@resetdoamp +% \end{macrocode} +% Iterate through each column +% \begin{macrocode} + \DTLforeachkeyinrow{\@dtl@val}% + {% + \global\let\@dtl@val\@dtl@val + \expandafter\DTLifinlist\expandafter{\dtlkey}{\@dtl@omitlist}% + {}% + {% + \@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} +% +% +%\section{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 or 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 existence 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} +% +%\section{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@db@name:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@db@name}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@db@name}{\@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@db@name:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@db@name}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@db@name}{\@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@db@name:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@db@name}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@db@name}{\@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@db@name:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@db@name}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@db@name}{\@dtl@key}% + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \dtlgetentryfromrow{\DTLthisval}{\@dtl@col}{\dtlcurrentrow}% + \expandafter\ifthenelse\expandafter{\@dtl@cond}% + {% +% \end{macrocode} +%\changes{2.15}{2013-07-10}{Replaced \cs{ifstrempty} with +%\cs{ifdefempty}} +% \begin{macrocode} + \ifdefempty{#4}% + {% + \let#4\DTLthisval + }% + {% + \DTLmin{#4}{#4}{\DTLthisval}% + }% + }{}% + }% + }% + }% +} +% \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}% + {% + \ifdefempty{#3}% + {% + \let#3\DTLthisval + }% + {% + \DTLmin{#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}{\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@db@name:=#2\do{% +% \end{macrocode} +% Iterate through this database (using read only version) +% \begin{macrocode} + \@sDTLforeach{\@dtl@db@name}% + {#1}% assignment list + {% +% \end{macrocode} +% Iterate through key list. +% \begin{macrocode} + \@for\@dtl@key:=#3\do{% + \@sdtl@getcolumnindex{\@dtl@col}{\@dtl@db@name}{\@dtl@key}% + \dtlcurrentrow=\expandafter{\dtl@thisrow}% + \dtlgetentryfromrow{\DTLthisval}{\@dtl@col}{\dtlcurrentrow}% + \expandafter\ifthenelse\expandafter{\@dtl@cond}% + {% + \ifdefempty{#4}% + {% + \let#4\DTLthisval + }% + {% + \DTLmax{#4}{#4}{\DTLthisval}% + }% + }{}% + }% + }% + }% +} +% \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}% + {% + \ifdefempty{#3}% + {% + \let#3\DTLthisval + }% + {% + \DTLmax{#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}{\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}{% + \expandafter\DTLconverttodecimal\expandafter{\DTLthisX}{\dtl@decx}% + \expandafter\DTLconverttodecimal\expandafter{\DTLthisY}{\dtl@decy}% + \ifx#5\relax + \let#5=\dtl@decx + \let#6=\dtl@decy + \let#7=\dtl@decx + \let#8=\dtl@decy + \else + \dtlmin{#5}{#5}{\dtl@decx}% + \dtlmin{#6}{#6}{\dtl@decy}% + \dtlmax{#7}{#7}{\dtl@decx}% + \dtlmax{#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} +% +%\section{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. +%\changes{2.23}{2015-07-11}{bug fix: replaced \cs{dtlicompare} with +%\cs{dtlcompare}} +% \begin{macrocode} +\newcommand{\@DTLsort}[3][]{% + \dtlsort[#1]{#2}{#3}{\dtlcompare}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@sDTLsort} +% Starred (case insensitive) version. +% \begin{macrocode} +\newcommand*{\@sDTLsort}[3][]{% + \dtlsort[#1]{#2}{#3}{\dtlicompare}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlsort} +%\changes{2.13}{2013-01-15}{new} +%\begin{definition} +%\cs{dtlsort}\oarg{replacement keys}\marg{sort criteria}\marg{db +%name}\marg{handler} +%\end{definition} +% More general version where user supplies a handler for the +% comparison. +% \begin{macrocode} +\newcommand{\dtlsort}[4][]{% +% \end{macrocode} +% Check the database exists +% \begin{macrocode} + \DTLifdbexists{#3}% + {% + \ifnum\DTLrowcount{#3}>100\relax + \typeout{Sorting `#3' - this may take a while.}% + \fi +% \end{macrocode} +% Store replacement keys in \cs{@dtl@replacementkeys}. +% \begin{macrocode} + \edef\@dtl@replacementkeys{#1}% +% \end{macrocode} +% Store sort order in \cs{@dtl@sortorder}, but check specified keys exist. +%\changes{2.18}{2013-09-06}{added check for existence of keys listed in sort +%criteria} +% \begin{macrocode} + \def\@dtl@sortorder{}% + \@for\@dtl@level:=#2\do + {% +% \end{macrocode} +% Get key (stored in \cs{@dtl@key}). +% \begin{macrocode} + \expandafter\@dtl@getsortdirection\@dtl@level=\relax +% \end{macrocode} +% Check key exists. +% \begin{macrocode} + \DTLifhaskey{#3}{\@dtl@key}% + {% +% \end{macrocode} +% Key exists, so add to \cs{@dtl@sortorder}. +% \begin{macrocode} + \ifdefempty\@dtl@sortorder + {\let\@dtl@sortorder=\@dtl@level}% + {\eappto\@dtl@sortorder{,\@dtl@level}}% + }% + {% +% \end{macrocode} +% Key doesn't exist. +% \begin{macrocode} + \PackageError{datatool}% + {% + Can't sort on `\@dtl@level'. + No such key `\@dtl@key' in database `#3'% + }{}% + }% + }% +% \end{macrocode} +% Now check if we have any keys left to sort on. +% \begin{macrocode} + \ifdefempty\@dtl@sortorder + {% + \PackageWarning{datatool}{No keys provided to sort database `#3'}% + }% + {% +% \end{macrocode} +% Set \cs{@dtl@comparecs} to the required string comparison +% function. (Using case insensitive comparison macro +% \cs{dtlicompare}.) +% \begin{macrocode} + \let\@dtl@comparecs=#4% +% \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\@dtl@dbname\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} + \ifdefempty{\@dtl@sortdirection}% + {% +% \end{macrocode} +% No direction specified so assume ascending. +% \begin{macrocode} + \def\@dtl@sortdirection{-1}% + }% + {% +% \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. +%\changes{2.13}{2013-01-15}{removed spurious space} +% \begin{macrocode} + \def\@dtl@sortdirection{-1}% + \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@compare} +%\begin{definition} +%\cs{dtl@compare}\marg{key}\marg{a toks}\marg{b toks} +%\end{definition} +% Compares two values according to \meta{key} of database given by +% \cs{@dtl@dbname}. Sets \cs{dtl@sortresult}. \cs{@dtl@comparecs} +% must be set to the required comparison macro. +%\changes{2.0}{2009 February 27}{no longer used} +% \begin{macrocode} +\newcommand{\dtl@compare}[3]{% + \dtl@compare@{#1}{#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@compare@} +%\begin{definition} +% \cs{dtl@compare@}\marg{keyA}\marg{keyB}\marg{A toks}\marg{B toks} +%\end{definition} +% Compare \meta{A} and \meta{B} according \meta{keyA} and +% \meta{keyB} for database given by \cs{@dtl@dbname}. Sets +% \cs{dtl@sortresult}. +% \cs{@dtl@comparecs} must be set before use. +%\changes{2.0}{2009 February 27}{updated to use new database +% structure} +% \begin{macrocode} +\newcommand{\dtl@compare@}[4]{% +% \end{macrocode} +% Get the data type for first key and store in \cs{@dtl@typeA}. +% \begin{macrocode} + \DTLgetdatatype{\@dtl@typeA}{\@dtl@dbname}{#1}% +% \end{macrocode} +% Is it unset? If so, assume string +% \begin{macrocode} + \ifx\@dtl@typeA\DTLunsettype + \let\@dtl@typeA\DTLstringtype + \fi +% \end{macrocode} +% Get the data type for the second key and store in \cs{@dtl@typeB} +% \begin{macrocode} + \DTLgetdatatype{\@dtl@typeB}{\@dtl@dbname}{#2}% +% \end{macrocode} +% Is it unset? If so, assume string +% \begin{macrocode} + \ifx\@dtl@typeB\DTLunsettype + \let\@dtl@typeB\DTLstringtype + \fi +% \end{macrocode} +% Multiply the two values together +% \begin{macrocode} + \@dtl@tmpcount=\@dtl@typeA\relax + \multiply\@dtl@tmpcount by \@dtl@typeB\relax +% \end{macrocode} +% If either type is 0 (a string) then the product will also be +% 0 (string) otherwise it will be one of the numerical types. +% \begin{macrocode} + \ifnum\@dtl@tmpcount=0\relax +% \end{macrocode} +% A string, so use comparison function +% \begin{macrocode} + \edef\@dtl@tmpcmp{% + \noexpand\@dtl@comparecs{\noexpand\dtl@sortresult}% + {\the#3}{\the#4}% + }% + \@dtl@tmpcmp + \ifdtlverbose + \edef\@dtl@a{\the#3}% + \edef\@dtl@b{\the#4}% + \fi + \else +% \end{macrocode} +% Store the first value +% \begin{macrocode} + \edef\@dtl@a{\the#3}% +% \end{macrocode} +% Store the second value +% \begin{macrocode} + \edef\@dtl@b{\the#4}% +% \end{macrocode} +% Compare +% \begin{macrocode} + \DTLifnumlt{\@dtl@a}{\@dtl@b}% + {% +% \end{macrocode} +% $A < B$ +% \begin{macrocode} + \dtl@sortresult=-1\relax + }% + {% + \DTLifnumgt{\@dtl@a}{\@dtl@b}% + {% +% \end{macrocode} +% $A > B$ +% \begin{macrocode} + \dtl@sortresult=1\relax + }% + {% +% \end{macrocode} +% $A = B$ +% \begin{macrocode} + \dtl@sortresult=0\relax + }% + }% + \fi +% \end{macrocode} +% Write comparison result to terminal/log if verbose mode. +% \begin{macrocode} + \ifdtlverbose + \@onelevel@sanitize\@dtl@a + \@onelevel@sanitize\@dtl@b + \dtl@message{`\@dtl@a' <=> `\@dtl@b' = \number\dtl@sortresult}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\section{Saving a database to an external file} +% +%\begin{macro}{\@dtl@write} +% \begin{macrocode} +\newwrite\@dtl@write +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLsavedb} +%\begin{definition} +% \cs{DTLsavedb}\marg{db name}\marg{filename} +%\end{definition} +% Save a database as an ASCII data file using the separator +% and delimiter given by \cs{@dtl@separator} and \cs{@dtl@delimiter}. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\DTLsavedb}[2]{% + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Open output file +%\changes{2.02}{2009 July 13}{Fixed bug that didn't set the filename} +% \begin{macrocode} + \openout\@dtl@write=#2\relax +% \end{macrocode} +% Initialise header row +% \begin{macrocode} + \def\@dtl@header{}% +% \end{macrocode} +% Construct the header row +% \begin{macrocode} + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)% + \in{#1}\do + {% + \IfSubStringInString{\@dtl@separator}{\@dtl@key}% + {% + \ifdefempty{\@dtl@header}% + {% + \protected@edef\@dtl@header{% + \@dtl@delimiter\@dtl@key\@dtl@delimiter}% + }% + {% + \toks@=\expandafter{\@dtl@header}% + \protected@edef\@dtl@header{% + \the\toks@\@dtl@separator + \@dtl@delimiter\@dtl@key\@dtl@delimiter}% + }% + }% + {% + \ifdefempty{\@dtl@header}% + {% + \protected@edef\@dtl@header{\@dtl@key}% + }% + {% + \toks@=\expandafter{\@dtl@header}% + \protected@edef\@dtl@header{\the\toks@ + \@dtl@separator\@dtl@key}% + }% + }% + }% +% \end{macrocode} +% Print header +% \begin{macrocode} + \protected@write\@dtl@write{}{\@dtl@header}% +% \end{macrocode} +% Iterate through each row +% \begin{macrocode} + \@sDTLforeach{#1}{}% + {% +% \end{macrocode} +% Initialise row +% \begin{macrocode} + \def\@dtl@row{}% +% \end{macrocode} +% Iterate through each key +% \begin{macrocode} + \DTLforeachkeyinrow{\@dtl@val}% + {% + \IfSubStringInString{\@dtl@separator}{\@dtl@val}% + {% + \ifdefempty{\@dtl@row}% + {% + \protected@edef\@dtl@row{% + \@dtl@delimiter\@dtl@val\@dtl@delimiter}% + }% + {% + \toks@=\expandafter{\@dtl@row}% + \protected@edef\@dtl@row{\the\toks@\@dtl@separator + \@dtl@delimiter\@dtl@val\@dtl@delimiter}% + }% + }% + {% + \ifdefempty{\@dtl@row}% + {% + \protected@edef\@dtl@row{\@dtl@val}% + }% + {% + \toks@=\expandafter{\@dtl@row}% + \protected@edef\@dtl@row{\the\toks@\@dtl@separator + \@dtl@val}% + }% + }% + }% +% \end{macrocode} +% Print row\changes{2.03}{2009 November 15}{Moved outside loop} +% \begin{macrocode} + \protected@write\@dtl@write{}{\@dtl@row}% + }% +% \end{macrocode} +% Close output file +% \begin{macrocode} + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsavetexdb} +%\begin{definition} +% \cs{DTLsavetexdb}\marg{db name}\marg{filename} +%\end{definition} +% Save a database as a \LaTeX\ file. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\DTLsavetexdb}[2]{% + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Open output file +% \begin{macrocode} + \openout\@dtl@write=#2\relax +% \end{macrocode} +% Write new data base definition +% \begin{macrocode} + \protected@write\@dtl@write{}{\string\DTLnewdb{#1}}% +% \end{macrocode} +% Iterate through each row +% \begin{macrocode} + \@sDTLforeach{#1}{}% + {% +% \end{macrocode} +% Start new row +% \begin{macrocode} + \protected@write\@dtl@write{}{\string\DTLnewrow*{#1}}% +% \end{macrocode} +% Iterate through each column +% \begin{macrocode} + \DTLforeachkeyinrow{\@dtl@val}% + {% +% \end{macrocode} +% Is this entry null? +% \begin{macrocode} + \DTLifnull{\@dtl@val}% + {\def\@dtl@val{}}% + {}% +% \end{macrocode} +% Add entry +% \begin{macrocode} + \protected@write\@dtl@write{}{% + \string\DTLnewdbentry*{#1}{\dtlkey}{\@dtl@val}}% + }% + }% +% \end{macrocode} +% Save the column headers. +% \begin{macrocode} + \dtlforeachkey(\@dtl@k,\@dtl@c,\@dtl@t,\@dtl@h)\in{#1}\do + {% + \@onelevel@sanitize\@dtl@h + \protected@write\@dtl@write{}{% + \string\DTLsetheader*{#1}{\@dtl@k}{\@dtl@h}}% + }% +% \end{macrocode} +% Store name of database in case required after database loaded: +%\changes{2.15}{2013-07-10}{added \cs{dtllastloadeddb}} +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\def\string\dtllastloadeddb{#1}}% +% \end{macrocode} +% Close output file +% \begin{macrocode} + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@saverawdbhook} +% Hook used by \cs{DTLsaverawdb}. +% \begin{macrocode} +\newcommand*{\dtl@saverawdbhook}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsaverawdb} +% Saves given database in its internal form. Not easy for a human to +% read, but much faster to load. +%\changes{2.13}{2013-01-15}{new} +% \begin{macrocode} +\newcommand*{\DTLsaverawdb}[2]{% + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Open output file +% \begin{macrocode} + \openout\@dtl@write=#2\relax +% \end{macrocode} +% Add code at the start of the output file to check for the +% existence of the database: +% \begin{macrocode} + \protected@write{\@dtl@write}{}{% + \string\DTLifdbexists{#1}\expandafter\@gobble\string\%^^J% + {% + \string\PackageError{datatool}{Database `#1' ^^Jalready exists}{}% + \expandafter\@gobble\string\%^^J% + \string\aftergroup\string\endinput + }% + {% + }\expandafter\@gobble\string\% + }% +% \end{macrocode} +% Scope need to localise definitions: +% \begin{macrocode} + {% +% \end{macrocode} +% \begin{macrocode} + \def\db@row@elt@w{\expandafter\@gobble\string\%^^J\string\db@row@elt@w\space}% + \def\db@row@elt@end@{\expandafter\@gobble\string\%^^J\string\db@row@elt@end@\space}% + \def\db@row@id@w{\expandafter\@gobble\string\%^^J\string\db@row@id@w\space}% + \def\db@row@id@end@{\expandafter\@gobble\string\%^^J\string\db@row@id@end@\space}% + \def\db@col@elt@w{\expandafter\@gobble\string\%^^J\string\db@col@elt@w\space}% + \def\db@col@elt@end@{\expandafter\@gobble\string\%^^J\string\db@col@elt@end@\space}% + \def\db@col@id@w{\expandafter\@gobble\string\%^^J\string\db@col@id@w\space}% + \def\db@col@id@end@{\expandafter\@gobble\string\%^^J\string\db@col@id@end@\space}% +% + \def\db@plist@elt@w{\expandafter\@gobble\string\%^^J\string\db@plist@elt@w\space}% + \def\db@plist@elt@end@{\expandafter\@gobble\string\%^^J\string\db@plist@elt@end@\space}% + \def\db@key@id@w{\expandafter\@gobble\string\%^^J\string\db@key@id@w\space}% + \def\db@key@id@end@{\expandafter\@gobble\string\%^^J\string\db@key@id@end@\space}% + \def\db@type@id@w{\expandafter\@gobble\string\%^^J\string\db@type@id@w\space}% + \def\db@type@id@end@{\expandafter\@gobble\string\%^^J\string\db@type@id@end@\space}% + \def\db@header@id@w{\expandafter\@gobble\string\%^^J\string\db@header@id@w\space}% + \def\db@header@id@end@{\expandafter\@gobble\string\%^^J\string\db@header@id@end@\space}% +% \end{macrocode} +% Need to ensure the @ character can be used so \ics{makeatletter} +% is required, but localise the effect. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\bgroup\string\makeatletter}% +% \end{macrocode} +% If in verbose mode, add a message to let the user know what's +% happening when the file is later loaded. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{% + \string\dtl@message{Reconstructing database^^J`#1'}% + \expandafter\@gobble\string\%}% +% \end{macrocode} +% Save the contents of the token register that holds the column +% information (column id, header, type). (The write is delayed, +% so the contents are first expanded and stored in a temporary +% (global) macro to ensure its in the correct format when the write happens.) +% \begin{macrocode} + \protected@write{\@dtl@write}{}{% + \string\expandafter + \string\global\string\expandafter^^J\string\newtoks + \string\csname\space dtlkeys@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{% + \string\expandafter + \string\global^^J + \string\csname\space dtlkeys@#1\string\endcsname + =\expandafter\@gobble\string\{\expandafter\@gobble\string\%}% + \expandafter\protected@xdef\csname dtl@rawwritedbkeys@#1\endcsname{% + \the\csname dtlkeys@#1\endcsname}% + \protected@write{\@dtl@write}{}{\csname dtl@rawwritedbkeys@#1\endcsname}% + \protected@write{\@dtl@write}{}% + {\expandafter\@gobble\string\}\expandafter\@gobble\string\%}% +% \end{macrocode} +% Hook used by \sty{datagidx}: +% \begin{macrocode} + \dtl@saverawdbhook +% \end{macrocode} +% Save the contents of the token register that holds the database +% body. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{% + \string\expandafter\string\global + \string\expandafter^^J\string\newtoks + \string\csname\space dtldb@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{% + \string\expandafter + \string\global^^J\string\csname\space dtldb@#1\string\endcsname + =\expandafter\@gobble\string\{\expandafter\@gobble\string\%}% + \expandafter\protected@xdef\csname dtl@rawwritedb@#1\endcsname{\the\csname dtldb@#1\endcsname}% + \protected@write{\@dtl@write}{}{\csname dtl@rawwritedb@#1\endcsname}% + \protected@write{\@dtl@write}{}{\expandafter\@gobble\string\}\expandafter\@gobble\string\%}% +% \end{macrocode} +% Now for the count register that keeps track of the row count. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\expandafter\string\newcount + \string\csname\space dtlrows@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\csname\space dtlrows@#1\string\endcsname + =\expandafter\number\csname dtlrows@#1\endcsname\string\relax}% +% \end{macrocode} +% Similarly for the column count. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\expandafter\string\newcount + \string\csname\space dtlcols@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\csname\space dtlcols@#1\string\endcsname + =\expandafter\number\csname dtlcols@#1\endcsname\string\relax}% +% \end{macrocode} +% Add key mappings +% \begin{macrocode} + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do + {% + \edef\dtl@tmp{% + \string\expandafter^^J + \string\gdef + \string\csname\space dtl@ci@#1@\@dtl@key\string\endcsname + {\csname dtl@ci@#1@\@dtl@key\endcsname}\expandafter\@gobble\string\% + }% + \expandafter\write\expandafter\@dtl@write\expandafter{\dtl@tmp}% + }% +% \end{macrocode} +% End the scope for \ics{makeatletter:} +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\egroup}% +% \end{macrocode} +% End current scope: +% \begin{macrocode} + }% +% \end{macrocode} +% Store name of database in case required after database loaded: +%\changes{2.15}{2013-07-10}{added \cs{dtllastloadeddb}} +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\def\string\dtllastloadeddb{#1}}% +% \end{macrocode} +% Close output file +% \begin{macrocode} + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLprotectedsaverawdb} +% Like \cs{DTLsaverawdb} but works with fragile contents. If there's a +% problem with unwanted line breaks every 80 characters, try loading +% \sty{morewrites} before \sty{datatool}. +%\changes{2.15}{2013-07-10}{new} +% \begin{macrocode} +\newcommand*{\DTLprotectedsaverawdb}[2]{% + \DTLifdbexists{#1}% + {% +% \end{macrocode} +% Open output file +% \begin{macrocode} + \openout\@dtl@write=#2\relax +% \end{macrocode} +% Add code at the start of the output file to check for the +% existence of the database: +% \begin{macrocode} + \protected@write{\@dtl@write}{}{% + \string\DTLifdbexists{#1}\expandafter\@gobble\string\%^^J% + {% + \string\PackageError{datatool}{Database `#1' ^^Jalready exists}{}% + \expandafter\@gobble\string\%^^J% + \string\aftergroup\string\endinput + }% + {% + }\expandafter\@gobble\string\% + }% +% \end{macrocode} +% Scope needed to localise definitions: +% \begin{macrocode} + {% +% \end{macrocode} +% Need to ensure the @ character can be used so \ics{makeatletter} +% is required, but localise the effect. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\bgroup\string\makeatletter}% +% \end{macrocode} +% If in verbose mode, add a message to let the user know what's +% happening when the file is later loaded. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\dtl@message{Reconstructing database + ^^J`#1'}\expandafter\@gobble\string\%}% +% \end{macrocode} +% Start writing the header token definition. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{% + \string\expandafter + \string\global\string\expandafter^^J\string\newtoks + \string\csname\space dtlkeys@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{% + \string\expandafter + \string\global^^J + \string\csname\space dtlkeys@#1\string\endcsname + =\expandafter\@gobble\string\{\expandafter\@gobble\string\%}% +% Store the contents of the token register that holds the column +% information (column id, header, type) and sanitize. +% \begin{macrocode} + \edef\dtl@rawwrite@keys{\the\csname dtlkeys@#1\endcsname}% + \@onelevel@sanitize\dtl@rawwrite@keys +% \end{macrocode} +% The write can get delayed, so expand after to ensure it has the +% actual contents of the database rather than +% \cs{dtl@rawwrite@keys}, which may have changed by the time the +% write occurs. Include the closing brace of the token contents. +% \begin{macrocode} + \expandafter\write\expandafter\@dtl@write\expandafter + {\dtl@rawwrite@keys\expandafter\@gobble\string\}}% +% \end{macrocode} +% Similarly for the token register that holds the database +% body. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{% + \string\expandafter\string\global + \string\expandafter^^J\string\newtoks + \string\csname\space dtldb@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{% + \string\expandafter + \string\global^^J\string\csname\space dtldb@#1\string\endcsname + =\expandafter\@gobble\string\{\expandafter\@gobble\string\%}% +% \end{macrocode} +% \begin{macrocode} + \edef\dtl@rawwrite@db{\the\csname dtldb@#1\endcsname}% + \@onelevel@sanitize\dtl@rawwrite@db +% \end{macrocode} +% Now write the sanitize contents. +% \begin{macrocode} + \expandafter\write\expandafter\@dtl@write\expandafter + {\dtl@rawwrite@db\expandafter\@gobble\string\}}% +% \end{macrocode} +% Now for the count register that keeps track of the row count. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\expandafter\string\newcount + \string\csname\space dtlrows@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\csname\space dtlrows@#1\string\endcsname + =\expandafter\number\csname dtlrows@#1\endcsname\string\relax}% +% \end{macrocode} +% Similarly for the column count. +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\expandafter\string\newcount + \string\csname\space dtlcols@#1\string\endcsname}% + \protected@write{\@dtl@write}{}{\string\expandafter\string\global^^J + \string\csname\space dtlcols@#1\string\endcsname + =\expandafter\number\csname dtlcols@#1\endcsname\string\relax}% +% \end{macrocode} +% Add key mappings +% \begin{macrocode} + \dtlforeachkey(\@dtl@key,\@dtl@col,\@dtl@type,\@dtl@head)\in{#1}\do + {% + \edef\dtl@tmp{% + \string\expandafter^^J + \string\gdef + \string\csname\space dtl@ci@#1@\@dtl@key\string\endcsname + {\csname dtl@ci@#1@\@dtl@key\endcsname}\expandafter\@gobble\string\% + }% + \expandafter\write\expandafter\@dtl@write\expandafter{\dtl@tmp}% + }% +% \end{macrocode} +% End the scope for \ics{makeatletter}: +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\egroup}% +% \end{macrocode} +% End current scope: +% \begin{macrocode} + }% +% \end{macrocode} +% Provide a means to keep track of the last loaded file: +% \begin{macrocode} + \protected@write{\@dtl@write}{}{\string\def\string\dtllastloadeddb{#1}}% +% \end{macrocode} +% Close output file +% \begin{macrocode} + \closeout\@dtl@write + }% + {% + \PackageError{datatool}{Can't save database `#1': no such + database}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\section{Loading a database from an external file} +% +%\begin{macro}{\DTLloaddbtex} +%\begin{definition} +%\cs{DTLloaddbtex}\marg{cs}\marg{file} +%\end{definition} +% Load a \texttt{.dbtex} file and assign the database name to the +% control sequence \meta{cs}. Checks the file name exists and the +% control sequence doesn't exist. +%\changes{2.20}{2014-02-03}{new} +% \begin{macrocode} +\newcommand*{\DTLloaddbtex}[2]{% + \IfFileExists{#2}% + {% + \input{#2}% + \ifdef#1% + {% + \PackageError{datatool}{Command \string#1\space is already defined}% + {}% + }% + {% + \let#1\dtllastloadeddb + }% + }% + {% + \PackageError{datatool}{File `#2' doesn't exist.}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@read} +% \begin{macrocode} +\newread\@dtl@read +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@entrycr} +% Keep track of current column in data file +% \begin{macrocode} +\newcount\dtl@entrycr +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifdtlnoheader} +% The "noheader" option indicates that the file doesn't have a +% header row. +% \begin{macrocode} +\define@boolkey{loaddb}[dtl]{noheader}[true]{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifdtlautokeys} +%\changes{2.22}{2014-06-10}{new} +%Assign the default keys even if a header row is supplied. +% \begin{macrocode} +\define@boolkey{loaddb}[dtl]{autokeys}[true]{} +\dtlautokeysfalse +% \end{macrocode} +%\end{macro} +% The "keys" option specifies the list of keys in the same order +% as the columns in the data file. +% Each key is stored in \cs{@dtl@inky@}\meta{n} where \meta{n} is the +% roman numeral representation of the current column. +% \begin{macrocode} +\define@key{loaddb}{keys}{% + \dtl@entrycr=0\relax + \@for\@dtl@key:=#1\do + {% + \advance\dtl@entrycr by 1\relax + \expandafter + \edef\csname @dtl@inky@\romannumeral\dtl@entrycr\endcsname{% + \@dtl@key}% + }% +} +% \end{macrocode} +% The "headers" option specifies the list of headers in the +% same order as the columns in the data file. +% \begin{macrocode} +\define@key{loaddb}{headers}{% + \dtl@entrycr=0\relax + \@for\@dtl@head:=#1\do + {% + \advance\dtl@entrycr by 1\relax + \toks@=\expandafter{\@dtl@head}% + \expandafter + \edef\csname @dtl@inhd@\romannumeral\dtl@entrycr\endcsname{% + \the\toks@}% + }% +} +% \end{macrocode} +% +% The following is supplied in a patch by Bruno Le Floch: +%\changes{2.10}{2012-07-18}{added omitlines key} +% \begin{macrocode} +\newcount{\dtl@omitlines} +\define@key{loaddb}{omitlines}{\dtl@omitlines=#1\relax} +% \end{macrocode} +% +%\begin{macro}{\dtldefaultkey} +% Default key to use if none specified (column index will be +% appended). +% \begin{macrocode} +\newcommand*{\dtldefaultkey}{Column} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@readline} +%\begin{definition} +%\cs{@dtl@readline}\marg{file reg}\marg{cs} +%\end{definition} +% Reads line from \meta{file reg}, trims end of line character +% and stores in \meta{cs}. +% \begin{macrocode} +\newcommand*{\@dtl@readline}[2]{% +% \end{macrocode} +% Read a line from "#1" and store in "#2" but make sure end of line +% character is removed. +%\changes{2.29}{2017-11-12}{changed line read} +% \begin{macrocode} + \begingroup + \catcode\endlinechar=\active% + \global\read#1 to #2% + \endgroup% +% \end{macrocode} +%If empty the row starts with a comment +% \begin{macrocode} + \ifx#2\empty% + \else% + \expandafter\@dtl@stripeol#2% + \let#2\@dtl@strippedline% + \fi% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@stripeol} +%\changes{2.29}{2017-11-12}{new} +% \begin{macrocode} +\begingroup +\catcode\endlinechar=\active% +\gdef\@dtl@stripeol#1 +{\gdef\@dtl@strippedline{#1}} +\endgroup +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@readrawline} +%\begin{definition} +%\cs{@dtl@readrawline}\marg{file register}\marg{cs} +%\end{definition} +% Reads line from \meta{file register}, trims end of line character, +% applies mappings and stores in \meta{cs}. +% \begin{macrocode} +\newcommand*{\@dtl@readrawline}[2]{% +% \end{macrocode} +% Read a line from "#1" and store in "#2" +% \begin{macrocode} + \@dtl@rawread#1 to #2% +% \end{macrocode} +% Apply mappings +% \begin{macrocode} + \dtl@domappings\@dtl@line +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifDTLnewdbonload} +% Governs whether or not the database should be defined by +% \ics{DTLloaddb} and \ics{DTLloadrawdb}. +%\changes{2.13}{2013-01-15}{new} +% \begin{macrocode} +\newif\ifDTLnewdbonload +% \end{macrocode} +% Ensure compatibility with previous versions: +% \begin{macrocode} +\DTLnewdbonloadtrue +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLloaddb} +%\begin{definition} +% \cs{DTLloaddb}\oarg{options}\marg{db name}\marg{filename} +%\end{definition} +% Creates a new database called \meta{db name}, and loads the data +% in \meta{filename} into it. The separator and delimiter used in +% the file must match \cs{@dtl@separator} and \cs{@dtl@delimiter}. +% The optional argument is a comma-separated list. +%\changes{2.0}{2009 February 27}{removed checks to see if the +% database exists when adding to it} +%\changes{2.0}{2009 February 27}{added optional argument} +% \begin{macrocode} +\newcommand*{\DTLloaddb}{% + \let\@dtl@doreadline\@dtl@readline + \@dtlloaddb +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtlloaddb} +% Loads database using \cs{@dtl@doreadline} to read and trim +% line from file. (\cs{@dtl@doreadline} must be set before use.) +% \begin{macrocode} +\newcommand*{\@dtlloaddb}[3][]{% +% \end{macrocode} +% Check if file exists +% \begin{macrocode} + \IfFileExists{#3}{% +% \end{macrocode} +% File exists. Locally change catcode of double quote character in +% case it has been made active. +% \begin{macrocode} + \begingroup + \catcode`\"12\relax +% \end{macrocode} +% Initialise default options +% \begin{macrocode} + \dtlnoheaderfalse +% \end{macrocode} +% Get the options +% \begin{macrocode} + \setkeys{loaddb}{#1}% +% \end{macrocode} +% Open the file for reading. +% \begin{macrocode} + \openin\@dtl@read=#3% + \dtl@message{Reading `#3'}% +% \end{macrocode} +% The following supplied in patch by Bruno Le~Floch: +%\changes{2.10}{2012-07-18}{added code to skip lines} +% \begin{macrocode} + \loop + \ifnum \dtl@omitlines > \z@ + \advance\dtl@omitlines by \m@ne + \read\@dtl@read to \@dtl@line + \repeat +% \end{macrocode} +% Create the database if required. +% \begin{macrocode} + \ifDTLnewdbonload + \DTLnewdb{#2}% + \fi +% \end{macrocode} +% Check if the file is empty. +% \begin{macrocode} + \ifeof\@dtl@read +% \end{macrocode} +% File is empty, so just issue a warning. +% \begin{macrocode} + \PackageWarning{datatool}{File `#3' has no data}% + \else +% \end{macrocode} +% Does the file have a header row? +% \begin{macrocode} + \ifdtlnoheader + \else +% \end{macrocode} +% Remove initial blank rows +% \begin{macrocode} + \loop +% \end{macrocode} +% Set repeat condition to false +% \begin{macrocode} + \@dtl@conditionfalse +% \end{macrocode} +% Do nothing if reached the end of file +% \begin{macrocode} + \ifeof\@dtl@read + \else +% \end{macrocode} +% Read a line from the file and store in \cs{@dtl@line} +% \begin{macrocode} + \@dtl@doreadline\@dtl@read\@dtl@line +% \end{macrocode} +% If this is a blank row, set repeat condition to true +% \begin{macrocode} + \ifdefempty{\@dtl@line}% + {% + \@dtl@conditiontrue + }% + {% + }% + \fi +% \end{macrocode} +% Repeat loop if necessary +% \begin{macrocode} + \if@dtl@condition + \repeat +% \end{macrocode} +% Parse the header row. Store the row as +% \meta{sep}\meta{row}\meta{sep} in \cs{@dtl@lin@}. +% \begin{macrocode} + \protected@edef\@dtl@lin@{% + \@dtl@separator\@dtl@line\@dtl@separator}% +% \end{macrocode} +% Keep track of columns: +% \begin{macrocode} + \dtl@entrycr=0\relax +% \end{macrocode} +% Keep lopping off elements until the end of the row is reached. +% (That is, until \cs{@dtl@lin@} is \cs{@dtl@separator}.) +%\changes{2.0}{2009 February 27}{changed \cs{whiledo} to +% \cs{loop} to improve efficiency}% +% \begin{macrocode} + \loop +% \end{macrocode} +% Lopoff the first element and store in \cs{@dtl@key} +% \begin{macrocode} + \expandafter\@dtl@lopoff\@dtl@lin@\to\@dtl@lin@\@dtl@key +% \end{macrocode} +% Increment column count. +% \begin{macrocode} + \advance\dtl@entrycr by 1\relax +% \end{macrocode} +% If autokeys option is on, add generic key +%\changes{2.22}{2014-06-10}{added check for autokeys} +% \begin{macrocode} + \ifdtlautokeys + \csedef{@dtl@inky@\romannumeral\dtl@entrycr}% + {\dtldefaultkey\number\dtl@entrycr}% + \else +% \end{macrocode} +% If missing a key, add generic one: +%\changes{2.10}{2012-07-18}{add generic header if missing} +% \begin{macrocode} + \ifdefempty{\@dtl@key}% + {% + \edef\@dtl@key{\dtldefaultkey\number\dtl@entrycr}% + }% + {}% + \fi +% \end{macrocode} +% Store key in \cs{@dtl@toks} +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{\@dtl@key}% +% \end{macrocode} +% Store the key in \cs{@dtl@inky@}\meta{n} where \meta{n} is the +% roman numeral representation of the current column, unless +% already defined. +% \begin{macrocode} + \@ifundefined{@dtl@inky@\romannumeral\dtl@entrycr}% + {% + \expandafter + \edef\csname @dtl@inky@\romannumeral + \dtl@entrycr\endcsname{\the\@dtl@toks}% + }% + {% +% \end{macrocode} +% If key has been specified in "#1", then use the header found in the +% file, unless a header has also been specified in "#1" +% \begin{macrocode} + \@ifundefined{@dtl@inhd@\romannumeral\dtl@entrycr}% + {% + \expandafter + \edef\csname @dtl@inhd@\romannumeral + \dtl@entrycr\endcsname{\the\@dtl@toks}% + }% + {}% + }% +% \end{macrocode} +% Check if the loop should be repeated +% \begin{macrocode} + \ifx\@dtl@lin@\@dtl@separator + \@dtl@conditionfalse + \else + \@dtl@conditiontrue + \fi +% \end{macrocode} +% Repeat loop if necessary. +% \begin{macrocode} + \if@dtl@condition + \repeat +% \end{macrocode} +% End if no header +% \begin{macrocode} + \fi +% \end{macrocode} +% Now for the rest of the data. If the end of file has been +% reached, then only the header row is available or file is empty. +% \begin{macrocode} + \ifeof\@dtl@read + \ifdtlnoheader + \PackageWarning{datatool}{No data in `#3'}% + \else + \PackageWarning{datatool}{Only header row found in `#3'}% + \fi + \else +% \end{macrocode} +% Iterate through the rest of the file. First set the repeat +% condition to true: +% \begin{macrocode} + \@dtl@conditiontrue + \loop +% \end{macrocode} +% Read in a line +% \begin{macrocode} + \@dtl@doreadline\@dtl@read\@dtl@line +% \end{macrocode} +% Check if the line is empty. +%\changes{2.0}{2009 February 27}{changed \cs{ifthenelse} to +%\cs{ifx} to improve efficiency} +%\changes{2.10}{2012-07-18}{changed \cs{ifx} to \cs{ifdefempty}} +% \begin{macrocode} + \ifdefempty{\@dtl@line}% + {% +% \end{macrocode} +% Do nothing if the row is empty. +% \begin{macrocode} + }% + {% +% \end{macrocode} +% Add a new row to the database. (Don't need to check if the +% database exists, since it's just been created.) +% \begin{macrocode} + \@sDTLnewrow{#2}% +% \end{macrocode} +% Store the row as \meta{sep}\meta{row}\meta{sep} to make the +% lopping off easier +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{\@dtl@line}% + \edef\@dtl@lin@{\@dtl@separator\the\@dtl@toks + \@dtl@separator}% +% \end{macrocode} +% Reset the column counter. +% \begin{macrocode} + \dtl@entrycr=0\relax +% \end{macrocode} +%\changes{2.0}{2009 February 27}{changed \cs{whiledo} to \cs{loop} +% to improve efficiency} +% Iterate through each element in the row. Needs to be grouped +% since we're already inside a loop. +% \begin{macrocode} + {% +% \end{macrocode} +% Initialise repeat condition +% \begin{macrocode} + \@dtl@conditiontrue +% \end{macrocode} +% Iterate through the list +% \begin{macrocode} + \loop +% \end{macrocode} +% lop off first element and store in \cs{@dtl@thisentry} +% \begin{macrocode} + \expandafter\@dtl@lopoff\@dtl@lin@\to + \@dtl@lin@\@dtl@thisentry +% \end{macrocode} +% Increment the column count. +% \begin{macrocode} + \advance\dtl@entrycr by 1\relax +% \end{macrocode} +% Get the key for this column and store in \cs{@dtl@thiskey}. +% Use default value if not defined. +% \begin{macrocode} + \@ifundefined{@dtl@inky@\romannumeral\dtl@entrycr}% + {% + \edef\@dtl@thiskey{\dtldefaultkey + \number\dtl@entrycr}% + \expandafter\let + \csname @dtl@inky@\romannumeral + \dtl@entrycr\endcsname\@dtl@thiskey + }% + {% + \edef\@dtl@thiskey{% + \csname @dtl@inky@\romannumeral + \dtl@entrycr\endcsname}% + }% +% \end{macrocode} +% Store this entry in \cs{@dtl@toks} +% \begin{macrocode} + \expandafter\@dtl@toks\expandafter{\@dtl@thisentry}% +% \end{macrocode} +% Add this entry to the database +% \begin{macrocode} + \edef\@do@dtlnewentry{\noexpand\@sDTLnewdbentry + {#2}{\@dtl@thiskey}{\the\@dtl@toks}}% + \@do@dtlnewentry +% \end{macrocode} +% Check if loop should be terminated +% \begin{macrocode} + \ifx\@dtl@lin@\@dtl@separator + \@dtl@conditionfalse + \fi +% \end{macrocode} +% Repeat loop if necessary +% \begin{macrocode} + \if@dtl@condition + \repeat + }% +% \end{macrocode} +% End of parsing this row +% \begin{macrocode} + }% +% \end{macrocode} +% If the end of file has been reached, set the repeat condition +% to false. +% \begin{macrocode} + \ifeof\@dtl@read \@dtl@conditionfalse\fi +% \end{macrocode} +% Repeat if necessary +% \begin{macrocode} + \if@dtl@condition + \repeat + \fi +% \end{macrocode} +% End of first \cs{ifeof} +% \begin{macrocode} + \fi +% \end{macrocode} +% Close the input file +% \begin{macrocode} + \closein\@dtl@read +% \end{macrocode} +% Set the headers if required +% \begin{macrocode} + \edef\@dtl@maxcols{\expandafter + \number\csname dtlcols@#2\endcsname}% + \dtlgforint\dtl@entrycr=1\to\@dtl@maxcols\step1\do + {% + \@ifundefined{@dtl@inhd@\romannumeral\dtl@entrycr}% + {}% + {% + \expandafter\let\expandafter\@dtl@head + \csname @dtl@inhd@\romannumeral\dtl@entrycr\endcsname + \@dtl@toks=\expandafter{\@dtl@head}% + \edef\@dtl@dosetheader{\noexpand\@dtl@setheaderforindex + {#2}{\number\dtl@entrycr}{\the\@dtl@toks}}% + \@dtl@dosetheader + }% + }% +% \end{macrocode} +% End current scope +% \begin{macrocode} + \endgroup +% \end{macrocode} +% End true part of if file exists +% \begin{macrocode} + }{% +% \end{macrocode} +% Requested file not found on TeX's path +% \begin{macrocode} + \PackageError{datatool}{Can't load database `#2' (file `#3' + doesn't exist)}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLloadrawdb} +%\begin{definition} +%\cs{DTLloadrawdb}\marg{db name}\marg{filename} +%\end{definition} +% Loads a raw database (substitutes "%" $\to$ "\%", +% "$" $\to$ "\$", "&" $\to$ "\&", "#" $\to$ "\#", +% "~" $\to$ "\textasciitilde", "_" $\to$ "\_" +% and "^" $\to$ "\textasciicircum".) The user can add additional +% mappings. +% \begin{macrocode} +\newcommand*\DTLloadrawdb{% + \let\@dtl@doreadline\@dtl@readrawline + \@dtlloaddb +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@rawread} +%\begin{definition} +% \cs{@dtl@rawread}\meta{number}to\meta{cmd} +%\end{definition} +% Reads in a raw line from file given by \meta{number} +% converts special characters and stores in \meta{cmd} +% \begin{macrocode} +\begingroup +\catcode`\%=\active +\catcode`$=\active +\catcode`&=\active +\catcode`~=\active +\catcode`_=\active +\catcode`^=\active +\catcode`#=\active +\catcode`?=6\relax +\catcode`<=1\relax +\catcode`>=2\relax +\catcode`\{=\active +\catcode`\}=\active +\gdef\@dtl@rawread?1to?2<\relax +<<\catcode`\%=\active +\catcode`$=\active +\catcode`&=\active +\catcode`~=\active +\catcode`_=\active +\catcode`^=\active +\catcode`#=\active +\catcode`\{=\active +\catcode`\}=\active +\def%<\noexpand\%>\relax +\def$<\noexpand\$>\relax +\def&<\&>\relax +\def#<\#>\relax +\def~<\noexpand\textasciitilde>\relax +\def_<\noexpand\_>\relax +\def^<\noexpand\textasciicircum>\relax +\@dtl@activatebraces +\@dtl@doreadraw?1?2>>> +\gdef\@dtl@doreadraw?1?2<\relax +\begingroup\catcode\endlinechar=\active\global\read?1 to \dtl@tmp\endgroup +\expandafter\@dtl@stripeol\dtl@tmp +\let\dtl@tmp\@dtl@strippedline +\protected@xdef?2<\dtl@tmp>\relax +> +\endgroup +% \end{macrocode} +%\changes{2.28}{2017-11-10}{changed \cs{xdef} to \cs{protected@xdef}}. +%\end{macro} +%\begin{macro}{\@dtl@activatebraces} +% \cs{@dtl@activatebraces} resets braces for \cs{@dtl@rawread} +% \begin{macrocode} +\begingroup +\catcode`\{=\active +\catcode`\}=\active +\catcode`<=1\relax +\catcode`>=2\relax +\gdef\@dtl@activatebraces<% + \catcode`\{=\active + \catcode`\}=\active + \def{<\noexpand\{>% + \def}<\noexpand\}>% +>% +\endgroup +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLrawmap} +%\begin{definition} +%\cs{DTLrawmap}\marg{string}\marg{replacement} +%\end{definition} +% Additional mappings to perform when reading a raw data file +% \begin{macrocode} +\newcommand*{\DTLrawmap}[2]{% + \expandafter\@dtl@toks\expandafter{\@dtl@rawmappings}% + \ifdefempty{\@dtl@rawmappings}% + {% + \def\@dtl@rawmappings{{#1}{#2}}% + }% + {% +% \end{macrocode} +%\changes{2.13}{2013-01-15}{removed spurious space} +% \begin{macrocode} + \def\@dtl@tmp{{#1}{#2}}% + \protected@edef\@dtl@rawmappings{\the\@dtl@toks,\@dtl@tmp}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@rawmappings} +% List of mappings. +% \begin{macrocode} +\newcommand*{\@dtl@rawmappings}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@domappings} +%\begin{definition} +% \cs{dtl@domappings}\marg{cmd} +%\end{definition} +% Do all mappings in string given by \meta{cmd}. +%\changes{2.10}{2012-07-18}{replaced \cs{DTLsubstitute} with +%\cs{DTLsubstituteall}} +% \begin{macrocode} +\newcommand*{\dtl@domappings}[1]{% + \@for\@dtl@map:=\@dtl@rawmappings\do{% + \expandafter\DTLsubstituteall\expandafter#1\@dtl@map + }% +} +% \end{macrocode} +%\end{macro} +% +%\section{Debugging commands} +% These commands are provided to assist debugging +%\begin{macro}{\dtlshowdb} +%\begin{definition} +%\cs{dtlshowdb}\marg{db name} +%\end{definition} +% Shows the database. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\dtlshowdb}[1]{% + \expandafter\showthe\csname dtldb@#1\endcsname +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlshowdbkeys} +%\begin{definition} +%\cs{dtlshowdbkeys}\marg{db name} +%\end{definition} +% Shows the key list for the named database. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\dtlshowdbkeys}[1]{% + \expandafter\showthe\csname dtlkeys@#1\endcsname +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlshowtype} +%\begin{definition} +%\cs{dtlshowtype}\marg{db name}\marg{key} +%\end{definition} +% Show the data type for given key in the named database. +% This should be an integer from 0 to 3. +%\changes{2.0}{2009 February 27}{updated to use new database structure} +% \begin{macrocode} +\newcommand*{\dtlshowtype}[2]{% + \DTLgetdatatype{\@dtl@type}{#1}{#2}\show\@dtl@type +} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</datatool.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*datagidx.sty> +% \end{macrocode} +%\fi +%\chapter{datagidx.sty} +%\changes{2.13}{2013-01-15}{added datagidx package} +% This package provides a means to produces indices and glossaries +% without the need for an external indexing application, such as +% \app{makeindex} or \app{xindy}. However, the code here has +% been developed to implement the word order style described by the +% Oxford Style Manual. If you are not writing in English, this may +% not be applicable to your needs. You may be able to define your +% own comparison handler to use with \cs{dtlsort}. If not, you'll +% need to use \app{xindy} with a package such as +% \sty{glossaries}. +% +% Declare package: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datagidx}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{datatool} +\RequirePackage{etoolbox} +\RequirePackage{xkeyval} +\RequirePackage{mfirstuc} +\RequirePackage{xfor} +\RequirePackage{multicol} +\RequirePackage{textcase} +% \end{macrocode} +%\changes{2.15}{2013-07-10}{added afterpage as a required package} +% \begin{macrocode} +\RequirePackage{afterpage} +% \end{macrocode} +% +%\section{Default Settings} +% These commands need to be defined before the package options are +% used. +%\begin{macro}{\datagidx@columns} +% The number of columns to use for the index/glossary. +% \begin{macrocode} +\newcommand*{\datagidx@columns}{2} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSetColumns} +% \begin{macrocode} +\newcommand*{\DTLgidxSetColumns}[1]{% + \DTLifint{#1}% + {% + \def\datagidx@columns{#1}% + }% + {% + \PackageError{datagidx}% + {Number of columns must be an integer}% + {% + You have requested `#1' columns, which can't be parsed as a + number% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{counter}{DTLgidxChildCount} +% Child counter. +% \begin{macrocode} +\newcounter{DTLgidxChildCount} +% \end{macrocode} +%\end{counter} +%\begin{macro}{\theHDTLgidxChildCount} +% Reduce duplicate identifier warnings if \sty{hyperref} in use. +% \begin{macrocode} +\def\theHDTLgidxChildCount{\Label.\arabic{DTLgidxChildCount}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxChildCountLabel} +% Label for child counter. +% \begin{macrocode} +\newcommand*{\DTLgidxChildCountLabel}{\theDTLgidxChildCount) } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxChildStyle} +% Should the child name be displayed? (Default: show name.) +% If the name shouldn't be displayed, replace with a number. +% \begin{macrocode} +\newcommand*{\DTLgidxChildStyle}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@setchildstyle} +% \begin{macrocode} +\newcommand*{\datagidx@setchildstyle}[1]{% + \ifcase#1\relax + \renewcommand*{\DTLgidxChildStyle}[1]{##1}% + \or + \renewcommand*{\DTLgidxChildStyle}[1]{% + \DTLgidxChildCountLabel + }% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@foreachchild} +% Iterate through each child label +% \begin{macrocode} +\newcommand{\datagidx@foreachchild}{% + \datagidx@sort@foreachchild +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@setchildsort} +% \begin{macrocode} +\newcommand*{\datagidx@setchildsort}[1]{% + \ifcase#1\relax + \renewcommand*{\datagidx@foreachchild}{% + \datagidx@sort@foreachchild + }% + \or + \renewcommand*{\datagidx@foreachchild}{% + \datagidx@unsort@foreachchild + }% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxPostName} +% What to put after the name. (Defaults to space.) +% \begin{macrocode} +\newcommand*{\DTLgidxPostName}{ } +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgidxPostChildName} +% What to put after the child name. +% \begin{macrocode} +\newcommand*{\DTLgidxPostChildName}{\DTLgidxPostName} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxNameCase} +% Should the name have a case change in the index/glossary? +% (Default: no change.) +% \begin{macrocode} +\newcommand*{\DTLgidxNameCase}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidx@setnamecase} +% \begin{macrocode} +\newcommand*{\datagidx@setnamecase}[1]{% + \ifcase#1\relax + \renewcommand*{\DTLgidxNameCase}[1]{##1}% + \or + \let\DTLgidxNameCase\MakeTextUppercase + \or + \let\DTLgidxNameCase\MakeTextLowercase + \or + \let\DTLgidxNameCase\xmakefirstuc + \or + \let\DTLgidxNameCase\xcapitalisewords + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxNameFont} +% The font to use for the name in the index/glossary. +% (Default: normal font.) +% \begin{macrocode} +\newcommand*{\DTLgidxNameFont}[1]{\textnormal{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxPostDescription} +% What to put after the description. (Defaults to nothing.) +% \begin{macrocode} +\newcommand*{\DTLgidxPostDescription}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@setpostdesc} +% \begin{macrocode} +\newcommand*{\datagidx@setpostdesc}[1]{% + \ifcase#1\relax + \renewcommand*{\DTLgidxPostDescription}{}% + \or + \renewcommand*{\DTLgidxPostDescription}{.}% + \fi + } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxPreLocation} +% What to put before the location list. (Defaults to en-space.) +% \begin{macrocode} +\newcommand*{\DTLgidxPreLocation}{\enspace} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@setprelocation} +% \begin{macrocode} +\newcommand*{\datagidx@setprelocation}[1]{% + \ifcase#1\relax + \renewcommand*{\DTLgidxPreLocation}{}% + \or + \renewcommand*{\DTLgidxPreLocation}{\enspace}% + \or + \renewcommand*{\DTLgidxPreLocation}{ }% + \or + \renewcommand*{\DTLgidxPreLocation}{\dotfill}% + \or + \renewcommand*{\DTLgidxPreLocation}{\hfill}% + \fi + } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxLocation} +% How to display the location. (Defaults to show the location list.) +% \begin{macrocode} +\newcommand*{\DTLgidxLocation}{\dtldolocationlist} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@setlocation} +% Should the location list be displayed? +% \begin{macrocode} +\newcommand*{\datagidx@setlocation}[1]{% + \ifcase#1\relax + \renewcommand*{\DTLgidxLocation}{}% + \or + \renewcommand*{\DTLgidxLocation}{\dtldolocationlist}% + \or + \renewcommand*{\DTLgidxLocation}{\dtldofirstlocation}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSee} +% How to display the cross-reference list. +% \begin{macrocode} +\newcommand*{\DTLgidxSee}{% + \DTLifnull{\See}% + {}% + {% + \DTLgidxPreLocation + \DTLgidxFormatSee{\seename}{\See}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgidxSeeAlso} +% How to display the ``see also'' list. +% \begin{macrocode} +\newcommand*{\DTLgidxSeeAlso}{% + \DTLifnull{\SeeAlso}% + {}% + {% + \DTLgidxFormatSeeAlso{\seealsoname}{\SeeAlso}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxChildrenSeeAlso} +% Display the children and the see also attributes. +% \begin{macrocode} +\newcommand*{\DTLgidxChildrenSeeAlso}{% + \DTLgidxChildren + \DTLgidxSeeAlso +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@setsee} +% How should cross-references appear? +% \begin{macrocode} +\newcommand*{\datagidx@setsee}[1]{% + \ifcase#1\relax + \renewcommand*{\DTLgidxSee}{% + \DTLifnull{\See}{}% + {% + , \DTLgidxFormatSee{\seename}{\See}% + }% + }% + \or + \renewcommand*{\DTLgidxSee}{% + \DTLifnull{\See}{} + {% + \space(\DTLgidxFormatSee{\seename}{\See})% + }% + }% + \or + \renewcommand*{\DTLgidxSee}{% + \DTLifnull{\See}{}% + {% + . \DTLgidxFormatSee{\xmakefirstuc{\seename}}{\See}% + }% + }% + \or + \renewcommand*{\DTLgidxSee}{% + \DTLifnull{\See}{} + {% + \space\DTLgidxFormatSee{\seename}{\See}% + }% + }% + \or + \renewcommand*{\DTLgidxSee}{% + \DTLifnull{\See}{} + {% + \DTLgidxFormatSee{\seename}{\See}% + }% + }% + \or + \renewcommand*{\DTLgidxSee}{% + \DTLifnull{\See}{} + {% + ; \DTLgidxFormatSee{\seename}{\See}% + }% + }% + \or + \renewcommand*{\DTLgidxSee}{% + \DTLifnull{\See}{} + {% + \DTLgidxPreLocation\DTLgidxFormatSee{\seename}{\See}% + }% + }% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSymDescSep} +% Separator character between symbol and description if both are +% present. +% \begin{macrocode} +\newcommand*{\DTLgidxSymDescSep}{\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxsymbolwidth} +% Space to allocate for the symbol. If zero or negative, symbol just +% occupies its natural space. +% \begin{macrocode} +\newlength\datagidxsymbolwidth +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxlocationwidth} +% Space to allocate for the location list. If zero or negative, the +% list just occupies its natural space. +% \begin{macrocode} +\newlength\datagidxlocationwidth +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxFormatDesc} +% How to format the description. +% \begin{macrocode} +\newcommand{\DTLgidxFormatDesc}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSymbolDescription} +% How to format the symbol and description fields. +% \begin{macrocode} +\newcommand*{\DTLgidxSymbolDescription}{% + \DTLgidxSymbolDescLeft + \DTLgidxSymbolDescRight +} +\newcommand*{\DTLgidxSymbolDescLeft}{% + \ifdefempty{\Symbol}{}{(\Symbol)\DTLgidxSymDescSep}% +} +\newcommand*{\DTLgidxSymbolDescRight}{% + \ifdefempty{\Description}{}% + {% + \DTLgidxFormatDesc{\Description}\DTLgidxPostDescription + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\if@datagidxsymbolleft} +% Identifies whether the symbol has been set to left or right. +% \begin{macrocode} +\newif\if@datagidxsymbolleft +\@datagidxsymbollefttrue +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@formatsymdesc} +% \begin{macrocode} +\newcommand*{\datagidx@formatsymdesc}[1]{% + \ifcase#1\relax +% \end{macrocode} +% Only symbol +% \begin{macrocode} + \renewcommand*{\DTLgidxSymbolDescLeft}{% + \ifdefempty{\Symbol}{}{\Symbol}% + }% + \renewcommand*{\DTLgidxSymbolDescRight}{}% + \@datagidxsymbollefttrue + \or +% \end{macrocode} +% Only description +% \begin{macrocode} + \renewcommand*{\DTLgidxSymbolDescLeft}{% + \ifdefempty{\Description}{}% + {% + \DTLgidxFormatDesc{\Description}\DTLgidxPostDescription + }% + }% + \renewcommand*{\DTLgidxSymbolDescRight}{}% + \@datagidxsymbolleftfalse + \or +% \end{macrocode} +% (symbol) description +% \begin{macrocode} + \renewcommand*{\DTLgidxSymbolDescLeft}{% + \ifdefempty{\Symbol}{}{(\Symbol)\DTLgidxSymDescSep}% + }% + \renewcommand*{\DTLgidxSymbolDescRight}{% + \ifdefempty{\Description}{}% + {% + \DTLgidxFormatDesc{\Description}\DTLgidxPostDescription + }% + }% + \@datagidxsymbollefttrue + \or +% \end{macrocode} +% description (symbol) +% \begin{macrocode} + \renewcommand*{\DTLgidxSymbolDescLeft}{% + \ifdefempty{\Description}{}% + {% + \DTLgidxFormatDesc{\Description}% + \DTLgidxPostDescription\DTLgidxSymDescSep + }% + }% + \renewcommand*{\DTLgidxSymbolDescRight}{% + \ifdefempty{\Symbol}{}{(\Symbol)}% + }% + \@datagidxsymbolleftfalse + \or +% \end{macrocode} +% symbol description +% \begin{macrocode} + \renewcommand*{\DTLgidxSymbolDescLeft}{% + \ifdefempty{\Symbol}{}{\Symbol\DTLgidxSymDescSep}% + }% + \renewcommand*{\DTLgidxSymbolDescRight}{% + \ifdefempty{\Description}{}% + {% + \DTLgidxFormatDesc{\Description}% + \DTLgidxPostDescription + }% + }% + \@datagidxsymbollefttrue + \or +% \end{macrocode} +% description symbol +% \begin{macrocode} + \renewcommand*{\DTLgidxSymbolDescLeft}{% + \ifdefempty{\Description}{}% + {% + \DTLgidxFormatDesc{\Description}% + \DTLgidxPostDescription\DTLgidxSymDescSep + }% + }% + \renewcommand*{\DTLgidxSymbolDescRight}{% + \ifdefempty{\Symbol}{}{\Symbol}% + }% + \@datagidxsymbolleftfalse + \fi + } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSetCompositor} +%\begin{definition} +%\cs{DTLgidxSetCompositor}\marg{symbol} +%\end{definition} +%Set the location compositor. +% \begin{macrocode} +\newcommand*{\DTLgidxSetCompositor}[1]{% + \undef\datagidx@docomplist + \DeclareListParser{\datagidx@docomplist}{#1}% + \def\datagidx@compositor{#1}% +} +% \end{macrocode} +%\end{macro} +%Set the default compositor to \texttt{.} (full stop). +% \begin{macrocode} +\DTLgidxSetCompositor{.} +% \end{macrocode} +% +% Sorting can take a long time (especially with large databases) but +% two \LaTeX\ runs are usually required to get the index or glossary +% up-to-date, so we usually don't need to worry about sorting on the +% first run (unless the order in some way affects the document, +% e.g.\ the group headings are to appear in the table of contents). +% It may also be that some modifications are done to the document +% that don't require a re-sort. The optimize setting tries to +% minimize the amount of sorting done to help speed up document +% compilation. +% +% There are to optimization levels: low and high. The low level +% optimization just sorts every other \LaTeX\ run. This is done by +% writing to the aux file to determine whether or not the sort +% should be done next run. This is a cheap and easy hack that won't +% work if sorting makes the document out-of-date (for example, if +% the sorted index or glossary affects the table of contents by, +% say, making the group headings a sectional unit). +% +% The high level optimization is more complicated and involves +% writing the sorted database to an external file and reading it in +% on the next run. This requires checks to see if the location lists +% have changed, in which case a new sort may be required. +% +%\begin{important} +% The optimization function is only implemented when the sorting is +% specified via the sort key. Any explicit sorting done by the user +% via commands such as \ics{dltsort} are not effected by the +% optimization setting. +%\end{important} +% +%\begin{macro}{\datagidx@do@sort} +% Indicate what to do when it's time to sort the index/glossary. +% This defaults to un-optimised setting to avoid confusing users who +% don't like to read the manual. +% \begin{macrocode} +\newcommand*{\datagidx@do@sort}{\datagidx@sort} +% \end{macrocode} +%\end{macro} +% +% First deal with the low-level optimization as it's easier to +% implement. +% +%\begin{macro}{\datagidx@optimize@sort} +% The code to perform when the low optimize setting is on. +% If the command \ics{datagidx@do@optimize@sort} has been defined, +% do the sort. If it hasn't been defined, don't sort. If a sort +% isn't performed, the command definition is written to the aux +% file. If a sort is performed, the command definition isn't written +% to the aux file. This will do the sort every other run. +% \begin{macrocode} +\newcommand*{\datagidx@optimize@sort}{% +% \end{macrocode} +% First, has \cs{datagidx@do@optimize@sort} been defined? +% \begin{macrocode} + \ifdef\datagidx@do@optimize@sort + {% +% \end{macrocode} +% It has been defined so go ahead and do the sort. +% \begin{macrocode} + \datagidx@sort + }% + {% +% \end{macrocode} +% It hasn't been defined so don't sort. Write the command definition +% into the aux file for the next run. +% \begin{macrocode} + \protected@write\@auxout{}{% + \string\gdef\string\datagidx@do@optimize@sort{}% + }% +% \end{macrocode} +% Let the user know they need to recompile the document. +% \begin{macrocode} + \global\let\@datagidx@dorerun@warn@sort\@data@rerun@warn@sort + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\if@datagidx@warn} +% Provide a switch to allow warnings to be suppressed. +% \begin{macrocode} +\newif\if@datagidx@warn +\@datagidx@warntrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@datagidx@dorerun@warn} +% \begin{macrocode} +\newcommand*\@datagidx@dorerun@warn{} +\AtEndDocument{\if@datagidx@warn\@datagidx@dorerun@warn\fi} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@datagidx@dorerun@warn@sort} +% \begin{macrocode} +\newcommand*\@datagidx@dorerun@warn@sort{} +\AtEndDocument{\if@datagidx@warn\@datagidx@dorerun@warn@sort\fi} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@datagidx@rerun@warn@sort} +% Warning issued when a rerun is required to sort the index or +% glossary. +% \begin{macrocode} +\newcommand*\@data@rerun@warn@sort{% + \PackageWarningNoLine{datagidx}{Rerun required to sort the + index/glossary databases}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@datagidx@rerun@warn} +% Warning issued when a rerun is required to update the location +% lists. +% \begin{macrocode} +\newcommand*\@data@rerun@warn{% + \PackageWarningNoLine{datagidx}{Rerun required to ensure the + index/glossary location lists are up-to-date}% +} +% \end{macrocode} +%\end{macro} +% +% +%The high optimize setting is more complicated. +% This involves writing each database to an external file (named +% \cs{jobname}-\meta{db label}.gidx). The sort is only performed if +% new terms are added or used. +% +%\begin{macro}{\datagidx@do@highopt@optimize} +% \begin{macrocode} +\newcommand*{\datagidx@do@highopt@optimize}{% + \renewcommand*{\datagidx@do@sort}{% +% \end{macrocode} +% Only sort if database has changed. +% \begin{macrocode} + \ifcsdef{datagidx@do@highopt@sort@\DTLgidxCurrentdb}% + {% + \csuse{datagidx@do@highopt@sort@\DTLgidxCurrentdb}% + }% + {% +% \end{macrocode} +% Do nothing +% \begin{macrocode} + }% +% \end{macrocode} +% Save the database to file. +% \begin{macrocode} + \bgroup +% \end{macrocode} +% Hook into write macro to clear certain fields and protect commands +% like \ics{DTLgidxName}. +% \begin{macrocode} + \def\dtl@saverawdbhook{% + \let\db@col@id@w\@datagidx@db@col@id@w + \def\DTLgidxName{\string\DTLgidxName\space}% + \def\DTLgidxMac{\string\DTLgidxMac\space}% + \def\DTLgidxRank{\string\DTLgidxRank\space}% + \def\DTLgidxParen{\string\DTLgidxParen\space}% + \def\DTLgidxParticle{\string\DTLgidxParticle\space}% + \def\DTLgidxOffice{\string\DTLgidxOffice\space}% + \def\DTLgidxSaint{\string\DTLgidxSaint\space}% + \def\DTLgidxPlace{\string\DTLgidxPlace\space}% + \def\DTLgidxIgnore{\string\DTLgidxIgnore\space}% + \def\DTLgidxNameNum{\string\DTLgidxNameNum\space}% + \def\DTLgidxSubject{\string\DTLgidxSubject\space}% + }% + \DTLsaverawdb{\DTLgidxCurrentdb}{\datagidxhighoptfilename\DTLgidxCurrentdb}% + \egroup + }% +% \end{macrocode} +% Change the behaviour of \cs{newgidx} +% \begin{macrocode} + \def\newgidx{\datagidx@highopt@newgidx}% +% \end{macrocode} +% Change the behaviour of \cs{newterm} +% \begin{macrocode} + \def\newterm{\datagidx@highopt@newterm}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@datagidx@db@col@id@w} +% A bit of trickery is need to clear the Used and Location fields when +% writing the raw database to file. +% \begin{macrocode} +\def\@datagidx@db@col@id@w#1\db@col@id@end@\db@col@elt@w#2\db@col@elt@end@\db@col@id@w#3\db@col@id@end@{% + \expandafter\@gobble\string\%^^J + \string\db@col@id@w\space #1% + \expandafter\@gobble\string\%^^J + \string\db@col@id@end@\space + \expandafter\@gobble\string\%^^J + \string\db@col@elt@w\space + \expandafter\ifnum\csname dtl@ci@\DTLgidxCurrentdb @Used\endcsname=#1\space + 0% + \else + \expandafter\ifnum\csname dtl@ci@\DTLgidxCurrentdb @Location\endcsname=#1\space + \else + \expandafter\ifnum\csname dtl@ci@\DTLgidxCurrentdb @CurrentLocation\endcsname=#1\space + \else +% \end{macrocode} +% We also want to prevent the first character of the sort field from +% being expanded to help get the group correct (in case the user +% wants to sort on, say, the tilde character). +% \begin{macrocode} + \expandafter\ifnum\csname dtl@ci@\DTLgidxCurrentdb @Sort\endcsname=#1\space + \protect#2% + \else + #2% + \fi + \fi + \fi + \fi + \expandafter\@gobble\string\%^^J + \string\db@col@elt@end@\space + \expandafter\@gobble\string\%^^J + \string\db@col@id@w\space #3% + \expandafter\@gobble\string\%^^J + \string\db@col@id@end@\space +} +% \end{macrocode} +%\end{macro} +% +% With the `highopt optimize' setting, whenever a location is written to the aux +% file, if no location has been defined the database needs sorting. +% +%\begin{macro}{\datagidx@do@highopt@update} +% Default does nothing. (Argument is the entry's label.) +% \begin{macrocode} +\newcommand*{\datagidx@do@highopt@update}[1]{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxhighoptfilename} +% Expands to the name of the filename associated with the database +% identified by the argument for the `highopt' setting. +% \begin{macrocode} +\newcommand*{\datagidxhighoptfilename}[1]{\jobname-#1.gidx} +% \end{macrocode} +%\end{macro} +% +%\section{Package Options} +% +%\begin{option}{optimize} +% A boolean option indicating whether or not to optimize the sort. +% This is only available as a global option. If you want to optimize +% some glossaries but not others, switch on the optimize function +% and clear the sort key for the relevant glossaries and manually +% sort using \ics{dtlsort} before the glossary is displayed. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{optimize}[\val\nr]% + {off,low,high}[high]% + {% + \ifcase\nr\relax + \renewcommand*{\datagidx@do@sort}{\datagidx@sort} + \or + \renewcommand*{\datagidx@do@sort}{\datagidx@optimize@sort} + \or + \datagidx@do@highopt@optimize + \fi + } +% \end{macrocode} +%\end{option} +% +%\begin{option}{nowarn} +% A boolean option to suppress warnings. +%\changes{2.15}{2013-07-10}{new} +% \begin{macrocode} +\define@choicekey{datagidx.sty}{nowarn}[\val\nr]{true,false}[true]% +{% + \ifcase\nr\relax + \@datagidx@warnfalse + \or + \@datagidx@warntrue + \fi +} +% \end{macrocode} +%\end{option} +% +%\begin{option}{utf8} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\define@choicekey{datatool.sty}{utf8}{true,false}[true]{% + \setbool{@dtl@utf8}{#1}% +} +% \end{macrocode} +%\end{option} +% +% These options govern the general layout of the glossary/index. +%\begin{option}{columns} +% The number of columns used by \env{multicols} (or +% \env{multicols*}). If only one column is specified, +% \env{multicols} (or \env{multicols*}) isn't used. +% \begin{macrocode} +\define@key{datagidx.sty}{columns}% +{% + \DTLgidxSetColumns{#1}% +} +% \end{macrocode} +%\end{option} +%\begin{option}{child} +% Indicates whether or not to show the name in child entries. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{child}[\val\nr]% + {named,noname}% + {% + \datagidx@setchildstyle\nr + } +% \end{macrocode} +%\end{option} +%\begin{option}{namecase} +% Options for name case. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{namecase}[\val\nr]% + {nochange,uc,lc,firstuc,capitalise}% + {% + \datagidx@setnamecase\nr + } +% \end{macrocode} +%\end{option} +% +%\begin{option}{namefont} +% Option to set the name font. +% \begin{macrocode} +\define@key{datagidx.sty}{namefont}% +{% + \renewcommand*{\DTLgidxNameFont}[1]{{#1{##1}}}% +} +% \end{macrocode} +%\end{option} +% +%\begin{option}{postname} +% What to put after the name. +% \begin{macrocode} +\define@key{datagidx.sty}{postname} +{% + \renewcommand*{\DTLgidxPostName}{#1}% +} +% \end{macrocode} +%\end{option} +% +%\begin{option}{postdesc} +% what to put after the description. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{postdesc}[\val\nr]% + {none,dot}% + {% + \datagidx@setpostdesc\nr + } +% \end{macrocode} +%\end{option} +% +%\begin{option}{prelocation} +% What to put before the location list. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{prelocation}[\val\nr]% + {none,enspace,space,dotfill,hfill}% + {% + \datagidx@setprelocation\nr + } +% \end{macrocode} +%\end{option} +% +%\begin{option}{location} +% How to display the location list. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{location}[\val\nr]% + {hide,list,first}% + {\datagidx@setlocation\nr} +% \end{macrocode} +%\end{option} +% +%\begin{option}{see} +% How to display the cross-reference list. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{see}[\val\nr]% + {comma,brackets,dot,space,nosep,semicolon,location}% + {\datagidx@setsee\nr} +% \end{macrocode} +%\end{option} +% +%\begin{option}{symbol} +% How to format the symbol in relation to the description. +% \begin{macrocode} +\define@choicekey{datagidx.sty}{symboldesc}[\val\nr]% + {symbol,desc,(symbol) desc,desc (symbol),symbol desc,desc symbol}% + {\datagidx@formatsymdesc\nr} +% \end{macrocode} +%\end{option} +% +%\begin{option}{compositor} +% Location compositor. +% \begin{macrocode} +\define@key{datagidx.sty}{compositor}% +{% + \DTLgidxSetCompositor{#1}% +}% +% \end{macrocode} +%\end{option} +% +%\begin{option}{final} +% \begin{macrocode} +\DeclareOptionX{final}{% + \let\datagidxshowifdraft\@gobble +} +% \end{macrocode} +% Set as default: +% \begin{macrocode} +\let\datagidxshowifdraft\@gobble +% \end{macrocode} +%\end{option} +% +%\begin{option}{draft} +% \begin{macrocode} +\DeclareOptionX{draft}{% + \let\datagidxshowifdraft\@firstofone +} +% \end{macrocode} +%\end{option} +% +%\begin{option}{verbose} +% \begin{macrocode} +\define@choicekey{datagidx.sty}{verbose}[\val\nr]% + {true,false}[true]% + {% + \csuse{dtlverbose\val}% + } +% \end{macrocode} +%\end{option} +% +% Process package options: +% \begin{macrocode} +\ProcessOptionsX +% \end{macrocode} +% +% Database to keep track of all the defined terms. +% \begin{macrocode} +\DTLnewdb{datagidx} +% \end{macrocode} +% +%\section{Glossary/Index Formatting} +%\begin{macro}{\seename} +% \begin{macrocode} +\providecommand*{\seename}{see} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\seealsoname} +% \begin{macrocode} +\providecommand*{\seealsoname}{see also} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSeeTagFont} +% \begin{macrocode} +\newcommand*{\DTLgidxSeeTagFont}[1]{\emph{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxFormatSee} +%\begin{definition} +%\cs{DTLgidxFormatSee}\marg{tag}\marg{label list} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLgidxFormatSee}[2]{% + \DTLgidxSeeTagFont{#1} \DTLgidxSeeList{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxFormatSeeAlso} +%\begin{definition} +%\cs{DTLgidxFormatSeeAlso}\marg{tag}\marg{label list} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLgidxFormatSeeAlso}[2]{% + \datagidxdoseealso + {% + \DTLgidxSeeTagFont{#1} \DTLgidxSeeList{#2}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxdoseealso} +% \begin{macrocode} +\newcommand*{\datagidxdoseealso}[1]{% + \datagidxseealsostart + #1% + \datagidxseealsoend +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSeeList} +%\begin{definition} +%\cs{DTLgidxSeeList}\marg{label list} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLgidxSeeList}[1]{% + \def\datagidx@sep{}% + \@for\dtl@thislabel:=#1\do + {% + \ifx\@xfor@nextelement\@nnil +% \end{macrocode} +% Last iteration. +% \begin{macrocode} + \ifdefempty{\datagidx@sep}% + {% +% \end{macrocode} +% Only one element in the list. +% \begin{macrocode} + }% + {% +% \end{macrocode} +% Not the only element in the list. +% \begin{macrocode} + \DTLidxSeeLastSep + }% + \else +% \end{macrocode} +% Not last iteration +% \begin{macrocode} + \datagidx@sep + \let\datagidx@sep\DTLidxSeeSep + \fi + \DTLidxFormatSeeItem{\dtl@thislabel}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLidxFormatSeeItem} +%\begin{definition} +%\cs{DTLidxFormatSeeItem}\marg{label} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLidxFormatSeeItem}[1]{% + \DTLgidxFetchEntry{\datagidx@value}{#1}{Name}% + \datagidxlink{#1}% + {% + \datagidx@value + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLidxSeeSep} +% Separator in cross-reference list. +% \begin{macrocode} +\newcommand*{\DTLidxSeeSep}{, } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLidxSeeLastSep} +% Final separator in cross-reference list. +% \begin{macrocode} +\newcommand*{\DTLidxSeeLastSep}{ \& } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxDoSeeOrLocation} +% You should have both a ``see'' list and a location list. This +% checks if \cs{See} is null. If it isn't null, it does the ``see'' +% part, otherwise it deals with the location list. +% \begin{macrocode} +\newcommand*{\DTLgidxDoSeeOrLocation}{% + \DTLifnull\See + {% +% \end{macrocode} +% \cs{See} is null. Do we have a location? +% \begin{macrocode} + \ifdefempty\Location + {% + }% + {% + \DTLgidxPreLocation + \DTLgidxLocation + }% + }% + {% +% \end{macrocode} +% \cs{See} is not null, so do the cross-reference. +% \begin{macrocode} + \DTLgidxSee + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@sortchildren} +% The list of child labels needs to be sorted so that the child list +% follows the same ordering as the database. +% \begin{macrocode} +\newcommand*{\datagidx@sortchildren}{% + \def\datagidx@sortedlist{}% + \@for\Label:=\Children\do + {% + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\DTLgidxCurrentdb}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Label}}% + {\Label}% + }% + \do@getrow +% \end{macrocode} +% Row index is stored in \cs{dtlrownum}. Is the sorted list empty? +% \begin{macrocode} + \ifdefempty\datagidx@sortedlist + {% +% \end{macrocode} +% Yes, it's empty. +% \begin{macrocode} + \edef\datagidx@newsortedlist{{\number\dtlrownum}{\Label}}% + }% + {% +% \end{macrocode} +% No, it's not empty. Need to insert into list. +% \begin{macrocode} + \def\datagidx@newsortedlist{}% + \@for\@datagidx@thisval:=\datagidx@sortedlist\do + {% +% \end{macrocode} +% Get the index: +% \begin{macrocode} + \edef\datagidx@thisidx{\expandafter\@firstoftwo\@datagidx@thisval}% +% \end{macrocode} +% Is index greater than \cs{dtlrownum}? +% \begin{macrocode} + \ifnum\datagidx@thisidx>\dtlrownum\relax +% \end{macrocode} +% Yes, it is. So insert here. +% \begin{macrocode} + \ifdefempty\datagidx@newsortedlist + {% + \eappto\datagidx@newsortedlist + {% + {\number\dtlrownum}{\Label},\@datagidx@thisval + }% + }% + {% + \eappto\datagidx@newsortedlist + {% + ,{\number\dtlrownum}{\Label},\@datagidx@thisval + }% + }% +% \end{macrocode} +% Break out of inner loop. +% \begin{macrocode} + \@endfortrue + \else + \ifdefempty\datagidx@newsortedlist + {% + \edef\datagidx@newsortedlist{% + \@datagidx@thisval + }% + }% + {% + \eappto\datagidx@newsortedlist + {% + ,\@datagidx@thisval + }% + }% + \fi + }% +% \end{macrocode} +% Was the loop ended prematurely? +% \begin{macrocode} + \if@endfor +% \end{macrocode} +% If loop was ended on the last iteration, \cs{@forremainder} will +% be empty and there's nothing left to do. +% \begin{macrocode} + \ifdefempty\@forremainder + {% + }% + {% +% \end{macrocode} +% Loop prematurely ended, so append remainder to list. + \eappto\datagidx@newsortedlist{,\@forremainder}% +% \begin{macrocode} + }% + \else +% \end{macrocode} +% Loop wasn't prematurely terminated, so new value hasn't been +% added. Add now. +% \begin{macrocode} + \ifdefempty\datagidx@newsortedlist + {% + \edef\datagidx@newsortedlist{{\number\dtlrownum}{\Label}}% + }% + {% + \eappto\datagidx@newsortedlist{,{\number\dtlrownum}{\Label}}% + }% + \fi + }% +% \end{macrocode} +% Update. +% \begin{macrocode} + \let\datagidx@sortedlist\datagidx@newsortedlist +% \end{macrocode} +% Don't break out of outer loop. +% \begin{macrocode} + \@endforfalse + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@sort@foreachchild} +% Sorted iteration through all the child labels. +% \begin{macrocode} +\newcommand{\datagidx@sort@foreachchild}[1]{% + \datagidx@sortchildren +% \end{macrocode} +% Sorted list stored in \cs{datagidx@sortedlist} +% \begin{macrocode} + \@for\@datagidx@thisval:=\datagidx@sortedlist\do + {% + \edef\Label{\expandafter\@secondoftwo\@datagidx@thisval}% + #1% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@unsort@foreachchild} +% Unsorted iteration through all the child labels. +% \begin{macrocode} +\newcommand{\datagidx@unsort@foreachchild}[1]{% + \@for\Label:=\Children\do + {% + #1% + }% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\DTLgidxChildren} +% How to display the children +% \begin{macrocode} +\newcommand*{\DTLgidxChildren}{% + \bgroup + \DTLifnull\Children + {}% + {% + \advance\datagidx@level by 1\relax + \datagidxchildstart + \let\Parent\Label + \datagidx@foreachchild + {% + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\DTLgidxCurrentdb}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Label}}% + {\Label}% + }% + \do@getrow + \dtlgetentryfromcurrentrow + {\Location}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Location}}% + \dtlgetentryfromcurrentrow + {\See}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{See}}% + \dtlgetentryfromcurrentrow + {\SeeAlso}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{SeeAlso}}% + \DTLifnull\Location + {% + \DTLifnull\See + {% + \DTLifnull\SeeAlso + {}% + {% + \datagidx@displaychild + }% + }% + {% + \datagidx@displaychild + }% + }% + {% + \datagidx@displaychild + }% + }% + \datagidxchildend + }% + \egroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxgetchildfields} +% Get the child fields from the current row. +% \begin{macrocode} +\newcommand*{\datagidxgetchildfields}{% + \dtlgetentryfromcurrentrow + {\Name}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Name}}% + \dtlgetentryfromcurrentrow + {\Description}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Description}}% + \dtlgetentryfromcurrentrow + {\Symbol}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Symbol}}% + \dtlgetentryfromcurrentrow + {\Long}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Long}}% + \dtlgetentryfromcurrentrow + {\Short}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Short}}% + \dtlgetentryfromcurrentrow + {\Text}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Text}}% + \dtlgetentryfromcurrentrow + {\Plural}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Plural}}% + \dtlgetentryfromcurrentrow + {\Short}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Used}}% + \dtlgetentryfromcurrentrow + {\Children}% + {\dtlcolumnindex{\DTLgidxCurrentdb}{Child}}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@displaychild} +% \begin{macrocode} +\newcommand*{\datagidx@displaychild}{% + \datagidxgetchildfields + \datagidxchilditem +} +% \end{macrocode} +%\end{macro} +% +% +% Define some keys for \ics{newgloss}: +%\begin{macro}{\datagidx@heading} +% Indicates how to format the heading in the glossary/index. +% \begin{macrocode} +\ifdef{\chapter} +{% + \newcommand*{\datagidx@heading}{\chapter*} +}% +{% + \newcommand*{\datagidx@heading}{\section*} +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgidxNoHeading} +% Allow user to suppress the heading. (So to suppress the +% heading do \texttt{heading=\cs{DTLgidxNoHeading}}). +% \begin{macrocode} +\let\DTLgidxNoHeading\@gobble +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@postheading} +% Indicates what to do immediately after the heading. +% \begin{macrocode} +\newcommand*{\datagidx@postheading}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@multicols} +% Should we use \env{multicols} or \env{multicols*}? +% \begin{macrocode} +\newcommand*{\datagidx@multicols}{multicols} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@sort} +% Indicates how to sort the glossary/index. +% Defaults to word order. +% \begin{macrocode} +\newcommand*{\datagidx@sort}{% + \dtlsort{Sort,FirstId}{\DTLgidxCurrentdb}{\dtlwordindexcompare}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@idxitem} +% Some classes, such as \cls{beamer}, don't define \cs{@idxitem} so +% if it's not already defined, define it here. +% \begin{macrocode} +\providecommand{\@idxitem}{\par\hangindent 40\p@} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidxstart} +% Indicates what to do at the start of the glossary/index. +% \begin{macrocode} +\newcommand*{\datagidxstart}% +{% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \let\item\@idxitem +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidxend} +% Indicates what to do at the end of the glossary/index. +% \begin{macrocode} +\newcommand*{\datagidxend}{\egroup} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxtarget} +% Provide a means to add a hypertarget if \ics{hypertarget} has been +% defined. +% \begin{macrocode} +\newcommand*{\@datagidxtarget}[2]{% + \ifdef\hypertarget + {% + \bgroup + \let\glsadd\@gobble + \settoheight\dimen@{#2}% + \raisebox{\dimen@}{\hypertarget{#1}{}}% + \egroup + }% + {% + }% + #2% +} +\newcommand*{\datagidxtarget}{\@datagidxtarget} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxlink} +% Provide a means to add a link if \ics{hyperlink} has been +% defined. +% \begin{macrocode} +\newcommand*{\@datagidxlink}[2]{% + \ifdef\hyperlink + {% + \hyperlink{#1}{#2}% + }% + {% + #2% + }% +} +\newcommand*{\datagidxlink}{\@datagidxlink} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxEnableHyper} +% Enable hyperlinks (if they are defined). +% \begin{macrocode} +\newcommand*{\DTLgidxEnableHyper}{% + \let\datagidxtarget\@datagidxtarget + \let\datagidxlink\@datagidxlink +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxDisableHyper} +% Disable hyperlinks (if they are defined). +% \begin{macrocode} +\newcommand*{\DTLgidxDisableHyper}{% + \let\datagidxtarget\@secondoftwo + \let\datagidxlink\@secondoftwo +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxgroupsep} +% Indicates what to do between groups (after the previous group and +% before the header of the next group). +% \begin{macrocode} +\newcommand*{\datagidxgroupsep}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxgroupheader} +% Indicates what to do at the start of a group. (The current group +% label can be accessed via \cs{datagidxcurrentgroup} and the previous +% group label can be accessed via \cs{datagidxprevgroup}.) +% \begin{macrocode} +\newcommand*{\datagidxgroupheader}{} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\datagidxitem} +% Indicates what to do at the start of each item of the glossary/index. +% \begin{macrocode} +\newcommand*{\datagidxitem}{}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxchildstart} +% Indicates what to do at the start of the child glossary/index. +% \begin{macrocode} +\newcommand*{\datagidxchildstart}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidxchildend} +% Indicates what to do at the end of the child glossary/index. +% \begin{macrocode} +\newcommand*{\datagidxchildend}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidxchilditem} +% Indicates what to do at the start of each item of the child glossary/index. +% \begin{macrocode} +\newcommand*{\datagidxchilditem}{}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxseealsostart} +% Indicates what to do at the start of the ``see also'' list. +% \begin{macrocode} +\newcommand*{\datagidxseealsostart}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidxseealsoend} +% Indicates what to do at the end of the ``see also'' list. +% \begin{macrocode} +\newcommand*{\datagidxseealsoend}{} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\datagidx@doifsymlocwidth} +%\begin{definition} +%\cs{datagidx@doifsymlocwidth}\marg{indent}\marg{Name code}\marg{Location code} +%\end{definition} +% What to do if both the symbol width and the location width have +% been set. +% \begin{macrocode} +\newcommand*{\datagidx@doifsymlocwidth}[3]{% +% \end{macrocode} +% Calculate remaining space left for the description. +% \begin{macrocode} + \setlength{\dtl@tmplength}{\linewidth}% + \addtolength{\dtl@tmplength}{-#1}% + \settowidth{\dimen@}{#2}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \addtolength{\dtl@tmplength}{-\datagidxsymbolwidth}% + \addtolength{\dtl@tmplength}{-\datagidxlocationwidth}% + \settowidth{\dimen@}{\DTLgidxPreLocation}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \settowidth{\dimen@}{\DTLgidxSymDescSep}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \if@datagidxsymbolleft + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\dtl@tmplength}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescRight + \end{minipage}% + \else + \begin{minipage}[t]{\dtl@tmplength}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescRight + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \fi + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + #3% + \end{minipage}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@doiflocwidth} +%\begin{definition} +%\cs{datagidx@doiflocwidth}\marg{indent}\marg{Name code}\marg{Location code} +%\end{definition} +% What to do if only the location width has +% been set. +% \begin{macrocode} +\newcommand*{\datagidx@doiflocwidth}[3]{% +% \end{macrocode} +% Calculate remaining space left for the symbol and description. +% \begin{macrocode} + \setlength{\dtl@tmplength}{\linewidth}% + \addtolength{\dtl@tmplength}{-#1}% + \settowidth{\dimen@}{#2}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \addtolength{\dtl@tmplength}{-\datagidxlocationwidth}% + \settowidth{\dimen@}{\DTLgidxPreLocation}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \begin{minipage}[t]{\dtl@tmplength}% + \DTLgidxSymbolDescription + \end{minipage}% + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + #3% + \end{minipage}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@doifsymwidth} +%\begin{definition} +%\cs{datagidx@doifsymwidth}\marg{indent}\marg{Name code}\marg{Location code} +%\end{definition} +% What to do if only the location width has +% been set. +% \begin{macrocode} +\newcommand*{\datagidx@doifsymwidth}[3]{% +% \end{macrocode} +% Calculate remaining space left for the description and location. +% \begin{macrocode} + \setlength{\dtl@tmplength}{\linewidth}% + \addtolength{\dtl@tmplength}{-#1}% + \settowidth{\dimen@}{#2}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \addtolength{\dtl@tmplength}{-\datagidxsymbolwidth}% + \settowidth{\dimen@}{\DTLgidxSymDescSep}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \if@datagidxsymbolleft + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\dtl@tmplength}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescRight + #3% + \end{minipage}% + \else + \begin{minipage}[t]{\dtl@tmplength}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescRight + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft +% \end{macrocode} +% This arrangement may look a bit weird. +% \begin{macrocode} + #3% + \end{minipage}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxlocalign} +% Alignment of the location when the location width has been set. +% \begin{macrocode} +\newcommand*{\datagidxlocalign}{\raggedleft} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxsymalign} +% Alignment of the symbol when the symbol width has been set. +% \begin{macrocode} +\newcommand*{\datagidxsymalign}{\centering} +% \end{macrocode} +%\end{macro} +% +% +%\subsection{Predefined styles} +% +%\begin{macro}{\datagidxsetstyle} +% Sets the current index/glossary style +% \begin{macrocode} +\newcommand*{\datagidxsetstyle}[1]{% + \ifcsdef{datagidx@style@#1}% + {% + \csuse{datagidx@style@#1}% + }% + {% + \PackageError{datagidx}{Unknown style `#1'}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\subsubsection{index} +%\begin{macro}{\datagidx@style@index} +% Basic index style. +% \begin{macrocode} +\newcommand*{\datagidx@style@index}{% + \renewcommand*{\datagidxstart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% +% \end{macrocode} +% Index columns are usually too narrow for fully justified text. +% \begin{macrocode} + \raggedright + \let\item\@idxitem +% \end{macrocode} +% Have the symbol or location widths been set? +% \begin{macrocode} + \ifdim\datagidxsymbolwidth>0pt\relax +% \end{macrocode} +% Symbol width has been set +% Has the location width been set? +% \begin{macrocode} + \ifdim\datagidxlocationwidth>0pt\relax +% \end{macrocode} +% Both have been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \datagidx@doifsymlocwidth{0pt}% + {\DTLgidxNameFont{\DTLgidxNameCase{\Name}}}% + {% + \DTLgidxDoSeeOrLocation + }% + }% + \else +% \end{macrocode} +% Location width hasn't been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \datagidx@doiflocwidth{0pt}% + {\DTLgidxNameFont{\DTLgidxNameCase{\Name}}}% + {% + \DTLgidxDoSeeOrLocation + }% + }% + \fi + \else +% \end{macrocode} +% Symbol width hasn't been set +% Has the location width been set? +% \begin{macrocode} + \ifdim\datagidxlocationwidth>0pt\relax +% \end{macrocode} +% Location width has been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \datagidx@doiflocwidth{0pt}% + {\DTLgidxNameFont{\DTLgidxNameCase{\Name}}}% + {% + \DTLgidxDoSeeOrLocation + }% + }% + \else +% \end{macrocode} +% Neither have been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + }% + \fi + \fi + }% + \renewcommand*{\datagidxend}{\egroup}% + \renewcommand*{\datagidxgroupsep}{\ifdatagidxshowgroups\indexspace\fi}% + \renewcommand{\datagidxgroupheader}{% + \ifdatagidxshowgroups + \item + \makebox[\linewidth]% + {% + \textbf{\DTLgidxGroupHeaderTitle{\datagidxcurrentgroup}}% + }% + \DTLpar\nobreak\@afterheading + \fi + }% + \renewcommand*{\datagidxitem}{% +% \end{macrocode} +% Is this the start of a new group? +% \begin{macrocode} + \ifdefempty\datagidxprevgroup + {% +% \end{macrocode} +% First item of the list. +% \begin{macrocode} + \datagidxgroupheader + }% + {% +% \end{macrocode} +% Not the first item of the list. Is this item's group the same as +% the last item's group? +% \begin{macrocode} + \ifdefequal\datagidxcurrentgroup\datagidxprevgroup + {% +% \end{macrocode} +% Same, so do nothing. +% \begin{macrocode} + }% + {% +% \end{macrocode} +% Different, so do the separator and the header. +% \begin{macrocode} + \datagidxgroupsep + \datagidxgroupheader + }% + }% +% \end{macrocode} +% Now get on with this item. +% \begin{macrocode} + \item + \datagidxtarget{\Label}% + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + }% + \DTLgidxPostName + \datagidx@item@body + \DTLgidxChildrenSeeAlso + }% + \renewcommand*{\datagidxchildstart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \let\item\@idxitem + }% + \renewcommand*{\datagidxchildend}{\egroup}% + \renewcommand*{\datagidxchilditem}{% + \setlength{\dimen@}{\datagidxindent}% + \multiply\dimen@ by \datagidx@level\relax + \@idxitem\hspace*{\dimen@}% + \refstepcounter{DTLgidxChildCount}% + \datagidxtarget{\Label}% + {% + \DTLgidxChildStyle + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostChildName + }% + }% + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + }% + \renewcommand*{\datagidxseealsostart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \setlength{\dimen@}{\datagidxindent}% + \advance\datagidx@level by 1\relax + \multiply\dimen@ by \datagidx@level\relax + \@idxitem\hspace*{\dimen@}% + }% + \renewcommand{\datagidxseealsoend}{\egroup}% +} +% \end{macrocode} +%\end{macro} +% +%Make this the default style: +% \begin{macrocode} +\datagidx@style@index +% \end{macrocode} +% +%\subsubsection{indexalign} +% Similar to index style but aligns the descriptions. +%\begin{macro}{\datagidx@style@indexalign} +% \begin{macrocode} +\newcommand*{\datagidx@style@indexalign}{% + \renewcommand*{\datagidxstart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \setlength{\datagidxnamewidth}{0pt}% + \DTLforeach*{\DTLgidxCurrentdb}% + {\Name=Name,\Location=Location,\See=See,\SeeAlso=SeeAlso,% + \Parent=Parent}% + {% + \DTLifnull{\Parent}% + {% + \datagidx@doifdisplayed + {% + \settowidth{\dimen@}{\DTLgidxNameFont{\DTLgidxNameCase{\Name}}}% + \ifdim\dimen@>\datagidxnamewidth\relax + \datagidxnamewidth=\dimen@\relax + \fi + }% + }% + {}% + }% + \settowidth{\dimen@}{\DTLgidxPostName}% + \addtolength{\datagidxnamewidth}{\dimen@}% + \setlength{\datagidxdescwidth}{\linewidth}% + \addtolength{\datagidxdescwidth}{-\datagidxnamewidth}% + \ifdim\datagidxsymbolwidth>0pt\relax + \addtolength{\datagidxdescwidth}{-\datagidxsymbolwidth}% + \settowidth{\dimen@}{\DTLgidxSymDescSep}% + \addtolength{\datagidxdescwidth}{-\dimen@}% + \fi + \ifdim\datagidxlocationwidth>0pt\relax + \addtolength{\datagidxdescwidth}{-\datagidxlocationwidth}% + \settowidth{\dimen@}{\DTLgidxPreLocation}% + \addtolength{\datagidxdescwidth}{-\dimen@}% + \fi +% \end{macrocode} +% Has the symbol width been set? +% \begin{macrocode} + \ifdim\datagidxsymbolwidth>0pt\relax +% \end{macrocode} +% Yes, symbol width has been set. +% Has the location width been set? +% \begin{macrocode} + \ifdim\datagidxlocationwidth>0pt\relax +% \end{macrocode} +% Both symbol and location widths have been set. +% \begin{macrocode} + \if@datagidxsymbolleft +% \end{macrocode} +% Symbol is on the left. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \end{minipage}% + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + \DTLgidxDoSeeOrLocation + \end{minipage}% + }% + \else +% \end{macrocode} +% Symbol is on the right. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \end{minipage}% + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + \DTLgidxDoSeeOrLocation + \end{minipage}% + }% + \fi + \else +% \end{macrocode} +% Location width hasn't been set. (Only symbol width has been set.) +% \begin{macrocode} + \if@datagidxsymbolleft + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \DTLgidxDoSeeOrLocation + \end{minipage}% + }% + \else +% \end{macrocode} +% Symbol is on the right. +% This combination may look weird. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \DTLgidxDoSeeOrLocation + \end{minipage}% + }% + \fi + \fi + \else +% \end{macrocode} +% Symbol width hasn't been set. +% Has the location width been set? +% \begin{macrocode} + \ifdim\datagidxlocationwidth>0pt\relax +% \end{macrocode} +% Only location width has been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescription + \end{minipage}% + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + \DTLgidxDoSeeOrLocation + }% + \else +% \end{macrocode} +% Neither location nor symbol widths have been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + \end{minipage}% + }% + \fi + \fi + }% + \renewcommand*{\datagidxend}{\egroup}% + \renewcommand*{\datagidxgroupsep}{}% + \renewcommand*{\datagidxgroupheader}{}% + \renewcommand*{\datagidxitem}{% +% \end{macrocode} +% Is this the start of a new group? +% \begin{macrocode} + \ifdefempty\datagidxprevgroup + {% +% \end{macrocode} +% First item of the list. +% \begin{macrocode} + \datagidxgroupheader + }% + {% +% \end{macrocode} +% Not the first item of the list. Is this item's group the same as +% the last item's group? +% \begin{macrocode} + \ifdefequal\datagidxcurrentgroup\datagidxprevgroup + {% +% \end{macrocode} +% Same, so do nothing. +% \begin{macrocode} + }% + {% +% \end{macrocode} +% Different, so do the separator and the header. +% \begin{macrocode} + \datagidxgroupsep + \datagidxgroupheader + }% + }% +% \end{macrocode} +% Get on with this item +% \begin{macrocode} + \hangindent0pt\relax + \parindent0pt\relax + \makebox[\datagidxnamewidth][l]% + {% + \datagidxtarget{\Label}% + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostName + }% + }% + \datagidx@item@body + \par + \DTLgidxChildrenSeeAlso + \par + }% + \renewcommand*{\datagidxchildstart}% + {% + \bgroup + \setlength{\dimen@}{\datagidxindent}% + \multiply\dimen@ by \datagidx@level\relax + \setlength{\dtl@tmplength}{\linewidth}% + \addtolength{\dtl@tmplength}{-\dimen@}% + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \edef\item{\noexpand\parshape=1 \the\dimen@ \the\dtl@tmplength}% + \setlength{\datagidxnamewidth}{0pt}% + \DTLforeach*{\DTLgidxCurrentdb}% + {\Name=Name,\Location=Location,\See=See,\SeeAlso=SeeAlso,% + \Parent=Parent}% + {% + \DTLifnull{\Parent}% + {% + \datagidx@doifdisplayed + {% + \settowidth{\dimen@}% + {% + \DTLgidxChildStyle + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + }% + }% + \ifdim\dimen@>\datagidxnamewidth\relax + \datagidxnamewidth=\dimen@\relax + \fi + }% + }% + {}% + }% + \settowidth{\dimen@}{\DTLgidxChildStyle\DTLgidxPostChildName}% + \addtolength{\datagidxnamewidth}{\dimen@}% + \setlength{\datagidxdescwidth}{\dtl@tmplength}% + \addtolength{\datagidxdescwidth}{-\datagidxnamewidth}% + }% + \renewcommand{\datagidxchildend}{\egroup}% + \renewcommand*{\datagidxchilditem}{% + \item + \refstepcounter{DTLgidxChildCount}% + \makebox[\datagidxnamewidth][l]% + {% + \datagidxtarget{\Label}% + {% + \DTLgidxChildStyle + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostChildName + }% + }% + }% + \begin{minipage}[t]{\datagidxdescwidth}% + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + \par + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidxindent} +% Indent used by "index" and "indexalign" styles. +% \begin{macrocode} +\newlength\datagidxindent +\setlength\datagidxindent{10\p@} +% \end{macrocode} +%\end{macro} +% +% +%\subsubsection{align} +%\begin{macro}{\datagidxnamewidth} +% Length used by "align" and "indexalign" style name. +% \begin{macrocode} +\newlength\datagidxnamewidth +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxdescwidth} +% Length used by "align" and "indexalign" style description. +% \begin{macrocode} +\newlength\datagidxdescwidth +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@style@align} +% \begin{macrocode} +\newcommand*{\datagidx@style@align}{% + \renewcommand*{\datagidxstart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \setlength{\datagidxnamewidth}{0pt}% + \DTLforeach*{\DTLgidxCurrentdb}% + {\Name=Name,\Location=Location,\See=See,\SeeAlso=SeeAlso,% + \Parent=Parent}% + {% + \DTLifnull{\Parent}% + {% + \datagidx@doifdisplayed + {% + \settowidth{\dimen@}{\DTLgidxNameFont{\DTLgidxNameCase{\Name}}}% + \ifdim\dimen@>\datagidxnamewidth\relax + \datagidxnamewidth=\dimen@\relax + \fi + }% + }% + {}% + }% + \settowidth{\dimen@}{\DTLgidxPostName}% + \addtolength{\datagidxnamewidth}{\dimen@}% + \setlength{\datagidxdescwidth}{\linewidth}% + \addtolength{\datagidxdescwidth}{-\datagidxnamewidth}% + \ifdim\datagidxsymbolwidth>0pt\relax + \addtolength{\datagidxdescwidth}{-\datagidxsymbolwidth}% + \settowidth{\dimen@}{\DTLgidxSymDescSep}% + \addtolength{\datagidxdescwidth}{-\dimen@}% + \fi + \ifdim\datagidxlocationwidth>0pt\relax + \addtolength{\datagidxdescwidth}{-\datagidxlocationwidth}% + \settowidth{\dimen@}{\DTLgidxPreLocation}% + \addtolength{\datagidxdescwidth}{-\dimen@}% + \fi +% \end{macrocode} +% Has the symbol width been set? +% \begin{macrocode} + \ifdim\datagidxsymbolwidth>0pt\relax +% \end{macrocode} +% Yes, symbol width has been set. +% Has the location width been set? +% \begin{macrocode} + \ifdim\datagidxlocationwidth>0pt\relax +% \end{macrocode} +% Both symbol and location widths have been set. +% \begin{macrocode} + \if@datagidxsymbolleft +% \end{macrocode} +% Symbol is on the left. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \end{minipage}% + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + }% + \else +% \end{macrocode} +% Symbol is on the right. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \end{minipage}% + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + }% + \fi + \else +% \end{macrocode} +% Location width hasn't been set. (Only symbol width has been set.) +% \begin{macrocode} + \if@datagidxsymbolleft + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + }% + \else +% \end{macrocode} +% Symbol is on the right. +% This combination may look weird. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \let\DTLgidxSymDescSep\@empty + \DTLgidxSymbolDescLeft + \end{minipage}% + \DTLgidxSymDescSep + \begin{minipage}[t]{\datagidxsymbolwidth}% + \datagidxsymalign + \let\DTLgidxSymDescSep\@empty + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescRight + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + }% + \fi + \fi + \else +% \end{macrocode} +% Symbol width hasn't been set. +% Has the location width been set? +% \begin{macrocode} + \ifdim\datagidxlocationwidth>0pt\relax +% \end{macrocode} +% Only location width has been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescription + \end{minipage}% + \DTLgidxPreLocation + \begin{minipage}[t]{\datagidxlocationwidth}% + \datagidxlocalign + \let\DTLgidxPreLocation\@empty + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + }% + \else +% \end{macrocode} +% Neither location nor symbol widths have been set. +% \begin{macrocode} + \def\datagidx@item@body{% + \begin{minipage}[t]{\datagidxdescwidth}% + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + }% + \fi + \fi + }% + \renewcommand*{\datagidxend}{\egroup}% + \renewcommand*{\datagidxgroupsep}{\ifdatagidxshowgroups\indexspace\fi}% + \renewcommand{\datagidxgroupheader}{% + \ifdatagidxshowgroups + \item + \makebox[\linewidth]% + {% + \textbf{\DTLgidxGroupHeaderTitle{\datagidxcurrentgroup}}% + }% + \DTLpar\nobreak\@afterheading + \fi + }% + \renewcommand*{\datagidxitem}{% +% \end{macrocode} +% Is this the start of a new group? +% \begin{macrocode} + \ifdefempty\datagidxprevgroup + {% +% \end{macrocode} +% First item of the list. +% \begin{macrocode} + \datagidxgroupheader + }% + {% +% \end{macrocode} +% Not the first item of the list. Is this item's group the same as +% the last item's group? +% \begin{macrocode} + \ifdefequal\datagidxcurrentgroup\datagidxprevgroup + {% +% \end{macrocode} +% Same, so do nothing. +% \begin{macrocode} + }% + {% +% \end{macrocode} +% Different, so do the separator and the header. +% \begin{macrocode} + \datagidxgroupsep + \datagidxgroupheader + }% + }% + \hangindent0pt\relax + \parindent0pt\relax + \makebox[\datagidxnamewidth][l]% + {% + \datagidxtarget{\Label}% + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostName + }% + }% + \datagidx@item@body + \par + }% + \renewcommand*{\datagidxchildstart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \setlength{\datagidxnamewidth}{0pt}% + \DTLforeach*{\DTLgidxCurrentdb}% + {\Name=Name,\Location=Location,\See=See,\SeeAlso=SeeAlso,% + \Parent=Parent}% + {% + \DTLifnull{\Parent}% + {% + \datagidx@doifdisplayed + {% + \settowidth{\dimen@}% + {% + \DTLgidxChildStyle + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + }% + }% + \ifdim\dimen@>\datagidxnamewidth\relax + \datagidxnamewidth=\dimen@\relax + \fi + }% + }% + {}% + }% + \settowidth{\dimen@}{\DTLgidxChildStyle\DTLgidxPostChildName}% + \addtolength{\datagidxnamewidth}{\dimen@}% + \setlength{\datagidxdescwidth}{\linewidth}% + \addtolength{\datagidxdescwidth}{-\datagidxnamewidth}% + }% + \renewcommand{\datagidxchildend}{\egroup}% + \renewcommand*{\datagidxchilditem}{% + \hangindent0pt\relax + \parindent0pt\relax + \refstepcounter{DTLgidxChildCount}% + \makebox[\datagidxnamewidth][l]% + {% + \datagidxtarget{\Label}% + {% + \DTLgidxChildStyle + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostChildName + }% + }% + }% + \begin{minipage}[t]{\datagidxdescwidth}% + \setlength{\parskip}{0pt plus 0.3pt}% + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \end{minipage}% + \par + }% +} +% \end{macrocode} +%\end{macro} +% +%\subsubsection{gloss} +%\begin{macro}{\datagidx@style@gloss} +% \begin{macrocode} +\newcommand*{\datagidx@style@gloss}{% + \renewcommand*{\datagidxstart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \setlength{\datagidxnamewidth}{0pt}% + \DTLforeach*{\DTLgidxCurrentdb}% + {\Name=Name,\Location=Location,\See=See,\SeeAlso=SeeAlso,% + \Parent=Parent}% + {% + \DTLifnull{\Parent}% + {% + \datagidx@doifdisplayed + {% + \settowidth{\dimen@}{\DTLgidxNameFont{\DTLgidxNameCase{\Name}}}% + \ifdim\dimen@>\datagidxnamewidth\relax + \datagidxnamewidth=\dimen@\relax + \fi + }% + }% + {}% + }% + \settowidth{\dimen@}{\DTLgidxPostName}% + \addtolength{\datagidxnamewidth}{\dimen@}% + \setlength{\datagidxdescwidth}{\linewidth}% + \addtolength{\datagidxdescwidth}{-\datagidxnamewidth}% + }% + \renewcommand*{\datagidxend}{\egroup}% + \renewcommand*{\datagidxgroupsep}{\ifdatagidxshowgroups\indexspace\fi}% + \renewcommand{\datagidxgroupheader}{% + \ifdatagidxshowgroups + \item + \makebox[\linewidth]% + {% + \textbf{\DTLgidxGroupHeaderTitle{\datagidxcurrentgroup}}% + }% + \DTLpar\nobreak\@afterheading + \fi + }% + \renewcommand*{\datagidxitem}{% +% \end{macrocode} +% Is this the start of a new group? +% \begin{macrocode} + \ifdefempty\datagidxprevgroup + {% +% \end{macrocode} +% First item of the list. +% \begin{macrocode} + \datagidxgroupheader + }% + {% +% \end{macrocode} +% Not the first item of the list. Is this item's group the same as +% the last item's group? +% \begin{macrocode} + \ifdefequal\datagidxcurrentgroup\datagidxprevgroup + {% +% \end{macrocode} +% Same, so do nothing. +% \begin{macrocode} + }% + {% +% \end{macrocode} +% Different, so do the separator and the header. +% \begin{macrocode} + \datagidxgroupsep + \datagidxgroupheader + }% + }% + \hangindent0pt\relax + \parindent0pt\relax + \makebox[\datagidxnamewidth][l]% + {% + \datagidxtarget{\Label}% + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostName + }% + }% + \begin{minipage}[t]{\datagidxdescwidth}% + \setlength{\parskip}{0pt plus 0.3pt}% + \@tempswatrue + \ifdefempty{\Description}% + {% + \ifdefempty{\Symbol}% + {% + \ifdefempty{\Location}{\@tempswafalse}{}% + }% + {}% + }% + {}% + \if@tempswa + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation +% \end{macrocode} +%\changes{2.14}{2013-06-28}{removed spurious see also line} +% \begin{macrocode} + \else + \mbox{}% + \fi + \DTLgidxChildrenSeeAlso + \end{minipage}% + \par + }% + \renewcommand*{\datagidxchildstart}% + {% + \bgroup + \def\datagidx@childsep{}% + \setcounter{DTLgidxChildCount}{0}% + }% + \renewcommand{\datagidxchildend}{\DTLgidxPostChild\egroup}% + \renewcommand*{\datagidxchilditem}{% + \datagidx@childsep + \refstepcounter{DTLgidxChildCount}% + \datagidxtarget{\Label}% + {% + \DTLgidxChildStyle + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostChildName + }% + }% + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + \let\datagidx@childsep\DTLgidxChildSep + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxChildSep} +% Separator between child entries for gloss style. +% \begin{macrocode} +\newcommand*{\DTLgidxChildSep}{ } +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxPostChild} +%What to put at the end of child entries for gloss style. +% \begin{macrocode} +\newcommand*{\DTLgidxPostChild}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxDictHead} +% Group header for dict style. +% \begin{macrocode} +\ifdef\chapter +{% + \newcommand\DTLgidxDictHead{% + \chapter{\DTLgidxGroupHeaderTitle{\datagidxcurrentgroup}}% + }% +}% +{% + \newcommand\DTLgidxDictHead{% + \section{\DTLgidxGroupHeaderTitle{\datagidxcurrentgroup}}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxCategoryNameFont} +% Font used for `category' entries with `dict' style. +% \begin{macrocode} +\newcommand*{\DTLgidxCategoryNameFont}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxCategorySep} +% Separator used with `dict' style. +% \begin{macrocode} +\newcommand*{\DTLgidxCategorySep}{\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSubCategorySep} +% Separator used with `dict' style. +% \begin{macrocode} +\newcommand*{\DTLgidxSubCategorySep}{\space} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxdictindent} +% Indent used by `dict' style. +% \begin{macrocode} +\newcommand*{\datagidxdictindent}{1em} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxDictPostItem} +% What to do at the end of each item in the `dict' style. +% \begin{macrocode} +\newcommand{\DTLgidxDictPostItem}{\par} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@style@dict} +% Dictionary style. This assumes a hierarchical structure where the +% top level entries have a name. The next level is used to indicate +% a category, such as ``adjective'' or ``noun''. If there is only +% one meaning this level also has a description. If there is more +% than one meaning, each meaning should be a child of the category +% entry. Only third level entries are numbered. The "child" key is +% ignored in this style. The symbol is ignored. The location and +% symbols widths are also ignored. +% \begin{macrocode} +\newcommand*{\datagidx@style@dict}{% + \renewcommand*{\datagidxstart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \dimen@=\linewidth + \advance\dimen@ by -\datagidxdictindent\relax + \dtl@tmplength=\datagidxdictindent\relax + \xdef\datagidxdictparshape{% + \noexpand\parshape=2 0pt \the\linewidth\space + \the\dtl@tmplength\space \the\dimen@\relax + }% + \datagidx@level=1\relax +% \end{macrocode} +% Index columns are usually too narrow for fully justified text. +% \begin{macrocode} + \raggedright + }% + \renewcommand*{\datagidxend}{\egroup}% + \renewcommand*{\datagidxgroupsep}{}% + \renewcommand{\datagidxgroupheader}{% + \ifdatagidxshowgroups + \datagidxend + \datagidx@postend + \DTLgidxDictHead + \datagidx@prestart + \datagidxstart + \fi + }% + \renewcommand*{\datagidxitem}{% +% \end{macrocode} +% Is this the start of a new group? +% \begin{macrocode} + \ifdefempty\datagidxprevgroup + {% +% \end{macrocode} +% First item of the list. +% \begin{macrocode} + \datagidxgroupheader + }% + {% +% \end{macrocode} +% Not the first item of the list. Is this item's group the same as +% the last item's group? +% \begin{macrocode} + \ifdefequal\datagidxcurrentgroup\datagidxprevgroup + {% +% \end{macrocode} +% Same, so do nothing. +% \begin{macrocode} + }% + {% +% \end{macrocode} +% Different, so do the separator and the header. +% \begin{macrocode} + \datagidxgroupsep + \datagidxgroupheader + }% + }% +% \end{macrocode} +% Now get on with this item. +% \begin{macrocode} + \datagidxdictparshape + \datagidxtarget{\Label}% + {% + \DTLgidxNameFont{\DTLgidxNameCase{\Name}}% + }% + \DTLgidxPostName +% \end{macrocode} +% Initialise category separator to do nothing. +% \begin{macrocode} + \let\datagidx@catsep\@empty + \let\datagidx@subcatsep\@empty + \DTLgidxSymbolDescription +% \end{macrocode} +% No location list. +% \begin{macrocode} + \DTLgidxChildrenSeeAlso + \DTLgidxDictPostItem + }% + \renewcommand*{\datagidxchildstart}% + {% + \bgroup + }% + \renewcommand*{\datagidxchildend}{\egroup}% + \renewcommand*{\datagidxchilditem}{% +% \end{macrocode} +% Which level are we on? +% \begin{macrocode} + \ifnum\datagidx@level=2\relax +% \end{macrocode} +% Category entry +% \begin{macrocode} + \datagidx@catsep + \let\datagidx@catsep\DTLgidxCategorySep + \let\datagidx@subcapsep\@empty + \datagidxtarget{\Label}% + {% + \DTLgidxChildStyle + {% + \DTLgidxCategoryNameFont{\DTLgidxNameCase{\Name}}% + \DTLgidxPostChildName + }% + }% + \setcounter{DTLgidxChildCount}{0}% + \else +% \end{macrocode} +% Sub Category entry +% \begin{macrocode} + \datagidx@subcatsep + \let\datagidx@subcatsep\DTLgidxSubCategorySep + \refstepcounter{DTLgidxChildCount}% + \DTLgidxChildCountLabel + \DTLgidxPostChildName + \fi + \DTLgidxSymbolDescription + \DTLgidxDoSeeOrLocation + \DTLgidxChildrenSeeAlso + }% + \renewcommand*{\datagidxseealsostart}% + {% + \bgroup + \setlength{\parindent}{0pt}% + \setlength{\parskip}{0pt plus 0.3pt}% + \setlength{\dimen@}{\datagidxindent}% + \advance\datagidx@level by 1\relax + \multiply\dimen@ by \datagidx@level\relax + \@idxitem\hspace*{\dimen@}% + }% + \renewcommand{\datagidxseealsoend}{\egroup}% +} +% \end{macrocode} +%\end{macro} +% +%\subsection{Location Lists} +%\begin{macro}{\dtldofirstlocation} +% Only display the first location in the list. +% \begin{macrocode} +\newcommand*{\dtldofirstlocation}{% + \@for\dtl@thisloc:=\Location\do{% + \ifdefempty\dtl@thisloc + {}% + {% + \expandafter\datagidx@getlocation\dtl@thisloc + \datagidxlink{\datagidx@current@target}% + {% + \datagidx@formatlocation + \datagidx@current@format\datagidx@current@locationstring + }% +% \end{macrocode} +% Only interested in the first item, so break out of loop. +% \begin{macrocode} + \@endfortrue + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@formatlocation} +% \begin{macrocode} +\newcommand*{\datagidx@formatlocation}[2]{% + \ifdefempty{#1}% + {#2}% + {% + \ifcsdef{#1}% + {% + \csuse{#1}{#2}% + }% + {% + \PackageWarning{datagidx}{Unknown format `#1'}% + #2% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtldolocationlist} +% Display the location list. +% \begin{macrocode} +\newcommand*{\dtldolocationlist}{% + \DTLifnull{\Location}% + {}% + {% + \def\datagidx@prev@location{-1}% + \def\datagidx@prev@locationstring{}% + \def\datagidx@prev@format{}% + \def\datagidx@prev@locationformat{}% + \def\datagidx@prev@prefix{}% + \def\datagidx@prev@target{}% + \def\datagidx@location@sep{}% + \def\datagidx@location@start{-1}% + \expandafter\forcsvlist\expandafter\datagidx@parse@location + \expandafter{\Location}% + \do@prevlocation % tidy up loose ends + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\if@dtl@sequential} +% Conditional to keep track of sequences. +% \begin{macrocode} +\newif\if@dtl@sequential +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidx@getlocdo} +% Handler for \cs{datagidx@docomplist} +% \begin{macrocode} +\newcommand*\datagidx@getlocdo[1]{% + \ifdefempty\datagidx@current@location + {}% + {% + \eappto\datagidx@current@prefix{% + \datagidx@current@location\datagidx@compositor + }% + }% + \def\datagidx@current@location{#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@getlocation} +% Get the location and store in \cs{current@location}: +% \begin{macrocode} +\def\datagidx@getlocation[#1]#2#3{% +% \end{macrocode} +% Store the original value. +% \begin{macrocode} + \def\datagidx@current@locationstring{#2}% +% \end{macrocode} +% \begin{macrocode} + \bgroup + \datagidx@escapelocationformat + \xdef\datagidx@current@locationformat{#2}% + \datagidx@clearlocationformat + \xdef\datagidx@current@location{#2}% + \egroup +% \end{macrocode} +% If the location contains a compositor, we need to get the final +% element and store the rest as a prefix: +% \begin{macrocode} + \let\datagidx@list\datagidx@current@location + \def\datagidx@current@prefix{}% + \def\datagidx@current@location{}% + \let\do\datagidx@getlocdo + \expandafter\datagidx@docomplist + \expandafter{\datagidx@list}% +% \end{macrocode} +% Store the format: +% \begin{macrocode} + \def\datagidx@current@format{#1}% +% \end{macrocode} +% Store the target: +% \begin{macrocode} + \def\datagidx@current@target{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@parse@location} +% Parses the location list (given in the argument). +% \begin{macrocode} +\newcommand*{\datagidx@parse@location}[1]{% +% \end{macrocode} +% Parse location format. +% \begin{macrocode} + \datagidx@getlocation#1\relax +% \end{macrocode} +% If this is the same as the previous location, do nothing. +% \begin{macrocode} + \ifdefequal{\datagidx@prev@locationstring}{\datagidx@current@locationstring}% + {% +% \end{macrocode} +% If the format is different, let the non-empty format over-ride +% the empty format. +%\changes{2.21}{2014-03-08}{replaced \cs{ifstrequal} with +%\cs{ifdefequal}} +% \begin{macrocode} + \ifdefequal{\datagidx@prev@format}{\datagidx@current@format}% + {% + }% + {% + \ifdefempty{\datagidx@current@format}% + {% +% \end{macrocode} +% Current format is empty, so keep previous unchanged. +% \begin{macrocode} + }% + {% + \ifdefempty{\datagidx@prev@format}% + {% +% \end{macrocode} +% Previous format is empty, so update. +% \begin{macrocode} + \let\datagidx@prev@format\datagidx@current@format + }% + {% + \PackageWarning{datagidx}% + {% + Conflicting location formats `\datagidx@prev@format' and + `\datagidx@current@format' for location `\datagidx@current@location'% + }% + }% + }% + }% + }% + {% + \@datagidx@parse@location + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@datagidx@parse@location} +% \begin{macrocode} +\newcommand*{\@datagidx@parse@location}{% +% \end{macrocode} +% Check if we have a sequence. +% \begin{macrocode} + \@dtl@sequentialtrue +% \end{macrocode} +% A change in font format breaks the sequence. +% \begin{macrocode} + \ifdefequal{\datagidx@prev@format}{\datagidx@current@format}% + {% +% \end{macrocode} +% A change in location format breaks the sequence. +% \begin{macrocode} + \ifdefequal{\datagidx@prev@locationformat}{\datagidx@current@locationformat}% + {% +% \end{macrocode} +% A change in prefix breaks the sequence. +% \begin{macrocode} + \ifdefequal{\datagidx@prev@prefix}{\datagidx@current@prefix}% + {% + }% + {% +% \end{macrocode} +% Prefixes are different, so not a sequence. +% \begin{macrocode} + \@dtl@sequentialfalse + }% + }% + {% +% \end{macrocode} +% Formats are different, so not a sequence. +% \begin{macrocode} + \@dtl@sequentialfalse + }% + }% + {% +% \end{macrocode} +% Formats are different, so not a sequence. +% \begin{macrocode} + \@dtl@sequentialfalse + }% + \if@dtl@sequential +% \end{macrocode} +% Is this location one more than the previous location? +% \begin{macrocode} + \ifnumequal{\datagidx@prev@location+1}{\datagidx@current@location}% + {% +% \end{macrocode} +% It is one more than previous value. +% Is this location the same type as the previous location? +% \begin{macrocode} + \ifdefequal + \datagidx@current@locationformat + \datagidx@prev@locationformat + {% +% \end{macrocode} +% They are the same, so we have a sequence. +% \begin{macrocode} + \@dtl@sequentialtrue + }% + {% +% \end{macrocode} +% They aren't the same, so we don't have a sequence. +% \begin{macrocode} + \@dtl@sequentialfalse + }% + }% + {% + \@dtl@sequentialfalse + }% + \fi +% \end{macrocode} +% Has the sequence flag been set? +% \begin{macrocode} + \if@dtl@sequential +% \end{macrocode} +% Yes, we have a sequence. +% Has the start of the sequence been set? +% \begin{macrocode} + \ifnumequal{\datagidx@location@start}{-1}% + {% +% \end{macrocode} +% No it hasn't, so set it +% \begin{macrocode} + \let\datagidx@location@start\datagidx@prev@location + \let\datagidx@location@startval\datagidx@prev@locationstring + \let\datagidx@location@format\datagidx@prev@format + \let\datagidx@location@target\datagidx@prev@target + }% + {% + }% + \else +% \end{macrocode} +% We don't have a sequence, so do the previous location. +% \begin{macrocode} + \do@prevlocation + \fi +% \end{macrocode} +% Update previous location macros to this location. +% \begin{macrocode} + \let\datagidx@prev@location\datagidx@current@location + \let\datagidx@prev@format\datagidx@current@format + \let\datagidx@prev@prefix\datagidx@current@prefix + \let\datagidx@prev@locationformat\datagidx@current@locationformat + \let\datagidx@prev@locationstring\datagidx@current@locationstring + \let\datagidx@prev@target\datagidx@current@target +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxLocationSep} +% Separator between locations. +% \begin{macrocode} +\newcommand*{\DTLgidxLocationSep}{, } +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgidxLocationF} +% How to format a location list consisting of only two locations. +% \begin{macrocode} +\newcommand*{\DTLgidxLocationF}[2]{% + #1\DTLgidxLocationSep#2% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgidxLocationFF} +% How to format a location list consisting of three or more locations. +% \begin{macrocode} +\newcommand*{\DTLgidxLocationFF}[2]{% + #1--#2% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\do@prevlocation} +% Do the previous location in the current list. +% \begin{macrocode} +\newcommand*{\do@prevlocation}{% +% \end{macrocode} +% Have we come to the end of a sequence? +% \begin{macrocode} + \ifnumequal{\datagidx@location@start}{-1}% + {% +% \end{macrocode} +% Not the end of a sequence. +% \begin{macrocode} + \ifdefempty{\datagidx@prev@locationstring}% + {}% + {% + \datagidx@location@sep + \datagidxlink{\datagidx@prev@target}% + {% + \datagidx@formatlocation + \datagidx@prev@format\datagidx@prev@locationstring + }% + \def\datagidx@location@sep{\DTLgidxLocationSep}% + }% + }% + {% +% \end{macrocode} +% At the end of a sequence. +% \begin{macrocode} + \datagidx@location@sep + \do@locrange + \def\datagidx@location@sep{\DTLgidxLocationSep}% + \def\datagidx@location@start{-1}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\do@locrange} +% Format the location range. +% \begin{macrocode} +\newcommand*{\do@locrange}{% +% \end{macrocode} +% Are the start and end locations 2 or more apart? +% \begin{macrocode} + \ifnumgreater{\datagidx@prev@location}{\datagidx@location@start+1}% + {% +% \end{macrocode} +% Yes, they are, so form a range: +% \begin{macrocode} + \DTLgidxLocationFF + {% + \datagidxlink{\datagidx@location@target}% + {% + \datagidx@formatlocation + \datagidx@location@format\datagidx@location@startval + }% + }% + {% + \datagidxlink{\datagidx@prev@target}% + {% + \datagidx@formatlocation + \datagidx@prev@format\datagidx@prev@locationstring + }% + }% + }% + {% +% \end{macrocode} +% No, they aren't so don't form a range: +%\changes{2.15}{2013-07-10}{removed spurious space} +% \begin{macrocode} + \DTLgidxLocationF + {% + \datagidxlink{\datagidx@location@target}% + {% + \datagidx@formatlocation + \datagidx@location@format\datagidx@location@startval + }% + }% + {% + \datagidxlink{\datagidx@prev@target}% + {% + \datagidx@formatlocation + \datagidx@prev@format\datagidx@prev@locationstring + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\section{Defining New Glossary/Index Databases} +% +%\begin{macro}{\datagidx@defaultdatabase} +% The default database to which terms should be added. +% \begin{macrocode} +\newcommand*{\datagidx@defaultdatabase}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSetDefaultDB} +% Allow user to set the default database +% \begin{macrocode} +\newcommand*{\DTLgidxSetDefaultDB}[1]{% + \renewcommand*{\datagidx@defaultdatabase}{#1}% +} +% \end{macrocode} +%\end{macro} +% +%Define keys for \cs{newgidx}: +% \begin{macrocode} +\define@key{newgloss}{heading}{\renewcommand*{\datagidx@heading}{#1}} +\define@key{newgloss}{postheading}{% + \renewcommand*{\datagidx@postheading}{#1}% +} +% \end{macrocode} +%\begin{macro}{\ifdatagidxbalance} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newif\ifdatagidxbalance +\datagidxbalancetrue +% \end{macrocode} +%\end{macro} +% \begin{macrocode} +\define@choicekey{newgloss}{balance}[\val\nr]{true,false}[true]{% + \ifcase\nr\relax + \renewcommand*{\datagidx@multicols}{multicols}% + \datagidxbalancetrue + \or + \renewcommand*{\datagidx@multicols}{multicols*}% + \datagidxbalancefalse + \fi +} +\define@key{newgloss}{sort}{\renewcommand*{\datagidx@sort}{#1}} +% \end{macrocode} +% Default style is `index': +% \begin{macrocode} +\newcommand*{\datagidx@style}{index} +\define@key{newgloss}{style}{\renewcommand*{\datagidx@style}{#1}} +% \end{macrocode} +% Define conditional to determine whether or not to show group +% headers and do sep. (Default is false.) +%\begin{macro}{\ifdatagidxshowgroups} +% \begin{macrocode} +\newif\ifdatagidxshowgroups +\newcommand*{\datagidx@showgroups}{false} +% \end{macrocode} +%\end{macro} +% \begin{macrocode} +\define@choicekey{newgloss}{showgroups}{true,false}[true]% +{% + \renewcommand{\datagidx@showgroups}{#1}% +}% +% \end{macrocode} +% +%\begin{macro}{\newgidx} +%\begin{definition} +% \cs{newgloss}\oarg{options}\marg{database name}\marg{title} +%\end{definition} +% Define \cs{newgidx} if it hasn't already been defined by the +% `highopt' optimize setting. +% \begin{macrocode} +\ifundef\newgidx +{% + \newcommand*{\newgidx}{\datagidx@newgidx} +}% +{} +% \end{macrocode} +% May only be used in the preamble (otherwise the entries will be +% undefined when their locations are read from the aux file). +% \begin{macrocode} +\@onlypreamble\newgidx +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@highopt@newgidx} +% The behaviour of \cs{newgidx} when the `highopt' optimize option has +% been set. +% \begin{macrocode} +\newcommand*{\datagidx@highopt@newgidx}[3][]{% +% \end{macrocode} +% Get the file name: +% \begin{macrocode} + \edef\datagidx@indexfilename{\datagidxhighoptfilename{#2}}% +% \end{macrocode} +% Has the file been created? +% \begin{macrocode} + \IfFileExists{\datagidx@indexfilename}% + {% +% \end{macrocode} +% File does exists. Load it. +% \begin{macrocode} + \input{\datagidx@indexfilename}% +% \end{macrocode} +% Update the `datagidx' database. +% \begin{macrocode} + \bgroup + \setkeys{newgloss}{#1}% + \datagidx@newgidx@update{#2}{#3}% + \egroup + }% + {% +% \end{macrocode} +% File doesn't exist. Behave as normal. +% \begin{macrocode} + \datagidx@newgidx[#1]{#2}{#3}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\loadgidx} +%\begin{definition} +%\cs{loadgidx}\oarg{options}\marg{filename}\marg{title} +%\end{definition} +%\changes{2.15}{2013-07-10}{new} +% Loads a datagidx database. +% \begin{macrocode} +\newcommand*{\loadgidx}[3][]{% +% \end{macrocode} +% Load database: +% \begin{macrocode} + \input{#2}% +% \end{macrocode} +% Update the `datagidx' database. (Assume database is already +% sorted.) +% \begin{macrocode} + \bgroup + \setkeys{newgloss}{sort={},#1}% + \expandafter\datagidx@newgidx@update\expandafter + {\dtllastloadeddb}{#3}% + \egroup +% \end{macrocode} +% Set this as the default database: +% \begin{macrocode} + \edef\datagidx@defaultdatabase{\dtllastloadeddb}% +% \end{macrocode} +% Assign labels to this database. +% \begin{macrocode} + \dtlforcolumn{\Label}{\dtllastloadeddb}{Label}% + {% + \csxdef{datagidxentry@\Label}{\dtllastloadeddb}% + }% +} +% \end{macrocode} +% May only be used in the preamble (otherwise the entries will be +% undefined when their locations are read from the aux file). +% \begin{macrocode} +\@onlypreamble\loadgidx +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@newgidx} +% The normal behaviour of \cs{newgidx} +% \begin{macrocode} +\newcommand*{\datagidx@newgidx}[3][]{% +\bgroup + \setkeys{newgloss}{#1}% +% \end{macrocode} +% If no default database has been identified, set the default to +% this database. +% \begin{macrocode} + \ifdefempty{\datagidx@defaultdatabase}% + {\xdef\datagidx@defaultdatabase{#2}}% + {}% + \DTLgnewdb{#2}% + \DTLaddcolumn{#2}{Label}% + \DTLaddcolumn{#2}{Location}% + \DTLaddcolumn{#2}{CurrentLocation}% + \DTLaddcolumn{#2}{FirstId}% + \DTLaddcolumn{#2}{Name}% + \DTLaddcolumn{#2}{Text}% + \DTLaddcolumn{#2}{Parent}% + \DTLaddcolumn{#2}{Child}% + \DTLaddcolumn{#2}{Description}% + \DTLaddcolumn{#2}{Used}% + \DTLaddcolumn{#2}{Symbol}% + \DTLaddcolumn{#2}{Long}% + \DTLaddcolumn{#2}{Short}% + \DTLaddcolumn{#2}{See}% + \DTLaddcolumn{#2}{SeeAlso}% + \datagidx@newgidx@update{#2}{#3}% +\egroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@newgidx@update} +% Update the `datagidx' database. +% \begin{macrocode} +\newcommand*{\datagidx@newgidx@update}[2]{% + \DTLnewrow{datagidx}% + \DTLnewdbentry{datagidx}{Glossary}{#1}% + \DTLnewdbentry{datagidx}{Title}{#2}% + {% + \dtlexpandnewvalue + \DTLnewdbentry{datagidx}{Heading}{\expandonce\datagidx@heading}% + \DTLnewdbentry{datagidx}{PostHeading}{\expandonce\datagidx@postheading}% + \DTLnewdbentry{datagidx}{MultiCols}{\expandonce\datagidx@multicols}% + \DTLnewdbentry{datagidx}{Sort}{\expandonce\datagidx@sort}% + \DTLnewdbentry{datagidx}{Style}{\expandonce\datagidx@style}% + \DTLnewdbentry{datagidx}{ShowGroups}{\expandonce\datagidx@showgroups}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\section{Defining New Terms} +% +%\subsection{Options} +% Define some keys for \cs{newterm}: +%\begin{macro}{\newterm@label} +% \begin{macrocode} +\newcommand*{\newterm@label}{} +\define@key{newterm}{label}{\renewcommand*{\newterm@label}{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@parent} +% \begin{macrocode} +\newcommand*{\newterm@parent}{} +\define@key{newterm}{parent}{\renewcommand*{\newterm@parent}{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@text} +% \begin{macrocode} +\newcommand*{\newterm@text}{} +\define@key{newterm}{text}{\renewcommand*{\newterm@text}{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@description} +% \begin{macrocode} +\newcommand*{\newterm@description}{} +\define@key{newterm}{description}{% + \renewcommand*{\newterm@description}{#1}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@plural} +% \begin{macrocode} +\define@key{newterm}{plural}{\def\newterm@plural{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@sort} +% \begin{macrocode} +\newcommand*{\newterm@sort}{} +\define@key{newterm}{sort}{\renewcommand*{\newterm@sort}{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@symbol} +% \begin{macrocode} +\newcommand*{\newterm@symbol}{} +\define@key{newterm}{symbol}{\renewcommand*{\newterm@symbol}{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@database} +% \begin{macrocode} +\newcommand*{\newterm@database}{} +\define@key{newterm}{database}{\renewcommand*{\newterm@database}{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@long} +% \begin{macrocode} +\newcommand*{\newterm@long}{} +\define@key{newterm}{long}{% + \renewcommand*{\newterm@long}{#1}% + \def\newterm@longplural{#1s}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@short} +% \begin{macrocode} +\newcommand*{\newterm@short}{} +\define@key{newterm}{short}{% + \renewcommand*{\newterm@short}{#1}% + \def\newterm@shortplural{#1s}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@longplural} +% \begin{macrocode} +\define@key{newterm}{longplural}{% + \def\newterm@longplural{#1}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newterm@shortplural} +% \begin{macrocode} +\define@key{newterm}{shortplural}{% + \def\newterm@shortplural{#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\newterm@see} +% ``see'' should not be used with a location list. If you have a +% location list and want a cross-reference use ``see also'' instead. +% \begin{macrocode} +\newcommand*{\newterm@see}{} +\define@key{newterm}{see}{% + \renewcommand*{\newterm@see}{#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\newterm@seealso} +% ``see also'' should be used with a location list (or with child +% entries with location lists). If an entry has no location list and +% not child entries use ``see'' instead. +% \begin{macrocode} +\newcommand*{\newterm@seealso}{} +\define@key{newterm}{seealso}{% + \renewcommand*{\newterm@seealso}{#1}% +} +% \end{macrocode} +%\end{macro} +% +%\subsection{New Terms} +% +%\begin{macro}{\newterm@defaultshook} +% \begin{macrocode} +\newcommand*{\newterm@defaultshook}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\newterm@extrafields} +% \begin{macrocode} +\newcommand*{\newterm@extrafields}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxAssignList} +% Assignment list used by \ics{printterms} +% \begin{macrocode} +\newcommand*{\DTLgidxAssignList}{% + \Name=Name,\Description=Description,\Used=Used,\Symbol=Symbol,% + \Long=Long,\Short=Short,\LongPlural=LongPlural,\ShortPlural=ShortPlural,% + \Location=Location,\See=See,\SeeAlso=SeeAlso,% + \Text=Text,\Plural=Plural,\CurrentLocation=CurrentLocation,% + \Label=Label,\Parent=Parent,\Children=Child,\FirstId=FirstId,\Sort=Sort% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxtermkeys} +% Keys defined for \cs{newterm} corresponding to fields (``name'' is +% added for convenience). +% \begin{macrocode} +\newcommand*{\datagidxtermkeys}{% + name,description,symbol,long,short,see,seealso,text,plural,% + label,parent,sort% +} +% \end{macrocode} +%\end{macro} +% Access keys corresponding to given fields +% \begin{macrocode} +\newcommand*\@datagidx@fieldkey@Name{name}% +\newcommand*\@datagidx@fieldkey@Description{description}% +\newcommand*\@datagidx@fieldkey@Symbol{symbol}% +\newcommand*\@datagidx@fieldkey@Long{long}% +\newcommand*\@datagidx@fieldkey@Short{short}% +\newcommand*\@datagidx@fieldkey@See{see}% +\newcommand*\@datagidx@fieldkey@SeeAlso{seealso}% +\newcommand*\@datagidx@fieldkey@Text{text}% +\newcommand*\@datagidx@fieldkey@Plural{plural}% +\newcommand*\@datagidx@fieldkey@Label{label}% +\newcommand*\@datagidx@fieldkey@Parent{parent}% +\newcommand*\@datagidx@fieldkey@Sort{sort}% +% \end{macrocode} +% +%\begin{macro}{\newtermaddfield} +%\begin{definition} +%\cs{newtermaddfield}\oarg{db list}\marg{column key}\marg{new term +%key}\marg{default value} +%\end{definition} +% The default value may contain \ics{field}\marg{key} to get the +% value of another field. +% \begin{macrocode} +\newcommand*{\newtermaddfield}[4][]{% +% \end{macrocode} +% If optional argument not specified, iterate over all defined +% glossaries/indices +% \begin{macrocode} + \ifstrempty{#1}% + {% + \dtlforcolumn{\datagidx@thisidx}{datagidx}{Glossary}% + {% + \DTLaddcolumn{\datagidx@thisidx}{#2}% + }% + }% + {% + \@for\datagidx@thisidx:=#1\do + {% + \DTLaddcolumn{\datagidx@thisidx}{#2}% + }% + }% + \expandafter\gdef\csname newterm@#3\endcsname{}% + \define@key{newterm}{#3}% + {% + \expandafter\def\csname newterm@#3\endcsname{##1}% + }% + \gappto\newterm@defaultshook + {% + \expandafter\protected@edef\csname newterm@#3\endcsname{#4}% + }% + \gappto\newterm@extrafields + {% + \protected@edef\datagidx@value{\csname newterm@#3\endcsname}% + \DTLnewdbentry{\newterm@database}{#2}{\expandonce\datagidx@value}% + }% + \xappto\DTLgidxAssignList + {% + ,\expandafter\noexpand\csname#2\endcsname=#2% + }% + \xappto\datagidxtermkeys{,#3}% + \expandafter\xdef\csname @datagidx@fieldkey@#2\endcsname{#3}% + \xappto\datagidxgetchildfields + {% + \noexpand\dtlgetentryfromcurrentrow + {\expandafter\noexpand\csname#2\endcsname}% + {\noexpand\dtlcolumnindex{\noexpand\DTLgidxCurrentdb}{#2}}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\newtermlabelhook} +% \begin{macrocode} +\newcommand*{\newtermlabelhook}{} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\DTLgidxNoFormat} +% \begin{macrocode} +\newcommand*{\DTLgidxNoFormat}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxGobble} +% \begin{macrocode} +\newcommand*{\DTLgidxGobble}[1]{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxStripBackslash} +% Argument must be a control sequence. This is stringified and the +% first character (The backslash) is removed). +% \begin{macrocode} +\newcommand*{\DTLgidxStripBackslash}[1]{% + \expandafter\@gobble\string#1% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxName} +%\begin{definition} +%\cs{DTLgidxName}\marg{forenames}\marg{surname} +%\end{definition} +% How to format a person's name in the text. +% \begin{macrocode} +\newcommand*{\DTLgidxName}[2]{% + #1\space #2% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxNameNum} +%\begin{definition} +%\cs{DTLgidxNameNum}\marg{n} +%\end{definition} +% The argument \meta{n} should be a number applied to a name +% (e.g.\ \verb*"James "\cs{DTLgidxNameNum}{1}). This is converted to +% a two-digit number for sorting but a Roman numeral for the label +% and in the text. +% \begin{macrocode} +\newcommand*{\DTLgidxNameNum}[1]{\@Roman{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidx@namenum} +% Conversion for sort key. +% \begin{macrocode} +\newcommand*{\datagidx@namenum}[1]{\two@digits{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxPlace} +%\begin{definition} +%\cs{DTLgidxPlace}\marg{country}\marg{town/city} +%\end{definition} +% How to format a place in the text. +% \begin{macrocode} +\newcommand*{\DTLgidxPlace}[2]{% + #2% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSubject} +%\begin{definition} +%\cs{DTLgidxSubject}\marg{main}\marg{category} +%\end{definition} +% How to format a subject in the text. Ignore the main part in the +% text. +% \begin{macrocode} +\newcommand*{\DTLgidxSubject}[2]{% + #2% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxOffice} +%\begin{definition} +%\cs{DTLgidxOffice}\marg{office}\marg{name} +%\end{definition} +% Put the office in parentheses in the document text. +% \begin{macrocode} +\newcommand*{\DTLgidxOffice}[2]{% + #2 (#1)% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxIgnore} +% Show argument in document text, but disregard in the sort and +% label. +% \begin{macrocode} +\newcommand*{\DTLgidxIgnore}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxMac} +%\begin{definition} +%\cs{DTLgidxMac}\marg{text} +%\end{definition} +% In the document, just does \meta{text}, but gets converted to +% ``Mac'' in the sort key. (Unless overridden by the user.) +% \begin{macrocode} +\newcommand*{\DTLgidxMac}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@mac} +%\cs{DTLgidxMac} gets temporarily redefined to \cs{datagidx@mac} +%when construction the sort key. +% \begin{macrocode} +\newcommand*{\datagidx@mac}[1]{Mac} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxSaint} +%\begin{definition} +%\cs{DTLgidxSaint}\marg{text} +%\end{definition} +% In the document, just does \meta{text}, but gets converted to +% ``Saint'' in the sort key. (Unless overridden by the user.) +% \begin{macrocode} +\newcommand*{\DTLgidxSaint}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@saint} +%\cs{DTLgidxMac} gets temporarily redefined to \cs{datagidx@saint} +%when construction the sort key. +% \begin{macrocode} +\newcommand*{\datagidx@saint}[1]{Saint} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxRank} +%\begin{definition} +%\cs{DTLgidxRank}\marg{rank}\marg{forenames} +%\end{definition} +% A person's title, rank or sanctity should be ignored when sorting. +% \begin{macrocode} +\newcommand*{\DTLgidxRank}[2]{#1~#2} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@rank} +%\cs{DTLidxRank} gets temporarily redefined to \cs{datagidx@rank} +%when constructing the sort key. An extra dot is added to the end to +%ensure names without a rank are sorted before identical names with +%a rank. +% \begin{macrocode} +\newcommand*{\datagidx@rank}[2]{#2.} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxParticle} +%\begin{definition} +%\cs{DTLgidxParticle}\marg{particle}\marg{surname} +%\end{definition} +% A particle such as ``of'', ``de'' or ``von'' should be ignored when sorting. +% \begin{macrocode} +\newcommand*{\DTLgidxParticle}[2]{#1~#2} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@particle} +%\cs{DTLidxParticle} gets temporarily redefined to \cs{datagidx@particle} +%when constructing the sort key. An extra dot is added to the end to +%ensure names without a particle are sorted before identical names with +%a particle. +% \begin{macrocode} +\newcommand*{\datagidx@particle}[2]{#2.} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@bothoftwo} +% \begin{macrocode} +\newcommand*{\datagidx@bothoftwo}[2]{#1#2} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@person} +% Used when constructing the sort key for a name. +% \begin{macrocode} +\newcommand*{\datagidx@person}[2]{#2\noexpand\datatoolpersoncomma #1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@place} +% Used when constructing the sort key for a place. +% \begin{macrocode} +\newcommand*{\datagidx@place}[2]{#2\noexpand\datatoolplacecomma #1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@subject} +% Used when constructing the sort key for a place. +% \begin{macrocode} +\newcommand*{\datagidx@subject}[2]{#2\noexpand\datatoolsubjectcomma #1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@paren} +% Used when constructing the sort key for a parenthesis. +% \begin{macrocode} +\newcommand*{\datagidx@paren}[1]{\noexpand\datatoolparenstart #1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@invert} +% \begin{macrocode} +\newcommand*{\datagidx@invert}[2]{#2, #1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxParen} +% Parenthetical material. +% \begin{macrocode} +\newcommand*{\DTLgidxParen}[1]{\space(#1)} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxwordifygreek} +% Convert commands like \ics{alpha} into words for indexing and +% labelling purposes. +% \begin{macrocode} +\newcommand*{\datagidxwordifygreek}{% + \def\alpha{alpha}% + \def\beta{beta}% + \def\gamma{gamma}% + \def\delta{delta}% + \def\epsilon{epsilon}% + \def\varepsilon{epsilon}% + \def\zeta{zeta}% + \def\eta{eta}% + \def\theta{theta}% + \def\vartheta{theta}% + \def\iota{iota}% + \def\kappa{kappa}% + \def\lambda{lambda}% + \def\mu{mu}% + \def\nu{nu}% + \def\xi{xi}% + \def\pi{pi}% + \def\varpi{pi}% + \def\rho{rho}% + \def\varrho{rho}% + \def\sigma{sigma}% + \def\varsigma{sigma}% + \def\tau{tau}% + \def\upsilon{upsilon}% + \def\phi{phi}% + \def\varphi{phi}% + \def\chi{chi}% + \def\psi{psi}% + \def\omega{omega}% + \def\Gamma{Gamma}% + \def\Delta{Delta}% + \def\Theta{Theta}% + \def\Lambda{Lambda}% + \def\Xi{Xi}% + \def\Pi{Pi}% + \def\Sigma{Sigma}% + \def\Upsilon{Upsilon}% + \def\Phi{Phi}% + \def\Psi{Psi}% + \def\Omega{Omega}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxextendedtoascii} +% Convert commands like \ics{aa} into the closest ASCII equivalent. +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand{\datagidxextendedtoascii}{% + \def\AE{AE}% + \def\ae{ae}% + \def\OE{OE}% + \def\oe{oe}% + \def\AA{AA}% + \def\aa{aa}% + \def\L{L}% + \def\l{l}% + \def\O{O}% + \def\o{o}% + \def\SS{SS}% + \def\ss{ss}% + \def\th{th}% + \def\TH{TH}% + \def\dh{dh}% + \def\DH{DH}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxconvertchars} +% Convert commands like \cs{\&}. +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\datagidxconvertchars}{% + \let~\space + \ifdef\andname + {% + \let\&\andname + }% + {% + \def\&{\expandafter\@gobble\string\&}% + }% + \def\_{\string_}% + \def\${\string$}% + \def\#{\expandafter\@gobble\string\#}% + \def\%{\expandafter\@gobble\string\%}% + \def\{{\expandafter\@gobble\string\{}% + \def\}{\expandafter\@gobble\string\}}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxstripaccents} +% Strip accents so they don't interfere with the label and sort. +% If you want to write your own comparison handler macro, you'll +% need to redefine this if you want accented letters to be sorted +% differently from the unaccented version. This command should +% only be used within a scope. +% \begin{macrocode} +\newcommand*{\datagidxstripaccents}{% +% \end{macrocode} +% These redefinitions will only work with \cs{edef} or \cs{xdef}: +% \begin{macrocode} + \let\add@accent@\@secondoftwo + \let\@text@composite@x\@secondoftwo + \let\@tabacckludge\@secondoftwo +% \end{macrocode} +% The following are need with \cs{protected@edef} or \cs{protected@xdef}: +% \begin{macrocode} + \expandafter\def\csname \encodingdefault-cmd\endcsname##1##2##3{##3}% + \expandafter\def\csname OT1-cmd\endcsname##1##2##3{##3}% + \expandafter\def\csname T1-cmd\endcsname##1##2##3{##3}% + \expandafter\def\csname PD1-cmd\endcsname##1##2##3{##3}% + \def\IeC##1{\@gobbletwo##1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\newterm} +%\begin{definition} +% \cs{newterm}\oarg{options}{name} +%\end{definition} +% Defaults to normal behaviour. +% \begin{macrocode} +\providecommand{\newterm}{\datagidx@newterm} +% \end{macrocode} +%\end{macro} +% +%May only be used in the preamble. (Terms must be defined before the +%aux file is read.) +% \begin{macrocode} +\@onlypreamble\newterm +% \end{macrocode} +% +%\begin{macro}{\datagidx@setfieldvalues} +% Sets the values for all the field. +% \begin{macrocode} +\newcommand{\datagidx@setfieldvalues}[2]{% +% \end{macrocode} +% Set defaults. +% \begin{macrocode} + \def\newterm@name{#2}% + \renewcommand*\newterm@label{#2}% + \renewcommand*\newterm@text{#2}% + \undef\newterm@plural + \renewcommand*{\newterm@description}{}% + \renewcommand*{\newterm@sort}{#2}% + \renewcommand*{\newterm@symbol}{}% + \let\newterm@database\datagidx@defaultdatabase + \renewcommand*{\newterm@short}{#2}% + \undef\newterm@shortplural + \renewcommand*{\newterm@long}{#2}% + \undef\newterm@longplural + \renewcommand*{\newterm@see}{}% + \renewcommand*{\newterm@seealso}{}% + \renewcommand*{\newterm@parent}{}% +% \end{macrocode} +% Allow hook to access other fields. +% \begin{macrocode} + \let\datagidx@orgfield\field + \def\field##1{\expandafter\noexpand\csname newterm@##1\endcsname}% +% \end{macrocode} +% Hook to make it easier to add extra fields. +% \begin{macrocode} + \newterm@defaultshook + \let\field\datagidx@orgfield +% \end{macrocode} +% Assign values given in optional argument. +% \begin{macrocode} + \setkeys{newterm}{#1}% +% \end{macrocode} +% Temporary redefine commands likely to be contained in the name +% that may interfere with the label and sort. +% \begin{macrocode} + \bgroup +% \end{macrocode} +% Allow users to, say, specify the name as +% \meta{name}\ics{glsadd}\marg{other label} without having to specify +% a separate label. +% \begin{macrocode} + \let\glsadd\@gobble +% \end{macrocode} +% Strip common formatting commands. +% \begin{macrocode} + \let\MakeUppercase\DTLgidxNoFormat + \let\MakeTextUppercase\DTLgidxNoFormat + \let\MakeLowercase\DTLgidxNoFormat + \let\MakeTextLowercase\DTLgidxNoFormat + \let\acronymfont\DTLgidxNoFormat + \let\textrm\DTLgidxNoFormat + \let\texttt\DTLgidxNoFormat + \let\textsf\DTLgidxNoFormat + \let\textsc\DTLgidxNoFormat + \let\textbf\DTLgidxNoFormat + \let\textmd\DTLgidxNoFormat + \let\textit\DTLgidxNoFormat + \let\textsl\DTLgidxNoFormat + \let\emph\DTLgidxNoFormat + \let\textsuperscript\DTLgidxNoFormat +% \end{macrocode} +% Convert character commands like \cs{\&}. +% \begin{macrocode} + \datagidxconvertchars +% \end{macrocode} +% Strip \cs{ensuremath}. +% \begin{macrocode} + \let\ensuremath\DTLgidxNoFormat +% \end{macrocode} +% Ensure that inversions are dealt with for the label. +% \begin{macrocode} + \let\DTLgidxParen\@gobble + \let\DTLgidxName\@secondoftwo + \let\DTLgidxPlace\datagidx@invert + \let\DTLgidxSubject\datagidx@invert + \let\DTLgidxOffice\@secondoftwo + \let\DTLgidxParticle\datagidx@bothoftwo +% \end{macrocode} +% Convert Greek maths (such as \cs{alpha}) to text. +% \begin{macrocode} + \datagidxwordifygreek +% \end{macrocode} +% Strip accent commands so they don't interfere with the label. +% \begin{macrocode} + \datagidxstripaccents + \datagidxextendedtoascii +% \end{macrocode} +% Allow user to hook into this. +% \begin{macrocode} + \newtermlabelhook +% \end{macrocode} +%There shouldn't really be any fragile commands in \verb|#2| but +%using \cs{protected@xdef} to be on the safe side. +% \begin{macrocode} + \protected@xdef\newterm@label{\newterm@label}% +% \end{macrocode} +% These commands behave differently for the sort key: +% \begin{macrocode} + \let\DTLgidxName\datagidx@person + \let\DTLgidxPlace\datagidx@place + \let\DTLgidxSubject\datagidx@subject + \let\DTLgidxOffice\datagidx@person + \let\DTLgidxParen\datagidx@paren + \let\DTLgidxMac\datagidx@mac + \let\DTLgidxSaint\datagidx@saint + \let\DTLgidxIgnore\@gobble + \let\DTLgidxRank\datagidx@rank + \let\DTLgidxParticle\datagidx@particle + \let\DTLgidxNameNum\datagidx@namenum +% \end{macrocode} +%Need to use \cs{protected@xdef} here, which means limited support +%for stripping accents. +% \begin{macrocode} + \protected@xdef\newterm@sort{\newterm@sort}% + \egroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@add@term} +% Add term (once all fields have been set. Argument is the name +% field. +% \begin{macrocode} +\newcommand*{\datagidx@add@term}[1]{% + \global\cslet{datagidxentry@\newterm@label}{\newterm@database}% + \DTLnewrow{\newterm@database}% + \DTLnewdbentry{\newterm@database}{Name}{#1}% + \DTLnewdbentry{\newterm@database}{Used}{0}% + {% + \dtlexpandnewvalue + \DTLnewdbentry{\newterm@database}{Text}{\expandonce\newterm@text}% + \DTLnewdbentry{\newterm@database}{Description}{\expandonce\newterm@description}% + \DTLnewdbentry{\newterm@database}{Label}{\expandonce\newterm@label}% + \DTLnewdbentry{\newterm@database}{Sort}{\expandonce\newterm@sort}% + \DTLnewdbentry{\newterm@database}{Symbol}{\expandonce\newterm@symbol}% + \DTLnewdbentry{\newterm@database}{Short}{\expandonce\newterm@short}% + \DTLnewdbentry{\newterm@database}{Long}{\expandonce\newterm@long}% + \ifundef\newterm@plural + {% + \DTLnewdbentry{\newterm@database}{Plural}{\expandonce\newterm@text s}% + }% + {% + \DTLnewdbentry{\newterm@database}{Plural}{\expandonce\newterm@plural}% + }% + \ifundef\newterm@shortplural + {% + \DTLnewdbentry{\newterm@database}{ShortPlural}{\expandonce\newterm@short s}% + }% + {% + \DTLnewdbentry{\newterm@database}{ShortPlural}{\expandonce\newterm@shortplural}% + }% + \ifundef\newterm@longplural + {% + \DTLnewdbentry{\newterm@database}{LongPlural}{\expandonce\newterm@long s}% + }% + {% + \DTLnewdbentry{\newterm@database}{LongPlural}{\expandonce\newterm@longplural}% + }% + \ifdefempty{\newterm@see}% + {}% + {\DTLnewdbentry{\newterm@database}{See}{\newterm@see}}% + \ifdefempty{\newterm@seealso}% + {}% + {\DTLnewdbentry{\newterm@database}{SeeAlso}{\newterm@seealso}}% +% \end{macrocode} +% Hook to make it easier to add extra fields. +% \begin{macrocode} + \newterm@extrafields +% \end{macrocode} +% Add parent, if supplied. +% \begin{macrocode} + \ifdefempty{\newterm@parent}% + {}% + {% + \iftermexists{\newterm@parent}% + {% + \edef\newterm@parentdatabase{\csuse{datagidxentry@\newterm@parent}}% +% \end{macrocode} +% Parent entry must belong to same database as child entry. +% \begin{macrocode} + \ifthenelse{\equal{\newterm@parentdatabase}{\newterm@database}} + {% + \DTLnewdbentry{\newterm@database}{Parent}{\newterm@parent}% + \datagidx@addchild{\newterm@database}{\newterm@parent}{\newterm@label}% + }% + {% + \PackageError{datagidx}% + {% + Parent entry `\newterm@parent' must belong to the + same database as child entry `\newterm@label'% + }% + {% + Parent entry is in database + `\newterm@parentdatabase' and child entry is in + database `\newterm@database'% + }% + }% + }% + {% + \PackageError{datagidx}% + {% + Can't assign parent to `\newterm@label': + `\newterm@parent' doesn't exist% + }% + {}% + }% + }% + }% +% \end{macrocode} +% Provide user with a means to access the label of the latest defined +% term: +% \begin{macrocode} + \global\let\datagidxlastlabel\newterm@label +% \end{macrocode} +%\changes{2.14}{2013-06-28}{added \cs{postnewtermhook}} +% Allow user to hook in here +% \begin{macrocode} + \postnewtermhook +}% +%\end{macro} +% +%\begin{macro}{\postnewtermhook} +%\changes{2.14}{2013-06-28}{new} +% \begin{macrocode} +\newcommand*{\postnewtermhook}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\newtermfield} +%\changes{2.14}{2013-06-28}{new} +% Expandable access to field name. (No check for existence of the +% field. Uses \sty{etoolbox's} \cs{csuse}, so expands to an empty +% string if the field is undefined.) +% \begin{macrocode} +\newcommand*{\newtermfield}[1]{\csuse{newterm@#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifnewtermfield} +%\changes{2.14}{2013-06-28}{new} +% If the named field (given in first argument) is empty or undefined do third argument, +% otherwise do second argument. +% \begin{macrocode} +\newcommand{\ifnewtermfield}[3]{% + \ifcsdef{newterm@#1} + {% + \ifcsempty{newterm@#1}{#3}{#2}% + }% + {% + #3% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@newterm} +% Normal behaviour for \cs{newterm} +% \begin{macrocode} +\newcommand{\datagidx@newterm}[2][]{% +% \end{macrocode} +% Assign values to all the fields. +% \begin{macrocode} + \datagidx@setfieldvalues{#1}{#2}% +% \end{macrocode} +% Check if database exists. +% \begin{macrocode} + \DTLifdbexists{\newterm@database}% + {% +% \end{macrocode} +% Database exists. Check if term already exists. +% \begin{macrocode} + \iftermexists{\newterm@label}% + {% + \PackageError{datagidx}{Term `\newterm@label' already + exists in database `\newterm@database'}{}% + }% + {% +% \end{macrocode} +% Add this entry to the database. +% \begin{macrocode} + \datagidx@add@term{#2}% + }% + }% + {% +% \end{macrocode} +% Database doesn't exist. +% \begin{macrocode} + \PackageError{datagidx}% + {Glossary/index data base `\newterm@database' doesn't exist}% + {% + You must define the glossary/index data base before you can + add any terms to it.% + }% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidx@highopt@newterm} +% Used when high optimized setting enabled. This setting must be +% switched off if the user wants to modify the database. +% \begin{macrocode} +\newcommand{\datagidx@highopt@newterm}[2][]{% +% \end{macrocode} +% Assign values to all the fields. +% \begin{macrocode} + \datagidx@setfieldvalues{#1}{#2}% +% \end{macrocode} +% Check if database exists. +% \begin{macrocode} + \DTLifdbexists{\newterm@database}% + {% +% \end{macrocode} +% Database exists. If this is the first run, we need to add the term +% as usual, otherwise we just need to define +% \cs{datagidxentry@}\meta{label} +% \begin{macrocode} + \edef\dtl@dogetrow{% + \noexpand\dtlgetrowindex + {\noexpand\dtl@rowidx}% + {\newterm@database}% + {% + \dtlcolumnindex{\newterm@database}{Label}% + }% + {\newterm@label}}% + \dtl@dogetrow + \ifx\dtl@rowidx\dtlnovalue +% \end{macrocode} +% Hasn't been defined so add. +% \begin{macrocode} + \datagidx@add@term{#2}% +% \end{macrocode} +% Database will need to be sorted. +% \begin{macrocode} + \csdef{datagidx@do@highopt@sort@\newterm@database}{\datagidx@sort}% + \else +% \end{macrocode} +% Has been defined, so just define \cs{datagidxentry@}\meta{label} +% and \cs{datagidxlastlabel} +% \begin{macrocode} + \global\cslet{datagidxentry@\newterm@label}{\newterm@database}% + \global\let\datagidxlastlabel\newterm@label + \fi + }% + {% +% \end{macrocode} +% Database doesn't exist. +% \begin{macrocode} + \PackageError{datagidx}% + {Glossary/index data base `\newterm@database' doesn't exist}% + {% + You must define the glossary/index data base before you can + add any terms to it.% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +% +%\begin{macro}{\datagidx@addchild} +% \begin{macrocode} +\newcommand*{\datagidx@addchild}[3]{% + \edef\dtl@dogetrow{% + \noexpand\dtlgetrowforvalue + {#1}% + {% + \dtlcolumnindex{\newterm@database}{Label}% + }% + {#2}}% + \dtl@dogetrow + \dtlgetentryfromcurrentrow + {\datagidx@child}% + {\dtlcolumnindex{#1}{Child}}% + \ifx\datagidx@child\dtlnovalue + \edef\datagidx@child{#3}% + \else + \edef\datagidx@child{\datagidx@child,#3}% + \fi + \edef\do@update{\noexpand\dtlupdateentryincurrentrow + {Child}{\datagidx@child}}% + \do@update + \dtlrecombine +} +% \end{macrocode} +%\end{macro} +%\subsection{Defining Acronyms} +%\begin{macro}{\newacro} +%\begin{definition} +%\cs{newacro}\oarg{options}\marg{short}\marg{long} +%\end{definition} +% Shortcut command for acronyms. +% \begin{macrocode} +\newcommand{\newacro}[3][]{% + \newterm + [% + description={\capitalisewords{#3}},% + short={\acronymfont{#2}},% + long={#3},% + text={\DTLgidxAcrStyle{#3}{\acronymfont{#2}}},% + plural={\DTLgidxAcrStyle{#3s}{\acronymfont{#2s}}},% + sort={#2},% + #1% + ]% + {\MakeTextUppercase{#2}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\acronymfont} +% The font to use for the acronym. +% \begin{macrocode} +\newcommand*{\acronymfont}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgidxAcrStyle} +%\begin{definition} +%\cs{DTLgidxAcrStyle}\marg{long}\marg{short} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLgidxAcrStyle}[2]{#1 (#2)} +% \end{macrocode} +%\end{macro} +% +% +%\section{Conditionals} +% +%\begin{macro}{\iftermexists} +%\begin{definition} +% \cs{iftermexists}\marg{label}\marg{true part}\marg{false part} +%\end{definition} +% Check if term with given label exists. +% \begin{macrocode} +\newcommand{\iftermexists}[3]{% + \ifcsdef{datagidxentry@#1}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidxdb} +%\changes{2.14}{2013-06-28}{new} +% Gets the label of database containing the given entry. No check is +% made for the existence of the entry. Expands to empty if label is +% undefined. +% \begin{macrocode} +\newcommand*{\datagidxdb}[1]{% + \csuse{datagidxentry@#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifentryused} +%\begin{definition} +% \cs{ifentryused}\marg{label}\marg{true part}\marg{false part} +%\end{definition} +% Check if entry with given label has been used. +% \begin{macrocode} +\newcommand*{\ifentryused}[3]{% + \letcs{\newterm@database}{datagidxentry@#1}% +% \end{macrocode} +% \cs{dtlgetrowforvalue} doesn't expand the value when it checks for +% a match, so make sure label is fully expanded. +% \begin{macrocode} + \edef\dtl@dogetrow{% + \noexpand\dtlgetrowforvalue + {\newterm@database}% + {% + \dtlcolumnindex{\newterm@database}{Label}% + }% + {#1}}% + \dtl@dogetrow + \dtlgetentryfromcurrentrow + {\datagidx@value}% + {\dtlcolumnindex{\newterm@database}{Used}}% + \ifnum\datagidx@value=1\relax + #2% + \else + #3% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\section{Unsetting and Resetting} +% +%\begin{macro}{\glsreset} +%\begin{definition} +%\cs{glsunset}\marg{label} +%\end{definition} +% Mark as un-used. +% \begin{macrocode} +\newcommand*{\glsreset}[1]{% +% \end{macrocode} +% Fetch the name of the database with which this entry is +% associated. +% \begin{macrocode} + \letcs{\newterm@database}{datagidxentry@#1}% +% \end{macrocode} +% Get the row associated with this label and make it the current row. +% \begin{macrocode} + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\newterm@database}% + {\dtlcolumnindex{\newterm@database}{Label}}% + {#1}% + }% + \do@getrow +% \end{macrocode} +% Update the "Used" field. +% \begin{macrocode} + \dtlreplaceentryincurrentrow + {0}{\dtlcolumnindex{\newterm@database}{Used}}% +% \end{macrocode} +% Current row has been edited, so we need to merge the current row +% back into the database. +% \begin{macrocode} + \dtlrecombine +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\glsunset} +%\begin{definition} +%\cs{glsunset}\marg{label} +%\end{definition} +% Mark as used without affecting location. +% \begin{macrocode} +\newcommand*{\glsunset}[1]{% +% \end{macrocode} +% Fetch the name of the database with which this entry is +% associated. +% \begin{macrocode} + \letcs{\newterm@database}{datagidxentry@#1}% +% \end{macrocode} +% Get the row associated with this label and make it the current row. +% \begin{macrocode} + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\newterm@database}% + {\dtlcolumnindex{\newterm@database}{Label}}% + {#1}% + }% + \do@getrow +% \end{macrocode} +% Update the "Used" field. +% \begin{macrocode} + \dtlreplaceentryincurrentrow + {1}{\dtlcolumnindex{\newterm@database}{Used}}% +% \end{macrocode} +% Current row has been edited, so we need to merge the current row +% back into the database. +% \begin{macrocode} + \dtlrecombine +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\glsresetall} +%\begin{definition} +%\cs{glsresetall}\marg{db} +%\end{definition} +% Resets all entries in the given database. +% \begin{macrocode} +\newcommand*{\glsresetall}[1]{% + \def\datagidx@list{}% + \dtlforcolumn{\datagidx@label}{#1}{Label}% + {% + \ifdefempty\datagidx@list + {% + \let\datagidx@list\datagidx@label + }% + {% + \eappto\datagidx@list{,\datagidx@label}% + }% + }% + \@for\datagidx@thislabel:=\datagidx@list\do + {% + \glsreset{\datagidx@thislabel}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\glsunsetall} +%\begin{definition} +%\cs{glsunsetall}\marg{db} +%\end{definition} +% Resets all entries in the given database. +% \begin{macrocode} +\newcommand*{\glsunsetall}[1]{% + \def\datagidx@list{}% + \dtlforcolumn{\datagidx@label}{#1}{Label}% + {% + \ifdefempty\datagidx@list + {% + \let\datagidx@list\datagidx@label + }% + {% + \eappto\datagidx@list{,\datagidx@label}% + }% + }% + \@for\datagidx@thislabel:=\datagidx@list\do + {% + \glsunset{\datagidx@thislabel}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\section{Accessing Entry Information} +% +%\begin{macro}{\datagidx@anchorcount} +% Register to make unique anchors. +% \begin{macrocode} +\newcount\datagidx@anchorcount +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidx@formatanchor} +% Format number using six digits. +% \begin{macrocode} +\newcommand*{\datagidx@formatanchor}[1]{% + \ifnum#1<10000 + 0% + \ifnum#1<1000 + 0% + \ifnum#1<100 + 0% + \ifnum#1<10 + 0% + \fi + \fi + \fi + \fi + \number#1% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@datagidx@escloc} +% \begin{macrocode} +\newcommand*{\@datagidx@escloc}[2]{% + \expandafter\string\csname#1\endcsname{\noexpand\number#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@escapelocation} +% \begin{macrocode} +\newcommand*{\datagidx@escapelocation}{% + \def\@arabic{\@datagidx@escloc{@arabic}}% + \def\@roman{\@datagidx@escloc{@roman}}% + \def\@Roman{\@datagidx@escloc{@Roman}}% + \def\@alph{\@datagidx@escloc{@alph}}% + \def\@Alph{\@datagidx@escloc{@Alph}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidx@escapelocationformat} +% \begin{macrocode} +\newcommand*{\datagidx@escapelocationformat}{% + \def\@arabic##1{arabic}% + \def\@roman##1{roman}% + \def\@Roman##1{Roman}% + \def\@alph##1{alph}% + \def\@Alph##1{Alph}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\datagidx@clearlocationformat} +% \begin{macrocode} +\newcommand*{\datagidx@clearlocationformat}{% + \let\@arabic\@firstofone + \let\@roman\@firstofone + \let\@Roman\@firstofone + \let\@alph\@firstofone + \let\@Alph\@firstofone +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxAddLocationType} +% Allow user to add their own location type. Argument must be +% control sequence name without initial backslash. +% \begin{macrocode} +\newcommand*{\DTLgidxAddLocationType}[1]{% + \gappto\datagidx@escapelocation{% + \expandafter\def\csname#1\endcsname{\@datagidx@escloc{#1}}% + }% + \gappto\datagidx@escapelocationformat{% + \expandafter\def\csname#1\endcsname##1{#1}% + }% + \gappto\datagidx@clearlocationformat{% + \expandafter\let\csname#1\endcsname\@firstofone + }% +} +% \end{macrocode} +% May only be used in the preamble. (Needs to be set before the aux +% file is read.) +% \begin{macrocode} +\@onlypreamble\DTLgidxAddLocationType +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@target} +%\begin{definition} +%\cs{datagidx@target}\marg{label}\marg{format}\marg{location}\marg{text} +%\end{definition} +% Make a target if \cs{hypertarget} has been defined. +% \begin{macrocode} +\newcommand*{\datagidx@target}[4]{% + \global\advance\datagidx@anchorcount by 1\relax + \edef\@datagidx@target{datagidx.\datagidx@formatanchor\datagidx@anchorcount}% + \ifstrempty{#3} + {% + \datagidx@write@usedentry{#1}{}% + }% + {% + \bgroup + \datagidx@escapelocation +% \end{macrocode} +% Need to prevent \cs{@arabic} etc from being expanded just yet (or it +% will throw the page numbering out of sync for entries that occur +% by a page break). +%\changes{2.15}{2013-07-10}{fixed page breaking bug} +% \begin{macrocode} + \def\@arabic{\noexpand\@arabic}% + \def\@roman{\noexpand\@roman}% + \def\@Roman{\noexpand\@Roman}% + \def\@alph{\noexpand\@alph}% + \def\@Alph{\noexpand\@Alph}% + \protected@edef\@datagidx@dowriteaux{% + \noexpand\datagidx@write@usedentry{#1}% + {[#2]{#3}{\@datagidx@target}}% + }% + \@datagidx@dowriteaux + \egroup + }% + \ifdef\hypertarget + {% +% \end{macrocode} +% Make sure the current line doesn't scroll off the top of the +% screen. +% \begin{macrocode} + \datagidxshowifdraft + {% + [\@datagidx@target]% + \discretionary{}{}{}% + }% + \bgroup + \let\glsadd\@gobble + \settoheight\dimen@{#4}% + \raisebox{\dimen@}% + {% + \datagidxtarget{\@datagidx@target}{}% + }% + \egroup + }% + {% + }% + \datagidxshowifdraft{[#1]\discretionary{}{}{}}% + #4% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\glsdispentry} +%\begin{definition} +%\cs{glsdispentry}\marg{label}\marg{field} +%\end{definition} +% Short cut that fetches and displays a value. +% \begin{macrocode} +\DeclareRobustCommand*{\glsdispentry}[2]{% + \DTLgidxFetchEntry{\datagidx@dispentryval}{#1}{#2}% + \datagidx@dispentryval +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\Glsdispentry} +%\begin{definition} +%\cs{Glsdispentry}\marg{label}\marg{field} +%\end{definition} +% As previous but makes the first letter upper case. +% \begin{macrocode} +\DeclareRobustCommand*{\Glsdispentry}[2]{% + \DTLgidxFetchEntry{\datagidx@dispentryval}{#1}{#2}% + \xmakefirstuc\datagidx@dispentryval +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxFetchEntry} +% Fetch value for the given field for the term identified by +% \meta{label} and store the value in \meta{cs} (a control sequence). +% \begin{macrocode} +\newcommand*{\DTLgidxFetchEntry}[3]{% +% \end{macrocode} +% Does this entry exist? +% \begin{macrocode} + \ifcsdef{datagidxentry@#2}% + {% +% \end{macrocode} +% Fetch the name of the database with which this entry is +% associated. +% \begin{macrocode} + \letcs{\newterm@database}{datagidxentry@#2}% +% \end{macrocode} +% Get the row associated with this label and make it the current row. +% \begin{macrocode} + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\newterm@database}% + {\dtlcolumnindex{\newterm@database}{Label}}% + {#2}% + }% + \do@getrow +% \end{macrocode} +% Get the entry for the given field in the current row and store in +% \meta{cs}. +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {#1}% + {\dtlcolumnindex{\newterm@database}{#3}}% + }% + {% +% \end{macrocode} +% Entry hasn't been defined. +% \begin{macrocode} + \PackageError{datagidx}{No term `#2' defined}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@parse@formatlabel} +%\begin{definition} +%\cs{parse@formatlabel}\marg{\oarg{format}label} +%\end{definition} +% Separate format and label from argument. +% \begin{macrocode} +\newcommand*{\datagidx@parse@formatlabel}[1]{% + \datagidx@parse@format@label@#1\@endparse@formatlabel@ +} +\newcommand*\datagidx@parse@format@label@{% + \@ifnextchar[{\datagidx@parse@formatlabel@}{\datagidx@parse@formatlabel@[]}% +} +\def\datagidx@parse@formatlabel@[#1]#2\@endparse@formatlabel@{% + \def\datagidx@format{#1}% + \def\datagidx@label{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@datagidx@use@entry} +%\begin{definition} +%\cs{@datagidx@use@entry}\marg{link text} +%\end{definition} +% The label and format should have been stored in +% \cs{datagidx@label} and \cs{datagidx@format} before calling this +% macro. +%\changes{2.19}{2014-01-17}{renamed \cs{datagidx@use@entry} to +%\cs{@datagidx@use@entry} and removed redundant field argument} +% \begin{macrocode} +\newcommand*{\@datagidx@use@entry}[1]{% +% \end{macrocode} +% Does this term exist? +% \begin{macrocode} + \ifcsundef{datagidxentry@\datagidx@label} + {% + \PackageError{datagidx}{Entry `\datagidx@label' doesn't exist}{}% + }% + {% +% \end{macrocode} +% Fetch the name of the database with which this entry is +% associated. +% \begin{macrocode} + \letcs{\newterm@database}{datagidxentry@\datagidx@label}% +% \end{macrocode} +% Get the row associated with this label and make it the current row. +% \begin{macrocode} + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\newterm@database}% + {\dtlcolumnindex{\newterm@database}{Label}}% + {\datagidx@label}% + }% + \do@getrow +% \end{macrocode} +% Get the entry for the "FirstId" field and store in \cs{datagidx@id} +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@id}% + {\dtlcolumnindex{\newterm@database}{FirstId}}% +% \end{macrocode} +% If it hasn't been defined set it. +% \begin{macrocode} + \DTLifnull\datagidx@id + {% +% \end{macrocode} +% Count register hasn't been updated yet. +% \begin{macrocode} + \count@=\datagidx@anchorcount\relax + \advance\count@ by 1\relax + \dtlappendentrytocurrentrow{FirstId}{\datagidx@formatanchor\count@}% + }% + {}% +% \end{macrocode} +% Update the "Used" field. +% \begin{macrocode} + \dtlreplaceentryincurrentrow + {1}{\dtlcolumnindex{\newterm@database}{Used}}% +% \end{macrocode} +% Get the parent entry label (if one exists). +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@parent}% + {\dtlcolumnindex{\newterm@database}{Parent}}% +% \end{macrocode} +% Current row has been edited, so we need to merge the current row +% back into the database. +% \begin{macrocode} + \dtlrecombine +% \end{macrocode} +% If parent hasn't be used, give it an empty location. +% \begin{macrocode} + \datagidx@markparent{\newterm@database}{\datagidx@parent}% +% \end{macrocode} +% Write the location to the auxiliary file and display value of +% field. +% \begin{macrocode} + \datagidx@target{\datagidx@label}{\datagidx@format}% + {\csuse{the\DTLgidxCounter}}{#1}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxCounter} +% The counter used for the location lists. +% \begin{macrocode} +\newcommand*{\DTLgidxCounter}{page} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@markparent} +% Assign empty location to parent, if location of that parent is null. +% (Recursive). +% \begin{macrocode} +\newcommand*{\datagidx@markparent}[2]{% + \ifx#2\dtlnovalue +% \end{macrocode} +% Null parent, so break out of recursion. +% \begin{macrocode} + \else +% \end{macrocode} +% Write empty location to the auxiliary file. +% \begin{macrocode} + \datagidx@target{#2}{}{}{}% +% \end{macrocode} +% Fetch this parent's parent entry. +% Get the row associated with this and make it the current row. +% \begin{macrocode} + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {#1}% + {\dtlcolumnindex{#1}{Label}}% + {#2}}% + \do@getrow +% \end{macrocode} +% Get the entry for the "FirstId" field and store in \cs{datagidx@id} +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@id}% + {\dtlcolumnindex{\newterm@database}{FirstId}}% +% \end{macrocode} +% If it hasn't been defined set it. +% \begin{macrocode} + \DTLifnull\datagidx@id + {% + \dtlappendentrytocurrentrow{FirstId}{\datagidx@formatanchor\datagidx@anchorcount}% + }% + {}% +% \end{macrocode} +% Get the parent +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@parent}% + {\dtlcolumnindex{#1}{Parent}}% +% \end{macrocode} +% Current row has been edited, so we need to merge the current row +% back into the database. +% \begin{macrocode} + \dtlrecombine +% \end{macrocode} +% Recurse +% \begin{macrocode} + \datagidx@markparent{#1}{\datagidx@parent}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@write@usedentry} +% Write out location to aux file and add location to the location +% list for the current run. +% \begin{macrocode} +\newcommand*{\datagidx@write@usedentry}[2]{% +% \end{macrocode} +% Do update if `highopt optimize' setting is on. +% \begin{macrocode} + \datagidx@do@highopt@update{#1}% +% \end{macrocode} +% Write out location to aux file. +% \begin{macrocode} + \protected@write{\@auxout}{}% + {% + \string\datagidx@usedentry{#1}{#2}% + }% +% \end{macrocode} +% Add to this run's location field. +% \begin{macrocode} + \protected@edef\datagidx@do@usedentry{% + \noexpand\datagidx@xusedentry{CurrentLocation}{#1}{#2}% + }% +% \end{macrocode} +% If the location counter is the page counter, defer until after the +% page break. +%\changes{2.15}{2013-07-10}{Added check for page counter} +% \begin{macrocode} + \expandafter\ifstrequal\expandafter{\DTLgidxCounter}{page}% + {% + \expandafter\afterpage\expandafter{\datagidx@do@usedentry}% + }% + { + \datagidx@do@usedentry + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@xusedentry} +%\begin{definition} +%\cs{datagidx@usedentry}\marg{location tag}\marg{label}\marg{location} +%\end{definition} +% Like \cs{datagidx@usedentry} but expands the location. Unlike +% \cs{datagidx@usedentry} the first argument isn't optional. +% \begin{macrocode} +\newcommand*{\datagidx@xusedentry}[3]{% + \protected@edef\@datagidx@do@xusedentry{% + \noexpand\datagidx@usedentry[#1]{#2}{#3}% + }% + \@datagidx@do@xusedentry +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@usedentry} +%\begin{definition} +%\cs{datagidx@usedentry}\oarg{location tag}\marg{label}\marg{location} +%\end{definition} +% Add to the location list for the given entry. +% \begin{macrocode} +\newcommand*{\datagidx@usedentry}[3][Location]{% +% \end{macrocode} +% Check if label exists. (It may have been deleted or had a label +% change.) +% \begin{macrocode} + \ifcsundef{datagidxentry@#2}% + {% + \PackageWarning{datagidx}{No term `#2' defined. Ignoring}% + }% + {% +% Fetch the name of the database with which this entry is +% associated. +% \begin{macrocode} + \letcs{\newterm@database}{datagidxentry@#2}% +% \end{macrocode} +% Get the row associated with this label and make it the current row. +% \begin{macrocode} + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\newterm@database}% + {\dtlcolumnindex{\newterm@database}{Label}}% + {#2}% + }% + \do@getrow +% \end{macrocode} +% \begin{macrocode} +% Get the entry for the \meta{location tag} field in the current row and store in +% \cs{datagidx@loc}. +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@loc}% + {\dtlcolumnindex{\newterm@database}{#1}}% +% \end{macrocode} +% Check the success of the previous command. +% \begin{macrocode} + \ifx\datagidx@loc\dtlnovalue +% \end{macrocode} +% There's no \meta{location tag} field in the current row, so add one with +% the given location. +% \begin{macrocode} + \def\datagidx@loc{#3}% + \dtlappendentrytocurrentrow{#1}{\expandonce\datagidx@loc}% + \else +% \end{macrocode} +% There is a \meta{location tag} field in the current row, so append the +% given location to the list, unless one or the other is empty. +% \begin{macrocode} + \ifdefempty{\datagidx@loc}% + {% + \def\datagidx@loc{#3}% + }% + {% + \ifstrempty{#3}% + {}% + {% + \appto\datagidx@loc{,#3}% + }% + }% +% \end{macrocode} +% and update the entry in the current row. +% \begin{macrocode} + \expandafter\dtlreplaceentryincurrentrow\expandafter + {\datagidx@loc}% + {\dtlcolumnindex{\newterm@database}{#1}}% + \fi +% \end{macrocode} +% Current row has been edited, so we need to merge the current row +% back into the database. +% \begin{macrocode} + \dtlrecombine + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@save@loc} +% Store the current location from the previous run. +% \begin{macrocode} +\newcommand*{\datagidx@save@loc}[2]{% + \bgroup + \datagidx@escapelocation + \xdef\datagidx@tmp{#2}% + \egroup + \expandafter\xdef\csname datagidx@prev@loc@#1\endcsname{\datagidx@tmp}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\glsadd} +%\begin{definition} +%\cs{glsadd}\marg{\oarg{format}label} +%\end{definition} +% \begin{macrocode} +\newcommand*{\glsadd}[1]{% + \NoCaseChange{\@glsadd{#1}}% +} +\DeclareRobustCommand*{\@glsadd}[1]{% +% \end{macrocode} +% Check term has been defined. +% \begin{macrocode} + \ifcsundef{datagidxentry@\datagidx@label}% + {% + \PackageError{datagidx}{Term `\datagidx@label' doesn't exist}{}% + }% + {% +% \end{macrocode} +% \begin{macrocode} + \datagidx@parse@formatlabel{#1}% +% \end{macrocode} +% Write the location to the auxiliary file. +% \begin{macrocode} + \datagidx@target{\datagidx@label}{\datagidx@format}% + {\csuse{the\DTLgidxCounter}}{}% +% \end{macrocode} +% Fetch the name of the database with which this entry is +% associated. +% \begin{macrocode} + \letcs{\newterm@database}{datagidxentry@\datagidx@label}% +% \end{macrocode} +% Get the row associated with this label and make it the current row. +% \begin{macrocode} + \edef\do@getrow{% + \noexpand\dtlgetrowforvalue + {\newterm@database}% + {\dtlcolumnindex{\newterm@database}{Label}}% + {\datagidx@label}% + }% + \do@getrow +% \end{macrocode} +% Update the "Used" field. +% \begin{macrocode} + \dtlreplaceentryincurrentrow + {1}{\dtlcolumnindex{\newterm@database}{Used}}% +% \end{macrocode} +% Get the entry for the "FirstId" field and store in \cs{datagidx@id} +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@id}% + {\dtlcolumnindex{\newterm@database}{FirstId}}% +% \end{macrocode} +% If it hasn't been defined set it. +% \begin{macrocode} + \DTLifnull\datagidx@id + {% + \dtlappendentrytocurrentrow{FirstId}{\datagidx@formatanchor\datagidx@anchorcount}% + }% + {}% +% \end{macrocode} +% Current row has been edited, so we need to merge the current row +% back into the database. +% \begin{macrocode} + \dtlrecombine + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@count} +% Loop counter used by \cs{glsaddall} +% \begin{macrocode} +\newcount\datagidx@count +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\glsaddall} +%\begin{definition} +%\cs{glsaddall}\marg{db} +%\end{definition} +% Adds all entries in the given database. +% \begin{macrocode} +\newcommand*{\glsaddall}[1]{% + \DTLifdbexists{#1}% + {% + \edef\datagidx@rowcount{\number\DTLrowcount{#1}}% + \datagidx@count=0\relax + \loop + \advance\datagidx@count by 1\relax + \dtlgetrow{#1}{\datagidx@count}% +% \end{macrocode} +% Get the label for this row. +%\changes{2.19}{2014-01-17}{Fixed bug in database reference} +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@label}% + {\dtlcolumnindex{#1}{Label}}% +% \end{macrocode} +% Write blank location to the auxiliary file but temporarily undefine +% \cs{hypertarget} as it doesn't make sense to have a target here. +% \begin{macrocode} + \bgroup + \undef\hypertarget + \datagidx@target{\datagidx@label}{}{}{}% + \egroup +% \end{macrocode} +% Update the "Used" field. +%\changes{2.19}{2014-01-17}{Fixed bug in database reference} +% \begin{macrocode} + \dtlreplaceentryincurrentrow + {1}{\dtlcolumnindex{#1}{Used}}% +% \end{macrocode} +% Get the entry for the "FirstId" field and store in \cs{datagidx@id} +%\changes{2.19}{2014-01-17}{Fixed bug in database reference} +% \begin{macrocode} + \dtlgetentryfromcurrentrow + {\datagidx@id}% + {\dtlcolumnindex{#1}{FirstId}}% +% \end{macrocode} +% If it hasn't been defined set it. +% \begin{macrocode} + \DTLifnull\datagidx@id + {% + \dtlappendentrytocurrentrow{FirstId}{\datagidx@formatanchor\datagidx@anchorcount}% + }% + {}% +% \end{macrocode} +% Current row has been edited, so we need to merge the current row +% back into the database. +% \begin{macrocode} + \dtlrecombine +% \end{macrocode} +% Repeat loop if not finished. +% \begin{macrocode} + \ifnum\datagidx@count<\datagidx@rowcount + \repeat + }% + {% + \PackageError{datagidx}{Database `#1' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\glslink} +%\begin{definition} +%\cs{glslink}\marg{label}\marg{text} +%\end{definition} +% Use given entry but user supplies text. +% \begin{macrocode} +\DeclareRobustCommand*{\glslink}[2]{% + \datagidx@parse@formatlabel{#1}% + \datagidxlink{\datagidx@label}% + {% + \@datagidx@use@entry{#2}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\useentry} +%\begin{definition} +%\cs{useentry}\marg{label}\marg{field} +%\end{definition} +% Fetch and use the given field for the given entry. +% \begin{macrocode} +\DeclareRobustCommand*{\useentry}[2]{% + \datagidx@parse@formatlabel{#1}% + \DTLgidxFetchEntry{\datagidx@value}{\datagidx@label}{#2}% + \datagidxlink{\datagidx@label}% + {% + \@datagidx@use@entry{\datagidx@value}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Useentry} +%\begin{definition} +%\cs{Useentry}\marg{label}\marg{field} +%\end{definition} +% As \cs{useentry}, but capitalise the first word. +% \begin{macrocode} +\DeclareRobustCommand*{\Useentry}[2]{% + \datagidx@parse@formatlabel{#1}% + \DTLgidxFetchEntry{\datagidx@value}{\datagidx@label}{#2}% + \datagidxlink{\datagidx@label}% + {% + \@datagidx@use@entry{\xmakefirstuc{\datagidx@value}}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\USEentry} +%\begin{definition} +%\cs{USEentry}\marg{label}\marg{field} +%\end{definition} +% As \cs{useentry}, but make the whole term upper case. +% \begin{macrocode} +\DeclareRobustCommand*{\USEentry}[2]{% + \datagidx@parse@formatlabel{#1}% + \DTLgidxFetchEntry{\datagidx@value}{\datagidx@label}{#2}% + \datagidxlink{\datagidx@label}% + {% + \@datagidx@use@entry{\MakeTextUppercase{\datagidx@value}}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\useentrynl} +%\begin{definition} +%\cs{useentrynl}\marg{label}\marg{field} +%\end{definition} +% Fetch and use the given field for the given entry without creating +% a hyperlink. +% \begin{macrocode} +\DeclareRobustCommand*{\useentrynl}[2]{% + \datagidx@parse@formatlabel{#1}% + \DTLgidxFetchEntry{\datagidx@value}{\datagidx@label}{#2}% + \@datagidx@use@entry{\datagidx@value}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Useentrynl} +%\begin{definition} +%\cs{Useentrynl}\marg{label}\marg{field} +%\end{definition} +% As \cs{useentry}, but capitalise the first word. +% \begin{macrocode} +\DeclareRobustCommand*{\Useentrynl}[2]{% + \datagidx@parse@formatlabel{#1}% + \DTLgidxFetchEntry{\datagidx@value}{\datagidx@label}{#2}% + \@datagidx@use@entry{\xmakefirstuc{\datagidx@value}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\USEentrynl} +%\begin{definition} +%\cs{USEentrynl}\marg{label}\marg{field} +%\end{definition} +% As \cs{useentry}, but make the whole term upper case. +% \begin{macrocode} +\DeclareRobustCommand*{\USEentrynl}[2]{% + \datagidx@parse@formatlabel{#1}% + \DTLgidxFetchEntry{\datagidx@value}{\datagidx@label}{#2}% + \@datagidx@use@entry{\MakeTextUppercase{\datagidx@value}}% +} +% \end{macrocode} +%\end{macro} +% +% +% Short cuts to common fields. +%\begin{macro}{\gls} +% \begin{macrocode} +\DeclareRobustCommand*{\gls}[1]{\useentry{#1}{Text}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\glspl} +% \begin{macrocode} +\DeclareRobustCommand*{\glspl}[1]{\useentry{#1}{Plural}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Gls} +% \begin{macrocode} +\DeclareRobustCommand*{\Gls}[1]{\Useentry{#1}{Text}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Glspl} +% \begin{macrocode} +\DeclareRobustCommand*{\Glspl}[1]{\Useentry{#1}{Plural}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\glsnl} +% \begin{macrocode} +\DeclareRobustCommand*{\glsnl}[1]{\useentrynl{#1}{Text}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\glsplnl} +% \begin{macrocode} +\DeclareRobustCommand*{\glsplnl}[1]{\useentrynl{#1}{Plural}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Glsnl} +% \begin{macrocode} +\DeclareRobustCommand*{\Glsnl}[1]{\Useentrynl{#1}{Text}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Glsplnl} +% \begin{macrocode} +\DeclareRobustCommand*{\Glsplnl}[1]{\Useentrynl{#1}{Plural}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\glssym} +% \begin{macrocode} +\DeclareRobustCommand*{\glssym}[1]{\useentry{#1}{Symbol}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Glssym} +% \begin{macrocode} +\DeclareRobustCommand*{\Glssym}[1]{\Useentry{#1}{Symbol}} +% \end{macrocode} +%\end{macro} +% +%\subsection{Using Acronyms} +%\begin{macro}{\DTLgidxFormatAcr} +%\begin{definition} +%\cs{DTLgidxFormatAcr}\marg{label}\marg{long field}\marg{short field} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLgidxFormatAcr}[3]{% + \DTLgidxAcrStyle{\glsdispentry{#1}{#2}}{\useentry{#1}{#3}}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxFormatAcrUC} +%\begin{definition} +%\cs{DTLgidxFormatAcr}\marg{label}\marg{long field}\marg{short field} +%\end{definition} +%As previous but capitalise first word. +% \begin{macrocode} +\newcommand*{\DTLgidxFormatAcrUC}[3]{% + \DTLgidxAcrStyle{\Glsdispentry{#1}{#2}}{\useentry{#1}{#3}}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\acr} +% \begin{macrocode} +\DeclareRobustCommand*{\acr}[1]{% + \ifentryused{#1}% + {\useentry{#1}{Short}}% + {\DTLgidxFormatAcr{#1}{Long}{Short}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\acrpl} +% \begin{macrocode} +\DeclareRobustCommand*{\acrpl}[1]{% + \ifentryused{#1}% + {\useentry{#1}{ShortPlural}}% + {\DTLgidxFormatAcr{#1}{LongPlural}{ShortPlural}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Acr} +% \begin{macrocode} +\DeclareRobustCommand*{\Acr}[1]{% + \ifentryused{#1}% + {\Useentry{#1}{Short}}% + {\DTLgidxFormatAcrUC{#1}{Long}{Short}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Acrpl} +% \begin{macrocode} +\DeclareRobustCommand*{\Acrpl}[1]{% + \ifentryused{#1}% + {\Useentry{#1}{ShortPlural}}% + {\DTLgidxFormatAcrUC{#1}{LongPlural}{ShortPlural}}% +} +% \end{macrocode} +%\end{macro} +% +%\section{Displaying Glossaries, Lists of Acronyms, Indices} +% Define keys for \cs{printterms}: +% \begin{macrocode} +\define@key{printterms}{database}{\renewcommand*{\newterm@database}{#1}} +% \end{macrocode} +% Options for post description. +% \begin{macrocode} +\define@choicekey{printterms}{postdesc}[\val\nr]% + {none,dot}% + {% + \datagidx@setpostdesc\nr + } +% \end{macrocode} +% Options for pre-location. +% \begin{macrocode} +\define@choicekey{printterms}{prelocation}[\val\nr]% + {none,enspace,space,dotfill,hfill}% + {% + \datagidx@setprelocation\nr + } +% \end{macrocode} +% How to display the location list. +% \begin{macrocode} +\define@choicekey{printterms}{location}[\val\nr]% + {hide,list,first}% + {\datagidx@setlocation\nr} +% \end{macrocode} +% How to format the symbol in relation to the description. +% \begin{macrocode} +\define@choicekey{printterms}{symboldesc}[\val\nr]% + {symbol,desc,(symbol) desc,desc (symbol),symbol desc,desc symbol}% + {\datagidx@formatsymdesc\nr} +% \end{macrocode} +% How many columns to have. +% \begin{macrocode} +\define@key{printterms}{columns}% +{% + \DTLgidxSetColumns{#1}% +} +% \end{macrocode} +% How to format the name. +% \begin{macrocode} +\define@choicekey{printterms}{namecase}[\val\nr]% + {nochange,uc,lc,firstuc,capitalise}% + {% + \datagidx@setnamecase\nr + } +% \end{macrocode} +% \begin{macrocode} +\define@key{printterms}{namefont}% +{% + \renewcommand*{\DTLgidxNameFont}[1]{{#1{##1}}}% +} +% \end{macrocode} +% \begin{macrocode} +\define@key{printterms}{postname} +{% + \renewcommand*{\DTLgidxPostName}{#1}% +} +% \end{macrocode} +% \begin{macrocode} +\define@choicekey{printterms}{see}[\val\nr]% + {comma,brackets,dot,space,nosep,semicolon,location}% + {\datagidx@setsee\nr} +% \end{macrocode} +% +% \begin{macrocode} +\define@choicekey{printterms}{child}[\val\nr]% + {named,noname}% + {% + \datagidx@setchildstyle\nr + } +% \end{macrocode} +% Symbol width +% \begin{macrocode} +\define@key{printterms}{symbolwidth}% +{% + \setlength{\datagidxsymbolwidth}{#1}% +} +% \end{macrocode} +% Location width +% \begin{macrocode} +\define@key{printterms}{locationwidth}% +{% + \setlength{\datagidxlocationwidth}{#1}% +} +% \end{macrocode} +% Child sort: +% \begin{macrocode} +\define@choicekey{printterms}{childsort}[\val\nr]% + {true,false}[true]% + {% + \datagidx@setchildsort\nr + } +% \end{macrocode} +% Change style: +% \begin{macrocode} +\define@choicekey{printterms}{showgroups}{true,false}[true]{% + \appto\newterm@styles{showgroups={#1},}% +} +% \end{macrocode} +% \begin{macrocode} +\define@key{printterms}{style}{\appto\newterm@styles{style={#1},}} +% \end{macrocode} +% \begin{macrocode} +\define@key{printterms}{heading}{\appto\newterm@styles{heading={#1},}} +% \end{macrocode} +% \begin{macrocode} +\define@key{printterms}{postheading}{% + \appto\newterm@styles{postheading={#1},}% +} +% \end{macrocode} +% \begin{macrocode} +\define@key{printterms}{sort}{\appto\newterm@styles{sort={#1},}} +% \end{macrocode} +% \begin{macrocode} +\define@choicekey{printterms}{balance}[\val\nr]{true,false}[true]{% + \ifcase\nr\relax + \appto\newterm@styles{balance=true,}% + \or + \appto\newterm@styles{balance=false,}% + \fi +} +% \end{macrocode} +%\begin{macro}{\printterms@condition} +%\changes{2.14}{2013-06-28}{new} +% \begin{macrocode} +\newcommand*{\printterms@condition}{\boolean{true}} +\define@key{printterms}{condition}{\renewcommand*{\printterms@condition}{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\printtermsstartpar} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand{\printtermsstartpar}{\par} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\printterms@setupmulticol} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\printterms@setupmulticol}{% + \ifdefempty\datagidx@postheading + {% + \edef\datagidx@prestart{% + \noexpand\datagidx@heading{\noexpand\datagidx@title}% + \noexpand\begin{\datagidx@multicols}{\datagidx@columns}% + }% + }% + {% + \edef\datagidx@prestart{% + \noexpand\datagidx@heading{\noexpand\datagidx@title}% + \noexpand\begin{\datagidx@multicols}{\datagidx@columns}% + [\noexpand\datagidx@postheading]% + }% + }% + \edef\datagidx@postend{% + \noexpand\end{\datagidx@multicols}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\printterms@setuptwocol} +%\changes{2.28}{2017-11-10}{new} +% \begin{macrocode} +\newcommand*{\printterms@setuptwocol}{% + \def\datagidx@prestart{% + \twocolumn[\datagidx@heading{\datagidx@title}% + \datagidx@postheading]}% + \if@twocolumn + \def\datagidx@postend{}% + \else + \def\datagidx@postend{\printtermsrestoreonecolumn}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\printtermsrestoreonecolumn} +% \begin{macrocode} +\newcommand{\printtermsrestoreonecolumn}{\onecolumn} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\printterms} +%\begin{definition} +%\cs{printterms}[options] +%\end{definition} +% Print the list of terms +% \begin{macrocode} +\newcommand{\printterms}[1][]{% +\bgroup +% \end{macrocode} +% Set default database. +% \begin{macrocode} + \let\newterm@database\datagidx@defaultdatabase +% \end{macrocode} +% Initialise key list for style: +% \begin{macrocode} + \let\newterm@styles\@empty +% \end{macrocode} +% Set options: +% \begin{macrocode} + \setkeys{printterms}{#1}% +% \end{macrocode} +% Check if database exists. +% \begin{macrocode} + \DTLifdbexists{\newterm@database}% + {% +% \end{macrocode} +% Provide user the means to access the current database name. +% \begin{macrocode} + \edef\DTLgidxCurrentdb{\newterm@database}% +% \end{macrocode} +% Get the fields from datagidx: +% \begin{macrocode} + \edef\do@getrow{\noexpand\dtlgetrowforvalue + {datagidx}% + {\dtlcolumnindex{datagidx}{Glossary}}% + {\newterm@database}% + }% + \do@getrow + \dtlgetentryfromcurrentrow + {\datagidx@title}% + {\dtlcolumnindex{datagidx}{Title}}% + \dtlgetentryfromcurrentrow + {\datagidx@heading}% + {\dtlcolumnindex{datagidx}{Heading}}% + \dtlgetentryfromcurrentrow + {\datagidx@postheading}% + {\dtlcolumnindex{datagidx}{PostHeading}}% + \dtlgetentryfromcurrentrow + {\datagidx@multicols}% + {\dtlcolumnindex{datagidx}{MultiCols}}% + \dtlgetentryfromcurrentrow + {\datagidx@sort}% + {\dtlcolumnindex{datagidx}{Sort}}% + \dtlgetentryfromcurrentrow + {\datagidx@style}% + {\dtlcolumnindex{datagidx}{Style}}% + \dtlgetentryfromcurrentrow + {\datagidx@showgroups}% + {\dtlcolumnindex{datagidx}{ShowGroups}}% +% \end{macrocode} +% Allow user to override style here. +% \begin{macrocode} + \edef\dtl@do@setkeys{\noexpand\setkeys{newgloss}{\expandonce\newterm@styles}}% + \dtl@do@setkeys +% \end{macrocode} +% Do we need to use \env{multicols}? +% \begin{macrocode} + \ifnum\datagidx@columns>1\relax + \ifnum\datagidx@columns=2\relax + \ifdatagidxbalance + \printterms@setupmulticol + \else + \printterms@setuptwocol + \fi + \else + \printterms@setupmulticol + \fi + \else + \def\datagidx@prestart{}% + \def\datagidx@postend{}% + \fi + \let\@dtl@dbname\DTLgidxCurrentdb +% \end{macrocode} +% Set the style +% \begin{macrocode} + \csuse{datagidxshowgroups\datagidx@showgroups}% + \datagidxsetstyle{\datagidx@style}% +% \end{macrocode} +% Now display the glossary/index: +% \begin{macrocode} + \def\datagidx@labellist{}% + \ifnum\datagidx@columns=1\relax + \datagidx@heading{\datagidx@title}% + \datagidx@postheading + \fi + \datagidx@do@sort + \datagidx@prestart +% \end{macrocode} +%\changes{2.28}{2017-11-10}{added paragraph break at the start}: +% \begin{macrocode} + \printtermsstartpar + \datagidxstart + \let\DTLgidxName\datagidx@invert + \let\DTLgidxPlace\datagidx@invert + \let\DTLgidxSubject\datagidx@invert + \let\DTLgidxOffice\datagidx@invert + \DTLgidxForeachEntry + {% + \datagidxitem + }% + \datagidxend + \datagidx@postend + }% + {% +% \end{macrocode} +% Database doesn't exist. +% \begin{macrocode} + \PackageError{datagidx}% + {Glossary/index data base `\newterm@database' doesn't exist}% + {% + You must define the glossary/index data base before you can + use it.% + }% + }% +\egroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@getgroup} +% Get the current group. +% \begin{macrocode} +\def\datagidx@getgroup#1#2\datagidx@endgetgroup{% + \dtl@setcharcode{#1}{\count@}% + \dtlifintclosedbetween{\count@}{48}{57}% + {% + \gdef\datagidxcurrentgroup{Numbers}% + }% + {% + \dtlifintclosedbetween{\count@}{97}{122}% + {% + \advance\count@ by -96\relax + \xdef\datagidxcurrentgroup{\@Alph\count@}% + }% + {% + \dtlifintclosedbetween{\count@}{65}{90}% + {% + \gdef\datagidxcurrentgroup{#1}% + }% + {% + \gdef\datagidxcurrentgroup{Symbols}% + }% + }% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLgidxGroupHeaderTitle} +% Produce the group title from the group label. +% \begin{macrocode} +\newcommand*{\DTLgidxGroupHeaderTitle}[1]{% + \ifcsdef{datagidx#1name} + {% + \csuse{datagidx#1name}% + }% + {% + #1% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgidxForeachEntry} +%\begin{definition} +%\cs{DTLgidxForeachEntry}\marg{body} +%\end{definition} +% Iterate through the current database, but only do \meta{body} +% if there is a location or cross-reference. +%\changes{2.14}{2013-06-28}{Added optional argument when using +%\cs{DTLforeach}} +% \begin{macrocode} +\newcommand{\DTLgidxForeachEntry}[1]{% + \def\datagidxprevgroup{}% + \edef\datagidx@doforeachentry{% + \noexpand\DTLforeach*[\expandonce\printterms@condition]{\DTLgidxCurrentdb}% + {\expandonce\DTLgidxAssignList} + }% + \datagidx@doforeachentry + {% +% \end{macrocode} +% Iterate through top-level entries. +% \begin{macrocode} + \DTLifnull{\Parent}% + {% +% \end{macrocode} +% If there's no location, but there is a current location, then +% document needs updating. +% \begin{macrocode} + \DTLifnull\Location + {% + \DTLifnull\CurrentLocation + {% + }% + {% +% \end{macrocode} +% We have a current location but not a location. +% \begin{macrocode} + \global\let\@datagidx@dorerun@warn\@data@rerun@warn + }% + }% + {% +% \end{macrocode} +% We have a location. Is it up-to-date? +% \begin{macrocode} + \ifcsdef{datagidx@prev@loc@\Label}% + {% +% \end{macrocode} +% Current location was saved in the previous run. Has it changed? +%\changes{2.15}{2013-07-10}{expanded and sanitize locations before +%comparing them}% +% \begin{macrocode} + \protected@edef\@prev@location{% + \csname datagidx@prev@loc@\Label\endcsname}% + \@onelevel@sanitize\@prev@location + \protected@edef\@cur@location{\CurrentLocation}% + \@onelevel@sanitize\@cur@location + \ifdefequal{\@prev@location}{\@cur@location}% + {}% + {% + \global\let\@datagidx@dorerun@warn\@data@rerun@warn + }% + }% + {% +% \end{macrocode} +% Current location wasn't saved last run, so rerun required. +% \begin{macrocode} + \global\let\@datagidx@dorerun@warn\@data@rerun@warn + }% + }% + \datagidx@doifdisplayed + {% +% \end{macrocode} +% Write current location to file to compare current and previous +% lists. (Can't compare \cs{Location} with \cs{CurrentLocation} as +% there may be locations occurring across a page boundary.) +% \begin{macrocode} + \edef\datagidx@dowrite{% + \noexpand\protected@write\noexpand\@auxout{}% + {% + \string\datagidx@save@loc{\Label}{\CurrentLocation}% + }% + }% + \datagidx@dowrite +% \end{macrocode} +% Initialise level. +% \begin{macrocode} + \datagidx@level=1\relax + \expandafter\datagidx@getgroup\Sort{}\datagidx@endgetgroup + #1% + \global\let\datagidxprevgroup\datagidxcurrentgroup + }% + }% + {}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@doifdisplayed} +%\begin{definition} +%\cs{datagidx@doifdisplayed}\marg{body} +%\end{definition} +% Do \meta{body} if entry should appear in the glossary/index. +% \cs{Location}, \cs{See} and \cs{SeeAlso} must be set before use. +% \begin{macrocode} +\newcommand{\datagidx@doifdisplayed}[1]{% + \DTLifnull{\Location}% + {% + \DTLifnull{\See} + {% + \DTLifnull{\SeeAlso}{}% + {% + #1% + }% + }% + {% +% \end{macrocode} +% "See" is not null, but have any of the cross-referenced items been +% used? +% \begin{macrocode} + \@for\dtl@thislabel:=\See\do + {% +% \end{macrocode} +% Does the cross-referenced term exist? +% \begin{macrocode} + \iftermexists{\dtl@thislabel}% + {% +% \end{macrocode} +% Has it been used? +% \begin{macrocode} + \ifentryused{\dtl@thislabel}% + {% + #1% +% \end{macrocode} +% Break out of loop. +% \begin{macrocode} + \@endfortrue + }% + {}% + }% + {% + }% + }% + }% + }% + {% + #1% + }% +}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\datagidx@level} +% Keep track of current level +% \begin{macrocode} +\newcount\datagidx@level +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</datagidx.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*databib.sty> +% \end{macrocode} +%\fi +%\chapter{databib.sty} +%\label{sec:src:databib} +%\section{Package Declaration} +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{databib}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Load required packages: +% \begin{macrocode} +\RequirePackage{datatool} +% \end{macrocode} +%\section{Package Options} +%\begin{macro}{\dtlbib@style} +%The default bib style is stored in \cs{dtlbib@style}. +% \begin{macrocode} +\newcommand*{\dtlbib@style}{plain} +% \end{macrocode} +%\end{macro} +% The \pkgopt[databib]{style} package option sets \cs{dtlbib@style}. +% \begin{macrocode} +\define@choicekey{databib.sty}{style}{plain,abbrv,alpha}{% +\def\dtlbib@style{#1}} +% \end{macrocode} +% Process package options: +% \begin{macrocode} +\ProcessOptionsX +% \end{macrocode} +%\section{Loading BBL file} +%\begin{macro}{\DTLloadbbl} +%\begin{definition} +%\cs{DTLloadbib}\oarg{bbl file}\marg{db name}\marg{bib list} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLloadbbl}[3][\jobname.bbl]{% +\bibliographystyle{databib}% +\if@filesw + \immediate\write\@auxout{\string\bibdata{#3}}% +\fi +\DTLnewdb{#2}% +\edef\DTLBIBdbname{#2}% +\@input@{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLnewbibrow} +% \cs{DTLnewbibrow} adds a new row to the bibliography database. +% (\cs{DTLBIBdbname} must be set prior to use to the name +% of the \sty{datatool} database which must exist. Any check +% to determine its existence should be performed when +% \cs{DTLBIBdbname} is set.) +%\changes{1.03}{2009 January 27}{removed check if database exists} +% \begin{macrocode} +\newcommand*{\DTLnewbibrow}{\@DTLnewrow{\DTLBIBdbname}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLnewbibitem} +%\begin{definition} +%\cs{DTLnewbibitem}\marg{key}\marg{value} +%\end{definition} +% Adds a new database entry with the given key and value. +%\changes{1.03}{2009 January 27}{removed check if database exists} +% \begin{macrocode} +\newcommand*{\DTLnewbibitem}[2]{% + \@DTLnewdbentry{\DTLBIBdbname}{#1}{#2}} +% \end{macrocode} +%\end{macro} +%\section{Predefined text} +%\label{sec:src:bibnames} +%\begin{macro}{\andname} +% \begin{macrocode} +\providecommand*{\andname}{and} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ofname} +% \begin{macrocode} +\providecommand*{\ofname}{of} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\inname} +% \begin{macrocode} +\providecommand*{\inname}{in} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\etalname} +% \begin{macrocode} +\providecommand*{\etalname}{et al.} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\editorname} +% \begin{macrocode} +\providecommand*{\editorname}{editor} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\editorsname} +% \begin{macrocode} +\providecommand*{\editorsname}{editors} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\volumename} +% \begin{macrocode} +\providecommand*{\volumename}{volume} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\numbername} +% \begin{macrocode} +\providecommand*{\numbername}{number} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pagesname} +% \begin{macrocode} +\providecommand*{\pagesname}{pages} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pagename} +% \begin{macrocode} +\providecommand*{\pagename}{page} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\editionname} +% \begin{macrocode} +\providecommand*{\editionname}{edition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\techreportname} +% \begin{macrocode} +\providecommand*{\techreportname}{Technical report} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\mscthesisname} +% \begin{macrocode} +\providecommand*{\mscthesisname}{Master's thesis} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\phdthesisname} +% \begin{macrocode} +\providecommand*{\phdthesisname}{PhD thesis} +% \end{macrocode} +%\end{macro} +% +% +%\section{Displaying the bibliography} +%\label{sec:src:displaybib} +%\begin{definition} +%\cs{DTLbibliography}\marg{bib dbname} +%\end{definition} +% Displays the bibliography for the database \meta{bib dbname} +% which must have previously been loaded using +% \cs{DTLloadbbl}. +%\begin{macro}{\DTLbibliography} +% \begin{macrocode} +\newcommand*{\DTLbibliography}[2][\boolean{true}]{% + \begin{DTLthebibliography}[#1]{#2}% + \DTLforeachbibentry[#1]{#2}{% + \DTLbibitem \DTLformatbibentry \DTLendbibitem + }% + \end{DTLthebibliography}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatbibentry} +%\begin{definition} +%\cs{DTLformatbibentry} +%\end{definition} +% Formats the current bib entry. +% \begin{macrocode} +\newcommand*{\DTLformatbibentry}{% +% \end{macrocode} +% Check format for this type is defined. +% \begin{macrocode} + \@ifundefined{DTLformat\DBIBentrytype}% + {% + \PackageError{databib}{Don't know how to format bibliography + entries of type `\DBIBentrytype'}{}% + }% + {% +% \end{macrocode} +% Print information to terminal and log file if in verbose mode. +% \begin{macrocode} + \dtl@message{[\DBIBcitekey]}% +% \end{macrocode} +% Initialise +% \begin{macrocode} + \DTLstartsentencefalse\DTLmidsentencefalse\DTLperiodfalse +% \end{macrocode} +% Format this entry +% \begin{macrocode} + \csname DTLformat\DBIBentrytype\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\gDTLformatbibentry} +%\begin{definition} +%\cs{gDTLformatbibentry} +%\end{definition} +%\changes{2.21}{2014-03-08}{new} +% Global version. +% \begin{macrocode} +\newcommand*{\gDTLformatbibentry}{% +% \end{macrocode} +% Check format for this type is defined. +% \begin{macrocode} + \@ifundefined{DTLformat\DBIBentrytype}% + {% + \PackageError{databib}{Don't know how to format bibliography + entries of type `\DBIBentrytype'}{}% + }% + {% +% \end{macrocode} +% Print information to terminal and log file if in verbose mode. +% \begin{macrocode} + \dtl@message{[\DBIBcitekey]}% +% \end{macrocode} +% Initialise +% \begin{macrocode} + \global\DTLstartsentencefalse + \global\DTLmidsentencefalse + \global\DTLperiodfalse +% \end{macrocode} +% Format this entry +% \begin{macrocode} + \csname DTLformat\DBIBentrytype\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatthisbibentry} +%\begin{definition} +%\cs{DTLformatthisbibentry}\marg{db}\marg{cite key} +%\end{definition} +%\changes{2.22}{2014-06-10}{new} +% Just does \cs{DTLformatbibentry} for a given entry. +% \begin{macrocode} +\newcommand*{\DTLformatthisbibentry}[2]{% + \edef\DBIBname{#1}% + \edef\DBIBcitekey{#2}% + \edtlgetrowforvalue{#1}{\dtlcolumnindex{#1}{CiteKey}}{\DBIBcitekey}% + \dtl@gathervalues{#1}{\dtlcurrentrow}% + \letcs{\DBIBentrytype}{@dtl@key@EntryType}% + \DTLformatbibentry +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLendbibitem} +% Hook to add extra information at the end of a bibliography item. +% This does nothing by default. +% \begin{macrocode} +\newcommand*{\DTLendbibitem}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLwidest} +%Define a length to store the widest bib entry label +% \begin{macrocode} +\newlength\dtl@widest +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLcomputewidestbibentry} +%\begin{definition} +%\cs{DTLcomputewidestbibentry}\marg{conditions}\marg{db +%name}\marg{bib label}\marg{cmd} +%\end{definition} +%Computes the widest bibliography entry over all entries satisfying +%\meta{condition} for the database called \meta{db name}, where +% the bibliography label is formated according to \meta{bib label} and +% stores the result in \meta{cmd} which must be a command name. +% \begin{macrocode} +\newcommand*{\DTLcomputewidestbibentry}[4]{% +\dtl@widest=0pt\relax +\let#4=\@empty +\DTLforeachbibentry[#1]{#2}{% +\settowidth{\dtl@tmplength}{#3}% +\ifdim\dtl@tmplength>\dtl@widest\relax + \dtl@widest=\dtl@tmplength + \protected@edef#4{#3}% +\fi +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLforeachbibentry} +%\begin{definition} +%\cs{DTLforeachbibentry}\oarg{condition}\marg{db name}\marg{text} +%\end{definition} +%\begin{definition} +%\cs{DTLforeachbibentry*}\oarg{condition}\marg{db name}\marg{text} +%\end{definition} +% Iterates through the database called \meta{db name} and does +% \meta{text} if \meta{condition} is met. As with +% \cs{DTLforeach}, the starred version is read only. +%\changes{2.21}{2014-03-08}{fixed bug in starred version} +% \begin{macrocode} +\newcommand*{\DTLforeachbibentry}{% +\@ifstar\@sDTLforeachbibentry\@DTLforeachbibentry} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@DTLforeachbibentry} +% Unstarred version +% \begin{macrocode} +\newcommand*{\@DTLforeachbibentry}[3][\boolean{true}]{% +% \end{macrocode} +% Store database name. +% \begin{macrocode} + \edef\DBIBname{#2}% +% \end{macrocode} +% Reset row counter. +% \begin{macrocode} + \setcounter{DTLbibrow}{0}% +% \end{macrocode} +% Iterate through the database. +% \begin{macrocode} + \@DTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@sDTLforeachbibentry} +% Starred version +% \begin{macrocode} +\newcommand*{\@sDTLforeachbibentry}[3][\boolean{true}]{% +% \end{macrocode} +% Store database name. +% \begin{macrocode} + \edef\DBIBname{#2}% +% \end{macrocode} +% Reset row counter. +% \begin{macrocode} + \setcounter{DTLbibrow}{0}% +% \end{macrocode} +% Iterate through the database (read only). +% \begin{macrocode} + \@sDTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}{\refstepcounter{DTLbibrow}#3}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\gDTLforeachbibentry} +%\begin{definition} +%\cs{gDTLforeachbibentry}\oarg{condition}\marg{db name}\marg{text} +%\end{definition} +%\begin{definition} +%\cs{gDTLforeachbibentry*}\oarg{condition}\marg{db name}\marg{text} +%\end{definition} +% Global version. +%\changes{2.21}{2014-03-08}{new} +% \begin{macrocode} +\newcommand{\gDTLforeachbibentry}{% +\@ifstar\@sgDTLforeachbibentry\@gDTLforeachbibentry} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@gDTLforeachbibentry} +%\changes{2.21}{2014-03-08}{new} +% Unstarred version +% \begin{macrocode} +\newcommand*{\@gDTLforeachbibentry}[3][\boolean{true}]{% +% \end{macrocode} +% Store database name. +% \begin{macrocode} + \xdef\DBIBname{#2}% +% \end{macrocode} +% Reset row counter. +% \begin{macrocode} + \global\c@DTLbibrow = 0\relax +% \end{macrocode} +% Iterate through the database. +% \begin{macrocode} + \@DTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@g@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}% + {% + \refstepcounter{DTLbibrow}% + \global\c@DTLbibrow=\c@DTLbibrow + #3% + }% + {}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@sgDTLforeachbibentry} +%\changes{2.21}{2014-03-08}{new} +% Starred version +% \begin{macrocode} +\newcommand*{\@sgDTLforeachbibentry}[3][\boolean{true}]{% +% \end{macrocode} +% Store database name. +% \begin{macrocode} + \xdef\DBIBname{#2}% +% \end{macrocode} +% Reset row counter. +% \begin{macrocode} + \global\c@DTLbibrow = 0\relax +% \end{macrocode} +% Iterate through the database (read only). +% \begin{macrocode} + \@sDTLforeach{#2}{\DBIBcitekey=CiteKey,\DBIBentrytype=EntryType}% + {% + \dtl@g@gathervalues{#2}{\dtlcurrentrow}% + \ifthenelse{#1}% + {% + \refstepcounter{DTLbibrow}% + \global\c@DTLbibrow=\c@DTLbibrow + #3% + }% + {}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{counter}{DTLbibrow} +%The counter \ctrfmt{DTLbibrow} keeps track of the current +%row in the body of \cs{DTLforeachbibentry}. (You can't rely on +%\ctr{DTLrowi}, \ctr{DTLrowii} and +% \ctr{DTLrowiii}, as \cs{DTLforeachbibentry} pass the +% conditions to the optional argument of \cs{DTLforeach}, but +% instead uses \cs{ifthenelse}, which means that \ctr{DTLrowi} +% etc will be incremented, even when the given condition is not met.) +% \begin{macrocode} +\newcounter{DTLbibrow} +% \end{macrocode} +%\end{counter} +%\begin{macro}{\theHDTLbibrow} +% Keep \sty{hyperref} happy: +% \begin{macrocode} +\def\theHDTLbibrow{\theHDTLrow.bib.\arabic{DTLbibrow}}% +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibfield} +%\begin{definition} +%\cs{DTLbibfield}\marg{field name} +%\end{definition} +% Gets the value assigned to the field \meta{field name} for +% the current row of \cs{DTLforeachbibentry}. (Doesn't check if +% the field exists, or if it is being used within +% \cs{DTLforeachbibentry}.) +% \begin{macrocode} +\newcommand*{\DTLbibfield}[1]{\csname @dtl@key@#1\endcsname} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLbibfieldlet} +%\begin{definition} +%\cs{DTLbibfield}\marg{cs}\marg{field name} +%\end{definition} +% Gets the value assigned to the field \meta{field name} for +% the current row of \cs{DTLforeachbibentry} and assigns it to the +% control sequence \meta{cs}. (Doesn't check if +% the field exists, or if it is being used within +% \cs{DTLforeachbibentry}.) +% \begin{macrocode} +\newcommand*{\DTLbibfieldlet}[2]{% + \letcs{#1}{@dtl@key@#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLifbibfieldexists} +%\begin{definition} +%\cs{DTLifbibfieldexists}\marg{field name}\marg{true part}\marg{false +%part} +%\end{definition} +%Determines whether the given field name exists for the current +% row of \cs{DTLforeachbibentry}. +% \begin{macrocode} +\newcommand*{\DTLifbibfieldexists}[3]{% +\@ifundefined{@dtl@key@#1}{#3}{% +\expandafter\DTLifnull\csname @dtl@key@#1\endcsname +{#3}{#2}}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLifanybibfieldexists} +%\begin{definition} +%\cs{DTLifanybibfieldexists}\marg{list of field name}\marg{true part}\marg{false +%part} +%\end{definition} +% Determines whether any of the listed fields exist for the current +% row of \cs{DTLforeachbibentry}. +% \begin{macrocode} +\newcommand*{\DTLifanybibfieldexists}[3]{% +\@for\dtl@thisfield:=#1\do{% +\@ifundefined{@dtl@key@\dtl@thisfield}{}{% +\expandafter\DTLifnull\csname @dtl@key@\dtl@thisfield\endcsname +{}{% +\@endfortrue}}}% +\if@endfor + #2% +\else + #3% +\fi +\@endforfalse +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifDTLperiod} +% The conditional \cs{ifDTLperiod} is used to keep track of any +% abbreviations ending with a period, this is to ensure that +% abbreviations aren't followed by a full stop if they already +% have a full stop terminating the abbreviation. +% \begin{macrocode} +\newif\ifDTLperiod +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLcheckendsperiod} +%\begin{definition} +%\cs{DTLcheckendperiod}\marg{string} +%\end{definition} +% Checks if \meta{string} ends with a full stop. This sets +% \cs{ifDTLperiod}. +% \begin{macrocode} +\newcommand*{\DTLcheckendsperiod}[1]{% +\dtl@checkendsperiod#1\@nil\relax} +% \end{macrocode} +% \begin{macrocode} +\def\dtl@checkendsperiod#1#2{% +\def\@dtl@argi{#1}\def\@dtl@argii{#2}% +\def\@dtl@period{.}% +\ifx\@dtl@argi\@nnil + \global\DTLperiodfalse + \let\@dtl@donext=\relax +\else + \ifx\@dtl@argii\@nnil + \ifx\@dtl@argi\@dtl@period + \global\DTLperiodtrue + \else + \global\DTLperiodfalse + \fi + \let\@dtl@donext=\@gobble + \else + \let\@dtl@donext=\dtl@checkendsperiod + \fi +\fi +\@dtl@donext{#2}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLcheckbibfieldendsperiod} +%\begin{definition} +%\cs{DTLcheckbibfieldendperiod}\marg{label} +%\end{definition} +% Checks if the bib field \meta{label} ends with a full stop. +% This sets \cs{ifDTLperiod}. +% \begin{macrocode} +\newcommand*{\DTLcheckbibfieldendsperiod}[1]{% +\protected@edef\@dtl@tmp{\DTLbibfield{#1}}% +\expandafter\DTLcheckendsperiod\expandafter{\@dtl@tmp}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifDTLmidsentence} +%\begin{definition} +%\cs{ifDTLmidsentence} +%\end{definition} +% Determine whether we are in the middle +% of a sentence. +% \begin{macrocode} +\newif\ifDTLmidsentence +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLstartsentence} +%\begin{definition} +%\cs{ifDTLstartsentence} +%\end{definition} +% Determine whether we are at the start +% of a sentence. +% \begin{macrocode} +\newif\ifDTLstartsentence +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLaddperiod} +%\begin{definition} +%\cs{DTLaddperiod} +%\end{definition} +%Adds a full stop and sets \cs{DTLmidsentencefalse}, +%\cs{DTLstartsentencetrue} and +%\cs{DTLperiodfalse}. +% \begin{macrocode} +\newcommand*{\DTLaddperiod}{\DTLmidsentencefalse\DTLperiodfalse +\DTLstartsentencetrue +\ifDTLperiod\else.\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLaddcomma} +%\begin{definition} +%\cs{DTLaddcomma} +%\end{definition} +%Adds a comma and sets \cs{DTLmidsentencetrue}, \cs{DTLperiodfalse} +%and \cs{DTLstartsentencefalse} +% \begin{macrocode} +\newcommand*{\DTLaddcomma}{, \DTLmidsentencetrue +\DTLperiodfalse\DTLstartsentencefalse} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLstartsentencespace} +%Adds a space if at the start of the sentence, otherwise does +% nothing. (The space between sentences is added this way, rather +% than in \cs{DTLaddperiod} otherwise spurious extra space can +% occur at the end of the bib item. The spacefactor needs to be +% set manually, because there's stuff in the way of the previous +% sentence's full stop and this space which confuses the inter +% sentence spacing (and, of course, the previous sentence could +% have ended with a capital letter.) +% \begin{macrocode} +\newcommand*{\DTLstartsentencespace}{% +\ifDTLstartsentence\spacefactor=\sfcode`\.\relax\space +\fi\DTLstartsentencefalse} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtwoand} +% In a list of only two author (or editor) names, the text between the +% two names is given by \cs{DTLtwoand}: +% \begin{macrocode} +\newcommand*{\DTLtwoand}{\ \andname\ } +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLandlast} +% In a list of author (or editor) names, the text between the +% penultimate and last name is given by \cs{DTLandlast}: +% \begin{macrocode} +\newcommand*{\DTLandlast}{, \andname\ } +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLandnotlast} +% In a list of author (or editor) names, the text between the +% names (except the penultimate and last name) is given by +% \cs{DTLandnotlast}: +% \begin{macrocode} +\newcommand*{\DTLandnotlast}{, } +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@authorcount} +% Define a count register to keep track of the number of authors: +% \begin{macrocode} +\newcount\@dtl@authorcount +% \end{macrocode} +%\end{macro} +%\begin{counter}{DTLmaxauthors} +% The counter \ctrfmt{DTLmaxauthors} indicates the maximum number of +% author names to display, if there are more than that number, +% \cs{etalname} is used. +% \begin{macrocode} +\newcounter{DTLmaxauthors} +\setcounter{DTLmaxauthors}{10} +% \end{macrocode} +%\end{counter} +%\begin{macro}{\DTLformatauthorlist} +% Format a list of author names (the list is stored in +% \cs{@dtl@key@Author}): +% \begin{macrocode} +\newcommand*{\DTLformatauthorlist}{% +\DTLifbibfieldexists{Author}{% +\DTLstartsentencespace +\@dtl@authorcount=0\relax +\@for\@dtl@author:=\@dtl@key@Author\do{% +\advance\@dtl@authorcount by 1\relax}% +\@dtl@tmpcount=0\relax +\ifnum\@dtl@authorcount>\c@DTLmaxauthors +{% + \@for\@dtl@author:=\@dtl@key@Author\do{% + \advance\@dtl@tmpcount by 1\relax + \ifnum\@dtl@tmpcount=1\relax + \expandafter\DTLformatauthor\@dtl@author + \else + \ifnum\@dtl@tmpcount>\c@DTLmaxauthors + \DTLandnotlast \etalname + \expandafter\DTLcheckendsperiod\expandafter{\etalname}% + \@endfortrue + \else + \DTLandnotlast \expandafter\DTLformatauthor\@dtl@author + \fi + \fi + }% +}% +\else + \@for\@dtl@author:=\@dtl@key@Author\do{% + \advance\@dtl@tmpcount by 1\relax + \ifnum\@dtl@tmpcount=1\relax + \expandafter\DTLformatauthor\@dtl@author + \else + \ifnum\@dtl@tmpcount=\@dtl@authorcount + \ifnum\@dtl@authorcount=2\relax + \DTLtwoand + \else + \DTLandlast + \fi + \expandafter\DTLformatauthor\@dtl@author + \else + \DTLandnotlast \expandafter\DTLformatauthor\@dtl@author + \fi + \fi + }% +\fi +}{}% +} +% \end{macrocode} +%\end{macro} +%\begin{counter}{DTLmaxeditors} +% The counter \ctrfmt{DTLmaxeditors} indicates the maximum number of +% editor names to display, if there are more than that number, +% \cs{etalname} is used. +% \begin{macrocode} +\newcounter{DTLmaxeditors} +\setcounter{DTLmaxeditors}{10} +% \end{macrocode} +%\end{counter} +% +%\begin{macro}{\DTLformateditorlist} +% Format a list of editor names (the list is stored in +% \cs{@dtl@key@Editor}): +% \begin{macrocode} +\newcommand*{\DTLformateditorlist}{% +\DTLifbibfieldexists{Editor}{% +\DTLstartsentencespace +\@dtl@authorcount=0\relax +\@for\@dtl@author:=\@dtl@key@Editor\do{% +\advance\@dtl@authorcount by 1\relax}% +\@dtl@tmpcount=0\relax +\ifnum\@dtl@authorcount>\c@DTLmaxeditors +{% + \@for\@dtl@author:=\@dtl@key@Editor\do{% + \advance\@dtl@tmpcount by 1\relax + \ifnum\@dtl@tmpcount=1\relax + \expandafter\DTLformateditor\@dtl@author + \else + \ifnum\@dtl@tmpcount>\c@DTLmaxeditors + \DTLandnotlast \etalname + \expandafter\DTLcheckendsperiod\expandafter{\etalname}% + \@endfortrue + \else + \DTLandnotlast \expandafter\DTLformateditor\@dtl@author + \fi + \fi + }% +}% +\else +\@for\@dtl@author:=\@dtl@key@Editor\do{% + \advance\@dtl@tmpcount by 1\relax + \ifnum\@dtl@tmpcount=1\relax + \expandafter\DTLformateditor\@dtl@author + \else + \ifnum\@dtl@tmpcount=\@dtl@authorcount + \ifnum\@dtl@authorcount=2\relax + \DTLtwoand + \else + \DTLandlast + \fi + \expandafter\DTLformateditor\@dtl@author + \else + \DTLandnotlast \expandafter\DTLformateditor\@dtl@author + \fi + \fi + }% +\fi +, +\ifnum\@dtl@authorcount=1\relax + \editorname + \expandafter\DTLcheckendsperiod\expandafter{\editorname}% +\else + \editorsname + \expandafter\DTLcheckendsperiod\expandafter{\editorsname}% +\fi +}{}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLformatsurnameonly} +%\begin{definition} +%\cs{DTLformatsurnameonly}\marg{von part}\marg{surname}\marg{jr +%part}\marg{forenames} +%\end{definition} +% This is used when only the surname should be displayed. (The +% final argument, \meta{forenames}, is ignored.) +% \begin{macrocode} +\newcommand*{\DTLformatsurnameonly}[4]{% +\DTLstartsentencespace +\def\@dtl@tmp{#1}% +\ifx\@dtl@tmp\@empty\else#1~\fi +#2% +\def\@dtl@tmp{#3}% +\ifx\@dtl@tmp\@empty + \DTLcheckendsperiod{#2}% +\else + , #3% + \DTLcheckendsperiod{#3}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatforenames} +%\begin{definition} +%\cs{DTLformatforenames}\marg{forenames} +%\end{definition} +% The format of an author/editor's forenames. If the forenames +% occur at the start of sentence, a new sentence space is added. +% The argument is checked to determine whether it ends with a +% full stop (sometimes the forenames may include initials.) +% \begin{macrocode} +\newcommand*{\DTLformatforenames}[1]{% +\DTLstartsentencespace +#1% +\DTLcheckendsperiod{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatabbrvforenames} +%\begin{definition} +%\cs{DTLformatabbrvforenames}\marg{forenames} +%\end{definition} +% The format of an author/editor's abbreviated forenames. The initials +% may or may not end in a full stop depending on the commands +% governing the format of \cs{DTLstoreinitials}, so the initials +% need to be check using \cs{DTLcheckendsperiod}. +% \begin{macrocode} +\newcommand*{\DTLformatabbrvforenames}[1]{% +\DTLstartsentencespace +\DTLstoreinitials{#1}{\@dtl@tmp}\@dtl@tmp +\expandafter\DTLcheckendsperiod\expandafter{\@dtl@tmp}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatvon} +%\begin{definition} +%\cs{DTLformatvon}\marg{von part} +%\end{definition} +% The format of the ``von'' part. This does nothing if the argument +% is empty, otherwise it does the argument followed by a +% non-breakable space. +% \begin{macrocode} +\newcommand*{\DTLformatvon}[1]{% +\DTLstartsentencespace +\def\@dtl@tmp{#1}% +\ifx\@dtl@tmp\@empty +\else + #1~% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatsurname} +%\begin{definition} +%\cs{DTLformatsurname}\marg{surname} +%\end{definition} +% The format of an author/editor's surname. +% \begin{macrocode} +\newcommand*{\DTLformatsurname}[1]{% +\DTLstartsentencespace +#1\DTLcheckendsperiod{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatjr} +%\begin{definition} +%\cs{DTLformatjr}\marg{jr part} +%\end{definition} +% The format of the ``jr'' part. This does nothing if the +% argument is empty. +% \begin{macrocode} +\newcommand*{\DTLformatjr}[1]{% +\DTLstartsentencespace +\def\@dtl@tmp{#1}% +\ifx\@dtl@tmp\@empty +\else + , #1\DTLcheckendsperiod{#1}% +\fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatcrossrefeditor} +% Format cross reference editors: +% \begin{macrocode} +\newcommand*{\DTLformatcrossrefeditor}{% +\DTLifbibfieldexists{Editor}{% +\DTLstartsentencespace +\@dtl@authorcount=0\relax +\@for\@dtl@author:=\@dtl@key@Editor\do{% +\advance\@dtl@authorcount by 1\relax}% +{\@dtl@tmpcount=0\relax +\@for\@dtl@author:=\@dtl@key@Editor\do{% +\ifnum\@dtl@authorcount=1\relax + \expandafter\DTLformatsurnameonly\@dtl@author +\else + \advance\@dtl@tmpcount by 1\relax + \ifnum\@dtl@tmpcount=1\relax + \expandafter\DTLformatsurnameonly\@dtl@author + \else + \ifnum\@dtl@authorcount=2\relax + \ \andname\ \expandafter\DTLformatsurnameonly\@dtl@author + \else + \ \etalname + \expandafter\DTLcheckendsperiod\expandafter{\etalname} + \fi + \@endfortrue + \fi +\fi +}}% +}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatvolnumpages} +% Format volume, number and pages (of an article). +% \begin{macrocode} +\newcommand*{\DTLformatvolnumpages}{% +\DTLifbibfieldexists{Volume}{% +\DTLstartsentencespace +\DTLbibfield{Volume}\DTLperiodfalse}{}% +\DTLifbibfieldexists{Number}{% +\DTLstartsentencespace +(\DTLbibfield{Number})\DTLperiodfalse}{}% +\DTLifbibfieldexists{Pages}{% +\DTLifanybibfieldexists{Volume,Number}{:}{% +\DTLstartsentencespace +\protected@edef\@dtl@pages{0\DTLbibfield{Pages}}% +\DTLifnumerical{\@dtl@pages}{\pagename}{\pagesname}~}% +\DTLbibfield{Pages}\DTLperiodfalse}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatbvolume} +% Format book volume. +% \begin{macrocode} +\newcommand*{\DTLformatbvolume}{% +\DTLifbibfieldexists{Volume}{% +\ifDTLmidsentence + \volumename +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\volumename +\fi +~\DTLbibfield{Volume}% +\DTLifbibfieldexists{Series}{\ \ofname\ +{\em\DTLbibfield{Series}}\DTLcheckbibfieldendsperiod{Series}}{% +\DTLcheckbibfieldendsperiod{Volume}}% +}{}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatchapterpages} +% Format chapter and pages: +% \begin{macrocode} +\newcommand*{\DTLformatchapterpages}{% +\DTLifbibfieldexists{Chapter}{% +\DTLifbibfieldexists{Type}{% +\DTLstartsentencespace +\DTLbibfield{Type}}{% +\DTLstartsentencespace +\chaptername}~\DTLbibfield{Chapter}% +\DTLifbibfieldexists{Pages}{\DTLaddcomma}{% +\DTLcheckbibfieldendsperiod{Chapter}}}{}% +\DTLstartsentencespace +\DTLformatpages} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatpages} +% Format pages: +% \begin{macrocode} +\newcommand*{\DTLformatpages}{% +\DTLifbibfieldexists{Pages}{% +\DTLstartsentencespace +\protected@edef\@dtl@pages{0\DTLbibfield{Pages}}% +\DTLifnumerical{\@dtl@pages}{\pagename}{\pagesname}~% +\DTLbibfield{Pages}\DTLcheckbibfieldendsperiod{Pages}}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatnumberseries} +% Format number and series (of book) +% \begin{macrocode} +\newcommand*{\DTLformatnumberseries}{% +\DTLifbibfieldexists{Volume}{}{% +\DTLifbibfieldexists{Number}{% +\ifDTLmidsentence + \numbername +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\numbername +\fi~\DTLbibfield{Number}% +\DTLifbibfieldexists{Series}{\ \inname\ \DTLbibfield{Series}% +\DTLcheckbibfieldendsperiod{Series}}{% +\DTLcheckbibfieldendsperiod{Number}}% +}{% +\DTLifbibfieldexists{Series}{% +\DTLstartsentencespace +\DTLbibfield{Series}% +\DTLcheckbibfieldendsperiod{Series}}{}}% +}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLformatbookcrossref} +% Format a book cross reference. +% \begin{macrocode} +\newcommand*{\DTLformatbookcrossref}{% +\DTLifbibfieldexists{Volume}{% +\ifDTLmidsentence + \volumename +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\volumename +\fi +~\DTLbibfield{Volume}\ \ofname\ +}{% +\ifDTLmidsentence + \inname +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\inname +\fi\ }% +\DTLifbibfieldexists{Editor}{\DTLformatcrossrefeditor}{% +\DTLifbibfieldexists{Key}{% +\DTLbibfield{Key}}{% +\DTLifbibfieldexists{Series}{% +{\em\DTLbibfield{Series}}}{}% +}% +}% +~\DTLpcite{\DTLbibfield{CrossRef}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLformatincollproccrossref} +% Format `incollections' cross reference. +% \begin{macrocode} +\newcommand*{\DTLformatincollproccrossref}{% +\DTLifbibfieldexists{Editor}{% +\ifDTLmidsentence + \inname +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\inname +\fi\ +\DTLformatcrossrefeditor +}{% +\DTLifbibfieldexists{Key}{% +\ifDTLmidsentence + \inname +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\inname +\fi\ \DTLbibfield{Key}% +}{% +\DTLifbibfieldexists{BookTitle}{% +\ifDTLmidsentence + \inname +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\inname +\fi\ \DTLformatbooktitle{\DTLbibfield{BookTitle}}}{}% +}}% +~\DTLpcite{\DTLbibfield{CrossRef}}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatinedbooktitle} +%Format editor and booktitle: +% \begin{macrocode} +\newcommand*{\DTLformatinedbooktitle}{% +\DTLifbibfieldexists{BookTitle}{% +\ifDTLmidsentence + \inname +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\inname +\fi\ +\DTLifbibfieldexists{Editor}{% +\DTLformateditorlist\DTLaddcomma \DTLformatbooktitle{\DTLbibfield{BookTitle}}% +\DTLcheckbibfieldendsperiod{BookTitle}% +}{\DTLformatbooktitle{\DTLbibfield{BookTitle}}% +\DTLcheckbibfieldendsperiod{BookTitle}% +}}{}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatdate} +%Format date. +% \begin{macrocode} +\newcommand*{\DTLformatdate}{% +\DTLifbibfieldexists{Year}{% +\DTLifbibfieldexists{Month}{% +\protected@edef\@dtl@tmp{\DTLbibfield{Month}}% +\ifDTLmidsentence + \@dtl@tmp +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\@dtl@tmp +\fi\ +\DTLmidsentencefalse}{}% +\DTLstartsentencespace +\DTLbibfield{Year}}{% +\DTLifbibfieldexists{Month}{% +\protected@edef\@dtl@tmp{\DTLbibfield{Month}}% +\ifDTLmidsentence + \@dtl@tmp +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\@dtl@tmp +\fi +\DTLcheckbibfieldendsperiod{Month}% +}{}}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLformatarticlecrossref} +% Format article cross reference. +% \begin{macrocode} +\newcommand*{\DTLformatarticlecrossref}{% +\DTLifbibfieldexists{Key}{% +\ifDTLmidsentence + \inname +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\inname +\fi +\ {\em\DTLbibfield{Key}}}{% +\DTLifbibfieldexists{Journal}{% +\ifDTLmidsentence + \inname +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\inname +\fi +\ {\em\DTLbibfield{Journal}}}{}}% +~\DTLpcite{\DTLbibfield{CrossRef}}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLpcite} +%\changes{2.22}{2014-06-10}{new} +% \begin{macrocode} +\newrobustcmd*{\DTLpcite}[1]{% + \protected@edef\@dtl@tmp{#1}% + \cite{\@dtl@tmp}% +} +% \end{macrocode} +%\end{macro} +% +%\subsection{ifthen conditionals} +% The conditionals defined in this section may be used in the +% optional argument of \cs{DTLforeachbibentry}. They may also be +% used in the first argument of \cs{ifthenelse}, but only if the +% command occurs within the body of \cs{DTLforeachbibentry}. +% +%\begin{macro}{\DTLbibfieldexists} +%\begin{definition} +%\cs{DTLbibfieldexists}\marg{field label} +%\end{definition} +% Checks if named bib field exists for current entry +% \begin{macrocode} +\newcommand*{\DTLbibfieldexists}[1]{% +\TE@throw\noexpand\dtl@testbibfieldexists{#1}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testbibfieldexists} +% \begin{macrocode} +\newcommand*{\dtl@testbibfieldexists}[1]{% +\DTLifbibfieldexists{#1}{\@dtl@conditiontrue}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibfieldiseq} +%\begin{definition} +%\cs{DTLbibfieldiseq}\marg{field label}\marg{value} +%\end{definition} +% Checks if the value of the bib field given by \meta{field label} +% is equal to \meta{value}. (Uses \cs{dtlcompare} to determine if +% the values are equal. If the bib field doesn't exist, the +% condition is false.) +% \begin{macrocode} +\newcommand*{\DTLbibfieldiseq}[2]{% +\TE@throw\noexpand\dtl@testbibfieldiseq{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testbibfieldiseq} +% \begin{macrocode} +\newcommand*{\dtl@testbibfieldiseq}[2]{% +\DTLifbibfieldexists{#1}{% +\expandafter\let\expandafter\@dtl@tmp\expandafter + =\csname @dtl@key@#1\endcsname +\expandafter\toks@\expandafter{\@dtl@tmp}% +\@dtl@toks{#2}% +\edef\@dtl@docompare{\noexpand\dtlcompare{\noexpand\@dtl@tmpcount}% +{\the\toks@}{\the\@dtl@toks}}% +\@dtl@docompare +\ifnum\@dtl@tmpcount=0\relax + \@dtl@conditiontrue +\else + \@dtl@conditionfalse +\fi +}{% +\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibfieldislt} +%\begin{definition} +%\cs{DTLbibfieldislt}\marg{field label}\marg{value} +%\end{definition} +% Checks if the value of the bib field given by \meta{field label} +% is less than \meta{value}. (If the bib field doesn't exist, the +% condition is false.) +% \begin{macrocode} +\newcommand*{\DTLbibfieldislt}[2]{% +\TE@throw\noexpand\dtl@testbibfieldislt{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testbibfieldislt} +% \begin{macrocode} +\newcommand*{\dtl@testbibfieldislt}[2]{% +\DTLifbibfieldexists{#1}{% +\expandafter\let\expandafter\@dtl@tmp\expandafter + =\csname @dtl@key@#1\endcsname +\expandafter\toks@\expandafter{\@dtl@tmp}% +\@dtl@toks{#2}% +\edef\@dtl@docompare{\noexpand\dtlcompare{\noexpand\@dtl@tmpcount}% +{\the\toks@}{\the\@dtl@toks}}% +\@dtl@docompare +\ifnum\@dtl@tmpcount=-1\relax + \@dtl@conditiontrue +\else + \@dtl@conditionfalse +\fi +}{% +\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibfieldisle} +%\begin{definition} +%\cs{DTLbibfieldisle}\marg{field label}\marg{value} +%\end{definition} +% Checks if the value of the bib field given by \meta{field label} +% is less than or equal to \meta{value}. +% (If the bib field doesn't exist, the +% condition is false.) +% \begin{macrocode} +\newcommand*{\DTLbibfieldisle}[2]{% +\TE@throw\noexpand\dtl@testbibfieldisle{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testbibfieldisle} +% \begin{macrocode} +\newcommand*{\dtl@testbibfieldisle}[2]{% +\DTLifbibfieldexists{#1}{% +\expandafter\let\expandafter\@dtl@tmp\expandafter + =\csname @dtl@key@#1\endcsname +\expandafter\toks@\expandafter{\@dtl@tmp}% +\@dtl@toks{#2}% +\edef\@dtl@docompare{\noexpand\dtlcompare{\noexpand\@dtl@tmpcount}% +{\the\toks@}{\the\@dtl@toks}}% +\@dtl@docompare +\ifnum\@dtl@tmpcount<1\relax + \@dtl@conditiontrue +\else + \@dtl@conditionfalse +\fi +}{% +\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibfieldisgt} +%\begin{definition} +%\cs{DTLbibfieldisgt}\marg{field label}\marg{value} +%\end{definition} +% Checks if the value of the bib field given by \meta{field label} +% is greater than \meta{value}. (If the bib field doesn't exist, the +% condition is false.) +% \begin{macrocode} +\newcommand*{\DTLbibfieldisgt}[2]{% +\TE@throw\noexpand\dtl@testbibfieldisgt{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testbibfieldisgt} +% \begin{macrocode} +\newcommand*{\dtl@testbibfieldisgt}[2]{% +\DTLifbibfieldexists{#1}{% +\expandafter\let\expandafter\@dtl@tmp\expandafter + =\csname @dtl@key@#1\endcsname +\expandafter\toks@\expandafter{\@dtl@tmp}% +\@dtl@toks{#2}% +\edef\@dtl@docompare{\noexpand\dtlcompare{\noexpand\@dtl@tmpcount}% +{\the\toks@}{\the\@dtl@toks}}% +\@dtl@docompare +\ifnum\@dtl@tmpcount=1\relax + \@dtl@conditiontrue +\else + \@dtl@conditionfalse +\fi +}{% +\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibfieldisge} +%\begin{definition} +%\cs{DTLbibfieldisge}\marg{field label}\marg{value} +%\end{definition} +% Checks if the value of the bib field given by \meta{field label} +% is less than or equal to \meta{value}. +% (If the bib field doesn't exist, the +% condition is false.) +% \begin{macrocode} +\newcommand*{\DTLbibfieldisge}[2]{% +\TE@throw\noexpand\dtl@testbibfieldisge{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testbibfieldisge} +% \begin{macrocode} +\newcommand*{\dtl@testbibfieldisge}[2]{% +\DTLifbibfieldexists{#1}{% +\expandafter\let\expandafter\@dtl@tmp\expandafter + =\csname @dtl@key@#1\endcsname +\expandafter\toks@\expandafter{\@dtl@tmp}% +\@dtl@toks{#2}% +\edef\@dtl@docompare{\noexpand\dtlcompare{\noexpand\@dtl@tmpcount}% +{\the\toks@}{\the\@dtl@toks}}% +\@dtl@docompare +\ifnum\@dtl@tmpcount>-1\relax + \@dtl@conditiontrue +\else + \@dtl@conditionfalse +\fi +}{% +\@dtl@conditionfalse}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibfieldcontains} +%\begin{definition} +%\cs{DTLbibfieldcontains}\marg{field label}\marg{sub string} +%\end{definition} +% Checks if the value of the bib field given by \meta{field label} +% contains \meta{sub string}. +% (If the bib field doesn't exist, the +% condition is false.) +% \begin{macrocode} +\newcommand*{\DTLbibfieldcontains}[2]{% +\TE@throw\noexpand\dtl@testbibfieldcontains{#1}{#2}% +\noexpand\if@dtl@condition} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@testbibfieldcontains} +% \begin{macrocode} +\newcommand*{\dtl@testbibfieldcontains}[2]{% +\DTLifbibfieldexists{#1}{% +\expandafter\let\expandafter\@dtl@tmp\expandafter + =\csname @dtl@key@#1\endcsname +\expandafter\dtl@testifsubstring\expandafter{\@dtl@tmp}{#2}% +}{\@dtl@conditionfalse}} +% \end{macrocode} +%\end{macro} +% +%\section{Bibliography Style Macros} +%\label{sec:src:bibstyle} +% The macros defined in this section should be redefined by +% bibliography styles. +% +%\begin{environment}{DTLthebibliography} +% How to format the entire bibliography: +% \begin{macrocode} +\newenvironment{DTLthebibliography}[2][\boolean{true}]{% +\@dtl@tmpcount=0\relax +\@sDTLforeach[#1]{#2}{}{\advance\@dtl@tmpcount by 1\relax}% +\begin{thebibliography}{\number\@dtl@tmpcount} +}{\end{thebibliography}} +% \end{macrocode} +%\end{environment} +%\begin{macro}{\DTLmonthname} +% The monthname style. The argument must be a number from~1 +% to~12. By default, uses \cs{dtl@monthname}. +% \begin{macrocode} +\newcommand*{\DTLmonthname}[1]{% +\dtl@monthname{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@monthname} +% Full month names: +% \begin{macrocode} +\newcommand*{\dtl@monthname}[1]{% +\ifcase#1% +\or January% +\or February% +\or March% +\or April% +\or May% +\or June% +\or July% +\or August% +\or September% +\or October% +\or November% +\or December% +\fi} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@abbrvmonthname} +% Abbreviated months: +% \begin{macrocode} +\newcommand*{\dtl@abbrvmonthname}[1]{% +\ifcase#1% +\or Jan.% +\or Feb.% +\or Mar.% +\or Apr.% +\or May% +\or June% +\or July% +\or Aug.% +\or Sept.% +\or Oct.% +\or Nov.% +\or Dec.% +\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbibitem} +% Define how to start a new bibitem: +% \begin{macrocode} +\newcommand*{\DTLbibitem}{\bibitem{\DBIBcitekey}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmbibitem} +% As \cs{DTLbibitem} but for \cs{DTLmbibliography} +% \begin{macrocode} +\newcommand*{\DTLmbibitem}[1]{\bibitem{#1@\DBIBcitekey}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLcustombibitem} +%\changes{2.22}{2014-06-10}{new} +%\begin{definition} +%\cs{DTLcustombibitem}\marg{item code}\marg{ref text}\marg{cite key} +%\end{definition} +% As \cs{DTLbibitem} but user provides \meta{item code} to use in place of +% \cs{item}. This code can access the cite key using +% \cs{DBIBcitekey}. The \meta{ref text} is the text associated with +% this bib item. (For example, if used in an enumerate environment, +% \meta{ref text} might be \verb|\theenumi|.) +% \begin{macrocode} +\newcommand*{\DTLcustombibitem}[3]{% + #1% + \if@filesw + \immediate\write\@auxout{\string\bibcite{#3}{#2}}% + \fi + \ignorespaces +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatauthor} +%\begin{definition} +%\cs{DTLformatauthor}\marg{von part}\marg{surname}\marg{junior +%part}\marg{forenames} +%\end{definition} +% The format of an author's name. +% \begin{macrocode} +\newcommand*{\DTLformatauthor}[4]{% +\DTLformatforenames{#4} +\DTLformatvon{#1}% +\DTLformatsurname{#2}% +\DTLformatjr{#3}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformateditor} +% The format of an editor's name. +% \begin{macrocode} +\newcommand*{\DTLformateditor}[4]{% +\DTLformatforenames{#4} +\DTLformatvon{#1}% +\DTLformatsurname{#2}% +\DTLformatjr{#3}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatedition} +% The format of an edition: +% \begin{macrocode} +\newcommand*{\DTLformatedition}[1]{#1 \editionname} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatarticle} +% The format of an article: +% \begin{macrocode} +\newcommand{\DTLformatarticle}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatbook} +% The format of a book: +% \begin{macrocode} +\newcommand{\DTLformatbook}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatbooklet} +% The format of a booklet: +% \begin{macrocode} +\newcommand{\DTLformatbooklet}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatinbook} +% The format of an ``inbook'' type: +% \begin{macrocode} +\newcommand{\DTLformatinbook}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatincollection} +% The format of an ``incollection'' type: +% \begin{macrocode} +\newcommand{\DTLformatincollection}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatinproceedings} +% The format of an ``inproceedings'' type: +% \begin{macrocode} +\newcommand{\DTLformatinproceedings}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatmanual} +% The format of a manual: +% \begin{macrocode} +\newcommand{\DTLformatmanual}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatmastersthesis} +% The format of a master's thesis: +% \begin{macrocode} +\newcommand{\DTLformatmastersthesis}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatmisc} +% The format of a miscellaneous entry: +% \begin{macrocode} +\newcommand{\DTLformatmisc}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatphdthesis} +% The format of a Ph.D. thesis: +% \begin{macrocode} +\newcommand{\DTLformatphdthesis}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatproceedings} +% The format of a proceedings: +% \begin{macrocode} +\newcommand{\DTLformatproceedings}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformattechreport} +% The format of a technical report: +% \begin{macrocode} +\newcommand{\DTLformattechreport}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLformatunpublished} +% The format of an unpublished work: +% \begin{macrocode} +\newcommand{\DTLformatunpublished}{} +% \end{macrocode} +%\end{macro} +% +% Predefined names (these correspond to the standard \BibTeX\ +% predefined strings of the same name without the leading +% \cs{DTL}): +%\begin{macro}{\DTLacmcs} +% \begin{macrocode} +\newcommand*{\DTLacmcs}{ACM Computing Surveys} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLacta} +% \begin{macrocode} +\newcommand*{\DTLacta}{Acta Informatica} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLcacm} +% \begin{macrocode} +\newcommand*{\DTLcacm}{Communications of the ACM} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLibmjrd} +% \begin{macrocode} +\newcommand*{\DTLibmjrd}{IBM Journal of Research and Development} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLibmsj} +% \begin{macrocode} +\newcommand*{\DTLibmsj}{IBM Systems Journal} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLieeese} +% \begin{macrocode} +\newcommand*{\DTLieeese}{IEEE Transactions on Software Engineering} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLieeetc} +% \begin{macrocode} +\newcommand*{\DTLieeetc}{IEEE Transactions on Computers} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLieeetcad} +% \begin{macrocode} +\newcommand*{\DTLieeetcad}{IEEE Transactions on Computer-Aided Design +of Integrated Circuits} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLipl} +% \begin{macrocode} +\newcommand*{\DTLipl}{Information Processing Letters} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLjacm} +% \begin{macrocode} +\newcommand*{\DTLjacm}{Journal of the ACM} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLjcss} +% \begin{macrocode} +\newcommand*{\DTLjcss}{Journal of Computer and System Sciences} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLscp} +% \begin{macrocode} +\newcommand*{\DTLscp}{Science of Computer Programming} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsicomp} +% \begin{macrocode} +\newcommand*{\DTLsicomp}{SIAM Journal on Computing} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtocs} +% \begin{macrocode} +\newcommand*{\DTLtocs}{ACM Transactions on Computer Systems} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtods} +% \begin{macrocode} +\newcommand*{\DTLtods}{ACM Transactions on Database Systems} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtog} +% \begin{macrocode} +\newcommand*{\DTLtog}{ACM Transactions on Graphics} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtoms} +% \begin{macrocode} +\newcommand*{\DTLtoms}{ACM Transactions on Mathematical Software} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtoois} +% \begin{macrocode} +\newcommand*{\DTLtoois}{ACM Transactions on Office Information +Systems} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtoplas} +% \begin{macrocode} +\newcommand*{\DTLtoplas}{ACM Transactions on Programming Languages +and Systems} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLtcs} +% \begin{macrocode} +\newcommand*{\DTLtcs}{Theoretical Computer Science} +% \end{macrocode} +%\end{macro} +% +%\section{Bibliography Styles} +% Each bibliography style is set by the command +% \cs{dtlbst@}\meta{style}, where \meta{style} is the name +% of the bibliography style. +% +%\begin{macro}{\dtlbst@plain} +% The `plain' style: +% \begin{macrocode} +\newcommand{\dtlbst@plain}{% +% \end{macrocode} +% Set how to format the entire bibliography: +% \begin{macrocode} + \renewenvironment{DTLthebibliography}[2][\boolean{true}]{% + \@dtl@tmpcount=0\relax + \@sDTLforeach[##1]{##2}{}{\advance\@dtl@tmpcount by 1\relax}% + \begin{thebibliography}{\number\@dtl@tmpcount}% + }{\end{thebibliography}}% +% \end{macrocode} +% Set how to start the bibliography entry: +% \begin{macrocode} + \renewcommand*{\DTLbibitem}{\bibitem{\DBIBcitekey}}% + \renewcommand*{\DTLmbibitem}[1]{\bibitem{##1@\DBIBcitekey}}% +% \end{macrocode} +% Sets the author name format. +% \begin{macrocode} + \renewcommand*{\DTLformatauthor}[4]{% + \DTLformatforenames{##4} + \DTLformatvon{##1}% + \DTLformatsurname{##2}% + \DTLformatjr{##3}} +% \end{macrocode} +% Sets the editor name format. +% \begin{macrocode} + \renewcommand*{\DTLformateditor}[4]{% + \DTLformatforenames{##4} + \DTLformatvon{##1}% + \DTLformatsurname{##2}% + \DTLformatjr{##3}} +% \end{macrocode} +% Sets the edition format. +% \begin{macrocode} + \renewcommand*{\DTLformatedition}[1]{##1 \editionname}% +% \end{macrocode} +% Sets the monthname format. +% \begin{macrocode} + \let\DTLmonthname\dtl@monthname +% \end{macrocode} +% Sets other predefined names: +% \begin{macrocode} + \renewcommand*{\DTLacmcs}{ACM Computing Surveys} + \renewcommand*{\DTLacta}{Acta Informatica} + \renewcommand*{\DTLcacm}{Communications of the ACM} + \renewcommand*{\DTLibmjrd}{IBM Journal of Research and Development} + \renewcommand*{\DTLibmsj}{IBM Systems Journal} + \renewcommand*{\DTLieeese}{IEEE Transactions on Software Engineering} + \renewcommand*{\DTLieeetc}{IEEE Transactions on Computers} + \renewcommand*{\DTLieeetcad}{IEEE Transactions on Computer-Aided Design +of Integrated Circuits} + \renewcommand*{\DTLipl}{Information Processing Letters} + \renewcommand*{\DTLjacm}{Journal of the ACM} + \renewcommand*{\DTLjcss}{Journal of Computer and System Sciences} + \renewcommand*{\DTLscp}{Science of Computer Programming} + \renewcommand*{\DTLsicomp}{SIAM Journal on Computing} + \renewcommand*{\DTLtocs}{ACM Transactions on Computer Systems} + \renewcommand*{\DTLtods}{ACM Transactions on Database Systems} + \renewcommand*{\DTLtog}{ACM Transactions on Graphics} + \renewcommand*{\DTLtoms}{ACM Transactions on Mathematical Software} + \renewcommand*{\DTLtoois}{ACM Transactions on Office Information +Systems} + \renewcommand*{\DTLtoplas}{ACM Transactions on Programming Languages +and Systems} + \renewcommand*{\DTLtcs}{Theoretical Computer Science} +% \end{macrocode} +% The format of an article. +% \begin{macrocode} + \renewcommand*{\DTLformatarticle}{% + \DTLformatauthorlist + \DTLifbibfieldexists{Author}{\DTLaddperiod}{}% + \DTLifbibfieldexists{Title}{% + \DTLstartsentencespace\DTLbibfield{Title}% + \DTLcheckbibfieldendsperiod{Title}% + \DTLaddperiod}{}% + \DTLifbibfieldexists{CrossRef}{% +% cross ref field + \DTLformatarticlecrossref + \DTLifbibfieldexists{Pages}{\DTLaddcomma}{}% + \DTLformatpages + \DTLaddperiod + }{% no cross ref field + \DTLifbibfieldexists{Journal}{\DTLstartsentencespace + {\em\DTLbibfield{Journal}}% + \DTLcheckbibfieldendsperiod{Journal}% + \DTLifanybibfieldexists{Number,Volume,Pages,Month,Year}{% + \DTLaddcomma}{\DTLaddperiod}}{}% + \DTLformatvolnumpages + \DTLifanybibfieldexists{Volume,Number,Pages}{% + \DTLifanybibfieldexists{Year,Month}{\DTLaddcomma}{% + \DTLaddperiod}% + \DTLmidsentencefalse}{}% + \DTLformatdate + \DTLifanybibfieldexists{Year,Month}{\DTLaddperiod}{}% + }% + \DTLifbibfieldexists{Note}{\DTLstartsentencespace\DTLbibfield{Note}% + \DTLcheckbibfieldendsperiod{Note}% + \DTLaddperiod}{}% + } +% \end{macrocode} +% The format of a book. +% \begin{macrocode} +\renewcommand*{\DTLformatbook}{% + \DTLifbibfieldexists{Author}% + {% + \DTLformatauthorlist\DTLaddperiod + }% + {% + \DTLformateditorlist + \DTLifbibfieldexists{Editor}% + {% + \DTLaddperiod + }% + {}% + }% + \DTLifbibfieldexists{Title}% + {% + \DTLstartsentencespace + \DTLformatbooktitle{\DTLbibfield{Title}}% + \DTLcheckbibfieldendsperiod{Title}% + }% + {}% + \DTLifbibfieldexists{CrossRef}% + {% +% \end{macrocode} +% Cross ref field +% \begin{macrocode} + \DTLifbibfieldexists{Title}{\DTLaddperiod}{}% + \DTLformatbookcrossref + \DTLifanybibfieldexists{Edition,Month,Year}% + {\DTLaddcomma}% + {\DTLaddperiod}% + }% + {% +% \end{macrocode} +% no cross ref field +% \begin{macrocode} + \DTLifbibfieldexists{Title}% + {% + \DTLifbibfieldexists{Volume}{\DTLaddcomma}{\DTLaddperiod}% + }% + {}% + \DTLformatbvolume + \DTLformatnumberseries + \DTLifanybibfieldexists{Number,Series,Volume}{\DTLaddperiod}{}% + \DTLifbibfieldexists{Publisher}% + {% + \DTLstartsentencespace + \DTLbibfield{Publisher}% + \DTLcheckbibfieldendsperiod{Publisher}% + \DTLifbibfieldexists{Address}% + {\DTLaddcomma}% + {% + \DTLifanybibfieldexists{Month,Year}% + {\DTLaddcomma}% + {\DTLaddperiod}% + }% + }% + {}% + \DTLifbibfieldexists{Address}% + {% + \DTLstartsentencespace + \DTLbibfield{Address}% + \DTLcheckbibfieldendsperiod{Address}% + \DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{\DTLaddperiod}% + }% + {}% + }% + \DTLifbibfieldexists{Edition}% + {% + \protected@edef\@dtl@tmp{\DTLformatedition{\DTLbibfield{Edition}}}% + \ifDTLmidsentence + \@dtl@tmp + \else + \DTLstartsentencespace\expandafter\MakeUppercase\@dtl@tmp + \fi + \expandafter\DTLcheckendsperiod\expandafter{\@dtl@tmp}% + \DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{\DTLaddperiod}% + }% + {}% + \DTLformatdate + \DTLifanybibfieldexists{Year,Month}{\DTLaddperiod}{}% + \DTLifbibfieldexists{Note}% + {% + \DTLstartsentencespace + \DTLbibfield{Note}% + \DTLcheckbibfieldendsperiod{Note}% + \DTLaddperiod + }% + {}% +}% +% \end{macrocode} +% The format of a booklet. +% \begin{macrocode} +\renewcommand*{\DTLformatbooklet}{% +\DTLifbibfieldexists{Author}{% +\DTLformatauthorlist\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{\DTLstartsentencespace +\DTLbibfield{Title}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLaddperiod}{}% +\DTLifbibfieldexists{HowPublished}{% +\DTLstartsentencespace\DTLbibfield{HowPublished}% +\DTLcheckbibfieldendsperiod{HowPublished}% +\DTLifanybibfieldexists{Address,Month,Year}{\DTLaddcomma +}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Year,Month}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{\DTLstartsentencespace\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of an `inbook' entry. +% \begin{macrocode} +\renewcommand*{\DTLformatinbook}{% +\DTLifbibfieldexists{Author}{% +\DTLformatauthorlist\DTLaddperiod}{% +\DTLifbibfieldexists{Editor}{\DTLformateditorlist\DTLaddperiod}{}}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +{\em\DTLbibfield{Title}}% +\DTLcheckbibfieldendsperiod{Title}% +}{}% +\DTLifbibfieldexists{CrossRef}{% +% Cross ref entry +\DTLifbibfieldexists{Title}{% +\DTLifbibfieldexists{Chapter}{\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatchapterpages +\DTLifanybibfieldexists{Chapter,Pages}{\DTLaddperiod}{}% +\DTLformatbookcrossref +}{% no cross ref +\DTLifbibfieldexists{Title}{% +\DTLifanybibfieldexists{Chapter,Volume}{\DTLaddcomma +}{\DTLaddperiod}}{}% +\DTLformatbvolume +\DTLifanybibfieldexists{Volume,Series}{% +\DTLifanybibfieldexists{Chapter,Pages}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatchapterpages +\DTLifanybibfieldexists{Chapter,Pages}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Publisher}{% +\DTLstartsentencespace +\DTLbibfield{Publisher}% +\DTLcheckbibfieldendsperiod{Publisher}% +\DTLifbibfieldexists{Address}{\DTLaddcomma}{}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}}{}% +}% +\DTLifanybibfieldexists{Edition,Month,Year}{\DTLaddcomma +}{\DTLaddperiod}% +\DTLifbibfieldexists{Edition}{% +\protected@edef\@dtl@tmp{\DTLformatedition{\DTLbibfield{Edition}}}% +\ifDTLmidsentence + \@dtl@tmp +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\@dtl@tmp +\fi +\expandafter\DTLcheckendsperiod\expandafter{\@dtl@tmp}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma +}{\DTLaddperiod}% +}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of an `incollection' entry. +% \begin{macrocode} +\renewcommand*{\DTLformatincollection}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +\DTLbibfield{Title}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLaddperiod}{}% +\DTLifbibfieldexists{CrossRef}{% +% cross ref entry +\DTLformatincollproccrossref +\DTLifanybibfieldexists{Chapter,Pages}{\DTLaddcomma}{}% +\DTLformatchapterpages\DTLaddperiod +}{% no cross ref entry +\DTLformatinedbooktitle +\DTLifbibfieldexists{BookTitle}{% +\DTLifanybibfieldexists{Volume,Series,Chapter,Pages,Number}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatbvolume +\DTLifbibfieldexists{Volume}{% +\DTLifanybibfieldexists{Number,Series,Chapter,Pages}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatnumberseries +\DTLifanybibfieldexists{Number,Series}{% +\DTLifanybibfieldexists{Chapter,Pages}{\DTLaddcomma +}{\DTLaddperiod}}{}% +\DTLformatchapterpages +\DTLifanybibfieldexists{Chapter,Pages}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Publisher}{% +\DTLstartsentencespace +\DTLbibfield{Publisher}% +\DTLcheckbibfieldendsperiod{Publisher}% +\DTLifanybibfieldexists{Address,Edition,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Edition,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Edition}{% +\protected@edef\@dtl@tmp{\DTLformatedition{\DTLbibfield{Edition}}}% +\ifDTLmidsentence + \@dtl@tmp +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\@dtl@tmp +\fi +\expandafter\DTLcheckendsperiod\expandafter{\@dtl@tmp}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma +}{\DTLaddperiod}% +}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of an `inproceedings' entry. +% \begin{macrocode} +\renewcommand*{\DTLformatinproceedings}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist +\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +\DTLbibfield{Title}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLaddperiod}{}% +\DTLifbibfieldexists{CrossRef}{% +% cross ref entry +\DTLformatincollproccrossref +\DTLifbibfieldexists{Pages}{\DTLaddcomma}{% +\DTLaddperiod}% +\DTLformatpages +\DTLifbibfieldexists{Pages}{\DTLaddperiod}{}% +}{% no cross ref +\DTLformatinedbooktitle +\DTLifbibfieldexists{BookTitle}{% +\DTLifanybibfieldexists{Volume,Series,Pages,Number,Address,% +Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatbvolume +\DTLifbibfieldexists{Volume}{% +\DTLifanybibfieldexists{Number,Series,Pages,Address,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatnumberseries +\DTLifanybibfieldexists{Number,Series}{% +\DTLifanybibfieldexists{Pages,Address,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatpages +\DTLifbibfieldexists{Pages}{% +\DTLifanybibfieldexists{Address,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{% +\DTLaddperiod}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Organization}{% +\DTLstartsentencespace +\DTLbibfield{Organization}% +\DTLcheckbibfieldendsperiod{Organization}% +\DTLifbibfieldexists{Publisher}{\DTLaddcomma}{% +\DTLaddperiod}}{}% +\DTLifbibfieldexists{Publisher}{% +\DTLstartsentencespace +\DTLbibfield{Publisher}% +\DTLcheckbibfieldendsperiod{Publisher}% +\DTLaddperiod}{}% +}{% +\DTLifanybibfieldexists{Publisher,Organization}{% +\DTLaddperiod}{}% +\DTLifbibfieldexists{Organization}{% +\DTLstartsentencespace +\DTLbibfield{Organization}% +\DTLcheckbibfieldendsperiod{Organization}% +\DTLifanybibfieldexists{Publisher,Month,Year}{% +\DTLaddcomma}{}}{}% +\DTLifbibfieldexists{Publisher}{% +\DTLstartsentencespace +\DTLbibfield{Publisher}% +\DTLcheckbibfieldendsperiod{Publisher}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{% +\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +}% +}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of a manual. +% \begin{macrocode} +\renewcommand*{\DTLformatmanual}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist +\DTLaddperiod}{% +\DTLifbibfieldexists{Organization}{% +\DTLstartsentencespace +\DTLbibfield{Organization}% +\DTLcheckbibfieldendsperiod{Organization}% +\DTLifbibfieldexists{Address}{\DTLaddcomma \DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +}{}% +\DTLaddperiod}{}% +}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +{\em\DTLbibfield{Title}}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLifbibfieldexists{Author}{% +\DTLifanybibfieldexists{Organization,Address}{% +\DTLaddperiod}{\DTLaddcomma}}{% +\DTLifanybibfieldexists{Organization,Address,Edition,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}}{}% +\DTLifbibfieldexists{Author}{% +\DTLifbibfieldexists{Organization}{% +\DTLstartsentencespace +\DTLbibfield{Organization}% +\DTLcheckbibfieldendsperiod{Organization}% +\DTLifanybibfieldexists{Address,Edition,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Edition,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +}{% +\DTLifbibfieldexists{Organization}{}{% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Edition,Month,Year}{\DTLaddcomma}{% +\DTLaddperiod}}{}}% +}% +\DTLifbibfieldexists{Edition}{% +\protected@edef\@dtl@tmp{\DTLformatedition{\DTLbibfield{Edition}}}% +\ifDTLmidsentence + \@dtl@tmp +\else + \DTLstartsentencespace + \expandafter\MakeUppercase\@dtl@tmp +\fi +\expandafter\DTLcheckendsperiod\expandafter{\@dtl@tmp}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{% +\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of a master's thesis. +% \begin{macrocode} +\renewcommand*{\DTLformatmastersthesis}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +\DTLbibfield{Title}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLaddperiod}{}% +\DTLifbibfieldexists{Type}{% +\DTLstartsentencespace +\DTLbibfield{Type}% +\DTLcheckbibfieldendsperiod{Type}% +\DTLifanybibfieldexists{School,Address,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{School}{% +\DTLstartsentencespace +\DTLbibfield{School}% +\DTLcheckbibfieldendsperiod{School}% +\DTLifanybibfieldexists{Address,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of a miscellaneous entry. +% \begin{macrocode} +\renewcommand*{\DTLformatmisc}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +\DTLbibfield{Title}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLifbibfieldexists{HowPublished}{\DTLaddperiod}{% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{% +\DTLaddperiod}% +}% +\DTLmidsentencefalse}{}% +\DTLifbibfieldexists{HowPublished}{% +\DTLstartsentencespace +\DTLbibfield{HowPublished}% +\DTLcheckbibfieldendsperiod{HowPublished}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{% +\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of a PhD thesis. +% \begin{macrocode} +\renewcommand*{\DTLformatphdthesis}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +{\em\DTLbibfield{Title}}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLaddperiod}{}% +\DTLifbibfieldexists{Type}{% +\DTLstartsentencespace +\DTLbibfield{Type}% +\DTLcheckbibfieldendsperiod{Type}% +\DTLifanybibfieldexists{School,Address,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{School}{% +\DTLstartsentencespace +\DTLbibfield{School}% +\DTLcheckbibfieldendsperiod{School}% +\DTLifanybibfieldexists{Address,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of a proceedings. +% \begin{macrocode} +\renewcommand*{\DTLformatproceedings}{% +\DTLifbibfieldexists{Editor}{% +\DTLformateditorlist\DTLaddperiod}{% +\DTLifbibfieldexists{Organization}{% +\DTLstartsentencespace +\DTLbibfield{Organization}% +\DTLcheckbibfieldendsperiod{Organization}% +\DTLaddperiod}{}}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +{\em\DTLbibfield{Title}}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLifanybibfieldexists{Volume,Number,Address,Editor,Publisher,% +Month,Year}{\DTLaddcomma}{\DTLaddperiod}% +}{}% +\DTLformatbvolume +\DTLifbibfieldexists{Volume}{% +\DTLifanybibfieldexists{Number,Address,Editor,Publisher,% +Month,Year}{\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatnumberseries +\DTLifbibfieldexists{Number}{% +\DTLifanybibfieldexists{Address,Editor,Publisher,% +Month,Year}{\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{\DTLaddperiod}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Editor}{\DTLifbibfieldexists{Organization}{% +\DTLstartsentencespace +\DTLbibfield{Organization}% +\DTLcheckbibfieldendsperiod{Organization}% +\DTLifbibfieldexists{Publisher}{% +\DTLaddcomma}{\DTLaddperiod}}{}}{}% +\DTLifbibfieldexists{Publisher}{% +\DTLstartsentencespace +\DTLbibfield{Publisher}% +\DTLcheckbibfieldendsperiod{Publisher}% +\DTLaddperiod +}{}% +}{% no address +\DTLifbibfieldexists{Editor}{% +\DTLifbibfieldexists{Organization}{% +\DTLstartsentencespace +\DTLbibfield{Organization}% +\DTLcheckbibfieldendsperiod{Organization}% +\DTLifanybibfieldexists{Publisher,Month,Year}{% +\DTLaddcomma}{\DTLaddperiod}}{}% +}{}% +\DTLifbibfieldexists{Publisher}{% +\DTLstartsentencespace +\DTLbibfield{Publisher}% +\DTLcheckbibfieldendsperiod{Publisher}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of a technical report. +% \begin{macrocode} +\renewcommand*{\DTLformattechreport}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +\DTLbibfield{Title}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLaddperiod}{}% +\DTLifbibfieldexists{Type}{% +\DTLstartsentencespace +\DTLbibfield{Type}% +\DTLcheckbibfieldendsperiod{Type}% +\DTLifbibfieldexists{Number}{~}{}}{}% +\DTLifbibfieldexists{Number}{% +\DTLstartsentencespace +\DTLbibfield{Number}% +\DTLcheckbibfieldendsperiod{Number}% +}{}% +\DTLifanybibfieldexists{Type,Number}{% +\DTLifanybibfieldexists{Institution,Address,Month,Year}{\DTLaddcomma +}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Institution}{% +\DTLstartsentencespace +\DTLbibfield{Institution}% +\DTLcheckbibfieldendsperiod{Institution}% +\DTLifanybibfieldexists{Address,Month,Year}{\DTLaddcomma +}{\DTLaddperiod}}{}% +\DTLifbibfieldexists{Address}{% +\DTLstartsentencespace +\DTLbibfield{Address}% +\DTLcheckbibfieldendsperiod{Address}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma +}{\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLaddperiod}{}% +}% +% \end{macrocode} +% The format of an unpublished work. +% \begin{macrocode} +\renewcommand*{\DTLformatunpublished}{% +\DTLifbibfieldexists{Author}{\DTLformatauthorlist\DTLaddperiod}{}% +\DTLifbibfieldexists{Title}{% +\DTLstartsentencespace +\DTLbibfield{Title}% +\DTLcheckbibfieldendsperiod{Title}% +\DTLaddperiod}{}% +\DTLifbibfieldexists{Note}{% +\DTLstartsentencespace +\DTLbibfield{Note}% +\DTLcheckbibfieldendsperiod{Note}% +\DTLifanybibfieldexists{Month,Year}{\DTLaddcomma}{\DTLaddperiod}}{}% +\DTLformatdate +\DTLifanybibfieldexists{Month,Year}{\DTLaddperiod}{}% +}% +% \end{macrocode} +% End of `plain' style. +% \begin{macrocode} +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLformatbooktitle} +%\changes{2.22}{2014-06-10}{new} +% \begin{macrocode} +\newcommand*{\DTLformatbooktitle}[1]{\emph{#1}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlbst@abbrv} +% Define `abbrv' style. This is similar to `plain' except that +% some of the values are abbreviated +% \begin{macrocode} +\newcommand{\dtlbst@abbrv}{% +% \end{macrocode} +% Base this style on `plain': +% \begin{macrocode} +\dtlbst@plain +% \end{macrocode} +% Sets the author name format. +% \begin{macrocode} +\renewcommand*{\DTLformatauthor}[4]{% +\DTLformatabbrvforenames{##4} +\DTLformatvon{##1}% +\DTLformatsurname{##2}% +\DTLformatjr{##3}} +% \end{macrocode} +% Sets the editor name format. +% \begin{macrocode} +\renewcommand*{\DTLformateditor}[4]{% +\DTLformatabbrvforenames{##4} +\DTLformatvon{##1}% +\DTLformatsurname{##2}% +\DTLformatjr{##3}} +% \end{macrocode} +% Sets the monthname format. +% \begin{macrocode} +\let\DTLmonthname\dtl@abbrvmonthname +% \end{macrocode} +% Sets other predefined names: +% \begin{macrocode} +\renewcommand*{\DTLacmcs}{ACM Comput.\ Surv.} +\renewcommand*{\DTLacta}{Acta Inf.} +\renewcommand*{\DTLcacm}{Commun.\ ACM} +\renewcommand*{\DTLibmjrd}{IBM J.\ Res.\ Dev.} +\renewcommand*{\DTLibmsj}{IBM Syst.~J.} +\renewcommand*{\DTLieeese}{IEEE Trans. Softw.\ Eng.} +\renewcommand*{\DTLieeetc}{IEEE Trans.\ Comput.} +\renewcommand*{\DTLieeetcad}{IEEE Trans.\ Comput.-Aided Design +Integrated Circuits} +\renewcommand*{\DTLipl}{Inf.\ Process.\ Lett.} +\renewcommand*{\DTLjacm}{J.~ACM} +\renewcommand*{\DTLjcss}{J.~Comput.\ Syst.\ Sci.} +\renewcommand*{\DTLscp}{Sci.\ Comput.\ Programming} +\renewcommand*{\DTLsicomp}{SIAM J.~Comput.} +\renewcommand*{\DTLtocs}{ACM Trans.\ Comput.\ Syst.} +\renewcommand*{\DTLtods}{ACM Trans.\ Database Syst.} +\renewcommand*{\DTLtog}{ACM Trans.\ Gr.} +\renewcommand*{\DTLtoms}{ACM Trans.\ Math. Softw.} +\renewcommand*{\DTLtoois}{ACM Trans. Office Inf.\ Syst.} +\renewcommand*{\DTLtoplas}{ACM Trans.\ Prog. Lang.\ Syst.} +\renewcommand*{\DTLtcs}{Theoretical Comput.\ Sci.} +% \end{macrocode} +% End of `abbrv' style. +% \begin{macrocode} +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlbst@alpha} +% Define `alpha' style. This is similar to `plain' except that +% the labels are strings rather than numerical. +% \begin{macrocode} +\newcommand{\dtlbst@alpha}{% +% \end{macrocode} +% Base this style on `plain': +% \begin{macrocode} +\dtlbst@plain +% \end{macrocode} +% Set how to format the entire bibliography: +% \begin{macrocode} +\renewenvironment{DTLthebibliography}[2][\boolean{true}]{% +\dtl@createalphabiblabels{##1}{##2}% +\begin{thebibliography}{\@dtl@widestlabel}% +}{\end{thebibliography}}% +% \end{macrocode} +% Set how to start the bibliography entry: +% \begin{macrocode} +\renewcommand*{\DTLbibitem}{% +\expandafter\bibitem\expandafter + [\csname dtl@biblabel@\DBIBcitekey\endcsname]{\DBIBcitekey}}% +\renewcommand*{\DTLmbibitem}[1]{% +\expandafter\bibitem\expandafter + [\csname dtl@biblabel@\DBIBcitekey\endcsname]{##1@\DBIBcitekey}}% +% \end{macrocode} +% End of `alpha' style. +% \begin{macrocode} +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{dtl@createalphabiblabels} +%\begin{definition} +%\cs{dtl@createalphabiblabels}\marg{condition}\marg{db name} +%\end{definition} +% Constructs the alpha style bib labels for the given database. +% (Labels are stored in the control sequence +%\cs{dtl@biblabel@}\meta{citekey}.) This also sets +% \cs{@dtl@widestlabel} to the widest label. +% \begin{macrocode} +\newcommand*{\dtl@createalphabiblabels}[2]{% +\dtl@message{Creating bib labels}% +\begingroup +\gdef\@dtl@widestlabel{}% +\dtl@widest=0pt\relax +\DTLforeachbibentry[#1]{#2}{% +\dtl@message{\DBIBcitekey}% +\DTLifbibfieldexists{Author}{% + \dtl@listgetalphalabel{\@dtl@thislabel}{\@dtl@key@Author}% +}{% +\DTLifbibfieldexists{Editor}{% + \dtl@listgetalphalabel{\@dtl@thislabel}{\@dtl@key@Editor}% + }{% + \DTLifbibfieldexists{Key}{% + \expandafter\dtl@get@firstthree\expandafter + {\@dtl@key@Key}{\@dtl@thislabel}% + }{% + \DTLifbibfieldexists{Organization}{% + \expandafter\dtl@get@firstthree\expandafter + {\@dtl@key@Organization}{\@dtl@thislabel}% + }{% + \expandafter\dtl@get@firstthree\expandafter + {\DBIBentrytype}{\@dtl@thislabel}% + }% + }}}% +\DTLifbibfieldexists{Year}{}{\DTLifbibfieldexists{CrossRef}{% +\DTLgetvalueforkey{\@dtl@key@Year}{Year}{#2}{CiteKey}{% +\@dtl@key@CrossRef}}{}}% +\DTLifbibfieldexists{Year}{% +\expandafter\dtl@get@yearsuffix\expandafter{\@dtl@key@Year}% +\expandafter\toks@\expandafter{\@dtl@thislabel}% +\expandafter\@dtl@toks\expandafter{\@dtl@year}% +\edef\@dtl@thislabel{\the\toks@\the\@dtl@toks}% +}{}% +\let\@dtl@s@thislabel=\@dtl@thislabel +\@onelevel@sanitize\@dtl@s@thislabel +\@ifundefined{c@biblabel@\@dtl@s@thislabel}{% +\newcounter{biblabel@\@dtl@s@thislabel}% +\setcounter{biblabel@\@dtl@s@thislabel}{1}% +\expandafter\edef\csname @dtl@bibfirst@\@dtl@s@thislabel\endcsname{% +\DBIBcitekey}% +\expandafter\global +\expandafter\let\csname dtl@biblabel@\DBIBcitekey\endcsname= + \@dtl@thislabel +}{% +\expandafter\ifnum\csname c@biblabel@\@dtl@s@thislabel\endcsname=1\relax + \expandafter\let\expandafter\@dtl@tmp + \csname @dtl@bibfirst@\@dtl@s@thislabel\endcsname + \expandafter\protected@xdef\csname dtl@biblabel@\@dtl@tmp\endcsname{% + \@dtl@thislabel a}% +\fi +\stepcounter{biblabel@\@dtl@s@thislabel}% +\expandafter\protected@xdef\csname dtl@biblabel@\DBIBcitekey\endcsname{% + \@dtl@thislabel\alph{biblabel@\@dtl@s@thislabel}}% +}% +\settowidth{\dtl@tmplength}{% + \csname dtl@biblabel@\DBIBcitekey\endcsname}% +\ifdim\dtl@tmplength>\dtl@widest + \dtl@widest=\dtl@tmplength + \expandafter\global\expandafter\let\expandafter\@dtl@widestlabel + \expandafter=\csname dtl@biblabel@\DBIBcitekey\endcsname +\fi +}% +\endgroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@listgetalphalabel} +% Determine the alpha style label from a list of authors/editors +% (the first argument must be a control sequence (in which the +% label is stored), the second argument must be the list of names.) +% \begin{macrocode} +\newcommand*{\dtl@listgetalphalabel}[2]{% +\@dtl@authorcount=0\relax +\@for\@dtl@author:=#2\do{% +\advance\@dtl@authorcount by 1\relax}% +\ifnum\@dtl@authorcount=1\relax + \expandafter\dtl@getsinglealphalabel#2{#1}\relax +\else + {% + \xdef#1{}% + \@dtl@tmpcount=0\relax + \def\DTLafterinitials{}\def\DTLbetweeninitials{}% + \def\DTLafterinitialbeforehyphen{}\def\DTLinitialhyphen{}% + \@for\@dtl@author:=#2\do{% + \expandafter\dtl@getauthorinitial\@dtl@author + \expandafter\toks@\expandafter{\@dtl@tmp}% + \expandafter\@dtl@toks\expandafter{#1}% + \xdef#1{\the\@dtl@toks\the\toks@}% + \advance\@dtl@tmpcount by 1\relax + \ifnum\@dtl@tmpcount>2\relax\@endfortrue\fi + }}% +\fi +} +% \end{macrocode} +%\end{macro} +% Get author's initial (stores in \cs{@dtl@tmp}): +% \begin{macrocode} +\newcommand*{\dtl@getauthorinitial}[4]{% +\def\@dtl@vonpart{#1}% +\ifx\@dtl@vonpart\@empty + \DTLstoreinitials{#2}{\@dtl@tmp}% +\else + \DTLstoreinitials{#1 #2}{\@dtl@tmp}% +\fi} +% \end{macrocode} +% Get label for single author (last argument is control sequence +% in which to store the label): +% \begin{macrocode} +\newcommand*{\dtl@getsinglealphalabel}[5]{% +\def\@dtl@vonpart{#1}% +\ifx\@dtl@vonpart\@empty + \DTLifSubString{#2}{-}{% + {\def\DTLafterinitials{}\def\DTLbetweeninitials{}% + \def\DTLafterinitialbeforehyphen{}% + \def\DTLinitialhyphen{}% + \DTLstoreinitials{#2}{\@dtl@tmp}\global\let#5=\@dtl@tmp}% + }{% + \dtl@getfirstthree{#5}#2{}{}{}{}\@nil + } +\else + {\def\DTLafterinitials{}\def\DTLbetweeninitials{}% + \def\DTLafterinitialbeforehyphen{}% + \def\DTLinitialhyphen{}% + \DTLstoreinitials{#1 #2}{\@dtl@tmp}\global\let#5=\@dtl@tmp}% +\fi +} +% \end{macrocode} +%Get first three letters from the given string: +% \begin{macrocode} +\def\dtl@getfirstthree#1#2#3#4#5\@nil{% + \def#1{#2#3#4}% +} +\newcommand*{\dtl@get@firstthree}[2]{% +\dtl@getfirstthree#2#1{}{}{}{}{}\@nil} +% \end{macrocode} +%Get year suffix: +% \begin{macrocode} +\newcommand*{\dtl@get@yearsuffix}[1]{% +\dtl@getyearsuffix#1\@nil\relax\relax} + +\def\dtl@getyearsuffix#1#2#3{% +\def\@dtl@argi{#1}\def\@dtl@argii{#2}% +\def\@dtl@argiii{#3}% +\ifx\@dtl@argi\@nnil + \def\@dtl@year{}% + \let\@dtl@donext=\relax +\else + \ifx\@dtl@argii\@nnil + \dtl@ifsingle{#1}{% + \def\@dtl@year{#1}% + \let\@dtl@donext=\relax + }{% + \def\@dtl@donext{\dtl@getyearsuffix#1#2#3}% + }% + \else + \ifx\@dtl@argiii\@nnil + \dtl@ifsingle{#1}{% + \dtl@ifsingle{#2}{% + \def\@dtl@year{#1#2}% + \let\@dtl@donext=\relax + }{% + \def\@dtl@donext{\dtl@getyearsuffix#2#3}% + }% + }{% + \def\@dtl@donext{\dtl@getyearsuffix#2#3}% + }% + \else + \def\@dtl@donext{\dtl@getyearsuffix{#2}{#3}}% + \fi + \fi +\fi +\@dtl@donext +} +% \end{macrocode} +% +%\begin{macro}{\DTLbibliographystyle} +%\begin{definition} +%\cs{DTLbibliographystyle}\marg{style} +%\end{definition} +% Sets the bibliography style. +% \begin{macrocode} +\newcommand*{\DTLbibliographystyle}[1]{% +\@ifundefined{dtlbst@#1}{\PackageError{databib}{Unknown +bibliography style `#1'}{}}{\csname dtlbst@#1\endcsname}} +% \end{macrocode} +%\end{macro} +%Set the default bibliography style: +% \begin{macrocode} +\DTLbibliographystyle{\dtlbib@style} +% \end{macrocode} +% +%\section{Multiple Bibliographies} +% In order to have multiple bibliographies, there needs to be +% an aux file for each bibliography. The main bibliography is in +% \cs{jobname}.aux, but need to provide a means of creating +% additional aux files. +%\begin{macro}{\DTLmultibibs} +%\begin{definition} +%\cs{DTLmultibibs}\marg{list} +%\end{definition} +%\changes{1.01}{2007/08/22}{new} +% This creates an auxiliary file for each name in \meta{list}. +% For example, "\DTLmultibibs{foo,bar}" will create the files +% "foo.aux" and "bar.aux". +% \begin{macrocode} +\newcommand*{\DTLmultibibs}[1]{% +\@for\@dtl@af:=#1\do{% +\@ifundefined{dtl@aux@\@dtl@af}{% +\expandafter\newwrite\csname dtl@aux@\@dtl@af\endcsname +\expandafter\immediate +\expandafter\openout\csname dtl@aux@\@dtl@af\endcsname=\@dtl@af.aux +\expandafter\def\csname b@\@dtl@af @*\endcsname{}% +}{% +\PackageError{databib}{Can't create auxiliary file `\@dtl@af.aux', +\expandafter\string\csname dtl@aux@\@dtl@af\endcsname\space +already exists}{}}}} +% \end{macrocode} +% Can only be used in the preamble: +% \begin{macrocode} +\@onlypreamble{\DTLmultibibs} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLcite} +%\begin{definition} +%\cs{DTLcite}\oarg{text}\marg{mbib}\marg{labels} +%\end{definition} +% This is similar to \cs{cite}\oarg{text}\marg{labels}, except +% 1) the cite information is written to the auxiliary file +% associated with the multi-bib \meta{mbib} (which must be named +% in \cs{DTLmultibibs}) and 2) the cross referencing label is +% constructed from \meta{mbib} and \meta{label} to allow for +% the same citation to appear in multiple bibliographies. +% \begin{macrocode} +\newcommand*{\DTLcite}{\@ifnextchar[{\@tempswatrue \dtl@citex +}{\@tempswafalse \dtl@citex[]}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@citex} +% \begin{macrocode} +\def\dtl@citex[#1]#2#3{% +\leavevmode\let\@citea\@empty +\@cite{\@for\@citeb:=#3\do{\@citea + \def\@citea{,\penalty \@m \ }% + \edef\@citeb{\expandafter\@firstofone\@citeb\@empty}% + \if@filesw + \@ifundefined{dtl@aux@#2}{% + \PackageError{databib}{multibib `#2' not defined}{% + You need to define `#2' in \string\DTLmutlibibs}% + }{% + \expandafter\immediate + \expandafter\write\csname dtl@aux@#2\endcsname{% + \string\citation{\@citeb}}% + }% + \fi + \@ifundefined{b@#2@\@citeb}{% + \hbox{\reset@font\bfseries ?}% + \G@refundefinedtrue + \@latex@warning{Citation `\@citeb ' on page \thepage \space + undefined}% + }{% + \@cite@ofmt{\csname b@#2@\@citeb \endcsname }% + }% +}}{#1}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLnocite} +%\begin{definition} +%\cs{DTLnocite}\marg{mbib}\marg{key list} +%\end{definition} +% As \cs{nocite} but uses the aux file associated with \meta{mbib} +% which must have been defined using \cs{DTLmultibibs}. +% \begin{macrocode} +\newcommand*{\DTLnocite}[2]{% +\@ifundefined{dtl@aux@#1}{% + \PackageError{databib}{multibib `#1' not defined}{% + You need to define `#1' in \string\DTLmutlibibs}% +}{% + \@bsphack + \ifx\@onlypreamble\document + \@for\@citeb:=#2\do{% + \edef\@citeb{\expandafter\@firstofone\@citeb}% + \if@filesw + \expandafter\immediate + \expandafter\write\csname dtl@aux@#1\endcsname{% + \string\citation{\@citeb}}% + \fi + \@ifundefined{b@#1@\@citeb}{% + \G@refundefinedtrue + \@latex@warning{Citation `\@citeb ' undefined}}{}% + }% + \else + \@latex@error{Cannot be used in preamble}\@eha + \fi + \@esphack +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLloadmbbl} +%\begin{definition} +%\cs{DTLloadmbib}\marg{mbib}\marg{db name}\marg{bib list} +%\end{definition} +% \begin{macrocode} +\newcommand*{\DTLloadmbbl}[3]{% +\@ifundefined{dtl@aux@#1}{% + \PackageError{databib}{multibib `#1' not defined}{% + You need to define `#1' in \string\DTLmutlibibs}% +}{% + \if@filesw + \expandafter\immediate\expandafter + \write\csname dtl@aux@#1\endcsname{\string\bibstyle{databib}}% + \expandafter\immediate\expandafter + \write\csname dtl@aux@#1\endcsname{\string\bibdata{#3}}% + \fi + \DTLnewdb{#2}% + \edef\DTLBIBdbname{#2}% + \@input@{#1.bbl}% +}% +} +% \end{macrocode} +%\end{macro} +%\begin{definition} +%\cs{DTLmbibliography}\oarg{condition}\marg{mbib name}\marg{bib dbname} +%\end{definition} +% Displays the bibliography for the database \meta{bib dbname} +% which must have previously been loaded using +% \cs{DTLloadmbbl}, where \meta{mbib name} must be listed +% in \cs{DTLmultibibs}. +%\begin{macro}{\DTLmbibliography} +% \begin{macrocode} +\newcommand*{\DTLmbibliography}[3][\boolean{true}]{% +\begin{DTLthebibliography}[#1]{#3}% +\DTLforeachbibentry[#1]{#3}{% +\DTLmbibitem{#2} \DTLformatbibentry \DTLendbibitem +}% +\end{DTLthebibliography}% +} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</databib.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*databar.sty> +% \end{macrocode} +%\fi +%\chapter{databar.sty} +% Declare package: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{databar}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Require \sty{xkeyval} package +% \begin{macrocode} +\RequirePackage{xkeyval} +% \end{macrocode} +% Require \sty{dataplot} package +% \begin{macrocode} +\RequirePackage{dataplot} +% \end{macrocode} +%\begin{macro}{\ifDTLcolorbarchart} +% The conditional \cs{ifDTLcolorbarchart} is used to determine +% whether to use colour or grey scale. +% \begin{macrocode} +\newif\ifDTLcolorbarchart +\DTLcolorbarcharttrue +% \end{macrocode} +%\end{macro} +% Package options to change the conditional: +% \begin{macrocode} +\DeclareOption{color}{\DTLcolorbarcharttrue} +\DeclareOption{gray}{\DTLcolorbarchartfalse} +% \end{macrocode} +%\cs{DTLbarXlabelalign} specifies the alignment +% for the $x$ axis labels. +% \begin{macrocode} +\newcommand*{\DTLbarXlabelalign}{left,rotate=-90} +% \end{macrocode} +%\cs{DTLbarYticklabelalign} specifies the alignment +% for the $x$ axis labels. +% \begin{macrocode} +\newcommand*{\DTLbarYticklabelalign}{right} +% \end{macrocode} +%\begin{macro}{\ifDTLverticalbars} +% Define boolean keys to govern bar chart orientation. +% \begin{macrocode} +\define@boolkey{databar}[DTL]{verticalbars}[true]{% +\ifDTLverticalbars + \def\DTLbarXlabelalign{left,rotate=-90}% + \def\DTLbarYticklabelalign{right} +\else + \def\DTLbarXlabelalign{right}% + \def\DTLbarYticklabelalign{center} +\fi} +% \end{macrocode} +%\end{macro} +% Set defaults: +% \begin{macrocode} +\DTLverticalbarstrue +% \end{macrocode} +% Package options to change \cs{ifDTLverticalbars} +% \begin{macrocode} +\DeclareOption{vertical}{\DTLverticalbarstrue + \def\DTLbarXlabelalign{left,rotate=-90}% + \def\DTLbarYticklabelalign{right} +} +\DeclareOption{horizontal}{\DTLverticalbarsfalse + \def\DTLbarXlabelalign{right}% + \def\DTLbarYticklabelalign{center} +} +% \end{macrocode} +% Process options: +% \begin{macrocode} +\ProcessOptions +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{datatool} +\RequirePackage{tikz} +% \end{macrocode} +% Define some variables that govern the appearance of the bar +% chart. +% +%\begin{macro}{\DTLbarchartlength} +% The total height of the bar chart is given by \cs{DTLbarchartheight} +% \begin{macrocode} +\newlength\DTLbarchartlength +\DTLbarchartlength=3in +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbarwidth} +% The width of each bar is given by \cs{DTLbarwidth}. +% \begin{macrocode} +\newlength\DTLbarwidth +\DTLbarwidth=1cm +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbarlabeloffset} +% The offset from the $x$ axis to the bar label if given by +% \cs{DTLbarlabeloffset}. +% \begin{macrocode} +\newlength\DTLbarlabeloffset +\setlength\DTLbarlabeloffset{10pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLBarXAxisStyle} +% The style of the $x$ axis is given by \cs{DTLBarXAxisStyle} +% \begin{macrocode} +\newcommand*{\DTLBarXAxisStyle}{-} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLBarYAxisStyle} +% The style of the $y$ axis is given by \cs{DTLBarYAxisStyle}. +% \begin{macrocode} +\newcommand*{\DTLBarYAxisStyle}{-} +% \end{macrocode} +%\end{macro} +% +%\begin{counter}{DTLbarroundvar} +% \ctrfmt{DTLbarroundvar} is a counter governing the number of digits +% to round to when using \cs{FPround}. +% \begin{macrocode} +\newcounter{DTLbarroundvar} +\setcounter{DTLbarroundvar}{1} +% \end{macrocode} +%\end{counter} +% +%\begin{macro}{\DTLbardisplayYticklabel} +%\cs{DTLbardisplayYticklabel} governs how the $y$ tick labels appear. +% \begin{macrocode} +\newcommand*{\DTLbardisplayYticklabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLdisplaylowerbarlabel} +%\cs{DTLdisplaylowerbarlabel} governs how the lower bar labels appear. +% \begin{macrocode} +\newcommand*{\DTLdisplaylowerbarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLdisplaylowermultibarlabel} +%\cs{DTLdisplaylowermultibarlabel} governs how the lower multi bar labels appear. +% \begin{macrocode} +\newcommand*{\DTLdisplaylowermultibarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLdisplayupperbarlabel} +%\cs{DTLdisplayupperbarlabel} governs how the upper bar labels +% appear. +% \begin{macrocode} +\newcommand*{\DTLdisplayupperbarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLdisplayuppermultibarlabel} +%\cs{DTLdisplayuppermultibarlabel} governs how the upper multi bar +% labels appear. +% \begin{macrocode} +\newcommand*{\DTLdisplayuppermultibarlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbaratbegintikz} +% \cs{DTLbaratbegintikz} specifies any commands +% to apply at the start of the \env{tikzpicture} environment. +% By default it does nothing. +% \begin{macrocode} +\newcommand*{\DTLbaratbegintikz}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbaratendtikz} +% \cs{DTLbaratendtikz} specifies any commands +% to apply at the end of the \env{tikzpicture} environment. +% By default it does nothing. +% \begin{macrocode} +\newcommand*{\DTLbaratendtikz}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifDTLbarxaxis} +% The conditional \cs{ifDTLbarxaxis} is used to determine +% whether or not to display the $x$ axis +% \begin{macrocode} +\newif\ifDTLbarxaxis +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLbaryaxis} +% The conditional \cs{ifDTLbaryaxis} is used to determine +% whether or not to display the $y$ axis. +% \begin{macrocode} +\newif\ifDTLbaryaxis +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLbarytics} +% The conditional \cs{ifDTLbarytics} to determine whether +% or not to display the $y$ tick marks. +% \begin{macrocode} +\newif\ifDTLbarytics +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\@dtl@barcount} +% The count register \cs{@dtl@barcount} is used to store +% the current bar index. +% \begin{macrocode} +\newcount\@dtl@barcount +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsetbarcolor} +%\begin{definition} +% \cs{DTLsetbarcolor}\marg{n}\marg{color} +%\end{definition} +% Assigns colour name \meta{color} to the \meta{n}th bar. +% \begin{macrocode} +\newcommand*{\DTLsetbarcolor}[2]{% +\expandafter\def\csname dtlbar@segcol\romannumeral#1\endcsname{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgetbarcolor} +%\begin{definition} +%\cs{DTLgetbarcolor}\marg{n} +%\end{definition} +% Gets the colour specification for the \meta{n}th bar. +% \begin{macrocode} +\newcommand*{\DTLgetbarcolor}[1]{% +\csname dtlbar@segcol\romannumeral#1\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLdobarcolor} +%\begin{definition} +%\cs{DTLdobarcolor}\marg{n} +%\end{definition} +% Sets the colour to that for the \meta{n}th bar. +% \begin{macrocode} +\newcommand*{\DTLdobarcolor}[1]{% +\expandafter\color\expandafter +{\csname dtlbar@segcol\romannumeral#1\endcsname}} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLdocurrentbarcolor} +%\cs{DTLdocurrentbarcolor} +% sets the colour to that of the current bar. +% \begin{macrocode} +\newcommand*{\DTLdocurrentbarcolor}{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{databar}{Can't use + \string\DTLdocurrentbarcolor\space outside + \string\DTLbarchart}{}% +\else + \expandafter\DTLdobarcolor\expandafter{% + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname}% +\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbaroutlinecolor} +%\cs{DTLbaroutlinecolor} specifies what colour to draw the +% outline. +% \begin{macrocode} +\newcommand*{\DTLbaroutlinecolor}{black} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLbaroutlinewidth} +%\cs{DTLbaroutlinewidth} specifies the line width of the outline: +% Outline is only drawn if the linewidth is greater than 0pt. +% \begin{macrocode} +\newlength\DTLbaroutlinewidth +\DTLbaroutlinewidth=0pt +% \end{macrocode} +%\end{macro} +% +% Set the default colours. If there are more than eight bars, +% more colours will need to be defined. +% \begin{macrocode} +\ifDTLcolorbarchart + \DTLsetbarcolor{1}{red} + \DTLsetbarcolor{2}{green} + \DTLsetbarcolor{3}{blue} + \DTLsetbarcolor{4}{yellow} + \DTLsetbarcolor{5}{magenta} + \DTLsetbarcolor{6}{cyan} + \DTLsetbarcolor{7}{orange} + \DTLsetbarcolor{8}{white} +\else + \DTLsetbarcolor{1}{black!15} + \DTLsetbarcolor{2}{black!25} + \DTLsetbarcolor{3}{black!35} + \DTLsetbarcolor{4}{black!45} + \DTLsetbarcolor{5}{black!55} + \DTLsetbarcolor{6}{black!65} + \DTLsetbarcolor{7}{black!75} + \DTLsetbarcolor{8}{black!85} +\fi +% \end{macrocode} +%\begin{macro}{\DTLeverybarhook} +% Code to apply at every bar. The start point of the bar +% can be accessed via \cs{DTLstartpt}, the mid point of the bar +% can be accessed via \cs{DTLmidpt} and the end point of the +% bar can be accessed via \cs{DTLendpt} +%\changes{2.0}{2009 February 27}{new}% +% \begin{macrocode} +\newcommand*{\DTLeverybarhook}{} +% \end{macrocode} +%\end{macro} +% +% Define keys for \cs{DTLbarchart} optional argument. +% Set the maximum value of the $y$ axis. +% \begin{macrocode} +\define@key{databar}{max}{\def\DTLbarmax{#1}} +% \end{macrocode} +% Set the total length of the bar chart +% \begin{macrocode} +\define@key{databar}{length}{\DTLbarchartlength=#1\relax +} +% \end{macrocode} +% Set the maximum depth (negative extent) +% \begin{macrocode} +\define@key{databar}{maxdepth}{% +\ifnum#1>0\relax + \PackageError{databar}{depth must be zero or negative}{}% +\else + \def\DTLnegextent{#1}% +\fi} +% \end{macrocode} +% Determine which axes should be shown +% \begin{macrocode} +\define@choicekey{databar}{axes}[\var\nr]{both,x,y,none}{% +\ifcase\nr\relax + % both + \DTLbarxaxistrue + \DTLbaryaxistrue + \DTLbaryticstrue +\or + % x only + \DTLbarxaxistrue + \DTLbaryaxisfalse + \DTLbaryticsfalse +\or + % y only + \DTLbarxaxisfalse + \DTLbaryaxistrue + \DTLbaryticstrue +\or + % neither + \DTLbarxaxisfalse + \DTLbaryaxisfalse + \DTLbaryticsfalse +\fi +} +% \end{macrocode} +% Variable used to create the bar chart. (Must be a control +% sequence.) +% \begin{macrocode} +\define@key{databar}{variable}{% + \def\DTLbarvariable{#1}% +} +% \end{macrocode} +% Variables used to create the multi bar chart. (Must be a +% comma separated list of control sequences.) +% \begin{macrocode} +\define@key{databar}{variables}{% + \def\dtlbar@variables{#1}% +} +% \end{macrocode} +% Bar width +% \begin{macrocode} +\define@key{databar}{barwidth}{\setlength{\DTLbarwidth}{#1}} +% \end{macrocode} +% Lower bar labels +% \begin{macrocode} +\define@key{databar}{barlabel}{% +\def\dtl@barlabel{#1}} +\def\dtl@barlabel{} +% \end{macrocode} +% Lower bar labels for multi-bar charts +% \begin{macrocode} +\define@key{databar}{multibarlabels}{% +\def\dtl@multibarlabels{#1}} +\def\dtl@multibarlabels{} +% \end{macrocode} +% Gap between groups in multi-bar charts (This should be in $x$ units +% where 1 $x$ unit is the width of a bar.) +% \begin{macrocode} +\define@key{databar}{groupgap}{\def\dtlbar@groupgap{#1}} +\def\dtlbar@groupgap{1} +% \end{macrocode} +% Upper bar labels +% \begin{macrocode} +\define@key{databar}{upperbarlabel}{% +\def\dtl@upperbarlabel{#1}} +\def\dtl@upperbarlabel{} +% \end{macrocode} +% Upper bar labels for multi-bar charts +% \begin{macrocode} +\define@key{databar}{uppermultibarlabels}{% +\def\dtl@uppermultibarlabels{#1}} +\def\dtl@uppermultibarlabels{} +% \end{macrocode} +% Define list of points for $y$ tics. (Must be a comma separated list +% of decimal numbers.) +% \begin{macrocode} +\define@key{databar}{yticpoints}{% +\def\dtlbar@yticlist{#1}\DTLbaryticstrue\DTLbaryaxistrue} +\let\dtlbar@yticlist=\relax +% \end{macrocode} +% Set the $y$ tick gap: +% \begin{macrocode} +\define@key{databar}{yticgap}{% +\def\dtlbar@yticgap{#1}\DTLbaryticstrue\DTLbaryaxistrue} +\let\dtlbar@yticgap=\relax +% \end{macrocode} +% Define list of labels for $y$ tics. +% \begin{macrocode} +\define@key{databar}{yticlabels}{% +\def\dtlbar@yticlabels{#1}\DTLbaryticstrue\DTLbaryaxistrue} +\let\dtlbar@yticlabels=\relax +% \end{macrocode} +% Define $y$ axis label. +% \begin{macrocode} +\define@key{databar}{ylabel}{% +\def\dtlbar@ylabel{#1}} +\let\dtlbar@ylabel=\relax +% \end{macrocode} +% +%\begin{macro}{\DTLbarchart} +%\begin{definition} +% \cs{DTLbarchart}\oarg{conditions}\marg{option list}\marg{db name}\marg{assign list} +%\end{definition} +% Make a bar chart from data given in data base \meta{db name}, +% where \meta{assign list} is a comma-separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. \meta{option list} must +% include \texttt{variable}\texttt{=}\meta{cmd}, where \meta{cmd} +% is included in \meta{assign list}. The optional argument +% \meta{conditions} is the same as that for \cs{DTLforeach}. +% \begin{macrocode} +\newcommand*{\DTLbarchart}[4][\boolean{true}]{% +{% + \undef\DTLbarvariable + \undef\DTLbarmax + \undef\DTLnegextent + \disable@keys{databar}{variables,multibarlabels,% + uppermultibarlabels,groupgap}% + \setkeys{databar}{#2}% + \ifundef{\DTLbarvariable}% + {% + \PackageError{databar}% + {\string\DTLbarchart\space missing variable}% + {You haven't use the "variable" key}% + }% + {% +% \end{macrocode} +% Compute the maximum bar height, unless \cs{DTLbarmax} has been +% set. +%\changes{1.01}{2007 Aug 17}{uses \cs{@sDTLforeach} instead of +%\cs{DTLforeach}} +% \begin{macrocode} + \ifundef{\DTLbarmax}% + {% + \@sDTLforeach[#1]{#3}{#4}{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \ifundef{\DTLbarmax}% + {% + \let\DTLbarmax=\dtl@barvar + }% + {% + \let\dtl@old=\DTLbarmax + \dtlmax{\DTLbarmax}{\dtl@old}{\dtl@barvar}% + }% + }% + \ifx\dtlbar@yticgap\relax + \else + \let\dtl@thistick=\dtlbar@yticgap + \whiledo{\DTLisFPopenbetween{\dtl@thistick}{0}{\DTLbarmax}}% + {% + \dtladd{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLbarmax=\dtl@thistick + \fi + }% + {}% +% \end{macrocode} +% Compute the bar depth, unless \cs{DTLnegextent} has been +% set. +% \begin{macrocode} + \ifundef{\DTLnegextent}% + {% + \def\DTLnegextent{0}% + \@sDTLforeach[#1]{#3}{#4}{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \let\dtl@old=\DTLnegextent + \DTLmin{\DTLnegextent}{\dtl@old}{\dtl@barvar}% + }% + \ifx\dtlbar@yticgap\relax + \else + \ifthenelse{\DTLisFPlt{\DTLnegextent}{0}}% + {% + \edef\dtl@thistick{0}% + \whiledo{\DTLisFPclosedbetween{\dtl@thistick}{\DTLnegextent}{0}}{% + \dtlsub{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLnegextent=\dtl@thistick + }{}% + \fi + }% + {}% +% \end{macrocode} +% Determine scaling factor +% \begin{macrocode} + \@dtl@tmpcount=\DTLbarchartlength + \dtlsub{\dtl@extent}{\DTLbarmax}{\DTLnegextent}% + \dtldiv{\dtl@unit}{\number\@dtl@tmpcount}{\dtl@extent}% +% \end{macrocode} +% Construct $y$ tick list if required +% \begin{macrocode} + \setlength{\dtl@yticlabelwidth}{0pt}% + \ifDTLbarytics + \ifx\dtlbar@yticlist\relax + \ifx\dtlbar@yticgap\relax + \@dtl@tmpcount=\DTLmintickgap + \divide\@dtl@tmpcount by 65536\relax + \dtldiv{\dtl@mingap}{\number\@dtl@tmpcount}{\dtl@unit}% + \dtl@constructticklist\DTLnegextent\DTLbarmax + \dtl@mingap\dtlbar@yticlist + \else + \dtl@constructticklistwithgapz + \DTLnegextent\DTLbarmax\dtlbar@yticlist\dtlbar@yticgap + \fi + \fi + \ifx\dtlbar@ylabel\relax + \else + \ifx\dtlbar@yticlabels\relax + \@for\dtl@thislabel:=\dtlbar@yticlist\do{% + \dtlround{\dtl@thislabel}{\dtl@thislabel} + {\c@DTLbarroundvar}% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \else + \@for\dtl@thislabel:=\dtlbar@yticlabels\do{% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \fi + \fi + \fi +% \end{macrocode} +% Store the width of the bar chart in \cs{DTLbarchartwidth} +% \begin{macrocode} + \edef\DTLbarchartwidth{\expandafter\number\csname dtlrows@#3\endcsname} +% \end{macrocode} +% Do the bar chart +% \begin{macrocode} + \begin{tikzpicture} +% \end{macrocode} +% Set unit vectors +% \begin{macrocode} + \ifDTLverticalbars + \pgfsetyvec{\pgfpoint{0pt}{\dtl@unit sp}}% + \pgfsetxvec{\pgfpoint{\DTLbarwidth}{0pt}}% + \else + \pgfsetxvec{\pgfpoint{\dtl@unit sp}{0pt}}% + \pgfsetyvec{\pgfpoint{0pt}{\DTLbarwidth}}% + \fi +% \end{macrocode} +% Begin hook +% \begin{macrocode} + \DTLbaratbegintikz +% \end{macrocode} +% Initialise +% \begin{macrocode} + \def\@dtl@start{0}% +% \end{macrocode} +% Iterate through data +% \begin{macrocode} + \@sDTLforeach[#1]{#3}{#4}{% +% \end{macrocode} +% Store the bar number in \cs{@dtl@bar} +% \begin{macrocode} + \expandafter\let\expandafter\@dtl@bar + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname% +% \end{macrocode} +% Convert variable to decimal +% \begin{macrocode} + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@variable}% +% \end{macrocode} +% Draw bars +% \begin{macrocode} + \begin{scope} + \DTLdocurrentbarcolor + \ifDTLverticalbars + \fill (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@bar,\dtl@variable) -- (\@dtl@bar,0) -- cycle; + \else + \fill (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@bar) -- (0,\@dtl@bar) -- cycle; + \fi + \end{scope} +% \end{macrocode} +% Draw outline +% \begin{macrocode} + \begin{scope} + \ifdim\DTLbaroutlinewidth>0pt + \expandafter\color\expandafter{\DTLbaroutlinecolor} + \ifDTLverticalbars + \draw (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@bar,\dtl@variable) -- (\@dtl@bar,0) -- cycle; + \else + \draw (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@bar) -- (0,\@dtl@bar) -- cycle; + \fi + \fi + \end{scope} +% \end{macrocode} +% Draw lower $x$ labels +% \begin{macrocode} + \ifDTLverticalbars + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@start.5}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, + \DTLbarXlabelalign + }% +% \end{macrocode} +% Set \cs{DTLstartpt} to the starting point. +% \begin{macrocode} + \edef\DTLstartpt{\noexpand\pgfpointxy{\@dtl@start.5}{0}}% + \else + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\@dtl@start.5}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, + \DTLbarXlabelalign + }% +% \end{macrocode} +% Set \cs{DTLstartpt} to the starting point. +% \begin{macrocode} + \edef\DTLstartpt{\noexpand\pgfpointxy{0}{\@dtl@start.5}}% + \fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplaylowerbarlabel{\dtl@barlabel}} +% \end{macrocode} +% Draw upper $x$ labels +% \begin{macrocode} + \ifDTLverticalbars +% \end{macrocode} +% Vertical bars +% \begin{macrocode} + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0}% + { + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@start.5}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}} + }% + }{% + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@start.5}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} + }% + } +% \end{macrocode} +% Set \cs{DTLendpt} to the end point. +% \begin{macrocode} + \edef\DTLendpt{\noexpand\pgfpointxy{\@dtl@start.5}{\dtl@variable}}% + \else +% \end{macrocode} +% Horizontal bars +% \begin{macrocode} + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0}% + { + \edef\dtl@textopt{right, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@start.5}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}} + }% + }{% + \edef\dtl@textopt{left, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@start.5}} + {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} + }% + } +% \end{macrocode} +% Set \cs{DTLendpt} to the end point. +% \begin{macrocode} + \edef\DTLendpt{\noexpand\pgfpointxy{\dtl@variable}{\@dtl@start.5}}% + \fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplayupperbarlabel{\dtl@upperbarlabel}} +% \end{macrocode} +% Set the mid point +% \begin{macrocode} + \def\DTLmidpt{\pgfpointlineattime{0.5}{\DTLstartpt}{\DTLendpt}}% +% \end{macrocode} +% Do every bar hook +%\changes{2.0}{2009 February 27}{added \cs{DTLeverybarhook}}% +% \begin{macrocode} + \DTLeverybarhook +% \end{macrocode} +% End of loop +% \begin{macrocode} + \edef\@dtl@start{\number\@dtl@bar}% + }% +% \end{macrocode} +% Draw $x$ axis +% \begin{macrocode} + \ifDTLbarxaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (\DTLbarchartwidth,0); + \else + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (0,\DTLbarchartwidth); + \fi + \fi +% \end{macrocode} +% Draw $y$ axis +% \begin{macrocode} + \ifDTLbaryaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (0,\DTLnegextent) -- (0,\DTLbarmax); + \else + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (\DTLnegextent,0) -- (\DTLbarmax,0); + \fi + \fi +% \end{macrocode} +% Plot $y$ tick marks if required +% \begin{macrocode} + \ifx\dtlbar@yticlist\relax + \else + \@for\dtl@thistick:=\dtlbar@yticlist\do{% + \ifDTLverticalbars + \pgfpathmoveto{\pgfpointxy{0}{\dtl@thistick}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{0}{\dtl@thistick}} + {\pgfpoint{-\DTLticklength}{0pt}}} + \else + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{0}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{0}} + {\pgfpoint{0pt}{-\DTLticklength}}} + \fi + \pgfusepath{stroke} + \ifx\dtlbar@yticlabels\relax + \dtlround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLbarroundvar}% + \else + \dtl@chopfirst\dtlbar@yticlabels\dtl@thislabel\dtl@rest + \let\dtlbar@yticlabels=\dtl@rest + \fi + \ifDTLverticalbars + \edef\dtl@textopt{\DTLbarYticklabelalign,% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\dtl@thistick}} + {\noexpand\pgfpoint{-\noexpand\DTLticklabeloffset}{0pt}}, + }}% + \else + \edef\dtl@textopt{\DTLbarYticklabelalign, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@thistick}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLticklabeloffset}} + }}% + \fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLbardisplayYticklabel{\dtl@thislabel}} + }% + \fi +% \end{macrocode} +% Plot the $y$ label if required +% \begin{macrocode} + \ifx\dtlbar@ylabel\relax + \else + \addtolength{\dtl@yticlabelwidth}{\baselineskip}% + \setlength{\dtl@tmplength}{0.5\DTLbarchartlength} + \ifDTLverticalbars + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{0}{\DTLnegextent}}% + {\pgfpoint{-\dtl@yticlabelwidth}{\dtl@tmplength}}}, + rotate=90]{% + \dtlbar@ylabel} + \else + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{\DTLnegextent}{0}}% + {\pgfpoint{\dtl@tmplength}{-\dtl@yticlabelwidth}}}]{% + \dtlbar@ylabel} + \fi + \fi +% \end{macrocode} +% Finish bar chart +% \begin{macrocode} + \DTLbaratendtikz + \end{tikzpicture} + }% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLmultibarchart} +%\begin{definition} +% \cs{DTLmultibarchart}\oarg{conditions}\marg{option list}\marg{db name}\marg{assign list} +%\end{definition} +% Make a multi-bar chart from data given in data base \meta{db name}, +% where \meta{assign list} is a comma-separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. \meta{option list} must +% include the \texttt{variables} key which must be a comma separated +% list of commands, where each command +% is included in \meta{assign list}. The optional argument +% \meta{conditions} is the same as that for \cs{DTLforeach}. +% \begin{macrocode} +\newcommand*{\DTLmultibarchart}[4][\boolean{true}]{% +{\let\dtlbar@variables=\relax +\let\DTLbarmax=\relax +\let\DTLnegextent=\relax +\disable@keys{databar}{variable,upperbarlabel}% +\setkeys{databar}{#2}% +\ifx\dtlbar@variables\relax + \PackageError{databar}{\string\DTLmultibarchart\space missing variables setting}{}% +\else +% \end{macrocode} +% Compute the maximum bar height, unless \cs{DTLbarmax} has been +% set. +%\changes{1.01}{2007 Aug 17}{uses \cs{@sDTLforeach} instead of +%\cs{DTLforeach}} +% \begin{macrocode} + \ifx\DTLbarmax\relax + \@sDTLforeach[#1]{#3}{#4}{% + \@for\DTLbarvariable:=\dtlbar@variables\do{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \ifx\DTLbarmax\relax + \let\DTLbarmax=\dtl@barvar + \else + \let\dtl@old=\DTLbarmax + \dtlmax{\DTLbarmax}{\dtl@old}{\dtl@barvar}% + \fi + }% + }% + \ifx\dtlbar@yticgap\relax + \else + \let\dtl@thistick=\dtlbar@yticgap% + \whiledo{\DTLisFPopenbetween{\dtl@thistick}{0}{\DTLbarmax}}{% + \dtladd{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLbarmax=\dtl@thistick + \fi + \fi +% \end{macrocode} +% Compute the bar depth, unless \cs{DTLnegextent} has been +% set. +% \begin{macrocode} + \ifx\DTLnegextent\relax + \def\DTLnegextent{0}% + \@sDTLforeach[#1]{#3}{#4}{% + \@for\DTLbarvariable:=\dtlbar@variables\do{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@barvar}% + \let\dtl@old=\DTLnegextent + \DTLmin{\DTLnegextent}{\dtl@old}{\dtl@barvar}% + }% + }% + \ifx\dtlbar@yticgap\relax + \else + \ifthenelse{\DTLisFPlt{\DTLnegextent}{0}}{% + \edef\dtl@thistick{0}% + \whiledo{\DTLisFPclosedbetween{\dtl@thistick}{\DTLnegextent}{0}}{% + \dtlsub{\dtl@thistick}{\dtl@thistick}{\dtlbar@yticgap}% + }% + \let\DTLnegextent=\dtl@thistick + }{}% + \fi + \fi +% \end{macrocode} +% Determine scaling factor +% \begin{macrocode} + \@dtl@tmpcount=\DTLbarchartlength + \dtlsub{\dtl@extent}{\DTLbarmax}{\DTLnegextent}% + \dtldiv{\dtl@unit}{\number\@dtl@tmpcount}{\dtl@extent}% +% \end{macrocode} +% Construct $y$ tick list if required +% \begin{macrocode} + \setlength{\dtl@yticlabelwidth}{0pt}% + \ifDTLbarytics + \ifx\dtlbar@yticlist\relax + \ifx\dtlbar@yticgap\relax + \@dtl@tmpcount=\DTLmintickgap + \divide\@dtl@tmpcount by 65536\relax + \dtldiv{\dtl@mingap}{\number\@dtl@tmpcount}{\dtl@unit}% + \dtl@constructticklist\DTLnegextent\DTLbarmax + \dtl@mingap\dtlbar@yticlist + \else + \dtl@constructticklistwithgapz + \DTLnegextent\DTLbarmax\dtlbar@yticlist\dtlbar@yticgap + \fi + \fi + \ifx\dtlbar@ylabel\relax + \else + \ifx\dtlbar@yticlabels\relax + \@for\dtl@thislabel:=\dtlbar@yticlist\do{% + \dtlround{\dtl@thislabel}{\dtl@thislabel} + {\c@DTLbarroundvar}% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \else + \@for\dtl@thislabel:=\dtlbar@yticlabels\do{% + \ifDTLverticalbars + \settowidth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \else + \settoheight{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{% + \DTLbardisplayYticklabel{\dtl@thislabel}}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \fi + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \fi + \fi + \fi +% \end{macrocode} +% Calculate the offset for the lower label and number of labels +% \begin{macrocode} +\dtl@xticlabelheight=0pt\relax +\@dtl@tmpcount=0\relax +\@for\dtl@thislabel:=\dtl@multibarlabels\do{% + \advance\@dtl@tmpcount by 1\relax + \settoheight{\dtl@tmplength}{\tikz\expandafter\pgftext\expandafter + [\DTLbarXlabelalign]{\DTLdisplaylowerbarlabel{\dtl@thislabel}};}% + \edef\@dtl@h{\the\dtl@tmplength}% + \settodepth{\dtl@tmplength}{\tikz\expandafter\pgftext\expandafter + [\DTLbarXlabelalign]{\DTLdisplaylowerbarlabel{\dtl@thislabel}};}% + \addtolength{\dtl@tmplength}{\@dtl@h}% + \addtolength{\dtl@tmplength}{\baselineskip}% + \ifdim\dtl@tmplength>\dtl@xticlabelheight + \setlength{\dtl@xticlabelheight}{\dtl@tmplength}% + \fi +} +% \end{macrocode} +% Calculate number of bars per group +% \begin{macrocode} +\@dtl@tmpcount=0\relax +\@for\dtl@this:=\dtlbar@variables\do{% + \advance\@dtl@tmpcount by 1\relax +}% +\edef\DTLbargroupwidth{\number\@dtl@tmpcount}% +% \end{macrocode} +% Compute the total width of the bar chart (in terms of +% the $x$ unit vector.) +% \begin{macrocode} +\edef\dtl@n{\expandafter\number\csname dtlrows@#3\endcsname} +\dtlmul{\dtl@tmpi}{\dtl@n}{\DTLbargroupwidth} +\dtlsub{\dtl@tmpii}{\dtl@n}{1}% +\dtlmul{\dtl@tmpii}{\dtl@tmpii}{\dtlbar@groupgap}% +\dtladd{\DTLbarchartwidth}{\dtl@tmpi}{\dtl@tmpii} +% \end{macrocode} +% Do the bar chart +% \begin{macrocode} +\begin{tikzpicture} +% \end{macrocode} +% Set unit vectors +% \begin{macrocode} +\ifDTLverticalbars + \pgfsetyvec{\pgfpoint{0pt}{\dtl@unit sp}}% + \pgfsetxvec{\pgfpoint{\DTLbarwidth}{0pt}}% +\else + \pgfsetxvec{\pgfpoint{\dtl@unit sp}{0pt}}% + \pgfsetyvec{\pgfpoint{0pt}{\DTLbarwidth}}% +\fi +% \end{macrocode} +% Begin hook +% \begin{macrocode} +\DTLbaratbegintikz +% \end{macrocode} +% Initialise +% \begin{macrocode} +\def\@dtl@start{0}% +% \end{macrocode} +% Iterate through data +% \begin{macrocode} +\@sDTLforeach[#1]{#3}{#4}{% +% \end{macrocode} +% Store the bar number in \cs{@dtl@bar} +% \begin{macrocode} +\@dtl@barcount = 1\relax +% \end{macrocode} +% Set the multibar label lists +% \begin{macrocode} +\let\dtl@multibar@labels=\dtl@multibarlabels +\let\dtl@uppermultibar@labels=\dtl@uppermultibarlabels +% \end{macrocode} +% Compute mid point over group +% \begin{macrocode} +\dtlmul{\dtl@multimidpt}{\DTLbargroupwidth}{0.5}% +\dtladd{\dtl@multimidpt}{\dtl@multimidpt}{\@dtl@start}% +% \end{macrocode} +% Iterate through each variable +% \begin{macrocode} +\@for\DTLbarvariable:=\dtlbar@variables\do{% +% \end{macrocode} +% Set end point +% \begin{macrocode} +\dtladd{\@dtl@endpt}{\@dtl@start}{1}% +% \end{macrocode} +% Convert variable to decimal +% \begin{macrocode} +\expandafter\DTLconverttodecimal\expandafter + {\DTLbarvariable}{\dtl@variable}% +% \end{macrocode} +% Get the current lower label: +% \begin{macrocode} +\dtl@chopfirst\dtl@multibar@labels\dtl@thisbarlabel\dtl@rest +\let\dtl@multibar@labels=\dtl@rest +% \end{macrocode} +% Get the current upper label: +% \begin{macrocode} +\dtl@chopfirst\dtl@uppermultibar@labels\dtl@thisupperbarlabel\dtl@rest +\let\dtl@uppermultibar@labels=\dtl@rest +% \end{macrocode} +% Draw bars +% \begin{macrocode} +\begin{scope} + \expandafter\color\expandafter{\DTLgetbarcolor{\@dtl@barcount}}% + \ifDTLverticalbars + \fill (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@endpt,\dtl@variable) -- (\@dtl@endpt,0) -- cycle; + \else + \fill (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@endpt) -- (0,\@dtl@endpt) -- cycle; + \fi +\end{scope} +% \end{macrocode} +% Draw outline +% \begin{macrocode} +\begin{scope} +\ifdim\DTLbaroutlinewidth>0pt + \expandafter\color\expandafter{\DTLbaroutlinecolor} + \ifDTLverticalbars + \draw (\@dtl@start,0) -- (\@dtl@start,\dtl@variable) + -- (\@dtl@endpt,\dtl@variable) -- (\@dtl@endpt,0) -- cycle; + \else + \draw (0,\@dtl@start) -- (\dtl@variable,\@dtl@start) + -- (\dtl@variable,\@dtl@endpt) -- (0,\@dtl@endpt) -- cycle; + \fi +\fi +\end{scope} +% \end{macrocode} +% Calculate mid point +% \begin{macrocode} +\dtladd{\@dtl@midpt}{\@dtl@start}{0.5}% +% \end{macrocode} +% Draw lower $x$ labels +% \begin{macrocode} +\ifDTLverticalbars + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@midpt}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}}, + \DTLbarXlabelalign + }% + \edef\DTLstartpt{\noexpand\pgfpointxy{\@dtl@midpt}{0}}% +\else + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\@dtl@midpt}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}}, + \DTLbarXlabelalign + }% + \edef\DTLstartpt{\noexpand\pgfpointxy{0}{\@dtl@midpt}}% +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplaylowermultibarlabel{\dtl@thisbarlabel}} +% \end{macrocode} +% Draw upper $x$ labels +% \begin{macrocode} +\ifDTLverticalbars + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} + { + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@midpt}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLbarlabeloffset}}} + }% + }{% + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\@dtl@midpt}{\dtl@variable}} + {\noexpand\pgfpoint{0pt}{\noexpand\DTLbarlabeloffset}}} + }% + } + \edef\DTLendpt{\noexpand\pgfpointxy{\@dtl@midpt}{\dtl@variable}}% +\else + \expandafter\DTLifnumlt\expandafter{\DTLbarvariable}{0} + { + \edef\dtl@textopt{right, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@midpt}} + {\noexpand\pgfpoint{-\noexpand\DTLbarlabeloffset}{0pt}}} + }% + }{% + \edef\dtl@textopt{left, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@variable}{\@dtl@midpt}} + {\noexpand\pgfpoint{\noexpand\DTLbarlabeloffset}{0pt}}} + }% + } + \edef\DTLendpt{\noexpand\pgfpointxy{\dtl@variable}{\@dtl@midpt}}% +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplayuppermultibarlabel{\dtl@thisupperbarlabel}} +% \end{macrocode} +% Set the mid point +% \begin{macrocode} +\def\DTLmidpt{\pgfpointlineattime{0.5}{\DTLstartpt}{\DTLendpt}}% +% \end{macrocode} +% Do every bar hook +%\changes{2.0}{2009 February 27}{added \cs{DTLeverybarhook}}% +% \begin{macrocode} +\DTLeverybarhook +% \end{macrocode} +% End of loop increment loop variables +% \begin{macrocode} + \dtladd{\@dtl@start}{\@dtl@start}{1}% + \advance\@dtl@barcount by 1\relax +}% +% Draw lower group $x$ labels +% \begin{macrocode} +\setlength{\dtl@tmplength}{\DTLbarlabeloffset}% +\addtolength{\dtl@tmplength}{\dtl@xticlabelheight}% +\ifDTLverticalbars + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@multimidpt}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\dtl@tmplength}}}, + \DTLbarXlabelalign + }% +\else + \edef\dtl@textopt{% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\dtl@multimidpt}} + {\noexpand\pgfpoint{-\noexpand\dtl@tmplength}{0pt}}}, + \DTLbarXlabelalign + }% +\fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLdisplaylowerbarlabel{\dtl@barlabel}} +% \end{macrocode} +% Increment starting position by \cs{dtlbar@groupgap} +% \begin{macrocode} + \dtladd{\@dtl@start}{\@dtl@start}{\dtlbar@groupgap}% +} +% \end{macrocode} +% Draw $x$ axis +% \begin{macrocode} +\ifDTLbarxaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (\DTLbarchartwidth,0); + \else + \expandafter\draw\expandafter[\DTLBarXAxisStyle] + (0,0) -- (0,\DTLbarchartwidth); + \fi +\fi +% \end{macrocode} +% Draw $y$ axis +% \begin{macrocode} +\ifDTLbaryaxis + \ifDTLverticalbars + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (0,\DTLnegextent) -- (0,\DTLbarmax); + \else + \expandafter\draw\expandafter[\DTLBarYAxisStyle] + (\DTLnegextent,0) -- (\DTLbarmax,0); + \fi +\fi +% \end{macrocode} +% Plot $y$ tick marks if required +% \begin{macrocode} +\ifx\dtlbar@yticlist\relax +\else + \@for\dtl@thistick:=\dtlbar@yticlist\do{% + \ifDTLverticalbars + \pgfpathmoveto{\pgfpointxy{0}{\dtl@thistick}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{0}{\dtl@thistick}} + {\pgfpoint{-\DTLticklength}{0pt}}} + \else + \pgfpathmoveto{\pgfpointxy{\dtl@thistick}{0}} + \pgfpathlineto{ + \pgfpointadd{\pgfpointxy{\dtl@thistick}{0}} + {\pgfpoint{0pt}{-\DTLticklength}}} + \fi + \pgfusepath{stroke} + \ifx\dtlbar@yticlabels\relax + \dtlround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLbarroundvar}% + \else + \dtl@chopfirst\dtlbar@yticlabels\dtl@thislabel\dtl@rest + \let\dtlbar@yticlabels=\dtl@rest + \fi + \ifDTLverticalbars + \edef\dtl@textopt{\DTLbarYticklabelalign,% + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{0}{\dtl@thistick}} + {\noexpand\pgfpoint{-\noexpand\DTLticklabeloffset}{0pt}}, + }}% + \else + \edef\dtl@textopt{\DTLbarYticklabelalign, + at={\noexpand\pgfpointadd + {\noexpand\pgfpointxy{\dtl@thistick}{0}} + {\noexpand\pgfpoint{0pt}{-\noexpand\DTLticklabeloffset}} + }}% + \fi + \expandafter\pgftext\expandafter[\dtl@textopt]{% + \DTLbardisplayYticklabel{\dtl@thislabel}} + }% +\fi +% \end{macrocode} +% Plot the $y$ label if required +% \begin{macrocode} +\ifx\dtlbar@ylabel\relax +\else + \addtolength{\dtl@yticlabelwidth}{\baselineskip}% + \setlength{\dtl@tmplength}{0.5\DTLbarchartlength} + \ifDTLverticalbars + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{0}{\DTLnegextent}}% + {\pgfpoint{-\dtl@yticlabelwidth}{\dtl@tmplength}}}, + rotate=90]{% + \dtlbar@ylabel} + \else + \pgftext[bottom,center,at={\pgfpointadd + {\pgfpointxy{\DTLnegextent}{0}}% + {\pgfpoint{\dtl@tmplength}{-\dtl@yticlabelwidth}}}]{% + \dtlbar@ylabel} + \fi +\fi +% \end{macrocode} +% Finish bar chart +% \begin{macrocode} +\DTLbaratendtikz +\end{tikzpicture} +\fi +}} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</databar.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*datapie.sty> +% \end{macrocode} +%\fi +%\chapter{datapie.sty} +% Declare package: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{datapie}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Require \sty{xkeyval} package +% \begin{macrocode} +\RequirePackage{xkeyval} +% \end{macrocode} +%\begin{macro}{\ifDTLcolorpiechart} +% The conditional \cs{ifDTLcolorpiechart} is to determine +% whether to use colour or grey scale. +% \begin{macrocode} +\newif\ifDTLcolorpiechart +\DTLcolorpiecharttrue +% \end{macrocode} +%\end{macro} +% Package options to change the conditional: +% \begin{macrocode} +\DeclareOption{color}{\DTLcolorpiecharttrue} +\DeclareOption{gray}{\DTLcolorpiechartfalse} +% \end{macrocode} +%\begin{macro}{\ifDTLrotateinner} +% Define boolean keys to govern label rotations. +% \begin{macrocode} +\define@boolkey{datapie}[DTL]{rotateinner}[true]{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLrotateouter} +% \begin{macrocode} +\define@boolkey{datapie}[DTL]{rotateouter}[true]{} +% \end{macrocode} +%\end{macro} +% Set defaults: +% \begin{macrocode} +\DTLrotateinnerfalse +\DTLrotateouterfalse +% \end{macrocode} +% Package options to change \cs{DTLrotateinner} +% \begin{macrocode} +\DeclareOption{rotateinner}{\DTLrotateinnertrue} +\DeclareOption{norotateinner}{\DTLrotateinnerfalse} +% \end{macrocode} +% Package options to change \cs{DTLrotateouter} +% \begin{macrocode} +\DeclareOption{rotateouter}{\DTLrotateoutertrue} +\DeclareOption{norotateouter}{\DTLrotateouterfalse} +% \end{macrocode} +% Process options: +% \begin{macrocode} +\ProcessOptions +% \end{macrocode} +% Required packages: +% \begin{macrocode} +\RequirePackage{datatool} +\RequirePackage{tikz} +% \end{macrocode} +% Define some variables that govern the appearance of the pie +% chart. +% +%\begin{macro}{\DTLradius} +% The radius of the pie chart is given by \cs{DTLradius}. +% \begin{macrocode} +\newlength\DTLradius +\DTLradius=2cm +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLinnerratio} +% The inner label offset ratio is given by \cs{DTLinnerratio} +% \begin{macrocode} +\newcommand*{\DTLinnerratio}{0.5} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLouterratio} +% The outer label offset ratio is given by \cs{DTLouterratio}. +% \begin{macrocode} +\newcommand*{\DTLouterratio}{1.25} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLcutawayratio} +% The cutaway offset ratio is given by \cs{DTLcutawayratio}. +% \begin{macrocode} +\newcommand*\DTLcutawayratio{0.2} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLstartangle} +% The angle of the first segment is given by \cs{DTLstartangle}. +% \begin{macrocode} +\newcommand*{\DTLstartangle}{0} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@inneroffset} +% \begin{macrocode} +\newlength\dtl@inneroffset +\dtl@inneroffset=\DTLinnerratio\DTLradius +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@outeroffset} +% \begin{macrocode} +\newlength\dtl@outeroffset +\dtl@outeroffset=\DTLouterratio\DTLradius +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@cutawayoffset} +% \begin{macrocode} +\newlength\dtl@cutawayoffset +\dtl@cutawayoffset=\DTLcutawayratio\DTLradius +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@piecutaways} +% \cs{dtl@piecutaways} is a comma separated list of segments that +% need to be cut away from the pie chart. +% \begin{macrocode} +\newcommand*{\dtl@piecutaways}{} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@innerlabel} +% \cs{dtl@innerlabel} specifies the label to appear inside +% the segment. By default this is the variable used to create +% the pie chart. +% \begin{macrocode} +\def\dtl@innerlabel{\DTLpievariable}% +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@outerlabel} +% \begin{macrocode} +\def\dtl@outerlabel{}% +% \end{macrocode} +%\end{macro} +%\begin{counter}{DTLpieroundvar} +% \ctrfmt{DTLpieroundvar} is a counter governing the number of digits +% to round to when using \cs{FPround}. +% \begin{macrocode} +\newcounter{DTLpieroundvar} +\setcounter{DTLpieroundvar}{1} +% \end{macrocode} +%\end{counter} +% +%\begin{macro}{\DTLdisplayinnerlabel} +%\begin{definition} +%\cs{DTLdisplayinnerlabel}\marg{label} +%\end{definition} +% This is used to format the inner label. This just does the +% label by default. +% \begin{macrocode} +\newcommand*{\DTLdisplayinnerlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLdisplayouterlabel} +%\begin{definition} +%\cs{DTLdisplayouterlabel}\marg{label} +%\end{definition} +% This is used to format the outer label. This just does the +% label by default. +% \begin{macrocode} +\newcommand*{\DTLdisplayouterlabel}[1]{#1} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLpiepercent} +%\cs{DTLpiepercent} +% returns the percentage value of the current segment. +% \begin{macrocode} +\newcommand*{\DTLpiepercent}{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datapie}{Can't use + \string\DTLpiepercent\space outside + \string\DTLpiechart}{}% +\else + \csname dtl@piepercent@\romannumeral\@dtl@seg\endcsname +\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLpieatbegintikz} +% \cs{DTLpieatbegintikz} specifies any commands +% to apply at the start of the \env{tikzpicture} environment. +% By default it does nothing. +% \begin{macrocode} +\newcommand*{\DTLpieatbegintikz}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLpieatendtikz} +% \cs{DTLpieatendtikz} specifies any commands +% to apply at the end of the \env{tikzpicture} environment. +% By default it does nothing. +% \begin{macrocode} +\newcommand*{\DTLpieatendtikz}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLsetpiesegmentcolor} +%\begin{definition} +% \cs{DTLsetpiesegmentcolor}\marg{n}\marg{color} +%\end{definition} +% Assign colour name \meta{color} to the \meta{n}th segment. +% \begin{macrocode} +\newcommand*{\DTLsetpiesegmentcolor}[2]{% +\expandafter\def\csname dtlpie@segcol\romannumeral#1\endcsname{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLgetpiesegmentcolor} +%\begin{definition} +%\cs{DTLgetpiesegmentcolor}\marg{n} +%\end{definition} +% Get the colour specification for segment \meta{n} +% \begin{macrocode} +\newcommand*{\DTLgetpiesegmentcolor}[1]{% +\csname dtlpie@segcol\romannumeral#1\endcsname} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLdopiesegmentcolor} +%\begin{definition} +%\cs{DTLdopiesegmentcolor}\marg{n} +%\end{definition} +% Set the colour to that for segment \meta{n} +% \begin{macrocode} +\newcommand*{\DTLdopiesegmentcolor}[1]{% +\expandafter\color\expandafter +{\csname dtlpie@segcol\romannumeral#1\endcsname}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLdocurrentpiesegmentcolor} +%\cs{DTLdocurrentpiesegmentcolor} +% sets the colour to that of the current segment. +% \begin{macrocode} +\newcommand*{\DTLdocurrentpiesegmentcolor}{% +\ifnum\dtlforeachlevel=0\relax + \PackageError{datapie}{Can't use + \string\DTLdocurrentpiesegmentcolor\space outside + \string\DTLpiechart}{}% +\else + \expandafter\DTLdopiesegmentcolor\expandafter{% + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname}% +\fi} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLpieoutlinecolor} +%\cs{DTLpieoutlinecolor} specifies what colour to draw the +% outline. +% \begin{macrocode} +\newcommand*{\DTLpieoutlinecolor}{black} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLpieoutlinewidth} +%\cs{DTLpieoutlinewidth} specifies the line width of the outline: +% Outline is only drawn if the linewidth is greater than 0pt. +% \begin{macrocode} +\newlength\DTLpieoutlinewidth +\DTLpieoutlinewidth=0pt +% \end{macrocode} +%\end{macro} +% +% Set the default colours. If there are more than eight segments, +% more colours will need to be defined. +% \begin{macrocode} +\ifDTLcolorpiechart + \DTLsetpiesegmentcolor{1}{red} + \DTLsetpiesegmentcolor{2}{green} + \DTLsetpiesegmentcolor{3}{blue} + \DTLsetpiesegmentcolor{4}{yellow} + \DTLsetpiesegmentcolor{5}{magenta} + \DTLsetpiesegmentcolor{6}{cyan} + \DTLsetpiesegmentcolor{7}{orange} + \DTLsetpiesegmentcolor{8}{white} +\else + \DTLsetpiesegmentcolor{1}{black!15} + \DTLsetpiesegmentcolor{2}{black!25} + \DTLsetpiesegmentcolor{3}{black!35} + \DTLsetpiesegmentcolor{4}{black!45} + \DTLsetpiesegmentcolor{5}{black!55} + \DTLsetpiesegmentcolor{6}{black!65} + \DTLsetpiesegmentcolor{7}{black!75} + \DTLsetpiesegmentcolor{8}{black!85} +\fi +% \end{macrocode} +% Define keys for \cs{DTLpiechart} optional argument. +% Set the starting angle of the first segment. +% \begin{macrocode} +\define@key{datapie}{start}{\def\DTLstartangle{#1}} +% \end{macrocode} +% Set the radius of the pie chart (must be set prior to +% inneroffset and outeroffset keys.) +% \begin{macrocode} +\define@key{datapie}{radius}{\DTLradius=#1\relax +\dtl@inneroffset=\DTLinnerratio\DTLradius +\dtl@outeroffset=\DTLouterratio\DTLradius +\dtl@cutawayoffset=\DTLcutawayratio\DTLradius} +% \end{macrocode} +% Set the inner ratio. +% \begin{macrocode} +\define@key{datapie}{innerratio}{% +\def\DTLinnerratio{#1}% +\dtl@inneroffset=\DTLinnerratio\DTLradius} +% \end{macrocode} +% Set the outer ratio +% \begin{macrocode} +\define@key{datapie}{outerratio}{% +\def\DTLouterratio{#1}% +\dtl@outeroffset=\DTLouterratio\DTLradius} +% \end{macrocode} +% The cutaway offset ratio +% \begin{macrocode} +\define@key{datapie}{cutawayratio}{% +\def\DTLcutawayratio{#1}% +\dtl@cutawayoffset=\DTLcutawayratio\DTLradius} +% \end{macrocode} +% Set the inner offset as an absolute value (not dependent +% on the radius.) +% \begin{macrocode} +\define@key{datapie}{inneroffset}{% +\dtl@inneroffset=#1} +% \end{macrocode} +% Set the outer offset as an absolute value (not dependent +% on the radius.) +% \begin{macrocode} +\define@key{datapie}{outeroffset}{% +\dtl@outeroffset=#1} +% \end{macrocode} +% Set the cutaway offset as an absolute value (not dependent +% on the radius.) +% \begin{macrocode} +\define@key{datapie}{cutawayoffset}{% +\dtl@cutawayoffset=#1} +% \end{macrocode} +% List of cut away segments. +% \begin{macrocode} +\define@key{datapie}{cutaway}{% +\renewcommand*{\dtl@piecutaways}{#1}} +% \end{macrocode} +% Variable used to create the pie chart. (Must be a control +% sequence.) +% \begin{macrocode} +\define@key{datapie}{variable}{% +\def\DTLpievariable{#1}} +% \end{macrocode} +% Inner label +% \begin{macrocode} +\define@key{datapie}{innerlabel}{% +\def\dtl@innerlabel{#1}} +% \end{macrocode} +% Outer label +% \begin{macrocode} +\define@key{datapie}{outerlabel}{% +\def\dtl@outerlabel{#1}} +% \end{macrocode} +% +%\begin{macro}{\DTLpiechart} +%\begin{definition} +% \cs{DTLpiechart}\oarg{conditions}\marg{option list}\marg{db name}\marg{assign list} +%\end{definition} +% Make a pie chart from data given in data base \meta{db name}, +% where \meta{assign list} is a comma-separated list of +% \meta{cmd}\texttt{=}\meta{key} pairs. \meta{option list} must +% include \texttt{variable}\texttt{=}\meta{cmd}, where \meta{cmd} +% is included in \meta{assign list}. The optional argument +% \meta{conditions} is the same as that for \cs{DTLforeach}. +%\changes{2.26}{2016-07-20}{replaced fp commands} +% \begin{macrocode} +\newcommand*{\DTLpiechart}[4][\boolean{true}]{% +\bgroup + \let\DTLpievariable=\relax + \setkeys{datapie}{#2}% + \ifx\DTLpievariable\relax + \PackageError{datapie}% + {\string\DTLpiechart\space missing variable}{}% + \else +% \end{macrocode} +% Compute the total. +%\changes{1.01}{2007 Aug 17}{uses \cs{@sDTLforeach} instead of +%\cs{DTLforeach}} +% \begin{macrocode} + \def\dtl@total{0}% + \@sDTLforeach[#1]{#3}{#4}{% + \let\dtl@oldtotal=\dtl@total + \expandafter\DTLconverttodecimal\expandafter + {\DTLpievariable}{\dtl@variable}% + \dtladd{\dtl@total}{\dtl@variable}{\dtl@total}% + }% +% \end{macrocode} +% Compute the angles +% \begin{macrocode} + \expandafter\DTLconverttodecimal\expandafter + {\DTLstartangle}{\@dtl@start}% + \@sDTLforeach[#1]{#3}{#4}{% + \expandafter\DTLconverttodecimal\expandafter + {\DTLpievariable}{\dtl@variable}% + \dtl@computeangles + {\csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname}% + {\dtl@variable}% + \expandafter\@dtl@seg\expandafter= + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname% + \dtlmul{\dtl@tmp}{\dtl@variable}{100}% + \let\dtl@old=\dtl@tmp + \dtldiv{\dtl@tmp}{\dtl@old}{\dtl@total}% + \expandafter\dtlround + \csname dtl@piepercent@\romannumeral\@dtl@seg\endcsname\dtl@tmp + \c@DTLpieroundvar + }% +% \end{macrocode} +% Compute the offsets for each cut away segment +% \begin{macrocode} + \@for\dtl@row:=\dtl@piecutaways\do{% + \expandafter\@dtl@set@off\dtl@row-\relax + }% +% \end{macrocode} +% Set the starting angle +% \begin{macrocode} + \let\dtl@start=\DTLstartangle +% \end{macrocode} +% Do the pie chart +% \begin{macrocode} + \begin{tikzpicture} + \DTLpieatbegintikz + \@sDTLforeach[#1]{#3}{#4}% + {% +% \end{macrocode} +% Store the segment number in \cs{@dtl@seg} +% \begin{macrocode} + \expandafter\@dtl@seg\expandafter= + \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname% +% \end{macrocode} +% Set the start angle. +% \begin{macrocode} + \edef\dtl@start{% + \csname dtl@sang@\romannumeral\@dtl@seg\endcsname}% +% \end{macrocode} +% Set the extent +% \begin{macrocode} + \edef\dtl@extent{% + \csname dtl@angle@\romannumeral\@dtl@seg\endcsname}% +% \end{macrocode} +% Compute the end angle +% \begin{macrocode} + \dtladd{\dtl@endangle}{\dtl@start}{\dtl@extent}% +% \end{macrocode} +% Compute the shift. +% \begin{macrocode} + \edef\dtl@angle{% + \csname dtl@cut@angle@\romannumeral\@dtl@seg\endcsname}% + \let\dtl@old=\dtl@angle + \dtl@truncatedecimal\dtl@angle + \ifnum\dtl@angle>180\relax + \dtlsub{\dtl@angle}{\dtl@old}{360}% + \dtl@truncatedecimal\dtl@angle + \fi + \edef\dtl@cutlen{% + \csname dtl@cut@len@\romannumeral\@dtl@seg\endcsname + }% + \edef\@dtl@shift{(\dtl@angle:\dtl@cutlen)}% +% \end{macrocode} +% Compute the mid way angle. +% \begin{macrocode} + \dtlmul{\dtl@angle}{\dtl@extent}{0.5}% + \dtladd{\dtl@midangle}{\dtl@angle}{\dtl@start}% +% \end{macrocode} +% Draw the segment. +% \begin{macrocode} + \begin{scope}[shift={\@dtl@shift}]% +% \end{macrocode} +%\changes{2.26}{2016-07-20}{removed truncation (caused minor gap between +%first and last segments)} +% \begin{macrocode} + \fill[color=\DTLgetpiesegmentcolor\@dtl@seg] (0,0) -- + (\dtl@start:\DTLradius) + arc (\dtl@start:\dtl@endangle:\DTLradius) -- cycle; +% \end{macrocode} +% Draw the outline if required: +% \begin{macrocode} + \ifdim\DTLpieoutlinewidth>0pt\relax + \draw[color=\DTLpieoutlinecolor,% + line width=\DTLpieoutlinewidth] + (0,0) -- (\dtl@start:\DTLradius) + arc (\dtl@start:\dtl@endangle:\DTLradius) -- cycle; + \fi +% \end{macrocode} +% Convert decimal to an integer +% \begin{macrocode} + \dtl@truncatedecimal\dtl@midangle +% \end{macrocode} +% Determine whether to rotate inner labels +% \begin{macrocode} + \ifDTLrotateinner +% \end{macrocode} +% If the mid way angle is between 90 and 270, the text will look +% upside-down, so adjust accordingly. +%\changes{2.26}{2016-07-20}{replaced \cs{ifthen}} +% \begin{macrocode} + \dtlifnumopenbetween{\dtl@midangle}{90}{270}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumlt{\dtl@midangle}{-90}% + {\let\@dtl@next\@firstoftwo}% + {\let\@dtl@next\@secondoftwo}% + }% + \@dtl@next + {% + \dtlsub{\dtl@labelangle}{\dtl@midangle}{180}% + \dtl@truncatedecimal\dtl@labelangle + \edef\dtl@innernodeopt{anchor=east,rotate=\dtl@labelangle}% + }% + {% + \edef\dtl@innernodeopt{anchor=west,rotate=\dtl@midangle}% + }% +% \end{macrocode} +% Don't rotate inner labels +% \begin{macrocode} + \else + \edef\dtl@innernodeopt{anchor=center}% + \fi +% \end{macrocode} +% Determine whether to rotate outer labels +% \begin{macrocode} + \ifDTLrotateouter +% \end{macrocode} +% If the mid way angle is between 90 and 270, the text will look +% upside-down, so adjust accordingly. +% \begin{macrocode} + \dtlifnumopenbetween{\dtl@midangle}{90}{270}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumlt{\dtl@midangle}{-90}% + {\let\@dtl@next\@firstoftwo}% + {\let\@dtl@next\@secondoftwo}% + }% + \@dtl@next + {% + \dtlsub{\dtl@labelangle}{\dtl@midangle}{180}% + \dtl@truncatedecimal\dtl@labelangle + \edef\dtl@outernodeopt{anchor=east,rotate=\dtl@labelangle}% + }% + {% + \edef\dtl@outernodeopt{anchor=west,rotate=\dtl@midangle}% + }% +% \end{macrocode} +% Don't rotate outer labels +% \begin{macrocode} + \else +% \end{macrocode} +% If ($\theta>-45$ and $\theta < 45$) or $\theta=45$ or $\theta>315$ +% \begin{macrocode} + \dtlifnumeq{\dtl@midangle}{45} + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumgt{\dtl@midangle}{315} + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumopenbetween{\dtl@midangle}{-45}{45}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \let\@dtl@next\@secondoftwo + }% + }% + }% + \@dtl@next + {% +% \end{macrocode} +% East quadrant +% \begin{macrocode} + \edef\dtl@outernodeopt{anchor=west}% + }% + {% + \dtlifnumopenbetween{\dtl@midangle}{45}{135}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumeq{\dtl@midangle}{135}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \let\@dtl@next\@secondoftwo + }% + }% + \@dtl@next + {% +% \end{macrocode} +% North quadrant +% \begin{macrocode} + \edef\dtl@outernodeopt{anchor=south}% + }% + {% +% \end{macrocode} +%If ($\theta>135$ and $\theta<225$) or $\theta=225$ or $\theta=-135$ +%or $\theta<-135$ +% \begin{macrocode} + \dtlifnumopenbetween{\dtl@midangle}{135}{225}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumeq{\dtl@midangle}{225}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumeq{\dtl@midangle}{-135}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \dtlifnumlt{\dtl@midangle}{-135}% + {% + \let\@dtl@next\@firstoftwo + }% + {% + \let\@dtl@next\@secondoftwo + }% + }% + }% + }% + \@dtl@next + {% +% \end{macrocode} +% West quadrant +% \begin{macrocode} + \edef\dtl@outernodeopt{anchor=east}% + }% + {% + \edef\dtl@outernodeopt{anchor=north}% + }% + }% + }% + \fi +% \end{macrocode} +% Draw inner and outer labels +% \begin{macrocode} + \edef\@dtl@dolabel{% + \noexpand\draw (\dtl@midangle:\the\dtl@inneroffset) + node[\dtl@innernodeopt]{% + \noexpand\DTLdisplayinnerlabel{\noexpand\dtl@innerlabel}}; + }% + \@dtl@dolabel + \edef\@dtl@dolabel{% + \noexpand\draw (\dtl@midangle:\the\dtl@outeroffset) + node[\dtl@outernodeopt]{% + \noexpand\DTLdisplayouterlabel{\noexpand\dtl@outerlabel}}; + }% + \@dtl@dolabel + \end{scope}% + }% + \DTLpieatendtikz + \end{tikzpicture}% + \fi +\egroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@computeangles} +%\begin{definition} +%\cs{dtl@computeangles}\marg{n}\marg{variable} +%\end{definition} +% Compute the angles for segment \meta{n}. This sets +% \cs{dtl@sang@}\meta{n} (start angle), +% \cs{dtl@angle@}\meta{n} (extent angle), +% \cs{dtl@cut@angle@}\meta{n} (cut away angle) and +% \cs{dtl@cut@len@}\meta{n} (cut away length). +%\changes{2.26}{2016-07-20}{replaced fp commands} +% \begin{macrocode} +\newcommand*{\dtl@computeangles}[2]{% + \dtlifnumgt{\@dtl@start}{180}% + {% +% \end{macrocode} +% if $\mathrm{startangle} > 180$ +% \begin{macrocode} + \let\dtl@old=\@dtl@start +% \end{macrocode} +% $\mathrm{startangle} := \mathrm{startangle} - 360$ +% \begin{macrocode} + \dtlsub{\@dtl@start}{\dtl@old}{360}% + }% + {}% + \dtlifnumlt{\@dtl@start}{-180}% + {% +% \end{macrocode} +% if $\mathrm{startangle} < -180$ +% \begin{macrocode} + \let\dtl@old=\@dtl@start +% \end{macrocode} +% $\mathrm{startangle} = \mathrm{startangle} + 360$ +% \begin{macrocode} + \dtladd{\@dtl@start}{\dtl@old}{360}% + }% + {}% + \expandafter\edef\csname dtl@sang@\romannumeral#1\endcsname{% + \@dtl@start}% + \dtlmul{\dtl@angle}{360}{#2}% + \let\dtl@old=\dtl@angle + \dtldiv{\dtl@angle}{\dtl@old}{\dtl@total}% + \expandafter\let\csname dtl@angle@\romannumeral#1\endcsname=\dtl@angle + \let\dtl@old=\@dtl@start + \dtladd{\@dtl@start}{\dtl@old}{\dtl@angle}% + \expandafter\def\csname dtl@cut@angle@\romannumeral#1\endcsname{0}% + \expandafter\def\csname dtl@cut@len@\romannumeral#1\endcsname{0cm}% +} +% \end{macrocode} +%\end{macro} +% +% Set the offset angles. +%\begin{macro}{\@dtl@set@off} +% \begin{macrocode} +\def\@dtl@set@off#1-#2\relax{% + \ifstrempty{#2}% + {% + \@@dtl@set@off{#1}% + }% + {% + \@@dtl@set@offr#1-#2\relax + }% +} +% \end{macrocode} +%\end{macro} +% Set offset for individual segment: +%\begin{macro}{\@@dtl@set@off} +%\changes{2.26}{2016-07-20}{replaced fp commands} +% \begin{macrocode} +\newcommand*{\@@dtl@set@off}[1]{% + \edef\dtl@old{\csname dtl@angle@\romannumeral#1\endcsname}% + \dtlmul{\dtl@angle}{\dtl@old}{0.5}% + \let\dtl@old=\dtl@angle + \edef\dtl@sang{\csname dtl@sang@\romannumeral#1\endcsname}% + \dtladd{\dtl@angle}{\dtl@old}{\dtl@sang}% + \expandafter\edef\csname dtl@cut@angle@\romannumeral#1\endcsname{% + \dtl@angle}% + \expandafter\edef\csname dtl@cut@len@\romannumeral#1\endcsname{% + \the\dtl@cutawayoffset}% +} +% \end{macrocode} +%\end{macro} +% Define count register to keep track of segments +%\begin{macro}{\@dtl@seg} +% \begin{macrocode} +\newcount\@dtl@seg +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@@dtl@setoffr} +% Set offset for a range of segments +%\changes{2.26}{2016-07-20}{replaced fp commands} +% \begin{macrocode} +\def\@@dtl@set@offr#1-#2-\relax{% + \ifnum#1>#2\relax + \PackageError{datapie}{Segment ranges must go in ascending order}{% + Try #2-#1 instead of #1-#2}% + \else + \def\dtl@angle{0}% + \@dtl@seg=#1\relax + \whiledo{\not\(\@dtl@seg > #2\)}{% + \let\dtl@old=\dtl@angle + \edef\dtl@segang{\csname dtl@angle@\romannumeral\@dtl@seg\endcsname}% + \dtladd{\dtl@angle}{\dtl@old}{\dtl@segang}% + \advance\@dtl@seg by 1\relax + }% + \let\dtl@old=\dtl@angle + \dtlmul{\dtl@angle}{\dtl@old}{0.5}% + \edef\dtl@sang{\csname dtl@sang@\romannumeral#1\endcsname}% + \let\dtl@old=\dtl@angle + \dtladd{\dtl@angle}{\dtl@old}{\dtl@sang}% + \@dtl@seg=#1\relax + \whiledo{\not\(\@dtl@seg > #2\)}{% + \expandafter + \let\csname dtl@cut@angle@\romannumeral\@dtl@seg\endcsname + =\dtl@angle + \expandafter + \edef\csname dtl@cut@len@\romannumeral\@dtl@seg\endcsname{% + \the\dtl@cutawayoffset} + \advance\@dtl@seg by 1\relax + }% + \fi +} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</datapie.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*dataplot.sty> +% \end{macrocode} +%\fi +%\chapter{dataplot.sty} +% Declare package: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{dataplot}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Required packages +% \begin{macrocode} +\RequirePackage{xkeyval} +\RequirePackage{tikz} +\RequirePackage{datatool} +% \end{macrocode} +% Load TikZ plot libraries +% \begin{macrocode} +\usetikzlibrary{plotmarks} +\usetikzlibrary{plothandlers} +% \end{macrocode} +% Load calc library +%\changes{2.14}{2013-06-28}{added calc library requirement} +% \begin{macrocode} +\usetikzlibrary{calc} +% \end{macrocode} +% +%\begin{macro}{\DTLplotstream} +%\begin{definition} +%\cs{DTLplotstream}\oarg{condition}\marg{db name}\marg{x key}\marg{y key} +%\end{definition} +% Add 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}. +% The optional argument \meta{condition} is the same as that +% for \cs{DTLforeach} +%\changes{1.01}{2007 Aug 17}{uses \cs{@sDTLforeach} instead of +%\cs{DTLforeach}} +% \begin{macrocode} +\newcommand*{\DTLplotstream}[4][\boolean{true}]{% + \@sDTLforeach[#1]{#2}{\dtl@x=#3,\dtl@y=#4}{% + \DTLconverttodecimal{\dtl@x}{\dtl@decx}% + \DTLconverttodecimal{\dtl@y}{\dtl@decy}% + \pgfplotstreampoint{\pgfpointxy{\dtl@decx}{\dtl@decy}}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLplotmarks} +%\cs{DTLplotmarks} contains a list of plot marks used by +%\cs{DTLplot}. +% \begin{macrocode} +\newcommand*{\DTLplotmarks}{% + \pgfuseplotmark{o},% + \pgfuseplotmark{x},% + \pgfuseplotmark{+},% + \pgfuseplotmark{square},% + \pgfuseplotmark{triangle},% + \pgfuseplotmark{diamond},% + \pgfuseplotmark{pentagon},% + \pgfuseplotmark{asterisk},% + \pgfuseplotmark{star}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLplotmarkcolors} +%\cs{DTLplotmarkcolors} contains a list of the plot mark colours. +% \begin{macrocode} +\newcommand*{\DTLplotmarkcolors}{% + red,% + green,% + blue,% + yellow,% + magenta,% + cyan,% + orange,% + black,% + gray} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLplotlines} +%\cs{DTLplotlines} contains a list of dash patterns used by +%\cs{DLTplot}. +%\changes{1.03}{2009 January 27}{fixed error in solid line setting} +% \begin{macrocode} +\newcommand*{\DTLplotlines}{% + \pgfsetdash{}{0pt},% solid line + \pgfsetdash{{10pt}{5pt}}{0pt},% + \pgfsetdash{{5pt}{5pt}}{0pt},% + \pgfsetdash{{1pt}{5pt}}{0pt},% + \pgfsetdash{{5pt}{5pt}{1pt}{5pt}}{0pt},% + \pgfsetdash{{1pt}{3pt}}{0pt},% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLplotlinecolors} +%\cs{DTLplotlinecolors} contains a list of the plot line colours. +% \begin{macrocode} +\newcommand*{\DTLplotlinecolors}{% + red,% + green,% + blue,% + yellow,% + magenta,% + cyan,% + orange,% + black,% + gray} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLplotwidth} +% The default total plot width is stored in the length +% \cs{dtlplotwidth} +% \begin{macrocode} +\newlength\DTLplotwidth +\setlength\DTLplotwidth{4in} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLplotheight} +% The default total plot height is stored in the length +% \cs{dtlplotheight} +% \begin{macrocode} +\newlength\DTLplotheight +\setlength\DTLplotheight{4in} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLticklength} +% The length of the tick marks is given by \cs{DTLticklength} +% \begin{macrocode} +\newlength\DTLticklength +\setlength\DTLticklength{5pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLminorticklength} +% The length of the minor tick marks is given by +% \cs{DTLminorticklength}. +% \begin{macrocode} +\newlength\DTLminorticklength +\setlength\DTLminorticklength{2pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLticklabeloffset} +% The offset from the axis to the tick label is given by +% \cs{DTLticklabeloffset}. +% \begin{macrocode} +\newlength\DTLticklabeloffset +\setlength\DTLticklabeloffset{8pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@xticlabelheight} +% \cs{dtl@xticlabelheight} is used to store the height of +% the $x$ tick labels. +% \begin{macrocode} +\newlength\dtl@xticlabelheight +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@yticlabelwidth} +% \cs{dtl@yticlabelwidth} is used to store the width of +% the $y$ tick labels. +% \begin{macrocode} +\newlength\dtl@yticlabelwidth +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLmintickgap} +% \cs{DTLmintickgap} stores the suggested minimum distance between +% tick marks where the gap is not specified. +% \begin{macrocode} +\newlength\DTLmintickgap +\setlength\DTLmintickgap{20pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLminminortickgap} +% The suggested minimum distance between minor tick marks where the +% gap is not specified is given by \cs{DTLminminortickgap}. +% \begin{macrocode} +\newlength\DTLminminortickgap +\setlength\DTLminminortickgap{5pt} +% \end{macrocode} +%\end{macro} +%\begin{counter}{DTLplotroundvar} +% Round $x$ tick labels to the number of digits given by +% the counter \ctrfmt{DTLplotroundXvar}. +% \begin{macrocode} +\newcounter{DTLplotroundXvar} +\setcounter{DTLplotroundXvar}{2} +% \end{macrocode} +%\end{counter} +%\begin{counter}{DTLplotroundYvar} +% Round $y$ tick labels to the number of digits given by +% the counter \ctrfmt{DTLplotroundYvar}. +% \begin{macrocode} +\newcounter{DTLplotroundYvar} +\setcounter{DTLplotroundYvar}{2} +% \end{macrocode} +%\end{counter} +%\begin{macro}{\ifDTLxaxis} +% The conditional \cs {ifDTLxaxis} is used to determine whether or +% not to display the $x$ axis. +% \begin{macrocode} +\newif\ifDTLxaxis +\DTLxaxistrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLXAxisStyle} +% The style of the $x$ axis is given by \cs{DTLXAxisStyle}. This +% is just a solid line by default. +% \begin{macrocode} +\newcommand*{\DTLXAxisStyle}{-} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifDTLyaxis} +% The conditional \cs{ifDTLyaxis} is used to determine whether or +% not to display the $y$ axis +% \begin{macrocode} +\newif\ifDTLyaxis +\DTLyaxistrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLYAxisStyle} +% The style of the $y$ axis is given by \cs{DTLYAxisStyle}. This +% is just a solid line by default. +% \begin{macrocode} +\newcommand*{\DTLYAxisStyle}{-} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLmajorgridstyle} +% The style of the major grid lines is given by +% \cs{DTLmajorgridstyle}. +% \begin{macrocode} +\newcommand*{\DTLmajorgridstyle}{color=gray,-} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLminorgridstyle} +% The style of the minor grid lines is given by +% \cs{DTLminorgridstyle}. +% \begin{macrocode} +\newcommand*{\DTLminorgridstyle}{color=gray,loosely dotted} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifDTLxticsin} +% The conditional \cs{ifDTLxticsin} is used to determine whether +% the $x$ tics should point in or out. +% \begin{macrocode} +\newif\ifDTLxticsin +\DTLxticsintrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLyticsin} +% The conditional \cs{ifDTLyticsin} is used to determine whether +% the $y$ tics should point in or out. +% \begin{macrocode} +\newif\ifDTLyticsin +\DTLyticsintrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\dtl@legendsetting} +% The legend setting is stored in the count register +% \cs{dtl@legendsetting}. +% \begin{macrocode} +\newcount\dtl@legendsetting +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLlegendxoffset} +% The gap between the border of plot and legend is given by the +% lengths \cs{DTLlegendxoffset} and \cs{DTLlegendyoffset} +% \begin{macrocode} +\newlength\DTLlegendxoffset +\setlength\DTLlegendxoffset{10pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLlegendyoffset} +% \begin{macrocode} +\newlength\DTLlegendyoffset +\setlength\DTLlegendyoffset{10pt} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLformatlegend} +%\begin{definition} +%\cs{DTLformatlegend}\marg{legend} +%\end{definition} +% This formats the legend. +% \begin{macrocode} +\newcommand*{\DTLformatlegend}[1]{% +\setlength{\fboxrule}{1.1pt}% +\fcolorbox{black}{white}{#1}} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLshowmarkers} +% The conditional \cs{ifDTLshowmarkers} is used to specify +% whether or not to use markers. +% \begin{macrocode} +\newif\ifDTLshowmarkers +\DTLshowmarkerstrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLshowlines} +% The conditional \cs{ifDTLshowlines} is used to specify +% whether or not to use lines. +% \begin{macrocode} +\newif\ifDTLshowlines +\DTLshowlinesfalse +% \end{macrocode} +%\end{macro} +%\begin{macro}{\DTLplotatbegintikz} +% \cs{DTLplotatbegintikz} is a hook to insert stuff at the +% start of the \env{tikzpicture} +% environment (after the unit vectors have been set). +% \begin{macrocode} +\newcommand*{\DTLplotatbegintikz}{} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtlplothandlermark} +%\changes{2.15}{2013-07-10}{new} +% Provide a convenient access to \cs{pgfplothandlermark} that +% reverses the effect of the plot scaling. +% \begin{macrocode} +\newcommand*{\@dtlplothandlermark}[1]{% + \pgfplothandlermark + {% + \pgfmathparse{1/\dtl@scale@x}% + \pgftransformxscale{\pgfmathresult}% + \pgfmathparse{1/\dtl@scale@y}% + \pgftransformyscale{\pgfmathresult}% + #1% + }% +} +% \end{macrocode} +% Just in case a user attempts to use \cs{dtlplothandermark} outside +% \ics{DTLplot}: +% \begin{macrocode} +\newcommand*{\dtlplothandlermark}[1]{% + \PackageWarning{dataplot}{\string\dtlplothandlermark\space + found outside \string\DTLplot}% + \pgfplothandlermark{#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLplotatendtikz} +% \cs{DTLplotatendtikz} is a hook to insert stuff at the end +% of the \env{tikzpicture} environment. +% \begin{macrocode} +\newcommand*{\DTLplotatendtikz}{} +% \end{macrocode} +%\end{macro} +% +% Plot settings. The database key for the $x$ value is +% given by the "x" setting: +% \begin{macrocode} +\define@key{dataplot}{x}{% +\def\dtl@xkey{#1}} +% \end{macrocode} +% The database key for the $y$ value is given by the "y" setting: +% \begin{macrocode} +\define@key{dataplot}{y}{% +\def\dtl@ykey{#1}} +% \end{macrocode} +% The list of plot mark colours is given by the "markcolors" setting. +% (This should be a comma separated list of colour names.) +% \begin{macrocode} +\define@key{dataplot}{markcolors}{% +\def\DTLplotmarkcolors{#1}} +% \end{macrocode} +% The list of plot line colours is given by the "linecolors" setting. +% (This should be a comma separated list of colour names.) +% \begin{macrocode} +\define@key{dataplot}{linecolors}{% +\def\DTLplotlinecolors{#1}} +% \end{macrocode} +% The list of plot mark and line colours is given by the "colors" +% setting. (This should be a comma separated list of colour names.) +% \begin{macrocode} +\define@key{dataplot}{colors}{% +\def\DTLplotmarkcolors{#1}% +\def\DTLplotlinecolors{#1}} +% \end{macrocode} +% The list of plot marks is given by the "marks" setting. (This +% should be a comma separated list of code that generates +% pgf plot marks.) +% \begin{macrocode} +\define@key{dataplot}{marks}{% +\def\DTLplotmarks{#1}} +% \end{macrocode} +% The list of plot line styles is given by the "lines" setting. (This +% should be a comma separated list of code that sets the line +% style.) An empty set will create solid lines. +% \begin{macrocode} +\define@key{dataplot}{lines}{% +\def\DTLplotlines{#1}} +% \end{macrocode} +% The total width of the plot is given by the "width" setting. +% \begin{macrocode} +\define@key{dataplot}{width}{% +\setlength\DTLplotwidth{#1}} +% \end{macrocode} +% The total height of the plot is given by the "height" setting. +% \begin{macrocode} +\define@key{dataplot}{height}{% +\setlength\DTLplotheight{#1}} +% \end{macrocode} +% Determine whether to show lines, markers or both +% \begin{macrocode} +\define@choicekey{dataplot}{style}[\val\nr]{both,lines,markers}{% +\ifcase\nr\relax + \DTLshowlinestrue + \DTLshowmarkerstrue +\or + \DTLshowlinestrue + \DTLshowmarkersfalse +\or + \DTLshowmarkerstrue + \DTLshowlinesfalse +\fi} +% \end{macrocode} +% Determine whether or not to display the axes +% \begin{macrocode} +\define@choicekey{dataplot}{axes}[\val\nr]{both,x,y,none}[both]{% +\ifcase\nr\relax + % both + \DTLxaxistrue + \DTLxticstrue + \DTLyaxistrue + \DTLyticstrue +\or % x + \DTLxaxistrue + \DTLxticstrue + \DTLyaxisfalse + \DTLyticsfalse +\or % y + \DTLxaxisfalse + \DTLxticsfalse + \DTLyaxistrue + \DTLyticstrue +\or % none + \DTLxaxisfalse + \DTLxticsfalse + \DTLyaxisfalse + \DTLyticsfalse +\fi +} +% \end{macrocode} +%\begin{macro}{\ifDTLbox} +% Enclose plot in a box +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{box}[true]{} +\DTLboxfalse +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLxticstrue} +% Condition to determine whether to show the $x$ tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{xtics}[true]{} +\DTLxticstrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLyticstrue} +% Condition to determine whether to show the $y$ tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{ytics}[true]{} +\DTLyticstrue +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLxminortics} +% Condition to determine whether to show the $x$ minor tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{xminortics}[true]{% +\ifDTLxminortics \DTLxticstrue\fi} +\DTLxminorticsfalse +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLyminortics} +% Condition to determine whether to show the $y$ minor tick marks +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{yminortics}[true]{% +\ifDTLyminortics \DTLyticstrue\fi} +\DTLyminorticsfalse +% \end{macrocode} +%\end{macro} +%\begin{macro}{\ifDTLgrid} +% Determine whether to draw the grid +% \begin{macrocode} +\define@boolkey{dataplot}[DTL]{grid}[true]{} +% \end{macrocode} +%\end{macro} +% Determine whether the $x$ tick marks should point +% in or out: +% \begin{macrocode} +\define@choicekey{dataplot}{xticdir}[\val\nr]{in,out}{% +\ifcase\nr\relax + \DTLxticsintrue +\or + \DTLxticsinfalse +\fi +} +% \end{macrocode} +% Determine whether the $y$ tick marks should point +% in or out: +% \begin{macrocode} +\define@choicekey{dataplot}{yticdir}[\val\nr]{in,out}{% +\ifcase\nr\relax + \DTLyticsintrue +\or + \DTLyticsinfalse +\fi +} +% \end{macrocode} +% Determine whether the $x$ and $y$ tick marks should point +% in or out; +% \begin{macrocode} +\define@choicekey{dataplot}{ticdir}[\val\nr]{in,out}{% +\ifcase\nr\relax + \DTLxticsintrue + \DTLyticsintrue +\or + \DTLxticsinfalse + \DTLyticsinfalse +\fi +} +% \end{macrocode} +% Set the bounds of the graph (value must be in the form +% \meta{min x}","\meta{min y}","\meta{max x}","\meta{max y} +% (bounds overrides minx, miny, maxx and maxy settings.) +% \begin{macrocode} +\define@key{dataplot}{bounds}{% +\def\dtl@bounds{#1}} +\let\dtl@bounds=\relax +% \end{macrocode} +% Set only the lower $x$ bound +% \begin{macrocode} +\define@key{dataplot}{minx}{% +\def\dtl@minx{#1}} +\let\dtl@minx=\relax +% \end{macrocode} +% Set only the upper $x$ bound: +% \begin{macrocode} +\define@key{dataplot}{maxx}{% +\def\dtl@maxx{#1}} +\let\dtl@maxx=\relax +% \end{macrocode} +% Set only the lower $y$ bound: +% \begin{macrocode} +\define@key{dataplot}{miny}{% +\def\dtl@miny{#1}} +\let\dtl@miny=\relax +% \end{macrocode} +% Set only the upper $y$ bound: +% \begin{macrocode} +\define@key{dataplot}{maxy}{% +\def\dtl@maxy{#1}} +\let\dtl@maxy=\relax +% \end{macrocode} +% Define list of points for $x$ ticks. (Must be a comma separated +% list of decimal numbers.) +% \begin{macrocode} +\define@key{dataplot}{xticpoints}{% +\def\dtl@xticlist{#1}\DTLxticstrue\DTLxaxistrue} +\let\dtl@xticlist=\relax +% \end{macrocode} +% Define list of points for $y$ ticks. (Must be a comma separated +% list of decimal numbers.) +% \begin{macrocode} +\define@key{dataplot}{yticpoints}{% +\def\dtl@yticlist{#1}\DTLyticstrue\DTLyaxistrue} +\let\dtl@yticlist=\relax +% \end{macrocode} +% Define a the gap between $x$ tick marks (xticpoints overrides +% xticgap) +% \begin{macrocode} +\define@key{dataplot}{xticgap}{\def\dtl@xticgap{#1}% +\DTLxticstrue\DTLxaxistrue} +\let\dtl@xticgap=\relax +% \end{macrocode} +% Define a the gap between $y$ tick marks (yticpoints overrides +% yticgap) +% \begin{macrocode} +\define@key{dataplot}{yticgap}{\def\dtl@yticgap{#1}% +\DTLyticstrue\DTLyaxistrue} +\let\dtl@yticgap=\relax +% \end{macrocode} +% Define comma separated list of labels for $x$ ticks. +% \begin{macrocode} +\define@key{dataplot}{xticlabels}{% +\def\dtl@xticlabels{#1}\DTLxticstrue\DTLxaxistrue} +\let\dtl@xticlabels=\relax +% \end{macrocode} +% Define comma separated list of labels for $y$ ticks. +% \begin{macrocode} +\define@key{dataplot}{yticlabels}{% +\def\dtl@yticlabels{#1}\DTLyticstrue\DTLyaxistrue} +\let\dtl@yticlabels=\relax +% \end{macrocode} +% Define $x$ axis label +% \begin{macrocode} +\define@key{dataplot}{xlabel}{% +\def\dtl@xlabel{#1}} +\let\dtl@xlabel=\relax +% \end{macrocode} +% Define $y$ axis label +% \begin{macrocode} +\define@key{dataplot}{ylabel}{% +\def\dtl@ylabel{#1}} +\let\dtl@ylabel=\relax +% \end{macrocode} +% The legend setting may be one of: "none" (don't show it), +% "north", "northeast", "east", "southeast", "south", "southwest", +% "west", or "northwest". These set the count register +% \cs{dtl@legendsetting}. +% \begin{macrocode} +\define@choicekey{dataplot}{legend}[\val\nr]{none,north,northeast,% +east,southeast,south,southwest,west,northwest}[northeast]{% +\dtl@legendsetting=\nr\relax +} +% \end{macrocode} +% Legend labels (comma separated list). If omitted, the database +% name is used. +% \begin{macrocode} +\define@key{dataplot}{legendlabels}{\def\dtl@legendlabels{#1}} +% \end{macrocode} +% +%\begin{macro}{\DTLplot} +%\begin{definition} +%\cs{DTLplot}\oarg{condition}\marg{db list}\marg{settings} +%\end{definition} +% Creates a plot (inside a \env{tikzpicture} environment) of all +% the data given in the databases listed in \meta{db list}. +% \begin{macrocode} +\newcommand*{\DTLplot}[3][\boolean{true}]{% +\bgroup + \let\dtl@xkey=\relax + \let\dtl@ykey=\relax + \let\dtl@legendlabels=\relax + \setkeys{dataplot}{#3}% + \let\dtl@plotmarklist=\DTLplotmarks + \let\dtl@plotlinelist=\DTLplotlines + \let\dtl@plotmarkcolorlist=\DTLplotmarkcolors + \let\dtl@plotlinecolorlist=\DTLplotlinecolors + \def\dtl@legend{}% + \ifx\dtl@legendlabels\relax + \edef\dtl@legendlabels{#2}% + \fi + \ifx\dtl@xkey\relax + \PackageError{dataplot}{Missing x setting for + \string\DTLplot}{}% + \else + \ifx\dtl@ykey\relax + \PackageError{dataplot}{Missing y setting for + \string\DTLplot}{}% + \else +% \end{macrocode} +% If user didn't specified bounds, +% compute the maximum and minimum $x$ and $y$ values over +% all the databases listed. +% \begin{macrocode} + \ifx\dtl@bounds\relax + \DTLcomputebounds[#1]{#2}{\dtl@xkey}{\dtl@ykey} + {\DTLminX}{\DTLminY}{\DTLmaxX}{\DTLmaxY}% + \ifx\dtl@minx\relax + \else + \let\DTLminX=\dtl@minx + \fi + \ifx\dtl@maxx\relax + \else + \let\DTLmaxX=\dtl@maxx + \fi + \ifx\dtl@miny\relax + \else + \let\DTLminY=\dtl@miny + \fi + \ifx\dtl@maxy\relax + \else + \let\DTLmaxY=\dtl@maxy + \fi +% \end{macrocode} +% Otherwise extract information from \cs{dtl@bounds} +% \begin{macrocode} + \else + \expandafter\dtl@getbounds\dtl@bounds\@nil + \fi +% \end{macrocode} +% Determine scaling factors and offsets. The $x$-scale factor is +% given by: +%\[ +% s_x = \frac{W}{x_{\max}-x_{\min}} +%\] +% where $W$ is the plot width. The $x$ offset is $-s_x x_{\min}$. +% Similarly for $y$. +%\changes{2.14}{2013-06-28}{replaced \cs{FPsub} etc with \cs{dtlsub} etc} +% \begin{macrocode} + \@dtl@tmpcount=\DTLplotwidth + \divide\@dtl@tmpcount by 65536\relax + \dtlsub{\dtl@dx}{\DTLmaxX}{\DTLminX}% + \dtldiv{\dtl@scale@x}{\number\@dtl@tmpcount}{\dtl@dx}% + \dtlmul{\dtl@offset@x}{-\dtl@scale@x}{\DTLminX}% + \@dtl@tmpcount=\DTLplotheight + \divide\@dtl@tmpcount by 65536\relax + \dtlsub{\dtl@dy}{\DTLmaxY}{\DTLminY}% + \dtldiv{\dtl@scale@y}{\number\@dtl@tmpcount}{\dtl@dy}% + \dtlmul{\dtl@offset@y}{-\dtl@scale@y}{\DTLminY}% +% \end{macrocode} +% If x tics specified, construct a list of x tic points if not +% already specified. +% \begin{macrocode} + \ifDTLxtics + \ifx\dtl@xticlist\relax + \ifx\dtl@xticgap\relax +% \end{macrocode} +% Get the min tick gap in data co-ordinates +% \begin{macrocode} + \dtlsub{\dtl@mingap}{\number\DTLmintickgap}{\dtl@offset@x}% + \dtldiv{\dtl@mingap}{\dtl@mingap}{\dtl@scale@x}% + \dtldiv{\dtl@mingap}{\dtl@mingap}{65536}% +% \end{macrocode} +% construct tick list +% \begin{macrocode} + \dtl@constructticklist\DTLminX\DTLmaxX + \dtl@mingap\dtl@xticlist + \else + \DTLifFPopenbetween{0}{\DTLminX}{\DTLmaxX}{% + \dtl@constructticklistwithgapz + \DTLminX\DTLmaxX\dtl@xticlist\dtl@xticgap}{% + \dtl@constructticklistwithgap + \DTLminX\DTLmaxX\dtl@xticlist\dtl@xticgap}% + \fi + \fi +% \end{macrocode} +% Construct a list of $x$ minor tick points if required +% \begin{macrocode} + \let\dtl@xminorticlist\@empty + \ifDTLxminortics + \let\dtl@prevtick=\relax + \@for\dtl@nexttick:=\dtl@xticlist\do{% + \ifx\dtl@prevtick\relax + \else + \dtl@constructminorticklist + \dtl@prevtick\dtl@nexttick\dtl@scale@x\dtl@xminorticlist + \fi + \let\dtl@prevtick=\dtl@nexttick + }% + \fi +% \end{macrocode} +% Determine the height of the $x$ tick labels. +% \begin{macrocode} + \ifx\dtl@xticlabels\relax + \settoheight{\dtl@xticlabelheight}{\dtl@xticlist}% + \else + \settoheight{\dtl@xticlabelheight}{\dtl@xticlabels}% + \fi + \else + \setlength{\dtl@xticlabelheight}{0pt}% + \fi +% \end{macrocode} +% If y tics specified, construct a list of y tic points if not +% already specified. +% \begin{macrocode} + \setlength{\dtl@yticlabelwidth}{0pt}% + \ifDTLytics + \ifx\dtl@yticlist\relax + \ifx\dtl@yticgap\relax +% \end{macrocode} +% Get the min tick gap in data co-ordinates +% \begin{macrocode} + \dtlsub{\dtl@mingap}{\number\DTLmintickgap}{\dtl@offset@y}% + \dtldiv{\dtl@mingap}{\dtl@mingap}{\dtl@scale@y}% + \dtldiv{\dtl@mingap}{\dtl@mingap}{65536}% +% \end{macrocode} +% construct tick list +% \begin{macrocode} + \dtl@constructticklist\DTLminY\DTLmaxY + \dtl@mingap\dtl@yticlist + \else + \DTLifFPopenbetween{0}{\DTLminY}{\DTLmaxY}{% + \dtl@constructticklistwithgapz + \DTLminY\DTLmaxY\dtl@yticlist\dtl@yticgap}{% + \dtl@constructticklistwithgap + \DTLminY\DTLmaxY\dtl@yticlist\dtl@yticgap}% + \fi + \fi +% \end{macrocode} +% Construct a list of $y$ minor tick points if required +% \begin{macrocode} + \let\dtl@yminorticlist\@empty + \ifDTLyminortics + \let\dtl@prevtick=\relax + \@for\dtl@nexttick:=\dtl@yticlist\do{% + \ifx\dtl@prevtick\relax + \else + \dtl@constructminorticklist + \dtl@prevtick\dtl@nexttick\dtl@scale@y\dtl@yminorticlist + \fi + \let\dtl@prevtick=\dtl@nexttick + }% + \fi +% \end{macrocode} +% Determine the width of the $y$ tick labels. +%\changes{2.14}{2013-06-28}{replaced \cs{FPround} with \cs{dtlround}} +% \begin{macrocode} + \ifx\dtl@ylabel\relax + \else + \ifx\dtl@yticlabels\relax + \@for\dtl@thislabel:=\dtl@yticlist\do{% + \dtlround{\dtl@thislabel}{\dtl@thislabel} + {\c@DTLplotroundYvar}% + \settowidth{\dtl@tmplength}{\dtl@thislabel}% + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \else + \@for\dtl@thislabel:=\dtl@yticlabels\do{% + \settowidth{\dtl@tmplength}{\dtl@thislabel}% + \ifdim\dtl@tmplength>\dtl@yticlabelwidth + \setlength{\dtl@yticlabelwidth}{\dtl@tmplength}% + \fi + }% + \fi + \fi + \fi +% \end{macrocode} +% Start the picture. +% \begin{macrocode} + \begin{tikzpicture} +% \end{macrocode} +% Set the $x$ and $y$ unit vectors. +% \begin{macrocode} + \pgfsetxvec{\pgfpoint{1pt}{0pt}}% + \pgfsetyvec{\pgfpoint{0pt}{1pt}}% +% \end{macrocode} +% Set the transformation matrix, so user can plot things using the +% data co-ordinate space, but scope it, so it doesn't affect any plot +% marks later +% \begin{macrocode} + \begin{scope} + \pgftransformcm{\dtl@scale@x}{0}{0}{\dtl@scale@y}% + {\pgfpoint{\dtl@offset@x pt}{\dtl@offset@y pt}}% +% \end{macrocode} +% Add any extra information the user requires +% \begin{macrocode} + \let\dtlplothandlermark\@dtlplothandlermark + \DTLplotatbegintikz +% \end{macrocode} +% Determine whether to put a box around the plot +% \begin{macrocode} + \ifDTLbox + \draw (\DTLminX,\DTLminY) -- (\DTLmaxX,\DTLminY) -- + (\DTLmaxX,\DTLmaxY) -- (\DTLminX,\DTLmaxY) -- + cycle; + \else +% \end{macrocode} +% Plot $x$ axis if required. +% \begin{macrocode} + \ifDTLxaxis + \expandafter\draw\expandafter[\DTLXAxisStyle] + (\DTLminX,\DTLminY) -- (\DTLmaxX,\DTLminY); + \fi +% \end{macrocode} +% Plot $y$ axis if required. +% \begin{macrocode} + \ifDTLyaxis + \expandafter\draw\expandafter[\DTLYAxisStyle] + (\DTLminX,\DTLminY) -- (\DTLminX,\DTLmaxY); + \fi + \fi +% \end{macrocode} +% Plot grid if required +% \begin{macrocode} + \ifDTLgrid + \ifDTLxminortics + \@for\dtl@thistick:=\dtl@xminorticlist\do{% + \expandafter\draw\expandafter[\DTLminorgridstyle] + (\dtl@thistick,\DTLminY) -- (\dtl@thistick,\DTLmaxY); + }% + \fi + \ifDTLyminortics + \@for\dtl@thistick:=\dtl@yminorticlist\do{% + \expandafter\draw\expandafter[\DTLminorgridstyle] + (\DTLminX,\dtl@thistick) -- (\DTLmaxX,\dtl@thistick); + }% + \fi + \@for\dtl@thistick:=\dtl@xticlist\do{% + \expandafter\draw\expandafter[\DTLmajorgridstyle] + (\dtl@thistick,\DTLminY) -- (\dtl@thistick,\DTLmaxY); + }% + \@for\dtl@thistick:=\dtl@yticlist\do{% + \expandafter\draw\expandafter[\DTLmajorgridstyle] + (\DTLminX,\dtl@thistick) -- (\DTLmaxX,\dtl@thistick); + }% + \fi +% \end{macrocode} +% Plot $x$ tics if required. +% \begin{macrocode} + \ifDTLxtics +% \end{macrocode} +% Get tick length in terms of canvas co-ordinates +% \begin{macrocode} + \dtlsub{\dtl@ticklength}{\number\DTLticklength}{-\dtl@offset@y}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{\dtl@scale@y}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{65536}% +% \end{macrocode} +% Get tick label offset in terms of canvas co-ordinates +% \begin{macrocode} + \addtolength\dtl@xticlabelheight{\DTLticklabeloffset}% + \dtlsub{\dtl@ticlabeloffset}{\number\dtl@xticlabelheight}{-\dtl@offset@y}% + \dtldiv{\dtl@ticlabeloffset}{\dtl@ticlabeloffset}{\dtl@scale@y}% + \dtldiv{\dtl@ticlabeloffset}{\dtl@ticlabeloffset}{65536}% +% \end{macrocode} +% Iterate through tick list. +% \begin{macrocode} + \@for\dtl@thistick:=\dtl@xticlist\do{% +% \end{macrocode} +% Store tick label in \cs{dtl@thislabel} +% \begin{macrocode} + \let\dtl@thisticklabel\dtl@thistick + \ifx\dtl@xticlabels\relax + \dtlround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLplotroundXvar}% + \else + \dtl@chopfirst\dtl@xticlabels\dtl@thislabel\dtl@rest + \let\dtl@xticlabels=\dtl@rest + \fi +% \end{macrocode} +% Draw tick. +% \begin{macrocode} + \ifDTLxticsin + \draw (\dtl@thistick,\DTLminY) -- ++(0,\dtl@ticklength); + \draw (\dtl@thistick,\DTLminY) + ++ (0,-\dtl@ticlabeloffset) node {\dtl@thislabel}; + \else + \draw (\dtl@thistick,\DTLminY) -- ++(0,-\dtl@ticklength) + ++ (0,-\dtl@ticlabeloffset) node {\dtl@thislabel}; + \fi +% \end{macrocode} +% Draw opposite tick, if box setting is on. +% \begin{macrocode} + \ifDTLbox + \ifDTLxticsin + \draw (\dtl@thistick,\DTLmaxY) -- ++(0,-\dtl@ticklength); + \else + \draw (\dtl@thistick,\DTLmaxY) -- ++(0,\dtl@ticklength); + \fi + \fi + }% + \fi +% \end{macrocode} +% Plot $x$ label if required. +% \begin{macrocode} + \ifx\dtl@xlabel\relax + \else +% \end{macrocode} +% Get baseline in terms of canvas co-ordinates +% \begin{macrocode} + \dtladd{\dtl@x}{\number\baselineskip}{\dtl@offset@y}% + \dtldiv{\dtl@x}{\dtl@x}{\dtl@scale@y}% + \dtldiv{\dtl@x}{\dtl@x}{65536}% + \dtladd{\dtl@ticlabeloffset}{\dtl@ticlabeloffset}{\dtl@x}% +% \end{macrocode} +% Get halfway position +% \begin{macrocode} + \dtlmul{\dtl@x}{\dtl@dx}{0.5}% + \draw (\DTLminX,\DTLminY) ++(\dtl@x,-\dtl@ticlabeloffset) + node[anchor=north] {\dtl@xlabel}; + \fi +% \end{macrocode} +% Plot the $x$ minor ticks if required +% \begin{macrocode} + \ifDTLxminortics +% \end{macrocode} +% Get tick length in terms of canvas co-ordinates +% \begin{macrocode} + \dtlsub{\dtl@ticklength}{\number\DTLminorticklength}{-\dtl@offset@y}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{\dtl@scale@y}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{65536}% +% \end{macrocode} +% Iterate through minor ticks. +% \begin{macrocode} + \@for\dtl@thistick:=\dtl@xminorticlist\do{% + \ifDTLxticsin + \draw (\dtl@thistick,\DTLminY) -- ++(0,\dtl@ticklength); + \draw (\dtl@thistick,\DTLminY) + ++ (0,-\dtl@ticlabeloffset) node[anchor=north] {\dtl@thislabel}; + \else + \draw (\dtl@thistick,\DTLminY) -- ++(0,-\dtl@ticklength) + ++ (0,-\dtl@ticlabeloffset) node[anchor=north] {\dtl@thislabel}; + \fi +% \end{macrocode} +% Draw opposite tick, if box setting is on. +% \begin{macrocode} + \ifDTLbox + \ifDTLxticsin + \draw (\dtl@thistick,\DTLmaxY) -- ++(0,-\dtl@ticklength); + \else + \draw (\dtl@thistick,\DTLmaxY) -- ++(0,\dtl@ticklength); + \fi + \fi + }% + \fi +% \end{macrocode} +% Plot $y$ tics if required. +% \begin{macrocode} + \ifDTLytics +% \end{macrocode} +% Get tick length in terms of canvas co-ordinates +% \begin{macrocode} + \dtlsub{\dtl@ticklength}{\number\DTLticklength}{-\dtl@offset@x}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{\dtl@scale@x}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{65536}% +% \end{macrocode} +% Get tick label offset in terms of canvas co-ordinates +% \begin{macrocode} + \dtladd{\dtl@ticlabeloffset}{\number\DTLticklabeloffset}{0}% + \dtlsub{\dtl@ticlabeloffset}{\number\DTLticklabeloffset}{-\dtl@offset@x}% + \dtldiv{\dtl@ticlabeloffset}{\dtl@ticlabeloffset}{\dtl@scale@x}% + \dtldiv{\dtl@ticlabeloffset}{\dtl@ticlabeloffset}{65536}% +% \end{macrocode} +% Iterate through tick list. +% \begin{macrocode} + \@for\dtl@thistick:=\dtl@yticlist\do{% +% \end{macrocode} +% Store tick label in \cs{dtl@thislabel} +% \begin{macrocode} + \let\dtl@thisticklabel\dtl@thistick + \ifx\dtl@yticlabels\relax + \dtlround{\dtl@thislabel}{\dtl@thistick} + {\c@DTLplotroundXvar}% + \else + \dtl@chopfirst\dtl@yticlabels\dtl@thislabel\dtl@rest + \let\dtl@yticlabels=\dtl@rest + \fi +% \end{macrocode} +% Draw tick. +% \begin{macrocode} + \ifDTLyticsin + \draw (\DTLminX,\dtl@thistick) -- ++(\dtl@ticklength,0); + \draw (\DTLminX,\dtl@thistick) + ++ (-\dtl@ticlabeloffset,0) node[anchor=east] {\dtl@thislabel}; + \else + \draw (\DTLminX,\dtl@thistick) -- ++(-\dtl@ticklength,0) + ++ (-\dtl@ticlabeloffset,0) node[anchor=east] {\dtl@thislabel}; + \fi +% \end{macrocode} +% Draw opposite tick, if box setting is on. +% \begin{macrocode} + \ifDTLbox + \ifDTLyticsin + \draw (\DTLmaxX,\dtl@thistick) -- ++(-\dtl@ticklength,0); + \else + \draw (\DTLmaxX,\dtl@thistick) -- ++(\dtl@ticklength,0); + \fi + \fi + }% + \fi +% \end{macrocode} +% Plot $y$ label if required. +% \begin{macrocode} + \ifx\dtl@ylabel\relax + \else + \setlength{\dtl@tmplength}{\baselineskip}% + \addtolength{\dtl@tmplength}{\dtl@yticlabelwidth}% + \addtolength{\dtl@tmplength}{\DTLticklabeloffset}% + \dtlsub{\dtl@ticlabeloffset}{\number\dtl@tmplength}{-\dtl@offset@x}% + \dtldiv{\dtl@ticlabeloffset}{\dtl@ticlabeloffset}{\dtl@scale@x}% + \dtldiv{\dtl@ticlabeloffset}{\dtl@ticlabeloffset}{65536}% +% \end{macrocode} +% Get halfway position +% \begin{macrocode} + \dtlmul{\dtl@y}{\dtl@dy}{0.5}% + \draw (\DTLminX,\DTLminY) ++(-\dtl@ticlabeloffset,\dtl@y) + node[rotate=90,anchor=south] {\dtl@ylabel}; + \fi +% \end{macrocode} +% Plot the $y$ minor ticks if required +% \begin{macrocode} + \ifDTLyminortics +% \end{macrocode} +% Get tick length in terms of canvas co-ordinates +% \begin{macrocode} + \dtlsub{\dtl@ticklength}{\number\DTLminorticklength}{-\dtl@offset@x}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{\dtl@scale@x}% + \dtldiv{\dtl@ticklength}{\dtl@ticklength}{65536}% +% \end{macrocode} +% Iterate through minor ticks. +% \begin{macrocode} + \@for\dtl@thistick:=\dtl@yminorticlist\do{% + \ifDTLyticsin + \draw (\DTLminX,\dtl@thistick) -- ++(\dtl@ticklength,0); + \else + \draw (\DTLminX,\dtl@thistick) -- ++(-\dtl@ticklength,0); + \fi +% \end{macrocode} +% Draw opposite tick, if box setting is on. +% \begin{macrocode} + \ifDTLbox + \ifDTLyticsin + \draw (\DTLmaxX,\dtl@thistick) -- ++(-\dtl@ticklength,0); + \else + \draw (\DTLmaxX,\dtl@thistick) -- ++(\dtl@ticklength,0); + \fi + \fi + }% + \fi +% \end{macrocode} +% End the transformation scope. (Don't want marker shapes to be +% scaled or skewed.) +% \begin{macrocode} + \end{scope} +% \end{macrocode} +% Iterate through each database +% \begin{macrocode} + \@for\dtl@thisdb:=#2\do{% +% \end{macrocode} +% Get the current plot mark colour. +% \begin{macrocode} + \ifx\dtl@plotmarkcolorlist\@empty + \let\dtl@plotmarkcolorlist=\DTLplotmarkcolors + \fi + \dtl@chopfirst\dtl@plotmarkcolorlist\dtl@thisplotmarkcolor + \dtl@remainder + \let\dtl@plotmarkcolorlist=\dtl@remainder +% \end{macrocode} +% Get the current plot mark, and store in \cs{dtl@mark} +% \begin{macrocode} + \ifDTLshowmarkers + \ifx\dtl@plotmarklist\@empty + \let\dtl@plotmarklist=\DTLplotmarks + \fi + \dtl@chopfirst\dtl@plotmarklist\dtl@thisplotmark + \dtl@remainder + \let\dtl@plotmarklist=\dtl@remainder + \ifx\dtl@thisplotmark\relax + \let\dtl@mark=\relax + \else + \expandafter\toks@\expandafter{\dtl@thisplotmark}% + \ifx\dtl@thisplotmarkcolor\@empty + \edef\dtl@mark{\the\toks@}% + \else + \edef\dtl@mark{% + \noexpand\color{\dtl@thisplotmarkcolor}% + \the\toks@}% + \fi + \fi + \else + \let\dtl@mark=\relax + \fi +% \end{macrocode} +% Get the current plot line colour. +% \begin{macrocode} + \ifx\dtl@plotlinecolorlist\@empty + \let\dtl@plotlinecolorlist=\DTLplotlinecolors + \fi + \dtl@chopfirst\dtl@plotlinecolorlist\dtl@thisplotlinecolor + \dtl@remainder + \let\dtl@plotlinecolorlist=\dtl@remainder +% \end{macrocode} +% Get the current line style, and store in \cs{dtl@linestyle} +% \begin{macrocode} + \ifDTLshowlines + \ifx\dtl@plotlinelist\@empty + \let\dtl@plotlinelist=\DTLplotlines + \fi + \dtl@chopfirst\dtl@plotlinelist\dtl@thisplotline + \dtl@remainder + \let\dtl@plotlinelist=\dtl@remainder + \expandafter\ifx\dtl@thisplotline\relax + \let\dtl@linestyle=\relax + \else + \expandafter\toks@\expandafter{\dtl@thisplotline}% + \ifx\dtl@thisplotlinecolor\@empty + \edef\dtl@linestyle{\the\toks@}% + \else + \edef\dtl@linestyle{% + \noexpand\color{\dtl@thisplotlinecolor}% + \the\toks@}% + \fi + \fi + \else + \let\dtl@linestyle=\relax + \fi +% \end{macrocode} +% Append this plot setting to the legend. +% \begin{macrocode} + \ifnum\dtl@legendsetting>0\relax + \dtl@chopfirst\dtl@legendlabels\dtl@thislabel\dtl@rest + \let\dtl@legendlabels=\dtl@rest + \expandafter\toks@\expandafter{\dtl@mark}% + \expandafter\@dtl@toks\expandafter{\dtl@linestyle}% + \edef\dtl@addtolegend{\noexpand\DTLaddtoplotlegend + {\the\toks@}{\the\@dtl@toks}{\dtl@thislabel}}% + \dtl@addtolegend + \fi +% \end{macrocode} +% Store stream in \cs{dtl@stream} +% \begin{macrocode} + \def\dtl@stream{\pgfplotstreamstart}% +% \end{macrocode} +% Only plot points that lie inside bounds. +%\changes{1.01}{2007 Aug 17}{uses \cs{@sDTLforeach} instead of +%\cs{DTLforeach}} +% \begin{macrocode} + \@sDTLforeach[#1]{\dtl@thisdb}{\dtl@x=\dtl@xkey,% + \dtl@y=\dtl@ykey}{% + \DTLconverttodecimal{\dtl@x}{\dtl@decx}% + \DTLconverttodecimal{\dtl@y}{\dtl@decy}% + \ifthenelse{% + \DTLisclosedbetween{\dtl@x}{\DTLminX}{\DTLmaxX}% + \and + \DTLisclosedbetween{\dtl@y}{\DTLminY}{\DTLmaxY}% + }% + {% + \expandafter\toks@\expandafter{\dtl@stream}% +% \end{macrocode} +% Apply transformation to co-ordinates +% \begin{macrocode} + \dtlmul{\dtl@decx}{\dtl@decx}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \dtlround{\dtl@decx}{\dtl@decx}{1}% + \dtlmul{\dtl@decy}{\dtl@decy}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \dtlround{\dtl@decy}{\dtl@decy}{1}% + \edef\dtl@stream{\the\toks@ + \noexpand\pgfplotstreampoint + {\noexpand\pgfpointxy{\dtl@decx}{\dtl@decy}}}% + }{}% + }% + \expandafter\toks@\expandafter{\dtl@stream}% + \edef\dtl@stream{\the\toks@\noexpand\pgfplotstreamend}% +% \end{macrocode} +% End plot stream and draw path. +% \begin{macrocode} + \ifx\dtl@linestyle\relax + \else + \begin{scope} + \dtl@linestyle + \pgfplothandlerlineto + \dtl@stream + \pgfusepath{stroke} + \end{scope} + \fi + \ifx\dtl@mark\relax + \else + \begin{scope} + \pgfplothandlermark{\dtl@mark}% + \dtl@stream + \pgfusepath{stroke} + \end{scope} + \fi + }% +% \end{macrocode} +% Plot legend if required. +% \begin{macrocode} + \ifcase\dtl@legendsetting + % none + \or % north + \dtlmul{\dtl@decx}{\dtl@dx}{0.5}% + \dtladd{\dtl@decx}{\DTLminX}{\dtl@decx}% + \dtlmul{\dtl@decx}{\dtl@decx}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \dtlmul{\dtl@decy}{\DTLmaxY}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \draw (\dtl@decx,\dtl@decy) ++(0,-\DTLlegendyoffset) + node[anchor=north] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \or % north east + \dtlmul{\dtl@decx}{\DTLmaxX}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \dtlmul{\dtl@decy}{\DTLmaxY}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \draw (\dtl@decx,\dtl@decy) ++(-\DTLlegendxoffset,-\DTLlegendyoffset) + node[anchor=north east] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \or % east + \dtlmul{\dtl@decy}{\dtl@dy}{0.5}% + \dtladd{\dtl@decy}{\DTLminY}{\dtl@decy}% + \dtlmul{\dtl@decy}{\dtl@decy}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \dtlmul{\dtl@decx}{\DTLmaxX}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \draw (\dtl@decx,\dtl@decy) ++(-\DTLlegendxoffset,0) + node[anchor=east] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \or % south east + \dtlmul{\dtl@decx}{\DTLmaxX}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \dtlmul{\dtl@decy}{\DTLminY}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \draw (\dtl@decx,\dtl@decy) ++(-\DTLlegendxoffset,\DTLlegendyoffset) + node[anchor=south east] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \or % south + \dtlmul{\dtl@decx}{\dtl@dx}{0.5}% + \dtladd{\dtl@decx}{\DTLminX}{\dtl@decx}% + \dtlmul{\dtl@decx}{\dtl@decx}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \dtlmul{\dtl@decy}{\DTLminY}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \draw (\dtl@decx,\dtl@decy) ++(0,\DTLlegendyoffset) + node[anchor=south] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \or % south west + \dtlmul{\dtl@decx}{\DTLminX}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \dtlmul{\dtl@decy}{\DTLminY}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \draw (\dtl@decx,\dtl@decy) ++(\DTLlegendxoffset,\DTLlegendyoffset) + node[anchor=south west] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \or % west + \dtlmul{\dtl@decy}{\dtl@dy}{0.5}% + \dtladd{\dtl@decy}{\DTLminY}{\dtl@decy}% + \dtlmul{\dtl@decy}{\dtl@decy}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \dtlmul{\dtl@decx}{\DTLminX}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \draw (\dtl@decx,\dtl@decy) ++(\DTLlegendxoffset,0) + node[anchor=west] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \or % north west + \dtlmul{\dtl@decx}{\DTLminX}{\dtl@scale@x}% + \dtladd{\dtl@decx}{\dtl@decx}{\dtl@offset@x}% + \dtlmul{\dtl@decy}{\DTLmaxY}{\dtl@scale@y}% + \dtladd{\dtl@decy}{\dtl@decy}{\dtl@offset@y}% + \draw (\dtl@decx,\dtl@decy) ++(\DTLlegendxoffset,-\DTLlegendyoffset) + node[anchor=north west] + {\DTLformatlegend + {\begin{tabular}{cl}\dtl@legend\end{tabular}}% + }; + \fi +% \end{macrocode} +% Set the transformation matrix, so user can plot things using the +% data co-ordinate space +% \begin{macrocode} + \pgftransformcm{\dtl@scale@x}{0}{0}{\dtl@scale@y}% + {\pgfpoint{\dtl@offset@x pt}{\dtl@offset@y pt}}% +% \end{macrocode} +% End hook +% \begin{macrocode} + \let\dtlplothandlermark\@dtlplothandlermark + \DTLplotatendtikz + \end{tikzpicture} + \fi + \fi +\egroup +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@getbounds} +% Extract bounds: +%\changes{2.14}{2013-06-28}{changed \cs{FPifgt} to \cs{dtlifnumgt}} +% \begin{macrocode} +\def\dtl@getbounds#1,#2,#3,#4\@nil{% +\def\DTLminX{#1}% +\def\DTLminY{#2}% +\def\DTLmaxX{#3}% +\def\DTLmaxY{#4}% +\dtlifnumgt{\DTLminX}{\DTLmaxX} +{% + \PackageError{dataplot}{Min X > Max X in bounds #1,#2,#3,#4}{% + The bounds must be specified as minX,minY,maxX,maxY}% +}{}% +\dtlifnumgt{\DTLminY}{\DTLmaxY} +{% + \PackageError{dataplot}{Min Y > Max Y in bounds #1,#2,#3,#4}{% + The bounds must be specified as minX,minY,maxX,maxY}% +}{}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@constructticklist} +%\begin{definition} +%\cs{dtl@constructticklist}\marg{min}\marg{max}\marg{min gap}\marg{list} +%\end{definition} +% Constructs a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence.) +%\changes{2.14}{2013-06-28}{replaced \cs{FPsub} with \cs{dtlsub} etc} +% \begin{macrocode} +\newcommand*{\dtl@constructticklist}[4]{% + \DTLifFPopenbetween{0}{#1}{#2}% + {% +% \end{macrocode} +% Tick list straddles the origin. +% \begin{macrocode} + \dtlsub{\@dtl@width}{0}{#1}% + \dtldiv{\@dtl@neggap}{\@dtl@width}{10}% + \dtlifnumlt{\@dtl@neggap}{#3}% + {% + \edef\@dtl@neggap{#3}% + }% + {}% + \dtldiv{\@dtl@posgap}{#2}{10}% + \dtlifnumlt{\@dtl@posgap}{#3}% + {% + \edef\@dtl@posgap{#3}% + }% + {}% + \dtlmax{\@dtl@gap}{\@dtl@neggap}{\@dtl@posgap}% +% \end{macrocode} +% Don't construct a list if minimum gap is greater than plot width +% \begin{macrocode} + \dtlifnumgt{\@dtl@gap}{\@dtl@width}% + {}% + {% + \dtl@constructticklistwithgapz{#1}{#2}{#4}{\@dtl@gap}% + }% + }% + {% +% \end{macrocode} +% Tick list doesn't straddle the origin. +% \begin{macrocode} + \dtlsub{\@dtl@width}{#2}{#1}% + \dtldiv{\@dtl@gap}{\@dtl@width}{10}% + \dtlifnumlt{\@dtl@gap}{#3}% + {% +% \end{macrocode} +% Don't construct a list if minimum gap is greater than plot width +% \begin{macrocode} + \dtlifnumgt{#3}{\@dtl@width}% + {% + \def#4{#1,#2}% + }% + {% + \dtl@constructticklistwithgap{#1}{#2}{#4}{#3}% + } + }% + {% + \dtl@constructticklistwithgap{#1}{#2}{#4}{\@dtl@gap}% + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@constructticklistwithgap} +%\begin{definition} +%\cs{dtl@constructticklistwithgap}\marg{min}\marg{max}\marg{list}\marg{gap} +%\end{definition} +% Constructs a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence) using the gap given +% by \meta{gap} where the gap is given in user co-ordinates. +%\changes{2.14}{2013-06-28}{replaced \cs{FPadd} with \cs{dtladd}} +% \begin{macrocode} +\newcommand*{\dtl@constructticklistwithgap}[4]{% +\edef\@dtl@thistick{#1}% +\edef#3{#1}% +\dtladd{\@dtl@thistick}{\@dtl@thistick}{#4}% +\whiledo{\DTLisFPopenbetween{\@dtl@thistick}{#1}{#2}}{% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \edef#3{#3,\the\toks@}% + \dtladd{\@dtl@thistick}{\@dtl@thistick}{#4}% +}% +\expandafter\toks@\expandafter{#2}% +\edef#3{#3,\the\toks@}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@constructticklistwithgapz} +%\begin{definition} +%\cs{dtl@constructticklistwithgapz}\marg{min}\marg{max}\marg{list}\marg{gap} +%\end{definition} +% Constructs a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence) using the gap given +% by \meta{gap} where the tick list straddles zero. +%\changes{2.14}{2013-06-28}{replaced \cs{FPadd} with \cs{dtladd} etc} +% \begin{macrocode} +\newcommand*{\dtl@constructticklistwithgapz}[4]{% + \edef\@dtl@thistick{0}% + \edef#3{0}% + \dtladd{\@dtl@thistick}{\@dtl@thistick}{#4}% + \whiledo{\DTLisFPopenbetween{\@dtl@thistick}{0}{#2}}% + {% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \edef#3{#3,\the\toks@}% + \dtladd{\@dtl@thistick}{\@dtl@thistick}{#4}% + }% + \expandafter\toks@\expandafter{#2}% + \edef#3{#3,\the\toks@}% + \dtlifnumeq{#1}{0}% + {}% + {% + \edef\@dtl@thistick{0}% + \dtlsub{\@dtl@thistick}{\@dtl@thistick}{#4}% + \whiledo{\DTLisFPopenbetween{\@dtl@thistick}{#1}{0}}% + {% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \edef#3{\the\toks@,#3}% + \dtlsub{\@dtl@thistick}{\@dtl@thistick}{#4}% + }% + \expandafter\toks@\expandafter{#1}% + \edef#3{\the\toks@,#3}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@constructminorticklist} +%\begin{definition} +%\cs{dtl@constructminorticklist}\marg{min}\marg{max}\marg{scale factor}\marg{list} +%\end{definition} +% Constructs a list of minor tick points between \meta{min} and \meta{max} +% and append to \meta{list} (a control sequence.) +%\changes{2.14}{2013-06-28}{replaced \cs{FPsub} with \cs{dtlsub} etc} +% \begin{macrocode} +\newcommand*{\dtl@constructminorticklist}[4]{% + \dtlsub{\@dtl@width}{#2}{#1}% + \dtlmul{\@dtl@width}{\@dtl@width}{#3}% + \dtldiv{\@dtl@gap}{\@dtl@width}{10}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLminminortickgap + \dtldiv{\@dtl@gap}{\@dtl@width}{4}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLminminortickgap + \dtldiv{\@dtl@gap}{\@dtl@width}{2}% + \setlength\dtl@tmplength{\@dtl@gap sp}% + \ifdim\dtl@tmplength<\DTLminminortickgap + \let\@dtl@gap=\@dtl@width + \fi + \fi + \fi + \dtldiv{\@dtl@gap}{\@dtl@gap}{#3}% + \dtl@constructticklistwithgapex{#1}{#2}{\dtl@tmp}{\@dtl@gap}% + \ifx#4\@empty + \let#4=\dtl@tmp + \else + \expandafter\toks@\expandafter{#4}% + \edef#4{#4,\dtl@tmp}% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\dtl@constructticklistwithgapex} +%\begin{definition} +%\cs{dtl@constructticklistwithgapex}\marg{min}\marg{max}\marg{list}\marg{gap} +%\end{definition} +% Constructs a list of tick points between \meta{min} and \meta{max} +% and store in \meta{list} (a control sequence) using the gap given +% by \meta{gap} where the gap is given in user co-ordinates. +% The end points are excluded from the list. +%\changes{2.14}{2013-06-28}{replaced \cs{FPadd} with \cs{dtladd} and +%changed third argument to minimum gap width (in data co-ordinates)} +% \begin{macrocode} +\newcommand*{\dtl@constructticklistwithgapex}[4]{% +\edef\@dtl@thistick{#1}% +\let#3=\@empty +\dtladd{\@dtl@thistick}{\@dtl@thistick}{#4}% +\whiledo{\DTLisFPopenbetween{\@dtl@thistick}{#1}{#2}}{% + \expandafter\toks@\expandafter{\@dtl@thistick}% + \ifx#3\@empty + \edef#3{\the\toks@}% + \else + \edef#3{#3,\the\toks@}% + \fi + \dtladd{\@dtl@thistick}{\@dtl@thistick}{#4}% +}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\DTLaddtoplotlegend} +%\begin{definition} +%\cs{DTLaddtoplotlegend}\marg{marker}\marg{line style}\marg{label} +%\end{definition} +% Adds entry to legend. +%\changes{2.15}{2013-07-10}{Used \cs{xdef} instead of \cs{edef} as +%may be scoped.} +% \begin{macrocode} +\newcommand*{\DTLaddtoplotlegend}[3]{% +\def\dtl@legendline{}% +\ifx\relax#2\relax +\else + \toks@{#2% + \pgfpathmoveto{\pgfpoint{-10pt}{0pt}}% + \pgfpathlineto{\pgfpoint{10pt}{0pt}}% + \pgfusepath{stroke}}% + \edef\dtl@legendline{\the\toks@}% +\fi +\ifx\relax#1\relax +\else + \toks@{#1}% + \expandafter\@dtl@toks\expandafter{\dtl@legendline}% + \edef\dtl@legendline{\the\@dtl@toks\the\toks@}% +\fi +\expandafter\toks@\expandafter{\dtl@legendline}% +\ifx\dtl@legend\@empty + \xdef\dtl@legend{\noexpand\tikz\the\toks@; \noexpand& #3}% +\else + \expandafter\@dtl@toks\expandafter{\dtl@legend}% + \xdef\dtl@legend{\the\@dtl@toks\noexpand\\% + \noexpand\tikz\the\toks@; \noexpand& #3}% +\fi +} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</dataplot.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*person.sty> +% \end{macrocode} +%\fi +%\chapter{person.sty}\label{sec:code:person} +%\section{Package Declaration} +% Package identification: +% \begin{macrocode} +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{person}[2018/12/07 v2.31 (NLCT)] +% \end{macrocode} +% Requires the \sty{ifthen} package. +% \begin{macrocode} +\RequirePackage{ifthen} +\RequirePackage{datatool} +% \end{macrocode} +%\section{Defining People} +%\begin{counter}{people} +% Keep count of the number of people who have been defined: +% \begin{macrocode} +\newcounter{people} +% \end{macrocode} +%\end{counter} +%\begin{counter}{person} +% Temporary counter +% \begin{macrocode} +\newcounter{person} +% \end{macrocode} +%\end{counter} +%\begin{macro}{\@people@list} +% Keep a list of labels for each person who has been defined: +% \begin{macrocode} +\newcommand*{\@people@list}{,} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\@get@firstperson} +% Get the first person's name in \cs{@people@list}, and store in +% the argument (which must be a control sequence.) +% \begin{macrocode} +\newcommand*{\@get@firstperson}[1]{% + \expandafter\@@get@firstperson\@people@list,\@nil{#1}} + \def\@@get@firstperson,#1,#2\@nil#3{% + \def#3{#1}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\malelabels} +% List of labels that can be used to indicate that a person is +% male (when defining a person using \cs{newperson}). +% \begin{macrocode} +\newcommand*{\malelabels}{male,Male,MALE,M,m} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\addmalelabel} +% Adds a label to the list of male labels. +% \begin{macrocode} +\newcommand*{\addmalelabel}[1]{% + \expandafter\@dtl@toksA\expandafter{\malelabels}% + \expandafter\@dtl@toksB\expandafter{#1}% + \edef\malelabels{\the\@dtl@toksA,\the\@dtl@toksB}% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\addfemalelabel} +% Adds a label to the list of female labels. +% \begin{macrocode} +\newcommand*{\addfemalelabel}[1]{% + \expandafter\@dtl@toksA\expandafter{\femalelabels}% + \expandafter\@dtl@toksB\expandafter{#1}% + \edef\femalelabels{\the\@dtl@toksA,\the\@dtl@toksB}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\femalelabels} +% List of labels that can be used to indicate that a person is +% female (when defining a person using \cs{newperson}). +% \begin{macrocode} +\newcommand*{\femalelabels}{female,Female,FEMALE,F,f} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifmalelabel} +% Determines if first argument is contained in the list of male +% labels. (One level expansion is performed on the first object +% in first argument.) +% If true does second argument, otherwise does third argument. +% \begin{macrocode} +\newcommand{\ifmalelabel}[3]{% + \expandafter\DTLifinlist\expandafter{#1}{\malelabels}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\iffemalelabel} +% Determines if first argument is contained in the list of female +% labels. (One level expansion is performed on the first object +% in first argument.) +% If true does second argument, otherwise does third argument. +% \begin{macrocode} +\newcommand{\iffemalelabel}[3]{% + \expandafter\DTLifinlist\expandafter{#1}{\femalelabels}{#2}{#3}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\newperson} +% Define a new person. The optional argument specifies a label +% with which to refer to that person. If omitted, \texttt{anon} +% is used. If more than one person is defined, the optional +% argument will be required to specify a unique label. The +% compulsory arguments are the person's full name, their +% familiar name and their gender. +% \begin{macrocode} +\newcommand*{\newperson}[4][anon]{% + \@ifundefined{person@#1@name}% + {% + \ifmalelabel{#4}% + {% + \expandafter\gdef\csname person@#1@gender\endcsname{male}% + }% + {% + \iffemalelabel{#4}% + {% + \expandafter\gdef\csname person@#1@gender\endcsname{female}% + }% + {% + \PackageError{person}{Unknown gender `#4' for person + `#1'}{Allowed gender labels are: \malelabels\space or + \femalelabels}% + \@namedef{person@#1@gender}{other}% + }% + }% + \expandafter + \protected@xdef\csname person@#1@fullname\endcsname{#2}% + \expandafter + \protected@xdef\csname person@#1@name\endcsname{#3}% + \protected@xdef\@people@list{\@people@list#1,}% + \stepcounter{people}% + }% + {% + \PackageError{person}{Person `#1' has already been defined}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\section{Remove People} +% +%\begin{macro}{\removeperson} +% Removes person identified by their label from the list. +% \begin{macrocode} +\newcommand*{\removeperson}[1][anon]{% + \edef\@person@label{#1}% + \expandafter\@removeperson\expandafter{\@person@label}% +} +% \end{macrocode} +% The label has to be full expanded for the internal command. +% \begin{macrocode} +\newcommand*{\@removeperson}[1]{% + \ifpersonexists{#1}% + {% +% \end{macrocode} +% Remove label from list of people. +% \begin{macrocode} + \def\@remove@person##1,#1,##2\@nil{% + \def\@prsn@pre{##1}\def\@prsn@post{##2}}% + \expandafter\@remove@person\@people@list\@nil + \xdef\@people@list{\@prsn@pre,\@prsn@post}% +% \end{macrocode} +% Decrement number of people: +% \begin{macrocode} + \addtocounter{people}{-1}% +% \end{macrocode} +% Undefine associated control sequences: +% \begin{macrocode} + \expandafter\global\expandafter + \let\csname person@#1@name\endcsname\undefined + \expandafter\global\expandafter + \let\csname person@#1@fullname\endcsname\undefined + \expandafter\global\expandafter + \let\csname person@#1@gender\endcsname\undefined + }% + {% + \PackageError{person}{Can't remove person `#1': no such + person}{}% + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\removepeople} +% Removes the people listed. +% \begin{macrocode} +\newcommand*{\removepeople}[1]{% + \@for\@thisperson:=#1\do{% + \ifx\@thisperson\@empty + \else + \expandafter\removeperson\expandafter[\@thisperson]% + \fi + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\removeallpeople} +% Removes everyone. +% \begin{macrocode} +\newcommand*{\removeallpeople}{% + \@for\@thisperson:=\@people@list\do{% + \expandafter\global\expandafter + \let\csname person@\@thisperson @name\endcsname\undefined + \expandafter\global\expandafter + \let\csname person@\@thisperson @fullname\endcsname\undefined + \expandafter\global\expandafter + \let\csname person@\@thisperson @gender\endcsname\undefined + }% + \setcounter{people}{0}% + \gdef\@people@list{,}% +} +% \end{macrocode} +%\end{macro} +% +%\section{Conditionals and Loops} +%\begin{macro}{\ifpersonexists} +% If person whose label is given by the first argument exists, then +% do the second argument otherwise do third argument. +% \begin{macrocode} +\newcommand{\ifpersonexists}[3]{% + \@ifundefined{person@#1@name}{#3}{#2}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifmale} +% If the person given by the label in the first argument is male, +% do the second argument, otherwise do the third argument. +%\changes{2.23}{2015-07-11}{bug fix: replaced \cs{@thisperson} with \#1} +% \begin{macrocode} +\newcommand{\ifmale}[3]{% + \ifpersonexists{#1}% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \ifx\@gender\@male@label + #2% + \else + #3% + \fi + }% + {% + \PackageError{person}{Person `#1' doesn't exist.}{}% + }% +} +\def\@male@label{male} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifallmale} +% If all people listed in first argument are male, do the second +% argument otherwise do the third argument. If the first argument +% is omitted, all defined people are checked. +% \begin{macrocode} +\newcommand{\ifallmale}[3][\@people@list]{% + \@for\@thisperson:=#1\do{% + \ifpersonexists{\@thisperson}% + {% + \edef\@gender{\csname person@\@thisperson @gender\endcsname}% + \ifx\@gender\@male@label + \else + \@endfortrue + \fi + }% + {% + \PackageError{person}{Person `#1' doesn't exist.}{}% + }% + }% + \if@endfor + #3% + \else + #2% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\iffemale} +% If the person given by the label in the first argument is female, +% do the second argument, otherwise do the third argument. +%\changes{2.23}{2015-07-11}{bug fix: replaced \cs{@thisperson} with \#1} +% \begin{macrocode} +\newcommand{\iffemale}[3]{% + \ifpersonexists{#1}% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \ifx\@gender\@female@label + #2% + \else + #3% + \fi + }% + {% + \PackageError{person}{Person `#1' doesn't exist.}{}% + }% +} +\def\@female@label{female} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\ifallfemale} +% If all people listed in first argument are female, do the second +% argument otherwise do the third argument. +% \begin{macrocode} +\newcommand{\ifallfemale}[3][\@people@list]{% + \@for\@thisperson:=#1\do{% + \edef\@gender{\csname person@\@thisperson @gender\endcsname}% + \ifx\@gender\@female@label + \else + \@endfortrue + \fi + }% + \if@endfor + #3% + \else + #2% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\foreachperson} +%\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} +% Iterates through list of people the \cs{in}\marg{list} is optional. +% If omitted, the list of all defined people is used. +% \begin{macrocode} +\def\foreachperson(#1,#2,#3,#4)#5{% + \ifx#5\in + \def\@do@foreachperson{\@foreachperson(#1,#2,#3,#4)#5}% + \else + \def\@do@foreachperson{% + \@foreachperson(#1,#2,#3,#4)\in\@people@list#5}% + \fi + \@do@foreachperson +} +\long\def\@foreachperson(#1,#2,#3,#4)\in#5\do#6{% + \@for#4:=#5\do{% + \ifx#4\@empty + \else + \ifpersonexists{#4}% + {% + \expandafter + \let\expandafter#1\csname person@#4@name\endcsname + \expandafter + \let\expandafter#2\csname person@#4@fullname\endcsname + \expandafter + \let\expandafter#3\csname person@#4@gender\endcsname + \ifx#3\@male@label + \let#3\malename + \else + \ifx#3\@female@label + \let#3\femalename + \fi + \fi + #6% + }% + {% + \PackageError{person}{Person `#4' doesn't exist}{}% + }% + \fi + }% +} +% \end{macrocode} +%\end{macro} +% +%\section{Predefined Words}\label{sec:code:peoplenames} +% These commands should be redefined if +% you are writing in another language, but note that these +% are structured according to English grammar. +%\begin{macro}{\malepronoun} +% \begin{macrocode} +\newcommand*{\malepronoun}{he} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femalepronoun} +% \begin{macrocode} +\newcommand*{\femalepronoun}{she} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pluralpronoun} +% \begin{macrocode} +\newcommand*{\pluralpronoun}{they} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\maleobjpronoun} +% \begin{macrocode} +\newcommand*{\maleobjpronoun}{him} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femaleobjpronoun} +% \begin{macrocode} +\newcommand*{\femaleobjpronoun}{her} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pluralobjpronoun} +% \begin{macrocode} +\newcommand*{\pluralobjpronoun}{them} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\malepossadj} +% \begin{macrocode} +\newcommand*{\malepossadj}{his} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femalepossadj} +% \begin{macrocode} +\newcommand*{\femalepossadj}{her} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pluralpossadj} +% \begin{macrocode} +\newcommand*{\pluralpossadj}{their} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\maleposspronoun} +% \begin{macrocode} +\newcommand*{\maleposspronoun}{his} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femaleposspronoun} +% \begin{macrocode} +\newcommand*{\femaleposspronoun}{hers} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pluralposspronoun} +% \begin{macrocode} +\newcommand*{\pluralposspronoun}{theirs} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\malechild} +% \begin{macrocode} +\newcommand*{\malechild}{son} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femalechild} +% \begin{macrocode} +\newcommand*{\femalechild}{daughter} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pluralchild} +% \begin{macrocode} +\newcommand*{\pluralchild}{children} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\malechildren} +% \begin{macrocode} +\newcommand*{\malechildren}{sons} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femalechildren} +% \begin{macrocode} +\newcommand*{\femalechildren}{daughters} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\maleparent} +% \begin{macrocode} +\newcommand*{\maleparent}{father} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femaleparent} +% \begin{macrocode} +\newcommand*{\femaleparent}{mother} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pluralparent} +% \begin{macrocode} +\newcommand*{\pluralparent}{parents} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\malesibling} +% \begin{macrocode} +\newcommand*{\malesibling}{brother} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femalesibling} +% \begin{macrocode} +\newcommand*{\femalesibling}{sister} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\pluralsibling} +% \begin{macrocode} +\newcommand*{\pluralsibling}{siblings} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\malesiblings} +% \begin{macrocode} +\newcommand*{\malesiblings}{brothers} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femalesiblings} +% \begin{macrocode} +\newcommand*{\femalesiblings}{sisters} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\andname} +% Define \cs{andname} if it hasn't already been defined: +% \begin{macrocode} +\providecommand*{\andname}{and} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\malename} +% \begin{macrocode} +\newcommand*{\malename}{male} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\femalename} +% \begin{macrocode} +\newcommand*{\femalename}{female} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personsep} +% Separator to use between people (but not the between the last +% two). +% \begin{macrocode} +\newcommand*{\personsep}{, } +% \end{macrocode} +%\end{macro} +%\begin{macro}{\personlastsep} +% Separator to use between last two people. +% \begin{macrocode} +\newcommand*{\personlastsep}{\space\andname\space} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\twopeoplesep} +% Separator to use when list only contains two people. +% \begin{macrocode} +\newcommand*{\twopeoplesep}{\space\andname\space} +% \end{macrocode} +%\end{macro} +% +%\section{Displaying Information} +%\begin{macro}{\personfullname} +% The person's full name can be displayed using +% \cs{personfullname}\oarg{label}, where \meta{label} is the +% unique label used when defining that person. If \meta{label} +% is omitted, \texttt{anon} is used. +% \begin{macrocode} +\newcommand*{\personfullname}[1][anon]{% + \@ifundefined{person@#1@fullname}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \csname person@#1@fullname\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\peoplefullname} +% List all defined people's full names. This iterates through all +% labels in \cs{@people@list}. +% \begin{macrocode} +\newcommand*{\peoplefullname}{% + \setcounter{person}{1}% + \@for\@thisperson:=\@people@list\do{% + \ifthenelse{\equal{\@thisperson}{}}% + {}% + {% + \personfullname[\@thisperson]% + \stepcounter{person}% + \ifnum\c@people=1\relax + \else + \ifnum\c@person=\c@people + \ifnum\c@people=2\relax + \twopeoplesep + \else + \personlastsep + \fi + \else + \ifnum\c@person<\c@people + \personsep + \fi + \fi + \fi + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personname} +% As \cs{personfullname}, but for the person's familiar name. +% \begin{macrocode} +\newcommand*{\personname}[1][anon]{% + \@ifundefined{person@#1@name}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \csname person@#1@name\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\peoplename} +% List all defined people's familiar names. This iterates through all +% labels in \cs{@people@list}. +% \begin{macrocode} +\newcommand*{\peoplename}{% + \setcounter{person}{1}% + \@for\@thisperson:=\@people@list\do{% + \ifthenelse{\equal{\@thisperson}{}}% + {}% + {% + \personname[\@thisperson]% + \stepcounter{person}% + \ifnum\c@people=1\relax + \else + \ifnum\c@person=\c@people + \ifnum\c@people=2\relax + \twopeoplesep + \else + \personlastsep + \fi + \else + \ifnum\c@person<\c@people + \personsep + \fi + \fi + \fi + }% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personpronoun} +% Display the pronoun (he/she) according to the person's gender. +% \begin{macrocode} +\newcommand*{\personpronoun}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \csname\@gender pronoun\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Personpronoun} +% As above, but make the first letter uppercase. +% \begin{macrocode} +\newcommand*{\Personpronoun}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \expandafter\expandafter\expandafter + \MakeUppercase\csname\@gender pronoun\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\peoplepronoun} +% If there is more than one person, \cs{peoplepronoun} will use +% \cs{pluralpronoun}, otherwise it will use \cs{personpronoun}. +% \begin{macrocode} +\newcommand*{\peoplepronoun}{% + \ifnum\c@people>1\relax + \pluralpronoun + \else + \@get@firstperson{\@thisperson}% + \personpronoun[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\Peoplepronoun} +% As above, but first letter in upper case +% \begin{macrocode} +\newcommand*{\Peoplepronoun}{% + \ifnum\c@people>1\relax + \expandafter\MakeUppercase\pluralpronoun + \else + \@get@firstperson{\@thisperson}% + \Personpronoun[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\personobjpronoun} +% Display the objective pronoun (him/her) according to the person's +% gender. +% \begin{macrocode} +\newcommand*{\personobjpronoun}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \csname\@gender objpronoun\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Personobjpronoun} +% As above, but make the first letter uppercase. +% \begin{macrocode} +\newcommand*{\Personobjpronoun}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \expandafter\expandafter\expandafter + \MakeUppercase\csname\@gender objpronoun\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\peopleobjpronoun} +% If there is more than one person, \cs{peopleobjpronoun} will use +% \cs{pluralobjpronoun}, otherwise it will use \cs{personobjpronoun}. +% \begin{macrocode} +\newcommand*{\peopleobjpronoun}{% + \ifnum\c@people>1\relax + \pluralobjpronoun + \else + \@get@firstperson{\@thisperson}% + \personobjpronoun[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Peopleobjpronoun} +% As above, but first letter in upper case +% \begin{macrocode} +\newcommand*{\Peopleobjpronoun}{% + \ifnum\c@people>1\relax + \expandafter\MakeUppercase\pluralobjpronoun + \else + \@get@firstperson{\@thisperson}% + \Personobjpronoun[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personpssadj} +% Display the possessive adjective (his/her) according to the person's +% gender. +% \begin{macrocode} +\newcommand*{\personpossadj}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \csname\@gender possadj\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Personpossadj} +% As above, but make the first letter uppercase. +% \begin{macrocode} +\newcommand*{\Personpossadj}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \expandafter\expandafter\expandafter + \MakeUppercase\csname\@gender possadj\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\peoplepossadj} +% If there is more than one person, \cs{peoplepossadj} will use +% \cs{pluralpossadj}, otherwise it will use \cs{personpossadj}. +% \begin{macrocode} +\newcommand*{\peoplepossadj}{% + \ifnum\c@people>1\relax + \pluralpossadj + \else + \@get@firstperson{\@thisperson}% + \personpossadj[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Peoplepossadj} +% As above, but first letter in upper case +% \begin{macrocode} +\newcommand*{\Peoplepossadj}{% + \ifnum\c@people>1\relax + \expandafter\MakeUppercase\pluralpossadj + \else + \@get@firstperson{\@thisperson}% + \Personpossadj[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personposspronoun} +% Display possessive pronoun (his/hers) according to the +% person's gender. +% \begin{macrocode} +\newcommand*{\personposspronoun}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \csname\@gender posspronoun\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Personposspronoun} +% As above, but make the first letter uppercase. +% \begin{macrocode} +\newcommand*{\Personposspronoun}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \expandafter\expandafter\expandafter + \MakeUppercase\csname\@gender posspronoun\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\peopleposspronoun} +% If there is more than one person, \cs{peopleposspronoun} will use +% \cs{pluralposspronoun}, otherwise it will use \cs{personposspronoun}. +% \begin{macrocode} +\newcommand*{\peopleposspronoun}{% + \ifnum\c@people>1\relax + \pluralposspronoun + \else + \@get@firstperson{\@thisperson}% + \personposspronoun[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\Peopleposspronoun} +% As above, but first letter in upper case +% \begin{macrocode} +\newcommand*{\Peopleposspronoun}{% + \ifnum\c@people>1\relax + \expandafter\MakeUppercase\pluralposspronoun + \else + \@get@firstperson{\@thisperson}% + \Personposspronoun[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personchild} +% Display this person's relationship to their parent (i.e.\ son +% or daughter). +% \begin{macrocode} +\newcommand*{\personchild}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \csname\@gender child\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\Personchild} +% As above, but make first letter uppercase. +% \begin{macrocode} +\newcommand*{\Personchild}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \expandafter\expandafter\expandafter\MakeUppercase + \csname\@gender child\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\peoplechild} +% If there is more than one person, \cs{peoplechild} will use +% \cs{malechildren} (if all male), \cs{femalechildren} (if all +% female) or \cs{pluralchild} (if mixed), otherwise it will use +% \cs{personchild}. +% \begin{macrocode} +\newcommand*{\peoplechild}{% + \ifnum\c@people>1\relax + \ifallmale + {\malechildren}% + {\ifallfemale{\femalechildren}{\pluralchild}}% + \else + \@get@firstperson{\@thisperson}% + \personchild[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\Peoplechild} +% As above but first letter is made uppercase. +% \begin{macrocode} +\newcommand*{\Peoplechild}{% + \ifnum\c@people>1\relax + \ifallmale + {\expandafter\MakeUppercase\malechildren}% + {\ifallfemale + {\expandafter\MakeUppercase\femalechildren} + {\expandafter\MakeUppercase\pluralchild}}% + \else + \@get@firstperson{\@thisperson}% + \Personchild[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personparent} +% Display this person's relationship to their child (i.e.\ father +% or mother). +% \begin{macrocode} +\newcommand*{\personparent}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \csname\@gender parent\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\Personparent} +% As above, but make the first letter uppercase. +% \begin{macrocode} +\newcommand*{\Personparent}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \expandafter\expandafter\expandafter\MakeUppercase + \csname\@gender parent\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\peopleparent} +% If there is more than one person, \cs{peopleparent} will use +% \cs{pluralparent}, otherwise it will use \cs{personparent}. +% \begin{macrocode} +\newcommand*{\peopleparent}{% + \ifnum\c@people>1\relax + \pluralparent + \else + \@get@firstperson{\@thisperson}% + \personparent[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\Peopleparent} +% As above, but make first letter uppercase. +% \begin{macrocode} +\newcommand*{\Peopleparent}{% + \ifnum\c@people>1\relax + \expandafter\MakeUppercase\pluralparent + \else + \@get@firstperson{\@thisperson}% + \Personparent[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\personsibling} +% Display this person's relationship to their siblings (i.e.\ +% brother or sister). +% \begin{macrocode} +\newcommand*{\personsibling}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \csname\@gender sibling\endcsname + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\Personsibling} +% Display this person's relationship to their siblings (i.e.\ +% brother or sister). +% \begin{macrocode} +\newcommand*{\Personsibling}[1][anon]{% + \@ifundefined{person@#1@gender}% + {% + \PackageError{person}{Person `#1' has not been defined}{}% + }% + {% + \edef\@gender{\csname person@#1@gender\endcsname}% + \expandafter\expandafter\expandafter\MakeUppercase + \csname\@gender sibling\endcsname + }% +} +% \end{macrocode} +%\end{macro} +%\begin{macro}{\peoplesibling} +% If there is more than one person, \cs{peoplesibling} will use +% \cs{malesiblings} (if all male), \cs{femalesiblings} (if all +% female) or \cs{pluralsibling} (if mixed), otherwise it will use +% \cs{personsibling}. +% \begin{macrocode} +\newcommand*{\peoplesibling}{% + \ifnum\c@people>1\relax + \ifallmale + {\malesiblings}% + {\ifallfemale{\femalesiblings}{\pluralsibling}}% + \else + \@get@firstperson{\@thisperson}% + \personsibling[\@thisperson]% + \fi +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\persongender} +% Displays the given person's gender (\cs{malename} or +% \cs{femalename}). +%\changes{2.23}{2015-07-11}{bug fix: replaced \cs{ifpersonmale} with +%\cs{ifmale}} +% \begin{macrocode} +\newcommand*{\persongender}[1]{% + \ifmale{#1}{\malename}{\femalename}% +} +% \end{macrocode} +%\end{macro} +% +%\section{Extracting Information} +% +%\begin{macro}{\getpersongender} +% Gets person's gender and stores in first argument which must be +% a control sequence. +%\changes{2.23}{2015-07-11}{bug fix: replaced \cs{ifpersonmale} with +%\cs{ifmale}} +% \begin{macrocode} +\newcommand*{\getpersongender}[2]{% + \ifmale{#2}{\let#1\malename}{\let#1\femalename}% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\getpersonname} +% Gets person's name and stores in first argument which must be +% a control sequence. +% \begin{macrocode} +\newcommand*{\getpersonname}[2]{% + \ifpersonexists{#2}% + {% + \expandafter\let\expandafter#1\csname person@#2@name\endcsname + }% + {% + \PackageError{person}{Person `#2' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +% +%\begin{macro}{\getpersonfullname} +% Gets person's full name and stores in first argument which must be +% a control sequence. +% \begin{macrocode} +\newcommand*{\getpersonfullname}[2]{% + \ifpersonexists{#2}% + {% + \expandafter + \let\expandafter#1\csname person@#2@fullname\endcsname + }% + {% + \PackageError{person}{Person `#2' doesn't exist}{}% + }% +} +% \end{macrocode} +%\end{macro} +%\iffalse +% \begin{macrocode} +%</person.sty> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%<*databib.bst> +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +ENTRY + { 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 + url + abstract + file + eprints + } + {} + { label } + +INTEGERS { output.state before.all mid.sentence after.sentence after.block } + +FUNCTION {init.state.consts} +{ #0 'before.all := + #1 'mid.sentence := + #2 'after.sentence := + #3 'after.block := +} + +STRINGS { s t } + +FUNCTION {output.nonnull} +{ 's := + output.state before.all = + { + "%" * write$ + newline$ + } + { newline$ + %add.period$ " " * write$ + } + if$ + % if$ + % mid.sentence 'output.state := + % } + %if$ + s +} + +FUNCTION {output} +{ duplicate$ empty$ + 'pop$ + 'output.nonnull + if$ +} + +FUNCTION {output.check} +{ 't := + duplicate$ empty$ + { pop$ "empty " t * " in " * cite$ * warning$ } + { + output.nonnull + } + if$ +} + +FUNCTION {output.bibitem} +{ "\DTLnewbibrow" write$ + newline$ + "\DTLnewbibitem {CiteKey}{" write$ + cite$ write$ + "}%" write$ + newline$ + "" + before.all 'output.state := +} + +FUNCTION {fin.entry} +{ "%" * + write$ + newline$ +} + +FUNCTION {new.block} +{ output.state before.all = + 'skip$ + { after.block 'output.state := } + if$ +} + +FUNCTION {new.sentence} +{ output.state after.block = + 'skip$ + { output.state before.all = +'skip$ +{ after.sentence 'output.state := } + if$ + } + if$ +} + +FUNCTION {not} +{ { #0 } + { #1 } + if$ +} + +FUNCTION {and} +{ 'skip$ + { pop$ #0 } + if$ +} + +FUNCTION {or} +{ { pop$ #1 } + 'skip$ + if$ +} + +FUNCTION {new.block.checka} +{ empty$ + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.block.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.block + if$ +} + +FUNCTION {new.sentence.checka} +{ empty$ + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {new.sentence.checkb} +{ empty$ + swap$ empty$ + and + 'skip$ + 'new.sentence + if$ +} + +FUNCTION {field.or.null} +{ duplicate$ empty$ + { pop$ "" } + 'skip$ + if$ +} + +FUNCTION {emphasize} +{ duplicate$ empty$ + { pop$ "" } + { "{\em " swap$ * "}" * } + if$ +} + +FUNCTION {group} +{ duplicate$ empty$ + { pop$ "" } + { "{" swap$ * "}" * } + if$ +} + +INTEGERS { nameptr namesleft numnames } + +FUNCTION {format.names} +{ + 's := + #1 'nameptr := + s num.names$ 'numnames := + numnames 'namesleft := + { namesleft #0 > } + { + %s nameptr "{vv,}{ll,}{jj,}{ff}" format.name$ 't := + "{" * + s nameptr "{vv}" format.name$ 't := + t * "}" * + "{" * + s nameptr "{ll}" format.name$ 't := + t * "}{" * + s nameptr "{jj}" format.name$ 't := + t * "}" * + "{" * + s nameptr "{ff}" format.name$ 't := + t * "}" * + s nameptr "" format.name$ 't := + namesleft #1 > + { "," * } + { } + if$ + nameptr #1 > +{ + t * +} +'t + if$ + nameptr #1 + 'nameptr := + namesleft #1 - 'namesleft := + } + while$ + "}" * +} + +FUNCTION {format.authors} +{ + author empty$ + { "" } + { author + "\DTLnewbibitem {Author}{" write$ + format.names } + if$ +} + +FUNCTION {format.editors} +{ editor empty$ + { "" } + { editor + "\DTLnewbibitem {Editor}{" write$ + format.names + } + if$ +} + +FUNCTION {format.title} +{ title empty$ + { "" } + { + "\DTLnewbibitem {Title}" + title "t" change.case$ group * + } + if$ +} + +FUNCTION {format.howpublished} +{ howpublished empty$ + { "" } + { + howpublished + "\DTLnewbibitem {HowPublished}" swap$ group * + } + if$ +} + +FUNCTION {format.organization} +{ organization empty$ + { "" } + { + organization + "\DTLnewbibitem {Organization}" swap$ group * + } + if$ +} + +FUNCTION {format.institution} +{ institution empty$ + { "" } + { + institution + "\DTLnewbibitem {Institution}" swap$ group * + } + if$ +} + +FUNCTION {format.key} +{ key empty$ + { "" } + { + key + "\DTLnewbibitem {Key}" swap$ group * + } + if$ +} + +FUNCTION {format.note} +{ note empty$ + { "" } + { + note + "\DTLnewbibitem {Note}" swap$ group * + } + if$ +} + +FUNCTION {format.isbn} +{ isbn empty$ + { "" } + { + isbn + "\DTLnewbibitem {ISBN}" swap$ group * + } + if$ +} + +FUNCTION {format.doi} +{ doi empty$ + { "" } + { + doi + "\DTLnewbibitem {DOI}" swap$ group * + } + if$ +} + +FUNCTION {format.pubmed} +{ pubmed empty$ + { "" } + { + pubmed + "\DTLnewbibitem {PubMed}" swap$ group * + } + if$ +} + +FUNCTION {format.abstract} +{ abstract empty$ + { "" } + { + abstract + "\DTLnewbibitem {Abstract}" swap$ group * + } + if$ +} + +FUNCTION {format.url} +{ url empty$ + { "" } + { + url + "\DTLnewbibitem {Url}" swap$ group * + } + if$ +} + +FUNCTION {format.file} +{ file empty$ + { "" } + { + file + "\DTLnewbibitem {File}" swap$ group * + } + if$ +} + +FUNCTION {format.eprints} +{ eprints empty$ + { "" } + { + eprints + "\DTLnewbibitem {Eprints}" swap$ group * + } + if$ +} + +FUNCTION {format.address} +{ address empty$ + { "" } + { + address + "\DTLnewbibitem {Address}" swap$ group * + } + if$ +} + +FUNCTION {format.school} +{ school empty$ + { "" } + { + school + "\DTLnewbibitem {School}" swap$ group * + } + if$ +} + +FUNCTION {format.publisher} +{ publisher empty$ + { "" } + { + publisher + "\DTLnewbibitem {Publisher}" swap$ group * + } + if$ +} + +FUNCTION {n.dashify} +{ 't := + "" + { t empty$ not } + { t #1 #1 substring$ "-" = +{ t #1 #2 substring$ "--" = not + { "--" * + t #2 global.max$ substring$ 't := + } + { { t #1 #1 substring$ "-" = } +{ "-" * + t #2 global.max$ substring$ 't := +} + while$ + } + if$ +} +{ t #1 #1 substring$ * + t #2 global.max$ substring$ 't := +} + if$ + } + while$ +} + +FUNCTION {format.date} +{ year empty$ + { month empty$ +{ "" } +{ "there's a month but no year in " cite$ * warning$ + "\DTLnewbibitem {Month}" * + month group +} + if$ + } + { month empty$ +{ } +{ "\DTLnewbibitem {Month}{" * month * "}" * } + if$ + "\DTLnewbibitem {Year}{" * year * "}" + } + if$ +} + +FUNCTION {format.btitle} +{ title + "\DTLnewbibitem {Title}{" swap$ * + "}" * +} + +FUNCTION {tie.or.space.connect} +{ duplicate$ text.length$ #3 < + { "~" } + { " " } + if$ + swap$ * * +} + +FUNCTION {either.or.check} +{ empty$ + 'pop$ + { "can't use both " swap$ * " fields in " * cite$ * warning$ } + if$ +} + +FUNCTION {format.bvolume} +{ volume empty$ + { "" } + { + "\DTLnewbibitem {Volume}{" volume * "}" * + series empty$ +'skip$ +{ + "\DTLnewbibitem {Series}" * series group * + } + if$ + "volume and number" number either.or.check + } + if$ +} + +FUNCTION {format.number.series} +{ volume empty$ + { number empty$ +{ + %series field.or.null group + series empty$ + { "" } + { "\DTLnewbibitem {Series}" * series group } + if$ + } +{ + "\DTLnewbibitem {Number}" number group * + series empty$ + { "there's a number but no series in " cite$ * warning$ } + { "\DTLnewbibitem {Series}{" * series * "}" * } + if$ +} + if$ + } + { "" } + if$ +} + +FUNCTION {format.edition} +{ edition empty$ + { "" } + { + "\DTLnewbibitem {Edition}" + edition "l" change.case$ group * + } + if$ +} + +INTEGERS { multiresult } + +FUNCTION {multi.page.check} +{ 't := + #0 'multiresult := + { multiresult not + t empty$ not + and + } + { t #1 #1 substring$ + duplicate$ "-" = + swap$ duplicate$ "," = + swap$ "+" = + or or +{ #1 'multiresult := } +{ t #2 global.max$ substring$ 't := } + if$ + } + while$ + multiresult +} + +FUNCTION {format.pages} +{ pages empty$ + { "" } + { pages multi.page.check +{ "\DTLnewbibitem {Pages}" pages n.dashify + group * } +{ "\DTLnewbibitem {Pages}" pages + group *} + if$ + } + if$ +} + +FUNCTION {format.vol.num.pages} +{ + volume empty$ + { "" } + { + "\DTLnewbibitem {Volume}{" volume * "}" * + } + if$ + number empty$ + 'skip$ + { "\DTLnewbibitem {Number}{" number * "}\relax " * * + volume empty$ +{ "there's a number but no volume in " cite$ * warning$ } +'skip$ + if$ + } + if$ + pages empty$ + 'skip$ + { duplicate$ empty$ +{ pop$ format.pages } +{ "\DTLnewbibitem {Pages}" * pages n.dashify group * } + if$ + } + if$ +} + +FUNCTION {format.chapter.pages} +{ chapter empty$ + 'format.pages + { type empty$ +{ "\DTLnewbibitem {Type}{chapter}" } +{ "\DTLnewbibitem {Type}" type "l" change.case$ group *} + if$ + "\DTLnewbibitem {Chapter}{" * chapter * "}" * + pages empty$ +'skip$ +{ format.pages * } + if$ + } + if$ +} + +FUNCTION {format.in.ed.booktitle} +{ booktitle empty$ + { "" } + { + "\DTLnewbibitem {BookTitle}" booktitle group * + editor empty$ + {} + { + "\DTLnewbibitem {Editor}{" * + editor format.names * + } + if$ + } + if$ +} + +FUNCTION {empty.misc.check} +{ author empty$ title empty$ howpublished empty$ + month empty$ year empty$ note empty$ + and and and and and + { "all relevant fields are empty in " cite$ * warning$ } + 'skip$ + if$ +} + +FUNCTION {format.thesis.type} +{ type empty$ + 'skip$ + { pop$ + type "t" change.case$ + "\DTLnewbibitem {Type}" swap$ group * + } + if$ +} + +FUNCTION {format.tr.number} +{ + type empty$ + { "\techreportname " } + 'type + if$ + number empty$ + { "t" change.case$ "\DTLnewbibitem {Type}" swap$ group *} + { "\DTLnewbibitem {Type}" swap$ group * + "\DTLnewbibitem {Number}" * + number group * } + if$ +} + +FUNCTION {format.article.crossref} +{ key empty$ + { journal empty$ +{ "need key or journal for " cite$ * " to crossref " * crossref * + warning$ + "" +} +{ + "\DTLnewbibitem {Journal}" journal group * + } + if$ + } + { + "" + } + if$ + "\DTLnewbibitem {CrossRef}{" * crossref * "}" * +} + +FUNCTION {format.crossref.editor} +{ format.editors +} + +FUNCTION {format.book.crossref} +{ volume empty$ + { "empty volume in " cite$ * "'s crossref of " * crossref * warning$ + } + { + "\DTLnewbibitem {Volume}" + volume group * + } + if$ + editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ +{ series empty$ + { "need editor, key, or series for " cite$ * " to crossref " * + crossref * warning$ + "" * + } + { + "\DTLnewbibitem {Series}{" * series * + "}" * + } + if$ +} +{ "" + } + if$ + } + { + format.crossref.editor * + } + if$ + "\DTLnewbibitem {CrossRef}{" * crossref * "}" * +} + +FUNCTION {format.incoll.inproc.crossref} +{ editor empty$ + editor field.or.null author field.or.null = + or + { key empty$ +{ booktitle empty$ + { "need editor, key, or booktitle for " cite$ * " to crossref " * + crossref * warning$ + "" + } + { "\DTLnewbibitem {BookTitle}{" booktitle * "}" * } + if$ +} +{ "" } + if$ + } + { + "\DTLnewbibitem {Editor}{" * + editor format.names + } + if$ + "\DTLnewbibitem {CrossRef}{" * crossref * "}" * +} + +FUNCTION {article} +{ output.bibitem + "\DTLnewbibitem {EntryType}{article}%" write$ + newline$ + format.authors "author" + output.check + format.title "title" output.check + new.block + crossref missing$ + { + journal missing$ + { + } + { + "\DTLnewbibitem {Journal}" * + } + if$ + journal group "journal" output.check + format.vol.num.pages output + format.date "year" output.check + } + { format.article.crossref output.nonnull + format.pages output + } + if$ + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {book} +{ output.bibitem + "\DTLnewbibitem {EntryType}{book}%" write$ + newline$ + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ +{ "author and editor" editor either.or.check + } +'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + new.block + format.number.series output + %new.sentence + format.publisher "publisher" output.check + format.address output + } + { new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {booklet} +{ output.bibitem + "\DTLnewbibitem {EntryType}{booklet}%" write$ + newline$ + format.authors output + new.block + format.title "title" output.check + howpublished address new.block.checkb + format.howpublished output + format.address output + format.date output + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {inbook} +{ output.bibitem + "\DTLnewbibitem {EntryType}{inbook}%" write$ + newline$ + author empty$ + { format.editors "author and editor" output.check } + { format.authors output.nonnull + crossref missing$ +{ "author and editor" editor either.or.check } +'skip$ + if$ + } + if$ + new.block + format.btitle "title" output.check + crossref missing$ + { format.bvolume output + format.chapter.pages "chapter and pages" output.check + new.block + format.number.series output + new.sentence + format.publisher "publisher" output.check + format.address output + } + { format.chapter.pages "chapter and pages" output.check + new.block + format.book.crossref output.nonnull + } + if$ + format.edition output + format.date "year" output.check + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {incollection} +{ output.bibitem + "\DTLnewbibitem {EntryType}{incollection}%" write$ + newline$ + format.authors "author" output.check + format.title "title" output.check + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.chapter.pages output + new.sentence + format.publisher "publisher" output.check + format.address output + format.edition output + format.date "year" output.check + } + { format.incoll.inproc.crossref output.nonnull + format.chapter.pages output + } + if$ + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {inproceedings} +{ output.bibitem + "\DTLnewbibitem {EntryType}{inproceedings}%" write$ + newline$ + format.authors "author" output.check + format.title "title" output.check + crossref missing$ + { format.in.ed.booktitle "booktitle" output.check + format.bvolume output + format.number.series output + format.pages output + address empty$ +{ %organization publisher new.sentence.checkb + format.organization write$ + format.publisher output +} +{ format.address write$ + new.sentence + format.organization output + format.publisher output +} + if$ + format.date "year" output.check + } + { + format.incoll.inproc.crossref output.nonnull + format.pages output + } + if$ + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {conference} { inproceedings } + +FUNCTION {manual} +{ output.bibitem + "\DTLnewbibitem {EntryType}{manual}%" write$ + newline$ + author empty$ + { organization empty$ +'skip$ +{ format.organization output + format.address output +} + if$ + } + { format.authors output } + if$ + new.block + format.btitle "title" output.check + author empty$ + { organization empty$ +{ address new.block.checka + address output +} +'skip$ + if$ + } + { %organization address new.block.checkb + format.organization output + format.address output + } + if$ + format.edition output + format.date output + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {mastersthesis} +{ output.bibitem + "\DTLnewbibitem {EntryType}{mastersthesis}%" write$ + newline$ + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + "\DTLnewbibitem {Type}{\mscthesisname }" + format.thesis.type output.nonnull + format.school "school" output.check + format.address output + format.date "year" output.check + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {misc} +{ output.bibitem + "\DTLnewbibitem {EntryType}{misc}%" write$ + newline$ + format.authors output + title howpublished new.block.checkb + format.title output + %howpublished new.block.checka + format.howpublished output + format.date output + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry + empty.misc.check +} + +FUNCTION {phdthesis} +{ output.bibitem + "\DTLnewbibitem {EntryType}{phdthesis}%" write$ + newline$ + format.authors "author" output.check + new.block + format.btitle "title" output.check + new.block + "\DTLnewbibitem {Type}{\phdthesisname }" + format.thesis.type output.nonnull + format.school "school" output.check + format.address output + format.date "year" output.check + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {proceedings} +{ output.bibitem + "\DTLnewbibitem {EntryType}{proceedings}%" write$ + newline$ + editor empty$ + { format.organization output } + { format.editors output.nonnull } + if$ + new.block + format.btitle "title" output.check + format.bvolume output + format.number.series output + address empty$ + { editor empty$ +{ publisher new.sentence.checka } +{ organization publisher new.sentence.checkb + format.organization output +} + if$ + format.publisher output + format.date "year" output.check + } + { format.address output + format.date "year" output.check + new.sentence + editor empty$ +'skip$ +{ format.organization output } + if$ + format.publisher output + } + if$ + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {techreport} +{ output.bibitem + "\DTLnewbibitem {EntryType}{techreport}%" write$ + newline$ + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.tr.number output.nonnull + format.institution "institution" output.check + format.address output + format.date "year" output.check + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + fin.entry +} + +FUNCTION {unpublished} +{ output.bibitem + "\DTLnewbibitem {EntryType}{unpublished}%" write$ + newline$ + format.authors "author" output.check + new.block + format.title "title" output.check + new.block + format.key output + format.note output + format.isbn output + format.doi output + format.pubmed output + format.url output + format.abstract output + format.file output + format.date output + fin.entry +} + +FUNCTION {default.type} { misc } + +MACRO {jan} {"\DTLmonthname{01}"} + +MACRO {feb} {"\DTLmonthname{02}"} + +MACRO {mar} {"\DTLmonthname{03}"} + +MACRO {apr} {"\DTLmonthname{04}"} + +MACRO {may} {"\DTLmonthname{05}"} + +MACRO {jun} {"\DTLmonthname{06}"} + +MACRO {jul} {"\DTLmonthname{07}"} + +MACRO {aug} {"\DTLmonthname{08}"} + +MACRO {sep} {"\DTLmonthname{09}"} + +MACRO {oct} {"\DTLmonthname{10}"} + +MACRO {nov} {"\DTLmonthname{11}"} + +MACRO {dec} {"\DTLmonthname{12}"} + +MACRO {acmcs} {"\DTLacmcs "} + +MACRO {acta} {"\DTLacta "} + +MACRO {cacm} {"\DTLcacm "} + +MACRO {ibmjrd} {"\DTLibmjrd "} + +MACRO {ibmsj} {"\DTLibmsj "} + +MACRO {ieeese} {"\DTLieeese "} + +MACRO {ieeetc} {"\DTLieeetc "} + +MACRO {ieeetcad} {"\DTLieeetcad "} + +MACRO {ipl} {"\DTLipl "} + +MACRO {jacm} {"\DTLjacm "} + +MACRO {jcss} {"\DTLjcss "} + +MACRO {scp} {"\DTLscp "} + +MACRO {sicomp} {"\DTLsicomp "} + +MACRO {tocs} {"\DTLtocs "} + +MACRO {tods} {"\DTLtods "} + +MACRO {tog} {"\DTLtog "} + +MACRO {toms} {"\DTLtoms "} + +MACRO {toois} {"\DTLtoois "} + +MACRO {toplas} {"\DTLtoplas "} + +MACRO {tcs} {"\DTLtcs "} + +READ + +STRINGS { longest.label } + +INTEGERS { number.label longest.label.width } + +FUNCTION {initialize.longest.label} +{ "" 'longest.label := + #1 'number.label := + #0 'longest.label.width := +} + +FUNCTION {longest.label.pass} +{ number.label int.to.str$ 'label := + number.label #1 + 'number.label := + label width$ longest.label.width > + { label 'longest.label := + label width$ 'longest.label.width := + } + 'skip$ + if$ +} + +EXECUTE {initialize.longest.label} + +ITERATE {longest.label.pass} + +FUNCTION {begin.bib} +{ preamble$ empty$ + 'skip$ + { preamble$ write$ newline$ } + if$ +} + +EXECUTE {begin.bib} + +EXECUTE {init.state.consts} + +ITERATE {call.type$} + +FUNCTION {end.bib} +{ +} + +EXECUTE {end.bib} +% \end{macrocode} +%\fi +%\iffalse +% \begin{macrocode} +%</databib.bst> +% \end{macrocode} +%\fi +%\Finale +\endinput |