%\iffalse % datatool.dtx generated using makedtx version 1.2 (c) Nicola Talbot % Command line args: % -author "Nicola Talbot" % -codetitle "" % -macrocode "databib\.bst" % -setambles "databib\.bst=>\nopreamble\nopostamble" % -doc "datatool-manual.tex" % -comment "databib\.bst" % -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" % datatool % Created on 2019/9/27 19:53 %\fi %\iffalse %<*package> %% \CharacterTable %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z %% Digits \0\1\2\3\4\5\6\7\8\9 %% Exclamation \! Double quote \" Hash (number) \# %% Dollar \$ Percent \% Ampersand \& %% Acute accent \' Left paren \( Right paren \) %% Asterisk \* Plus \+ Comma \, %% Minus \- Point \. Solidus \/ %% Colon \: Semicolon \; Less than \< %% Equals \= Greater than \> Question mark \? %% Commercial at \@ Left bracket \[ Backslash \\ %% Right bracket \] Circumflex \^ Underscore \_ %% Grave accent \` Left brace \{ Vertical bar \| %% Right brace \} Tilde \~} % %\fi % \iffalse % Doc-Source file to use with LaTeX2e % Copyright (C) 2019 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{24235} \RecordChanges \PageIndex \setcounter{IndexColumns}{2} \begin{document} \DocInput{datatool.dtx} \end{document} % %\fi %\MakeShortVerb{"} % %\title{Documented Code for datatool v2.32} %\author{Nicola L. C. Talbot\\ %\url{http://www.dickimaw-books.com/}} % %\date{2019-09-27} %\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{% % \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}[2019/09/27 v2.32 (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} % %\begin{macro}{\ifdtlcompareskipcs} %\changes{2.32}{2019-09-27}{new} %If true, \cs{dtlcompare} should skip control sequences. % \begin{macrocode} \newif\ifdtlcompareskipcs \dtlcompareskipcsfalse % \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 A control sequence is treated as having the character code %value of 0. Pre version 2.32, \cs{dtlcompare} was advertised here %as skipping control sequences when actually it was treating a %control sequence as character 0. To avoid breaking %backward-compatibility where a control sequence is expected to have %this behaviour, we now have a switch to determine whether to treat %control sequences as 0 or to skip them. % %So you can now ``trick'' \cs{dtlcompare} using a command which doesn't %output any text if switch this conditional on. 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 }% {% % \end{macrocode} % Identify all word breaks. %\changes{2.32}{2019-09-27}{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 \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}% % \end{macrocode} %\changes{2.32}{2019-09-27}{added check to determine if control sequences %should be skipped} % If control sequences should be skipped, check if either is a % control sequence (the character code will be 0). % \begin{macrocode} \let\dtl@donextcompare\@firstofone \ifdtlcompareskipcs \ifnum\dtl@codeA=0\relax \ifnum\dtl@codeB=0\relax % \end{macrocode} %Skip both. % \begin{macrocode} \edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\expandonce\dtl@restA}{\expandonce\dtl@restB}}% \dtl@donext \let\dtl@donextcompare\@gobble \else % \end{macrocode} %Skip A. % \begin{macrocode} \edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\expandonce\dtl@restA}{\expandonce\@dtl@argB}}% \dtl@donext \let\dtl@donextcompare\@gobble \fi \else \ifnum\dtl@codeB=0\relax % \end{macrocode} %Skip B. % \begin{macrocode} \edef\dtl@donext{% \noexpand\dtlcompare {\noexpand#1}{\expandonce\@dtl@argA}{\expandonce\dtl@restB}}% \dtl@donext \let\dtl@donextcompare\@gobble \fi \fi \fi \dtl@donextcompare {% \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 }% }% {% % \end{macrocode} %\changes{2.32}{2019-09-27}{corrected misspelt command} % \begin{macrocode} \ifdefempty{\dtl@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 empty, or to % 0 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}% % \end{macrocode} %\changes{2.32}{2019-09-27}{added check to determine if control sequences %should be skipped} % If control sequences should be skipped, check if either is a % control sequence (the character code will be 0). % \begin{macrocode} \let\dtl@donextcompare\@firstofone \ifdtlcompareskipcs \ifnum\dtl@codeA=0\relax \ifnum\dtl@codeB=0\relax % \end{macrocode} %Skip both. % \begin{macrocode} \edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\expandonce\dtl@restA}{\expandonce\dtl@restB}}% \dtl@donext \let\dtl@donextcompare\@gobble \else % \end{macrocode} %Skip A. % \begin{macrocode} \edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\expandonce\dtl@restA}{\expandonce\@dtl@argB}}% \dtl@donext \let\dtl@donextcompare\@gobble \fi \else \ifnum\dtl@codeB=0\relax % \end{macrocode} %Skip B. % \begin{macrocode} \edef\dtl@donext{% \noexpand\dtlicompare {\noexpand#1}{\expandonce\@dtl@argA}{\expandonce\dtl@restB}}% \dtl@donext \let\dtl@donextcompare\@gobble \fi \fi \fi \dtl@donextcompare {% \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 }% }% {% % \end{macrocode} %\changes{2.32}{2019-09-27}{corrected misspelt command} % \begin{macrocode} \ifdefempty{\dtl@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 to at the end % of the current iteration). % \begin{macrocode} \gdef\dtlbreak{\expandafter \gdef\csname @dtl@endhook@\the\@dtl@foreach@level\endcsname{% #1=#3}}% % \end{macrocode} % check the direction % \begin{macrocode} \ifnum#4<0\relax % \end{macrocode} % Counting down % \begin{macrocode} \whiledo{\(#1>#3\)\TE@or\(#1=#3\)}% {% #5% \csname @dtl@endhook@\the\@dtl@foreach@level\endcsname \global\advance#1 by #4\relax }% \else % \end{macrocode} % Counting up (or 0 increments) % \begin{macrocode} \whiledo{\(#1<#3\)\TE@or\(#1=#3\)}% {% #5% \csname @dtl@endhook@\the\@dtl@foreach@level\endcsname \global\advance#1 by #4\relax }% \fi % \end{macrocode} % Restore break function % \begin{macrocode} \expandafter\global\expandafter\let\expandafter\dtlbreak \csname @dtl@break@\the\@dtl@foreach@level\endcsname % \end{macrocode} % Decrement level counter % \begin{macrocode} \global\advance\@dtl@foreach@level by -1\relax } % \end{macrocode} %\end{macro} % %\begin{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} % % \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}[2019/09/27 v2.32 (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} % % \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}[2019/09/27 v2.32 (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} % % \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}[2019/09/27 v2.32 (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 \db@row@id@w #3\db@row@id@end@% row id ##2% stuff in row before column \db@col@id@w #4\db@col@id@end@% column id \db@col@elt@w ##3\db@col@elt@end@% value ##4% stuff after value \q@nil{\def#1{##3}}% \toks@=\csname dtldb@#2\endcsname \expandafter\@dtl@getvalue\the\toks@% contents of data base \db@row@id@w #3\db@row@id@end@% \db@col@id@w #4\db@col@id@end@% \db@col@elt@w \@dtlnovalue\db@col@elt@end@% undefined value \q@nil \ifx#1\dtlnovalue \PackageError{datatool}{There is no element at (row=#3,\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 in database . % Starred version doesn't check if database exists. %\changes{2.0}{2009 February 27}{new} % \begin{macrocode} \newcommand*{\dtlforcolumnidx}{% \@ifstar\@sdtlforcolumnidx\@dtlforcolumnidx } % \end{macrocode} %\end{macro} % %\begin{macro}{\@dtlforcolumnidx} % \begin{macrocode} \newcommand{\@dtlforcolumnidx}[4]{% \DTLifdbexists{#2}% {% \expandafter\ifnum\csname dtlcols@#2\endcsname<#3\relax \PackageError{datatool}{Column index \number#3\space out of bounds for database `#2'}{Database `#2' only has \expandafter\number\csname dtlcols@#2\endcsname\space columns}% \else \ifnum#3<1\relax \PackageError{datatool}{Column index \number#3\space out of bounds for database `#2'}{Indices start from 1}% \else \@sdtlforcolumnidx{#1}{#2}{#3}{#4}% \fi \fi }% % \end{macrocode} % data base doesn't exist % \begin{macrocode} {% \PackageError{datatool}{Database `#2' doesn't exist}{}% }% } % \end{macrocode} %\end{macro} % %\begin{macro}{\@sdtlforcolumnidx} % \begin{macrocode} \newcommand{\@sdtlforcolumnidx}[4]{% \toks@{#4}% \edef\@dtl@doforcol{\noexpand\dtl@forcolumn{\noexpand#1}% {\expandafter\the\csname dtldb@#2\endcsname}% {\number#3}{\the\toks@}% }% \@dtl@doforcol } % \end{macrocode} %\end{macro} % %\begin{macro}{\dtl@forcolumn} %\begin{definition} %\cs{dtl@forcolumn}\marg{cs}\marg{db specs}\marg{col num}\marg{body} %\end{definition} % \meta{col num} needs to be fully expanded % \begin{macrocode} \newcommand{\dtl@forcolumn}[4]{% % \end{macrocode} % make a copy of break function % \begin{macrocode} \let\@dtl@oldbreak\dtlbreak % \end{macrocode} % set up break function % \begin{macrocode} \def\dtlbreak{\let\@dtl@forcolnext=\@dtl@forcolnoop}% % \end{macrocode} % define loop macro for this column % \begin{macrocode} \def\@dtl@forcolumn##1% before stuff \db@col@id@w #3\db@col@id@end@% column index \db@col@elt@w ##2\db@col@elt@end@% entry \db@col@id@w #3\db@col@id@end@% column index ##3% after stuff \q@nil{% \def#1{##2}% assign value to % \end{macrocode} % check if end of loop % \begin{macrocode} \ifx#1\@nnil \let\@dtl@forcolnext=\@dtl@forcolnoop \else % \end{macrocode} % do body of loop % \begin{macrocode} #4% \let\@dtl@forcolnext=\@dtl@forcolumn \fi % \end{macrocode} % repeat if necessary % \begin{macrocode} \@dtl@forcolnext##3\q@nil }% % \end{macrocode} % do loop % \begin{macrocode} \@dtl@forcolumn#2% \db@col@id@w #3\db@col@id@end@% \db@col@elt@w \@nil\db@col@elt@end@% \db@col@id@w #3\db@col@id@end@\q@nil % \end{macrocode} % restore break function % \begin{macrocode} \let\dtlbreak\@dtl@oldbreak } % \end{macrocode} %\end{macro} %\begin{macro}{\@dtl@forcolnoop} % \begin{macrocode} \def\@dtl@forcolnoop#1\q@nil{} % \end{macrocode} %\end{macro} %\begin{macro}{\dtlforeachlevel} %\cs{DTLforeach} can only be nested up to three levels. % \cs{dtlforeachlevel} keeps track of the current level. % \begin{macrocode} \newcount\dtlforeachlevel % \end{macrocode} %\end{macro} % % The counter DTLrow\meta{n} keeps track of each row of data during % the \meta{n} nested \cs{DTLforeach}. It is only incremented in the % conditions (given by the optional argument) are met. % \begin{macrocode} \newcounter{DTLrowi} \newcounter{DTLrowii} \newcounter{DTLrowiii} % \end{macrocode} % Keep \sty{hyperref} happy % \begin{macrocode} \newcounter{DTLrow} \def\theHDTLrow{\arabic{DTLrow}} \def\theHDTLrowi{\theHDTLrow.\arabic{DTLrowi}} \def\theHDTLrowii{\theHDTLrowi.\arabic{DTLrowii}} \def\theHDTLrowiii{\theHDTLrowii.\arabic{DTLrowiii}} % \end{macrocode} % % \begin{macrocode} \newcount\dtl@rowi \newcount\dtl@rowii \newcount\dtl@rowiii % \end{macrocode} % % \begin{macrocode} \newtoks\@dtl@curi \newtoks\@dtl@previ \newtoks\@dtl@nexti \newtoks\@dtl@curii \newtoks\@dtl@previi \newtoks\@dtl@nextii \newtoks\@dtl@curiii \newtoks\@dtl@previii \newtoks\@dtl@nextiii % \end{macrocode} % %\begin{macro}{\DTLsaverowcount} %\begin{definition} %\cs{DTLsavelastrowcount}\marg{cmd} %\end{definition} % Stores the maximum row count for the last \cs{DTLforeach}. % \begin{macrocode} \newcommand*{\DTLsavelastrowcount}[1]{% \ifnum\dtlforeachlevel>2\relax \def#1{0}% \else \ifnum\dtlforeachlevel<0\relax \def#1{0}% \else \@dtl@tmpcount=\dtlforeachlevel \advance\@dtl@tmpcount by 1\relax \edef#1{\expandafter\number \csname c@DTLrow\romannumeral\@dtl@tmpcount\endcsname}% \fi \fi} % \end{macrocode} %\end{macro} % %\begin{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} %\changes{2.32}{2019-09-27}{removed \cs{relax}} % \begin{macrocode} \gdef\DTLiffirstrow##1##2{% \expandafter\ifnum \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname =1 %space intended ##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}} %\changes{2.32}{2019-09-27}{removed \cs{relax}} % \begin{macrocode} \gdef\DTLiflastrow##1##2{% \expandafter\ifnum \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname =\csname dtlrows@#2\endcsname ##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 %\changes{2.32}{2019-09-27}{changed \cs{ifx} test to \cs{ifblank}} % \begin{macrocode} \ifblank{#3}{}{\@dtl@assign{#3}{#2}}% % \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} %\changes{2.32}{2019-09-27}{removed \cs{relax}} % \begin{macrocode} \gdef\DTLiffirstrow##1##2{% \expandafter\ifnum \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname =1 % space intended ##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}} %\changes{2.32}{2019-09-27}{removed \cs{relax}} % \begin{macrocode} \gdef\DTLiflastrow##1##2{% \expandafter\ifnum \csname c@DTLrow\romannumeral\dtlforeachlevel\endcsname =\csname dtlrows@#2\endcsname ##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 %\changes{2.32}{2019-09-27}{changed \cs{ifx} test to \cs{ifblank}} % \begin{macrocode} \ifblank{#3}{} {% % \end{macrocode} % Need to set \cs{dtlcurrentrow} for \cs{@dtl@assign} % \begin{macrocode} \dtlcurrentrow=\expandafter{\dtl@thisrow}% \@dtl@assign{#3}{#2}% }% % \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} % % \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}[2019/09/27 v2.32 (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. %\changes{2.32}{2019-09-27}{added test for kernel version} % Need to test kernel version. The new 2019/10/01 version has a % different definition of \cs{UTFviii@two@octets} which won't expand % UTF-8 characters to \cs{IeC} in the required context. (This is % really useful if you want extended characters in labels but not if % they need to be stripped.) If you don't want accents stripped then % redefine \cs{datagidxstripaccents} to do nothing. % \begin{macrocode} \@ifl@t@r\fmtversion{2019/10/01} {% \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}% \let\UTFviii@two@octets\UTFviii@two@octets@combine }% } {% % \end{macrocode} % Older kernels: % \begin{macrocode} \newcommand*{\datagidxstripaccents}{% \let\add@accent@\@secondoftwo \let\@text@composite@x\@secondoftwo \let\@tabacckludge\@secondoftwo \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}% %This may cause a problem on page boundaries so this code block may %be removed in future versions. % \begin{macrocode} \dtlgidx@checklocationchange }% {% % \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}{\dtlgidx@checklocationchange} %\changes{2.32}{??}{new} % \begin{macrocode} \newcommand*{\dtlgidx@checklocationchange}{% \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} %\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} % % \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}[2019/09/27 v2.32 (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} % % \end{macrocode} %\fi %\iffalse % \begin{macrocode} %<*databar.sty> % \end{macrocode} %\fi %\chapter{databar.sty} % Declare package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{databar}[2019/09/27 v2.32 (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} % % \end{macrocode} %\fi %\iffalse % \begin{macrocode} %<*datapie.sty> % \end{macrocode} %\fi %\chapter{datapie.sty} % Declare package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{datapie}[2019/09/27 v2.32 (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} % % \end{macrocode} %\fi %\iffalse % \begin{macrocode} %<*dataplot.sty> % \end{macrocode} %\fi %\chapter{dataplot.sty} % Declare package: % \begin{macrocode} \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{dataplot}[2019/09/27 v2.32 (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} % % \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}[2019/09/27 v2.32 (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} % % \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} % % \end{macrocode} %\fi %\Finale \endinput