% arara: lualatex
% arara: bib2gls: { group: on, options: [ "--replace-quotes" ] } if  missing("glstex")
% arara: lualatex: { shell: on }
% arara: bib2gls: { group: on, options: [ "--replace-quotes" ] }
% arara: lualatex
% arara: lualatex if found ("log", "Rerun to")

% This manual creates example documents on the fly in the 
% directory created by the following line:
\directlua{os.execute("mkdir -p datatool-user-examples")}
% If the above doesn't work, you'll have to create the directory
% manually.


\documentclass[titlepage=false,oneside,
 fontsize=12pt,captions=tableheading]{scrbook}

\usepackage{textcomp}
\usepackage{microtype}
\usepackage
 [
   deephierarchy,
   %debug=showwrgloss,
   %showtargets=innerleft,
   novref,
   tikzsymbols,
   indexmarks
 ]
 {nlctuserguide}

\hypersetup{pdfauthor={Nicola Talbot},
 pdftitle={datatool manual},
 bookmarksdepth=5}

\GetTitleStringSetup{expand}

\renewcommand*{\thispackagename}{datatool}

\newfontfamily\liberationserif{Liberation Serif}
\newfontfamily\liberationmono{Liberation Mono}
\newfontfamily\libertinemono{Linux Libertine Mono O}

\NewDocumentCommand{\textliberationserif}{m}{{\liberationserif #1}}
\NewDocumentCommand{\textliberationmono}{m}{{\liberationmono #1}}
\NewDocumentCommand{\textlibertinemono}{m}{{\libertinemono #1}}

\NewDocumentCommand{\bitcoin}{}{\textliberationserif{₿}}
\NewDocumentCommand{\ttbitcoin}{}{\textliberationmono{₿}}

\tcbset{floatplacement=htbp}

\newcommand{\hex}[1]{\textliberationserif{0x#1}}
\newcommand{\hexcp}[1]{\idxc{hexcp}{\hex{#1}}}

\newcommand{\ldf}[1]{%
 \glslink{file.datatool-locale.ldf}{\filefmt{datatool\dhyphen #1.ldf}}%
}

\newcommand{\ldfmeta}[1]{%
 \glslink{file.datatool-locale.ldf}{\metafilefmt{datatool\dhyphen}{#1}{.ldf}}%
}

\newcommand{\DTLcurrISO}[1]{\glslink{DTLcurrISO}{\csfmt{DTLcurr#1}}}

\newcommand{\datatoolRegionSetNumberChars}[1]{%
 \glslink{datatoolRegionSetNumberChars}{\csfmt{data\-tool\-#1\-Set\-Num\-ber\-Chars}}%
}

\newcommand{\datatoolRegionSetCurrency}[1]{%
 \glslink{datatoolRegionSetCurrency}{\csfmt{data\-tool\-#1\-Set\-Cur\-rency}}%
}

\newcommand{\datatoolRegionsymbolprefix}[1]{%
  \glslink{datatoolRegionsymbolprefix}{\csfmt{data\-tool\-#1\-sym\-bol\-pre\-fix}}%
}

\newcommand{\DTLtagLocaleHook}[1]{%
 \glslink{DTLtagLocaleHook}{\csfmt{DTL#1LocaleHook}}%
}

\newcommand{\datatoolRegionSetTemporalParsers}[1]{%
 \glslink{datatoolRegionSetTemporalParsers}{\csfmt{datatool#1SetTemporalParsers}}%
}

\newcommand{\datatoolRegionSetTemporalFormatters}[1]{%
 \glslink{datatoolRegionSetTemporalFormatters}{\csfmt{datatool#1SetTemporalFormatters}}%
}

\newcommand{\symvardef}[1]{%
 \cmddef{ldatatool#1str}\Glsentrydesc{ldatatool#1str}.\par
 \cmddef{ldatatool#1tl}\Glsentrydesc{ldatatool#1tl}.\par
}
\newcommand{\usesymvar}[1]{\csuse{ldatatool#1tl}}

\defsemanticcmd[style1]{\actionfmt}{\texttt}{}
\defsemanticcmd[style2]{\displayoptfmt}{\texttt}{}
\defsemanticcmd[style3]{\actionoptfmt}{\texttt}{}
\defsemanticcmd[style2]{\iooptfmt}{\texttt}{}
\defsemanticcmd[style2]{\listsoptfmt}{\texttt}{}
\defsemanticcmd[style2]{\numericoptfmt}{\texttt}{}
\defsemanticcmd[style2]{\datetimeoptfmt}{\texttt}{}
\defsemanticcmd[style2]{\mapoptfmt}{\texttt}{}
\defsemanticcmd[style2]{\sortdataoptfmt}{\texttt}{}
\defsemanticcmd[style2]{\gidxoptfmt}{\texttt}{}

\defsemanticcmd[style4]{\compareoptfmt}{\texttt}{}
\defsemanticcmd[style4]{\sortdatacolumnoptfmt}{\texttt}{}

\defsemanticcmd[style5]{\databibcolkeyfmt}{\texttt}{}

\glsxtrnewgls{opt.lists.}{\listsopt}
\newcommand{\listsoptval}[2]{\optval{lists.#1}{#2}}
\newcommand{\listsoptvalm}[2]{\optval{lists.#1}{\marg{#2}}}

\glsxtrnewgls{opt.compare.}{\compareopt}
\newcommand{\compareoptval}[2]{\optval{compare.#1}{#2}}
\newcommand{\compareoptvalm}[2]{\optval{compare.#1}{\marg{#2}}}

\glsxtrnewgls{opt.numeric.}{\numericopt}
\newcommand{\numericoptval}[2]{\optval{numeric.#1}{#2}}
\newcommand{\numericoptvalm}[2]{\optval{numeric.#1}{\marg{#2}}}

\glsxtrnewgls{opt.datetime.}{\datetimeopt}
\newcommand{\datetimeoptval}[2]{\optval{datetime.#1}{#2}}
\newcommand{\datetimeoptvalm}[2]{\optval{datetime.#1}{\marg{#2}}}

\glsxtrnewgls{opt.actionname.}{\action}

\glsxtrnewgls{opt.action.}{\actionopt}
\newcommand{\actionoptval}[2]{\optval{action.#1}{#2}}
\newcommand{\actionoptvalm}[2]{\optval{action.#1}{\marg{#2}}}

\glsxtrnewgls{opt.action.datum.}{\actiondatumopt}
\newcommand{\actiondatumoptval}[2]{\optval{action.datum.#1}{#2}}
\newcommand{\actiondatumoptvalm}[2]{\optval{action.datum.#1}{\marg{#2}}}

\glsxtrnewgls{opt.action.find.}{\actionfindopt}
\newcommand{\actionfindoptval}[2]{\optval{action.find.#1}{#2}}
\newcommand{\actionfindoptvalm}[2]{\optval{action.find.#1}{\marg{#2}}}

\glsxtrnewgls{opt.sortdata.}{\sortdataopt}
\newcommand{\sortdataoptval}[2]{\optval{sortdata.#1}{#2}}
\newcommand{\sortdataoptvalm}[2]{\optval{sortdata.#1}{\marg{#2}}}

\glsxtrnewgls{opt.sortdata.column.}{\sortdatacolumnopt}
\newcommand{\sortdatacolumnoptval}[2]{\optval{sortdata.column.#1}{#2}}
\newcommand{\sortdatacolumnoptvalm}[2]{\optval{sortdata.column.#1}{\marg{#2}}}

\glsxtrnewgls{opt.databibcolkey.}{\databibcolkey}

\newcommand{\actionentryname}[1]{%
 \texttt{%
  \gls{DTLaction}\faded{\oargm{settings}}%
  \marg{\createtarget{#1}{\strong{\glossentryname{#1}}}}%
 }%
}

\newcommand{\actiondef}[1]{%
 \bgroup
  \renewcommand{\optiondefhook}{%
   \let\GlsXtrStandaloneEntryName\actionentryname
  }%
  \optiondef[\cmddefbookmarklevel]{actionname.#1}%
 \egroup
 \noindent\ignorespaces
}

\glsxtrnewgls{opt.io.}{\ioopt}
\newcommand{\iooptval}[2]{\optval{io.#1}{#2}}
\newcommand{\iooptvalm}[2]{\optval{io.#1}{\marg{#2}}}
\newcommand{\iooptvalref}[2]{\optvalref{io.#1}{#2}}
\newcommand{\ioopteqvalref}[2]{\opteqvalref{io.#1}{#2}}

\glsxtrnewgls{opt.display.}{\displayopt}
\newcommand{\displayoptval}[2]{\optval{display.#1}{#2}}
\newcommand{\displayoptvalm}[2]{\optval{display.#1}{\marg{#2}}}

\glsxtrnewgls{opt.mapdata.}{\mapdataopt}
\newcommand{\mapdataoptval}[2]{\optval{mapdata.#1}{#2}}
\newcommand{\mapdataoptvalm}[2]{\optval{mapdata.#1}{\marg{#2}}}

\glsxtrnewgls{opt.mapget.}{\mapgetopt}
\newcommand{\mapgetoptval}[2]{\optval{mapget.#1}{#2}}
\newcommand{\mapgetoptvalm}[2]{\optval{mapget.#1}{\marg{#2}}}

\glsxtrnewgls{opt.mapdataedit.}{\mapdataeditopt}
\newcommand{\mapdataeditoptval}[2]{\optval{mapdataedit.#1}{#2}}
\newcommand{\mapdataeditoptvalm}[2]{\optval{mapdataedit.#1}{\marg{#2}}}

\glsxtrnewgls{opt.plot.}{\plotopt}
\newcommand{\plotoptval}[2]{\optval{plot.#1}{#2}}
\newcommand{\plotoptvalm}[2]{\optval{plot.#1}{\marg{#2}}}

\newcommand{\plotgroupstyleval}[1]{\optvalref{plot.group-styles}{#1}}
\newcommand{\plotstyleresetval}[1]{\optvalref{plot.style-resets}{#1}}

\glsxtrnewgls{opt.pie.}{\pieopt}
\newcommand{\pieoptval}[2]{\optval{pie.#1}{#2}}
\newcommand{\pieoptvalm}[2]{\optval{pie.#1}{\marg{#2}}}

\glsxtrnewgls{opt.bar.}{\baropt}
\newcommand{\baroptval}[2]{\optval{bar.#1}{#2}}
\newcommand{\baroptvalm}[2]{\optval{bar.#1}{\marg{#2}}}
\newcommand{\baropteqvalref}[2]{\opteqvalref{bar.#1}{#2}}

\glsxtrnewgls{opt.personsty.}{\personstyopt}
\glsxtrnewgls{opt.person.}{\personopt}
\newcommand{\personoptval}[2]{\optval{person.#1}{#2}}
\newcommand{\personoptvalm}[2]{\optval{person.#1}{\marg{#2}}}

\glsxtrnewgls{opt.newperson.}{\newpersonopt}
\newcommand{\newpersonoptval}[2]{\optval{newperson.#1}{#2}}
\newcommand{\newpersonoptvalm}[2]{\optval{newperson.#1}{\marg{#2}}}

\glsxtrnewgls{opt.gidx.}{\gidxopt}
\newcommand{\gidxoptval}[2]{\optval{gidx.#1}{#2}}
\newcommand{\gidxoptvalm}[2]{\optval{gidx.#1}{\marg{#2}}}

\glsxtrnewgls{opt.newterm.}{\newtermopt}
\newcommand{\newtermoptval}[2]{\optval{newterm.#1}{#2}}
\newcommand{\newtermoptvalm}[2]{\optval{newterm.#1}{\marg{#2}}}

\glsxtrnewgls{gidxvar.}{\gidxvar}

\appto\nlctexamplelets{%
  \def\listsopt#1{\glsentrytext{opt.lists.#1}}%
  \def\numericopt#1{\glsentrytext{opt.numeric.#1}}%
  \def\compareopt#1{\glsentrytext{opt.compare.#1}}%
  \def\datetimeopt#1{\glsentrytext{opt.datetime.#1}}%
  \def\action#1{\glsentrytext{opt.actionname.#1}}%
  \def\actionopt#1{\glsentrytext{opt.action.#1}}%
  \def\actiondatumopt#1{\glsentrytext{opt.action.datum.#1}}%
  \def\actionfindopt#1{\glsentrytext{opt.action.find.#1}}%
  \def\ioopt#1{\glsentrytext{opt.io.#1}}%
  \def\displayopt#1{\glsentrytext{opt.display.#1}}%
  \def\mapgetopt#1{\glsentrytext{opt.mapget.#1}}%
  \def\mapdataopt#1{\glsentrytext{opt.mapdata.#1}}%
  \def\plotopt#1{\glsentrytext{opt.plot.#1}}%
  \def\plotoptval#1#2{\glsentrytext{opt.plot.#1}=#2}%
  \def\pieopt#1{\glsentrytext{opt.pie.#1}}%
  \def\pieoptval#1#2{\glsentrytext{opt.pie.#1}=#2}%
  \def\baropt#1{\glsentrytext{opt.bar.#1}}%
  \def\personopt#1{\glsentrytext{opt.person.#1}}%
  \def\sortdataopt#1{\glsentrytext{opt.sortdata.#1}}%
  \def\sortdatacolumnopt#1{\glsentrytext{opt.sortdata.column.#1}}%
}

\appto\nlctuserguidebibextrapreamble{%
 \string\providecommand\string\hex[1]{0x\glshashchar1}%
}

\nlctuserguidegls
{
  \def\gioopt#1#2{\glsbibwriteentry{option}{opt.io.#1}%
   {\field{name}{\iooptfmt{#1}}\parent{opt.io}#2}}%
  \def\glistsopt#1#2{\glsbibwriteentry{option}{opt.lists.#1}%
   {\field{name}{\listsoptfmt{#1}}\parent{opt.lists}#2}}%
  \def\gcompareopt#1#2{\glsbibwriteentry{option}{opt.compare.#1}%
   {\field{name}{\compareoptfmt{#1}}\parent{opt.compare}#2}}%
  \def\gnumericopt#1#2{\glsbibwriteentry{option}{opt.numeric.#1}%
   {\field{name}{\numericoptfmt{#1}}\parent{opt.numeric}#2}}%
  \def\gdatetimeopt#1#2{\glsbibwriteentry{option}{opt.datetime.#1}%
   {\field{name}{\datetimeoptfmt{#1}}\parent{opt.datetime}#2}}%
  \def\gdisplayopt#1#2{\glsbibwriteentry{option}{opt.display.#1}%
   {\field{name}{\displayoptfmt{#1}}\parent{opt.display}#2}}%
  \def\gactionopt#1#2{\glsbibwriteentry{option}{opt.action.#1}%
   {\field{name}{\actionoptfmt{#1}}\parent{DTLaction}#2}}%
  \def\gactiondatumopt#1#2{\glsbibwriteentry{option}{opt.action.datum.#1}%
   {\field{name}{\optfmt{#1}}\parent{opt.action.datum}#2}}%
  \def\gactionfindopt#1#2{\glsbibwriteentry{option}{opt.action.find.#1}%
   {\field{name}{\optfmt{#1}}\parent{opt.actionname.find}#2}}%
  \gidxpl{action}{\field{see}{DTLaction}}
  \def\gactionname#1#2{\glsbibwriteentry{option}{opt.actionname.#1}%
   {\field{name}{\actionfmt{#1}}\parent{idx.action}#2}}%
  \def\gmapgetopt#1#2{\glsbibwriteentry{option}{opt.mapget.#1}%
   {\field{name}{\mapoptfmt{#1}}\parent{DTLmapget}#2}}%
  \def\gmapdataopt#1#2{\glsbibwriteentry{option}{opt.mapdata.#1}%
   {\field{name}{\mapoptfmt{#1}}\parent{DTLmapdata}#2}}%
  \gidxpl{DTLmapdataedit}{\field{text}{\csfmt{DTLmapdata} edit option}}
  \def\gmapdataeditopt#1#2{\glsbibwriteentry{option}{opt.mapdataedit.#1}%
   {\field{name}{\mapoptfmt{#1}}\parent{idx.DTLmapdataedit}#2}}%
  \def\gplotopt#1#2{\glsbibwriteentry{option}{opt.plot.#1}%
   {\field{name}{\optfmt{#1}}\parent{opt.plot}#2}}%
  \def\gpieopt#1#2{\glsbibwriteentry{option}{opt.pie.#1}%
   {\field{name}{\optfmt{#1}}\parent{opt.pie}#2}}%
  \def\gbaropt#1#2{\glsbibwriteentry{option}{opt.bar.#1}%
   {\field{name}{\optfmt{#1}}\parent{opt.bar}#2}}%
  \def\gpersonopt#1#2{\glsbibwriteentry{option}{opt.person.#1}%
   {\field{name}{\optfmt{#1}}\parent{opt.person}#2}}%
  \def\gnewpersonopt#1#2{\glsbibwriteentry{option}{opt.newperson.#1}%
   {\field{name}{\optfmt{#1}}\parent{newperson*}#2}}%
  \def\ggidxopt#1#2{\glsbibwriteentry{option}{opt.gidx.#1}%
   {\field{name}{\gidxoptfmt{#1}}\parent{opt.index}#2}}%
  \def\gnewtermopt#1#2{\glsbibwriteentry{option}{opt.newterm.#1}%
   {\field{name}{\optfmt{#1}}\parent{newterm}#2}}%
  \gidx{databibcolkey}{\name{\styfmt{databib} column keys}}%
  \def\gdatabibcolkey#1#2{\glsbibwriteentry{option}{opt.databibcolkey.#1}%
   {\field{name}{\databibcolkeyfmt{#1}}\parent{idx.databibcolkey}#2}}%
  \def\ggidxvar#1#2{%
    \glsbibwriteentry{command}{gidxvar.#1}%
     {\name{\csfmt{#1}}#2}%
  }%
  \def\gsortdataopt#1#2{\glsbibwriteentry{option}{opt.sortdata.#1}%
   {\field{name}{\sortdataoptfmt{#1}}\parent{DTLsortdata}#2}}%
  \gidxpl{opt.sortdata.column}
    {\field{text}{\csfmt{DTLsortdata} column criteria option}}
  \def\gsortdatacolumnopt#1#2{\glsbibwriteentry{option}{opt.sortdata.column.#1}%
   {\field{name}{\sortdatacolumnoptfmt{#1}}\parent{idx.opt.sortdata.column}#2}}%
  \def\gsymvar#1#2#3#4#5{\gcmd{l\dsb data\-tool\dsb #1\dsb str}{%
     \providedby{\sty{datatool-base} v3.0+}%
     \desc{expands to the string representation of #2
     \qtt{\usesymvar{#1}}, if supported by the current encoding, 
     or \qtt{#3} otherwise}#4}
     \gcmd{l\dsb data\-tool\dsb #1\dsb tl}{%
     \providedby{\sty{datatool-base} v3.0+}%
     \desc{expands to the symbol representation of #2
     \qtt{\usesymvar{#1}}, if supported by the current encoding, 
     or \qtt{#3} otherwise} #5}}%
  % COMMANDS: DATA TYPES
  % \DTLparse
  \gcmd{DTL\-parse}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{content}}
    \desc{parses \meta{content} and stores the data in the control
    sequence \meta{cs}, which can then be passed to
    \gls{DTLusedatum}, \gls{DTLdatumvalue}, \gls{DTLdatumcurrency}
    or \gls{DTLdatumtype}}
  }
  % \DTLxparse
  \gcmd{DTL\-x\-parse}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{content}}
    \desc{as \gls{DTLparse} but first fully expands \meta{content}}
  }
  % \DTLusedatum
  \gcmd{DTL\-use\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}}
    \desc{expands to the original value that was parsed by
    \gls{DTLparse} (or the expanded value for \gls{DTLxparse})}
  }
  % \datatool_datum_string:Nnnnn
  \gcmd{data\-tool\dsb datum\dsb string:Nnnnn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{marker-cs} \margm{string} \margm{value} \margm{currency} \margm{type}}
    \desc{expands to \meta{string}}
  }
  % \datatool_datum_value:Nnnnn
  \gcmd{data\-tool\dsb datum\dsb value:Nnnnn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{marker-cs} \margm{string} \margm{value} \margm{currency} \margm{type}}
    \desc{expands to \meta{value}}
  }
  % \datatool_datum_currency:Nnnnn
  \gcmd{data\-tool\dsb datum\dsb currency:Nnnnn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{marker-cs} \margm{string} \margm{value} \margm{currency} \margm{type}}
    \desc{expands to \meta{currency}}
  }
  % \datatool_datum_type:Nnnnn
  \gcmd{data\-tool\dsb datum\dsb type:Nnnnn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{marker-cs} \margm{string} \margm{value} \margm{currency} \margm{type}}
    \desc{expands to \meta{type}}
  }
  % \datatool_max_known_type:
  \gcmd{datatool\dsb max\dsb known\dsb type:}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{expands to the current maximum known data type identifier}
  }
  % \DTLdatumvalue
  \gcmd{DTL\-datum\-value}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}}
    \desc{expands to the numeric value that was parsed by
    \gls{DTLparse} or \gls{DTLxparse} (as a \idx{plainnumber})}
  }
  % \DTLdatumcurrency
  \gcmd{DTL\-datum\-currency}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}}
    \desc{expands to the \idx{currencysym} that was parsed by
    \gls{DTLparse} or \gls{DTLxparse}}
  }
  % \DTLdatumtype
  \gcmd{DTL\-datum\-type}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}}
    \desc{expands to an integer representing the data type that was parsed by
    \gls{DTLparse} or \gls{DTLxparse}}
  }
  % \datatool_datum_show:N
  \gcmd{data\-tool\dsb datum\dsb show:N}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}}
    \desc{interrupts the \LaTeX\ run and shows the component parts
of the given \idx{datumcs}}
  }
  % \DTLgetDataTypeName
  \gcmd{DTL\-get\-Data\-Type\-Name}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{number}}
    \desc{expands to textual label associated with the data type
    \meta{number}}
  }
  % \DTLdatatypeunsetname
  \gcmd{DTL\-data\-type\-un\-set\-name}
  {
     \initval{unset}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the unset data type}
     \note{language-sensitive}
  }
  % \DTLdatatypestringname
  \gcmd{DTL\-data\-type\-string\-name}
  {
     \initval{string}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the string data type}
     \note{language-sensitive}
  }
  % \DTLdatatypeintegername
  \gcmd{DTL\-data\-type\-int\-e\-ger\-name}
  {
     \initval{integer}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the integer data type}
     \note{language-sensitive}
  }
  % \DTLdatatypedecimalname
  \gcmd{DTL\-data\-type\-decimal\-name}
  {
     \initval{decimal}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the decimal data type}
     \note{language-sensitive}
  }
  % \DTLdatatypecurrencyname
  \gcmd{DTL\-data\-type\-currency\-name}
  {
     \initval{currency}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the currency data type}
     \note{language-sensitive}
  }
  % \DTLdatatypedatetimename
  \gcmd{DTL\-data\-type\-date\-time\-name}
  {
     \initval{date-time}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the datetime data type}
     \note{language-sensitive}
  }
  % \DTLdatatypedatename
  \gcmd{DTL\-data\-type\-date\-name}
  {
     \initval{date}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the date data type}
     \note{language-sensitive}
  }
  % \DTLdatatypetimename
  \gcmd{DTL\-data\-type\-time\-name}
  {
     \initval{time}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of the time data type}
     \note{language-sensitive}
  }
  % \DTLdatatypeinvalidname
  \gcmd{DTL\-data\-type\-invalid\-name}
  {
     \initval{invalid}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the name of an invalid data type identifier}
     \note{language-sensitive}
  }
  % \c_datatool_unknown_int
  \gcmd{c\dsb datatool\dsb unknown\dsb int}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{constant integer ($-1$) used to identify unknown data
     types (typically because no non-empty data has been
     encountered). Not that, for backward-compatibility, \sty{datatool}
     column metadata may have a blank value for an unknown type
     rather that \code{-1}. The use of an integer type makes type
     comparisons easier}
  }
  % \c_datatool_string_int
  \gcmd{c\dsb datatool\dsb string\dsb int}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{constant integer (0) used to identify the string data
     type. Note that \sty{datatool} provides \gls{DTLstringtype},
     which is the older command}
  }
  % \c_datatool_integer_int
  \gcmd{c\dsb datatool\dsb integer\dsb int}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{constant integer (1) used to identify the integer data
     type. Note that \sty{datatool} provides \gls{DTLinttype},
     which is the older command}
  }
  % \c_datatool_decimal_int
  \gcmd{c\dsb datatool\dsb decimal\dsb int}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{constant integer (2) used to identify the decimal or real data
     type. Note that \sty{datatool} provides \gls{DTLrealtype},
     which is the older command}
  }
  % \c_datatool_currency_int
  \gcmd{c\dsb datatool\dsb currency\dsb int}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{constant integer (3) used to identify the currency data
     type. Note that \sty{datatool} provides \gls{DTLcurrencytype},
     which is the older command}
  }
  % \DTLtemporalvalue
  \gcmd{DTL\-temporal\-value}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{number}\margm{ISO}}
    \desc{used within temporal datum values to store both the numeric value and ISO
     format within the value part}
  }
  % \datatool_extract_timestamp:NN
  \gcmd{data\-tool\dsb extract\dsb time\-stamp:NN}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{datum-cs} \meta{result-tl}}
    \desc{extracts the date/time data stored in the given \idx{datumcs}
     and stores the result in the token list register \meta{result-tl}}
  }
  % \DTLsetintegerdatum
  \gcmd{DTL\-set\-integer\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{value}}
    \desc{defines \meta{cs} to an integer datum}
  }
  % \DTLxsetintegerdatum
  \gcmd{DTL\-x\-set\-integer\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{value}}
    \desc{defines \meta{cs} to an integer datum, expanding
     \meta{formatted value} and \meta{value}}
  }
  % \DTLsetfpdatum
  \gcmd{DTL\-set\-fp\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{value}}
    \desc{defines \meta{cs} to a decimal datum where the value
     is converted into
     \code{\gls{datatooldatumfp:nnn}\margm{value}\margm{fp}\margm{decimal}}
     for easy conversion to an \styfmt{l3fp} variable}
  }
  % \datatool_datum_fp:nnn
  \gcmd{data\-tool\dsb datum\dsb fp:nnn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{fp-value} \margm{fp-var-content} \margm{decimal}}
    \desc{used to markup a decimal value}
  }
  % \datatool_set_fp:Nn
  \gcmd{data\-tool\dsb set\dsb fp:Nn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{fp-var} \margm{value}}
    \desc{sets the floating point variable \meta{fp-var} to the floating
point number obtained from the given
\meta{value}, which may be a \idx{datumcs} or a \idx{datumitem} or
in a locale-sensitive format that requires parsing}
  }
  % \DTLsetdecimaldatum
  \gcmd{DTL\-set\-decimal\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{value}}
    \desc{defines \meta{cs} to a decimal datum}
  }
  % \DTLxsetdecimaldatum
  \gcmd{DTL\-x\-set\-decimal\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{value}}
    \desc{defines \meta{cs} to a decimal datum, expanding
    \meta{formatted value} and \meta{value}}
  }
  % \DTLsetcurrencydatum
  \gcmd{DTL\-set\-currency\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{value}\margm{currency symbol}}
    \desc{defines \meta{cs} to a currency datum}
  }
  % \DTLxsetcurrencydatum
  \gcmd{DTL\-x\-set\-currency\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{value}\margm{currency symbol}}
    \desc{defines \meta{cs} to a currency datum, expanding
    \meta{formatted value}, \meta{value} and \meta{currency symbol}}
  }
  % \DTLsettemporaldatum
  \gcmd{DTL\-set\-temporal\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{date/time stamp}}
    \desc{defines \meta{cs} to a temporal datum obtained by parsing
    \meta{date/time stamp}}
  }
  % \DTLxsettemporaldatum
  \gcmd{DTL\-x\-set\-temporal\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{formatted value}\margm{date/time stamp}}
    \desc{as \gls{DTLsettemporaldatum} but expands
     \meta{formatted value} and \meta{date/time stamp}}
  }
  % \DTLsetstringdatum
  \gcmd{DTL\-set\-string\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{string}}
    \desc{defines \meta{cs} to a string datum}
  }
  % \DTLxsetstringdatum
  \gcmd{DTL\-x\-set\-string\-datum}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{cs}\margm{string}}
    \desc{defines \meta{cs} to a string datum, expanding \meta{string}}
  }
  % COMMANDS: NUMERIC
  % \DTLsetnumberchars
  \gcmd{DTL\-set\-number\-chars}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{number group char}\margm{decimal char}}
     \desc{sets the current \idx{numbergroupchar} and \idx{decimalchar}}
  }
  % \datatool_set_numberchars:nn
  \gfnsuffix{data\-tool\dsb set\dsb number\-chars}{nn}{nV,Vn,VV}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{number group char}\margm{decimal char}}
     \desc{sets the current \idx{numbergroupchar} and \idx{decimalchar}}
   }
  % \datatool_set_numberchars:nnnn
  \gfnsuffix{data\-tool\dsb set\dsb number\-chars}{nnnn}{VVVV,eeee}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{format number group char}\margm{format decimal
char}\margm{parse number group char}\margm{parse decimal
char}}
     \desc{sets the current \idx{numbergroupchar} and \idx{decimalchar}
      for formatting and parsing}
   }
  % \datatool_set_numberchars_regex:nnnn
  \gfnsuffix{datatool\dsb set\dsb numberchars\dsb regex}{nnnn}{VVnn,Vnnn,nVnn}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{format number group char}\margm{format decimal
char}\margm{parse number group regex}\margm{parse decimal
regex}}
     \desc{sets the current \idx{numbergroupchar} and \idx{decimalchar}
      for formatting to \meta{format number group char} and \meta{format decimal
char} and sets \idx{numbergroupchar} and \idx{decimalchar} regular
expressions used by the parser to \meta{parse number group regex}
and \meta{parse decimal regex}}
   }
  % \datatool_set_numberchars_regex_tl:nnnn
  \gfnsuffix{datatool\dsb set\dsb numberchars\dsb regex\dsb tl}{nnnn}{VVnn,Vnnn,nVnn,nVnV,nnnV}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{format number group char}\margm{format decimal
char}\margm{parse number group regex}\margm{parse decimal
char}}
     \desc{sets the current \idx{numbergroupchar} and \idx{decimalchar}
      for formatting to \meta{format number group char} and \meta{format decimal
char} and sets \idx{numbergroupchar} regular
expressions used by the parser to \meta{parse number group regex}
and the \idx{decimalchar} to \meta{parse decimal char}}
   }
  % \datatool_set_numberchars_tl_regex:nnnn
  \gfnsuffix{datatool\dsb set\dsb numberchars\dsb tl\dsb regex}{nnnn}{VVnn,Vnnn,nVnn,VnVn,nnVn}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{format number group char}\margm{format decimal
char}\margm{parse number group char}\margm{parse decimal
regex}}
     \desc{sets the current \idx{numbergroupchar} and \idx{decimalchar}
      for formatting to \meta{format number group char} and \meta{format decimal
char}, and sets the \idx{numbergroupchar} to \meta{parse number group char}
and the \idx{decimalchar} regular
expressions used by the parser to \meta{parse decimal regex}}
   }
  % \datatool_set_thinspace_group_decimal_char:n
  \gfnsuffix{data\-tool\dsb set\dsb thin\-space\dsb group\dsb decimal\dsb char}{n}{V}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{decimal char}}
     \desc{similar to \gls{datatoolsetnumberchars:nn} but uses
      \gls{cs.comma} (thin space) for the \idx{numbergroupchar} when
formatting, and allows \gls{cs.comma} or a normal space or the Unicode
character U+2009 (thin space) as the \idx{numbergroupchar} when
parsing. The \idx{decimalchar} for both formatting and parsing is
set to \meta{decimal char}}
   }
  % \datatool_set_apos_group_decimal_char:n
  \gfnsuffix{data\-tool\dsb set\dsb apos\dsb group\dsb decimal\dsb char}{n}{V}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{decimal char}}
     \desc{similar to \gls{datatoolsetnumberchars:nn} but uses
      an apostrophe character for the \idx{numbergroupchar} when
formatting, and allows either straight apostrophe (U+27) or curly apostrophe
(U+2019) as the \idx{numbergroupchar} when
parsing. The \idx{decimalchar} for both formatting and parsing is
set to \meta{decimal char}}
   }
  % \c_datatool_apostrophe_regex
  \gcmd{c\dsb data\-tool\dsb apostrophe\dsb regex}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{constant regular expression that matches either a
straight apostrophe character or a closing single quote character}
   }
  % \datatool_set_underscore_group_decimal_char:n
  \gfnsuffix{data\-tool\dsb set\dsb under\-score\dsb group\dsb decimal\dsb char}{n}{V}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{decimal char}}
     \desc{similar to \gls{datatoolsetnumberchars:nn} but uses
      \gls{cs.underscore}  for the \idx{numbergroupchar} when
formatting, and allows \gls{cs.underscore} or the underscore character as the \idx{numbergroupchar} when
parsing. The \idx{decimalchar} for both formatting and parsing is
set to \meta{decimal char}}
   }
  % \datatool_register_regional_currency_code:nn
  \gcmd{data\-tool\dsb reg\-is\-ter\dsb region\-al\dsb cur\-rency\dsb code:nn}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{region-code} \margm{currency-code}}
     \desc{region files should use this command to register the
currency code defined by that region}
   }
  % \datatool<Region>SetNumberChars
  \gcmdmeta{data\-tool}{Region}{Set\-Num\-ber\-Chars}
  {
    \providedby{\ldfmeta{Region}}
    \desc{hook provided by region files to set the region's
number group and decimal characters. This hook should check the
boolean \gls{ldatatoolregionsetnumbercharsbool}
and only set the \idx{numbergroupchar} and \idx{decimalchar} if true}
  }
  % \l_datatool_region_set_numberchars_bool
  \gcmd{l\dsb data\-tool\dsb region\dsb set\dsb num\-ber\-chars\dsb bool}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{boolean variable that corresponds to 
     the \numericopt{region-number-chars} option,
    which should be checked by region files}
  }
  % \l_datatool_middot_str
  % \l_datatool_middot_tl
  \gsymvar{middot}{the middle dot (raised decimal point)}{.}{}{}
  % \DTLconverttodecimal
  \gcmd{DTL\-con\-vert\-to\-dec\-i\-mal}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{cs}}
     \desc{converts the \idx{formattednumber} \meta{num} to a
     \idx{plainnumber} and stores the result in the control sequence
     \meta{cs}}
  }
  % \DTLdecimaltolocale
  \gcmd{DTL\-dec\-i\-mal\-to\-loc\-ale}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{cs}}
     \desc{converts the \idx{plainnumber} \meta{num} to a
     \idx{formattednumber} and stores the result in the control
     sequence \meta{cs}}
  }
  % \DTLdecimaltocurrency
  \gcmd{DTL\-dec\-i\-mal\-to\-cur\-rency}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\oargm{currency symbol}\margm{num}\margm{cs}}
     \desc{converts the \idx{plainnumber} \meta{num} to a
     formatted currency using the supplied \meta{currency symbol}
     and stores the result in the control
     sequence \meta{cs}. If the optional argument is omitted, the
     default currency symbol is used}
  }
  % \DTLscinum
  \gcmd{DTL\-sci\-num}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{value}}
     \desc{if \sty{siunitx} is loaded, this will expand to
\code{\gls{num}\marg{value}} otherwise it will just expand to
\meta{value}}
  }
  % \dtladd
  \gcmd{dtl\-add}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} + \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtladdall
  \gcmd{dtl\-add\-all}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}\margm{num list}}
     \desc{adds all the numbers in the comma-separated list
      \meta{num list} and stores the result in
      the control sequence \meta{cs}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtlsub
  \gcmd{dtl\-sub}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} - \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtlmul
  \gcmd{dtl\-mul}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} \times \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtldiv
  \gcmd{dtl\-div}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} \div \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtlsqrt
  \gcmd{dtl\-sqrt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{Calculates the square root of \meta{num} and stores the result in
      the control sequence \meta{cs}, where the number is a
       \idx{plainnumber}}
  }
  % \dtlroot
  \gcmd{dtl\-root}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}\margm{n}}
     \desc{Calculates the \meta{n}th root of \meta{num} and stores the result in
      the control sequence \meta{cs}, where the number is a
       \idx{plainnumber}}
  }
  % \dtlround
  \gcmd{dtl\-round}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}\margm{dp}}
     \desc{Rounds \meta{num} to \meta{dp} decimal places and stores the result in
      the control sequence \meta{cs}, where the number is a
       \idx{plainnumber}}
  }
  % \dtltrunc
  \gcmd{dtl\-trunc}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}\margm{dp}}
     \desc{Truncates \meta{num} to \meta{dp} decimal places and stores the result in
      the control sequence \meta{cs}, where the number is a
       \idx{plainnumber}}
  }
  % \dtlclip
  \gcmd{dtl\-clip}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{Removes redundant trailing zeros from \meta{num} and
       stores the result in the control sequence \meta{cs}, where the number is a
       \idx{plainnumber}}
  }
  % \dtlmin
  \gcmd{dtl\-min}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{defines the control sequence \meta{cs} to the smaller of
      the two numbers, where the numbers are \idxpl{plainnumber}}
  }
  % \dtlminall
  \gcmd{dtl\-min\-all}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}\margm{num list}}
     \desc{Sets \meta{cs} to the minimum of all the 
      \idxpl{plainnumber} in the comma-separated \meta{num list}}
  }
  % \dtlmax
  \gcmd{dtl\-max}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{defines the control sequence \meta{cs} to the larger of
      the two numbers, where the numbers are \idxpl{plainnumber}}
  }
  % \dtlmaxall
  \gcmd{dtl\-max\-all}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}\margm{num list}}
     \desc{Sets \meta{cs} to the maximum of all the 
      \idxpl{plainnumber} in the comma-separated \meta{num list}}
  }
  % \dtlabs
  \gcmd{dtl\-abs}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{defines the control sequence \meta{cs} to the absolute
       value of the number \meta{num}, where the number is a
       \idx{plainnumber}}
  }
  % \dtlneg
  \gcmd{dtl\-neg}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{defines the control sequence \meta{cs} to the negative
      of the number \meta{num}, where the number is a \idx{plainnumber}}
  }
  % \dtlmeanforall
  \gcmd{dtl\-mean\-for\-all}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}\margm{num list}}
     \desc{calculates the mean (average) of all the numbers in the 
      comma-separated list \meta{num list} and stores the result 
      in the control sequence \meta{cs}, where the numbers are
      \idxpl{plainnumber}}
  }
  % \dtlvarianceforall
  \gcmd{dtl\-variance\-for\-all}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\oargm{mean}\margm{cs}\margm{num list}}
     \desc{calculates the variance of all the numbers in the 
      comma-separated list \meta{num list} and stores the result 
      in the control sequence \meta{cs}, where the numbers are
      \idxpl{plainnumber}. If the mean value has already been
      computed, it can be supplied in the optional argument
      \meta{mean}. If omitted, the mean will be calculated before
      calculating the variance}
  }
  % \dtlsdforall
  \gcmd{dtl\-sd\-for\-all}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\oargm{mean}\margm{cs}\margm{num list}}
     \desc{calculates the standard deviation of all the numbers in the 
      comma-separated list \meta{num list} and stores the result 
      in the control sequence \meta{cs}, where the numbers are
      \idxpl{plainnumber}. If the mean value has already been
      computed, it can be supplied in the optional argument
      \meta{mean}. If omitted, the mean will be calculated before
      calculating the standard deviation}
  }
  % \dtlpadleadingzeros
  \gcmd{dtl\-pad\-lead\-ing\-zeros}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{num-digits}\margm{value}}
    \desc{displays the \idx{plainnumber} \meta{value} zero-padded
    to \meta{num-digits}. This command is designed for sorting
    numbers by character code and so is expandable. Unlike
    \gls{two@digits}, the \meta{value} may be a decimal. The
    expansion is also a \idx{plainnumber}. The \meta{num-digits}
    argument should be in the range 1--7}
  }
  % \dtlpadleadingzerosminus
  \gcmd{dtl\-pad\-leading\-zeros\-minus}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \initval{-}
    \desc{inserted at the start of the expansion text of
    \gls{dtlpadleadingzeros} if the value is negative}
  }
  % \dtlpadleadingzerosplus
  \gcmd{dtl\-pad\-leading\-zeros\-plus}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \initvalempty
    \desc{inserted at the start of the expansion text of
    \gls{dtlpadleadingzeros} if the value is positive}
  }
  % \DTLadd
  \gcmd{DTL\-add}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} + \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
      \idxpl{formattednumber}. The result will be a
      \idx{formattednumber}}
  }
  % \DTLgadd
  \gcmd{DTL\-g\-add}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{as \gls{DTLadd} but globally defines \meta{cs}}
  }
  % \DTLaddall
  \gcmd{DTL\-add\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{adds all the \idxpl{formattednumber} in the
     comma-separated \meta{num list} and stores the result as a 
     \idx{formattednumber} in \meta{cs}}
  }
  % \DTLgaddall
  \gcmd{DTL\-g\-add\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{as \gls{DTLaddall} but globally defines \meta{cs}}
  }
  % \DTLsub
  \gcmd{DTL\-sub}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} - \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
      \idxpl{formattednumber}. The result will be a
      \idx{formattednumber}}
  }
  % \DTLgsub
  \gcmd{DTL\-g\-sub}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{as \gls{DTLsub} but globally defines \meta{cs}}
  }
  % \DTLmul
  \gcmd{DTL\-mul}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} \times \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
      \idxpl{formattednumber}. The result will be a
      \idx{formattednumber}}
  }
  % \DTLgmul
  \gcmd{DTL\-g\-mul}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{as \gls{DTLmul} but globally defines \meta{cs}}
  }
  % \DTLdiv
  \gcmd{DTL\-div}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Calculates $\meta{num1} \div \meta{num2}$ and stores the result in
      the control sequence \meta{cs}, where the numbers are
      \idxpl{formattednumber}. The result will be a
      \idx{formattednumber}}
  }
  % \DTLgdiv
  \gcmd{DTL\-g\-div}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{as \gls{DTLdiv} but globally defines \meta{cs}}
  }
  % \DTLabs
  \gcmd{DTL\-abs}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{Calculates the absolute value of the \idx{formattednumber}
      \meta{num} and stores the result as a \idx{formattednumber} in
      the control sequence \meta{cs}}
  }
  % \DTLgabs
  \gcmd{DTL\-g\-abs}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{as \gls{DTLabs} but globally defines \meta{cs}}
  }
  % \DTLneg
  \gcmd{DTL\-neg}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{Calculates the negative of the \idx{formattednumber}
      \meta{num} and stores the result as a \idx{formattednumber} in
      the control sequence \meta{cs}}
  }
  % \DTLgneg
  \gcmd{DTL\-g\-neg}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{as \gls{DTLneg} but globally defines \meta{cs}}
  }
  % \DTLsqrt
  \gcmd{DTL\-sqrt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{Calculates the square root of the \idx{formattednumber}
      \meta{num} and stores the result as a \idx{formattednumber} in
      the control sequence \meta{cs}}
  }
  % \DTLgsqrt
  \gcmd{DTL\-g\-sqrt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{as \gls{DTLsqrt} but globally defines \meta{cs}}
  }
  % \DTLround
  \gcmd{DTL\-round}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}\margm{num digits}}
     \desc{Rounds the \idx{formattednumber} \meta{num} to \meta{num digits}
       and stores the result as a \idx{formattednumber} in
      the control sequence \meta{cs}}
  }
  % \DTLground
  \gcmd{DTL\-g\-round}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}\margm{num digits}}
     \desc{as \gls{DTLround} but globally defines \meta{cs}}
  }
  % \DTLtrunc
  \gcmd{DTL\-trunc}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}\margm{num digits}}
     \desc{truncates the \idx{formattednumber} \meta{num} to \meta{num digits}
       and stores the result as a \idx{formattednumber} in
      the control sequence \meta{cs}}
  }
  % \DTLgtrunc
  \gcmd{DTL\-g\-trunc}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}\margm{num digits}}
     \desc{as \gls{DTLtrunc} but globally defines \meta{cs}}
  }
  % \DTLclip
  \gcmd{DTL\-clip}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{converts the \idx{formattednumber} to a 
      \idx{plainnumber}, clips it using \gls{dtlclip}
      and stores the result as a \idx{formattednumber} in
      the control sequence \meta{cs}}
  }
  % \DTLgclip
  \gcmd{DTL\-g\-clip}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num}}
     \desc{as \gls{DTLclip} but globally defines \meta{cs}}
  }
  % \DTLmin
  \gcmd{DTL\-min}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Sets \meta{cs} to the minimum of \meta{num1} and
      \meta{num2}, where the numbers are
      \idxpl{formattednumber}. The result will be a
      \idx{formattednumber}}
  }
  % \DTLgmin
  \gcmd{DTL\-g\-min}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{as \gls{DTLmin} but globally defines \meta{cs}}
  }
  % \DTLminall
  \gcmd{DTL\-min\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{Sets \meta{cs} to the minimum of all the 
      \idxpl{formattednumber} in the comma-separated \meta{num list}.
      The result will be a \idx{formattednumber}}
  }
  % \DTLgminall
  \gcmd{DTL\-g\-min\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{as \gls{DTLminall} but globally defines \meta{cs}}
  }
  % \DTLmax
  \gcmd{DTL\-max}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{Sets \meta{cs} to the maximum of \meta{num1} and
      \meta{num2}, where the numbers are
      \idxpl{formattednumber}. The result will be a
      \idx{formattednumber}}
  }
  % \DTLgmax
  \gcmd{DTL\-g\-max}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num1}\margm{num2}}
     \desc{as \gls{DTLmax} but globally defines \meta{cs}}
  }
  % \DTLmaxall
  \gcmd{DTL\-max\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{Sets \meta{cs} to the maximum of all the 
      \idxpl{formattednumber} in the comma-separated \meta{num list}.
      The result will be a \idx{formattednumber}}
  }
  % \DTLgmaxall
  \gcmd{DTL\-g\-max\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{as \gls{DTLmaxall} but globally defines \meta{cs}}
  }
  % \DTLmeanforall
  \gcmd{DTL\-mean\-for\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{Sets \meta{cs} to the mean (average) of all the 
      \idxpl{formattednumber} in the comma-separated \meta{num list}.
      The result will be a \idx{formattednumber}}
  }
  % \DTLgmeanforall
  \gcmd{DTL\-g\-mean\-for\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{as \gls{DTLmeanforall} but globally defines \meta{cs}}
  }
  % \DTLvarianceforall
  \gcmd{DTL\-variance\-for\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{Sets \meta{cs} to the variance of all the 
      \idxpl{formattednumber} in the comma-separated \meta{num list}.
      The result will be a \idx{formattednumber}}
  }
  % \DTLgvarianceforall
  \gcmd{DTL\-g\-variance\-for\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{as \gls{DTLvarianceforall} but globally defines \meta{cs}}
  }
  % \DTLsdforall
  \gcmd{DTL\-sd\-for\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{Sets \meta{cs} to the standard deviation of all the 
      \idxpl{formattednumber} in the comma-separated \meta{num list}.
      The result will be a \idx{formattednumber}}
  }
  % \DTLgsdforall
  \gcmd{DTL\-g\-sd\-for\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{num list}}
     \desc{as \gls{DTLsdforall} but globally defines \meta{cs}}
  }
  % \datatool_pad_trailing_zeros:Nn
  \gcmd{data\-tool\dsb pad\dsb trailing\dsb zeros:Nn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{tl-var} \margm{n}}
    \desc{pads \meta{tl-var} with 0s to ensure that there are a
    minimum of \meta{n} digits after the decimal point. The \meta{token
    list} should contain a \idx{plainnumber} (decimal or integer) before
    use. If the number in \meta{tl-var} was originally an
    integer, it will become a decimal with \meta{n} 0s after the
    decimal point. This command does nothing if \meta{n} is not
    greater than zero}
  }
  % \dtlforint
  \gcmd{dtl\-for\-int}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\meta{count-reg}\dequals\meta{start}\csfmt{to}\meta{end}\csfmt{step}\meta{inc}\csfmt{do}\margm{body}}
     \desc{integer iteration from \meta{start} to \meta{end}, incrementing by \meta{incr}
using \meta{count-reg} as the loop variable. This command is retained for backward-compatibility
but \LaTeX3 now provides integer step functions}
  }
  % \dtlgforint
  \gcmd{dtl\-g\-for\-int}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\meta{count-reg}\dequals\meta{start}\csfmt{to}\meta{end}\csfmt{step}\meta{inc}\csfmt{do}\margm{body}}
     \desc{as \gls{dtlforint} but globally sets the count register}
  }
  % dtlenvgforint ENVIRONMENT
  \genv{dtl\-env\-g\-for\-int}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\marg{\meta{count-reg}\dequals\meta{start}\csfmt{to}\meta{end}\csfmt{step}\meta{inc}}}
     \desc{environment form of \gls{dtlgforint} where leading and trailing spaces are trimmed from the environment body}
  }
  \genv{dtl\-env\-g\-for\-int*}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\marg{\meta{count-reg}\dequals\meta{start}\csfmt{to}\meta{end}\csfmt{step}\meta{inc}}}
     \desc{environment form of \gls{dtlgforint} where leading and trailing spaces aren't trimmed from the environment body}
  }
  % COMMANDS: CURRENCY
  % \DTLsetdefaultcurrency
  \gcmd{DTL\-set\-default\-currency}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{ISO or symbol}}
     \desc{sets the default currency}
     \field{seealso}{DTLdefcurrency}
  }
  % \DTLdefcurrency
  \gcmd{DTL\-def\-currency}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\oargm{fmt}\margm{ISO}\margm{symbol}\margm{string}}
     \desc{defines a new currency with associated ISO code, symbol
      and string equivalent. The optional argument indicates how the
      currency is formatted and defaults to \gls{dtlcurrdefaultfmt}
     if omitted}
  }
  % \datatool_def_currency:nnn
  \gfnsuffix{datatool\dsb def\dsb currency}{nnn}{nnV,nne}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{ISO} \margm{symbol} \margm{string}}
     \desc{shortcut that uses \gls{datatooldefcurrency:nnnn}
     with the first argument set to \gls{dtlcurrdefaultfmt}}
  }
  % \datatool_def_currency:nnnn
  \gfnsuffix{datatool\dsb def\dsb currency}{nnnn}{nnnV,nnne}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{fmt} \margm{ISO} \margm{symbol} \margm{string}}
     \desc{used by \gls{DTLdefcurrency} to define a new currency.
     Note that, unlike \gls{DTLdefcurrency}, no category code change
     is performed so make sure that the final argument contains the
     appropriate category code}
  }
  % \datatool_set_currency_symbol:nn
  \gfnsuffix{datatool\dsb set\dsb currency\dsb symbol}{nn}{nV,ne}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{ISO} \margm{symbol}}
     \desc{set the symbol to \meta{symbol} for the currency
identified by \meta{ISO}, which should already have been defined}
     \field{seealso}{datatoolsetcurrencysymbol:nn,DTLdefcurrency}
  }
  % \DTLcurr<ISO>
  \gcmdmeta{DTLcurr}{ISO}{}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{defined by \gls{DTLdefcurrency}}
  }
  % \DTLcurr
  \gcmd{DTL\-curr}%
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{ISO}}
     \desc{expands to \gls{DTLcurrISO} if defined or to
     \meta{ISO} otherwise}
  }
  % \DTLcurrXXX
  \gcmd{DTL\-curr\-XXX}%
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{generic currency XXX with symbol \textcurrency}
  }
  % \DTLcurrXBT
  \gcmd{DTL\-curr\-XBT}%
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{Bitcoin currency XBT with symbol \bitcoin}
  }
  % \DTLcurrEUR
  \gcmd{DTL\-curr\-EUR}%
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{Euro currency EUR with symbol \texteuro}
  }
  % \DTLdefaultEURcurrencyfmt
  \gcmd{DTL\-default\-EUR\-currency\-fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{EUR currency formatting command}
  }
  % \datatool<Region>SetCurrency
  % Label: datatoolRegionSetCurrency
  \gcmdmeta{data\-tool}{Region}{Set\-Currency}
  {
    \providedby{\ldfmeta{Region}}
    \desc{hook provided by region files to set the region's
currency. This hook should check the boolean \gls{ldatatoolregionsetcurrencybool}
and only set the currency if true}
  }
  % \l_datatool_region_set_currency_bool
  \gcmd{l\dsb data\-tool\dsb region\dsb set\dsb cur\-rency\dsb bool}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{boolean variable that corresponds to 
     the \numericopt{region-currency} option,
    which should be checked by region files}
  }
  % \datatool<Region>symbolprefix
  % Label: datatoolRegionsymbolprefix
  \gcmdmeta{data\-tool}{Region}{sym\-bol\-pre\-fix}
  {
    \providedby{\ldfmeta{Region}}
    \syntax{\margm{tag}}
    \desc{provided by region files that support a prefix for the
currency symbol (not all do). If supported, the region should
provide an option called \optfmt{currency\dhyphen symbol\dhyphen
prefix} which can show or hide the prefix. The prefix, if enabled,
is formatted with \gls{datatoolcurrencysymbolprefixfmt}}
  }
  % \datatool_currency_symbol_region_prefix:n
  \gcmd{data\-tool\dsb cur\-rency\dsb sym\-bol\dsb region\dsb pre\-fix:n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{tag}}
    \desc{for use by regions that support a prefix for the currency
symbol. The \meta{tag} should typically be the region code. This
command will encapsulate the \meta{tag} with 
\gls{datatoolcurrencysymbolprefixfmt}}
  }
  % \datatoolcurrencysymbolprefixfmt
  \gcmd{data\-tool\-cur\-rency\-sym\-bol\-pre\-fix\-fmt}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{tag}}
    \desc{used by \gls{datatoolcurrencysymbolregionprefix:n} to
format the tag. Simply expands to \meta{tag} by default}
  }
  % \l_datatool_currencysigns_regex
  \gcmd{l\dsb data\-tool\dsb currency\-signs\dsb regex}
   {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{a regular expression that matches supported currency
symbols}
   }
  % \l_datatool_cent_str
  % \l_datatool_cent_tl
  \gsymvar{cent}{the cent sign}{c}{}{}
  % \l_datatool_pound_str
  % \l_datatool_pound_tl
  \gsymvar{pound}{the pound sign}{L}{}{}
  % \l_datatool_lira_str
  % \l_datatool_lira_tl
  \gsymvar{lira}{the lira sign}{L}{}{}
  % \l_datatool_turkishlira_str
  % \l_datatool_turkishlira_tl
  \gsymvar{turkishlira}{the Turkish lira sign}{L}{}{}
  % \l_datatool_currency_str
  % \l_datatool_currency_tl
  \gsymvar{currency}{the currency sign}{\#}{}{}
  % \l_datatool_yen_str
  % \l_datatool_yen_tl
  \gsymvar{yen}{the yen sign}{Y}{}{}
  % \l_datatool_euro_str
  % \l_datatool_euro_tl
  \gsymvar{euro}{the euro sign}{E}{}{}
  % \l_datatool_baht_str
  % \l_datatool_baht_tl
  \gsymvar{baht}{the baht sign}{B}{}{}
  % \l_datatool_florin_str
  % \l_datatool_florin_tl
  \gsymvar{florin}{the florin sign}{f}{}{}
  % \l_datatool_ecu_str
  % \l_datatool_ecu_tl
  \gsymvar{ecu}{the ecu sign}{CE}{}{}
  % \l_datatool_colonsign_str
  % \l_datatool_colonsign_tl
  \gsymvar{colonsign}{the colon sign}{C}{}{}
  % \l_datatool_cruzerio_str
  % \l_datatool_cruzerio_tl
  \gsymvar{cruzerio}{the cruzerio sign}{Cr}{}{}
  % \l_datatool_frenchfranc_str
  % \l_datatool_frenchfranc_tl
  \gsymvar{frenchfranc}{the French franc sign}{F}{}{}
  % \l_datatool_mill_str
  % \l_datatool_mill_tl
  \gsymvar{mill}{the mill sign}{m}{}{}
  % \l_datatool_naira_str
  % \l_datatool_naira_tl
  \gsymvar{naira}{the naira sign}{N}{}{}
  % \l_datatool_peseta_str
  % \l_datatool_peseta_tl
  \gsymvar{peseta}{the peseta sign}{Pts}{}{}
  % \l_datatool_rupee_str
  % \l_datatool_rupee_tl
  \gsymvar{rupee}{the rupee sign}{Rs}{}{}
  % \l_datatool_indianrupee_str
  % \l_datatool_indianrupee_tl
  \gsymvar{indianrupee}{the Indian rupee sign}{R}{}{}
  % \l_datatool_won_str
  % \l_datatool_won_tl
  \gsymvar{won}{the won sign}{W}{}{}
  % \l_datatool_shekel_str
  % \l_datatool_shekel_tl
  \gsymvar{shekel}{the shekel sign}{S}{}{}
  % \l_datatool_dong_str
  % \l_datatool_dong_tl
  \gsymvar{dong}{the dong sign}{d}{}{}
  % \l_datatool_kip_str
  % \l_datatool_kip_tl
  \gsymvar{kip}{the kip sign}{K}{}{}
  % \l_datatool_tugrik_str
  % \l_datatool_tugrik_tl
  \gsymvar{tugrik}{the tugrik sign}{T}{}{}
  % \l_datatool_drachma_str
  % \l_datatool_drachma_tl
  \gsymvar{drachma}{the drachma sign}{Dr}{}{}
  % \l_datatool_germanpenny_str
  % \l_datatool_germanpenny_tl
  \gsymvar{germanpenny}{the Germany penny sign}{p}{}{}
  % \l_datatool_peso_str
  % \l_datatool_peso_tl
  \gsymvar{peso}{the peso sign}{P}{}{}
  % \l_datatool_guarani_str
  % \l_datatool_guarani_tl
  \gsymvar{guarani}{the guarani sign}{G.}{}{}
  % \l_datatool_austral_str
  % \l_datatool_austral_tl
  \gsymvar{austral}{the austral sign}{A}{}{}
  % \l_datatool_hryvnia_str
  % \l_datatool_hryvnia_tl
  \gsymvar{hryvnia}{the hryvnia sign}{S}{}{}
  % \l_datatool_cedi_str
  % \l_datatool_cedi_tl
  \gsymvar{cedi}{the cedi sign}{S}{}{}
  % \l_datatool_livretournois_str
  % \l_datatool_livretournois_tl
  \gsymvar{livretournois}{the livre tournois sign}{lt}{}{}
  % \l_datatool_spesmilo_str
  % \l_datatool_spesmilo_tl
  \gsymvar{spesmilo}{the spesmilo sign}{Sm}{}{}
  % \l_datatool_tenge_str
  % \l_datatool_tenge_tl
  \gsymvar{tenge}{the tenge sign}{T}{}{}
  % \l_datatool_nordicmark_str
  % \l_datatool_nordicmark_tl
  \gsymvar{nordicmark}{the Nordic mark sign}{M}{}{}
  % \l_datatool_manat_str
  % \l_datatool_manat_tl
  \gsymvar{manat}{the manat sign}{M}{}{}
  % \l_datatool_ruble_str
  % \l_datatool_ruble_tl
  \gsymvar{ruble}{the ruble sign}{R}{}{}
  % \l_datatool_lari_str
  % \l_datatool_lari_tl
  \gsymvar{lari}{the lari sign}{L}{}{}
  % \l_datatool_bitcoin_str
  % \l_datatool_bitcoin_tl
  \gsymvar{bitcoin}{the bitcoin sign}{L}{}{}
  % \l_datatool_som_str
  % \l_datatool_som_tl
  \gsymvar{som}{the som sign}{c}{}{}
  % \datatoolGBcurrencyfmt
  \gcmd{data\-tool\-GB\-currency\-fmt}
  {
     \providedby{\ldf{GB}}
     \syntax{\margm{symbol}\margm{value}}
     \desc{currency format for GBP (requires \sty{datatool-regions},
      which is not included with \sty{datatool})}
  }
  % \datatoolSetCurrencySort
  \gcmd{data\-tool\-Set\-Currency\-Sort}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{locally redefines common currency commands (for sorting)}
  }
  % \dtlcurrdefaultfmt
  \gcmd{dtl\-curr\-default\-fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{symbol}\margm{value}}
     \desc{default currency format (initialised to use
     \gls{dtlcurrprefixfmt})}
  }
  % \dtlcurrprefixfmt
  \gcmd{dtl\-curr\-prefix\-fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{symbol}\margm{value}}
     \desc{formats the currency with the symbol as a prefix
       using \gls{datatoolprefixadjustsign:nnn}}
  }
  % \datatool_prefix_adjust_sign:nnn
  \gcmd{data\-tool\dsb prefix\dsb adjust\dsb sign:nnn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{symbol} \margm{sep} \margm{value}}
     \desc{designed for use in \gls{dtlcurrprefixfmt}
      this tests if \meta{value} starts with a plus (\code{+})
      or minus (\code{-}) and, if so, shifts the sign in front of
      the symbol and encapsulates the sign with 
      \gls{datatooladjustsignfmt:n}}
  }
  % \datatool_adjust_sign_fmt:n
  \gcmd{data\-tool\dsb adjust\dsb sign\dsb fmt:n}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{sign}}
     \desc{used by \gls{datatoolprefixadjustsign:nnn} and
     \gls{datatoolsuffixadjustsign:nnn} to format the sign}
  }
  % \dtlcurrsuffixfmt
  \gcmd{dtl\-curr\-suffix\-fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{symbol}\margm{value}}
     \desc{formats the currency with the symbol as a suffix
       using \gls{datatoolsuffixadjustsign:nnn}}
  }
  % \datatool_suffix_adjust_sign:nnn
  \gcmd{data\-tool\dsb suffix\dsb adjust\dsb sign:nnn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{symbol} \margm{sep} \margm{value}}
     \desc{designed for use in \gls{dtlcurrsuffixfmt}
      this tests if \meta{value} starts with a plus (\code{+})
      or minus (\code{-}) and, if so, encapsulates it with 
      \gls{datatooladjustsignfmt:n}. The separator and symbol are
placed after the value}
  }
  % \dtlcurrfmtsep
  \gcmd{dtl\-curr\-fmt\-sep}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{separator used by currency formats}
  }
  % \dtlcurrfmtsymsep
  \gcmd{dtl\-curr\-fmt\-sym\-sep}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \initvalempty
     \note{region-sensitive}
     \desc{used by \gls{dtlcurrfmtsep} when \gls{DTLcurrCodeOrSymOrChar}
      expands to either its second or third argument}
  }
  % \DTLnewcurrencysymbol
  \gcmd{DTL\-new\-currency\-symbol}
  {
    \providedby{\sty{datatool-base}}
    \syntax{\margm{symbol}}
    \desc{adds \meta{symbol} to the list of known currencies}
  }
  % \DTLCurrencyCode
  \gcmd{DTL\-Currency\-Code}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the ISO code associated with the default currency}
  }
  % \DTLCurrencySymbol
  \gcmd{DTL\-Currency\-Symbol}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to the internal command used to store the default
currency symbol}
  }
  % \DTLcurrCodeOrSymOrChar
  \gcmd{DTL\-curr\-Code\-Or\-Sym\-Or\-Char}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{ISO}\margm{symbol}\margm{character}}
     \desc{expands to one of its arguments (\meta{symbol} by default)}
  }
  % \DTLcurrSym
  \gcmd{DTL\-curr\-Sym}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{ISO}}
     \desc{expands to the symbol associated with the currency
identified by \meta{ISO}, or nothing if not defined}
  }
  % \DTLcurrChar
  \gcmd{DTL\-curr\-Char}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{ISO}}
     \desc{expands to the currency character associated with the currency
identified by \meta{ISO}, or nothing if not defined}
  }
  % \DTLcurrStr
  \gcmd{DTL\-curr\-Str}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{ISO}}
     \desc{expands to the detokenised string associated with the currency
identified by \meta{ISO}, or nothing if not defined}
  }
  % \DTLfmtcurrency
  \gcmd{DTL\-fmt\-currency}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{symbol}\margm{value}}
     \desc{formats \meta{value} as a currency with the given symbol}
  }
  % \DTLfmtcurr
  \gcmd{DTL\-fmt\-curr}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{currency-code}\margm{value}}
     \desc{formats \meta{value} as a currency according to the given
currency code (which should already have been defined)}
  }
  % \DTLcurrency
  \gcmd{DTL\-currency}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{value}}
     \desc{formats \meta{value} as a currency using
     \gls{DTLfmtcurrency} with the default currency symbol}
  }
  % \DTLCurrentLocaleCurrencyDP
  \gcmd{DTL\-Current\-Locale\-Currency\-DP}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \initval{2}
    \desc{the expansion text should be either empty (no rounding) or the number of
    decimal places that \gls{DTLdecimaltocurrency} should round to.
This command should be redefined by the appropriate localisation hooks}
  }
  % COMMANDS: TEMPORAL
  % \DataToolDateFmt
  \gcmd{Data\-Tool\-Date\-Fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{year}\margm{month}\margm{day}\margm{dow}}
     \desc{inserted by \datetimeoptval{parse}{auto-format} to format
a date. The arguments should all be integers, but \meta{dow} may be
empty. By default, simply uses \gls{DTLCurrentLocaleFormatDate}}
  }
  % \DTLCurrentLocaleFormatDate
  \gcmd{DTL\-Current\-Locale\-Format\-Date}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{year}\margm{month}\margm{day}\margm{dow}}
     \desc{this command should be redefined by the applicable localisation hook.
     The arguments should all be integers, but \meta{dow} may be empty}
  }
  % \DataToolTimeFmt
  \gcmd{Data\-Tool\-Time\-Fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{hour}\margm{minute}\margm{second}}
     \desc{inserted by \datetimeoptval{parse}{auto-format} to format
a time. The arguments should all be integers, but \meta{second} may
be empty. By default, simply uses \gls{DTLCurrentLocaleFormatTime}}
  }
  % \DTLCurrentLocaleFormatTime
  \gcmd{DTL\-Current\-Locale\-Format\-Time}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{hour}\margm{minute}\margm{second}}
     \desc{this command should be redefined by the applicable localisation hook.
     The arguments should all be integers, but \meta{second} may
     be empty}
  }
  % \DataToolTimeZoneFmt
  \gcmd{Data\-Tool\-Time\-Zone\-Fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{tzh}\margm{tzm}}
     \desc{inserted by \datetimeoptval{parse}{auto-format} to format
a time zone offset. 
The arguments should all be integers. By default, simply uses
\gls{DTLCurrentLocaleFormatTimeZone}}
  }
  % \DTLCurrentLocaleFormatTimeZone
  \gcmd{DTL\-Current\-Locale\-Format\-Time\-Zone}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{tzh}\margm{tzm}}
     \desc{this command should be redefined by the applicable localisation hook. 
The arguments should all be integers}
  }
  % \DataToolDateTimeFmt
  \gcmd{Data\-Tool\-Date\-Time\-Fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{date-specs}\margm{time-specs}\margm{offset-specs}}
     \desc{inserted by \datetimeoptval{parse}{auto-format} to format
timestamps. The arguments may either be empty or the appropriate
arguments to pass to \gls{DataToolDateFmt} (\meta{date-specs} should
be \margm{year}\margm{month}\margm{day}\margm{dow}), \gls{DataToolTimeFmt}
(\meta{time-specs} should be \margm{hour}\margm{minute}\margm{second})
and \gls{DataToolTimeZoneFmt}
(\meta{offset-specs} should be \margm{tzh}\margm{tzm})}
     \field{seealso}{DataToolTimeStampFmtSep}
  }
  % \DataToolTimeStampNoZoneFmt
  \gcmd{Data\-Tool\-Time\-Stamp\-No\-Zone\-Fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{year}\margm{month}\margm{day}\margm{dow}\margm{hour}\margm{minute}\margm{second}}
     \desc{used by \gls{DataToolDateTimeFmt} if
      \margm{date-specs} and \margm{time-specs} are both not empty,
      but \meta{offset-specs} is empty. By default, simply uses
      \gls{DTLCurrentLocaleFormatTimeStampNoZone}}
  }
  % \DataToolTimeStampWithZoneFmt
  \gcmd{Data\-Tool\-Time\-Stamp\-With\-Zone\-Fmt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{year}\margm{month}\margm{day}\margm{dow}\margm{hour}\margm{minute}\margm{second}\margm{tzh}\margm{tzm}}
     \desc{used by \gls{DataToolDateTimeFmt} if
      \margm{date-specs} and \margm{time-specs} and
      \meta{offset-specs} are all not empty. By default, simply uses
      \gls{DTLCurrentLocaleFormatTimeStampWithZone}}
  }
  % \DTLCurrentLocaleFormatTimeStampWithZone
  \gcmd{DTL\-Current\-Locale\-Format\-Time\-Stamp\-With\-Zone}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{year}\margm{month}\margm{day}\margm{dow}\margm{hour}\margm{minute}\margm{second}\margm{tzh}\margm{tzm}}
     \desc{this command should be redefined by the applicable localisation hook. 
The arguments should all be integers, but \meta{dow} and
\meta{second} may be empty}
  }
  % \DTLCurrentLocaleFormatTimeStampNoZone
  \gcmd{DTL\-Current\-Locale\-Format\-Time\-Stamp\-No\-Zone}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{year}\margm{month}\margm{day}\margm{dow}\margm{hour}\margm{minute}\margm{second}}
     \desc{this command should be redefined by the applicable localisation hook. 
The arguments should all be integers, but \meta{dow} and
\meta{second} may be empty}
  }
  % \DataToolTimeStampFmtSep
  \gcmd{Data\-Tool\-Time\-Stamp\-Fmt\-Sep}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{used by the default timestamp formats to separate the date
and time if both provided. By default, simply expands to
\gls{DTLCurrentLocaleTimeStampFmtSep}}
  }
  % \DTLCurrentLocaleTimeStampFmtSep
  \gcmd{DTL\-Current\-Locale\-Time\-Stamp\-Fmt\-Sep}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \initval{\visiblespace}
     \desc{this command should be redefined by the applicable localisation hook}
  }
  % \datatool<Region>SetTemporalParsers
  \gcmdmeta{datatool}{Region}{Set\-Temporal\-Parsers}
  {
    \providedby{\ldfmeta{tag}}
    \desc{hook provided by localisation files that support temporal
parsing}
  }
  % \datatool<Region>SetTemporalFormatters
  \gcmdmeta{datatool}{Region}{Set\-Temporal\-Formatters}
  {
    \providedby{\ldfmeta{tag}}
    \desc{hook provided by localisation files that support temporal
formatting}
  }
  % COMMANDS: LOCALISATION
  % \DTLsetLocaleOptions
  \gcmds{DTL\-set\-Locale\-Options}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\oargm{parent module(s)}\margm{module(s)}\marg{\keyvallist}}
     \desc{set localisation options for all parent\slash module
      combinations}
  }
  % \datatool_set_locale_options:nn
  \gcmd{data\-tool\dsb set\dsb locale\dsb options:nn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{module(s)}\marg{\keyvallist}}
     \desc{sets localisation options for each module}
  }
  % \datatool_locale_define_keys:nn
  \gcmd{data\-tool\dsb locale\dsb define\dsb keys:nn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{module}\margm{\keyvallist}}
     \desc{define keys for localisation support}
  }
  % \l_datatool_current_region_tl
  \gcmd{l\dsb data\-tool\dsb current\dsb region\dsb tl}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \initvalempty
     \desc{each region file should ensure that the captions hook
      sets this token list variable to expand to the region's ISO
code}
  }
  % \l_datatool_current_language_tl
  \gcmd{l\dsb datatool\dsb current\dsb language\dsb tl}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \initvalempty
     \desc{each language file should ensure that the captions hook
      sets this token list variable to expand to the language's ISO
code}
  }
  % \DTLresetLanguage
  \gcmd{DTL\-re\-set\-Language}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{resets all language (not region) sensitive commands back
to their default definitions (but only those defined by
\sty{datatool-base}). Commands provided by supplementary packages
are not affected}
  }
  % \DTLresetRegion
  \gcmd{DTL\-re\-set\-Region}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{resets all region sensitive commands back
to their default definitions}
  }
  % \DTL<tag>LocaleHook
  % Label: DTLtagLocaleHook
  \gcmdmeta{DTL}{tag}{LocaleHook}
  {
    \providedby{\ldfmeta{tag}}
    \desc{hook provided by localisation files, in particular, the
    region hook control sequence name needs to be in this form
    for \sty{datatool-base} to add it to the captions hook}
  }
  % COMMANDS: CONDITIONALS
  % \ifDTLlistskipempty
  \gcond{if\-DTL\-list\-skip\-empty}
  {
     \initval{\cmd{iftrue}}
     \providedby{\sty{datatool-base} v2.31+}
     \desc{indicates whether or not to omit empty elements 
     in \idx{CSV} list arguments (see \sectionref{sec:csvlists}).
     This conditional can now be set with the \listsopt{skip-empty}
     option in the \opt{lists} setting}
  }
  % \DTLlistskipemptytrue
  \gcmd{DTL\-list\-skip\-empty\-true}
  {
     \providedby{\sty{datatool-base} v2.31+}
     \desc{sets \gls{ifDTLlistskipempty} to true}
  }
  % \DTLlistskipemptyfalse
  \gcmd{DTL\-list\-skip\-empty\-false}
  {
     \providedby{\sty{datatool-base} v2.31+}
     \desc{sets \gls{ifDTLlistskipempty} to false}
  }
  % \ifdtlcompareskipcs
  \gcond{if\-dtl\-compare\-skip\-cs}
  {
     \initval{\cmd{iffalse}}
     \providedby{\sty{datatool-base} v2.32+}
     \desc{indicates whether or not to skip control sequences in
     \gls{dtlcompare} and \gls{dtlicompare} if 
     \compareoptval{expand-cs}{false}
     (see \sectionref{sec:compare}). This conditional can now be set
     with the \compareopt{skip-cs} option in the \opt{compare} setting}
  }
  % \dtlcompareskipcstrue
  \gcmd{dtl\-compare\-skip\-cs\-true}
  {
     \providedby{\sty{datatool-base} v2.32+}
     \desc{sets \gls{ifdtlcompareskipcs} to true}
  }
  % \dtlcompareskipcsfalse
  \gcmd{dtl\-compare\-skip\-cs\-false}
  {
     \providedby{\sty{datatool-base} v2.32+}
     \desc{sets \gls{ifdtlcompareskipcs} to false}
  }
  % \ifDTLnewdbonload
  \gcond{if\-DTL\-new\-db\-on\-load}
  {
     \initval{\cmd{iftrue}}
     \providedby{\sty{datatool-base} v2.13+}
     \deprecated
     \desc{if true, create a new database when loading a
     \idx{CSV}/\idx{TSV} file. Use \ioopt{load-action} option instead}
  }
  % \DTLifnumerical
  \gcmd{DTL\-if\-numerical}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}\margm{true}\margm{false}}
     \desc{does \meta{true} if the first argument \meta{arg} is numerical
     (a \idx{formattednumber} that's an integer, decimal or currency)
     otherwise does \meta{false}}
  }
  % \DTLifreal
  \gcmd{DTL\-if\-real}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}\margm{true}\margm{false}}
     \desc{does \meta{true} if the first argument \meta{arg} is a
     real (decimal) \idx{formattednumber} (not an integer or
     currency) otherwise does \meta{false}}
  }
  % \DTLifint
  \gcmd{DTL\-if\-int}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}\margm{true}\margm{false}}
     \desc{does \meta{true} if the first argument \meta{arg} is a
     an integer \idx{formattednumber} (not a decimal or
     currency) otherwise does \meta{false}}
  }
  % \DTLifcurrency
  \gcmd{DTL\-if\-currency}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}\margm{true}\margm{false}}
     \desc{does \meta{true} if the first argument \meta{arg} is a
     currency \idx{formattednumber} (not an integer or
     decimal) otherwise does \meta{false}}
  }
  % \DTLifstring
  \gcmd{DTL\-if\-string}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}\margm{true}\margm{false}}
     \desc{does \meta{true} if the first argument \meta{arg} is a
     string (not numerical) otherwise does \meta{false}}
  }
  % \DTLiftemporal
  \gcmd{DTL\-if\-temporal}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{arg}\margm{true}\margm{false}}
     \desc{does \meta{true} if the first argument \meta{arg} is a
     temporal value otherwise does \meta{false}}
  }
  % \DTLifcurrencyunit
  \gcmd{DTL\-if\-currency\-unit}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}\margm{symbol}\margm{true}\margm{false}}
     \desc{does \meta{true} if the first argument \meta{arg} is a
     currency \idx{formattednumber} (not an integer or
     decimal) and has the given currency \meta{symbol} otherwise does \meta{false}}
  }
  % \DTLifcasedatatype
  \gcmd{DTL\-if\-case\-data\-type}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}\margm{string case}\margm{int
    case}\margm{real case}\margm{currency case}}
     \desc{parses the first argument \meta{arg} and does
     \meta{string case} if \meta{arg} is a string, 
     \meta{int case} if \meta{arg} is an integer, 
     \meta{real case} if \meta{arg} is a real (decimal), or 
     \meta{currency case} if \meta{arg} is currency} 
  }
  % \dtlifnumeq
  \gcmd{dtl\-if\-num\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num1}\margm{num2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{num1} equals \meta{num2}
       otherwise does \meta{false}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtlifnumlt
  \gcmd{dtl\-if\-num\-lt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num1}\margm{num2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{num1} is less than \meta{num2}
       otherwise does \meta{false}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtlifnumgt
  \gcmd{dtl\-if\-num\-gt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num1}\margm{num2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{num1} is greater than \meta{num2}
       otherwise does \meta{false}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtlifnumopenbetween
  \gcmd{dtl\-if\-num\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if $\meta{min} < \meta{num} < \meta{max}$
       otherwise does \meta{false}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \DTLifFPopenbetween
  \gcmd{DTL\-if\-FP\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{synonym of \gls{dtlifnumopenbetween}}
     \field{see}{dtlifnumopenbetween}
  }
  % \dtlifintopenbetween
  \gcmd{dtl\-if\-int\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if $\meta{min} < \meta{num} < \meta{max}$
       otherwise does \meta{false}, where the numbers are
       \idx{plainnumber} integers}
  }
  % \DTLifFPclosedbetween
  \gcmd{DTL\-if\-FP\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{synonym of \gls{dtlifnumclosedbetween}}
     \field{see}{dtlifnumclosedbetween}
  }
  % \dtlifnumclosedbetween
  \gcmd{dtl\-if\-num\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if $\meta{min} \leq \meta{num} \leq \meta{max}$
       otherwise does \meta{false}, where the numbers are
       \idxpl{plainnumber}}
  }
  % \dtlifintclosedbetween
  \gcmd{dtl\-if\-int\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if $\meta{min} \leq \meta{num} \leq \meta{max}$
       otherwise does \meta{false}, where the numbers are
       \idx{plainnumber} integers}
  }
  % \DTLifnumeq
  \gcmd{DTL\-if\-num\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num1}\margm{num2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{num1} equals \meta{num2}
       otherwise does \meta{false}, where the numbers are
       \idxpl{formattednumber}}
  }
  % \DTLifnumlt
  \gcmd{DTL\-if\-num\-lt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num1}\margm{num2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{num1} is less than \meta{num2}
       otherwise does \meta{false}, where the numbers are
       \idxpl{formattednumber}}
  }
  % \DTLifnumgt
  \gcmd{DTL\-if\-num\-gt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num1}\margm{num2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{num1} is greater than \meta{num2}
       otherwise does \meta{false}, where the numbers are
       \idxpl{formattednumber}}
  }
  % \DTLifnumopenbetween
  \gcmd{DTL\-if\-num\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if $\meta{min} < \meta{num} < \meta{max}$
       otherwise does \meta{false}, where the numbers are
       \idxpl{formattednumber}}
  }
  % \DTLifnumclosedbetween
  \gcmd{DTL\-if\-num\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if $\meta{min} \leq \meta{num} \leq \meta{max}$
       otherwise does \meta{false}, where the numbers are
       \idxpl{formattednumber}}
  }
  % \DTLnumcompare
  \gcmd{DTL\-num\-compare}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{count-reg}\margm{num1}\margm{num2}}
     \desc{compares \meta{num1} and \meta{num2}, where the numbers are
       \idxpl{formattednumber} or \idxpl{datumcs}, and sets the count register (integer variable)
       \meta{count-reg} to $-1$ if \meta{num1} is less than \meta{num2}, to 0 if
       \meta{num1} and \meta{num2} are equal or to $+1$ if \meta{num1} is greater than \meta{num2}}
  }
  % \DTLifstringeq
  \gcmds{DTL\-if\-string\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{str1}\margm{str2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{str1} is lexicographically equal to \meta{str2}
       otherwise does \meta{false}. The starred version ignores case}
  }
  % \DTLifstringlt
  \gcmds{DTL\-if\-string\-lt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{str1}\margm{str2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{str1} is lexicographically less than \meta{str2}
       otherwise does \meta{false}. The starred version ignores case}
  }
  % \DTLifstringgt
  \gcmds{DTL\-if\-string\-gt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{str1}\margm{str2}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{str1} is lexicographically 
      greater than \meta{str2} otherwise does \meta{false}.
      The starred version ignores case}
  }
  % \DTLifstringopenbetween
  \gcmds{DTL\-if\-string\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{str}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{str} lies between \meta{min}
     and \meta{max}, but is not equal to
     \meta{min} or \meta{max}, otherwise does \meta{false}}
  }
  % \DTLifstringclosedbetween
  \gcmds{DTL\-if\-string\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{str}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{str} lies between \meta{min}
     and \meta{max}, inclusive, otherwise does \meta{false}}
  }
  % \DTLifSubString
  \gcmds{DTL\-if\-Sub\-String}
  {
     \providedby{\sty{datatool-base} v1.01+}
     \syntax{\margm{string}\margm{fragment}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{fragment} is a substring of
     \meta{string} otherwise does \meta{false}. The starred version
     is case-insensitive}
  }
  % \DTLifStartsWith
  \gcmds{DTL\-if\-Starts\-With}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{string}\margm{fragment}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{string} starts with \meta{fragment} 
     otherwise does \meta{false}. The starred version
     is case-insensitive}
  }
  % \DTLifEndsWith
  \gcmds{DTL\-if\-Ends\-With}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{string}\margm{fragment}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{string} ends with \meta{fragment} 
     otherwise does \meta{false}. The starred version
     is case-insensitive}
  }
  % \DTLifAllUpperCase
  \gcmd{DTL\-if\-All\-Upper\-Case}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{string}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{string} is all in 
     \idx{uppercase} (disregarding punctuation and spaces)
     otherwise does \meta{false}}
  }
  % \DTLifAllLowerCase
  \gcmd{DTL\-if\-All\-Lower\-Case}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{string}\margm{true}\margm{false}}
     \desc{Does \meta{true} if \meta{string} is all in 
     \idx{lowercase} (disregarding punctuation and spaces)
     otherwise does \meta{false}}
  }
  % \DTLifinlist
  \gcmd{DTL\-if\-in\-list}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{element}\margm{list}\margm{true}\margm{false}}
     \desc{does \meta{true} if \meta{element} is in the \idx{CSV}
     \meta{list} otherwise does \meta{false}. One level \idx{expansion}
     performed on \meta{list} but not \meta{element}}
  }
  % \DTLifeq
  \gcmds{DTL\-if\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}\margm{true}\margm{false}}
     \desc{Uses either \gls{DTLifnumeq} or \gls{DTLifstringeq}
     depending on the data type of both \meta{arg1} and \meta{arg2}.
     The starred version ignores case if \gls{DTLifstringeq} is required}
  }
  % \DTLiflt
  \gcmds{DTL\-if\-lt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}\margm{true}\margm{false}}
     \desc{Uses either \gls{DTLifnumlt} or \gls{DTLifstringlt}
     depending on the data type of both \meta{arg1} and \meta{arg2}.
     The starred version ignores case if \gls{DTLifstringlt} is required}
  }
  % \DTLifgt
  \gcmds{DTL\-if\-gt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}\margm{true}\margm{false}}
     \desc{Uses either \gls{DTLifnumgt} or \gls{DTLifstringgt}
     depending on the data type of both \meta{arg1} and \meta{arg2}.
     The starred version ignores case if \gls{DTLifstringgt} is required}
  }
  % \DTLifopenbetween
  \gcmds{DTL\-if\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{value}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Uses either \gls{DTLifnumopenbetween} or \gls{DTLifstringopenbetween}
     depending on the data type of \meta{value}, \meta{min} and \meta{max}.
     The starred version ignores case if \gls{DTLifstringopenbetween} is required}
  }
  % \DTLifclosedbetween
  \gcmds{DTL\-if\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{value}\margm{min}\margm{min}\margm{true}\margm{false}}
     \desc{Uses either \gls{DTLifnumclosedbetween} or
     \gls{DTLifstringclosedbetween} depending on the data type of
     \meta{value}, \meta{min} and \meta{max}.
     The starred version ignores case if \gls{DTLifstringclosedbetween} is required}
  }
  % \DTLisint
  \gcmd{DTL\-is\-int}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}}
     \desc{as \gls{DTLifint} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisreal
  \gcmd{DTL\-is\-real}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}}
     \desc{as \gls{DTLifreal} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLiscurrency
  \gcmd{DTL\-is\-currency}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}}
     \desc{as \gls{DTLifcurrency} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLiscurrencyunit
  \gcmd{DTL\-is\-currency\-unit}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}}
     \desc{as \gls{DTLifcurrencyunit} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisnumerical
  \gcmd{DTL\-is\-numerical}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}}
     \desc{as \gls{DTLifnumerical} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisstring
  \gcmd{DTL\-is\-string}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg}}
     \desc{as \gls{DTLifstring} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLislt
  \gcmd{DTL\-is\-lt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as the unstarred \gls{DTLiflt} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisilt
  \gcmd{DTL\-is\-i\-lt}
  {
     \providedby{\sty{datatool-base} v1.01+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as the starred \starredcs{DTLiflt} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisgt
  \gcmd{DTL\-is\-gt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as the unstarred \gls{DTLifgt} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisigt
  \gcmd{DTL\-is\-i\-gt}
  {
     \providedby{\sty{datatool-base} v1.01+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as the starred \starredcs{DTLifgt} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLiseq
  \gcmd{DTL\-is\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as the unstarred \gls{DTLifeq} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisieq
  \gcmd{DTL\-is\-i\-eq}
  {
     \providedby{\sty{datatool-base} v1.01+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as the starred \starredcs{DTLifeq} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisnumlt
  \gcmd{DTL\-is\-num\-lt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as \gls{DTLifnumlt} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisFPlt
  \gcmd{DTL\-is\-FP\-lt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{synonym of \gls{DTLisnumlt}}
     \field{see}{DTLisnumlt}
  }
  % \DTLisnumgt
  \gcmd{DTL\-is\-num\-gt}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as \gls{DTLifnumgt} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisFPgt
  \gcmd{DTL\-is\-FP\-gt}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{synonym of \gls{DTLisnumgt}}
     \field{see}{DTLisnumgt}
  }
  % \DTLisnumeq
  \gcmd{DTL\-is\-num\-eq}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{as \gls{DTLifnumeq} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisFPeq
  \gcmd{DTL\-is\-FP\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{synonym of \gls{DTLisnumeq}}
     \field{see}{DTLisnumeq}
  }
  % \DTLisnumlteq
  \gcmd{DTL\-is\-num\-lt\-eq}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{numerical \qt{less than or equal to} for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisFPlteq
  \gcmd{DTL\-is\-FP\-lt\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{synonym of \gls{DTLisnumlteq}}
     \field{see}{DTLisnumeq}
  }
  % \DTLisnumgteq
  \gcmd{DTL\-is\-num\-gt\-eq}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{numerical \qt{less than or equal to} for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisFPgteq
  \gcmd{DTL\-is\-FP\-gt\-eq}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{arg1}\margm{arg2}}
     \desc{synonym of \gls{DTLisnumgteq}}
     \field{see}{DTLisnumeq}
  }
  % \DTLisclosedbetween
  \gcmd{DTL\-is\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{as the unstarred \gls{DTLifclosedbetween} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisiclosedbetween
  \gcmd{DTL\-is\-i\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{as the starred \starredcs{DTLifclosedbetween} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisnumclosedbetween
  \gcmd{DTL\-is\-num\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{as \gls{DTLifnumclosedbetween} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisFPclosedbetween
  \gcmd{DTL\-is\-FP\-closed\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{synonym of \gls{DTLisnumclosedbetween}}
     \field{see}{DTLisnumclosedbetween}
  }
  % \DTLisopenbetween
  \gcmd{DTL\-is\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{as the unstarred \gls{DTLifopenbetween} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisiopenbetween
  \gcmd{DTL\-is\-i\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{as the starred \starredcs{DTLifopenbetween} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisnumopenbetween
  \gcmd{DTL\-is\-num\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{as \gls{DTLifnumopenbetween} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisFPopenbetween
  \gcmd{DTL\-is\-FP\-open\-between}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{num}\margm{min}\margm{min}}
     \desc{synonym of \gls{DTLisnumopenbetween}}
     \field{see}{DTLisnumopenbetween}
  }
  % \DTLisSubString
  \gcmd{DTL\-is\-Sub\-String}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{string}\margm{fragment}}
     \desc{as \gls{DTLifSubString} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisiSubString
  \gcmd{DTL\-is\-i\-Sub\-String}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{string}\margm{fragment}}
     \desc{as \starredcs{DTLifSubString} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisPrefix
  \gcmd{DTL\-is\-Prefix}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{string}\margm{fragment}}
     \desc{as \gls{DTLifStartsWith} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisiPrefix
  \gcmd{DTL\-is\-i\-Prefix}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{string}\margm{fragment}}
     \desc{as \starredcs{DTLifStartsWith} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisSuffix
  \gcmd{DTL\-is\-Suffix}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{string}\margm{fragment}}
     \desc{as \gls{DTLifEndsWith} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisiSuffix
  \gcmd{DTL\-is\-i\-Suffix}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{string}\margm{fragment}}
     \desc{as \starredcs{DTLifEndsWith} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \DTLisinlist
  \gcmd{DTL\-is\-in\-list}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{element}\margm{list}}
     \desc{as \gls{DTLifinlist} but for use in the conditional part of
     commands like \gls{ifthenelse}}
  }
  % \c_datatool_empty_datum_tl
  \gcmd{c\dsb data\-tool\dsb empty\dsb datum\dsb tl}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{constant \idx{datumcs} representing an empty value with the
unknown data type}
  }
  % \dtlnovalue
  \gcmd{dtl\-no\-value}
  {
    \providedby{\sty{datatool-base}}
    \desc{used to represent a null value (see
\sectionref{sec:null}). Prior to version 3.0, this was defined by
\sty{datatool} rather than \sty{datatool-base}}
  }
  % \DTLstringnull
  \gcmd{DTL\-string\-null}
  {
    \providedby{\sty{datatool-base}}
    \desc{used to represent a null value for a string column (see
\sectionref{sec:null}). Prior to version 3.0, this was defined by
\sty{datatool} rather than \sty{datatool-base}}
  }
  % \DTLnumbernull
  \gcmd{DTL\-number\-null}
  {
    \providedby{\sty{datatool-base}}
    \desc{used to represent a null value for a numeric column (see
\sectionref{sec:null}). Prior to version 3.0, this was defined by
\sty{datatool} rather than \sty{datatool-base}}
  }
  % \DTLifnull
  \gcmd{DTL\-if\-null}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{arg}\margm{true}\margm{false}}
    \desc{expands to \meta{true} if the first argument represents null (see
     \sectionref{sec:null}), or to \meta{false} otherwise}
  }
  % \DTLifnullorempty
  \gcmd{DTL\-if\-null\-or\-empty}
  {
    \providedby{\sty{datatool} v2.20+}
    \syntax{\margm{arg}\margm{true}\margm{false}}
    \desc{expands to \meta{true} if the first argument is empty or represents null (see
     \sectionref{sec:null}), or to \meta{false} otherwise}
  }
  % \datatool_if_null:NTF and \datatool_if_null_p:N
  \gexplpred{datatool\dsb if\dsb null}{N}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{tl var} \TFsyntax}
    \desc{tests if \meta{tl var} represents null (see
     \sectionref{sec:null})}
  }
  % \datatool_if_null_or_empty:NTF and \datatool_if_null_or_empty_p:N
  \gexplpred{datatool\dsb if\dsb null\dsb or\dsb empty}{N}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{tl var} \TFsyntax}
    \desc{tests if \meta{tl var} is empty or represents null (see
     \sectionref{sec:null})}
  }
  % \datatool_if_null:nTF
  \gexplcond{datatool\dsb if\dsb null}{n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{tl} \TFsyntax}
    \desc{tests if \meta{tl} represents null (see
     \sectionref{sec:null})}
  }
  % \datatool_if_null_or_empty:nTF
  \gexplcond{datatool\dsb if\dsb null\dsb or\dsb empty}{n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{tl} \TFsyntax}
    \desc{tests if \meta{tl} is empty or represents null (see
     \sectionref{sec:null})}
  }
  % \datatool_if_value_eq:NN
  \gexplcond{datatool\dsb if\dsb value\dsb eq}{NN}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{tl var1} \meta{tl var2} \TFsyntax}
    \desc{tests for equality where one or other variable
    may be a \idx{datumcs}. If both are numeric \idxpl{datumcs} they
    will be compared numerically, otherwise they will be compared by
    their string values}
  }
  % \datatool_if_value_eq:Nn
  \gexplcond{datatool\dsb if\dsb value\dsb eq}{Nn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \meta{tl var} \margm{tl} \TFsyntax}
    \desc{tests for equality where \meta{tl var}
    may be a \idx{datumcs} and \meta{tl} may be a \idx{datumitem}.
    If both are a numeric \idx{datumcs} and \idx{datumitem} they
    will be compared numerically, otherwise they will be compared by
    their string values}
  }
  % \datatool_if_value_eq:nN
  \gexplcond{datatool\dsb if\dsb value\dsb eq}{nN}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{tl} \meta{tl var} \TFsyntax}
    \desc{tests for equality where \meta{tl var}
    may be a \idx{datumcs} and \meta{tl} may be a \idx{datumitem}.
    If both are a numeric \idx{datumitem} and \idx{datumcs} they
    will be compared numerically, otherwise they will be compared by
    their string values}
  }
  % \datatool_if_value_eq:nn
  \gexplcond{datatool\dsb if\dsb value\dsb eq}{nn}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{tl1} \margm{tl2} \TFsyntax}
    \desc{tests for equality where one or other or the token lists
     may be a \idx{datumitem}.  If both are numeric \idxpl{datumitem} they
    will be compared numerically, otherwise they will be compared by
    their string values}
  }
  % \datatool_if_valid_datum_type:nTF and
  % \datatool_if_valid_datum_type_p:n
  \gexplpred{data\-tool\dsb if\dsb valid\dsb datum\dsb type}{n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{n} \TFsyntax}
    \desc{tests if the integer \meta{n} represents a valid data type
     (including unknown)}
  }
  % \datatool_if_numeric_datum_type:nTF and
  % \datatool_if_numeric_datum_type_p:n
  \gexplpred{data\-tool\dsb if\dsb numeric\dsb datum\dsb type}{n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{n} \TFsyntax}
    \desc{tests if the integer \meta{n} represents a numeric data type}
  }
  % \datatool_if_temporal_datum_type:nTF and
  % \datatool_if_temporal_datum_type_p:n
  \gexplpred{data\-tool\dsb if\dsb temporal\dsb datum\dsb type}{n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{n} \TFsyntax}
    \desc{tests if the integer \meta{n} represents a temporal data type}
  }
  % \datatool_if_number_only_datum_type:nTF and
  % \datatool_if_number_only_datum_type_p:n
  \gexplpred{data\-tool\dsb if\dsb number\dsb only\dsb datum\dsb type}{n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{n} \TFsyntax}
    \desc{tests if the integer \meta{n} represents a temporal data type}
  }
  % \datatool_if_number_any_int_type:nTF and
  % \datatool_if_number_any_int_type_p:n
  \gexplpred{data\-tool\dsb if\dsb any\dsb int\dsb datum\dsb type}{n}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\ \margm{n} \TFsyntax}
    \desc{tests if the integer \meta{n} represents a temporal data type}
  }
  % COMMANDS: SORTING
  % \dtlsortlist
  \gcmd{dtl\-sort\-list}
  {
     \providedby{\sty{datatool-base} v2.27+}
     \syntax{\margm{list-cs}\margm{criteria cs}}
     \desc{sorts the given \idx{CSV} list according to the
     \meta{criteria cs} command, which must take three arguments:
     \code{\margm{reg}\margm{A}\margm{B}} where \meta{reg} is a
     count register and \meta{A} and \meta{B} are two elements to
     compare}
  }
  % \dtlinsertinto
  \gcmd{dtl\-insert\-into}
  {
     \providedby{\sty{datatool-base} v2.27+}
     \syntax{\margm{element}\margm{sorted-list cs}\margm{criteria cs}}
     \desc{globally inserts \meta{element} into the given sorted
     list according to the \meta{criteria cs} handler macro}
  }
  % \dtltexorsort
  \gcmd{dtl\-tex\-or\-sort}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{\TeX}\margm{sort}}
     \desc{by default this expands to \meta{\TeX}, ignoring the
     second argument, but is redefined to \idxc{expansion}{expand} to the second
     argument, ignoring the first, by commands like \gls{DTLsortwordlist}}
  }
  % \DTLsortwordlist
  \gcmd{DTL\-sort\-word\-list}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{list-cs}\margm{handler-cs}}
     \desc{sorts the \idx{CSV} list stored in the command
     \meta{list-cs}. The \meta{handler-cs} argument is a handler
     macro used to convert the original value into a byte sequence.
     The handler macro should be defined with the syntax
     \code{\meta{handler-cs}\margm{original}\margm{tl}} where
     \meta{original} is the original value and \meta{tl} is a token
    list control sequence in which to store the byte sequence}
  }
  % \dtlfallbackaction
  \gcmd{dtl\-fall\-back\-action}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{val1}\margm{val2}\margm{swap code}\margm{no swap code}}
     \desc{used during sorting when two sort values are identical.
     The \meta{val1} and \meta{val2} arguments are the
     \emph{original} values, which may not be identical. This
     command should \idxc{expansion}{expand} to \meta{swap code}, if the 
     values should be swapped and \meta{no swap code} otherwise. The default
     behaviour uses \gls{DTLifstringgt} to compare the original \meta{val1}
     and \meta{val2}}
  }
  % \DTLsortwordhandler
  \gcmd{DTL\-sort\-word\-handler}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{original}\margm{cs}}
     \desc{case-insensitive word handler for use in \gls{DTLsortwordlist}
     and \gls{dtlwordindexcompare} and \gls{dtlletterindexcompare}. 
     Expands and converts \meta{original} to lowercase, then 
     applies \gls{DTLDefaultLocaleWordHandler} and purifies the result}
  }
  % \DTLsortwordcasehandler
  \gcmd{DTL\-sort\-word\-case\-handler}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{original}\margm{cs}}
     \desc{case-sensitive word handler for use in \gls{DTLsortwordlist}. Expands
     \meta{original}, then applies \gls{DTLDefaultLocaleWordHandler}
     and purifies the result}
  }
  % \DTLsortletterhandler
  \gcmd{DTL\-sort\-letter\-handler}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{original}\margm{cs}}
     \desc{case-insensitive letter handler for use in \gls{DTLsortwordlist}. 
     Expands and converts \meta{original} to lowercase, strips
     hyphens and spaces, then applies \gls{DTLDefaultLocaleWordHandler} 
     and purifies the result}
  }
  % \DTLsortlettercasehandler
  \gcmd{DTL\-sort\-letter\-case\-handler}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{original}\margm{cs}}
     \desc{case-sensitive letter handler for use in \gls{DTLsortwordlist}. 
     Expands \meta{original}, strips hyphens and spaces, 
     then applies \gls{DTLDefaultLocaleWordHandler} and purifies the result}
  }
  % \dtlSortWordCommands
  \gcmd{dtl\-Sort\-Word\-Commands}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{code}}
     \desc{globally adds \meta{code} to the hook used by
     \gls{DTLsortwordlist}, \gls{dtlwordindexcompare} and \gls{dtlletterindexcompare}}
  }
  % \datatoolasciistart
  \gcmd{data\-tool\-ascii\-start}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to nothing normally but expands to null character
      inside \gls{dtlwordindexcompare}, \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \datatoolasciiend
  \gcmd{data\-tool\-ascii\-end}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to nothing normally but expands to the delete character
      (\hexcp{7F}, the highest \idx{ascii} character) inside 
      \gls{dtlwordindexcompare}, \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \datatoolctrlboundary
  \gcmd{data\-tool\-ctrl\-bound\-ary}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{expands to nothing normally but expands to the control character
      \hexcp{1F},  inside \gls{dtlwordindexcompare}, \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \datatoolpersoncomma
  \gcmd{data\-tool\-per\-son\-comma}
  {
     \providedby{\sty{datatool-base} v2.13+}
     \desc{designed to indicate word inversion for a person, this
      command expands to \code{,\gls{space}} normally but expands to the character
      \hexcp{1C} inside \gls{dtlwordindexcompare}, \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \datatoolplacecomma
  \gcmd{data\-tool\-place\-comma}
  {
     \providedby{\sty{datatool-base} v2.13+}
     \desc{designed to indicate a comma to clarify a place, this
      command expands to \code{,\gls{space}} normally but expands to the character
      \hexcp{1D} inside \gls{dtlwordindexcompare}, \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \datatoolsubjectcomma
  \gcmd{data\-tool\-sub\-ject\-comma}
  {
     \providedby{\sty{datatool-base} v2.13+}
     \desc{designed to indicate heading inversion, this
      command expands to \code{,\gls{space}} normally but expands to the character
      \hexcp{1E} inside \gls{dtlwordindexcompare}, \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \datatoolparenstart
  \gcmd{data\-tool\-paren\-start}
  {
     \providedby{\sty{datatool-base} v2.13+}
     \desc{designed to indicate the start of parenthetical content, this
      command expands to \gls{space} normally but expands to the character
      \hexcp{1F} inside \gls{dtlwordindexcompare}, \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \datatoolparen
  \gcmd{data\-tool\-paren}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{text}}
     \desc{typesets parenthetical content, this
      command expands to \code{\gls{space}(\meta{text})} normally
      but expands to nothing within \gls{dtlwordindexcompare}, 
      \gls{dtlletterindexcompare}
      and \gls{DTLsortwordlist}}
  }
  % \DTLassignlettergroup
  \gcmd{DTL\-assign\-letter\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{actual}\margm{sort value}\margm{cs}}
     \desc{used by \gls{DTLsortwordlist} and \gls{DTLsortdata}
     to assign the letter group based on the actual or sort value}
  }
  % \DTLPreProcessLetterGroup
  \gcmd{DTL\-Pre\-Process\-Letter\-Group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}}
     \desc{used by \gls{DTLassignlettergroup} to pre-process the 
     (alphabetical) letter group stored in the given
     token list variable \meta{cs}. This is performed after 
     \gls{DTLCurrentLocaleGetInitialLetter} and before
     encapsulation with \gls{dtllettergroup}}
  }
  % \DTLPreProcessNonLetterGroup
  \gcmd{DTL\-Pre\-Process\-Non\-Letter\-Group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}}
     \desc{used by \gls{DTLassignlettergroup} to pre-process the 
     (symbol\slash punctuation) non-letter group stored in the given
     token list variable \meta{cs}. This is performed before
     encapsulation with \gls{dtlnonlettergroup}}
  }
  % \DTLPreProcessIntegerGroup
  \gcmd{DTL\-Pre\-Process\-Integer\-Group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}\margm{actual}}
     \desc{used by \gls{DTLassignlettergroup} to pre-process the 
     (integer) numeric group stored in the given
     token list variable \meta{cs}. This is performed before
     encapsulation with \gls{dtlnumbergroup}}
  }
  % \DTLPreProcessDecimalGroup
  \gcmd{DTL\-Pre\-Process\-Decimal\-Group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}\margm{actual}}
     \desc{used by \gls{DTLassignlettergroup} to pre-process the 
     (decimal) numeric group stored in the given
     token list variable \meta{cs}. This is performed before
     encapsulation with \gls{dtlnumbergroup}}
  }
  % \DTLPreProcessCurrencyGroup
  \gcmd{DTL\-Pre\-Process\-Currency\-Group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{sym-cs}\margm{num-cs}\margm{actual}}
     \desc{used by \gls{DTLassignlettergroup} to pre-process the 
     currency group, where \meta{num-cs} contains the numeric value
     and \meta{sym-cs} contains the currency symbol. This is performed before
     encapsulation with \gls{dtlcurrencygroup}}
  }
  % \dtllettergroup
  \gcmd{dtl\-letter\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{character}}
     \desc{used by \gls{DTLassignlettergroup} to identify
      alphabetical letter groups}
  }
  % \dtlnonlettergroup
  \gcmd{dtl\-non\-letter\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{character}}
     \desc{used by \gls{DTLassignlettergroup} to identify non-letter
      groups}
  }
  % \dtlnumbergroup
  \gcmd{dtl\-number\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{num}}
     \desc{used by \gls{DTLassignlettergroup} to identify number
      groups}
  }
  % \dtlcurrencygroup
  \gcmd{dtl\-currency\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{sym}\margm{num}}
     \desc{used by \gls{DTLassignlettergroup} to identify currency
      groups}
  }
  % \dtldatetimegroup
  \gcmd{dtl\-date\-time\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{value}}
     \desc{used by \gls{DTLassignlettergroup} to identify datetime
      groups}
  }
  % \dtldategroup
  \gcmd{dtl\-date\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{value}}
     \desc{used by \gls{DTLassignlettergroup} to identify date
      groups}
  }
  % \dtltimegroup
  \gcmd{dtl\-time\-group}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{value}}
     \desc{used by \gls{DTLassignlettergroup} to identify time
      groups}
  }
  % \DTLsortedactual
  \gcmd{DTL\-sorted\-actual}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{sorted element}}
     \desc{expands the actual (original) value from a sorted element
     obtained by \gls{DTLsortwordlist}}
  }
  % \DTLsortedvalue
  \gcmd{DTL\-sorted\-value}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{sorted element}}
     \desc{expands the sort value from a sorted element
     obtained by \gls{DTLsortwordlist}}
  }
  % \DTLsortedletter
  \gcmd{DTL\-sorted\-letter}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{sorted element}}
     \desc{expands the letter group from a sorted element
     obtained by \gls{DTLsortwordlist}}
  }
  % COMMANDS: STRINGS
  % \l_datatool_measure_hook_tl
  \gcmd{l\dsb datatool\dsb measure\dsb hook\dsb tl}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \desc{token list variable used by the measuring commands
    \gls{datatoolmeasureheight:Nn},
    \gls{datatoolmeasurewidth:Nn} and
    \gls{datatoolmeasuredepth:Nn}
    }
  }
  % \datatool_measure_height:Nn
  \gcmd{data\-tool\dsb measure\dsb height:Nn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \meta{dim} \margm{text}}
     \desc{a shortcut that uses \gls{settoheight} to measure the
     height of \meta{text} but first implements \gls{ldatatoolmeasurehooktl}
     to locally disable problematic commands}
  }
  % \datatool_measure_depth:Nn
  \gcmd{data\-tool\dsb measure\dsb depth:Nn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \meta{dim} \margm{text}}
     \desc{a shortcut that uses \gls{settodepth} to measure the
     depth of \meta{text} but first implements \gls{ldatatoolmeasurehooktl}
     to locally disable problematic commands}
  }
  % \datatool_measure_width:Nn
  \gcmd{data\-tool\dsb measure\dsb width:Nn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \meta{dim} \margm{text}}
     \desc{a shortcut that uses \gls{settowidth} to measure the
     width of \meta{text} but first implements \gls{ldatatoolmeasurehooktl}
     to locally disable problematic commands}
  }
  % \datatool_measure:NNNn
  \gcmd{datatool\dsb measure:NNNn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \meta{wd-dim} \meta{ht-dim} \meta{dp-dim} \margm{text}}
     \desc{measures the width, height and depth of \meta{text}
      but first implements \gls{ldatatoolmeasurehooktl}
      to locally disable problematic commands}
  }
  % \datatool_measure_ht_plus_dp:Nn
  \gcmd{datatool\dsb measure\dsb ht\dsb plus\dsb dp:Nn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \meta{dim} \margm{text}}
     \desc{measures the combined height and
     depth of \meta{text} but first implements \gls{ldatatoolmeasurehooktl}
     to locally disable problematic commands}
  }
  % \DTLCurrentLocaleWordHandler
  \gcmd{DTL\-Current\-Locale\-Word\-Handler}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}}
     \desc{current locale word handler used by string sorting}
  }
  % \DTLenLocaleHandler
  \gcmd{DTL\-en\-Lo\-cale\-Han\-dler}
  {
     \providedby{\sty{datatool-english}}
     \syntax{\margm{cs}}
     \desc{English locale word handler}
  }
  % \DTLDefaultLocaleWordHandler
  \gcmd{DTL\-Default\-Locale\-Word\-Handler}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{cs}}
     \desc{word handler used by string sorting}
  }
  % \datatool_get_first_grapheme:nN
  \gcmd{data\-tool\dsb get\dsb first\dsb grapheme:nN}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{text} \meta{tl-var}}
     \desc{obtains the first grapheme of \meta{text} and defines
      \meta{tl-var} to \idxc{expansion}{expand} to that grapheme}
  }
  % \datatool_get_first_letter:nN
  \gcmd{data\-tool\dsb get\dsb first\dsb letter:nN}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{text} \meta{tl-var}}
     \desc{similar to \gls{datatoolgetfirstgrapheme:nN} but will
     skip leading punctuation}
  }
  % \datatool_if_letter:nTF
  \gexplcond{datatool\dsb if\dsb letter}{n}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \margm{grapheme} \TFsyntax}
     \desc{tests if \meta{grapheme} is a letter}
  }
  % \datatool_sort_preprocess:Nn
  \gcmd{data\-tool\dsb sort\dsb pre\-process:Nn}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\ \meta{tl-var} \margm{text}}
     \desc{expand and apply the current sort hooks to \meta{text}
and store the result in \meta{tl-var}}
  }
  % \datatool_sort_preprocess:NnN
  \gcmd{data\-tool\dsb sort\dsb pre\-process:NnN}
  {
     \providedby{\sty{datatool-base} v3.2+}
     \syntax{\ \meta{tl-var} \margm{text} \meta{bool-var}}
     \desc{expand and apply the current sort hooks to \meta{text}
and store the result in \meta{tl-var}. If \meta{bool-var} is true,
the sort value will be converted to lowercase}
  }
  % \DTLCurrentLocaleGetGroupString
  \gcmd{DTL\-Current\-Locale\-Get\-Group\-String}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{actual}\margm{sort value}\margm{cs}}
     \desc{used by \gls{DTLassignlettergroup} to determine
     whether to obtain the letter group from the actual or sort
     value. Localisation support should redefine this as appropriate
     and may further process the value to ensure that the first
     character matches the appropriate group}
  }
  % \DTLenLocaleGetGroupString
  \gcmd{DTL\-en\-Locale\-Get\-Group\-String}
  {
     \providedby{\sty{datatool-english}}
     \syntax{\margm{actual}\margm{sort value}\margm{cs}}
     \desc{English group string handler}
  }
  % \DTLangLatnLocaleGetGroupString
  \gcmd{DTL\-ang\-Latn\-Locale\-Get\-Group\-String}
  {
     \providedby{\ldf{ang-Latn}}
     \syntax{\margm{actual}\margm{sort value}\margm{cs}}
     \desc{Anglo-Saxon (Latin Script) group string handler}
  }
  % \DTLCurrentLocaleGetInitialLetter
  \gcmd{DTL\-Current\-Locale\-Get\-Initial\-Letter}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{text}\margm{cs}}
     \desc{used by \gls{DTLGetInitialLetter} and
     \gls{DTLassignlettergroup}}
  }
  % \DTLGetInitialLetter
  \gcmd{DTL\-Get\-Initial\-Letter}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{text}\margm{cs}}
     \desc{gets the initial letter of \meta{text} and stores it in
      \meta{cs}}
  }
  % \DTLinitials
  \gcmd{DTL\-ini\-tials}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{text}}
     \desc{splits \meta{text} into words and displays the initial of
     each word. Internally uses \gls{DTLstoreinitials}}
  }
  % \xDTLinitials
  \gcmd{xDTL\-ini\-tials}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{text}}
     \desc{expands the first token in \meta{text} before passing to
\gls{DTLinitials}}
  }
  % \DTLstoreinitials
  \gcmd{DTL\-store\-ini\-tials}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{text}\margm{cs}}
     \desc{splits \meta{text} into words and defines the control
     sequence \meta{cs} to \idxc{expansion}{expand} to the initials of each word}
     \field{seealso}{DTLstoreinitials,DTLStoreInitialGetLetter,DTLbetweeninitials,DTLafterinitials,DTLinitialhyphen,DTLafterinitialbeforehyphen,DTLinitialpunc,DTLaposinitialpunc}
  }
  % \DTLStoreInitialGetLetter
  \gcmd{DTL\-Store\-Initial\-Get\-Letter}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{word}\margm{cs}}
     \desc{used by \gls{DTLstoreinitials} to get the initial letter
     of \meta{word}. Default definition just uses
     \gls{DTLGetInitialLetter}}
  }
  % \DTLaposinitialpunc
  \gcmd{DTL\-apos\-initial\-punc}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{H}\margm{T}\margm{punc}}
     \desc{used by \gls{DTLstoreinitials} to markup initials from
     words with an apostrophe}
  }
  % \DTLinitialpunc
  \gcmd{DTL\-initial\-punc}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{letter}\margm{punc}}
     \desc{used by \gls{DTLstoreinitials} to markup initials}
  }
  % \DTLbetweeninitials
  \gcmd{DTL\-between\-initials}
  {
     \initval{\code{.}}
     \providedby{\sty{datatool-base}}
     \desc{used by \gls{DTLinitials} and \gls{DTLstoreinitials} between initials}
  }
  % \DTLafterinitials
  \gcmd{DTL\-after\-initials}
  {
     \initval{\code{.}}
     \providedby{\sty{datatool-base}}
     \desc{used by \gls{DTLinitials} and \gls{DTLstoreinitials} after the initials}
  }
  % \DTLafterinitialbeforehyphen
  \gcmd{DTL\-after\-initial\-before\-hyphen}
  {
     \initval{\code{.}}
     \providedby{\sty{datatool-base}}
     \desc{used by \gls{DTLinitials} and \gls{DTLstoreinitials}
      after an initial before a hyphen}
  }
  % \DTLinitialhyphen
  \gcmd{DTL\-initial\-hyphen}
  {
     \initval{\code{-}}
     \providedby{\sty{datatool-base}}
     \desc{used by \gls{DTLinitials} and \gls{DTLstoreinitials}
      where a hyphen occurs}
  }
  % \DTLsubstitute
  \gcmd{DTL\-sub\-stitute}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{original}\margm{replacement}}
     \desc{substitutes the first occurrence of \meta{original} with
      \meta{replacement} within the \idx{expansion} text of the command
      \meta{cs}}
  }
  % \DTLsubstituteall
  \gcmd{DTL\-sub\-stitute\-all}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{cs}\margm{original}\margm{replacement}}
     \desc{substitutes all occurrences of \meta{original} with
      \meta{replacement} within the \idx{expansion} text of the command
      \meta{cs}}
  }
  % \DTLsplitstring
  \gcmd{DTL\-split\-string}
  {
     \providedby{\sty{datatool-base} v1.01+}
     \syntax{\margm{string}\margm{split text}\margm{before cmd}\margm{after cmd}}
     \desc{splits \meta{string} at \meta{split text} and defines
     \meta{before cmd} to the pre-split text and \meta{after cmd} to the
      post-split text (neither \meta{string} nor \meta{split text}
     are expanded)}
  }
  % \DTLxsplitstring
  \gcmd{DTL\-x\-split\-string}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{string}\margm{split text}\margm{before cmd}\margm{after cmd}}
     \desc{as \gls{DTLsplitstring} but expands \meta{string}
     and \meta{split text} once}
  }
  % \dtlcompare
  \gcmd{dtl\-com\-pare}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{count-reg}\margm{string1}\margm{string2}}
     \desc{compares \meta{string1} and \meta{string2} and stores the
      result in the count register \meta{count-reg}, where \code{0}
      indicates the strings are the same, \code{-1} means that
      \meta{string1} comes before (less than) \meta{string2} and \code{1}
       means that \meta{string1} comes after (greater than) \meta{string2}
       (case-sensitive)
     }
     \field{seealso}{dtlicompare}
  }
  % \dtlicompare
  \gcmd{dtl\-i\-com\-pare}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{count-reg}\margm{string1}\margm{string2}}
     \desc{compares \meta{string1} and \meta{string2} and stores the
      result in the count register \meta{count-reg}, where \code{0}
      indicates the strings are the same, \code{-1} means that
      \meta{string1} comes before (less than) \meta{string2} and \code{1}
       means that \meta{string1} comes after (greater than) \meta{string2}
       (case-insensitive)
     }
     \field{seealso}{dtlcompare}
  }
  % \dtlletterindexcompare
  \gcmd{dtl\-letter\-index\-com\-pare}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{count-reg}\margm{string1}\margm{string2}}
     \desc{letter order comparison that may be used in \gls{dtlsortlist}}
     \field{seealso}{dtlwordindexcompare}
  }
  % \dtlwordindexcompare
  \gcmd{dtl\-word\-index\-com\-pare}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{count-reg}\margm{string1}\margm{string2}}
     \desc{word order comparison that may be used in \gls{dtlsortlist}}
     \field{seealso}{dtlwordindexcompare}
  }
  % COMMANDS: CSV LISTS
  % \DTLformatlist
  \gcmds{DTL\-format\-list}
  {
     \providedby{\sty{datatool-base} v2.28+}
     \syntax{\margm{list}}
     \desc{formats the supplied \idx{CSV} list. The unstarred version
      adds grouping}
  }
  % \DTLlistformatitem
  \gcmd{DTL\-list\-format\-item}
  {
     \providedby{\sty{datatool-base} v2.28+}
     \syntax{\margm{item}}
     \desc{formats an item within \gls{DTLformatlist}}
  }
  % \DTLlistformatsep
  \gcmd{DTL\-list\-format\-sep}
  {
     \initval{,\visiblespace}
     \providedby{\sty{datatool-base} v2.28+}
     \syntax{\margm{item}}
     \desc{separator used between each item except for the final two
       within \gls{DTLformatlist}}
  }
  % \DTLlistformatlastsep
  \gcmd{DTL\-list\-format\-last\-sep}
  {
     \providedby{\sty{datatool-base} v2.28+}
     \desc{separator used between the final two elements in
     \gls{DTLformatlist}}
  }
  % \DTLlistformatoxford
  \gcmd{DTL\-list\-format\-oxford}
  {
     \initvalempty
     \providedby{\sty{datatool-base} v2.28+}
     \desc{inserted before \gls{DTLlistformatlastsep} if the list
     contains more than two items}
  }
  % \DTLlistand
  \gcmd{DTL\-list\-and}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{used in the default definition of
     \gls{DTLlistformatlastsep}. Expands either to \gls{DTLandname}
     or to \gls{cs.amp}, depending on the \listsopt{and} option in
     the \opt{lists} setting}
  }
  % \DTLandname
  \gcmd{DTL\-and\-name}
  {
     \initvalvaries
     \providedby{\sty{datatool-base} v2.28+}
     \desc{expands to \gls{andname} if that command was defined when
     \sty{datatool-base} was loaded otherwise expands to \gls{cs.amp}
      or the applicable localisation text}
     \note{language-sensitive}
  }
  % \DTLlistelement
  \gcmd{DTL\-list\-element}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{list}\margm{idx}}
     \desc{does the \meta{idx}th element in the list (starting with
      1 for the first element)}
  }
  % \DTLfetchlistelement
  \gcmd{DTL\-fetch\-list\-element}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{list}\margm{idx}\margm{cs}}
     \desc{fetches the \meta{idx}th element in the list (starting with
      1 for the first element) and defines the control sequence
     \meta{cs} to that element value}
  }
  % \DTLnumitemsinlist
  \gcmd{DTL\-num\-items\-in\-list}
  {
     \providedby{\sty{datatool-base}}
     \syntax{\margm{list}\margm{cs}}
     \desc{counts the number of elements in \meta{list}
     and defines the command \meta{cs} to that number}
  }
  % COMMANDS: DATABASES
  % \DTLpar
  \gcmd{DTL\-par}
  {
    \providedby{\sty{datatool}}
    \desc{robust command defined to do \gls{par}. For use in
\qt{short} arguments where \gls{par} isn't permitted}
  }
  % \dtldbname
  \gcmd{dtl\-db\-name}
  {
    \providedby{\sty{datatool}}
    \desc{placeholder that expands to the current database name in certain
contexts}
  }
  % \DTLaction
  \gcmd{DTL\-action}
  {
    \common
    \providedby{\sty{datatool} v3.0+}
    \syntax{\oargm{settings}\margm{action}}
    \desc{performs a command corresponding to \meta{action}}
  }
  % ACTION: new
  \gactionname{new}{}
  % ACTION: delete
  \gactionname{delete}{}
  % ACTION: clear
  \gactionname{clear}{}
  % ACTION: new row
  \gactionname{new-row}{\name{\actionfmt{new row}}}
  % ACTION: new entry
  \gactionname{new-entry}{\name{\actionfmt{new entry}}}
  % ACTION: add column
  \gactionname{add-column}{\name{\actionfmt{add column}}}
  % ACTION: column index
  \gactionname{column-index}{\name{\actionfmt{column index}}}
  % ACTION: column data
  \gactionname{column-data}{\name{\actionfmt{column data}}}
  % ACTION: display
  \gactionname{display}{}
  % ACTION: display long
  \gactionname{display-long}{\name{\actionfmt{display long}}}
  % ACTION: aggregate
  \gactionname{aggregate}{}
  % ACTION: row aggregate
  \gactionname{row-aggregate}{\name{\actionfmt{row aggregate}}}
  % ACTION: current row aggregate
  \gactionname{current-row-aggregate}{\name{\actionfmt{current row aggregate}}}
  % ACTION: select row
  \gactionname{select-row}{\name{\actionfmt{select row}}}
  % ACTION: current row values
  \gactionname{current-row-values}{\name{\actionfmt{current row values}}}
  % ACTION: find
  \gactionname{find}{}
  % ACTION: sort
  \gactionname{sort}{}
  % ACTION: pie chart
  \gactionname{pie-chart}
   {
     \providedby{\sty{databar} v3.0+}
     \name{\actionfmt{pie chart}}
   }
  % ACTION: bar chart
  \gactionname{bar-chart}
   {
     \providedby{\sty{databar} v3.0+}
     \name{\actionfmt{bar chart}}
   }
  % ACTION: multibar chart
  \gactionname{multibar-chart}
   {
     \providedby{\sty{databar} v3.0+}
     \name{\actionfmt{multibar chart}}
   }
  % ACTION: plot
  \gactionname{plot}
   {
     \providedby{\sty{dataplot} v3.0+}
   }
  % \DTLaction OPTION: name 
  \gactionopt{name}
  {
    \syntax{\meta{db-name(s)}}
    \desc{the database name or (where the action supports multiple databases)
     the list of database names. If omitted, the default is obtained
     from the \opt{default-name}}
  }
  % \DTLaction OPTION: key 
  \gactionopt{key}
  {
    \syntax{\meta{label}}
    \desc{the key that uniquely identifies the required column}
  }
  \gactionopt{key2}
  {
    \syntax{\meta{label}}
    \desc{the key that uniquely identifies the second required column}
  }
  % \DTLaction OPTION: keys 
  \gactionopt{keys}
  {
    \syntax{\margm{list}}
    \desc{list of keys that uniquely identifies one or more columns}
  }
  % \DTLaction OPTION: column 
  \gactionopt{column}
  {
    \syntax{\meta{n}}
    \desc{the index of the required column}
  }
  % \DTLaction OPTION: column2 
  \gactionopt{column2}
  {
    \syntax{\meta{n}}
    \desc{the index of the second required column}
  }
  % \DTLaction OPTION: columns 
  \gactionopt{columns}
  {
    \syntax{\margm{list}}
    \desc{list of column indexes or ranges}
  }
  % \DTLaction OPTION: return 
  \gactionopt{return}
  {
    \syntax{\marg{\idx{assign-list}}}
    \desc{provides an assignment list for return values}
  }
  % \DTLaction OPTION: value 
  \gactionopt{value}
  {
    \syntax{\meta{value}}
    \desc{the value that may be referenced by certain actions}
  }
  % \DTLaction OPTION: options 
  \gactionopt{options}
  {
    \syntax{\margm{list}}
    \desc{provides a list of options for certain actions}
  }
  % \DTLaction OPTION: assign 
  \gactionopt{assign}
  {
    \syntax{\marg{\keyvallist}}
    \desc{provides a list of assignments for certain actions}
  }
  % \DTLaction OPTION: expand-value 
  \gactionopt{expand\dhyphen value}
  {
    \syntax{\meta{text}}
    \desc{equivalent to \actionoptval{value}{\meta{expanded text}}, 
     where \meta{text} is fully expanded to \meta{expanded text}}
  }
  % \DTLaction OPTION: expand-once-value 
  \gactionopt{expand\dhyphen once\dhyphen value}
  {
    \syntax{\meta{text}}
    \desc{equivalent to \actionoptval{value}{\meta{expanded text}}, 
     where \meta{text} is expanded once to \meta{expanded text}}
  }
  % \DTLaction OPTION: row 
  \gactionopt{row}
  {
    \syntax{\meta{n}}
    \desc{the index of the required row}
  }
  % \DTLaction OPTION: row2 
  \gactionopt{row2}
  {
    \syntax{\meta{n}}
    \desc{the index of the second required row}
  }
  % \DTLaction OPTION: type 
  \gactionopt{type}
  {
    \syntax{\meta{value}}
    \desc{the data type. The value may be one of: \optfmt{string},
\optfmt{integer} (or \optfmt{int}), \optfmt{decimal} (or
\optfmt{real}), or \optfmt{currency}}
  }
  % \DTLaction OPTION: datum 
  \gactionopt{datum}
  {
    \initval{false}
    \defval{true}
    \syntax{\marg{\keyvallist|true|false}}
    \desc{if set, secondary return values will be in the form of a
     \idx{datumitem}}
  }
  % \DTLaction OPTION datum = { round = { ... } }
  \gactiondatumopt{round}
  {
    \initval{false}
    \defval{0}
    \syntax{\meta{number}|false}
    \desc{round to the given number of decimal places, or switch off rounding
    if the value is \code{false} or negative}
  }
  % \DTLaction OPTION datum = { locale-integer = { ... } }
  \gactiondatumopt{locale\dhyphen integer}
  {
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{if true, format return values that are guaranteed to be
integers}
  }
  % \DTLaction OPTION datum = { locale-decimal = { ... } }
  \gactiondatumopt{locale-decimal}
  {
    \initval{true}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{if true, format numeric return values that may be decimal
or integers}
  }
  % \DTLaction OPTION datum = { currency = { ... } }
  \gactiondatumopt{currency}
  {
    \initval{match}
    \defval{default}
    \syntax{\code{false}|\code{match}|\code{default}|\meta{symbol}}
    \desc{governs whether or not decimal return values will be formatted as currency}
  }
  % \DTLaction find OPTION select: options = { select = { boolean } }
  \gactionfindopt{select}
  {
    \syntax{\meta{boolean}}
    \initval{false}
    \defval{true}
    \desc{if a match is found, the row will be set as the \idx{current-row}}
  }
  % \DTLaction find OPTION direction: options = { direction = { ... } }
  \gactionfindopt{direction}
  {
    \syntax{\meta{value}}
    \initval{ascending}
    \desc{the search order}
  }
  % \DTLaction find OPTION inline: options = { inline = { ... } }
  \gactionfindopt{inline}
  {
    \syntax{\margm{definition}}
    \desc{defines the criteria function inline. The function takes a
single argument and the \meta{definition} should expand to that
argument to indicate a match}
  }
  % \DTLaction find OPTION function: options = { function = { ... } }
  \gactionfindopt{function}
  {
    \syntax{\meta{cs}}
    \desc{sets the criteria function to \meta{cs}. The function
\meta{cs} must take a single argument, and the definition should expand to that
argument to indicate a match}
  }
  % \DTLget
  \gcmd{DTL\-get}
  {
    \common
    \providedby{\sty{datatool} v3.0+}
    \syntax{\oargm{property}\margm{cs}}
    \desc{gets the returned value from the last \gls{DTLaction} in
     the current scope, and stores the value in the token list 
     control sequence \meta{cs}. Leave the optional argument \meta{property}
     empty (or omit) for the main return value, otherwise \meta{property} 
     should identify the particular value when there are multiple return values}
  }
  % \DTLuse
  \gcmd{DTL\-use}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{property}}
    \desc{uses the returned value from the last \gls{DTLaction} in
     the current scope. Leave the argument empty for the main return
     value, otherwise \meta{property} should identify the particular
     value when there are multiple return values}
  }
  % \DTLifaction
  \gcmd{DTL\-if\-action}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{property}\margm{true}\margm{false}}
    \desc{expands to \meta{true} if the last action set the given
property or \meta{false} otherwise}
  }
  % \dtldefaultkey
  \gcmd{dtl\-default\-key}
  {
    \providedby{\sty{datatool}}
    \desc{expands to the default key prefix when column keys need to
    be automatically generated in \gls{DTLread}}
  }
  % \dtllastloadeddb
  \gcmd{dtl\-last\-load\-ed\-db}
  {
    \providedby{\sty{datatool}}
    \desc{expands to the label of the last database to be loaded by
    \gls{DTLread}}
  }
  % \dtlexpandnewvalue
  \gcmd{dtl\-expand\-new\-value}
  {
    \providedby{\sty{datatool}}
    \desc{ensures that new values are expanded before being added to
    a database (equivalent to the \optval{new-value-expand}{true}
    option). Has no effect when loading \ext{dbtex} files}
  }
  % \dtlnoexpandnewvalue
  \gcmd{dtl\-no\-expand\-new\-value}
  {
    \providedby{\sty{datatool}}
    \desc{prevents new values from being expanded when added to
    a database (equivalent to the \optval{new-value-expand}{false} option). 
    Has no effect when loading \ext{dbtex} files. Note that values
can still be expanded with the \actionopt{expand-value} and
\actionopt{expand-once-value} action settings}
  }
  % \DTLnewdb
  \gcmd{DTL\-new\-db}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}}
    \desc{creates a new database with the label \meta{db-name}. 
    Note that new databases are always global, regardless 
    of the \opt{global} option, so this command is equivalent to
    \gls{DTLgnewdb}}
  }
  % \DTLgnewdb
  \gcmd{DTL\-g\-new\-db}
  {
    \providedby{\sty{datatool} v2.13+}
    \syntax{\margm{db-name}}
    \desc{globally creates a new database with the label \meta{db-name}}
  }
  % \DTLifdbexists
  \gcmd{DTL\-if\-db\-exists}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}\margm{true}\margm{false}}
    \desc{does \meta{true} if a database with the label
     \meta{db-name} exists, otherwise does \meta{false}}
  }
  % \DTLifdbempty
  \gcmd{DTL\-if\-db\-empty}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}\margm{true}\margm{false}}
    \desc{does \meta{true} if a database with the label
     \meta{db-name} is empty, otherwise does \meta{false}}
  }
  % \datatool_db_state:nnnn
  \gcmd{data\-tool\dsb db\dsb state:nnnn}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{db-name}\margm{not empty}\margm{empty}\margm{not exists}}
    \desc{if the database identified by \meta{db-name} exists and is
not empty, this does \meta{not empty}, if it exists but is empty,
this does \meta{empty}. If the database doesn't exist, this does
\meta{not exists}}
  }
  % \DTLcleardb
  \gcmd{DTL\-clear\-db}
  {
    \providedby{\sty{datatool} v2.03+}
    \syntax{\margm{db-name}}
    \desc{clears the database with the label \meta{db-name}. That
    is, the database becomes empty but is still defined}
  }
  % \DTLgcleardb
  \gcmd{DTL\-g\-clear\-db}
  {
    \providedby{\sty{datatool} v2.13+}
    \syntax{\margm{db-name}}
    \desc{clears the database with the label \meta{db-name}. That
    is, the database becomes empty but is still defined}
  }
  % \DTLdeletedb
  \gcmd{DTL\-delete\-db}
  {
    \providedby{\sty{datatool} v2.03+}
    \syntax{\margm{db-name}}
    \desc{deletes the database with the label \meta{db-name}}
  }
  % \DTLgdeletedb
  \gcmd{DTL\-g\-delete\-db}
  {
    \providedby{\sty{datatool} v2.13+}
    \syntax{\margm{db-name}}
    \desc{deletes the database with the label \meta{db-name}}
  }
  % \DTLnewrow
  \gcmds{DTL\-new\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}}
    \desc{adds a new row to the database identified by the label
     \meta{db-name}. The unstarred version checks the database
     exists. The starred version doesn't}
  }
  % \DTLdbProvideData
  \gcmd{DTL\-db\-Provide\-Data}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{used at the start of a DTLTEX v3.0 and DBTEX v3.0 file to declare
    the database}
  }
  % \DTLreconstructdbdata
  \gcmd{DTL\-re\-construct\-db\-data}
  {
    \deprecated
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{header code}\margm{body
code}\margm{num-rows}\margm{num-columns}\margm{key-index code}}
    \desc{used in experimental version of DBTEX v3.0 file to
construct the database. This command has been replaced with
    \gls{DTLreconstructdatabase}}
    \field{see}{DTLreconstructdatabase}
  }
  % \DTLreconstructdatabase
  \gcmd{DTL\-re\-construct\-data\-base}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{num-rows}\margm{num-columns}\margm{header code}\margm{body code}\margm{key-index code}}
    \desc{used in a DBTEX v3.0 file to construct the database}
  }
  % \dtldbheaderreconstruct
  \gcmd{dtl\-db\-head\-er\-re\-construct}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{column-idx}\margm{key}\margm{type}\margm{header}}
    \desc{only for use within the \meta{header code} argument of
\gls{DTLreconstructdatabase}}
  }
  % \dtldbrowreconstruct
  \gcmd{dtl\-db\-row\-re\-construct}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{row-idx}\margm{row code}}
    \desc{only for use within the \meta{body code} argument of
\gls{DTLreconstructdatabase}}
  }
  % \dtldbcolreconstruct
  \gcmd{dtl\-db\-col\-re\-construct}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{column-idx}\margm{content}}
    \desc{only for use within the \meta{row code} argument of
\gls{dtldbrowreconstruct}}
  }
  % \dtldbdatumreconstruct
  \gcmd{dtl\-db\-datum\-re\-construct}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{string}\margm{numeric}\margm{currency}\margm{type}}
    \desc{only for use within the \meta{content} argument of
\gls{dtldbcolreconstruct}}
  }
  % \dtldbvaluereconstruct
  \gcmd{dtl\-db\-value\-re\-construct}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{string}}
    \desc{only for use within the \meta{content} argument of
\gls{dtldbcolreconstruct}}
  }
  % \dtldbreconstructkeyindex
  \gcmd{dtl\-db\-re\-construct\-key\-index}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{key}\margm{column-idx}}
    \desc{only for use within the \meta{key-index code} argument of
\gls{DTLreconstructdatabase}}
  }
  % \DTLdbNewRow
  \gcmd{DTL\-db\-New\-Row}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{does \code{\gls{DTLnewrow}\margm{db-name}} where
    \meta{db-name} is the \opt{default-name}}
  }
  % \DTLnewdbentry
  \gcmds{DTL\-new\-db\-entry}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}\margm{col key}\margm{value}}
    \desc{adds an entry to the last row of the database identified by the label
     \meta{db-name} for the column identified by its label \meta{col
     key}. The unstarred version checks the database exists. The
     starred version doesn't. Both versions will trigger an error if the
     row already contains an entry for the given column}
  }
  % \DTLdbNewEntry
  \gcmd{DTL\-db\-New\-Entry}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{col key}\margm{value}}
    \desc{does \code{\gls{DTLnewdbentry}\margm{db-name}\margm{col key}\margm{value}} where
    \meta{db-name} is the \opt{default-name}}
  }
  % \DTLrowcount
  \gcmd{DTL\-row\-count}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}}
    \desc{expands to the row count of the database with the label \meta{db-name}}
  }
  % \DTLcolumncount
  \gcmd{DTL\-column\-count}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}}
    \desc{expands to the column count of the database with the label \meta{db-name}}
  }
  % \DTLifhaskey
  \gcmds{DTL\-if\-has\-key}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{db-name}\margm{key}\margm{true}\margm{false}}
    \desc{tests if the database with the label \meta{db-name} has
    a column with the given \meta{key} (label). The starred version
    doesn't check if the database exists}
  }
  % \datatool_if_has_key:nnTF
  \gexplpred{datatool\dsb if\dsb has\dsb key}{nn}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\ \margm{db-name} \margm{key} \TFsyntax}
    \desc{tests if the database with the label \meta{db-name} exists and has
    a column with the given \meta{key} (label)}
  }
  % \DTLgetcolumnindex
  \gcmds{DTL\-get\-column\-index}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{cs}\margm{db-name}\margm{col key}}
    \desc{gets the index for the column labelled \meta{col key}
     from the database identified by \meta{db-name} and defines the 
     control sequence \meta{cs} to expand to that value. The starred version
     doesn't check if the database or column exists}
  }
  % \dtlcolumnindex
  \gcmd{dtl\-column\-index}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{db-name}\margm{col key}}
    \desc{expands to the column index for the column with the label
    \meta{col key} in the database identified by \meta{db-name}.
     Expands to 0 if the database or column don't exist}
  }
  % \DTLgetkeyforcolumn
  \gcmds{DTL\-get\-key\-for\-column}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{cs}\margm{db-name}\margm{col idx}}
    \desc{gets the key for the column with the index \meta{col idx}
     from the database identified by \meta{db-name} and defines the 
     control sequence \meta{cs} to expand to that value. The starred version
     doesn't check if the database or column exists}
  }
  % \DTLsetheader
  \gcmds{DTL\-set\-header}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}\margm{col key}\margm{header}}
    \desc{sets the header for the column given by \meta{col key} in
     the database identified by \meta{db-name}. The starred version
     doesn't check if the database exists}
  }
  % \DTLdbSetHeader
  \gcmd{DTL\-db\-Set\-Header}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{col key}\margm{header}}
    \desc{does \code{\gls{DTLsetheader}\margm{db-name}\margm{col key}\margm{header}} 
     where \meta{db-name} is the \opt{default-name}}
  }
  % \DTLaddcolumn
  \gcmds{DTL\-add\-column}
  {
    \providedby{\sty{datatool} v2.11+}
    \syntax{\margm{db-name}\margm{col key}}
    \desc{adds a column with the label \meta{col key} to the
    column meta data for the database identified by \meta{db-name}.
    The starred version doesn't check if the database exists}
  }
  % \DTLaddcolumnwithheader
  \gcmds{DTL\-add\-column\-with\-header}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{db-name}\margm{col key}\margm{header}}
    \desc{adds a column with the label \meta{col key} and the given
    \meta{header} to the column meta data for the database identified 
    by \meta{db-name}.  The starred version doesn't check if the database exists}
  }
  % \DTLgetdatatype
  \gcmds{DTL\-get\-data\-type}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{cs}\margm{db-name}\margm{col key}}
    \desc{sets the control sequence \meta{cs} to expand to the data
    type integer identifier for the column labelled \meta{col key} in
    the database identified by \meta{db-name}}
  }
  % \DTLunsettype
  \gcmd{DTL\-un\-set\-type}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{expands to empty}
  }
  % \DTLstringtype
  \gcmd{DTL\-string\-type}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{expands to 0}
  }
  % \DTLinttype
  \gcmd{DTL\-int\-type}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{expands to 1}
  }
  % \DTLrealtype
  \gcmd{DTL\-real\-type}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{expands to 2}
  }
  % \DTLcurrencytype
  \gcmd{DTL\-currency\-type}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{expands to 3}
  }
  % \DTLdisplaydb
  \gcmds{DTL\-display\-db}
  {
    \common
    \providedby{\sty{datatool} v2.0+}
    \syntax{\oargm{omit list}\margm{db-name}}
    \desc{displays the database identified by \meta{db-name} in a
    \env{tabular} environment, omitting the columns listed by their
    label in \meta{omit list}}
  }
  % \DTLdisplaydb*
  \gcmd{DTL\-display\-db*}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\oargm{options}\margm{db-name}}
    \desc{displays the database identified by \meta{db-name} in a
    \env{tabular} environment with \keyval\ list of options}
  }
  % \DTLdisplaylongdb
  \gcmd{DTL\-display\-long\-db}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\oargm{options}\margm{db-name}}
    \desc{displays the database identified by \meta{db-name} in a
    \env{longtable} environment}
  }
  % \dtlheaderformat
  \gcmd{dtl\-header\-format}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{text}}
    \desc{used by \gls{dtlcolumnheader} to apply any font change to
the header text}
  }
  % \dtlcolumnheader
  \gcmd{dtl\-column\-header}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{align}\margm{text}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    align the column headers}
  }
  % \dtlstringformat
  \gcmd{dtl\-string\-format}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{text}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    format entries in string columns}
  }
  % \dtlnumericformat
  \gcmd{dtl\-numeric\-format}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{text}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    format entries in numeric columns}
  }
  % \dtlintformat
  \gcmd{dtl\-int\-format}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{text}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    format entries in integer columns. Defined to use
    \gls{dtlnumericformat} by default}
  }
  % \dtlrealformat
  \gcmd{dtl\-real\-format}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{text}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    format entries in decimal columns. Defined to use
    \gls{dtlnumericformat} by default}
  }
  % \dtlcurrencyformat
  \gcmd{dtl\-currency\-format}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{text}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    format entries in currency columns. Defined to use
    \gls{dtlnumericformat} by default}
  }
  % \dtldisplaystarttab
  \gcmd{dtl\-display\-start\-tab}
  {
    \providedby{\sty{datatool} v2.0+}
    \initvalempty
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    insert content before the header}
  }
  % \dtldisplayafterhead
  \gcmd{dtl\-display\-after\-head}
  {
    \providedby{\sty{datatool} v2.0+}
    \initvalempty
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    insert content after the header}
  }
  % \dtldisplayendtab
  \gcmd{dtl\-display\-end\-tab}
  {
    \providedby{\sty{datatool} v2.0+}
    \initvalempty
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    insert content before the end of the environment}
  }
  % \dtldisplaycr
  \gcmd{dtl\-display\-cr}
  {
    \providedby{\sty{datatool} v2.19+}
    \initvalcs{tabularnewline}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    insert a new line}
  }
  % \dtldisplayvalign
  \gcmd{dtl\-display\-v\-align}
  {
    \providedby{\sty{datatool} v2.11+}
    \initval{c}
    \desc{expands to the \env{tabular} vertical alignment specifier used by \gls{DTLdisplaydb}}
  }
  % \dtldisplaydbenv
  \gcmd{dtl\-display\-db\-env}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{tabular}
    \desc{expands to the name of the environment used by
      \gls{DTLdisplaydb}}
  }
  % \dtldisplaylongdbenv
  \gcmd{dtl\-display\-long\-db\-env}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{longtable}
    \desc{expands to the name of the environment used by
      \gls{DTLdisplaylongdb}}
  }
  % \DTLdisplayTBrowidxmap
  \gcmd{DTL\-display\-TB\-row\-idx\-map}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{idx}}
    \desc{provided for use with \displayopt{row-idx-map-function},
this command expands to a row index that will arrange data rows from
top to bottom instead of left to right when \displayopt{per-row} is
greater than 1. Note that this is only designed to work when no rows
are omitted}
  }
  % \dtlstringalign
  \gcmd{dtl\-string\-align}
  {
    \providedby{\sty{datatool} v2.0+}
    \initval{l}
    \desc{expands to the column alignment specifier used by \gls{DTLdisplaydb}
      and \gls{DTLdisplaylongdb} for columns with the string data
type. Ignored if the \displayopt{align-specs} option is set}
  }
  % \dtlintalign
  \gcmd{dtl\-int\-align}
  {
    \providedby{\sty{datatool} v2.0+}
    \initval{r}
    \desc{expands to the column alignment specifier used by \gls{DTLdisplaydb}
      and \gls{DTLdisplaylongdb} for columns with the integer data
type. Ignored if the \displayopt{align-specs} option is set}
  }
  % \dtlrealalign
  \gcmd{dtl\-real\-align}
  {
    \providedby{\sty{datatool} v2.0+}
    \initval{r}
    \desc{expands to the column alignment specifier used by \gls{DTLdisplaydb}
      and \gls{DTLdisplaylongdb} for columns with the decimal (real)
data type. Ignored if the \displayopt{align-specs} option is set}
  }
  % \dtlcurrencyalign
  \gcmd{dtl\-currency\-align}
  {
    \providedby{\sty{datatool} v2.0+}
    \initval{r}
    \desc{expands to the column alignment specifier used by \gls{DTLdisplaydb}
      and \gls{DTLdisplaylongdb} for columns with the currency data
type. Ignored if the \displayopt{align-specs} option is set}
  }
  % \dtlbeforecols
  \gcmd{dtl\-before\-cols}
  {
    \providedby{\sty{datatool} v2.0+}
    \initvalempty
    \desc{expands to content to be inserted by \gls{DTLdisplaydb}
      and \gls{DTLdisplaylongdb} at the start of the
      alignment specification. Ignored if the
\displayopt{align-specs} option is set}
  }
  % \dtlbetweencols
  \gcmd{dtl\-between\-cols}
  {
    \providedby{\sty{datatool} v2.0+}
    \initvalempty
    \desc{expands to content to be inserted by \gls{DTLdisplaydb}
      and \gls{DTLdisplaylongdb} between the column
      alignment specifiers. Ignored if the \displayopt{align-specs}
option is set}
  }
  % \dtlaftercols
  \gcmd{dtl\-after\-cols}
  {
    \providedby{\sty{datatool} v2.0+}
    \initvalempty
    \desc{expands to content to be inserted by \gls{DTLdisplaydb}
      and \gls{DTLdisplaylongdb} at the end of the
      alignment specification. Ignored if the
\displayopt{align-specs} option is set}
  }
  % \dtldisplaystartrow
  \gcmd{dtl\-display\-start\-row}
  {
    \providedby{\sty{datatool} v2.0+}
    \initvalempty
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to
    insert content at the start of each row}
  }
  % \dtladdalign
  \gcmd{dtl\-add\-align}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\ \meta{align-token-tl} \margm{type}\margm{col-num}\margm{max-cols}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to add
     the appropriate column alignment specifier to the
      \meta{align-token-tl} token list variable. Not used if the
     \displayopt{align-specs} option is set}
  }
  % \dtladdheaderalign
  \gcmd{dtl\-add\-header\-align}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\ \meta{align-token-tl} \margm{type}\margm{col-num}\margm{max-cols}}
    \desc{used by \gls{DTLdisplaydb} and \gls{DTLdisplaylongdb} to add
     the appropriate column alignment specifier for the header row to the
      \meta{align-token-tl} token list variable. Not used if the
     \displayopt{header-row} option is set}
  }
  % \DTLdisplaydbAddBegin
  \gcmd{DTL\-display\-db\-Add\-Begin}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{content-tl-var}\margm{align-spec}\margm{header}}
    \desc{used by \gls{DTLdisplaydb} to add the start of the
     \env{tabular} environment to \meta{content-tl-var}}
  }
  % \DTLdisplaydbAddEnd
  \gcmd{DTL\-display\-db\-Add\-End}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{content-tl-var}}
    \desc{used by \gls{DTLdisplaydb} to add the end of the
     \env{tabular} environment to \meta{content-tl-var}}
  }
  % \DTLdisplaylongdbAddBegin
  \gcmd{DTL\-display\-long\-db\-Add\-Begin}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{content-tl-var}\margm{align-spec}\margm{header}}
    \desc{used by \gls{DTLdisplaylongdb} to add the start of the
     \env{tabular} environment to \meta{content-tl-var}}
  }
  % \DTLdisplaylongdbAddEnd
  \gcmd{DTL\-display\-long\-db\-Add\-End}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{content-tl-var}}
    \desc{used by \gls{DTLdisplaylongdb} to add the end of the
     \env{tabular} environment to \meta{content-tl-var}}
  }
  % \DTLdisplaydbAddItem
  \gcmd{DTL\-display\-db\-Add\-Item}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{content-tl-var}\margm{item}\margm{fmt-cs}\margm{type}\margm{row-num}\margm{row-idx}\margm{col-num}\margm{col-idx}}
    \desc{appends the item to the \meta{content-tl-var} token list
    variable during construction within \gls{DTLdisplaydb} and
    \gls{DTLdisplaylongdb}}
  }
  % \datatool_if_row_start:nnTF and \datatool_if_row_start_p:nn
  \gexplpred{datatool\dsb if\dsb row\dsb start}{nn}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\ \margm{row-num} \margm{col-num} \TFsyntax}
    \desc{for use with display hooks such as
\gls{DTLdisplaydbAddItem}, this tests if the given combination of \meta{row-num} and
\meta{col-num} corresponds to the first column of the
\env{tabular} or \env{longtable} environment, taking the
\displayopt{per-row} setting into account}
  }
  % \l_datatool_display_per_row_int
  \gcmd{l\dsb data\-tool\dsb display\dsb per\dsb row\dsb int}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{integer variable that corresponds to the
\displayopt{per-row} option}
  }
  % \l_datatool_display_tab_rows_int
  \gcmd{l\dsb data\-tool\dsb display\dsb tab\dsb rows\dsb int}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{integer variable set to the database row count divided by
the value of \displayopt{per-row} rounded up}
  }
  % \dtlrownum
  \gcmd{dtl\-row\-num}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{a count register used by various commands to keep track of
     a row number, which may be used by hooks}
  }
  % \dtlcolumnnum
  \gcmd{dtl\-column\-num}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{a count register used by various commands to keep track of
     a column number, which may be used by hooks}
  }
  % \l_datatool_caption_tl
  \gcmd{l\dsb datatool\dsb caption\dsb tl}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{\csfmt{c\_novalue\_tl}}
    \desc{a token list variable assigned by the \displayopt{caption} key}
  }
  % \l_datatool_short_caption_tl
  \gcmd{l\dsb datatool\dsb short\dsb caption\dsb tl}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{\csfmt{c\_novalue\_tl}}
    \desc{a token list variable assigned by the \displayopt{short-caption} key}
  }
  % \l_datatool_cont_caption_tl
  \gcmd{l\dsb datatool\dsb cont\dsb caption\dsb tl}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{\csfmt{c\_novalue\_tl}}
    \desc{a token list variable assigned by the \displayopt{cont-caption} key}
  }
  % \l_datatool_label_tl
  \gcmd{l\dsb datatool\dsb label\dsb tl}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{\csfmt{c\_novalue\_tl}}
    \desc{a token list variable assigned by the \displayopt{label} key}
  }
  % \l_datatool_post_head_tl
  \gcmd{l\dsb datatool\dsb post\dsb head\dsb tl}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{\csfmt{c\_novalue\_tl}}
    \desc{a token list variable assigned by the \displayopt{post-head} key}
  }
  % \l_datatool_foot_tl
  \gcmd{l\dsb datatool\dsb foot\dsb tl}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{\csfmt{c\_novalue\_tl}}
    \desc{a token list variable assigned by the \displayopt{foot} key}
  }
  % \l_datatool_last_foot_tl
  \gcmd{l\dsb datatool\dsb last\dsb foot\dsb tl}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{\csfmt{c\_novalue\_tl}}
    \desc{a token list variable assigned by the \displayopt{last-foot} key}
  }
  % \l_datatool_include_header_bool
  \gcmd{l\dsb datatool\dsb include\dsb header\dsb bool}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{true}
    \desc{a boolean variable corresponding to the inverse of the
       \displayopt{no-header} key}
  }
  % \DTLassign
  \gcmd{DTL\-assign}
  {
    \providedby{\sty{datatool} v2.10+}
    \syntax{\margm{db-name}\margm{row idx}\marg{\idx{assign-list}}}
    \desc{selects the \idx{current-row} according to its row index
     \meta{row idx} (using \gls{dtlgetrow}) and globally 
     defines the commands in the assignment list
    \idx{assign-list} for the row identified by the row index
    \meta{row idx} in the database identified by \meta{db-name}. This
    command is not affected by the \opt{global} option. If you
     prefer a local assignment, use \gls{dtlgetrow} and
    \gls{DTLassignfromcurrentrow} instead}
  }
  % \DTLassignfirstmatch
  \gcmd{DTL\-assign\-first\-match}
  {
    \providedby{\sty{datatool} v2.10+}
    \syntax{\margm{db-name}\margm{col key}\margm{value}\marg{\idx{assign-list}}}
    \desc{globally defines the commands in the assignment list
    \idx{assign-list} for the first row in the database identified
    by \meta{db-name} where the column identified by \meta{col key}
    matches \meta{value}. This command is not affected by the \opt{global} option}
  }
  % \xDTLassignfirstmatch
  \gcmd{xDTL\-assign\-first\-match}
  {
    \providedby{\sty{datatool} v2.10+}
    \syntax{\margm{db-name}\margm{col key}\margm{value}\marg{\idx{assign-list}}}
    \desc{as \gls{DTLassignfirstmatch} but performs one-level
    expansion of \meta{value}}
  }
  % \DTLgetkeydata
  \gcmds{DTL\-get\-key\-data}
  {
    \providedby{\sty{datatool} v2.10+}
    \syntax{\margm{col key}\margm{db-name}\margm{col cs}\margm{type cs}\margm{header cs}}
    \desc{gets data for the column identified by \meta{col key} in
the database identified by \meta{db-name} and locally assigns the
commands \meta{col cs} (to the column index), \meta{type cs} (to the
column type) and \meta{header cs} (to the column header). 
    The unstarred version tests for the existence of the database.
    This command is not affected by the \opt{global} option}
  }
  % \dtlgetrow
  \gcmd{dtl\-get\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db-name}\margm{row idx}}
    \desc{gets the row identified by the row index \meta{row idx}
from the database identified by \meta{db-name} and stores the row in 
\gls{dtlcurrentrow} with preceding rows in \gls{dtlbeforerow} and
following rows in \gls{dtlafterrow}. The row index is stored in
\gls{dtlrownum}, and the database label \meta{db-name} is stored in
\gls{dtldbname}. This command assumes that the given row exists.
Assignments are local. This command does not check the \opt{global}
option}
  }
  % \DTLassignfromcurrentrow
  \gcmd{DTL\-assign\-from\-current\-row}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\marg{\idx{assign-list}}}
    \desc{assignments elements in the \idx{current-row}
    (\gls{dtlcurrentrow}) to the provided placeholder commands in
the \idx{assign-list}}
  }
  % \dtlcurrentrow
  \gcmd{dtl\-current\-row}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{token register used to store the \idx{current-row}. Once set by
    commands such as \gls{DTLforeach} or \gls{dtlgetrow}, the row
    content can then be referenced or modified by commands 
    like \gls{dtlreplaceentryincurrentrow}}
  }
  % \dtlbeforerow
  \gcmd{dtl\-before\-row}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{token register used to store the content before the
    \idx{current-row} when \gls{dtlcurrentrow} is set}
  }
  % \dtlafterrow
  \gcmd{dtl\-after\-row}
  {
    \providedby{\sty{datatool} v2.0+}
    \desc{token register used to store the content after the
    \idx{current-row} when \gls{dtlcurrentrow} is set}
  }
  % \dtlgetrowforvalue
  \gcmd{dtl\-get\-row\-for\-value}
  {
    \providedby{\sty{datatool} v2.11+}
    \syntax{\margm{db-name}\margm{col idx}\margm{value}}
    \desc{as \gls{dtlgetrow} but gets the row where the entry in the
    column identified by its index \meta{col idx} matches
    \meta{value}}
  }
  % \edtlgetrowforvalue
  \gcmd{edtl\-get\-row\-for\-value}
  {
    \providedby{\sty{datatool} v2.17+}
    \syntax{\margm{db-name}\margm{col idx}\margm{value}}
    \desc{as \gls{dtlgetrowforvalue} but first expands \meta{value}}
  }
  % \DTLfetch
  \gcmd{DTL\-fetch}
  {
    \providedby{\sty{datatool} v2.17+}
    \syntax{\margm{db-name}\margm{col1 key}\margm{col1 value}\margm{col2 key}}
    \desc{fetches and displays the value for the column identified
    by \meta{col2 key} in the first row where the element in the
    column identified by \meta{col1 key} matches the expansion of
    the value \meta{col1 value} in the database identified by \meta{db-name}. 
    This is a shortcut command that uses \gls{edtlgetrowforvalue} and 
    \gls{dtlgetentryfromcurrentrow}}
  }
  % \dtlrecombine
  \gcmd{dtl\-re\-combine}
  {
     \providedby{\sty{datatool}}
     \desc{recombines the database (identified by \gls{dtldbname}) 
     from \gls{dtlbeforerow}, \gls{dtlcurrentrow} and \gls{dtlafterrow}. 
     This command checks the \opt{global} option}
  }
  % \dtlrecombineomitcurrent
  \gcmd{dtl\-re\-combine\-omit\-current}
  {
     \providedby{\sty{datatool}}
     \desc{as \gls{dtlrecombine} but omits the \idx{current-row} (that is,
     the current row is deleted from the database)}
  }
  % \dtlsplitrow
  \gcmd{dtl\-split\-row}
  {
     \providedby{\sty{datatool}}
     \syntax{\margm{row specs}\margm{col num}\margm{before cs}\margm{after cs}}
     \desc{splits the \meta{row specs} around the entry identified
by \meta{col num}. The control sequence \meta{before cs} is defined
to the row entry specs for the entries before the split, and the
control sequence \meta{after cs} is defined to the row entry specs
for the entries after the split. Note that the \meta{row specs} must
be in the special row spec format and the \meta{col num} needs to be 
expanded before use}
  }
  % \dtlreplaceentryincurrentrow
  \gcmd{dtl\-re\-place\-entry\-in\-current\-row}
  {
     \providedby{\sty{datatool} v2.10+}
     \syntax{\margm{new value}\margm{col idx}}
     \desc{replaces the entry for the column identified by the index
\meta{col idx} in \gls{dtlcurrentrow} with the given value \meta{new
value}. The column data is updated according to the new value
honouring the \opt{global} option (but \gls{dtlcurrentrow} will only
be locally changed)}
  }
  % \dtlremoveentryincurrentrow
  \gcmd{dtl\-remove\-entry\-in\-current\-row}
  {
     \providedby{\sty{datatool} v2.10+}
     \syntax{\margm{col idx}}
     \desc{locally removes the entry for the column identified by the index
\meta{col idx} from \gls{dtlcurrentrow}}
  }
  % \dtlswapentriesincurrentrow
  \gcmd{dtl\-swap\-entries\-in\-current\-row}
  {
     \providedby{\sty{datatool} v2.10+}
     \syntax{\margm{col1 num}\margm{col2 num}}
     \desc{locally swaps the values in the columns identified by their
     index, \meta{col1 num} and \meta{col2 num}, in \gls{dtlcurrentrow}}
  }
  % \dtlmapcurrentrow
  \gcmd{dtl\-map\-current\-row}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\margm{cs}\margm{body}}
     \desc{iterates over the columns of the current row (as stored in
\gls{dtlcurrentrow}) and, at each iteration, defines the control
sequence \meta{cs} to the current column and does \meta{body}}
  }
  % \dtlgetentryfromcurrentrow
  \gcmd{dtl\-get\-entry\-from\-current\-row}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\margm{cs}\margm{col num}}
     \desc{gets the value for the column identified by its index
     \meta{col num} in \gls{dtlcurrentrow} and locally defines the control sequence
     \meta{cs} to that value. This is just a shortcut that uses
     \gls{dtlgetentryfromrow}}
  }
  % \dtlgetentryfromrow
  \gcmd{dtl\-get\-entry\-from\-row}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\margm{cs}\margm{col num}\margm{row toks}}
     \desc{gets the value for the column identified by its index
     \meta{col num} in the token \meta{row toks} (that should be in
     the correct row spec format) and locally defines the control sequence
     \meta{cs} to that value}
  }
  % \dtlappendentrytocurrentrow
  \gcmd{dtl\-append\-entry\-to\-current\-row}
  {
     \providedby{\sty{datatool} v2.10+}
     \syntax{\margm{col key}\margm{value}}
     \desc{appends an entry with the given \meta{value} to 
     \gls{dtlcurrentrow} for the column identified by \meta{col key}.
     The row must not already contain an element in the given column.
      The column data is updated according to \meta{value}
      (the \opt{global} option is checked)}
  }
  % \dtlupdateentryincurrentrow
  \gcmd{dtl\-up\-date\-entry\-in\-current\-row}
  {
     \providedby{\sty{datatool} v2.11+}
     \syntax{\margm{col key}\margm{value}}
     \desc{appends the entry, as per
     \gls{dtlappendentrytocurrentrow}, if there is no entry for the given
     column in the \idx{current-row}, otherwise updates the entry}
  }
  % \dtlswaprows
  \gcmd{dtl\-swap\-rows}
  {
     \providedby{\sty{datatool}}
     \syntax{\margm{db-name}\margm{row1-idx}\margm{row2-idx}}
     \desc{swaps the rows identified by their index. No check is performed
     to determine if the database exists or if the indexes are in range}
  }
  % \DTLgetvalue
  \gcmd{DTL\-get\-value}
  {
     \providedby{\sty{datatool}}
     \syntax{\margm{cs}\margm{db-name}\margm{row idx}\margm{col idx}}
     \desc{gets the element in the row identified by \meta{row idx}
     for the column identified by its index \meta{col idx} in the
     database identified by \meta{db-name} and defines the control
     sequence \meta{cs} to expand to the element's value}
  }
  % \DTLgetlocation
  \gcmd{DTL\-get\-location}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{row-cs}\margm{col-cs}\margm{db-name}\margm{value}}
    \desc{defines the control sequences \meta{row-cs} and
\meta{col-cs} to expand to the row and column indexes, respectively,
of the first entry in the database identified by \meta{db-name} that
matches the given \meta{value}}
  }
  % \DTLgetrowindex
  \gcmds{DTL\-get\-row\-index}
  {
    \providedby{\sty{datatool} v2.11+}
    \syntax{\margm{row-cs}\margm{db-name}\margm{col idx}\margm{value}}
    \desc{defines the control sequence \meta{row cs} to expand to
     the row index of the first entry in the column identified by its
     index \meta{col idx} that matches the given \meta{value}
     in the database identified by \meta{db-name}.
     The unstarred version triggers an error if not found}
  }
  % \dtlgetrowindex
  \gcmd{dtl\-get\-row\-index}
  {
    \providedby{\sty{datatool} v2.11+}
    \syntax{\margm{row-cs}\margm{db-name}\margm{col idx}\margm{value}}
    \desc{as \gls{DTLgetrowindex} but doesn't produce an error if
     not found}
  }
  % \xdtlgetrowindex
  \gcmd{xdtl\-get\-row\-index}
  {
    \providedby{\sty{datatool} v2.28+}
    \syntax{\margm{row-cs}\margm{db-name}\margm{col idx}\margm{value}}
    \desc{as \gls{dtlgetrowindex} but expands the value}
  }
  % \DTLcomputebounds
  \gcmd{DTL\-compute\-bounds}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\margm{db-list}\margm{x-key}\margm{y-key}\margm{minX cmd}\margm{minY cmd}\margm{maxX cmd}\margm{maxY cmd}}
    \desc{computes the maximum and minimum $x$ and $y$ values over all databases
listed in \meta{db-list} for the columns identified by \meta{x-key}
and \meta{y-key}}
  }
  % \DTLsumforkeys
  \gcmd{DTL\-sum\-for\-keys}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\oarg{\idx{assign-list}}\margm{db
list}\margm{key list}\margm{cmd}}
    \desc{sums over all numeric values in the listed columns in the
given databases and stores the result as a \idx{formattednumber} in
the control sequence \meta{cmd}. The optional arguments may be used
to skip rows where the condition evaluates to false}
  }
  % \DTLsumcolumn
  \gcmd{DTL\-sum\-column}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db}\margm{key}\margm{cmd}}
    \desc{sums all numeric values in the column with the label
    \meta{key} of the database identified by \meta{db} and stores
    the result as a \idx{formattednumber} in the control sequence
\meta{cmd}}
  }
  % \DTLmeanforkeys
  \gcmd{DTL\-mean\-for\-keys}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\oarg{\idx{assign-list}}\margm{db list}\margm{key list}\margm{cmd}}
    \desc{computes the mean (average) over all numeric values in the listed columns in the
given databases and stores the result as a \idx{formattednumber} in
the control sequence \meta{cmd}. The optional arguments may be used
to skip rows where the condition evaluates to false}
  }
  % \DTLmeanforcolumn
  \gcmd{DTL\-mean\-for\-column}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db}\margm{key}\margm{cmd}}
    \desc{computes the mean (average) over all numeric values in the column with the label
    \meta{key} of the database identified by \meta{db} and stores
    the result as a \idx{formattednumber} in the control sequence
\meta{cmd}}
  }
  % \DTLvarianceforkeys
  \gcmd{DTL\-variance\-for\-keys}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\oarg{\idx{assign-list}}\margm{db
list}\margm{key list}\margm{cmd}}
    \desc{computes the variance over all numeric values in the listed columns in the
given databases and stores the result as a \idx{formattednumber} in
the control sequence \meta{cmd}. The optional arguments may be used
to skip rows where the condition evaluates to false}
  }
  % \DTLvarianceforcolumn
  \gcmd{DTL\-variance\-for\-column}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db}\margm{key}\margm{cmd}}
    \desc{computes the variance over all numeric values in the column with the label
    \meta{key} of the database identified by \meta{db} and stores
    the result as a \idx{formattednumber} in the control sequence
\meta{cmd}}
  }
  % \DTLsdforkeys
  \gcmd{DTL\-sd\-for\-keys}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\oarg{\idx{assign-list}}\margm{db
list}\margm{key list}\margm{cmd}}
    \desc{computes the standard deviation over all numeric values in the listed columns in the
given databases and stores the result as a \idx{formattednumber} in
the control sequence \meta{cmd}. The optional arguments may be used
to skip rows where the condition evaluates to false}
  }
  % \DTLsdforcolumn
  \gcmd{DTL\-sd\-for\-column}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db}\margm{key}\margm{cmd}}
    \desc{computes the standard deviation over all numeric values in the column with the label
    \meta{key} of the database identified by \meta{db} and stores
    the result as a \idx{formattednumber} in the control sequence
\meta{cmd}}
  }
  % \DTLminforkeys
  \gcmd{DTL\-min\-for\-keys}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\oarg{\idx{assign-list}}\margm{db
list}\margm{key list}\margm{cmd}}
    \desc{determines the minimum value over all numeric values in the listed columns in the
given databases and stores the result as a \idx{formattednumber} in
the control sequence \meta{cmd}. The optional arguments may be used
to skip rows where the condition evaluates to false}
  }
  % \DTLminforcolumn
  \gcmd{DTL\-min\-for\-column}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db}\margm{key}\margm{cmd}}
    \desc{determines the minimum value over all numeric values in the column with the label
    \meta{key} of the database identified by \meta{db} and stores
    the result as a \idx{formattednumber} in the control sequence
\meta{cmd}}
  }
  % \DTLmaxforkeys
  \gcmd{DTL\-max\-for\-keys}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\oarg{\idx{assign-list}}\margm{db list}\margm{key list}\margm{cmd}}
    \desc{determines the maximum value over all numeric values in the listed columns in the
given databases and stores the result as a \idx{formattednumber} in
the control sequence \meta{cmd}. The optional arguments may be used
to skip rows where the condition evaluates to false}
  }
  % \DTLmaxforcolumn
  \gcmd{DTL\-max\-for\-column}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{db}\margm{key}\margm{cmd}}
    \desc{determines the maximum value over all numeric values in the column with the label
    \meta{key} of the database identified by \meta{db} and stores
    the result as a \idx{formattednumber} in the control sequence
\meta{cmd}}
  }
  % COMMANDS: DATABASE - SORTING
  % \DTLsortdata
  \gcmd{DTL\-sort\-data}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\oargm{options}\margm{db-name}\margm{criteria}}
    \desc{sorts a database according to the given criteria, 
     which should be a \keyval\ list}
  }
  % \DTLsortdata options
  % OPTION missing-column-action = {error|warn|ignore}
  \gsortdataopt{missing-column-action}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{error}
    \syntax{\meta{value}}
    \desc{indicates whether an undefined column referenced in the
sort criteria should generate an error, or a warning or be ignored}
  }
  % OPTION replace = {null|null or empty}
  \gsortdataopt{replace}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{null or empty}
    \syntax{\meta{value}}
    \desc{indicates whether only null values or null and empty
     values should be replaced}
  }
  % OPTION function = { fn }
  \gsortdataopt{function}
  {
    \providedby{\sty{datatool} v3.0+}
    \initvalcs{DTLsortwordhandler}
    \syntax{\meta{function}}
    \desc{the handler function to use to convert the sort value to a
byte sequence}
  }
  % OPTION encap = { fn }
  \gsortdataopt{encap}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{cs}}
    \desc{the command to encapsulate values before obtaining
the sort value. The command should be defined to take three
arguments: the actual value, the column index and the
database name}
  }
  % OPTION save-sort-key = { col-key }
  \gsortdataopt{save\dhyphen sort\dhyphen key}
  {
    \providedby{\sty{datatool} v3.0+}
    \initvalempty
    \syntax{\meta{col-key}}
    \desc{if not empty, \gls{DTLsortdata} will save the primary sort values
used in the column identified by the label \meta{col-key}}
  }
  % OPTION save-sort-column = { col-idx }
  \gsortdataopt{save\dhyphen sort\dhyphen column}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{0}
    \syntax{\meta{col-idx}}
    \desc{if not zero, \gls{DTLsortdata} will save the primary sort values
used in the column with the index \meta{col-idx}}
  }
  % OPTION save-sort
  \gsortdataopt{save\dhyphen sort}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{equivalent to \sortdataoptval{save-sort-key}{sort}}
  }
  % OPTION save-group-key = { col-key }
  \gsortdataopt{save\dhyphen group\dhyphen key}
  {
    \providedby{\sty{datatool} v3.0+}
    \initvalempty
    \syntax{\meta{col-key}}
    \desc{if not empty, \gls{DTLsortdata} will save the letter group
obtained from the primary sort value in the column identified by the 
label \meta{col-key}}
  }
  % OPTION save-group-column = { col-idx }
  \gsortdataopt{save\dhyphen group\dhyphen column}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{0}
    \syntax{\meta{col-idx}}
    \desc{if not zero, \gls{DTLsortdata} will save the letter group
obtained from the primary sort value in the column with the index
\meta{col-idx}}
  }
  % OPTION save-group
  \gsortdataopt{save\dhyphen group}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{equivalent to \sortdataoptval{save-group-key}{group}}
  }
  % \DTLsortdata column criteria options
  % OPTION ascending
  \gsortdatacolumnopt{ascending}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{true}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{if true, sort in ascending order}
  }
  % OPTION asc
  \gsortdatacolumnopt{asc}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{synonym of \sortdatacolumnoptval{ascending}{true}}
  }
  % OPTION descending
  \gsortdatacolumnopt{descending}
  {
    \providedby{\sty{datatool} v3.0+}
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{if true, sort descending order. This is an antonym of
     \sortdatacolumnopt{ascending}}
  }
  % OPTION desc
  \gsortdatacolumnopt{desc}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{synonym of \sortdatacolumnoptval{descending}{true}}
  }
  % OPTION replacements
  \gsortdatacolumnopt{replacements}
  {
    \providedby{\sty{datatool} v3.0+}
    \initvalempty
    \syntax{\meta{list}}
    \desc{specifies list of column keys to use as a replacement if
    the sort value is missing (according to the
     \sortdataopt{replace} setting)}
  }
  % \datatool_post_process_lettergroup:N
  \gcmd{datatool\dsb post\dsb process\dsb letter\-group:N}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\ \meta{tl var}}
    \desc{a hook that may be used to post-process the letter group
     token variable after sorting}
  }
  % \dtlsort
  \gcmd{dtl\-sort}
  {
    \providedby{\sty{datatool} v2.13+}
    \syntax{\oargm{replacements}\margm{criteria}\margm{db-name}\margm{handler-cs}}
    \desc{sorts the rows of the database identified by \meta{db-name}}
  }
  % \DTLsort
  \gcmds{DTL\-sort}
  {
    \providedby{\sty{datatool}}
    \syntax{\oargm{replacements}\margm{criteria}\margm{db-name}}
    \desc{uses \gls{dtlsort} to sort the given database. The starred
version uses \gls{dtlicompare} as the handler function, and the
unstarred version uses \gls{dtlcompare}}
  }
  % COMMANDS: DATABASE - IO
  % \DTLread
  \gcmd{DTL\-read}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\oargm{options}\margm{filename}}
     \desc{loads the data in \meta{filename} to create a new database
     or, if applicable, append to an existing database}
  }
  % \DTLwrite
  \gcmd{DTL\-write}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\oargm{options}\margm{filename}}
     \desc{saves the data in the database identified by
     the \ioopt{name} option in the file called \meta{filename}. If the file
     extension is omitted, the default for the given format is used}
  }
  % \dtlspecialvalue
  \gcmd{dtl\-spe\-cial\-value}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{text}}
    \desc{ordinarily simply expands to \meta{text}. However, if
    present at the start of a database element, \gls{DTLwrite} will allow it to
    expand for DBTEX formats during the write operation,
     even if \iooptval{expand}{none} is on}
  }
  % \DTLsetseparator
  \gcmd{DTL\-set\-separator}
  {
     \providedby{\sty{datatool}}
     \syntax{\margm{char}}
     \desc{sets the separator for \idx{CSV} files to \meta{char}}
  }
  % \DTLsetdelimiter
  \gcmd{DTL\-set\-delimiter}
  {
     \providedby{\sty{datatool}}
     \syntax{\margm{char}}
     \desc{sets the delimiter for \idx{CSV} files to \meta{char}}
  }
  % \DTLsettabseparator
  \gcmd{DTL\-set\-tab\-separator}
  {
     \providedby{\sty{datatool}}
     \desc{sets the separator to the \idx{tabchar} in order to load \idx{TSV} files
       and changes the category code for the \idx{tabchar} to 12 \qt{other}}
  }
  % \l_datatool_str_csv_regex_cases_tl
  \gcmd{l\dsb datatool\dsb str\dsb csv\dsb regex\dsb cases\dsb tl}
  {
     \providedby{\sty{datatool} v3.0+}
     \desc{a token list variable containing regular expression cases used 
     by the \iooptval{csv-content}{literal} setting}
  }
  % \DTLrawmap
  \gcmd{DTL\-raw\-map}
  {
     \providedby{\sty{datatool}}
     \syntax{\margm{original}\margm{replacement}}
     \desc{appends a mapping used by the \iooptval{csv-content}{literal} setting}
  }
  % \DTLloaddbtex
  \gcmd{DTL\-load\-db\-tex}
   {
     \deprecated
     \providedby{\sty{datatool} v2.20+}
     \syntax{\margm{cs}\margm{filename}}
     \desc{inputs a \ext{dbtex} file}
     \field{see}{DTLread}
   }
  % \DTLloaddb
  \gcmd{DTL\-load\-db}
   {
     \deprecated
     \providedby{\sty{datatool}}
     \syntax{\oargm{options}\margm{db-name}\margm{filename}}
     \desc{loads a \idx{CSV}\Slash \idx{TSV} file according to the
      current delimiter and separator and globally defines a
      database labelled \meta{db-name}}
     \field{see}{DTLread}
   }
  % \DTLloadrawdb
  \gcmd{DTL\-load\-raw\-db}
   {
     \deprecated
     \providedby{\sty{datatool}}
     \syntax{\oargm{options}\margm{db-name}\margm{filename}}
     \desc{loads a \idx{CSV}\Slash \idx{TSV} file where \TeX\ special
      characters should be interpreted literally according to the
      current delimiter and separator and globally defines a
      database labelled \meta{db-name}}
     \field{see}{DTLread}
   }
  % \DTLsavedb
  \gcmd{DTL\-save\-db}
  {
     \deprecated
     \providedby{\sty{datatool} v2.13+}
     \syntax{\margm{db-name}\margm{filename}}
     \desc{saves the given database as a \idx{CSV} file}
     \field{see}{DTLwrite}
  }
  % \DTLsavetexdb
  \gcmd{DTL\-save\-tex\-db}
  {
     \deprecated
     \providedby{\sty{datatool}}
     \syntax{\margm{db-name}\margm{filename}}
     \desc{saves the given database in DTLTEX v2.0 format}
     \field{see}{DTLwrite}
  }
  % \DTLsaverawdb
  \gcmd{DTL\-save\-raw\-db}
  {
     \deprecated
     \providedby{\sty{datatool} v2.13+}
     \syntax{\margm{db-name}\margm{filename}}
     \desc{saves the given database in its internal form}
     \field{see}{DTLwrite}
  }
  % \DTLprotectedsaverawdb
  \gcmd{DTL\-protected\-save\-raw\-db}
  {
     \deprecated
     \providedby{\sty{datatool} v2.15+}
     \syntax{\margm{db-name}\margm{filename}}
     \desc{similar to \gls{DTLsaverawdb} but designed for database
     with fragile commands}
     \field{see}{DTLwrite}
  }
  % COMMANDS: DATABASE - LOOPS
  % \DTLmapdata
  \gcmd{DTL\-map\-data}
  {
    \common
    \providedby{\sty{datatool} v3.0+}
    \syntax{\oarg{\keyvallist}\margm{loop-body}}
    \desc{iterates over each row in the given database and does
    \meta{loop-body}. Within the loop body, the row index
    is stored in the register \gls{dtlrownum}. Values can be
    accessed with \gls{DTLmapget} or iterated over with \gls{DTLmaprow}
    }
  }
  % \DTLmapdata OPTIONS
  % OPTION name
  \gmapdataopt{name}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{value}}
    \desc{specifies the database. Initialised to the default database}
  }
  % OPTION read-only
  \gmapdataopt{read\dhyphen only}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{boolean}}
    \defval{true}
    \initval{true}
    \desc{if true, switches on read-only mode}
  }
  % OPTION allow-edits
  \gmapdataopt{allow\dhyphen edits}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{boolean}}
    \defval{true}
    \initval{false}
    \desc{an antonym of \mapdataopt{read-only}: 
    if true, switches off read-only mode}
  }
  % \DTLmapdatabreak
  \gcmds{DTLmapdatabreak}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{breaks out of \gls{DTLmapdata} and \env{DTLenvmapdata}.
    The starred version will discard any pending edits}
  }
  % \DTLrmrow
  \gcmd{DTL\-rm\-row}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{only available with \gls{DTLmapdata} and
\mapdataoptval{read-only}{false}, this command will remove the
current iteration row}
  }
  % \DTLsetentry
  \gcmd{DTL\-set\-entry}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\marg{\keyvallist}}
    \desc{only available with \gls{DTLmapdata} and
    \mapdataoptval{read-only}{false}, this command will set a column
    in the current iteration row}
  }
  % \DTLrmentry
  \gcmd{DTL\-rm\-entry}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\marg{\keyvallist}}
    \desc{only available with \gls{DTLmapdata} and
    \mapdataoptval{read-only}{false}, this command will remove a column
    from the current iteration row}
  }
  % \DTLmapdata EDIT OPTIONS
  % OPTION key
  \gmapdataeditopt{key}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{column-key}}
    \desc{identifies a column by its key (label)}
  }
  % OPTION column
  \gmapdataeditopt{column}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{column-index}}
    \desc{identifies a column by its numeric index}
  }
  % OPTION value
  \gmapdataeditopt{value}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{value}}
    \desc{the value}
  }
  % OPTION expand-value
  \gmapdataeditopt{expand\dhyphen value}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{value}}
    \desc{as \mapdataeditopt{value} but fully expands the value}
  }
  % OPTION expand-once-value
  \gmapdataeditopt{expand\dhyphen once\dhyphen value}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{value}}
    \desc{as \mapdataeditopt{value} but expands the value once}
  }
  % \DTLmaprow
  \gcmd{DTL\-map\-row}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{cs}\margm{body}}
    \desc{only for use within the \meta{loop-body} argument of
    \gls{DTLmapdata} or the environment body of \env{DTLenvmapdata},
    this command iterates over each column in the current \gls{DTLmapdata} row, 
    sets \gls{dtlcolumnnum} to the column index and \meta{cs} to the 
    column value and does \meta{body}}
  }
  % \DTLmaprowbreak
  \gcmd{DTL\-map\-row\-break}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{breaks out of \gls{DTLmaprow}}
  }
  % \DTLmapgetvalues
  \gcmds{DTL\-map\-get\-values}
  {
    \common
    \providedby{\sty{datatool} v3.0+}
    \syntax{\marg{\idx{assign-list}}}
    \desc{for use within \gls{DTLmapdata} (or \env{DTLenvmapdata})
    to access values in the current iteration row. The starred form won't
    trigger an error if a column key in \idx{assign-list} isn't
    defined}
  }
  % \DTLmapget
  \gcmd{DTL\-map\-get}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\marg{\keyvallist}}
    \desc{for use within \gls{DTLmapdata} (or \env{DTLenvmapdata})
    to access a value in the current iteration row}
  }
  % \DTLmapget OPTIONS
  % OPTION key
  \gmapgetopt{key}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{value}}
    \desc{specifies the column key}
  }
  % OPTION column
  \gmapgetopt{column}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{value}}
    \desc{specifies the column index}
  }
  % OPTION return
  \gmapgetopt{return}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\meta{cs}}
    \desc{if \meta{cs} is provided, the command \meta{cs} will be
    defined to the obtained value. If \meta{cs} is omitted, the value
    will be inserted into the document}
  }
  % \DTLforeach
  \gcmd{DTL\-for\-each}
  {
    \field{modifiers}{*}
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\margm{db-name}\marg{\idx{assign-list}}\margm{body}}
    \desc{iterates over the database identified by \meta{db-name},
    performs the assignments given in \idx{assign-list} and does
    \meta{body}}
  }
  % \dtlbreak
  \gcmd{dtl\-break}
  {
    \providedby{\sty{datatool-base}}
    \desc{when used in the loop body of \gls{DTLforeach}, this
     command will cause the loop to terminate at the end of the current
     iteration}
  }
  % \dtlforeachlevel
  \gcmd{dtl\-for\-each\-level}
  {
    \providedby{\sty{datatool}}
    \desc{a count register that keeps track of the current
    \gls{DTLforeach} nested level}
  }
  % \DTLrowreset
  \gcmd{DTL\-row\-reset}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{increments \ctr{DTLrow} and resets the counter \ctrfmt{DTLrow\meta{n}} 
    where \meta{n} is one more than \gls{dtlforeachlevel}}
  }
  % \DTLrowincr
  \gcmd{DTL\-row\-incr}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{increments the counter \ctrfmt{DTLrow\meta{n}} 
    where \meta{n} is one more than \gls{dtlforeachlevel}}
  }
  % \DTLtherow
  \gcmd{DTL\-the\-row}
  {
    \providedby{\sty{datatool} v3.0+}
    \desc{uses \csmetafmt{theDTLrow}{n}{} where \meta{n}
     is one more than \gls{dtlforeachlevel}}
  }
  % \DTLcurrentindex
  \gcmd{DTL\-current\-index}
  {
    \providedby{\sty{datatool}}
    \desc{defined by \gls{DTLforeach} to expand to the current
iteration index}
  }
  % \dtlforeachkey
  \gcmd{dtl\-for\-each\-key}
  {
    \providedby{\sty{datatool}}
    \syntax{(\meta{key-cs}\dcomma\meta{col-cs}\dcomma\meta{type-cs}\dcomma\meta{header-cs})%
\csfmt{in}\margm{db-name}\csfmt{do}\margm{body}}
    \desc{iterates over each column in the database identified by
\meta{db-name}, and at each iteration defines \meta{key-cs} to
expand to the column key, \meta{col-cs} to expand to the column
index, \meta{type-cs} to expand to the data type, and
\meta{header-cs} to expand to the column header, and then does
\meta{body}}
  }
  % \datatool_map_keys_function:nn
  \gcmd{data\-tool\dsb map\dsb keys\dsb function:nN}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{db-name}\marg{function}}
    \desc{maps over all the columns in the given database, applying the 
    function to each set of column meta data. The function should have
    four arguments \code{\margm{key}\margm{col-idx}\margm{type}\margm{header}} 
    where \meta{key} is the column key, \meta{col-idx} is the column index,
    \meta{type} is the data type ($-1$ for unknown) and \meta{header} is the column header}
  }
  % \datatool_map_keys_inline:nn
  \gcmd{data\-tool\dsb map\dsb keys\dsb in\-line:nn}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\margm{db-name}\margm{def}}
    \desc{maps over all the columns in the given database, applying the inline
    function to each set of column meta data. Within \meta{def}, 
    \code{\#1} references the column key, \code{\#2} references the column index,
    \code{\#3} references the data type ($-1$ for unknown) and \code{\#4}
    references the column header}
  }
  % \dtlforcolumn
  \gcmds{dtl\-for\-column}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{cs}\margm{db-name}\margm{key}\margm{body}}
    \desc{loops through the column identified by \meta{key} in the database identified
    by \meta{db-name} and, for each iteration, defines \meta{cs} to the value of
    the entry in the row}
  }
  % \dtlforcolumnidx
  \gcmds{dtl\-for\-column\-idx}
  {
    \providedby{\sty{datatool} v2.0+}
    \syntax{\margm{cs}\margm{db-name}\margm{col-idx}\margm{body}}
    \desc{loops through the column with the index \meta{col-idx} in the database identified
    by \meta{db-name} and, for each iteration, defines \meta{cs} to the value of
    the entry in the row}
  }
  % \DTLiffirstrow
  \gcmd{DTL\-if\-first\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{true}\margm{false}}
    \desc{may only be used within \gls{DTLforeach}, this command
     does \meta{true} if the current row is the first iteration of
     the loop (that is, where \ctrfmt{DTLrow\meta{n}} is 1), 
     otherwise it does false. Note that if \gls{DTLforeach} has a
     condition, this references the loop index which may not match
     the actual row index}
  }
  % \DTLiflastrow
  \gcmd{DTL\-if\-last\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{true}\margm{false}}
    \desc{may only be used within \gls{DTLforeach}, this command
     does \meta{true} if the current loop is on the last row}
  }
  % \DTLifoddrow
  \gcmd{DTL\-if\-odd\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{true}\margm{false}}
    \desc{may only be used within \gls{DTLforeach}, this command
     does \meta{true} if the current loop index is odd}
  }
  % \DTLappendtorow
  \gcmd{DTL\-append\-to\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{col-key}\margm{value}}
    \desc{may only be used within the unstarred \gls{DTLforeach}, this command
     will append an entry to the current row with the given value
for the column identified by \meta{col-key}}
  }
  % \DTLreplaceentryforrow
  \gcmd{DTL\-replace\-entry\-for\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{col-key}\margm{value}}
    \desc{may only be used within the unstarred \gls{DTLforeach}, this command
     will replace the entry in the current row with the given value
for the column identified by \meta{col-key}}
  }
  % \DTLremoveentryfromrow
  \gcmd{DTL\-remove\-entry\-from\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{col-key}}
    \desc{may only be used within the unstarred \gls{DTLforeach}, this command
     will remove the entry in the current row 
for the column identified by \meta{col-key}}
  }
  % \DTLremovecurrentrow
  \gcmd{DTL\-remove\-current\-row}
  {
    \providedby{\sty{datatool}}
    \desc{may only be used within the unstarred \gls{DTLforeach}, this command
     will remove the current row}
  }
  % \DTLsavelastrowcount
  \gcmd{DTL\-save\-last\-row\-count}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{cs}}
    \desc{saves the final loop index of the most recent \gls{DTLforeach}
     in \meta{cs}}
  }
  % \DTLforeachkeyinrow
  \gcmd{DTL\-for\-each\-key\-in\-row}
  {
    \providedby{\sty{datatool}}
    \syntax{\margm{cs}\margm{code}}
    \desc{iterates over each column in the current row of
\gls{DTLforeach}, defines \meta{cs} to the value in the current
column, and does \meta{code}}
    \field{seealso}{dtlkey,dtlcol,dtltype,dtlheader}
  }
  % \dtlkey
  \gcmd{dtl\-key}
  {
    \providedby{\sty{datatool}}
    \desc{defined by \gls{DTLforeachkeyinrow} to the current column key}
  }
  % \dtlcol
  \gcmd{dtl\-col}
  {
    \providedby{\sty{datatool}}
    \desc{defined by \gls{DTLforeachkeyinrow} to the current column
index}
  }
  % \dtltype
  \gcmd{dtl\-type}
  {
    \providedby{\sty{datatool}}
    \desc{defined by \gls{DTLforeachkeyinrow} to the current column
type}
  }
  % \dtlheader
  \gcmd{dtl\-header}
  {
    \providedby{\sty{datatool}}
    \desc{defined by \gls{DTLforeachkeyinrow} to the current column
header}
  }
  % 
  % COMMANDS: DATABASE - PLOTS
  % \DTLplot
  \gcmd{DTL\-plot}
  {
    \providedby{\sty{dataplot}}
    \syntax{\oargm{condition}\margm{db-list}\marg{\keyvallist}}
    \desc{plots the data from the listed databases as line or scatter diagrams}
  }
  % \DTLplotwidth
  \gcmd{DTL\-plot\-width}
  {
    \initval{4in}
    \providedby{\sty{dataplot}}
    \desc{dimension that controls the plot width}
  }
  % \DTLplotheight
  \gcmd{DTL\-plot\-height}
  {
    \initval{4in}
    \providedby{\sty{dataplot}}
    \desc{dimension that controls the plot height}
  }
  % \DTLticklength
  \gcmd{DTL\-tick\-length}
  {
    \initval{5pt}
    \providedby{\sty{dataplot}}
    \desc{dimension that specifies length of the tick marks}
  }
  % \DTLminorticklength
  \gcmd{DTL\-minor\-tick\-length}
  {
    \initval{2pt}
    \providedby{\sty{dataplot}}
    \desc{dimension that specifies length of the minor tick marks}
  }
  % \DTLticklabeloffset
  \gcmd{DTL\-tick\-label\-offset}
  {
    \initval{8pt}
    \providedby{\sty{dataplot}}
    \desc{dimension that specifies the offset from the axis to the
tick label}
  }
  % \DTLmintickgap
  \gcmd{DTL\-min\-tick\-gap}
  {
    \initval{20pt}
    \desc{dimension used to obtain the suggested minimum tick gap if not overridden by
    \plotopt{x-tick-gap} or \plotopt{y-tick-gap} or \plotopt{x-tick-points}
    or \plotopt{y-tick-points}}
  }
  % \DTLminminortickgap
  \gcmd{DTL\-min\-minor\-tick\-gap}
  {
    \initval{5pt}
    \desc{dimension used to obtain the suggested minimum minor tick gap when not
     otherwise specified}
  }
  % \DTLlegendxoffset
  \gcmd{DTL\-legend\-x\-off\-set}
  {
    \initval{10pt}
    \providedby{\sty{dataplot}}
    \desc{dimension that specifies the gap between the border of the
plot and the legend for the $x$-axis}
  }
  % \DTLlegendyoffset
  \gcmd{DTL\-legend\-y\-off\-set}
  {
    \initval{10pt}
    \providedby{\sty{dataplot}}
    \desc{dimension that specifies the gap between the border of the
plot and the legend for the $y$-axis}
  }
  % \DTLXAxisStyle
  \gcmd{DTL\-X\-Axis\-Style}
  {
    \initval{-}
    \providedby{\sty{dataplot}}
    \desc{expands to the \sty{tikz} option to use for the $x$-axis
line style}
  }
  % \DTLYAxisStyle
  \gcmd{DTL\-Y\-Axis\-Style}
  {
    \initval{-}
    \providedby{\sty{dataplot}}
    \desc{expands to the \sty{tikz} option to use for the $y$-axis
line style}
  }
  % \DTLmajorgridstyle
  \gcmd{DTL\-major\-grid\-style}
  {
    \initval{color=gray,-}
    \providedby{\sty{dataplot}}
    \desc{expands to the \sty{tikz} option to use for the major grid
line style}
  }
  % \DTLminorgridstyle
  \gcmd{DTL\-minor\-grid\-style}
  {
    \initval{color=lightgray,very thin}
    \providedby{\sty{dataplot}}
    \desc{expands to the \sty{tikz} option to use for the minor grid
line style. If this is redefined to expand to nothing, the minor
grid lines won't be drawn}
  }
  % \ifDTLxticsin
  \gcond{if\-DTL\-x\-tics\-in}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{dataplot}}
    \desc{if true, the $x$ ticks will be drawn inwards (if they
       should be drawn) otherwise they will be draw outwards}
  }
  % \ifDTLyticsin
  \gcond{if\-DTL\-y\-tics\-in}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{dataplot}}
    \desc{if true, the $y$ ticks will be drawn inwards (if they
       should be drawn) otherwise they will be draw outwards}
  }
  % \ifDTLgrid
  \gcond{if\-DTL\-grid}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{dataplot}}
    \desc{if true, a grid will be drawn. The minor grid lines will
only be drawn if the corresponding minor tick mark setting is on}
  }
  % \ifDTLxtics
  \gcond{if\-DTL\-x\-tics}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{dataplot}}
    \desc{if true, the $x$ ticks will be drawn}
  }
  % \ifDTLytics
  \gcond{if\-DTL\-y\-tics}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{dataplot}}
    \desc{if true, the $y$ ticks will be drawn}
  }
  % \ifDTLxminortics
  \gcond{if\-DTL\-x\-minor\-tics}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{dataplot}}
    \desc{if true, the $x$ minor ticks will be drawn}
  }
  % \ifDTLyminortics
  \gcond{if\-DTL\-y\-minor\-tics}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{dataplot}}
    \desc{if true, the $y$ minor ticks will be drawn}
  }
  % \ifDTLbox
  \gcond{if\-DTL\-box}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{dataplot}}
    \desc{if true, the plot will be enclosed in a box}
  }
  % \ifDTLxaxis
  \gcond{if\-DTL\-x\-axis}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{dataplot}}
    \desc{if true, $x$-axis should be drawn}
  }
  % \ifDTLyaxis
  \gcond{if\-DTL\-y\-axis}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{dataplot}}
    \desc{if true, $y$-axis should be drawn}
  }
  % \ifDTLshowmarkers
  \gcond{if\-DTL\-show\-markers}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{dataplot}}
    \desc{if true, markers should be drawn}
  }
  % \ifDTLshowlines
  \gcond{if\-DTL\-show\-lines}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{dataplot}}
    \desc{if true, lines should be drawn}
  }
  % \DTLplotmarks
  \gcmd{DTL\-plot\-marks}
  {
    \providedby{\sty{dataplot}}
    \desc{expands to a comma-separated list of plot marks}
  }
  % \DTLplotlines
  \gcmd{DTL\-plot\-lines}
  {
    \providedby{\sty{dataplot}}
    \desc{expands to a comma-separated list of plot line styles}
  }
  % \DTLplotmarkcolors
  \gcmd{DTL\-plot\-mark\-colors}
  {
    \providedby{\sty{dataplot}}
    \desc{expands to a comma-separated list of colour specifications
     for plot marks}
  }
  % \DTLplotlinecolors
  \gcmd{DTL\-plot\-line\-colors}
  {
    \providedby{\sty{dataplot}}
    \desc{expands to a comma-separated list of colour specifications
     for plot lines}
  }
  % \DTLplotatbegintikz
  \gcmd{DTL\-plot\-at\-begin\-tikz}
  {
    \providedby{\sty{dataplot}}
    \desc{hook used at the start of the \env{tikzpicture}
    environment within \gls{DTLplot}}
  }
  % \DTLplotatendtikz
  \gcmd{DTL\-plot\-at\-end\-tikz}
  {
    \providedby{\sty{dataplot}}
    \desc{hook used at the end of the \env{tikzpicture}
    environment within \gls{DTLplot}}
  }
  % \DTLminX
  \gcmd{DTL\-min\-X}
  {
    \providedby{\sty{dataplot}}
    \desc{placeholder for use in \gls{DTLplot} hooks, this expands
    to the minimum $x$ value of the plot bounds}
  }
  % \DTLminY
  \gcmd{DTL\-min\-Y}
  {
    \providedby{\sty{dataplot}}
    \desc{placeholder for use in \gls{DTLplot} hooks, this expands
    to the minimum $y$ value of the plot bounds}
  }
  % \DTLmaxX
  \gcmd{DTL\-max\-X}
  {
    \providedby{\sty{dataplot}}
    \desc{placeholder for use in \gls{DTLplot} hooks, this expands
    to the maximum $x$ value of the plot bounds}
  }
  % \DTLmaxY
  \gcmd{DTL\-max\-Y}
  {
    \providedby{\sty{dataplot}}
    \desc{placeholder for use in \gls{DTLplot} hooks, this expands
    to the maximum $y$ value of the plot bounds}
  }
  % \dtlplothandlermark
  \gcmd{dtl\-plot\-handler\-mark}
  {
    \providedby{\sty{dataplot} v2.15+}
    \syntax{\margm{mark code}}
    \desc{only for use within the \gls{DTLplot} hooks, this resets
    the \sty{pgf} transformation matrix and uses 
    \code{\gls{pgfplothandlermark}\margm{mark code}}}
  }
  % \DTLplotstream
  \gcmd{DTL\-plot\-stream}
  {
    \providedby{\sty{dataplot}}
    \syntax{\oargm{condition}\margm{db-name}\margm{x-key}\margm{y-key}}
    \desc{adds data from columns identified by \meta{x-key} and
     \meta{y-key} from the given database to the current \sty{pgf} plot
     stream}
  }
  % \dataplot_apply_pgftransform:
  \gcmd{dataplot\dsb apply\dsb pgftransform:}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{for use within \gls{DTLplotatbegintikz} this may be used
    to restore \gls{DTLplot}['s] transformation matrix if the hook has
    altered it}
  }
  % \DTLaddtoplotlegend
  \gcmd{DTL\-add\-to\-plot\-legend}
  {
    \providedby{\sty{dataplot}}
    \syntax{\margm{marker}\margm{line style}\margm{text}}
    \desc{adds an entry to the legend}
  }
  % \l_dataplot_legend_tl
  \gcmd{l\dsb data\-plot\dsb legend\dsb tl}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{token list variable used to construct the legend}
  }
  % \dataplot_legend_add_begin:
  \gcmd{dataplot\dsb legend\dsb add\dsb begin:}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{adds the beginning of the legend code to \gls{ldataplotlegendtl}}
  }
  % \dataplot_legend_add_end:
  \gcmd{dataplot\dsb legend\dsb add\dsb end:}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{adds the end of the legend code to \gls{ldataplotlegendtl}}
  }
  % \dataplot_get_default_legend:Nnnnn
  \gcmd{data\-plot\dsb get\dsb default\dsb legend:Nnnnn}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\ \meta{tl-var} \margm{db-index} \margm{db-name} \margm{x-key} \margm{y-key}}
    \desc{gets the default legend label (if not provided by
     \plotopt{legend-labels}). The label should be stored in the
     provided token list variable \meta{tl-var}, which will
     initially be empty}
  }
  % \l_dataplot_legend_names_prop
  \gcmd{l\dsb dataplot\dsb legend\dsb names\dsb prop}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{property list used by \gls{DTLplotlegendname} and modified
    by \gls{DTLplotlegendsetname}}
  }
  % \l_dataplot_legend_name_tl
  \gcmd{l\dsb dataplot\dsb legend\dsb name\dsb tl}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{token list variable specifically for accessing values in
the \gls{ldataplotlegendnamesprop} property list}
  }
  % \l_dataplot_stream_index_int
  \gcmd{l\dsb dataplot\dsb stream\dsb index\dsb int}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{integer variable that keeps track of the stream index
    (starting from 1)}
  }
  % \DTLplotlegendname
  \gcmd{DTL\-plot\-legend\-name}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\oargm{db-index}\margm{db-name}}
    \desc{if there more than one database is supplied for the plot
     or if there is only a single \plotopt{x} and \plotopt{y} key, 
     the legend will include this command to typeset the database
     name or a mapping that was previously provided with
     \gls{DTLplotlegendsetname}}
  }
  % \DTLplotlegendsetname
  \gcmd{DTL\-plot\-legend\-set\-name}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{db-name}\margm{text}}
    \desc{provides a mapping from a database name to \meta{text},
which \gls{DTLplotlegendname} should use instead of \meta{db-name}}
  }
  % \DTLplotlegendxy
  \gcmd{DTL\-plot\-legend\-xy}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\oargm{db-index}\margm{db-name}\oargm{x-index}\margm{x-key}\oargm{y-index}\margm{y-key}}
    \desc{if there are multiple keys listed in \plotopt{x},
    this command will be used to show both the $x$ and $y$ headers
    in the legend}
    \field{seealso}{DTLplotlegendx,DTLplotlegendy,DTLplotlegendxysep}
  }
  % \l_dataplot_legend_xlabels_prop
  \gcmd{l\dsb dataplot\dsb legend\dsb xlabels\dsb prop}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{property list used by \gls{DTLplotlegendx} and modified
    by \gls{DTLplotlegendsetxlabel}}
  }
  % \l_dataplot_legend_xlabel_tl
  \gcmd{l\dsb dataplot\dsb legend\dsb xlabel\dsb tl}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{token list variable specifically for accessing values in
the \gls{ldataplotlegendxlabelsprop} property list}
  }
  % \DTLplotlegendsetxlabel
  \gcmd{DTL\-plot\-legend\-set\-x\-label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{x-key}\margm{text}}
    \desc{provides a mapping from a column key to \meta{text},
which \gls{DTLplotlegendx} should use instead of the column header}
  }
  % \DTLplotlegendx
  \gcmd{DTL\-plot\-legendx}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\oargm{db-index}\margm{db-name}\oargm{x-index}\margm{x-key}}
    \desc{used by \gls{DTLplotlegendxy} show the $x$ label in the
    legend.  The default definition is to show the header
    for the column identified by \meta{x-key} unless a mapping has
been provided with \gls{DTLplotlegendsetxlabel}. The optional
arguments are ignored}
  }
  % \DTLplotlegendy
  \gcmd{DTL\-plot\-legendy}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\oargm{db-index}\margm{db-name}\oargm{y-index}\margm{y-key}}
    \desc{the legend will show the $y$ text using this command
    if the \plotopt{y} option had more than one key.
    The default definition is to show the header
    for the column identified by \meta{y-key} unless a mapping has
    been provided with \gls{DTLplotlegendsetylabel}. The optional
arguments are ignored}
  }
  % \DTLplotlegendsetylabel
  \gcmd{DTL\-plot\-legend\-set\-y\-label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{y-key}\margm{text}}
    \desc{provides a mapping from a column key to \meta{text},
which \gls{DTLplotlegendy} should use instead of the column header}
  }
  % \l_dataplot_legend_ylabels_prop
  \gcmd{l\dsb dataplot\dsb legend\dsb ylabels\dsb prop}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{property list used by \gls{DTLplotlegendy} and modified
    by \gls{DTLplotlegendsetylabel}}
  }
  % \l_dataplot_legend_ylabel_tl
  \gcmd{l\dsb dataplot\dsb legend\dsb ylabel\dsb tl}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{token variable list specifically for accessing values in
the \gls{ldataplotlegendylabelsprop} property list}
  }
  % \DTLplotlegendxysep
  \gcmd{DTL\-plot\-legend\-xy\-sep}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{if there are more than one column keys in \plotopt{x},
     this command will be used to separate the $x$ label from the
     $y$ label. The default definition is a slash with a space on
     either side}
  }
  % \DTLplotlegendnamesep
  \gcmd{DTL\-plot\-legend\-name\-sep}
  {
    \initval{\visiblespace}
    \providedby{\sty{dataplot} v3.0+}
    \desc{if more than one database was specified, this command will
be placed after \gls{DTLplotlegendname}}
  }
  % \l_dataplot_x_key_int
  \gcmd{l\dsb data\-plot\dsb x\dsb key\dsb int}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{integer variable used by \gls{DTLplot} to keep track of
     the index of the \plotopt{x} list}
  }
  % \l_dataplot_y_key_int
  \gcmd{l\dsb data\-plot\dsb y\dsb key\dsb int}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{integer variable used by \gls{DTLplot} to keep track of
     the index of the \plotopt{y} list}
  }
  % \dataplot_x_key_count:
  \gcmd{data\-plot\dsb x\dsb key\dsb count:}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{may be used with \gls{DTLplot} hooks to return the total number of 
     items given in the \plotopt{x} list}
  }
  % \dataplot_y_key_count:
  \gcmd{data\-plot\dsb y\dsb key\dsb count:}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{may be used with \gls{DTLplot} hooks to return the total number of 
     items given in the \plotopt{y} list}
  }
  % \dataplot_db_count:
  \gcmd{data\-plot\dsb db\dsb count:}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{may be used with \gls{DTLplot} hooks to return the total number of 
     database names}
  }
  % \l_dataplot_stream_tl
  \gcmd{l\dsb dataplot\dsb stream\dsb tl}
  {
    \providedby{\sty{dataplot} v3.0+}
    \desc{token list variable used by \gls{DTLplot} to construct the
    plot stream code}
  }
  % \DTLformatlegend
  \gcmd{DTL\-format\-legend}
  {
    \providedby{\sty{dataplot}}
    \syntax{\margm{legend code}}
    \desc{outer formatting of the legend}
  }
  % \DTLcustomlegend
  \gcmd{DTL\-custom\-legend}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{legend code}}
    \desc{used to position the legend with
    \plotoptval{legend}{custom}. This command should be redefined as
     applicable}
  }
  % \DTLplotdisplayticklabel
  \gcmd{DTL\-plot\-display\-tick\-label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{text}}
    \desc{used by both \gls{DTLplotdisplayXticklabel} and 
     \gls{DTLplotdisplayYticklabel} to format the $x$ and $y$ tick
     labels}
  }
  % \DTLplotdisplayXticklabel
  \gcmd{DTL\-plot\-display\-X\-tick\-label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{text}}
    \desc{used to format $x$ tick labels}
  }
  % \DTLplotdisplayYticklabel
  \gcmd{DTL\-plot\-display\-Y\-tick\-label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{text}}
    \desc{used to format $y$ tick labels}
  }
  %
  % COMMANDS: DATABASE - PIE CHARTS
  % \DTLpiechart
  \gcmd{DTL\-pie\-chart}
  {
    \providedby{\sty{datapie}}
    \syntax{\oargm{condition}\margm{settings-list}\margm{db-name}\marg{\idx{assign-list}}}
    \desc{draws a pie chart using data from the database identified
     by \meta{db-name}. The \meta{settings-list} must include
     the \pieopt{variable} setting to identify the placeholder
     command included in \idx{assign-list} that will be assigned to the numeric
     values for the chart}
  }
  % \DTLpievariable
  \gcmd{DTL\-pie\-variable}
  {
    \providedby{\sty{datapie}}
    \desc{placeholder command that may be used in inner or outer
     labels to show the actual value}
  }
  % \DTLpiepercent
  \gcmd{DTL\-pie\-percent}
  {
    \providedby{\sty{datapie}}
    \desc{placeholder command that may be used in inner or outer
     labels to show the percent value}
  }
  % \DTLdisplayinnerlabel
  \gcmd{DTL\-display\-inner\-label}
  {
    \providedby{\sty{datapie}}
     \syntax{\margm{text}}
     \desc{used to format the inner label}
  }
  % \DTLdisplayouterlabel
  \gcmd{DTL\-display\-outer\-label}
  {
    \providedby{\sty{datapie}}
    \syntax{\margm{text}}
    \desc{used to format the outer label}
  }
  % \DTLpieatsegment
  \gcmd{DTL\-pie\-at\-seg\-ment}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\margm{index}\margm{total}\margm{start
angle}\margm{mid angle}\margm{end angle}\margm{shift
angle}\margm{shift offset}\margm{inner offset}\margm{outer offset}}
    \desc{hook used at each segment of the pie chart}
  }
  % \DTLsetpiesegmentcolor
  \gcmd{DTL\-set\-pie\-segment\-color}
  {
    \providedby{\sty{datapie}}
    \syntax{\margm{n}\margm{colour}}
    \desc{assigns the colour for the \meta{n}th segment}
  }
  % \DTLgetpiesegmentcolor
  \gcmd{DTL\-get\-pie\-seg\-ment\-color}
  {
    \providedby{\sty{datapie}}
    \syntax{\margm{n}}
    \desc{expands to the current colour to that associated
     with the \meta{n}th segment or \code{white} if not set}
  }
  % \DTLdopiesegmentcolor
  \gcmd{DTL\-do\-pie\-seg\-ment\-color}
  {
    \providedby{\sty{datapie}}
    \syntax{\margm{n}}
    \desc{locally sets the current colour (with \gls{color}) to that associated
     with the \meta{n}th segment}
  }
  % \DTLdocurrentpiesegmentcolor
  \gcmd{DTL\-do\-current\-pie\-seg\-ment\-color}
  {
    \providedby{\sty{datapie}}
    \desc{locally sets the current text colour to that of the
    current pie segment}
  }
  % \ifDTLcolorpiechart
  \gcond{if\-DTL\-color\-pie\-chart}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{datapie}}
    \desc{this conditional is set to true by the package option
\opt{datapie.color} or the setting \pieopt{segment-default-colors}
and to false by the package option \opt{datapie.gray} or the setting
\pieopt{segment-default-gray}. Note that there's no guarantee that the
colours have been changed after the conditional was set and so
shouldn't be relied upon. This conditional may be deprecated or
removed in a future release}
  }
  % \DTLpieoutlinecolor
  \gcmd{DTL\-pie\-out\-line\-color}
  {
    \initval{black}
    \providedby{\sty{datapie}}
    \desc{expands to the colour name for the segment outline}
  }
  % \DTLpieoutlinewidth
  \gcmd{DTL\-pie\-out\-line\-width}
  {
    \initval{0pt}
    \providedby{\sty{datapie}}
    \desc{length register that stores the width of the segment
outline}
  }
  % \DTLpieatbegintikz
  \gcmd{DTL\-pie\-at\-begin\-tikz}
  {
    \providedby{\sty{datapie}}
    \desc{hook used by \gls{DTLpiechart} at the start of the \env{tikzpicture}
environment}
  }
  % \DTLpieatendtikz
  \gcmd{DTL\-pie\-at\-end\-tikz}
  {
    \providedby{\sty{datapie}}
    \desc{hook used by \gls{DTLpiechart} at the end of the \env{tikzpicture}
environment}
  }
  % COMMANDS: DATABASE - BAR CHARTS
  % \DTLbarchart
  \gcmd{DTL\-bar\-chart}
  {
    \providedby{\sty{databar}}
    \syntax{\oargm{condition}\margm{settings-list}\margm{db-name}\marg{\idx{assign-list}}}
    \desc{draws a bar chart using data from the database identified
     by \meta{db-name}. The \meta{settings-list} must include
     the \baropt{variable} setting to identify the placeholder
     command \idx{assign-list} that will be assigned to the numeric
     values for the chart}
  }
  % \DTLmultibarchart
  \gcmd{DTL\-multi\-bar\-chart}
  {
    \providedby{\sty{databar}}
    \syntax{\oargm{condition}\margm{settings-list}\margm{db-name}\marg{\idx{assign-list}}}
    \desc{draws a multi-bar bar chart using data from the database identified
     by \meta{db-name}. The \meta{settings-list} must include
     the \baropt{variables} setting to identify the placeholder
     commands \idx{assign-list} that will be assigned to the numeric
     values for the chart}
  }
  % \DTLbarvariable
  \gcmd{DTL\-bar\-variable}
  {
    \providedby{\sty{databar}}
    \desc{placeholder command that may be used in lower or upper
     labels to show the actual value}
  }
  % \DTLbarvalue
  \gcmd{DTL\-bar\-value}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{placeholder command that may be used in lower or upper
     labels to show the \idx{formattednumber} (which will be rounded
     according to the \baropt{round} setting) for the bar value}
  }
  % \DTLbarindex
  \gcmd{DTL\-bar\-index}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{placeholder command that expands to the current bar index,
     for use in lower or upper labels or hooks. For
     \gls{DTLmultibarchart}, this is reset at the start of each group}
  }
  % \DTLbargroupindex
  \gcmd{DTL\-bar\-group\-index}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{placeholder command that expands to the current group bar index,
     for use in lower or upper labels or hooks (expands to 0 in
     \gls{DTLbarchart})}
  }
  % \DTLbaratbegintikz
  \gcmd{DTL\-bar\-at\-begin\-tikz}
  {
    \providedby{\sty{databar}}
    \desc{hook used by \gls{DTLbarchart} and \gls{DTLmultibarchart} at the start of the \env{tikzpicture}
environment}
  }
  % \DTLbaratendtikz
  \gcmd{DTL\-bar\-at\-end\-tikz}
  {
    \providedby{\sty{databar}}
    \desc{hook used by \gls{DTLbarchart} and \gls{DTLmultibarchart} at the end of the \env{tikzpicture}
environment}
  }
  % \DTLeverybarhook
  \gcmd{DTL\-every\-bar\-hook}
  {
    \providedby{\sty{databar}}
    \desc{hook used by \gls{DTLbarchart} and \gls{DTLmultibarchart}
after the current bar is drawn}
  }
  % \DTLeveryprebarhook
  \gcmd{DTL\-every\-pre\-bar\-hook}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{hook used by \gls{DTLbarchart} and \gls{DTLmultibarchart}
before the current bar is drawn}
  }
  % \DTLeverybargrouphook
  \gcmd{DTL\-every\-bar\-group\-hook}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{hook used by \gls{DTLmultibarchart} at the end of every bar group}
  }
  % \DTLstartpt
  \gcmd{DTL\-start\-pt}
  {
    \providedby{\sty{databar}}
    \desc{for use in the definition of \gls{DTLeverybarhook}, this
expands to the starting point of the current bar along its mid-axis as a
\sty{pgf} point}
  }
  % \DTLmidpt
  \gcmd{DTL\-mid\-pt}
  {
    \providedby{\sty{databar}}
    \desc{for use in the definition of \gls{DTLeverybarhook}, this
expands to the mid point of the current bar as a
\sty{pgf} point}
  }
  % \DTLendpt
  \gcmd{DTL\-end\-pt}
  {
    \providedby{\sty{databar}}
    \desc{for use in the definition of \gls{DTLeverybarhook}, this
expands to the end point of the current bar along its mid-axis as a
\sty{pgf} point}
  }
  % \DTLtotalbars
  \gcmd{DTL\-total\-bars}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{for use in the bar chart hooks, this will expand to the
total number of bars in the current bar chart}
  } 
  % \DTLbartotalvariables
  \gcmd{DTL\-bar\-total\-variables}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{for use in the bar chart hooks with \gls{DTLmultibarchart}, 
    this will expand to the total number of variables (that is, the  
    number of bars per group) for the current bar chart}
  } 
  % \DTLtotalbargroups
  \gcmd{DTL\-total\-bar\-groups}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{for use in the bar chart hooks with \gls{DTLmultibarchart}, 
    this will expand to the total number of bar groups in the current bar chart}
  } 
  % \DTLbarchartwidth
  \gcmd{DTL\-bar\-chart\-width}
  {
    \providedby{\sty{databar}}
    \desc{for use in the bar chart hooks, this will expand to the
length of the current bar chart's $x$-axis (in terms of bar width) as a
dimensionless number}
  } 
  % \DTLbargroupwidth
  \gcmd{DTL\-bar\-group\-width}
  {
    \providedby{\sty{databar}}
    \desc{for use in the bar chart hooks, this will expand to the
width of the bar groups in the current bar chart (in terms of bar width) as a
dimensionless number}
  } 
  % \DTLbarwidth
  \gcmd{DTL\-bar\-width}
  {
    \initval{1cm}
    \providedby{\sty{databar}}
    \desc{length register that governs the bar width}
  }
  % \DTLbarchartlength
  \gcmd{DTL\-bar\-chart\-length}
  {
    \initval{3in}
    \providedby{\sty{databar}}
    \desc{length register that governs the bar chart length}
  }
  % \DTLbaroutlinewidth
  \gcmd{DTL\-bar\-out\-line\-width}
  {
    \initval{0pt}
    \providedby{\sty{databar}}
    \desc{length register that governs the bar outline width}
  }
  % \DTLbarlabeloffset
  \gcmd{DTL\-bar\-label\-off\-set}
  {
    \initval{10pt}
    \providedby{\sty{databar}}
    \desc{length register that governs the distance from the
bar to the bar label}
  }
  % \DTLbarXlabelalign
  \gcmd{DTL\-bar\-X\-label\-align}
  {
    \providedby{\sty{databar}}
    \desc{the expansion text of this command should be the
\gls{pgftext} alignment
options for the $x$-axis bar labels}
  }
  % \DTLbargrouplabelalign
  \gcmd{DTL\-bar\-group\-label\-align}
  {
    \initvalcs{DTLbarXlabelalign}
    \providedby{\sty{databar} v3.0+}
    \desc{the expansion text of this command should be the
\gls{pgftext} alignment
options for the $x$-axis bar group labels}
  }
  % \DTLbarXupperlabelalign
  \gcmd{DTL\-bar\-X\-upper\-label\-align}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{the expansion text of this command should be the
\gls{pgftext} alignment
options for the upper labels of bars with positive values}
  }
  % \DTLbarXneglabelalign
  \gcmd{DTL\-bar\-X\-neg\-label\-align}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{the expansion text of this command should be the
\gls{pgftext} alignment
options for the lower labels of bars with negative values}
  }
  % \DTLbarXnegupperlabelalign
  \gcmd{DTL\-bar\-X\-neg\-upper\-label\-align}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{the expansion text of this command should be the
\gls{pgftext} alignment
options for the upper labels of bars with negative values}
  }
  % \DTLbarsetupperlabelalign
  \gcmd{DTL\-bar\-set\-upper\-label\-align}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\oargm{-ve align}\margm{+ve align}}
    \desc{used by the \baroptval{upper-label-align} to
redefine \gls{DTLbarXupperlabelalign} and optionally redefine
\gls{DTLbarXnegupperlabelalign}}
  }
  % \DTLbarYticklabelalign
  \gcmd{DTL\-bar\-Y\-tick\-label\-align}
  {
    \initvalvaries
    \providedby{\sty{databar}}
    \desc{the expansion text of this command should be the
\gls{pgftext} alignment
options for the $y$-axis tick labels}
  }
  % \DTLBarXAxisStyle
  \gcmd{DTL\-Bar\-X\-Axis\-Style}
  {
    \initval{-}
    \providedby{\sty{databar}}
    \desc{the expansion text of this command should be the
\sty{tikz} line style specifier for the $x$-axis}
  }
  % \DTLBarYAxisStyle
  \gcmd{DTL\-Bar\-Y\-Axis\-Style}
  {
    \initval{-}
    \providedby{\sty{databar}}
    \desc{the expansion text of this command should be the
\sty{tikz} line style specifier for the $y$-axis}
  }
  % \DTLBarStyle
  \gcmd{DTL\-Bar\-Style}
  {
    \initvalempty
    \providedby{\sty{databar} v3.0+}
    \desc{this command expands within the optional argument of
     \gls{path} when drawing or filling a bar. It may be redefined
to apply additional styling}
  }
  % \DTLbardisplayYticklabel
  \gcmd{DTL\-bar\-display\-Y\-tick\-label}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\margm{text}}
    \desc{used to format $y$ tick labels}
  }
  % \DTLdisplaylowerbarlabel
  \gcmd{DTL\-display\-lower\-bar\-label}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{text}}
    \desc{used to format lower bar labels}
  }
  % \DTLdisplaybargrouplabel
  \gcmd{DTL\-display\-bar\-group\-label}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\margm{text}}
    \desc{used to format group bar labels}
  }
  % \DTLdisplaylowermultibarlabel
  \gcmd{DTL\-display\-lower\-multi\-bar\-label}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{text}}
    \desc{used to format lower bar labels for \gls{DTLmultibarchart}}
  }
  % \DTLdisplayupperbarlabel
  \gcmd{DTL\-display\-upper\-bar\-label}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{text}}
    \desc{used to format upper bar labels}
  }
  % \DTLdisplayuppermultibarlabel
  \gcmd{DTL\-display\-upper\-multi\-bar\-label}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{text}}
    \desc{used to format upper bar labels for \gls{DTLmultibarchart}}
  }
  % \ifDTLverticalbars
  \gcond{if\-DTL\-vertical\-bars}
  {
    \initval{\cmd{iftrue}}
    \providedby{\sty{databar}}
    \desc{if true, the bar charts will be drawn with vertical bars,
     otherwise they will be drawn with horizontal bars}
  }
  % \ifDTLbarytics
  \gcond{if\-DTL\-bar\-y\-tics}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{databar}}
    \desc{if true, $y$ ticks should be drawn on bar charts}
  }
  % \ifDTLbarxaxis
  \gcond{if\-DTL\-bar\-x\-axis}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{databar}}
    \desc{if true, the $x$ axis should be drawn on bar charts}
  }
  % \ifDTLbaryaxis
  \gcond{if\-DTL\-bar\-y\-axis}
  {
    \initval{\cmd{iffalse}}
    \providedby{\sty{databar}}
    \desc{if true, the $y$ axis should be drawn on bar charts}
  }
  % \ifDTLcolorbarchart
  \gcond{if\-DTL\-color\-bar\-chart}
  {
    \deprecated
    \initval{\cmd{iftrue}}
    \providedby{\sty{databar}}
    \desc{this conditional is set to true by the package option
\opt{databar.color} or the setting \baropt{bar-default-colors}
and to false by the package option \opt{databar.gray} or the setting
\baropt{bar-default-gray}. Note that there's no guarantee that the
colours have been changed after the conditional was set and so
shouldn't be relied upon. This conditional may be deprecated or
removed in a future release}
  }
  % \DTLbaroutlinecolor
  \gcmd{DTL\-bar\-out\-line\-color}
  {
    \initval{black}
    \providedby{\sty{databar}}
    \desc{the expansion text of this command should be the colour
of the bar outline or empty if no outline should be drawn}
  }
  % \DTLsetbarcolor
  \gcmd{DTL\-set\-bar\-color}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{index}\margm{colour}}
    \desc{sets the colour for the given index in the bar colour list}
  }
  % \DTLclearbarcolors
  \gcmd{DTL\-clear\-bar\-colors}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{clears the bar colour list}
  }
  % \DTLgetbarcolor
  \gcmd{DTL\-get\-bar\-color}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{index}}
    \desc{expands to the colour for the given index in the bar
     colour list or \code{white} if not set. This takes the
     \baropt{color-style} setting into account}
  }
  % \DTLsetnegbarcolor
  \gcmd{DTL\-set\-neg\-bar\-color}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{index}\margm{colour}}
    \desc{sets the colour for the given index in the negative bar colour list}
  }
  % \DTLclearnegbarcolors
  \gcmd{DTL\-clear\-neg\-bar\-colors}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{clears the negative bar colour list}
  }
  % \DTLgetnegbarcolor
  \gcmd{DTL\-get\-neg\-bar\-color}
  {
    \providedby{\sty{databar}}
    \syntax{\margm{index}}
    \desc{expands to the colour for the given index in the negative bar
     colour list or the default colour list if not set. This takes the
     \baropt{negative-color-style} setting into account}
  }
  % \DTLdobarcolor
  \gcmd{DTL\-do\-bar\-color}
  {
    \providedby{\sty{databar}}
    \syntax{\oargm{value}\margm{index}}
    \desc{shortcut that does \code{\gls{color}\margm{col}} where
     \meta{col} is obtained by expanding
     \code{\gls{DTLgetbarcolor}\margm{index}} if the value is
      non-negative or omitted and to
      \code{\gls{DTLgetnegbarcolor}\margm{index}}, otherwise.
      Does nothing if an empty colour specification has been applied
to the given bar index}
  }
  % \DTLdocurrentbarcolor
  \gcmd{DTL\-do\-current\-bar\-color}
  {
    \providedby{\sty{databar}}
    \desc{for use in bar chart hooks, this will use
    \gls{DTLdobarcolor} for the current bar index}
  }
  % \DTLbarmax
  \gcmd{DTL\-bar\-max}
  {
    \initvalempty
    \providedby{\sty{databar}}
    \desc{the maximum value of the $y$ axis or empty if the maximum
value in the data should be used}
  }
  % \DTLnegextent
  \gcmd{DTL\-neg\-extent}
  {
    \initvalempty
    \providedby{\sty{databar}}
    \desc{the maximum depth (negative) of the $y$ axis or empty if the maximum
depth in the data should be used. The expansion text must be either empty
(for the default) or a decimal number less than or equal to 0}
  }
  % COMMANDS: DATABASE - INDEXING/GLOSSARIES
  % \useentry
  \gcmd{use\-entry}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{displays the value of the given column in the row
identified by \meta{label} from the index\slash glossary database
associated with \meta{label}. This command also indexes and, if
enabled, will provide a hyperlink to the relevant line in
\gls{printterms}}
  }
  % \Useentry
  \gcmd{Use\-entry}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{as \gls{useentry} but the text is converted to sentence case}
  }
  % \USEentry
  \gcmd{USE\-entry}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{as \gls{useentry} but the text is converted to uppercase}
  }
  % \useentrynl
  \gcmd{use\-entry\-nl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{as \gls{useentry} but doesn't create a hyperlink}
  }
  % \Useentrynl
  \gcmd{Use\-entry\-nl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{as \gls{Useentry} but doesn't create a hyperlink}
  }
  % \USEentrynl
  \gcmd{USE\-entry\-nl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{as \gls{USEentry} but doesn't create a hyperlink}
  }
  % \glslink
  \gcmd{gls\-link}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{text}}
    \desc{like \gls{useentry} but displays the provided text instead of
the value of a field}
  }
  % \glsdispentry
  \gcmd{gls\-disp\-entry}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{displays the value of the given column in the row
identified by \meta{label} from the index\slash glossary database
associated with \meta{label} (without indexing or creating a
hyperlink)}
  }
  % \Glsdispentry
  \gcmd{Gls\-disp\-entry}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{col-key}}
    \desc{as \gls{Glsdispentry} but converts the value to sentence case}
  }
  % \DTLgidxFetchEntry
  \gcmd{DTL\-gidx\-Fetch\-Entry}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{cs}\margm{label}\margm{col-key}}
    \desc{fetches the value of the given column in the row
identified by \meta{label} from the index\slash glossary database
associated with \meta{label} and defines the command \meta{cs} to
expand to that value}
  }
  % \glsadd
  \gcmd{gls\-add}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{indexes the term identified by \meta{label} without
producing any text}
  }
  % \glsaddall
  \gcmd{gls\-add\-all}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{db-name}}
    \desc{indexes all the terms in the database identified by
\meta{db-name} without producing any text}
  }
  % \gls
  \gcmd{gls}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{useentry}\margm{label}\marg{Text}}}
  }
  % \glspl
  \gcmd{gls\-pl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{useentry}\margm{label}\marg{Plural}}}
  }
  % \glsnl
  \gcmd{gls\-nl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{useentrynl}\margm{label}\marg{Text}}}
  }
  % \glsplnl
  \gcmd{gls\-pl\-nl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{useentrynl}\margm{label}\marg{Plural}}}
  }
  % \Gls
  \gcmd{Gls}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{Useentry}\margm{label}\marg{Text}}}
  }
  % \Glspl
  \gcmd{Gls\-pl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{Useentry}\margm{label}\marg{Plural}}}
  }
  % \Glsnl
  \gcmd{Gls\-nl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{Useentrynl}\margm{label}\marg{Text}}}
  }
  % \Glsplnl
  \gcmd{Gls\-pl\-nl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{Useentrynl}\margm{label}\marg{Plural}}}
  }
  % \glssym
  \gcmd{gls\-sym}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{useentry}\margm{label}\marg{Symbol}}}
  }
  % \Glssym
  \gcmd{Gls\-sym}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{shortcut for \code{\gls{Useentry}\margm{label}\marg{Symbol}}}
  }
  % \newacro
  \gcmd{new\-acro}
  {
    \providedby{\sty{datagidx}}
    \syntax{\oargm{options}\margm{short}\margm{long}}
    \desc{shortcut that defines an abbreviation with \gls{newterm}}
  }
  % \acronymfont
  \gcmd{acronym\-font}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{used to encapsulate the short form of an abbreviation
defined with \gls{newacro}}
  }
  % \DTLgidxAcrStyle
  \gcmd{DTLgidxAcrStyle}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{long}\margm{short}}
    \desc{used to encapsulate the long and short form in the
\optfmt{Text} field}
  }
  % \DTLgidxFormatAcr
  \gcmd{DTL\-gidx\-Format\-Acr}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{long-field}\margm{short-field}}
    \desc{used by \gls{acr} and \gls{acrpl} to format the full form}
  }
  % \DTLgidxFormatAcrUC
  \gcmd{DTL\-gidx\-Format\-Acr\-UC}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}\margm{long-field}\margm{short-field}}
    \desc{used by \gls{Acr} and \gls{Acrpl} to format the full form}
  }
  % \acr
  \gcmd{acr}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{displays the short form if the abbreviation identified by
\meta{label} has been marked as used, otherwise shows both the long
and short form}
  }
  % \acrpl
  \gcmd{acr\-pl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{displays the plural short form if the abbreviation identified by
\meta{label} has been marked as used, otherwise shows both the
plural long and short form}
  }
  % \Acr
  \gcmd{Acr}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{as \gls{acr} but sentence case}
  }
  % \Acrpl
  \gcmd{Acr\-pl}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{as \gls{acrpl} but sentence case}
  }
  % \glsreset
  \gcmd{gls\-reset}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{resets a term so that it's marked as not used}
  }
  % \glsunset
  \gcmd{gls\-unset}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{unsets a term so that it's marked as used}
  }
  % \glsresetall
  \gcmd{gls\-reset\-all}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{db-name}}
    \desc{resets all terms in the given database}
  }
  % \glsunsetall
  \gcmd{gls\-unset\-all}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{db-name}}
    \desc{unsets all terms in the given database}
  }
  % \DTLgidxCurrentdb
  \gcmd{DTL\-gidx\-Current\-db}
  {
    \providedby{\sty{datagidx}}
    \desc{defined by \gls{printterms} to the name of the current
database}
  }
  % \ifentryused
  \gcmd{if\-entry\-used}
  {
    \providedby{\sty{datagidx}}
    \syntax{\oargm{label}\margm{true}\margm{false}}
    \desc{robust command that does \meta{true} if the entry
identified by \meta{label} has been marked as used, otherwise does
false}
  }
  % \iftermexists
  \gcmd{if\-term\-exists}
  {
    \providedby{\sty{datagidx}}
    \syntax{\oargm{label}\margm{true}\margm{false}}
    \desc{expandable command that does \meta{true} if an entry has
been defined with the given label, otherwise does \meta{false}}
  }
  % \printterms
  \gcmd{print\-terms}
  {
    \providedby{\sty{datagidx}}
    \syntax{\oargm{options}}
    \desc{displays index\slash glossary according to the given
options}
  }
  % \newgidx
  \gcmd{new\-gidx}
  {
    \providedby{\sty{datagidx}}
    \syntax{\oargm{options}\margm{db-name}\margm{title}}
    \desc{defines a new index\slash glossary database}
    \note{preamble only}
  }
  % \DTLgidxForeachEntry
  \gcmd{DTL\-gidx\-Foreach\-Entry}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{body}}
    \desc{used by \gls{printterms} to iterate over the database}
  }
  % \datagidxmapdata
  \gcmd{data\-gidx\-map\-data}
  {
    \providedby{\sty{datagidx} v3.0+}
    \syntax{\margm{body}}
    \desc{used by styles to iterate over the database}
  }
  % \datagidxprevgroup
  \gcmd{data\-gidx\-prev\-group}
  {
    \providedby{\sty{datagidx}}
    \desc{assigned by \gls{DTLgidxForeachEntry} to the letter group
for the previous term}
  }
  % \DTLgidxGroupHeaderTitle
  \gcmd{DTL\-gidx\-Group\-Header\-Title}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{group}}
    \desc{expands to the title corresponding to the given letter
group}
  }
  % \printtermsstartpar
  \gcmd{print\-terms\-start\-par}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{par}
    \desc{used in \gls{printterms} to insert a paragraph break at
    the start}
  }
  % \postnewtermhook
  \gcmd{post\-new\-term\-hook}
  {
    \providedby{\sty{datagidx} v2.14+}
    \desc{a hook used at the end of \gls{newterm}}
  }
  % \datagidxlastlabel
  \gcmd{data\-gidx\-last\-label}
  {
    \providedby{\sty{datagidx}}
    \desc{defined at the end of \gls{newterm} to expand to the new
term's label}
  }
  % \DTLgidxAssignList
  \gcmd{DTL\-gidx\-Assign\-List}
  {
    \providedby{\sty{datagidx}}
    \desc{expands to the assignment list used by
\gls{DTLgidxForeachEntry}, which is internally used by
\gls{printterms}}
  }
  % \DTLgidxNoFormat
  \gcmd{DTL\-gidx\-No\-Format}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{used by \gls{newterm} when creating a label or sort value,
simply expands to \meta{text}}
  }
  % \DTLgidxGobble
  \gcmd{DTL\-gidx\-Gobble}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{used by \gls{newterm} when creating a label or sort value,
expands to nothing}
  }
  % \DTLgidxStripBackslash
  \gcmd{DTL\-gidx\-Strip\-Back\-slash}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{cs}}
    \desc{expands to the command name without the leading backslash}
  }
  % \datagidxconvertchars
  \gcmd{data\-gidx\-convert\-chars}
  {
    \providedby{\sty{datagidx}}
    \desc{used by \gls{newterm} when creating a label or sort value}
  }
  % \datagidxwordifygreek
  \gcmd{data\-gidx\-wordify\-greek}
  {
    \providedby{\sty{datagidx}}
    \desc{used by \gls{newterm} when creating a label or sort value}
  }
  % \newtermlabelhook
  \gcmd{new\-term\-label\-hook}
  {
    \providedby{\sty{datagidx}}
    \desc{used by \gls{newterm} when creating a label}
  }
  % \newtermsorthook
  \gcmd{new\-term\-sort\-hook}
  {
    \providedby{\sty{datagidx}}
    \desc{used by \gls{newterm} when creating a sort value}
  }
  % \DTLgidxName
  \gcmd{DTL\-gidx\-Name}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{forename}\margm{surname}}
    \desc{used to markup a person's name}
  }
  % \DTLgidxNameNum
  \gcmd{DTL\-gidx\-Name\-Num}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{num}}
    \desc{used to markup a person's ordinal (for a monarch etc)}
  }
  % \DTLgidxPlace
  \gcmd{DTL\-gidx\-Place}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{country}\margm{town/city}}
    \desc{used to markup a place}
  }
  % \DTLgidxSubject
  \gcmd{DTL\-gidx\-Subject}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{main}\margm{category}}
    \desc{used to markup a subject}
  }
  % \DTLgidxOffice
  \gcmd{DTL\-gidx\-Office}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{office}\margm{name}}
    \desc{used to markup a person's office}
  }
  % \DTLgidxRank
  \gcmd{DTL\-gidx\-Rank}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{title}\margm{forename(s)/initial(s)}}
    \desc{used to markup a person's rank}
  }
  % \DTLgidxParticle
  \gcmd{DTL\-gidx\-Particle}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{particle}\margm{surname}}
    \desc{used to markup a surname with a particle}
  }
  % \DTLgidxIgnore
  \gcmd{DTL\-gidx\-Ignore}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{normally simply expands to \meta{text} but may be 
used to markup content to be stripped by the automated
label and sort values}
  }
  % \DTLgidxParen
  \gcmd{DTL\-gidx\-Paren}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{used to markup parenthetical material}
  }
  % \DTLgidxMac
  \gcmd{DTL\-gidx\-Mac}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{normally simply expands to \meta{text} but may be 
used to markup content to be converted to \qt{Mac} in the sort value}
  }
  % \DTLgidxSaint
  \gcmd{DTL\-gidx\-Saint}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{normally simply expands to \meta{text} but may be 
used to markup content to be converted to \qt{Saint} in the sort value}
  }
  % \newterm
  \gcmd{new\-term}
  {
    \providedby{\sty{datagidx}}
    \syntax{\oargm{options}\margm{name}}
    \desc{defines a term with the given name}
    \note{preamble only}
  }
  % \newterm OPTION database 
   \gnewtermopt{data\-base}
   {
     \syntax{\margm{db-name}}
     \desc{the database name}
   }
  % \newterm OPTION label 
   \gnewtermopt{label}
   {
     \syntax{\margm{label}}
     \desc{the term's unique label}
   }
  % \newterm OPTION parent 
   \gnewtermopt{parent}
   {
     \syntax{\margm{parent-label}}
     \desc{the label identifying the term's parent entry}
   }
  % \newterm OPTION text 
   \gnewtermopt{text}
   {
     \syntax{\margm{text}}
     \desc{the text to use by command like \gls{gls}}
   }
  % \newterm OPTION plural 
   \gnewtermopt{plural}
   {
     \syntax{\margm{text}}
     \desc{the text to use by command like \gls{glspl}}
   }
  % \newterm OPTION symbol 
   \gnewtermopt{symbol}
   {
     \syntax{\margm{text}}
     \desc{the text to use by command like \gls{glssym}}
   }
  % \newterm OPTION description 
   \gnewtermopt{description}
   {
     \syntax{\margm{text}}
     \desc{the term's description to be shown in \gls{printterms},
if applicable}
   }
  % \newterm OPTION sort 
   \gnewtermopt{sort}
   {
     \syntax{\margm{text}}
     \desc{the term's sort value}
   }
  % \newterm OPTION see
   \gnewtermopt{see}
   {
     \syntax{\margm{xr-labels}}
     \desc{the list of \qt{see} cross-reference labels}
   }
  % \newterm OPTION seealso
   \gnewtermopt{see\-also}
   {
     \syntax{\margm{xr-labels}}
     \desc{the list of \qt{see also} cross-reference labels}
   }
  % \newterm OPTION short
   \gnewtermopt{short}
   {
     \syntax{\margm{text}}
     \desc{the term's short (abbreviated) form}
   }
  % \newterm OPTION shortplural
   \gnewtermopt{short\-plural}
   {
     \syntax{\margm{text}}
     \desc{the term's plural short (abbreviated) form}
   }
  % \newterm OPTION long
   \gnewtermopt{long}
   {
     \syntax{\margm{text}}
     \desc{the term's long form}
   }
  % \newterm OPTION longplural
   \gnewtermopt{long\-plural}
   {
     \syntax{\margm{text}}
     \desc{the term's plural long form}
   }
  % \DTLgidxSetDefaultDB
  \gcmd{DTL\-gidx\-Set\-Default\-DB}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{db-name}}
    \desc{sets the default \sty{datagidx} database name}
  }
  % \DTLgidxSetColumns
  \gcmd{DTL\-gidx\-Set\-Columns}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{n}}
    \desc{sets the number of columns in the index}
  }
  % \datagidxsymbolwidth
  \gcmd{data\-gidx\-symbol\-width}
  {
    \providedby{\sty{datagidx}}
    \initval{0pt}
    \desc{dimension that indicates the space to allocate for each
symbol. If zero or negative, the symbol will simply occupy its
natural space}
  }
  % \datagidxlocationwidth
  \gcmd{data\-gidx\-location\-width}
  {
    \providedby{\sty{datagidx}}
    \initval{0pt}
    \desc{dimension that indicates the space to allocate for each
location list. If zero or negative, the location list will simply occupy its
natural space}
  }
  % \DTLgidxNameCase
  \gcmd{DTL\-gidx\-Name\-Case}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{used to apply the appropriate case change to the name}
  }
  % \DTLgidxNameFont
  \gcmd{DTL\-gidx\-Name\-Font}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{used to apply the appropriate font change to the name}
  }
  % \DTLgidxPostName
  \gcmd{DTL\-gidx\-Post\-Name}
  {
    \providedby{\sty{datagidx}}
    \initval{\visiblespace}
    \desc{inserted after the name}
  }
  % \DTLgidxPostChildName
  \gcmd{DTL\-gidx\-Post\-Child\-Name}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{DTLgidxPostName}
    \desc{inserted after the child name}
  }
  % \DTLgidxPostDescription
  \gcmd{DTL\-gidx\-Post\-De\-scrip\-tion}
  {
    \providedby{\sty{datagidx}}
    \initvalempty
    \desc{inserted after the description}
  }
  % \DTLgidxEndItem
  \gcmd{DTL\-gidx\-End\-Item}
  {
    \providedby{\sty{datagidx}}
    \desc{inserted at the end of each item (after the location list, child list and
cross references, if applicable)}
  }
  % DTLgidxDictPostItem
  \gcmd{DTL\-gidx\-Dict\-Post\-Item}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{DTLgidxEndItem}
    \desc{specific to the \optfmt{dict} style, this is done at the end of each
item}
  }
  % \datagidxdictindent
  \gcmd{data\-gidx\-dict\-indent}
  {
    \providedby{\sty{datagidx}}
    \initval{1em}
    \desc{indentation used by the \optfmt{dict} style}
  }
  % \DTLgidxDictHead
  \gcmd{DTL\-gidx\-Dict\-Head}
  {
    \providedby{\sty{datagidx}}
    \desc{specific to \gidxoptval{style}{dict}, this inserts the
group header}
  }
  % \DTLgidxCategoryNameFont
  \gcmd{DTL\-gidx\-Category\-Name\-Font}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{specific to \gidxoptval{style}{dict}, this encapsulates
the \qt{category} child name}
  }
  % \DTLgidxCategorySep
  \gcmd{DTL\-gidx\-Category\-Sep}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{space}
    \desc{separator used with \gidxoptval{style}{dict} between
\qt{category} child entries}
  }
  % \DTLgidxSubCategorySep
  \gcmd{DTL\-gidx\-Sub\-Category\-Sep}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{space}
    \desc{separator used with \gidxoptval{style}{dict} between
sub-category child entries}
  }
  % \DTLgidxChildSep
  \gcmd{DTL\-gidx\-Child\-Sep}
  {
    \providedby{\sty{datagidx}}
    \initval{\visiblespace}
    \desc{separator between child entries for \gidxoptval{style}{gloss}}
  }
  % \DTLgidxPostChild
  \gcmd{DTL\-gidx\-Post\-Child}
  {
    \providedby{\sty{datagidx}}
    \initvalempty
    \desc{hook inserted at the end of the list of child entries for
\gidxoptval{style}{gloss}}
  }
  % \DTLgidxPreLocation
  \gcmd{DTL\-gidx\-Pre\-Location}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{enspace}
    \desc{inserted before the location list}
  }
  % \DTLgidxLocation
  \gcmd{DTL\-gidx\-Location}
  {
    \providedby{\sty{datagidx}}
    \desc{used to display the location list, if applicable}
  }
  % \DTLgidxPostLocation
  \gcmd{DTL\-gidx\-Post\-Location}
  {
    \providedby{\sty{datagidx}}
    \initval{\visiblespace}
    \desc{inserted after the location list}
  }
  % \datagidxsymalign
  \gcmd{data\-gidx\-sym\-align}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{centering}
    \desc{alignment of the symbol when the symbol width has been
set.}
  }
  % \datagidxlocalign
  \gcmd{data\-gidx\-loc\-align}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{raggedleft}
    \desc{alignment of the location list when the location width has been
set.}
  }
  % \dtldolocationlist
  \gcmd{dtl\-do\-location\-list}
  {
    \providedby{\sty{datagidx}}
    \desc{displays the current item's location list}
  }
  % \dtldofirstlocation
  \gcmd{dtl\-do\-first\-location}
  {
    \providedby{\sty{datagidx}}
    \desc{displays the first location in the current item's location list}
  }
  % \ifdatagidxbalance
  \gcond{if\-data\-gidx\-balance}
  {
     \initval{\cmd{iftrue}}
     \desc{corresponds to the \gidxopt{balance} setting, but note
that setting does more than simply change this conditional. This
conditional shouldn't be explicitly changed but may be referenced,
if required}
  }
  % \datagidxtarget
  \gcmd{data\-gidx\-target}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{target-name}\margm{text}}
    \desc{creates a hyperlink target, if supported, and does \meta{text}}
  }
  % \datagidxlink
  \gcmd{data\-gidx\-link}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{target-name}\margm{text}}
    \desc{if hyperlinks are support, creates a hyperlink with
\meta{text} as the link text, otherwise just does \meta{text}}
  }
  % \DTLgidxEnableHyper
  \gcmd{DTL\-gidx\-Enable\-Hyper}
  {
    \providedby{\sty{datagidx}}
    \desc{enable hyperlinks, if supported}
  }
  % \DTLgidxDisableHyper
  \gcmd{DTL\-gidx\-Disable\-Hyper}
  {
    \providedby{\sty{datagidx}}
    \desc{disable hyperlinks}
  }
  % \DTLgidxSetCompositor
  \gcmd{DTL\-gidx\-Set\-Compositor}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{character}}
    \desc{sets the location compositor}
  }
  % \DTLgidxCounter
  \gcmd{DTL\-gidx\-Counter}
  {
    \providedby{\sty{datagidx}}
    \initval{page}
    \desc{expands to the counter to use for locations}
  }
  % \DTLgidxFormatSee
  \gcmd{DTL\-gidx\-Format\-See}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{tag}\margm{label list}}
    \desc{used to format the \qt{see} cross-reference list}
  }
  % \DTLgidxSeeTagFont
  \gcmd{DTL\-gidx\-See\-Tag\-Font}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{used to format the \meta{tag} argument of \gls{DTLgidxFormatSee}}
  }
  % \DTLgidxSeeList
  \gcmd{DTL\-gidx\-See\-List}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label list}}
    \desc{used to format the \meta{label list} argument of \gls{DTLgidxFormatSee}}
  }
  % \DTLgidxFormatSeeAlso
  \gcmd{DTL\-gidx\-Format\-See\-Also}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{tag}\margm{label list}}
    \desc{used to format the \qt{see also} cross-reference list}
  }
  % \DTLidxFormatSeeItem
  \gcmd{DTL\-idx\-Format\-See\-Item}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{label}}
    \desc{used to fetch the name of the cross-reference label and
display it in a hyperlink, if supported}
  }
  % \DTLidxSeeSep
  \gcmd{DTL\-idx\-See\-Sep}
  {
    \providedby{\sty{datagidx}}
    \initval{,\visiblespace}
    \desc{separator used in all but final pair of items in
cross-reference list}
  }
  % \DTLidxSeeLastSep
  \gcmd{DTL\-idx\-See\-Last\-Sep}
  {
    \providedby{\sty{datagidx}}
    \initval{\visiblespace\cmd{\&}\visiblespace}
    \desc{separator between final pair of items in cross-reference
list}
  }
  % \seealsoname
  \gcmd{see\-also\-name}
   {
     \providedby{\sty{datagidx}}
     \desc{if not already defined, this will be defined to
\gls{alsoname} if that is defined or to \qt{see also} otherwise}
   }
  % DTLgidxChildCount COUNTER
  \gctr{DTL\-gidx\-Child\-Count}
  {
    \providedby{\sty{datagidx}}
    \desc{initialised at the start of each child list and
     incremented for each child item}
  }
  % \DTLgidxChildCountLabel
  \gcmd{DTL\-gidx\-Child\-Count\-Label}
  {
    \providedby{\sty{datagidx}}
    \desc{used by \gidxoptval{child}{noname} to show the child index
instead of the name}
  }
  % \DTLgidxChildStyle
  \gcmd{DTL\-gidx\-Child\-Style}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{name}}
    \desc{encapsulates the child entry's name (including font and
case-changing commands and post name hook)}
  }
  % \DTLgidxSymDescSep
  \gcmd{DTL\-gidx\-Sym\-Desc\-Sep}
  {
    \providedby{\sty{datagidx}}
    \initvalcs{space}
    \desc{separator between symbol and description if both are
present}
  }
  % \DTLgidxFormatDesc
  \gcmd{DTL\-gidx\-Format\-Desc}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{text}}
    \desc{encapsulates the description, if set}
  }
  % \datagidxstart
  \gcmd{data\-gidx\-start}
  {
    \providedby{\sty{datagidx}}
    \desc{style command used by \gls{printterms} at the start of the
list}
  }
  % \datagidxend
  \gcmd{data\-gidx\-end}
  {
    \providedby{\sty{datagidx}}
    \desc{style command used by \gls{printterms} at the end of the
list}
  }
  % \datagidxitem
  \gcmd{data\-gidx\-item}
  {
    \providedby{\sty{datagidx}}
    \desc{style command used to display the current entry within
\gls{printterms}}
  }
  % \printtermsrestoreonecolumn
  \gcmd{print\-terms\-restore\-one\-column}
  {
    \providedby{\sty{datagidx}}
    \desc{used to restore one column if \gls{twocolumn} was issued
by \gls{printterms} and two-column mode wasn't already in effect}
  }
  % \datagidxsetstyle
  \gcmd{data\-gidx\-set\-style}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{style-name}}
    \desc{used by \gls{printterms} to set the current style}
  }
  % \datagidxnewstyle 
  \gcmd{data\-gidx\-new\-style}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{style-name}\margm{definitions}}
    \desc{defines a new style called \meta{style-name} for use with the \gidxopt{style}
setting}
  }
  % \loadgidx
  \gcmd{load\-gidx}
  {
    \providedby{\sty{datagidx} v2.15+}
    \syntax{\oargm{options}\margm{filename}\margm{title}}
    \desc{loads a previously saved \sty{datagidx} database}
  }
  % \newtermaddfield
  \gcmd{new\-term\-add\-field}
  {
    \providedby{\sty{datagidx}}
    \syntax{\oargm{db list}\margm{column key}\oargm{placeholder
cs}\margm{new term key}\oargm{data type}\margm{default value}}
    \desc{defines a new column and associated option}
  }
  % \field
  \gcmd{field}
  {
    \providedby{\sty{datagidx}}
    \syntax{\margm{key}}
    \desc{may be used in the \meta{default value} argument of
\gls{newtermaddfield} to reference the value of another field}
  }
  % PLACEHOLDERS
  % \Name
  \ggidxvar{Name}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Name} value}
  }
  % \Description
  \ggidxvar{Description}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Description} value}
  }
  % \Used
  \ggidxvar{Used}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Used} value}
  }
  % \Symbol
  \ggidxvar{Symbol}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Symbol} value}
  }
  % \Long
  \ggidxvar{Long}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Long} value}
  }
  % \LongPlural
  \ggidxvar{Long\-Plural}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Long\-Plural} value}
  }
  % \Short
  \ggidxvar{Short}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Short} value}
  }
  % \ShortPlural
  \ggidxvar{Short\-Plural}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Short\-Plural} value}
  }
  % \Location
  \ggidxvar{Location}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Location} value}
  }
  % \See
  \ggidxvar{See}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{See} value}
  }
  % \SeeAlso
  \ggidxvar{See\-Also}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{See\-Also} value}
  }
  % \Text
  \ggidxvar{Text}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Text} value}
  }
  % \Plural
  \ggidxvar{Plural}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Plural} value}
  }
  % \CurrentLocation
  \ggidxvar{Current\-Location}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Current\-Location} value}
  }
  % \Label
  \ggidxvar{Label}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Label} value}
  }
  % \Parent
  \ggidxvar{Parent}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Parent} value}
  }
  % \Children
  \ggidxvar{Children}
  {
    \providedby{\sty{datagidx} v2.15+}
    \field{extra}{\styfmt{datagidx}}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Child} value}
  }
  % \FirstId
  \ggidxvar{First\-Id}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{First\-Id} value}
  }
  % \HierSort
  \ggidxvar{Hier\-Sort}
  {
    \providedby{\sty{datagidx} v3.0+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Hier\-Sort} value}
  }
  % \Sort
  \ggidxvar{Sort}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{Sort} value}
  }
  % \datagidxcurrentgroup
  \gcmd{data\-gidx\-current\-group}
  {
    \providedby{\sty{datagidx} v2.15+}
    \desc{placeholder in \gls{printterms} that expands to the
current entry's \optfmt{LetterGroup} value}
  }
  % COMMANDS: DATABASE - BIBLIOGRAPHIES
  % \DTLbibliographystyle
  \gcmd{DTL\-bib\-lio\-graphy\-style}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{name}}
    \desc{sets the bibliography style to \meta{name}, which may be
one of: \optfmt{plain}, \optfmt{abbrv} or \optfmt{alpha}}
  }
  % \DTLloadbbl
  \gcmd{DTL\-load\-bbl}
  {
    \providedby{\sty{databib}}
    \syntax{\oargm{bbl file}\margm{db-name}\margm{bib-list}}
    \desc{does \code{\gls{bibliographystyle}\marg{databib}},
     creates a new database called \meta{db-name} (and defines
     the placeholder command \gls{DTLBIBdbname} to \meta{db-name}), and
     inputs the given \meta{bbl file}, which is expected to be in
     the format created by the \file{databib.bst} \app{bibtex} style
     file. The \meta{bib-list} identifies the list of \ext{bib}
     files that \app{bibtex} needs to read in order to create the
     \meta{bbl file}. If the optional argument is omitted,
     \code{\gls{jobname}.bbl} is assumed. If the \meta{db-name}
     argument is empty, the default database name will be used}
  }
  % \DTLloadmbbl
  \gcmd{DTL\-load\-mbbl}
  {
    \providedby{\sty{databib}}
    \syntax{\marg{mbib}\margm{db-name}\margm{bib-list}}
    \desc{similar to \gls{DTLloadbbl} but for multiple
    bibliographies}
  }
  % \DTLmultibibs
  \gcmd{DTL\-multi\-bibs}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{list}}
    \desc{creates an auxiliary file for each name in the given
     \meta{list}. Each element in the list should be the base name
     without the extension}
    \note{preamble only}
  }
  % \DTLcite
  \gcmd{DTL\-cite}
  {
    \providedby{\sty{databib}}
    \syntax{\oargm{text}\margm{mbib}\margm{label-list}}
    \desc{similar to \code{\gls{cite}\oargm{text}\margm{label-list}}
except that the cite information is written to the auxiliary file
associated with the multi-bib \meta{mbib} (as identified in
\gls{DTLmultibibs}). The cross-referencing label is constructed from
both \meta{mbib} and the label to allow the same citation to appear
in multiple bibliographies}
  }
  % \DTLnocite
  \gcmd{DTL\-no\-cite}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{mbib}\margm{label-list}}
    \desc{as \gls{DTLcite} but analogous to \gls{nocite}}
  }
  % \DTLBIBdbname
  \gcmd{DTL\-BIB\-db\-name}
  {
    \providedby{\sty{databib}}
    \desc{placeholder command set by \gls{DTLloadbbl} that should 
    expand to the name of the \sty{databib} database containing 
    the bibliography data}
  }
  % \DBIBname
  \gcmd{DBIB\-name}
  {
    \providedby{\sty{databib}}
    \desc{placeholder command set by commands such as \gls{DTLformatthisbibentry}
    and \gls{DTLforeachbibentry} that should expand to database name supplied 
    in the \meta{db-name} argument of those commands}
  }
  % \DBIBcitekey
  \gcmd{DBIB\-cite\-key}
  {
    \providedby{\sty{databib}}
    \desc{placeholder command set by commands such as \gls{DTLformatthisbibentry}
    and \gls{DTLforeachbibentry} that should expand to the cite key
   identifying the required row of the database}
  }
  % \DBIBentrytype
  \gcmd{DBIB\-entry\-type}
  {
    \providedby{\sty{databib}}
    \desc{placeholder command set by commands such as \gls{DTLformatthisbibentry}
    and \gls{DTLforeachbibentry} that should expand to the entry
    type obtained from the \optfmt{EntryType} field of the current row}
  }
  % \DTLnewbibrow
  \gcmd{DTL\-new\-bib\-row}
  {
    \providedby{\sty{databib}}
    \desc{intended for use in the \ext{bbl} loaded by
    \gls{DTLloadbbl}, this creates a new row in the database identified
    by \gls{DTLBIBdbname} (without checking for existence).
    Internally uses \starredcs{DTLnewrow}, so it obeys the
    general database options}
  }
  % \DTLnewbibitem
  \gcmd{DTL\-new\-bib\-item}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{col-key}\margm{item}}
    \desc{intended for use in the \ext{bbl} loaded by
    \gls{DTLloadbbl}, this adds a new value to the last row in the database identified
    by \gls{DTLBIBdbname} (without checking for existence).
    Internally uses \starredcs{DTLnewdbentry}, so it obeys the
    general database options}
  }
  % \DTLnewbibliteralitem
  \gcmd{DTL\-new\-bib\-literal\-item}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{col-key}\margm{item}}
    \desc{as \gls{DTLnewbibitem} but the item has literal content}
  }
  % \DTLbibliography
  \gcmd{DTL\-bib\-lio\-graphy}
  {
    \providedby{\sty{databib}}
    \syntax{\oargm{condition}\margm{db-name}}
    \desc{shortcut command that starts and ends \env{DTLthebibliography}
     and, within the body of that environment, iterates over the
     given database with \starredcs{DTLforeachbibentry}, formatting each item according
     to the current style (as set by \gls{DTLbibliographystyle}).
     The supplied arguments are provided to both the
     \env{DTLthebibliography} environment and \gls{DTLforeachbibentry}}
  }
  % \DTLmbibliography
  \gcmd{DTL\-m\-bib\-lio\-graphy}
  {
    \providedby{\sty{databib}}
    \syntax{\oargm{condition}\margm{mbib name}\margm{db-name}}
    \desc{similar to \gls{DTLbibliography} but for the given
     multi-bib database, which should have been loaded with
     \gls{DTLloadmbbl}}
  }
  % \DTLformatbibentry
  \gcmd{DTL\-format\-bib\-entry}
  {
    \providedby{\sty{databib}}
    \desc{designed for use within \gls{DTLbibliography} to format
    the database row in the current iteration of \gls{DTLforeachbibentry}}
  }
  % \gDTLformatbibentry
  \gcmd{gDTL\-format\-bib\-entry}
  {
    \providedby{\sty{databib}}
    \desc{as \gls{DTLformatbibentry} but performs global changes}
  }
  % \DTLbibitem
  \gcmd{DTL\-bib\-item}
  {
    \providedby{\sty{databib}}
    \desc{used within \gls{DTLbibliography} at the start of each
    iteration}
  }
  % \DTLmbibitem
  \gcmd{DTL\-m\-bib\-item}
  {
    \providedby{\sty{databib}}
    \desc{used within \gls{DTLmbibliography} at the start of each
    iteration}
  }
  % \DTLendbibitem
  \gcmd{DTL\-end\-bib\-item}
  {
    \providedby{\sty{databib}}
    \desc{hook used within \gls{DTLbibliography} and \gls{DTLmbibliography} 
    at the end of each iteration. Does nothing by default}
  }
  % \DTLcustombibitem
  \gcmd{DTL\-custom\-bib\-item}
  {
    \providedby{\sty{databib} v2.22+}
    \syntax{\margm{item code}\margm{ref text}\margm{cite key}}
    \desc{as \meta{DTLbibitem} but \meta{item code} will be used
    instead of \gls{item}}
  }
  % \DTLformatthisbibentry
  \gcmd{DTL\-format\-this\-bib\-entry}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{db-name}\margm{cite key}}
    \desc{as \gls{DTLformatbibentry} but for the 
    row identified by \meta{cite key} in the given database
    \meta{db-name}}
  }
  % \DTLcomputewidestbibentry
  \gcmd{DTL\-compute\-widest\-bib\-entry}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{condition}\margm{db-name}\margm{bib-label}\margm{cs}}
    \desc{computes the widest bibliography entry over all entries
satisfying the given condition for the given database, where the
bibliography label is formatted according to \meta{bib label} and
stores the result in the command (token list variable) \meta{cs}}
  }
  % \DTLforeachbibentry
  \gcmds{DTL\-for\-each\-bib\-entry}
  {
    \providedby{\sty{databib}}
    \syntax{\oargm{condition}\margm{db-name}\margm{body}}
    \desc{iterates over all rows in the given database using
     \gls{DTLforeach} (or \starredcs{DTLforeach} for the starred form),
     setting up the placeholder commands \gls{DBIBname},
     \gls{DBIBcitekey} and \gls{DBIBentrytype} and, for each row that
     satisfies the given (\sty{ifthen}) condition, increments 
    \ctr{DTLbibrow} and does \meta{body}. Locally assigns
     placeholder commands}
  }
  % \gDTLforeachbibentry
  \gcmds{gDTL\-for\-each\-bib\-entry}
  {
    \providedby{\sty{databib}}
    \syntax{\oargm{condition}\margm{db-name}\margm{body}}
    \desc{as \gls{DTLforeachbibentry} but performs global assignments}
  }
  % \DTLbibfield
  \gcmd{DTL\-bib\-field}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field name}}
    \desc{for use in \gls{DTLforeachbibentry}, this expands to the
    value of the column identified by \meta{field name} in the current
    iteration. Expands to nothing if the field isn't set or doesn't
    exist}
  }
  % \DTLencapbibfield
  \gcmd{DTL\-en\-cap\-bib\-field}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{cs}\margm{field name}}
    \desc{similar to \code{\gls{DTLbibfield}\margm{field name}} but
     encapsulates the value with \meta{cs}. Expands to nothing if
     the field isn't set or doesn't exist}
  }
  % \DTLbibdatefield
  \gcmd{DTL\-bib\-date\-field}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field name}}
    \desc{as \gls{DTLbibfield} but is specifically used for
    \databibcolkey{Date} and \databibcolkey{UrlDate}}
  }
  % \DTLbibfieldlet
  \gcmd{DTL\-bib\-field\-let}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{cs}\margm{field name}}
    \desc{for use in \gls{DTLforeachbibentry}, this sets the command
    (token list variable) \meta{cs} to the value of the column identified
    by \meta{field name} in the current iteration}
  }
  % \DTLifbibfieldexists
  \gcmd{DTL\-if\-bib\-field\-exists}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field name}\margm{true}\margm{false}}
    \desc{for use in \gls{DTLforeachbibentry}, this tests if the
    given field exists (that is, if both the column is defined and
    the value is not null) for the current iteration}
  }
  % \DTLifanybibfieldexists
  \gcmd{DTL\-if\-any\-bib\-field\-exists}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field list}\margm{true}\margm{false}}
    \desc{for use in \gls{DTLforeachbibentry}, this tests if any of
    the given fields exists (that is, if both the column is defined and
    the value is not null) for the current iteration}
  }
  % \ifDTLmidsentence
  \gcond{if\-DTL\-mid\-sentence}
  {
    \providedby{\sty{databib}}
    \desc{conditional used by styles to keep track of whether or not
the current code is deemed to be in the middle of a sentence}
  }
  % \ifDTLstartsentence
  \gcond{if\-DTL\-start\-sentence}
  {
    \providedby{\sty{databib}}
    \desc{conditional used by styles to keep track of whether or not
a new sentence has just started}
  }
  % \ifDTLperiod
  \gcond{if\-DTL\-period}
  {
    \providedby{\sty{databib}}
    \desc{conditional set by \gls{DTLcheckendsperiod}}
  }
  % \DTLaddperiod
  \gcmd{DTL\-add\-period}
  {
    \providedby{\sty{databib}}
    \desc{adds a period and resets the conditionals
    \gls{ifDTLstartsentence}, \gls{ifDTLmidsentence} and \gls{ifDTLperiod}}
  }
  % \DTLaddcomma
  \gcmd{DTL\-add\-comma}
  {
    \providedby{\sty{databib}}
    \desc{adds a comma followed by a space and updates the conditionals
    \gls{ifDTLstartsentence}, \gls{ifDTLmidsentence} and \gls{ifDTLperiod}}
  }
  % \DTLstartsentencespace
  \gcmd{DTL\-start\-sentence\-space}
  {
    \providedby{\sty{databib}}
    \desc{adds a space with (if at the start of a sentence) the
    applicable space factor, resets \gls{ifDTLstartsentence}}
  }
  % \DTLcheckendsperiod
  \gcmd{DTL\-check\-ends\-period}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{text}}
    \desc{tests if \meta{text} ends with a full stop/period and sets
    \gls{ifDTLperiod} accordingly}
  }
  % \DTLcheckbibfieldendsperiod
  \gcmd{DTL\-check\-bib\-field\-ends\-period}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}}
    \desc{a shortcut that uses \gls{DTLbibfield} to obtain the value 
    of the identified field and \gls{DTLcheckendsperiod} to
    determine if the value ends with a full stop/period}
  }
  % \DTLtwoand
  \gcmd{DTL\-two\-and}
  {
    \providedby{\sty{databib}}
    \desc{used between the names where there are only two names in
the list}
  }
  % \DTLandlast
  \gcmd{DTL\-and\-last}
  {
    \providedby{\sty{databib}}
    \desc{used between the final pair of names where there are more
     than two names in the list}
  }
  % \DTLandnotlast
  \gcmd{DTL\-and\-not\-last}
  {
    \providedby{\sty{databib}}
    \desc{used between all except the final pair of names where there are more
     than two names in the list}
  }
  % \DTLformatbibnamelist
  \gcmd{DTL\-format\-bib\-name\-list}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{list}\margm{max}\margm{fmt-cs}}
    \desc{used by \gls{DTLformatauthorlist} and \gls{DTLformateditorlist}
    to format the list of names. Each element in the list must be in the form
    \code{\margm{von}\margm{surname}\margm{jr}\margm{forenames}} and
    \meta{fmt-cs} must have those four arguments for its syntax. If
     the list has more than \meta{max} items, it will be truncated with
    \gls{etalname}}
  }
  % \DTLformatauthorlist
  \gcmd{DTL\-format\-author\-list}
  {
    \providedby{\sty{databib}}
    \desc{used by styles to format the list of author names (which
    will be obtained from the \optfmt{Author} field). Each name is
   formatted according to \gls{DTLformatauthor}}
  }
  % \DTLformateditorlist
  \gcmd{DTL\-format\-editor\-list}
  {
    \providedby{\sty{databib}}
    \desc{used by styles to format the list of editor names (which
    will be obtained from the \optfmt{Editor} field). Each name is
   formatted according to \gls{DTLformateditor}}
  }
  % \DTLpostvon
  \gcmd{DTL\-post\-von}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{\textasciitilde}
    \desc{space to insert after the \meta{von part} of a name}
  }
  % \DTLpostvolnum
  \gcmd{DTL\-post\-vol\-num}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{:}
    \desc{inserted after the volume number}
  }
  % \DTLpostpagename
  \gcmd{DTL\-post\-page\-name}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{\textasciitilde}
    \desc{space inserted after \gls{pagename} or \gls{pagesname}
    (before the page number)}
  }
  % \DTLpostvolumename
  \gcmd{DTL\-post\-volume\-name}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{\textasciitilde}
    \desc{space inserted after \gls{volumename}
    (before the volume number)}
  }
  % \DTLpostchaptername
  \gcmd{DTL\-post\-chapter\-name}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{\textasciitilde}
    \desc{space inserted after \gls{chaptername}
    (before the chapter number)}
  }
  % \DTLpostnumbername
  \gcmd{DTL\-post\-number\-name}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{\textasciitilde}
    \desc{space inserted after \gls{numbername}
    (before the number)}
  }
  % \DTLprecite
  \gcmd{DTL\-pre\-cite}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{\textasciitilde}
    \desc{space inserted before \gls{DTLpcite} for
     cross-references}
  }
  % \DTLofseries
  \gcmd{DTL\-of\-series}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{series}}
    \desc{formats \qt{of \meta{series}}}
  }
  % \DTLofseriesfmt
  \gcmd{DTL\-of\-series\-fmt}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{series}}
    \desc{formats the series name in \qt{of \meta{series}}}
  }
  % \DTLinseries
  \gcmd{DTL\-in\-series}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{series}}
    \desc{formats \qt{in \meta{series}}}
  }
  % \DTLjournalfmt
  \gcmd{DTL\-journal\-fmt}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{journal}}
    \desc{formats the journal name}
  }
  % \DTLinbooktitlefmt
  \gcmd{DTL\-in\-book\-title\-fmt}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{title}}
    \desc{formats the book title for an \qt{in book} reference}
  }
  % \DTLmanualtitlefmt
  \gcmd{DTL\-manual\-title\-fmt}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{title}}
    \desc{formats the manual title}
  }
  % \DTLthesistitlefmt
  \gcmd{DTL\-thesis\-title\-fmt}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{title}}
    \desc{formats the thesis title}
  }
  % \DTLproceedingstitlefmt
  \gcmd{DTL\-proceedings\-title\-fmt}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{title}}
    \desc{formats the proceedings title}
  }
  % \DTLformatbooktitle
  \gcmd{DTL\-format\-book\-title}
  {
    \providedby{\sty{databib} v2.22+}
    \syntax{\margm{title}}
    \desc{formats a book title}
  }
  % \DTLformatauthor
  \gcmd{DTL\-format\-author}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{von part}\margm{surname}\margm{jr part}\margm{forenames}}
    \desc{formats the author's name}
  }
  % \DTLformateditor
  \gcmd{DTL\-format\-editor}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{von part}\margm{surname}\margm{jr part}\margm{forenames}}
    \desc{formats the editor's name}
  }
  % \DTLformatsurnameonly
  \gcmd{DTL\-format\-surname\-only}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{von part}\margm{surname}\margm{jr part}\margm{forenames}}
    \desc{formats the name, omitting the forenames}
  }
  % \DTLformatforenames
  \gcmd{DTL\-format\-forenames}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{forenames}}
    \desc{formats the forenames (with a leading space and updating
conditionals)}
  }
  % \DTLformatabbrvforenames
  \gcmd{DTL\-format\-abbrv\-fore\-names}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{forenames}}
    \desc{as \gls{DTLformatforenames} but converts the forenames to
initials with \gls{DTLstoreinitials}}
  }
  % \DTLformatvon
  \gcmd{DTL\-format\-von}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{von}}
    \desc{formats \meta{von} (with a leading space and updating
conditionals) if not empty}
  }
  % \DTLformatsurname
  \gcmd{DTL\-format\-surname}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{surname}}
    \desc{formats \meta{surname} (with a leading space and updating
conditionals)}
  }
  % \DTLformatjr
  \gcmd{DTL\-format\-jr}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{jr}}
    \desc{formats \meta{jr} (with a leading space and updating
conditionals) if not empty}
  }
  % \DTLformatcrossrefeditor
  \gcmd{DTL\-format\-cross\-ref\-editor}
  {
    \providedby{\sty{databib}}
    \desc{formats cross-reference editors}
  }
  % \DTLformatvolnumpages
  \gcmd{DTL\-format\-vol\-num\-pages}
  {
    \providedby{\sty{databib}}
    \desc{formats the volume, number and pages (of an article)}
  }
  % \DTLformatbvolume
  \gcmd{DTL\-format\-b\-volume}
  {
    \providedby{\sty{databib}}
    \desc{formats the volume for a book}
  }
  % \DTLformatchapterpages
  \gcmd{DTL\-format\-chapter\-pages}
  {
    \providedby{\sty{databib}}
    \desc{formats the chapter and page(s)}
  }
  % \DTLformatpages
  \gcmd{DTL\-format\-pages}
  {
    \providedby{\sty{databib}}
    \desc{formats page(s)}
  }
  % \DTLformatnumberseries
  \gcmd{DTL\-format\-number\-series}
  {
    \providedby{\sty{databib}}
    \desc{formats number and series (of a book)}
  }
  % \DTLformatbookcrossref
  \gcmd{DTL\-format\-book\-cross\-ref}
  {
    \providedby{\sty{databib}}
    \desc{formats a book cross reference}
  }
  % \DTLformatincollproccrossref
  \gcmd{DTL\-format\-in\-coll\-proc\-cross\-ref}
  {
    \providedby{\sty{databib}}
    \desc{formats an \qt{in collections} reference}
  }
  % \DTLformatinedbooktitle
  \gcmd{DTLformat\-in\-ed\-book\-title}
  {
    \providedby{\sty{databib}}
    \desc{formats in editor and book title}
  }
  % \DTLformatdate
  \gcmd{DTL\-format\-date}
  {
    \providedby{\sty{databib}}
    \desc{formats the date obtained from the \databibcolkey{Date}
    field if set, or from the \databibcolkey{Year} and
    \databibcolkey{Month} fields (if set)}
  }
  % \DTLbibformatdigital
  \gcmd{DTL\-bib\-format\-digital}
  {
    \providedby{\sty{databib} v3.0+}
    \desc{formats the information provided in the
    \databibcolkey{PubMed}, \databibcolkey{DOI}, \databibcolkey{Url}
    and \databibcolkey{Eprints} fields}
  }
  % \DTLbibdoi
  \gcmd{DTL\-bib\-doi}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{doi}}
    \desc{used to format the \databibcolkey{DOI} field (which should
already be detokenized)}
  }
  % \DTLbibdoihome
  \gcmd{DTL\-bib\-doi\-home}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{https://doi.org/}
    \desc{used by \gls{DTLbibdoi} in the formation of the hyperlink, if applicable}
  }
  % \DTLbibdoitag
  \gcmd{DTL\-bib\-doi\-tag}
  {
    \providedby{\sty{databib} v3.0+}
    \desc{expands to the textual tag used at the start of \gls{DTLbibdoi}}
  }
  % \DTLbibpubmedhome
  \gcmd{DTL\-bib\-pub\-med\-home}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{https://pubmed.ncbi.nlm.nih.gov/}
    \desc{used by \gls{DTLbibpubmed} in the formation of the hyperlink, if applicable}
  }
  % \DTLbibpubmed
  \gcmd{DTL\-bib\-pub\-med}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{pmid}}
    \desc{used to format the \databibcolkey{PubMed} field}
  }
  % \DTLbibpubmedtag
  \gcmd{DTL\-bib\-pub\-med\-tag}
  {
    \providedby{\sty{databib} v3.0+}
    \desc{expands to the textual tag used at the start of \gls{DTLbibpubmed}}
  }
  % \DTLbiburl
  \gcmd{DTL\-bib\-url}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{url}}
    \desc{used to format the \databibcolkey{Url} field (which should
already be detokenized)}
  }
  % \DTLbiburldate
  \gcmd{DTL\-bib\-url\-date}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{date}}
    \desc{used to format the \databibcolkey{UrlDate} field}
  }
  % \DTLbibaccessedname
  \gcmd{DTL\-bib\-accessed\-name}
  {
    \providedby{\sty{databib} v3.0+}
    \initval{accessed}
    \desc{locale-sensitive command used by \gls{DTLbiburldate}}
  }
  % \DTLformatarticlecrossref
  \gcmd{DTL\-format\-article\-cross\-ref}
  {
    \providedby{\sty{databib}}
    \desc{formats an article cross reference}
  }
  % \DTLbibeprints
  \gcmd{DTL\-bib\-eprints}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{url}\margm{eprint-type}}
    \desc{used to format the \databibcolkey{Eprints} field (which should
already be detokenized)}
  }
  % \DTLpcite
  \gcmd{DTL\-p\-cite}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{cite key(s)}}
    \desc{used to cite cross-references. This essential does 
    \code{\gls{cite}\margm{cite key(s)}} ensuring that the argument
    is first expanded}
  }
  % \DTLformatedition
  \gcmd{DTL\-format\-edition}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{edition}}
    \desc{formats the edition}
  }
  % \DTLformatarticle
  \gcmd{DTL\-format\-article}
  {
    \providedby{\sty{databib}}
    \desc{formats an article reference according to the current style}
  }
  % \DTLformatbook
  \gcmd{DTL\-format\-book}
  {
    \providedby{\sty{databib}}
    \desc{formats a book reference according to the current style}
  }
  % \DTLformatbooklet
  \gcmd{DTL\-format\-book\-let}
  {
    \providedby{\sty{databib}}
    \desc{formats a booklet reference according to the current style}
  }
  % \DTLformatinbook
  \gcmd{DTL\-format\-in\-book}
  {
    \providedby{\sty{databib}}
    \desc{formats an \qt{in book} reference according to the current style}
  }
  % \DTLformatincollection
  \gcmd{DTL\-format\-in\-collection}
  {
    \providedby{\sty{databib}}
    \desc{formats an \qt{in collection} reference according to the current style}
  }
  % \DTLformatinproceedings
  \gcmd{DTL\-format\-in\-proceedings}
  {
    \providedby{\sty{databib}}
    \desc{formats an \qt{in proceedings} reference according to the current style}
  }
  % \DTLformatmanual
  \gcmd{DTL\-format\-manual}
  {
    \providedby{\sty{databib}}
    \desc{formats a manual reference according to the current style}
  }
  % \DTLformatmastersthesis
  \gcmd{DTL\-format\-masters\-thesis}
  {
    \providedby{\sty{databib}}
    \desc{formats a master's thesis reference according to the current style}
  }
  % \DTLformatmisc
  \gcmd{DTL\-format\-misc}
  {
    \providedby{\sty{databib}}
    \desc{formats a miscellaneous reference according to the current style}
  }
  % \DTLformatphdthesis
  \gcmd{DTL\-format\-phd\-thesis}
  {
    \providedby{\sty{databib}}
    \desc{formats a PhD thesis reference according to the current style}
  }
  % \DTLformatproceedings
  \gcmd{DTL\-format\-proceedings}
  {
    \providedby{\sty{databib}}
    \desc{formats a proceedings reference according to the current style}
  }
  % \DTLformattechreport
  \gcmd{DTL\-format\-tech\-report}
  {
    \providedby{\sty{databib}}
    \desc{formats a technical report reference according to the current style}
  }
  % \DTLformatunpublished
  \gcmd{DTL\-format\-un\-published}
  {
    \providedby{\sty{databib}}
    \desc{formats an unpublished reference according to the current style}
  }
  % \DTLbibfieldexists
  \gcmd{DTL\-bib\-field\-exists}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}}
    \desc{for use in \gls{ifthenelse}, this conditional tests if the
     named field exists (the column is defined and the value is not null)
     for the current row}
  }
  % \DTLbibfieldiseq
  \gcmd{DTL\-bib\-field\-is\-eq}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}\margm{value}}
    \desc{for use in \gls{ifthenelse}, this conditional tests if the
     value of the named field for the current row is equal to \meta{value}}
  }
  % \DTLbibfieldislt
  \gcmd{DTL\-bib\-field\-is\-lt}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}\margm{value}}
    \desc{for use in \gls{ifthenelse}, this conditional tests if the
     value of the named field for the current row is
     lexicographically less than \meta{value}}
  }
  % \DTLbibfieldisle
  \gcmd{DTL\-bib\-field\-is\-le}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}\margm{value}}
    \desc{for use in \gls{ifthenelse}, this conditional tests if the
     value of the named field for the current row is
     lexicographically less than or equal to \meta{value}}
  }
  % \DTLbibfieldisgt
  \gcmd{DTL\-bib\-field\-is\-gt}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}\margm{value}}
    \desc{for use in \gls{ifthenelse}, this conditional tests if the
     value of the named field for the current row is
     lexicographically greater than \meta{value}}
  }
  % \DTLbibfieldisge
  \gcmd{DTL\-bib\-field\-is\-ge}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}\margm{value}}
    \desc{for use in \gls{ifthenelse}, this conditional tests if the
     value of the named field for the current row is
     lexicographically greater than or equal to \meta{value}}
  }
  % \DTLbibfieldcontains
  \gcmd{DTL\-bib\-field\-contains}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{field label}\margm{value}}
    \desc{for use in \gls{ifthenelse}, this conditional tests if the
     value of the named field for the current row contains \meta{value}}
  }
  % \DTLbibsortencap
  \gcmd{DTL\-bib\-sort\-en\-cap}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{value}\margm{col-idx}\margm{db-name}}
    \desc{provided for use with the \sortdataopt{encap} sort option to
    convert the comma-separated name lists in the \optfmt{Author} and
    \optfmt{Editor} fields to a format better suited for a sort
value. Each element in the list will be encapsulated with
\gls{DTLbibsortname} and separated by \gls{DTLbibsortnamesep}}
  }
  % \DTLbibsortname
  \gcmd{DTL\-bib\-sort\-name}
  {
    \providedby{\sty{databib} v3.0+}
    \syntax{\margm{von}\margm{surname}\margm{jr}\margm{forename}}
    \desc{used by \gls{DTLbibsortencap}, this command should expand
    to the format of the name best suited for sorting}
  }
  % \DTLbibsortnamesep
  \gcmd{DTL\-bib\-sort\-name\-sep}
  {
    \providedby{\sty{databib} v3.0+}
    \initvalcs{datatoolasciiend}
    \desc{separator used by \gls{DTLbibsortencap}}
  }
  % \ofname
  \gcmd{of\-name}
  {
    \providedby{\sty{databib}}
    \initval{of}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \inname
  \gcmd{in\-name}
  {
    \providedby{\sty{databib}}
    \initval{in}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \etalname
  \gcmd{et\-al\-name}
  {
    \providedby{\sty{databib}}
    \initval{et al.}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \editorname
  \gcmd{editor\-name}
  {
    \providedby{\sty{databib}}
    \initval{editor}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \editorsname
  \gcmd{editors\-name}
  {
    \providedby{\sty{databib}}
    \initval{editors}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \volumename
  \gcmd{volume\-name}
  {
    \providedby{\sty{databib}}
    \initval{volume}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \numbername
  \gcmd{number\-name}
  {
    \providedby{\sty{databib}}
    \initval{number}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \pagename
  \gcmd{page\-name}
  {
    \providedby{\sty{databib}}
    \initval{page}
    \desc{locale-sensitive command provided if it hasn't already
     been defined. This command is defined by language packages,
     such as \sty{babel}}
  }
  % \pagesname
  \gcmd{pages\-name}
  {
    \providedby{\sty{databib}}
    \initval{pages}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \editionname
  \gcmd{edition\-name}
  {
    \providedby{\sty{databib}}
    \initval{edition}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \techreportname
  \gcmd{tech\-report\-name}
  {
    \providedby{\sty{databib}}
    \initval{Technical report}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \mscthesisname
  \gcmd{msc\-thesis\-name}
  {
    \providedby{\sty{databib}}
    \initval{Master's thesis}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \phdthesisname
  \gcmd{phd\-thesis\-name}
  {
    \providedby{\sty{databib}}
    \initval{PhD thesis}
    \desc{locale-sensitive command provided if it hasn't already
     been defined}
  }
  % \DTLmonthname
  \gcmd{DTL\-month\-name}
  {
    \providedby{\sty{databib}}
    \syntax{\margm{month num}}
    \desc{formats the month name according to the current style}
  }
  % \DTLacmcs
  \gcmd{DTL\-acmcs}
  {
    \providedby{\sty{databib}}
    \desc{expands to ACM Computing Surveys or its abbreviation,
according to the style}
  }
  % \DTLacta
  \gcmd{DTL\-acta}
  {
    \providedby{\sty{databib}}
    \desc{expands to Acta Informatica or its abbreviation,
according to the style}
  }
  % \DTLcacm
  \gcmd{DTL\-cacm}
  {
    \providedby{\sty{databib}}
    \desc{expands to Communications of the ACM or its abbreviation,
according to the style}
  }
  % \DTLibmjrd
  \gcmd{DTL\-ibmjrd}
  {
    \providedby{\sty{databib}}
    \desc{expands to IBM Journal of Research and Development or its abbreviation,
according to the style}
  }
  % \DTLibmsj
  \gcmd{DTL\-ibmsj}
  {
    \providedby{\sty{databib}}
    \desc{expands to IBM Systems Journal or its abbreviation,
according to the style}
  }
  % \DTLieeese
  \gcmd{DTL\-ieeese}
  {
    \providedby{\sty{databib}}
    \desc{expands to IEEE Transactions on Software Engineering or its abbreviation,
according to the style}
  }
  % \DTLieeetc
  \gcmd{DTL\-ieeetc}
  {
    \providedby{\sty{databib}}
    \desc{expands to IEEE Transactions on Computers or its abbreviation,
according to the style}
  }
  % \DTLieeetcad
  \gcmd{DTL\-ieeetcad}
  {
    \providedby{\sty{databib}}
    \desc{expands to IEEE Transactions on Computer-Aided Design
of Integrated Circuits or its abbreviation,
according to the style}
  }
  % \DTLipl
  \gcmd{DTL\-ipl}
  {
    \providedby{\sty{databib}}
    \desc{expands to Information Processing Letters or its abbreviation,
according to the style}
  }
  % \DTLjacm
  \gcmd{DTL\-jacm}
  {
    \providedby{\sty{databib}}
    \desc{expands to Journal of the ACM or its abbreviation,
according to the style}
  }
  % \DTLjcss
  \gcmd{DTL\-jcss}
  {
    \providedby{\sty{databib}}
    \desc{expands to Journal of Computer and System Sciences or its abbreviation,
according to the style}
  }
  % \DTLscp
  \gcmd{DTL\-scp}
  {
    \providedby{\sty{databib}}
    \desc{expands to Science of Computer Programming or its abbreviation,
according to the style}
  }
  % \DTLsicomp
  \gcmd{DTL\-sicomp}
  {
    \providedby{\sty{databib}}
    \desc{expands to SIAM Journal on Computing or its abbreviation,
according to the style}
  }
  % \DTLtocs
  \gcmd{DTL\-tocs}
  {
    \providedby{\sty{databib}}
    \desc{expands to ACM Transactions on Computer Systems or its abbreviation,
according to the style}
  }
  % \DTLtods
  \gcmd{DTL\-tods}
  {
    \providedby{\sty{databib}}
    \desc{expands to ACM Transactions on Database Systems or its abbreviation,
according to the style}
  }
  % \DTLtog
  \gcmd{DTL\-tog}
  {
    \providedby{\sty{databib}}
    \desc{expands to ACM Transactions on Graphics or its abbreviation,
according to the style}
  }
  % \DTLtoms
  \gcmd{DTL\-toms}
  {
    \providedby{\sty{databib}}
    \desc{expands to ACM Transactions on Mathematical Software or its abbreviation,
according to the style}
  }
  % \DTLtoois
  \gcmd{DTL\-toois}
  {
    \providedby{\sty{databib}}
    \desc{expands to ACM Transactions on Office Information
Systems or its abbreviation,
according to the style}
  }
  % \DTLtoplas
  \gcmd{DTL\-toplas}
  {
    \providedby{\sty{databib}}
    \desc{expands to ACM Transactions on Programming Languages
and Systems or its abbreviation,
according to the style}
  }
  % \DTLtcs
  \gcmd{DTL\-tcs}
  {
    \providedby{\sty{databib}}
    \desc{expands to Theoretical Computer Science or its abbreviation,
according to the style}
  }
  % \DTLresetpredefined
  \gcmd{DTL\-reset\-pre\-defined}
  {
    \providedby{\sty{databib} v3.0+}
    \desc{redefines \gls{DTLacmcs} etc to their long titles}
  }
  % \DTLresetpredefinedabbrv
  \gcmd{DTL\-reset\-pre\-defined\-abbrv}
  {
    \providedby{\sty{databib} v3.0+}
    \desc{redefines \gls{DTLacmcs} etc to their abbreviated titles}
  }
  % DTLthebibliography ENVIRONMENT
  \genv{DTL\-the\-bib\-lio\-graphy}
  {
    \providedby{\sty{databib}}
    \syntax{\oargm{condition}\margm{db-name}}
    \desc{formats the bibliography (using \env{thebibliography})
according to the current style}
  }
  % DTLbibrow COUNTER
  \gctr{DTL\-bib\-row}
  {
    \providedby{\sty{databib}}
    \desc{used by \gls{DTLforeachbibentry} and \gls{sDTLforeachbibentry}
    to keep track of the current (filtered) row number}
  }
  % DTLmaxauthors COUNTER
  \gctr{DTL\-max\-authors}
  {
    \providedby{\sty{databib}}
    \initval{10}
    \desc{the value of this counter indicates the maximum number of
    author names to display. If there are more than this
    number, \gls{etalname} is used}
  }
  % DTLmaxeditors COUNTER
  \gctr{DTL\-max\-editors}
  {
    \providedby{\sty{databib}}
    \initval{10}
    \desc{the value of this counter indicates the maximum number of
    editor names to display. If there are more than this
    number, \gls{etalname} is used}
  }
  % databib COLUMN KEYS
  \gdatabibcolkey{EntryType}{}
  \gdatabibcolkey{CiteKey}{}
  \gdatabibcolkey{Address}{}
  \gdatabibcolkey{Author}{}
  \gdatabibcolkey{BookTitle}{}
  \gdatabibcolkey{Chapter}{}
  \gdatabibcolkey{Edition}{}
  \gdatabibcolkey{Editor}{}
  \gdatabibcolkey{HowPublished}{}
  \gdatabibcolkey{Institution}{}
  \gdatabibcolkey{Journal}{}
  \gdatabibcolkey{Key}{}
  \gdatabibcolkey{Month}{}
  \gdatabibcolkey{Note}{}
  \gdatabibcolkey{Number}{}
  \gdatabibcolkey{Organization}{}
  \gdatabibcolkey{Pages}{}
  \gdatabibcolkey{Publisher}{}
  \gdatabibcolkey{School}{}
  \gdatabibcolkey{Series}{}
  \gdatabibcolkey{Title}{}
  \gdatabibcolkey{Type}{}
  \gdatabibcolkey{Volume}{}
  \gdatabibcolkey{Year}{}
  \gdatabibcolkey{Date}{}
  \gdatabibcolkey{ISBN}{}
  \gdatabibcolkey{ISSN}{}
  \gdatabibcolkey{EID}{}
  \gdatabibcolkey{DOI}{}
  \gdatabibcolkey{PubMed}{}
  \gdatabibcolkey{Url}{}
  \gdatabibcolkey{UrlDate}{}
  \gdatabibcolkey{Abstract}{}
  \gdatabibcolkey{File}{}
  \gdatabibcolkey{Eprints}{}
  \gdatabibcolkey{EprintType}{}
  \gdatabibcolkey{Citations}{}
  % COMMANDS: PERSON
  % \newperson
  \gcmd{new\-person}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}\margm{full name}\margm{name}\margm{gender-label}}
    \desc{defines a person identified by the given label. If
    omitted, \meta{person-label} will default to \code{anon}. The
    \meta{gender-label} may be \qt{unknown} or empty, if not known,
    or a valid gender label. The starred form \gls{newperson*} uses
    a \keyval\ interface}
   }
  % \newperson*
  \gcmd{new\-person*}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\oargm{person-label}\marg{\keyvallist}}
    \desc{defines a person identified by the given label. If
    omitted, \meta{person-label} will default to \code{anon}}
   }
  % \newperson* OPTION fullname
   \gnewpersonopt{full\-name}
   {
     \initvalempty
     \syntax{\margm{full name}}
     \desc{the person's full name}
   }
  % \newperson* OPTION expand-fullname
   \gnewpersonopt{expand\dhyphen full\-name}
   {
     \initvalempty
     \syntax{\margm{full name}}
     \desc{as \newpersonopt{fullname} but fully expands the value}
   }
  % \newperson* OPTION expand-once-fullname
   \gnewpersonopt{expand\dhyphen once\dhyphen full\-name}
   {
     \initvalempty
     \syntax{\margm{full name}}
     \desc{as \newpersonopt{fullname} but expands the first token
      of value once}
   }
  % \newperson* OPTION name
   \gnewpersonopt{name}
   {
     \initvalempty
     \syntax{\margm{name}}
     \desc{the person's forename or familiar name}
   }
  % \newperson* OPTION expand-name
   \gnewpersonopt{expand\dhyphen name}
   {
     \initvalempty
     \syntax{\margm{name}}
     \desc{as \newpersonopt{name} but fully expands the value}
   }
  % \newperson* OPTION expand-once-name
   \gnewpersonopt{expand\dhyphen once\dhyphen name}
   {
     \initvalempty
     \syntax{\margm{name}}
     \desc{as \newpersonopt{name} but expands the first token
      of value once}
   }
  % \newperson* OPTION surname
   \gnewpersonopt{surname}
   {
     \initvalempty
     \syntax{\margm{surname}}
     \desc{the person's surname}
   }
  % \newperson* OPTION expand-surname
   \gnewpersonopt{expand\dhyphen surname}
   {
     \initvalempty
     \syntax{\margm{surname}}
     \desc{as \newpersonopt{surname} but fully expands the value}
   }
  % \newperson* OPTION expand-once-surname
   \gnewpersonopt{expand\dhyphen once\dhyphen surname}
   {
     \initvalempty
     \syntax{\margm{surname}}
     \desc{as \newpersonopt{surname} but expands the first token
      of value once}
   }
  % \newperson* OPTION forenames
   \gnewpersonopt{forenames}
   {
     \initvalempty
     \syntax{\margm{forenames}}
     \desc{the person's forenames}
   }
  % \newperson* OPTION expand-forenames
   \gnewpersonopt{expand\dhyphen forenames}
   {
     \initvalempty
     \syntax{\margm{forenames}}
     \desc{as \newpersonopt{forenames} but fully expands the value}
   }
  % \newperson* OPTION expand-once-forenames
   \gnewpersonopt{expand\dhyphen once\dhyphen forenames}
   {
     \initvalempty
     \syntax{\margm{forenames}}
     \desc{as \newpersonopt{forenames} but expands the first token
      of value once}
   }
  % \newperson* OPTION title
   \gnewpersonopt{title}
   {
     \initvalempty
     \syntax{\margm{title}}
     \desc{the person's title (form of address)}
   }
  % \newperson* OPTION expand-title
   \gnewpersonopt{expand\dhyphen title}
   {
     \initvalempty
     \syntax{\margm{title}}
     \desc{as \newpersonopt{title} but fully expands the value}
   }
  % \newperson* OPTION expand-once-title
   \gnewpersonopt{expand\dhyphen once\dhyphen title}
   {
     \initvalempty
     \syntax{\margm{title}}
     \desc{as \newpersonopt{title} but expands the first token
      of value once}
   }
  % \newperson* OPTION gender
   \gnewpersonopt{gender}
   {
     \initvalempty
     \syntax{\margm{gender-label}}
     \desc{the person's gender as identified by \meta{gender-label}
     (which will be fully expanded before testing). If empty or
      omitted, \qt{unknown} will be assumed}
   }
  % \malelabels
  \gcmd{male\-labels}
   {
    \providedby{\sty{person} pre v3.0}
    \banned
    \desc{prior to v3.0, \gls{malelabels} expanded to the comma-separated list of recognised male
gender labels. This command was replaced with \gls{gpersonmalelabelclist} variable in
version 3.0 to reduce the possibility of a command name clash.
Now only available with rollback.
Use \gls{PersonSetMaleLabels} to reset the list or
\gls{PersonAddMaleLabel} to append to the list}
   }
  % \g_person_male_label_clist
  \gcmd{g\dsb person\dsb male\dsb label\dsb clist}
   {
    \providedby{\sty{person} v3.0+}
    \desc{comma separated list variable used to store the list of
labels that may be used to identify the male gender}
   }
  % \addmalelabel
  \gcmd{add\-male\-label}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\margm{label}}
    \desc{this deprecated command has been replaced with
\gls{PersonAddMaleLabel} and may be removed in future}
   }
  % \PersonAddMaleLabel
  \gcmd{Person\-Add\-Male\-Label}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{label}}
    \desc{adds the given label (after expansion) to the list of
labels that may be used to identify the male gender}
   }
  % \PersonSetMaleLabels
  \gcmd{Person\-Set\-Male\-Labels}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{label list}}
    \desc{sets the list of labels that may be used to identify the male gender}
   }
  % \femalelabels
  \gcmd{fe\-male\-labels}
   {
    \providedby{\sty{person} pre v3.0}
    \banned
    \desc{prior to v3.0, \gls{femalelabels} expanded to the
comma-separated list of recognised female
gender labels. This command was replaced with \gls{gpersonfemalelabelclist} variable in
version 3.0 to reduce the possibility of a command name clash.
Now only available with rollback.
Use \gls{PersonSetFemaleLabels} to reset the list or
\gls{PersonAddFemaleLabel} to append to the list}
   }
  % \g_person_female_label_clist
  \gcmd{g\dsb person\dsb female\dsb label\dsb clist}
   {
    \providedby{\sty{person} v3.0+}
    \desc{comma separated list variable used to store the list of
labels that may be used to identify the female gender}
   }
  % \addfemalelabel
  \gcmd{add\-female\-label}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\margm{label}}
    \desc{this deprecated command has been replaced with
\gls{PersonAddFemaleLabel} and may be removed in future}
   }
  % \PersonAddFemaleLabel
  \gcmd{Person\-Add\-Female\-Label}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{label}}
    \desc{adds the given label (after expansion) to the list of
labels that may be used to identify the female gender}
   }
  % \PersonSetFemaleLabels
  \gcmd{Person\-Set\-Female\-Labels}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{label list}}
    \desc{sets the list of labels that may be used to identify the
female gender}
   }
  % \g_person_nonbinary_label_clist
  \gcmd{g\dsb person\dsb nonbinary\dsb label\dsb clist}
   {
    \providedby{\sty{person} v3.0+}
    \desc{comma separated list variable used to store the list of
     non-binary labels}
   }
  % \PersonAddNonBinaryLabel
  \gcmd{Person\-Add\-Non\-Binary\-Label}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{label}}
    \desc{adds the given label (after expansion) to the list of
labels that may be used to identify the non-binary gender}
   }
  % \PersonSetNonBinaryLabels
  \gcmd{Person\-Set\-NonBinary\-Labels}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{label list}}
    \desc{sets the list of labels that may be used to identify the
non-binary gender}
   }
  % \PersonIfMaleLabel
  \gcmd{Person\-If\-Male\-Label}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{gender-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if the one-level expansion of
    \meta{gender-label} is recognised as a male gender identifier}
    \field{seealso}{PersonAddMaleLabel,PersonSetMaleLabels}
   }
  % \ifmalelabel
  \gcmd{if\-male\-label}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\margm{gender-label}\margm{true}\margm{false}}
    \desc{deprecated. Use \gls{PersonIfMaleLabel} instead}
   }
  % \PersonIfFemaleLabel
  \gcmd{Person\-If\-Female\-Label}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{gender-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if the one-level expansion of
    \meta{gender-label} is recognised as a female gender identifier}
    \field{seealso}{PersonAddFemaleLabel,PersonSetFemaleLabels}
   }
  % \iffemalelabel
  \gcmd{if\-female\-label}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\margm{gender-label}\margm{true}\margm{false}}
    \desc{deprecated. Use \gls{PersonIfFemaleLabel} instead}
   }
  % \PersonIfNonBinaryLabel
  \gcmd{Person\-If\-Non\-Binary\-Label}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{gender-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if the one-level expansion of
    \meta{gender-label} is recognised as a non-binary gender identifier
     (does not include \qt{unknown})}
    \field{seealso}{PersonAddNonBinaryLabel,PersonSetNonBinaryLabels}
   }
  % \PersonIfMale
  \gcmd{Person\-If\-Male}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{person-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if the person identified by
    \meta{person-label} was defined with the gender set to male,
otherwise does \meta{false}}
   }
  % \ifmale
  \gcmd{if\-male}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\margm{person-label}\margm{true}\margm{false}}
    \desc{deprecated. Use \gls{PersonIfMale} instead}
   }
  % \PersonIfAllMale
  \gcmd{Person\-If\-All\-Male}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\oargm{person-label-list}\margm{true}\margm{false}}
    \desc{does \meta{true} if all the people identified in the list
    \meta{person-label-list} were defined with the gender set to male,
otherwise does \meta{false}. If the optional argument is omitted,
this simply compares if \gls{PersonTotalCount} is equal
to \gls{PersonMaleCount}}
   }
  % \ifallmale
  \gcmd{if\-all\-male}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\oargm{person-label-list}\margm{true}\margm{false}}
    \desc{deprecated. Use \gls{PersonIfAllMale} instead}
   }
  % \PersonIfFemale
  \gcmd{Person\-If\-Female}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{person-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if the person identified by
    \meta{person-label} was defined with the gender set to female,
otherwise does \meta{false}}
   }
  % \iffemale
  \gcmd{if\-female}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\margm{person-label}\margm{true}\margm{false}}
    \desc{deprecated. Use \gls{PersonIfFemale} instead}
   }
  % \PersonIfAllFemale
  \gcmd{Person\-If\-All\-Female}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\oargm{person-label-list}\margm{true}\margm{false}}
    \desc{does \meta{true} if all the people identified in the list
    \meta{person-label-list} were defined with the gender set to female,
otherwise does \meta{false}. If the optional argument is omitted,
this simply compares if \gls{PersonTotalCount} is equal
to \gls{PersonFemaleCount}}
   }
  % \ifallfemale
  \gcmd{if\-all\-female}
   {
    \deprecated
    \providedby{\sty{person}}
    \syntax{\oargm{person-label-list}\margm{true}\margm{false}}
    \desc{deprecated. Use \gls{PersonIfAllFemale} instead}
   }
  % \PersonIfNonBinary
  \gcmd{Person\-If\-Non\-Binary}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{person-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if the person identified by
    \meta{person-label} was defined with the gender set to non-binary,
otherwise does \meta{false}}
   }
  % \PersonIfAllNonBinary
  \gcmd{Person\-If\-All\-Non\-Binary}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\oargm{person-label-list}\margm{true}\margm{false}}
    \desc{does \meta{true} if all the people identified in the list
    \meta{person-label-list} were defined with the gender set to non-binary,
otherwise does \meta{false}. If the optional argument is omitted,
this simply compares if \gls{PersonTotalCount} is equal
to \gls{PersonNonBinaryCount}}
   }
  % \PersonIfUnknownGender
  \gcmd{Person\-If\-Un\-known\-Gender}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{person-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if the person identified by
    \meta{person-label} was defined with the gender set to unknown,
otherwise does \meta{false}}
   }
  % \PersonIfAllUnknownGender
  \gcmd{Person\-If\-All\-Unknown\-Gender}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\oargm{person-label-list}\margm{true}\margm{false}}
    \desc{does \meta{true} if all the people identified in the list
    \meta{person-label-list} were defined with the gender set to unknown,
otherwise does \meta{false}. If the optional argument is omitted,
this simply compares if \gls{PersonTotalCount} is equal
to \gls{PersonUnknownGenderCount}}
   }
  % \removeperson
  \gcmd{remove\-person}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{removes (undefines) the person identified by
     \meta{person-label}. If omitted, this defaults to \optfmt{anon}}
   }
  % \removepeople
  \gcmd{remove\-people}
   {
    \providedby{\sty{person}}
    \syntax{\margm{list}}
    \desc{removes each person identified by their label in the given
comma-separated list}
   }
  % \removeallpeople
  \gcmd{remove\-all\-people}
   {
    \providedby{\sty{person}}
    \desc{removes all defined people}
   }
  % \foreachperson
  \gcmd{for\-each\-person}
   {
    \providedby{\sty{person}}
    \syntax{(\meta{name-cs},\meta{full-name-cs},\meta{gender-cs},\meta{label-cs})\csfmt{in}\margm{label-list}\csfmt{do}\margm{body}}
    \desc{iterates through the list of people and, at each
iteration, assigns \meta{name-cs} to the person's name,
\meta{full-name-cs} to the person's full name, \meta{gender-cs} to
the language-sensitive gender text, and \meta{label-cs} to the
person's label, and then does \meta{body}. The
\code{\csfmt{in}\margm{label-list}} is optional. If omitted
the list of all defined people is assumed}
     \field{seealso}{forallpeople,foreachpersonbreak}
   }
  % \forallpeople
  \gcmd{for\-all\-people}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{people-label-list}\margm{label-cs}\margm{body}}
    \desc{iterates over all labels in the given list and, at each
    iteration, sets \meta{label-cs} to the current label and does
\meta{body}. If the optional argument is omitted, the list of all
defined people is used}
     \field{seealso}{foreachpersonbreak}
   }
  % \foreachpersonbreak
  \gcmd{for\-each\-person\-break}
   {
    \providedby{\sty{person} v3.0+}
    \desc{breaks out of the people loops}
   }
  % \ifpersonexists
  \gcmd{if\-person\-exists}
   {
    \providedby{\sty{person}}
    \syntax{\margm{person-label}\margm{true}\margm{false}}
    \desc{does \meta{true} if there is a person defined with the
given label, otherwise does \meta{false}. The \meta{person-label}
argument is trimmed and expanded before testing}
   }
  % \person_if_exist:nTF
  \gexplpred{person\dsb if\dsb exist}{n}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{person-label} \TFsyntax}
    \desc{tests if a person has been defined with the given label}
   }
  % \person_gender_case:Nnnnnn
  \gcmd{person\dsb gender\dsb case:Nnnnnn}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \meta{tl\dhyphen var} \margm{invalid\dhyphen case}
     \margm{male\dhyphen case} \margm{female\dhyphen case}
     \margm{non\dhyphen binary\dhyphen case}
     \margm{unknown\dhyphen case}}
    \desc{compares the given token list variable (using
     \csfmt{tl\dsb if\dsb eq:NNTF}) against the constants
     \gls{cpersonmalelabeltl}, \gls{cpersonfemalelabeltl},
     \gls{cpersonnonbinarylabeltl}, and \gls{cpersonunknownlabeltl}
     and does the applicable case or \meta{invalid-case} if no match}
   }
  % \person_gender_case:nnnnnn
  \gcmd{person\dsb gender\dsb case:nnnnnn}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \meta{token\dhyphen list} \margm{invalid\dhyphen case}
     \margm{male\dhyphen case} \margm{female\dhyphen case}
     \margm{non\dhyphen binary\dhyphen case}
     \margm{unknown\dhyphen case}}
    \desc{as \gls{persongendercase:Nnnnnn} but the gender label is
    supplied as a token list}
   }
  % \person_gender_case:Nnnnn
  \gcmd{person\dsb gender\dsb case:Nnnnn}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \meta{tl\dhyphen var} 
     \margm{male\dhyphen case} \margm{female\dhyphen case}
     \margm{non\dhyphen binary\dhyphen case}
     \margm{unknown\dhyphen case}}
    \desc{as \gls{persongendercase:Nnnnnn} but issues an error for
the invalid case and treats it as unknown}
   }
  % \person_gender_case:nnnnn
  \gcmd{person\dsb gender\dsb case:nnnnn}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \meta{token\dhyphen list} 
     \margm{male\dhyphen case} \margm{female\dhyphen case}
     \margm{non\dhyphen binary\dhyphen case}
     \margm{unknown\dhyphen case}}
    \desc{as \gls{persongendercase:Nnnnn} but the gender label is
    supplied as a token list}
   }
  % \person_do_if_valid_gender:nT
  \gcmd{person\dsb do\dsb if\dsb valid\dsb gender:nT}
   {
     \providedby{\sty{person} v3.0+}
     \syntax{\ \margm{token\dhyphen list} \margm{code}}
     \desc{does \meta{code} if the given \meta{token-list} matches
     a recognised internal gender label, otherwise triggers an error
and does nothing}
   }
  % \person_all_gender_case:nnnn
  \gcmd{person\dsb all\dsb gender\dsb case:nnnn}
   {
     \providedby{\sty{person} v3.0+}
     \syntax{\ \margm{all\dhyphen male\dhyphen case}
      \margm{all\dhyphen female\dhyphen case}
      \margm{all\dhyphen non\dhyphen binary\dhyphen case}
      \margm{other\dhyphen case}}
     \desc{does \meta{all-male-case} if all defined people have been 
     identified as male, does \meta{all-female-case} if all defined
     people have been identified as female, does
\meta{all-non-binary-case} if all defined people have been
identified as non-binary, and does \meta{other-case} otherwise (that
is, a mixture of genders or all defined people have no gender
specified)}
   }
  % \l_person_label_tl
  \gcmd{l\dsb person\dsb label\dsb tl}
   {
    \providedby{\sty{person} v3.0+}
    \desc{token list variable that expands to the current person
label, which may be used in \gls{newperson} hooks}
   }
  % \person_new_appto_start:n
  \gcmd{person\dsb new\dsb appto\dsb start:n}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{code}}
    \desc{append \meta{code} to hook used at the start of \gls{newperson}}
   }
  % \person_new_appto_end:n
  \gcmd{person\dsb new\dsb appto\dsb end:n}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{code}}
    \desc{append \meta{code} to hook used at the end of \gls{newperson}}
   }
  % \person_remove_appto:n
  \gcmd{person\dsb remove\dsb appto:n}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{code}}
    \desc{append \meta{code} to hook used by \gls{removeperson} and
     \gls{removepeople}}
   }
  % \person_set_attribute:nnn
  \gfnsuffix{person\dsb set\dsb attribute}{nnn}{nnV}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{person-label} \margm{attribute} \margm{value}}
    \desc{sets the attribute for the given person to \meta{value}
     (according to the \personopt{local} setting).
     No test is made to determine if the person exists or if the
attribute is valid}
   }
  % \person_get_attribute:nn
  \gcmd{person\dsb get\dsb attribute:nn}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{person-label} \margm{attribute}}
    \desc{expands to the value of the attribute for the given
person. No test is made to determine if the person exists or if the
attribute is valid}
   }
  % \person_get_attribute:Nnn
  \gcmd{person\dsb get\dsb attribute:Nnn}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \meta{tl var} \margm{person-label} \margm{attribute}}
    \desc{sets the token list variable \meta{tl var} to the value of the attribute for the given
person. No test is made to determine if the person exists or if the
attribute is valid}
   }
  % \person_unset_attribute:nn
  \gcmd{person\dsb unset\dsb attribute:nn}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{person-label} \margm{attribute}}
    \desc{undefines the attribute for the given person to \meta{value}
     (according to the \personopt{local} setting).
     No test is made to determine if the person exists or if the
     attribute name is valid}
   }
  % \person_language_text:nn
  \gcmd{person\dsb language\dsb text:nn}
  {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{person-label} \margm{type}}
    \desc{expands to the localisation text for the given \meta{type}
for the gender label associated with the given person}
  }
  % \person_Language_text:nn
  \gcmd{person\dsb Language\dsb text:nn}
  {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{person-label} \margm{type}}
    \desc{as \gls{personlanguagetext:nn} but converts the text to
sentence case}
  }
  % \person_language_all_text:n
  \gcmd{person\dsb language\dsb all\dsb text:n}
  {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{type}}
    \desc{uses the plural form of the localisation text
    (\code{plural\meta{type}}) if more than one person is defined
otherwise uses the singular form \meta{type}}
  }
  % \person_Language_all_text:n
  \gcmd{person\dsb Language\dsb all\dsb text:n}
  {
    \providedby{\sty{person} v3.0+}
    \syntax{\ \margm{type}}
    \desc{as \gls{personlanguagealltext:n} but converts to sentence
case}
  }
  % \c_person_male_label_tl
  \gcmd{c\dsb person\dsb male\dsb label\dsb tl}
   {
    \providedby{\sty{person} v3.0+}
    \desc{constant that expands to \optfmt{male}, which is the internal label
    used to identify the male gender}
   }
  % \c_person_female_label_tl
  \gcmd{c\dsb person\dsb female\dsb label\dsb tl}
   {
    \providedby{\sty{person} v3.0+}
    \desc{constant that expands to \optfmt{female}, which is the internal label
    used to identify the female gender}
   }
  % \c_person_nonbinary_label_tl
  \gcmd{c\dsb person\dsb nonbinary\dsb label\dsb tl}
   {
    \providedby{\sty{person} v3.0+}
    \desc{constant that expands to \optfmt{nonbinary}, which is the internal label
    used to identify the nonbinary gender}
   }
  % \c_person_unknown_label_tl
  \gcmd{c\dsb person\dsb unknown\dsb label\dsb tl}
   {
    \providedby{\sty{person} v3.0+}
    \desc{constant that expands to \optfmt{unknown}, which is the internal label
    used to identify the unknown gender}
   }
  % \PersonSetLocalisation
  \gcmd{Person\-Set\-Localisation}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{gender-label}\margm{type}\margm{value}}
    \desc{sets the localisation text for the given gender label
(which must be one of the internal labels \optfmt{male},
\optfmt{female}, \optfmt{nonbinary} or \optfmt{unknown}) for the
given \meta{type}}
   }
  % \personsep
  \gcmd{person\-sep}
   {
    \providedby{\sty{person}}
    \initvalcs{DTLlistformatsep}
    \desc{separator to use between all but the last pair of people in a list}
   }
  % \personlastsep
  \gcmd{person\-last\-sep}
   {
    \providedby{\sty{person}}
    \desc{separator to use between the last pair of people in a list
that contains more that two people}
   }
  % \twopeoplesep
  \gcmd{two\-people\-sep}
   {
    \providedby{\sty{person}}
    \initvalcs{DTLlistformatlastsep}
    \desc{separator to use in a list of two people}
   }
  % \personfullname
  \gcmd{person\-full\-name}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the person's full name. If the label is omitted,
\optfmt{anon} is assumed}
   }
  % \peoplefullname
  \gcmd{people\-full\-name}
   {
    \providedby{\sty{person}}
    \desc{displays all the defined people, showing the full name for
each person}
   }
  % \personname
  \gcmd{person\-name}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the person's name. If the label is omitted,
\optfmt{anon} is assumed}
   }
  % \peoplename
  \gcmd{people\-name}
   {
    \providedby{\sty{person}}
    \desc{displays all the defined people, showing the name for
each person}
   }
  % \personforenames
  \gcmd{person\-fore\-names}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\oargm{person-label}}
    \desc{displays the person's forenames. If the label is omitted,
\optfmt{anon} is assumed}
   }
  % \peopleforenames
  \gcmd{people\-fore\-names}
   {
    \providedby{\sty{person} v3.0+}
    \desc{displays all the defined people, showing the forenames for
each person}
   }
  % \personsurname
  \gcmd{person\-sur\-name}
   {
    \providedby{\sty{person} v3.0+}
    \syntax{\oargm{person-label}}
    \desc{displays the person's surname. If the label is omitted,
\optfmt{anon} is assumed}
   }
  % \peoplesurname
  \gcmd{people\-sur\-name}
   {
    \providedby{\sty{person} v3.0+}
    \desc{displays all the defined people, showing the surname for
each person}
   }
  % \persontitlesurname
  \gcmd{person\-title\-sur\-name}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the person's title and surname. If the label is omitted,
\optfmt{anon} is assumed}
   }
  % \persontitlesurnamesep
  \gcmd{person\-title\-sur\-name\-sep}
  {
    \providedby{\sty{person}}
    \initvalcs{cs.space}
    \desc{the separator between a person's title and surname}
  }
  % \peopletitlesurname
  \gcmd{people\-title\-sur\-name}
   {
    \providedby{\sty{person}}
    \desc{displays all the defined people, showing the title and surname for
each person}
   }
  % \personpronoun
  \gcmd{person\-pro\-noun}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the third person singular subjective pronoun
according to the gender of the person identified by the label}
   }
  % \Personpronoun
  \gcmd{Person\-pro\-noun}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personpronoun}, but sentence-case}
   }
  % \peoplepronoun
  \gcmd{people\-pro\-noun}
   {
    \providedby{\sty{person}}
    \desc{displays the third person plural subjective pronoun
according to the gender of all defined people}
   }
  % \Peoplepronoun
  \gcmd{People\-pro\-noun}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peoplepronoun}, but sentence-case}
   }
  % \personpronounii
  \gcmd{person\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the second person singular subjective pronoun
according to the gender of the person identified by the label}
   }
  % \Personpronounii
  \gcmd{Person\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personpronounii}, but sentence-case}
   }
  % \peoplepronounii
  \gcmd{people\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \desc{displays the second person plural subjective pronoun
according to the gender of all defined people}
   }
  % \Peoplepronounii
  \gcmd{People\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peoplepronounii}, but sentence-case}
   }
  % \personobjpronoun
  \gcmd{person\-obj\-pro\-noun}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the third person singular objective pronoun
according to the gender of the person identified by the label}
   }
  % \Personobjpronoun
  \gcmd{Person\-obj\-pro\-noun}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personobjpronoun}, but sentence-case}
   }
  % \peopleobjpronoun
  \gcmd{people\-obj\-pro\-noun}
   {
    \providedby{\sty{person}}
    \desc{displays the third person plural objective pronoun
according to the gender of all defined people}
   }
  % \Peopleobjpronoun
  \gcmd{People\-obj\-pro\-noun}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peopleobjpronoun}, but sentence-case}
   }
  % \personobjpronounii
  \gcmd{person\-obj\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the second person singular objective pronoun
according to the gender of the person identified by the label}
   }
  % \Personobjpronounii
  \gcmd{Person\-obj\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personobjpronounii}, but sentence-case}
   }
  % \peopleobjpronounii
  \gcmd{people\-obj\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \desc{displays the second person plural objective pronoun
according to the gender of all defined people}
   }
  % \Peopleobjpronounii
  \gcmd{People\-obj\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peopleobjpronounii}, but sentence-case}
   }
  % \personpossadj
  \gcmd{person\-poss\-adj}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the third person singular possessive adjective
according to the gender of the person identified by the label}
   }
  % \Personpossadj
  \gcmd{Person\-poss\-adj}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personpossadj}, but sentence-case}
   }
  % \peoplepossadj
  \gcmd{people\-poss\-adj}
   {
    \providedby{\sty{person}}
    \desc{displays the third person plural possessive adjective
according to the gender of all defined people}
   }
  % \Peoplepossadj
  \gcmd{People\-poss\-adj}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peoplepossadj}, but sentence-case}
   }
  % \personpossadjii
  \gcmd{person\-poss\-adj\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the second person singular possessive adjective
according to the gender of the person identified by the label}
   }
  % \Personpossadjii
  \gcmd{Person\-poss\-adj\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personpossadjii}, but sentence-case}
   }
  % \peoplepossadjii
  \gcmd{people\-poss\-adj\-ii}
   {
    \providedby{\sty{person}}
    \desc{displays the second person plural possessive adjective
according to the gender of all defined people}
   }
  % \Peoplepossadjii
  \gcmd{People\-poss\-adj\-ii}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peoplepossadjii}, but sentence-case}
   }
  % \personposspronoun
  \gcmd{person\-poss\-pro\-noun}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the third person singular possessive pronoun
according to the gender of the person identified by the label}
   }
  % \Personposspronoun
  \gcmd{Person\-poss\-pro\-noun}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personposspronoun}, but sentence-case}
   }
  % \peopleposspronoun
  \gcmd{people\-poss\-pro\-noun}
   {
    \providedby{\sty{person}}
    \desc{displays the third person plural possessive pronoun
according to the gender of all defined people}
   }
  % \Peopleposspronoun
  \gcmd{People\-poss\-pro\-noun}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peopleposspronoun}, but sentence-case}
   }
  % \personposspronounii
  \gcmd{person\-poss\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the second person singular possessive pronoun
according to the gender of the person identified by the label}
   }
  % \Personposspronounii
  \gcmd{Person\-poss\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personposspronounii}, but sentence-case}
   }
  % \peopleposspronounii
  \gcmd{people\-poss\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \desc{displays the second person plural possessive pronoun
according to the gender of all defined people}
   }
  % \Peopleposspronounii
  \gcmd{People\-poss\-pro\-noun\-ii}
   {
    \providedby{\sty{person}}
    \desc{as \gls{peopleposspronounii}, but sentence-case}
   }
  % \they
  \gcmd{they}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peoplepronoun}}
    \note{requires \personopt{shortcuts} option}
  }
  % \They
  \gcmd{They}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peoplepronoun}}
    \note{requires \personopt{shortcuts} option}
  }
  % \them
  \gcmd{them}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peopleobjpronoun}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Them
  \gcmd{Them}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peopleobjpronoun}}
    \note{requires \personopt{shortcuts} option}
  }
  % \their
  \gcmd{their}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peoplepossadj}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Their
  \gcmd{Their}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peoplepossadj}}
    \note{requires \personopt{shortcuts} option}
  }
  % \theirs
  \gcmd{theirs}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peopleposspronoun}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Theirs
  \gcmd{Theirs}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peopleposspronoun}}
    \note{requires \personopt{shortcuts} option}
  }
  % \you
  \gcmd{you}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peoplepronounii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \You
  \gcmd{You}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peoplepronounii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \thee
  \gcmd{thee}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peopleobjpronounii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Thee
  \gcmd{Thee}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peopleobjpronounii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \your
  \gcmd{your}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peoplepossadjii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Your
  \gcmd{Your}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peoplepossadjii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \yours
  \gcmd{yours}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peopleposspronounii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Yours
  \gcmd{Yours}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peopleposspronounii}}
    \note{requires \personopt{shortcuts} option}
  }
  % \children
  \gcmd{children}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peoplechild}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Children
  \gcmd{Children}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peoplechild}}
    \field{extra}{\styfmt{person}}
    \note{requires \personopt{shortcuts} option}
  }
  % \parents
  \gcmd{parents}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peopleparent}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Parents
  \gcmd{Parents}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peopleparent}}
    \note{requires \personopt{shortcuts} option}
  }
  % \siblings
  \gcmd{siblings}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{peoplesibling}}
    \note{requires \personopt{shortcuts} option}
  }
  % \Siblings
  \gcmd{Siblings}
  {
    \providedby{\sty{person} v3.0+}
    \desc{shortcut for \gls{Peoplesibling}}
    \note{requires \personopt{shortcuts} option}
  }
  % \personchild
  \gcmd{person\-child}
  {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the person's relationship to their parents}
  }
  % \Personchild
  \gcmd{Person\-child}
  {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personchild} but starts with a capital}
  }
  % \peoplechild
  \gcmd{people\-child}
  {
    \providedby{\sty{person}}
    \desc{displays the relationship of the defined people to their
collective parents}
  }
  % \Peoplechild
  \gcmd{People\-child}
  {
    \providedby{\sty{person}}
    \desc{as \gls{peoplechild} but starts with a capital}
  }
  % \personparent
  \gcmd{person\-parent}
  {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the person's relationship to their child}
  }
  % \Personparent
  \gcmd{Person\-parent}
  {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personparent} but starts with a capital}
  }
  % \peopleparent
  \gcmd{people\-parent}
  {
    \providedby{\sty{person}}
    \desc{displays the relationship of the defined people to their
collective children}
  }
  % \Peopleparent
  \gcmd{People\-parent}
  {
    \providedby{\sty{person}}
    \desc{as \gls{peopleparent} but starts with a capital}
  }
  % \personsibling
  \gcmd{person\-sibling}
  {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{displays the person's relationship to their siblings}
  }
  % \Personsibling
  \gcmd{Person\-sibling}
  {
    \providedby{\sty{person}}
    \syntax{\oargm{person-label}}
    \desc{as \gls{personsibling} but starts with a capital}
  }
  % \peoplesibling
  \gcmd{people\-sibling}
  {
    \providedby{\sty{person}}
    \desc{displays the relationship of the defined people to their
collective siblings}
  }
  % \Peoplesibling
  \gcmd{People\-sibling}
  {
    \providedby{\sty{person}}
    \desc{as \gls{peoplesibling} but starts with a capital}
  }
  % \persongender
  \gcmd{person\-gender}
  {
    \providedby{\sty{person}}
    \syntax{\margm{person-label}}
    \desc{displays the person's gender using localisation}
  }
  % \Persongender
  \gcmd{Person\-gender}
  {
    \providedby{\sty{person}}
    \syntax{\margm{person-label}}
    \desc{as \gls{persongender} but starts with a capital}
  }
  % \getpersongender
  \gcmd{get\-person\-gender}
  {
    \providedby{\sty{person}}
    \syntax{\margm{cs}\margm{person-label}}
    \desc{defines \meta{cs} to the language-sensitive text
identifying the person's gender}
  }
  % \getpersongenderlabel
  \gcmd{get\-person\-gender\-label}
  {
    \providedby{\sty{person}}
    \syntax{\margm{cs}\margm{person-label}}
    \desc{defines \meta{cs} to the internal gender label associated with the
given person}
  }
  % \getpersonname
  \gcmd{get\-person\-name}
  {
    \providedby{\sty{person}}
    \syntax{\margm{cs}\margm{person-label}}
    \desc{defines \meta{cs} to the person's name}
  }
  % \getpersonforenames
  \gcmd{get\-person\-fore\-names}
  {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{cs}\margm{person-label}}
    \desc{defines \meta{cs} to the person's forenames}
  }
  % \getpersonsurname
  \gcmd{get\-person\-sur\-name}
  {
    \providedby{\sty{person} v3.0+}
    \syntax{\margm{cs}\margm{person-label}}
    \desc{defines \meta{cs} to the person's surname}
  }
  % \getpersonfullname
  \gcmd{get\-person\-full\-name}
  {
    \providedby{\sty{person}}
    \syntax{\margm{cs}\margm{person-label}}
    \desc{defines \meta{cs} to the person's full name}
  }
  % \getpersontitle
  \gcmd{get\-person\-title}
  {
    \providedby{\sty{person}}
    \syntax{\margm{cs}\margm{person-label}}
    \desc{defines \meta{cs} to the person's title}
  }
  % \PersonTotalCount
   \gcmd{Person\-Total\-Count}
    {
      \providedby{\sty{person} v3.0+}
      \desc{expands to the number of people who have been
defined}
    }
  % \PersonMaleCount
   \gcmd{Person\-Male\-Count}
    {
      \providedby{\sty{person} v3.0+}
      \desc{expands to the number of male people who have been
defined}
    }
  % \PersonFemaleCount
   \gcmd{Person\-Female\-Count}
    {
      \providedby{\sty{person} v3.0+}
      \desc{expands to the number of female people who have been
defined}
    }
  % \PersonNonBinaryCount
   \gcmd{Person\-Non\-Binary\-Count}
    {
      \providedby{\sty{person} v3.0+}
      \desc{expands to the number of non-binary people who have been
defined}
    }
  % \PersonUnknownGenderCount
   \gcmd{Person\-Un\-known\-Gender\-Count}
    {
      \providedby{\sty{person} v3.0+}
      \desc{expands to the number of people who have been
defined with the gender set to unknown}
    }
  % people counter
   \gctr{people}
    {
      \providedby{\sty{person}}
      \desc{keeps track of the number of people who have been
       defined}
    }
  % ENVIRONMENTS
  \genv{DTLenvmapdata}
  {
    \providedby{\sty{datatool} v3.0+}
    \syntax{\oarg{\keyvallist}}
    \desc{does \code{\gls{DTLmapdata}\oarg{\keyvallist}\margm{body}}
    but leading and trailing spaces are trimmed from the body}
  }
  \genv{DTL\-env\-for\-each}%
  {%
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\margm{db-name}\marg{\idx{assign-list}}}
    \desc{environment alternative to \gls{DTLforeach}}
  }
  \genv{DTL\-env\-for\-each*}%
  {%
    \providedby{\sty{datatool}}
    \syntax{\oargm{condition}\margm{db-name}\marg{\idx{assign-list}}}
    \desc{environment alternative to \starredcs{DTLforeach}}
  }
  % COUNTERS
  \gctr{DTL\-row}
  {
    \providedby{\sty{datatool}}
    \desc{used by \gls{DTLforeach} as a root counter to ensure hypertarget uniqueness}
  }
  \gctr{DTL\-row\-i}
  {
    \providedby{\sty{datatool}}
    \desc{used by \gls{DTLforeach} to keep track of the current row
     number for the outermost level}
  }
  \gctr{DTL\-row\-ii}
  {
    \providedby{\sty{datatool}}
    \desc{used by \gls{DTLforeach} to keep track of the current row
     number for nested level~2}
  }
  \gctr{DTL\-row\-iii}
  {
    \providedby{\sty{datatool}}
    \desc{used by \gls{DTLforeach} to keep track of the current row
     number for nested level~3}
  }
  % DTLplotroundXvar
  \gctr{DTL\-plot\-round\-X\-var}
  {
    \initval{2}
    \providedby{\sty{dataplot}}
    \desc{the value indicates the number of digits to round the $x$
    value}
  }
  % DTLplotroundYvar
  \gctr{DTL\-plot\-round\-Y\-var}
  {
    \initval{2}
    \providedby{\sty{dataplot}}
    \desc{the value indicates the number of digits to round the $y$
    value}
  }
  % DTLpieroundvar
  \gctr{DTL\-pie\-round\-var}
  {
    \initval{1}
    \providedby{\sty{datapie}}
    \desc{the value indicates the number of digits to round the pie
    chart variable for display purposes}
  }
  % DTLbarroundvar
  \gctr{DTL\-bar\-round\-var}
  {
    \initval{1}
    \providedby{\sty{databar}}
    \desc{the value indicates the number of digits to round the bar
    chart variable for display purposes}
  }
  % PACKAGES
  \gpkg{datatool}% datatool.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gpkg{datatool\dhyphen base}% datatool-base.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gpkg{databar}% databar.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gpkg{databib}% databib.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gpkg{datapie}% datapie.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gpkg{dataplot}% dataplot.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gpkg{datagidx}% datagidx.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gpkg{person}% person.sty
  {%
    \common
    \syntax{\meta{options}}
  }
  \gfile{datatool\dhyphen l3fp.def}{}% datatool-l3fp.def
  \gfile{datatool\dhyphen lua.def}{}% datatool-lua.def
  \gfile{datatool\dhyphen fp.def}{}% datatool-fp.def
  \gpkg{datatool\dhyphen fp}{}% datatool-fp.sty
  \gfile{datatool\dhyphen pgfmath.def}{}% datatool-pgfmath.def
  \gpkg{datatool\dhyphen pgfmath}{}% datatool-pgfmath.sty
  % PACKAGE ONLY OPTIONS
  % OPTION: separator
  \gstyopt{separator}
  {
     \inpackage{datatool}
     \syntax{\meta{char}}
     \initval{,}
     \desc{the separator character in \idx{CSV} files}
  }
  % OPTION: delimiter
  \gstyopt{delimiter}
  {
     \inpackage{datatool}
     \syntax{\meta{char}}
     \initval{"}
     \desc{the delimiter character in \idx{CSV} files}
  }
  % OPTION: math
  \gstyopt{math}
  {
     \inpackage{datatool-base}
     \providedby{\sty{datatool-base} v2.10+}
     \syntax{\meta{processor}}
     \initvalvaries
     \desc{Determines which processor should be used for
     mathematical functions. The default is \optvalref{math}{l3fp} unless
     \gls{directlua} is available, in which case the default is 
     \optvalref{math}{lua}}
  }
  % OPTION: math = l3fp
  \goptval{math}{l3fp}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{use \LaTeX3 commands for floating point arithmetic}
  }
  % OPTION: math = lua
  \goptval{math}{lua}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \desc{use \gls{directlua} for floating point arithmetic}
  }
  % OPTION: math = fp
  \goptval{math}{fp}
  {
     \providedby{\sty{datatool-base} v2.10+}
     \desc{use \sty{fp} commands for floating point arithmetic}
  }
  % OPTION: math = pgfmath
  \goptval{math}{pgfmath}
  {
     \providedby{\sty{datatool-base} v2.10+}
     \desc{use \sty{pgfmath} commands for floating point arithmetic}
  }
  % OPTION: lang-warn
  \gstyopt{lang\dhyphen warn}
  {
     \inpackage{datatool-base}
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{boolean}}
     \initval{true}
     \defval{true}
     \desc{if false, suppresses localisation warnings (and also
switches off \sty{tracklang} warnings). If true, enables
localisation warnings without affecting \sty{tracklang}['s] warning
setting}
  }
  % OPTION: nolocale
  \gstyopt{no\-locale}
  {
     \inpackage{datatool-base}
     \providedby{\sty{datatool-base} v3.0+}
     \desc{prevent localisation support from being loaded, even if
      the required localisation files are installed}
  }
  % OPTION: locales
  \gstyopt{locales}
  {
     \inpackage{datatool-base}
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{locale list}}
     \desc{adds each locale to the list of tracked languages (using
     \gls{TrackLanguageTag}) and will load the corresponding
     localisation files if they are installed}
  }
  % OPTION: lang
  \gstyopt{lang}
  {
     \inpackage{datatool-base}
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\margm{locale list}}
     \desc{synonym of \opt{locales}}
     \field{alias}{opt.locales}
  }
  % OPTION: color (datapie.sty)
  \gstyopt{datapie.color}
  {
     \name{\styoptfmt{color}}
     \inpackage{datapie}
     \providedby{\sty{datapie}}
     \desc{initialises the default colour list to: red, green, blue,
      yellow, magenta, cyan, orange, white}
  }
  % OPTION: gray (datapie.sty)
  \gstyopt{datapie.gray}
  {
     \name{\styoptfmt{gray}}
     \inpackage{datapie}
     \providedby{\sty{datapie}}
     \desc{initialises the default colour list to shades of grey}
  }
  % OPTION: rotateinner (datapie.sty)
  \gstyopt{datapie.rotateinner}
  {
     \name{\styoptfmt{rotate\-inner}}
     \inpackage{datapie}
     \providedby{\sty{datapie}}
     \desc{rotate inner labels}
  }
  % OPTION: norotateinner (datapie.sty)
  \gstyopt{datapie.norotateinner}
  {
     \name{\styoptfmt{no\-rotate\-inner}}
     \inpackage{datapie}
     \providedby{\sty{datapie}}
     \desc{don't rotate inner labels}
  }
  % OPTION: rotateouter (datapie.sty)
  \gstyopt{datapie.rotateouter}
  {
     \name{\styoptfmt{rotate\-outer}}
     \inpackage{datapie}
     \providedby{\sty{datapie}}
     \desc{rotate outer labels}
  }
  % OPTION: norotateouter (datapie.sty)
  \gstyopt{datapie.norotateouter}
  {
     \name{\styoptfmt{no\-rotate\-outer}}
     \inpackage{datapie}
     \providedby{\sty{datapie}}
     \desc{don't rotate outer labels}
  }
  % OPTION: color (databar.sty)
  \gstyopt{databar.color}
  {
     \name{\styoptfmt{color}}
     \inpackage{databar}
     \providedby{\sty{databar}}
     \desc{initialises the default colour list to: red, green, blue,
      yellow, magenta, cyan, orange, white}
  }
  % OPTION: gray (databar.sty)
  \gstyopt{databar.gray}
  {
     \name{\styoptfmt{gray}}
     \inpackage{databar}
     \providedby{\sty{databar}}
     \desc{initialises the default colour list to shades of grey}
  }
  % OPTION: verticalbars (databar.sty)
  \gstyopt{databar.vertical\-bars}
  {
     \name{\styoptfmt{verticalbars}}
     \inpackage{databar}
     \providedby{\sty{databar}}
     \syntax{\meta{boolean}}
     \initval{true}
     \defval{true}
     \desc{if true, the bars will be vertical, otherwise they will
be horizontal}
  }
  % OPTION: vertical (databar.sty)
  \gstyopt{databar.vertical}
  {
     \name{\styoptfmt{vertical}}
     \inpackage{databar}
     \providedby{\sty{databar}}
     \desc{equivalent to \optval{databar.verticalbars}{true}}
  }
  % OPTION: horizontal (databar.sty)
  \gstyopt{databar.horizontal}
  {
     \name{\styoptfmt{horizontal}}
     \inpackage{databar}
     \providedby{\sty{databar}}
     \desc{equivalent to \optval{databar.verticalbars}{false}}
  }
  % OPTION: base-only (person.sty)
  \gstyopt{personsty.base-only}
  {
     \name{\styoptfmt{base\dhyphen only}}
     \inpackage{person}
     \providedby{\sty{person}}
     \desc{only load \sty{datatool-base}, not \sty{datatool}}
  }
  % OPTION: datatool (person.sty)
  \gstyopt{personsty.datatool}
  {
     \name{\styoptfmt{datatool}}
     \inpackage{person}
     \providedby{\sty{person}}
     \desc{load \sty{datatool}}
  }
  % OPTION: shortcuts (person.sty)
  \gstyopt{personsty.shortcuts}
  {
     \name{\styoptfmt{shortcuts}}
     \inpackage{person}
     \providedby{\sty{person} v3.0+}
     \desc{define shortcut commands}
  }
  % OPTION: style (databib.sty)
  \gstyopt{databib.style}
  {
     \name{\styoptfmt{style}}
     \inpackage{databib}
     \providedby{\sty{databib}}
     \syntax{\meta{name}}
     \desc{sets the bibliography style to \meta{name}, which may be
one of: \optfmt{plain}, \optfmt{abbrv} or \optfmt{alpha}}
  }
  % OPTION: auto (databib.sty)
  \gstyopt{databib.auto}
  {
     \name{\styoptfmt{auto}}
     \inpackage{databib}
     \providedby{\sty{databib} v3.0+}
     \initval{false}
     \defval{true}
     \syntax{\meta{value}}
     \desc{if true, \app{bibtex} will be run via the shell escape}
  }
  % OPTION: final (datagidx.sty)
  \gstyopt{datagidx.final}
  {
     \name{\styoptfmt{final}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \desc{switches off draft mode (default)}
  }
  % OPTION: draft (datagidx.sty)
  \gstyopt{datagidx.draft}
  {
     \name{\styoptfmt{draft}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \desc{switches on draft mode}
  }
  % OPTION: nowarn (datagidx.sty)
  \gstyopt{datagidx.nowarn}
  {
     \name{\styoptfmt{no\-warn}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{boolean}}
     \initval{false}
     \defval{true}
     \desc{if true, switch off \sty{datagidx} warnings}
  }
  % OPTION: optimize (datagidx.sty)
  \gstyopt{datagidx.optimize}
  {
     \name{\styoptfmt{optimize}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{value}}
     \initval{off}
     \defval{high}
     \desc{sets the optimization mode}
  }
  % OPTION: optimize = off
  \goptval{datagidx.optimize}{off}
  {
    \desc{no optimization}
  }
  % OPTION: optimize = low
  \goptval{datagidx.optimize}{low}
  {
    \desc{some optimization}
  }
  % OPTION: optimize = high
  \goptval{datagidx.optimize}{high}
  {
    \desc{highest level of optimization}
  }
  % OPTION: columns (datagidx.sty)
  \gstyopt{datagidx.columns}
  {
     \name{\styoptfmt{columns}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{n}}
     \desc{sets the number of columns}
  }
  % OPTION: child (datagidx.sty)
  \gstyopt{datagidx.child}
  {
     \name{\styoptfmt{child}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{value}}
     \initval{named}
     \desc{sets child style, where the value may be \optfmt{named}
or \optfmt{noname}}
  }
  % OPTION: namecase (datagidx.sty)
  \gstyopt{datagidx.namecase}
  {
     \name{\styoptfmt{name\-case}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{value}}
     \desc{sets name case style, where the value may be
\optfmt{nochange}, \optfmt{uc}, \optfmt{lc}, \optfmt{firstuc}
or \optfmt{capitalise}}
  }
  % OPTION: postname (datagidx.sty)
  \gstyopt{datagidx.postname}
  {
     \name{\styoptfmt{post\-name}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\margm{value}}
     \desc{sets the code to insert after the name}
  }
  % OPTION: postdesc (datagidx.sty)
  \gstyopt{datagidx.postdesc}
  {
     \name{\styoptfmt{post\-desc}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{value}}
     \desc{sets the post-description style, where the
value may be one of: \optfmt{none} or \optfmt{dot}}
  }
  % OPTION: prelocation (datagidx.sty)
  \gstyopt{datagidx.prelocation}
  {
     \name{\styoptfmt{pre\-location}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{value}}
     \desc{sets the style of the pre-location content, where the value may be
\optfmt{none}, \optfmt{enspace}, \optfmt{space}, \optfmt{dotfill}
or \optfmt{hfill}}
  }
  % OPTION: location (datagidx.sty)
  \gstyopt{datagidx.location}
  {
     \name{\styoptfmt{location}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{value}}
     \desc{sets the location list style, where the
value may be one of: \optfmt{hide}, \optfmt{list} or \optfmt{first}}
  }
  % OPTION: see (datagidx.sty)
  \gstyopt{datagidx.see}
  {
     \name{\styoptfmt{see}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\meta{value}}
     \desc{sets the \qt{see} style, where the
value may be one of: \optfmt{comma}, \optfmt{brackets},
\optfmt{dot}, \optfmt{space}, \optfmt{nosep}, \optfmt{semicolon},
or \optfmt{location}}
  }
  % OPTION: symboldesc (datagidx.sty)
  \gstyopt{datagidx.symboldesc}
  {
     \name{\styoptfmt{symbol\-desc}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \syntax{\margm{value}}
     \desc{sets the symbol-description style, where the
value may be one of: \optfmt{symbol}, \optfmt{desc},
\optfmt{(symbol) desc}, \optfmt{desc (symbol)}, \optfmt{symbol desc}, 
or \optfmt{desc symbol}}
  }
  % OPTION: compositor (datagidx.sty)
  \gstyopt{datagidx.compositor}
  {
     \name{\styoptfmt{compositor}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \initval{.}
     \syntax{\margm{character}}
     \desc{sets the location compositor}
  }
  % OPTION: counter (datagidx.sty)
  \gstyopt{datagidx.counter}
  {
     \name{\styoptfmt{counter}}
     \inpackage{datagidx}
     \providedby{\sty{datagidx}}
     \initval{page}
     \syntax{\margm{counter name}}
     \desc{sets the location counter}
  }
  % GENERAL OPTIONS
  % \DTLsetup
  \gcmd{DTL\-set\-up}
  {
     \common
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\marg{\keyvallist}}
     \desc{set available options for all loaded packages in the
       \sty{datatool} bundle}
     \field{seealso}{DTLsetLocaleOptions}
  }
  % OPTION: default-name
  \gcsopt{default\dhyphen name}
  {
     \providedby{\sty{datatool} v3.0+}
     \parent{DTLsetup}
     \syntax{\meta{db-name}}
     \initval{untitled}
     \desc{the default database name for commands where the name is
     optional. Note that the value is expanded as the option is set}
  }
  % OPTION: global
  \gcsboolopt{global}
  {
    \providedby{\sty{datatool} v3.0+}
    \parent{DTLsetup}
    \initval{true}%
    \desc{if true, make assignments global for applicable commands}
  }
  % OPTION: store-datum
  \gcsboolopt{store\dhyphen datum}
  {
     \parent{DTLsetup}
     \initval{false}
     \providedby{\sty{datatool} v3.0+}
     \desc{indicates whether or not to store entries in the database
     as a \idx{datumitem}}
  }
  % OPTION: new-value-expand
  \gcsboolopt{new\dhyphen value\dhyphen expand}
  {
     \parent{DTLsetup}
     \initval{false}
     \providedby{\sty{datatool} v3.0+}
     \desc{indicates whether or not to expand new values before
adding them to a database}
  }
  % OPTION: new-value-trim
  \gcsboolopt{new\dhyphen value\dhyphen trim}
  {
     \parent{DTLsetup}
     \initval{true}
     \providedby{\sty{datatool} v3.0+}
     \desc{indicates whether or not to trim leading and trailing
     spaces from new values before adding them to a database}
  }
  % OPTION verbose
  \gcsboolopt{verbose}
  {
    \providedby{\sty{datatool-base}}
    \parent{DTLsetup}
    \initval{false}%
    \desc{if true, writes extra messages to the transcript}
  }
  % OPTION utf8
  \gstyboolopt{utf8}
  {
    \parent{DTLsetup}
    \providedby{\sty{datatool-base} v2.24+}
    \deprecated
  }
  % OPTION initial-purify
  \gcsopt{initial\dhyphen purify}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \parent{DTLsetup}
    \syntax{\meta{value}}
    \initval{early}%
    \desc{indicates whether or not to \idx{purify} the \meta{text}
     argument of \gls{DTLGetInitialLetter} before parsing}
  }
  % OPTION auto-reformat-types
  \gcsopt{auto\dhyphen reformat\dhyphen types}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \parent{DTLsetup}
    \syntax{\meta{list}}
    \initval{integer, decimal, si, currency, datetime, date, time}%
    \desc{identifies the type of data that should be reformatted if
     the corresponding \numericopt{auto-reformat} numeric option or
     \datetimeopt{auto-reformat} datetime option is used. This will
     automatically switch on the applicable option}
  }
  % OPTION display
  \gcsopt{display}
  {
    \providedby{\sty{datatool} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set options for \gls{DTLdisplaydb*}}
  }
  % OPTION display = { omit-columns = { list } }
  \gdisplayopt{omit\dhyphen columns}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\margm{col idx list}}
     \desc{indicates which columns should be omitted. The value
should be a comma-separated list of column indexes}
  }
  % OPTION display = { omit = { code } }
  \gdisplayopt{omit}
  {
     \deprecated
     \providedby{\sty{datatool} v2.0+}
     \syntax{\margm{col idx list}}
     \desc{deprecated synonym for \displayopt{omit-keys}}
     \field{alias}{opt.display.omit-keys}
  }
  % OPTION display = { omit-keys = { list } }
  \gdisplayopt{omit\dhyphen keys}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\margm{col key list}}
     \desc{indicates which columns should be omitted. The value
should be a comma-separated list of column keys}
  }
  % OPTION display = { only-columns = { list } }
  \gdisplayopt{only\dhyphen columns}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\margm{col idx list}}
     \desc{indicates which columns should only be shown (overrides
     \displayopt{omit-columns} and \displayopt{omit-keys}). The value
should be a comma-separated list of column indexes}
  }
  % OPTION display = { only-keys = { list } }
  \gdisplayopt{only\dhyphen keys}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\margm{col key list}}
     \desc{indicates which columns should only be shown (overrides
     \displayopt{omit-columns} and \displayopt{omit-keys}). The value
should be a comma-separated list of column keys}
  }
  % OPTION display = { per-row = { number } }
  \gdisplayopt{per\dhyphen row}
  {
     \providedby{\sty{datatool} v3.0+}
     \initval{1}
     \syntax{\meta{number}}
     \desc{the number of database rows per \env{tabular} (or \env{longtable}) row}
  }
  % OPTION display = { row-condition-inline = { defn } }
  \gdisplayopt{row\dhyphen condition\dhyphen inline}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{defn}}
     \desc{defines an inline function that has three arguments 
     \code{\margm{content-tl-var}\margm{row idx}\margm{true}} 
     which should expand to \meta{true} if \meta{row idx} should 
     be included and expand to nothing otherwise. The 
     \meta{content-tl-var} argument is the token list used to construct
     the \env{tabular} or \env{longtable} body, which the function
     may append content to, but bear in mind that the content will be
before \gls{tabularnewline}}
  }
  % OPTION display = { row-condition-function = { cs } }
  \gdisplayopt{row\dhyphen condition\dhyphen function}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{cs}}
     \desc{as \displayopt{row-condition-inline} but provides a command to
     use as the filtering function. The supplied command \meta{cs}
     must have three arguments as per the inline function for
     \displayopt{row-condition-inline}}
  }
  % OPTION display = { post-row-inline = { defn } }
  \gdisplayopt{post\dhyphen row\dhyphen inline}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{defn}}
     \desc{defines an inline function that has two arguments 
     \code{\margm{content-tl-var}\margm{row idx}} 
     which is implemented at the end of each row to be included in
     the tabular content. The 
     \meta{content-tl-var} argument is the token list used to construct
     the \env{tabular} or \env{longtable} body, which the function
     may append content to. The \meta{row idx} argument is the
     database row index. The current tabular row count (excluding
     header and extra content) can be obtained with \gls{dtlrownum}}
  }
  % OPTION display = { post-row-function = { cs } }
  \gdisplayopt{post\dhyphen row\dhyphen function}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{cs}}
     \desc{as \displayopt{post-row-inline} but provides a command to
     use as the hook. The supplied command \meta{cs}
     must have two arguments as per the inline function for
     \displayopt{post-row-inline}}
  }
  % OPTION display = { row-idx-map-inline = { defn } }
  \gdisplayopt{row\dhyphen idx\dhyphen map\dhyphen inline}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{defn}}
     \desc{defines an inline function that has one argument 
     which should expand to the row index to select from the
     database for the current iteration index}
  }
  % OPTION display = { row-idx-map-function = { cs } }
  \gdisplayopt{row\dhyphen idx\dhyphen map\dhyphen function}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{cs}}
     \desc{as \displayopt{row-idx-map-inline} but provides a command to
     use. The supplied command \meta{cs}
     must have one argument as per the inline function for
     \displayopt{row-idx-map-inline}}
  }
  % OPTION display = { init = { code } }
  \gdisplayopt{init}
  {
     \providedby{\sty{datatool} v3.0+}
     \initvalempty
     \syntax{\meta{code}}
     \desc{provides code to insert after the options have been
processed and before the content token list variable construction
starts}
  }
  % OPTION display = { pre-content = { code } }
  \gdisplayopt{pre\dhyphen content}
  {
     \providedby{\sty{datatool} v3.0+}
     \initvalempty
     \syntax{\meta{code}}
     \desc{provides code to insert immediate before the token list
     containing the \env{tabular} or \env{longtable} environment}
  }
  % OPTION display = { pre-head = { code } }
  \gdisplayopt{pre\dhyphen head}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{code}}
     \initvalempty
     \desc{provides code to insert immediate before the header. This
      option simply redefines \gls{dtldisplaystarttab} to \meta{code}}
  }
  % OPTION display = { post-head = { code } }
  \gdisplayopt{post\dhyphen head}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{code}}
     \initvalempty
     \desc{provides code to insert immediate before the header. This
      option simply redefines \gls{ldatatoolpostheadtl} to \meta{code}}
  }
  % OPTION display = { after-head = { code } }
  \gdisplayopt{after\dhyphen head}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{code}}
     \initvalempty
     \desc{redefines \gls{dtldisplayafterhead} to \meta{code}}
  }
  % OPTION display = { string-align = { col-spec } }
  \gdisplayopt{string\dhyphen align}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{col-spec}}
     \initval{l}
     \desc{column specifier for the string data type.
     This option simply redefines \gls{dtlstringalign} to \meta{col-spec}}
  }
  % OPTION display = { integer-align = { col-spec } }
  \gdisplayopt{integer\dhyphen align}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{col-spec}}
     \initval{r}
     \desc{column specifier for the integer data type.
     This option simply redefines \gls{dtlintalign} to \meta{col-spec}}
  }
  % OPTION display = { int-align = { col-spec } }
  \gdisplayopt{int\dhyphen align}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{col-spec}}
     \desc{synonym of \displayopt{integer-align}}
     \field{alias}{opt.display.integer-align}
  }
  % OPTION display = { decimal-align = { col-spec } }
  \gdisplayopt{decimal\dhyphen align}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{col-spec}}
     \initval{r}
     \desc{column specifier for the decimal (real) data type.
     This option simply redefines \gls{dtlrealalign} to \meta{col-spec}}
  }
  % OPTION display = { real-align = { col-spec } }
  \gdisplayopt{real\dhyphen align}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{col-spec}}
     \desc{synonym of \displayopt{decimal-align}}
     \field{alias}{opt.display.decimal-align}
  }
  % OPTION display = { currency-align = { col-spec } }
  \gdisplayopt{currency\dhyphen align}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{col-spec}}
     \initval{r}
     \desc{column specifier for the currency data type.
     This option simply redefines \gls{dtlcurrencyalign} to \meta{col-spec}}
  }
  % OPTION display = { inter-col = { align-spec } }
  \gdisplayopt{inter\dhyphen col}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{align-spec}}
     \initvalempty
     \desc{alignment specifier for between columns.
     This option simply redefines \gls{dtlbetweencols} to \meta{align-spec}}
  }
  % OPTION display = { pre-col = { align-spec } }
  \gdisplayopt{pre\dhyphen col}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{align-spec}}
     \initvalempty
     \desc{alignment specifier at the start of the columns.
     This option simply redefines \gls{dtlbeforecols} to \meta{align-spec}}
  }
  % OPTION display = { post-col = { align-spec } }
  \gdisplayopt{post\dhyphen col}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{align-spec}}
     \initvalempty
     \desc{alignment specifier at the end of the columns.
     This option simply redefines \gls{dtlaftercols} to \meta{align-spec}}
  }
  % OPTION display = { align-specs = { specs } }
  \gdisplayopt{align\dhyphen specs}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{specs}}
     \initvalempty
     \desc{manually set the column alignment specifiers (rather than
determining them from the column metadata). If set to a non-empty
value, this option will override \displayopt{string-align},
\displayopt{integer-align}, \displayopt{decimal-align},
\displayopt{currency-align}, \displayopt{inter-col},
\displayopt{pre-col}, \displayopt{post-col} and \gls{dtladdalign}}
  }
  % OPTION display = { header-row = { code } }
  \gdisplayopt{header\dhyphen row}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\margm{code}}
     \initvalempty
     \desc{manually set the table header (rather than determining
the headers from the column metadata). If the value is empty, the
default header (obtained from the column metadata) is used}
  }
  % OPTION display = { no-header = { boolean } }
  \gdisplayopt{no\dhyphen header}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{boolean}}
     \defval{true}
     \initval{false}
     \desc{if set to true, the header will be omitted. Note that
this option not only omits the header
row but also the \displayopt{pre-head}, \displayopt{post-head} and
\displayopt{after-head}}
  }
  % OPTION display = { caption = { code } }
  \gdisplayopt{caption}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\meta{text}}
     \desc{provides the caption text for \gls{DTLdisplaylongdb}}
  }
  % OPTION display = { short-caption = { code } }
  \gdisplayopt{short\dhyphen caption}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{text}}
     \desc{provides the short caption (list of tables) text for \gls{DTLdisplaylongdb}}
  }
  % OPTION display = { shortcaption = { code } }
  \gdisplayopt{short\-caption}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\meta{text}}
     \desc{synonym for \displayopt{short-caption}}
     \field{alias}{opt.display.short-caption}
  }
  % OPTION display = { cont-caption = { code } }
  \gdisplayopt{cont\dhyphen caption}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{text}}
     \desc{provides the continuation caption text for \gls{DTLdisplaylongdb}}
  }
  % OPTION display = { contcaption = { code } }
  \gdisplayopt{contcaption}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\meta{text}}
     \desc{synonym for \displayopt{cont-caption}}
     \field{alias}{opt.display.cont-caption}
  }
  % OPTION display = { label = { text } }
  \gdisplayopt{label}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\meta{label}}
     \desc{provides label if a caption should be used with \gls{DTLdisplaylongdb}}
  }
  % OPTION display = { foot = { code } }
  \gdisplayopt{foot}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\meta{code}}
     \desc{provides code to insert in the footer}
  }
  % OPTION display = { last-foot = { code } }
  \gdisplayopt{last\dhyphen foot}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{code}}
     \desc{provides code to insert in the last footer}
  }
  % OPTION display = { lastfoot = { code } }
  \gdisplayopt{lastfoot}
  {
     \providedby{\sty{datatool} v2.0+}
     \syntax{\meta{code}}
     \desc{synonym for \displayopt{last-foot}}
     \field{alias}{opt.display.last-foot}
  }
  % OPTION display = { longtable-env = { env-name } }
  \gdisplayopt{long\-table\dhyphen env}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{env-name}}
     \initval{longtable}
     \defval{longtable}
     \desc{redefines \gls{dtldisplaylongdbenv} but additionally checks that 
      the given environment is defined}
  }
  % OPTION display = { tabular-env = { env-name } }
  \gdisplayopt{tab\-u\-lar\dhyphen env}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{env-name}}
     \initval{tabular}
     \defval{tabular}
     \desc{redefines \gls{dtldisplaydbenv} but additionally checks that 
      the given environment is defined. If \meta{env-name} is
      \env{tabular} or \env{array}, \gls{dtldisplayvalign} will be
      redefined to \code{c} unless it is currently defined to \code{t} or
      \code{b}, otherwise \gls{dtldisplayvalign} will be set to empty}
  }
  % OPTION io
  \gcsopt{io}
  {
    \providedby{\sty{datatool} v3.0+}
    \parent{DTLsetup}
    \syntax{\marg{\keyvallist}}
    \desc{set I/O options}
  }
  % io = { delimiter = { ... } }
  \gioopt{delimiter}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{char}}
     \initval{"}
     \desc{sets the default delimiter for \idx{CSV} files to \meta{char}}
  }
  % io = { separator = { ... } }
  \gioopt{separator}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{char}}
     \initval{,}
     \desc{sets the default separator for \idx{CSV} files to \meta{char}}
  }
  % io = { name = { ... } }
  \gioopt{name}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \desc{sets the database name. Note that the value is expanded
      as the option is set}
  }
  % io = { format = { ... } }
  \gioopt{format}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{csv}
     \desc{sets the default file format for \gls{DTLwrite} and
      \gls{DTLread}}
  }
  % io = { format = { csv } }
  \goptval{io.format}{csv}
  {
     \desc{\idx{CSV} file format with the separator given by
      \ioopt{separator} and delimiter given by \ioopt{delimiter}}
  }
  % io = { format = { tsv } }
  \goptval{io.format}{tsv}
  {
     \desc{\idx{TSV} file format with the \idx{tabchar} separator 
      and the delimiter given by \ioopt{delimiter}}
  }
  % io = { format = { dtltex-2 } }
  \goptval{io.format}{dtltex-2}
  {
     \desc{\LaTeX\ file format with document level user commands and
hard-coded database name}
  }
  % io = { format = { dtltex-3 } }
  \goptval{io.format}{dtltex-3}
  {
     \desc{\LaTeX\ file format with v3.0 document level user commands}
  }
  % io = { format = { dtltex } }
  \goptval{io.format}{dtltex}
  {
     \desc{the latest DTLTEX format}
  }
  % io = { format = { dbtex-2 } }
  \goptval{io.format}{dbtex-2}
  {
     \desc{\LaTeX\ file format with internal commands (DBTEX v2.0)}
  }
  % io = { format = { dbtex-3 } }
  \goptval{io.format}{dbtex-3}
  {
     \desc{\LaTeX\ file format with internal commands (DBTEX v3.0)}
  }
  % io = { format = { dbtex } }
  \goptval{io.format}{dbtex}
  {
     \desc{the latest DBTEX format}
  }
  \gioopt{trim}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{boolean}}
     \desc{equivalent to \code{\gls{DTLsetup}\marg{\optval{new-value-trim}{\meta{boolean}}}}}
  }
  % io = { expand = { ... } }
  \gioopt{expand}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \defval{protected}
     \initvalvaries
     \desc{determines element expansion. The initial value is
       \optfmt{none} for \gls{DTLwrite}, and the current
       \opt{new-value-expand} setting for \gls{DTLread}}
  }
  % io = { expand = { none } }
  \goptval{io.expand}{none}
  {
     \desc{no expansion}
  }
  % io = { expand = { protected } }
  \goptval{io.expand}{protected}
  {
     \desc{protected expansion}
  }
  % io = { expand = { full } }
  \goptval{io.expand}{full}
  {
     \desc{full expansion}
  }
  % io = { add-delimiter = { ... } }
  \gioopt{add\dhyphen delimiter}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{detect}
     \desc{determines whether delimiters should be added with \gls{DTLwrite}}
  }
  % io = { add-delimiter = { always } }
  \goptval{io.add-delimiter}{always}
  {
     \desc{always add the delimiter in \idx{CSV} and \idx{TSV} files}
  }
  % io = { add-delimiter = { detect } }
  \goptval{io.add-delimiter}{detect}
  {
     \desc{only add the delimiter in \idx{CSV} and \idx{TSV} files
      if the separator is found in the value}
  }
  % io = { add-delimiter = { never } }
  \goptval{io.add-delimiter}{never}
  {
     \desc{never add the delimiter in \idx{CSV} and \idx{TSV} files}
  }
  % io = { csv-escape-chars = { ... } }
  \gioopt{csv\dhyphen escape\dhyphen chars}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{double-delim}
     \desc{determines whether or not \gls{DTLwrite} should escape
      the delimiter or backslash}
  }
  % io = { csv-escape-chars = { none } }
  \goptval{io.csv-escape-chars}{none}
  {
     \desc{don't escape special characters in \idx{CSV} and \idx{TSV} files}
  }
  % io = { csv-escape-chars = { delim } }
  \goptval{io.csv-escape-chars}{delim}
  {
     \desc{escape the delimiter found within elements in \idx{CSV} and \idx{TSV} files}
  }
  % io = { csv-escape-chars = { delim+bksl } }
  \goptval{io.csv-escape-chars}{delim+bksl}
  {
     \desc{escape the delimiter and backslash characters 
        found within elements in \idx{CSV} and \idx{TSV} files}
  }
  % io = { csv-escape-chars = { double-delim } }
  \goptval{io.csv-escape-chars}{double-delim}
  {
     \desc{double the delimiter found within elements in \idx{CSV} and \idx{TSV} files}
  }
  % io = { csv-content = { ... } }
  \gioopt{csv\dhyphen content}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{literal}
     \desc{determines how \gls{DTLread} should interpret
     the content of each value in \idx{CSV} and \idx{TSV} files}
  }
  % io = { csv-content = { literal } }
  \goptval{io.csv-content}{literal}
  {
     \desc{the content in each value should be interpreted
      literally. This means that \LaTeX\ special characters will be mapped
      to an appropriate command}
  }
  % io = { csv-content = { tex } }
  \goptval{io.csv-content}{tex}
  {
     \desc{the content in each value may contain \LaTeX\ markup so
     special characters should have their normal category codes}
  }
  % io = { csv-content = { no-parse } }
  \goptval{io.csv-content}{no\dhyphen parse}
  {
     \providedby{\sty{datatool} v3.2+}
     \desc{the content should be either text that may contain \LaTeX\ markup 
      or \idxpl{plainnumber}. If \ioopt{data-types} has not been
      set, all data will be assumed to be non-numeric (i.e.\ string
      data type)}
  }
  % io = { csv-blank = { ... } }
  \gioopt{csv\dhyphen blank}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{ignore}
     \desc{determines what \gls{DTLread} should do when it
     encounters a blank line in \idx{CSV} and \idx{TSV} files}
  }
  % io = { csv-blank = { ignore } }
  \goptval{io.csv-blank}{ignore}
  {
     \desc{ignores any blank lines}
  }
  % io = { csv-blank = { empty-row } }
  \goptval{io.csv-blank}{empty\dhyphen row}
  {
     \desc{creates an empty row in the database on encountering a blank line}
  }
  % io = { csv-blank = { end } }
  \goptval{io.csv-blank}{end}
  {
     \desc{ends parsing}
  }
  % io = { overwrite = { ... } }
  \gioopt{overwrite}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{error}
     \desc{determines whether or not \gls{DTLwrite} should be
     allowed to overwrite a file that already exists}
  }
  % io = { overwrite = { error } }
  \goptval{io.overwrite}{error}
  {
     \desc{trigger an error and don't allow the file to be overwritten}
  }
  % io = { overwrite = { warn } }
  \goptval{io.overwrite}{warn}
  {
     \desc{trigger a warning and don't allow the file to be overwritten}
  }
  % io = { overwrite = { allow } }
  \goptval{io.overwrite}{allow}
  {
     \desc{allow the file to be overwritten}
  }
  % io = { keys = { list } }
  \gioopt{keys}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{list}}
     \desc{identifies the column keys to be used when \gls{DTLread}
     parses \idx{CSV} or \idx{TSV} files}
  }
  % io = { headers = { list } }
  \gioopt{headers}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{list}}
     \desc{identifies the column headers to be used when \gls{DTLread}
     parses \idx{CSV} or \idx{TSV} files}
  }
  % io = { data-types = { list } }
  \gioopt{data\dhyphen types}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{list}}
     \desc{identifies the column data types to be used when \gls{DTLread}
     parses \idx{CSV} or \idx{TSV} files. Note that these settings
may be overridden if the column contains content that isn't covered
by the specified type (except in the case of
\iooptval{csv-content}{no-parse})}
  }
  % io = { convert\dhyphen numbers = { boolean } }
  \gioopt{convert\dhyphen numbers}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{boolean}}
     \initval{false}
     \desc{indicates whether or not columns identified as having
numerical data should be converted to the current localisation
format when \gls{DTLread} parses \idx{CSV} or \idx{TSV} files}
  }
  % io = { only-reformat-columns = { column index list } }
  \gioopt{only\dhyphen reformat\dhyphen columns}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{list}}
     \initvalempty
     \desc{indicates that each column identified by its index in the
comma-separated list should behave as though the 
numeric \numericopt{auto-reformat} and datetime
\datetimeopt{auto-reformat} settings are on. The other columns will
behave as though those settings are off}
  }
  % io = { auto-keys = { boolean } }
  \gioopt{auto\dhyphen keys}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{boolean}}
     \initval{false}
     \desc{indicates whether or not the column keys should be
     automatically be set to \code{\gls{dtldefaultkey} \meta{n}} when \gls{DTLread}
     parses \idx{CSV} or \idx{TSV} files}
  }
  % io = { autokeys = { boolean } }
  \gioopt{autokeys}
  {
     \syntax{\meta{boolean}}
     \field{alias}{opt.io.auto-keys}
  }
  % io = { csv-skip-lines = { ... } }
  \gioopt{csv\dhyphen skip\dhyphen lines}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{0}
     \desc{indicates how many lines should be skipped when reading a
      \idx{CSV} or \idx{TSV} file}
  }
  % io = { omitlines = { n } }
  \gioopt{omitlines}
  {
     \providedby{\sty{datatool} v2.10+}
     \syntax{\meta{n}}
     \initval{0}
     \desc{as \ioopt{csv-skip-lines} but doesn't allow the keyword
      \code{false} and doesn't trigger an error for negative values}
  }
  % io = { no-header = { boolean } }
  \gioopt{no\dhyphen header}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{boolean}}
     \initval{false}
     \desc{indicates whether or not the first line to be parsed 
     in a \idx{CSV} or \idx{TSV} file by \gls{DTLread}
     should be treated as a header row, where a true value indicates
     there's no header line. Also indicates whether or not
     \gls{DTLwrite} should write the header information}
  }
  % io = { noheader= { boolean } }
  \gioopt{noheader}
  {
     \syntax{\meta{boolean}}
     \field{alias}{opt.io.no-header}
  }
  % io = { load-action = { ... } }
  \gioopt{load-action}
  {
     \providedby{\sty{datatool} v3.0+}
     \syntax{\meta{value}}
     \initval{old-style}
     \desc{determines whether or not \gls{DTLread} should create a
      new database or append to an existing database (if the format
      supports this action)}
  }
  % io = { load-action = { create } }
  \goptval{io.load-action}{create}
  {
     \desc{create a new database}
  }
  % io = { load-action = { append } }
  \goptval{io.load-action}{append}
  {
     \desc{append to an existing database}
  }
  % io = { load-action = { overwrite } }
  \goptval{io.load-action}{overwrite}
  {
     \desc{overwrite the database if it already exists}
  }
  % io = { load-action = { detect } }
  \goptval{io.load-action}{detect}
  {
     \desc{create or append depending on whether or not the database
     already exists}
  }
  % io = { load-action = { old-style } }
  \goptval{io.load-action}{old\dhyphen style}
  {
     \desc{use the \gls{ifDTLnewdbonload} conditional to determine
      whether to create a new database or append to an existing one}
  }
  % OPTION: lists
  \gcsboolopt{lists}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set \idx{CSV} list options}
  }
  % lists = { skip-empty = bool }
  \glistsopt{skip\dhyphen empty}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{boolean}}
     \initval{true}
     \desc{if true, empty elements will be skipped when parsing a
      \idx{CSV} list}
  }
  % lists = { trim = bool }
  \glistsopt{trim}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{boolean}}
     \initval{true}
     \desc{if true, leading and trailing space will be trimmed when parsing a
      \idx{CSV} list}
  }
  % lists = { sort-datum = bool }
  \glistsopt{sort\dhyphen datum}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{boolean}}
     \initval{false}
     \desc{indicates whether or not to parse the list elements in
     \gls{DTLsortwordlist} (see \sectionref{sec:csvlists})}
  }
  % lists = { sort-reverse = bool }
  \glistsopt{sort\dhyphen reverse}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{boolean}}
     \initval{false}
     \desc{indicates whether or not to reverse the sort criteria
     (see \sectionref{sec:csvlists})}
  }
  % lists = { and = value }
  \glistsopt{and}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{value}}
     \initval{word}
     \desc{determines the expansion of \gls{DTLlistand}. If the
\meta{value} is \optfmt{word}, use \gls{DTLandname} or if the \meta{value}
is \optfmt{symbol} use \gls{cs.amp}}
  }
  % OPTION: compare
  \gcsboolopt{compare}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set compare handler options}
  }
  % compare = { skip-cs = bool }
  \gcompareopt{skip\dhyphen cs}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{boolean}}
     \initval{false}
     \desc{indicates whether or not to skip control sequences in
     \gls{dtlcompare} and \gls{dtlicompare} if the option
     \compareopt{expand-cs} is false (see \sectionref{sec:compare})}
  }
  % compare = { expand-cs = bool }
  \gcompareopt{expand\dhyphen cs}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \parent{opt.lists}
     \syntax{\meta{boolean}}
     \initval{false}
     \desc{indicates whether or not to \idxc{expansion}{expand} control sequences in
     \gls{dtlcompare} and \gls{dtlicompare}
     (see \sectionref{sec:compare})}
  }
  % OPTION numeric
  \gcsboolopt{numeric}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set numeric options}
  }
  % OPTION numeric = { region-currency = boolean }
  \gnumericopt{region\dhyphen currency}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\meta{boolean}}
    \initval{true}
    \defval{true}
    \desc{determines whether or not the region hook should change
the default currency}
  }
  % OPTION numeric = { auto-reformat = boolean }
  \gnumericopt{auto\dhyphen reformat}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\meta{boolean}}
    \initval{false}
    \defval{true}
    \desc{determines whether or not commands like \gls{DTLparse}
should reformat the string part for integers, decimals and currency data (does not cover
temporal data types, use \opt{datetime} settings for that). Note
that this option has no effect with \iooptval{csv-content}{no-parse}
as the values aren't parsed}
  }
  % OPTION numeric = { currency-symbol-style }
  \gnumericopt{currency\dhyphen symbol\dhyphen style}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\meta{value}}
    \initval{symbol}
    \desc{redefines \gls{DTLcurrCodeOrSymOrChar} to expand to its
first or second or third argument, according to the value}
  }
  % OPTION numeric = { set-currency = currency-code }
  \gnumericopt{set\dhyphen currency}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\meta{currency-code}}
    \desc{sets the default currency to \meta{currency-code}, which
must already be defined. This option also implements
\numericoptval{region-currency}{false}}
  }
  % OPTION numeric = { region-currency-prefix = value }
  \gnumericopt{region\dhyphen currency\dhyphen prefix}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\meta{value}}
    \initval{normal}
    \desc{redefines \gls{datatoolcurrencysymbolprefixfmt}}
  }
  % OPTION numeric = { set-number-chars = {group-char}{decimal-char} }
  \gnumericopt{set\dhyphen number\dhyphen chars}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\margm{group-char}\margm{decimal-char}}
    \desc{sets
\code{DTLsetnumberchars}\margm{group-char}\margm{decimal-char} and implements
\numericoptval{region-number-chars}{false}}
  }
  % OPTION numeric = { region-number-chars = boolean }
  \gnumericopt{region\dhyphen number\dhyphen chars}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \syntax{\meta{boolean}}
    \initval{true}
    \defval{true}
    \desc{determines whether or not the region hook should set the 
\idx{numbergroupchar} and \idx{decimalchar}}
  }
  % OPTION datetime
  \gcsboolopt{datetime}
  {
    \providedby{\sty{datatool-base} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set temporal options}
  }
  % datetime = { parse = value }
  \gdatetimeopt{parse}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{value}}
     \initval{false}
     \desc{determines whether or not commands such as \gls{DTLparse}
     should test for temporal data types}
  }
  % OPTION: datetime = { parse = false }
  \goptval{datetime.parse}{false}
  {
     \desc{don't check for dates and times when parsing}
  }
  % OPTION: datetime = { parse = true }
  \goptval{datetime.parse}{true}
  {
     \desc{check for dates and times when parsing}
  }
  % OPTION: datetime = { parse = parse-only }
  \goptval{datetime.parse}{parse\dhyphen only}
  {
     \desc{check for temporal values when parsing, but don't try reformatting the original string}
  }
  % OPTION: datetime = { parse = auto-reformat }
  \goptval{datetime.parse}{auto\dhyphen reformat}
  {
     \desc{check for temporal values when parsing and reformat the
       original string. This option is equivalent to
       \code{\datetimeoptval{parse}{true},
       \datetimeopt{auto-reformat}{true}}
      }
  }
  % OPTION: datetime = { parse = iso-only }
  \goptval{datetime.parse}{iso\dhyphen only}
  {
     \desc{only parse ISO dates and times}
  }
  % OPTION: datetime = { parse = region-only }
  \goptval{datetime.parse}{region\dhyphen only}
  {
     \desc{only parse regional dates and times (requires
localisation support)}
  }
  % OPTION: datetime = { parse = iso+region }
  \goptval{datetime.parse}{iso+region}
  {
     \desc{first check for ISO format then check regional date and
time format (if localisation support provided)}
  }
  % datetime = { auto-reformat = value }
  \gdatetimeopt{auto\dhyphen reformat}
  {
     \providedby{\sty{datatool-base} v3.0+}
     \syntax{\meta{value}}
     \initval{false}
     \desc{if temporal parsing is on, determines whether or not the
original value should be reformatted. Note
that this option has no effect with \iooptval{csv-content}{no-parse}
as the values aren't parsed}
  }
  % OPTION: datetime = { auto-reformat = false }
  \goptval{datetime.auto-reformat}{false}
  {
     \desc{if temporal parsing is on, don't reformat the original string}
  }
  % OPTION: datetime = { auto-reformat = true }
  \goptval{datetime.auto-reformat}{true}
  {
     \desc{if temporal parsing is on, reformat the original string}
  }
  % OPTION: datetime = { auto-reformat = region }
  \goptval{datetime.auto-reformat}{region}
  {
     \desc{if temporal parsing is on, reformat the original string
      according to the regional settings}
  }
  % OPTION: datetime = { auto-reformat = iso }
  \goptval{datetime.auto-reformat}{iso}
  {
     \desc{if temporal parsing is on, reformat the original string
      in ISO format}
  }
  % OPTION: datetime = { auto-reformat = datetime2 }
  \goptval{datetime.auto-reformat}{datetime2}
  {
     \desc{if temporal parsing is on, reformat the original string
      using \sty{datetime2} commands. The appropriate style should
then be set using \sty{datetime2}['s] interface}
  }
  % OPTION plot
  \gcsopt{plot}
  {
    \providedby{\sty{dataplot} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set options for \gls{DTLplot}}
  }
  % PLOT OPTIONS
  % plot = { x = { ... } }
  \gplotopt{x}
  {
    \syntax{\margm{key-list}}
    \desc{list of column keys to use for $x$ co-ordinates}
  } 
  % plot = { y = { ... } }
  \gplotopt{y}
  {
    \syntax{\margm{key-list}}
    \desc{list of column keys to use for $y$ co-ordinates}
  } 
  % plot = { extra-assign = { ... } }
  \gplotopt{extra\dhyphen assign}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\marg{\idx{assign-list}}}
    \desc{additional assignments to make for iteration, which can be
    referenced in the conditional or filter function}
  } 
  % plot = { markcolors = { ... } }
  \gplotopt{mark\-colors}
  {
    \syntax{\margm{colour-list}}
    \field{alias}{opt.plot.mark-colors}
  }
  % plot = { mark-colors = { ... } }
  \gplotopt{mark\dhyphen colors}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{colour-list}}
    \desc{comma-separated list of colours to use for the
     corresponding plot marks. Use \gls{relax} or \code{\marg{}} to
      omit the colour specification for the given index. Internally
      redefines \gls{DTLplotmarkcolors}}
  }
  % plot = { line-colors = { ... } }
  \gplotopt{line\dhyphen colors}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\margm{colour-list}}
    \desc{comma-separated list of colours to use for the
     corresponding plot lines. Use \gls{relax} or \code{\marg{}} to
     omit the colour specification for the given index. Internally
     redefines \gls{DTLplotlinecolors}}
  }
  % plot = { linecolors = { ... } }
  \gplotopt{line\-colors}
  {
    \syntax{\margm{colour-list}}
    \field{alias}{opt.plot.line-colors}
  }
  % plot = { colors = { ... } }
  \gplotopt{colors}
  {
    \syntax{\margm{colour-list}}
    \desc{shortcut equivalent to
     \code{\plotoptvalm{mark-colors}{\meta{colour-list}},
     \plotoptvalm{line-colors}{\meta{colour-list}}}
    }
  }
  % plot = { marks = { ... } }
  \gplotopt{marks}
  {
    \syntax{\margm{mark-list}}
    \desc{list of plot marks. Use \gls{relax} or \code{\marg{}} to
      omit the plot marks for the given index. Internally
      redefines \gls{DTLplotmarks}}
  }
  % plot = { lines = { ... } }
  \gplotopt{lines}
  {
    \syntax{\margm{line style list}}
    \desc{list of line styles. Use \gls{relax} or \code{\marg{}} to
      omit the line drawing for the given index. Internally
      redefines \gls{DTLplotlines}}
  }
  % plot = { group-styles = { ... } }
  \gplotopt{group\dhyphen styles}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{none}
    \defval{all}
    \syntax{\margm{settings}}
    \desc{multiple choice setting that sets whether to use the same mark
    and line styles for each database.
    The value may be a comma-separated list of allowed settings}
  }
  % plot = { group-styles = { mark-style } }
  \goptval{plot.group-styles}{mark\dhyphen style}
  {
    \desc{the plot marks listed in \plotopt{marks} correspond to
    each database}
  }
  % plot = { group-styles = { mark-color } }
  \goptval{plot.group-styles}{mark\dhyphen color}
  {
    \desc{the plot mark colours listed in \plotopt{mark-colors} correspond to
    each database}
  }
  % plot = { group-styles = { line-style } }
  \goptval{plot.group-styles}{line\dhyphen style}
  {
    \desc{the line styles listed in \plotopt{lines} correspond to
    each database}
  }
  % plot = { group-styles = { line-color } }
  \goptval{plot.group-styles}{line\dhyphen color}
  {
    \desc{the line colours listed in \plotopt{line-colors} correspond to
    each database}
  }
  % plot = { group-styles = { all } }
  \goptval{plot.group-styles}{all}
  {
    \desc{equivalent to
     \code
     {%
       \plotoptvalm{group-styles}
       {%
        \plotgroupstyleval{mark-style},
        \plotgroupstyleval{mark-color},
        \plotgroupstyleval{line-style},
        \plotgroupstyleval{line-color}
       }%
     }
   }
  }
  % plot = { group-styles = { none } }
  \goptval{plot.group-styles}{none}
  {
    \desc{all plot marks, line styles and colours are cycled through
     for each ($x$, $y$) pair}
  }
  % plot = { style-resets = { ... } }
  \gplotopt{style\dhyphen resets}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{none}
    \defval{all}
    \syntax{\margm{settings}}
    \desc{multiple choice setting that sets whether to reset mark
    and line styles for each database or to cycle round until the
end of the corresponding list, except for styles governed by
\plotopt{group-styles}}
  }
  % plot = { style-resets = { mark-style } }
  \goptval{plot.style-resets}{mark\dhyphen style}
  {
    \desc{the plot marks listed in \plotopt{marks} will be reset at
    the start of each database, unless
    \plotgroupstyleval{mark-style} has been set}
  }
  % plot = { style-resets = { mark-color } }
  \goptval{plot.style-resets}{mark\dhyphen color}
  {
    \desc{the plot mark colours listed in \plotopt{mark-colors} will
     be reset at the start of each database, unless
     \plotgroupstyleval{mark-color} has been set}
  }
  % plot = { style-resets = { line-style } }
  \goptval{plot.style-resets}{line\dhyphen style}
  {
    \desc{the line styles listed in \plotopt{lines} will be reset at
the start of each database, unless \plotgroupstyleval{line-style}
has been set}
  }
  % plot = { style-resets = { line-color } }
  \goptval{plot.style-resets}{line\dhyphen color}
  {
    \desc{the line colours listed in \plotopt{line-colors} will be
reset at the start of each database, unless
\plotgroupstyleval{line-color} has been set}
  }
  % plot = { style-resets = { all } }
  \goptval{plot.style-resets}{all}
  {
    \desc{equivalent to
     \code
     {%
       \plotoptvalm{style-resets}
       {%
        \plotstyleresetval{mark-style},
        \plotstyleresetval{mark-color},
        \plotstyleresetval{line-style},
        \plotstyleresetval{line-color}
       }%
     }
   }
  }
  % plot = { style-resets = { none } }
  \goptval{plot.style-resets}{none}
  {
    \desc{all plot marks, line styles and colours are cycled through
     their corresponding list, unless the corresponding
\plotopt{group-styles} option is set}
  }
  % plot = { width = { ... } }
  \gplotopt{width}
  {
    \syntax{\meta{dimension}}
    \desc{sets the plot width. Internally sets \gls{DTLplotwidth}}
  }
  % plot = { height = { ... } }
  \gplotopt{height}
  {
    \syntax{\meta{dimension}}
    \desc{sets the plot width. Internally sets \gls{DTLplotwidth}}
  }
  % plot = { style = { ... } }
  \gplotopt{style}
  {
    \initval{markers}
    \syntax{\meta{value}}
    \desc{sets whether to draw lines or markers or both. The value
    determines how to set the conditionals \gls{ifDTLshowlines}
    and \gls{ifDTLshowmarkers}}
  }
  % plot = { style = { both } }
  \goptval{plot.style}{both}
  {
    \desc{draw both lines and markers}
  }
  % plot = { style = { lines } }
  \goptval{plot.style}{lines}
  {
    \desc{only draw lines (no markers)}
  }
  % plot = { style = { markers } }
  \goptval{plot.style}{markers}
  {
    \desc{only draw markers (no lines)}
  }
  % plot = { axes = { ... } }
  \gplotopt{axes}
  {
    \initval{both}
    \syntax{\meta{value}}
    \desc{indicates whether or not to draw the $x$ and $y$ axes.
     The value determines how to set the conditionals
     \gls{ifDTLxaxis}, \gls{ifDTLxtics}, \gls{ifDTLyaxis} and
     \gls{ifDTLytics}}
  }
  % plot = { axes = { both } }
  \goptval{plot.axes}{both}
  {
    \desc{draw $x$ and $y$ axes and $x$ and $y$ ticks}
  }
  % plot = { axes = { x } }
  \goptval{plot.axes}{x}
  {
    \desc{only draw $x$ axis and $x$ ticks}
  }
  % plot = { axes = { y } }
  \goptval{plot.axes}{y}
  {
    \desc{only draw $y$ axis and $y$ ticks}
  }
  % plot = { axes = { none } }
  \goptval{plot.axes}{none}
  {
    \desc{don't draw $x$ or $y$ axes or $x$ or $y$ ticks}
  }
  % plot = { x-axis-style = { ... } }
  \gplotopt{x\dhyphen axis\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{-}
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} line style used to draw the $x$-axis.
     This option redefines \gls{DTLXAxisStyle} to \meta{value}}
  }
  % plot = { y-axis-style = { ... } }
  \gplotopt{y\dhyphen axis\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{-}
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} line style used to draw the $y$-axis.
     This option redefines \gls{DTLYAxisStyle} to \meta{value}}
  }
  % plot = { axis-style = { ... } }
  \gplotopt{axis\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{-}
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} line style used to draw the $x$ and $y$ axes.
     This option redefines \gls{DTLXAxisStyle} and \gls{DTLYAxisStyle}
     to \meta{value}}
  }
  % plot = { box = { ... } }
  \gplotopt{box}
  {
    \initval{false}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to enclose the plot in a box.
     The value sets the conditional \gls{ifDTLbox}}
  }
  % plot = { box-ticks = { ... } }
  \gplotopt{box\dhyphen ticks}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{match-axes}
    \defval{match-axes}
    \syntax{\meta{value}}
    \desc{if \plotoptval{box}{true}, this option determines whether
or not tick marks should be drawn on the box}
  }
  % plot = { box-ticks = { none } }
  \goptval{plot.box-ticks}{none}
  {
    \desc{don't draw tick marks on the box}
  }
  % plot = { box-ticks = { match-axes } }
  \goptval{plot.box-ticks}{match\dhyphen axes}
  {
    \desc{match the tick direction setting for the axes}
  }
  % plot = { box-ticks = { in } }
  \goptval{plot.box-ticks}{in}
  {
    \desc{draw tick marks facing inwards}
  }
  % plot = { box-ticks = { out } }
  \goptval{plot.box-ticks}{out}
  {
    \desc{draw tick marks facing outwards}
  }
  % plot = { round-x = { ... } }
  \gplotopt{round\dhyphen x}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{2}
    \syntax{\meta{n}}
    \desc{sets the rounding value for $x$ coordinates. Internally
     sets the \ctr{DTLplotroundXvar} counter}
  }
  % plot = { round-y = { ... } }
  \gplotopt{round\dhyphen y}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{2}
    \syntax{\meta{n}}
    \desc{sets the rounding value for $y$ coordinates. Internally
     sets the \ctr{DTLplotroundYvar} counter}
  }
  % plot = { round = { ... } }
  \gplotopt{round}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{2}
    \syntax{\meta{n}}
    \desc{equivalent to \code{\plotoptval{round-x}{\meta{n},
     \plotoptval{round-y}{n}}}}
  }
  % plot = { ticks = { ... } }
  \gplotopt{ticks}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{boolean}}
    \desc{shortcut for \code{\plotoptval{x-ticks}{\meta{boolean}},
    \plotoptval{y-ticks}{\meta{boolean}}}}
  }
  % plot = { tics = { ... } }
  \gplotopt{tics}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{boolean}}
    \field{alias}{opt.plot.ticks}
  }
  % plot = { minor-ticks = { ... } }
  \gplotopt{minor\dhyphen ticks}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{boolean}}
    \desc{shortcut for \code{\plotoptval{x-minor-ticks}{\meta{boolean}},
    \plotoptval{y-minor-ticks}{\meta{boolean}}}}
  }
  % plot = { minortics = { ... } }
  \gplotopt{minor\-tics}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{boolean}}
    \field{alias}{opt.plot.minor-ticks}
  }
  % plot = { x-ticks = { ... } }
  \gplotopt{x\dhyphen ticks}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{true}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to show the $x$ ticks. Internally
    sets the conditional \gls{ifDTLxtics}}
  }
  % plot = { xtics = { ... } }
  \gplotopt{xtics}
  {
    \syntax{\meta{boolean}}
    \field{alias}{opt.plot.x-ticks}
  }
  % plot = { y-ticks = { ... } }
  \gplotopt{y\dhyphen ticks}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{true}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to show the $y$ ticks. Internally
    sets the conditional \gls{ifDTLytics}}
  }
  % plot = { ytics = { ... } }
  \gplotopt{ytics}
  {
    \syntax{\meta{boolean}}
    \field{alias}{opt.plot.y-ticks}
  }
  % plot = { x-minor-ticks = { ... } }
  \gplotopt{x\dhyphen minor\dhyphen ticks}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{false}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to show the $x$ minor ticks. Internally
    sets the conditionals \gls{ifDTLxtics} and \gls{ifDTLxminortics}
    to true if \meta{boolean} is true, otherwise sets \gls{ifDTLxminortics}
    to false without changing \gls{ifDTLxtics}}
  }
  % plot = { xminortics = { ... } }
  \gplotopt{xminor\-tics}
  {
    \syntax{\meta{boolean}}
    \field{alias}{opt.plot.x-minor-ticks}
  }
  % plot = { y-minor-ticks = { ... } }
  \gplotopt{y\dhyphen minor\dhyphen ticks}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{false}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to show the $y$ minor ticks. Internally
    sets the conditionals \gls{ifDTLytics} and \gls{ifDTLyminortics}
    to true if \meta{boolean} is true, otherwise sets \gls{ifDTLyminortics}
    to false without changing \gls{ifDTLytics}}
  }
  % plot = { yminortics = { ... } }
  \gplotopt{yminor\-tics}
  {
    \syntax{\meta{boolean}}
    \field{alias}{opt.plot.y-minor-ticks}
  }
  % plot = { grid = { ... } }
  \gplotopt{grid}
  {
    \initval{false}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to draw a grid. If true,
     the major grid lines will be draw. The minor grid lines not
only depend on this option being true but also depend on the
corresponding minor tick mark setting being true and
\gls{DTLminorgridstyle} must have non-empty expansion text.
     The value sets the conditional \gls{ifDTLgrid}}
  }
  % plot = { major-grid-style = { ... } }
  \gplotopt{major\dhyphen grid\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{color=gray,-}
    \syntax{\margm{value}}
    \desc{sets the drawing style for the major grid lines, which
should be valid \sty{tikz} options. This option redefines
\gls{DTLmajorgridstyle} to \meta{value}}
  }
  % plot = { minor-grid-style = { ... } }
  \gplotopt{minor\dhyphen grid\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{color=lightgray,very thin}
    \syntax{\margm{value}}
    \desc{sets the drawing style for the minor grid lines, which
should be valid \sty{tikz} options. This option redefines
\gls{DTLminorgridstyle} to \meta{value}}
  }
  % plot = { x-tick-dir = { ... } }
  \gplotopt{x\dhyphen tick\dhyphen dir}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{in}
    \syntax{\meta{value}}
    \desc{indicates whether the $x$ ticks should be drawn inwards or
    outwards (if they should be drawn). The value may be either:
    \optfmt{in} or \optfmt{out}. This option internally sets
    the \gls{ifDTLxticsin} conditional}
  }
  % plot = { xticdir = { ... } }
  \gplotopt{xtic\-dir}
  {
    \initval{in}
    \syntax{\meta{value}}
    \field{alias}{opt.plot.x-tick-dir}
  }
  % plot = { y-tick-dir = { ... } }
  \gplotopt{y\dhyphen tick\dhyphen dir}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{in}
    \syntax{\meta{value}}
    \desc{indicates whether the $y$ ticks should be drawn inwards or
    outwards (if they should be drawn). The value may be either:
    \optfmt{in} or \optfmt{out}. This option internally sets
    the \gls{ifDTLyticsin} conditional}
  }
  % plot = { yticdir = { ... } }
  \gplotopt{ytic\-dir}
  {
    \initval{in}
    \syntax{\meta{value}}
    \field{alias}{opt.plot.y-tick-dir}
  }
  % plot = { tick-dir = { ... } }
  \gplotopt{tick\dhyphen dir}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{value}}
    \desc{equivalent to \code{\plotoptval{x-tick-dir}{\meta{value},
     \plotoptval{y-tick-dir}{value}}}}
  }
  % plot = { ticdir = { ... } }
  \gplotopt{tic\-dir}
  {
    \initval{in}
    \syntax{\meta{value}}
    \field{alias}{opt.plot.tick-dir}
  }
  % plot = { bounds = { ... } }
  \gplotopt{bounds}
  {
    \initvalempty
    \syntax{\meta{value}}
    \desc{the value should either be empty to indicate that the
    plot bounds should be computed from the data or in the form 
    \code{\meta{min-x}, \meta{min-y}, \meta{max-x}, \meta{max-y}}
    to specify the minimum and maximum $x$ and $y$ co-ordinates for
    the plot. Any co-ordinates outside of these bounds will be
    omitted}
  }
  % plot = { min-x = { ... } }
  \gplotopt{min\dhyphen x}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{value}}
    \desc{the value should either be empty to indicate that the
     minimum $x$ value should be computed from the data or the value
     should be the minimum $x$ co-ordinate for the plot bounds}
  }
  % plot = { minx = { ... } }
  \gplotopt{minx}
  {
    \initvalempty
    \syntax{\meta{value}}
    \field{alias}{opt.plot.min-x}
  }
  % plot = { min-y = { ... } }
  \gplotopt{min\dhyphen y}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{the value should either be empty to indicate that the
     minimum $y$ value should be computed from the data or the value
     should be the minimum $y$ co-ordinate for the plot bounds}
  }
  % plot = { miny = { ... } }
  \gplotopt{miny}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.plot.min-y}
  }
  % plot = { max-x = { ... } }
  \gplotopt{max\dhyphen x}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{the value should either be empty to indicate that the
     maximum $x$ value should be computed from the data or the value
     should be the maximum $x$ co-ordinate for the plot bounds}
  }
  % plot = { maxx = { ... } }
  \gplotopt{maxx}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.plot.max-x}
  }
  % plot = { max-y = { ... } }
  \gplotopt{max\dhyphen y}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{the value should either be empty to indicate that the
     maximum $y$ value should be computed from the data or the value
     should be the maximum $y$ co-ordinate for the plot bounds}
  }
  % plot = { maxy = { ... } }
  \gplotopt{maxy}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.plot.max-y}
  }
  % plot = { x-tick-points = { ... } }
  \gplotopt{x\dhyphen tick\dhyphen points}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\margm{list}}
    \desc{sets the list of $x$ tick co-ordinate values (additionally
     setting the conditionals \gls{ifDTLxtics} and \gls{ifDTLxaxis}
     to true). If the list is empty, the $x$ tick co-ordinates will
     be calculated according to the plot bounds and tick gap setting}
  }
  % plot = { xticpoints = { ... } }
  \gplotopt{x\-tic\-points}
  {
    \syntax{\margm{list}}
    \field{alias}{opt.plot.x-tick-points}
  }
  % plot = { y-tick-points = { ... } }
  \gplotopt{y\dhyphen tick\dhyphen points}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\margm{list}}
    \desc{sets the list of $y$ tick co-ordinate values (additionally
     setting the conditionals \gls{ifDTLytics} and \gls{ifDTLyaxis}
     to true). If the list is empty, the $y$ tick co-ordinates will
     be calculated according to the plot bounds and tick gap setting}
  }
  % plot = { yticpoints = { ... } }
  \gplotopt{y\-tic\-points}
  {
    \syntax{\margm{list}}
    \field{alias}{opt.plot.y-tick-points}
  }
  % plot = { x-tick-gap = { ... } }
  \gplotopt{x\dhyphen tick\dhyphen gap}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{if not empty, this will set the gap between $x$ tick points
     if they have to be computed. If the value is not empty, this 
     option will automatically set the conditionals
     \gls{ifDTLxtics} and \gls{ifDTLxaxis} to true. If the value is
     empty, the gap will be obtained by converting the length
     \gls{DTLmintickgap} to data co-ordinates (unless
     \plotopt{x-tick-points} is set).  This option will
     be ignored if \plotopt{x-tick-points} is set}
  }
  % plot = { xticgap = { ... } }
  \gplotopt{x\-tic\-gap}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.plot.x-tick-gap}
  }
  % plot = { y-tick-gap = { ... } }
  \gplotopt{y\dhyphen tick\dhyphen gap}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{if not empty, this will set the gap between $y$ tick points
     if they have to be computed. If the value is not empty, this 
     option will automatically set the conditionals
     \gls{ifDTLytics} and \gls{ifDTLyaxis} to true. If the value is
     empty, the gap will be obtained by converting the length
     \gls{DTLmintickgap} to data co-ordinates (unless
     \plotopt{y-tick-points} is set). This option will
     be ignored if \plotopt{y-tick-points} is set}
  }
  % plot = { yticgap = { ... } }
  \gplotopt{y\-tic\-gap}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.plot.y-tick-gap}
  }
  % plot = { tick-gap = { ... } }
  \gplotopt{tick\dhyphen gap}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{equivalent to
     \code{\plotoptval{x-tick-gap}{\meta{value}}\dcomma
     \plotoptval{y-tick-gap}{\meta{value}}}}
  }
  % plot = { ticgap = { ... } }
  \gplotopt{tic\-gap}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.plot.tick-gap}
  }
  % plot = { x-tick-labels = { ... } }
  \gplotopt{x\dhyphen tick\dhyphen labels}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\margm{list}}
    \desc{if not empty, this will set the labels for the $x$ ticks.
      If the value is not empty, this 
     option will automatically set the conditionals
     \gls{ifDTLxtics} and \gls{ifDTLxaxis} to true. If empty, the
     labels will be obtained from the $x$ co-ordinate rounded according
     to the value of the \ctr{DTLplotroundXvar} counter (see \plotopt{round-x})}
  }
  % plot = { xticlabels = { ... } }
  \gplotopt{x\-tic\-labels}
  {
    \syntax{\margm{list}}
    \field{alias}{opt.plot.x-tick-labels}
  }
  % plot = { y-tick-labels = { ... } }
  \gplotopt{y\dhyphen tick\dhyphen labels}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\margm{list}}
    \desc{if not empty, this will set the labels for the $y$ ticks.
      If the value is not empty, this 
     option will automatically set the conditionals
     \gls{ifDTLytics} and \gls{ifDTLyaxis} to true. If empty, the
     labels will be obtained from the $y$ co-ordinate rounded according
     to the value of the \ctr{DTLplotroundYvar} counter (see \plotopt{round-y})}
  }
  % plot = { yticlabels = { ... } }
  \gplotopt{y\-tic\-labels}
  {
    \syntax{\margm{list}}
    \field{alias}{opt.plot.y-tick-labels}
  }
  % plot = { xlabel = { ... } }
  \gplotopt{x\-label}
  {
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the mid $x$-axis label}
  }
  % plot = { x-label = { ... } }
  \gplotopt{x\dhyphen label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.plot.xlabel}
  }
  % plot = { ylabel = { ... } }
  \gplotopt{y\-label}
  {
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the mid $y$-axis label}
  }
  % plot = { y-label = { ... } }
  \gplotopt{y\dhyphen label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.plot.ylabel}
  }
  % plot = { min-x-label = { ... } }
  \gplotopt{min\dhyphen x\dhyphen label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the lower $x$-axis label}
  }
  % plot = { min-x-label-style = { ... } }
  \gplotopt{min\dhyphen x\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} style of the lower $x$-axis label}
  }
  % plot = { max-x-label = { ... } }
  \gplotopt{max\dhyphen x\dhyphen label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the upper $x$-axis label}
  }
  % plot = { max-x-label-style = { ... } }
  \gplotopt{max\dhyphen x\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} style of the upper $x$-axis label}
  }
  % plot = { min-y-label = { ... } }
  \gplotopt{min\dhyphen y\dhyphen label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the lower $y$-axis label}
  }
  % plot = { min-y-label-style = { ... } }
  \gplotopt{min\dhyphen y\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} style of the lower $y$-axis label}
  }
  % plot = { max-y-label = { ... } }
  \gplotopt{max\dhyphen y\dhyphen label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the upper $y$-axis label}
  }
  % plot = { max-y-label-style = { ... } }
  \gplotopt{max\dhyphen y\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} style of the upper $y$-axis label}
  }
  % plot = { tick-label-offset = { ... } }
  \gplotopt{tick\dhyphen label\dhyphen offset}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{dimension}}
    \desc{sets the offset for the tick labels. This option sets the
dimension \gls{DTLticklabeloffset}}
  }
  % plot = { x-tick-label-style = { ... } }
  \gplotopt{x\dhyphen tick\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} style for the $x$ tick labels}
  }
  % plot = { x-tic-label-style = { ... } }
  \gplotopt{x\dhyphen tic\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \field{alias}{opt.plot.x-tick-label-style}
  }
  % plot = { y-tick-label-style = { ... } }
  \gplotopt{y\dhyphen tick\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{anchor=east}
    \syntax{\meta{value}}
    \desc{sets the \sty{tikz} style for the $y$ tick labels}
  }
  % plot = { y-tic-label-style = { ... } }
  \gplotopt{y\dhyphen tic\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\meta{value}}
    \field{alias}{opt.plot.y-tick-label-style}
  }
  % plot = { tick-label-style = { ... } }
  \gplotopt{tick\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\margm{value}}
    \desc{shortcut for \code{\plotoptvalm{x-tick-label-style}{\meta{value}},
\plotoptvalm{y-tick-label-style}{anchor\dequals east, \meta{value}}}}
  }
  % plot = { tic-label-style = { ... } }
  \gplotopt{tic\dhyphen label\dhyphen style}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\margm{value}}
    \field{alias}{opt.plot.tick-label-style}
  }
  % plot = { side-axes = { ... } }
  \gplotopt{side\dhyphen axes}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{false}
    \syntax{\meta{boolean}}
    \desc{if true, axes will be drawn at the minimum plot bounds
    (not taking the axis extension into account). If false, the axes
    will intersect at zero if that is within the plot bounds, otherwise
    the axes will be drawn at the minimum plot bounds}
  }
  % plot = { omit-zero-label = { ... } }
  \gplotopt{omit\dhyphen zero\dhyphen label}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{auto}
    \defval{both}
    \syntax{\meta{value}}
    \desc{if there is a tick mark at zero, this option determines
whether or not a label should be added to that tick mark}
  }
  % plot = { omit-zero-label = { both } }
  \goptval{plot.omit-zero-label}{both}
  {
    \desc{omit the tick label for at zero for both axes}
  }
  % plot = { omit-zero-label = { x } }
  \goptval{plot.omit-zero-label}{x}
  {
    \desc{omit the tick label at zero for the $x$ axis}
  }
  % plot = { omit-zero-label = { y } }
  \goptval{plot.omit-zero-label}{y}
  {
    \desc{omit the tick label at zero for the $y$ axis}
  }
  % plot = { omit-zero-label = { false } }
  \goptval{plot.omit-zero-label}{false}
  {
    \desc{don't omit the tick labels at zero}
  }
  % plot = { omit-zero-label = { auto } }
  \goptval{plot.omit-zero-label}{auto}
  {
    \desc{determines whether or not to show the zero tick labels
based on whether the axes cross at zero. Note that this doesn't take the axis
extensions into account}
  }
  % plot = { extend-x-axis = { ... } }
  \gplotopt{extend\dhyphen x\dhyphen axis}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{0}
    \syntax{\marg{\meta{lower extent},\meta{upper extent}}}
    \desc{extends the $x$ axis beyond the plot bounds. If
\meta{upper extent} is omitted, it's assumed to be the same as
\meta{lower extent}}
  }
  % plot = { extend-y-axis = { ... } }
  \gplotopt{extend\dhyphen y\dhyphen axis}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{0}
    \syntax{\marg{\meta{lower extent},\meta{upper extent}}}
    \desc{extends the $y$ axis beyond the plot bounds. If
\meta{upper extent} is omitted, it's assumed to be the same as
\meta{lower extent}}
  }
  % plot = { extend-axes = { ... } }
  \gplotopt{extend\dhyphen axes}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initval{0}
    \syntax{\marg{\meta{lower extent},\meta{upper extent}}}
    \desc{equivalent to
\code{\plotoptvalm{extend-x-axis}{\meta{lower extent},\meta{upper extent}}, 
\plotoptvalm{extend-y-axis}{\meta{lower extent},\meta{upper
extent}}}}
  }
  % plot = { legend = { ... } }
  \gplotopt{legend}
  {
    \initval{none}
    \defval{northeast}
    \syntax{\meta{value}}
    \desc{sets legend location. The value may be one of:
     \optfmt{none}, \optfmt{north}, \optfmt{northeast},
     \optfmt{east}, \optfmt{southeast}, \optfmt{south},
     \optfmt{southwest}, \optfmt{west}, \optfmt{northwest} or
     \optfmt{custom}}
  }
  % plot = { legend-labels = { ... } }
  \gplotopt{legend\dhyphen labels}
  {
    \providedby{\sty{dataplot} v3.0+}
    \initvalempty
    \syntax{\margm{list}}
    \desc{sets legend labels. If omitted, the default is used}
  }
  % plot = { legendlabels = { ... } }
  \gplotopt{legend\-labels}
  {
    \initvalempty
    \syntax{\margm{list}}
    \field{alias}{opt.plot.legend-labels}
  }
  % plot = { legend-offset = { ... } }
  \gplotopt{legend\dhyphen offset}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\marg{\meta{x-dim},\meta{y-dim}}}
    \desc{sets the $x$ and $y$ offsets between the border of the
    plot and the legend. The \code{,\meta{y-dim} part may be omitted
   if both values are the same}}
  }
  % plot = { include-if = { ... } }
  \gplotopt{include\dhyphen if}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{definition}}
    \desc{an inline alternative to \plotopt{include-if-fn}, this
option defines the filter command, which should take one
argument, with the given \meta{definition}. The definition should
expand to its argument if the given row of data should be included
in the plot and do nothing otherwise.
Note that this will be overridden by the optional argument
of \gls{DTLplot}, if set}
  }
  % plot = { include-if-fn = <cs> }
  \gplotopt{include\dhyphen if\dhyphen fn}
  {
    \providedby{\sty{dataplot} v3.0+}
    \syntax{\meta{cs}}
    \desc{sets the filter command, which should take one
argument, to \meta{cs}. This may be used as an alternative to
\plotopt{include-if}.
Note that this will be overridden by the optional argument
of \gls{DTLplot}, if set}
  }
  % OPTION pie
  \gcsopt{pie}
  {
    \providedby{\sty{datapie} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set options for \gls{DTLpiechart}}
  }
  % PIE OPTIONS
  % pie = { rotateinner = { ... } }
  \gpieopt{rotate\-inner}
  {
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to rotate inner labels}
  } 
  % pie = { rotate-inner = { ... } }
  \gpieopt{rotate\dhyphen inner}
  {
    \initval{false}
    \defval{true}
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{boolean}}
    \field{alias}{opt.pie.rotateinner}
  } 
  % pie = { rotateouter = { ... } }
  \gpieopt{rotate\-outer}
  {
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{indicates whether or not to rotate outer labels}
  } 
  % pie = { rotate-outer = { ... } }
  \gpieopt{rotate\dhyphen outer}
  {
    \initval{false}
    \defval{true}
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{boolean}}
    \field{alias}{opt.pie.rotateouter}
  } 
  % pie = { innerratio = { ... } }
  \gpieopt{inner\-ratio}
  {
    \initval{0.5}
    \syntax{\meta{value}}
    \desc{the inner offset will be calculated as the given
    \meta{value} multiplied by the radius}
  } 
  % pie = { inner-ratio = { ... } }
  \gpieopt{inner\dhyphen ratio}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.pie.innerratio}
  } 
  % pie = { outerratio = { ... } }
  \gpieopt{outer\-ratio}
  {
    \initval{1.25}
    \syntax{\meta{value}}
    \desc{the outer offset will be calculated as the given
    \meta{value} multiplied by the radius}
  } 
  % pie = { outer-ratio = { ... } }
  \gpieopt{outer\dhyphen ratio}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.pie.outerratio}
  } 
  % pie = { cutawayratio = { ... } }
  \gpieopt{cutaway\-ratio}
  {
    \initval{0.2}
    \syntax{\meta{value}}
    \desc{the cutaway offset will be calculated as the given
    \meta{value} multiplied by the radius}
  } 
  % pie = { cutaway-ratio = { ... } }
  \gpieopt{cutaway\dhyphen ratio}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.pie.cutawayratio}
  } 
  % pie = { inneroffset = { ... } }
  \gpieopt{inner\-offset}
  {
    \syntax{\meta{dimension}}
    \desc{the inner offset}
  } 
  % pie = { inner-offset = { ... } }
  \gpieopt{inner\dhyphen offset}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{dimension}}
    \field{alias}{opt.pie.inneroffset}
  } 
  % pie = { outeroffset = { ... } }
  \gpieopt{outer\-offset}
  {
    \syntax{\meta{dimension}}
    \desc{the outer offset}
  } 
  % pie = { outer-offset = { ... } }
  \gpieopt{outer\dhyphen offset}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{dimension}}
    \field{alias}{opt.pie.outeroffset}
  } 
  % pie = { cutawayoffset = { ... } }
  \gpieopt{cutaway\-offset}
  {
    \syntax{\meta{dimension}}
    \desc{the cutaway offset}
  } 
  % pie = { cutaway-offset = { ... } }
  \gpieopt{cutaway\dhyphen offset}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{dimension}}
    \field{alias}{opt.pie.cutawayoffset}
  } 
  % pie = { radius = { ... } }
  \gpieopt{radius}
  {
    \initval{2cm}
    \syntax{\meta{dimension}}
    \desc{sets the radius of the pie chart and also updates the
inner, outer and cutaway offsets}
  } 
  % pie = { radius* = { ... } }
  \gpieopt{radius*}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{dimension}}
    \desc{sets the radius of the pie chart without modifying the
inner, outer and cutaway offsets}
  } 
  % pie = { round = { ... } }
  \gpieopt{round}
  {
    \initval{1}
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{n}}
    \desc{sets the rounding value used in \gls{DTLpiepercent}. Internally sets the
     \ctr{DTLpieroundvar} counter}
  } 
  % pie = { segment-colors = { ... } }
  \gpieopt{segment\dhyphen colors}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\margm{list}}
    \desc{sets the segment colour list. The default list depends on
    whether the \opt{pie.color} or \opt{pie.gray} package option was
    used}
  } 
  % pie = { segment-default-colors }
  \gpieopt{segment\dhyphen default\dhyphen colors}
  {
    \providedby{\sty{datapie} v3.0+}
    \desc{sets the segment colours to the default set: red, green,
blue, yellow, magenta, cyan, orange, white}
  } 
  % pie = { segment-default-gray }
  \gpieopt{segment\dhyphen default\dhyphen gray}
  {
    \providedby{\sty{datapie} v3.0+}
    \desc{sets the segment colours to the default grey set}
  } 
  % pie = { outline-width = { ... } }
  \gpieopt{outline\dhyphen width}
  {
    \initval{0pt}
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{dimension}}
    \desc{sets the width of the line drawn around the segments. A
value of 0pt indicates that the line should be omitted}
  } 
  % pie = { outline-color = { ... } }
  \gpieopt{outline\dhyphen color}
  {
    \initval{black}
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{colour}}
    \desc{sets the colour of the segment outlines}
  } 
  % pie = { cutaway = { ... } }
  \gpieopt{cut\-away}
  {
    \initvalempty
    \syntax{\margm{list}}
    \desc{the list of segments to cutaway (that is, offset from the
     centre of the pie chart by the cutaway offset). The list should
     be a comma-separated list of individual numbers or a number range
     (separated by a hyphen), where the number is the segment
     offset, starting from~1}
  } 
  % pie = { variable = { ... } }
  \gpieopt{variable}
  {
    \syntax{\meta{cs}}
    \desc{the control sequence placeholder that will be set to the pie chart
    segment value}
  } 
  % pie = { start = { ... } }
  \gpieopt{start}
  {
    \initval{0}
    \syntax{\meta{value}}
    \desc{the starting angle}
  } 
  % pie = { innerlabel = { ... } }
  \gpieopt{inner\-label}
  {
    \initvalcs{DTLpievariable}
    \syntax{\meta{value}}
    \desc{the inner label displayed within each segment}
  } 
  % pie = { inner-label = { ... } }
  \gpieopt{inner\dhyphen label}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.pie.innerlabel}
  } 
  % pie = { outerlabel = { ... } }
  \gpieopt{outer\-label}
  {
    \initvalempty
    \syntax{\meta{value}}
    \desc{the outer label displayed within each segment}
  } 
  % pie = { outer-label = { ... } }
  \gpieopt{outer\dhyphen label}
  {
    \providedby{\sty{datapie} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.pie.outerlabel}
  } 
  % pie = { include-if = { ... } }
  \gpieopt{include\dhyphen if}
  {
    \syntax{\meta{definition}}
    \desc{an inline alternative to \pieopt{include-if-fn}, this
option defines the filter command, which should take one
argument, with the given \meta{definition}. The definition should
expand to its argument if the given row of data should be included
in the pie chart and do nothing otherwise.
Note that this will be overridden by the optional argument
of \gls{DTLpiechart}, if set}
  }
  % pie = { include-if-fn = <cs> }
  \gpieopt{include\dhyphen if\dhyphen fn}
  {
    \syntax{\meta{cs}}
    \desc{sets the filter command, which should take one
argument, to \meta{cs}. This may be used as an alternative to
\pieopt{include-if}.
Note that this will be overridden by the optional argument
of \gls{DTLpiechart}, if set}
  }
  % OPTION bar
  \gcsopt{bar}
  {
    \providedby{\sty{databar} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set options for \gls{DTLbarchart}}
  }
  % BAR OPTIONS
  % bar = { verticalbars = { ... } }
  \gbaropt{vertical\-bars}
  {
    \initval{true}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{sets the \gls{ifDTLverticalbars} conditional to
     \meta{boolean}}
  } 
  % bar = { vertical }
  \gbaropt{vertical}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{synonym for \baroptval{verticalbars}{true}}
  } 
  % bar = { horizontal }
  \gbaropt{horizontal}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{synonym for \baroptval{verticalbars}{false}}
  } 
  % bar = {  lower-label-style = { ... } }
  \gbaropt{lower\dhyphen label\dhyphen style}
  {
    \initval{opposite}
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \desc{specifies the positioning and alignment of the lower bar label}
  }
  % bar = {  lower-label-style = { opposite } }
  \goptval{bar.lower-label-style}{opposite}
  {
    \desc{lower labels will be on the opposite side of the $x$-axis
    to the bar}
  }
  % bar = {  lower-label-style = { same } }
  \goptval{bar.lower-label-style}{same}
  {
    \desc{lower labels will be on the same side of the $x$-axis
    to the bar}
  }
  % bar = {  lower-label-style = { above } }
  \goptval{bar.lower-label-style}{above}
  {
    \desc{lower labels will be above the $x$-axis}
  }
  % bar = {  lower-label-style = { below } }
  \goptval{bar.lower-label-style}{below}
  {
    \desc{lower labels will be below the $x$-axis}
  }
  % bar = { upper-label-align = { } }
  \gbaropt{upper\dhyphen label\dhyphen align}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\oargm{-ve align}\margm{+ve align}}
    \desc{sets the alignment for upper bars}
  }
  % bar = { group-label-align = { } }
  \gbaropt{group\dhyphen label\dhyphen align}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \desc{sets the alignment for group labels}
  }
  % bar = { length = { ... } }
  \gbaropt{length}
  {
    \initval{3in}
    \syntax{\meta{dim}}
    \desc{sets the $y$-axis length \gls{DTLbarchartlength}}
  } 
  % bar = { bar-width = { ... } }
  \gbaropt{bar\dhyphen width}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{1cm}
    \syntax{\meta{dim}}
    \desc{sets the bar width \gls{DTLbarwidth}}
  } 
  % bar = { barwidth = { ... } }
  \gbaropt{bar\-width}
  {
    \initval{1cm}
    \syntax{\meta{dim}}
    \field{alias}{opt.bar.bar-width}
  } 
  % bar = { round = { ... } }
  \gbaropt{round}
  {
    \initval{1}
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{n}}
    \desc{sets the rounding value used for \gls{DTLbarvalue} 
     and (unless \baropt{y-tick-round} has been set)
     the default tick labels. Internally sets the
    \ctr{DTLbarroundvar} counter}
  } 
  % bar = { y-tick-round = { ... } }
  \gbaropt{y\dhyphen tick\dhyphen round}
  {
    \initvalempty
    \defvalempty
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{n}}
    \desc{sets the rounding value for the default $y$ tick labels. 
     If the value is missing or empty, it will match the \baropt{round} setting}
  } 
  % bar = { ytic-round = { ... } }
  \gbaropt{ytic\dhyphen round}
  {
    \initvalempty
    \defvalempty
    \providedby{\sty{databar} v3.0+}
    \field{alias}{opt.bar.y-tick-round}
  } 
  % bar = { variable = { ... } }
  \gbaropt{variable}
  {
    \syntax{\meta{cs}}
    \desc{the control sequence placeholder that will be set to the
    bar value for \gls{DTLbarchart}}
  } 
  % bar = { variables = { ... } }
  \gbaropt{variables}
  {
    \syntax{\meta{cs-list}}
    \desc{lists of control sequence placeholders that will be set to the
    bar value for \gls{DTLmultibarchart}}
  } 
  % bar = { label-offset = { ... } }
  \gbaropt{label\dhyphen offset}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{10pt}
    \syntax{\meta{dim}}
    \desc{the distance from the bar to the bar label}
  } 
  % bar = { upper-label-offset = { ... } }
  \gbaropt{upper\dhyphen label\dhyphen offset}
  {
    \providedby{\sty{databar} v3.0+}
    \initvalcs{DTLbarlabeloffset}
    \syntax{\meta{value}}
    \desc{the distance from the outer edge of the bar to the upper bar label}
  } 
  % bar = { y-tick-label-align = { ... } }
  \gbaropt{y\dhyphen tick\dhyphen label\dhyphen align}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \desc{the \gls{pgftext} alignment specifier for the $y$ tick labels}
  } 
  % bar = { y-tic-label-align = { ... } }
  \gbaropt{y\dhyphen tic\dhyphen label\dhyphen align}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.bar.y-tick-label-align}
  } 
  % bar = { ytic-label-align = { ... } }
  \gbaropt{ytic\dhyphen label\dhyphen align}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \field{alias}{opt.bar.y-tick-label-align}
  } 
  % bar = { init = { ... } }
  \gbaropt{init}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\margm{code}}
    \desc{initialisation code to perform at the start of
\gls{DTLbarchart} and \gls{DTLmultibarchart} after the settings
have been parsed}
  } 
  % bar = { pre-init = { ... } }
  \gbaropt{pre\dhyphen init}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\margm{code}}
    \desc{initialisation code to perform at the start of
\gls{DTLbarchart} and \gls{DTLmultibarchart} before the other settings
are parsed}
  } 
  % bar = { bar-label = { ... } }
  \gbaropt{bar\dhyphen label}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \desc{the lower bar label displayed on each bar}
  } 
  % bar = { barlabel = { ... } }
  \gbaropt{bar\-label}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.bar.bar-label}
  } 
  % bar = { upper-bar-label = { ... } }
  \gbaropt{upper\dhyphen bar\dhyphen label}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \desc{the upper bar label displayed on each bar}
  } 
  % bar = { upperbarlabel = { ... } }
  \gbaropt{upper\-bar\-label}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.bar.upper-bar-label}
  } 
  % bar = { multi-bar-labels = { ... } }
  \gbaropt{multi\dhyphen bar\dhyphen labels}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{list}}
    \desc{the lower bar labels displayed on each bar within a group
for \gls{DTLmultibarchart}}
  } 
  % bar = { multibarlabels = { ... } }
  \gbaropt{multi\-bar\-labels}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.bar.multi-bar-labels}
  } 
  % bar = { upper-multi-bar-labels = { ... } }
  \gbaropt{upper\dhyphen multi\dhyphen bar\dhyphen labels}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{list}}
    \desc{the upper bar labels displayed on each bar within a group
for \gls{DTLmultibarchart}}
  } 
  % bar = { uppermultibarlabels = { ... } }
  \gbaropt{upper\-multi\-bar\-labels}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.bar.upper-multi-bar-labels}
  } 
  % bar = { bar-gap = { ... } }
  \gbaropt{bar\dhyphen gap}
  {
    \initval{0}
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \desc{the gap between bars (but not between bar groups)}
  } 
  % bar = { bargap = { ... } }
  \gbaropt{bar\-gap}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{0}
    \syntax{\meta{value}}
    \field{alias}{opt.bar.bar-gap}
  } 
  % bar = { group-gap = { ... } }
  \gbaropt{group\dhyphen gap}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{1}
    \syntax{\meta{value}}
    \desc{the gap between bar groups with \gls{DTLmultibarchart}}
  } 
  % bar = { groupgap = { ... } }
  \gbaropt{group\-gap}
  {
    \initval{1}
    \syntax{\meta{value}}
    \field{alias}{opt.bar.group-gap}
  } 
  % bar = { y-axis = { ... } }
  \gbaropt{y\dhyphen axis}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{if true, the $y$-axis will be drawn}
  } 
  % bar = { yaxis = { ... } }
  \gbaropt{yaxis}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \field{alias}{opt.bar.y-axis}
  } 
  % bar = { y-ticks = { ... } }
  \gbaropt{y\dhyphen ticks}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{if true, $y$-tick marks will be drawn. If true, this
option will also set \baroptval{y-axis}{true}}
  } 
  % bar = { ytics = { ... } }
  \gbaropt{ytics}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \field{alias}{opt.bar.y-ticks}
  } 
  % bar = { y-tick-points = { ... } }
  \gbaropt{y\dhyphen tick\dhyphen points}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{list}}
    \desc{the list of $y$ tick marks (automatically sets
\baroptval{y-ticks}{true} and \baroptval{y-axis}{true})}
  } 
  % bar = { yticpoints = { ... } }
  \gbaropt{ytic\-points}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.bar.y-tick-points}
  } 
  % bar = { y-tick-gap = { ... } }
  \gbaropt{y\dhyphen tick\dhyphen gap}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{value}}
    \desc{the gap between $y$ tick marks (automatically sets
\baroptval{y-ticks}{true} and \baroptval{y-axis}{true})}
  } 
  % bar = { yticgap = { ... } }
  \gbaropt{ytic\-gap}
  {
    \syntax{\meta{value}}
    \field{alias}{opt.bar.y-tick-gap}
  } 
  % bar = { y-tick-labels = { ... } }
  \gbaropt{y\dhyphen tick\dhyphen labels}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{list}}
    \desc{the list of $y$ tick labels (automatically sets
\baroptval{y-ticks}{true} and \baroptval{y-axis}{true})}
  } 
  % bar = { yticlabels = { ... } }
  \gbaropt{ytic\-labels}
  {
    \syntax{\meta{list}}
    \field{alias}{opt.bar.y-tick-labels}
  } 
  % bar = { ylabel = { ... } }
  \gbaropt{ylabel}
  {
    \syntax{\meta{value}}
    \desc{the label for the $y$ axis}
  } 
  % bar = { ylabel-position = { ... } }
  \gbaropt{ylabel\dhyphen position}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{center}
    \syntax{\meta{value}}
    \desc{sets the $x$ position of the $y$ label}
  } 
  % bar = { ylabel-position = { center } }
  \goptval{bar.ylabel-position}{center}
  {
    \desc{sets the $x$ position of the $y$ label to the centre of
     the $x$ axis} 
  }
  % bar = { ylabel-position = { zero } }
  \goptval{bar.ylabel-position}{zero}
  {
    \desc{sets the $x$ position of the $y$ label to 0} 
  }
  % bar = { ylabel-position = { min } }
  \goptval{bar.ylabel-position}{min}
  {
    \desc{sets the $x$ position of the $y$ label to the minimum $x$
axis value} 
  }
  % bar = { ylabel-position = { max } }
  \goptval{bar.ylabel-position}{max}
  {
    \desc{sets the $x$ position of the $y$ label to the maximum $x$
axis value} 
  }
  % bar = { max = { ... } }
  \gbaropt{max}
  {
    \initvalempty
    \defvalempty
    \syntax{\meta{value}}
    \desc{the maximum value for the $y$ axis (in data units). An
     empty value indicates that the maximum should be the maximum
     value found in the data (or 0 if no non-negative values found)}
  } 
  % bar = { max-depth = { ... } }
  \gbaropt{max\dhyphen depth}
  {
    \providedby{\sty{databar} v3.0+}
    \initvalempty
    \defvalempty
    \syntax{\meta{value}}
    \desc{the maximum depth (negative extent) for the $y$ axis (in
data units as a \idx{plainnumber}). The supplied \meta{value} must 
be less than or equal to~0}
  } 
  % bar = { maxdepth = { ... } }
  \gbaropt{max\-depth}
  {
    \initvalempty
    \defvalempty
    \syntax{\meta{value}}
    \field{alias}{opt.bar.max-depth}
  }
  % bar = { axes = { ... } }
  \gbaropt{axes}
  {
    \initval{none}
    \defval{both}
    \syntax{\meta{value}}
    \desc{indicates whether or not to draw the $x$ and $y$ axes.
     The value determines how to set the conditionals
     \gls{ifDTLbarxaxis}, \gls{ifDTLbaryaxis} and
     \gls{ifDTLbarytics}}
  }
  % bar = { axes = { both } }
  \goptval{bar.axes}{both}
  {
    \desc{draw $x$ and $y$ axes and $x$ and $y$ ticks}
  }
  % bar = { axes = { x } }
  \goptval{bar.axes}{x}
  {
    \desc{only draw $x$ axis and $x$ ticks}
  }
  % bar = { axes = { y } }
  \goptval{bar.axes}{y}
  {
    \desc{only draw $y$ axis and $y$ ticks}
  }
  % bar = { axes = { none } }
  \goptval{bar.axes}{none}
  {
    \desc{don't draw $x$ or $y$ axes or $x$ or $y$ ticks}
  }
  % bar = { x-axis-style = { ... } }
  \gbaropt{x\dhyphen axis\dhyphen style}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{-}
    \syntax{\meta{value}}
    \desc{the \sty{tikz} line style for the $x$-axis}
  }
  % bar = { y-axis-style = { ... } }
  \gbaropt{y\dhyphen axis\dhyphen style}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{-}
    \syntax{\meta{value}}
    \desc{the \sty{tikz} line style for the $y$-axis}
  }
  % bar = { negative-bar-colors = { ... } }
  \gbaropt{negative\dhyphen bar\dhyphen colors}
  {
    \providedby{\sty{databar} v3.0+}
    \initvalempty
    \syntax{\margm{list}}
    \desc{sets the colour list for negative bars. If no colour
provided for the current bar index, the corresponding element of
\baropt{bar-colors} will be used instead}
  } 
  % bar = { bar-colors = { ... } }
  \gbaropt{bar\dhyphen colors}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\margm{list}}
    \desc{sets the bar colour list. The default list depends on
    whether the \opt{bar.color} or \opt{bar.gray} package option was
    used}
  } 
  % bar = { bar-default-colors }
  \gbaropt{bar\dhyphen default\dhyphen colors}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{sets the bar colours to the default set: red, green,
blue, yellow, magenta, cyan, orange, white}
  } 
  % bar = { bar-default-gray }
  \gbaropt{bar\dhyphen default\dhyphen gray}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{sets the bar colours to the default grey set}
  } 
  % bar = { color-style = { ... } }
  \gbaropt{color\dhyphen style}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{sets the colour style for the bars}
  } 
  % bar = { color-style = { single } }
  \goptval{bar.color-style}{single}
  {
    \desc{all bars will be filled with the same colour (the first in
the bar colour list)}
  }
  % bar = { color-style = { cycle } }
  \goptval{bar.color-style}{cycle}
  {
    \desc{the bar colours will cycle around the defined bar colour
list}
  }
  % bar = { color-style = { default } }
  \goptval{bar.color-style}{default}
  {
    \desc{the bar colours will be set according to the defined bar colour
list and any additional bars beyond the list length will be filled
white}
  }
  % bar = { negative-color-style = { ... } }
  \gbaropt{negative\dhyphen color\dhyphen style}
  {
    \providedby{\sty{databar} v3.0+}
    \desc{sets the colour style for the bars with negative values}
  } 
  % bar = { negative-color-style = { single } }
  \goptval{bar.negative-color-style}{single}
  {
    \desc{all bars with negative values will be filled with the same colour (the first in
the negative bar colour list or from the general colour list if the
negative bar colour list is empty)}
  }
  % bar = { negative-color-style = { cycle } }
  \goptval{bar.negative-color-style}{cycle}
  {
    \desc{the colours for bars with negative values will cycle
     around the defined negative bar colour list}
  }
  % bar = { negative-color-style = { default } }
  \goptval{bar.negative-color-style}{default}
  {
    \desc{match the \baropt{color-style} setting}
  }
  % bar = { outline-color }
  \gbaropt{outline\dhyphen color}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{black}
    \syntax{\meta{colour}}
    \desc{sets the bar outline colour}
  } 
  % bar = { outline-width = { ... } }
  \gbaropt{outline\dhyphen width}
  {
    \providedby{\sty{databar} v3.0+}
    \initval{0pt}
    \syntax{\meta{dimension}}
    \desc{sets the width of the line drawn around the bars. A
value of 0pt indicates that the line should be omitted}
  } 
  % bar = { include-if = { ... } }
  \gbaropt{include\dhyphen if}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{definition}}
    \desc{an inline alternative to \baropt{include-if-fn}, this
option defines the filter command, which should take one
argument, with the given \meta{definition}. The definition should
expand to its argument if the given row of data should be included
in the bar chart and do nothing otherwise. 
Note that this will be overridden by the optional argument
of \gls{DTLbarchart} or \gls{DTLmultibarchart}, if set}
  }
  % bar = { include-if-fn = <cs> }
  \gbaropt{include\dhyphen if\dhyphen fn}
  {
    \providedby{\sty{databar} v3.0+}
    \syntax{\meta{cs}}
    \desc{sets the filter command, which should take one
argument, to \meta{cs}. This may be used as an alternative to
\baropt{include-if}.
Note that this will be overridden by the optional argument
of \gls{DTLbarchart} or \gls{DTLmultibarchart}, if set}
  }
  % OPTION index
  \gcsopt{index}
  {
    \providedby{\sty{datagidx} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set options for \gls{newgidx} and \gls{printterms}}
  }
  % INDEX OPTIONS
  % index = { database = { ... } }
   \ggidxopt{data\-base}
   {
     \initvalempty
     \syntax{\margm{db-name}}
     \desc{the database name (\gls{printterms})}
   }
  % index = { sort = { ... } }
   \ggidxopt{sort}
   {
     \syntax{\margm{sort-code}}
     \desc{the code to sort the database at the start of
     \gls{printterms} (may be passed to \gls{newgidx} or \gls{printterms})}
   }
  % index = { columns = { ... } }
   \ggidxopt{columns}
   {
     \syntax{\meta{n}}
     \initval{2}
     \desc{the number of columns in the index (\gls{printterms})}
   }
  % index = { symbol-width = { ... } }
   \ggidxopt{symbol\dhyphen width}
   {
     \syntax{\meta{dim}}
     \initval{0pt}
     \desc{the space to allocate for each symbol (\gls{printterms}). If zero or
negative, the symbol just occupies its natural width}
   }
  % index = { symbolwidth = { ... } }
   \ggidxopt{symbol\-width}
   {
     \syntax{\meta{dim}}
     \initval{0pt}
     \field{alias}{opt.gidx.symbol-width}
   }
  % index = { location-width = { ... } }
   \ggidxopt{location\dhyphen width}
   {
     \syntax{\meta{dim}}
     \initval{0pt}
     \desc{the space to allocate for each location list (\gls{printterms}). If zero or
negative, the location list just occupies its natural width}
   }
  % index = { locationwidth = { ... } }
   \ggidxopt{location\-width}
   {
     \syntax{\meta{dim}}
     \initval{0pt}
     \field{alias}{opt.gidx.location-width}
   }
  % index = { child = { ... } }
   \ggidxopt{child}
   {
     \syntax{\margm{value}}
     \initval{named}
     \desc{sets the child style (\gls{printterms}). The value may be one of:
\optfmt{named} (show the child name) or \optfmt{noname} (only show
the label, not the child name)}
   }
  % index = { child-sort = { boolean } }
   \ggidxopt{child\dhyphen sort}
   {
     \syntax{\meta{boolean}}
     \initval{true}
     \defval{true}
     \desc{indicates whether or not the child list should follow the
ordering from the database}
   }
  % index = { childsort = { boolean } }
   \ggidxopt{child\-sort}
   {
     \syntax{\meta{boolean}}
     \initval{true}
     \defval{true}
     \field{alias}{opt.gidx.child-sort}
   }
  % index = { name-case = { ... } }
   \ggidxopt{name\dhyphen case}
   {
     \syntax{\margm{value}}
     \initval{nochange}
     \desc{specifies the case-change to apply to the name (\gls{printterms}). The value
must be one of: \optfmt{nochange} (no change), \optfmt{uc}
(convert to uppercase), \optfmt{lc} (convert to lowercase),
\optfmt{firstuc} (convert to sentence case), or \optfmt{capitalise}
(capitalise each word)}
   }
  % index = { namecase = { ... } }
   \ggidxopt{name\-case}
   {
     \syntax{\margm{value}}
     \initval{nochange}
     \field{alias}{opt.gidx.name-case}
   }
  % index = { name-font = { ... } }
   \ggidxopt{name\dhyphen font}
   {
     \syntax{\margm{code}}
     \desc{the font declaration or text block command to apply to
     the name (\gls{printterms})}
   }
  % index = { namefont = { ... } }
   \ggidxopt{name\-font}
   {
     \syntax{\margm{code}}
     \field{alias}{opt.gidx.name-font}
   }
  % index = { post-name = { ... } }
   \ggidxopt{post\dhyphen name}
   {
     \syntax{\margm{value}}
     \initval{\visiblespace}
     \desc{content to insert after the name (\gls{printterms})}
   }
  % index = { postname = { ... } }
   \ggidxopt{post\-name}
   {
     \syntax{\margm{value}}
     \field{alias}{opt.gidx.post-name}
   }
  % index = { post-desc = { ... } }
   \ggidxopt{post\dhyphen desc}
   {
     \syntax{\margm{value}}
     \initval{none}
     \desc{post-description content (\gls{printterms}).
     The value may be one of: \optfmt{none} (no content to
insert after the description) or \optfmt{dot} (insert a period\slash full
stop after the description)}
   }
  % index = { postdesc = { ... } }
   \ggidxopt{post\-desc}
   {
     \syntax{\margm{value}}
     \field{alias}{opt.gidx.post-desc}
   }
  % index = { pre-location = { ... } }
   \ggidxopt{pre\dhyphen location}
   {
     \syntax{\margm{value}}
     \initval{enspace}
     \desc{indicates what should be inserted before the location
list (\gls{printterms}). The value may be one of: \optfmt{none}, \optfmt{enspace},
\optfmt{space}, \optfmt{dotfill}, \optfmt{hfill}}
   }
  % index = { prelocation = { ... } }
   \ggidxopt{pre\-location}
   {
     \syntax{\margm{value}}
     \field{alias}{opt.gidx.pre-location}
   }
  % index = { location = { ... } }
   \ggidxopt{location}
   {
     \syntax{\margm{value}}
     \initval{list}
     \desc{sets the location style (\gls{printterms}). The value must be one of:
\optfmt{hide} (don't show the location list), \optfmt{list}
(show the location list), or \optfmt{first} (only show the first
location)}
   }
  % index = { see = { ... } }
   \ggidxopt{see}
   {
     \syntax{\margm{value}}
     \initval{location}
     \desc{sets the cross-reference style (\gls{printterms}). The value must be one of:
\optfmt{comma} (insert a comma and space, followed by the
cross-reference), 
\optfmt{dot} (insert a period\slash full stop and space, followed by the
cross-reference), 
\optfmt{semicolon} (insert a semi-colon and space, followed by the
cross-reference), 
\optfmt{brackets} (insert a space followed by the cross-reference in
parentheses),
\optfmt{space} (insert a space followed by the
cross-reference), 
\optfmt{location} (insert \gls{DTLgidxPreLocation} followed by the
cross-reference), or 
\optfmt{nosep} (insert the
cross-reference without any leading punctuation or space)
}
   }
  % index = { symbol-desc = { ... } }
   \ggidxopt{symbol\dhyphen desc}
   {
     \syntax{\margm{value}}
     \desc{specifies how the symbol and description should be
displayed (\gls{printterms}). The value must be one of:
\optfmt{symbol} (symbol only), \optfmt{desc} (description only),
\optfmt{(symbol) desc} (symbol in parentheses followed by
description), \optfmt{desc (symbol)} (description followed by symbol
in parentheses), \optfmt{symbol desc} (symbol followed by
description), or \optfmt{desc symbol} (description followed by symbol)}
   }
  % index = { symboldesc = { ... } }
   \ggidxopt{symbol\-desc}
   {
     \syntax{\margm{value}}
     \field{alias}{opt.gidx.symbol-desc}
   }
  % index = { compositor = { ... } }
   \ggidxopt{compositor}
   {
     \syntax{\margm{character}}
     \initval{.}
     \desc{sets the location compositor to \meta{character}}
   }
  % index = { counter = { ... } }
   \ggidxopt{counter}
   {
     \syntax{\margm{counter name}}
     \initval{page}
     \desc{sets the location counter}
   }
  % index = { warn = { ... } }
   \ggidxopt{warn}
   {
     \syntax{\meta{boolean}}
     \initval{true}
     \defval{true}
     \desc{if true, switch on \sty{datagidx} warnings}
   }
  % index = { heading = { ... } }
   \ggidxopt{heading}
   {
     \syntax{\margm{title}}
     \desc{sets the index\slash glossary heading (\gls{newgidx} or \gls{printterms})}
   }
  % index = { post-heading = { ... } }
   \ggidxopt{post\dhyphen heading}
   {
     \syntax{\margm{code}}
     \desc{sets content to insert after the heading (\gls{newgidx}
or \gls{printterms})}
   }
  % index = { postheading = { ... } }
   \ggidxopt{post\-heading}
   {
     \syntax{\margm{code}}
     \field{alias}{opt.gidx.post-heading}
   }
  % index = { balance = { boolean } }
   \ggidxopt{balance}
   {
     \syntax{\meta{boolean}}
     \initval{true}
     \defval{true}
     \desc{if true (and \gidxopt{columns} greater than 1), balance columns
       (\gls{newgidx} or \gls{printterms})}
   }
  % index = { style = { ... } }
   \ggidxopt{style}
   {
     \syntax{\margm{name}}
     \initval{index}
     \desc{sets the style used by \gls{printterms} (may also be
supplied in \gls{newgidx})}
   }
  % index = { show-groups = { boolean } }
   \ggidxopt{show\dhyphen groups}
   {
     \syntax{\meta{boolean}}
     \initval{true}
     \defval{true}
     \desc{if true, visually separate the letter groups
(\gls{newgidx} or \gls{printterms})}
   }
  % index = { showgroups = { boolean } }
   \ggidxopt{show\-groups}
   {
     \syntax{\meta{boolean}}
     \initval{true}
     \defval{true}
     \field{alias}{opt.gidx.show-groups}
   }
  % index = { condition = { ... } }
   \ggidxopt{condition}
   {
     \syntax{\margm{condition}}
     \desc{with \gls{printterms}, only include rows that satisfy the condition, where
     \meta{condition} must be suitable for use in \gls{ifthenelse}}
   }
  % index = { include-if = { ... } }
  \ggidxopt{include\dhyphen if}
  {
    \providedby{\sty{datagidx} v3.0+}
    \syntax{\meta{definition}}
    \desc{an inline alternative to \gidxopt{include-if-fn}, this
option defines the filter command, which should take one
argument, with the given \meta{definition}. The definition should
expand to its argument if the given row of data should be included
in \gls{printterms} and do nothing otherwise}
  }
  % index = { include-if-fn = <cs> }
  \ggidxopt{include\dhyphen if\dhyphen fn}
  {
    \providedby{\sty{datagidx} v3.0+}
    \syntax{\meta{cs}}
    \desc{sets the filter command, which should take one
argument, to \meta{cs}. This may be used as an alternative to
\gidxopt{include-if}}
  }
  % OPTION person
  \gcsopt{person}
  {
    \providedby{\sty{dataperson} v3.0+}
    \parent{DTLsetup}
    \syntax{\keyvallist}
    \desc{set options for the \sty{person} package}
  }
  % PERSON OPTIONS
  % person = { local = { boolean } }
  \gpersonopt{local}
  {
    \initval{true}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{sets whether or not to define people locally}
  } 
  % person = { global = { boolean } }
  \gpersonopt{global}
  {
    \initval{false}
    \defval{true}
    \syntax{\meta{boolean}}
    \desc{antonym of \personopt{local}}
  } 
  % person = { shortcuts }
  \gpersonopt{shortcuts}
  {
    \desc{defines shortcut commands (does nothing if this option has
already been used)}
  } 
  % APPLICATIONS
  \gapp{data\-tooltk}% datatooltk
  {
    \syntax{\meta{options}}%
    \desc{a Java application that may be used to create \sty{datatool} databases in 
    \sty{datatool}['s] internal format; such databases can be quickly imported 
    into a \LaTeX document using \gls{DTLread}. DatatoolTk may be used in 
    batch mode to convert from \idx{SQL} or \idx{CSV} or to import datasets from
    \sty{probsoln} or may be used in GUI mode to modify the data
    using its cell editor or menu items. The installer \ctansupportmirror{datatooltk/datatooltk-installer.jar}{\appfmt{datatooltk\dhyphen installer.jar}}
    is available on CTAN. The application will allow you to edit files saved 
    using \gls{DTLsaverawdb} or \gls{DTLprotectedsaverawdb} in a~graphical 
    interface or import data from a~\idx{SQL} database, a~\idx{CSV} file or a~\sty{probsoln}
    dataset}
  }
  \gapp{bib2gls}{}
  \gapp{bibtex}{}
  \gapp{biber}{}
  % FILES
  % datatool-<locale>.ldf
  \gfilemeta{datatool\dhyphen }{locale}{.ldf}{}
  \gfile{person\dhyphen english.ldf}{}% person-english.ldf
  \gfile{databib\dhyphen english.ldf}{}% databib-english.ldf
  \gfile{data\-bib.bst}{}% databib.bst
  \gext{def}{}
  \gext{ldf}{}
  \gext{csv}{}
  \gext{tsv}{}
  \gext{tex}{}
  \gext{dtltex}{}
  \gext{dbtex}{}
  \gext{bbl}{}
  \gext{bst}{}
  \gext{bib}{}
  \gext{aux}{}
  % OTHER PACKAGES
  \gmodule{datatool\dhyphen english}{}% datatool-english module
  \gmodule{datatool\dhyphen regions}{}% datatool-regions bundle
  \gpkg{etool\-box}{}% etoolbox.sty
  \gpkg{ams\-math}{}% amsmath.sty
  \gpkg{xkey\-val}{}% xkeyval.sty
  \gpkg{xfor}{}% xfor.sty
  \gpkg{if\-then}{}% ifthen.sty
  \gpkg{track\-lang}{}% tracklang.sty
  \gpkg{sub\-str}{}% substr.sty
  \gpkg{after\-page}{}% afterpage.sty
  \gpkg{fp}{}% fp.sty
  \gpkg{pgf\-math}{}% pgfmath.sty
  \gpkg{mfirst\-uc}{}% mfirstuc.sty
  \gpkg{pgf}{}% pgf.sty
  \gpkg{tikz}{}% tikz.sty
  \gpkg{prob\-soln}{}% probsoln.sty
  \gpkg{glossaries}{}% glossaries.sty
  \gpkg{glossaries\dhyphen extra}{}% glossaries-extra.sty
  \gpkg{si\-unitx}{}% siunitx.sty
  \gpkg{text\-comp}{}% textcomp.sty
  \gpkg{marvo\-sym}{}% marvosym.sty
  \gpkg{font\-awe\-some}{}% fontawesome.sty
  \gpkg{wasy\-sym}{}% wasysym.sty
  \gpkg{input\-enc}{}% inputenc.sty
  \gpkg{euro\-sym}{}% eurosym.sty
  \gpkg{multi\-col}{}% multicol.sty
  \gpkg{babel}{}% babel.sty
  \gpkg{poly\-glossia}{}% polyglossia.sty
  \gpkg{date\-time2}{}% datetime2.sty
  \gmodule{date\-time2\dhyphen english}{}% datetime2-english
  \gpkg{tab\-u\-lar\-ray}{}% tabularray.sty
  \gpkg{tabu}{}% tabu.sty
  \gpkg{l3keys}{}
  \gpkg{long\-table}{}% longtable.sty
  \gpkg{book\-tabs}{}% booktabs.sty
  \gpkg{color\-tbl}{}% colortbl.sty
  \gpkg{bib\-latex}{}% biblatex.sty
  \gpkg{url}{}% url.sty
  \gpkg{hyperref}{}% hyperref.sty
  \gpkg{relsize}{}% relsize.sty
  \gcls{beamer}{}% beamer.cls
  % COMMANDS AND ENVIRONMENTS: index only
  \genv{tab\-u\-lar}{}% tabular
  \genv{array}{}
  \genv{long\-table}{}% longtable
  \genv{tblr}{}% tblr (tabularray.sty)
  \genv{tabu}{}% tabu (tabu.sty)
  \genv{long\-tabu}{}% longtabu (tabu.sty)
  \genv{tikz\-picture}{}% tikzpicture (tikz.sty)
  \genv{pgf\-picture}{}% pgfpicture (pgf.sty)
  \genv{the\-bib\-lio\-graphy}{}% thebibliography
  \genv{multi\-cols}{} % multicols (multicol.sty)
  \gcmd{set\-counter}{}% \setcounter
  \gcmd{set\-length}{}% \setlength
  \gcmd{ref}{}% \ref
  \gcmd{page\-ref}{}% \pageref
  \gcmd{step\-counter}{}% \stepcounter
  \gcmd{ref\-step\-counter}{}% \refstepcounter
  \gcmd{hyper\-target}{}% \hypertarget
  \gcmd{hyper\-link}{}% \hyperlink
  \gcmd{url}{}% \url
  \gcmd{relax}{}% \relax
  \gcmd{par}{}% \par
  \gcmd{TeX}{}% \TeX
  \gcmd{La\-TeX}{}% \LaTeX
  \gcmd{print\-noidx\-glossary}{}% \printnoidxglossary
  \gcmd{print\-unsrt\-glossary}{}% \printunsrtglossary
  \gcmd{Track\-Language\-Tag}{}% \TrackLanguageTag
  \gcmd{Track\-Lang\-Encoding\-Name}{}% \TrackLangEncodingName
  \gcmd{Track\-Lang\-Add\-To\-Captions}{}% \TrackLangAddToCaptions
  \gcmd{Track\-Lang\-Provides\-Resource}{}% \TrackLangProvidesResource
  \gcmd{Track\-Lang\-Require\-Resource}{}% \TrackLangRequireResource
  \gcmd{Track\-Lang\-Show\-Warnings\-true}{}% 
  \gcmdmeta{captions}{dialect}{}{}% \captions<dialect>
  \gcmd{if\-then\-else}{}% \ifthenelse
  \gcmd{while\-do}{}% \whiledo
  \gcmd{and}{}% \and
  \gcmd{not}{}% \not
  \gcmd{or}{}% \or
  \gcmd{direct\-lua}{}% \directlua
  \gcmd{show}{}% \show
  \gcmd{space}{}% \space
  \gcmd{cs.space}{% "\ "
    \name{\cspuncfmt{\visiblespace}}
    \field{extra}{backslash space}
   }
  \gcmd{no\-break\-space}{}% \nobreakspace
  \gcmd{Expl\-Syntax\-On}{}% \ExplSyntaxOn
  \gcmd{Expl\-Syntax\-Off}{}% \ExplSyntaxOff
  \gcmd{fp\dsb to\dsb decimal:n}{}% \fp_to_decimal:n
  \gcmd{text\dsb map\dsb inline:nn}{}% \text_map_inline:nn
  \gcmd{text\dsb lowercase:n}{}% \text_lowercase:n
  \gcmd{text\dsb uppercase:n}{}% \text_uppercase:n
  \gcmd{text\dsb titlecase\dsb first:n}{}% \text_titlecase_first:n
  \gcmd{text\dsb purify:n}{}% \text_purify:n
  \gcmd{regex\dsb replace\dsb all:nnN}{}% \regex_replace_all:nnN
  \gcmd{regex\dsb replace\dsb case\dsb all:nN}{}% \regex_replace_case_all:nN
  \gcmd{c\dsb novalue\dsb tl}{}% \c_novalue_tl
  \gcmd{num\-expr}{}% \numexpr
  \gcmd{if\-num}{}% \ifnum
  \gcmd{pounds}{}% \pounds
  \gcmdpunc{cs.dollar}{\$}{}% \$
  \gcmdpunc{cs.openbrace}{\{}{}% \{
  \gcmdpunc{cs.closebrace}{\}}{}% \}
  \gcmdpunc{cs.amp}{\&}{}% \&
  \gcmdpunc{cs.underscore}{\_}{}% \_
  \gcmdpunc{cs.hash}{\#}{}% \#
  \gcmdpunc{cs.percent}{\%}{}% \%
  \gcmdpunc{cs.bksl}{\glsbackslash}{}% \\
  \gcmdpunc{cs.comma}{,}{}% \,
  \gcmd{tab\-u\-lar\-new\-line}{}% \tabularnewline
  \gcmd{and\-name}{}% \andname
  \gcmd{euro}{}% \euro
  \gcmd{text\-euro}{}% \texteuro
  \gcmd{EUR}{}% \EUR
  \gcmd{Euro}{}% \Euro
  \gcmd{wasyeuro}{}% \wasyeuro
  \gcmd{official\-euro}{}% \officialeuro
  \gcmd{text\-sterling}{}% \textsterling
  \gcmd{text\-dollar}{}% \textdollar
  \gcmd{text\-yen}{}% \textyen
  \gcmd{yen}{}% \yen
  \gcmd{text\-won}{}% \textwon
  \gcmd{text\-currency}{}% \textcurrency
  \gcmd{faBtc}{}% \faBtc
  \gcmd{faEur}{}% \faEur
  \gcmd{num}{}% \num
  \gcmd{edef}{}% \edef
  \gcmd{meaning}{}% \meaning
  \gcmd{no\-expand}{}% \noexpand
  \gcmd{expand\-once}{}% \expandonce
  \gcmd{un\-expanded}{}% \unexpanded
  \gcmd{protect}{}% \protect
  \gcmd{number}{}% \number
  \gcmd{if\-def\-string}{}% \ifdefstring
  \gcmd{if\-def\-empty}{}% \ifdefempty
  \gcmd{pre\-to}{}% \preto
  \gcmd{app\-to}{}% \appto
  \gcmd{eapp\-to}{}% \eappto
  \gcmd{for\-csv\-list}{}% \forcsvlist
  \gcmd{hfil}{}% \hfil
  \gcmd{hfill}{}% \hfill
  \gcmd{dotfill}{}% \dotfill
  \gcmd{en\-space}{}% \enspace
  \gcmd{see\-name}{}% \seename
  \gcmd{also\-name}{}% \alsoname
  \gcmd{multi\-column}{}% \multicolumn
  \gcmd{babel\-provide}{}% \babelprovide
  \gcmd{input\-encoding}{}% \inputencoding
  \gcmd{@for}{} % \@for
  \gcmd{two\-@\-digits}{}% \two@digits
  \gcmd{text\-sc}{}% \textsc
  \gcmd{text\-smaller}{}% \textsmaller
  \gcmd{text\-ascii\-circum}{}% \textasciicircum
  \gcmd{text\-ascii\-tilde}{}% \textasciitilde
  \gcmd{text\-back\-slash}{}% \textbackslash
  \gcmd{text\-period\-centered}{}% \textperiodcentered
  \gcmd{text\-minus}{}% \textminus
  \gcmd{in\-put}{}% \input
  \gcmd{In\-put\-If\-File\-Exists}{}% \InputIfFileExists
  \gcmd{today}{}% \today
  \gcmd{DTM\-now}{}% \DTMnow
  \gcmd{DTM\-date}{}% \DTMdate
  \gcmd{DTM\-month\-name}{}% \DTMmonthname
  \gcmd{DTM\-short\-month\-name}{}% \DTMshortmonthname
  \gcmd{end\-head}{}% \endhead
  \gcmd{end\-first\-head}{}% \endfirsthead
  \gcmd{end\-foot}{}% \endfoot
  \gcmd{end\-last\-foot}{}% \endlastfoot
  \gcmd{set\-keys}{}% \setkeys
  \gcmd{caption}{}% \caption
  \gcmd{label}{}% \label
  \gcmd{hline}{}% \hline
  \gcmd{top\-rule}{}% \toprule
  \gcmd{mid\-rule}{}% \midrule
  \gcmd{bottom\-rule}{}% \bottomrule
  \gcmd{row\-color}{}% \rowcolor (colortbl.sty)
  \gcmd{column\-color}{}% \columncolor (colortbl.sty)
  \gcmd{cell\-color}{}% \cellcolor (colortbl.sty)
  \gcmd{set\-to\-width}{}% \settowidth
  \gcmd{set\-to\-height}{}% \settoheight
  \gcmd{set\-to\-depth}{}% \settodepth
  \gcmd{color}{}% \color
  \gcmd{fcolor\-box}{}% \fcolorbox
  \gcmd{fbox\-rule}{}% \fboxrule
  \gcmd{path}{}% \path
  \gcmd{pgf\-text}{}% \pgftext
  \gcmd{pgf\-point\-xy}{}% \pgfpointxy
  \gcmd{pgf\-use\-plot\-mark}{}% \pgfuseplotmark
  \gcmd{pgf\-set\-dash}{}% \pgfsetdash
  \gcmd{pgf\-plot\-handler\-mark}{}% \pgfplothandlermark
  \gcmd{pgf\-trans\-form\-re\-set}{}% \pgftransformreset
  \gcmd{item}{}% \item
  \gcmd{bib\-item}{}% \bibitem
  \gcmd{bib\-data}{}% \bibdata
  \gcmd{bib\-style}{}% \bibstyle
  \gcmd{bib\-liography\-style}{}% \bibliographystyle
  \gcmd{cite}{}% \cite
  \gcmd{no\-cite}{}% \nocite
  \gcmd{citation}{}% \citation
  \gcmd{Make\-Upper\-case}{}% \MakeUppercase
  \gcmd{job\-name}{}% \jobname
  \gcmd{one\-column}{}% \onecolumn
  \gcmd{two\-column}{}% \twocolumn
  \gcmd{make\-first\-uc}{}% \makefirstuc (mfirstuc.sty)
  \gcmd{xmake\-first\-uc}{}% \xmakefirstuc (mfirstuc.sty)
  \gcmd{cap\-i\-talise\-words}{}% \capitalisewords (mfirstuc.sty)
  \gcmd{xcap\-i\-talise\-words}{}% \xcapitalisewords (mfirstuc.sty)
  \gcmd{alpha}{}% \alpha
  \gcmd{n}% \n
  {
    \name{\csfmt{n}}
    \field{extra}{newline}
  }
  \gcmd{f}% \f
  {
    \name{\csfmt{f}}
    \field{extra}{form feed}
  }
  \gcmd{r}% \r
  {
    \name{\csfmt{r}}
    \field{extra}{carriage return}
  }
  \gcmd{t}% \t
  {
    \name{\csfmt{t}}
    \field{extra}{tab}
  }
  % TERMS
  \gtermabbr{jdn}{JDN}{Julian Day Number}
  {
    \desc{an integer assigned to a whole solar day in the Julian day
     count starting from noon Universal Time}
  }
  \gtermabbr{jf}{JF}{Julian Time Fraction}
  {
    \desc{the time of day since noon UT as a decimal fraction of
      one day, with 0.5 representing midnight UT.}
  }
  \gtermabbr{jd}{JD}{Julian Date}
  {
    \desc{a decimal that's the sum of the \glsxtrlong{jdn}
     and the \glsxtrlong{jf}}
  }
  \gtermacr{ascii}{ASCII}{American Standard Code for Information Interchange}
  {
    \desc{a single-byte character \idx+{encoding}. Related blog article:
    \blog{binary-files-text-files-and-file-encodings/}{Binary
    Files, Text Files and File Encodings}}
  }
  \gtermacr{utf8}{UTF-8}{Unicode Transformation Format (8-bit)}
  {%
    \desc{a variable-width \idx+{encoding} that uses 8-bit code units. This
    means that some characters are represented by more that one byte.
    \XeLaTeX\ and \LuaLaTeX\ treat the multi-byte sequence as a single
    token, but the older \LaTeX\ formats have single-byte tokens, which
    can cause complications, although these have mostly been addressed with
    the newer kernels introduced over the past few years. Related blog article:
    \blog{binary-files-text-files-and-file-encodings/}{Binary Files,
    Text Files and File Encodings}}
  }
  \gtermacr{CSV}{CSV}{Comma Separated Values}
  {
    \common
    \desc{a CSV file is a text field that uses a comma to separate
    fields (see \sectionref{sec:csvfiles}). A CSV list is a string 
    (rather than specifically the content of a
    file) where values are separated by a comma, so each row in a
    CSV file is a CSV list. Some commands that allow a CSV list as
    the argument may allow the argument to be a command whose definition
    is a CSV list (see \sectionref{sec:csvlists})}
  }
  \gtermacr{TSV}{TSV}{Tab Separated Values}
  {
    \desc{as \idx{CSV} but uses a \idx{tabchar} as the separator}
  }
  \gtermacr{SQL}{SQL}{Structured Query Language}
  {
    \desc{a language used to manage data stored within a database
management system}
  }
  \gterm{plainnumber}
  {
    \name{plain number}
    \desc{a number without a \idx{currencysym} and without
    \idxpl{numbergroupchar}. If the number is a decimal, a
    \idx{decimalpoint} is used, regardless of \gls{DTLsetnumberchars}}
  }
  \gterm{formattednumber}
  {
    \name{formatted number}
    \desc{a number that uses the \idx{numbergroupchar} and (if a
     decimal) the \idx{decimalchar} according to the current setting
     of \gls{DTLsetnumberchars}, optionally prefixed with a
    \idx{currencysym}. Note that the \idx{numbergroupchar} is optional 
    but, if present, if must be at intervals of three digits}
  }
  \gterm{datumcs}
  {
     \common
     \name{datum control sequence}
     \desc{a control sequence whose replacement text is specially
     formatted to include the formatted\slash string content,
     numerical value (if applicable), currency symbol (if
     applicable), and data type (string, integer, real or currency)}
  }
  \gterm{datumitem}
  {
     \common
    \name{datum item}
    \desc{data that's formatted according to the replacement text of
    a \idx{datumcs}. See \sectionref{sec:datatypes}}
  }
  \gterm{sortedelement}
  {
    \name{sorted element}
    \desc{an element of a comma-separated list obtained with
    \gls{DTLsortwordlist} consisting of a marker, the original
    element, the sort value used for sorting, and the corresponding
    letter group}
  }
  \gterm{expansion}
  {
    \desc{single expansion (expand once) is where a command is replaced by its
     definition. Full expansion is where all the commands within the
     definition are also expanded recursively. Robust commands don't
     expand and fragile commands need to be protected from expansion
     to prevent an error from occurring. Expansion is important in
     certain situations, such as in the argument of section titles
     where the title also needs to be in the PDF bookmark, which
     requires just text and no formatting or assignments}
  }
  \gterm{purify}
  {
    \desc{fully \idxc{expansion}{expand} and remove remaining non-expandable
    commands. This is implemented by \LaTeX3's \gls+{textpurify:n}
    function. See \qt{The \LaTeX3 Interfaces} documentation for further details}
  }
  \gterm{hexcp}
  {
    \name{\hex{\meta{XX}}}
    \desc{a hexadecimal value. Used in this manual to denote a character by its
    codepoint, particularly control characters that don't have a
    visible symbol (glyph). For example, \hex{0A} denotes the line feed
    character. When entering the character into \LaTeX\ code you can use
    the double caret notation, such as
    \code{\textasciicircum\textasciicircum J}, but you may first need
    to set its category code appropriately}
  }
  \gterm{assign-list}
  {
    \common
    \name{\meta{assign-list}}
    \desc{indicates a comma-separated list of \meta{cs}=\meta{key}
     assignments, where \meta{cs} is a placeholder command (token
     list variable) and \meta{key} is a column key or property name.
     The \meta{cs} command will be assigned to the applicable value
     identified by \meta{key}}
  }
  % INDEX ONLY
  \gidx{encoding}{}
  \gidx{punctuation}{}
  \gpunc{sym.bksl}% \
  {
    \name{\code{\glsbackslash}}
    \field{extra}{literal}
  }
  \gpunc{sym.esc}% \
  {
    \name{\code{\glsbackslash}}
    \field{extra}{escape}
  }
  \gpunc{sym.dollar}{\name{\code{\$}}}% $
  \gpunc{sym.hash}{\name{\code{\#}}}% #
  \gpunc{sym.percent}{\name{\code{\%}}}% %
  \gpunc{sym.amp}{\name{\code{\&}}}% &
  \gpunc{sym.circum}{\name{\code{\textasciicircum}}}% ^
  \gpunc{sym.underscore}{\name{\code{\_}}}% _
  \gpunc{sym.openbrace}{\name{\code{\{}}}% {
  \gpunc{sym.closebrace}{\name{\code{\}}}}% }
  \gpunc{sym.tilde}% ~
  {
    \name{\code{\textasciitilde}}
    \field{extra}{literal}
  }
  \gpunc{nbsp}% ~
  {
    \name{\code{\textasciitilde}}
    \field{extra}{non-breakable space}
  }
  \gpunc{l3sp}% ~
  {
    \name{\code{\textasciitilde}}
    \field{extra}{space token}
  }
  \gpunc{@}
  {
    \name{\code{@}}
    \field{extra}{category code}
  }
  \gidx{tabchar}{
    \name{tab character \tabsym}
    \field{text}{tab character}
    \field{symbol}{\texorpdfstring{\tabsym}{\nlctliteraltabchar}}
  }
  \gidx{uppercase}{}
  \gidx{lowercase}{}
  \gpunc{sym.commasep}
  {
    \name{\code{,}}
    \field{extra}{separator}
  } 
  \gpunc{sym.dblqdelim}
  {
    \name{\code{"}}
    \field{extra}{delimiter}
  } 
  \gpunc{sym.numbergroup}{\name{\code{,}}
    \field{extra}{number group}
    \field{see}{idx.numbergroupchar}
  }
  \gpunc{sym.decimalpoint}{\name{\code{.}}
    \field{extra}{decimal point}
    \field{see}{idx.decimalpoint}
  }
  \gidx{decimalpoint}{\name{decimal point (\code{.})}%
    \field{text}{decimal point}
    \field{symbol}{\code{.}}
  }
  \gpunc{sym.unknownref}
  {
    \name{\code{??}}
    \field{extra}{unknown reference}
  }
  \gpunc{sym.unknowncite}
  {
    \name{\code{?}}
    \field{extra}{unknown citation}
  }
  \gidx{decimalchar}{\name{decimal character}}
  \gidx{numbergroupchar}{\name{number group character}}
  \gidx{currencysym}{\name{currency symbol}}
  \gidx{robust}{\field{seealso}{expansion}}
  \gidx{expandable}{\field{alias}{dual.expansion}}
  \gidx{Oxfordcomma}{\name{Oxford comma}}
  \gidx{comma}{}
  \gidx{commaOxford}{\name{Oxford}\parent{idx.comma}\field{alias}{idx.Oxfordcomma}}
  \gidx{commaSep}{\name{separator}\parent{idx.comma}\field{alias}{idx.sym.commasep}}
  \gidx{commaNumGrp}{\name{number group}\parent{idx.comma}\field{alias}{idx.numbergroupchar}}
  \gidx{misplacednoalign}
  {
    \name{\csfmt{noalign}, Misplaced error}
    \field{text}{misplaced \csfmt{noalign}}
  }
  \gidx{current-row}{\name{current row}}
}

% Used in examples:
\newcount\myrowctr
\newcounter{myrowctr}

\newcommand{\studentscoresdb}{%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{scores}}\nl
\comment{define database:}%
\gls{DTLaction}\marg{\action{new}}\nl
\comment{add columns in desired order:}%
\gls{DTLaction}\oarg{\actionoptval{key}{forename},\actionoptvalm{value}{First
Name}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{surname},\actionoptvalm{value}{Surname}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{regnum},\actionoptvalm{value}{Student
Number}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{gender}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{parent}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{score},\actionoptvalm{value}{Score (\gls{cs.percent})}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{award}}\marg{\action{add-column}}\nl
\comment{1st row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{
    forename = Jane,
    surname = Brown,\nldbsp
    regnum = 102647,
    score = 75,
    award = \marg{\gls{cs.dollar}1,830},\nldbsp
    gender = F, parent = \marg{Ms Brown}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{2nd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{
    forename = John,
    surname = \marg{Smith, Jr},\nldbsp
    regnum = 102689,
    score = 68,
    award = \marg{\gls{cs.dollar}1,560},\nldbsp
    gender = M, parent = \marg{Mr and Mrs Smith}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{3rd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{
    forename = Quinn,
    surname = Ó Coinn,\nldbsp
    regnum = 103294,
    score = 91,
    award = \marg{\gls{cs.dollar}3,280},\nldbsp
    parent = \marg{Mr and Mrs Ó Coinn}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{4th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{
    forename = Evelyn,
    surname = O'Leary,\nldbsp
    regnum = 107569,
    score = 81.5,
    award = \marg{\gls{cs.dollar}2,460},\nldbsp
    gender = n, parent = \marg{Prof O'Leary}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{5th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{
    forename = Zoë,
    surname = Adams,\nldbsp
    regnum = 105987,
    score = 52,
    award = \marg{\gls{cs.dollar}1,250},\nldbsp
    gender = f, parent = \marg{Mr and Mrs Adams}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{6th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{
    forename = Clare,
    surname = Vernon,\nldbsp
    regnum = 104356,
    score = 45,
    award = \marg{\gls{cs.dollar}500},\nldbsp
    gender = Female, parent = \marg{Mr Vernon}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{7th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{
    forename = Roger,
    surname = Brady,\nldbsp
    regnum = 106872,
    score = 58,
    award = \marg{\gls{cs.dollar}1,350},\nldbsp
    gender = m, parent = \marg{Dr Brady and Dr Mady}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{8th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    forename = Andy,
    surname = Brown,
    regnum = 103569,\nldbsp
    score = 42,
    award = \marg{\gls{cs.dollar}980},\nldbsp
    gender = male, parent = \marg{Mr Brown and Prof Sepia}\nlsp
  }\nl
 }\marg{\action{new-row}}
}

% NB these commands must expand fully
\newcommand{\exfile}[2]{%
\cbeg{filecontents}\oarg{noheader,overwrite}\marg{#1}\nl
#2\nl
\cend{filecontents}\nl
}

\newcommand{\extabfile}[2]{%
\cmd{usepackage}\marg{scontents}\comment{to write test file with
TABs preserved}%
\extabnextfile{#1}{#2}%
}

\newcommand{\extabnextfile}[2]{%
\cbeg{scontents}\oarg{write-out=\marg{#1},overwrite}\nl
#2\nl
\cend{scontents}\nl
}

\newcommand{\markscsv}{%
 Surname,Forename,StudentNo,Assign1,Assign2,Assign3\nl
 "Smith, Jr",John,102689,68,57,72\nl
 "Brown",Jane,102647,75,84,80\nl
 "Brown",Jane,102646,64,92,79\nl
 "Brown",Andy,103569,42,52,54\nl
 "Adams",Zoë,105987,52,48,57\nl
 "Brady",Roger,106872,68,60,62\nl
 "Verdon",Clare,104356,45,50,48%
}

\newcommand{\customerscsv}{%
Id,Organisation,Surname,Forename,Email,Age\nl
1,,Parrot,Polly,pp@example.com,42\nl
2,University of Somewhere,Canary,Mabel,mc@example.com\nl
3,University of Somewhere,Zebra,Zoë,zz@example.com,21\nl
4,Zinnia Florestry,Arara,José,ja@example.com,42\nl
5,,Duck,Dickie,dd@example.com,\nl
6,Newt Fellowship,Axolotl,Lizzie,la@example.com\nl
7,Avian Emporium,Canary,Fred,fc@example.com,19\nl
8,Newt Fellowship,,Molgina,m@example.com\nl
9,,Mander,Sally\nl
10,Élite Emporium,Fant,Eli,ef@example.com,101%
}

\newcommand{\customersdb}{%
\gls{DTLsetup}\marg{\optval{default-name}{customers}}\nl
\comment{define database:}%
\gls{DTLaction}\marg{\action{new}}\nl
\comment{add columns in desired order:}%
\gls{DTLaction}\oarg{\actionoptval{key}{Id}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Organisation}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Surname}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Forename}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Email}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Age}}\marg{\action{add-column}}\nl
\comment{1st row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
\commentdbsp{Organisation not set}%
   Id = 1, Email = {pp@example.com},\nldbsp
   Surname = \marg{Parrot}, Forename = \marg{Polly}, Age = 42\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{2nd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
\commentdbsp{Age not set}%
    Id = 2, Organisation = \marg{University of Somewhere},\nldbsp
    Email = {mc@example.com},
    Surname = \marg{Canary}, \nldbsp
    Forename = \marg{Mabel}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{3rd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Id = 3, Organisation = \marg{University of Somewhere}, \nldbsp
    Age = 21,
    Email = {zz@example.com},
    Surname = \marg{Zebra},\nldbsp
    Forename = \marg{Zoë}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{4th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Id = 4, Organisation = \marg{Zinnia Florestry}, Age = 42,\nldbsp
    Email = {ja@example.com},
    Surname = \marg{Arara},\nldbsp
    Forename = \marg{José}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{5th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
\commentdbsp{Organisation and Age not set}%
    Id = 5, Surname = \marg{Duck}, Forename = \marg{Dickie},\nldbsp
    Email = {dd@example.com}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{6th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
\commentdbsp{Age not set}%
    Id = 6, Organisation = \marg{Newt Fellowship},\nldbsp
    Email = {la@example.com},
    Surname = \marg{Axolotl},\nldbsp
    Forename = \marg{Lizzie}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{7th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Id = 7, Organisation = \marg{Avian Emporium}, Age =19,\nldbsp
    Email = {fc@example.com},
    Surname = \marg{Canary},\nldbsp
    Forename = \marg{Fred}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{8th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
\commentdbsp{Age and Surname not set}%
    Id = 8, Organisation = \marg{Newt Fellowship},\nldbsp
    Email = {m@example.com},
    Forename = \marg{Molgina}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{9th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
\commentdbsp{Organisation empty and Age and Email not set}%
    Id = 9, Organisation = \marg{},\nldbsp
    Surname = \marg{Mander}, Forename = \marg{Sally}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{10th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Id = 10, Organisation = \marg{Élite Emporium}, Age = 101,\nldbsp
    Email = {ef@example.com},
    Surname = \marg{Fant},\nldbsp
    Forename = \marg{Eli}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
}

\newcommand{\balancecsv}{%
Description,In,Out,Balance\nl
Travel expenses,,230,-230\nl
Conference fees,,400,-630\nl
Grant,700,,70\nl
Train fare,,70,0%
}

\newcommand{\productdb}{%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{products}}\nl
\comment{define database:}%
\gls{DTLaction}\marg{\action{new}}\nl
\comment{add columns in desired order:}%
\gls{DTLaction}\oarg{\actionoptval{key}{Title}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Author}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Format}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Quantity}}\marg{\action{add-column}}\nl
\gls{DTLaction}\oarg{\actionoptval{key}{Price},\actionoptvalm{value}{Price
(\gls{cs.dollar})}}\marg{\action{add-column}}\nl
\comment{1st row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{The Adventures of Duck and Goose},\nldbsp
    Author = \marg{Sir Quackalot},\nldbsp
    Format = paperback,\nldbsp
    Quantity = 3,
    Price = \marg{10.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{2nd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{The Return of Duck and Goose},\nldbsp
    Author = \marg{Sir Quackalot},\nldbsp
    Format = paperback,\nldbsp
    Quantity = 5,
    Price = \marg{19.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{3rd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{More Fun with Duck and Goose},\nldbsp
    Author = \marg{Sir Quackalot},\nldbsp
    Format = paperback,\nldbsp
    Quantity = 1,
    Price = \marg{12.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{4th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{Duck and Goose on Holiday},\nldbsp
    Author = \marg{Sir Quackalot},\nldbsp
    Format = paperback,\nldbsp
    Quantity = 3,
    Price = \marg{11.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{5th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{The Return of Duck and Goose},\nldbsp
    Author = \marg{Sir Quackalot},\nldbsp
    Format = hardback,\nldbsp
    Quantity = 3,
    Price = \marg{19.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{6th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{The Adventures of Duck and Goose},\nldbsp
    Author = \marg{Sir Quackalot},\nldbsp
    Format = hardback,\nldbsp
    Quantity = 9,
    Price = \marg{18.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{7th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{My Friend is a Duck},\nldbsp
    Author = \marg{A. Parrot},\nldbsp
    Format = paperback,\nldbsp
    Quantity = 20,
    Price = \marg{14.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{8th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{Annotated Notes on the ‘Duck and Goose’ chronicles},\nldbsp
    Author = \marg{Prof Macaw},\nldbsp
    Format = ebook,\nldbsp
    Quantity = 10,
    Price = \marg{8.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{9th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{‘Duck and Goose’ Cheat Sheet for Students},\nldbsp
    Author = \marg{Polly Parrot},\nldbsp
    Format = ebook,\nldbsp
    Quantity = 50,
    Price = \marg{5.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{10th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{‘Duck and Goose’: an allegory for modern times?},\nldbsp
    Author = \marg{Bor Ing},\nldbsp
    Format = hardback,\nldbsp
    Quantity = 0,
    Price = \marg{59.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{11th row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Title = \marg{Oh No! The Chickens have Escaped!},\nldbsp
    Author = \marg{Dickie Duck},\nldbsp
    Format = ebook,\nldbsp
    Quantity = 11,
    Price = \marg{2.0}\nlsp
  }\nl
 }\marg{\action{new-row}}
}

\newcommand{\pricelistdb}{%
\comment{custom expandable command:}%
\cmd{newcommand}\marg{\cmd{limiteded}}\marg{limited edition}\nl
\comment{define a database with the name 'pricelist':}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{pricelist}}\nl
\gls{DTLaction}\marg{\action{new}}\comment{create the default database}%
\comment{1st row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Product = \marg{The Adventures of Duck and Goose},\nldbsp
    Quantity = \marg{1,452},
    Price = \marg{\gls{cs.dollar}1.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{2nd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Product = \marg{Duck and Goose on Holiday},\nldbsp
    Quantity = \marg{94},
    Price = \marg{\gls{cs.dollar}2.99}\nlsp
  }\nl
 }\marg{\action{new-row}}\nl
\comment{the next value needs to be expanded:}%
\gls{DTLaction}\oarg{\nl
 \actionoptvalm{key}{Notes},
 \actionoptvalm{expand-value}{\cmd{limiteded}}
}\marg{\action{new-entry}}\nl
\comment{3rd row:}%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    Product = \marg{The Return of Sir Quackalot},\nldbsp
    Quantity = \marg{3},
    Price = \marg{\gls{cs.dollar}4.99}\nlsp
  }\nl
 }\marg{\action{new-row}}
}

\newcommand{\fruitcsv}{%
Name,Quantity\nl
"Apples",30\nl
"Pears",25\nl
"Lemons,Limes",40.5\nl
"Peaches",34.5\nl
"Cherries",20%
}

\newcommand{\profitscsv}{%
Year,Profit,Units\nl
1999,"-\gls{cs.dollar}4,673",12467\nl
2000,"\gls{cs.dollar}2,525.49",8965\nl
2001,"\gls{cs.dollar}1,673.52",14750\nl
2002,"-\gls{cs.dollar}1,320.01",14572\nl
2003,"\gls{cs.dollar}5,694.83",13312\nl
2004,"\gls{cs.dollar}-451.67",9764\nl
2005,"\gls{cs.dollar}6,785.20",11235%
}

\newcommand{\timetogrowthIcsv}{%
Time,Experiment 1,Experiment 2\nl
0,3.13,3.4\nl
15,3.42,3.45\nl
30,3.67,3.5\nl
45,4.2,3.64\nl
60,4.9,3.8%
}

\newcommand{\timetogrowthIIcsv}{%
Time,Experiment 1,Experiment 2\nl
0,3.14,3.2\nl
15,3.51,3.53\nl
30,3.79,3.61\nl
45,4.5,4.25\nl
60,5.1,4.9%
}

\newcommand{\growthItsv}{%
Experiment 1\glssymbol{idx.tabchar}\glssymbol{idx.tabchar}Experiment 2\glssymbol{idx.tabchar}\nl
Time\glssymbol{idx.tabchar}Log
Count\glssymbol{idx.tabchar}Time\glssymbol{idx.tabchar}Log Count\nl
0\glssymbol{idx.tabchar}2.9\glssymbol{idx.tabchar}0\glssymbol{idx.tabchar}3.31\nl
15\glssymbol{idx.tabchar}3.14\glssymbol{idx.tabchar}10\glssymbol{idx.tabchar}3.45\nl
30\glssymbol{idx.tabchar}3.26\glssymbol{idx.tabchar}25\glssymbol{idx.tabchar}3.61\nl
45\glssymbol{idx.tabchar}4.01\glssymbol{idx.tabchar}40\glssymbol{idx.tabchar}3.76\nl
60\glssymbol{idx.tabchar}4.2\glssymbol{idx.tabchar}55\glssymbol{idx.tabchar}3.89%
}

\newcommand{\growthIItsv}{%
Experiment 1\glssymbol{idx.tabchar}\glssymbol{idx.tabchar}Experiment 2\glssymbol{idx.tabchar}\glssymbol{idx.tabchar}Experiment 3\glssymbol{idx.tabchar}\nl
Time\glssymbol{idx.tabchar}Log Count\glssymbol{idx.tabchar}%
Time\glssymbol{idx.tabchar}Log Count\glssymbol{idx.tabchar}%
Time\glssymbol{idx.tabchar}Log Count\nl
0\glssymbol{idx.tabchar}3.21\glssymbol{idx.tabchar}0\glssymbol{idx.tabchar}3.39\glssymbol{idx.tabchar}0\glssymbol{idx.tabchar}3.28\nl
15\glssymbol{idx.tabchar}3.43\glssymbol{idx.tabchar}10\glssymbol{idx.tabchar}3.51\glssymbol{idx.tabchar}10\glssymbol{idx.tabchar}3.45\nl
30\glssymbol{idx.tabchar}3.68\glssymbol{idx.tabchar}25\glssymbol{idx.tabchar}3.65\glssymbol{idx.tabchar}20\glssymbol{idx.tabchar}3.57\nl
45\glssymbol{idx.tabchar}4.4\glssymbol{idx.tabchar}40\glssymbol{idx.tabchar}3.84\glssymbol{idx.tabchar}30\glssymbol{idx.tabchar}3.64\nl
60\glssymbol{idx.tabchar}4.8\glssymbol{idx.tabchar}55\glssymbol{idx.tabchar}3.92\glssymbol{idx.tabchar}40\glssymbol{idx.tabchar}3.95%
}

\newcommand{\xydatacsv}{%
X,Y\nl
-3.5,-2.75\nl
-3,3\nl
-2.5,-1\nl
-1,1.5\nl
1,-4.2\nl
2.6,1.8\nl
3.2,-0.4%
}

\newcommand{\sampleIbib}{%
@STRING\marg{TUGBOAT = \marg{TUGboat}}\nl
@STRING\marg{PRACTEX = \marg{The Prac\cmd{TeX}\gls{cs.space}Journal}}\nl
@ARTICLE\marg{Flom2005,\nlsp
  author = \marg{Peter Flom and Hans Hagen and Joe Hogg and Nicola Talbot and Philip
        Taylor and Christina Thiele and David Walden},\nlsp
  title = \marg{What is \marg{\cmd{TeX}}?},\nlsp
  journal = PRACTEX,\nlsp
  year = 2005,\nlsp
  volume = 3,\nlsp
  url = \marg{http://tug.org/pracjourn/2005-3/walden-whatis}\nl
}\nl
@ARTICLE\marg{tugboat2016,\nlsp
  title = "Localisation of \marg{\cmd{TeX}} documents: tracklang",\nlsp
  author = "Nicola Talbot",\nlsp
  month = NOV,\nlsp
  year = 2016,\nlsp
  volume = 37,\nlsp
  number = 3,\nlsp
  journal = TUGBOAT,\nlsp
  url = "http://www.tug.org/TUGboat/tb37-3/tb117talbot.pdf"\nl
}\nl
@ARTICLE\marg{tugboat2022,\nlsp
  title = "bib2gls: Standalone entries and repeated lists (a little
book of poisons)",\nlsp
  author = "Nicola Talbot",\nlsp
  month = APR,\nlsp
  year = 2022,\nlsp
  volume = 43,\nlsp
  number = 1,\nlsp
  journal = TUGBOAT,\nlsp
  doi = {10.47397/tb/43-1/tb133talbot-bib2gls-reorder},\nlsp
  url = "https://tug.org/TUGboat/tb43-1/tb133talbot-bib2gls-reorder.pdf"\nl
}\nl
@BOOK\marg{Talbot2012a,\nlsp
  title = \marg{\marg{\cmd{LaTeX}} for Complete Novices},\nlsp
  publisher = \marg{Dickimaw Books},\nlsp
  year = 2012,\nlsp
  month = SEP,\nlsp
  author = \marg{Nicola L C Talbot},\nlsp
  volume = 1,\nlsp
  series = \marg{Dickimaw \marg{\cmd{LaTeX}} Series},\nlsp
  isbn = {978-1-909440-00-5},\nlsp
  url = \marg{https://www.dickimaw-books.com/latex/novices/}\nl
}\nl
@INPROCEEDINGS\marg{Talbot2020,\nlsp
  author = \marg{Nicola L C Talbot},\nlsp
  title = \marg{Sorting Glossaries with bib2gls},\nlsp
  booktitle = \marg{\marg{LaTeX}.net},\nlsp
  year = 2020,\nlsp
  month = JUL,\nlsp
  url = \marg{https://latex.net/sorting-glossaries-with-bib2gls/}\nl
}\nl
@BOOK\marg{Talbot2013a,\nlsp
  title = \marg{Using \marg{\cmd{LaTeX}} to Write a \marg{PhD} Thesis},\nlsp
  publisher = \marg{Dickimaw Books},\nlsp
  year = 2013,\nlsp
  month = MAR,\nlsp
  author = \marg{Nicola L C Talbot},\nlsp
  volume = 2,\nlsp
  series = \marg{Dickimaw \marg{\cmd{LaTeX}} Series},\nlsp
  isbn = \marg{978-1-909440-02-9},\nlsp
  url = \marg{http://www.dickimaw-books.com/latex/thesis/}\nl
}\nl
@INPROCEEDINGS\marg{Talbot2012c,\nlsp
  author = \marg{Nicola L C Talbot},\nlsp
  title = \marg{Creating a glossary without using an external indexing
        application},\nlsp
  booktitle = \marg{\marg{LaTeX}.net},\nlsp
  year = 2012,\nlsp
  month = SEP,\nlsp
  url = \marg{https://latex.net/glossary-without-external-app/},\nlsp
  note=\marg{Originally posted on the \marg{\cmd{LaTeX}} Community's Know How
Section}\nl
}\nl
@BOOK\marg{Talbot2014a,\nlsp
  title = \marg{\marg{\cmd{LaTeX}} for Administrative Work},\nlsp
  publisher = \marg{Dickimaw Books},\nlsp
  month = SEP,\nlsp
  year = 2014,\nlsp
  author = \marg{Nicola L C Talbot},\nlsp
  volume = 3,\nlsp
  series = \marg{Dickimaw \marg{\cmd{LaTeX}} Series},\nlsp
  isbn = \marg{978-1-909440-07-4},\nlsp
  url = \marg{https://www.dickimaw-books.com/latex/admin/}\nl
}\nl
@BOOK\marg{Talbot2013b,\nlsp
  title = \marg{Quack, Quack, Quack. Give My Hat Back!},\nlsp
  publisher = \marg{Dickimaw Books},\nlsp
  year = 2013,\nlsp
  month = MAY,\nlsp
  author = \marg{Nicola L C Talbot and Magdalene Pritchett},\nlsp
  isbn = \marg{978-1-909440-03-6},\nlsp
  url = \marg{https://www.dickimaw-books.com/fiction/kids/duck/}\nl
}\nl
@BOOK\marg{Talbot2012b,\nlsp
  title = \marg{The Foolish Hedgehog},\nlsp
  publisher = \marg{Dickimaw Books},\nlsp
  year = 2012,\nlsp
  month = NOV,\nlsp
  author = \marg{Nicola L C Talbot and Magdalene Pritchett},\nlsp
  isbn = \marg{978-1-909440-01-2},\nlsp
  url = \marg{https://www.dickimaw-books.com/fiction/kids/hedgehog/}\nl
}
}

\newcommand{\sampleIIbib}{%
@Article\marg{duck2018,\nlsp
  Author = \marg{Dickie Duck and José Arara and Polly Parrot},\nlsp
  Title = \marg{Avian Friendship},\nlsp
  Journal = \marg{Fowl Times},\nlsp
  Year = 2018,\nlsp
  Volume = 7,\nlsp
  Number = 5,\nlsp
  Pages = "1032--5"\nl
}\nl
@BOOK\marg{duck2016,\nlsp
 AUTHOR = \marg{Dickie Duck},\nlsp
 TITLE = \marg{Feathered stunt doubles: \cmd{emph}\marg{The Birds}
and other films},\nlsp
 PUBLISHER = \marg{Duck Duck Goose},\nlsp
 YEAR = 2016\nl
}\nl
@book\marg{macaw,\nlsp
  author = \marg{Prof Macaw},\nlsp
  title = \marg{Annotated notes on the \cmd{emph}\marg{Duck and
Goose} chronicles},\nlsp
  publisher = {Duck Duck Goose},\nlsp
  year = 2012\nlsp
}\nl
@inproceedings\marg{parrot2021a,\nlsp
  author = \marg{Polly Parrot},\nlsp
  title = \marg{Who's a Pretty Polly? \marg{T}he surge of avian chatbots},\nlsp
  booktitle = \marg{Avian Intelligence},\nlsp
  month = jan,\nlsp
  year = 2021\nl
}\nl
@inproceedings\marg{parrot2021b,\nlsp
  author = \marg{Polly Parrot},\nlsp
  title = \marg{Pollybot: the next generation in avian translators},\nlsp
  booktitle = \marg{Avian Advances},\nlsp
  month = apr,\nlsp
  year = 2021\nl
}\nl
@phdthesis\marg{ing2020,\nlsp
  author = \marg{Bor Ing},\nlsp
  title = \marg{\cmd{emph}\marg{Duck and Goose}: an allegory for modern
times?},\nlsp
  school = \marg{Department of Literature, University of Somewhere},\nlsp
  month = mar,\nlsp
  year = 2010\nl
}\nl
@booklet\marg{parrots2013,\nlsp
  author = \marg{Polly Parrot and Dickie Duck},\nlsp
  title = \marg{\cmd{emph}\marg{Duck and Goose} Cheat Sheet},\nlsp
  howpublished = \marg{Limited print run},\nlsp
  address = \marg{Dubious Student Resources},\nlsp
  year = 2013\nl
}\nl
@book\marg{parrot2012,\nlsp
 author = \marg{von Parrot, Jr, Ann},\nlsp
 title = \marg{My Friend is a Duck},\nlsp
 publisher = \marg{Duck Duck Goose},\nlsp
 year = 2012,\nl
}\nl
@book\marg{quackalot,\nlsp
 author = \marg{Sir Quackalot},\nlsp
 title = \marg{The Adventures of Duck and Goose},\nlsp
 publisher = \marg{Duck Duck Goose},\nlsp
 year = 2011\nl
}\nl
@techreport\marg{zebra2022,\nlsp
 author = \marg{Zoë Zebra and Mabel Canary},\nlsp
 title = \marg{Health and Safety when Handling Mind-Controlling
Cookies},\nlsp
 institution = \marg{Secret Lab of Experimental Stuff},\nlsp
 month = \marg{22 } \# MAR,\nlsp
 year = 2014\nl
}\nl
@manual\marg{canary2015,\nlsp
 author = \marg{Mabel Canary},\nlsp
 title = \marg{Ray Gun User Guide},\nlsp
 organization = \marg{Secret Lab of Experimental Stuff},\nlsp
 edition = "2nd",\nlsp
 year = 2015\nl
}\nl
@book\marg{fan1992,\nlsp
 author = \marg{Éli-Fant, Nellie},\nlsp 
 title = \marg{The Duckinator},\nlsp
 publisher = \marg{Duck Duck Goose},\nlsp
 year = 1992,\nlsp
 note = \marg{A cyborg from the future travels to the past
to scramble some eggs.}\nl
}\nl
@misc\marg{henpecked,\nlsp
 title = \marg{Henpecked: Time for a Coup in the Coop!},\nlsp
 howpublished = \marg{Flyer}\nl
}
}

\versiondate
{
3.4.5
}
{
2026-08-23
}

\title{The datatool Bundle: Databases and Data Manipulation}
\author{Nicola L.C. Talbot\\[10pt]
Dickimaw Books\\
\href{https://www.dickimaw-books.com/}{\nolinkurl{dickimaw-books.com}}}
    
\begin{document}
\maketitle

\htmlavailable

The \sty{datatool} bundle includes the following documentation:
\begin{deflist}

\itemtitle{User Manual for datatool (\filefmt{datatool-user.pdf})}

\begin{itemdesc}
This document is the main user guide for the \sty{datatool} package.
\end{itemdesc}

\itemtitle{Documented Code for datatool (\url{datatool-code.pdf})}

\begin{itemdesc}
Advanced users wishing to know more about the inner workings of all the
packages provided in the \styfmt{datatool} bundle should read
\qt{Documented Code for datatool v3.4.5}.
\end{itemdesc}

\itemtitle{\url{CHANGES}}
\begin{itemdesc}
Change log.
\end{itemdesc}

\itemtitle{\url{README.md}}

\begin{itemdesc}
Package summary.
\end{itemdesc}

\itemtitle{\url{DEPENDS.txt}}

\begin{itemdesc}
List of all packages unconditionally required by \sty{datatool}
(hard dependencies).
Other unlisted packages may be required under certain circumstances.
For help on installing packages see, for example,
\texseref{questions/55437}{How
do I update my \TeX\ distribution?} or (for Linux users)
\texseref{questions/14925}{Updating \TeX\ on Linux}.
\end{itemdesc}

\end{deflist}

Related resources:
\begin{itemize}
\item \faqspkg{datatool}

\item \dickimawhref{bugtracker.php?category=datatool}{Bug tracker}

\item \gallerytopic{performance}

\item \ctanref{pkg/datatool-regions}{\styfmt{datatool-regions}}

\item \ctanref{pkg/datatool-english}{\styfmt{datatool-english}}

\item \ctanref{pkg/datatooltk}{\appfmt{datatooltk}}

\end{itemize}

\begin{important}
The \sty{datatool} bundle is provided to help perform repetitive
commands, such as mail merging, but since \TeX\ is designed as a
typesetting language, don't expect this bundle to perform as
efficiently as custom database systems or a dedicated mathematical
or scripting language. \strong{If the provided packages take a frustratingly
long time to compile your document, use another language to perform
your calculations or data manipulation and save the results in a
file that can be input into your document.} For large amounts of
data that need to be sorted or filtered or joined, consider storing your data
in an~\idx{SQL} database and use \app{datatooltk} to import the data,
using \idx{SQL} syntax to filter, sort and otherwise
manipulate the values.
\end{important}

\frontmatter
\tableofcontents
\listoftables
\listofexamples

\mainmatter

\part{User Guide}
\label{userguide}

\chapter{Introduction}
\label{sec:intro}


The following packages are provided by the \sty{datatool} bundle:
\begin{itemize}
\item \sty{datatool-base}
This is the underlying package automatically loaded by all the other
listed packages, but may be loaded without the other packages if
only the base functions are required. The \sty{datatool-base} package may be used to:
\begin{itemize}
\item Determine whether an argument is an integer, a real number,
currency or a string. Locale dependent number settings are supported (such
as a comma as a decimal character and a full stop as a number
group character). As from version 3.0, scientific notation is also
supported.
\item Convert locale dependent numbers or currency to \idx{plainnumber}
format, enabling arithmetic to be performed on elements of the database.
\item Names can be converted to initials.
\item Determine if strings are all upper or lower case.
\item Perform string comparisons (both case sensitive and case insensitive).
\end{itemize}
See \sectionref{sec:base}.

\item \sty{datatool}

Main package providing database support.
Automatically loads \sty{datatool-base}.
This package can be used to:
\begin{itemize}
\item Create or load databases.
\item Sort rows of a database (either numerically or alphabetically,
ascending or descending).
\item Perform repetitive operations on each row of a database
(e.g.\ mail merging). Conditions may be imposed to exclude rows.
\end{itemize}
Database commands are described in \sectionref{sec:databases}.

\item \sty{datagidx}

The \sty{datagidx} package (see \sectionref{sec:datagidx}) can be used
to generate indexes or glossaries as an alternative to packages
such as \sty{glossaries}. Note that \sty{datagidx} is far more
limited than \sty{glossaries} and doesn't provide any localisation
support. See \sectionref{sec:datagidx}.

\item \sty{datapie}

The \sty{datapie} package can be used to convert a database into
a pie chart:
\begin{itemize}
\item Segments can be separated from the rest of the chart to make
them stand out.
\item Colour/grey scale options.
\item Predefined segment colours can be changed.
\item Hooks provided to add extra information to the chart
\end{itemize}
See \sectionref{sec:datapie}.

\item \sty{dataplot}

The \sty{dataplot} package can be used to convert a database into
a two dimensional plot using markers and/or lines. Three dimensional
plots are currently not supported.
See \sectionref{sec:dataplot}.

\item \sty{databar}

The \sty{databar} package can be used to convert a database into
a bar chart:
\begin{itemize}
\item Colour/grey scale options.
\item Predefined bar colours can be changed.
\item Hooks provided to add extra information to the chart
\end{itemize}
See \sectionref{sec:databar}.

\item \sty{databib}

The \sty{databib} package can be used to convert a \BibTeX\ database
into a \sty{datatool} database.
See \sectionref{sec:databib}.

\item \sty{person}

The \sty{person} package can be used to reference people by the
appropriate gender pronouns. Automatically loads \sty{datatool}.
See \sectionref{sec:person}.

\end{itemize}

\begin{information}
The \sty{datapie} and \sty{databar} packages do not support the
creation of 3D charts, and I have no plans to implement them at any
later date. The use of 3D charts should be discouraged. They may look
pretty, but the purpose of a chart is to be informative. Three
dimensional graphics cause distortion, which can result in misleading
impressions. The \sty{pgf} manual provides a more in-depth
discussion on the matter.
\end{information}

The code providing the mathematical functions have some limitations.
These limitations will therefore also be present in the various
packages provided with \sty{datatool}, according to the underlying
package (\sty{fp} or \sty{pgfmath}) or \LaTeX3 kernel commands or Lua
code used. As from version 3.0, the new default is
\optvalref{math}{lua}, if \gls{directlua} is defined, or
\optvalref{math}{l3fp} otherwise. To avoid repeated parsing, some
functions, such as the aggregate functions
(\sectionref{sec:dbarith}) or charts
(\sectionsref{sec:datapie,sec:dataplot,sec:databar}), will use \LaTeX3
commands regardless of the \opt{math} option.

\section{Rollback}
\label{sec:rollback}

Version 3.0 is a major new version where many commands have been
rewritten to use \LaTeX3 macros. Additionally, some packages, such
as \sty{xkeyval} and \sty{substr} are no longer loaded.
If you experience any backward-compatibility problems with the new
version, you can rollback to the previous version (2.32):
\begin{codebox}
\cmd{usepackage}\marg{datatool}[=v2.32]
\end{codebox}

\begin{important}
Rollback provides a useful way of reverting back to an earlier
release if there's a problem with a new version. However,
the further away the rollback date is from the current LaTeX kernel,
the more likely that incompatibilities will occur.
If you have historic documents that you need to compile, consider
using the historic \TeXLive\ Docker images.
(See, for example,
\blog{legacy-documents-and-tex-live-docker-images}%
{Legacy Documents and \TeXLive\ Docker Images}.)
\end{important}

\section{\LaTeX3}
\label{sec:latex3}

The \LaTeX\ kernel has changed significantly since \sty{datatool}
was first released in 2007. There is now improved support for
\idx{utf8} and many of the commands provided by \sty{datatool} now
have much better \LaTeX3 alternatives.  You may find some tasks more
efficient if you use \LaTeX3 commands directly. However, \LaTeX3
commands are intended for internal use within the definitions of
document commands rather than explicit use in the document.

\LaTeX3 syntax must first be switched on (\inlineglsdef{ExplSyntaxOn})
before defining commands that use them and then switched off
(\inlineglsdef{ExplSyntaxOff}) afterwards. Spaces are ignored, so you
need to use \inlineidxdef{l3sp} if an actual space is required.
Further information can be found in the \filefmt{interface3.pdf}
document:
\texdocref{interface3}

\subsection{Regular Expressions}
\label{sec:l3regex}

\examplemarginref{ex:l3regex}%
\LaTeX3 provides commands for regular expressions. A simple example
is shown below that replaces \code{\cmd{emph}\marg{boo}} with
\code{\cmd{textbf}\marg{BOO}}. More generally, the custom command
searches for any instance of \code{\cmd{emph}\margm{word}}, where
\meta{word} consists of one or more word characters
(\code{\csfmt{w}+}), and replaces it with
\code{\cmd{textbf}\margm{WORD}}, where the argument is the original
\meta{word} converted to \idx{uppercase} using \gls{textuppercase:n}.

\begin{codebox*}
\cmd{documentclass}\marg{article}
\gls{ExplSyntaxOn}
\cmd{NewDocumentCommand}\marg{\cmd{testreplace}} \marg{ m }
\marg{
  \gls{regexreplaceall:nnN} 
   \marg{ \cmd{c}\marg{emph} \cmd{cB}\gls{cs.openbrace} (\cmd{w}+) \cmd{cE}\gls{cs.closebrace} }
   \marg{ \cmd{c}\marg{textbf} \marg{ \cmd{c}\marg{text\_uppercase:n}\marg{ \cmd{1} } } }
   \#1
}
\gls{ExplSyntaxOff}
\cbeg{document}
\cmd{newcommand}\marg{\cmd{teststring}}\marg{The duck said \cmd{emph}\marg{boo} to the goose.}
Original: \cmd{teststring}
\codepar
\cmd{testreplace}\marg{\cmd{teststring}}
Replaced: \cmd{teststring}
\cend{document}
\end{codebox*}
\begin{resultbox}
\createexample*[label={ex:l3regex},link={sec:l3regex},
  title={Regular Expressions with \LaTeX3},
  description={Example document using LaTeX3 regular expressions}
]
{%
\gls{ExplSyntaxOn}\nl
\cmd{NewDocumentCommand}\marg{\cmd{testreplace}} \marg{ m }\nl
\marg{\nlsp
  \gls{regexreplaceall:nnN}\nldbsp
   \marg{ \cmd{c}\marg{emph} \cmd{cB}\string\{ (\cmd{w}+) \cmd{cE}\string\}}\nldbsp
   \marg{ \cmd{c}\marg{textbf} \marg{ \cmd{c}\marg{text\_uppercase:n}\marg{ \cmd{1} } } }\nlsp
   \#1\nl
}\nl
\gls{ExplSyntaxOff}
}
{%
\cmd{newcommand}\marg{\cmd{teststring}}\marg{The duck said
\cmd{emph}\marg{boo} to the goose.}\nl
Original: \cmd{teststring}
\codepar
\cmd{testreplace}\marg{\cmd{teststring}}\nl
Replaced: \cmd{teststring}
}
\end{resultbox}

\subsection{Comma-Separated Lists}
\label{sec:l3clist}

\examplemarginref{ex:l3clist}%
\LaTeX3 provides commands for dealing with \idx{CSV} lists.
You may prefer to use those instead of the commands provided by
\sty{datatool-base} described in \sectionref{sec:csvlists}.
\begin{codebox*}
\cmd{documentclass}\marg{article}
\gls{ExplSyntaxOn}
\cmd{clist\_new:N \cmd{l\_my\_clist}}
\cmd{NewDocumentCommand} \cmd{createmylist} \marg{ m }
\marg{
  \cmd{clist\_set:Nn} \cmd{l\_my\_clist} \marg{ \#1 }
}
\cmd{NewDocumentCommand} \cmd{mylistelement} \marg{ m }
\marg{
  \cmd{clist\_item:Nn} \cmd{l\_my\_clist} \marg{ \#1 }
}
\cmd{NewDocumentCommand} \cmd{reversemylist} \marg{ }
\marg{
  \cmd{clist\_reverse:N} \cmd{l\_my\_clist}
}
\cmd{NewDocumentCommand} \cmd{displaymylist} \marg{ }
\marg{
  \cmd{clist\_use:Nnnn} \cmd{l\_my\_clist} \marg{\idx{l3sp}and\idx{l3sp} } \marg{ ,\idx{l3sp} } \marg{ ,\idx{l3sp}and\idx{l3sp}}
}
\gls{ExplSyntaxOff}
\cbeg{document}
\cmd{createmylist}\marg{ant,duck,goose,zebra}
\cmd{displaymylist}
\codepar
Second element: \cmd{mylistelement}\marg{2}.
\codepar
\cmd{reversemylist}
\cmd{displaymylist}
\codepar
Second element: \cmd{mylistelement}\marg{2}.
\cend{document}
\end{codebox*}
\begin{resultbox}
\createexample*[label={ex:l3clist},link={sec:l3clist},
 title={Comma-Separated Lists with \LaTeX3},
 description={Example document using LaTeX3 comma-separated list commands}
]
{%
\gls{ExplSyntaxOn}\nl
\cmd{clist\_new:N \cmd{l\_my\_clist}}\nl
\cmd{NewDocumentCommand} \cmd{createmylist} \marg{ m }\nl
\marg{\nlsp
  \cmd{clist\_set:Nn} \cmd{l\_my\_clist} \marg{ \#1 }\nl
}\nl
\cmd{NewDocumentCommand} \cmd{mylistelement} \marg{ m }\nl
\marg{\nlsp
  \cmd{clist\_item:Nn} \cmd{l\_my\_clist} \marg{ \#1 }\nl
}\nl
\cmd{NewDocumentCommand} \cmd{reversemylist} \marg{ }\nl
\marg{\nlsp
  \cmd{clist\_reverse:N} \cmd{l\_my\_clist}\nl
}\nl
\cmd{NewDocumentCommand} \cmd{displaymylist} \marg{ }\nl
\marg{\nlsp
  \cmd{clist\_use:Nnnn} \cmd{l\_my\_clist} \marg{\string~and\string~
} \marg{ ,\string~ } \marg{ ,\string~and\string~}\nl
}\nl
\gls{ExplSyntaxOff}
}%
{%
\cmd{createmylist}\marg{ant,duck,goose,zebra}\nl
\cmd{displaymylist}\nl
\codepar
Second element: \cmd{mylistelement}\marg{2}.
\codepar
\cmd{reversemylist}\nl
\cmd{displaymylist}\nl
\codepar
Second element: \cmd{mylistelement}\marg{2}.
}
\end{resultbox}

\subsection{Calculations}
\label{sec:l3calc}

\examplemarginref{ex:l3fptodec}%
If you have complex calculations, you may prefer to use \LaTeX3
commands directly instead of
using the \sty{datatool-base} commands described in
\sectionref{sec:plainfp}.

\begin{codebox*}
\cmd{documentclass}\marg{article}
\gls{ExplSyntaxOn}
\cmd{newcommand}\marg{\cmd{myfunc}} \oarg{3}
\marg{
  \gls{fptodecimal:n}\marg{ \#1 + 0.5 * sqrt(\#2) / (\#3) }
}
\gls{ExplSyntaxOff}
\cmd{newcommand}\marg{\cmd{numA}}\marg{1023.5}
\cmd{newcommand}\marg{\cmd{numB}}\marg{54.75000}
\cmd{newcommand}\marg{\cmd{numC}}\marg{-20648.68}
\cbeg{document}
\$ \cmd{numA}+\cmd{frac}\marg{\cmd{sqrt}\marg{\cmd{numB}}}\marg{2\cmd{times}\cmd{numC}} = 
\cmd{myfunc}\marg{\cmd{numA}}\marg{\cmd{numB}}\marg{\cmd{numC}} \$
\cend{document}
\end{codebox*}
\begin{resultbox}
\createexample*[label={ex:l3fptodec},link={sec:l3calc},
title={Performing Calculations with \LaTeX3},
description={Example document that uses \LaTeX3 floating point
commands}
]
{
\gls{ExplSyntaxOn}\nl
\cmd{newcommand}\marg{\cmd{myfunc}} \oarg{3}\nl
\marg{\nlsp
  \gls{fptodecimal:n}\marg{ \#1 + 0.5 * sqrt(\#2) / (\#3) }\nl
}\nl
\gls{ExplSyntaxOff}\nl
\cmd{newcommand}\marg{\cmd{numA}}\marg{1023.5}\nl
\cmd{newcommand}\marg{\cmd{numB}}\marg{54.75000}\nl
\cmd{newcommand}\marg{\cmd{numC}}\marg{-20648.68}
}
{
\$ \cmd{numA}+\cmd{frac}\marg{\cmd{sqrt}\marg{\cmd{numB}}}\marg{2\cmd{times}\cmd{numC}} = 
\cmd{myfunc}\marg{\cmd{numA}}\marg{\cmd{numB}}\marg{\cmd{numC}} \$
}
\end{resultbox}
If you plan on re-parsing commands such as the example \csfmt{numA},
\csfmt{numB} and \csfmt{numC} commands, then it would be better to
convert them to \LaTeX3 floating point variables or constants.
See the \LaTeX3 Interfaces document for further details.

\mExampleref{ex:directlua} performs the same calculation but
uses \gls{directlua}, which requires \LuaLaTeX:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{myfunc}}\oarg{3}\marg{\comment{}
  \gls{directlua}\marg{tex.print(\#1+0.5*math.sqrt(\#2)/(\#3))}\comment{}
}
\end{codebox}
\begin{resultbox}
\createexample*[arara={lualatex,pdfcrop},label={ex:directlua},
title={Performing Calculations with LuaLaTeX},link={sec:l3calc},
description={Example document that uses Lua to perform floating
point arithmetic}
]
{%
\cmd{newcommand}\marg{\cmd{myfunc}}\oarg{3}\marg{\comment{}
  \gls{directlua}\marg{tex.print(\#1+0.5*math.sqrt(\#2)/(\#3))}\comment{}%
}\nl
\cmd{newcommand}\marg{\cmd{numA}}\marg{1023.5}\nl
\cmd{newcommand}\marg{\cmd{numB}}\marg{54.75000}\nl
\cmd{newcommand}\marg{\cmd{numC}}\marg{-20648.68}
}
{
\$ \cmd{numA}+\cmd{frac}\marg{\cmd{sqrt}\marg{\cmd{numB}}}\marg{2\cmd{times}\cmd{numC}} = 
\cmd{myfunc}\marg{\cmd{numA}}\marg{\cmd{numB}}\marg{\cmd{numC}} \$
}
\end{resultbox}

\chapter{Base Commands (\stytext{datatool-base} package)}
\label{sec:base}

\pkgdef*{datatool-base}

The \sty{datatool-base} package may be loaded on its own, without
the \sty{datatool} package, if no database commands (see
\sectionref{sec:databases}) are required. Available package options
for \sty{datatool-base} are listed below.

\section{\stytext{datatool-base} Options}
\label{sec:baseoptions}

Options can be passed through the package option list in the usual
way. Some options may also be later set with:
\cmddef{DTLsetup}
(Options specific to locale files should be set with \gls{DTLsetLocaleOptions},
see \sectionref{sec:localisation}.)

\optiondef{math}
This setting may only be used as a package option, not in
\gls{DTLsetup}, and identifies the required maths processor. This determines
how the floating point commands described in \sectionref{sec:fp}
are defined. The value may be one of the following.

\optionvaldef{math}{l3fp}
This setting defines the \sty{datatool-base}
floating point commands (such as \gls{dtladd}) to use \LaTeX3 commands.
This is the default setting unless \LuaLaTeX\ is used.

\optionvaldef{math}{lua}
This setting defines the \sty{datatool-base} floating point commands
(such as \gls{dtladd}) to use \gls{directlua} to perform the
mathematical calculations. This is the default setting if \LuaLaTeX\
is used.

\optionvaldef{math}{fp}
This setting defines the \sty{datatool-base} floating point commands
(such as \gls{dtladd}) to use the \sty{fp} package commands to perform the
mathematical calculations. (Automatically loads the \sty{fp}
package.) Note that the \sty{fp} package can be less precise than 
\LaTeX3 or Lua. (See \examplesref{ex:l3fpcalc,ex:fpcalc,ex:luacalc}.)

\optionvaldef{math}{pgfmath}
This setting defines the \sty{datatool-base} floating point commands
(such as \gls{dtladd}) to use the \sty{pgfmath} package commands to perform the
mathematical calculations. (Automatically loads the \sty{pgfmath}
package.) Note that the \sty{pgfmath} package has limitations and
may produce the error:
\begin{transcript}
! Dimension too large
\end{transcript}
This option is maintained for backward-compatibility but, in
general, the new default \optvalref{math}{l3fp} or \optvalref{math}{lua} 
options are better.

\begin{information}
As from version 3.0, some functions, such as the aggregate functions
(\sectionref{sec:dbarith}) or charts
(\sectionsref{sec:datapie,sec:dataplot,sec:databar}), will use \LaTeX3
commands regardless of the \opt{math} option to avoid repeated
parsing.
\end{information}

\optiondef{verbose}
If true, this option will write extra informational messages to the
transcript.

\optiondef{lang-warn}
This setting may only be used as a package option, not in \gls{DTLsetup}.
If false, this setting switches off localisation warnings. Note that
this will also switch off \sty{tracklang} warnings. If true, this
setting will switch on \sty{datatool-base} localisation warnings
without altering \sty{tracklang} warnings. If you need
\sty{tracklang} warnings to be switched back on again for the next
package that requires it, use \gls{TrackLangShowWarningstrue}.

\optiondef{nolocale}
This setting may only be used as a package option, not in
\gls{DTLsetup}, and has no value. If used it will prevent any localisation
files from being loaded, regardless of the document language
settings. This option will override \opt{locales} (and \opt{lang}).
See \sectionref{sec:localisation}.

\optiondef{locales}
This setting may only be used as a package option, not in
\gls{DTLsetup}. It counteracts the effect of \opt{nolocale} and
tracks each listed language tag using \sty{tracklang}['s]
\gls{TrackLanguageTag}. Note that localisation support must be
installed separately.  See \sectionref{sec:localisation}.

\begin{information}
This option will have an effect on packages that are subsequently loaded
that also use \sty{tracklang}. Note that multiple instances of this
option override each other.
\end{information}

\optiondef{lang}
A synonym of \opt{locales}.

\optiondef{initial-purify}
This boolean setting indicates whether or not to \idx{purify} the \meta{text}
argument of \gls{DTLGetInitialLetter} before parsing.

\optiondef{auto-reformat-types}
This option takes a comma-separated list, where the items in the
list may be any of the following keywords:
\optfmt{integer}, \optfmt{decimal}, \optfmt{si}, \optfmt{currency}, 
\optfmt{datetime}, \optfmt{date}, \optfmt{time}.
This identifies which data types should be automatically reformatted
if the corresponding \numericopt{auto-reformat} numeric option
or \datetimeopt{auto-reformat} datetime option is on.

The \opt{auto-reformat-types} does not switch on the corresponding
\numericopt{auto-reformat} \opt{numeric} option
or \datetimeopt{auto-reformat} \opt{datetime} option.
It simply establishes which data types should be affected when the
applicable option is on.

For example:
\begin{compactcodebox}
\gls{DTLsetup}\marg{
 \optvalm{auto-reformat-types}{decimal,si,datetime},
 \optvalm{numeric}{\numericopt{auto-reformat}},
 \optvalm{datetime}{\datetimeoptval{parse}{auto-reformat}}
}
\end{compactcodebox}
In the above, if \gls{DTLparse} identifies a decimal or SI notation
(but not an integer) or a datetime (but not a date or a time)
then the string value will be automatically reformatted.

\begin{important}
If \opt{auto-reformat-types} is missing all numeric types, then
the \numericopt{auto-reformat} numeric option will have no effect.
Similarly, 
if \opt{auto-reformat-types} is missing all temporal types, then
the \datetimeopt{auto-reformat} datetime option will have no effect.
\end{important}

\optiondef{lists}
This setting may be used to adjust the behaviour of commands that
deal with lists. The value should be a \keyval\ list of options,
which are described in \sectionref{sec:listopts}.

\optiondef{compare}
This setting may be used to adjust the behaviour of commands that
deal with comparisons. The value should be a \keyval\ list of options,
which are described in \sectionref{sec:compare}.

\optiondef{numeric}
This setting may be used to adjust the behaviour of commands that
deal with numeric (but not temporal) values. The value should be a \keyval\ list of options,
which are described in \sectionref{sec:numericopts}.

\optiondef{datetime}
This determines whether or not commands such as \gls{DTLparse}
should also try parsing for timestamps (date and time), dates (no
time) or times (no date). The temporal data types were only added to
\sty{datatool-base} version 3.0 and are still experimental so
this feature is off by default. The value should be a \keyval\ list
of options, which are described in \sectionref{sec:datetime}.

\section{Data Types}
\label{sec:datatypes}

The \sty{datatool-base} package recognises the following data types:

\begin{deflist}
\itemtitle{Integers}

\begin{itemdesc}
An integer is a sequence of digits, optionally groups of three
digits may be separated by the \idx{numbergroupchar}.  The default
\idx{numbergroupchar} is a comma (\idx{numbergroup}) but may be
changed using \gls{DTLsetnumberchars}. Examples: 1,234 (which has
the default \idx{numbergroupchar}) and 1234 (which is also a
\idx{plainnumber}) but not 1234.0 (which is a decimal). A double sign (such as
\code{++1234} or \code{-+1234}) isn't permitted and will be treated
as a string.

If a whole number is represented in scientific notation (for example,
\code{1e+4} instead of 1000) then it will be identified as a decimal not an integer.
Otherwise, a large integer will be considered a string (otherwise it
will trip \TeX's integer limit).
\end{itemdesc}

\itemtitle{Real Numbers (Decimals)}

\begin{itemdesc}
A real number is a sequence of digits as per integers followed by
the decimal character followed by one or more digits. The
\idx{numbergroupchar} is only recognised before the
\idx{decimalchar}. The \idx{decimalchar} is a full stop
\qtt{\idx{decimalpoint}} by default.  The number group and decimal
characters may be changed using \gls{DTLsetnumberchars}. 
Examples: 1,234.0 (which has the default \idx{numbergroupchar} and
\idx{decimalchar}), 1234.0 (which is also a \idx{plainnumber})
but not 1234 (which is an integer). A double sign (such as
\code{++1234.0} or \code{-+1234.0}) isn't permitted and will be treated
as a string.

As from version 3.0, scientific notation, such as \code{2.5e+10} or
\code{1E-5} is supported. Note that the locale symbols aren't
supported when parsing for scientific notation. The format should be
\code{\meta{mantissa}E\meta{exponent}} or
\code{\meta{mantissa}e\meta{exponent}}. A space may occur between 
the mantissa and the E/e. The exponent must be an integer. The
mantissa may include a \idx{decimalpoint}.
If the \numericopt{auto-reformat} setting is on, parsed scientific
notation will have the value encapsulated with \gls{DTLscinum}.
\end{itemdesc}

\itemtitle{Currency}

\begin{itemdesc}
The parser recognises currency values if provided in one of the
following forms: \code{\gls{DTLcurrency}\margm{num}},
\code{\gls{DTLfmtcurrency}\margm{sym}\margm{num}}
\code{\gls{DTLfmtcurr}\margm{currency-code}\margm{num}}
or \code{\meta{sym}\meta{num}} where \meta{sym} is a recognised
currency symbol (identified with \gls{DTLnewcurrencysymbol})
and \meta{num} is an integer or decimal using the current
\idx{numbergroupchar} and \idx{decimalchar} (not scientific notation).
The sign may occur before the currency symbol.
Some regional localisation files will also recognise currency where
the symbol is prefixed with the region's code.

Examples: 
\code{\$1,234.56} and \code{\gls{pounds}1234} 
(which both have a recognised currency symbol) and
\code{\gls{DTLfmtcurrency}\marg{£}{1,234}} or 
\code{\gls{DTLcurrency}\marg{1,234.00}} (which both use
known currency formatting commands) but not \qtt{1,234 USD}
(which doesn't fit the recognised format). Both
\code{-\gls{pounds}1234} and \code{\gls{pounds}-1234} are recognised
as a currency with a negative numeric value.

Additionally, \code{\gls{DTLfmtcurr}\marg{GBP}{1,234}}
will also be recognised as currency (although it requires
the \ldf{GB} region file to be loaded in order to correctly format
the value). If \ldf{GB} has been loaded, then \code{GB£1,234} will
also be recognised. However, if, say, \ldf{IE} has been loaded,
then \code{IE€1,234} \emph{won't} be recognised as that region
doesn't support a currency prefix.
See \sectionref{sec:currency}.
\end{itemdesc}

\itemtitle{Temporal Values (Dates and Times)}
New to version 3.0 and still experimental.  ISO dates and times can
be parsed (if enabled with \datetimeopt{parse}) 
and converted into a numerical form so that they can be
treated as numbers.

\begin{information}
If temporal parsing is off or the format is unsupported, dates and
times will be treated as strings. Regional formats can only be
supported if they have been defined in a loaded region file.
See \sectionref{sec:localisation}.
\end{information}

There are three temporal types:
\begin{enumerate}
\item Dates are in the form \code{\meta{YYYY}-\meta{MM}-\meta{DD}}
where \meta{YYYY} is the year, \meta{MM} is the two digit month
and \meta{DD} is the two digit day. The numeric value is the integer
\gls{jdn}.
\item Times are in the form \code{\meta{hh}:\meta{mm}:\meta{ss}}
or \code{\meta{hh}:\meta{mm}} where \meta{hh} is the two digit 24
hour, \meta{mm} is the two digit minute, and \meta{ss} is the two
digit second (\qt{00} if omitted). The numeric value is the \gls{jf}.
\item Timestamps include both a date and time. If the time zone is
missing, UTC+0 is assumed. Recognised formats:
\begin{compactcodebox}
\meta{YYYY}-\meta{MM}-\meta{DD}T\meta{hh}:\meta{mm}:\meta{ss}\meta{TZh}:\meta{TZm}
\meta{YYYY}-\meta{MM}-\meta{DD}T\meta{hh}:\meta{mm}:\meta{ss}Z
\meta{YYYY}-\meta{MM}-\meta{DD}T\meta{hh}:\meta{mm}:\meta{ss}
\end{compactcodebox}
Where \meta{TZh} is the time zone hour and \meta{TZm} is the time
zone minute.
A space may also be used instead of \qt{T} as the separator between
the date and time. The corresponding numeric value is the \gls{jd}, 
which is the integer \gls{jdn} plus the fractional \gls{jf}.
\end{enumerate}

\itemtitle{Strings}

\begin{itemdesc}
Any non-blank content that doesn't belong to the above 
types is considered to be a string. See \sectionref{sec:strings}.
\end{itemdesc}

\itemtitle{Unknown}

\begin{itemdesc}
Blank values are classified as an unknown type. This may be the
result of an empty element in a \idx{CSV} list or file.
\end{itemdesc}

\itemtitle{Null}

\begin{itemdesc}
Values that are missing (not simply empty) are considered null
values. This is similar in concept to \gls{cnovaluetl} but uses a
different internal marker. See \sectionref{sec:null} for further
details.
\end{itemdesc}

\end{deflist}

\subsection{Numeric Options}
\label{sec:numericopts}

The options listed here govern parsing and formatting of localised
integers, decimals and currency. The options may be passed in the value of
the \opt{numeric} option.
For example:
\begin{codebox}
\gls{DTLsetup}\marg{
  \optvalm{numeric}{
    \numericopt{auto-reformat},
    \numericoptval{region-currency-prefix}{smallcaps}
  }
}
\end{codebox}

\optiondef{numeric.auto-reformat}
Determines whether or not commands like \gls{DTLparse}
should reformat the string part for integers, decimals and currency.
(According to the \opt{auto-reformat-types} setting.)

\begin{information}
This option has no effect with \iooptval{csv-content}{no-parse}
as the values aren't parsed. Use \ioopt{convert-numbers} instead.
\end{information}

If \opt{auto-reformat-types} includes the keyword \optfmt{integer},
then any integers will be reformatted according to the current
localisation settings.  If \opt{auto-reformat-types} includes the
keyword \optfmt{decimal}, then any decimals not in scientific
notation will be reformatted according to the current localisation
settings.

If \opt{auto-reformat-types} includes the keyword \optfmt{si}, then
any scientific notation, will be have the string part set to 
\cmddef{DTLscinum}
If \sty{siunitx} is loaded, this will be defined to use \gls{num}
otherwise it will simply expand to its argument.

If \opt{auto-reformat-types} includes the keyword \optfmt{currency},
then currency will be reformatted to use \gls{DTLfmtcurr}, if the
associated currency code can be determined, or to
\gls{DTLfmtcurrency} otherwise.

\optiondef{numeric.region-currency}
Determines whether or not the region hook should change
the default currency. The region files should provide a command
called \gls{datatoolRegionSetCurrency} which checks this boolean
value before setting the default currency.

\begin{important}
Note that if the region hook has already set the default currency,
this option won't undo that. It can only prevent the change the next
time the hook is used (for example, when the document language
changes).
\end{important}

\optiondef{numeric.currency-symbol-style}
This option simply redefines \gls{DTLcurrCodeOrSymOrChar} to expand
to its first argument (\optfmt{iso}) or second argument
(\optfmt{symbol}) or third argument (\optfmt{string}).

\optiondef{numeric.set-currency}
Essentially this is like doing:
\begin{compactcodebox}
\gls{DTLsetdefaultcurrency}\margm{currency-code}
\gls{DTLsetup}\marg{\numericoptval{region-currency}{false}}
\end{compactcodebox}
However, unlike \gls{DTLsetdefaultcurrency} the value \meta{currency-code}
must be a defined currency code.

\optiondef{numeric.region-currency-prefix}
Redefines \gls{datatoolcurrencysymbolprefixfmt}. Allows values are:
\optfmt{normal} (redefines to expand to its argument),
\optfmt{smallcaps} (redefines to expand to use \gls{textsc} with
the argument converted to lowercase), or \optfmt{smaller} (redefines
to use \gls{textsmaller}, which will require the \sty{relsize}
package).

\subsection{Parsing Locale-Formatted Numbers and Currency Values}
\label{sec:parsefmtnum}

\Idxpl{formattednumber} can be parsed provided the appropriate
\idx{numbergroupchar} and \idx{decimalchar} have been set with
\gls{DTLsetnumberchars} and the \idx{currencysym} has been declared
with \gls{DTLdefcurrency} (typically by loading a region file
via \opt{locales} or the document language support).  If you want to format a
\idx{plainnumber}, you can use \gls{DTLdecimaltolocale} or
\gls{DTLdecimaltocurrency}, described in
\sectionref{sec:localisation}, or use \sty{siunitx}.

\cmddef{DTLconverttodecimal}
Converts a \idx{formattednumber} \meta{num} to a \idx{plainnumber} and stores
the result in \meta{cs}. The \meta{num} argument may be a command
whose definition is a \idx{formattednumber}. A full \idx{expansion}
is not used on \meta{num} to allow for non-robust currency symbols.

\begin{information}
\gls{DTLconverttodecimal} is internally used by commands like
\gls{DTLadd} to obtain the numerical value. The result is then
converted back to a \idx{formattednumber} using either
\gls{DTLdecimaltolocale} or \gls{DTLdecimaltocurrency}, depending on
the data type of the supplied arguments.
The result is a \idx{datumcs} to reduce the need for re-parsing.
\end{information}

A warning is issued if the data type is a string rather
than a numeric value and the value will be treated as zero. 
An empty \meta{num} is also treated as zero.
No trimming is performed on \meta{num}.

For example:
\begin{codebox}
\gls{DTLconverttodecimal}\marg{\gls{cs.dollar}1,234.50}\marg{\cmd{myNum}}
\end{codebox}
This will define \cmd{myName} to expand to \code{1234.50} (assuming
the default \idx{numbergroupchar} and \idx{decimalchar}).
Again, the result is a \idx{datumcs} to reduce the need for re-parsing.

\subsection{Datum Commands}
\label{sec:datumcs}

\glsstartrange{datumcs,datumitem}%
Instead of repeatedly parsing the same content, you may prefer to parse it once
and store the information for later use. This can be done with the following
command:
\cmddef{DTLparse}
This parses \meta{content} (without \idx{expansion}) to determine its data
type and (if numerical) its value.
\cmddef{DTLxparse}
As \gls{DTLparse} but fully expands \meta{content} before parsing.

In both cases, the parsed data is stored in the control sequence
\meta{cs} (a \idx{datumcs}) in a form that includes the original
value (or expanded value in the case of \gls{DTLxparse}), the data
type, the numerical value (if one of the numerical types), and the
currency symbol (if applicable).

The \qt{string value}, which is the content that \meta{cs} will
expand to, may be automatically reformatted if an applicable setting is
in effect (such as \optvalm{numeric}{\numericopt{auto-reformat}}).

\begin{important}
This means that the numerical value is still available even if the 
\idx{numbergroupchar} and \idx{decimalchar} are later changed. The
important thing is to ensure that they are correct before parsing
the data.
\end{important}

The \idx{datumitem} format is particularly useful with databases
(see \sectionref{sec:databases}) that
have numeric data which needs to be converted into
\idxpl{plainnumber} for arithmetic computations (such as aggregates)
or plotting. If \optfmt{store-datum} is enabled before creating the
database, each value will be stored as a \idx{datumitem}. If you
then assign a placeholder command to the value,
for example with \gls+{DTLmapgetvalues}, then that command will be a
\idx{datumcs} in the same format as that obtained with
\gls{DTLparse}.

The component parts can then be extracted using the following
\idx{expandable} commands, where \meta{cs} is the \idx{datumcs}.
\cmddef{DTLusedatum}
Expands to the original value \meta{content} that was parsed (or the expanded value
in the case of \gls{DTLxparse}, or the reformatted string value, if
the applicable option was in effect). You can also simply use the
\idx{datumcs}. The difference is that \gls{DTLusedatum} can fully
\idxc{expansion}{expand} the datum value whereas using the \idx{datumcs}
directly won't.
If \meta{cs} is \gls{dtlnovalue}, then
\code{\gls{DTLusedatum}\margm{cs}} will expand to \gls{dtlnovalue}.

\cmddef{DTLdatumvalue}
Expands to the numeric value (as a \idx{plainnumber}) if the
parsed value was numerical, otherwise expands to empty.
If \meta{cs} is \gls{dtlnovalue}, then \code{\gls{DTLdatumvalue}\margm{cs}} will 
expand to \gls{DTLnumbernull}.

\cmddef{DTLdatumcurrency}
Expands to the \idx{currencysym} if the parsed value was a currency, 
otherwise expands to empty.
If \meta{cs} is \gls{dtlnovalue}, then
\code{\gls{DTLdatumcurrency}\margm{cs}} will expand to \gls{dtlnovalue}.

\cmddef{DTLdatumtype}
Expands to an integer representing the data type: \code{0} (string),
\code{1} (integer), \code{2} (decimal), \code{3} (currency),
\code{4} (timestamp), \code{5} (date), \code{6} (time) or
\code{-1} (unknown). If \meta{cs} is \gls{dtlnovalue}, 
then \code{\gls{DTLdatumtype}\margm{cs}} 
will expand to the unknown data type value.

For example:
\begin{codebox}
\gls{DTLparse}\cmd{mydatum}\marg{1,234.0}
Data type: \gls{DTLdatumtype}\marg{\cmd{mydatum}}.
\end{codebox}

Note that the data type is actually stored as a
\LaTeX3 integer constant, but \gls{DTLdatumtype} will convert
the constant value to an integer denotation. 
If you want the actual constant, use:
\begin{codebox}
\cmd{exp\_args:NV} \gls{datatooldatumtype:Nnnnn} \meta{cs}
\end{codebox}
but there's no check for \gls{dtlnovalue} in this case.

For debugging purposes, you may find it easier to have a textual
representation of the data type so that you don't have to lookup
what the numeric value represents. You can do this with:
\cmddef{DTLgetDataTypeName}
This will expand to one of:
\inlineglsdef{DTLdatatypeunsetname},
\inlineglsdef{DTLdatatypestringname},
\inlineglsdef{DTLdatatypeintegername},
\inlineglsdef{DTLdatatypedecimalname},
\inlineglsdef{DTLdatatypecurrencyname},
\inlineglsdef{DTLdatatypedatetimename},
\inlineglsdef{DTLdatatypedatename},
\inlineglsdef{DTLdatatypetimename}, or
\inlineglsdef{DTLdatatypeinvalidname}.

You may also \qt{show} the component parts in the console and
transcript:
\cmddef{datatooldatumshow:N}

Instead of parsing an existing value, you can define a new
\idx{datumcs} using one of the commands below. Only
\gls{DTLsetfpdatum} performs any parsing.

\cmddef{DTLsetintegerdatum}
Defines the control sequence \meta{cs} as an integer datum, where
\meta{formatted value} is the formatted integer and \meta{value} is
the integer value as a \idx{plainnumber}.

\cmddef{DTLxsetintegerdatum}
As \gls{DTLsetintegerdatum} but expands \meta{formatted value} and
\meta{value}.

\cmddef{DTLsetdecimaldatum}
Defines the control sequence \meta{cs} as a decimal datum, where
\meta{formatted value} is the formatted decimal and \meta{value} is
the decimal value as a \idx{plainnumber}.

\cmddef{DTLxsetdecimaldatum}
As \gls{DTLsetdecimaldatum} but expands \meta{formatted value} and
\meta{value}.

\cmddef{DTLsetfpdatum}
Similar to \gls{DTLsetdecimaldatum} but this will expand and parse
\meta{value} and store it with the \gls{datatooldatumfp:nnn} markup.

\cmddef{DTLsetcurrencydatum}
Defines the control sequence \meta{cs} as a currency datum, where
\meta{formatted value} is the formatted currency and \meta{value} is
the currency value as a \idx{plainnumber}. This has an extra
argument which is the currency symbol.

\cmddef{DTLxsetcurrencydatum}
As \gls{DTLsetcurrencydatum} but expands \meta{formatted value},
\meta{value} and \meta{currency symbol}.

\cmddef{DTLsetstringdatum}
Defines the control sequence \meta{cs} as a string datum.

\cmddef{DTLxsetstringdatum}
As \gls{DTLsetstringdatum} but expands \meta{string}.

\Idxpl{datumcs} may be used in commands that expect a
\idx{formattednumber}, such as \gls{DTLadd}, as demonstrated in
\mexampleref{ex:datumcs}, which is produced with the code below.

\begin{codebox*}
\cmd{usepackage}\marg{datatool-base}
\cmd{usepackage}\marg{siunitx}
\gls{DTLparse}\marg{\cmd{numA}}\marg{23,452}
\gls{DTLparse}\marg{\cmd{numB}}\marg{45.0}
\gls{DTLparse}\marg{\cmd{numC}}\marg{\gls{pounds} 24.50}
\gls{DTLsetfpdatum}\marg{\cmd{numD}}\marg{\gls{num}\marg{1.5e-4}}\marg{1.5e-4}
\cbeg{document}
Original value: \gls{DTLusedatum}\marg{\cmd{numC}} or \cmd{numC}.
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{numC}}.
Currency: \gls{DTLdatumcurrency}\marg{\cmd{numC}}.
Data type: \gls{number}\gls{DTLdatumtype}\marg{\cmd{numC}}.
\codepar
\gls{DTLadd}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}
\$\cmd{numA} + \cmd{numB} = \cmd{result}\$
\codepar
\gls{DTLaddall}\marg{\cmd{result}}\marg{\cmd{numA},\cmd{numB},\cmd{numC}}
\$\cmd{numA} + \cmd{numB} + \cmd{numC} = \cmd{result}\$
\codepar
\gls{dtladd}\marg{\cmd{result}}\marg{\gls{DTLdatumvalue}\marg{\cmd{numA}}}\marg{\gls{DTLdatumvalue}\marg{\cmd{numB}}}
\$\gls{DTLdatumvalue}\marg{\cmd{numA}} + \gls{DTLdatumvalue}\marg{\cmd{numB}} = \cmd{result}\$
\codepar
\gls{dtladdall}\marg{\cmd{result}}
\marg{\gls{DTLdatumvalue}\marg{\cmd{numA}},\gls{DTLdatumvalue}\marg{\cmd{numB}},\gls{DTLdatumvalue}\marg{\cmd{numC}}}
\$\gls{DTLdatumvalue}\marg{\cmd{numA}} + \gls{DTLdatumvalue}\marg{\cmd{numB}}
 + \gls{DTLdatumvalue}\marg{\cmd{numC}} = \cmd{result}\$
\codepar
\gls{DTLxsetdecimaldatum}\marg{\cmd{total}}\marg{\gls{num}\marg{\cmd{result}}}\marg{\cmd{result}}
Total: \cmd{total}.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{20}\marg{\gls{DTLdatumvalue}\marg{\cmd{numD}}}
\$20 \cmd{times} \cmd{numD} = \cmd{result}\$
\codepar
\cend{document}
\end{codebox*}
\begin{resultbox}
\createexample*[label={ex:datumcs},
 title={Datum Control Sequences},
 description={Example document that demonstrates parsing data and
 storing the content in datum control sequences}]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLparse}\marg{\cmd{numA}}\marg{23,452}\nl
\gls{DTLparse}\marg{\cmd{numB}}\marg{45.0}\nl
\gls{DTLparse}\marg{\cmd{numC}}\marg{\gls{pounds} 24.50}\nl
\gls{DTLsetfpdatum}\marg{\cmd{numD}}\marg{\gls{num}\marg{1.5e-4}}\marg{1.5e-4}
}%
{%
Original value: \gls{DTLusedatum}\marg{\cmd{numC}} or \cmd{numC}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{numC}}.\nl
Currency: \gls{DTLdatumcurrency}\marg{\cmd{numC}}.\nl
Data type: \gls{number}\gls{DTLdatumtype}\marg{\cmd{numC}}.
\codepar
\gls{DTLadd}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} + \cmd{numB} = \cmd{result}\$
\codepar
\gls{DTLaddall}\marg{\cmd{result}}\marg{\cmd{numA},\cmd{numB},\cmd{numC}}\nl
\$\cmd{numA} + \cmd{numB} + \cmd{numC} = \cmd{result}\$
\codepar
\gls{dtladd}\marg{\cmd{result}}\marg{\gls{DTLdatumvalue}\marg{\cmd{numA}}}\marg{\gls{DTLdatumvalue}\marg{\cmd{numB}}}\nl
\$\gls{DTLdatumvalue}\marg{\cmd{numA}} + \gls{DTLdatumvalue}\marg{\cmd{numB}}
= \cmd{result}\$
\codepar
\gls{dtladdall}\marg{\cmd{result}}\marg{\gls{DTLdatumvalue}\marg{\cmd{numA}},\gls{DTLdatumvalue}\marg{\cmd{numB}},\gls{DTLdatumvalue}\marg{\cmd{numC}}}\nl
\$\gls{DTLdatumvalue}\marg{\cmd{numA}} + \gls{DTLdatumvalue}\marg{\cmd{numB}} + \gls{DTLdatumvalue}\marg{\cmd{numC}}
= \cmd{result}\$
\codepar
\gls{DTLxsetdecimaldatum}\marg{\cmd{total}}\marg{\gls{num}\marg{\cmd{result}}}\marg{\cmd{result}}\nl
Total: \cmd{total}.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{20}\marg{\gls{DTLdatumvalue}\marg{\cmd{numD}}}\nl
\$20 \cmd{times} \cmd{numD} = \cmd{result}\$
}
\end{resultbox}

\subsection{Datum Items (Advanced)}
\label{sec:datumitems}

If you have the \idx{expansion} text from a \idx{datumcs} (a
\idx{datumitem}), that text will be in the form:
\begin{compactcodebox}
\meta{marker-cs}\margm{string}\margm{value}\margm{currency}\margm{type}
\end{compactcodebox}

Decimals may have the \meta{value} part stored as:
\cmddef{datatooldatumfp:nnn}
With \optval{math}{fp} this expands to \meta{decimal} (since the
\sty{fp} package can't parse scientific notation) otherwise this
expands to \meta{fp-value} (the original value if supplied in
scientific notation or the \idx{plainnumber} obtained from parsing
a locale decimal). The \meta{fp-var-content} argument allows an \styfmt{l3fp}
variable to be reconstructed (with \gls{datatoolsetfp:Nn}) without 
having to reparse the value.

Temporal data types may have the \meta{value} part stored as:
\cmddef{DTLtemporalvalue}
This allows the date/time stamp to be retained. This simply expands
to the first argument by default, which is the numeric value
associated with the data. In the case of date (without time), the
value is an integer Julian day; in the case of a timestamp (date and
time), the value is a decimal Julian date; in the case of time
(without a date), the value is the fractional part of the Julian
date.

The date/time stamp can be extracted with:
\cmddef{datatoolextracttimestamp:NN}
where \meta{result-tl-var} is the token list variable in which to
store the date/time stamp and \meta{datum-cs} is the \idx{datumcs}.
This works by locally redefining \gls{DTLtemporalvalue} and then
expanding \code{\gls{DTLtemporalvalue}\margm{value}}. If the
\meta{value} part in \meta{datum-cs} is just a number and not
encapsulated within \gls{DTLtemporalvalue} then this trick won't
work and the number will need to be converted back.
The result will be empty if there is no date/time information.

To allow for new data types introduced in a later version, you can
check for the current maximum allowed value with:
\cmddef{datatoolmaxknowntype:}
This will expand to the appropriate constant.

\cmddef{datatoolifvaliddatumtype:n}
Tests if the argument \meta{n} represents a valid data type
(including unknown).

\cmddef{datatoolifnumericdatumtype:n}
Tests if the argument \meta{n} represents a numeric data type.
Note that temporal data types are considered numeric.

\cmddef{datatooliftemporaldatumtype:n}
Tests if the argument \meta{n} represents a temporal data type.

\cmddef{datatoolifnumberonlydatumtype:n}
Tests if the argument \meta{n} represents an integer or decimal data type
(not currency or temporal).

\cmddef{datatoolifanyintdatumtype:n}
Tests if the argument \meta{n} represents data type that has an
integer value (integer or date, but not decimal or currency or
timestamps or times).

\subsubsection{Datum Components}
\label{sec:datumcomponents}

It's possible to pick out the desired component using an
\meta{n} of \meta{m} style of command. However, the following
commands are provided as it's more obvious from the command name
which element is required. Note that these require \LaTeX3 syntax
enabled:
\cmddef{datatooldatumstring:Nnnnn}
Expands to \meta{string}.

\cmddef{datatooldatumvalue:Nnnnn}
Expands to \meta{value}.

\cmddef{datatooldatumcurrency:Nnnnn}
Expands to \meta{currency}.

\cmddef{datatooldatumtype:Nnnnn}
Expands to \meta{type}.

\subsubsection{Datum Tests for Equality}
\label{sec:datumifeq}

If you want to test if a \idx{datumcs} is equal to a string, then
you can't simply use \csfmt{tl\_if\_eq:NnTF} or \gls{ifdefstring} as
the datum markup will prevent a match. Commands such as
\gls{DTLifstringeq} expand the arguments which will remove the datum
markup, but the following commands take the data type into account.

If both arguments have a numeric type then they will be compared
numerically and by the currency symbol. If both are ordinary token
lists without the datum markup then they will be compared using a
normal token list comparison. If one has the datum format and the
other doesn't, then a string comparison is used.

\cmddef{datatoolifvalueeq:NN}
Compares two variables where one or other may be a \idx{datumcs} or
simply a token list variable.

\cmddef{datatoolifvalueeq:Nn}
Test for equality where the variable \meta{tl var} may be a \idx{datumcs} and the
token list \meta{tl} may be a \idx{datumitem}.

\cmddef{datatoolifvalueeq:nN}
Test for equality where the token list \meta{tl} may be a
\idx{datumitem} and the variable \meta{tl var} may be a
\idx{datumcs}.

\cmddef{datatoolifvalueeq:nn}
Compares two token lists where one or other may be a \idx{datumitem}.

\mExampleref{ex:datumifeq} demonstrates the above commands. First some
\idxpl{datumcs} are defined:
\begin{codebox}
\gls{DTLparse}\marg{\cmd{Fruit}}\marg{Pear}
\gls{DTLparse}\marg{\cmd{Price}}\marg{\gls{cs.dollar}1.50}
\gls{DTLparse}\marg{\cmd{Quantity}}\marg{10}
\end{codebox}
The following \csfmt{OtherPrice} is numerically equivalent to \csfmt{Price} 
and has the same currency symbol but the string representation is different:
\begin{codebox}
\gls{DTLsetcurrencydatum}\marg{\cmd{OtherPrice}}\marg{1 dollar 50\cmd{textcent}}\marg{1.5}\marg{\gls{cs.dollar}}
\end{codebox}
Similarly, the following \csfmt{OtherQuantity} has the same
numerical value as \csfmt{Quantity} but it's a decimal instead of an
integer:
\begin{codebox}
\gls{DTLsetdecimaldatum}\marg{\cmd{OtherQuantity}}\marg{10.00}\marg{10.0}
\end{codebox}
For convenience a command is provided for the tests:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{test}}[3]\marg{\#1=\#2 (\cmd{texttt}\marg{\cmd{string}\#3}) ?
  \#3\marg{\#1}\marg{\#2}\marg{true}\marg{false}.\cmd{par}}
\end{codebox}
The actual tests need to have \LaTeX3 syntax enabled:
\begin{codebox}
\gls{ExplSyntaxOn}
\end{codebox}
First are the string tests:
\begin{codebox}
\cmd{test} \cmd{Fruit} \marg{Pear} \cmd{tl\_if\_eq:NnTF}
\cmd{test} \cmd{Fruit} \marg{Pear} \cmd{tl\_if\_eq:enTF}
\cmd{test} \cmd{Fruit} \marg{Pear} \gls{datatoolifvalueeq:Nn}
\end{codebox}
The next set may appear to be numeric tests but they are still string
tests because they are being compared with a non-datum token list.
\begin{codebox}
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.50} \cmd{tl\_if\_eq:NnTF}
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.50} \cmd{tl\_if\_eq:enTF}
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.50} \gls{datatoolifvalueeq:Nn}
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.5} \gls{datatoolifvalueeq:Nn}
\end{codebox}
For an actual numeric test, both arguments must use the datum
format. Note that \csfmt{Price} and \csfmt{OtherPrice} are
numerically equivalent but when viewed as token list variables, they
don't have the same content.
\begin{codebox}
\cmd{test} \cmd{Price} \cmd{OtherPrice} \cmd{tl\_if\_eq:NNTF}
\cmd{test} \cmd{Price} \cmd{OtherPrice} \gls{datatoolifvalueeq:NN}
\end{codebox}
There are similar tests for the quantity:
\begin{codebox}
\cmd{test} \cmd{Quantity} \marg{10} \cmd{tl\_if\_eq:NnTF}
\cmd{test} \cmd{Quantity} \marg{10} \cmd{tl\_if\_eq:enTF}
\cmd{test} \cmd{Quantity} \marg{10} \gls{datatoolifvalueeq:Nn}
\cmd{test} \cmd{Quantity} \marg{10.00} \gls{datatoolifvalueeq:Nn}
\cmd{test} \cmd{Quantity} \cmd{OtherQuantity} \cmd{tl\_if\_eq:NNTF}
\cmd{test} \cmd{Quantity} \cmd{OtherQuantity} \gls{datatoolifvalueeq:NN}
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:datumifeq},
 title={Datum Tests for Equality},
 description={Example document that demonstrates equality tests with
datum markup}]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\gls{DTLparse}\marg{\cmd{Fruit}}\marg{Pear}\nl
\gls{DTLparse}\marg{\cmd{Price}}\marg{\gls{cs.dollar}1.50}\nl
\gls{DTLparse}\marg{\cmd{Quantity}}\marg{10}\nl
\gls{DTLsetcurrencydatum}\marg{\cmd{OtherPrice}}\marg{1 dollar 50\cmd{textcent}}\marg{1.5}\marg{\gls{cs.dollar}}\nl
\gls{DTLsetdecimaldatum}\marg{\cmd{OtherQuantity}}\marg{10.00}\marg{10.0}\nl
\cmd{newcommand}\marg{\cmd{test}}[3]\marg{\#1=\#2 (\cmd{texttt}\marg{\cmd{string}\#3}) ? \#3\marg{\#1}\marg{\#2}\marg{true}\marg{false}.\cmd{par}}
}
{%
\gls{ExplSyntaxOn}\nl
\cmd{test} \cmd{Fruit} \marg{Pear} \cmd{tl\_if\_eq:NnTF}\nl
\cmd{test} \cmd{Fruit} \marg{Pear} \cmd{tl\_if\_eq:enTF}\nl
\cmd{test} \cmd{Fruit} \marg{Pear} \gls{datatoolifvalueeq:Nn}
\codepar
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.50} \cmd{tl\_if\_eq:NnTF}\nl
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.50} \cmd{tl\_if\_eq:enTF}\nl
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.50} \gls{datatoolifvalueeq:Nn}\nl
\cmd{test} \cmd{Price} \marg{\gls{cs.dollar}1.5} \gls{datatoolifvalueeq:Nn}\nl
\cmd{test} \cmd{Price} \cmd{OtherPrice} \cmd{tl\_if\_eq:NNTF}\nl
\cmd{test} \cmd{Price} \cmd{OtherPrice} \gls{datatoolifvalueeq:NN}
\codepar
\cmd{test} \cmd{Quantity} \marg{10} \cmd{tl\_if\_eq:NnTF}\nl
\cmd{test} \cmd{Quantity} \marg{10} \cmd{tl\_if\_eq:enTF}\nl
\cmd{test} \cmd{Quantity} \marg{10} \gls{datatoolifvalueeq:Nn}\nl
\cmd{test} \cmd{Quantity} \marg{10.00} \gls{datatoolifvalueeq:Nn}\nl
\cmd{test} \cmd{Quantity} \cmd{OtherQuantity} \cmd{tl\_if\_eq:NNTF}\nl
\cmd{test} \cmd{Quantity} \cmd{OtherQuantity} \gls{datatoolifvalueeq:NN}\nl
\gls{ExplSyntaxOff}
}
\end{resultbox}

\subsubsection{Conversion to Floating Point}
\label{sec:datumfp}

If you need to set an \styfmt{l3fp} variable to a value that may be
a \idx{datumcs} or \idx{datumitem} or may not yet be parsed, you can
use:
\cmddef{datatoolsetfp:Nn}
This sets the floating point variable \meta{fp-var} to the floating
point number obtained from the given \meta{value}. If the
\meta{value} is either a \idx{datumcs} or \idx{datumitem}
then no parsing is required. If not, the \meta{value} will be
expanded and then parsed to obtain its numeric value before setting 
the variable. (Be aware that this may cause non-robust currency symbols to
expand so that they are no longer recognised as a currency symbol.)
If \meta{value} is determined to have a string or unknown data type
the variable will be set to zero.

\mExampleref{ex:datumfp} performs floating point calculations on 
a \idx{formattednumber} (which needs to be parsed according to the current settings)
and a value provided in scientific notation (with a formatted representation 
using \sty{siunitx}).
\begin{codebox*}
\cmd{usepackage}\marg{datatool-base}
\cmd{usepackage}\marg{siunitx}
\gls{DTLparse}\marg{\cmd{numA}}\marg{1,500.0}
\gls{DTLsetfpdatum}\marg{\cmd{numB}}\marg{\gls{num}\marg{1.5e-4}}\marg{1.5e-4}
\cbeg{document}
A = \cmd{numA} \cmd{space} (value: \gls{DTLdatumvalue}\cmd{numA}).
B = \cmd{numB} \cmd{space} (value: \gls{DTLdatumvalue}\cmd{numB}).
\codepar
\gls{ExplSyntaxOn}
\gls{datatoolsetfp:Nn} \cmd{l\_tmpa\_fp} \marg{ \cmd{numA} }
\gls{datatoolsetfp:Nn} \cmd{l\_tmpb\_fp} \marg{ \cmd{numB} }
\cmd{fp\_to\_tl:N} \cmd{l\_tmpa\_fp} \cmd{c\_space\_tl}
 \cmd{texttimes} \cmd{c\_space\_tl}
\cmd{fp\_to\_tl:N} \cmd{l\_tmpb\_fp} \cmd{c\_space\_tl} = \cmd{c\_space\_tl}
\cmd{fp\_eval:n} \marg{ \cmd{l\_tmpa\_fp} * \cmd{l\_tmpb\_fp} }
\gls{ExplSyntaxOff}
\cend{document}
\end{codebox*}
\begin{resultbox}
\createexample*[label={ex:datumfp},
 title={Datum Control Sequences to Floating Point Variables},
 description={Example document that demonstrates converting locale
formatted numbers to floating point variables}]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLparse}\marg{\cmd{numA}}\marg{1,500.0}\nl
\gls{DTLsetfpdatum}\marg{\cmd{numB}}\marg{\gls{num}\marg{1.5e-4}}\marg{1.5e-4}
}%
{%
A = \cmd{numA} \cmd{space} (value: \gls{DTLdatumvalue}\cmd{numA}).\nl
B = \cmd{numB} \cmd{space} (value: \gls{DTLdatumvalue}\cmd{numB}).
\codepar
\gls{ExplSyntaxOn}\nl
\gls{datatoolsetfp:Nn} \cmd{l\_tmpa\_fp} \marg{ \cmd{numA} }\nl
\gls{datatoolsetfp:Nn} \cmd{l\_tmpb\_fp} \marg{ \cmd{numB} }\nl
\cmd{fp\_to\_tl:N} \cmd{l\_tmpa\_fp} \cmd{c\_space\_tl} \cmd{texttimes} \cmd{c\_space\_tl}\nl
\cmd{fp\_to\_tl:N} \cmd{l\_tmpb\_fp} \cmd{c\_space\_tl} = \cmd{c\_space\_tl}\nl
\cmd{fp\_eval:n} \marg{ \cmd{l\_tmpa\_fp} * \cmd{l\_tmpb\_fp} }\nl
\gls{ExplSyntaxOff}
}
\end{resultbox}
\glsendrange{datumcs,datumitem}%

\section{Localisation}
\label{sec:localisation}

The \sty{datatool-base} package (v3.0+) loads the \sty{tracklang}
package, which attempts to determine the document localisation
settings.  No actual localisation is provided by \sty{tracklang},
but it enables support to be easily added and maintained
independently from a package (that uses the \sty{tracklang}
interface) with \ext+{ldf} files that have a particular naming
scheme.

This means that by adding a file
called \file{datatool-locale.ldf} to \TeX's path, the file can
automatically be loaded by \sty{datatool-base} without any
adjustments to the \sty{datatool-base} code.
There is a search order for \meta{locale} to allow for fine grained
support. See the \sty{tracklang} documentation for further details
or the \qt{Locale Sensitive Files} section of
\dickimawhref{latex/tracklang/otherpkg.shtml}{Using
\styfmt{tracklang} in Packages with Localisation Features}.

The \sty{tracklang} package has limitations, but you may be
able to supply the language identifier as a document class
option, for example:
\begin{codebox}
\cmd{documentclass}\oarg{british}\marg{article}
\end{codebox}
or load \sty{babel}\slash\sty{polyglossia} and setup language
support before the first package to load \sty{tracklang}, for example:
\begin{codebox}
\cmd{usepackage}\oarg{british}\marg{babel}
\cmd{usepackage}\marg{datatool-base}
\end{codebox}
or use \sty{datatool-base}['s] \opt{locales} (or \opt{lang}) option, for example:
\begin{codebox}
\cmd{usepackage}\oarg{\optval{locales}{en-GB}}\marg{datatool-base}
\end{codebox}
If you use \gls{babelprovide}, ensure that you have at least
version 1.6.4 of \sty{tracklang} and load \sty{tracklang} after all
instances of \gls{babelprovide}. There's no support for
\qt{lazy loading} in the document environment.

Note that this option will have an effect on packages that are
subsequently loaded that also use \sty{tracklang}.
Likewise, if you have already loaded a package that uses
\sty{tracklang} (such as \sty{datetime2}) then the tracked locales 
from that will be picked up.
For example:
\begin{codebox}
\cmd{usepackage}[en-GB]\marg{datetime2}
\cmd{usepackage}\marg{datatool-base}
\end{codebox}
See the \sty{tracklang} documentation or
\dickimawhref{latex/tracklang}{Localisation with
\filefmt{tracklang.tex}} for further details.

\begin{information}
If \sty{tracklang} doesn't recognise the language identifier, 
the root language will be \qt{undetermined} (with code \qt{und}) and so the file
\ldf{undetermined} (provided with \sty{datatool}) will be loaded.
\end{information}

For some packages (such as \sty{databib} and \sty{person}), the
localisation support just relates to translating fixed text and the
corresponding filename may simply have \meta{locale} as the
\sty{tracklang} root language label. So regardless of whether you
have used \optval{locales}{en-GB} or \optval{locales}{en-US}, the
\sty{person} package will require the file 
\filefmt{person\dhyphen english.ldf} (provided with
\sty{datatool-english}).

However, settings such as the currency symbol are specific to a
region not a language. So \optval{locales}{en-GB} would need the
default currency switched to GBP whereas \optval{locales}{en-IE} would
need the default currency switched to EUR and \optval{locales}{en-ZA}
would need the default currency switched to ZAR.

Therefore, localisation support for \sty{datatool-base} (and its
supplementary packages) is split into two parts: the language file
\metafilefmt{datatool-}{language}{.ldf} (for example, \ldf{english})
which deals with the orthography, translations of fixed text, and
other language-specific code, and the region file
\metafilefmt{datatool-}{region}{.ldf} (for example, \ldf{GB}) which
deals with language-independent region code. You will need both
files for full support but partial support can be obtained if one is
missing.

The region files are fairly straightforward (albeit time-consuming)
to create. They are therefore all bundled together in a single
distribution \sty{datatool-regions} which needs to be installed in addition to
installing \sty{datatool}. See \sectionref{sec:addregion} for
further details.

Locale-sensitive commands that relate to regions may all be reset back to their
original definitions with:
\cmddef{DTLresetRegion}
Note that this will clear \gls{ldatatoolcurrentregiontl} and reset
the current \idx{numbergroupchar} and \idx{decimalchar} and currency
in addition to redefining commands such as
\gls{DTLCurrentLocaleCurrencyDP}.

The language files are more complicated and require knowledge of
someone familiar with the language. Each language bundle should
therefore be developed independently by a maintainer fluent in the
language and it will need to be installed in addition to installing
\sty{datatool}. At the time of writing, only \sty{datatool-english} is
available, but you can copy and adapt it as appropriate. 
(Don't add me as author or maintainer of your contribution.)
The \sty{datatool-english} bundle includes limited support for
Old English (Anglo-Saxon) for Latin and Runic scripts, which may be
used as examples for extended Latin or non-Latin languages.
See \sectionref{sec:addlang} for further details.

Locale-sensitive commands that relate to language may all be reset back to their
original definitions with:
\cmddef{DTLresetLanguage}
Note that this clears \gls{ldatatoolcurrentlanguagetl}
in addition to redefining commands such as
\gls{DTLandname}, but only for the \sty{datatool-base} set of
commands. Additional commands provided for the supplementary
packages are not affected.

\mExampleref{ex:enCA} assumes that \sty{datatool-regions} and 
\sty{datatool-english} are both installed.
\begin{codebox}
\cmd{usepackage}[\optval{locales}{en-CA}]\marg{datatool-base}
\cbeg{document}
Default currency: \gls{DTLCurrencyCode}.
\codepar
\cmd{newcommand}\marg{\cmd{mylist}}\marg{elk,élite,elephant}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\cend{document}
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:enCA},
 title={Localisation Support (en-CA)},
 description={Example document demonstrating support for en-CA
region (datatool-regions and datatool-english must be installed as well)}
]
{%
\cmd{usepackage}[\optval{locales}{en-CA}]\marg{datatool-base}
}
{%
Default currency: \gls{DTLCurrencyCode}.
\codepar
\cmd{newcommand}\marg{\cmd{mylist}}\marg{elk,élite,elephant}\nl
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}\nl
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}
The above example shows the default currency code \qt{CAD}, which
has been set by \ldf{CA}. The sorted list has \qt{élite} between
\qt{elephant} and \qt{elk} because \ldf{english} has enabled support
for common \idx{utf8} characters so that \qt{é} is treated as \qt{e}
for sorting purposes.

\examplemarginref{ex:frCA}%
Suppose now that you have \sty{datatool-regions}  
installed but no French support. However your document language is French Canadian
(fr-CA):
\begin{codebox}
\cmd{usepackage}\marg{babel}
\gls{babelprovide}\marg{canadianfrench}
\cmd{usepackage}\marg{datatool-base}
\cbeg{document}
Default currency: \gls{DTLCurrencyCode}.
\codepar
\cmd{newcommand}\marg{\cmd{mylist}}\marg{elk,élite,elephant}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\cend{document}
\end{codebox}
In this case, the \ldf{CA} file is found, so the default currency
code is still CAD but no file is found to provide support for the
sorting handler so the extended Latin character \qt{é} is placed after
the Basic Latin characters.
\begin{resultbox}
\createexample*[label={ex:frCA},
 title={Localisation Support (fr-CA)},
 description={Example document demonstrating support for fr-CA
region (datatool localisation files must be installed as well)}
]
{%
\cmd{usepackage}\oarg{T1}\marg{fontenc}\nl
\cmd{usepackage}\marg{babel}\nl
\gls{babelprovide}\marg{canadianfrench}\nl
\cmd{usepackage}\marg{datatool-base}
}
{%
Default currency: \gls{DTLCurrencyCode}.
\codepar
\cmd{newcommand}\marg{\cmd{mylist}}\marg{elk,élite,elephant}\nl
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}\nl
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

Localisation files may provide options. These are define with:
\cmd{datatoollocaledefinekeys:nn}
This is simply a shortcut that uses \csfmt{keys\_define:nn}. The
\meta{module} should be the applicable language code (for example,
\qt{en}) or region code (for example, \qt{GB}) or tag (for example,
\qt{en-CA} or \qt{fr-CA}), depending on what kind of support the
file provides. Sub-modules may also be specified.

These options can be set in the document with:
\cmddef{DTLsetLocaleOptions}
If the optional argument is provided, this iterates over each locale parent module 
and sets the given options for each sub-module identified by
\code{\meta{parent}\slash\meta{module}}.
If the optional argument is omitted or empty, this iterates over
each locale module and sets the given options. 

For example, with \ldf{GB} the parent module is \qt{GB} and there
are no sub-modules. To switch number style:
\begin{codebox}
\gls{DTLsetLocaleOptions}\marg{GB}\marg{number-style=education}
\end{codebox}
Another example, both \ldf{GB} and \ldf{CA} support a currency
symbol prefix so the setting can be switched on for both at the same
time:
\begin{codebox}
\gls{DTLsetLocaleOptions}\marg{CA,GB}\marg{currency-symbol-prefix}
\end{codebox}

The \file{databib-english.ldf} has parent module \qt{en} and
sub-module \qt{databib}. To switch the way month names are
abbreviated for the \optfmt{abbrv} style:
\begin{codebox}
\gls{DTLsetLocaleOptions}\oarg{en}\marg{databib}\marg{short-month-style=dotless}
\end{codebox}
Or:
\begin{codebox}
\gls{DTLsetLocaleOptions}\marg{en/databib}\marg{short-month-style=dotless}
\end{codebox}

The unstarred form uses:
\cmd{datatoolsetlocaleoptions:nn}
This iterates over each module and sets the provided options using
\csfmt{keys\dsb set:nn}, which will trigger an error 
for unknown options.

The starred form uses:
\cmd{datatoolsetlocaleoptions:nn}
This iterates over each module and sets the provided options using
\csfmt{keys\dsb set\dsb known:nn}, which won't trigger an error 
for unknown options.

If you want to directly use the \styfmt{l3keys} functions, the
module path should be prefixed with \qtt{datatool / locale~/}.

\subsection{Encoding}
\label{sec:encoding}

In recent years, the \LaTeX\ kernel has provided significant
improvements to \idx{utf8} support for \pdfLaTeX. (The newer
engines, \XeLaTeX\ and \LuaLaTeX\ are natively \idx{utf8}.)
In particular, even if you don't load \sty{inputenc}, the document
is now assumed to be \idx{utf8} (whereas in the past the default
\idx{encoding} was \idx{ascii}).

\begin{warning}
If \sty{inputenc} is required, it should be loaded
before \sty{datatool-base} (and \sty{tracklang}).
Non-\idx{utf8} documents may not be supported by the localisation
files. For example, the \meta{string} argument of
\gls{DTLdefcurrency} may not be correct.
\end{warning}

To assist localisation files, the \sty{datatool-base} package provides 
both a string (detokenized)
variable and corresponding token list variables that expand to common 
symbols (mostly currency) that are included in Unicode and may be of
use with localisation.
These variables are first defined to expand to an
approximate \idx{ascii} representation, but then will be
redefined if the relevant
\metafilefmt{datatool\dhyphen}{encoding}{.ldf} file is found.
This means that unsupported encodings will fallback
on \idx{ascii} values. There is limited support for ISO-8859-1
(cent, pound, currency and yen). 

For example, \ldf{GB} defines the GBP currency as follows:
\begin{compactcodebox*}
\expfunc{datatooldefcurrency:nnnn}{nnnV}
 \marg{ \gls{datatoolGBcurrencyfmt} }
 \marg{ GBP }
 \marg{ \gls{pounds} }
 \gls{ldatatoolpoundtl}
\end{compactcodebox*}
This means that the region \ext{ldf} file doesn't need to keep track 
of the encoding. (The language \ext{ldf} typically does.)

\symvardef{cent}
\symvardef{pound}
\symvardef{currency}
\symvardef{yen}
\symvardef{middot}
\symvardef{florin}
\symvardef{baht}
\symvardef{ecu}
\symvardef{colonsign}
\symvardef{cruzerio}
\symvardef{frenchfranc}
\symvardef{lira}
\symvardef{mill}
\symvardef{naira}
\symvardef{peseta}
\symvardef{rupee}
\symvardef{won}
\symvardef{shekel}
\symvardef{dong}
\symvardef{euro}
\symvardef{kip}
\symvardef{tugrik}
\symvardef{drachma}
\symvardef{germanpenny}
\symvardef{peso}
\symvardef{guarani}
\symvardef{austral}
\symvardef{hryvnia}
\symvardef{cedi}
\symvardef{livretournois}
\symvardef{spesmilo}
\symvardef{tenge}
\symvardef{indianrupee}
\symvardef{turkishlira}
\symvardef{nordicmark}
\symvardef{manat}
\symvardef{ruble}
\symvardef{lari}
\symvardef{bitcoin}
\symvardef{som}

If any of the currency symbols are available in the current
encoding, they will be added to the currency signs regular
expression variable:
\cmddef{ldatatoolcurrencysignsregex}
This may be used within the locale handler to match for supported
currency symbols.

\subsection{Numerical}
\label{sec:numerical}

Non locale-sensitive numeric commands (such as \gls{dtladd})
require \idxpl{plainnumber} with a period/full stop \idxn{decimalpoint}
and no \idx{numbergroupchar} or \idx{currencysym}.

Numeric commands for \idxpl{formattednumber} (such as \gls{DTLadd})
parse their values for the \idx{currencysym}, \idx{decimalchar} and
\idx{numbergroupchar}. The \idx{numbergroupchar} is only used in
integers and before the \idx{decimalchar} in decimal and currency
values.  The \idx{decimalchar} is only relevant to decimal numbers
and currency values.

\cmddef{DTLsetnumberchars}
Sets the current \idx{numbergroupchar} and \idx{decimalchar}. The
default values are \qtt{\idx{numbergroup}} (comma) and
\qtt{\idx{decimalpoint}} (full stop/period), although localisation
support may change this.

With \LaTeX3 syntax enabled, the following may be used instead.
\cmddef{datatoolsetnumberchars:nn}
As from version 3.0, \gls{DTLsetnumberchars} simply uses this
function to set the current \idx{numbergroupchar} and
\idx{decimalchar}.
\cmddef{datatoolsetnumberchars:nnnn}
Allows alternative content to be used when formatting, but be aware 
that repeated parsing and formatting will fail if the parsing and
formatting characters are different.

For more complex parsing requirements, regular expressions can be
provided to match the \idx{numbergroupchar} and
\idx{decimalchar} sub-groups:
\cmddef{datatoolsetnumbercharsregex:nnnn}
The final two arguments should be in a regular expression form.
These will be embedded into the main parsing regular expression with
\csfmt{ur}.
\cmddef{datatoolsetnumbercharsregextl:nnnn}
The third argument is a regular expression to match the
\idx{numbergroupchar} but the fourth is just the
\idx{decimalchar}.
\cmddef{datatoolsetnumbercharstlregex:nnnn}
The third is just the \idx{decimalchar} but 
the fourth argument is a regular expression to match the
\idx{decimalchar}.

The following are just shortcuts that use one of the above.
\cmddef{datatoolsetthinspacegroupdecimalchar:n}
A special case for thin space number group separators.
This command is similar to \gls{datatoolsetnumberchars:nn} but uses
\gls{cs.comma} (thin space) for the \idx{numbergroupchar} when
formatting, and allows \gls{cs.comma} or a normal space or the Unicode
character U+2009 (thin space) as the \idx{numbergroupchar} when
parsing. The \idx{decimalchar} for both formatting and parsing is
set to \meta{decimal char}.

\cmddef{datatoolsetunderscoregroupdecimalchar:n}
Similarly, but uses \gls{cs.underscore} for the \idx{numbergroupchar}
when formatting but accepts both \gls{cs.underscore} or
the underscore character when parsing.

\cmddef{datatoolsetaposgroupdecimalchar:n}
Similarly, but uses an apostrophe (') for the \idx{numbergroupchar}
when formatting but will match on:
\cmddef{cdatatoolapostropheregex}
when parsing. This matches either the straight apostrophe (U+27) or
the curly apostrophe (U+2019).

\cmddef{DTLsetdefaultcurrency}
Sets the default currency. If the argument is an ISO code, then the
currency must have first been defined with \gls{DTLdefcurrency}
(see \sectionref{sec:currency}). This commands also defines
\gls{DTLCurrencyCode} to \idxc{expansion}{expand} to the associated ISO code and
redefines \gls{DTLfmtcurrency} to match the formatting associated
with the currency.

\begin{information}
To allow for backward-compatibility, if the argument hasn't been
identified with \gls{DTLdefcurrency} then it's assumed to be just a
currency symbol and \gls{DTLCurrencyCode} will be defined to
\qt{XXX}. \gls{DTLfmtcurrency} won't be changed.
This form is now discouraged and may be deprecated in future.
\end{information}

The region file should register the currency code with:
\cmddef{datatoolregisterregionalcurrencycode:nn}
This makes it easier for the currency parser to check for currency
symbols that are prefixed by the region code (for example,
US\$ or GB\pounds). Note that this check is only performed if the
region file defines:
\cmddef{datatoolRegionsymbolprefix}
The prefix command allows the region code to be shown before the
currency symbol, if applicable. It may be used in the definition of
the currency formatting command.

\begin{information}
The naming of the \gls{datatoolRegionsymbolprefix} command is
important as the parser used by commands like \gls{DTLparse} will check for it 
and, if defined, will also check for currency symbols prefixed by
their region's code.
\end{information}

The prefix command may either expand to nothing or to:
\cmddef{datatoolcurrencysymbolregionprefix:n}
This uses \gls{DTLcurrCodeOrSymOrChar} to only show the tag when that
command expands to its second or third argument. (Since the tag is typically
the region code, it's redundant to insert it before the currency
code.) The tag is formatted with:
\cmddef{datatoolcurrencysymbolprefixfmt}
This may be redefined, which will change the way the tag is
formatted for all regions that support it. For convenience, the 
\opt{numeric} option \numericopt{region-currency-prefix} may be used
to redefine this formatting command to use small caps. 

Region files should provide a hook called
\cmddef{datatoolRegionSetCurrency}
where \meta{Region} is the two letter uppercase region code.
This command should check the boolean variable:
\cmddef{ldatatoolregionsetcurrencybool}
(which corresponds to the \numericopt{region-currency} numeric
option). The hook should only set the currency if this boolean value
is true.

Similarly, a hook to set the current \idx{numbergroupchar} and
\idx{decimalchar}:
\cmddef{datatoolRegionSetNumberChars}
This command should check the boolean variable:
\cmddef{ldatatoolregionsetnumbercharsbool}
(which corresponds to the \numericopt{region-number-chars} numeric
option). The hook should only set the number group and decimal
characters if this boolean value is true.

If you simply want to typeset \idxpl{plainnumber} as
\idxpl{formattednumber} then consider using \sty{siunitx} instead.
However you can use the following, which picks up the above settings.

\cmddef{DTLdecimaltolocale}
Converts a \idx{plainnumber} \meta{num} into a \idx{formattednumber}
and stores the result in \meta{cs}. If a currency symbol is
required, use \gls{DTLdecimaltocurrency} instead.
If \gls{datatoolsetnumberchars:nnnn} was used, the characters
supplied with the
\meta{format number group char} and \meta{format decimal char} arguments 
will be used.

If the supplied value is not a \idx{plainnumber} then a warning will
occur and the result will be a string. This is to allow for
databases that contain missing value markup, such as \qt{N/A}
or \csfmt{textemdash}. 

\cmddef{DTLdecimaltocurrency}
Converts a \idx{plainnumber} \meta{num} into a \idx{formattednumber}
(as above)
with the currency symbol supplied in the optional argument (or the
default currency symbol if omitted) and stores the result in \meta{cs}.
The number of digits will be rounded according to:
\cmddef{DTLCurrentLocaleCurrencyDP}
If the expansion text is empty then \gls{DTLdecimaltocurrency} won't
round the result. Otherwise, the expansion text should be the number
of decimal places to round to. This command is redefined by
localisation hooks.

For example
\begin{codebox}
\cmd{documentclass}\marg{article}
\cmd{usepackage}[en-GB]\marg{datatool-base}
\cbeg{document}
\gls{DTLdecimaltocurrency}\marg{1234.5672}\marg{\cmd{result}}\comment{parse number}
Result: \cmd{result}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\cend{document}
\end{codebox}

\subsection{Lexicographical}
\label{sec:lexicographical}

The commands described in this section are used by string sorting
and initial letter commands to enable locale-sensitive functions to
be used, if available.
\cmddef{DTLCurrentLocaleWordHandler}
This is the current locale word handler used by \gls{DTLDefaultLocaleWordHandler}.
If no localisation support is provided, this command does nothing.
If localisation support is added, this handler should make any
appropriate adjustments to \meta{cs} to convert its content to a
byte sequence that will ensure the string is correctly sorted
according to the locale's alphabet.

The handler definition will usually depend on the encoding.
For example, \ldf{english\dhyphen utf8} defines
\gls{DTLenLocaleHandler} and the following is
added (indirectly) to the language hook (see \sectionref{sec:addlang}):
\begin{compactcodebox}
\cmd{let}\gls{DTLCurrentLocaleWordHandler}\gls{DTLenLocaleHandler}
\end{compactcodebox}
This allows accented characters, such as \qt{Á}, to be converted to
non-accented Basic Latin characters, such as \qt{A}.
This command is also defined by \ldf{english\dhyphen latin1} and
\ldf{english\dhyphen ascii} but has less support.

\begin{information}
Remember that the purpose of the handler is to convert a string into
a byte sequence that reflects the desired ordering. This byte
sequence is not intended to be typeset. It's therefore possible to
use \idx{ascii} control characters to influence the order. This is
the method used by the marker commands, such as
\gls{datatoolpersoncomma}.
\end{information}

For example\examplemarginref{ex:icelandic}, suppose you want to provide support for Icelandic,
where Áá, Ðð, Éé, Íí, Óó, Úú, Ýý, Þþ, Ææ and Öö are all distinct
letters of the alphabet.  This means that the method used by the
English hander isn't appropriate.

As with the English handler, the punctuation characters can be
adjusted to ensure that they are placed before \qt{A}. This means
that the final \idx{uppercase} letters \qt{Þ}, \qt{Æ} and \qt{Ö} can be reassigned
to the character positions after \qt{Z} and the \idx{lowercase} \qt{þ}, \qt{æ} and
\qt{ö} can be reassigned to the character positions after \qt{z}
(similar to \ldf{ang-Latn}).
The other characters need to be positioned between Basic Latin characters. For
example, \qt{Á} needs to be between \qt{A} and \qt{B}. This can be
achieved by replacing \idx{uppercase} \qt{Á} with \qt{A} followed by 
the control character \hexcp{7F} (which is the final \idx{ascii} character). 
Similarly \idx{lowercase} \qt{á} is replaced by \qt{a} followed by
\hexcp{7F} and so on.

The language code for Icelandic is \qt{is} so it will be used in
the command names. Remember that 
\gls{ldatatoolcurrentlanguagetl} will need to be redefined to match.
(Alternatively, \qt{isl} or \qt{ice} could also be used but the
important thing is to be consistent in the event that a region file
tries searching for a command name to determine if it's supported
for the current language.)

\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{newcommand} \marg{\cmd{DTLisLocaleHandler}} [ 1 ]
\marg{
  \cmd{regex\_replace\_case\_all:nN}
  \marg{
    \marg{ Á } \marg{ A\cmd{cL}\cmd{x}\marg{7f} } \marg{ á } \marg{ a\cmd{cL}\cmd{x}\marg{7f} }
    \marg{ Ð } \marg{ D\cmd{cL}\cmd{x}\marg{7f} } \marg{ ð } \marg{ d\cmd{cL}\cmd{x}\marg{7f} }
    \marg{ É } \marg{ E\cmd{cL}\cmd{x}\marg{7f} } \marg{ é } \marg{ e\cmd{cL}\cmd{x}\marg{7f} }
    \marg{ Í } \marg{ I\cmd{cL}\cmd{x}\marg{7f} } \marg{ í } \marg{ i\cmd{cL}\cmd{x}\marg{7f} }
    \marg{ Ó } \marg{ O\cmd{cL}\cmd{x}\marg{7f} } \marg{ ó } \marg{ o\cmd{cL}\cmd{x}\marg{7f} }
    \marg{ Ú } \marg{ U\cmd{cL}\cmd{x}\marg{7f} } \marg{ ú } \marg{ u\cmd{cL}\cmd{x}\marg{7f} }
    \marg{ Ý } \marg{ Y\cmd{cL}\cmd{x}\marg{7f} } \marg{ ý } \marg{ y\cmd{cL}\cmd{x}\marg{7f} }
    \marg{ Þ } \marg{ \cmd{cL}\cmd{x}\marg{5b} } \marg{ þ } \marg{ \cmd{cL}\cmd{x}\marg{7b} }
    \marg{ Æ } \marg{ \cmd{cL}\cmd{x}\marg{5c} } \marg{ æ } \marg{ \cmd{cL}\cmd{x}\marg{7c} }
    \marg{ Ö } \marg{ \cmd{cL}\cmd{x}\marg{5d} } \marg{ ö } \marg{ \cmd{cL}\cmd{x}\marg{7d} }
\comment{currency signs and punctuation}
\comment{[\ldots]}
  }
  \#1
}
\gls{ExplSyntaxOff}
\end{codebox}
Substitutions for foreign language letters (such as replacing \qt{ß}
with \qt{ss}) should be added as applicable. The currency signs and
punctuation are as for \gls{DTLenLocaleHandler}, shown
earlier.

For example, the string \qt{az} will be unchanged and has the byte
sequence \hexcp{61} \hexcp{7A}. Whereas the string \qt{áa} will be converted by
the above Icelandic handler to the byte sequence \hexcp{61} \hexcp{7F} \hexcp{61}.
Since \hexcp{7A} is less than \hexcp{7F}, \qt{az} comes before \qt{áa}. With the
English handler, \qt{áa} will be converted to \qt{aa} which has the
byte sequence \hexcp{61} \hexcp{61}. Since \hexcp{61} is less than \hexcp{7A}, \qt{áa} would
come before \qt{az}.

Note the use of \csfmt{cL} to ensure that the replacement characters
have a letter category code (even though they're not actually letters).
This will allow the process to be reversed without changing
punctuation characters that were originally present in the sort string
(see \exampleref{ex:icelandiclettergroup}).

The language hook (see \sectionref{sec:addlang}) then needs to set the locale handler:
\begin{codebox}
\cmd{let}\gls{DTLCurrentLocaleWordHandler}\cmd{DTLisLocaleHandler}
\end{codebox}
You may prefer to use \csfmt{renewcommand} if you want to provide
options to adjust the handler (as with \ldf{ang-Runr}).

\Exampleref{ex:icelandic} uses the above to sort a list of words:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{bókstafinn, vera, eða, ég, býsna, 
þú, vakna, epli, bragðs, aldar, bað, bolli, ýmist, af,
óáreiðanleg, bær, dalur, ör, þorn, þau, október, esja, 
öngull, dæmi, að, yfir, öðrum, orð, detta, áhrif, yngri, 
óvinur, ætlað}
\codepar
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:icelandic},
 title={Icelandic Alphabetic},
 description={Example document demonstrating how support for the
Icelandic alphabet can be provided for sorting. Typically the
preamble code would be placed in a localisation file}
]
{%
\cmd{usepackage}[utf8]\marg{inputenc}\nl
\cmd{usepackage}[T1]\marg{fontenc}\nl
\cmd{usepackage}\marg{datatool-base}\nl
\gls{ExplSyntaxOn}
\codepar
\cmd{newcommand}\marg{\cmd{DTLisLocaleHandler}}[1]\marg{\nlsp
  \cmd{regex\_replace\_case\_all:nN}\nlsp
  \marg{\nldbsp
    \marg{ Á } \marg{ A\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ á } \marg{ a\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ Ð } \marg{ D\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ ð } \marg{ d\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ É } \marg{ E\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ é } \marg{ e\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ Í } \marg{ I\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ í } \marg{ i\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ Ó } \marg{ O\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ ó } \marg{ o\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ Ú } \marg{ U\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ ú } \marg{ u\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ Ý } \marg{ Y\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ ý } \marg{ y\cmd{cL}\cmd{x}\marg{7f} }\nldbsp
    \marg{ Þ } \marg{ \cmd{cL}\cmd{x}\marg{5b} }\nldbsp
    \marg{ þ } \marg{ \cmd{cL}\cmd{x}\marg{7b} }\nldbsp
    \marg{ Æ } \marg{ \cmd{cL}\cmd{x}\marg{5c} }\nldbsp
    \marg{ æ } \marg{ \cmd{cL}\cmd{x}\marg{7c} }\nldbsp
    \marg{ Ö } \marg{ \cmd{cL}\cmd{x}\marg{5d} }\nldbsp
    \marg{ ö } \marg{ \cmd{cL}\cmd{x}\marg{7d} }\nldbsp
    \marg{ ([[:punct:]]+) } \marg{ \cmd{cO}"\cmd{1} }\nldbsp
  }\nlsp
  \#1\nl
}
\codepar
\gls{ExplSyntaxOff}
\codepar
\cmd{let}\gls{DTLCurrentLocaleWordHandler}\cmd{DTLisLocaleHandler}
\codepar
\cmd{newcommand}\marg{\cmd{mylist}}\marg{bókstafinn, vera, eða, \nlsp
ég, býsna, þú, vakna, epli, bragðs, aldar, bað, bolli, ýmist, af,
\nlsp
óáreiðanleg, bær, dalur, ör, þorn, þau, október, esja, öngull, dæmi,
að, yfir, \nlsp
öðrum, orð, detta, áhrif, yngri, óvinur, ætlað}
}
{%
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}\nl
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

\cmddef{DTLCurrentLocaleGetGroupString}
This is used by \gls{DTLassignlettergroup} to set \meta{cs}
(a token list variable) to the content from which the letter group
will be obtained (but only for string data types). 

For example, \ldf{english} sets \meta{cs} to the 
sort value as this ensures that any supported accented characters and
ligatures will have already been converted to Basic Latin
characters.

However \ldf{ang-Latn} and \ldf{ang-Runr} can't do this as 
the construction of the sort value means that the characters in the
sort value may be significantly different from the actual letters.
In this case, the original value must be used instead, but it's
needs some processing to map extended characters to their equivalent
sort group. For example, \qt{Ǽ} needs to be mapped to \qt{Æ}.
Additionally, the actual value is likely to need pre-processing
with \gls{datatoolsortpreprocess:Nn}.

\cmddef{DTLCurrentLocaleGetInitialLetter}
This is used by \gls{DTLGetInitialLetter} and
\gls{DTLassignlettergroup} to obtain the initial letter of
the given text. The default definition just uses
\gls{datatoolgetfirstletter:nN} which skips leading non-letters.

This command is intended for use with sorting functions to obtain the letter
group, so the actual letter returned may not be the initial
letter. For example, if the word starts with the ligature \qt{\AE}
then the localisation may return \qt{A} rather than \qt{\AE}.

For example, \ldf{english} defines:
\begin{compactcodebox}
\cmd{newcommand}\marg{\cmd{DTLenLocaleGetInitialLetter}}[2]\marg{
  \gls{datatoolgetfirstletter:nN} \marg{ \#1 } \#2
  \gls{DTLenLocaleHandler} \#2
  \cmd{int\_compare:nNnT} \marg{ \cmd{tl\_count:N} \#2 } > \marg{ \cmd{c\_one\_int} }
   \marg{
     \cmd{exp\_args:NV} \gls{datatoolgetfirstletter:nN} \#2 \#2
   }
}
\end{compactcodebox}
and adds the following to the language hook:
\begin{compactcodebox}
\cmd{let}\gls{DTLCurrentLocaleGetInitialLetter}
 \cmd{DTLenLocaleGetInitialLetter}
\end{compactcodebox}
(See \sectionref{sec:addlang} for further details.)

\mExampleref{ex:ijinitial} has a possible implementation for Dutch that will search for
\qt{IJ} or \qt{ij}:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{DTLdutchLocaleGetInitialLetter}}[2]\marg{
  \cmd{tl\_clear:N} \#2
  \gls{textmapinline:nn} \marg{ \#1 }
  \marg{
    \cmd{tl\_if\_empty:NTF} \#2
     \marg{
       \condcsT{datatoolifletter:n} \marg{ \#\#1 }
        \marg{
          \cmd{tl\_set:Nn} \#2 \marg{ \#\#1 }
          \cmd{tl\_if\_in:nnF} \marg{ Ii } { \#\#1 } \marg{ \cmd{text\_map\_break:} }
        }
     }
     \marg{
       \cmd{tl\_if\_in:nnT} \marg{ Jj } \marg{ \#\#1 }
        \marg{
          \cmd{tl\_put\_right:Nn} \#2 \marg{ \#\#1 }
        }
       \cmd{text\_map\_break:}
     }
  }
}
\end{codebox}
(Note that this will also find \qt{Ij} and \qt{iJ}. Some adjustment
is required to exclude those cases.)
Suppose that this has been implemented via a language hook (see \sectionref{sec:addlang}):
\begin{compactcodebox}
\cmd{let}\gls{DTLCurrentLocaleGetInitialLetter}
 \cmd{DTLdutchLocaleGetInitialLetter}
\end{compactcodebox}
Then it will affect commands that fetch an initial letter, such as
\gls{DTLinitials}:
\begin{codebox}
IJsselmeer: \gls{DTLinitials}\marg{IJsselmeer}
Industrieel: \gls{DTLinitials}\marg{Industrieel}
``IJsselmeer'': \gls{DTLinitials}\marg{``IJsselmeer''}
``Industrieel'': \gls{DTLinitials}\marg{``Industrieel''}
\end{codebox}
The test for a letter (with \condcsT{datatoolifletter:n}) ensures that
leading punctuation is skipped.
\begin{resultbox}
\createexample*[label={ex:ijinitial},
 title={IJ-Initial Support},
 description={Example document demonstrating how IJ support can be
added to commands that fetch an initial letter. Typically the
preamble code would be placed in a localisation file}
]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\gls{ExplSyntaxOn}\nlsp
\cmd{newcommand}\marg{\cmd{DTLdutchLocaleGetInitialLetter}}[2]\marg{\nlsp
  \cmd{tl\_clear:N} \#2\nlsp
  \gls{textmapinline:nn} \marg{ \#1 } \nlsp
  \marg{ \nlsp
    \cmd{tl\_if\_empty:NTF} \#2 \nldbsp
     \marg{\nldbdbsp
       \cmd{datatool\_if\_letter:nT} \marg{ \#\#1 }\nldbdbsp
        \marg{\nldbdbdbsp
          \cmd{tl\_set:Nn} \#2 \marg{ \#\#1 }\nldbdbdbsp
          \cmd{tl\_if\_in:nnF} \marg{ Ii } { \#\#1 } \marg{ \cmd{text\_map\_break:} }
\nldbdbsp
        }\nldbsp
     } \nlsp
     \marg{\nldbsp
       \cmd{tl\_if\_in:nnT} \marg{ Jj } \marg{ \#\#1 } \nldbdbsp
        \marg{\nldbdbdbsp
          \cmd{tl\_put\_right:Nn} \#2 \marg{ \#\#1 }\nldbdbsp
        }\nldbsp
       \cmd{text\_map\_break:}\nlsp
     }\nlsp
  }\nl
}\nl
\gls{ExplSyntaxOff}
\codepar
\cmd{let}\gls{DTLCurrentLocaleGetInitialLetter}\cmd{DTLdutchLocaleGetInitialLetter}
}
{%
IJsselmeer: \gls{DTLinitials}\marg{IJsselmeer}\nl
Industrieel: \gls{DTLinitials}\marg{Industrieel}\nl
``IJsselmeer'': \gls{DTLinitials}\marg{``IJsselmeer''}\nl
``Industrieel'': \gls{DTLinitials}\marg{``Industrieel''}
}
\end{resultbox}

Remember that \gls{DTLCurrentLocaleGetInitialLetter} is also used to obtain the
letter group (but not the non-letter group) from sort values with
\gls{DTLsortwordlist}.  

\mExampleref{ex:icelandiclettergroup} adapts the
earlier Icelandic \exampleref{ex:icelandic} to show the letter groups.
Recall that \exampleref{ex:icelandic} substituted
\idx{utf8} characters for \idx{ascii} characters with control codes
or punctuation characters used to influencing sorting. This means
that, for example, \qt{ý} will be replaced with \qt{y} followed by
the control code \hexcp{7F} assigned with the letter category code.

The content used to obtain the group letter may be either the
original (\qt{actual}) string or the sort value. This is determined
by \gls{DTLCurrentLocaleGetGroupString}. For example,
\ldf{english} uses the sort value, since all the extended characters
are mapped to Basic Latin letters. In this case, we have some
awkward control characters which will mess up the letter group.

There are two ways of dealing with this. The first method is the
case used by \ldf{ang-Latn} which defines
\gls{DTLangLatnLocaleGetGroupString}.
That starts with the actual value and processes it
with \gls{datatoolsortpreprocess:Nn} and then replaces any
leading accented character with the unaccented letter.

The second method is used here. This starts with the sort value and
reverses the mapping applied by the handler.
In this case, a localisation file that provides
\csfmt{DTLisLocaleHandler} would also need to provide a way
of reversing the substitutions for the letter groups. Since the replacement
(non-alphabetic) characters are assigned the letter category code, this makes
them easier to distinguish from actual punctuation characters.

\begin{codebox}
\cmd{newcommand}\marg{\cmd{DTLisLocaleGetGroupString}}[3]\marg{
  \cmd{tl\_set:Nn} \#3 \marg{ \#2 }
  \cmd{regex\_replace\_case\_once:nN}
   \marg{
     \marg{ A\cmd{cL}\cmd{x}\marg{7f} } \marg{ Á } \marg{ a\cmd{cL}\cmd{x}\marg{7f} } \marg{ á }
     \marg{ D\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ð } \marg{ d\cmd{cL}\cmd{x}\marg{7f} } \marg{ ð }
     \marg{ E\cmd{cL}\cmd{x}\marg{7f} } \marg{ É } \marg{ e\cmd{cL}\cmd{x}\marg{7f} } \marg{ é }
     \marg{ I\cmd{cL}\cmd{x}\marg{7f} } \marg{ Í } \marg{ i\cmd{cL}\cmd{x}\marg{7f} } \marg{ í }
     \marg{ O\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ó } \marg{ o\cmd{cL}\cmd{x}\marg{7f} } \marg{ ó }
     \marg{ U\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ú } \marg{ u\cmd{cL}\cmd{x}\marg{7f} } \marg{ ú }
     \marg{ Y\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ý } \marg{ y\cmd{cL}\cmd{x}\marg{7f} } \marg{ ý }
     \marg{ \cmd{cL}\cmd{x}\marg{5b} } \marg{ Þ } \marg{ \cmd{cL}\cmd{x}\marg{7b} } \marg{ þ }
     \marg{ \cmd{cL}\cmd{x}\marg{5c} } \marg{ Æ } \marg{ \cmd{cL}\cmd{x}\marg{7c} } \marg{ æ }
     \marg{ \cmd{cL}\cmd{x}\marg{5d} } \marg{ Ö } \marg{ \cmd{cL}\cmd{x}\marg{7d} } \marg{ ö }
   } \#3
}
\end{codebox}
Note that, unlike the handler function, this only needs to perform
one replacement as we're only interested in the start of the string.
Unlike the first method (used by \gls{DTLangLatnLocaleGetGroupString})
we don't need to worry about whether or not leading hyphens have
been stripped.
Deciding which method to use comes down to whether it's more complex
to reverse the mapping on the sort value or to process the actual
value.

Suppose that this has been implemented via a language hook 
(see \sectionref{sec:addlang}):
\begin{compactcodebox}
\cmd{let}\gls{DTLCurrentLocaleGetInitialLetter}
 \cmd{DTLisLocaleGetInitialLetter}
\end{compactcodebox}
\Exampleref{ex:icelandic} can now be adapted to show the letter groups:
\begin{codebox}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}
\cmd{renewcommand}\marg{\gls{DTLlistformatitem}}[1]\marg{\#1 (\gls{DTLsortedletter}\marg{\#1})}
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:icelandiclettergroup},
 title={Icelandic Sorting and Letter Groups},
 description={Example document demonstrating how support for the
Icelandic alphabet can be provided for sorting and letter groups. Typically the
preamble code would be placed in a localisation file}
]
{%
\cmd{usepackage}[utf8]\marg{inputenc}\nl
\cmd{usepackage}[T1]\marg{fontenc}\nl
\cmd{usepackage}\marg{datatool-base}\nl
\gls{ExplSyntaxOn}
\codepar
\cmd{newcommand}\marg{\cmd{DTLisLocaleHandler}}[1]\marg{\nlsp
  \cmd{regex\_replace\_case\_all:nN}\nlsp
  \marg{\nldbsp
    \marg{ Á } \marg{ A\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ á } \marg{ a\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ Ð } \marg{ D\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ ð } \marg{ d\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ É } \marg{ E\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ é } \marg{ e\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ Í } \marg{ I\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ í } \marg{ i\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ Ó } \marg{ O\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ ó } \marg{ o\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ Ú } \marg{ U\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ ú } \marg{ u\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ Ý } \marg{ Y\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ ý } \marg{ y\cmd{cL}\cmd{x}\marg{7f} }\nldbdbsp
    \marg{ Þ } \marg{ \cmd{cL}\cmd{x}\marg{5b} }\nldbdbsp
    \marg{ þ } \marg{ \cmd{cL}\cmd{x}\marg{7b} }\nldbdbsp
    \marg{ Æ } \marg{ \cmd{cL}\cmd{x}\marg{5c} }\nldbdbsp
    \marg{ æ } \marg{ \cmd{cL}\cmd{x}\marg{7c} }\nldbdbsp
    \marg{ Ö } \marg{ \cmd{cL}\cmd{x}\marg{5d} }\nldbdbsp
    \marg{ ö } \marg{ \cmd{cL}\cmd{x}\marg{7d} }\nldbdbsp
    \marg{ ([[:punct:]]+) } \marg{ \cmd{cO}"\cmd{1} }\nldbdbsp
  }\nlsp
  \#1\nl
}
\codepar
\cmd{newcommand}\marg{\cmd{DTLisLocaleGetInitialLetter}}[2]\marg{\nlsp
  \cmd{tl\_set:Nn} \#2 \marg{ \#1 }\nlsp
  \cmd{regex\_replace\_case\_all:nN}\nlsp
   \marg{\nldbsp
     \marg{ A\cmd{cL}\cmd{x}\marg{7f} } \marg{ Á } \marg{
a\cmd{cL}\cmd{x}\marg{7f} } \marg{ á }\nldbsp
     \marg{ D\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ð } \marg{
d\cmd{cL}\cmd{x}\marg{7f} } \marg{ ð }\nldbsp
     \marg{ E\cmd{cL}\cmd{x}\marg{7f} } \marg{ É } \marg{
e\cmd{cL}\cmd{x}\marg{7f} } \marg{ é }\nldbsp
     \marg{ I\cmd{cL}\cmd{x}\marg{7f} } \marg{ Í } \marg{
i\cmd{cL}\cmd{x}\marg{7f} } \marg{ í }\nldbsp
     \marg{ O\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ó } \marg{
o\cmd{cL}\cmd{x}\marg{7f} } \marg{ ó }\nldbsp
     \marg{ U\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ú } \marg{
u\cmd{cL}\cmd{x}\marg{7f} } \marg{ ú }\nldbsp
     \marg{ Y\cmd{cL}\cmd{x}\marg{7f} } \marg{ Ý } \marg{
y\cmd{cL}\cmd{x}\marg{7f} } \marg{ ý }\nldbsp
     \marg{ \cmd{cL}\cmd{x}\marg{5b} } \marg{ Þ } \marg{
\cmd{cL}\cmd{x}\marg{7b} } \marg{ þ }\nldbsp
     \marg{ \cmd{cL}\cmd{x}\marg{5c} } \marg{ Æ } \marg{
\cmd{cL}\cmd{x}\marg{7c} } \marg{ æ }\nldbsp
     \marg{ \cmd{cL}\cmd{x}\marg{5d} } \marg{ Ö } \marg{
\cmd{cL}\cmd{x}\marg{7d} } \marg{ ö }\nldbsp
   } \#2\nlsp
  \cmd{exp\_args:No} \gls{datatoolgetfirstletter:nN} \marg{ \#2 } \#2\nl
}
\codepar
\gls{ExplSyntaxOff}
\codepar
\cmd{let}\gls{DTLCurrentLocaleWordHandler}\cmd{DTLisLocaleHandler}
\cmd{let}\gls{DTLCurrentLocaleGetInitialLetter}\cmd{DTLisLocaleGetInitialLetter}
\codepar
\cmd{newcommand}\marg{\cmd{mylist}}\marg{bókstafinn, vera, eða,
\nlsp
ég, býsna, þú, vakna, epli, bragðs, aldar, bað, bolli, ýmist, af,
\nlsp
óáreiðanleg, bær, dalur, ör, þorn, þau, október, esja, öngull, dæmi,
að, yfir, \nlsp
öðrum, orð, detta, áhrif, yngri, óvinur, ætlað}
}
{%
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}\nl
\cmd{renewcommand}\marg{\gls{DTLlistformatitem}}[1]\marg{\#1
(\gls{DTLsortedletter}\marg{\#1})}\nl
Sorted list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

\cmddef{dtllettergroup}
By default, this expands to \code{\gls{texttitlecasefirst:n}\margm{character}}.
In the case of Dutch, this would need to be changed to use
\gls{textuppercase:n} instead to ensure that \qt{ij} becomes \qt{IJ}
instead of \qt{Ij}.

\cmddef{dtlnonlettergroup}
By default, this simply expands to \meta{character}. A language file
may redefine this to produce a textual title. For example,
\qt{Symbols}.

For the Icelandic word sort handler in \exampleref{ex:icelandic},
the \meta{character} will always be the double-quote \code{"}
because of the final substitution case in the regular expression.
For the handler provided in \ldf{english\dhyphen utf8} (see
\sectionref{sec:addlang}), the character will either be a
double-quote \code{"} or a literal dollar \code{\$} (with category
code other).

\cmddef{dtlnumbergroup}
(Only used with \listsoptvalm{sort-datum}{true}.)
By default, this simply expands to \meta{num}. A language file
may redefine this to produce a textual title. For example,
\qt{Numbers}.

\cmddef{dtlcurrencygroup}
(Only used with \listsoptvalm{sort-datum}{true}.)
By default, this simply expands to \meta{sym}. A language file
may redefine this to produce a textual title. For example,
\qt{Currency}.

\subsection{Adding New Region Support}
\label{sec:addregion}

The language-independent region files are all bundled together in a
single distribution \sty{datatool-regions} which is separate from
the core \sty{datatool} distribution and available on GitHub
(\url{https://github.com/nlct/datatool-regions}). There are
currently only a limited number of regions supported but more can be
added via a pull request and only the \sty{datatool-regions}
collection need be uploaded, without the extra overhead of producing
a new version of \sty{datatool}.

\begin{information}
There is an interactive Perl script on GitHub that will create a
\ldfmeta{region} file based on your responses.
\end{information}

The region file deals with setting the default currency,
\idx{numbergroupchar} and \idx{decimalchar}, and also the numeric
date formats for use with \datetimeoptval{parse}{region}
or \datetimeoptval{parse}{iso+region}. Note that any date formats
that have textual parts (such as month names) should be dealt with
by the language support.

A more specific 
\metametafilefmt{datatool-}{lang}{-}{region}{.ldf} file may be used to
override any of these settings but that file should be provided with the
corresponding language support (see \sectionref{sec:addlang}).
For example, \sty{datatool-english} provides \ldf{en-CA} to set the 
\idx{numbergroupchar} and \idx{decimalchar} since it varies
according to the language for that region.

\begin{information}
For further details, see the \sty{datatool-regions} documentation.
\end{information}

\subsection{Adding New Language Support}
\label{sec:addlang}

The \inlinepkgdef{datatool-english} package (distributed separately)
may be used as an example. (The \sty{datatool-english} bundle
includes \file{databib-english.ldf} to provide localisation support
for the \sty{databib} package, and \file{person-english.ldf} to
provide localisation support for the \sty{person} package, see
\sectionsref{sec:databiblang,sec:personlang} for further details.)

The \sty{datatool-english} bundle also includes limited support for
Old English (Anglo-Saxon) for Latin and Runic scripts, which may be
used as examples for extended Latin or non-Latin languages.

The language file should be called
\metafilefmt{datatool\dhyphen}{language}{.ldf} where \meta{language}
is the root language label (\sty{tracklang} label). Using the root
language label ensures that it's the last in \sty{tracklang}['s]
file search list, which means that it can be overridden by a more
specific label, if required.
So in the event that there is some particular language setting that is specific to
a particular region, a language module may also include a file named
\metametafilefmt{datatool\dhyphen}{lang}{\dhyphen}{region}{.ldf} where
\meta{lang} is the language code (such as \qt{fr}) and 
\meta{region} is the region code (such as \qt{CA})..
For example:
\begin{codebox*}
\gls{TrackLangProvidesResource}\marg{fr-CA}
\cmd{TrackLangRequireResource}\marg{french}
\gls{ExplSyntaxOn}
\cmd{newcommand}\datatoolRegionSetNumberChars{frCA}
\marg{
 \cmd{bool\_if:NT} \gls{ldatatoolregionsetnumbercharsbool}
  {
    \gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{number group and decimal symbol} 
  }
}
\cmd{newcommand}\DTLtagLocaleHook{frCA}
\marg{
 \datatoolRegionSetNumberChars{frCA}
}
\gls{ExplSyntaxOff}
\gls{TrackLangAddToCaptions}\marg{\DTLtagLocaleHook{frCA}}
\end{codebox*}
The \sty{datatool-english} distribution provides a similar
\ldf{en-CA} file.

In the case of \sty{datatool-english}, the root language label is \qt{english} (even if
the language has been specified using a dialect label, such as
\qt{british}) so the filename is \ldf{english}. 
The file needs to identify itself (analogous
to \csfmt{ProvidesPackage} for packages):
\begin{compactcodebox}
\gls{TrackLangProvidesResource}\margm{language}\oarg{\meta{yyyy}/\meta{mm}/\meta{dd} v\meta{version}}
\end{compactcodebox}
Although \pdfLaTeX\ now defaults to \idx{utf8}, it can be helpful to
provide some support for other encodings. The document encoding (as
detected by \sty{tracklang}) can be obtained by expanding
\gls{TrackLangEncodingName} (\gls{inputencoding} isn't guaranteed to
be defined).

The \sty{datatool-english} bundle includes (limited) support for ISO-8859-1
(Latin-1) and \idx{ascii} in addition to \idx{utf8}. The
encoding support is provided in the files \ldf{english\dhyphen latin1},
\ldf{english\dhyphen ascii} and \ldf{english\dhyphen utf8}. The
following code will input the appropriate file or fallback on the
\idx{ascii} file if the encoding isn't supported:
\begin{compactcodebox}
\cmd{TrackLangRequestResource}\marg{english-\gls{TrackLangEncodingName}}
\marg{
  \cmd{TrackLangRequireResource}\marg{english-ascii}
}
\end{compactcodebox}
Note the difference between requesting a resource and requiring it.

Compare this with the Anglo-Saxon support. The root language label
is \qt{anglosaxon} so there is a file called \ldf{anglosaxon}
but because there are two different scripts to cater for, it just
ensures that the appropriate file is loaded.
\begin{compactcodebox}
\gls{TrackLangProvidesResource}\marg{anglosaxon}
\cmd{TrackLangRequestResource}
 \marg{ang-\cmd{CurrentTrackedDialectScript}-\gls{TrackLangEncodingName}}
\marg{\comment{}
 \cmd{PackageWarning}\marg{datatool-anglosaxon}\comment{}
  \marg{\comment{}
    No support for `anglosaxon' with script
    `\cmd{CurrentTrackedDialectScript}'
    and encoding `\gls{TrackLangEncodingName}'\comment{}
  }\comment{}
}
\end{compactcodebox}
This file is actually just a fallback as the files
\ldf{ang-Latn} and \ldf{ang-Runr} should be found first.
Note that the script indicates the script of the input or source
text. That is, the text used in the document source code, which
may not correspond to the glyphs visible in the PDF file.

For example, a package may provide a command called, say
\cmd{runic}, which expects Latin characters in the argument
but the font encoding ensures that those characters appear as runes
in the PDF. In this case, the source is Latin and so 
\qt{ang-Latn} is needed when specifying the locale.

If, however, the source code actually contains characters from 
the Runic Unicode block (with an appropriate font that supports
those characters), the source is Runic and so \qt{ang-Runr}
is needed when specifying the locale.

The files \ldf{ang\dhyphen Latn} and \ldf{ang\dhyphen Runr} are similar
to \ldf{english} but, in these cases, there's no fallback to
\idx{ascii} as it doesn't cover all characters from the Latin script
and doesn't cover any for the Runic script. Instead, if the encoding
isn't supported, then no localisation can be provided. For example,
\ldf{ang-Latn} starts with:
\begin{compactcodebox}
\gls{TrackLangProvidesResource}\marg{ang-Latn}
\cmd{TrackLangRequestResource}\marg{ang-Latn-\gls{TrackLangEncodingName}}
\marg{\comment{}
  \cmd{PackageWarning}\marg{datatool-ang-Latn}\comment{}
   \marg{\comment{}
     No support for `anglosaxon' with script `Latn'
     and encoding `\gls{TrackLangEncodingName}'.\comment{}
   }\comment{}
  \cmd{endinput}
}
\end{compactcodebox} 
The code for \ldf{ang-Runr} is similar. Only \idx{utf8} is
supported (\ldf{ang\dhyphen Latn\dhyphen utf8} and
\ldf{ang\dhyphen Runr\dhyphen utf8}), but this method allows for
other encodings to be added by simply creating a file with an
appropriate name.

For both the English and Old English support, 
we will be using some \LaTeX3 syntax, so the 
appropriate category codes must be changed:
\begin{compactcodebox}
\gls{ExplSyntaxOn}
\end{compactcodebox} 

The definition of \gls{DTLenLocaleGetGroupString} ensures that the
letter group is obtained from the sort value rather than the actual
value:
\begin{compactcodebox}
\cmd{newcommand}\gls{DTLenLocaleGetGroupString}\oarg{3}
\marg{
 \cmd{tl\_set:Nn} \#3 \marg{ \#2 }
}
\end{compactcodebox}
This ensures that the accents are stripped, but it will mean that
the currency and punctuation marks will have their initial marker
that's inserted by the handler function \gls{DTLenLocaleHandler}.
Bear in mind that \gls{DTLenLocaleGetGroupString} is only used for
values that have been identified as strings. It's not used by other
data types. The non-letter characters used to alter the order
of currency and punctuation marks is usually not relevant, as the
non-letter group title (\gls{dtlnonlettergroup}) typically ignores
the character.

This conveniently works for English, which just maps extended
characters to Basic Latin letters (A--Z, a--z), but will cause a
problem for Anglo-Saxon, both Latin and Runic. In the case of
\ldf{ang\dhyphen Latn}, the extended characters Ƿ (wynn), Ð (eth), Æ
(AE-ligature), Þ (thorn) are converted to the character codes
following \qt{Z} and, similarly, the lowercase ƿ, ð, æ, þ are
converted to the character codes following \qt{z}.  This means that
if the sort value is used to obtain the letter group, then these
extended characters will be assigned to the non-letter group.

Therefore, it's necessary to use the actual value rather than the
sort value, but some additional processing is required to ensure
that characters with diacritics are placed in the same group as the
unaccented character. For example, \qt{Ǽ} needs to be mapped to \qt{Æ}.
This is performed by a low-level function that performs a regular
expression substitution.

Note that this doesn't take into account a sort handler that strips
content, such as the letter handler functions that remove spaces and
hyphens. This will cause a problem for any words that start with a
hyphen. Since the handler function \cmd{DTL\-ang\-Latn\-Locale\-Handler}
inserts a double-quote character in front of any punctuation, it's
possible to check if the actual value starts with a hyphen and
if the sort value starts with a double-quote then the hyphen likely
wasn't stripped so it can be removed.
This is done as follows:
\begin{compactcodebox*}
\cmd{newcommand} \inlineglsdef{DTLangLatnLocaleGetGroupString} \marg{ 3 }
 \marg{
   \cmd{tl\_set:Nn} \#3 \marg{ \#1 }
   \cmd{datatool\_angLatn\_process\_letter\_group:N} \#3
   \cmd{bool\_lazy\_and:nnT}
     \marg{ \cmd{tl\_if\_head\_eq\_charcode\_p:nN} \marg{ \#1 } - }
     \marg{ \cmd{bool\_not\_p:n} \marg{ \cmd{tl\_if\_head\_eq\_charcode\_p:nN} \marg{ \#2 } " } }
    \marg{
      \cmd{exp\_args:NNe} \cmd{tl\_set:Nn} \#3 \marg{ \cmd{tl\_tail:N} \#3 }
    }
 }
\end{compactcodebox*}

In the case of \ldf{ang-Runr} there are no hyphens to worry about
so it's far simpler to just assign the token list variable to the
actual value. Any further processing is down to whether or not the
sort handler considers multiple runes to be considered equivalent
for sorting purposes.


For both English and the two different scripts of Old English,
the support for \gls{DTLCurrentLocaleGetInitialLetter} is the same
as the default definition provided by \sty{datatool-base}.
For example, \ldf{english} defines:
\begin{compactcodebox*}
\codepar
\cmd{newcommand} \cmd{DTLenLocaleGetInitialLetter} [ 2 ]
 \marg{
   \gls{datatoolgetfirstletter:nN} \marg{ \#1 } \#2
 }
\end{compactcodebox*}

The only other support provided by \ldf{ang\dhyphen Latn}
and \ldf{ang\dhyphen Runr} is to redefine \gls{DTLandname}
to use the Tironian et.

Returning to \ldf{english}, support is provided to produce textual
labels for the non-letter group, number group, currency group
and temporal group commands:
\begin{compactcodebox*}
\cmd{newcommand} \cmd{DTLenSetLetterGroups}
 \marg{
  \cmd{renewcommand} \gls{dtllettergroup} \oarg{ 1 }
    \marg{ \gls{texttitlecasefirst:n} \marg{ \#\#1 } }
  \cmd{renewcommand} \gls{dtlnonlettergroup} \oarg{ 1 } \marg{ Symbols }
  \cmd{renewcommand} \gls{dtlnumbergroup} \oarg{ 1 } \marg{ Numbers }
  \cmd{renewcommand} \gls{dtlcurrencygroup} \oarg{ 2 } \marg{ Currency }
  \cmd{renewcommand} \gls{dtldatetimegroup} \oarg{ 1 } \marg{ Timestamps }
  \cmd{renewcommand} \gls{dtldategroup} \oarg{ 1 } \marg{ Dates }
  \cmd{renewcommand} \gls{dtltimegroup} \oarg{ 1 } \marg{ Times }
 }
\end{compactcodebox*}
Aside from the above, the fixed-text commands for
\sty{datatool-base} are \gls{DTLandname},
\gls{DTLdatatypeunsetname},
\gls{DTLdatatypestringname},
\gls{DTLdatatypeintegername},
\gls{DTLdatatypedecimalname},
\gls{DTLdatatypecurrencyname},
\gls{DTLdatatypedatetimename},
\gls{DTLdatatypedatename},
\gls{DTLdatatypetimename}, and
\gls{DTLdatatypeinvalidname}.

(Some of the supplementary packages have additional fixed-text
commands, but they are dealt with in their own \ext{ldf} files.) An
intermediate command is defined to set \gls{DTLandname}:
\begin{compactcodebox}
\cmd{newcommand} \cmd{DTLenSetAndName}
 \marg{
  \cmd{renewcommand} \gls{DTLandname} \marg{ and }
 }
\end{compactcodebox}
This makes it easier to for the supplied option to redefine it:
\begin{compactcodebox*}
\gls{datatoollocaledefinekeys:nn} \marg{ en }
 \marg{
    and .choice:,
    and / word .code:n =
     \marg{
      \cmd{renewcommand} \cmd{DTLenSetAndName}
       \marg{
         \cmd{renewcommand} \gls{DTLandname} \marg{ and }
       }
      \cmd{tl\_if\_eq:NnT} \gls{ldatatoolcurrentlanguagetl} \marg{ en }
       \marg{ \cmd{DTLenSetAndName} }
     } ,
    and / amp .code:n =
     \marg{
      \cmd{renewcommand} \cmd{DTLenSetAndName}
       \marg{
         \cmd{renewcommand} \gls{DTLandname} \marg{ \gls{cs.amp} }
       }
      \cmd{tl\_if\_eq:NnT} \gls{ldatatoolcurrentlanguagetl} \marg{ en }
       \marg{ \cmd{DTLenSetAndName} }
     } ,
 }
\end{compactcodebox*}
This is added to the hook that sets all the \sty{datatool-base}
textual commands:
\begin{compactcodebox}
\cmd{newcommand} \cmd{DTLenTranslations}
 \marg{
  \cmd{DTLenSetAndName}
  \cmd{renewcommand} \gls{DTLdatatypeunsetname} \marg{ unset }
  \cmd{renewcommand} \gls{DTLdatatypestringname} \marg{ string }
  \cmd{renewcommand} \gls{DTLdatatypeintegername} \marg{ integer }
  \cmd{renewcommand} \gls{DTLdatatypedecimalname} \marg{ decimal }
  \cmd{renewcommand} \gls{DTLdatatypecurrencyname} \marg{ currency }
  \cmd{renewcommand} \gls{DTLdatatypedatetimename} \marg{ date-time }
  \cmd{renewcommand} \gls{DTLdatatypedatename} \marg{ date }
  \cmd{renewcommand} \gls{DTLdatatypetimename} \marg{ time }
  \cmd{renewcommand} \gls{DTLdatatypeinvalidname} \marg{ invalid }
 }
\end{compactcodebox}

After that comes the support for date and time formatting, but it's
still experimental.

As with the region \ldf{GB} file, describe in
\sectionref{sec:addregion}, a single intermediate command is defined
that will be added to the captions hook:
\begin{compactcodebox*}
\cmd{newcommand} \DTLtagLocaleHook{en}
 \marg{
  \cmd{renewcommand}
    \gls{DTLCurrentLocaleWordHandler}
    \marg{ \gls{DTLenLocaleHandler} }
  \cmd{renewcommand}
    \gls{DTLCurrentLocaleGetInitialLetter}
    \marg{ \cmd{DTLenLocaleGetInitialLetter} }
  \cmd{renewcommand}
    \gls{DTLCurrentLocaleGetGroupString}
    \marg{ \gls{DTLenLocaleGetGroupString} }
  \cmd{DTLenSetLetterGroups}
\comment{date and time assignments}
\comment{[\ldots]}
  \cmd{tl\_set:Nn} \gls{ldatatoolcurrentlanguagetl} \marg{ en }
\comment{Fixed text command:}
  \cmd{DTLenTranslations}
}
\gls{ExplSyntaxOff}
\gls{TrackLangAddToCaptions}\marg{\DTLtagLocaleHook{en}}
\end{compactcodebox*}
If \sty{babel} or \sty{polyglossia} have been loaded, this will
add \DTLtagLocaleHook{en} to the \gls{captionsdialect} hook.
The command will be implemented at this point as well, which will make
it the current setting if there's no hook.

Note that each language file should ensure that the caption hook sets
the token list variable:
\cmddef{ldatatoolcurrentlanguagetl}
to expand to the language code (as above). This may then be
referenced by the region file, if necessary. Note that it's used for
checking control sequence names to test if the language provides support for
particular settings, therefore don't include a hyphen as it will
make it harder to define the appropriate commands.
For example, \ldf{ang-Latn} has:
\begin{compactcodebox}
\cmd{tl\_set:Nn} \gls{ldatatoolcurrentlanguagetl} \marg{ angLatn }
\end{compactcodebox}
and \ldf{ang-Runr} has:
\begin{compactcodebox}
\cmd{tl\_set:Nn} \gls{ldatatoolcurrentlanguagetl} \marg{ angRunr }
\end{compactcodebox}

The locale handlers are provided in the encoding files.
For example, \inlineglsdef{DTLenLocaleHandler} is provided in 
\ldf{english\dhyphen utf8}, \ldf{english\dhyphen latin1}
and \ldf{english\dhyphen ascii}. This is used to convert strings 
into byte sequences for
lexicographical comparisons. For example, \ldf{english\dhyphen utf8}
replaces common extended Latin characters into the nearest
\idx{ascii} equivalent, suitable for English ordering.
This can conveniently be done with regular expression replacement.
\begin{compactcodebox}
\cmd{cs\_new:Npn} \gls{DTLenLocaleHandler} \#1
\marg{
  \cmd{regex\_replace\_case\_all:nN}
  \marg{ 
\comment{alphabetical cases}
\comment{[ \ldots ]}
    \marg{ (\cmd{ur}\marg{\glscsname{l\_datatool\_currencysigns\_regex}}) } \marg{ \cmd{cO}\cmd{x}\marg{24}\cmd{1} }
    \marg{ ’ } \marg{ \cmd{cO}"' }
    \marg{ ‘ } \marg{ \cmd{cO}"` }
    \marg{ (“|”) } \marg{ \cmd{cO}"\cmd{cO}" }
    \marg{ (—|–) } \marg{ \cmd{cO}"- }
    \marg{ ([[:punct:]]+) } \marg{ \cmd{cO}"\cmd{1} }
  } 
  \#1
}
\end{compactcodebox}
The final substitutions are for currency and any punctuation and
is designed to gather together currency symbols and punctuation marks.
(Otherwise they would be in their character code order which would
spread them before and after letters.) Note that character classes
such as \code{[:punct:]} and \code{[:alpha:]} only apply to Basic
Latin characters. (The use of \csfmt{cO} ensures that the next
character has category code \qt{other}.)

\begin{warning}
The more complex the regular expression cases, the longer the
document build time. There needs to be a trade-off between likely
characters to support and processing time.
\end{warning}

In the case of a non-Latin script, such as Runic, the conversion
simply ensures that the characters follow the appropriate order when
the character codes are compared. For example, \ldf{ang-Runr}
provides two different ways of ordering the runes.  The first mostly
follows the order in the Runic Unicode block.  So feoh (U+16A0) is
mapped to character code 31, Runic V (U+16A1) is mapped to character
code 32, etc.  The second follows the Old English rune poem order
(fuþorc) so feoh (U+16A0) is mapped to character code 31, ur
(U+16A2) is mapped to character code 32, thorn (U+16A6) is mapped to
character code 33, etc.

\section{Conditionals}
\label{sec:conditionals}

There are two types of conditional commands provided by
\sty{datatool-base}: those with \code{\margm{true}\margm{false}}
arguments (such as \gls{DTLifint}) or case arguments (such as
\gls{DTLifcasedatatype}) and those that are designed to be used in
the conditional part of \gls{ifthenelse} (provided by the
\sty{ifthen} package). The first type have command names that start
\qtt{DTLif} or \qtt{dtlif} and are described in
\sectionref{sec:ifconditions}, and the second type have command
names starting \qt{DTLis} and are described in
\sectionref{sec:ifthen}.

\subsection{If-Else or Case Conditionals}
\label{sec:ifconditions}

The \idx{robust} commands listed in \sectionref{sec:strif}, such as
\gls{DTLifstringeq}, treat their
arguments as strings. For example, \gls{DTLifstringlt} is a 
test if one string is lexicographical less than another.

The \idx{robust} numeric \qtt{DTLif} commands listed in
\sectionref{sec:fmtnumif}, such as \gls{DTLifnumeq}, expect
\idxpl{formattednumber} or \idxpl{datumcs} in the numeric arguments.
If you know that all your values are \idxpl{plainnumber}, the
\qtt{dtlif} listed in \sectionref{sec:plainnumif} commands are
quicker. 

Numeric commands listed in \sectionref{sec:plainnumif}, such as
\gls{dtlifnumeq}, don't parse for the current \idx{decimalchar} and
\idx{numbergroupchar} or for a \idx{currencysym}. They require a
\idx{plainnumber}, either a bare integer (such as 12345) or a number
with a \idx{decimalpoint} (such as 1234.5). These commands are
listed as being provided by \sty{datatool-base}, but are actually
defined in the maths processor file \metafilefmt{datatool\dhyphen
}{processor}{.def} corresponding to the value of the \opt{math}
package option. With \opteqvalref{math}{l3fp} or
\opteqvalref{math}{lua}, these commands are \idx{expandable} but
with \opteqvalref{math}{fp} or \opteqvalref{math}{pgfmath} they are
\idx{robust}. Note that the \sty{fp} package doesn't support
scientific notation.

The multi-type \idx{robust} commands listed in \sectionref{sec:strnumif}, such
as \gls{DTLifeq}, parse the arguments to determine the data type and
then use the corresponding command from \sectionref{sec:fmtnumif} or
\sectionref{sec:strif}.

\subsubsection{Data Type Conditionals}
\label{sec:ifdatatype}

The commands described in this section test the data type of the
argument according to the current settings for the
\idx{numbergroupchar} and \idx{decimalchar} and recognised
\idxpl{currencysym}.

\begin{information}
Note that you can also use \gls{DTLdatumtype} on a \idx+{datumcs}
(obtained with \gls{DTLparse} or \gls{DTLxparse}) to determine the
data type.
\end{information}

\cmddef{DTLifint}
Parses \meta{arg} and does \meta{true} if \meta{arg} is an
integer \idx{formattednumber}, otherwise it does \meta{false}.
Note that if \meta{arg} is a decimal or currency this command will
do \meta{false}. The \idx{numbergroupchar} is optional but, if
present, if must be at intervals of three digits (from the right).
See \exampleref{ex:ifint}.


\cmddef{DTLifreal}
Parses \meta{arg} and does \meta{true} if \meta{arg} is a
real (decimal) \idx{formattednumber} or is in scientific notation, 
otherwise it does \meta{false}.
Note that if \meta{arg} is an integer or currency this command will
do \meta{false} (even though integers are technically a subset of
real numbers). The \idx{numbergroupchar} is optional but, if
present, if must be at intervals of three digits (left of the
\idx{decimalchar}). See \exampleref{ex:ifreal}.

\cmddef{DTLifcurrency}
Parses \meta{arg} and does \meta{true} if \meta{arg} is a
currency \idx{formattednumber}, otherwise it does \meta{false} (see
\exampleref{ex:ifcurr}).
Note that if \meta{arg} is an integer or decimal without a currency
prefix this command will do \meta{false}.

\cmddef{DTLifcurrencyunit}
Parses \meta{arg} and does \meta{true} if \meta{arg} is a
recognised currency \idx{formattednumber} and uses the currency 
\meta{symbol}, otherwise it does \meta{false} (see
\exampleref{ex:ifcurr}).
Note that if \meta{arg} is an integer or decimal this command will
do \meta{false}. Rather than repeatedly parsing the same \meta{arg},
you may prefer to use \gls{DTLparse}.

\cmddef{DTLifnumerical}
Parses \meta{arg} and does \meta{true} if \meta{arg} is numerical,
otherwise it does \meta{false}, where numerical means a
\idx{formattednumber} that may be an integer, real number, currency
or temporal (see \exampleref{ex:ifnum}).

\cmddef{DTLiftemporal}
Parses \meta{arg} and does \meta{true} if \meta{arg} is temporal,
otherwise it does \meta{false}, where temporal means a timestamp
(date, time and, optionally, a time zone), a date (year, month, and
day) or time (hours, minutes, and, optionally, seconds).
Temporal types are considered numerical and may be used in numerical
calculations but the result will be in UTC+0 for timestamps.

\cmddef{DTLifstring}
Parses \meta{arg} and does \meta{true} if \meta{arg} is a string,
otherwise it does \meta{false}. This is essentially like the reverse
of \gls{DTLifnumerical} except in the case of an empty argument,
which has an unknown type, and so is neither numerical nor a string.
See \exampleref{ex:ifstr}.

\cmddef{DTLifcasedatatype}
This command parses \meta{arg} and does \meta{string case} if
\meta{arg} is a string, \meta{int case} if \meta{arg} is an integer,
\meta{real case} if \meta{arg} is a real number (decimal) or
\meta{currency case} if \meta{arg} is a currency (according to the
current \idx{numbergroupchar}, \idx{decimalchar} and
known \idxpl{currencysym}). Note that an empty argument,
which has an unknown type, or a temporal value will do nothing.
See \exampleref{ex:ifcasedata}. This command is retained for
backward-compatibility but lacks the ability to detect new data
types.

\paragraph{Test if Integer Example}
\label{sec:ifintex}

\mExampleref{ex:ifint} uses \gls{DTLifint} to determine if the
argument is an integer according to the current localisation
setting.
\begin{codebox}
2536: \gls{DTLifint}\marg{2536}\marg{integer}\marg{not an integer}.
\codepar
2536.0: \gls{DTLifint}\marg{2536.0}\marg{integer}\marg{not an integer}.
\codepar
2,536: \gls{DTLifint}\marg{2,536}\marg{integer}\marg{not an integer}.
\codepar
2,5,3,6: \gls{DTLifint}\marg{2,5,3,6}\marg{integer}\marg{not an integer}.
\codepar
\gls{DTLparse}\marg{\cmd{numA}}\marg{2,536}
\cmd{numA}: \gls{DTLifint}\marg{\cmd{numA}}\marg{integer}\marg{not an integer}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
2,536: \gls{DTLifint}\marg{2,536}\marg{integer}\marg{not an integer}.
\codepar
2.536: \gls{DTLifint}\marg{2.536}\marg{integer}\marg{not an integer}.
\codepar
\cmd{numA}: \gls{DTLifint}\marg{\cmd{numA}}\marg{integer}\marg{not an integer}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:ifint},link={sec:ifintex},
 title={Test for Integer Value},
 description={Example document illustrating integer tests}
]
{%
  \cmd{usepackage}\marg{datatool-base}
}
{%
2536: \gls{DTLifint}\marg{2536}\marg{integer}\marg{not an integer}.
\codepar
2536.0: \gls{DTLifint}\marg{2536.0}\marg{integer}\marg{not an integer}.
\codepar
2,536: \gls{DTLifint}\marg{2,536}\marg{integer}\marg{not an integer}.
\codepar
2,5,3,6: \gls{DTLifint}\marg{2,5,3,6}\marg{integer}\marg{not an integer}.
\codepar
\gls{DTLparse}\marg{\cmd{numA}}\marg{2,536}\nl
\cmd{numA}: \gls{DTLifint}\marg{\cmd{numA}}\marg{integer}\marg{not an integer}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
2,536: \gls{DTLifint}\marg{2,536}\marg{integer}\marg{not an integer}.
\codepar
2.536: \gls{DTLifint}\marg{2.536}\marg{integer}\marg{not an integer}.
\codepar
\cmd{numA}: \gls{DTLifint}\marg{\cmd{numA}}\marg{integer}\marg{not an integer}.
}
\end{resultbox}
Note that the \idx{datumcs} \csfmt{numA} is still identified as an
integer after \gls{DTLsetnumberchars} even though it uses the
original \idx{numbergroupchar} and \idx{decimalchar}. This is
because once the \idx{datumcs} has had its data type set there's no
need to reparse its value.

\paragraph{Test if Decimal Example}
\label{sec:ifrealex}

\mExampleref{ex:ifreal} uses \gls{DTLifreal} to determine if the
argument is a decimal according to the current localisation
setting. Note that although integers are a subset of real numbers, 
this test will only be true if the argument has a fractional part or
is in scientific notation.

\begin{codebox}
1000.0: \gls{DTLifreal}\marg{1000.0}\marg{real}\marg{not real}.
\codepar
1,000: \gls{DTLifreal}\marg{1,000}\marg{real}\marg{not real}.
\codepar
1,000.0: \gls{DTLifreal}\marg{1,000.0}\marg{real}\marg{not real}.
\codepar
1e+3: \gls{DTLifreal}\marg{1e+3}\marg{real}\marg{not real}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
1,000.0: \gls{DTLifreal}\marg{1,000.0}\marg{real}\marg{not real}.
\codepar
1.000,0: \gls{DTLifreal}\marg{1.000,0}\marg{real}\marg{not real}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:ifreal},link={sec:ifrealex},
 title={Test for Real Value},
 description={Example document illustrating decimal tests}
]
{%
  \cmd{usepackage}\marg{datatool-base}
}
{%
1000.0: \gls{DTLifreal}\marg{1000.0}\marg{real}\marg{not real}.
\codepar
1,000: \gls{DTLifreal}\marg{1,000}\marg{real}\marg{not real}.
\codepar
1,000.0: \gls{DTLifreal}\marg{1,000.0}\marg{real}\marg{not real}.
\codepar
1e+3: \gls{DTLifreal}\marg{1e+3}\marg{real}\marg{not real}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
1,000.0: \gls{DTLifreal}\marg{1,000.0}\marg{real}\marg{not real}.
\codepar
1.000,0: \gls{DTLifreal}\marg{1.000,0}\marg{real}\marg{not real}.
}
\end{resultbox}

\paragraph{Test if Currency Example}
\label{sec:ifcurrex}

\mExampleref{ex:ifcurr} uses \gls{DTLifcurrency} and
\gls{DTLifcurrencyunit} to determine if the argument is a currency
value or a \idx{currencysym} according to the current localisation
setting and defined \idxpl{currencysym}. 

\begin{codebox*}
\gls{cs.dollar}5.99: \gls{DTLifcurrency}\marg{\gls{cs.dollar}5.99}\marg{currency}\marg{not currency}.
\codepar
\gls{DTLcurrency}\marg{5.99}:
\gls{DTLifcurrency}\marg{\gls{DTLcurrency}\marg{5.99}}\marg{currency}\marg{not currency}.
\codepar
\gls{pounds}5.99:
\gls{DTLifcurrency}\marg{\gls{pounds}5.99}\marg{currency}\marg{not currency}.
\codepar
\gls{textsterling}5.99:
\gls{DTLifcurrency}\marg{\gls{textsterling}5.99}\marg{currency}\marg{not currency}.
\codepar
\gls{cs.dollar}6.99:
\gls{DTLifcurrencyunit}\marg{\gls{cs.dollar}6.99}\marg{\gls{cs.dollar}}\marg{dollars}\marg{not dollars}.
\codepar
\cmd{newcommand}\marg{\cmd{cost}}\marg{\gls{pounds}10.50}\comment{}
\cmd{cost}: \gls{DTLifcurrencyunit}\marg{\cmd{cost}}\marg{\gls{pounds}}\marg{pounds}\marg{not pounds}.
\codepar
US\gls{cs.dollar}5.99:
\gls{DTLifcurrency}\marg{US\gls{cs.dollar}}\marg{currency}\marg{not currency}.
\codepar
\gls{DTLnewcurrencysymbol}\marg{US\gls{cs.dollar}}\comment{}
US\gls{cs.dollar}5.99:
\gls{DTLifcurrency}\marg{US\gls{cs.dollar}}\marg{currency}\marg{not currency}.
\end{codebox*}
\begin{resultbox}
\createexample*[label={ex:ifcurr},link={sec:ifcurrex},
 title={Test for Currency},
 description={Example document demonstrating tests for currency
values}]
{%
  \cmd{usepackage}\marg{datatool-base}
}
{%
\gls{cs.dollar}5.99:
\gls{DTLifcurrency}\marg{\gls{cs.dollar}5.99}\marg{currency}\marg{not currency}.
\codepar
\gls{DTLcurrency}\marg{5.99}:
\gls{DTLifcurrency}\marg{\gls{DTLcurrency}\marg{5.99}}\marg{currency}\marg{not currency}.
\codepar
\gls{pounds}5.99:
\gls{DTLifcurrency}\marg{\gls{pounds}5.99}\marg{currency}\marg{not currency}.
\codepar
\gls{textsterling}5.99:
\gls{DTLifcurrency}\marg{\gls{textsterling}5.99}\marg{currency}\marg{not currency}.
\codepar
\gls{cs.dollar}6.99:
\gls{DTLifcurrencyunit}\marg{\gls{cs.dollar}6.99}\marg{\gls{cs.dollar}}\marg{dollars}\marg{not
dollars}.
\codepar
\cmd{newcommand}\marg{\cmd{cost}}\marg{\gls{pounds}10.50}\comment{}
\cmd{cost}: \gls{DTLifcurrencyunit}\marg{\cmd{cost}}\marg{\gls{pounds}}\marg{pounds}\marg{not pounds}.
\codepar
US\gls{cs.dollar}5.99:
\gls{DTLifcurrency}\marg{US\gls{cs.dollar}}\marg{currency}\marg{not currency}.
\codepar
\gls{DTLnewcurrencysymbol}\marg{US\gls{cs.dollar}}\comment{}
US\gls{cs.dollar}5.99:
\gls{DTLifcurrency}\marg{US\gls{cs.dollar}}\marg{currency}\marg{not currency}.
}
\end{resultbox}

\paragraph{Test if Numerical Example}
\label{sec:ifnumex}

\mExampleref{ex:ifnum} uses \gls{DTLifnumerical} to determine if the
argument is numerical (integer, real or currency value) according to 
the current localisation setting and defined \idxpl{currencysym}.

\begin{codebox}
1,234: \gls{DTLifnumerical}\marg{1,234}\marg{numeric}\marg{not numeric}.
\codepar
1,234.0: \gls{DTLifnumerical}\marg{1,234.0}\marg{numeric}\marg{not numeric}.
\codepar
\gls{cs.dollar}1,234.0:
\gls{DTLifnumerical}\marg{\gls{cs.dollar}1,234.0}\marg{numeric}\marg{not numeric}.
\codepar
1.234,0: \gls{DTLifnumerical}\marg{1.234,0}\marg{numeric}\marg{not numeric}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
1.234,0: \gls{DTLifnumerical}\marg{1.234,0}\marg{numeric}\marg{not numeric}.
\codepar
Empty: \gls{DTLifnumerical}\marg{}\marg{numeric}\marg{not numeric}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:ifnum},link={sec:ifnumex},
 title={Test for Numerical},
 description={Example document demonstrating tests for numeric
values}]
{%
  \cmd{usepackage}\marg{datatool-base}
}
{%
1,234: \gls{DTLifnumerical}\marg{1,234}\marg{numeric}\marg{not numeric}.
\codepar
1,234.0: \gls{DTLifnumerical}\marg{1,234.0}\marg{numeric}\marg{not numeric}.
\codepar
\gls{cs.dollar}1,234.0:
\gls{DTLifnumerical}\marg{\gls{cs.dollar}1,234.0}\marg{numeric}\marg{not numeric}.
\codepar
1.234,0: \gls{DTLifnumerical}\marg{1.234,0}\marg{numeric}\marg{not numeric}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
1.234,0: \gls{DTLifnumerical}\marg{1.234,0}\marg{numeric}\marg{not numeric}.
\codepar
Empty: \gls{DTLifnumerical}\marg{}\marg{numeric}\marg{not numeric}.
}
\end{resultbox}

\paragraph{Test if String Example}
\label{sec:ifstrex}

\mExampleref{ex:ifstr} uses \gls{DTLifstring} to test if the argument
is considered a string (that is, not numeric and not empty).

\begin{codebox}
1,234: \gls{DTLifstring}\marg{1,234}\marg{string}\marg{not string}.
\codepar
\gls{cs.dollar}1,234.0: \gls{DTLifstring}\marg{\gls{cs.dollar}1,234.0}\marg{string}\marg{not string}.
\codepar
1,2,3,4: \gls{DTLifstring}\marg{1,2,3,4}\marg{string}\marg{not string}.
\codepar
Empty: \gls{DTLifstring}\marg{}\marg{string}\marg{not string}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:ifstr},link={sec:ifstrex},
 title={Test for Strings},
 description={Example document demonstrating tests for string
(non-numeric) values}
]
{%
  \cmd{usepackage}\marg{datatool-base}
}
{%
1,234: \gls{DTLifstring}\marg{1,234}\marg{string}\marg{not string}.
\codepar
\gls{cs.dollar}1,234.0: \gls{DTLifstring}\marg{\gls{cs.dollar}1,234.0}\marg{string}\marg{not string}.
\codepar
1,2,3,4: \gls{DTLifstring}\marg{1,2,3,4}\marg{string}\marg{not string}.
\codepar
Empty: \gls{DTLifstring}\marg{}\marg{string}\marg{not string}.
}
\end{resultbox}

\paragraph{Test Data Type Example}
\label{sec:ifcasedataex}

\mExampleref{ex:ifcasedata} uses \gls{DTLifcasedatatype} to determine
the data type of its argument, according to the current localisation
setting and known \idxpl{currencysym}.

\begin{codebox}
1,234: \gls{DTLifcasedatatype}\marg{1,234}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
1,234.0: \gls{DTLifcasedatatype}\marg{1,234.0}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
\gls{cs.dollar}1,234: \gls{DTLifcasedatatype}\marg{\gls{cs.dollar}1,234}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
1,2,3,4: \gls{DTLifcasedatatype}\marg{1,2,3,4}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
Empty: \gls{DTLifcasedatatype}\marg{}\marg{string}\marg{int}\marg{real}\marg{currency}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:ifcasedata},link={sec:ifcasedataex},
 title={Test for Data Type},
 description={Example document demonstrating case tests for data type}
]
{%
  \cmd{usepackage}\marg{datatool-base}
}
{%
1,234: \gls{DTLifcasedatatype}\marg{1,234}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
1,234.0: \gls{DTLifcasedatatype}\marg{1,234.0}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
\gls{cs.dollar}1,234: \gls{DTLifcasedatatype}\marg{\gls{cs.dollar}1,234}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
1,2,3,4: \gls{DTLifcasedatatype}\marg{1,2,3,4}\marg{string}\marg{int}\marg{real}\marg{currency}.
\codepar
Empty: \gls{DTLifcasedatatype}\marg{}\marg{string}\marg{int}\marg{real}\marg{currency}.
}
\end{resultbox}

\subsubsection{String and List Conditionals}
\label{sec:strif}

\begin{warning}
The implementation of these commands has changed in v3.0. You may
find different behaviour in certain cases. 
You can rollback if necessary (see \sectionref{sec:rollback}).
The \sty{datatool-base} package no longer loads the \sty{substr}
package. If you want to use any commands provided by that package
you will need to load it separately.
\end{warning}

\cmddef{DTLifinlist}
Does \meta{true} if \meta{element} is an element of the \idx{CSV}
\meta{list}, otherwise does \meta{false}. The \meta{list} may be a
command whose definition is a \idx{CSV} list (see
\sectionref{sec:csvlists}). No \idx{expansion} on \meta{element}.
See \exampleref{ex:DTLifinlist}.

The following comparison commands test for lexicographically
equality, less than (comes before) and greater than (comes after).
The string arguments have a single expansion applied on the
first token and then they are expanded in the same way as for
\gls{dtlcompare} and \gls{dtlicompare}, taking into account the
\opt{compare} settings (see \exampleref{ex:streq}).

\cmddef{DTLifstringeq}
Does \meta{true} if \meta{str1} is lexicographically equal to
\meta{str2}. This command is robust. The starred version ignores
case (see \exampleref{ex:streq}).

\cmddef{DTLifstringlt}
Does \meta{true} if \meta{str1} is lexicographically less than
(comes before) \meta{str2}. This command is robust. The starred version ignores
case (see \exampleref{ex:strlt}).

\cmddef{DTLifstringgt}
Does \meta{true} if \meta{str1} is lexicographically greater than
(comes after) \meta{str2}. This command is robust. The starred version ignores
case (see \exampleref{ex:strgt}).

\cmddef{DTLifstringopenbetween}
Does \meta{true} if \meta{str} is lexicographically between
\meta{min} and \meta{max}, but is not equal to \meta{min} or
\meta{max}. This command is robust. The starred version ignores
case (see \exampleref{ex:strcmp}).

\cmddef{DTLifstringclosedbetween}
Does \meta{true} if \meta{str} is lexicographically between
\meta{min} and \meta{max}, inclusive. This command is robust. The
starred version ignores case (see \exampleref{ex:strcmp}).


\cmddef{DTLifSubString}
Does \meta{true} if \meta{fragment} is a substring of \meta{string}
otherwise does \meta{false}. This command \idxc{purify}{purifies} the string and
fragment before searching for the substring. This command is
robust. The starred version is case-insensitive. A space character, \idx{nbsp},
\gls{nobreakspace} and \gls{space} are considered identical (see
\exampleref{ex:substrif}).
Note that this does not take category codes into account.

\cmddef{DTLifStartsWith}
Similar to \gls{DTLifSubString} but tests if \meta{string} starts
with \meta{fragment} (see \exampleref{ex:prefixif}).
Note that this does not take category codes into account.

\begin{information}
A bug in earlier versions of \sty{datatool-base} meant that
\gls{DTLifStartsWith} didn't ignore commands despite the
documentation. This has now been corrected in v3.0.
\end{information}

\cmddef{DTLifEndsWith}
Similar to \gls{DTLifSubString} but tests if \meta{string} ends
with \meta{fragment}. The starred version is case-insensitive.
Note that this does not take category codes into account.

\cmddef{DTLifAllUpperCase}
Does \meta{true} if \meta{string} contains only \idx{uppercase}
characters (disregarding punctuation and spaces), otherwise 
does \meta{false}. The \meta{string} is
expanded before testing. This command is robust (see
\exampleref{ex:suffixif}).

\cmddef{DTLifAllLowerCase}
Does \meta{true} if \meta{string} contains only \idx{lowercase}
characters (disregarding punctuation and spaces), otherwise does
\meta{false}. The \meta{string} is expanded before testing. This
command is robust.

\begin{information}
Robust commands like \csfmt{emph} are disregarded by the all
upper/lower case conditionals, as illustrated in \exampleref{ex:ifallcase}.
\end{information}

\paragraph{Element in List Example}
\label{sec:inlistex}

\mExampleref{ex:DTLifinlist} defines the following commands:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{goose}}\marg{goose}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{duck,\cmd{goose},\marg{ant},zebra}
\end{codebox}
\gls{DTLifinlist} is used to determine if certain items are the list:
\begin{codebox}
`ant' in list?  \gls{DTLifinlist}\marg{ant}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\end{codebox}
The following tests if \qt{goose} is an element of the list. This is
false, because the actual element is \csfmt{goose}. The
\csfmt{mylist} command is only expanded once not fully.
\begin{codebox}
\codepar
`goose' in list?  \gls{DTLifinlist}\marg{goose}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`\cmd{goose}' in list?  \gls{DTLifinlist}\marg{\cmd{goose}}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`duck' in list?  \gls{DTLifinlist}\marg{duck}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`zebra' in list?  \gls{DTLifinlist}\marg{zebra}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:DTLifinlist},link={sec:inlistex},
 title={Testing if an Element is in a Comma-Separated List},
 description={Example document demonstrating \cmd{DTLifinlist}
 highlighting when expansion occurs}
]
{
  \cmd{usepackage}\marg{datatool-base}\nl
  \cmd{newcommand}\marg{\cmd{goose}}\marg{goose}\nl
  \cmd{newcommand}\marg{\cmd{mylist}}\marg{duck,\cmd{goose},\marg{ant},zebra}
}
{
`ant' in list?  \gls{DTLifinlist}\marg{ant}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`goose' in list?  \gls{DTLifinlist}\marg{goose}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`\cmd{goose}' in list?  \gls{DTLifinlist}\marg{\cmd{goose}}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`duck' in list?  \gls{DTLifinlist}\marg{duck}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`zebra' in list?  \gls{DTLifinlist}\marg{zebra}\marg{\cmd{mylist}}\marg{true}\marg{false}.
}
\end{resultbox}

\paragraph{String Equality Example}
\label{sec:streqex}

\mExampleref{ex:streq} defines two commands that expand to \qt{zebra}
and \qt{Zebra}.
\begin{codebox}
\cmd{newcommand}\marg{\cmd{strA}}\marg{zebra}
\cmd{newcommand}\marg{\cmd{strB}}\marg{Zebra}
\end{codebox}
The initial first token expansion will expand these commands once before
applying the rules according to the current \opt{compare}
setting.
\begin{codebox}
`\cmd{strA}' is 
\gls{DTLifstringeq}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{the same}\marg{not the same}
as `\cmd{strB}' (case).
\codepar
`\cmd{strA}' is 
\gls{DTLifstringeq}*\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{the same}\marg{not the same}
as `\cmd{strB}' (no case).
\codepar
`\cmd{strA}' is 
\gls{DTLifstringeq}\marg{\cmd{strA}}\marg{zebra}\marg{the same}\marg{not the same}
as `zebra' (case).
\end{codebox}
The command \csfmt{emph} is robust so it
won't be expanded by the initial expand first token action in the following:
\begin{codebox}
`\cmd{emph}\marg{ant}' is
\gls{DTLifstringeq}\marg{\cmd{emph}\marg{ant}}\marg{ant}\marg{the same}\marg{not the same}
as `ant'.
\end{codebox}
The default \compareoptval{expand-cs}{false} and 
\compareoptval{skip-cs}{false} settings mean that commands won't be
skipped in the comparison. Note the difference when the setting is
changed:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{compare}{\compareopt{skip-cs}}}
`\cmd{emph}\marg{ant}' is
\gls{DTLifstringeq}\marg{\cmd{emph}\marg{ant}}\marg{ant}\marg{the same}\marg{not the same}
as `ant' (skip cs).
\end{codebox}
Only the first token is expanded, so \csfmt{strA} isn't expanded in
the initial step:
\begin{codebox}
`ant zebra' is
\gls{DTLifstringeq}\marg{ant zebra}\marg{ant \cmd{strA}}\marg{the same}\marg{not the same}
as `ant \cmd{strA}' (no expansion).
\end{codebox}
With \compareoptval{expand-cs}{true}, expansion will be applied in
the second step:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{compare}{\compareopt{expand-cs}}}
`ant zebra' is
\gls{DTLifstringeq}\marg{ant zebra}\marg{ant \cmd{strA}}\marg{the same}\marg{not the same}
as `ant \cmd{strA}' (expansion).
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:streq},link={sec:streqex},
 title={String Equality Tests},
 description={Example document demonstrating string equality
commands}
]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{strA}}\marg{zebra}\nl
\cmd{newcommand}\marg{\cmd{strB}}\marg{Zebra}
}%
{%
`\cmd{strA}' is \gls{DTLifstringeq}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{the
same}\marg{not the same}
as `\cmd{strB}' (case).
\codepar
`\cmd{strA}' is \gls{DTLifstringeq}*\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{the
same}\marg{not the same}
as `\cmd{strB}' (no case).
\codepar
`\cmd{strA}' is \gls{DTLifstringeq}\marg{\cmd{strA}}\marg{zebra}\marg{the
same}\marg{not the same}
as `zebra' (case).
\codepar
`\cmd{emph}\marg{ant}' is
\gls{DTLifstringeq}\marg{\cmd{emph}\marg{ant}}\marg{ant}\marg{the same}\marg{not the same}
as `ant'.
\codepar
\gls{DTLsetup}\marg{\optvalm{compare}{\compareopt{skip-cs}}}
`\cmd{emph}\marg{ant}' is
\gls{DTLifstringeq}\marg{\cmd{emph}\marg{ant}}\marg{ant}\marg{the same}\marg{not the same}
as `ant' (skip cs).
\codepar
`ant zebra' is
\gls{DTLifstringeq}\marg{ant zebra}\marg{ant \cmd{strA}}\marg{the same}\marg{not the same}
as `ant \cmd{strA}' (no expansion).
\codepar
\gls{DTLsetup}\marg{\optvalm{compare}{\compareopt{expand-cs}}}
`ant zebra' is
\gls{DTLifstringeq}\marg{ant zebra}\marg{ant \cmd{strA}}\marg{the same}\marg{not the same}
as `ant \cmd{strA}' (expansion).
}
\end{resultbox}

\paragraph{String Less Than Example}
\label{sec:strltex}

\mExampleref{ex:strlt} uses \gls{DTLifstringlt} to determine if one
string is \qt{less than} (comes before) another.
\begin{codebox}
`aardvark' is \gls{DTLifstringlt}\marg{aardvark}\marg{Zebra}\marg{before}\marg{after}
`Zebra' (case).
\codepar
`aardvark' is \gls{DTLifstringlt}*\marg{aardvark}\marg{Zebra}\marg{before}\marg{after}
`Zebra' (no case).
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:strlt},
 title={String Less Than},link={sec:strltex},
 description={Example document demonstrating string less than
command}
]
{%
\cmd{usepackage}\marg{datatool-base}
}%
{%
`aardvark' is\nl
\gls{DTLifstringlt}\marg{aardvark}\marg{Zebra}\marg{before}\marg{after}\nl
`Zebra' (case).
\codepar
`aardvark' is\nl
\gls{DTLifstringlt}*\marg{aardvark}\marg{Zebra}\marg{before}\marg{after}\nl
`Zebra' (no case).
}
\end{resultbox}

\paragraph{String Greater Than Example}
\label{sec:strgtex}

\mExampleref{ex:strgt} produces the same result as
\exampleref{ex:strlt} but tests for \qt{greater than} (comes after)
instead:
\begin{codebox}
`aardvark' is \gls{DTLifstringgt}\marg{aardvark}\marg{Zebra}\marg{after}\marg{before}
`Zebra' (case).
\codepar
`aardvark' is \gls{DTLifstringgt}*\marg{aardvark}\marg{Zebra}\marg{after}\marg{before}
`Zebra' (no case).
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:strgt},
 title={String Greater Than},link={sec:strgtex},
 description={Example document demonstrating string greater than
command}
]
{%
\cmd{usepackage}\marg{datatool-base}
}%
{%
`aardvark' is\nl
\gls{DTLifstringgt}\marg{aardvark}\marg{Zebra}\marg{after}\marg{before}\nl
`Zebra' (case).
\codepar
`aardvark' is\nl
\gls{DTLifstringgt}*\marg{aardvark}\marg{Zebra}\marg{after}\marg{before}\nl
`Zebra' (no case).
}
\end{resultbox}

\paragraph{String Between Two Strings Example}
\label{sec:strbetweenex}

\mExampleref{ex:strcmp} tests if a string is lexicographically
between two other strings:
\begin{codebox}
`duck' lies between `Duck' and `Duckling' 
 (exclusive, case)?
\gls{DTLifstringopenbetween}\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
\codepar
`duck' lies between `Duck' and `Duckling'
 (exclusive, no case)?
\gls{DTLifstringopenbetween}*\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
\codepar
`duck' lies between `Duck' and `Duckling'
 (inclusive, case)?
\gls{DTLifstringclosedbetween}\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
\codepar
`duck' lies between `Duck' and `Duckling'
 (inclusive, no case)?
\gls{DTLifstringclosedbetween}*\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:strcmp},link={sec:strbetweenex},
 title={String Between Tests},
 description={Example document demonstrating string between comparison
commands}
]
{%
\cmd{usepackage}\marg{datatool-base}
}%
{%
`duck' lies between `Duck' and `Duckling' (exclusive, case)?\nl
\gls{DTLifstringopenbetween}\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
\codepar
`duck' lies between `Duck' and `Duckling' (exclusive, no case)?\nl
\gls{DTLifstringopenbetween}*\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
\codepar
`duck' lies between `Duck' and `Duckling' (inclusive, case)?\nl
\gls{DTLifstringclosedbetween}\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
\codepar
`duck' lies between `Duck' and `Duckling' (inclusive, no case)?\nl
\gls{DTLifstringclosedbetween}*\marg{duck}\marg{Duck}\marg{Duckling}\marg{true}\marg{false}.
}
\end{resultbox}

\paragraph{Substring Example}
\label{sec:substrex}

\mExampleref{ex:substrif} defines some commands that expand to text
with a normal space and with a non-breakable space:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{strA}}\marg{An apple}
\cmd{newcommand}\marg{\cmd{strB}}\marg{n\idx{nbsp}ap}
\end{codebox}
The \gls{DTLifSubString} command is used to test if the second
argument is a substring of the first:
\begin{codebox}
(First two arguments expanded) `\cmd{strB}' 
\gls{DTLifSubString}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{is substring}\marg{isn't substring}
of `\cmd{strA}'.
\codepar
`app'
\gls{DTLifSubString}\marg{An apple}\marg{app}\marg{is substring}\marg{isn't substring}
of `An apple'.
\codepar
(Non-breakable space same as space) `n\idx{nbsp}a'
\gls{DTLifSubString}\marg{An apple}\marg{n\idx{nbsp}a}\marg{is substring}\marg{isn't substring}
of `An apple'.
\codepar
(Robust commands stripped) `app'
\gls{DTLifSubString}\marg{An \gls{MakeUppercase}\marg{a}pple}\marg{app}\marg{is substring}\marg{isn't substring}
of `An \gls{MakeUppercase}\marg{a}pple'.
\codepar
(Grouping stripped) `app'
\gls{DTLifSubString}\marg{An \marg{ap}ple}\marg{app}\marg{is substring}\marg{isn't substring}
of `An \marg{ap}ple'.
\codepar
(Case-sensitive) `app'
\gls{DTLifSubString}\marg{An Apple}\marg{app}\marg{is substring}\marg{isn't substring}
of `An Apple'.
\codepar
(Not case-sensitive) `app'
\gls{DTLifSubString}*\marg{An Apple}\marg{app}\marg{is substring}\marg{isn't substring}
of `An Apple'.
\codepar
(Leading space) ` app'
\gls{DTLifSubString}\marg{Anapple}\marg{ app}\marg{is substring}\marg{isn't substring}
of `Anapple'.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:substrif},
  title={Substring Tests},link={sec:substrex},
  description={Example document demonstrating substring tests}
]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{strA}}\marg{An apple}\nl
\cmd{newcommand}\marg{\cmd{strB}}\marg{n\string~ap}
}%
{%
(First two arguments expanded) `\cmd{strB}' \nl
\gls{DTLifSubString}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{is
substring}\marg{isn't substring}\nl
of `\cmd{strA}'.
\codepar
`app'\nl
\gls{DTLifSubString}\marg{An apple}\marg{app}\marg{is
substring}\marg{isn't substring}\nl
of `An apple'.
\codepar
(Non-breakable space same as space) `n\string~a'\nl
\gls{DTLifSubString}\marg{An apple}\marg{n\string~a}\marg{is
substring}\marg{isn't substring}\nl
of `An apple'.
\codepar
(Robust commands stripped) `app'\nl
\gls{DTLifSubString}\marg{An
\gls{MakeUppercase}\marg{a}pple}\marg{app}\marg{is
substring}\marg{isn't substring}\nl
of `An \gls{MakeUppercase}\marg{a}pple'.
\codepar
(Grouping stripped) `app'\nl
\gls{DTLifSubString}\marg{An \marg{ap}ple}\marg{app}\marg{is
substring}\marg{isn't substring}\nl
of `An \marg{ap}ple'.
\codepar
(Case-sensitive) `app'\nl
\gls{DTLifSubString}\marg{An Apple}\marg{app}\marg{is
substring}\marg{isn't substring}\nl
of `An Apple'.
\codepar
(Not case-sensitive) `app'
\gls{DTLifSubString}*\marg{An Apple}\marg{app}\marg{is
substring}\marg{isn't substring}\nl
of `An Apple'.
\codepar
(Leading space) ` app'\nl
\gls{DTLifSubString}\marg{Anapple}\marg{ app}\marg{is
substring}\marg{isn't substring}\nl
of `Anapple'.
}
\end{resultbox}

\paragraph{String Prefix Example}
\label{sec:prefixifex}

\mExampleref{ex:prefixif} uses
\gls{DTLifStartsWith} to test if the second argument is at the start
(is a prefix) of the first:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{strA}}\marg{An apple}
\cmd{newcommand}\marg{\cmd{strB}}\marg{n\idx{nbsp}ap}
\cmd{newcommand}\marg{\cmd{strC}}\marg{An\idx{nbsp}ap}
\codepar
(First two arguments expanded) `\cmd{strB}'
\gls{DTLifStartsWith}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{is prefix}\marg{isn't prefix}
of `\cmd{strA}'.
\codepar
(First two arguments expanded) `\cmd{strC}' 
\gls{DTLifStartsWith}\marg{\cmd{strA}}\marg{\cmd{strC}}\marg{is prefix}\marg{isn't prefix}
of `\cmd{strA}'.
\codepar
(Non-breakable space same as space) `An\string~a'
\gls{DTLifStartsWith}\marg{An apple}\marg{An\idx{nbsp}a}\marg{is prefix}\marg{isn't prefix}
of `An apple'.
\codepar
(Robust commands stripped) `app'
\gls{DTLifStartsWith}\marg{\gls{MakeUppercase}\marg{a}pple}\marg{app}\marg{is prefix}\marg{isn't prefix}
of `\gls{MakeUppercase}\marg{a}pple'.
\codepar
(Case-sensitive) `app'
\gls{DTLifStartsWith}\marg{Apple}\marg{app}\marg{is prefix}\marg{isn't prefix}
of `Apple'.
\codepar
(Ignore case) `app'
\gls{DTLifStartsWith}*\marg{Apple}\marg{app}\marg{is prefix}\marg{isn't prefix}
of `Apple'.
\codepar
(Trailing space) `an '
\gls{DTLifStartsWith}\marg{an apple}\marg{an }\marg{is prefix}\marg{isn't prefix}
of `an apple'.
\codepar
(Trailing space) `an '
\gls{DTLifStartsWith}\marg{anapple}\marg{an }\marg{is prefix}\marg{isn't prefix}
of `anapple'.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:prefixif},
  title={Prefix Tests},link={sec:prefixifex},
  description={Example document demonstrating prefix tests}
]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{strA}}\marg{An apple}\nl
\cmd{newcommand}\marg{\cmd{strB}}\marg{n\string~ap}\nl
\cmd{newcommand}\marg{\cmd{strC}}\marg{An\string~ap}
}
{%
(First two arguments expanded) `\cmd{strB}' \nl
\gls{DTLifStartsWith}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{is
prefix}\marg{isn't prefix}\nl
of `\cmd{strA}'.
\codepar
(First two arguments expanded) `\cmd{strC}' \nl
\gls{DTLifStartsWith}\marg{\cmd{strA}}\marg{\cmd{strC}}\marg{is
prefix}\marg{isn't prefix}\nl
of `\cmd{strA}'.
\codepar
(Non-breakable space same as space) `An\string~a'\nl
\gls{DTLifStartsWith}\marg{An apple}\marg{An\string~a}\marg{is
prefix}\marg{isn't prefix}\nl
of `An apple'.
\codepar
(Robust commands stripped) `app'\nl
\gls{DTLifStartsWith}\marg{\gls{MakeUppercase}\marg{a}pple}{app}{is
prefix}{isn't prefix}\nl
of `\gls{MakeUppercase}\marg{a}pple'.
\codepar
(Case-sensitive) `app'\nl
\gls{DTLifStartsWith}\marg{Apple}\marg{app}\marg{is
prefix}\marg{isn't prefix}\nl
of `Apple'.
\codepar
(Ignore case) `app'\nl
\gls{DTLifStartsWith}*\marg{Apple}\marg{app}\marg{is
prefix}\marg{isn't prefix}\nl
of `Apple'.
\codepar
(Trailing space) `an '\nl
\gls{DTLifStartsWith}\marg{an apple}\marg{an }\marg{is
prefix}\marg{isn't prefix}\nl
of `an apple'.
\codepar
(Trailing space) `an '\nl
\gls{DTLifStartsWith}\marg{anapple}\marg{an }\marg{is
prefix}\marg{isn't prefix}\nl
of `anapple'.
}
\end{resultbox}

\paragraph{String Suffix Example}
\label{sec:suffixifex}

\mExampleref{ex:suffixif} uses
\gls{DTLifEndsWith} to test if the second argument is at the end
(is a suffix) of the first. It uses the same \csfmt{strA} and
\csfmt{strB} as before:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{strA}}\marg{An apple}
\cmd{newcommand}\marg{\cmd{strB}}\marg{n\idx{nbsp}apple}
\end{codebox}
The tests are as follows:
\begin{codebox}
(First two arguments expanded) `\cmd{strB}'
\gls{DTLifEndsWith}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{is suffix}\marg{isn't suffix}
of `\cmd{strA}'.
\codepar
(Non-breakable space same as space) `n\string~apple'
\gls{DTLifEndsWith}\marg{An apple}\marg{n\idx{nbsp}apple}\marg{is suffix}\marg{isn't suffix}
of `An apple'.
\codepar
(Robust commands stripped) `apple'
\gls{DTLifEndsWith}\marg{An \gls{MakeUppercase}\marg{a}pple}\marg{apple}\marg{is suffix}\marg{isn't suffix}
of `An \gls{MakeUppercase}\marg{a}pple'.
\codepar
(Case-sensitive) `apple'
\gls{DTLifEndsWith}\marg{An Apple}\marg{apple}\marg{is suffix}\marg{isn't suffix}
of `An Apple'.
\codepar
(Ignore case) `apple'
\gls{DTLifEndsWith}*\marg{An Apple}\marg{apple}\marg{is suffix}\marg{isn't suffix}
of `An Apple'.
\codepar
(Leading space) ` apple'
\gls{DTLifEndsWith}\marg{anapple}\marg{ apple}\marg{is suffix}\marg{isn't suffix}
of `anapple'.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:suffixif},link={sec:suffixifex},
  title={Suffix Tests},
  description={Example document demonstrating suffix tests}
]
{%
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{strA}}\marg{An apple}\nl
\cmd{newcommand}\marg{\cmd{strB}}\marg{n\string~apple}\nl
}
{%
(First two arguments expanded) `\cmd{strB}'\nl
\gls{DTLifEndsWith}\marg{\cmd{strA}}\marg{\cmd{strB}}\marg{is
suffix}\marg{isn't suffix}\nl
of `\cmd{strA}'.
\codepar
(Non-breakable space same as space) `n\string~apple'\nl
\gls{DTLifEndsWith}\marg{An apple}\marg{n\string~apple}\marg{is
suffix}\marg{isn't suffix}\nl
of `An apple'.
\codepar
(Robust commands stripped) `apple'\nl
\gls{DTLifEndsWith}\marg{An
\gls{MakeUppercase}\marg{a}pple}\marg{apple}\marg{is
suffix}\marg{isn't suffix}\nl
of `An \gls{MakeUppercase}\marg{a}pple'.
\codepar
(Case-sensitive) `apple'\nl
\gls{DTLifEndsWith}\marg{An Apple}\marg{apple}\marg{is
suffix}\marg{isn't suffix}\nl
of `An Apple'.
\codepar
(Ignore case) `apple'\nl
\gls{DTLifEndsWith}*\marg{An Apple}\marg{apple}\marg{is
suffix}\marg{isn't suffix}\nl
of `An Apple'.
\codepar
(Leading space) ` apple'\nl
\gls{DTLifEndsWith}\marg{an apple}\marg{ apple}\marg{is
suffix}\marg{isn't suffix}\nl
of `an apple'.
\codepar
(Leading space) ` apple'\nl
\gls{DTLifEndsWith}\marg{anapple}\marg{ apple}\marg{is
suffix}\marg{isn't suffix}\nl
of `anapple'.
}
\end{resultbox}

\paragraph{String Case Example}
\label{sec:ifallcaseex}

\mExampleref{ex:ifallcase} tests if the argument (once expanded and
purified) is all the same case:
\begin{codebox}
café: \gls{DTLifAllUpperCase}\marg{café}\marg{all caps}\marg{not all caps}.
\codepar
Café: \gls{DTLifAllUpperCase}\marg{Café}\marg{all caps}\marg{not all caps}.
\codepar
CAFÉ: \gls{DTLifAllUpperCase}\marg{CAFÉ}\marg{all caps}\marg{not all caps}.
\codepar
café: \gls{DTLifAllLowerCase}\marg{café}\marg{all lower}\marg{not all lower}.
\codepar
Café: \gls{DTLifAllLowerCase}\marg{Café}\marg{all lower}\marg{not all lower}.
\codepar
CAFÉ: \gls{DTLifAllLowerCase}\marg{CAFÉ}\marg{all lower}\marg{not all lower}.
\codepar
bric-\cmd{`}a-brac: 
\gls{DTLifAllLowerCase}\marg{bric-\cmd{`}a-brac}\marg{all lower}\marg{not all lower}.
\codepar
\cmd{emph}\marg{HORS D'\cmd{OE} UVRE}:
\gls{DTLifAllUpperCase}\marg{\cmd{emph}\marg{HORS D'\cmd{OE} UVRE}}\marg{all caps}\marg{not all caps}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:ifallcase},
 title={All Upper/Lower Case Tests},link={sec:ifallcaseex},
 description={Example document demonstrating tests for all upper or
lowercase}
]
{
\cmd{usepackage}\marg{datatool-base}
}%
{%
café: \gls{DTLifAllUpperCase}\marg{café}\marg{all caps}\marg{not all caps}.
\codepar
Café: \gls{DTLifAllUpperCase}\marg{Café}\marg{all caps}\marg{not all caps}.
\codepar
CAFÉ: \gls{DTLifAllUpperCase}\marg{CAFÉ}\marg{all caps}\marg{not all caps}.
\codepar
café: \gls{DTLifAllLowerCase}\marg{café}\marg{all lower}\marg{not all lower}.
\codepar
Café: \gls{DTLifAllLowerCase}\marg{Café}\marg{all lower}\marg{not all lower}.
\codepar
CAFÉ: \gls{DTLifAllLowerCase}\marg{CAFÉ}\marg{all lower}\marg{not all lower}.
\codepar
bric-\cmd{`}a-brac: 
\gls{DTLifAllLowerCase}\marg{bric-\cmd{`}a-brac}\marg{all lower}\marg{not all lower}.
\codepar
\cmd{emph}\marg{HORS D'\cmd{OE} UVRE}:
\gls{DTLifAllUpperCase}\marg{\cmd{emph}\marg{HORS D'\cmd{OE} UVRE}}\marg{all caps}\marg{not all caps}.
}
\end{resultbox}


\subsubsection{Formatted Number Conditionals}
\label{sec:fmtnumif}

These commands expect \idxpl{formattednumber} or \idxpl{datumcs} in
the numerical arguments and compare their values. They
internally use the corresponding command from
\sectionref{sec:plainnumif} after parsing to perform the actual
comparison.

\cmddef{DTLifnumeq}
Does \meta{true} if \meta{num1} equals \meta{num2}
($\meta{num1} = \meta{num2}$) otherwise does
\meta{false}, where the values are \idxpl{formattednumber}.
This command is \idx{robust}. Internally uses \gls{dtlifnumeq} after
parsing the values.

\cmddef{DTLifnumlt}
Does \meta{true} if \meta{num1} is less than \meta{num2}
($\meta{num1} < \meta{num2}$) otherwise does
\meta{false}, where the values are \idxpl{formattednumber}.
This command is \idx{robust}. Internally uses \gls{dtlifnumlt} after
parsing the values.

\cmddef{DTLifnumgt}
Does \meta{true} if \meta{num1} is greater than \meta{num2}
($\meta{num1} > \meta{num2}$) otherwise does
\meta{false}, where the values are \idxpl{formattednumber}.
This command is \idx{robust}. Internally uses \gls{dtlifnumgt} after
parsing the values.

\cmddef{DTLifnumopenbetween}
Does \meta{true} if \meta{num} lies between \meta{min} and
\meta{max}, excluding the end points (that is, $\meta{min} <
\meta{num} < \meta{max}$) otherwise does
\meta{false}, where the values are \idxpl{formattednumber}.
This command is \idx{robust}. Internally uses
\gls{dtlifnumopenbetween} after parsing the values.

\cmddef{DTLifnumclosedbetween}
Does \meta{true} if \meta{num} lies between \meta{min} and
\meta{max}, including the end points (that is, $\meta{min} \leq
\meta{num} \leq \meta{max}$) otherwise does
\meta{false}, where the values are \idxpl{formattednumber}.
This command is \idx{robust}. Internally uses
\gls{dtlifnumclosedbetween} after parsing the values.

Note that the currency unit (if given) in the above comparisons is disregarded. 
Only the numeric value obtained from parsing is considered. 
\mExampleref{ex:DTLifnum} uses the default \opteqvalref{math}{l3fp} setting.
\begin{codebox}
\$1,234.0=1234\$? \gls{DTLifnumeq}\marg{1,234.0}\marg{1234}\marg{true}\marg{false}.
\codepar
\$\gls{cs.dollar}12.00=\gls{pounds}12\$? \gls{DTLifnumeq}\marg{\gls{cs.dollar}12.00}\marg{\gls{pounds}12}\marg{true}\marg{false}.
\codepar
\$\gls{cs.dollar}10.50<\gls{pounds}10\$? \gls{DTLifnumlt}\marg{\gls{cs.dollar}10.50}\marg{\gls{pounds}10}\marg{true}\marg{false}.
\codepar
\$1,000.0 > 1,000\$? \gls{DTLifnumgt}\marg{1,000.0}\marg{1,000}\marg{true}\marg{false}.
\codepar
\$1000 < \gls{cs.dollar}1,000.00 < 2000\$?
\gls{DTLifnumopenbetween}\marg{\gls{cs.dollar}1,000.00}\marg{1000}\marg{2000}\marg{true}\marg{false}.
\codepar
\$1000 \cmd{leq} \gls{cs.dollar}1,000.00 \cmd{leq} 2000\$?
\gls{DTLifnumclosedbetween}\marg{\gls{cs.dollar}1,000.00}\marg{1000}\marg{2000}\marg{true}\marg{false}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:DTLifnum},
 title={Numerical Comparisons (Parsed)},
 description={Example document demonstrating numerical comparisons
where the numeric value is obtained by parsing the arguments}
]
{
\cmd{usepackage}\oarg{math=l3fp}\marg{datatool-base}
}%
{%
\$1,234.0 = 1234\$? \gls{DTLifnumeq}\marg{1,234.0}\marg{1234}\marg{true}\marg{false}.
\codepar
\$\gls{cs.dollar}12.00 = \gls{pounds}12\$? \gls{DTLifnumeq}\marg{\gls{cs.dollar}12.00}\marg{\gls{pounds}12}\marg{true}\marg{false}.
\codepar
\$\gls{cs.dollar}10.50 < \gls{pounds}10\$? \gls{DTLifnumlt}\marg{\gls{cs.dollar}10.50}\marg{\gls{pounds}10}\marg{true}\marg{false}.
\codepar
\$1,000.0 > 1,000\$? \gls{DTLifnumgt}\marg{1,000.0}\marg{1,000}\marg{true}\marg{false}.
\codepar
\$1000 < \gls{cs.dollar}1,000.00 < 2000\$?
\gls{DTLifnumopenbetween}\marg{\gls{cs.dollar}1,000.00}\marg{1000}\marg{2000}\marg{true}\marg{false}.
\codepar
\$1000 \cmd{leq} \gls{cs.dollar}1,000.00 \cmd{leq} 2000\$?
\gls{DTLifnumclosedbetween}\marg{\gls{cs.dollar}1,000.00}\marg{1000}\marg{2000}\marg{true}\marg{false}.
}
\end{resultbox}

\subsubsection{Plain Number Conditionals}
\label{sec:plainnumif}

\cmddef{dtlifnumeq}
Does \meta{true} if \meta{num1} equals \meta{num2} otherwise does
\meta{false}. The numbers must be \idxpl{plainnumber}.
This command is \idx{expandable} with \opteqvalref{math}{l3fp} and
\opteqvalref{math}{lua} and \idx{robust} for \opteqvalref{math}{fp} and
\opteqvalref{math}{pgfmath}.

\cmddef{dtlifnumlt}
Does \meta{true} if \meta{num1} is less than \meta{num2} otherwise does
\meta{false}. The numbers must be \idxpl{plainnumber}.
This command is \idx{expandable} with \opteqvalref{math}{l3fp} and
\opteqvalref{math}{lua} and \idx{robust} for \opteqvalref{math}{fp} and
\opteqvalref{math}{pgfmath}.

\cmddef{dtlifnumgt}
Does \meta{true} if \meta{num1} is greater than \meta{num2} otherwise does
\meta{false}. The numbers must be \idxpl{plainnumber}.
This command is \idx{expandable} with \opteqvalref{math}{l3fp} and
\opteqvalref{math}{lua} and \idx{robust} for \opteqvalref{math}{fp} and
\opteqvalref{math}{pgfmath}.

\cmddef{dtlifnumopenbetween}
Does \meta{true} if \meta{num} lies between \meta{min} and
\meta{max}, excluding the end points (that is, $\meta{min} <
\meta{num} < \meta{max}$) otherwise does
\meta{false}. The numbers must be \idxpl{plainnumber}.

\cmddef{DTLifFPopenbetween}
Synonym of \gls{dtlifnumopenbetween}.

\cmddef{dtlifintopenbetween}
As \gls{dtlifnumopenbetween} but specifically for integers. This
simply uses \gls{ifnum} for the comparisons and is not dependent on
the \opt{math} option.

\cmddef{dtlifnumclosedbetween}
Does \meta{true} if \meta{num} lies between \meta{min} and
\meta{max}, including the end points (that is, $\meta{min} \leq
\meta{num} \leq \meta{max}$) otherwise does
\meta{false}. The numbers must be \idxpl{plainnumber}.

\cmddef{DTLifFPclosedbetween}
Synonym of \gls{dtlifnumclosedbetween}.

\cmddef{dtlifintclosedbetween}
As \gls{dtlifnumclosedbetween} but specifically for integers. This
simply uses \gls{ifnum} for the comparisons and is not dependent on
the \opt{math} option.

\paragraph{Example (\optfmt{l3fp})}
\label{sec:l3fpif}

\mExampleref{ex:l3fpif} uses \gls{edef} (which defines a command with its
provided definition \idxc{expansion}{expanded}) and \gls{meaning} (which writes the
command's definition to the PDF) to demonstrate commands that can
\idxc{expansion}{expand}. Compare the results with using \opteqvalref{math}{fp}
(\exampleref{ex:fpif}) and \opteqvalref{math}{pgfmath}
(\exampleref{ex:pgfmathif}).

\begin{codebox}
\cmd{usepackage}\oarg{\opteqvalref{math}{l3fp}}\marg{datatool-base}
\cmd{newcommand}\marg{\cmd{numducks}}\marg{4}
\cbeg{document}
\gls{edef}\cmd{test}\marg{There 
 \gls{dtlifnumeq}\marg{\cmd{numducks}}\marg{1}\marg{is 1 duck}\marg{are \cmd{numducks}\gls{space} ducks}.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are
 \gls{dtlifnumlt}\marg{\cmd{numducks}}\marg{10}\marg{less than}\marg{not less than}
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are
 \gls{dtlifnumgt}\marg{\cmd{numducks}}\marg{10}\marg{more than}\marg{not more than}
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There 
 \gls{dtlifnumopenbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are not}
 between 4 and 10 ducks (exclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There 
 \gls{dtlifnumclosedbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are not}
 between 4 and 10 ducks (inclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\cend{document}
\end{codebox}

\begin{resultbox}[float]
\createexample*[label={ex:l3fpif},
 title={Conditionals (\optfmt{l3fp})},link={sec:l3fpif},
 description={Example document with LaTeX3 conditionals}
]
{%
\cmd{usepackage}\oarg{math=l3fp}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numducks}}\marg{4}
}%
{%
\gls{edef}\cmd{test}\marg{There\nlsp
 \gls{dtlifnumeq}\marg{\cmd{numducks}}\marg{1}\marg{is 1
duck}\marg{are \cmd{numducks}\gls{space} ducks}.}\nl
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumlt}\marg{\cmd{numducks}}\marg{10}\marg{less
than}\marg{not less than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumgt}\marg{\cmd{numducks}}\marg{10}\marg{more
than}\marg{not more than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumopenbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (exclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumclosedbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (inclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
}
\end{resultbox}

\paragraph{Example (\optfmt{lua})}
\label{sec:luaif}

\mExampleref{ex:luaif} is the same as \exampleref{ex:l3fpif} except that it
uses \opteqvalref{math}{lua} (and so requires \LuaLaTeX):
\begin{codebox}
\cmd{usepackage}\oarg{\opteqvalref{math}{lua}}\marg{datatool-base}
\end{codebox}

\begin{resultbox}[float]
\createexample*[label={ex:luaif},arara={lualatex,pdfcrop},
 title={Conditionals (\optfmt{lua})},link={sec:luaif},
 description={Example document with Lua conditionals}
]
{%
\cmd{usepackage}\oarg{math=lua}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numducks}}\marg{4}
}%
{%
\gls{edef}\cmd{test}\marg{There\nlsp
 \gls{dtlifnumeq}\marg{\cmd{numducks}}\marg{1}\marg{is 1
duck}\marg{are \cmd{numducks}\gls{space} ducks}.}\nl
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumlt}\marg{\cmd{numducks}}\marg{10}\marg{less
than}\marg{not less than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumgt}\marg{\cmd{numducks}}\marg{10}\marg{more
than}\marg{not more than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumopenbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (exclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumclosedbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (inclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
}
\end{resultbox}


\paragraph{Example (\optfmt{fp})}
\label{sec:fpif}

\mExampleref{ex:fpif} is the same as \exampleref{ex:l3fpif} 
except that it uses \opteqvalref{math}{fp}:
\begin{codebox}
\cmd{usepackage}\oarg{\opteqvalref{math}{fp}}\marg{datatool-base}
\end{codebox}
However, note that commands like \gls{dtlifnumeq} are now \idx{robust} and
so can't \idxc{expansion}{expand} (but \csfmt{numducks} does 
\idxc{expansion}{expand}).

\begin{resultbox}[float]
\createexample*[label={ex:fpif},
 title={Conditionals (\optfmt{fp})},link={sec:fpif},
 description={Example document with fp conditionals}
]
{%
\cmd{usepackage}\oarg{math=fp}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numducks}}\marg{4}
}%
{%
\gls{edef}\cmd{test}\marg{There\nlsp
 \gls{dtlifnumeq}\marg{\cmd{numducks}}\marg{1}\marg{is 1
duck}\marg{are \cmd{numducks}\gls{space} ducks}.}\nl
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumlt}\marg{\cmd{numducks}}\marg{10}\marg{less
than}\marg{not less than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumgt}\marg{\cmd{numducks}}\marg{10}\marg{more
than}\marg{not more than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumopenbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (exclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumclosedbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (inclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
}
\end{resultbox}

\paragraph{Example (\optfmt{pgfmath})}
\label{sec:pgfmathif}

\mExampleref{ex:pgfmathif} is the same as for
\exampleref{ex:l3fpif} except that it
uses \opteqvalref{math}{pgfmath}:
\begin{codebox}
\cmd{usepackage}\oarg{\opteqvalref{math}{pgfmath}}\marg{datatool-base}
\end{codebox}
However, note that commands like \gls{dtlifnumeq} are now \idx{robust} and
so can't \idxc{expansion}{expand} (but \csfmt{numducks} 
does \idxc{expansion}{expand}).

\begin{resultbox}[float]
\createexample*[label={ex:pgfmathif},
 title={Conditionals (\optfmt{pgfmath})},link={sec:pgfmathif},
 description={Example document with fp conditionals}
]
{%
\cmd{usepackage}\oarg{math=pgfmath}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numducks}}\marg{4}
}%
{%
\gls{edef}\cmd{test}\marg{There\nlsp
 \gls{dtlifnumeq}\marg{\cmd{numducks}}\marg{1}\marg{is 1
duck}\marg{are \cmd{numducks}\gls{space} ducks}.}\nl
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumlt}\marg{\cmd{numducks}}\marg{10}\marg{less
than}\marg{not less than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There are\nlsp
 \gls{dtlifnumgt}\marg{\cmd{numducks}}\marg{10}\marg{more
than}\marg{not more than}\nlsp
 10 ducks.}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumopenbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (exclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
\codepar
\gls{edef}\cmd{test}\marg{There \nlsp
 \gls{dtlifnumclosedbetween}\marg{\cmd{numducks}}\marg{4}\marg{10}\marg{are}\marg{are
not}\nlsp
 between 4 and 10 ducks (inclusive).}
\cmd{texttt}\marg{\gls{meaning}\cmd{test}}
\codepar
Test text: \cmd{test}
}
\end{resultbox}

\subsubsection{String or Number Conditionals}
\label{sec:strnumif}

The commands listed in this section parse the \meta{arg1} and
\meta{arg2} arguments to determine whether to use the applicable
string (\sectionref{sec:strif}) or numeric
(\sectionref{sec:fmtnumif}) command. Those arguments may also be
\idxpl{datumcs}.

\cmddef{DTLifeq}
If \meta{arg1} and \meta{arg2} are both numeric
(\idxpl{formattednumber}) then \gls{DTLifnumeq} is used otherwise
\gls{DTLifstringeq} is used. The starred version is only applicable
for string equality and will ignore the case. This command is
robust.

\cmddef{DTLiflt}
If \meta{arg1} and \meta{arg2} are both numeric
(\idxpl{formattednumber}) then \gls{DTLifnumlt} is used otherwise
\gls{DTLifstringlt} is used. The starred version is only applicable
for a string comparison and will ignore the case. This command is
robust.

\cmddef{DTLifgt}
If \meta{arg1} and \meta{arg2} are both numeric
(\idxpl{formattednumber}) then \gls{DTLifnumgt} is used otherwise
\gls{DTLifstringgt} is used. The starred version is only applicable
for a string comparison and will ignore the case. This command is
robust.

\cmddef{DTLifopenbetween}
If \meta{value}, \meta{min} and \meta{max} are all numeric
(\idxpl{formattednumber}) then \gls{DTLifnumopenbetween} is used otherwise
\gls{DTLifstringopenbetween} is used. The starred version is only applicable
for a string comparison and will ignore the case. This command is
robust.

\cmddef{DTLifclosedbetween}
If \meta{value}, \meta{min} and \meta{max} are all numeric
(\idxpl{formattednumber}) then \gls{DTLifnumclosedbetween} is used otherwise
\gls{DTLifstringclosedbetween} is used. The starred version is only applicable
for a string comparison and will ignore the case. This command is
robust.

\mExampleref{ex:DTLif} uses the above conditional commands that determine
from the arguments whether to use string or numeric comparisons:
\begin{codebox}
1 = 1.0? (numeric) \gls{DTLifeq}\marg{1}\marg{1.0}\marg{true}\marg{false}.
\codepar
1p = 1.0p? (string) \gls{DTLifeq}\marg{1p}\marg{1.0p}\marg{true}\marg{false}.
\codepar
2 lt 10? (numeric) \gls{DTLiflt}\marg{2}\marg{10}\marg{true}\marg{false}.
\codepar
A2 lt A10? (string) \gls{DTLiflt}\marg{A2}\marg{A10}\marg{true}\marg{false}.
\codepar
2.0 gt 10.0? (numeric) \gls{DTLifgt}\marg{2}\marg{10}\marg{true}\marg{false}.
\codepar
A2.0 gt A10.0? (string) \gls{DTLifgt}\marg{A2.0}\marg{A10.0}\marg{true}\marg{false}.
\codepar
10 between 1 and 20 (numeric, exclusive)?
\gls{DTLifopenbetween}\marg{10}\marg{1}\marg{20}\marg{true}\marg{false}.
\codepar
10p between 1p and 20p (string, exclusive)?
\gls{DTLifopenbetween}\marg{10p}\marg{1p}\marg{20p}\marg{true}\marg{false}.
\codepar
1 between 1.0 and 2 (numeric, inclusive)?
\gls{DTLifclosedbetween}\marg{1}\marg{1.0}\marg{2}\marg{true}\marg{false}.
\codepar
1 between 1.0 and 2A (string, inclusive)?
\gls{DTLifclosedbetween}\marg{1}\marg{1.0}\marg{2A}\marg{true}\marg{false}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:DTLif},
 title={Numerical/String Comparisons},
 description={Example document demonstrating comparisons
where the arguments are parsed to determine the comparison type}
]
{
\cmd{usepackage}\oarg{math=l3fp}\marg{datatool-base}
}%
{%
1 = 1.0? (numeric) \gls{DTLifeq}\marg{1}\marg{1.0}\marg{true}\marg{false}.
\codepar
1p = 1.0p? (string) \gls{DTLifeq}\marg{1p}\marg{1.0p}\marg{true}\marg{false}.
\codepar
2 lt 10? (numeric) \gls{DTLiflt}\marg{2}\marg{10}\marg{true}\marg{false}.
\codepar
A2 lt A10? (string) \gls{DTLiflt}\marg{A2}\marg{A10}\marg{true}\marg{false}.
\codepar
2.0 gt 10.0? (numeric) \gls{DTLifgt}\marg{2}\marg{10}\marg{true}\marg{false}.
\codepar
A2.0 gt A10.0? (string) \gls{DTLifgt}\marg{A2.0}\marg{A10.0}\marg{true}\marg{false}.
\codepar
10 between 1 and 20 (numeric, exclusive)?\nl
\gls{DTLifopenbetween}\marg{10}\marg{1}\marg{20}\marg{true}\marg{false}.
\codepar
10p between 1p and 20p (string, exclusive)?\nl
\gls{DTLifopenbetween}\marg{10p}\marg{1p}\marg{20p}\marg{true}\marg{false}.
\codepar
1 between 1.0 and 2 (numeric, inclusive)?\nl
\gls{DTLifclosedbetween}\marg{1}\marg{1.0}\marg{2}\marg{true}\marg{false}.
\codepar
1 between 1.0 and 2A (string, inclusive)?\nl
\gls{DTLifclosedbetween}\marg{1}\marg{1.0}\marg{2A}\marg{true}\marg{false}.
}
\end{resultbox}


\subsection{\stytext{ifthen} conditionals}
\label{sec:ifthen}

The commands described in \sectionref{sec:ifconditions} can not be
used in the conditional part of the \gls{ifthenelse} or
\gls{whiledo} commands provided by the \sty{ifthen} package.
This section describes analogous commands which may only be in
the conditional part of the \gls{ifthenelse} or \gls{whiledo}. These
may be used with the boolean operations \gls{not}, \gls{and} and
\gls{or} provided by the \sty{ifthen} package. See the \sty{ifthen}
documentation for further details.
\texdocref{ifthen}

\begin{warning}
Be aware of protected \idx{expansion} in the argument of commands like
\gls{ifthenelse} that can cause a different result from using
\csfmt{DTLis\ldots} compared to the corresponding
\csfmt{DTLif\ldots} (see \exampleref{ex:DTListype}).
\end{warning}

\cmddef{DTLisint}
As \gls{DTLifint} but for use in \sty{ifthen} conditionals (see
\exampleref{sec:DTListypeex}).

\cmddef{DTLisreal}
As \gls{DTLifreal} but for use in \sty{ifthen} conditionals (see
\exampleref{sec:DTListypeex}).

\cmddef{DTLiscurrency}
As \gls{DTLifcurrency} but for use in \sty{ifthen} conditionals.
Note that \gls{DTLfmtcurr}, \gls{DTLfmtcurrency} and \gls{DTLcurrency} are
designed to \idxc{expansion}{expand} so if you have data that contains those commands
it's better to use \gls{DTLifcurrency} (see
\exampleref{sec:DTListypeex}).

\cmddef{DTLiscurrencyunit}
As \gls{DTLifcurrencyunit} but for use in \sty{ifthen} conditionals (see
\exampleref{sec:DTListypeex}).

\cmddef{DTLisnumerical}
As \gls{DTLifnumerical} but for use in \sty{ifthen} conditionals (see
\exampleref{sec:DTListypeex}).

\cmddef{DTLisstring}
As \gls{DTLifstring} but for use in \sty{ifthen} conditionals (see
\exampleref{sec:DTListypeex}).


\cmddef{DTLiseq}
As the unstarred \gls{DTLifeq} but for use in \sty{ifthen} conditionals
(see \exampleref{sec:DTLiscmpex}).

\cmddef{DTLisieq}
As the starred \starredcs{DTLifeq} but for use in \sty{ifthen} conditionals
(see \exampleref{sec:DTLiscmpex}).

\cmddef{DTLisnumeq}
As \gls{DTLifnumeq} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisFPeq}
Synonym of \gls{DTLisnumeq}.

\cmddef{DTLislt}
As the unstarred \gls{DTLiflt} but for use in \sty{ifthen} conditionals
(see \exampleref{sec:DTLiscmpex}).

\cmddef{DTLisilt}
As the starred \starredcs{DTLiflt} but for use in \sty{ifthen} conditionals
(see \exampleref{sec:DTLiscmpex}).

\cmddef{DTLisnumlt}
As \gls{DTLifnumlt} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisFPlt}
Synonym of \gls{DTLisnumlt}.

\cmddef{DTLisnumlteq}
There isn't a \csfmt{DTLif\ldots} direct equivalent of this command,
except using \gls{DTLifnumgt} with the final two arguments flipped.
Evaluates to true if $\meta{arg1} \leq \meta{arg2}$, where the
arguments are \idxpl{formattednumber}.

\cmddef{DTLisFPlteq}
Synonym of \gls{DTLisnumlteq}.

\cmddef{DTLisgt}
As the unstarred \gls{DTLifgt} but for use in \sty{ifthen} conditionals
(see \exampleref{sec:DTLiscmpex}).

\cmddef{DTLisigt}
As the starred \starredcs{DTLifgt} but for use in \sty{ifthen} conditionals
(see \exampleref{sec:DTLiscmpex}).

\cmddef{DTLisnumgt}
As \gls{DTLifnumgt} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisFPgt}
Synonym of \gls{DTLisnumgt}.

\cmddef{DTLisnumgteq}
There isn't a \csfmt{DTLif\ldots} direct equivalent of this command,
except using \gls{DTLifnumlt} with the final two arguments flipped.
Evaluates to true if $\meta{arg1} \geq \meta{arg2}$, where the
arguments are \idxpl{formattednumber}.

\cmddef{DTLisFPgteq}
Synonym of \gls{DTLisnumgteq}.

\cmddef{DTLisopenbetween}
As the unstarred \gls{DTLifopenbetween} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisiopenbetween}
As the starred \starredcs{DTLifopenbetween} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisnumopenbetween}
As \gls{DTLifnumopenbetween} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisFPopenbetween}
Synonym of \gls{DTLisnumopenbetween}.

\cmddef{DTLisclosedbetween}
As the unstarred \gls{DTLifclosedbetween} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisiclosedbetween}
As the starred \starredcs{DTLifclosedbetween} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisnumclosedbetween}
As \gls{DTLifnumclosedbetween} but for use in \sty{ifthen} conditionals.

\cmddef{DTLisFPclosedbetween}
Synonym of \gls{DTLisnumclosedbetween}.


\cmddef{DTLisinlist}
As \gls{DTLifinlist} but for use in \sty{ifthen} conditionals (see
\exampleref{ex:DTLissubstr}).

\cmddef{DTLisSubString}
As the unstarred \gls{DTLifSubString} but for use in \sty{ifthen} conditionals (see
\exampleref{ex:DTLissubstr}).

\cmddef{DTLisiSubString}
As the starred \starredcs{DTLifSubString} but for use in \sty{ifthen} conditionals
(see \exampleref{ex:DTLissubstr}).

\cmddef{DTLisPrefix}
As the unstarred \gls{DTLifStartsWith} but for use in \sty{ifthen} conditionals
(see \exampleref{ex:DTLissubstr}).

\cmddef{DTLisiPrefix}
As the starred \starredcs{DTLifStartsWith} but for use in \sty{ifthen} conditionals
(see \exampleref{ex:DTLissubstr}).

\cmddef{DTLisSuffix}
As the unstarred \gls{DTLifEndsWith} but for use in \sty{ifthen} conditionals
(see \exampleref{ex:DTLissubstr}).

\cmddef{DTLisiSuffix}
As the starred \starredcs{DTLifEndsWith} but for use in \sty{ifthen} conditionals
(see \exampleref{ex:DTLissubstr}).


\subsubsection{Data Type Conditionals Example}
\label{sec:DTListypeex}

\mExampleref{ex:DTListype} tests for the data type of the given
argument, which will be parsed according to the current locale
settings.
\begin{codebox}
1,234.0: \gls{ifthenelse}\marg{\gls{DTLisint}\marg{1,234.0}}\marg{int}\marg{not int}.
\codepar
1,234: \gls{ifthenelse}\marg{\gls{DTLisint}\marg{1,234}}\marg{int}\marg{not int}.
\codepar
1,234.0: \gls{ifthenelse}\marg{\gls{DTLisreal}\marg{1,234.0}}\marg{real}\marg{not real}.
\codepar
1,234: \gls{ifthenelse}\marg{\gls{DTLisreal}\marg{1,234}}\marg{real}\marg{not real}.
\codepar
Compare:
\gls{cs.dollar}1,234: \gls{DTLifcurrency}\marg{\gls{cs.dollar}1,234}\marg{currency}\marg{not currency}.
With: \gls{cs.dollar}1,234: \gls{ifthenelse}\marg{\gls{DTLiscurrency}\marg{\gls{cs.dollar}1,234}}\marg{currency}\marg{not currency}.
\codepar
\gls{DTLnewcurrencysymbol}\marg{\gls{protect}\gls{cs.dollar}}\comment{}
\gls{cs.dollar}1,234: \gls{ifthenelse}\marg{\gls{DTLiscurrency}\marg{\gls{cs.dollar}1,234}}\marg{currency}\marg{not currency}.
\codepar
1.234,0: \gls{ifthenelse}\marg{\gls{DTLisnumerical}\marg{1.234,0}}\marg{numerical}\marg{not numerical};
\gls{ifthenelse}\marg{\gls{DTLisstring}\marg{1.234,0}}\marg{string}\marg{not string}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
1.234,0: \gls{ifthenelse}\marg{\gls{DTLisnumerical}\marg{1.234,0}}\marg{numerical}\marg{not numerical};
\gls{ifthenelse}\marg{\gls{DTLisstring}\marg{1.234,0}}\marg{string}\marg{not string}.
\codepar
Empty: \gls{ifthenelse}\marg{\gls{DTLisnumerical}\marg{}}\marg{numerical}\marg{not numerical};
\gls{ifthenelse}\marg{\gls{DTLisstring}\marg{}}\marg{string}\marg{not string}.
\end{codebox}
Note the difference between \gls{DTLifcurrency} and
\gls{DTLiscurrency}. This is because \gls{ifthenelse} causes
\gls{cs.dollar} to \idxc{expansion}{expand} to \code{\gls{protect}\gls{cs.dollar}},
which isn't recognised as a currency unit by default. 
\begin{resultbox}
\createexample*[label={ex:DTListype},link={sec:DTListypeex},
 title={Data Type Conditionals for use with \stytext{ifthen}},
 description={Example document demonstrating data type conditionals
 for use in commands like \cmd{ifthenelse}}
]
{%
 \cmd{usepackage}\marg{datatool-base}
}%
{%
1,234.0: \gls{ifthenelse}\marg{\gls{DTLisint}\marg{1,234.0}}\marg{int}\marg{not int}.
\codepar
1,234: \gls{ifthenelse}\marg{\gls{DTLisint}\marg{1,234}}\marg{int}\marg{not int}.
\codepar
1,234.0: \gls{ifthenelse}\marg{\gls{DTLisreal}\marg{1,234.0}}\marg{real}\marg{not real}.
\codepar
1,234: \gls{ifthenelse}\marg{\gls{DTLisreal}\marg{1,234}}\marg{real}\marg{not real}.
\codepar
Compare:
\gls{cs.dollar}1,234: \gls{DTLifcurrency}\marg{\gls{cs.dollar}1,234}\marg{currency}\marg{not currency}.
With: \gls{cs.dollar}1,234: \gls{ifthenelse}\marg{\gls{DTLiscurrency}\marg{\gls{cs.dollar}1,234}}\marg{currency}\marg{not currency}.
\codepar
\gls{DTLnewcurrencysymbol}\marg{\gls{protect}\gls{cs.dollar}}\comment{}
\gls{cs.dollar}1,234: \gls{ifthenelse}\marg{\gls{DTLiscurrency}\marg{\gls{cs.dollar}1,234}}\marg{currency}\marg{not currency}.
\codepar
1.234,0: \gls{ifthenelse}\marg{\gls{DTLisnumerical}\marg{1.234,0}}\marg{numerical}\marg{not numerical};
\gls{ifthenelse}\marg{\gls{DTLisstring}\marg{1.234,0}}\marg{string}\marg{not string}.
\codepar
\gls{DTLsetnumberchars}\marg{.}\marg{,}\comment{}
1.234,0: \gls{ifthenelse}\marg{\gls{DTLisnumerical}\marg{1.234,0}}\marg{numerical}\marg{not numerical};
\gls{ifthenelse}\marg{\gls{DTLisstring}\marg{1.234,0}}\marg{string}\marg{not string}.
\codepar
Empty: \gls{ifthenelse}\marg{\gls{DTLisnumerical}\marg{}}\marg{numerical}\marg{not numerical};
\gls{ifthenelse}\marg{\gls{DTLisstring}\marg{}}\marg{string}\marg{not string}.
}
\end{resultbox}

\subsubsection{Order Conditionals Example}
\label{sec:DTLiscmpex}

\mExampleref{ex:DTLiscmp} demonstrates the order conditionals in
\gls{ifthenelse}:
\begin{codebox}
\$1 = 1.0\$?
\gls{ifthenelse}\marg{\gls{DTLiseq}\marg{1}\marg{1.0}}\marg{true}\marg{false}.
\codepar
duck = Duck? (case-sensitive)
\gls{ifthenelse}\marg{\gls{DTLiseq}\marg{duck}\marg{Duck}}\marg{true}\marg{false}.
\codepar
duck = Duck? (ignore case) 
\gls{ifthenelse}\marg{\gls{DTLisieq}\marg{duck}\marg{Duck}}\marg{true}\marg{false}.
\codepar
\$2 < 10\$? \gls{ifthenelse}\marg{\gls{DTLislt}\marg{2}\marg{10}}\marg{true}\marg{false}.
\codepar
a before Z? (case-sensitive)
\gls{ifthenelse}\marg{\gls{DTLislt}\marg{a}\marg{Z}}\marg{true}\marg{false}.
\codepar
a before Z? (ignore case)
\gls{ifthenelse}\marg{\gls{DTLisilt}\marg{2}\marg{10}}\marg{true}\marg{false}.
\codepar
\$1.5 > 1\$?
\gls{ifthenelse}\marg{\gls{DTLisgt}\marg{1.5}\marg{1}}\marg{true}\marg{false}.
\codepar
a after Z? (case-sensitive)
\gls{ifthenelse}\marg{\gls{DTLisgt}\marg{a}\marg{Z}}\marg{true}\marg{false}.
\codepar
a after Z? (ignore case)
\gls{ifthenelse}\marg{\gls{DTLisigt}\marg{2}\marg{10}}\marg{true}\marg{false}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:DTLiscmp},link={sec:DTLiscmpex},
 title={Order Conditionals for use with \stytext{ifthen}},
 description={Example document demonstrating order conditionals
 for use in commands like \cmd{ifthenelse}}
]
{%
  \cmd{usepackage}\marg{datatool-base}
}%
{%
\$1 = 1.0\$? \gls{ifthenelse}\marg{\gls{DTLiseq}\marg{1}\marg{1.0}}\marg{true}\marg{false}.
\codepar
duck = Duck? (case-sensitive)
 \gls{ifthenelse}\marg{\gls{DTLiseq}\marg{duck}\marg{Duck}}\marg{true}\marg{false}.
\codepar
duck = Duck? (ignore case) 
\gls{ifthenelse}\marg{\gls{DTLisieq}\marg{duck}\marg{Duck}}\marg{true}\marg{false}.
\codepar
\$2 < 10\$? \gls{ifthenelse}\marg{\gls{DTLislt}\marg{2}\marg{10}}\marg{true}\marg{false}.
\codepar
a before Z? (case-sensitive)
\gls{ifthenelse}\marg{\gls{DTLislt}\marg{a}\marg{Z}}\marg{true}\marg{false}.
\codepar
a before Z? (ignore case)
\gls{ifthenelse}\marg{\gls{DTLisilt}\marg{2}\marg{10}}\marg{true}\marg{false}.
\codepar
\$1.5 > 1\$? \gls{ifthenelse}\marg{\gls{DTLisgt}\marg{1.5}\marg{1}}\marg{true}\marg{false}.
\codepar
a after Z? (case-sensitive)
\gls{ifthenelse}\marg{\gls{DTLisgt}\marg{a}\marg{Z}}\marg{true}\marg{false}.
\codepar
a after Z? (ignore case)
\gls{ifthenelse}\marg{\gls{DTLisigt}\marg{2}\marg{10}}\marg{true}\marg{false}.
}
\end{resultbox}

\subsubsection{List Element and Substring Conditionals Example}
\label{sec:DTLissubstrex}

\mExampleref{ex:DTLissubstr} uses the list element conditional and substring conditionals:
\begin{codebox}
`goose' element of list `ant,duck,goose'?
\gls{ifthenelse}\marg{\gls{DTLisinlist}\marg{goose}\marg{ant,duck,goose}}\marg{true}\marg{false}.
\codepar
`oo' element of list `ant,duck,goose'?
\gls{ifthenelse}\marg{\gls{DTLisinlist}\marg{oo}\marg{ant,duck,goose}}\marg{true}\marg{false}.
\codepar
`oo' in `goose'?
\gls{ifthenelse}\marg{\gls{DTLisSubString}\marg{goose}\marg{oo}}\marg{true}\marg{false}.
\codepar
`oo' in `GOOSE' (case-sensitive)?
\gls{ifthenelse}\marg{\gls{DTLisSubString}\marg{GOOSE}\marg{oo}}\marg{true}\marg{false}.
\codepar
`oo' in `GOOSE' (ignore case)?
\gls{ifthenelse}\marg{\gls{DTLisiSubString}\marg{GOOSE}\marg{oo}}\marg{true}\marg{false}.
\codepar
`go' prefix of `goose'?
\gls{ifthenelse}\marg{\gls{DTLisPrefix}\marg{goose}\marg{go}}\marg{true}\marg{false}.
\codepar
`go' prefix of `GOOSE' (case-sensitive)?
\gls{ifthenelse}\marg{\gls{DTLisPrefix}\marg{GOOSE}\marg{go}}\marg{true}\marg{false}.
\codepar
`go' prefix of `GOOSE' (ignore case)?
\gls{ifthenelse}\marg{\gls{DTLisiPrefix}\marg{GOOSE}\marg{go}}\marg{true}\marg{false}.
\codepar
`se' suffix of `goose'?
\gls{ifthenelse}\marg{\gls{DTLisSuffix}\marg{goose}\marg{se}}\marg{true}\marg{false}.
\codepar
`se' suffix of `GOOSE' (case-sensitive)?
\gls{ifthenelse}\marg{\gls{DTLisSuffix}\marg{GOOSE}\marg{se}}\marg{true}\marg{false}.
\codepar
`se' suffix of `GOOSE' (ignore case)?
\gls{ifthenelse}\marg{\gls{DTLisiSuffix}\marg{GOOSE}\marg{se}}\marg{true}\marg{false}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:DTLissubstr},link={sec:DTLissubstrex},
  title={Substring Conditionals for use with \stytext{ifthen}},
  description={Example document demonstrating substring conditionals
  for use in commands like \cmd{ifthenelse}}
]
{%
 \cmd{usepackage}\marg{datatool-base}
}
{%
`goose' element of list `ant,duck,goose'?\nl
\gls{ifthenelse}\marg{\gls{DTLisinlist}\marg{goose}\marg{ant,duck,goose}}\marg{true}\marg{false}.
\codepar
`oo' element of list `ant,duck,goose'?\nl
\gls{ifthenelse}\marg{\gls{DTLisinlist}\marg{oo}\marg{ant,duck,goose}}\marg{true}\marg{false}.
\codepar
`oo' in `goose'?\nl
\gls{ifthenelse}\marg{\gls{DTLisSubString}\marg{goose}\marg{oo}}\marg{true}\marg{false}.
\codepar
`oo' in `GOOSE' (case-sensitive)?\nl
\gls{ifthenelse}\marg{\gls{DTLisSubString}\marg{GOOSE}\marg{oo}}\marg{true}\marg{false}.
\codepar
`oo' in `GOOSE' (ignore case)?\nl
\gls{ifthenelse}\marg{\gls{DTLisiSubString}\marg{GOOSE}\marg{oo}}\marg{true}\marg{false}.
\codepar
`go' prefix of `goose'?\nl
\gls{ifthenelse}\marg{\gls{DTLisPrefix}\marg{goose}\marg{go}}\marg{true}\marg{false}.
\codepar
`go' prefix of `GOOSE' (case-sensitive)?\nl
\gls{ifthenelse}\marg{\gls{DTLisPrefix}\marg{GOOSE}\marg{go}}\marg{true}\marg{false}.
\codepar
`go' prefix of `GOOSE' (ignore case)?\nl
\gls{ifthenelse}\marg{\gls{DTLisiPrefix}\marg{GOOSE}\marg{go}}\marg{true}\marg{false}.
\codepar
`se' suffix of `goose'?\nl
\gls{ifthenelse}\marg{\gls{DTLisSuffix}\marg{goose}\marg{se}}\marg{true}\marg{false}.
\codepar
`se' suffix of `GOOSE' (case-sensitive)?\nl
\gls{ifthenelse}\marg{\gls{DTLisSuffix}\marg{GOOSE}\marg{se}}\marg{true}\marg{false}.
\codepar
`se' suffix of `GOOSE' (ignore case)?\nl
\gls{ifthenelse}\marg{\gls{DTLisiSuffix}\marg{GOOSE}\marg{se}}\marg{true}\marg{false}.
}
\end{resultbox}

\section{Decimal Functions}
\label{sec:fp}

Commands with a name prefixed with \qtt{dtl} (such as \gls{dtladd}) that are
described in \sectionref{sec:plainfp} don't parse for the current
\idx{decimalchar} and \idx{numbergroupchar} or for a
\idx{currencysym}. They require a \idx{plainnumber}, either a bare
integer (such as 12345) or a number with a \idx{decimalpoint} (such
as 1234.5). The definition of these commands depends on the value 
of the \opt{math} package option.

Commands with a name prefixed with \qtt{DTL} (such as \gls{DTLadd})
that are described in \sectionref{sec:formattedfp} expect
\idxpl{formattednumber} in the supplied values. These commands are
provided by \sty{datatool-base} and use \gls{DTLconverttodecimal} to
convert the supplied values to \idxpl{plainnumber}.

\subsection{Plain Numbers}
\label{sec:plainfp}

\begin{information}
If you have complex calculations, you may prefer to use \LaTeX3
commands directly, as shown in \exampleref{ex:l3fptodec}.
Alternatively, if you are using \LuaLaTeX, you may prefer to use
\gls{directlua}, as shown in \exampleref{ex:directlua}.
\end{information}

Commands with a \idx{CSV} list argument, such as \gls{dtladdall},
will do at least one \idx{expansion}. The \opteqvalref{math}{l3fp} and
\opteqvalref{math}{lua} options will fully \idxc{expansion}{expand} \meta{num list},
but the \opteqvalref{math}{fp} and \opteqvalref{math}{pgfmath}
options will only do a single \idx{expansion}. This is different to most
\idx{CSV} list arguments provided by \sty{datatool-base} (see
\sectionref{sec:csvlists}). Since the list is expected to only
contain comma-separated \idxpl{plainnumber} there should be no
\idx{expansion} issues. Avoid empty elements.

\cmddef{dtlpadleadingzeros}
Expands to a \idx{plainnumber} that is the supplied \meta{value}
padded with leading zeros to the number of digits identified in the
\meta{num-digits} argument. Both arguments must be \idxpl{plainnumber}. The
\meta{num-digits} argument should lie between 1 and 7. No error will
occur if \meta{num-digits} is outside that range. This command is
primarily designed for sorting where the numbers are mixed with
strings where a character code comparison will be used, and so is
expandable. Unlike \gls{two@digits}, the \meta{value} may be a
decimal.

\cmddef{dtlpadleadingzerosminus}
This will be inserted by \gls{dtlpadleadingzeros} if the value is
negative.

\cmddef{dtlpadleadingzerosplus}
This will be inserted by \gls{dtlpadleadingzeros} if the value is
positive. Note that this expands to nothing by default. This is
because the plus (\code{+}) character has a lower character code
than the hyphen-minus (\code{-}) character, which would put positive
numbers before negative numbers in a character code sort.

\cmddef{dtladd}
Calculates $\meta{num1} + \meta{num2}$ (addition) and stores the result in
the control sequence \meta{cs}, where the numbers are
\idxpl{plainnumber}.

\cmddef{dtladdall}
Adds all the numbers in the comma-separated list \meta{num list} and
stores the result in the control sequence \meta{cs}, where the
numbers are \idxpl{plainnumber}.

\begin{warning}
The number list should not contain empty elements. 
\end{warning}

\cmddef{dtlsub}
Calculates $\meta{num1} - \meta{num2}$ (subtraction) and stores the result in
the control sequence \meta{cs}, where the numbers are
\idxpl{plainnumber}.

\cmddef{dtlmul}
Calculates $\meta{num1} \times \meta{num2}$ (multiplication) and stores the result in
the control sequence \meta{cs}, where the numbers are
\idxpl{plainnumber}.

\cmddef{dtldiv}
Calculates $\meta{num1} \div \meta{num2}$ (division) and stores the result in
the control sequence \meta{cs}, where the numbers are
\idxpl{plainnumber}.

\cmddef{dtlsqrt}
Calculates the square root of \meta{num} and stores the result in
the control sequence \meta{cs}, where the number is a
\idx{plainnumber}.

\cmddef{dtlroot}
Calculates the \meta{n}th root of \meta{num} and stores the result in
the control sequence \meta{cs}, where the number is a
\idx{plainnumber}.

\cmddef{dtlround}
Rounds \meta{num} to \meta{dp} decimal places and stores the result in
the control sequence \meta{cs}, where the number is a \idx{plainnumber}.

\cmddef{dtltrunc}
Truncates \meta{num} to \meta{dp} decimal places and stores the result in
the control sequence \meta{cs}, where the number is a \idx{plainnumber}.

\cmddef{dtlclip}
Removes redundant trailing zeros from \meta{num} and stores the
result in the control sequence \meta{cs}, where the number is a
\idx{plainnumber}.

\cmddef{dtlmin}
Defines the control sequence \meta{cs} to the smaller of the two
numbers, where the numbers are \idxpl{plainnumber}.

\cmddef{dtlminall}
Defines the control sequence \meta{cs} to the minimum value in the
given comma-separated list \meta{num-list} of numbers, where the 
numbers are \idxpl{plainnumber}.

\begin{warning}
The number list should not contain empty elements. 
\end{warning}

\cmddef{dtlmax}
Defines the control sequence \meta{cs} to the larger of the two
numbers, where the numbers are \idxpl{plainnumber}.

\cmddef{dtlmaxall}
Defines the control sequence \meta{cs} to the maximum value in the
given comma-separated list \meta{num-list} of numbers, where the 
numbers are \idxpl{plainnumber}.

\begin{warning}
The number list should not contain empty elements. 
\end{warning}

\cmddef{dtlabs}
Defines the control sequence \meta{cs} to the absolute value of the
number \meta{num}, where the number is a \idxpl{plainnumber}.

\cmddef{dtlneg}
Defines the control sequence \meta{cs} to the negative of the
number \meta{num}, where the number is a \idxpl{plainnumber}.

\cmddef{dtlmeanforall}
Calculates the mean (average) of all the numbers in the
comma-separated list \meta{num list} and stores the result in the
control sequence \meta{cs}, where the numbers are
\idxpl{plainnumber}.

\begin{warning}
The number list should not contain empty elements. 
\end{warning}

\cmddef{dtlvarianceforall}
Calculates the variance of all the numbers in the
comma-separated list \meta{num list} and stores the result in the
control sequence \meta{cs}, where the numbers are
\idxpl{plainnumber}. If the mean has already been calculated, it can
be supplied in the optional argument \meta{mean}. If omitted, the
mean will be calculated before calculating the variance.

\begin{warning}
The number list should not contain empty elements. 
\end{warning}

\cmddef{dtlsdforall}
Calculates the standard deviation of all the numbers in the
comma-separated list \meta{num list} and stores the result in the
control sequence \meta{cs}, where the numbers are
\idxpl{plainnumber}. If the mean has already been calculated, it can
be supplied in the optional argument \meta{mean}. If omitted, the
mean will be calculated before calculating the standard deviation.
If you have already calculated the variance you can simply use
\gls{dtlsqrt}.

\begin{warning}
The number list should not contain empty elements. 
\end{warning}

\subsubsection{Example (\optfmt{l3fp})}
\label{sec:excalcl3fp}

\mExampleref{ex:l3fpcalc} explicitly sets the processor to
\optvalref{math}{l3fp}, which uses
\LaTeX3 floating point commands. This is now the
default setting unless \LuaLaTeX\ is used.
\begin{codebox}
\cmd{documentclass}\marg{article}
\cmd{usepackage}\oarg{\opteqvalref{math}{l3fp}}\marg{datatool-base}
\cmd{newcommand}\marg{\cmd{numA}}\marg{1023.5}
\cmd{newcommand}\marg{\cmd{numB}}\marg{54.75000}
\cmd{newcommand}\marg{\cmd{numC}}\marg{-20648.68}
\cmd{newcommand}\marg{\cmd{numlist}}\marg{32.456,0.15,-25,48.7,92}
\cbeg{document}
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}
\$\cmd{numA} + \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}
Add \$\cmd{numC}\$ to previous result. 
Updated result: \cmd{result}.
\codepar
\gls{dtladdall}\marg{\cmd{result}}\marg{\cmd{numlist}}
Sum of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}
\$\cmd{numA} - \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}
Subtract \$\cmd{numC}\$ from previous result. 
Updated result: \cmd{result}.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}
\$\cmd{numA} \cmd{times} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}
Multiply previous result by \$\cmd{numC}\$. 
Updated result: \cmd{result}.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}
\$\cmd{numA} \cmd{div} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}
Divide previous result by \$\cmd{numC}\$. 
Updated result: \cmd{result}.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{\cmd{numA}}
\$\cmd{sqrt}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{9}
\$\cmd{sqrt}\marg{9} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{3}
\$\cmd{sqrt}\oarg{3}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{8}\marg{3}
\$\cmd{sqrt}\oarg{3}\marg{8} = \cmd{result}\$.
\codepar
\gls{dtlround}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}
Round \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtltrunc}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}
Truncate \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtlclip}\marg{\cmd{result}}\marg{\cmd{numB}}
Clip \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmin}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}
Minimum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlminall}\marg{\cmd{result}}\marg{\cmd{numlist}}
Minimum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlmax}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}
Maximum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmaxall}\marg{\cmd{result}}\marg{\cmd{numlist}}
Maximum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlabs}\marg{\cmd{result}}\marg{\cmd{numC}}
Absolute value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlneg}\marg{\cmd{result}}\marg{\cmd{numC}}
Negate value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlmeanforall}\marg{\cmd{meanvalue}}\marg{\cmd{numlist}}
Mean of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: 
\cmd{meanvalue}.
\codepar
\gls{dtlvarianceforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}
Variance of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$
(using previously calculated mean): \cmd{result}.
\codepar
\gls{dtlvarianceforall}\marg{\cmd{result}}\marg{\cmd{numlist}}
Variance of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ 
(not using previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}
Standard deviation of all numbers in the set 
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$
(using previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\marg{\cmd{result}}\marg{\cmd{numlist}}
Standard deviation of all numbers in the set 
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$
(not using previously calculated mean): \cmd{result}.
\cend{document}
\end{codebox}
\begin{resultbox}[float]
\createexample*[label={ex:l3fpcalc},
 title={Decimal Functions (\optfmt{l3fp})},link={sec:excalcl3fp},
 description={Example document demonstrating decimal functions using
 LaTeX3 floating point commands}
]
{%
\cmd{usepackage}\oarg{math=l3fp}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numA}}\marg{1023.5}\nl
\cmd{newcommand}\marg{\cmd{numB}}\marg{54.75000}\nl
\cmd{newcommand}\marg{\cmd{numC}}\marg{-20648.68}\nl
\cmd{newcommand}\marg{\cmd{numlist}}\marg{32.456,0.15,-25,48.7,92}
}%
{%
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} + \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Add \$\cmd{numC}\$ to previous result. Updated result: \cmd{result}.
\codepar
\gls{dtladdall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Sum of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} - \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Subtract \$\cmd{numC}\$ from previous result. Updated result: \cmd{result}.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{times} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Multiply previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{div} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Divide previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{\cmd{numA}}\nl
\$\cmd{sqrt}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{9}\nl
\$\cmd{sqrt}\marg{9} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{8}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{8} = \cmd{result}\$.
\codepar
\gls{dtlround}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Round \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtltrunc}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Truncate \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtlclip}\marg{\cmd{result}}\marg{\cmd{numB}}\nl
Clip \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmin}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Minimum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlminall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Minimum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlmax}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Maximum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmaxall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Maximum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlabs}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Absolute value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlneg}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Negate value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlmeanforall}\marg{\cmd{meanvalue}}\marg{\cmd{numlist}}\nl
Mean of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$:
\cmd{meanvalue}.
\codepar
\gls{dtlvarianceforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlvarianceforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
}
\end{resultbox}

\subsubsection{Example (\optfmt{lua})}
\label{sec:excalclua}

\mExampleref{ex:luacalc} uses the \optvalref{math}{lua} processor, which
uses \gls{directlua} to perform the calculations, and so requires
\LuaLaTeX.  The only difference to \exampleref{ex:l3fpcalc} is the
package option:
\begin{codebox}
\cmd{usepackage}\oarg{\opteqvalref{math}{lua}}\marg{datatool-base}
\end{codebox}
(and the need to use \LuaLaTeX).

Note that this produces slightly different results from
\examplesref{ex:l3fpcalc,ex:fpcalc}.  For the division 
$1023.5\div 54.75000$, \opteqvalref{math}{lua} produces 
18.694063926941 whereas \opteqvalref{math}{l3fp} produces the result 
18.69406392694064. This is due to rounding when the result from Lua 
is input into the \TeX\ stream. With \opteqvalref{math}{fp} the result is
18.694063926940639269, which has even more significant digits.
On the other hand, for the square root $\sqrt{9}$ and cubic root 
$\sqrt[3]{8}$, \opteqvalref{math}{l3fp} produces integers 3 and 2,
\opteqvalref{math}{lua} returns equivalent decimals 3.0 and 2.0 but
\opteqvalref{math}{fp} has rounding errors.

\begin{resultbox}[float]
\createexample*[arara={lualatex,pdfcrop},
 label={ex:luacalc},link={sec:excalclua},
 title={Decimal Functions (\optfmt{lua})},
 description={Example document demonstrating decimal functions using
 Lua floating point commands}
]
{%
\cmd{usepackage}\oarg{math=lua}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numA}}\marg{1023.5}\nl
\cmd{newcommand}\marg{\cmd{numB}}\marg{54.75000}\nl
\cmd{newcommand}\marg{\cmd{numC}}\marg{-20648.68}\nl
\cmd{newcommand}\marg{\cmd{numlist}}\marg{32.456,0.15,-25,48.7,92}
}%
{%
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} + \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Add \$\cmd{numC}\$ to previous result. Updated result: \cmd{result}.
\codepar
\gls{dtladdall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Sum of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} - \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Subtract \$\cmd{numC}\$ from previous result. Updated result: \cmd{result}.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{times} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Multiply previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{div} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Divide previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{\cmd{numA}}\nl
\$\cmd{sqrt}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{9}\nl
\$\cmd{sqrt}\marg{9} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{8}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{8} = \cmd{result}\$.
\codepar
\gls{dtlround}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Round \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtltrunc}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Truncate \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtlclip}\marg{\cmd{result}}\marg{\cmd{numB}}\nl
Clip \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmin}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Minimum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlminall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Minimum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlmax}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Maximum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmaxall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Maximum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlabs}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Absolute value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlneg}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Negate value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlmeanforall}\marg{\cmd{meanvalue}}\marg{\cmd{numlist}}\nl
Mean of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$:
\cmd{meanvalue}.
\codepar
\gls{dtlvarianceforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$
(using previously calculated mean): \cmd{result}.
\codepar
\gls{dtlvarianceforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
}
\end{resultbox}

\subsubsection{Example (\optfmt{fp})}
\label{sec:excalcfp}

\mExampleref{ex:fpcalc} is almost identical to \exampleref{ex:l3fpcalc} but uses the
\optvalref{math}{fp} processor, which uses the commands provided by the 
\sty{fp} package.
Note that the results have trailing redundant zeros and there are
rounding errors for $\sqrt{9}$ and $\sqrt[3]{8}$.
\begin{codebox}
\cmd{usepackage}\oarg{\opteqvalref{math}{fp}}\marg{datatool-base}
\end{codebox}
\begin{resultbox}[float]
\createexample*[label={ex:fpcalc},
 title={Decimal Functions (\optfmt{fp})},link={sec:excalcfp},
 description={Example document demonstrating decimal functions using
 fp.sty floating point commands}
]
{%
\cmd{usepackage}\oarg{math=fp}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numA}}\marg{1023.5}\nl
\cmd{newcommand}\marg{\cmd{numB}}\marg{54.75000}\nl
\cmd{newcommand}\marg{\cmd{numC}}\marg{-20648.68}\nl
\cmd{newcommand}\marg{\cmd{numlist}}\marg{32.456,0.15,-25,48.7,92}
}%
{%
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} + \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Add \$\cmd{numC}\$ to previous result. Updated result: \cmd{result}.
\codepar
\gls{dtladdall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Sum of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} - \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Subtract \$\cmd{numC}\$ from previous result. Updated result: \cmd{result}.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{times} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Multiply previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{div} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Divide previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{\cmd{numA}}\nl
\$\cmd{sqrt}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{9}\nl
\$\cmd{sqrt}\marg{9} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{8}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{8} = \cmd{result}\$.
\codepar
\gls{dtlround}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Round \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtltrunc}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Truncate \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtlclip}\marg{\cmd{result}}\marg{\cmd{numB}}\nl
Clip \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmin}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Minimum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlminall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Minimum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlmax}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Maximum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmaxall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Maximum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlabs}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Absolute value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlneg}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Negate value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlmeanforall}\marg{\cmd{meanvalue}}\marg{\cmd{numlist}}\nl
Mean of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$:
\cmd{meanvalue}.
\codepar
\gls{dtlvarianceforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$
(using previously calculated mean): \cmd{result}.
\codepar
\gls{dtlvarianceforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
}
\end{resultbox}

\subsubsection{Example (\optfmt{pgfmath})}
\label{sec:excalcpgfmath}

If \exampleref{ex:l3fpcalc} is modified to use the
\optvalref{math}{pgfmath} processor, which uses the commands provided by
the \sty{pgfmath} package, then the \LaTeX\ run will fail with the
error:
\begin{transcript}
! Dimension too large
\end{transcript}
\mExampleref{ex:pgfmathcalc} has the commands \csfmt{numA}, \csfmt{numB}
and \csfmt{numC} defined to smaller numbers. The rest of the
document is as \exampleref{ex:l3fpcalc}.
\begin{codebox}
\cmd{usepackage}\oarg{\opteqvalref{math}{pgfmath}}\marg{datatool-base}
\cmd{newcommand}\marg{\cmd{numA}}\marg{10.235}
\cmd{newcommand}\marg{\cmd{numB}}\marg{0.5475000}
\cmd{newcommand}\marg{\cmd{numC}}\marg{-206.4868}
\end{codebox}
Note that there are rounding errors.
\begin{resultbox}[float]
\createexample*[label={ex:pgfmathcalc},
 title={Decimal Functions (\optfmt{pgfmath})},link={sec:excalcpgfmath},
 description={Example document demonstrating decimal functions using
 pgfmath.sty floating point commands}
]
{%
\cmd{usepackage}\oarg{math=pgfmath}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{numA}}\marg{10.235}\nl
\cmd{newcommand}\marg{\cmd{numB}}\marg{0.5475000}\nl
\cmd{newcommand}\marg{\cmd{numC}}\marg{-206.4868}\nl
\cmd{newcommand}\marg{\cmd{numlist}}\marg{32.456,0.15,-25,48.7,92}
}%
{%
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} + \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtladd}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Add \$\cmd{numC}\$ to previous result. Updated result: \cmd{result}.
\codepar
\gls{dtladdall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Sum of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} - \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlsub}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Subtract \$\cmd{numC}\$ from previous result. Updated result: \cmd{result}.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{times} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtlmul}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Multiply previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
\$\cmd{numA} \cmd{div} \cmd{numB} = \cmd{result}\$.
\codepar
\gls{dtldiv}\marg{\cmd{result}}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Divide previous result by \$\cmd{numC}\$. Updated result: \cmd{result}.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{\cmd{numA}}\nl
\$\cmd{sqrt}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlsqrt}\marg{\cmd{result}}\marg{9}\nl
\$\cmd{sqrt}\marg{9} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{\cmd{numA}} = \cmd{result}\$.
\codepar
\gls{dtlroot}\marg{\cmd{result}}\marg{8}\marg{3}\nl
\$\cmd{sqrt}\oarg{3}\marg{8} = \cmd{result}\$.
\codepar
\gls{dtlround}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Round \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtltrunc}\marg{\cmd{result}}\marg{\cmd{numB}}\marg{1}\nl
Truncate \$\cmd{numB}\$ to 1dp: \cmd{result}.
\codepar
\gls{dtlclip}\marg{\cmd{result}}\marg{\cmd{numB}}\nl
Clip \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmin}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Minimum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlminall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Minimum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlmax}\marg{\cmd{result}}\marg{\cmd{numA}}\marg{\cmd{numB}}\nl
Maximum of \$\cmd{numA}\$ and \$\cmd{numB}\$: \cmd{result}.
\codepar
\gls{dtlmaxall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Maximum value in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$: \cmd{result}.
\codepar
\gls{dtlabs}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Absolute value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlneg}\marg{\cmd{result}}\marg{\cmd{numC}}\nl
Negate value of \$\cmd{numC}\$: \cmd{result}.
\codepar
\gls{dtlmeanforall}\marg{\cmd{meanvalue}}\marg{\cmd{numlist}}\nl
Mean of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$:
\cmd{meanvalue}.
\codepar
\gls{dtlvarianceforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set \$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$
(using previously calculated mean): \cmd{result}.
\codepar
\gls{dtlvarianceforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Variance of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\oarg{\cmd{meanvalue}}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (using
previously calculated mean): \cmd{result}.
\codepar
\gls{dtlsdforall}\marg{\cmd{result}}\marg{\cmd{numlist}}\nl
Standard deviation of all numbers in the set
\$\cmd{\glsopenbrace}\cmd{numlist}\cmd{\glsclosebrace}\$ (not using
previously calculated mean): \cmd{result}.
}
\end{resultbox}

\subsection{Formatted Numbers}
\label{sec:formattedfp}

The commands listed in this section expect \idxpl{formattednumber}
in the values according to the current \idx{numbergroupchar} and
\idx{decimalchar} settings. Use \gls{DTLsetnumberchars} to set these
first. In general, if calculations are required, it's better to
store the values as \idxpl{plainnumber} if possible and only format
them (for example, using \sty{siunitx}) when they need to be
typeset. That way the formatted values don't need to be repeatedly parsed.

\begin{information}
Commands that have a \meta{num list} argument, such as
\gls{DTLaddall}, expect a \idx{CSV} list or a command with a
\idx{CSV} list definition (see \sectionref{sec:csvlists}). 
The argument isn't fully expanded to allow for non-robust currency
symbols. Any elements that aren't numeric will be treated as zero.
\end{information}

\cmddef{DTLadd}
Converts the \idxpl{formattednumber} \meta{num1} and \meta{num2} to
\idxpl{plainnumber} and adds them together
($\meta{num1} + \meta{num2}$). If parsing determines
that both \meta{num1} and \meta{num2} are integers, integer
arithmetic is performed with \gls{numexpr} otherwise \gls{dtladd} is
used. The result is stored as a \idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgadd}
As \gls{DTLadd} but globally sets \meta{cs}.

\cmddef{DTLaddall}
Converts all the \idxpl{formattednumber} in the comma-separated list
to \idxpl{plainnumber}, adds them all, and stores the result as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgaddall}
As \gls{DTLaddall} but globally sets \meta{cs}.

\cmddef{DTLsub}
Converts the \idxpl{formattednumber} \meta{num1} and \meta{num2} to
\idxpl{plainnumber} and subtracts \meta{num2} from \meta{num1}
($\meta{num1} - \meta{num2}$). If
parsing determines that both \meta{num1} and \meta{num2} are
integers, integer arithmetic is performed with \gls{numexpr}
otherwise \gls{dtlsub} is used. The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgsub}
As \gls{DTLsub} but globally sets \meta{cs}.

\cmddef{DTLmul}
Converts the \idxpl{formattednumber} \meta{num1} and \meta{num2} to
\idxpl{plainnumber} and multiplies them
($\meta{num1} \times \meta{num2}$). If
parsing determines that both \meta{num1} and \meta{num2} are
integers, integer arithmetic is performed with \gls{numexpr}
otherwise \gls{dtlmul} is used. The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgmul}
As \gls{DTLmul} but globally sets \meta{cs}.

\cmddef{DTLdiv}
Converts the \idxpl{formattednumber} \meta{num1} and \meta{num2} to
\idxpl{plainnumber} and divides them ($\meta{num1} \div
\meta{num2}$) using \gls{dtldiv}. The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgdiv}
As \gls{DTLdiv} but globally sets \meta{cs}.

\cmddef{DTLabs}
Converts the \idxpl{formattednumber} \meta{num} to a
\idx{plainnumber} and stores the absolute value as a
\idx{formattednumber} in the command \meta{cs}. If parsing
determines that \meta{num} is an integer then \gls{ifnum} and
\gls{numexpr} are used to negate the number if it's negative. If
\meta{num} is determined to be a decimal or currency, then
\gls{dtlabs} is used.

\cmddef{DTLgabs}
As \gls{DTLabs} but globally sets \meta{cs}.

\cmddef{DTLneg}
Converts the \idxpl{formattednumber} \meta{num} to a
\idx{plainnumber} and stores the negation ($-\meta{num}$) as a
\idx{formattednumber} in the command \meta{cs}. If parsing
determines that \meta{num} is an integer then \gls{numexpr} is used
to negate the number. If \meta{num} is determined
to be a decimal or currency, then \gls{dtlneg} is used.

\cmddef{DTLgneg}
As \gls{DTLneg} but globally sets \meta{cs}.

\cmddef{DTLsqrt}
Converts the \idxpl{formattednumber} \meta{num} to a
\idx{plainnumber} and stores the square root ($\surd\meta{num}$) as a
\idx{formattednumber} in the command \meta{cs}. The square root is
calculated using \gls{dtlsqrt}.

\cmddef{DTLgsqrt}
As \gls{DTLsqrt} but globally sets \meta{cs}.

\begin{information}
There is no equivalent to \gls{dtlroot}. If an arbitrary root is
required for a \idx{formattednumber}, you will have to convert the
\idx{formattednumber} to a \idx{plainnumber} with
\gls{DTLconverttodecimal} and use \gls{dtlroot}.
\end{information}

\cmddef{DTLround}
Converts the \idxpl{formattednumber} \meta{num} to a
\idx{plainnumber}, rounds it to \meta{num digits} (using
\gls{dtlround}), and stores the result as a \idx{formattednumber} in
the command \meta{cs}.

\cmddef{DTLground}
As \gls{DTLround} but globally sets \meta{cs}.

\cmddef{DTLtrunc}
Converts the \idxpl{formattednumber} \meta{num} to a
\idx{plainnumber}, truncates it to \meta{num digits} (using
\gls{dtltrunc}), and stores the result as a \idx{formattednumber} in
the command \meta{cs}.

\cmddef{DTLgtrunc}
As \gls{DTLtrunc} but globally sets \meta{cs}.

\cmddef{DTLclip}
Converts the \idxpl{formattednumber} \meta{num} to a
\idx{plainnumber}, clips it (using \gls{dtlclip}), and stores the
result as a \idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgclip}
As \gls{DTLclip} but globally sets \meta{cs}.

\begin{warning}
When finding the maximum or minimum of \idxpl{formattednumber} the 
parsing of the values and formatting of the result may lead the result to have a
different appearance to its original formatted value.
\end{warning}

\cmddef{DTLmin}
Converts the \idxpl{formattednumber} \meta{num1} and \meta{num2} to
\idxpl{plainnumber} and determines the minimum. If parsing
determines that \meta{num1} and \meta{num2} are integers then \gls{ifnum} is used
otherwise \gls{dtlmin} is used.  The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\begin{warning}
The number list should not contain empty elements. 
\end{warning}

\cmddef{DTLgmin}
As \gls{DTLmin} but globally sets \meta{cs}.

\cmddef{DTLminall}
Converts all the \idxpl{formattednumber} in the comma-separated list
\meta{num list} to \idxpl{plainnumber} and determines the minimum
(using \gls{dtlmin}).  The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgminall}
As \gls{DTLminall} but globally sets \meta{cs}.

\cmddef{DTLmax}
Converts the \idxpl{formattednumber} \meta{num1} and \meta{num2} to
\idxpl{plainnumber} and determines the maximum. If parsing
determines that \meta{num1} and \meta{num2} are integers then \gls{ifnum} is used
otherwise \gls{dtlmax} is used.  The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgmax}
As \gls{DTLmax} but globally sets \meta{cs}.

\cmddef{DTLmaxall}
Converts all the \idxpl{formattednumber} in the comma-separated list
\meta{num list} to \idxpl{plainnumber} and determines the maximum
(using \gls{dtlmax}).  The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgmaxall}
As \gls{DTLmaxall} but globally sets \meta{cs}.

\cmddef{DTLmeanforall}
Converts all the \idxpl{formattednumber} in the comma-separated list
\meta{num list} to \idxpl{plainnumber} and determines the mean
(average) value.  The result is stored as a
\idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgmeanforall}
As \gls{DTLmeanforall} but globally sets \meta{cs}.

\cmddef{DTLvarianceforall}
Converts all the \idxpl{formattednumber} in the comma-separated list
\meta{num list} to \idxpl{plainnumber} and determines the variance.
The result is stored as a \idx{formattednumber} in the command \meta{cs}.

\cmddef{DTLgvarianceforall}
As \gls{DTLvarianceforall} but globally sets \meta{cs}.

\cmddef{DTLsdforall}
Converts all the \idxpl{formattednumber} in the comma-separated list
\meta{num list} to \idxpl{plainnumber} and determines the standard
deviation.  The result is stored as a \idx{formattednumber} in the
command \meta{cs}.

\cmddef{DTLgsdforall}
As \gls{DTLsdforall} but globally sets \meta{cs}.

\section{Currency}
\label{sec:currency}

The currency data type is represented by a currency symbol and a
numerical value. There is no provision for exchange rates. Commands
such as \gls{DTLadd} parse their arguments (which are provided as
\idxpl{formattednumber}) to obtain the actual numerical value, which
can then be passed to commands like \gls{dtladd}, which expect
\idx{plainnumber} arguments. The result is then formatted to match
the dominant data type in the arguments. This means that if one or
more of the arguments is a currency value, then the result will use
the same currency symbol.
Parsing is performed using the same method as \gls{DTLparse}.

In order for the parser to determine the difference between a
currency value and a string (see \sectionref{sec:datatypes}),
\sty{datatool-base} needs to know the currency symbols.
As from version 3.0, \sty{datatool-base} can now load region files
that setup the currency associated with the region.

\begin{information}
If you don't want the default currency to change when the language
changes, use:
\begin{compactcodebox*}
\gls{DTLsetup}\marg{\optvalm{numeric}{\numericoptval{region-currency}{false}}}
\end{compactcodebox*}
\end{information}

As described in \sectionref{sec:numerical},
a \idx{plainnumber} can be converted to a formatted currency with
\gls{DTLdecimaltocurrency}. The formatting of the number is
performed in the same manner as with \gls{DTLdecimaltolocale}.
The way that the currency symbol is formatted in relation to the
\idx{formattednumber} depends on the currency formatting style.

\mExampleref{ex:noregioncurrency} has a simple document with no
localisation support:
\begin{codebox}
\cmd{documentclass}\marg{article}
\cmd{usepackage}\marg{datatool-base}
\end{codebox}
First the default currency code and symbol are displayed:
\begin{codebox}
Currency code: \gls{DTLCurrencyCode}.
Currency symbol: \gls{DTLCurrencySymbol}.
\end{codebox}
Then a \idx{plainnumber} is converted to a formatted currency:
\begin{codebox}
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{formattedresult}}
Formatted: \cmd{formattedresult}.
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{formattedresult}}.)
\end{codebox}
This will use the current \idx{numbergroupchar} and \idx{decimalchar}
to format the value and the current currency symbol and style to
format the currency unit. 

Next a formatted currency (using the current \idx{numbergroupchar} and \idx{decimalchar}
settings) is added to a \idx{formattednumber}. Note that the symbol
doesn't need to match the current currency symbol:
\begin{codebox}
\gls{cs.dollar}1,234.57 add 1,236.59:
\gls{DTLadd}\marg{\cmd{total}}\marg{\gls{cs.dollar}1,234.57}\marg{1,236.59}
Total: \cmd{total}.
\codepar
1,234.57 add £1,236.59:
\gls{DTLadd}\marg{\cmd{total}}\marg{1,234.57}\marg{£1,236.59}
Total: \cmd{total}.
\end{codebox}
The symbol is ignored during the arithmetic computation. The result
is formatted according to the current settings.

Rounding is determined by \gls{DTLCurrentLocaleCurrencyDP} which is
adjusted by regional support.
\begin{codebox}
€48,236.59 multiplied by 0.5:
\gls{DTLmul}\marg{\cmd{result}}\marg{€48,236.59}\marg{0.5}
\cmd{result}\gls{cs.space}(\gls{DTLdatumvalue}\marg{\cmd{result}}).
\end{codebox}
Note that the rounding only affects the formatting, not the value
stored within the \idx{datumcs}.

To demonstrate currency parsing, \gls{DTLparse} is used to parse to
different currencies. The first has a Euro symbol:
\begin{codebox}
\gls{DTLparse}\cmd{parsed}\marg{€19,234.56}
String value: \cmd{parsed}.
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\end{codebox}
The second has a pound symbol:
\begin{codebox}
\gls{DTLparse}\cmd{parsed}\marg{£28,342.64}
String value: \cmd{parsed}.
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\end{codebox}
Note that even though these symbols don't match the current default currency
symbol, they are still recognised as currency.

The symbol may also occur after the value:
\begin{codebox}
\gls{DTLparse}\cmd{parsed}\marg{19,234.56€}
String value: \cmd{parsed}.
Data type: 
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\end{codebox}

The currency style formatting is described in more detail later in
this section, but \gls{DTLfmtcurrency} can be used to apply the
current formatting style to the currency symbol provided in the
first argument and the \idx{formattednumber} provided in the second
argument. Note that this is just a style command, and doesn't parse
or format the value. (It's redefined whenever the default currency
setting is changed.) This means that the following works fine even though
it's using different \idx{numbergroupchar} and \idx{decimalchar}
to the current default:
\begin{codebox}
Formatting specific currency symbol:
\gls{DTLfmtcurrency}\marg{\gls{texteuro}}\marg{12.345,65}
\end{codebox}
The command \gls{DTLcurrency} is simply a shortcut that uses
\gls{DTLfmtcurrency} with the current default currency symbol:
\begin{codebox}
Formatting default currency symbol:
\gls{DTLcurrency}\marg{12 345,65}
\end{codebox}
Again, the value argument is expected to be in the correct format.

The above uses the formatting style for the current default currency, 
but if a currency has been defined with a three-letter currency
code, then \gls{DTLfmtcurr} may be used to format the currency
according to the style and symbol associated with that currency code. Again, 
the value argument is expected to be in the correct format:
\begin{codebox}
Formatting EUR:
\gls{DTLfmtcurr}\marg{EUR}\marg{12.345,65}
\end{codebox}
The \qt{EUR} currency code is predefined by \sty{datatool-base} as
it covers an number of regions (although any region that sets
\qt{EUR} as the currency should also redefine
\gls{DTLdefaultEURcurrencyfmt} as applicable). Other currency codes need regional
support to provide them, which will be covered in the next example.

\begin{resultbox}
\createexample*[label={ex:noregioncurrency},
 arara={pdflatex,pdfcrop},
 title={Formatting and Parsing Currency (No Region)},
 description={Example document that formats and parses currency
without regional support}
]
{%
\cmd{usepackage}\marg{datatool-base}
}
{%
Currency code: \gls{DTLCurrencyCode}.
Currency symbol: \gls{DTLCurrencySymbol}.
\codepar
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{formattedresult}}\nl
Formatted: \cmd{formattedresult}.\nl
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{formattedresult}}.)
\codepar
\string\$1,234.57 add 1,236.59:\nl
\gls{DTLadd}\marg{\cmd{total}}\marg{\string\$1,234.57}\marg{1,236.59}\nl
Total: \cmd{total}.
\codepar
1,234.57 add £1,236.59:\nl
\gls{DTLadd}\marg{\cmd{total}}\marg{1,234.57}\marg{£1,236.59}\nl
Total: \cmd{total}.
\codepar
€48,236.59 multiplied by 0.5:\nl
\gls{DTLmul}\marg{\cmd{result}}\marg{€48,236.59}\marg{0.5}\nl
\cmd{result}\string\ (\gls{DTLdatumvalue}\marg{\cmd{result}}).
\codepar
\gls{DTLparse}\cmd{parsed}\marg{€19,234.56}\nl
String value: \cmd{parsed}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.\nl
\codepar
\gls{DTLparse}\cmd{parsed}\marg{£28,342.64}\nl
String value: \cmd{parsed}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.\nl
\codepar
\gls{DTLparse}\cmd{parsed}\marg{19,234.56€}\nl
String value: \cmd{parsed}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\codepar
Formatting specific currency symbol:
\gls{DTLfmtcurrency}\marg{\gls{texteuro}}\marg{12.345,65}
\codepar
Formatting default currency symbol:
\gls{DTLcurrency}\marg{12 345,65}
\codepar
Formatting EUR:
\gls{DTLfmtcurr}\marg{EUR}\marg{12.345,65}
}
\end{resultbox}

\mExampleref{ex:regionGBcurrency} requires
\sty{datatool-regions} to be installed. The region needs to be
established. This can be done by loading a language package first,
where the dialect has an associated region. For example:
\begin{compactcodebox}
\cmd{usepackage}\oarg{british}\marg{babel}
\cmd{usepackage}\marg{datatool-base}
\end{compactcodebox}
Or if just the root language is specified, \opt{locales} may be used
to add the region to the language:
\begin{compactcodebox}
\cmd{usepackage}\oarg{english}\marg{babel}
\cmd{usepackage}\oarg{\optval{locales}{GB}}\marg{datatool-base}
\end{compactcodebox}
In this example, I'm not using a language package so I need to use
the \opt{locales} option with both the language and region in the
tag:
\begin{codebox}
\cmd{usepackage}\oarg{\optvalm{locales}{en-GB}}\marg{datatool-base}
\end{codebox}
First the default currency code and symbol are displayed:
\begin{codebox}
Currency code: \gls{DTLCurrencyCode}.
Currency symbol: \gls{DTLCurrencySymbol}.
\end{codebox}
As with the previous example, I can use \gls{DTLdecimaltocurrency}
to convert a \idx{plainnumber} into formatted currency using the
current style settings:
\begin{codebox}
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{formattedresult}}
Formatted: \cmd{formattedresult}.
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{formattedresult}}.)
\end{codebox}
As before, currency can be parsed.
\begin{codebox}
\gls{DTLparse}\cmd{parsed}\marg{£28,342.64}
String value: \cmd{parsed}.
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\end{codebox}
The currency symbol needs to be
known but doesn't need to be the current default. However, the 
\idx{numbergroupchar} and \idx{decimalchar} must match the current
setting.
\begin{codebox}
\gls{DTLparse}\cmd{parsed}\marg{€19,234.56}
String value: \cmd{parsed}.
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\end{codebox}
A region may provide its own settings. For example, the GB region
support provides different number styles: \optfmt{official} (the
default), \optfmt{education} (a thin space for the \idx{numbergroupchar})
or \optfmt{old} (a mid-dot for the \idx{decimalchar}).
There is also an option to prefix the currency symbol with the
region code:
\begin{codebox*}
\gls{DTLsetLocaleOptions}\marg{GB}\marg{
  number-style=old,
  currency-symbol-prefix
}
(GB settings: number-style=old, 
currency-symbol-prefix=true.)
\end{codebox*}
This affects the formatting:
\begin{codebox}
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{formattedresult}}
Formatted: \cmd{formattedresult}.
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{formattedresult}}.)
\end{codebox}
The \optfmt{old} number style uses \gls{textperiodcentered} when formatting but
allows \gls{textperiodcentered} or a mid-dot character or a normal dot when parsing:
\begin{codebox}
\gls{DTLparse}\cmd{parsed}\marg{£28,342.648}
String value: \cmd{parsed}.
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\end{codebox}
Note that this doesn't round the value or format it. The formatted
string is simply parsed to determine its type, numeric value and
currency symbol.

The \numericopt{auto-reformat} option will make \gls{DTLparse}
automatically reformat the string value and,
since GBP supports a regional prefix, \numericopt{region-currency-prefix}
may be used to alter the prefix format:
\begin{codebox}
\gls{DTLsetup}\marg{
  \optvalm{numeric}{
    \numericopt{auto-reformat},
    \numericoptval{region-currency-prefix}{smallcaps}
  }
}
(Numeric settings: auto-reformat, 
region-currency-prefix=smallcaps.)
\end{codebox}
Note that the prefix isn't included with the currency symbol
obtained with \gls{DTLdatumcurrency}.
\begin{codebox}
\gls{DTLparse}\cmd{parsed}\marg{£28,342.648}
String value: \cmd{parsed}.
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
Currency symbol: \gls{DTLdatumcurrency}\marg{\cmd{parsed}}.
\end{codebox}

\begin{resultbox}[float]
\createexample*[label={ex:regionGBcurrency},
 arara={xelatex,pdfcrop},
 title={Currency Formats (GB Region)},
 description={Example document that formats currencies according to
GB region}
]
{%
\cmd{usepackage}\oarg{\optvalm{locales}{en-GB}}\marg{datatool-base}\nl
}
{%
Currency code: \gls{DTLCurrencyCode}.\nl
Currency symbol: \gls{DTLCurrencySymbol}.
\codepar
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{formattedresult}}\nl
Formatted: \cmd{formattedresult}.\nl
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{formattedresult}}.)
\codepar
\gls{DTLparse}\cmd{parsed}\marg{£28,342.64}\nl
String value: \cmd{parsed}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\codepar
\gls{DTLparse}\cmd{parsed}\marg{€19,234.56}\nl
String value: \cmd{parsed}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\codepar
\gls{DTLsetLocaleOptions}\marg{GB}\marg{\nlsp
  number-style=old,\nlsp
  currency-symbol-prefix\nl
}\nl
(GB settings: number-style=old, currency-symbol-prefix=true.)
\codepar
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{formattedresult}}\nl
Formatted: \cmd{formattedresult}.\nl
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{formattedresult}}.)
\codepar
\gls{DTLparse}\cmd{parsed}\marg{£28,342.648}\nl
String value: \cmd{parsed}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.
\codepar
\gls{DTLsetup}\marg{\nlsp
  \optvalm{numeric}{\nldbsp
    auto-reformat,\nldbsp
    region-currency-prefix=smallcaps\nlsp
  }\nl
}\nl
(Numeric settings: auto-reformat, region-currency-prefix=smallcaps.)
\codepar
\gls{DTLparse}\cmd{parsed}\marg{£28,342.648}\nl
String value: \cmd{parsed}.\nl
Numeric value: \gls{DTLdatumvalue}\marg{\cmd{parsed}}.\nl
Currency symbol: \gls{DTLdatumcurrency}\marg{\cmd{parsed}}.
}
\end{resultbox}

\mExampleref{ex:multiregioncurrency} has two regions: GB and IE but
the same language for both. No language package is loaded. This
means that the region hook must be explicitly used to switch between
the two regions. The locales are identified:
\begin{codebox}
\cmd{usepackage}\oarg{\optvalm{locales}{en-GB,en-IE}}\marg{datatool-base}
\end{codebox}
For the GB region, I'm going to use the \qt{education} number
style, which uses a thin space for the \idx{numbergroupchar} when
formatting. For parsing, it allows either a thin space or a normal
space:
\begin{codebox}
\gls{DTLsetLocaleOptions}\marg{GB}\marg{ number-style = education }
\end{codebox}
I'm also going to switch on the \numericopt{auto-reformat} option:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{numeric}{\numericopt{auto-reformat}}}
\end{codebox}

Switch to the GB region:
\begin{codebox}
\DTLtagLocaleHook{GB}
\end{codebox}
and display the currency code and symbol:
\begin{codebox}
Currency code: \gls{DTLCurrencyCode}.
Currency symbol: \gls{DTLCurrencySymbol}.
\end{codebox}
Convert a \idx{plainnumber} to a formatted currency:
\begin{codebox}
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{GBformattedresult}}
Formatted: \cmd{GBformattedresult}.
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{GBformattedresult}}.)
\end{codebox}
Parse a formatted currency:
\begin{codebox}
Parsing £12 345.67.
\gls{DTLparse}\cmd{GBparsed}\marg{£12 345.67}
\codepar
Parsed: \cmd{GBparsed}.
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{GBparsed}}.)
\end{codebox}
Since the \numericopt{auto-reformat} option is on, the string value
will be reformatted to use a thin space, instead of the normal space
used in the original.

The code is similar for the IE region:
\begin{codebox}
\DTLtagLocaleHook{IE}
Currency code: \gls{DTLCurrencyCode}.
Currency symbol: \gls{DTLCurrencySymbol}.
\codepar
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{IEformattedresult}}
Formatted: \cmd{IEformattedresult}.
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{IEformattedresult}}.)
\end{codebox}
Note that the \idx{numbergroupchar} has been changed to a comma.
The \idx{decimalchar} has been set to a dot, which is the same as
before.
\begin{codebox}
Parsing €12,345.67.
\gls{DTLparse}\cmd{IEparsed}\marg{€12,345.67}
\codepar
Parsed: \cmd{IEparsed}.
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{IEparsed}}.)
\end{codebox}
The package-wide settings are changed:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{numeric}{\numericoptval{currency-symbol-style}{iso}}}
\end{codebox}
Both the GB and IE regions support the \optfmt{currency-symbol-position}
setting:
\begin{codebox}
\gls{DTLsetLocaleOptions}\marg{GB,IE}
 \marg{currency-symbol-position=after}
\end{codebox}
The \idxpl{datumcs} are redisplayed:
\begin{codebox}
\cbeg{enumerate}
\cmd{item} \cmd{GBformattedresult}.
\cmd{item} \cmd{GBparsed}.
\cmd{item} \cmd{IEformattedresult}.
\cmd{item} \cmd{IEparsed}.
\cend{enumerate}
\end{codebox}
Note that although this has changed the way that the currency symbol
is formatted in relation to the value, the formatting of the value
hasn't changed.

\begin{resultbox}
\createexample*[label={ex:multiregioncurrency},
 arara={xelatex,pdfcrop},
 title={Currency Formats (GB and IE Regions)},
 description={Example document that formats currencies according to
GB and IE regions}
]
{%
\cmd{usepackage}\oarg{\optvalm{locales}{en-GB,en-IE}}\marg{datatool-base}\nl
\gls{DTLsetLocaleOptions}\marg{GB}\marg{ number-style = education }\nl
\gls{DTLsetup}\marg{\optvalm{numeric}{\numericopt{auto-reformat}}}
}
{%
\cmd{DTLGBLocaleHook}\nl
Currency code: \gls{DTLCurrencyCode}.\nl
Currency symbol: \gls{DTLCurrencySymbol}.
\codepar
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{GBformattedresult}}\nl
Formatted: \cmd{GBformattedresult}.\nl
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{GBformattedresult}}.)
\codepar
Parsing £12 345.67.\nl
\gls{DTLparse}\cmd{GBparsed}\marg{£12 345.67}\nl
\codepar
Parsed: \cmd{GBparsed}.\nl
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{GBparsed}}.)
\codepar
\cmd{DTLIELocaleHook}\nl
Currency code: \gls{DTLCurrencyCode}.\nl
Currency symbol: \gls{DTLCurrencySymbol}.
\codepar
\gls{DTLdecimaltocurrency}\marg{12345.678}\marg{\cmd{IEformattedresult}}\nl
Formatted: \cmd{IEformattedresult}.\nl
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{IEformattedresult}}.)
\codepar
Parsing €12,345.67.\nl
\gls{DTLparse}\cmd{IEparsed}\marg{€12,345.67}\nl
\codepar
Parsed: \cmd{IEparsed}.\nl
(Numeric value: \gls{DTLdatumvalue}\marg{\cmd{IEparsed}}.)
\codepar
\gls{DTLsetup}\marg{\optvalm{numeric}{\numericoptval{currency-symbol-style}{iso}}}\nl
\gls{DTLsetLocaleOptions}\marg{GB,IE}\marg{currency-symbol-position=after}\nl
\cbeg{enumerate}\nl
\cmd{item} \cmd{GBformattedresult}.\nl
\cmd{item} \cmd{GBparsed}.\nl
\cmd{item} \cmd{IEformattedresult}.\nl
\cmd{item} \cmd{IEparsed}.\nl
\cend{enumerate}
}
\end{resultbox}

If there is no support for your region, or if you are using a
currency that's not connected to your region (for example, Bitcoin), 
then you can use the commands described below to define a currency
(if not already provided by \sty{datatool-base}) and to switch to a
previously defined currency.

\cmddef{DTLnewcurrencysymbol}
This adds \meta{symbol} to the list of known currencies (if not
already in the list).

\begin{warning}
Be careful of non-robust currency symbol commands. If these are
expanded before the parser scans the value, the symbol won't be
detected and the value will be deemed a string instead.
(See \exampleref{ex:DTListype}.) However, many commands that were
previously partially expandable, and therefore susceptible to this problem,
have been made robust with recent \LaTeX\ kernels.
\end{warning}

The set of known currencies is initialised to contain
common currency symbols supported by the document encoding, and the
currency commands:
\gls{cs.dollar}, \gls{pounds}, \gls{texteuro},
\gls{textdollar}, \gls{textsterling}, \gls{textyen}, \gls{textwon},
and \gls{textcurrency}.

The known currency list simply assists parsing, but it's also
possible to define a currency with a corresponding ISO code and
alternative representation to adjust the way a currency value is
formatted.

\cmddef{DTLdefcurrency}
This locally defines a new currency (or redefines an existing
currency) identified by the given ISO code.  The \meta{symbol}
argument is the currency symbol using \LaTeX\ markup, such as
\gls{pounds} or \gls{cs.dollar}, and the \meta{char} argument is a
string (non-command) representation of the currency symbol, such
as \code{£} or \idx{sym.dollar}. (Note that \idx{sym.dollar}
will have category code \qt{other} within the \meta{char} argument.)

\begin{information}
The \meta{char} argument is expanded when the currency is defined.
The \meta{symbol} argument isn't expanded.
\end{information}

The optional argument \meta{fmt} indicates how this currency should
be formatted and should end with (or solely consist of) a command
that takes two arguments \code{\margm{sym}\margm{value}}. The
default is \gls{dtlcurrdefaultfmt} (see below).

The following command is defined by \gls{DTLdefcurrency}:
\cmddef{DTLcurrISO}
which expands to:
\begin{compactcodebox}
\gls{dtltexorsort}
 \marg{\gls{DTLcurrCodeOrSymOrChar}\margm{ISO}\margm{symbol}\margm{char}}
 \margm{string}
\end{compactcodebox}
where \meta{string} is the detokenized \meta{char}.
Additionally, \gls{DTLdefcurrency} automatically implements:
\begin{compactcodebox}
\gls{DTLnewcurrencysymbol}\margm{symbol}
\gls{DTLnewcurrencysymbol}\margm{string}
\gls{DTLnewcurrencysymbol}\marg{\gls{DTLcurrISO}}
\end{compactcodebox}
This ensures that the parser can identify \meta{symbol},
\meta{string} and \gls{DTLcurrISO} as currency symbols. 
For example, the file \ldf{GB} (provided with
\sty{datatool-regions}) includes the equivalent to:
\begin{codebox}
\gls{DTLdefcurrency}\oarg{\gls{datatoolGBcurrencyfmt}}\marg{GBP}\marg{\gls{pounds}}\marg{£}
\end{codebox}
(where \gls{datatoolGBcurrencyfmt} is also provided.)
This locally defines a currency identified as
\code{GBP}, with the associated symbol \gls{pounds} and character
alternative \qtt{£}. It also defines the command \DTLcurrISO{GBP},
and adds \DTLcurrISO{GBP} to the set of
known currencies (\qtt{£} and \gls{pounds} should typically already
be in the set).
So the above essentially does (where the second argument of
\gls{dtltexorsort} has been detokenized):
\begin{compactcodebox}
\cmd{def}\DTLcurrISO{GBP}\marg{\comment{}
 \gls{dtltexorsort}\marg{\gls{DTLcurrCodeOrSymOrChar}\marg{GBP}\marg{\gls{pounds}}\marg{£}}\marg{£}}
\gls{DTLnewcurrencysymbol}\marg{\gls{pounds}}\comment{redundant}
\gls{DTLnewcurrencysymbol}\marg{£}
\gls{DTLnewcurrencysymbol}\marg{\DTLcurrISO{GBP}}
\end{compactcodebox}
As well as setting the format for the GBP currency to
\gls{datatoolGBcurrencyfmt}.

\begin{information}
\gls{DTLdefcurrency} doesn't change the default currency (see \exampleref{ex:defcurr}).
It simply defines a currency.
\end{information}

The underlying function used by \gls{DTLdefcurrency} is:
\cmddef{datatooldefcurrency:nnnn}
Note that, unlike \gls{DTLdefcurrency}, this doesn't perform any
category code change or expansion for the final argument.
(If expansion is needed, one of the variants may be used.)
For example, the file \ldf{CA} has:
\begin{codebox}
\expfunc{datatooldefcurrency:nnnn}{nnnV}
 { \cmd{datatoolCAcurrencyfmt} }
 { CAD } 
 { \gls{cs.dollar} }
 \cmd{c\_dollar\_str}
\end{codebox}

There is a shortcut that sets the format to \gls{dtlcurrdefaultfmt}:
\cmddef{datatooldefcurrency:nnn}
This internally calls the \gls{datatooldefcurrency:nnnn} function.

The symbol associated with a defined currency may be changed with:
\cmddef{datatoolsetcurrencysymbol:nn}
Note that this also adds the symbol with \gls{DTLnewcurrencysymbol}
but does not remove the previous symbol from the set of known
currency symbols.

The symbol and associated string value for a currency that has been defined 
can be obtained with:
\cmddef{DTLcurrSym}
Expands to the symbol (such as \gls{cs.dollar} or \gls{pounds}) associated with currency 
\meta{ISO} or to nothing if not defined.
\cmddef{DTLcurrChar}
Expands to the character associated with currency \meta{ISO} or to
nothing if not defined (for example, \$ or £).
\cmddef{DTLcurrStr}
Expands to the detokenised string value associated with currency \meta{ISO} or to
nothing if not defined.

If you don't know whether or not \gls{DTLcurrISO} has been defined
for a given \meta{ISO} code, you can use:
\cmddef{DTLcurr}
This command will expand to \gls{DTLcurrISO}, if defined, otherwise
it will expand to \meta{ISO}. (The \app{datatooltk} application uses
this for currency symbols when importing data that has been given an
associated currency code.)

If you want to switch to a previously defined currency, you need to use
\gls{DTLsetdefaultcurrency}. For example:
\begin{codebox}
\gls{DTLsetdefaultcurrency}\marg{GBP}
\end{codebox}
This is done by \ldf{GB} in the language hook.

If no localisation file has been loaded (see
\sectionref{sec:localisation}), then the default is ISO code
\qt{XXX} and symbol \code{\gls{cs.dollar}}. (The default symbol is
for backward-compatibility, and \code{\gls{cs.dollar}} was one of the
few currency commands guaranteed to be defined when the first
version of \sty{datatool} was written.)

The following currencies are defined by \sty{datatool-base}:
\qt{XXX} (associated command \inlineglsdef{DTLcurrXXX}),
\qt{XBT} (associated command \inlineglsdef{DTLcurrXBT}),
\qt{EUR} (associated command \inlineglsdef{DTLcurrEUR}). 

The \qt{XXX} and \qt{XBT} currencies use the default currency
formatting command \gls{dtlcurrdefaultfmt} but the \qt{EUR} currency
is associated with:
\cmddef{DTLdefaultEURcurrencyfmt}
The default definition is just \gls{dtlcurrdefaultfmt} but this
makes it possible to vary the format of EUR specifically without
affecting other currencies.

If you prefer a different symbol, you can use
\gls{datatoolsetcurrencysymbol:nn}. For example:
\begin{codebox}
\cmd{newfontfamily}\cmd{liberationserif}\marg{Liberation Serif}
\cmd{NewDocumentCommand}\marg{\cmd{bitcoin}}\marg{}\marg{\marg{\cmd{liberationserif} \ttbitcoin}}
\gls{ExplSyntaxOn}
\gls{datatoolsetcurrencysymbol:nn} \marg{ XBT } \marg{ \cmd{bitcoin} }
\gls{ExplSyntaxOff}
\end{codebox}

The currency string depends on the file encoding 
(see \sectionref{sec:encoding}).

\cmddef{DTLCurrencySymbol}
This command is simply defined to the internal command used to store
the default currency symbol. It's provided to allow access to the
currency symbol without having to switch category code. Redefining
this command will not change the default currency symbol.
The command \gls{DTLCurrencySymbol} is not automatically added to
the list of known currency symbols.

\begin{important}
If you want to change the default currency, use
\gls{DTLsetdefaultcurrency}.  Don't redefine
placeholder commands, such as \gls{DTLCurrencySymbol} and
\gls{DTLCurrencyCode}.
\end{important}

\cmddef{DTLCurrencyCode}
This command is redefined by \gls{DTLsetdefaultcurrency} to
\idxc{expansion}{expand} to the associated ISO code.

\cmddef{DTLfmtcurrency}
This command is redefined by \gls{DTLsetdefaultcurrency} to
\idxc{expansion}{expand} to the associated currency formatting code
(as supplied in the \meta{fmt} optional argument of
\gls{DTLdefcurrency}). The \meta{symbol} argument doesn't need to
have been identified as a known currency symbol, but the
\meta{value} must be a \idx{formattednumber} with the correct
rounding that uses the current \idx{numbergroupchar} and
\idx{decimalchar}.

The default definition of \gls{DTLfmtcurrency} just does:
\cmddef{dtlcurrdefaultfmt}
which is defined to use the following command.
\cmddef{dtlcurrprefixfmt}
This internally uses:
\cmddef{datatoolprefixadjustsign:nnn}
(where the separator is \cmd{dtlcurrfmtsep})
which tests if \meta{value} starts with a plus (\code{+})
or minus (\code{-}) and, if so, shifts the sign in front of
the symbol and encapsulates it with:
\cmddef{datatooladjustsignfmt:n}
This will convert the hyphen-minus sign (\code{-}) to 
\gls{textminus} if not in math mode.

For currencies that have the symbol at the end:
\cmddef{dtlcurrsuffixfmt}
This internally uses:
\cmddef{datatoolsuffixadjustsign:nnn}
(where the separator is \cmd{dtlcurrfmtsep})
which similarly adjusts the leading sign (if present) but in this
case puts the separator and symbol after the value.

Both \gls{dtlcurrprefixfmt} and \gls{dtlcurrsuffixfmt} use:
\cmddef{dtlcurrfmtsep}
as the separator. This defaults to:
\begin{compactcodebox}
\gls{DTLcurrCodeOrSymOrChar}
 \marg{\idx{nbsp}}
 \marg{\gls{dtlcurrfmtsymsep}}
 \marg{\gls{dtlcurrfmtsymsep}}
\end{compactcodebox}
This expands to a space with
\numericoptval{currency-symbol-style}{iso}, otherwise to:
\cmddef{dtlcurrfmtsymsep}
This should be redefined by region files.

Since \gls{DTLfmtcurrency} will change its format according to the
current localisation settings, which may not be appropriate, you may prefer to use:
\cmddef{DTLfmtcurr}
This will use the format associated with the given currency code.
If the currency code hasn't been defined, then this simply expands
to \code{\gls{DTLcurrency}\margm{num}} instead.

Region files may provide their own format that inserts a tag before
the currency symbol. For example, \ldf{GB} provides:
\begin{compactcodebox}
\cmd{newcommand}\gls{datatoolGBcurrencyfmt}\oarg{2}\marg{\comment{}
 \gls{dtlcurrprefixfmt}
  \marg{\datatoolRegionsymbolprefix{GB}\marg{GB}\#1}\comment{symbol}
  \marg{\#2}\comment{value}
}
\end{compactcodebox}
The default definition of \datatoolRegionsymbolprefix{GB} does
nothing, but the region provides an option to redefine this command
to \gls{datatoolcurrencysymbolregionprefix:n}.

Note that \gls{DTLfmtcurrency} requires the currency symbol as an
argument, which doesn't have to be the default symbol (or even a
recognised currency symbol). If you want the default symbol without
having to specify it, you can use:
\cmddef{DTLcurrency}
This expands to \code{\gls{DTLfmtcurrency}\margm{sym}\margm{value}}
where \meta{sym} is the default currency symbol, which is initially
\code{\gls{cs.dollar}} but will be changed to \gls{DTLcurrISO} by
\code{\gls{DTLsetdefaultcurrency}\margm{ISO}}.

\cmddef{DTLcurrCodeOrSymOrChar}
This is used in both \gls{DTLcurrISO} and \gls{dtlcurrfmtsep} and
should be defined to \idxc{expansion}{expand} to one of its arguments (ignoring the
other two). The default is to \idxc{expansion}{expand} to \meta{symbol}. This means
that \gls{DTLcurrency} will use the symbol command associated with the
default currency. You can redefine \gls{DTLcurrCodeOrSymOrChar} to
\idxc{expansion}{expand} to a different argument if you prefer.
The \opt{numeric} option \numericopt{currency-symbol-style}
redefines \gls{DTLcurrCodeOrSymOrChar}.

\begin{information}
\gls{DTLdecimaltocurrency} internally uses \gls{DTLfmtcurrency} with
the value rounded to the decimal places specified
by \gls{DTLCurrentLocaleCurrencyDP} and formatted according to 
the current \idx{numbergroupchar} and \idx{decimalchar}. The
optional argument to \gls{DTLdecimaltocurrency} is used in the
\meta{symbol} argument of \gls{DTLfmtcurrency}.
\end{information}

The \ldf{GB} file provided with \sty{datatool-regions} provides
the GBP currency. The example below is provided to demonstrate how
to define currencies and modify the formatting.
If you want to add support for your region, there is a Perl script 
in the \sty{datatool-regions} GitHub repository that can get you
started. You can then add your region file via a pull request.
See the \qt{README} file at \url{https://github.com/nlct/datatool-regions}
for further details.

\mExampleref{ex:defcurr} ensures that \DTLcurrISO{GBP}, \gls{pounds} and \code{£}
are all recognised as currency symbols when parsing currency values
(although \gls{pounds} and \code{£} are recognised by default).
However, it's necessary to explicitly change the default currency
for instances where the currency symbol is omitted:
\begin{codebox}
Default currency: \gls{DTLCurrencyCode}.
\gls{DTLdecimaltocurrency}\marg{1234.567}\marg{\cmd{result}}
Formatted value: \cmd{result}.
\codepar
£1.99:
 \gls{DTLifcurrency}\marg{£1.99}\marg{currency}\marg{not currency};
\gls{DTLfmtcurrency}\marg{£}\marg{1.99}: 
\gls{DTLifcurrency}\marg{\gls{DTLfmtcurrency}\marg{£}\marg{1.99}}\marg{currency}\marg{not currency}.
\codepar
Defining GBP.
\gls{DTLdefcurrency}\marg{GBP}\marg{\gls{pounds}}\marg{£}
Default currency: \gls{DTLCurrencyCode}.
\codepar
£1.99:
 \gls{DTLifcurrency}\marg{£1.99}\marg{currency}\marg{not currency}.
\codepar
Switching to GBP.\gls{DTLsetdefaultcurrency}\marg{GBP}
Default currency: \gls{DTLCurrencyCode}.
\codepar
\gls{DTLdecimaltocurrency}\marg{1234.567}\marg{\cmd{result}}
Formatted value: \cmd{result}.
\codepar
\cmd{renewcommand}\marg{\gls{dtlcurrdefaultfmt}}\marg{\gls{dtlcurrsuffixfmt}}
\cmd{renewcommand}\marg{\gls{DTLcurrCodeOrSymOrChar}}[3]\marg{\#1}
Formatted value: \cmd{result}.
\codepar
\gls{DTLaddall}\marg{\cmd{result}}\marg{\gls{pounds}2.50,\DTLcurrISO{GBP} 1.25,£0.25}
Formatted value: \cmd{result}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:defcurr},arara={xelatex,pdfcrop},
 title={Defining a Currency},
 description={Example document that defines GBP currency}
]
{%
\comment{This is an example document to demonstrate provided
commands}
\comment{To create your own region ldf file, see https://github.com/nlct/datatool-regions}
\cmd{usepackage}\marg{datatool-base}\nl
}
{%
Default currency: \gls{DTLCurrencyCode}.\nl
\gls{DTLdecimaltocurrency}\marg{1234.567}\marg{\cmd{result}}\nl
Formatted value: \cmd{result}.
\codepar
£1.99: \gls{DTLifcurrency}\marg{£1.99}\marg{currency}\marg{not
currency};\nl
\gls{DTLfmtcurrency}\marg{£}\marg{1.99}: \gls{DTLifcurrency}\marg{\gls{DTLfmtcurrency}\marg{£}\marg{1.99}}\marg{currency}\marg{not currency}.
\codepar
Defining GBP.\nl
\gls{DTLdefcurrency}\marg{GBP}\marg{\gls{pounds}}\marg{£}\nl
Default currency: \gls{DTLCurrencyCode}.
\codepar
£1.99: \gls{DTLifcurrency}\marg{£1.99}\marg{currency}\marg{not currency}.
\codepar
Switching to GBP.\gls{DTLsetdefaultcurrency}\marg{GBP}\nl
Default currency: \gls{DTLCurrencyCode}.
\codepar
\gls{DTLdecimaltocurrency}\marg{1234.567}\marg{\cmd{result}}\nl
Formatted value: \cmd{result}.
\codepar
\cmd{renewcommand}\marg{\gls{dtlcurrdefaultfmt}}\marg{\gls{dtlcurrsuffixfmt}}
\cmd{renewcommand}\marg{\gls{DTLcurrCodeOrSymOrChar}}[3]\marg{\#1}
Formatted value: \cmd{result}.
\codepar
\gls{DTLaddall}\marg{\cmd{result}}\marg{\gls{pounds}2.50,\DTLcurrISO{GBP}
1.25,£0.25}\nl
Formatted value: \cmd{result}.
}
\end{resultbox}
Note that \cmd{result} is defined as a \idx{datumcs}. This means
that the resulting command doesn't need to be reparsed to obtain its
numerical value.

In the case of \gls{DTLaddall} the symbol from the final currency in
the list is used (the character \qtt{£}). So the final \cmd{result}
(indirectly) expands to \code{\gls{DTLfmtcurrency}\marg{£}\marg{4}}. 
This now shows the currency unit as a suffix
because of the redefinition of \gls{dtlcurrdefaultfmt}.

\section{Dates and Times}
\label{sec:datetime}

The temporal data types (datetime, date, and time) were only added to
\sty{datatool-base} version 3.0 and are still experimental so
this feature is off by default. Parsing can be enabled with
the \opt{datetime} option.

Options that govern date and time parsing can be set within the
\opt{datetime} setting value. For example:
\begin{codebox}
\gls{DTLsetup}\marg{ \optvalm{datetime}{\datetimeoptval{parse}{auto-reformat}} }
\end{codebox}
Available options are listed below.

\optiondef{datetime.parse}
Determines whether or not to check for temporal values when parsing.
The default is:
\begin{codebox}
\gls{DTLsetup}\marg{
  \optvalm{datetime}{
   \datetimeoptval{parse}{iso+region},
   \datetimeoptval{auto-reformat}{false},
   \datetimeoptval{parse}{false}
  }
 }
\end{codebox}

\optionvaldef{datetime.parse}{false}
Don't check for temporal values when parsing. (The default.)

\optionvaldef{datetime.parse}{true}
Check for temporal values when parsing.
This switches on parsing without altering any of the other settings.

\optionvaldef{datetime.parse}{parse-only}
Check for temporal values when parsing but don't alter the original.
This is equivalent to \code{\datetimeoptval{parse}{true},
\datetimeoptval{auto-reformat}{false}}.

\optionvaldef{datetime.parse}{auto-reformat}
Check for temporal values when parsing and reformat the original.
This is equivalent to \code{\datetimeoptval{parse}{true},
\datetimeoptval{auto-reformat}{true}}.

\optionvaldef{datetime.parse}{iso-only}
Check for temporal values when parsing but
only check for ISO formatted dates and times. For example,
\code{2025-01-14} (date) or \code{16:25:02} (time) or
\code{2025-01-14T16:25:02} (timestamp with no offset) or
\code{2025-01-14T16:25:02+01:00} (timestamp with offset).

\optionvaldef{datetime.parse}{region-only}
Check for temporal values when parsing but
only parse the current region's date and time formatting. This
requires localisation support.
See \sectionref{sec:localisation}.

\optionvaldef{datetime.parse}{iso+region}
First check for ISO format then check for current region's format.
If there is no localisation support provided, this will be
equivalent to \datetimeoptval{parse}{iso-only}

\optiondef{datetime.auto-reformat}
If temporal parsing is on, this option determines whether or not the
original value should be reformatted.

\begin{information}
This option has no effect with \iooptval{csv-content}{no-parse}
as the values aren't parsed. Use \ioopt{convert-numbers} instead.
\end{information}

\optionvaldef{datetime.auto-reformat}{false}
If temporal parsing is on, don't reformat the original.

\optionvaldef{datetime.auto-reformat}{true}
If temporal parsing is on, reformat the original according to the
current settings.
(According to the \opt{auto-reformat-types} setting.)

\optionvaldef{datetime.auto-reformat}{region}
If temporal parsing is on, reformat the original according to the
region settings. 
(Provided the temporal type is included in the \opt{auto-reformat-types} setting.)
This essentially does
\begin{compactcodebox*}
\gls{DTLsetup}\marg{\optval{datetime}{\datetimeoptval{auto-reformat}{true}}}
\cmd{renewcommand}\gls{DataToolDateFmt}\marg{\comment{}
 \gls{DTLCurrentLocaleFormatDate}}
\cmd{renewcommand}\gls{DataToolTimeFmt}\marg{\comment{}
 \gls{DTLCurrentLocaleFormatTime}}
\cmd{renewcommand}\gls{DataToolTimeZoneFmt}\marg{\comment{}
 \gls{DTLCurrentLocaleFormatTimeZone}}
\cmd{renewcommand}\gls{DataToolTimeStampWithZoneFmt}\marg{\comment{}
 \gls{DTLCurrentLocaleFormatTimeStampWithZone}}
\cmd{renewcommand}\gls{DataToolTimeStampNoZoneFmt}\marg{\comment{}
 \gls{DTLCurrentLocaleFormatTimeStampNoZone}}
\cmd{renewcommand}\gls{DataToolTimeStampFmtSep}\marg{\comment{}
 \gls{DTLCurrentLocaleTimeStampFmtSep}}
\end{compactcodebox*}
Note that regional support may simply defer to \sty{datetime2}, if
it has been installed, or may just use the ISO numeric format.
See the applicable localisation documentation for further details.
For example, \texdocref{datatool-regions}

\optionvaldef{datetime.auto-reformat}{iso}
If temporal parsing is on, redefine the formatting commands to use
the ISO numeric format.
(Provided the temporal type is included in the \opt{auto-reformat-types} setting.)

\optionvaldef{datetime.auto-reformat}{datetime2}
If temporal parsing is on, redefine the formatting commands to use
the applicable \sty{datetime2} formatting commands.
(Provided the temporal type is included in the \opt{auto-reformat-types} setting.)

Note that this will require \sty{datetime2} to be loaded and you
will need to set the style using \sty{datetime2}['s] interface.

\begin{information}
The \sty{datetime2} style defaults to ISO unless regional support
has been requested and provided.
\end{information}

\mExampleref{ex:parsetemporal} illustrates the different settings:
\begin{codebox}
Parsing off by default.

\gls{DTLparse}\cmd{result}\marg{2025-01-09}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{2025-01-09T14:42:01}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{2025-01-09T15:42:01+01:00}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{14:42:01}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLsetup}\marg{\optvalm{datetime}{\datetimeopt{parse}}}
Parsing on.

\gls{DTLparse}\cmd{result}\marg{2025-01-09}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{2025-01-09T14:42:01}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{2025-01-09T15:42:01+01:00}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{14:42:01}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:parsetemporal},
 title={Parsing Dates and Times},
 description={Example document illustrating date and time parsing}
]
{%
 \cmd{usepackage}\marg{datatool-base}
}
{%
Parsing off by default.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09T14:42:01}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09T15:42:01+01:00}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{14:42:01}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLsetup}\marg{\optvalm{datetime}{parse}}\nl
Parsing on.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09T14:42:01}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09T15:42:01+01:00}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{14:42:01}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
}
\end{resultbox}

\mExampleref{ex:parsetemporalreformat} loads \sty{datetime2}
and not only parses but also reformats the string representation.
(Advanced users: the ISO string can be extracted with
\gls{datatoolextracttimestamp:NN}, see \sectionref{sec:datumitems}.)
\begin{codebox}
\cmd{usepackage}\oarg{en-GB}\marg{datetime2}
\cmd{usepackage}\marg{datatool-base}
\cbeg{document}
\gls{DTLsetup}\marg{\optvalm{datetime}{\datetimeoptval{parse}{auto-reformat}}}

\gls{DTLparse}\cmd{result}\marg{2025-01-09}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{2025-01-09T14:42:01}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{2025-01-09T15:42:01+01:00}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.

\gls{DTLparse}\cmd{result}\marg{14:42:01}
String value: \cmd{result}.
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\cend{document}
\end{codebox}

Note that \sty{datatool-base} will automatically pick up 
\sty{datetime2}['s] regional setting. This will require not only
\sty{datetime2} but also \sty{datetime2-english} (which will be
implicitly loaded by \sty{datetime2} if it is installed).

\begin{resultbox}
\createexample*[label={ex:parsetemporalreformat},
 title={Parsing Dates and Times and Reformatting},
 description={Example document illustrating date and time parsing
with auto-reformatting on}
]
{%
\comment{This will not only require datetime2.sty to be installed }
\comment{but also datetime2-english should be installed }
\cmd{usepackage}\oarg{en-GB}\marg{datetime2}\nl
\cmd{usepackage}\marg{datatool-base}
}
{%
\gls{DTLsetup}\marg{\optvalm{datetime}{parse={auto-reformat}}}
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09T14:42:01}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{2025-01-09T15:42:01+01:00}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
\codepar
\gls{DTLparse}\cmd{result}\marg{14:42:01}\nl
String value: \cmd{result}.\nl
Data type: \gls{DTLdatumtype}\marg{\cmd{result}}.\nl
Value: \gls{DTLdatumvalue}\marg{\cmd{result}}.
}
\end{resultbox}

The \datetimeoptval{auto-reformat}{true} setting will cause commands like
\gls{DTLparse} to replace the original string with the applicable
commands listed below. These commands will be redefined by settings
such as \datetimeoptval{auto-reformat}{iso} or you can redefine them
yourself.

\cmddef{DataToolDateTimeFmt}
Use to format timestamps (datetime date types). Any of the arguments
may be empty, which indicates to omit that part, but if not empty
the arguments should be in the appropriate format to pass to
\gls{DataToolDateFmt} (\meta{date-specs} should
be \margm{year}\margm{month}\margm{day}\margm{dow}), \gls{DataToolTimeFmt}
(\meta{time-specs} should be \margm{hour}\margm{minute}\margm{second})
and \gls{DataToolTimeZoneFmt}
(\meta{offset-specs} should be \margm{tzh}\margm{tzm}).

If both the \meta{date-specs} and \meta{time-specs} are non-empty
then, if \meta{offset-specs} is empty 
\gls{DataToolTimeStampNoZoneFmt} will be
used or if \meta{offset-specs} is not empty
\gls{DataToolTimeStampWithZoneFmt} will be used.

\cmddef{DataToolTimeStampNoZoneFmt}
Formats the date and time. The default definition is to 
use \gls{DTLCurrentLocaleFormatTimeStampNoZone}, which may be
redefined by localisation support.

\cmddef{DataToolTimeStampWithZoneFmt}
Formats the date, time and time zone. The default definition is to 
use \gls{DTLCurrentLocaleFormatTimeStampWithZone}, which may be
redefined by localisation support.

The above commands may use:
\cmddef{DataToolTimeStampFmtSep}
This is placed between the date and time. The default definition
simply expands to \gls{DTLCurrentLocaleTimeStampFmtSep}.

\cmddef{DataToolDateFmt}
Formats the date. The default definition is to use
\gls{DTLCurrentLocaleFormatDate}, which may be
redefined by localisation support. Note that the \meta{dow} argument
may be empty. Otherwise, all arguments must be integers.

\cmddef{DataToolTimeFmt}
Formats the time. The default definition is to use
\gls{DTLCurrentLocaleFormatTime}, which may be
redefined by localisation support. Note that the \meta{second} argument
may be empty. Otherwise, all arguments must be integers.

\cmddef{DataToolTimeZoneFmt}
Formats the time zone offset. The default definition is to use
\gls{DTLCurrentLocaleFormatTimeZone}, which may be
redefined by localisation support. All arguments must be integers.

\section{Strings}
\label{sec:strings}

\begin{warning}
The string related code provided by \sty{datatool-base} has been
rewritten in v3.0.  This means that there may be some differences
in the results from earlier versions. You may need to use rollback
if this causes a problem for existing documents.
\end{warning}

The string data type is any non-empty content that can't be parsed
as a number (or currency). For more information on data types, see
\sectionref{sec:datatypes}. For conditionals, see
\sectionref{sec:conditionals}. For \idx{CSV} lists, see
\sectionref{sec:csvlists}. The commands described below assume
that the text arguments are strings without parsing them to
determine their data type. Unexpected results may occur if the text
includes math-mode content.

\subsection{Substitution and String Splitting}
\label{sec:strreplace}

\cmddef{DTLsubstitute}
Substitutes the first occurrence of \meta{original} with
\meta{replacement} within the \idx{expansion} text of the command
\meta{cs}.

\cmddef{DTLsubstituteall}
Substitutes all occurrences of \meta{original} with
\meta{replacement} within the \idx{expansion} text of the command
\meta{cs}.

\cmddef{DTLsplitstring}
Splits \meta{string} at \meta{split text} and defines
\meta{before cmd} to the pre-split text and \meta{after cmd} to the
post-split text. Note that \meta{string} and \meta{split text} are
not expanded.

\cmddef{DTLxsplitstring}
As \gls{DTLsplitstring} but expands \meta{string} and \meta{split
text} once.

Note that in each case the change is localised to the current scope. 
\mExampleref{ex:subsplitstr} demonstrates this by adding grouping to
limit the effect of the change.

\begin{codebox}
\cmd{newcommand}\marg{\cmd{test}}\marg{The goose looked at a book and said \cmd{emph}\marg{ooh}.}
\marg{\comment{local scope}
 Original: \cmd{test}
 \gls{DTLsubstitute}\marg{\cmd{test}}\marg{oo}\marg{ee}
 Substituted first: \cmd{test}
}
\codepar
\marg{\comment{local scope}
 Original: \cmd{test}
 \gls{DTLsubstituteall}\marg{\cmd{test}}\marg{oo}\marg{ee}
 Substituted all: \cmd{test}
}
\codepar
Split on `looked' (no expansion)
\gls{DTLsplitstring}\marg{\cmd{test}}\marg{looked}\marg{\cmd{before}}\marg{\cmd{after}}
\codepar
Before: `\cmd{before}'. After: `\cmd{after}'
\codepar
Split on `looked' (with expansion)
\gls{DTLxsplitstring}\marg{\cmd{test}}\marg{looked}\marg{\cmd{before}}\marg{\cmd{after}}
\codepar
Before: `\cmd{before}'. After: `\cmd{after}'
\end{codebox}
Note that the \qt{oo} in \code{\cmd{emph}\marg{ooh}} isn't
substituted as it's inside a group, which hides it from the search. 
\begin{resultbox}
\createexample*[label={ex:subsplitstr},
 title={String Substitution and Splitting},
 description={Example document illustrating string substitution and
splitting}
]
{%
 \cmd{usepackage}\marg{datatool-base}
}
{%
\cmd{newcommand}\marg{\cmd{test}}\marg{The goose looked at a book
and said \cmd{emph}\marg{ooh}.}\nl
\marg{\comment{local scope}
Original: \cmd{test}\nl
\gls{DTLsubstitute}\marg{\cmd{test}}\marg{oo}\marg{ee}\nl
Substituted first: \cmd{test}
}
\codepar
\marg{\comment{local scope}
Original: \cmd{test}\nlsp
\gls{DTLsubstituteall}\marg{\cmd{test}}\marg{oo}\marg{ee}\nlsp
Substituted all: \cmd{test}
}
\codepar
Split on `looked' (no expansion)\nl
\gls{DTLsplitstring}\marg{\cmd{test}}\marg{looked}\marg{\cmd{before}}\marg{\cmd{after}}
\codepar
Before: `\cmd{before}'. After: `\cmd{after}'
\codepar
Split on `looked' (with expansion)\nl
\gls{DTLxsplitstring}\marg{\cmd{test}}\marg{looked}\marg{\cmd{before}}\marg{\cmd{after}}
\codepar
Before: `\cmd{before}'. After: `\cmd{after}'
}
\end{resultbox}

For more complex substitutions,
including replacing commands or command arguments,
use \LaTeX3 regular expressions (see \sectionref{sec:l3regex}).

\subsection{Initial Letters}
\label{sec:initials}

\cmddef{DTLinitials}
This is simply a shortcut that uses \gls{DTLstoreinitials} to obtain
the initials and then displays the result.

\cmddef{xDTLinitials}
Designed for use with placeholder commands, this expands the first
token in its argument before passing it to \gls{DTLinitials}.

\cmddef{DTLstoreinitials}
Splits \meta{text} into words and stores the initial of each word in
the control sequence \meta{cs}.  Normal space characters, the hyphen
character (\code{-}), non-breakable spaces (\idx{nbsp}) and space
commands \gls{nobreakspace} and \gls{space} are all considered word
boundaries. Words broken by an apostrophe are also detected but by
default the apostrophe and following initial are ignored. For
example, \qt{O'Brien} will become just \qt{O} (followed by a dot)
but it will actually be converted to:
\begin{compactcodebox}
\gls{DTLaposinitialpunc}\marg{O}\marg{B}\margm{punc}
\end{compactcodebox}
Only the first apostrophe in the word is treated in this way. If a
word has multiple apostrophes, such as \qt{fo'c's'le} in the example
below, then the word will be split on the first apostrophe (\qt{fo},
which has the initial \qt{f} and \qt{c's'le}, which has the initial
\qt{c}). An apostrophe at the end of a word is considered trailing
punctuation.

Once the supplied \meta{text} has been split into words, 
\gls{DTLstoreinitials} uses:
\cmddef{DTLStoreInitialGetLetter}
to get the initial letter of each word. The default definition just
uses \gls{DTLGetInitialLetter} which means that the results can vary
if localisation support is provided. Ordinarily, this should produce
at least one letter, but it's possible for \gls{DTLStoreInitialGetLetter}
to set the control sequence \meta{cs} to \idxc{expansion}{expand} to nothing. If this
occurs, \gls{DTLstoreinitials} will usually skip the initial and the
following punctuation. The exception is where a word is split by an
apostrophe. 

In the case of \code{\meta{head}'\meta{tail}}, where \meta{H}
indicates the initial for \meta{head} and \meta{T} indicates the
initial for \meta{tail} (as obtained by
\gls{DTLStoreInitialGetLetter}), then if \meta{H} and \meta{T} are
both empty, the initials and following punctuation are omitted.
If \meta{H} is empty but \meta{T} isn't then
\code{\gls{DTLinitialpunc}\margm{T}\margm{punc}} is used, otherwise
(regardless of whether or not \meta{T} is empty)
\code{\gls{DTLaposinitialpunc}\margm{H}\margm{T}\margm{punc}} is
used.

\cmddef{DTLinitialpunc}
This command is used to encapsulate each initial (except in the case
of a word containing an apostrophe) and the following
period/full stop. The first argument \meta{letter} is the initial that was
obtained by \gls{DTLStoreInitialGetLetter} and the second argument
\meta{punc} is the command that may \idxc{expansion}{expand} to the trailing
punctuation character (see below).

\cmddef{DTLaposinitialpunc}
This command is used to encapsulate an initial in a word split by
an apostrophe in the form \code{\meta{head}'\meta{tail}}. The first 
argument \meta{H} is the initial for \meta{head} and the second argument
\meta{T} is the initial for \meta{tail}. The final argument
\meta{punc} is as for \gls{DTLinitialpunc}. By default this just
expands to \code{\meta{H}\meta{punc}} (that is, the initial
following the apostrophe is ignored).

The following commands are used for the punctuation.
\cmddef{DTLbetweeninitials}
Placed between initials.

\cmddef{DTLafterinitials}
Placed after the initials (that is, at the end after the final
initial).

\cmddef{DTLafterinitialbeforehyphen}
Placed after an initial before a hyphen.

\cmddef{DTLinitialhyphen}
Placed where a hyphen occurs. Note that this isn't included in the
final argument of \gls{DTLinitialpunc} or \gls{DTLaposinitialpunc}.

\begin{warning}
\gls{DTLstoreinitials} is designed for text consisting of words with
possible leading or trailing punctuation. Aside from apostrophes and
hyphens, mid-word punctuation isn't supported. This is demonstrated
in \exampleref{ex:initials} where the sequence \qtt{+12x,y} is skipped.
\end{warning}

If you want to remove the dots, you can either redefine
\gls{DTLbetweeninitials}, \gls{DTLafterinitials} and \gls{DTLafterinitialbeforehyphen}
to do nothing or redefine \gls{DTLinitialpunc} and \gls{DTLaposinitialpunc}
to ignore the final argument. If you want to remove the hyphen then
you need to redefine \gls{DTLinitialhyphen} to do nothing.

\cmddef{DTLGetInitialLetter}
Obtains the first letter of \meta{text} and stores it in the control
sequence \meta{cs}. This is intended for use in commands that need
initials or letter groups and is governed by the \opt{initial-purify}
option.

The \optval{initial-purify}{early} setting makes \gls{DTLGetInitialLetter} \idx{purify} the
\meta{text} argument (that is, \idxc{expansion}{expand} and remove
functions in \meta{text}) before applying the initial letter
algorithm. With \optval{initial-purify}{late}, the \meta{text} argument
won't be expanded until content is passed to
\gls{DTLCurrentLocaleGetInitialLetter} (steps~\ref{itm:initialcs}
or~\ref{itm:localegetinitial}). Note that if
\optval{initial-purify}{early} then step~\ref{itm:initialcs} in the algorithm below won't
apply since any commands will have already been stripped or
replaced.

The algorithm used by \code{\gls{DTLGetInitialLetter}\margm{text}\margm{cs}} 
is as follows:
\begin{enumerate}
\item if \meta{text} is blank (empty or spaces) then \meta{cs} is
set to empty;
\item\label{itm:initialgrp} if \meta{text} starts with a group, the
content of the group is assumed to be an initial letter (even if it
consists of multiple letter or non-letter characters) and 
\meta{cs} will be set to the \idxc{purify}{purified} content of that group;
\item\label{itm:initialcs} if \meta{text} starts with
\code{\csmetafmt{}{cmd}{}\margm{substr}} then \meta{cs} will be set to 
\code{\csmetafmt{}{cmd}{}\margm{letter}} where \meta{letter} is obtained from applying
\gls{DTLCurrentLocaleGetInitialLetter} to the \meta{substr} argument;
\item\label{itm:localegetinitial} otherwise
\gls{DTLCurrentLocaleGetInitialLetter} is used to obtain the first
letter of \meta{text}.
\end{enumerate} 
See \sectionref{sec:initialsutf8ex}.

\begin{information}
If localisation support is provided by a \file{datatool-locale.ldf}
file, then that should define \gls{DTLCurrentLocaleGetInitialLetter}
as described in \sectionref{sec:localisation}.
\end{information}


\subsubsection{Initial Letters Example}
\label{sec:initialsex}

\mExampleref{ex:initials} obtains initials from names containing
hyphens and apostrophes.
\begin{codebox}
Marie\gls{space} Élise del\idx{nbsp}Rosario:
\gls{DTLinitials}\marg{Marie\gls{space} Élise del\idx{nbsp}Rosario}
\codepar
Élouise-Mary de Vere: \gls{DTLinitials}\marg{Élouise-Mary de Vere}
\codepar
Mary-Jane d'Arcy: \gls{DTLinitials}\marg{Mary-Jane d'Arcy}
\codepar
Mary-Jane d'Arcy-Lancaster: 
\gls{DTLinitials}\marg{Mary-Jane d'Arcy-Lancaster}
\codepar
Mary-Jane d'Arcy FitzGerald: 
\gls{DTLinitials}\marg{Mary-Jane d'Arcy FitzGerald}
\codepar
Niall O'Brien: \gls{DTLinitials}\marg{Niall O'Brien}
\codepar
De'Ondre Andros: \gls{DTLinitials}\marg{De'Ondre Andros}
\codepar
Dickie `Quack' von Duck:
\gls{DTLinitials}\marg{Dickie `Quack' von Duck}
\end{codebox}
Aside from apostrophes and hyphens, mid-word punctuation isn't supported.
The sequence \qtt{+12x,y} in the following will be skipped because
it isn't recognised as a word.
\begin{codebox}
@aardvark +12x,y fo'c's'le *zebra?:
\gls{DTLinitials}\marg{@aardvark +12x,y fo'c's'le *zebra?}
\end{codebox}
\gls{DTLStoreInitialGetLetter} is then redefined to set the second
argument to empty for the given set of words: \qt{d}, \qt{de}, \qt{del} and \qt{von}.
This means that they will be omitted from the list of initials.
\begin{codebox}
Skip `d', `de', `del', and `von':
\cmd{renewcommand}\marg{\gls{DTLStoreInitialGetLetter}}[2]\marg{\comment{}
 \gls{DTLifinlist}\marg{\#1}\marg{d,de,del,von}\marg{\cmd{def}\#2\marg{}}
 \marg{\gls{DTLGetInitialLetter}\marg{\#1}\marg{\#2}}\comment{}
}
\end{codebox}
The same names and words are repeated to illustrate the difference.

The default definition of \gls{DTLStoreInitialGetLetter}
means that, for example, \qt{d'Arcy} has the initial
\qt{d} but this redefinition will change the initial for \qt{d'Arcy}
to \qt{A}. This is a better method than simply redefining
\gls{DTLaposinitialpunc} to \idxc{expansion}{expand} to the second argument, which
would interfere with \qt{O'Brien} and \qt{De'Ondre}.

\begin{resultbox}[float]
\createexample*[label={ex:initials},link={sec:initialsex},
 title={Name or Phrase Initials},
 description={Example document demonstrating commands for obtaining
 initials from names or phrases}
]
{%
\cmd{usepackage}\marg{datatool-base}
}
{%
Marie\gls{space} Élise del\string~Rosario:\nl
\gls{DTLinitials}\marg{Marie\gls{space} Élise del\string~Rosario}
\codepar
Élouise-Mary de Vere: \gls{DTLinitials}\marg{Élouise-Mary de Vere}
\codepar
Mary-Jane d'Arcy: \gls{DTLinitials}\marg{Mary-Jane d'Arcy}
\codepar
Mary-Jane d'Arcy-Lancaster: \gls{DTLinitials}\marg{Mary-Jane d'Arcy-Lancaster}
\codepar
Mary-Jane d'Arcy FitzGerald: \gls{DTLinitials}\marg{Mary-Jane d'Arcy FitzGerald}
\codepar
Niall O'Brien: \gls{DTLinitials}\marg{Niall O'Brien}
\codepar
De'Ondre Andros: \gls{DTLinitials}\marg{De'Ondre Andros}
\codepar
Dickie `Quack' von Duck:\nl
\gls{DTLinitials}\marg{Dickie `Quack' von Duck}
\codepar
@aardvark +12x,y fo'c's'le *zebra?:\nl
\gls{DTLinitials}\marg{@aardvark +12x,y fo'c's'le *zebra?}
\codepar
Skip `d', `de', `del', and `von':\nl
\cmd{renewcommand}\marg{\gls{DTLStoreInitialGetLetter}}[2]\marg{\comment{}
 \gls{DTLifinlist}\marg{\#1}\marg{d,de,del,von}\marg{\cmd{def}\#2\marg{}}\nlsp
 \marg{\gls{DTLGetInitialLetter}\marg{\#1}\marg{\#2}}\comment{}
}
\codepar
Marie\gls{space} Élise del\string~Rosario:\nl
\gls{DTLinitials}\marg{Marie\gls{space} Élise del\string~Rosario}
\codepar
Élouise-Mary de Vere: \gls{DTLinitials}\marg{Élouise-Mary de Vere}
\codepar
Mary-Jane d'Arcy: \gls{DTLinitials}\marg{Mary-Jane d'Arcy}
\codepar
Mary-Jane d'Arcy-Lancaster: \gls{DTLinitials}\marg{Mary-Jane d'Arcy-Lancaster}
\codepar
Mary-Jane d'Arcy FitzGerald: \gls{DTLinitials}\marg{Mary-Jane d'Arcy FitzGerald}
\codepar
Niall O'Brien: \gls{DTLinitials}\marg{Niall O'Brien}
\codepar
De'Ondre Andros: \gls{DTLinitials}\marg{De'Ondre Andros}
\codepar
Dickie `Quack' von Duck:\nl
\gls{DTLinitials}\marg{Dickie `Quack' von Duck}
\codepar
@aardvark +12x,y fo'c's'le *zebra?:\nl
\gls{DTLinitials}\marg{@aardvark +12x,y fo'c's'le *zebra?}
}
\end{resultbox}

\subsubsection{Initial Letters with UTF-8 Example}
\label{sec:initialsutf8ex}

\mExampleref{ex:initialsutf8} has words containing \idx{utf8} characters. 
\begin{codebox}
ábc: \gls{DTLGetInitialLetter}\marg{ábc}\marg{\cmd{result}}
Initial: \cmd{result}.
\marg{áb}c (áb grouped): \gls{DTLGetInitialLetter}\marg{\marg{áb}c}\marg{\cmd{result}}
Initial: \cmd{result}.
\codepar
``ábc'': \gls{DTLGetInitialLetter}\marg{``ábc''}\marg{\cmd{result}}
Initial: \cmd{result}.
``\marg{áb}c'' (áb grouped): \gls{DTLGetInitialLetter}\marg{``\marg{áb}c''}\marg{\cmd{result}}
Initial: \cmd{result}.
\codepar
\end{codebox}
Note the difference between
\code{\marg{áb}c} (which satisfies step~\ref{itm:initialgrp} of the
\gls{DTLGetInitialLetter} algorithm) and
\code{``\marg{áb}c''} (which doesn't).

\begin{resultbox}[float]
\createexample*[label={ex:initialsutf8},link={sec:initialsutf8ex},
 title={Word Initial Letter with UTF-8},
 description={Example document demonstrating \cmd{DTLGetInitialLetter}}
]
{%
 \cmd{usepackage}\marg{datatool-base}
}%
{%
ábc:
\gls{DTLGetInitialLetter}\marg{ábc}\marg{\cmd{result}}\nl
Initial: \cmd{result}.
\marg{áb}c (áb grouped):
\gls{DTLGetInitialLetter}\marg{\marg{áb}c}\marg{\cmd{result}}\nl
Initial: \cmd{result}.
\codepar
``ábc'':
\gls{DTLGetInitialLetter}\marg{``ábc''}\marg{\cmd{result}}\nl
Initial: \cmd{result}.
``\marg{áb}c'' (áb grouped):
\gls{DTLGetInitialLetter}\marg{``\marg{áb}c''}\marg{\cmd{result}}\nl
Initial: \cmd{result}.
}
\end{resultbox}

\subsubsection{Initial Letters with Commands Example}
\label{sec:initialscsex}

\mExampleref{ex:initialscs} has words containing containing
commands. In the first instance, the command is an accent command,
which can expand. The second is a robust formatting command. 
\begin{codebox}
Purify early.\gls{DTLsetup}\marg{\optval{initial-purify}{early}}
\codepar
\cmd{'}\marg{a}bc (accent command): \gls{DTLGetInitialLetter}\marg{\cmd{'}\marg{a}bc}\marg{\cmd{result}}
Initial: \cmd{result}.
\cmd{emph}\marg{ábc}: \gls{DTLGetInitialLetter}\marg{\cmd{emph}\marg{ábc}}\marg{\cmd{result}}
Initial: \cmd{result}.
\codepar
Purify late.\gls{DTLsetup}\marg{\optval{initial-purify}{late}}
\codepar
\cmd{'}\marg{a}bc (accent command): \gls{DTLGetInitialLetter}\marg{\cmd{'}\marg{a}bc}\marg{\cmd{result}}
Initial: \cmd{result}.
\cmd{emph}\marg{ábc}: \gls{DTLGetInitialLetter}\marg{\cmd{emph}\marg{ábc}}\marg{\cmd{result}}
Initial: \cmd{result}.
\end{codebox}
Note that in the last case above, the formatting command
\csfmt{emph} isn't stripped.

\begin{resultbox}[float]
\createexample*[label={ex:initialscs},link={sec:initialscsex},
 title={Word Initial Commands},
 description={Example document demonstrating \cmd{DTLGetInitialLetter}}
]
{%
 \cmd{usepackage}\marg{datatool-base}
}%
{%
Purify early.\gls{DTLsetup}\marg{\optval{initial-purify}{early}}
\codepar
\cmd{'}\marg{a}bc (accent command): \gls{DTLGetInitialLetter}\marg{\cmd{'}\marg{a}bc}\marg{\cmd{result}}
Initial: \cmd{result}.
\codepar
\cmd{emph}\marg{ábc}: \gls{DTLGetInitialLetter}\marg{\cmd{emph}\marg{ábc}}\marg{\cmd{result}}
Initial: \cmd{result}.
\codepar
Purify late.\gls{DTLsetup}\marg{\optval{initial-purify}{late}}
\codepar
\cmd{'}\marg{a}bc (accent command): \gls{DTLGetInitialLetter}\marg{\cmd{'}\marg{a}bc}\marg{\cmd{result}}
Initial: \cmd{result}.
\codepar
\cmd{emph}\marg{ábc}: \gls{DTLGetInitialLetter}\marg{\cmd{emph}\marg{ábc}}\marg{\cmd{result}}
Initial: \cmd{result}.
}
\end{resultbox}

\subsection{Advanced Utility Commands}
\label{sec:initialsadvanced}

These commands use \LaTeX3 syntax so you will need
\gls{ExplSyntaxOn} to change the category codes.

\cmddef{datatoolpadtrailingzeros:Nn}
This command is intended for use with token list variables that
store a \idx{plainnumber} and will pad \meta{tl-var} with 0s to
ensure that there are a minimum of \meta{n} digits after the decimal
point. If the number in \meta{tl-var} was originally an integer, it
will become a decimal with \meta{n} 0s after the decimal point. This
command does nothing if \meta{n} is not greater than zero.

\begin{information}
The \meta{token list} should contain a \idx{plainnumber} (decimal or
integer) before use but there is no check to ensure this. The
command simply tests for the presence of a \idx{decimalpoint} (\code{.})
within \meta{token list}.
\end{information}

The commands \csmetafmt{datatool\_measure\_}{type}{:Nn} are simply shortcuts that use
\gls{settowidth}, \gls{settoheight} and \gls{settodepth} with a hook
to disable problematic commands. That is, each command is defined to
do:
\begin{compactcodebox}
\csmetafmt{setto}{type}{} \meta{dim} \marg{\meta{hook}\meta{text}}
\end{compactcodebox}
The commands \gls{datatoolmeasurehtplusdp:Nn} and
\gls{datatoolmeasure:NNNn} are slightly more complicated, but
essentially do something similar.

The hook is a token list variable:
\cmddef{ldatatoolmeasurehooktl}
The default definition disables \gls{label}, \gls{ref} and
\gls{pageref}, makes \gls{refstepcounter} behave like
\gls{stepcounter}, and \gls{hypertarget} and \gls{hyperlink} will
simply expand to their second argument.

\begin{warning}
If you are using a package that redefines any of those commands to
include a starred form or optional argument and you are using that
syntax within \meta{text}, then you will need to adjust
\gls{ldatatoolmeasurehooktl} as applicable.
\end{warning}

\cmddef{datatoolmeasurewidth:Nn}
Measures the width of the supplied text with
problematic commands locally disabled by the hook.

\cmddef{datatoolmeasureheight:Nn}
Measures the height of the supplied text with
problematic commands locally disabled by the hook.

\cmddef{datatoolmeasuredepth:Nn}
Measures the depth of the supplied text with
problematic commands locally disabled by the hook.

\cmddef{datatoolmeasurehtplusdp:Nn}
Measures the combined height and depth of the supplied text with
problematic commands locally disabled by the hook.

\cmddef{datatoolmeasure:NNNn}
Measures the width, height and depth of the supplied text with
problematic commands locally disabled by the hook.


The following commands are intended to work around
the problem of \idx{utf8} characters being represented by multiple
tokens with \pdfLaTeX, when a single grapheme is required from the
start of a token list (for example, when obtaining initials).

\begin{warning}
These commands are experimental.
\end{warning}

\cmddef{datatoolgetfirstgrapheme:nN}
This obtains the first grapheme by using \gls{textmapinline:nn} and
breaking after the first iteration. Note that this may not be a
\qt{letter} but may be a punctuation character. The \meta{text} is
\idxc{purify}{purified} before mapping.

\cmddef{datatoolgetfirstletter:nN}
Similar to the previous command but skips leading non-letters. 
This uses \condcsT{datatoolifletter:n} to test if the grapheme is a letter.

\cmddef{datatoolifletter:n}
Tests if \meta{grapheme} is a letter. Note that \meta{grapheme} is
expected to be a single character, which may be a multi-byte
character.  A grapheme is considered a letter if the first token of
\meta{grapheme} has a letter category code or if the upper and
lowercase versions of \meta{grapheme} are different.  Note that not
all letters have different upper and lowercase versions. If these
are likely to be tested in this command, then use \XeLaTeX\ or
\LuaLaTeX\ and ensure the character has the letter category code.

\begin{warning}
If the \meta{grapheme} argument doesn't contain a single character
but instead contains a mixture of letters and
punctuation, then \gls{datatoolifletter:n} will do \meta{true}.
Ensure that \meta{grapheme} is a single character stripped of all
commands and braces.
\end{warning}

For example, with \XeLaTeX\ and \LuaLaTeX\ the character 
\qt{Á} is considered a single token and has the category code 11
(letter), but with \pdfLaTeX\ and \idx{utf8} \qt{Á} consists of two tokens
where the first token has category code 13. However
\gls{textlowercase:n} is capable of converting \qt{Á} to \qt{á}
and \gls{textuppercase:n} is capable of converting \qt{á} to \qt{Á}.
So if \meta{grapheme} (which should already have been expanded and
purified) has different \idx{uppercase} and \idx{lowercase}
versions, it can be considered a letter.

The regular expression class \code{[:alpha:]} only covers
\idx{ascii} letters. Recall also from \exampleref{ex:icelandic} that
\idx{ascii} control codes or non-letter characters with the category
code set to \qt{letter} were used to influence sorting. Since
\gls{datatoolifletter:n} was provided to assist with obtaining
letter groups from sort values, it needs to take this into account.
If this behaviour is inappropriate for your use, then use more
appropriate commands provided by \LaTeX3, such as the regular
expression matching commands.

\section{Comma-Separated Lists}
\label{sec:csvlists}

\begin{information}
\LaTeX3 provides commands for processing \idx{CSV} lists.
See \sectionref{sec:l3clist} for an example.
\end{information}

The \sty{datatool-base} package provides some commands that take a
\idx{CSV} list as the argument, such as \gls{dtladdall} (see
\sectionref{sec:plainfp}), \gls{DTLaddall} (see
\sectionref{sec:formattedfp}) and \gls{DTLifinlist} (see
\sectionref{sec:strif}). Unless otherwise stated, the argument may
also be a command whose definition is a \idx{CSV} list, but note that
the argument must be exactly one token (the command) with no leading spaces or trailing
tokens.

\begin{warning}
This behaviour is new to v3.0. Older versions would \idxc{expansion}{expand} 
the first element in the list for some commands but not others.
\end{warning}

\mExampleref{ex:incsvlist} searches for an element in a list of four elements:
\begin{compactcodebox}
`duck' in `ant,duck,goose,zebra'?
\gls{DTLifinlist}\marg{duck}\marg{ant,duck,goose,zebra}\marg{true}\marg{false}.
\end{compactcodebox}
The above is equivalent to:
\begin{compactcodebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,duck,goose,zebra}
`duck' in `\cmd{mylist}'?
\gls{DTLifinlist}\marg{duck}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\end{compactcodebox}
However, the following searches a list of one element where the sole
element consists of two tokens (a space and the command
\csfmt{mylist}):
\begin{compactcodebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,duck,goose,zebra}
`duck' in ` \cmd{mylist}'?
\gls{DTLifinlist}\marg{duck}\marg{ \cmd{mylist}}\marg{true}\marg{false}
\end{compactcodebox}
The following searches a list of two elements, where the first
element is \csfmt{mylist} and the second element is \qt{zebu}:
\begin{compactcodebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,duck,goose,zebra}
`duck' in `\cmd{mylist},zebu'?
\gls{DTLifinlist}\marg{duck}\marg{\cmd{mylist},zebu}\marg{true}\marg{false}.
\end{compactcodebox}
\begin{resultbox}
\createexample*[label={ex:incsvlist},
 title={CSV List Argument Expansion},
 description={Example document illustrating whether or not a CSV
list argument is expanded}
]
{%
 \cmd{usepackage}\marg{datatool-base}\nl
 \cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,duck,goose,zebra}
}
{%
`duck' in `ant,duck,goose,zebra'?\nl
\gls{DTLifinlist}\marg{duck}\marg{ant,duck,goose,zebra}\marg{true}\marg{false}.
\codepar
`duck' in `\cmd{mylist}' (single token)?\nl
\gls{DTLifinlist}\marg{duck}\marg{\cmd{mylist}}\marg{true}\marg{false}.
\codepar
`duck' in ` \cmd{mylist}' (one element, two tokens)?
\gls{DTLifinlist}\marg{duck}\marg{ \cmd{mylist}}\marg{true}\marg{false}
\codepar
`duck' in `\cmd{mylist},zebu' (two elements)?
\gls{DTLifinlist}\marg{duck}\marg{\cmd{mylist},zebu}\marg{true}\marg{false}.
}
\end{resultbox}

There are two options, \listsopt{skip-empty} and \listsopt{trim}, 
that determine how to split the elements
in the \idx{CSV} list. These apply to most \idx{CSV} list arguments,
such as for \gls{DTLaddall} and \gls{DTLifinlist}, but not for commands
described in \sectionref{sec:plainfp} like \gls{dtladdall}. These
settings also don't apply to \keyval\ comma-separated list options. 
Package options and options provided in \gls{DTLsetup} are always
trimmed and skip empty elements.

The \sty{datatool-base} package automatically loads \sty{etoolbox}
so you can use the \sty{etoolbox} commands, such as
\gls{forcsvlist}, to iterate over \idx{CSV} lists. For examples, see
\dickimawhref{latex/admin/html/docsvlist.shtml}{Iterating Over a
Comma-Separated List}.

\subsection{List Settings}
\label{sec:listopts}

The options described in this section govern the \idx{CSV} list
settings. They may be passed in the value of the \opt{lists} option.
For example:
\begin{codebox}
\gls{DTLsetup}\marg{
 \optvalm{lists}{
   \listsoptvalm{trim}{false},
   \listsoptvalm{skip-empty}{false}
 }
}
\end{codebox}

\optiondef{lists.skip-empty}
If true, empty elements will be skipped when parsing a
\idx{CSV} list.

\optiondef{lists.trim}
If true, leading and trailing spaces will be trimmed from elements
when parsing a \idx{CSV} list.

\optiondef{lists.sort-reverse}
If true, \gls{DTLsortwordlist} and \gls{dtlsortlist} will perform a
reverse sort.

\optiondef{lists.sort-datum}
If this conditional is true, then \gls{DTLsortwordlist} will parse
each element when it uses the handler macro at the start, storing
each element as a \idx+{datumitem}, and will use numerical ordering for
numeric data types.  Integers and decimals will be numerically
compared against each other, but the string comparison will be used if
they are compared against another data type (including currency).
Currency elements will be numerically compared if they have the same
currency symbol, otherwise the string comparison will be used.

\optiondef{lists.and}
Determines how \gls{DTLlistand} should expand. The \meta{value} may
be: \optfmt{word} (expand to \gls{DTLandname}) or \optfmt{symbol}
(expand to \gls{cs.amp}). 

\begin{information}
If there is no language support, \gls{DTLandname} will expand
to \gls{cs.amp} in which case \listsoptval{and}{word} won't produce
any noticeable effect.
\end{information}

\subsection{Formatting Lists}
\label{sec:formatlist}

\cmddef{DTLformatlist}
Formats the \idx{CSV} list supplied in the argument \meta{list}. The
unstarred version adds grouping, the starred version doesn't.
Each item in the list is formatted with:
\cmddef{DTLlistformatitem}
This simply expands to \meta{item} by default.
Each pair of elements, except for the final pair are separated with:
\cmddef{DTLlistformatsep}
This expands to \code{,\visiblespace} (comma followed by a space) by default.
The final two elements are separated with:
\cmddef{DTLlistformatlastsep}
This expands to \code{\visiblespace\gls{DTLlistand}\gls{space}} by default.
\cmddef{DTLlistformatoxford}
If there are more than two items in the list,
\gls{DTLlistformatlastsep} will be preceded by \gls{DTLlistformatoxford}
which does nothing by default. If you want an \idx{Oxfordcomma} then 
redefine \gls{DTLlistformatoxford} to a comma:
\begin{compactcodebox}
\cmd{renewcommand}\marg{\gls{DTLlistformatoxford}}\marg{,}
\end{compactcodebox}

\cmddef{DTLlistand}
Expands either to \gls{DTLandname} or to \gls{cs.amp}, depending on
the \listsopt{and} option in the \opt{lists} setting.

\cmddef{DTLandname}
This is initially defined to \idxc{expansion}{expand} to
\gls{andname} if that command was defined when \sty{datatool-base}
was loaded otherwise to \gls{cs.amp}. However \gls{DTLandname} is
redefined by localisation support to expand to the appropriate word.

\mExampleref{ex:formatlist} redefines \gls{DTLlistformatitem} to render each item
in italic:
\begin{codebox*}
\cmd{renewcommand}\marg{\gls{DTLlistformatitem}}[1]\marg{\cmd{emph}\marg{\#1}}
One: \gls{DTLformatlist}\marg{elephant}.
\codepar
Two: \gls{DTLformatlist}\marg{elephant,ant}.
\codepar
Three: \gls{DTLformatlist}\marg{elephant,ant,zebra}.
\codepar
Four: \gls{DTLformatlist}\marg{elephant,ant,zebra,duck}.
\codepar
\cmd{renewcommand}\marg{\gls{DTLlistformatoxford}}\marg{,}
Oxford comma:
 \gls{DTLformatlist}\marg{elephant,ant,zebra,duck}.
\codepar
Omit empty elements and leading/trailing spaces:
\gls{DTLformatlist}\marg{elephant , ant,,duck}.
\codepar
\gls{DTLsetup}\marg{ 
 \optvalm{lists}{
    \listsoptval{trim}{false},
    \listsoptval{skip-empty}{false}
  }
}
Retain empty elements and leading/trailing spaces:
\gls{DTLformatlist}\marg{elephant , ant,,duck}.
\end{codebox*}
\begin{resultbox}
\createexample*[label={ex:formatlist},
 title={Formatting CSV Lists},
 description={Example document illustrating formatting
comma-separated lists}
]
{%
  \cmd{usepackage}\marg{datatool-base}
}
{%
\cmd{renewcommand}\marg{\gls{DTLlistformatitem}}[1]\marg{\cmd{emph}\marg{\#1}}\nl
One: \gls{DTLformatlist}\marg{elephant}.
\codepar
Two: \gls{DTLformatlist}\marg{elephant,ant}.
\codepar
Three: \gls{DTLformatlist}\marg{elephant,ant,zebra}.
\codepar
Four: \gls{DTLformatlist}\marg{elephant,ant,zebra,duck}.
\codepar
\cmd{renewcommand}\marg{\gls{DTLlistformatoxford}}\marg{,}\nl
Oxford comma: \gls{DTLformatlist}\marg{elephant,ant,zebra,duck}.
\codepar
Omit empty elements and leading/trailing spaces:\nl
\gls{DTLformatlist}\marg{elephant , ant,,duck}.
\codepar
\gls{DTLsetup}\marg{ \nlsp
 lists = \marg{ trim = false, skip-empty = false } \nl
}\nl
Retain empty elements and leading/trailing spaces:\nl
\gls{DTLformatlist}\marg{elephant , ant,,duck}.
}
\end{resultbox}

\subsection{List Elements}
\label{sec:listelements}

\cmddef{DTLlistelement}
Does the \meta{idx}th element in the list, where indexing starts
with 1 for the first element.

\cmddef{DTLfetchlistelement}
Fetches the \meta{idx}th element in the list and defines the command
\meta{cs} to that element value.

\cmddef{DTLnumitemsinlist}
Counts the number of elements in the list and defines the command
\meta{cs} to that number.

\mExampleref{ex:listelements} uses the above commands for a three-element list,
where the second element contains a comma.
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,\marg{bee, wasp and hornet},fly}
List: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
Number of elements: \gls{DTLnumitemsinlist}\marg{\cmd{mylist}}\marg{\cmd{total}}\cmd{total}.
\codepar
Second element: \gls{DTLlistelement}\marg{\cmd{mylist}}\marg{2}.
\codepar
Fetch third element:
\gls{DTLfetchlistelement}\marg{\cmd{mylist}}\marg{3}\marg{\cmd{myelem}}\cmd{myelem}.
\end{codebox}
For comparison, the closest \LaTeX3 code is:
\begin{codebox}
\cmd{LaTeX}3 List:
\gls{ExplSyntaxOn}
\cmd{clist\_set:NV} \cmd{l\_tmpa\_clist} \cmd{mylist}
\cmd{clist\_use:Nnnn} \cmd{l\_tmpa\_clist} \marg{ \idx{l3sp} and \idx{l3sp} } \marg{ , \idx{l3sp} } \marg{ , \idx{l3sp} and \idx{l3sp} }
\gls{ExplSyntaxOff}
\codepar
Number of elements:
\gls{ExplSyntaxOn}
\cmd{clist\_count:N} \cmd{l\_tmpa\_clist} .
\gls{ExplSyntaxOff}
\codepar
Second element:
\gls{ExplSyntaxOn}
\cmd{clist\_item:Nn} \cmd{l\_tmpa\_clist} \marg{ 2 } .
\gls{ExplSyntaxOff}
\codepar
Fetch third element:
\gls{ExplSyntaxOn}
\cmd{tl\_set:Ne} \cmd{l\_tmpa\_tl} \marg{ \cmd{clist\_item:Nn} \cmd{l\_tmpa\_clist} \marg{ 3 } }
\cmd{l\_tmpa\_tl} .
\gls{ExplSyntaxOff}
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:listelements},
 title={Elements of a CSV List},
 description={Example document demonstrating counting and accessing list elements}
]
{%
 \cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,\marg{bee, wasp and hornet},fly}
}
{%
List: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
Number of elements: \gls{DTLnumitemsinlist}\marg{\cmd{mylist}}\marg{\cmd{total}}\cmd{total}.
\codepar
Second element: \gls{DTLlistelement}\marg{\cmd{mylist}}\marg{2}.
\codepar
Fetch third element:\nl
\gls{DTLfetchlistelement}\marg{\cmd{mylist}}\marg{3}\marg{\cmd{myelem}}\cmd{myelem}.
\codepar
\cmd{LaTeX}3 List:\nl
\gls{ExplSyntaxOn}\nl
\cmd{clist\_set:NV} \cmd{l\_tmpa\_clist} \cmd{mylist}\nl
\cmd{clist\_use:Nnnn} \cmd{l\_tmpa\_clist} \marg{ \string~ and \string~ } \marg{ , \string~ } \marg{ , \string~ and \string~ }\nl
\gls{ExplSyntaxOff}
\codepar
Number of elements:\nl
\gls{ExplSyntaxOn}\nl
\cmd{clist\_count:N} \cmd{l\_tmpa\_clist} .\nl
\gls{ExplSyntaxOff}
\codepar
Second element:\nl
\gls{ExplSyntaxOn}\nl
\cmd{clist\_item:Nn} \cmd{l\_tmpa\_clist} \marg{ 2 } .\nl
\gls{ExplSyntaxOff}
\codepar
Fetch third element:\nl
\gls{ExplSyntaxOn}\nl
\cmd{tl\_set:Ne} \cmd{l\_tmpa\_tl} \marg{ \cmd{clist\_item:Nn} \cmd{l\_tmpa\_clist} \marg{ 3 } }\nl
\cmd{l\_tmpa\_tl} .\nl
\gls{ExplSyntaxOff}
}
\end{resultbox}

\subsection{Adding to Lists}
\label{sec:addtolist}

The \sty{datatool-base} package automatically loads \sty{etoolbox}
so you can use commands provided by that package to prepend or
append to a command definition, such as \gls{preto} and \gls{appto}.
Remember to include the comma separator.

\begin{important}
If you have more complex requirements, consider using \LaTeX3
commands (see \sectionref{sec:l3clist} for an example).
\end{important}

\cmddef{dtlinsertinto}
Globally inserts \meta{element} into a sorted list (provided in the
definition of the command \meta{sorted-list cs}) according to the
comparison macro \meta{criteria cs}, which should have the same
syntax as that for \gls{dtlsortlist}. Predefined
comparison commands are described in \sectionref{sec:compare}.

\mExampleref{ex:listinsert} constructs a list, typesetting the
contents with \gls{DTLformatlist} after each modification:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,bee}
Original list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{appto}\cmd{mylist}\marg{,zebra}
Item appended: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{preto}\cmd{mylist}\marg{aardvark,}
Item prepended: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{dtlinsertinto}\marg{duck}\marg{\cmd{mylist}}\marg{\gls{dtlcompare}}
Item inserted: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:listinsert},
 title={Appending, Prepending and Inserting List Elements},
 description={Example document demonstrating commands to append,
prepend and insert items into a comma-separated list}
]
{%
 \cmd{usepackage}\marg{datatool-base}
}
{%
\cmd{newcommand}\marg{\cmd{mylist}}\marg{ant,bee}\nl
Original list: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{appto}\cmd{mylist}\marg{,zebra}\nl
Item appended: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{preto}\cmd{mylist}\marg{aardvark,}\nl
Item prepended: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{dtlinsertinto}\marg{duck}\marg{\cmd{mylist}}\marg{\gls{dtlcompare}}\nl
Item inserted: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

\subsection{Sorting Lists}
\label{sec:listsort}

There are two commands provided by \sty{datatool-base} for sorting a
\idx{CSV} list. Both take a command as the first argument whose
definition should be the \idx{CSV} list. On completion this command
will be (locally) redefined to \idxc{expansion}{expand} to the ordered list. 
The second argument is also a command but its behaviour and syntax is different.

The first (and older) command is \gls{dtlsortlist}, which requires a
comparison macro. This macro is repeatedly used to compare pairs of
elements of the list throughout the sorting process.

The second command is \gls{DTLsortwordlist}, which requires a handler macro
that is used to convert each element of the list into a byte
sequence before sorting. The byte sequences are then compared throughout the
sorting process using a simple character code comparison.
\gls{DTLsortwordlist} is therefore more efficient, particularly if
any localisation support is provided.

\cmddef{dtlsortlist}
Sorts a \idx{CSV} list according to the comparison command 
\meta{criteria cs}. Note that \meta{list-cs} must be a command not 
an explicit list. After the function has completed, \meta{list-cs} 
will \idxc{expansion}{expand} to the sorted list. The comparison command compares two
list elements \meta{A} and \meta{B} and must have the syntax:
\begin{compactcodebox}
\meta{criteria cs}\margm{reg}\margm{A}\margm{B}
\end{compactcodebox}
where \meta{reg} is a count register. If \meta{A} is deemed to be
less than \meta{B} then \meta{criteria cs} should set \meta{reg} to
$-1$, if \meta{A} is deemed to be greater than \meta{B} then
\meta{reg} should be set to $+1$ and if \meta{A} and \meta{B} are
deemed equal then \meta{reg} should be set to 0. Predefined
comparison commands are described in \sectionref{sec:compare}.

\cmddef{DTLsortwordlist}
This command is an alternative to \gls{dtlsortlist} that has a
handler macro for converting the original string value of each list
element into a byte sequence. The handler macro should have the syntax:
\begin{compactcodebox}
\meta{handler-cs}\margm{actual}\margm{tl}
\end{compactcodebox}
where \meta{actual} is the original value and \meta{tl} is a token
list control sequence in which to store the byte sequence.
Predefined handlers are listed in \sectionref{sec:dtlsortwordlistcmds}.

The advantage with \gls{DTLsortwordlist} over \gls{dtlsortlist} is
that with \gls{DTLsortwordlist} all the sort values are processed
once at the start whereas with \gls{dtlsortlist} the values are
repeatedly processed every time the comparison function is used.
The \opt{lists} option \listsopt{sort-datum} only has an effect
with \gls{DTLsortwordlist}. The \listsopt{sort-reverse} option,
which reverses the sort, governs both 
\gls{DTLsortwordlist} and \gls{dtlsortlist}.

\begin{important}
Both \gls{dtlsortlist} and \gls{DTLsortwordlist} change the
definition of \meta{list-cs} so that it expands to the sorted list
on completion. However, with \gls{dtlsortlist} the resulting \meta{list-cs}
definition is just a comma-separated list of ordered items from the
original \idx{CSV} list, but with \gls{DTLsortwordlist}
the resulting \meta{list-cs} definition is a comma-separated list
of \emph{\idxpl{sortedelement}}.
\end{important}

A \idx{sortedelement} is in the form:
\begin{compactcodebox}
\meta{sorted-marker-cs}\margm{actual}\margm{sort value}\margm{letter group}
\end{compactcodebox}
where \meta{actual} is the original item or the \idx{datumitem} if
the \listsopt{sort-datum} option is true, \meta{sort value} is the sort value
obtained by the handler function (regardless of the data type), and
\meta{letter group} is the letter group identifier obtained from the
\meta{sort value} via:
\cmddef{DTLassignlettergroup}
The letter group is assigned as follows:
\begin{enumerate}
\item If the \meta{actual} part is a \idx{datumitem} then the
letter group is assigned according to the data type as follows:

\begin{description}
\item[Integer or Decimal]
The letter group is considered a numeric group so \meta{cs}
is defined as \code{\gls{dtlnumbergroup}\margm{num}} where \meta{num}
is the numeric value. Before encapsulating with \gls{dtlnumbergroup}
a hook may be used to alter the \meta{num} argument.
\cmddef{DTLPreProcessIntegerGroup}
This is used when \meta{num} has been identified as an integer.
\cmddef{DTLPreProcessDecimalGroup}
This is used when \meta{num} has been identified as a decimal.
In both cases, the \meta{cs} argument is a command that 
expands to the numeric value and \meta{actual} is the original value
passed to \gls{DTLassignlettergroup}. These hooks do nothing by
default.

\item[Currency]
The letter group is considered a currency group so \meta{cs}
is defined as \code{\gls{dtlcurrencygroup}\margm{sym}\margm{num}} 
where \meta{sym} is the currency symbol and \meta{num}
is the numeric value. Before encapsulating with \gls{dtlcurrencygroup}
a hook may be used to alter the \meta{sym} and \meta{num} arguments.
\cmddef{DTLPreProcessCurrencyGroup}
The \meta{sym-cs} is the command that expands to the currency
symbol, \meta{num-cs} is the command that expands to the numeric
value,  and \meta{actual} is the original value
passed to \gls{DTLassignlettergroup}. This hook does nothing by
default.

\item[String]
If the \meta{sort value} starts with a letter, \meta{cs} is set to
\code{\gls{dtllettergroup}\margm{initial}} where \meta{initial} is
obtained using \gls{DTLCurrentLocaleGetInitialLetter} otherwise
\meta{cs} is defined as \code{\gls{dtlnonlettergroup}\margm{grph}}
where \meta{grph} is the first grapheme in the \meta{sort value}. 
Before encapsulating with \gls{dtllettergroup} or
\gls{dtlnonlettergroup}, hooks are available to alter the
\meta{grph}.
\cmddef{DTLPreProcessLetterGroup}
This hook is used for a letter. This is defined to use
\gls{DTLCurrentLocaleWordHandler}.
\cmddef{DTLPreProcessNonLetterGroup}
This hook is used for a non-letter and does nothing by default.
In both cases, the \meta{cs} is a command that expands to
\meta{grph}.
\end{description}

\item Otherwise the letter group is assigned as for the string data
type above.
\end{enumerate}

If you want to iterate over a list that uses a handler function on
each list element (such as \sty{etoolbox}['s] \gls{forcsvlist}), then 
you can use the following commands on the element:
\cmddef{DTLsortedactual}
Expands to the actual element. You can also simply use \meta{sorted element}
directly. The difference is how \idx{expansion} is applied. If the
\listsopt{sort-datum} option was true then the actual element will
be a \idx{datumitem}. (That is, the format used in the \idx{expansion} text of a
\idx{datumcs}.)

\cmddef{DTLsortedvalue}
Expands to the string sort value. For numeric data types (if parsing
is on), this value would only have been used for comparing across different data
types.

\cmddef{DTLsortedletter}
Expands to the letter group.

\begin{warning}
The above commands all expect a \idx{sortedelement} with its special
markup as the argument.
If you are using \gls{@for} to iterate over the sorted list, you will
need to \idxc{expansion}{expand} the loop control sequence first.
\end{warning}

The following command is used by \gls{DTLsortwordlist} but not by \gls{dtlsortlist}.
\cmddef{dtlfallbackaction}
If two sort values are identical, this command is used to determine
whether or not the sort function should swap the elements. The
arguments \meta{val1} and \meta{val2} are the original values
or the \idxpl{datumitem} (not the identical byte sequences or numerical
values). This command should \idxc{expansion}{expand} to \meta{swap code} if the
elements should be swapped, otherwise it should \idxc{expansion}{expand} to \meta{no
swap code}. The default definition uses the case-sensitive \gls{DTLifstringgt} to
compare the original values.

For example, the following sorts a list and shows the result (with
\gls{show}) in the transcript:
\begin{compactcodebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{\gls{pounds}2,zebu,-.25,bee,\gls{cs.dollar}5,ant,duck,
+10,4.56,\gls{cs.dollar}23.10,123}
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlcompare}}
\gls{show}\cmd{mylist}
\end{compactcodebox}
The transcript shows the following:
\begin{transcript}
> \cmd{mylist}=macro:
->\gls{pounds} 2,\gls{cs.dollar}23.10,\gls{cs.dollar}5,+10,-.25,123,4.56,ant,bee,duck,zebu.
\end{transcript}
This is a simple character code sort that produces a simple
comma-separated list as the result.

Compare the above with:
\begin{compactcodebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{\gls{pounds}2,zebu,-.25,bee,\gls{cs.dollar}5,ant,duck,
+10,4.56,\gls{cs.dollar}23.10,123}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordcasehandler}}
\gls{show}\cmd{mylist}
\end{compactcodebox}
The result is now more complex. I've added line breaks for clarity
and replaced the private command for the sort element markup with
\meta{S-cs} for compactness:
\begin{transcript}
> \cmd{mylist}=macro:
->\meta{S-cs}\marg{\gls{cs.dollar}23.10}\marg{\$23.10}\marg{\gls{dtlnonlettergroup}\marg{\$}},
  \meta{S-cs}\marg{\gls{cs.dollar}5}\marg{\$5}\marg{\gls{dtlnonlettergroup}\marg{\$}},
  \meta{S-cs}\marg{+10}\marg{+10}\marg{\gls{dtlnonlettergroup}\marg{+}},
  \meta{S-cs}\marg{-.25}\marg{-.25}\marg{\gls{dtlnonlettergroup}\marg{-}},
  \meta{S-cs}\marg{123}\marg{123}\marg{\gls{dtlnonlettergroup}\marg{1}},
  \meta{S-cs}\marg{\gls{pounds} 2}\marg{2}\marg{\gls{dtlnonlettergroup}\marg{2}},
  \meta{S-cs}\marg{4.56}\marg{4.56}\marg{\gls{dtlnonlettergroup}\marg{4}},
  \meta{S-cs}\marg{ant}\marg{ant}\marg{\gls{dtllettergroup}\marg{a}},
  \meta{S-cs}\marg{bee}\marg{bee}\marg{\gls{dtllettergroup}\marg{b}},
  \meta{S-cs}\marg{duck}\marg{duck}\marg{\gls{dtllettergroup}\marg{d}},
  \meta{S-cs}\marg{zebu}\marg{zebu}\marg{\gls{dtllettergroup}\marg{z}}.
\end{transcript}
This produces a slightly different order: \$23.10, \$5, +10, -.25,
123, \pounds2, 4.56, ant, bee, duck, zebu. The \gls{pounds} command
is stripped by the handler as it is unable to
\idxc{expansion}{expand} to just text. Whereas the \gls{cs.dollar}
command is converted to the detokenized \idx{dollar} by the sort
hook (see \sectionref{sec:wordsorthook}).  Note that the currency
and numbers have all been assigned to the non-letter group.

\begin{important}
A different result can occur if localisation support is provided
(see \sectionref{sec:localisation}).
\end{important}

The closest match to the case-sensitive \gls{dtlcompare} is
\gls{DTLsortwordcasehandler} (used above). The closest match to the
case-insensitive \gls{dtlicompare} is \gls{DTLsortwordhandler}.
If the above example was switched to \gls{DTLsortlettercasehandler}
or \gls{DTLsortletterhandler}, the hyphen\slash minus character \code{-}
would be stripped from \code{-.25}, resulting in a sort value of
\code{.25}.

When using lexicographical ordering, there is a distinct difference
between \code{-.25} (a string containing four characters) and
\code{-0.25} (a string containing five characters) or between \code{+10} and \code{10}.
A simple character code comparison will place \code{+10} before
\code{-.25} (since the plus character \qtt{+} has a lower codepoint
value than the hyphen\slash minus character \qtt{-}).

Switching the \listsopt{sort-datum} option to true adds an extra
level of complexity in the result, but creates a different order
because the numbers can now be compared numerically:
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optvalm{lists}{\listsoptvalm{sort-datum}{true}}}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{\gls{pounds}2,zebu,-.25,bee,\gls{cs.dollar}5,ant,duck,
+10,4.56,\gls{cs.dollar}23.10,123}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordcasehandler}}
\gls{show}\cmd{mylist}
\end{compactcodebox}

I've added line breaks for clarity, replaced constants with
their actual numeric values, and replaced the private commands for
the sort element markup with \meta{S-cs} and \idxc{datumitem}{datum} markup with
\meta{D-cs} for compactness:
\begin{compactcodebox}
> \cmd{mylist}=macro:
->\meta{S-cs}\marg{\meta{D-cs}\marg{\gls{cs.dollar}5}\marg{5}\marg{\gls{cs.dollar}}\marg{3}}\marg{\$5}\marg{\gls{dtlcurrencygroup}\marg{\gls{cs.dollar}}\marg{5}},
\meta{S-cs}\marg{\meta{D-cs}\marg{\gls{cs.dollar}23.10}\marg{23.10}\marg{\gls{cs.dollar}}\marg{3}}\marg{\$23.10}\marg{\gls{dtlcurrencygroup}\marg{\gls{cs.dollar}}\marg{23.10}},
\meta{S-cs}\marg{\meta{D-cs}\marg{-.25}\marg{-0.25}\marg{}\marg{2}}\marg{-.25}\marg{\gls{dtlnumbergroup}\marg{-0.25}},
\meta{S-cs}\marg{\meta{D-cs}\marg{4.56}\marg{4.56}\marg{}\marg{2}}\marg{4.56}\marg{\gls{dtlnumbergroup}\marg{4.56}},
\meta{S-cs}\marg{\meta{D-cs}\marg{+10}\marg{10}\marg{}\marg{1}}\marg{+10}\marg{\gls{dtlnumbergroup}\marg{10}},
\meta{S-cs}\marg{\meta{D-cs}\marg{123}\marg{123}\marg{}\marg{1}}\marg{123}\marg{\gls{dtlnumbergroup}\marg{123}},
\meta{S-cs}\marg{\meta{D-cs}\marg{\gls{pounds} 2}\marg{2}\marg{\gls{pounds}}\marg{3}}\marg{2}\marg{\gls{dtlcurrencygroup}\marg{\gls{pounds}}\marg{2}},
\meta{S-cs}\marg{\meta{D-cs}\marg{ant}\marg{}\marg{}\marg{0}}\marg{ant}\marg{\gls{dtllettergroup}\marg{a}},
\meta{S-cs}\marg{\meta{D-cs}\marg{bee}\marg{}\marg{}\marg{0}}\marg{bee}\marg{\gls{dtllettergroup}\marg{b}},
\meta{S-cs}\marg{\meta{D-cs}\marg{duck}\marg{}\marg{}\marg{0}}\marg{duck}\marg{\gls{dtllettergroup}\marg{d}},
\meta{S-cs}\marg{\meta{D-cs}\marg{zebu}\marg{}\marg{}\marg{0}}\marg{zebu}\marg{\gls{dtllettergroup}\marg{z}}.
\end{compactcodebox}
This expands to a different order: \$5, \$23.10, -.25, 4.56, +10,
123, \pounds2, ant, bee, duck, zebu. Note that the numeric values
have been split into different sub-groups: currency and number. The
dollar \$ currency is placed before the numbers because a string comparison
is used between a currency numeric value and non-currency number.
For example, 4.56 and 123 are compared numerically, so 4.56 is
placed before 123, but \$23.10 and +10 are compared
lexicographically.

The \code{\gls{pounds}2} item has been correctly
parsed as currency, but the string sort value ends up as just
\code{2} as a result of stripping \gls{pounds}. Since 123 isn't
currency but \gls{pounds}2 is, the values are compared lexicography
instead of numerically, which means comparing the string \qt{123}
with the string \qt{2}. The best solution is to provide a local
redefinition of \gls{pounds}:
\begin{compactcodebox}
\gls{dtlSortWordCommands}\marg{\cmd{def}\gls{pounds}\marg{£}}
\end{compactcodebox}
This is done automatically by \ldf{GB} and other localisation files
that support pound sterling currency (see \sectionref{sec:addlang}). 
Adding localisation support, for example:
\begin{codebox}
\cmd{usepackage}[\optval{locales}{en-GB}]\marg{datatool-base}
\end{codebox}
results in a different order: -.25, +10, \$5, \$23.10, \pounds 2,
4.56, 123, ant, bee, duck, zebu.

\begin{important}
It's important to remember the item markup if you need to extract
information within a list loop.
\end{important}

If you have \LaTeX3 syntax enabled you can apply the changes made in
the internal hook with:
\cmddef{datatoolsortpreprocess:Nn}
where \meta{tl-var} is the token list variable in which to store the
result. Note that this expands the \meta{text} in the same way that
the sort handlers do and may also convert to lowercase, depending on
the current settings.
This command may be used in a locale's
definition of \gls{DTLCurrentLocaleGetGroupString}
if using the \qt{actual} argument.

If you prefer to ignore the current convert to lowercase setting,
you can instead use:
\cmddef{datatoolsortpreprocess:NnN}
The final argument should be a boolean (\csfmt{c\_true\_bool}
or \csfmt{c\_false\_bool}) to indicate whether or not the token list
should be converted to lowercase.

\subsubsection{Comparison Commands}
\label{sec:compare}

These comparison commands may be used with \gls{dtlsortlist},
\gls{dtlinsertinto}, and \gls{dtlsort}.  For \gls{DTLsortwordlist}
and \gls{DTLsortdata} handler functions, see
\sectionref{sec:dtlsortwordlistcmds}.
In each case, the syntax is:
\begin{compactcodebox}
\meta{cs}\margm{count-reg}\margm{arg1}\margm{arg2}
\end{compactcodebox}
where \meta{count-reg} is a count register (integer variable). If \meta{arg1}
is deemed to be less than (comes before) \meta{arg2} then \meta{cs} will set
\meta{count-reg} to $-1$, if \meta{arg1} is deemed to be greater than (comes
after) \meta{arg2} then \meta{count-reg} is set to $+1$ and if \meta{arg1} and
\meta{arg1} are deemed equal then \meta{count-reg} is set to~0.
Note that the handler's notion of equality doesn't necessarily mean 
the two arguments are identical. For example, a case-insensitive comparison will consider
\qt{word} and \qt{Word} as equal, and \gls{DTLnumcompare} will consider
\code{\gls{cs.dollar}1,234.50} and \code{1234.5} to be equal, since only the numerical
values are compared.

\cmddef{dtlletterindexcompare}
Designed for case-insensitive letter order comparison, but a hook 
(see \sectionref{sec:wordsorthook}) is used to locally redefine
certain commands to allow for adjustments in the compared strings.
Spaces are stripped from the strings so, for example, \qt{sea lion}
will come after \qt{sealant}. 
(Note that this isn't quite analogous to \gls{DTLsortletterhandler}
as that also discards hyphens.)

\gls{DTLsortwordhandler} is used to convert both strings
to byte sequences, which are then compared. It's therefore more
efficient to use \gls{DTLsortwordlist} to avoid repeatedly
converting the same strings to byte sequences.

\cmddef{dtlwordindexcompare}
As \gls{dtlletterindexcompare} but spaces aren't stripped from the
strings so, for example, \qt{sea lion} will come before \qt{sealant}.

\begin{information}
Since both \gls{dtlletterindexcompare} and \gls{dtlwordindexcompare}
use \gls{DTLsortwordhandler}, they are sensitive to the current
language \emph{provided that} a suitable language module has been
installed (see \sectionref{sec:localisation} for more details and
\exampleref{ex:sortlistutf8locale} for an example). This does not
apply to the simple character code commands \gls{dtlcompare} and
\gls{dtlicompare}.
\end{information}

\cmddef{dtlcompare}
This command is used internally by the unstarred 
\gls{DTLifstringlt}, \gls{DTLifstringeq} and \gls{DTLifstringgt}
for a case-sensitive comparison.
If you are using \gls{DTLsortwordlist}, the closest matching handler is
\gls{DTLsortwordcasehandler}. However \gls{dtlcompare} has no
localisation support and just performs a character code comparison.

\cmddef{dtlicompare}
This command is used internally by the starred 
\starredcs{DTLifstringlt}, \starredcs{DTLifstringeq} and
\starredcs{DTLifstringgt} for a case-insensitive comparison.
If you are using \gls{DTLsortwordlist}, the closest matching handler is
\gls{DTLsortwordhandler}. However \gls{dtlicompare} has no
localisation support and just performs a character code comparison
(after converting the strings to \idx{lowercase}).

\cmddef{DTLnumcompare}
Compares \meta{num1} and \meta{num2} numerically, where the arguments are
\idxpl{formattednumber} or \idxpl{datumcs}. Unlike the numerical comparison
commands in \sectionref{sec:fmtnumif}, this command ignores the
\opt{math} setting, and will use \styfmt{l3int} or \styfmt{l3fp}
comparisons, depending on the data types. Any currency symbol (if
present) will be ignored. If either \meta{num1} or \meta{num2} are not
recognised as numerical values, the value will be treated as zero.

Options that govern comparison commands can be set within the
\opt{compare} setting value. For example:
\begin{codebox}
\gls{DTLsetup}\marg{ \optvalm{compare}{\compareoptval{expand-cs}{true}} }
\end{codebox}

\optiondef{compare.expand-cs}
Both \gls{dtlcompare} and \gls{dtlicompare} (but not the other comparison
commands) are governed by the \compareopt{expand-cs} boolean option.  When used
with \gls{dtlcompare} or \gls{dtlicompare}: if true, \meta{string1} and
\meta{string2} will be fully expanded and \idxc{purify}{purified} before
comparison. If false, the following boolean option takes effect:

\optiondef{compare.skip-cs}
When used with \gls{dtlcompare} or \gls{dtlicompare} where 
\compareoptval{expand-cs}{false}:
if \compareoptval{skip-cs}{true}, any commands found in
\meta{string1} or \meta{string2} will be replaced with the control
code \hexcp{0A} (newline). This means that a command is considered
lexicographically smaller than punctuation, digits and letters. If
false, all commands will be removed.  This conditional has no effect
if \compareoptval{expand-cs}{true}.

\subsubsection{\glsfmttext{DTLsortwordlist} Handlers}
\label{sec:dtlsortwordlistcmds}

The following handler macros are provided for use with
\gls{DTLsortwordlist} and may also be used as the
\sortdataopt{function} in \gls{DTLsortdata}. In each case,
\meta{original} is the original string and \meta{cs} is a control
sequence that will be defined to the resulting sort value (which
will then be treated as a byte sequence).

\cmddef{DTLsortwordhandler}
A case-insensitive word order handler.
This expands \meta{original} and converts it to \idx{lowercase},
then applies \gls{DTLDefaultLocaleWordHandler} and
\idxc{purify}{purifies} the result.  This means that it's sensitive
to the current language \emph{provided that} a suitable language
module has been installed (see \sectionref{sec:localisation} for
more details and \exampleref{ex:sortlistutf8locale} for an example).

\cmddef{DTLsortwordcasehandler}
A case-sensitive word order handler.
This expands \meta{original}, then applies
\gls{DTLDefaultLocaleWordHandler} and \idxc{purify}{purifies} the result.

\cmddef{DTLsortletterhandler}
A case-insensitive letter order handler.
Similar to \gls{DTLsortwordhandler} but discards hyphens and spaces.

\cmddef{DTLsortlettercasehandler}
A case-sensitive letter order handler.
Similar to \gls{DTLsortwordcasehandler} but discards hyphens and spaces.

The above handler macros are simple wrapper functions that ensure
the value is expanded and pre-processed (case conversion or
stripping hyphens and spaces) and stored in \meta{cs} before using the default
word handler:
\cmddef{DTLDefaultLocaleWordHandler}
This uses \code{\gls{DTLCurrentLocaleWordHandler}\margm{cs}} to convert
\meta{cs} to a byte sequence that ensures the locale's alphabetic ordering,
and then appends \gls{datatoolctrlboundary} to \meta{cs}. 
If you don't require the boundary marker, you can redefine this command to 
just use the current locale handler:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLDefaultLocaleWordHandler}}[1]\marg{\comment{}
  \gls{DTLCurrentLocaleWordHandler}\marg{\#1}\comment{}
}
\end{codebox}

\subsubsection{Word Sort Hook}
\label{sec:wordsorthook}

The hook used by \gls{dtlwordindexcompare} and \gls{dtlletterindexcompare}
is also used at the start of \gls{DTLsortwordlist}. This means that
the hook is applied only once with an instance of
\gls{DTLsortwordlist}, but with \gls{dtlsortlist} the hook is
applied each time a comparison is required by
\gls{dtlwordindexcompare} or \gls{dtlletterindexcompare}.
Therefore, it you want word or letter sorting, it's better to use
the newer \gls{DTLsortwordlist} with \gls{DTLsortwordhandler} or
\gls{DTLsortletterhandler}.

The commands changed by this hook are listed below.
\cmddef{dtltexorsort}
This normally expands to just its first argument but inside
\gls{DTLsortwordlist} it expands to its second argument instead.
You may recall from \sectionref{sec:currency} that \gls{DTLdefcurrency}
defines \gls{DTLcurrISO} to use \gls{dtltexorsort} in its argument.
This allows the currency symbol to \idxc{expansion}{expand} to a string representation
within \gls{DTLsortwordlist}, \gls{dtlwordindexcompare} or \gls{dtlletterindexcompare}.

\cmddef{datatoolasciistart}
Expands to nothing normally. The hook redefines this command to
\idxc{expansion}{expand} to the null character, which means that it will come before
all other characters.
\cmddef{datatoolasciiend}
Expands to nothing normally. The hook redefines this command to
\idxc{expansion}{expand} to the delete character (\hexcp{7F}, the highest \idx{ascii} character).
\cmddef{datatoolctrlboundary}
Expands to nothing normally. The hook redefines this command to
\idxc{expansion}{expand} to the character \hexcp{1F} (the last control character before the
space character). This command is automatically appended to the sort
value by \gls{DTLDefaultLocaleWordHandler}.

\cmddef{datatoolpersoncomma}
Designed to indicate word inversion for a person, this
command expands to \code{,\gls{space}} normally. The hook redefines
this command to the character \hexcp{1C}. For example,
\begin{compactcodebox}
Kunth\gls{datatoolpersoncomma} Donald E.
\end{compactcodebox}

\cmddef{datatoolplacecomma}
Designed to indicate a comma to clarify a place, this
command expands to \code{,\gls{space}} normally. The hook redefines
this command to the character \hexcp{1D}. For example:
\begin{compactcodebox}
Paris\gls{datatoolplacecomma} Texas
\end{compactcodebox}

\cmddef{datatoolsubjectcomma}
Designed to indicate heading inversion (subjects, concepts and objects), this
command expands to \code{,\gls{space}} normally. The hook redefines
this command to the character \hexcp{1E}. For example:
\begin{compactcodebox}
New York\gls{datatoolsubjectcomma} population
\end{compactcodebox}

There are two ways of dealing with parenthetical content.
\cmddef{datatoolparen}
This command normally expands to \code{\gls{space} (\meta{text})}.
The hook redefines \gls{datatoolparen} to \idxc{expansion}{expand} to
\gls{datatoolctrlboundary}, ignoring the argument. For example:
\begin{compactcodebox}
duck\gls{datatoolparen}\marg{wildfowl}
\end{compactcodebox}
This means that the parenthetical content is omitted in the
comparison. Note that this will cause the following
terms to be considered identical:
\begin{compactcodebox}
duck\gls{datatoolparen}\marg{wildfowl}
duck\gls{datatoolparen}\marg{cricket}
\end{compactcodebox}
With \gls{DTLsortwordlist}, this is addressed by the default
definition of \gls{dtlfallbackaction} which will compare the
duplicate values using the original definition of \gls{datatoolparen}.
Note that since \gls{DTLDefaultLocaleWordHandler} appends
\gls{datatoolctrlboundary} to all values, \qt{duck} will become
\qt{duck} followed by \hexcp{1F} and
\code{duck\gls{datatoolparen}\margm{text}} will become 
\qt{duck} followed by \hexcp{1F} \hexcp{1F}. The first control character is inserted by
\gls{datatoolparen} and the second by
\gls{DTLDefaultLocaleWordHandler}. This means that the parenthetical
entries will come after the word on its own, and the word on its own
will come after the word followed by one of the comma markers.

An alternative method that can be used with \gls{dtlsortlist} is to mark 
where the parenthetical material starts:
\cmddef{datatoolparenstart}
Designed to indicate the start of parenthetical content, this
command expands to \gls{space} normally. The parenthesis characters
need to be added explicitly. The hook redefines
this command to \idxc{expansion}{expand} to the character \hexcp{1F}. For example:
\begin{compactcodebox}
duck\gls{datatoolparenstart} (cricket)
\end{compactcodebox}
In this case, the parenthetical content is included in the
comparison.

\begin{information}
The commands \gls{datatoolctrlboundary} and \gls{datatoolparenstart}
have the same definition within the hook but \idxc{expansion}{expand} differently in
normal text.
\end{information}

The use of control codes affects ordering. The normal space
character has character code \hexcp{20} and a comma has the character code
\hexcp{2C}. This means that a comma would ordinarily be placed after a
space character, whereas the low-end control codes come before
space.

\begin{information}
The control codes used in the above commands are all assigned the
\qt{other} category code (12) within the definition used by the hook.
They are only intended for use in sorting, not for typesetting.
\end{information}

Following the guidelines of the Oxford Style Manual, when sorting terms that have
identical pre-inversion parts, the following ordering is applied: people, places,
subjects, no inversions, and parenthetical. This is achieved through
the marker commands (see \examplesref{ex:sortlistcommas,ex:wordsortlistcommas}).

\cmddef{datatoolSetCurrencySort}
Locally redefines common currency commands to their string
alternatives. For example, \gls{pounds} is set to
\gls{ldatatoolpoundstr}.

The hook also redefines \gls{nobreakspace} and \gls{cs.space} to
\gls{space}, \gls{TeX} and \gls{LaTeX} are locally redefined to
simply expand to \qt{TeX} and \qt{LaTeX}, respectively, and the
following commands are locally redefined to \idxc{expansion}{expand}
to the corresponding detokenized character: \gls{cs.dollar}
(\code{\$}), \gls{cs.underscore} (\code{\_}), \gls{cs.hash}
(\code{\#}), \gls{cs.percent} (\code{\%}), and \gls{cs.amp}
(\code{\&}).

Additional code can be added to the hook with:
\cmddef{dtlSortWordCommands}
This globally adds \meta{code} to the hook. Within \meta{code} the
\idx{@} character has the letter category code, which means that
you can use internal \idx{@}-commands in \meta{code} (see
\exampleref{ex:sortwordhook}).
If you need to use \idxc{hexcp}{control codes}, make sure that you
first (locally) change the category code to \qt{other} before using
them in the hook.

\subsubsection{CSV List Sorting Examples}
\label{sec:sortlistexs}

The following examples demonstrate the different sorting methods.

\paragraph{Sorting with \glsfmttext{dtlsortlist}}
\label{sec:dtlsortlistexs}

\Examplesref{ex:sortlistcharcase,ex:sortlistwordletter} sort the
list: sea, sea lion, Sealyham, seal, sealant, sealing wax, which is
defined as:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{sea, sea lion, Sealyham, seal,
 sealant, sealing wax}
\end{codebox}
The sorted order varies depending on whether or not the sort method is
case-sensitive or strips spaces. (See
\exampleref{ex:sortlistutf8} for a \idx{utf8} example.)

\mExampleref{ex:sortlistcharcase} uses \gls{dtlsortlist} with
\gls{dtlcompare} (case-sensitive) and then with \gls{dtlicompare}
(case-insensitive). Note that case-sensitive sorting places the
\idx{uppercase} characters before the \idx{lowercase} characters
(so Sealyham comes first with \gls{dtlcompare} and last with
\gls{dtlicompare}). In both cases, \qt{sea lion} is placed before
\qt{sealing wax} (that is, the space is significant).

\begin{codebox}
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlcompare}}
Case-sensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlicompare}}
Case-insensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:sortlistcharcase},
 title={Sorting Lists with \cmd{dtlsortlist} (Case vs No Case)},
 description={Example document that sorts a comma-separated list
 using \cmd{dtlsortlist} with the predefined case-sensitive and
 case-insensitive character comparison macros}
]
{%
 \cmd{usepackage}\marg{datatool-base}\nl
 \cmd{newcommand}\marg{\cmd{mylist}}\marg{sea, sea lion, Sealyham,
seal, sealant, sealing wax}\nl
}
{%
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlcompare}}\nl
Case-sensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlicompare}}\nl
Case-insensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

\mExampleref{ex:sortlistwordletter} uses
\gls{dtlletterindexcompare} (letter sort) and
\gls{dtlwordindexcompare} (word sort) instead.  The order for both
is case-insensitive (so Sealyham comes last), but the letter order
method puts \qt{sea lion} after \qt{sealing wax} (spaces are
discarded, \qt{o} comes after \qt{n}) whereas the word order method
puts \qt{sea lion} before \qt{seal} (the space is significant,
\qt{l} comes after space). 

\begin{resultbox}
\createexample*[label={ex:sortlistwordletter},
 title={Sorting Lists with \cmd{dtlsortlist} (Letter vs Word)},
 description={Example document that sorts a comma-separated list
 using \cmd{dtlsortlist} with the predefined word and letter comparison macros}
]
{%
 \cmd{usepackage}\marg{datatool-base}\nl
 \cmd{newcommand}\marg{\cmd{mylist}}\marg{sea, sea lion, Sealyham,
seal, sealant, sealing wax}
}
{%
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlletterindexcompare}}\nl
Letter: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlwordindexcompare}}\nl
Word: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

\paragraph{Sort Markers}
\label{sec:sortlistmarkersexs}

\mExampleref{ex:sortlistcommas} demonstrates the use of the comma and
parenthetical markers. The simple character code commands \gls{dtlcompare} and
\gls{dtlicompare} are governed by the \compareopt{skip-cs} and
\compareopt{expand-cs} options within the \opt{compare} setting. If both
options are false, any commands found in the sort value, including the marker
commands, are replaced with the character code \hexcp{0A}.  If
\compareoptval{skip-cs}{true} (and \compareoptval{expand-cs}{false}) then the
marker commands will be stripped. If \compareoptval{expand-cs}{true}, then the
\compareopt{skip-cs} setting is ignored and the marker commands will
\idxc{expansion}{expand} to their usual meaning (not the meaning provided by
the word sort hook).  I've used \compareoptval{expand-cs}{true} to ensure the
marker commands are expanded.

The example doesn't use \gls{dtlcompare}, which would put the
elements starting with \qt{Duck} at the beginning, but would
otherwise use the same relative order as \gls{dtlicompare}.

The word and letter functions use the word sort hook (see
\sectionref{sec:wordsorthook}), which means that the special marker functions
\idxc{expansion}{expand} to low \idx{ascii} control characters, which means
that they are placed before ordinary punctuation and letters. The example
list is defined as:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{duckling, 
 Duck\gls{datatoolplacecomma} Mallard County,
 Duck\gls{datatoolpersoncomma} Robbie,
 Duck\gls{datatoolsubjectcomma} Anatomy of a,
 duck\gls{datatoolparenstart} (cricket),
 duck\gls{datatoolparen}\marg{verb},
 \marg{Duck, Duck, Goose},
 duck soup, duck, duck and dive
}
\end{codebox}
Note that there is one element that has normal commas (\qt{Duck,
Duck, Goose}). This requires braces to hide the commas from the list
parser. The other commas are hidden in the marker commands:
\gls{datatoolpersoncomma} (to signify \meta{surname},
\meta{forename}), \gls{datatoolsubjectcomma} (heading inversion), and
\gls{datatoolplacecomma} (to signify a place). The above example
uses two different ways of marking parenthetical material,
\gls{datatoolparenstart} and \gls{datatoolparen}. This affects
sorting.

Since the lists have long elements and elements with commas, I've used the
\sty{multicol} package to arrange them in columns and changed
the separators used by \gls{DTLformatlist} to insert line breaks.
This means that the only commas shown are those within the elements.
I've used grouping to localise the changes, which ensures that each
sort starts from the same list.
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLlistformatsep}}\marg{\cmd{newline}}
\cmd{renewcommand}\marg{\gls{DTLlistformatlastsep}}\marg{\cmd{newline}}
\gls{DTLsetup}\marg{\optvalm{compare}{\compareoptval{expand-cs}{true}}}
\cbeg{multicols}\marg{3}
\marg{\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlicompare}}
Case-insensitive:\cmd{newline} 
\gls{DTLformatlist}\marg{\cmd{mylist}}.}
\codepar
\marg{\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlwordindexcompare}}
Word sort:\cmd{newline}
\gls{DTLformatlist}\marg{\cmd{mylist}}.}
\codepar
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlletterindexcompare}}
Letter sort:\cmd{newline}
\gls{DTLformatlist}\marg{\cmd{mylist}}.
\cend{multicols}
\end{codebox}

The simple case-insensitive comparison (\gls{dtlicompare}) doesn't recognise any
difference between explicit commas and the commas within the marker
commands, so \qt{Duck, Duck, Goose} is placed between \qt{Duck, Anatomy of a}
and \qt{Duck, Mallard County}. Sorting by character code orders
the space character \hexcp{20} before the comma character \hexcp{2C}, so \qt{duck
soup} is placed before \qt{Duck, Anatomy of a}.

Note the difference between using \gls{datatoolparen} (which inserts
\hexcp{1F} and discards its argument) and \gls{datatoolparenstart}
(which inserts \hexcp{1F}). This means that \qt{(verb)} is omitted
from the comparison but \qt{(cricket)} isn't, so \qt{duck (verb)}
ends up before \qt{duck (cricket)}.

\begin{resultbox}
\createexample*[label={ex:sortlistcommas},fontsize={10},link={sec:sortlistmarkersexs},
 title={Sorting Lists with \cmd{dtlsortlist} (comma and parenthetical markers)},
 titleskip=small,
 description={Example document that sorts a comma-separated list
 using \cmd{dtlsortlist} with the comma and parenthesis marker macros}
]
{%
\cmd{usepackage}\marg{multicol}\nl
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{mylist}}\marg{duckling,\nlsp
Duck\gls{datatoolplacecomma} Mallard County,\nlsp
Duck\gls{datatoolpersoncomma} Robbie,\nlsp
Duck\gls{datatoolsubjectcomma} Anatomy of a,\nlsp
duck\gls{datatoolparenstart} (cricket),\nlsp
duck\gls{datatoolparen}\marg{verb},\nlsp
\marg{Duck, Duck, Goose},\nlsp
duck soup, duck, duck and dive\nlsp
}\nl
\cmd{renewcommand}\marg{\gls{DTLlistformatsep}}\marg{\cmd{newline}}\nl
\cmd{renewcommand}\marg{\gls{DTLlistformatlastsep}}\marg{\cmd{newline}}\nl
\gls{DTLsetup}\marg{\optvalm{compare}{expand-cs=true}}
}
{%
\cbeg{multicols}\marg{3}\nlsp
\marg{\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlicompare}}\nlsp
Case-insensitive:\cmd{newline} \nlsp
\gls{DTLformatlist}\marg{\cmd{mylist}}.}
\codepar
 \marg{\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlwordindexcompare}}\nlsp
 Word sort:\cmd{newline}\nlsp
 \gls{DTLformatlist}\marg{\cmd{mylist}}.}
\codepar
 \gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlletterindexcompare}}\nlsp
 Letter sort:\cmd{newline}\nlsp
 \gls{DTLformatlist}\marg{\cmd{mylist}}.\nlsp
\cend{multicols}
}
\end{resultbox}

\mExampleref{ex:wordsortlistcommas} adapts \exampleref{ex:sortlistcommas}
to use \gls{DTLsortwordlist}, but
there's no equivalent to the \gls{dtlicompare} handler:
\begin{codebox}
\marg{\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordhandler}}
Word sort:\cmd{newline}
\gls{DTLformatlist}\marg{\cmd{mylist}}.}
\codepar
\marg{\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}
Letter sort:\cmd{newline}
\gls{DTLformatlist}\marg{\cmd{mylist}}.}
\end{codebox}
I've also supplied my own custom handler that first strips explicit
commas and then behaves like \gls{DTLsortletterhandler}: 
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{NewDocumentCommand} \cmd{mycustomhandler} \marg{ m m } 
 \marg{
   \cmd{tl\_set:Nn} \#2 \marg{ \#1 }
   \cmd{regex\_replace\_all:nnN} \marg{ , } \marg{ } \#2
   \gls{DTLsortletterhandler} \marg{ \#2 } \#2
 }
\gls{ExplSyntaxOff}
\codepar
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\cmd{mycustomhandler}}
Custom sort:\cmd{newline}
\gls{DTLformatlist}\marg{\cmd{mylist}}.
\end{codebox}

Note that the position of \qt{duck} has changed. This is because of
the boundary marker that's appended to all the values. The boundary
marker control code is now compared with the comma and parentheses
marker control codes.
\begin{resultbox}
\createexample*[label={ex:wordsortlistcommas},fontsize={10},
 title={Sorting Lists with \cmd{DTLsortwordlist} (comma and parenthetical markers)},
 titleskip=small,
 description={Example document that sorts a comma-separated list
 using \cmd{DTLsortwordlist} with the comma and parenthesis marker macros}
]
{%
\cmd{usepackage}\marg{multicol}\nl
\cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{mylist}}\marg{duckling,\nlsp
Duck\gls{datatoolplacecomma} Mallard County,\nlsp
Duck\gls{datatoolpersoncomma} Robbie,\nlsp
Duck\gls{datatoolsubjectcomma} Anatomy of a,\nlsp
duck\gls{datatoolparenstart} (cricket),\nlsp
duck\gls{datatoolparen}\marg{verb},\nlsp
\marg{Duck, Duck, Goose},\nlsp
duck soup, duck, duck and dive\nlsp
}\nl
\cmd{renewcommand}\marg{\gls{DTLlistformatsep}}\marg{\cmd{newline}}\nl
\cmd{renewcommand}\marg{\gls{DTLlistformatlastsep}}\marg{\cmd{newline}}\nl
\gls{ExplSyntaxOn}\nl
\cmd{NewDocumentCommand} \cmd{mycustomhandler} \marg{ m m } \nlsp
 \marg{\nldbsp
   \cmd{tl\_set:Nn} \#2 \marg{ \#1 }\nldbdbsp
   \cmd{regex\_replace\_all:nnN} \marg{ , } \marg{ } \#2\nldbdbsp
   \gls{DTLsortletterhandler} \marg{ \#2 } \#2\nldbsp
 }\nlsp
\gls{ExplSyntaxOff}
}
{%
\cbeg{multicols}\marg{3}\nl
\marg{\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordhandler}}\nl
Word sort:\cmd{newline}\nl
\gls{DTLformatlist}\marg{\cmd{mylist}}.}\nl
\codepar
\marg{\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}\nl
Letter sort:\cmd{newline}\nl
\gls{DTLformatlist}\marg{\cmd{mylist}}.}\nl
\codepar
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\cmd{mycustomhandler}}
Custom sort:\cmd{newline}\nl
\gls{DTLformatlist}\marg{\cmd{mylist}}.
\cend{multicols}
}
\end{resultbox}

\paragraph{UTF-8}
\label{sec:sortlistutf8exs}

Results with \gls{dtlcompare} or \gls{dtlicompare} for \idx{utf8}
values are less satisfactory. The list for
\examplesref{ex:sortlistutf8,ex:sortwordlistutf8,ex:sortlistutf8locale}
is defined as: 
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mylist}}\marg{elk, Æthelstan, Arnulf, elf,résumé,
Óslác, élan, Aeolus, resume, elephant, zygote, élite, 
Valkyrie, Zulu, elbow, Adelolf, rose}
\end{codebox}
\XeLaTeX\ and \LuaLaTeX\ both natively support \idx{utf8}. Modern
\pdfLaTeX\ now defaults to \idx{utf8} but if you want to use
\sty{inputenc} remember to load it before \sty{datatool-base}:
\begin{codebox}
\cmd{usepackage}[utf8]\marg{inputenc}
\cmd{usepackage}\marg{datatool-base}
\end{codebox}

\mExampleref{ex:sortlistutf8} sorts the lists with \gls{dtlsortlist} as for the earlier
\exampleref{ex:sortlistcharcase}:
\begin{codebox}
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlcompare}}
Case-sensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlicompare}}
Case-insensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\end{codebox}
Note that the \idx{utf8} characters are all placed after the Basic
Latin characters, so \qt{Æthelstan} is placed after \qt{zygote} for
both the case-sensitive and case-insensitive comparators. However, 
\qt{Æthelstan} and \qt{Óslác} come before \qt{élan} and \qt{élite}
for the case-sensitive sort. Whereas for the case-insensitive sort,
\qt{Óslác} comes after \qt{élite}.
\begin{resultbox}
\createexample*[label={ex:sortlistutf8},
 title={Sorting Lists with \cmd{dtlsortlist} and UTF-8},
 description={Example document that sorts a comma-separated list
 using \cmd{dtlsortlist} with UTF-8 characters}
]
{%
 \cmd{usepackage}[utf8]\marg{inputenc}\nl
 \cmd{usepackage}\marg{datatool-base}\nl
\cmd{newcommand}\marg{\cmd{mylist}}\marg{elk, Æthelstan, Arnulf,
elf,résumé, \nlsp
Óslác, élan, Aeolus, resume, elephant, zygote, élite, Valkyrie,
\nlsp
Zulu, elbow, Adelolf, rose}
}
{%
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlcompare}}\nl
Case-sensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{dtlsortlist}\marg{\cmd{mylist}}\marg{\gls{dtlicompare}}\nl
Case-insensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

Note that because \gls{dtlletterindexcompare} and \gls{dtlwordindexcompare}
both internally use \gls{DTLsortwordhandler}, they are able to
handle \idx{utf8} in the same way as using \gls{DTLsortwordlist}
with the handler macros described in \sectionref{sec:dtlsortwordlistcmds}.
However, it's more efficient to use \gls{DTLsortwordlist} to avoid
repeatedly pre-processing the values.

\mExampleref{ex:sortwordlistutf8} adapts \exampleref{ex:sortlistutf8} to use
\gls{DTLsortwordlist} instead of \gls{dtlsortlist}.
\begin{codebox}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortlettercasehandler}}
Case-sensitive sort: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}
Case-insensitive sort: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\end{codebox}
Note that the \idx{utf8} characters are still listed after the Basic
Latin characters when there is no localisation support. So the
result is the same as before.
\begin{resultbox}
\createexample*[label={ex:sortwordlistutf8},
 title={Sorting Lists with \cmd{DTLsortwordlist} and UTF-8 and
 No Localisation Support},
 titleskip=small,
 description={Example document that sorts a comma-separated list
 using \cmd{DTLsortwordlist} with UTF-8 characters and no locale}
]
{%
 \cmd{usepackage}[utf8]\marg{inputenc}\nl
 \cmd{usepackage}\marg{datatool-base}\nl
 \cmd{newcommand}\marg{\cmd{mylist}}\marg{elk, Æthelstan, Arnulf, elf,résumé,
Óslác, élan, Aeolus, resume, elephant, zygote, élite, Valkyrie,
Zulu, elbow, Adelolf, rose}
}
{%
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortlettercasehandler}}\nl
Case-sensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}\nl
Case-insensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

\mExampleref{ex:sortlistutf8locale} is a minor modication of
\exampleref{ex:sortlistutf8}, but it requires 
\sty{datatool-english} to be installed. This can then be loaded via the
\sty{tracklang} interface (for example, with the \opt{locales} option) which ensures that
the localisation support provided by \sty{datatool-english} is used.
Remember to include the region if currency support is also required.
For example:
\begin{codebox}
\cmd{documentclass}[en-GB]\marg{article}
\end{codebox}
Or:
\begin{codebox}
\cmd{usepackage}[\optval{locales}{en-GB}]\marg{datatool-base}
\end{codebox}
This produces a better order because the \ldf{english\dhyphen utf8} file
substitutes common \idx{utf8} characters for the closest \idx{ascii}
equivalent (\qt{Æ} for \qt{AE}, \qt{Ó} for \qt{O}, \qt{á} for
\qt{a}, and \qt{é} for \qt{e}). This means that \qt{Æthelstan} is
now at the start before \qt{Adelolf} (because \qt{AE} comes before \qt{Ad})
for the case-sensitive sort but between \qt{Aeolus} and \qt{Arnulf}
for the case-insensitive sort.
\begin{resultbox}
\createexample*[label={ex:sortlistutf8locale},
 title={Sorting Lists with \cmd{DTLsortwordlist} and UTF-8 and
 Localisation Support},
 titleskip=small,
 description={Example document that sorts a comma-separated list
 using \cmd{DTLsortwordlist} with UTF-8 characters and localisation
 support (datatool-english must also be installed)}
]
{%
 \cmd{usepackage}[utf8]\marg{inputenc}\nl
 \cmd{usepackage}[locales={en-GB}]\marg{datatool-base}\nl
 \cmd{newcommand}\marg{\cmd{mylist}}\marg{elk, Æthelstan, Arnulf, elf,résumé,
Óslác, élan, Aeolus, resume, elephant, zygote, élite, Valkyrie,
Zulu, elbow, Adelolf, rose}
}
{%
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortlettercasehandler}}\nl
Case-sensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
\codepar
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortletterhandler}}\nl
Case-insensitive: \gls{DTLformatlist}\marg{\cmd{mylist}}.
}
\end{resultbox}

Note that with \ldf{english\dhyphen utf8}, \qt{résumé} is converted into
\qt{resume}, which means \qt{résumé} has an identical sort value to 
\qt{resume}. With \gls{DTLsortwordlist}, the relative ordering of
these duplicates is then determined by \gls{dtlfallbackaction}, which by default
compares the original values with \gls{DTLifstringgt}. Since the 
unstarred \gls{DTLifstringgt} internally uses \gls{dtlcompare}
without localisation, this places \qt{resume} before \qt{résumé}.

Remember that \gls{dtlsortlist} doesn't use \gls{dtlfallbackaction}
so \qt{résumé} and \qt{resume} are deemed equivalent with
\gls{dtlwordindexcompare} \gls{dtlletterindexcompare} so the result
with \gls{dtlsortlist} would retain their original relative order.

\paragraph{Roman Numerals}
\label{sec:sortlistromanexs}

\mExampleref{ex:sortwordhook} has a list of names with Roman numerals,
such as is used in the names of monarchs. In the first case, the
numerals are explicitly included in the list. In the second case a
command is provided that has a different definition in the hook.
\begin{codebox}[fontupper=\small\ttfamily]
\cmd{newcommand}\marg{\cmd{mylist}}\marg{John XVI,John VI,
John XIX, John IX, John IV,John VII, John V}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordhandler}}
\gls{DTLformatlist}{\cmd{mylist}}.
\codepar
\cmd{newcommand}\marg{\cmd{Ord}}[1]\marg{\gls{MakeUppercase}\marg{\cmd{romannumeral} \#1}}
\gls{dtlSortWordCommands}\marg{\cmd{renewcommand}\cmd{Ord}[1]\marg{\cmd{two@digits}\marg{\#1}}}
\cmd{renewcommand}{\cmd{mylist}}\marg{John \cmd{Ord}\marg{16},John \cmd{Ord}\marg{6},
John \cmd{Ord}\marg{19}, John \cmd{Ord}\marg{9}, John \cmd{Ord}\marg{4},John \cmd{Ord}\marg{7}, 
John \cmd{Ord}\marg{5}}
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordhandler}}
\gls{DTLformatlist}{\cmd{mylist}}.
\end{codebox}
Ordinarily this custom \csfmt{Ord} command will convert its numeric
argument into an \idx{uppercase} Roman numeral (for example,
\code{\cmd{Ord}\marg{16}} would expand to \qt{XVI}), but when sorting it
expands to a number instead (for example, \code{\cmd{Ord}\marg{16}}
would expand to \qt{16}).

Note the use of \gls{two@digits} that zero-pads the number to ensure
that it has at least two digits (for example,
\code{\cmd{Ord}\marg{6}} would expand to \qt{06}). This is because lexicographic
ordering rather than numeric ordering is used (otherwise \qt{16}
would come before \qt{6}). If large ordinals are
expected then extra padding would be required (which can
be obtained with \gls{dtlpadleadingzeros}).
\begin{resultbox}
\createexample*[label={ex:sortwordhook},
 title={Sort Word Hook (Roman Numerals)},link={sec:sortlistromanexs},
 description={Example document using the sort hook to alter sort
values}
]
{%
 \cmd{usepackage}\marg{datatool-base}\nl
 \cmd{newcommand}\marg{\cmd{mylist}}\marg{John XVI,John VI,
John XIX, John IX, John IV,John VII, John V}
}
{%
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordhandler}}\nl
\gls{DTLformatlist}{\cmd{mylist}}.
\codepar
\cmd{newcommand}\marg{\cmd{Ord}}[1]\marg{\gls{MakeUppercase}\marg{\cmd{romannumeral}
\#1}}\nl
\gls{dtlSortWordCommands}\marg{\cmd{renewcommand}\cmd{Ord}[1]\marg{\cmd{two@digits}\marg{\#1}}}\nl
\cmd{renewcommand}{\cmd{mylist}}\marg{John \cmd{Ord}\marg{16},John
\cmd{Ord}\marg{6},\nl
John \cmd{Ord}\marg{19}, John \cmd{Ord}\marg{9}, John
\cmd{Ord}\marg{4},John \cmd{Ord}\marg{7},\nl
John \cmd{Ord}\marg{5}}\nl
\gls{DTLsortwordlist}\marg{\cmd{mylist}}\marg{\gls{DTLsortwordhandler}}\nl
\gls{DTLformatlist}{\cmd{mylist}}.
}
\end{resultbox}

\chapter{Databases (\stytext{datatool} package)}
\label{sec:databases}

The \sty{datatool} package provides a means of creating and
loading databases. Once a database has been created (either with
supplied document commands or by parsing an external file),
it is possible to iterate through each row of data, to make it
easier to perform repetitive actions, such as mail merging.

\begin{important}
Whilst \TeX\ is an excellent typesetting language,
it is not designed as a database management system, and
attempting to use it as such is like trying to fasten a screw
with a knife instead of a screwdriver: it can be done, but requires
great care and is more time consuming. Version 2.0 of the
\sty{datatool} package switched to a completely different method of storing
the data to previous versions.\footnote{Many thanks to Morten H\o gholm
for providing the new code.} Version 3.0 has switched to using
\LaTeX3 commands internally for some of the database functions. 
As a result, the code is much more efficient.
However, large databases and complex operations will still slow the
time taken to process your document. Therefore, if you can, it is
better to do the complex operations using whatever system created
the data in the first place.
\end{important}

Some advanced commands for accessing database information are
described in \sectionref{sec:advanced}, but using \TeX\ is nowhere near
as efficient as, say, using a \idx{SQL} database, so don't expect too much
from this package.

\label{datatooltk}%
I've written a Java helper application to accompany \sty{datatool}
called \inlineappdef{datatooltk}. The installer
\ctansupportmirror{datatooltk/datatooltk-installer.jar}{\appfmt{datatooltk\dhyphen
installer.jar}} is available on \CTANpkg{datatooltk}.  The application will allow
you to edit DTLTEX (see \sectionref{sec:dtltexfiles}) and DBTEX (see
\sectionref{sec:dbtexfiles}) files saved using \gls{DTLwrite} in
a~graphical interface or import data from a~\idx{SQL} database,
a~\idx{CSV} file or a~\sty{probsoln} dataset.

\pkgdef{datatool}

The \sty{datatool} package automatically loads the
\sty{datatool-base} package, so all commands provided by
\sty{datatool-base} are available. The commands provided by
\sty{datatool} relate to databases.

The supplementary packages \sty{dataplot}, \sty{datapie},
\sty{databar}, \sty{databib} and \sty{datagidx} automatically load
\sty{datatool} and provide additional commands that act on
databases. In the case of \sty{databib} and \sty{datagidx}, the
databases have a specific structure. The \sty{dataplot},
\sty{datapie} and \sty{databar} packages provide commands to
visually represent numeric data stored in a database.

\section{Options}
\label{sec:datatoolopts}

All options provided by \sty{datatool-base} (see
\sectionref{sec:base}) may also be passed to
\sty{datatool}. Additionally, the following options are also
available, some of which can only be passed as a package option,
some of which can only be used in \gls{DTLsetup}, and some may be
used in either context.

% OPTION default-name

\optiondef+{default-name}
May be used either as a package option or in \gls{DTLsetup}, this
sets the default database name for commands where the name is
optional (such as \gls+{DTLaction} and \gls{DTLwrite}). Note that 
the argument is expanded when the option is set.
For example:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mydatacmd}}\marg{mydata}
\gls{DTLsetup}\marg{\optval{default-name}{\cmd{mydatacmd}}}
\cmd{renewcommand}\marg{\cmd{mydatacmd}}\marg{otherdata}
\end{codebox}
In the above, the default database name remains \qt{mydata} after
\csfmt{mydatacmd} is redefined.

% OPTION delimiter

\optiondef+{delimiter}
This option may only be used as a package option and sets the delimiter 
used in \idx{CSV} and \idx{TSV} files. The value \meta{char} must be a single
token, and is used in the file to delimit a value which may
contain the separator character to hide the separator from the parser.

After the package has loaded, you can use \gls{DTLsetdelimiter} to
set the delimiter. Alternatively, you can use the \ioopt{delimiter}
setting within the optional argument of \gls{DTLread} or
\gls{DTLwrite} or within the value of the \opt{io} option in
\gls{DTLsetup}. For example:
\begin{codebox}
\comment{Package option:}
\cmd{usepackage}\oarg{\optvalm{delimiter}{'}}\marg{datatool}
\comment{Change default:}
\gls{DTLsetdelimiter}\marg{|}
\comment{Or:}
\gls{DTLsetup}\marg{\optvalm{io}{\iooptvalm{delimiter}{|}}}
\comment{Override the default just for this file:}
\gls{DTLread}\oarg{\ioopteqvalref{format}{csv},\iooptvalm{delimiter}{"}}\marg{myfile}
\end{codebox}

% OPTION new-value-expand

\optiondef+{new-value-expand}
This boolean option determines whether or not new values should be
expanded before they are added to a database. This also includes 
data read from \idx{CSV} and \idx{TSV} files 
(see \sectionref{sec:csvfiles}), and DTLTEX files (see
\sectionref{sec:dtltexfiles}), but not DBTEX files (see
\sectionref{sec:dbtexfiles}).

\begin{information}
With \optval{new-value-expand}{false}, you can still expand
individual values using the \actionopt{expand-value} or
\actionopt{expand-once-value} when adding an entry to a database with the 
\action{new-entry} action.
\end{information}

If \optval{new-value-expand}{true}, protected expansion is applied to the
value, otherwise no expansion is performed.
For example:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{qt}}[1]\marg{``\#1''}
\gls{DTLsetup}\marg{\optval{new-value-expand}{true}}
\gls{DTLnewdbentry}\marg{mydata}\marg{Name}\marg{Zoë \cmd{qt}\marg{Stripes} Zebra}
\end{codebox}
In the above, the entry will be added to the database as 
\code{Zoë ``Stripes'' Zebra}. This means that if the definition of
\csfmt{qt} is later changed, it won't affect this entry. In this
particular case, it's better to have the default
\optval{new-value-expand}{false} setting to prevent expansion (or
use robust commands).

The \optval{new-value-expand}{true} option is useful if you are 
programmatically creating entries
with placeholder commands, which need to be expanded. 
\mExampleref{ex:newvalueexpand} demonstrates the difference:
\begin{codebox}
\cmd{makeatletter}
\gls{DTLsetup}\marg{\optval{new-value-expand}{false}}
\gls{DTLnewdb}\marg{test1}
\gls{DTLaddcolumnwithheader}\marg{test1}\marg{entry}\marg{Entry (Not Expanded)}
\cmd{@for}\cmd{myentry}:=ant,bee,duck,zebra\cmd{do}\marg{
 \gls{DTLnewrow}\marg{test1}
 \gls{DTLnewdbentry}\marg{test1}\marg{entry}\marg{\cmd{myentry}}
}
\gls{DTLsetup}\marg{\optval{new-value-expand}{true}}
\gls{DTLnewdb}\marg{test2}
\gls{DTLaddcolumnwithheader}\marg{test1}\marg{entry}\marg{Entry (Expanded)}
\cmd{@for}\cmd{myentry}:=ant,bee,duck,zebra\cmd{do}\marg{
 \gls{DTLnewrow}\marg{test2}
 \gls{DTLnewdbentry}\marg{test2}\marg{entry}\marg{\cmd{myentry}}
}
\cmd{makeatother}
\cmd{renewcommand}\marg{\cmd{myentry}}\marg{Unknown!}
\codepar
\gls{DTLdisplaydb}\marg{test1}
\gls{DTLdisplaydb}\marg{test2}
\end{codebox}
In the first case, the placeholder command ends up in the database
entry, which means it's susceptible to the changing definition of
that command. This means that every entry ends up with the same
value. (If I hadn't redefined \csfmt{myentry} after the \csfmt{@for}
loop it would have resulted in the \qt{Undefined control sequence}
error as at the end of the loop \csfmt{myentry} is \csfmt{@nil},
which is an undefined marker).

In the second case, the placeholder command \csfmt{myentry} is
expanded before the entry is added to the database.
\begin{resultbox}
\createexample*[label={ex:newvalueexpand},
  title={New Value Expansion},
  description={Example document illustrating the new-value-expand
setting}
]
{\cmd{usepackage}\marg{datatool}\nl
\cmd{makeatletter}\nl
\gls{DTLsetup}\marg{\optval{new-value-expand}{false}}\nl
\gls{DTLnewdb}\marg{test1}\nl
\gls{DTLaddcolumnwithheader}\marg{test1}\marg{entry}\marg{Entry (Not
Expanded)}\nl
\cmd{@for}\cmd{myentry}:=ant,bee,duck,zebra\cmd{do}\marg{\nlsp
 \gls{DTLnewrow}\marg{test1}\nlsp
 \gls{DTLnewdbentry}\marg{test1}\marg{entry}\marg{\cmd{myentry}}\nl
}\nl
\codepar
\gls{DTLsetup}\marg{\optval{new-value-expand}{true}}\nl
\gls{DTLnewdb}\marg{test2}\nl
\gls{DTLaddcolumnwithheader}\marg{test2}\marg{entry}\marg{Entry
(Expanded)}\nl
\cmd{@for}\cmd{myentry}:=ant,bee,duck,zebra\cmd{do}\marg{\nlsp
 \gls{DTLnewrow}\marg{test2}\nlsp
 \gls{DTLnewdbentry}\marg{test2}\marg{entry}\marg{\cmd{myentry}}\nl
}\nl
\cmd{makeatother}\nl
\cmd{renewcommand}\marg{\cmd{myentry}}\marg{Unknown!}
}
{%
\gls{DTLdisplaydb}\marg{test1}
\gls{DTLdisplaydb}\marg{test2}
}
\end{resultbox}

This setting may also be switched on with:
\cmddef*{dtlexpandnewvalue}
and switched off with:
\cmddef*{dtlnoexpandnewvalue}

Note that the I/O \ioopt{expand} option affects this setting. For
example:
\begin{codebox}
\gls{DTLsetup}\marg{ \optvalm{io}{\ioopteqvalref{expand}{protected}} }
\end{codebox}
This is equivalent to:
\begin{codebox}
\gls{DTLsetup}\marg{ 
  \optvalm{io}{\ioopteqvalref{expand}{protected}},
  \optval{new-value-expand}{true}
 }
\end{codebox}
This means that:
\begin{codebox}
\gls{DTLread}\oarg{\ioopteqvalref{expand}{protected}}\marg{filename}
\end{codebox}
is a convenient shortcut for:
\begin{compactcodebox}
\marg{\gls{DTLsetup}\marg{\optval{new-value-expand}{true}}\comment{local change}
 \gls{DTLread}\marg{filename}\comment{where the file contains \LaTeX\ commands}
}
\end{compactcodebox}

% OPTION new-value-trim

\optiondef+{new-value-trim}
This boolean option determines whether or not new values should have
leading and trailing spaces trimmed before they are added to a database.
Note that this option is independent of the \listsopt{trim} option
provided by the base package.

\begin{information}
Ungrouped values added with the \action{new-entry} action will always be
trimmed due to the automated trimming of the \keyval\ interface.
However, if you specifically want leading or trailing spaces, you
will need both \code{\gls{DTLsetup}\marg{\optval{new-value-trim}{false}}
and
\code{\gls{DTLaction}\oarg{\actionoptvalm{value}{~\meta{value}~},\ldots}\marg{\action{new-entry}}}}
(that is, group the value and put the spaces inside the group).
\end{information}

\mExampleref{ex:newvaluetrim} has the following:
\begin{codebox}
\gls{DTLnewdb}\marg{mydata}
\gls{DTLnewrow}\marg{mydata}
\gls{DTLsetup}\marg{\optval{new-value-trim}{true}}
\gls{DTLnewdbentry}\marg{mydata}\marg{Column1}\marg{ value1 }
\gls{DTLnewrow}\marg{mydata}
\gls{DTLsetup}\marg{\optval{new-value-trim}{false}}
\gls{DTLnewdbentry}\marg{mydata}\marg{Column1}\marg{ value2 }
\comment{compare with \cmd{DTLaction}:}
\gls{DTLsetup}\marg{\optval{default-name}{mydata}}
\gls{DTLaction}\marg{\action{new-row}}
\gls{DTLaction}\oarg{\actionoptval{column}{1},\actionoptval{value}{ value3 }}\marg{\action{new-entry}}
\gls{DTLaction}\marg{\action{new-row}}
\gls{DTLaction}\oarg{\actionoptval{column}{1},\actionoptvalm{value}{ value4 }}\marg{\action{new-entry}}
\end{codebox}
The spaces can be shown by modifying the string formatting command
to enclose the value in double-quotes:
\begin{codebox}
\cmd{renewcommand}\marg{\cmd{dtlstringformat}}[1]\marg{``\#1''}
\gls{DTLdisplaydb}\marg{mydata}
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:newvaluetrim},
  title={Trimming New Values},
  description={Example document illustrating the \opt{new-value-trim} setting}
]
{%
 \cmd{usepackage}\marg{datatool}\nl
\gls{DTLnewdb}\marg{mydata}\nl
\gls{DTLnewrow}\marg{mydata}\nl
\gls{DTLsetup}\marg{\optval{new-value-trim}{true}}\nl
\gls{DTLnewdbentry}\marg{mydata}\marg{Column1}\marg{ value1 }\nl
\gls{DTLnewrow}\marg{mydata}\nl
\gls{DTLsetup}\marg{\optval{new-value-trim}{false}}\nl
\gls{DTLnewdbentry}\marg{mydata}\marg{Column1}\marg{ value2 }\nl
\comment{compare with \cmd{DTLaction}:}%
\gls{DTLsetup}\marg{\optval{default-name}{mydata}}\nl
\gls{DTLaction}\marg{\action{new-row}}\nl
\gls{DTLaction}\oarg{\actionoptval{column}{1},\actionoptval{value}{
value3 }}\marg{\action{new-entry}}\nl
\gls{DTLaction}\marg{\action{new-row}}\nl
\gls{DTLaction}\oarg{\actionoptval{column}{1},\actionoptvalm{value}{
value4 }}\marg{\action{new-entry}}%
}
{%
\comment{display the data with the values quoted:}%
\cmd{renewcommand}\marg{\cmd{dtlstringformat}}[1]\marg{``\#1''}\nl
\gls{DTLdisplaydb}\marg{mydata}
}
\end{resultbox}

% OPTION io

\optiondef+{io}
This option can't be used as a package option. The value is a
\keyval\ list of I/O settings for use with \gls{DTLread} and
\gls{DTLwrite}, which are described in
\sectionref{sec:iosettings}.

% OPTION separator

\optiondef+{separator}
This option may only be used as a package option and sets the
separator used in \idx{CSV} files. The value \meta{char} must be a
single token, and is used in a \idx{CSV} file to separate columns
within each row. After the package has
loaded, you can use \gls{DTLsetseparator} to set the separator.
Alternatively, you can use the \ioopt{separator} setting 
within the optional argument of \gls{DTLread} or \gls{DTLwrite} or
within the value of \opt{io} option in \gls{DTLsetup}.

Note that the \idx{tabchar} is normally treated as a space by
\LaTeX. For \idx{TSV} files, the \idx{tabchar} will need to have its
category code changed to distinguish it from a space.
This can be done with \ioopteqvalref{format}{tsv} (in 
the \opt{io} option) or with \gls{DTLsettabseparator}.

Examples:
\begin{compactcodebox}
\comment{Set the default separator to ; }
\cmd{usepackage}\oarg{\optval{separator}{;}}\marg{datatool}
\comment{Set the default separator to | }
\gls{DTLsetup}\marg{ \optvalm{io}{\iooptval{separator}{|}} }
\comment{Load a CSV file with the separator : }
\gls{DTLread}\oarg{ \ioopteqvalref{format}{csv}, \iooptvalm{separator}{:} }\marg{file-1}
\comment{Load a TSV file with the tab separator}
\gls{DTLread}\oarg{ \ioopteqvalref{format}{tsv} }\marg{file-2}
\end{compactcodebox}

% OPTION: store-datum

\optiondef+{store-datum}
If true, new values will be stored as a \idx+{datumitem} in the
database (see \sectionref{sec:datatypes}). This means that each element
doesn't need to be repeatedly parsed to determine whether it is
numeric or what its numeric value is. If you want to save a database
with the datum markup retained, you will need to use 
\ioopteqvalref{format}{dbtex-3}, as that's the only format to support 
\idxpl{datumitem}.

\begin{information}
The \opt{store-datum} option is useful if your document requires a lot of
numeric computations (for example, aggregating data or plotting
charts). However, it makes looking up rows by unique labels harder,
so the setting is best left off with \sty{datagidx} and \sty{databib}.
\end{information}

\section{Example Databases}
\label{sec:exampledatabases}

There are a number of examples in this user guide that illustrate
database commands on sample data. This section describes the sample
data to provide a convenient point of reference for each example.
Some databases are constructed within the example document preamble
using \gls{DTLaction}. Some databases are loaded from a \idx{CSV}
file, which is the more common way of loading data, but the
self-contained example documents need to create the required
\idx{CSV} file. This is done using the \envfmt{filecontents}
environment, except for the examples with a \idx{TSV}
file, which needs to have the \idx{tabchar} preserved.

\subsection{Student Marks (CSV)}
\label{sec:marks}

The \qt{marks} database consists of columns with the labels: 
\optfmt{Surname}, \optfmt{Forename}, \optfmt{Student\-No} (a unique
identifier, which disambiguates between the two students with the
same name), and columns with the marks for each assignment.

\begin{information}
This sample database is used in \exampletagref{marks}.
\end{information}

The \qt{marks} database is read in from the file
\filefmt{studentmarks.csv}, which contains the following content:
\begin{compactcodebox}
\markscsv
\end{compactcodebox}
The data can be loaded with:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{marks}}\marg{studentmarks.csv}
\end{codebox}
Alternatively, you can setup the default database name first, to
avoid having to repeatedly specify it. Since the data contains
numeric values that may need to be parsed, it's also useful to
switch on the \opt{store-datum} option to reduce parsing:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}
\gls{DTLread}\marg{studentmarks.csv}
\end{codebox}
Note that this assumes the default settings for \gls{DTLread}:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{format}{csv},\iooptval{csv-content}{literal}}\marg{studentmarks.csv}
\end{codebox}

This is only a short database for compactness. A similar, but longer
database, is the students scores database.

\subsection{Student Scores}
\label{sec:studentscoresdb}

The \qt{scores} database consists of the columns: \optfmt{forename}
(with the title \qt{First Name}), \optfmt{surname} (with the title
\qt{Surname}), \optfmt{regnum} (with the title \qt{Student Number}),
\optfmt{gender} (which may be a recognised gender label, see
\sectionref{sec:persongender}), \optfmt{parent} (the student's
guardian, parent or parents), \optfmt{score} and \optfmt{award}.
The \optfmt{award} column contains currency values, and the
\optfmt{score} column contains decimal values.  The \optfmt{regnum}
column consists of a unique identifier. This happens to be numeric
for this data, but may not necessarily be numeric for a real-world
database. It's included in the example data to demonstrate querying
by a unique value and the data type isn't relevant for that.

\begin{information}
This sample database is used in \exampletagref{studentscores}.
\end{information}

Since the data contains numeric values that may need to be parsed,
it's useful to switch on the \opt{store-datum} option to reduce
parsing.
The database is constructed in the preamble of example
documents as follows:
\begin{codebox}[fontupper=\small\ttfamily]
\studentscoresdb
\end{codebox}

If you prefer a \idx{CSV} file, the nearest equivalent would be:
\begin{compactcodebox}[fontupper=\small\ttfamily]
forename,surname,regnum,gender,parent,score,award
Jane,Brown,102647,F,Ms Brown,75,"\$1,830"
John,"Smith, Jr",102689,M,Mr and Mrs Smith,68,"\$1,560"
Quinn,Ó Coinn,103294,,Mrs and Mrs Ó Coinn,91,"\$3,280"
Evelyn,"O'Leary",n,Prof O'Leary,107569,81.5,"\$2,460"
Zoë,Adams,105987,f,Mr and Mrs Adams,52,"\$1,250"
Clare,Vernon,104356,f,Mr Vernon,45,"\$500"
Roger,Brady,106872,m,Dr Brady and Dr Mady,58,"\$1,350"
Andy,Brown,103569,m,Mr Brown and Prof Sepia,42,"\$980"
\end{compactcodebox}
However, the \idx{CSV} format doesn't support missing mid-row values
so the missing gender field for Quinn is now empty. This will make a
difference if you display the data or test for null but not empty (see
\sectionref{sec:null}).

If the \idx{CSV} file is called \filefmt{studentscores.csv}, then it can be
loaded with:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{scores}}
\gls{DTLread}\oarg{ \iooptval{format}{csv}, \iooptval{csv-content}{literal},
 \iooptvalm{headers}{ First Name, Surname, Student Number,
   gender, parent, Score (\gls{cs.percent}), award }
}\marg{studentscores.csv}
\end{codebox}
Note that if the dollar symbols (\idx{dollar}) in the file are
replaced with \LaTeX\ markup (\gls{cs.dollar}), then you will need
\ioopteqvalref{csv-content}{tex} instead of
\ioopteqvalref{csv-content}{literal}.

\subsection{Customers}
\label{sec:customers}

The \qt{customers} database consists of columns with the
labels: \optfmt{Id} (a unique integer identifier, which happens to
match the data row number but this isn't guaranteed),
\optfmt{Organisation}, \optfmt{Surname}, \optfmt{Forename},
\optfmt{Email}, and \optfmt{Age} (another numeric column, which
could potentially be decimal but only has integer numbers or missing
items).  There are some empty entries in the Organisation, Email and Age
columns.

\begin{information}
This sample database is used in \exampletagref{customers}.
\end{information}

The customers database can be read in from the file
\filefmt{customers.csv}, which contains the following content:
\begin{compactcodebox}[fontupper=\small\ttfamily]\if@endpe\@doendpe\fi
\customerscsv
\end{compactcodebox}
The data can be loaded with:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{customers}}\marg{customers.csv}
\end{codebox}
Alternatively, you can setup the default database name first, to
avoid having to repeatedly specify it.
Since the data contains numeric values that may need to be parsed,
it's also useful to switch on the \opt{store-datum} option to reduce
parsing.
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{customers}}
\gls{DTLread}\marg{customers.csv}
\end{codebox}
Note that this assumes the default settings for \gls{DTLread}:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{format}{csv},\iooptval{csv-content}{literal}}\marg{customers.csv}
\end{codebox}
Null values can only occur with data loaded from a \idx{CSV} file
when final columns are missing. In this case, the Age column is the last
column and is not set in some rows. For example, there's no comma
following Lizzie so Lizzie's age will be null. Compare this with the
previous row where Dickie Duck has no age but there is a trailing
comma. This will set Dickie Duck's age to empty. In the case of
Sally Mander, both the Email and Age columns are missing. Since they
are final columns both the email and age are null.

This data may also be defined within the document. Note that there
is a slight difference here as most of the missing values are now entirely
omitted from the database, so any reference to them will result in a
null value rather than an empty value. However, there is one case
where the Organisation column has been set to empty rather then
being omitted, so a reference to that element will result in an
empty value not a null value.
\begin{codebox}[fontupper=\small\ttfamily]
\customersdb
\end{codebox}

\subsection{Product List}
\label{sec:productdb}

The \qt{product} database consists of the columns: \optfmt{Title},
\optfmt{Author}, \optfmt{Format} (hardback, paperback or ebook),
\optfmt{Quantity} (integer), \optfmt{Price} (decimal), and
\optfmt{Notes} (which is null in some rows and is only created by
the first row to add an item to it).

\begin{information}
This sample database is used in \exampletagref{product}.
\end{information}

Since the data contains numeric values that may need to be parsed,
it's also useful to switch on the \opt{store-datum} option to reduce
parsing.
The database is constructed in the preamble of example
documents as follows:
\begin{codebox}[fontupper=\small\ttfamily]
\productdb
\end{codebox}

\subsection{Price List}
\label{sec:pricelistdb}

The \qt{pricelist} database has the columns: \optfmt{Product},
\optfmt{Quantity} (integer), \optfmt{Price} (currency), and \optfmt{Notes}
(which is null in some rows). Note that, unlike the larger
\optfmt{products} database above, the price column includes the currency
symbol.

\begin{information}
This sample database is used in \exampletagref{pricelist}.
\end{information}

Since the data contains numeric values that may need to be parsed,
it's useful to switch on the \opt{store-datum} option to reduce
parsing.
The database is constructed in the preamble of example
documents as follows:
\begin{codebox}
\pricelistdb
\end{codebox}

\subsection{Balance Sheet (CSV)}
\label{sec:balancecsv}

The \qt{balance} database consists of columns with the labels: 
\optfmt{Description}, \optfmt{In}, \optfmt{Out}, and \optfmt{Balance}. The last
three columns are all numeric.

\begin{information}
This sample database is used in \exampletagref{balance}.
\end{information}

The \qt{balance} database is read in from the file
\filefmt{balance.csv}, which contains the following content:
\begin{compactcodebox}
\balancecsv
\end{compactcodebox}

The data can be loaded with:
\begin{codebox}
\gls{DTLread}\oarg{
   \iooptval{name}{balance}, \iooptval{format}{csv},
   \iooptvalm{headers}{ Description, in (\gls{pounds}),
     Out (\gls{pounds}), Balance (\gls{pounds}) }
 }\marg{balance.csv}
\end{codebox}
The database name can be set as the default, if preferred.
The \iooptval{format}{csv} setting is the default and so may be
omitted.
Since the data contains numeric values that may need to be parsed,
it's also useful to switch on the \opt{store-datum} option to reduce
parsing.
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{balance}}
\gls{DTLread}\oarg{
   \iooptvalm{headers}{ Description, in (\gls{pounds}),
     Out (\gls{pounds}), Balance (\gls{pounds}) }
 }\marg{balance.csv}
\end{codebox}

\subsection{Fruit (CSV)}
\label{sec:fruitcsv}

The \qt{fruit} database consists of columns with the labels: 
\optfmt{Name} (string) and \optfmt{Quantity} (numeric). The quantity
includes decimal values, so evidently some fruit has been cut in
half.

\begin{information}
This sample database is used in \exampletagref{fruit}.
\end{information}

The \qt{fruit} database is read in from the file
\filefmt{fruit.csv}, which contains the following content:
\begin{compactcodebox}
\fruitcsv
\end{compactcodebox}

This file can be loaded with:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{fruit},\iooptval{format}{csv}}\marg{fruit.csv}
\end{codebox}
Again, the database name can be set as the default, if preferred.
The \iooptval{format}{csv} setting is the default and so may be
omitted.
Since the data contains numeric values that may need to be parsed,
it's also useful to switch on the \opt{store-datum} option to reduce
parsing.
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}
\gls{DTLread}\marg{fruit.csv}
\end{codebox}

\subsection{Profits (CSV)}
\label{sec:profitscsv}

The \qt{profits} database has three columns with the labels:
\optfmt{Year}, \optfmt{Profit} and \optfmt{Units}. There are three negative values
for the \optfmt{Profit} column (that is, they are in fact losses
not profits) which have been formatted slightly differently. Two have
the minus sign before the currency symbol and one has the sign
after the symbol. Both formats are supported.
(\Exampleref{ex:auto-reformat-csv} demonstrates how to
automatically reformat the values to tidy them up.)

\begin{information}
This sample database is used in \exampletagref{profits}.
\end{information}

The \qt{profits} database is read in from the file
\filefmt{profits.csv}, which contains the following content:
\begin{compactcodebox}
\profitscsv
\end{compactcodebox}
Note that this uses \gls{cs.dollar} rather than a literal
\idx{dollar} symbol, so \iooptval{csv-content}{tex} is required:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{profits},\iooptval{format}{csv},\iooptval{csv-content}{tex}}\marg{profits.csv}
\end{codebox}
Again, the database name can be set as the default, if preferred,
and \iooptval{format}{csv} is the default so it may be omitted.
Since the data contains numeric values that may need to be parsed,
it's also useful to switch on the \opt{store-datum} option to reduce
parsing.
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
\end{codebox}

\subsection{Time to Growth (CSV)}
\label{sec:growthcsv}

The \qt{growth1} and \qt{growth2} databases represents data obtained
from hypothetical microbiological experiments, where a microbial
population is observed at various time points. The two different
sets of data correspond to different temperatures. (For example, the
\qt{growth1} data may have had the temperature set to 6 degrees and
\qt{growth2} may have had the temperature set to 8 degrees.) The
first column in each case is the time observations. The other
columns have the population figures as a log count.

\begin{information}
These sample databases are used in \exampletagref{growth}.
\end{information}

The \qt{growth1} database is read in from the file
\filefmt{growth1.csv}, which contains the following content:
\begin{compactcodebox}
\timetogrowthIcsv
\end{compactcodebox}

This file can be loaded with:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{growth1},\iooptval{format}{csv}}\marg{growth1.csv}
\end{codebox}
Since all values are \idxpl{plainnumber}, an alternative is:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum}}
\gls{DTLread}\oarg{
 \iooptval{name}{growth1},
 \iooptval{format}{csv},
 \iooptval{csv-content}{no-parse},
 \iooptval{data-types}{decimal}
}\marg{growth1.csv}
\end{codebox}
This indicates that all columns have non-localised decimal content
and by setting \opt{store-datum} first, they won't need parsing when
used in a numerical context.

The \qt{growth2} database is read in from the file
\filefmt{growth2.csv}, which contains the following content:
\begin{compactcodebox}
\timetogrowthIIcsv
\end{compactcodebox}

This file can be loaded with:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{growth2},\iooptval{format}{csv}}\marg{growth2.csv}
\end{codebox}
Again, since all values are \idxpl{plainnumber}, an alternative is:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum}}
\gls{DTLread}\oarg{
 \iooptval{name}{growth2},
 \iooptval{format}{csv},
 \iooptval{csv-content}{no-parse},
 \iooptval{data-types}{decimal}
}\marg{growth2.csv}
\end{codebox}

\subsection{Time to Growth (TSV)}
\label{sec:growthtsv}

The \qt{growthdata} database is an alternative to the above time to
growth data. In this case the data is provided in a \idx{TSV} file.
Instead of having a single time column with two columns for the
results of each experiment, it has four columns containing the time
and log count for each experiment.

\begin{information}
This sample database is used in \exampletagref{growthtsv}.
\end{information}

The \idx{tabchar} is represented by the \sym{tabchar} symbol. The
first file is \filefmt{growth.tsv}:
\begin{compactcodebox}
\growthItsv
\end{compactcodebox}
This represents a spreadsheet where the first row originally had
\qt{Experiment 1} spanning the first two columns and \qt{Experiment
2} spanning the last two columns. It was then exported to a
\idx{TSV} file, which doesn't support column spanning entries, so
\qt{Experiment 1} is now in the first column and \qt{Experiment 2}
is in the third. This line needs to be omitted when parsing the
file, which can be done with the \ioopt{csv-skip-lines} option.

There is a similar second database \qt{growthdata2} in the file
\filefmt{growth2.tsv}, but it has an extra pair of columns for a
third experiment:
\begin{compactcodebox}
\growthIItsv
\end{compactcodebox}

In both files, the actual headers are in the second line: \qt{Time},
\qt{Log Count}, \qt{Time} and \qt{Log Count} (and, for the second
file, another \qt{Time} and \qt{Log Count}). Note that they are
duplicated, which means they are not suitable as unique column keys.
Therefore it's necessary to override the default behaviour to ensure
unique keys. The format needs to be set to ensure that the
\idx{tabchar} is recognised as the separator and has its category
code changed so that it can be distinguished from a space.

Since the data contains numeric values, it can be more
efficient to switch on the \opt{store-datum} setting to reduce
parsing if, for example, the data needs to be displayed in a graph.
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum}}
\gls{DTLread}\oarg{
 \iooptval{name}{growthdata}, \iooptval{format}{tsv}, \iooptval{csv-skip-lines}{1},
 \iooptvalm{keys}{Exp1Time, Exp1Count, Exp2Time, Exp2Count}
 }\marg{growth}
\gls{DTLread}\oarg{
 \iooptval{name}{growthdata2}, \iooptval{format}{tsv}, \iooptval{csv-skip-lines}{1},
 \iooptvalm{keys}{Exp1Time, Exp1Count, Exp2Time, Exp2Count,
   Exp3Time, Exp3Count }
 }\marg{growth2}
\end{codebox}
Note that \gls{DTLread} will assume a \ext{tsv} extension with
\iooptval{format}{tsv} so file extension may be omitted.

As with the \idx{CSV} time to growth files, since the values
are all \idxpl{plainnumber}, a faster method is to switch off
element parsing:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum}}
\gls{DTLread}\oarg{
 \iooptval{name}{growthdata}, \iooptval{format}{tsv}, \iooptval{csv-skip-lines}{1},
 \iooptvalm{keys}{Exp1Time, Exp1Count, Exp2Time, Exp2Count},
 \iooptval{csv-content}{no-parse},
 \iooptval{data-types}{decimal}
 }\marg{growth}
\gls{DTLread}\oarg{
 \iooptval{name}{growthdata2}, \iooptval{format}{tsv}, \iooptval{csv-skip-lines}{1},
 \iooptvalm{keys}{Exp1Time, Exp1Count, Exp2Time, Exp2Count,
   Exp3Time, Exp3Count },
 \iooptval{csv-content}{no-parse},
 \iooptval{data-types}{decimal}
 }\marg{growth2}
\end{codebox}

\subsection{Generic X/Y Data (CSV)}
\label{sec:xydatacsv}

The \qt{xydata} database just contains two columns of numbers that range from
negative to positive.

\begin{information}
This sample database is used in \exampletagref{xydata}.
\end{information}

The \qt{xydata} database is read in from the file
\filefmt{xydata.csv}, which contains the following content:
\begin{compactcodebox}
\xydatacsv
\end{compactcodebox}

This file can be loaded with:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{xydata},\iooptval{format}{csv}}\marg{xydata.csv}
\end{codebox}

Again, since the data only contains \idxpl{plainnumber}, it's faster
to switch off parsing:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum}}
\gls{DTLread}\oarg{
 \iooptval{name}{xydata},
 \iooptval{format}{csv},
 \iooptval{csv-content}{no-parse},
 \iooptval{data-types}{decimal}
}\marg{xydata.csv}
\end{codebox}

\section{Action Command}
\label{sec:action}

\glsstartrange{DTLaction}%
Some of the commands provided by \sty{datatool} are quite long and
it can be difficult to remember the syntax. Version~3.0 provides:
\cmddef{DTLaction}
This will perform a command associated with the given \idx{action},
with the arguments correctly set according to the values given in 
\meta{settings}. For example:
\begin{compactcodebox}
\gls{DTLaction}\marg{\action{new}}
\end{compactcodebox}
is equivalent to:
\begin{compactcodebox}
\gls{DTLnewdb}\margm{default-name}
\end{compactcodebox}
where \meta{default-name} is the default name (which can be changed
with \opt{default-name} in \gls{DTLsetup}). Alternatively, you can
supply the database name:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptval{name}{mydata}}\marg{\action{new}}
\end{compactcodebox}
This is equivalent to:
\begin{compactcodebox}
\gls{DTLnewdb}\marg{mydata}
\end{compactcodebox}

Available \idxpl{action} are listed in \sectionref{sec:actionnames} and settings
are listed in \sectionref{sec:actionopts}. The \meta{action}
argument will be trimmed by \gls{DTLaction} to remove any leading or
trailing spaces.

\mExampleref{ex:actions} is essentially equivalent to
\exampleref{ex:newdb}. It defines the \qt{pricelist} database using
actions (see \sectionref{sec:pricelistdb}) and then displays the
database using the \action{display} action:
\begin{codebox}
\gls{DTLaction}\marg{display}
\end{codebox}
The \qt{pricelist} database has null values as the \optfmt{Notes} column
isn't set in every row (see \sectionref{sec:null}).
\begin{resultbox}
\createexample*[label={ex:actions},
  tag={pricelist},
  title={Creating and Displaying a Database with \glscmd{DTLaction}},
  description={Example document that creates a simple database and
displays it as a table}
]
{%
\cmd{usepackage}\marg{datatool}\nl
\pricelistdb
}
{%
\comment{Display the data:}%
\gls{DTLaction}\marg{display}
}
\end{resultbox}

An action may have one or more return values consisting of a
\emph{primary} return value and (optionally) \emph{secondary} return
values that have an associated property name. There are several ways
of fetching the return values.

The primary and secondary values can be obtained with:
\cmddef{DTLget}
This will define the (token list variable) control sequence \meta{cs} to the value
obtained from the most recent \gls{DTLaction} in the current scope.
Secondary return values should be identified by their property name. 
The \meta{property} should be empty or omitted for the primary value.

Secondary (but not primary) values can also be obtained with the
\actionopt{return} setting, which should provide a comma-separated
list of \code{\meta{cs}\dequals\meta{property}} assignments. Each
listed control sequence \meta{cs} will be defined to the value of
the secondary property identified by \meta{property}.

If no return value is available (for example, the action failed or
requested information was unavailable or the property name is
unknown) then \meta{cs} will be
defined to a null value (see \sectionref{sec:null}).

\begin{information}
If you get a null value for an action that doesn't produce any
errors or warnings, check the supplied action settings (such as
\actionopt{options} for the \action{aggregate} action) and also check 
that you have correctly spelt the property names.
\end{information}

For example, the \action{column-index} action has the column index
as the primary return value:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Price}}\marg{\action{column-index}}
\gls{DTLget}\marg{\cmd{colidx}}
Column index: \cmd{colidx}.
\end{codebox}

\cmddef{DTLuse}
This gets the primary or secondary return value and then uses it.
Note that this command is only expandable if the argument
\meta{property} is empty (that is, for the primary return value).
Otherwise it will expand to a robust internal command. If you need
the value associated with a property in an expandable context, you
will first have to fetch it with \gls{DTLget} or with the
\actionopt{return} option.

\cmddef{DTLifaction}
Expands to \meta{true} if the last action (within the current scope) set
the return value identified by \meta{property}, otherwise it expands
to \meta{false}. An empty \meta{property} indicates the primary
return value.

\subsection{Defined Actions}
\label{sec:actionnames}

All actions recognise the optional \actionopt{return} setting,
although it will have no effect with actions that don't have
secondary return values. The descriptions below only identify
optional settings where support varies according to the action.

\subsubsection{Creation and Editing}
\label{sec:dbactionnames}

\actiondef{new}
Creates a new database. This action has one optional setting:
\actionopt{name}, which should be a single name. 
There are no required settings. Other action
settings are ignored. The return value is the database name, which
can also be accessed via the \optfmt{name} secondary return property.

The \action{new} action internally uses \gls{DTLnewdb}.
For example:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptval{name}{mydata}}\marg{\action{new}}
\end{compactcodebox}
is equivalent to:
\begin{compactcodebox}
\gls{DTLnewdb}\marg{mydata}
\end{compactcodebox}
Note that new databases are always globally defined.

\actiondef{delete}
Deletes (undefines) a database (that is, the internal commands
associated with the database are undefined). This action has one
optional setting: \actionopt{name}, which should be a single name.
There are no required settings. Other action settings are ignored.
The return value is the database name, which can also be accessed
via the \optfmt{name} return property.  The other return properties
are \optfmt{rows} and \optfmt{columns}, which will be set to the row
and column count before the database was deleted.

\actiondef{clear}
Clears a database (that is, the database is made empty but remains
defined). This action has one optional setting: \actionopt{name},
which should be a single name. There are no required settings. Other
action settings are ignored. The return value is the database name,
which can also be accessed via the \optfmt{name} return property.
The other return properties are \optfmt{rows} and \optfmt{columns},
which will be set to the row and column count before the database
was cleared.

\actiondef{new-row}
Adds a new row to a database. This action has two optional settings:
\actionopt{name} (which should be a single name) and
\actionopt{assign}. There are no required settings. Other action
settings are ignored. As with \gls{DTLnewrow}, the \opt{global}
option determines whether or not the database is altered globally or
locally.

The \actionopt{assign} setting allows you to set the values for the
new row at the same time. You can also add values to this new row
with the \action{new-entry} action afterwards. It's more efficient
and more compact to set the values while creating the new row, but if
some values should be expanded but not others, use the
\action{new-entry} action for those that need expanding.
For example:
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptvalm{assign}{ Name = \marg{José Arara}, Score = \marg{68},
   Award = \marg{\gls{cs.dollar}2,453.99} }
}\marg{\action{new-row}}
\end{codebox}
This is equivalent to:
\begin{codebox}
\gls{DTLaction}\marg{\action{new-row}}
\gls{DTLaction}\oarg{ \actionoptval{key}{Name}, \actionoptvalm{value}{José Arara} }
 \marg{\action{new-entry}}
\gls{DTLaction}\oarg{ \actionoptval{key}{Score}, \actionoptvalm{value}{68} }\marg{\action{new-entry}}
\gls{DTLaction}\oarg{ \actionoptval{key}{Award}, \actionoptvalm{value}{\gls{cs.dollar}2,453.99} }
 \marg{\action{new-entry}}
\end{codebox}

The primary return value is the index of the new row, which will be
the same as the updated row count. There is also a secondary return
value that can be accessed with the \optfmt{name} property, which
will be the database name. The \optfmt{row} property can also be
used, which is the same as the primary return value. The difference
is that \code{\gls{DTLuse}\marg{}} is expandable but
\code{\gls{DTLuse}\marg{row}} isn't.

The internal action of \action{new-row} without the
\actionopt{assign} setting is essentially the same as
\gls{DTLnewrow}. For example:
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optvalm{default-name}{mydata}}
\gls{DTLaction}\marg{\action{new-row}}
\end{compactcodebox}
which is the same as:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{mydata}}\marg{\action{new-row}}
\end{compactcodebox}
is equivalent to:
\begin{compactcodebox}
\gls{DTLnewrow}\marg{mydata}
\end{compactcodebox}
Whereas with the \actionopt{assign} setting, the \action{new-row} action 
effectively implements not only \gls{DTLnewrow} but also one or more
instances of \gls{DTLnewdbentry}.

\actiondef{new-entry}
Adds a new entry to the last row of a database. As with
\gls{DTLnewdbentry}, the database must have a least one row, and the
\opt{global} option determines whether or not the database is
altered globally or locally.

This action has one optional setting: \actionopt{name}, which should
be a single name. The required settings are: \actionopt{value} (or
\actionopt{expand-value} or \actionopt{expand-once-value}) and
either \actionopt{key} or \actionopt{column}.  Other action settings
are ignored. 

This action has secondary return values, which can be accessed with
\gls{DTLget} or \gls{DTLuse} or the \actionopt{return} setting,
referenced by the following property
names:
\begin{itemize}
\item \optfmt{name}: the database name;
\item \optfmt{column}: the index of the new column;
\item \optfmt{key}: the column key;
\item \optfmt{row}: the index of the row (which will be the same as
the row count);
\item \optfmt{type}: the data type integer identifier 
(see \sectionref{sec:datatypes}). Note that while the \actionopt{type} action setting
is a keyword, the \optfmt{type} return value is a number.
\end{itemize}
The primary return value (accessed with an empty property) is the
column index, so you can access the column index with either
\code{\gls{DTLuse}\marg{column}} or \code{\gls{DTLuse}\marg{}}, but
only the latter is expandable.

\begin{information}
In general, it's better to have the default
\optval{new-value-expand}{false}, and use
\actionopt{expand-value} or \actionopt{expand-once-value} for
the values that require expanding. (Unless the majority of your
values require expansion.)
\end{information}

Note the difference between using the \gls{DTLsetup} option
\optval{new-value-expand}{true} and the action
setting \actionopt{expand-value}. The first performs a protected
expansion. For example:
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optval{new-value-expand}{true}}
\gls{DTLaction}\oarg{\actionoptval{key}{Price},\actionoptval{value}{\gls{cs.dollar}1,234}}\marg{\action{new-entry}}
\end{compactcodebox}
This will add \code{\cmd{protect} \gls{cs.dollar}1,234} to the
default database.  Whereas the following:
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optval{new-value-expand}{false}}
\gls{DTLaction}\oarg{\actionoptval{key}{Price},\actionoptval{expand-value}{\gls{cs.dollar}1,234}}\marg{\action{new-entry}}
\end{compactcodebox}
will add \code{\cmd{protect} \cmd{T}1\gls{textdollar} 1,234} to the
default database. In the case of currency, it's better not to expand
the value otherwise the currency symbol may expand to something that's not
recognised as a currency unit.

\begin{warning}
The \action{new-entry} action internally uses \gls{DTLnewdbentry} if
\actionopt{key} is set. If \actionopt{column} is used instead, a
similar function is used, but be aware that listing column indexes
out of order when the columns haven't yet been defined may have
unexpected side-effects.
\end{warning}

If you try to use both \actionopt{key} and \actionopt{column} this
will cause an error and the column index will be ignored. If you
use \actionopt{key} and a column hasn't yet been defined, the
column count will increase by 1 and a new column will be created at
the end. If you use \actionopt{column} and no column with that
index has been defined, then a new column will be created with the
key obtained by expanding \code{\gls{dtldefaultkey} \meta{column-idx}}
and, if the index is greater than the current number of columns, 
the database will be expanded so that it has a column count of
\meta{column-idx}.

\actiondef{add-column}
This action may be used to append a column to a database. 
Although the \action{new-entry} action will automatically create an
undefined column, you may prefer to define your columns in advance
to ensure the ordering and to provide additional column metadata.

The \action{add-column} action has optional settings:
\actionopt{name} (which should be a single name), \actionopt{key},
\actionopt{type}, and \actionopt{value} (or \actionopt{expand-value}
or \actionopt{expand-once-value}).  Note that the \actionopt{column}
setting should not be used and will trigger an error if set. All
other settings are ignored. The \gls{DTLsetup} \opt{global} option
determines whether or not the database is altered globally or
locally.

\begin{deflist}
\itemtitle{Column Key}
\begin{itemdesc}
The column key, which must be unique to the database, will be
obtained from the \actionopt{key} setting, if provided. Otherwise,
it will be obtained by expanding \code{\gls{dtldefaultkey}
\meta{col-idx}}, where \meta{col-idx} is the index of the new
column.
\end{itemdesc}

\itemtitle{Column Header}
\begin{itemdesc}
The column header will be set to the \actionopt{value}, if
provided. Otherwise, it will be set to the column key.
\end{itemdesc}

\itemtitle{Column Type}
\begin{itemdesc}
The column type will be set according to the \actionopt{type}
setting, if provided. Otherwise, the unknown type will be assumed.
Note that the type will be updated if an entry with a greater type
precedence is added to the column. For example, if you set
\actionoptval{type}{integer} but then add a decimal number to this
column, then the column type will be updated to decimal.
\end{itemdesc}
\end{deflist}

This action has secondary return values, which can be accessed with
\gls{DTLget} or \gls{DTLuse} or the \actionopt{return} setting, 
referenced by the following property names:
\begin{itemize}
\item \optfmt{name}: the database name;
\item \optfmt{column}: the index of the new column (which will be
the same as the updated column count);
\item \optfmt{key}: the column key;
\item \optfmt{header}: the column header;
\item \optfmt{type}: the data type integer identifier 
(see \sectionref{sec:datatypes}).
\end{itemize}
The primary return value (accessed with an empty property) is the
column index, so you can access the column index with either
\code{\gls{DTLuse}\marg{column}} or
\code{\gls{DTLuse}\marg{}}, but only the latter is expandable.
(Alternatively, use \code{\gls{DTLcolumncount}\margm{name}}.)

\mExampleref{ex:addcolaction} creates a database and adds columns
with actions:
\begin{codebox}
\gls{DTLaction}\marg{\action{new}}
\gls{DTLaction}\marg{\action{new-row}}
\gls{DTLaction}\marg{\action{add-column}}
Added column \gls{DTLuse}\marg{column} 
(key: \gls{DTLuse}\marg{key}; header: \gls{DTLuse}\marg{header})
to database `\gls{DTLuse}\marg{name}'.
\codepar
\gls{DTLaction}\oarg{\actionoptval{key}{quantity}}\marg{\action{add-column}}
Added column \gls{DTLuse}\marg{column} 
(key: \gls{DTLuse}\marg{key}; header: \gls{DTLuse}\marg{header})
to database `\gls{DTLuse}\marg{name}'.
\codepar
\gls{DTLaction}\oarg{\actionoptval{key}{price},\actionoptval{value}{Price (\gls{cs.dollar})}}\marg{\action{add-column}}
Added column \gls{DTLuse}\marg{column} 
(key: \gls{DTLuse}\marg{key}; header: \gls{DTLuse}\marg{header})
to database `\gls{DTLuse}\marg{name}'.
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:addcolaction},
  title={Adding New Columns Using Actions},
  description={Example document demonstrating how to add columns to
a database using actions}
]
{\cmd{usepackage}\marg{datatool}}
{%
\gls{DTLaction}\marg{\action{new}}\nl
\gls{DTLaction}\marg{\action{new-row}}\nl
\gls{DTLaction}\marg{\action{add-column}}\nl
Added column \gls{DTLuse}\marg{column} \nl
(key: \gls{DTLuse}\marg{key}; header: \gls{DTLuse}\marg{header})\nl
to database `\gls{DTLuse}\marg{name}'.
\codepar
\gls{DTLaction}\oarg{\actionoptval{key}{quantity}}\marg{\action{add-column}}\nl
Added column \gls{DTLuse}\marg{column} \nl
(key: \gls{DTLuse}\marg{key}; header: \gls{DTLuse}\marg{header})\nl
to database `\gls{DTLuse}\marg{name}'.
\codepar
\gls{DTLaction}\oarg{\actionoptval{key}{price},\actionoptval{value}{Price
(\gls{cs.dollar})}}\marg{\action{add-column}}\nl
Added column \gls{DTLuse}\marg{column} \nl
(key: \gls{DTLuse}\marg{key}; header: \gls{DTLuse}\marg{header})\nl
to database `\gls{DTLuse}\marg{name}'.
}
\end{resultbox}

\subsubsection{Querying}
\label{sec:dbrefactionnames}

\actiondef{find}
Finds the first row in the database to match the supplied criteria.
This action involves iterating over the database, applying the
criteria to each row. If you want to lookup by a unique value, you
may find it faster to use the \action{select-row} action. Unlike
the \action{select-row} action, the \action{find} action doesn't
change the \idx{current-row} (unless explicitly requested with the
\actionfindoptval{select}{true} option), so it may be used within the body of
\gls{DTLforeach} to either lookup another row in the current
database or in another database.

The \action{find} action doesn't have any required settings, but if
none are provided it will simply find the first row of the database
(if the database isn't empty). The optional settings are:
\begin{itemize}
  \item \actionopt{name}: identifies the database;

  \item \actionopt{row}: identifies the row index to start the search from
   (defaults to 1, if omitted);

  \item \actionopt{row2}: identifies the row index to end the search
   (defaults to the last row, if omitted);

  \item \actionopt{assign}: an \glsdisp{assign-list}{assignment list} 
  of \code{\meta{cs}\dequals\meta{col-key}} pairs to define
  placeholder commands for each row, before the match function
  is used;

  \item \actionopt{options}: may be used to specify options specific
to the \action{find} action, see below.
\end{itemize}

The \actionopt{options} value may include the following \keyval\
options.
\optiondef*{action.find.direction}
Indicates the search direction. The value may be one of:
\optfmt{ascending} (or \optfmt{asc}) or \optfmt{descending} (or
\optfmt{desc}). If \actionfindoptval{direction}{ascending}, the
search will start from the smallest row index. If
\actionfindoptval{direction}{descending} the search will start from
the largest row index.

\optiondef*{action.find.select}
A boolean option that governs whether the first matching row to be
found should be selected as the \idx{current-row}. If a match is found with
\actionfindoptval{select}{true}, then \gls{dtlgetrow} will be used to set
the \gls{dtlcurrentrow} token register (and related registers) for
use with actions (such as \action{row-aggregate}) or commands (such
as those described in \sectionref{sec:currentrow}).  If unsuccessful
or if \actionfindoptval{select}{false}, the \gls{dtlcurrentrow}
token register won't be changed.

\optiondef*{action.find.function}
Sets the match criteria function to \meta{cs}, which must be defined
to take a single argument, where the function definition expands to
that argument to indicate a match and does nothing otherwise. 

\optiondef*{action.find.inline}
An inline alternative to \actionfindopt{function}.

The default match function is simply a first of one function, which
means that the first row (or last row with
\actionfindoptval{direction}{descending}) in the range
\actionopt{row}--\actionopt{row2}, will
match, provided the database isn't empty. If the \actionopt{assign}
setting is used, the placeholders can be referenced in the function.
They will also still be available after the action, and will have
their values from the matching row or from the final row in the search
range if no match was found. They will be null if the database is
empty. If there was no corresponding value in the row, they will be
set to either \gls{DTLnumbernull} (if the column has a numeric
data type) or \gls{DTLstringnull} otherwise (see
\sectionref{sec:null}).

The primary return value will be the row index which satisfied the
match. The return value will not be set of no match was found.
The secondary values will be set to the values of the matching row,
where the property name is the column key. This means that you can
access the values from the match even if you didn't set the
corresponding assignment in \actionopt{assign}.

For example, the following simply fetches all the values from row~2:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{row}{2}}\marg{\action{find}}
\end{codebox}
Each value can then be displayed with
\code{\gls{DTLuse}\margm{col-key}}, where \meta{col-key} is the
column key.

The following finds the first row where the surname field is
\qt{Smith} and the forename field is \qt{John}:
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptvalm{assign}{\cmd{Surname}=surname,\cmd{Forename}=forename},
 \actionoptvalm{options}{
   \actionfindoptvalm{inline}{\gls{DTLifstringeq}\marg{\cmd{Surname}}\marg{Smith}
    \marg{\gls{DTLifstringeq}\marg{\cmd{Forename}}\marg{John}\marg{\#1}\marg{}}\marg{}}
 }
}\marg{\action{find}}
\gls{DTLifaction}\marg{}\comment{test for primary return value}
 \marg{\cmd{Forename}\gls{cs.space}\cmd{Surname}\gls{cs.space}found on row \gls{DTLuse}\marg{}}
 \marg{Not found}.
\end{codebox}

\actiondef{column-index}
Obtains the column index corresponding to the given \actionopt{key}.
This action does not create any typeset output. It performs a
similar function as \gls{DTLgetcolumnindex} but it won't trigger an
error if there's no column with the given key. Instead you need to
test the return value with \gls{DTLifnull}. Use \gls{dtlcolumnindex}
instead if you want a single expandable function with no error
checking.

An error will occur if the database is undefined or if the key is
missing.  This action has one optional setting: \actionopt{name}
(which should be a single name), and one required setting:
\actionopt{key}. Other settings are ignored.

The primary return value (if successful) is the column index, which
may be accessed with \code{\gls{DTLuse}\marg{}} or
\code{\gls{DTLget}\margm{cs}}. The \optfmt{name} return property
will be set to the database name, and the \optfmt{key} return
property will be set to the column key (if provided). The
\optfmt{column} property can also be referenced to obtain the column
index, if successful.

For example:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Price}}\marg{\action{column-index}}
\gls{DTLget}\marg{\cmd{colidx}}
\gls{DTLifnull}\marg{\cmd{colidx}}\marg{No such column}\marg{Column index: \cmd{colidx}}.
\end{codebox}

\actiondef{column-data}
This action is similar to \action{column-index} but gets all the
column metadata (column index, key, type and header) from either the
key or index.

The primary return value is the column key (regardless of whether
the \actionopt{key} or \actionopt{column} setting was used).  The
secondary return properties are: \optfmt{column} (the column index),
\optfmt{key} (the column key), \optfmt{type} (the data type), and
\optfmt{header} (the column header). The return value will be null
if the column doesn't exist.

An error will occur if the database is undefined or if there is no
\actionopt{key} or \actionopt{column} setting or if both are
provided.  This action has one optional setting: \actionopt{name}
(which should be a single name), and one required setting: either
\actionopt{key} or \actionopt{column} (but not both). Other settings
are ignored.

\actiondef{select-row}
Selects a row and sets the \gls{dtlcurrentrow} token register for
use with actions (such as \action{row-aggregate}) or commands (such
as those described in \sectionref{sec:currentrow}).

\begin{information}
If the \idx{current-row} has already been selected (that is,
\gls{dtlcurrentrow} and \gls{dtldbname} have already been set), for
example within the hooks used by \gls{DTLdisplaydb}, then you can
instead use the \action{current-row-values} action to access
information in the current row.
\end{information}

If you know the row index, you can use the \actionopt{row} setting
to select that row. This will internally use \gls{dtlgetrow}.

If you don't know the row index, but want to find the first row that
exactly matches a particular value for a specific column then you
need to use \actionopt{value} (or \actionopt{expand-value} or
\actionopt{expand-once-value}) for the required value and either
\actionopt{column} or \actionopt{key} (but not both) to identify the
column. In this case, the action will be similar to
\gls{dtlgetrowforvalue} to find the first row that exactly matches
the given value, but it won't trigger an error if no match is found. 

If you want to match by a more complex test, such as a regular
expression, use the \action{find} action instead with
\actionfindopt{function} or \actionfindopt{inline} and
\actionfindoptval{select}{true} set in the action \actionopt{options}.

\begin{important}
Note that \actionoptvalm{value}{} indicates an empty (not null)
value. If you want to find
the first row that doesn't have a particular column set, you can
instead use the \action{find} action and search for a null value.
\end{important}

In either case, the \actionopt{name} setting (which should be a
single name) may be used to identify the database (which must
exist). It omitted, the default is used. You can't have both
\actionopt{row} and a column identifier (\actionopt{column} or
\actionopt{key}) set.

\begin{information}
As with the underlying \gls{dtlgetrowforvalue}, this action (when
matching a column) is primarily intended to work with a column which
has unique values, such as an identification number. If you require
a match on multiple columns or a regular expression match, you will 
need to iterate over the database or use the \action{find} action.
\end{information}

If successful, this action will set the token registers
\gls{dtlcurrentrow}, \gls{dtlbeforerow} and \gls{dtlafterrow}, and
also the placeholders \gls{dtldbname} (expands to the database name), 
\gls{dtlrownum} (the row index) and \gls{dtlcolumnnum} (the column
index). If unsuccessful, \gls{dtlrownum} will be zero.

No return values will be set if unsuccessful, otherwise
the primary return value is the row index (which will be the same as
\gls{dtlrownum}), and the secondary return values will be the value of
each entry found in the \idx{current-row} with the return property key the
same as the column key.

The later \exampleref{ex:rowaggregates} uses
\gls{dtlgetrowforvalue} to select a row with a particular value
from the \qt{marks} database (see \sectionref{sec:marks}).
\mExampleref{ex:selectrow} replaces 
this cumbersome command with the \action{select-row}
action. First the row selection:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptval{name}{marks},
  \actionoptval{key}{StudentNo},
  \actionoptvalm{value}{105987}
 }\marg{\action{select-row}}
\codepar
Student \gls{DTLuse}\marg{Forename} \gls{DTLuse}\marg{Surname}
(105987).
\end{codebox}
Then calculate the mean for the columns \optfmt{Assign1},
\optfmt{Assign2} and \optfmt{Assign3}. This can be done by column
index, for example, \actionoptvalm{columns}{4-6} or by column key,
for example, \actionoptvalm{keys}{Assign1-Assign3}. Since
\optfmt{Assign3} is the last column of the database, an open-ended
range may be used:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{keys}{Assign1-},
  \actionoptvalm{options}{mean},
  \actionoptvalm{datum}{\actiondatumoptval{round}{1}}
}\marg{\action{current-row-aggregate}}
\codepar
Average mark: \gls{DTLuse}\marg{mean}.
\codepar
(Actual value: \gls{DTLget}\oarg{mean}\marg{\cmd{theMean}}
\gls{DTLdatumvalue}\marg{\cmd{theMean}}.)
\end{codebox}
Bear in mind that the second \gls{DTLaction} will clear the return
values from the first, so if you need to continue referencing those
values, take care to scope the second instance.

\begin{resultbox}
\createexample*
 [label={ex:selectrow},
  tag={marks},
  title={Select row action},
  description={Example document demonstrating select row action to
select a row by a unique value}
 ]
{%
\comment{sample CSV file:}%
\exfile{studentmarks.csv}\markscsv
\codepar
\cmd{usepackage}\marg{datatool}\nl
\codepar
\comment{Load data from studentmarks.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
Row selection:
\codepar
\gls{DTLaction}\oarg{\nlsp
  \actionoptval{name}{marks},\nlsp
  \actionoptval{key}{StudentNo},\nlsp
  \actionoptvalm{value}{105987}\nl
 }\marg{\action{select-row}}
\codepar
Student \gls{DTLuse}\marg{Forename} \gls{DTLuse}\marg{Surname}
(105987).
\codepar
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{keys}{Assign1-},\nlsp
  \actionoptvalm{options}{mean},\nlsp
  \actionoptvalm{datum}{\actiondatumoptval{round}{1}}\nl
}\marg{\action{current-row-aggregate}}
\codepar
Average mark: \gls{DTLuse}\marg{mean}.\nl
\codepar
(Actual value: \gls{DTLget}\oarg{mean}\marg{\cmd{theMean}} \gls{DTLdatumvalue}\marg{\cmd{theMean}}.)
}
\end{resultbox}

\actiondef{current-row-values}
If the \idx{current-row} has already been selected (that is,
\gls{dtlcurrentrow} and \gls{dtldbname} have already been set), for
example within the hooks used by \gls{DTLdisplaydb} or with
\gls{dtlgetrow}, then the
\action{current-row-values} action can be used to access values
within the \idx{current-row} rather than using the more cumbersome
\gls{dtlgetentryfromcurrentrow} for each required column.

For example, to fetch all values in the \idx{current-row} and use the
values from the \qt{Forename} and \qt{Surname} columns:
\begin{codebox}
\gls{DTLaction}\marg{\action{current-row-values}}
Name: \gls{DTLuse}\marg{Forename} \gls{DTLuse}\marg{Surname}.
\end{codebox}
To store the values in placeholder commands with \gls{DTLget}:
\begin{codebox}
\gls{DTLaction}\marg{\action{current-row-values}}
\gls{DTLget}\oarg{Forename}\marg{\cmd{Forename}}
\gls{DTLget}\oarg{Surname}\marg{\cmd{Surname}}
\end{codebox}
Alternatively, with the \actionopt{return} setting:
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptvalm{return}{
   \cmd{Forename}=Forename,
   \cmd{Surname}=Surname
 }
}\marg{\action{current-row-values}}
\end{codebox}

There are no required settings. If you only want the values from a
subset of columns you can identify those columns with
\actionopt{columns} and\slash or \actionopt{keys}.
Otherwise all columns will be assumed.
A warning will occur if the \actionopt{name} option is set as the
name is expected to be in \gls{dtldbname}. An error will occur if
\gls{dtldbname} hasn't been set.
All other settings are ignored.

For example, the following collects the values for the columns with
the labels \qt{Title}, \qt{Price}, \qt{Quantity}, \qt{Total} and the
columns with the indexes 1 and 2:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{keys}{Title,Price,Quantity,Total},
  \actionoptvalm{columns}{1,2}
}\marg{\action{current-row-values}}
\end{codebox}

The primary return value is the number of values collected. This may
be less than the total number of columns in the database or less
than the list of supplied keys if there are missing columns in the
\idx{current-row}. The secondary return properties are the column keys and
the return value the corresponding element (which may have been
parsed and converted into a \idx{datumitem} if the \actionopt{datum}
option was set, or if conversion automatically occurred with
\opt{store-datum} when the database was created).

\Exampleref{ex:displaydbpostrow} uses the
\action{current-row-values} action to fetch row entries within the
post-row hook of \gls{DTLdisplaydb} to append a total column to the
table.

\subsubsection{Aggregates}
\label{sec:dbstatsactionnames}

\actiondef{aggregate}
Aggregates numerical data in one or two columns of the identified
database. Either the \actionopt{key} or \actionopt{column} must be
set (but not both) to identify the required column. The
\actionopt{key2} or \actionopt{column2} values may also be set (but
not both) if a second column is also required.
Optional settings are: \actionopt{name} (which should be a single
name) and \actionopt{options}, which should be a comma-separated list of
the aggregate functions to apply. The aggregate functions are as
follows:
\begin{itemize}

\item \optfmt{sum}: sum all numeric items in the given column.
The return value will be in the \optfmt{sum} property for the first column and,
if applicable, \optfmt{sum2} for the second column.

\item \optfmt{mean}: calculates the mean (average) of all numeric
items in the given column.  The return value will be in the
\optfmt{mean} property for the first column and, if applicable,
\optfmt{mean2} for the second column. This function automatically
implements the \optfmt{sum} function, since the total is required to
calculate the mean.

\item \optfmt{variance}: calculates the variance of all numeric
items in the given column.  The return value will be in the
\optfmt{variance} property for the first column and, if applicable,
\optfmt{variance2} for the second column. This function
automatically implements the \optfmt{mean} function, since the mean
is required to calculate the variance.

\item \optfmt{sd}: calculates the standard deviation of all numeric
items in the given column.  The return value will be in the \optfmt{sd}
property for the first column and, if applicable, \optfmt{sd2} for the second
column. This function automatically implements the \optfmt{variance}
function, since the variance is required to calculate the standard
deviation.

\item \optfmt{min}: calculates the minimum of all numeric items in
the given column.  The return value will be in the \optfmt{min}
property for the first column and, if applicable, \optfmt{min2} for
the second column.

\item \optfmt{max}: calculates the maximum of all numeric items in
the given column.  The return value will be in the \optfmt{max}
property for the first column and, if applicable, \optfmt{max2} for the second
column.

\end{itemize}
If \actionopt{options} is empty, the only functions will be to count
and gather numeric items in a sequence.

The primary return value is the total number of numeric items in the first
column. (Non-numeric items are skipped.) This will typically be the
same as the row count, unless there are null or non-numeric items. 

\begin{information}
Return values that are numeric will be \idxpl{plainnumber}.
This is different to most of the aggregate commands described in
\sectionref{sec:dbarith}, such as \gls{DTLmaxforkeys}, that return
\idxpl{formattednumber}.
\end{information}

The secondary return value properties are:
\begin{itemize}
\item \optfmt{name}: the database name.

\item \optfmt{column}: the index of the first column.

\item \optfmt{count}: the number of numeric items in the first
column. This is the same as the primary return value.

\item \optfmt{seq}: the sequence of numeric items found in the first
column. If you use \code{\gls{DTLget}\oarg{seq}\marg{\meta{cs}}}
(or \actionoptvalm{return}{\meta{cs}\dequals seq})
then \meta{cs} will be in the form of a \styfmt{l3seq} sequence variable.

\item \optfmt{min}: if \optfmt{min} was included in the
\actionopt{options} list, then this property will be set to the
minimum value in the first column.

\item \optfmt{max}: if \optfmt{max} was included in the
\actionopt{options} list, then this property will be set to the
maximum value in the first column.

\item \optfmt{sum}: if \optfmt{sum} was included in the
\actionopt{options} list (or implied by a function that requires the
sum), then this property will be set to the
sum of all numeric values in the first column.

\item \optfmt{mean}: if \optfmt{mean} was included in the
\actionopt{options} list (or implied by a function that requires the
mean), then this property will be set to the
mean of all numeric values in the first column.

\item \optfmt{variance}: if \optfmt{variance} was included in the
\actionopt{options} list (or implied by a function that requires the
variance), then this property will be set to the
variance of all numeric values in the first column.

\item \optfmt{sd}: if \optfmt{sd} was included in the
\actionopt{options} list, then this property will be set to the
standard deviation of all numeric values in the first column.

\end{itemize}
Additionally, if \actionopt{key2} or \actionopt{column2} have been
set:
\begin{itemize}
\item \optfmt{column2}: the index of the second column.

\item \optfmt{count2}: the number of numeric items in the second
column.

\item \optfmt{seq2}: the sequence of numeric items found in the second
column. If you use \code{\gls{DTLget}\oarg{seq2}\marg{\meta{cs}}}
(or \actionoptvalm{return}{\meta{cs}\dequals seq2})
then \meta{cs} will be in the form of a \styfmt{l3seq} sequence variable.

\item \optfmt{min2}: if \optfmt{min} was included in the
\actionopt{options} list, then this property will be set to the
minimum value in the second column.

\item \optfmt{max2}: if \optfmt{max} was included in the
\actionopt{options} list, then this property will be set to the
maximum value in the second column.

\item \optfmt{sum2}: if \optfmt{sum} was included in the
\actionopt{options} list (or implied by a function that requires the
sum), then this property will be set to the
sum of all numeric values in the second column.

\item \optfmt{mean2}: if \optfmt{mean} was included in the
\actionopt{options} list (or implied by a function that requires the
mean), then this property will be set to the
mean of all numeric values in the second column.

\item \optfmt{variance2}: if \optfmt{variance} was included in the
\actionopt{options} list (or implied by a function that requires the
variance), then this property will be set to the
variance of all numeric values in the second column.

\item \optfmt{sd2}: if \optfmt{sd} was included in the
\actionopt{options} list, then this property will be set to the
standard deviation of all numeric values in the second column.
\end{itemize}

\actiondef{row-aggregate}
Calculate aggregates for the current iteration of \gls+{DTLmapdata}.
(See \exampleref{ex:mapdataedit}.)

\actiondef{current-row-aggregate}
Calculate aggregates for the \idx{current-row} stored in
\gls{dtlcurrentrow}.

The actions \action{row-aggregate} and
\action{current-row-aggregate} essentially perform the same
function. The difference between them is that \action{row-aggregate}
is for use within \gls{DTLmapdata} and
\action{current-row-aggregate} is for use within \gls{DTLforeach} or
after selecting a \idx{current-row} with the \action{select-row} action or
with commands like \gls{dtlgetrow}.

In either case, the database name should already be set in the
\gls{dtldbname} placeholder, so the \actionopt{name} option will
trigger a warning, if set, and an empty \gls{dtldbname} will trigger an
error. These actions are similar to \action{aggregate} but they
aggregate items in the columns of the \idx{current-row} that have a numeric value.

By default all columns in the \idx{current-row} will be checked, but you
can restrict the function to a subset of columns with the
\actionopt{columns} and\slash or \actionopt{keys} options.

The \actionopt{options} setting is as for the \action{aggregate}
action. The primary return value is the number of numeric columns
contributing to the aggregates. The secondary return value
properties are:
\begin{itemize}
\item \optfmt{name}: the database name (same as \gls{dtldbname}).
If any unexpected results occur, check this return value matches the
expected name.

\item \optfmt{row}: the row index (same as the value of
\gls{dtlrownum}).
If any unexpected results occur, check this return value matches the
expected row index.

\item \optfmt{columns}: the list of indexes of all column in the subset
or empty if no subset specified.

\item \optfmt{count}: the number of numeric items in the subset.
This is the same as the primary return value.

\item \optfmt{seq}: the sequence of numeric items found in the
subset. If you use \code{\gls{DTLget}\oarg{seq}\marg{\meta{cs}}}
(or \actionoptvalm{return}{\meta{cs}\dequals seq})
then \meta{cs} will be in the form of a \styfmt{l3seq} sequence variable.

\item \optfmt{min}: if \optfmt{min} was included in the
\actionopt{options} list, then this property will be set to the
minimum value in the subset.

\item \optfmt{max}: if \optfmt{max} was included in the
\actionopt{options} list, then this property will be set to the
maximum value in the subset.

\item \optfmt{sum}: if \optfmt{sum} was included in the
\actionopt{options} list (or implied by a function that requires the
sum), then this property will be set to the
sum of all numeric values in the subset.

\item \optfmt{mean}: if \optfmt{mean} was included in the
\actionopt{options} list (or implied by a function that requires the
mean), then this property will be set to the
mean of all numeric values in the subset.

\item \optfmt{variance}: if \optfmt{variance} was included in the
\actionopt{options} list (or implied by a function that requires the
variance), then this property will be set to the
variance of all numeric values in the subset.

\item \optfmt{sd}: if \optfmt{sd} was included in the
\actionopt{options} list, then this property will be set to the
standard deviation of all numeric values in the subset.

\end{itemize}

\mExampleref{ex:rowaggregates} uses the \qt{marks} database (see
\sectionref{sec:marks}) and calculates the average marks for each
student within \gls{DTLmapdata}:
\begin{codebox}
\gls{DTLmapdata}\oarg{\actionoptval{name}{marks}}\marg{
 \gls{DTLmapget}\marg{\mapgetoptval{key}{Forename}} \gls{DTLmapget}\marg{\mapgetoptval{key}{Surname}}
 average marks:
 \gls{DTLaction}\oarg{
   \actionoptvalm{columns}{4-},
   \actionoptvalm{options}{mean}
 }\marg{\action{row-aggregate}}
 \gls{DTLuse}\marg{mean}.\codepar
}
\end{codebox}
For comparison, the example also uses \gls{DTLforeach}:
\begin{codebox}
\gls{DTLforeach}\marg{marks}
\marg{\cmd{Forename}=Forename,\cmd{Surname}=Surname}
\marg{
 \cmd{Forename}\gls{cs.space}\cmd{Surname}\gls{cs.space} average mark:
 \gls{DTLaction}\oarg{
   \actionoptvalm{columns}{4-},
   \actionoptvalm{options}{mean}
 }\marg{\action{current-row-aggregate}}
 \gls{DTLuse}\marg{mean}.\codepar
}
\end{codebox}
And selects a particular row:
\begin{codebox}
\gls{dtlgetrowforvalue}\marg{marks}\marg{\gls{dtlcolumnindex}\marg{marks}\marg{StudentNo}}\marg{105987}
Student 105987 average mark:
\gls{DTLaction}\oarg{
  \actionoptvalm{columns}{4-},
  \actionoptvalm{options}{mean}
}\marg{\action{current-row-aggregate}}
\gls{DTLuse}\marg{mean}.
\end{codebox}
The rather cumbersome \gls{dtlgetrowforvalue} can be replaced with the \action{select-row}
action, as in the earlier \exampleref{ex:selectrow}.

\begin{resultbox}
\createexample*
 [label={ex:rowaggregates},
  tag={marks},
  title={Row aggregate actions},
  description={Example document demonstrating row aggregate and
  current row aggregate actions}
 ]
{%
\comment{sample CSV file:}%
\exfile{studentmarks.csv}\markscsv
\codepar
\cmd{usepackage}\marg{datatool}\nl
\codepar
\comment{Load data from studentmarks.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
Map data:
\codepar
\gls{DTLmapdata}\oarg{\actionoptval{name}{marks}}\marg{\nlsp
 \gls{DTLmapget}\marg{\mapgetoptval{key}{Forename}}
 \gls{DTLmapget}\marg{\mapgetoptval{key}{Surname}}
 average marks:\nlsp
 \gls{DTLaction}\oarg{\nldbsp
   \actionoptvalm{columns}{4-},\nldbsp
   \actionoptvalm{options}{mean}\nldbsp
 }\marg{\action{row-aggregate}}\nlsp
 \gls{DTLuse}\marg{mean}.
 \codepar
}
\codepar
For each:
\codepar
\gls{DTLforeach}\marg{marks}\marg{\cmd{Forename}=Forename,\cmd{Surname}=Surname}\marg{\nlsp
 \cmd{Forename}\gls{cs.space}\cmd{Surname}\gls{cs.space}\nlsp
 average mark:\nlsp
 \gls{DTLaction}\oarg{\nldbsp
   \actionoptvalm{columns}{4-},\nldbsp
   \actionoptvalm{options}{mean}\nldbsp
 }\marg{\action{current-row-aggregate}}\nlsp
 \gls{DTLuse}\marg{mean}.
 \codepar
}
\codepar
Row selection:
\codepar
\gls{dtlgetrowforvalue}\marg{marks}\marg{\gls{dtlcolumnindex}\marg{marks}\marg{StudentNo}}\marg{105987}\nl
Student 105987 average mark:\nl
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{columns}{4-},\nlsp
  \actionoptvalm{options}{mean}\nl
}\marg{\action{current-row-aggregate}}\nl
\gls{DTLuse}\marg{mean}.
}
\end{resultbox}

\subsubsection{Tabulation}
\label{sec:dbdisplayactionnames}

\actiondef{display}
This action may be used to display a database using the same
underlying function as \gls{DTLdisplaydb*}. This action has optional
settings: \actionopt{name} (which should be a single name) and
\actionopt{options} to pass any options to \gls{DTLdisplaydb*}.
Other settings are ignored.

There's no primary return value, but there are secondary return
values that can be accessed with the properties: \optfmt{name} (the
database name), \optfmt{columns} (the number of columns displayed),
and \optfmt{rows} (the number of rows displayed).

For example:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{options}{\displayoptvalm{omit-columns}{1,3}}}\marg{\action{display}}
\end{compactcodebox}
This is essentially the same as:
\begin{compactcodebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{omit-columns}{1,3}}\margm{default-name}
\end{compactcodebox}
where \meta{default-name} is obtained from the \opt{default-name} option.
The action has the advantage over \gls{DTLdisplaydb} as you can use
the return values to find out how many columns or rows were displayed (which
may not necessarily be the same as the column count or row count).

\actiondef{display-long}
This is similar to the \action{display} action, but it uses the
underlying function of \gls{DTLdisplaylongdb}, which uses
\env{longtable} instead of \env{tabular}. This action has optional
settings: \actionopt{name} (which should be a single name) and
\actionopt{options} to pass any options to \gls{DTLdisplaylongdb}.
Other settings are ignored.

There's no primary return value, but there are secondary return
values that can be accessed with the properties: \optfmt{name} (the
database name), \optfmt{columns} (the number of columns displayed),
and \optfmt{rows} (the number of rows displayed).

\subsubsection{Modifying a Database}
\label{sec:dbmodactionnames}

\actiondef{sort}
Sorts a database using \gls{DTLsortdata}. This action has optional
settings: \actionopt{name} (the database name), and
\actionopt{options} (the options to pass to the optional argument of
\gls{DTLsortdata}). There is one required settings:
\actionopt{assign}, which should be the criteria to pass in the
final argument of \gls{DTLsortdata}.

The primary return value should be equal to the number of rows of
the database if no errors occurred. The secondary return values
can be accessed with the properties: \optfmt{name} (the database
name, which will always be set), \optfmt{columns} (the number of
columns in the database after sorting) and \optfmt{rows} (the number
of rows in the database). The column count of the database may
increase if the options include instructions to add the sort or
group information to the database. See \sectionref{sec:DTLsortdata}
for further details.

\subsubsection{Other}
\label{sec:otheractionnames}

The \sty{databar} package provides the \action{bar-chart}
and \action{multibar-chart} actions.
The \sty{datapie} package provides the \action{pie-chart} action.
The \sty{dataplot} package provides the \action{plot} action.

\subsection{Action Settings}
\label{sec:actionopts}

\Idx{action} settings may only be used in the optional argument of
\gls{DTLaction} and can't be used in \gls{DTLsetup}. They are reset
to their default values by \gls{DTLaction} before the optional
argument is processed. Settings that aren't required by the given
\idx{action} are usually ignored, but an unrequired setting may
occasionally generate an error or warning if it's likely that the setting may
accidentally be used instead of the correct one (for example,
setting \actionopt{column} when the column can only be identified
with \actionopt{key}).

\optiondef{action.name}
The database name or (where supported) the list of names. 
If omitted, the value of the general
\opt{default-name} option is used. For example:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{name}{mydata}}\marg{\action{new}}
\end{codebox}
Some actions don't permit the database name to be specified as it's
expected to be provided by \gls{dtldbname} (such as
\action{current-row-aggregate}). Actions that require a
single name will take the first from the list and ignore the rest of
the list.

\optiondef{action.key}
The unique column key. This must be set to a non-empty value for an
action that allows a column reference by ID, except in the case of
actions that use \actionopt{keys} for a list of keys. Typically, you
won't be able to use both \actionopt{key} and \actionopt{column}.

\optiondef{action.key2}
If an action requires a second column reference, this should be used to
reference the second column by its unique ID. This is intended for
use by actions that require at most two columns, not for actions
that use \actionopt{keys} for a list of keys. Typically, you
won't be able to use both \actionopt{key2} and \actionopt{column2}.

\optiondef{action.column}
The column index. This must be set to a positive number for an
action that allows a column reference by index, except in the case of
actions that use \actionopt{columns} for a list of column indexes.

\optiondef{action.column2}
If an action requires two column references, this should be used to
reference the second column by its index. This is intended for
use by actions that require at most two columns, not for actions
that use \actionopt{columns} for a list of column indexes.

\optiondef{action.columns}
If an action allows an arbitrary number of column references, 
the \actionopt{columns} option can be used to reference the required
columns by their index in a comma-separated list.

The list may include ranges in the form
\code{\meta{$n_1$}-\meta{$n_2$}}, where \meta{$n_1$} is the start of
the range and \meta{$n_2$} is the end. If \meta{$n_1$} is omitted
then 1 is assumed and if \meta{$n_2$} is omitted, the last column is
assumed. For example, \actionoptvalm{columns}{-4} is equivalent to 
\actionoptvalm{columns}{1-4} and
\actionoptvalm{columns}{1,3-5} indicates columns 1, 3, 4, and~5.
Where a range with a start and end value is provided, the start
value must be less than or equal to the end value.

\optiondef{action.keys}
If an action allows an arbitrary number of column references, the
\actionopt{keys} option can be used to reference the required
columns by their key in a comma-separated list. Typically, an action
that allows a list of columns may allow both \actionopt{keys} and
\actionopt{columns} and will merge the subsets. As with
\actionopt{columns}, the list may include ranges in the form
\code{\meta{key1}-\meta{key2}}, where \meta{key1} is the start of
the range and \meta{key2} is the end.  As with \actionopt{columns},
if the start range is omitted, the first column is assumed, and if
the end range is omitted, the last column is assumed. For example,
the \qt{marks} database (see \sectionref{sec:marks}) may have
\code{\actionoptvalm{keys}{Assign1-}} (as in
\exampleref{ex:mapdataedit}).

Unlike \actionopt{columns}, if the
associated column index of \meta{key1} is greater that the
associated column index of \meta{key2}, the start and end references
will be switched round.

\optiondef{action.row}
The row index. This must be set to a positive number for an
action that requires a row reference by index.

\begin{information}
The row index is a reference to the internal data and is unrelated
to references in the original source (such as line numbers in a
\idx{CSV} file).
\end{information}

\optiondef{action.row2}
The second row index. This must be set to a positive number for an
action that requires a second row reference by index.

\optiondef{action.assign}
A \keyval\ list of assignments. For example, this can be used in the
\action{new-row} action to assign values to specific columns
according to the column key, in this case the \meta{key} part in
\keyval\ is the column key. In the case of actions such as
\action{pie-chart} and \action{bar-chart}, each \meta{key} part is 
a placeholder command.

\optiondef{action.options}
A comma-separated list or \keyval\ list used by certain actions.
In the case of the \action{display} action, this provides the option
list to pass to \gls{DTLdisplaydb*}. For example:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{options}{\displayoptvalm{only-keys}{Product,Price}}}\marg{\action{display}}
\end{compactcodebox}
This is equivalent to:
\begin{compactcodebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{only-keys}{Product,Price}}\margm{default-name}
\end{compactcodebox}
Whereas with the \action{aggregate} action, \actionopt{options}
provides a list of required aggregate functions.

\optiondef{action.value}
A value needed by certain actions.
For example, in the case of the \action{new-entry} action, the
\actionopt{value} setting
is the value to add to the database:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Price},\actionoptval{value}{\gls{cs.dollar}1.23}}\marg{\action{new-entry}}
\end{compactcodebox}
This is equivalent to:
\begin{compactcodebox}
\gls{DTLnewdbentry}\margm{default-name}\marg{Price}\marg{\gls{cs.dollar}1.23}
\end{compactcodebox}
where \meta{default-name} is obtained from the \opt{default-name} setting.

\begin{important}
If \actionopt{value}, \actionopt{expand-value} or
\actionopt{expand-once-value} occur in the same option list then
they will override each other. The last one in the list will take
precedence.
\end{important}

\optiondef{action.expand-value}
This is equivalent to using the \actionopt{value} key with
\meta{text} fully expanded.

\optiondef{action.expand-once-value}
This is equivalent to using the \actionopt{value} key with
\meta{text} expanded once. This is the best setting to use if you
have a placeholder command or token list. For example,
\begin{codebox}
\cmd{newcommand}\marg{\cmd{price}}\marg{\gls{cs.dollar}1.23}
\gls{DTLaction}\oarg{
 \actionoptval{key}{Price},
 \actionoptval{expand-once-value}{\cmd{price}}
}\marg{\action{new-entry}}
\end{codebox}

\optiondef{action.type}
The data type (see \sectionref{sec:datatypes}), where the value may
be one of: \optfmt{string}, \optfmt{integer} (or \optfmt{int}),
\optfmt{decimal} (or \optfmt{real}), or \optfmt{currency}.

\optiondef{action.return}
Secondary (but not primary) values can also be obtained with the
\actionopt{return} setting, which should provide a comma-separated
list of \code{\meta{cs}\dequals\meta{property}} assignments. Each
listed control sequence \meta{cs} will be defined to the value of
the secondary property identified by \meta{property}. This may be
used instead of, or in addition to, using \gls{DTLget}.

\optiondef{action.datum}
This setting governs whether or not secondary return values should
be formatted as \idxpl+{datumitem}. It's primarily intended as a
shortcut for actions such as \action{aggregate} to avoid the
cumbersome use of \gls{dtlround} and \gls{DTLdecimaltolocale} to
format the results.

\begin{important}
The \actionopt{datum} setting doesn't affect primary return values.
However, since the primary return value is often (but not always)
duplicated in the secondary set, the formatted value can be obtained
from the applicable secondary property.  Complex secondary values
that have their own markup, such as the \optfmt{seq} return property
for the \action{aggregate} action are also not affected. 
\end{important}

Available values are:
\actionoptval{datum}{false} (don't format secondary return values),
\actionoptval{datum}{true} (format secondary return values without
changing the \actionopt{datum} settings) or
\actionoptvalm{datum}{\keyvallist} to enable with the given subset
of \actionopt{datum} settings. For example,
\code{\actionoptvalm{datum}{\actiondatumoptval{round}{2}\dcomma
\actiondatumoptval{currency}{\gls{cs.dollar}}}}. Note that 
\actionoptval{datum}{true} is essentially the same as
\actionoptvalm{datum}{}.

\begin{information}
The original numeric value can still be obtained with a combination
of \gls{DTLget} to fetch the value as a \idx{datumcs} and
\gls{DTLdatumvalue} to extract the \idx{plainnumber} (see
\exampleref{ex:selectrow}). With
\gls{DTLuse}, the \idx{formattednumber} will be inserted into the
document.   There's little advantage in using \actionopt{datum}
with text-only return values.
\end{information}

If \actionopt{datum} is not set to \optfmt{false}, then the secondary
value format (in the string part of the \idx{datumitem}) can be
adjusted according to the following options, which may be set in
\actionoptvalm{datum}{\keyvallist}.  However, in the case of
secondary return values that simply provide elements from the
database (such as those from the \action{select-row} action), the
return values will be \idxpl{datumitem} (obtained using
\gls{DTLparse}), but won't be governed by the options listed below.

\optiondef*{action.datum.locale-integer}
If this boolean option is \optfmt{true}, then the string part of
secondary return values that are known to always be integers (if
set), such as a column or row index, will be formatted 
according to the current localisation setting.

\optiondef*{action.datum.locale-decimal}
If this boolean option is \optfmt{true}, then the string part of
calculated numeric \idxpl{datumitem} (such as \optfmt{sum} or
\optfmt{mean}) will formatted according to the current
localisation setting. If this option is \code{false}, the string
part will use a \idx{plainnumber} but it will still be affected by
the \actiondatumopt{currency} and \actiondatumopt{round} options. 
Note that the \optfmt{sum} return property is always
considered a decimal in this context, even if only integer values
were summed.

\optiondef*{action.datum.currency}
This option only governs decimal
return values that have been calculated (such as the sum or mean in
the \action{aggregate} action). Available option values:
\begin{itemize}
\item \optfmt{false}: no currency symbol is inserted;
\item \optfmt{match}: the matching currency symbol will be inserted
if one was found in the original data;
\item \optfmt{default}: the default currency symbol will be inserted
before all calculated decimal values (regardless of whether or not
the original values were identified as currency);
\item \meta{symbol}: the given currency symbol will be inserted
before all calculated decimal values (regardless of whether or not
the original values were identified as currency).
\end{itemize}

\optiondef*{action.datum.round}
This option only governs decimal return values that have been
calculated (such as the sum or mean in the \action{aggregate} action) and
indicates whether the value should be rounded. The keyword
\optfmt{false} or a negative value may be used to prevent rounding.
Otherwise the value should be set to a non-negative number
indicating the required number of decimal places.

\mExampleref{ex:actiondatum} uses the \qt{pricelist} database (see
\sectionref{sec:pricelistdb}), which has an integer column labelled
\qt{Quantity} and a currency column labelled \qt{Price}. The
aggregates for both columns can be obtained with the
\action{aggregate} action:
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptval{key}{Quantity},
 \actionoptval{key2}{Price},
 \actionoptvalm{options}{sd,min,max}
}\marg{\action{aggregate}}
\codepar
Quantity column index: \gls{DTLuse}\marg{column}.
Total quantity: \gls{DTLuse}\marg{sum}.
Average quantity: \gls{DTLuse}\marg{mean}.
Quantity standard deviation: \gls{DTLuse}\marg{sd}.
Minimum quantity: \gls{DTLuse}\marg{min}.
Maximum quantity: \gls{DTLuse}\marg{max}.
\codepar
Price column index: \gls{DTLuse}\marg{column2}.
Total price: \gls{DTLuse}\marg{sum2}.
Average price: \gls{DTLuse}\marg{mean2}.
Price standard deviation: \gls{DTLuse}\marg{sd2}.
Minimum price: \gls{DTLuse}\marg{min2}.
Maximum price: \gls{DTLuse}\marg{max2}.
\end{codebox}
This displays all the statistics as \idxpl{plainnumber}
(\exampleref{ex:actiondatum}).
Using \actionopt{datum} will produce \idxpl{formattednumber} for the
calculated values (but not for the column index):
\begin{codebox}
\gls{DTLaction}\oarg{
 \strong{\actionoptvalm{datum}{\actiondatumoptval{round}{2}}},
 \actionoptval{key}{Quantity},
 \actionoptval{key2}{Price},
 \actionoptvalm{options}{sd,min,max}
}\marg{\action{aggregate}}
\end{codebox}
Note that this will convert the total, minimum and maximum
quantities to decimals rounded to 2 decimal places (but not the
column index). The actual
numeric values can be obtained with \gls{DTLget} and
\gls{DTLdatumvalue}:
\begin{codebox}
Quantity column index: \gls{DTLuse}\marg{column}.
Total quantity: \gls{DTLuse}\marg{sum}
(\gls{DTLget}\oarg{sum}\marg{\cmd{theTotal}}\gls{DTLdatumvalue}\marg{\cmd{theTotal}}).
Average quantity: \gls{DTLuse}\marg{mean}.
Quantity standard deviation: \gls{DTLuse}\marg{sd}.
Minimum quantity: \gls{DTLuse}\marg{min}
(\gls{DTLget}\oarg{min}\marg{\cmd{theMin}}\gls{DTLdatumvalue}\marg{\cmd{theMin}}).
Maximum quantity: \gls{DTLuse}\marg{max}
(\gls{DTLget}\oarg{max}\marg{\cmd{theMax}}\gls{DTLdatumvalue}\marg{\cmd{theMax}}).
\end{codebox}

Note the difference if a currency symbol is enforced:
\begin{codebox}
\gls{DTLaction}\oarg{
 \strong{\actionoptvalm{datum}{\actiondatumoptval{round}{2},\actiondatumopt{currency}}},
 \actionoptval{key}{Quantity},
 \actionoptval{key2}{Price},
 \actionoptvalm{options}{sd,min,max}
}\marg{\action{aggregate}}
\end{codebox}
This converts all the quantity aggregate values to currency, which
is inappropriate in this case.

\begin{resultbox}
\createexample*[label={ex:actiondatum},
  tag={pricelist},
  title={Automatically Formatting Values Calculated by Actions},
  description={Example document that demonstrates the datum action
setting}
]
{%
\cmd{usepackage}\marg{datatool}\nl
\pricelistdb
}
{
\cmd{section}\marg{Default datum=false}
 \codepar
\gls{DTLaction}\oarg{\nlsp
 \actionoptval{key}{Quantity},\nlsp
 \actionoptval{key2}{Price},\nlsp
 \actionoptvalm{options}{sd,min,max}\nl
}\marg{\action{aggregate}}
\codepar
Quantity column index: \gls{DTLuse}\marg{column}.\nl
Total quantity: \gls{DTLuse}\marg{sum}.\nl
Average quantity: \gls{DTLuse}\marg{mean}.\nl
Quantity standard deviation: \gls{DTLuse}\marg{sd}.\nl
Minimum quantity: \gls{DTLuse}\marg{min}.\nl
Maximum quantity: \gls{DTLuse}\marg{max}.
\codepar
Price column index: \gls{DTLuse}\marg{column2}.\nl
Total price: \gls{DTLuse}\marg{sum2}.\nl
Average price: \gls{DTLuse}\marg{mean2}.\nl
Price standard deviation: \gls{DTLuse}\marg{sd2}.\nl
Minimum price: \gls{DTLuse}\marg{min2}.\nl
Maximum price: \gls{DTLuse}\marg{max2}.
\codepar
\cmd{section}\marg{datum=\{round=2\}}
\codepar
\gls{DTLaction}\oarg{\nlsp
 \actionoptvalm{datum}{\actiondatumoptval{round}{2}},\nlsp
 \actionoptval{key}{Quantity},\nlsp
 \actionoptval{key2}{Price},\nlsp
 \actionoptvalm{options}{sd,min,max}\nl
}\marg{\action{aggregate}}
\codepar
Quantity column index: \gls{DTLuse}\marg{column}.\nl
Total quantity: \gls{DTLuse}\marg{sum}\nl
(\gls{DTLget}\oarg{sum}\marg{\cmd{theTotal}}\gls{DTLdatumvalue}\marg{\cmd{theTotal}}).\nl
Average quantity: \gls{DTLuse}\marg{mean}.\nl
Quantity standard deviation: \gls{DTLuse}\marg{sd}.\nl
Minimum quantity: \gls{DTLuse}\marg{min}\nl
(\gls{DTLget}\oarg{min}\marg{\cmd{theMin}}\gls{DTLdatumvalue}\marg{\cmd{theMin}}).\nl
Maximum quantity: \gls{DTLuse}\marg{max}\nl
(\gls{DTLget}\oarg{max}\marg{\cmd{theMax}}\gls{DTLdatumvalue}\marg{\cmd{theMax}}).
\codepar
Price column index: \gls{DTLuse}\marg{column2}.\nl
Total price: \gls{DTLuse}\marg{sum2}.\nl
Average price: \gls{DTLuse}\marg{mean2}.\nl
Price standard deviation: \gls{DTLuse}\marg{sd2}.\nl
Minimum price: \gls{DTLuse}\marg{min2}.\nl
Maximum price: \gls{DTLuse}\marg{max2}.
\codepar
\cmd{section}\marg{datum=\{round=2,currency\}}
(All aggregate values become currency!)
\codepar
\gls{DTLaction}\oarg{\nlsp
 \actionoptvalm{datum}{\actiondatumoptval{round}{2},\actiondatumopt{currency}},\nlsp
 \actionoptval{key}{Quantity},\nlsp
 \actionoptval{key2}{Price},\nlsp
 \actionoptvalm{options}{sd,min,max}\nl
}\marg{\action{aggregate}}
 \codepar
Quantity column index: \gls{DTLuse}\marg{column}.\nl
Total quantity: \gls{DTLuse}\marg{sum}\nl
(\gls{DTLget}\oarg{sum}\marg{\cmd{theTotal}}\gls{DTLdatumvalue}\marg{\cmd{theTotal}}).\nl
Average quantity: \gls{DTLuse}\marg{mean}.\nl
Quantity standard deviation: \gls{DTLuse}\marg{sd}.\nl
Minimum quantity: \gls{DTLuse}\marg{min}\nl
(\gls{DTLget}\oarg{min}\marg{\cmd{theMin}}\gls{DTLdatumvalue}\marg{\cmd{theMin}}).\nl
Maximum quantity: \gls{DTLuse}\marg{max}\nl
(\gls{DTLget}\oarg{max}\marg{\cmd{theMax}}\gls{DTLdatumvalue}\marg{\cmd{theMax}}).
\codepar
Price column index: \gls{DTLuse}\marg{column2}.\nl
Total price: \gls{DTLuse}\marg{sum2}.\nl
Average price: \gls{DTLuse}\marg{mean2}.\nl
Price standard deviation: \gls{DTLuse}\marg{sd2}.\nl
Minimum price: \gls{DTLuse}\marg{min2}.\nl
Maximum price: \gls{DTLuse}\marg{max2}.
}
\end{resultbox}
\glsendrange{DTLaction}%

\section{Creating a New Database}
\label{sec:newdb}

This section describes commands that may be used in a document to
create a database or to locally or globally alter a database. The
\opt{global} option determines whether or not the modifications to
the database are global or local, except for those commands that are
listed as specifically global only. Note that new databases are
always globally defined.

The \opt{new-value-trim} option determines whether
or not values are trimmed before adding to a database, and the
\opt{new-value-expand} option determines whether or not values
should be expanded before adding. The \opt{store-datum} option
determines whether or not the values should be as a \idx{datumitem}.

\begin{information}
A new database can be created from data in an external file using
\gls{DTLread}. In that case, the database is always defined globally
because \gls{DTLread} introduces an implicit group to localise the
settings passed in the optional argument.
See \sectionref{sec:io} for further details. 
\end{information}

\cmddef{DTLgnewdb}
Globally defines a new database with the label \meta{db-name}. 
If a database already exists with the given label, an error
will occur. Alternatively, you can use the \action{new} action:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{\meta{db-name}}}\marg{\action{new}}
\end{compactcodebox}

\begin{important}
New databases are always global, regardless 
of the \opt{global} option, because the underlying registers used to
store the database structure have to be globally defined, so 
\inlineglsdef{DTLnewdb} is equivalent to \gls{DTLgnewdb}.
\end{important}

Before you can add any data to a database, you must start a new row.
\cmddef{DTLnewrow}
This adds a new row to the database identified by the label
\meta{db-name}. The \opt{global} option determines whether or not
the change is global. If a database with the given label doesn't
exists, an error will occur with the unstarred version. The starred
version \starredcs{DTLnewrow} doesn't check for existence. Alternatively, 
you can use the \action{new-row} action (which checks for existence):
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{\meta{db-name}}}\marg{\action{new-row}}
\end{compactcodebox}

Once you have added a new row, you can add entries to that row with:
\cmddef{DTLnewdbentry}
This adds an entry with the given value to the column identified by
the label \meta{col key} in the last row of the database identified
by the label \meta{db-name}. The \opt{global} option determines
whether or not the change is global.  Alternatively, 
you can use the \action{new-entry} action (which checks for existence):
\begin{compactcodebox}
\gls{DTLaction}\oarg{
 \actionoptvalm{name}{\meta{db-name}},
 \actionoptvalm{key}{\meta{col key}},
 \actionoptvalm{value}{\meta{value}}
}\marg{\action{new-entry}}
\end{compactcodebox}

If a database with the given label doesn't exists or the row already
contains an entry in that column, an error will occur with the
unstarred version. The starred version \starredcs{DTLnewdbentry}
doesn't check for existence of the database, but will still trigger
an error if an entry for the given column already exists.

If a column with the given label doesn't yet exist, it will be
created and the default metadata will be assigned. The
\opt{store-datum} option determines whether or not the value is
stored in the database as a \idx{datumitem}. It will be parsed
regardless of that setting in order to set or update the column data
type. The \opt{new-value-trim} option determines whether or not the
value should have leading and trailing spaces trimmed. The
\opt{new-value-expand} option determines whether or not the value
should be expanded.

Note that with the default \optval{new-value-expand}{false}, you can
expand a particular value in
\code{\gls{DTLaction}\marg{\action{new-entry}}} with the
\actionopt{expand-value} or \actionopt{expand-once-value}
action option. With \optval{new-value-expand}{true}, the value will
always have protected expansion applied.

\mExampleref{ex:newdb} creates a database labelled \qt{mydata} as
follows:
\begin{codebox}
\comment{custom expandable command:}
\cmd{newcommand}\marg{\cmd{limiteded}}\marg{limited edition}
\comment{define data}
\gls{DTLnewdb}\marg{mydata}
\gls{DTLnewrow}\marg{mydata}\comment{create a new row}
\comment{Add entries to the first row:}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Product}\comment{column key}
 \marg{The Adventures of Duck and Goose}\comment{value}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Quantity}\comment{column key}
 \marg{1,452}\comment{value}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Price}\comment{column key}
 \marg{\gls{cs.dollar}1.99}\comment{value}
\gls{DTLnewrow}\marg{mydata}\comment{create a new row}
\comment{Add entries to the second row:}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Product}\comment{column key}
 \marg{Duck and Goose on Holiday}\comment{value}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Quantity}\comment{column key}
 \marg{94}\comment{value}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Price}\comment{column key}
 \marg{\gls{cs.dollar}2.99}\comment{value}
\comment{the next value needs to be expanded:}
\gls{DTLsetup}\marg{\opt{new-value-expand}}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Notes}\comment{column key}
 \marg{\cmd{limiteded}}\comment{value}
\comment{switch off expansion:}
\gls{DTLsetup}\marg{\optval{new-value-expand}{false}}
\gls{DTLnewrow}\marg{mydata}\comment{create a new row}
\comment{Add entries to the third row:}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Product}\comment{column key}
 \marg{The Return of Sir Quackalot}\comment{value}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Quantity}\comment{column key}
 \marg{3}\comment{value}
\gls{DTLnewdbentry}
 \marg{mydata}\comment{database label}
 \marg{Price}\comment{column key}
 \marg{\gls{cs.dollar}4.99}\comment{value}
\end{codebox}
Note that the second row has introduced a fourth column with the
label \qt{Notes}. Since the other rows don't have this column set,
an attempt to access it will result in a null value. Expansion needs
to be switched on when a value must be expanded. This is commonly
the case with placeholder commands. The setting must be switched off
again or it will cause the currency symbol to prematurely expand in
the next row (which means the datum parser won't be able to detect
it as currency).

The contents of the database can now be displayed with:
\begin{codebox}
\gls{DTLdisplaydb}\marg{mydata}
\end{codebox}
This displays the database in a \env{tabular} environment, 
as shown in \exampleref{ex:newdb}.
\begin{resultbox}
\createexample*[label={ex:newdb},
  title={Creating a New Database with a Label},
  description={Example document that creates a simple database and
displays it as a table}
]
{%
\cmd{usepackage}\marg{datatool}\nl
\comment{custom expandable command:}%
\cmd{newcommand}\marg{\cmd{limiteded}}\marg{limited edition}\nl
\comment{define data}
\gls{DTLnewdb}\marg{mydata}\nl
\gls{DTLnewrow}\marg{mydata}\comment{create a new row}%
\comment{Add entries to the first row:}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Product}\comment{column key}
 \marg{The Adventures of Duck and Goose}\comment{value}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Quantity}\comment{column key}
 \marg{1,452}\comment{value}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Price}\comment{column key}
 \marg{\gls{cs.dollar}1.99}\comment{value}%
\gls{DTLnewrow}\marg{mydata}\comment{create a new row}%
\comment{Add entries to the second row:}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Product}\comment{column key}
 \marg{Duck and Goose on Holiday}\comment{value}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Quantity}\comment{column key}
 \marg{94}\comment{value}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Price}\comment{column key}
 \marg{\gls{cs.dollar}2.99}\comment{value}%
\comment{the next value needs to be expanded:}%
\gls{DTLsetup}\marg{\opt{new-value-expand}}\nl
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Notes}\comment{column key}
 \marg{\cmd{limiteded}}\comment{value}%
\comment{switch off expansion:}%
\gls{DTLsetup}\marg{\optval{new-value-expand}{false}}\nl
\gls{DTLnewrow}\marg{mydata}\comment{create a new row}%
\comment{Add entries to the third row:}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Product}\comment{column key}
 \marg{The Return of Sir Quackalot}\comment{value}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Quantity}\comment{column key}
 \marg{3}\comment{value}%
\gls{DTLnewdbentry}\nlsp
 \marg{mydata}\comment{database label}
 \marg{Price}\comment{column key}
 \marg{\gls{cs.dollar}4.99}\comment{value}
}
{\gls{DTLdisplaydb}\marg{mydata}}
\end{resultbox}
See \exampleref{ex:actions} for an equivalent document using \gls{DTLaction}.

Short commands, such as \gls{DTLnewdbentry} don't permit \gls{par}
on the argument. If you have a value that spans multiple paragraphs,
you will need to mark the paragraph breaks with:
\cmddef{DTLpar}
This is a robust command that simply does \gls{par}.

\section{Deleting or Clearing a Database}
\label{sec:deletedb}

Deleting or clearing a database simply undefines or resets the
underlying commands and registers that are used to represent the
database.

\cmddef{DTLdeletedb}
Deletes the database identified by the label \meta{db-name} (that
is, the internal commands associated with the database are
undefined). The \opt{global} option determines whether or not the
change is global. If a database with the given label doesn't exists,
an error will occur. Alternatively, you can use the \action{delete}
action:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{\meta{db-name}}}\marg{\action{delete}}
\end{compactcodebox}

\cmddef{DTLgdeletedb}
Globally deletes the database identified by the label \meta{db-name},
regardless of the \opt{global} setting. If a database with the given
label doesn't exists, an error will occur.

\cmddef{DTLcleardb}
Clears the database identified by the label \meta{db-name}. That is, the
database is made empty (no rows or columns) but is still defined. The
\opt{global} option determines whether or not the change is
global. If a database with the given label doesn't exists, an error
will occur. Alternatively, you can use the \action{clear}
action:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{\meta{db-name}}}\marg{\action{clear}}
\end{compactcodebox}

\cmddef{DTLgcleardb}
Globally clears the database identified by the label \meta{db-name},
regardless of the \opt{global} setting. If a database with the given
label doesn't exists, an error will occur.


\section{Database Conditionals and Metadata}
\label{sec:dbcondmeta}

You can test if a database exists with:
\cmddef{DTLifdbexists}
This does \meta{true} if a database with the label
\meta{db-name} exists, otherwise it does \meta{false}.

You can test if a database is empty with:
\cmddef{DTLifdbempty}
This does \meta{true} if a database with the label \meta{db-name} is
empty, otherwise it does \meta{false}. If a database with the given
label doesn't exists, an error will occur.

If you have \LaTeX3 syntax enabled, you can also use:
\cmddef{datatooldbstate:nnnn}
This is a shortcut that combines \gls{DTLifdbexists} and
\gls{DTLifdbempty}.
If the database identified by \meta{db-name} exists and is
not empty, this does \meta{not empty}, if it exists but is empty,
this does \meta{empty}. If the database doesn't exist, this does
\meta{not exists}.

The metadata associated with a database consists of the identifying
database label, the number of columns, the number of rows, and the
column metadata.

Rows in a database are only identified by an index (starting
from~1). Columns may be identified by an index (starting from~1) or
by a key (label) that must be unique to the database. You can test 
if a database has a column with a given key with:
\cmddef{DTLifhaskey}
This does \meta{true} if the database identified by the label
\meta{db-name} has a column labelled with the given \meta{label},
and \meta{false} otherwise. The unstarred version will trigger an
error if the database doesn't exist. The starred version will do
\meta{false} if the database doesn't exist.

If you have \LaTeX3 syntax enabled you may instead use:
\cmddef{datatoolifhaskey:nn}
This tests if the database with the label \meta{db-name} exists and has
a column with the given \meta{key}.
(\starredcs{DTLifhaskey} is now simply defined to use
\gls{datatoolifhaskey:nn}.)

\cmddef{DTLrowcount}
Expands to the number of rows in the database identified by the
label \meta{db-name}. No check is made for existence, but you will
get a \qt{Missing number, treated as zero} error if the database
hasn't been defined.

\cmddef{DTLcolumncount}
Expands to the number of columns in the database identified by the
label \meta{db-name}. No check is made for existence, but you will
get a \qt{Missing number, treated as zero} error if the database
hasn't been defined.

The column metadata not only consists of the index and unique key,
but also a header and the column data type (see \sectionref{sec:datatypes}).
When an entry is added to a database the entry is parsed to
determine its data type, and the column metadata is updated.
For example, if an integer is the first element to be added to a
column, the column metadata will be updated to set the column data
type to integer. If a decimal is then added to that column, the
metadata will be updated to \qt{real number}. If another integer is
added, the metadata won't be updated as the \qt{real number} type
takes precedence.

Some advanced commands require the column index rather than the
column key. You can lookup the index from the key with:
\cmddef{DTLgetcolumnindex}
This will define the control sequence \meta{cs} to expand to the
index of the column labelled \meta{col key} for the database
identified by the label \meta{db-name}. The starred version
doesn't check if the database or column exists. The unstarred
version will trigger an error if either the database doesn't exist
or doesn't have a column with the given key. Alternatively, you can
use the \action{column-index} action:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{key}{\meta{col key}}}\marg{\action{column-index}}
Index: \gls{DTLuse}\marg{}.
Or: \gls{DTLget}\margm{cs} index: \cmd{cs}.
\end{compactcodebox}

Note that \gls{DTLgetcolumnindex} is
robust. If you want the column index in an expandable context you
can use:
\cmddef{dtlcolumnindex}
This will expand to 0 if the database or column don't
exist, otherwise it will expand to the column index.
(Note that prior to version 3.0, this would expand to \gls{relax} if
the database or column didn't exist.)

If you want the reverse, that is the column key given the column
index, you can use:
\cmddef{DTLgetkeyforcolumn}
This gets the key for the column with the index \meta{col idx}
from the database identified by the label \meta{db-name} and defines 
the control sequence \meta{cs} to expand to that value. The starred version
\starredcs{DTLgetkeyforcolumn} doesn't check if the database or column exists.

The column data type is used in some commands, such as
\gls+{DTLdisplaydb} (where the column data type determines the column
alignment). However, if the data isn't stored as a \idx{datumitem},
it will have to be reparsed for commands like \gls{DTLmaxforkeys}.
It's more efficient to use \optval{store-datum}{true}, but if you do
so, you will need to remember that a command that is set to an element
value (such as those in an assignment list in \gls{DTLforeach}) will
be a \idx{datumcs} rather than a command whose expansion text is the original value.

You can look up the column data type with:
\cmddef{DTLgetdatatype}
This will define the control sequence \meta{cs} to expand to the
data type ID for the column labelled \meta{col key} in the
database identified by \meta{db-name}. The starred version doesn't
check if the database and column are defined. The unstarred version
will trigger an error if either are undefined.

Alternatively, you can use the \action{column-data} action, which
will get the index, key, type and header from the column key or
column index. For example, the following will display the meta data
for the first column:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{column}{1}}\marg{\action{column-data}}
Column 1 key: \gls{DTLuse}\marg{key}, 
title: \gls{DTLuse}\marg{header}, 
type: \gls{DTLuse}\marg{type}.
\end{codebox}
The following fetches the meta data for the column identified by the
key \code{Name}:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Name}}\marg{\action{column-data}}
\gls{DTLget}\oarg{column}{\cmd{colidx}} Column index: \cmd{colidx}.
\gls{DTLget}\oarg{header}{\cmd{colheader}} Column title: \cmd{colheader}.
\gls{DTLget}\oarg{type}{\cmd{coltype}} Column type: \cmd{coltype}.
\end{codebox}

The data type ID will be one of: 0 (string), 1 (int), 2 (real), 3 (currency),
or empty for unset (which typically means there are no non-empty
elements in the column). There are commands provided that expand to
the corresponding ID:
\cmddef{DTLunsettype}
This expands to nothing and so can be used to check for the unset ID.
Note that this is different from the way that \sty{datatool-base}
identifies unknown types (which have an ID of $-1$). The other IDs
have the same numeric value as those used by \sty{datatool-base}.
\cmddef{DTLstringtype}
This expands to 0 and so can be used to check for the string ID.
\cmddef{DTLinttype}
This expands to 1 and so can be used to check for the integer ID.
\cmddef{DTLrealtype}
This expands to 2 and so can be used to check for the real number ID.
\cmddef{DTLcurrencytype}
This expands to 3 and so can be used to check for the currency ID.

The column header defaults to the column key, but may be changed. For
example, when reading a \idx{CSV} or \idx{TSV} file with
\gls{DTLread}, the headers can be set with the \ioopt{headers}
option. Alternatively, you can use:
\cmddef{DTLsetheader}
This sets the header for the column labelled \meta{col key} in
the database identified by \meta{db-name}. The starred version
doesn't check if the database exists. The unstarred version will
trigger an error if the database doesn't exist.

Normally new column metadata is automatically added when an entry is
added with a new key. However, you can also add a new column with:
\cmddef{DTLaddcolumn}
This increments the column count for the database identified by
\meta{db-name} and assigns the label \meta{col key}. The header is
also set to \meta{col key} and the data type is initialised as
\qt{unknown}. This doesn't add an entry to the database. It just
modifies the metadata.

If you want to add a new column with a header that isn't the same as
the column key, then you use:
\cmddef{DTLaddcolumnwithheader}
This has the same effect as:
\begin{compactcodebox}
\gls{DTLaddcolumn}\margm{db-name}\margm{col key}
\gls{DTLsetheader}\margm{db-name}\margm{col key}\margm{header}
\end{compactcodebox}
but it's shorter and slightly quicker. Alternatively:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{\meta{db-name}},\actionoptvalm{key}{\meta{col key}},\actionoptvalm{value}{\meta{header}}}\marg{\action{add-column}}
\end{compactcodebox}
or set the database name as the default so you don't have to keep
supplying it:
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optvalm{default-name}{\meta{db-name}}}
\gls{DTLaction}\oarg{\actionoptvalm{key}{\meta{col key}},\actionoptvalm{value}{\meta{header}}}\marg{\action{add-column}}
\end{compactcodebox}

Be careful about defining columns that aren't required as you can
end up with null values (which isn't the same as an empty value). 
\mExampleref{ex:nullcol} defines two
columns but no value is added to the second column in any
of the rows:
\begin{codebox}
\gls{DTLnewdb}\marg{mydata}
\gls{DTLaddcolumnwithheader}\marg{mydata}\marg{name}\marg{Name}
\gls{DTLaddcolumnwithheader}\marg{mydata}\marg{address}\marg{Address}
\gls{DTLnewrow}\marg{mydata}
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{Zoë}
\gls{DTLnewrow}\marg{mydata}
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{José}
\gls{DTLnewrow}\marg{mydata}
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{Dickie}
\comment{this row has an empty name:}
\gls{DTLnewrow}\marg{mydata}
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{}
\codepar
Number of rows: \gls{DTLrowcount}\marg{mydata}.
Number of columns: \gls{DTLcolumncount}\marg{mydata}.
\codepar
\gls{DTLdisplaydb}\marg{mydata}
\end{codebox}
Missing values show as \qt{NULL} (see \sectionref{sec:null}).
\begin{resultbox}
\createexample*[label=ex:nullcol,
 title={Column with No Values},
 description={Example document demonstrating a database with an
unused column}
]
{%
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLnewdb}\marg{mydata}\nl
\gls{DTLaddcolumnwithheader}\marg{mydata}\marg{name}\marg{Name}\nl
\gls{DTLaddcolumnwithheader}\marg{mydata}\marg{address}\marg{Address}\nl
\gls{DTLnewrow}\marg{mydata}\nl
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{Zoë}\nl
\gls{DTLnewrow}\marg{mydata}\nl
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{José}\nl
\gls{DTLnewrow}\marg{mydata}\nl
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{Dickie}\nl
\comment{this row has an empty name:}%
\gls{DTLnewrow}\marg{mydata}\nl
\gls{DTLnewdbentry}\marg{mydata}\marg{name}\marg{}
}
{%
Number of rows: \gls{DTLrowcount}\marg{mydata}.\nl
Number of columns: \gls{DTLcolumncount}\marg{mydata}.
\codepar
\gls{DTLdisplaydb}\marg{mydata}
}
\end{resultbox}

\section{Displaying the Contents of a Database}
\label{sec:displaydb}

\glsstartrange{DTLdisplaydb,DTLdisplaydb*,DTLdisplaylongdb}%
A database can be displayed in a tabulated form using one of the
following commands.
\cmddef{DTLdisplaydb}
Displays the content of the database identified by the label
\meta{db-name} in a \env{tabular} environment. The optional argument
\meta{omit list} should be a comma-separated list of column keys
(not indexes) to omit. To allow for greater flexibility, there is also a starred
version where the optional argument is a \keyval\ list of options.
If the database is large and requires multiple pages, you can use
the following instead:
\cmddef{DTLdisplaylongdb}
This displays the data in a \env{longtable} environment (you will
need to load the \sty{longtable} package). The options
for \gls{DTLdisplaydb*} and \gls{DTLdisplaylongdb} are listed in
\sectionref{sec:displaydboptions}. Associated commands, which can be
redefined to make slight adjustments, are listed in
\sectionref{sec:displaydbcmds}. Examples are provided in
\sectionref{sec:displaydbexs}.

There are analogous actions: \action{display} (for
\gls{DTLdisplaydb*}) and \action{display-long} (for
\gls{DTLdisplaylongdb}).
For example:
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{mydata},\actionoptvalm{options}{\displayoptvalm{only-keys}{Name,Description}}}\marg{\action{display}}
\end{compactcodebox}
or
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optval{default-name}{mydata}}
\gls{DTLaction}\oarg{\actionoptvalm{options}{\displayoptvalm{only-keys}{Name,Description}}}\marg{\action{display}}
\end{compactcodebox}
are equivalent to:
\begin{compactcodebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{only-keys}{Name,Description}}\marg{mydata}
\end{compactcodebox}

As from version 3.0, both \gls{DTLdisplaydb} and
\gls{DTLdisplaylongdb} use a private token list variable
\meta{content-tl-var} to construct the content of the \env{tabular} or
\env{longtable} environment. This removes the loop from within the
alignment and avoids the need to globally set variables. Once
construction of \meta{content-tl-var} has been completed,
\meta{content-tl-var} is then expanded.

The \displayopt{pre-content} option value is placed immediately before
\meta{content-tl-var}, so you can set \displayopt{pre-content} to \gls{show}
for debugging purposes. This will show the tokens in
\meta{content-tl-var} in the transcript (and \meta{content-tl-var} won't be
expanded).

\subsection{Display Options}
\label{sec:displaydboptions}

Most of these options can be used with both \gls{DTLdisplaydb*} and
\gls{DTLdisplaylongdb}. However, some are only available with
one or other command. If you are using the \action{display} or
\action{display-long} actions, you can specify these options in the
\actionopt{options} action setting.

\begin{information}
When \sty{datatool} v2.0 introduced \gls{DTLdisplaylongdb}, options
were defined using the \sty{xkeyval} interface. In version 3.0, the
\sty{xkeyval} package has been dropped in favour of the newer
\sty{l3keys} interface. If you previously used
\code{\gls{setkeys}\marg{displaylong}\margm{options}} to set the
options (instead of using the optional argument), you will need to
switch to
\code{\gls{DTLsetup}\marg{\optvalm{display}{\meta{options}}}}.
\end{information}

\subsubsection{General}
\label{sec:displaydbgeneraloptions}

\optiondef{display.init}
The value should be code to insert after the options have been
processed and before the content token list variable construction
starts. This may be used to initialise variables for use in other
hooks (see \exampleref{ex:displaydbpostrow}).

\optiondef{display.pre-content}
The value should be code to insert immediately before the token list
containing the \env{tabular} environment. You can set the value to
\csfmt{show} for debugging purposes, and it will show rather than
typeset the content. Any local redefinitions within \meta{code} will be scoped. For
example, this option can be used to adjust \csfmt{tabcolsep} or
\env{longtable} settings.

\begin{important}
You can't use \displayopt{pre-content} to locally redefine
customization commands, such as \gls{dtldisplaydbenv}, as they will
have already been expanded.
\end{important}

\optiondef{display.per-row}
The number of database rows per \env{tabular} (or \env{longtable})
row. Note that the row number \gls{dtlrownum} is incremented per included database
row and the column number \gls{dtlcolumnnum} is incremented per included column
regardless of this option. For example, with
\displayoptval{per-row}{2} then \gls{dtlrownum} and the
\meta{row-num} argument of \gls{DTLdisplaydbAddItem} will first be 1
and then 2 for the first \env{tabular} line that follows the header
(not including any additional content that may have been inserted by
hooks).

\optiondef{display.row-idx-map-inline}
The value should be the definition of a command that takes a single
parameter which will be the loop iteration index (1 for the first
row, 2 for the second etc). The command definition should expand to
the row index to be used for the current iteration. The default
behaviour is a direct mapping from iteration index to the database
row index.

\begin{important}
The row index mapping function must expand to an integer between 1
and the total number of columns for the database. The function is
applied before filtering.
\end{important}

For example, to display the contents of the database in reverse order:
\begin{codebox}
\displayoptvalm{row-idx-map-inline}{\gls{DTLrowcount}\marg{\gls{dtldbname}}-\#1+1}
\end{codebox}

\optiondef{display.row-idx-map-function}
As above but the value is a command that takes a single argument.
For convenience, \gls{DTLdisplayTBrowidxmap} is provided for use
with \displayopt{per-row} that will arrange the data rows from top to
bottom instead of left to right, but note that this won't work if
filtering omits rows.

\optiondef{display.post-row-inline}
A hook is provided while the tabular content is constructed at the
end of each row (before the \gls{dtldisplaycr} separating the rows).
Unlike \gls{dtldisplaystartrow}, which has its expansion text
inserted into the content token list, the post-row hook determines
whether or not to append content to the token list variable or
accumulate information for later insertion. The
\displayopt{post-row-inline} option provides a way to define this
hook inline.

The hook takes two arguments: \meta{content-tl-var} (the content token
list, which contains the tabular content under construction) and
\meta{row idx} (the database row index). If filtering has been
applied, you can access the filtered row index (which is the current
tabular row count excluding header and extra content) with the
register \gls{dtlrownum}. If no rows have been filtered,
\gls{dtlrownum} will have the same value as \meta{row idx}.
The hook isn't used for excluded rows.

\begin{information}
The \gls{dtlcurrentrow} token register will be available within the
hook, so you access row information with commands such as
\gls{dtlgetentryfromcurrentrow} or \gls{DTLassignfromcurrentrow} 
or actions such as \action{current-row-aggregate}.
\end{information}

\optiondef{display.post-row-function}
As \displayopt{post-row-inline} but provides the name of a function
that takes two arguments.

\optiondef{display.tabular-env}
Only available with \gls{DTLdisplaydb*} and indicates the
environment to use.  This is a shortcut that redefines \gls{dtldisplaydbenv} to
\meta{env-name} but additionally checks that the given environment
is defined and redefines \gls{dtldisplayvalign} to empty, unless
\meta{env-name} is \env{tabular} or \env{array}, in which case
\gls{dtldisplayvalign} is redefined to \code{c} unless it is
currently defined to \code{t} or \code{b}.

For example (requires the \sty{tabularray} package):
\begin{codebox*}
\gls{DTLdisplaydb*}\oarg{\displayoptval{tabular-env}{\env{tblr}}}\marg{mydata}
\end{codebox*}

\optiondef{display.longtable-env}
Only available with \gls{DTLdisplaylongdb} and indicates the
environment to use.  This is a shortcut that redefines
\gls{dtldisplaylongdbenv} to \meta{env-name} but additionally checks
that the given environment is defined. Note that the 
environment needs to support \env{longtable} syntax.

For example (requires the \sty{tabu} package):
\begin{codebox*}
\gls{DTLdisplaylongdb}\oarg{\displayoptval{longtable-env}{\env{longtabu}}}\marg{mydata}
\end{codebox*}

\subsubsection{Alignment}
\label{sec:displaydbalignoptions}

\optiondef{display.string-align}
This option specifies the alignment for columns with the string data
type. It simply redefines \gls{dtlstringalign} to \meta{col-spec}.

\optiondef{display.integer-align}
This option specifies the alignment for columns with the integer data
type. It simply redefines \gls{dtlintalign} to \meta{col-spec}.

\optiondef{display.int-align}
A synonym of \displayopt{integer-align}.

\optiondef{display.decimal-align}
This option specifies the alignment for columns with the decimal
(real) data type. It simply redefines \gls{dtlrealalign} to \meta{col-spec}.

\optiondef{display.real-align}
A synonym of \displayopt{decimal-align}.

\optiondef{display.currency-align}
This option specifies the alignment for columns with the currency 
data type. It simply redefines \gls{dtlcurrencyalign} to \meta{col-spec}.

\optiondef{display.inter-col}
This option specifies the inter-column alignment markup.
It simply redefines \gls{dtlbetweencols} to \meta{align-spec}.
For example, \displayoptvalm{inter-col}{|} for a vertical line.

\optiondef{display.pre-col}
This option specifies the pre-column alignment markup.
It simply redefines \gls{dtlbeforecols} to \meta{align-spec}.
For example, \displayoptvalm{pre-col}{|} for a vertical line.

\optiondef{display.post-col}
This option specifies the post-column alignment markup.
It simply redefines \gls{dtlaftercols} to \meta{align-spec}.
For example, \displayoptvalm{post-col}{|} for a vertical line.

\optiondef{display.align-specs}
This option is essentially a manual override. The value should be
the complete column specifications for the table. If this setting
has a non-empty value, the value will be used for the \env{tabular}
or \env{longtable} \meta{align-spec} argument. The options
\displayopt{string-align}, \displayopt{integer-align},
\displayopt{decimal-align}, \displayopt{currency-align},
\displayopt{inter-col}, \displayopt{pre-col}, \displayopt{post-col}
will be ignored (although they will still set the underlying
commands).

\subsubsection{Headers and Footers}
\label{sec:displaydbheadfootoptions}

The header is essentially in the form:
\begin{compactcodebox}
\meta{pre-head}
\gls{dtlcolumnheader}\margm{align}\margm{header 1} \&
\gls{dtlcolumnheader}\margm{align}\margm{header 2} \&
\ldots
\gls{dtlcolumnheader}\margm{align}\margm{header n} 
\meta{post-head}
\end{compactcodebox}
where \meta{pre-head} is the expansion text of
\gls{dtldisplaystarttab} (the same as the value of the
\displayopt{pre-head} option), and \meta{header 1} etc are the column
headers, and \meta{post-head} is the value of the
\displayopt{post-head} option. If \gls{dtldisplayafterhead} (the same as the value of
\displayopt{after-head}) is not
empty, this is then followed by:
\begin{compactcodebox}
\gls{dtldisplaycr} \gls{dtldisplayafterhead}
\end{compactcodebox}

Each column title in the header row is aligned with:
\cmddef{dtlcolumnheader}
where \meta{align} is the header column alignment. This is simply defined
as:
\begin{compactcodebox*}
\gls{multicolumn}\marg{1}\margm{align}\marg{\gls{dtlheaderformat}\margm{title}}
\end{compactcodebox*}
The \meta{align} argument is obtained by:
\cmddef{dtladdheaderalign}
This adds the appropriate \meta{align} to \meta{align-token-tl},
taking into account the \displayopt{pre-col}, \displayopt{inter-col}
and \displayopt{post-col} settings. The default definition will use
\code{c} (centred) regardless of the data type. (Note used if
\displayopt{header-row} is set.) The token list
\meta{align-token-tl} is cleared before calling this command, so you
can either append or set it.

\optiondef{display.pre-head}
The value should be code to insert immediate before the header. This
option simply redefines \gls{dtldisplaystarttab} to \meta{code}.
Note that with \gls{DTLdisplaylongdb}, this will come after the
caption, if provided.

\optiondef{display.post-head}
The value should be code to insert at the end of the header (before
the end of row). This option redefines
\gls{ldatatoolpostheadtl} to \meta{code}.  Note that this is
different to \displayopt{after-head} which comes after the row end.

\optiondef{display.after-head}
This option simply redefines \gls{dtldisplayafterhead}, which comes
after the header, to \meta{code}.

For example, to add \gls{midrule} (\sty{booktabs}) after the
header, you can either redefine \gls{dtldisplayafterhead} to 
\gls{midrule}:
\begin{compactcodebox}
\cmd{renewcommand}\marg{\gls{dtldisplayafterhead}}\marg{\gls{midrule}}
\end{compactcodebox}
or you can use \displayopt{after-head}:
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optvalm{display}{\displayoptvalm{after-head}{\gls{midrule}}}}
\end{compactcodebox}
or (for a particular \env{longtable}):
\begin{compactcodebox}
\gls{DTLdisplaylongdb}\oarg{\displayoptvalm{after-head}{\gls{midrule}}}\marg{mydata}
\end{compactcodebox}

\optiondef{display.header-row}
This option is a manual override that may be used to explicitly set
the header row. An empty value indicates the default header, which
is obtained from the column metadata. For example:
\begin{compactcodebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{header-row}{Name \& Description}}\marg{mydata}
\end{compactcodebox}
You will need to include any required formatting and make sure you
have the correct number of columns.

\optiondef{display.no-header}
A boolean option that indicates that the header should be omitted.
Note that this option will not only omit the header
row but also the \displayopt{pre-head}, \displayopt{post-head} 
and \displayopt{after-head}.

\begin{important}
The following options default to \csfmt{c\_novalue\_tl} which
indicates the setting is switched off. This makes it possible to
distinguish between switching off the setting, and enabling the
setting but requiring an empty value. For example,
\displayoptvalm{caption}{} will create a caption with empty text
(the table number will be displayed).  Whereas the default
\displayoptval{caption}{\csfmt{c\_novalue\_tl}} (which would require
\LaTeX3 syntax to be enabled) will switch off the setting.
\end{important}

\optiondef{display.caption}
(Only available with \gls{DTLdisplaylongdb}.)
If set, \gls{caption} will be inserted at the start of
the header with the supplied value in the argument.

\optiondef{display.cont-caption}
(Only available with \gls{DTLdisplaylongdb}.)
If this option is set in addition to \displayopt{caption}, the
\gls{caption} argument for the first header (\gls{endfirsthead}) will be obtained from
\displayopt{caption} but the \gls{caption} argument for the
subsequent headers (\gls{endhead}) will be obtained from \displayopt{cont-caption}.
This option is ignored if \displayopt{caption} isn't set.

\optiondef{display.contcaption}
A synonym of \displayopt{cont-caption}.

\optiondef{display.short-caption}
(Only available with \gls{DTLdisplaylongdb}.)
If this option is set in addition to \displayopt{caption}, the
optional argument of \gls{caption} in the first header will be set to this value.
This option is ignored if \displayopt{caption} isn't set.

\optiondef{display.shortcaption}
A synonym of \displayopt{short-caption}.

\optiondef{display.label}
(Only available with \gls{DTLdisplaylongdb}.)
If this option is set in addition to \displayopt{caption}, the
\gls{caption} in the first header will be followed by
\code{\gls+{label}\margm{label}}.
This option is ignored if \displayopt{caption} isn't set.

\optiondef{display.foot}
If this option is set, the value will be inserted as the footer.  In
the case of \gls{DTLdisplaydb}, \code{\gls{dtldisplaycr}
\meta{code}} be inserted before \gls{dtldisplayendtab} at the end of
the \env{tabular} environment (see \gls{DTLdisplaydbAddEnd}). In the
case of \gls{DTLdisplaylongdb}, \code{\meta{code}\gls+{endfoot}} will
be inserted at the start of the \env{longtable} environment (see
\gls{DTLdisplaylongdbAddBegin}).

\optiondef{display.last-foot}
(Only available with \gls{DTLdisplaylongdb}.)
If this option is set, \code{\meta{code}\gls+{endlastfoot}} will be
inserted (by \gls{DTLdisplaylongdbAddBegin}) as the last footer of the \env{longtable}.

\optiondef{display.lastfoot}
A synonym of \displayopt{last-foot}.

\subsubsection{Filtering}
\label{sec:displaydbfilteroptions}

\optiondef{display.row-condition-inline}
The value should be an inline function that takes three arguments:
\meta{content-tl-var} (the content token list variable), \meta{row-idx} (the row
index), and \meta{true} which will contain the code to be performed
if the row should be included.  The function should expand to the
third argument (\meta{true}) if the row should be included and
expand to nothing otherwise. The \meta{true} code will include the
post-row hook provided by \displayopt{post-row-inline} or
\displayopt{post-row-function}.

\begin{information}
If you try to reference \gls{dtlrownum} within the filter function
before the \meta{true} code, it will contain the filtered row index
of the previous row to be added. The variable is incremented in the
\meta{true} argument.
\end{information}

The \meta{content-tl-var} argument is the token list variable used to construct
the \env{tabular} or \env{longtable} body, which the function
may append content to (regardless of whether or not it expands to
\meta{true}), but bear in mind that the content will be
before \gls{tabularnewline} (which is added to the content token
list at the start of the code provided in the third argument of the
filter function, since it's not possible to tell at the end of the
previous row if there are any additional rows that won't be filtered).

For example, to omit all the odd rows:
\begin{codebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{row-condition-inline}{\cmd{ifodd}\#2\cmd{else}\#3\cmd{fi}}}\marg{mydata}
\end{codebox}
Or to include all rows but insert a blank row before
every even row:
\begin{codebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{row-condition-inline}{
 \cmd{ifodd}\#2 \cmd{else} \gls{appto}\#1\marg{\cmd{tabularnewline}}\cmd{fi} \#3} }\marg{mydata}
\end{codebox}

\optiondef{display.row-condition-function}
Instead of using an inline function with \displayopt{row-condition-inline},
you can provide a function with \displayopt{row-condition-function}.
The supplied command \meta{cs} must have three arguments as per the
inline function for \displayopt{row-condition-inline}.

Both filter options can access information from the current database row
with \idx{current-row} commands such as \gls{dtlgetentryfromcurrentrow}
as in \exampleref{ex:displaydbcond}, or an action that acts on the
\idx{current-row}, such as \action{current-row-aggregate}.

\begin{information}
The following options cancel each other out. Only the last listed in
the options list will have effect.
\end{information}

\optiondef{display.omit-columns}
The value should be a comma-separated list of column indexes,
indicating which columns should be omitted.

\optiondef{display.omit-keys}
The value should be a comma-separated list of column keys,
indicating which columns should be omitted. Note that this has
replaced the now-deprecated \displayopt{omit} option.

\optiondef{display.only-columns}
The value should be a comma-separated list of column indexes, 
indicating which columns should be included.

\optiondef{display.only-keys}
The value should be a comma-separated list of column keys, 
indicating which columns should be included.

\begin{information}
With \displayopt{only-keys} and \displayopt{only-columns}, the
table column order will match the inclusion order (that is, the
order given in the option value). Otherwise, the
table column order will match the column index order (with excluded
columns omitted, if applicable).
\end{information}

\subsection{Associated Commands}
\label{sec:displaydbcmds}

The following commands are used by \gls{DTLdisplaydb} and
\gls{DTLdisplaylongdb} to format the table contents.

\cmddef{dtlheaderformat}
Used to format the column headers. This defaults to just
\code{\cmd{textbf}\margm{text}} Not used if
\displayopt{no-header} is set.
\begin{important}
Version 3.0 has changed the definition of \gls{dtlheaderformat}.
Previously, the definition included \gls{hfil} to centre the text.
The alignment is now performed with \gls{dtlcolumnheader} and
\gls{dtlheaderformat} just deals with any font change.
\end{important}

\cmddef{dtlstringformat}
Used to format values in columns with the string data type. The
default definition simply expands to \meta{text}.

\cmddef{dtlnumericformat}
Used to format values in columns with a numeric data type. This
command is used by the following:

\cmddef{dtlintformat}
Used to format values in columns with the integer data type. The
default definition expands to
\code{\gls{dtlnumericformat}\margm{text}}.

\cmddef{dtlrealformat}
Used to format values in columns with the decimal data type. The
default definition expands to 
\code{\gls{dtlnumericformat}\margm{text}}.

\cmddef{dtlcurrencyformat}
Used to format values in columns with the currency data type. The
default definition expands to 
\code{\gls{dtlnumericformat}\margm{text}}.

The following token list commands are provided to insert extra content into the
\env{tabular} or \env{longtable} body.

\cmddef{dtldisplaystarttab}
The expansion text of this command is inserted before the header. You
can either redefine this command or use the \displayopt{pre-head}
option. Not used if \displayopt{no-header} is set.

\cmddef{dtldisplayafterhead}
The expansion text of this command is inserted after the header. You
can either redefine this command or use the \displayopt{after-head}
option. Not used if \displayopt{no-header} is set.

\cmddef{dtldisplayendtab}
The expansion text of this command is inserted before the end of the
\env{tabular} or \env{longtable} environment.

\cmddef{dtldisplaystartrow}
The expansion text of this command is inserted at the start of each
row (except for the first row of data). Note that you can
also insert content by redefining \gls{DTLdisplaydbAddItem} and
adding a test for the first column with \gls{datatoolifrowstart:nn}, 
as in \exampleref{ex:displaydbaverages}
in \sectionref{sec:displaydbaverages}. (Content can be
inserted into the end of each row with \displayopt{post-row-inline}
or \displayopt{post-row-function}).

\cmddef{dtldisplaydbenv}
This should expand to the environment name used by
\gls{DTLdisplaydb}. Note that if you redefine this command to use an
environment that doesn't take \env{tabular}['s] optional vertical alignment
argument, you will also need to redefine \gls{dtldisplayvalign} to
expand to nothing.

You can use the \displayopt{tabular-env} option instead, which will
also redefine \gls{dtldisplayvalign}.

\cmddef{dtldisplayvalign}
The expansion of this command should be the vertical alignment
specifier for the optional argument of \env{tabular}. 
(Only used with \gls{DTLdisplaydb}.) This may be redefined to empty
if the optional argument should be omitted.

For example, to switch to \env{tblr} (provided by \sty{tabularray}):
\begin{codebox}
\cmd{renewcommand}\marg{\gls{dtldisplaydbenv}}\marg{tblr}
\cmd{renewcommand}\marg{dtldisplayvalign}\marg{}
\end{codebox}

\cmddef{dtldisplaylongdbenv}
This should expand to the environment name used by
\gls{DTLdisplaylongdb}. For example, to switch to \env{longtabu}
(provided by \sty{tabu}):
\begin{codebox}
\cmd{renewcommand}\marg{\gls{dtldisplaylongdbenv}}\marg{longtabu}
\end{codebox}

Alternatively, you can use the \displayopt{longtable-env} option
to redefine \gls{dtldisplaylongdbenv}.

\cmddef{dtlstringalign}
The expansion of this command should be the column alignment
specifier for columns with the string data type.
The option \displayopt{string-align} redefines this command.
Not used if \displayopt{align-specs} is set to a non-empty value.

\cmddef{dtlintalign}
The expansion of this command should be the column alignment
specifier for columns with the integer data type.
The option \displayopt{integer-align} (or \displayopt{int-align})
redefines this command.
Not used if \displayopt{align-specs} is set to a non-empty value.

\cmddef{dtlrealalign}
The expansion of this command should be the column alignment
specifier for columns with the decimal (real) data type.
The option \displayopt{decimal-align} (or \displayopt{real-align})
redefines this command.
Not used if \displayopt{align-specs} is set to a non-empty value.

\cmddef{dtlcurrencyalign}
The expansion of this command should be the column alignment
specifier for columns with the currency data type. 
The option \displayopt{currency-align} redefines this command.
Not used if \displayopt{align-specs} is set to a non-empty value.

\cmddef{dtlbeforecols}
The expansion of this command is inserted at the start of the
alignment specification. The option \displayopt{pre-col} redefines
this command. Not used if \displayopt{align-specs} is set to a non-empty value.

\cmddef{dtlbetweencols}
The expansion of this command is inserted between columns in the
alignment specification. The option \displayopt{inter-col} redefines
this command. Not used if \displayopt{align-specs} is set to a non-empty value.

\cmddef{dtlaftercols}
The expansion of this command is inserted at the end of the
alignment specification. The option \displayopt{post-col} redefines
this command. Not used if \displayopt{align-specs} is set to a non-empty value.

\cmddef{dtldisplaycr}
The expansion text of this command is inserted between rows. The default
definition is \gls{tabularnewline} rather than \gls{cs.bksl} as
\gls{cs.bksl} can interfere with paragraph columns. This allows
\gls{dtlstringalign} to be redefined to \code{p} where the final
column has the string data type.

\begin{information}
The following are robust commands.
\end{information}

\cmddef{DTLdisplaydbAddItem}
This command is used to append an item to the \meta{content-tl-var}
token list variable. The \meta{fmt-cs} argument is the formatting
command applicable to the data type (such as \gls{dtlstringformat}).
The default definition of this command simply appends 
\code{\meta{fmt-cs}\margm{item}} to \meta{content-tl-var}. The remaining
arguments are ignored by default.

The \meta{type} argument is an integer representing the data type,  
the \meta{row-idx} argument is the index to the row in the database
that contains \meta{item}, and the \meta{col-idx} argument is the
index to the column in the database that contains \meta{item}.

The \meta{row-num} and \meta{col-num} arguments correspond to the
value of the integer variables that are incremented for each
included row and each included column, respectively. If you use the
default options, then these will be the same as the row index and
column index, but if you change the order of the columns or exclude
columns or filter out rows or change the mapping from the loop index
to the row index, then they will be different.

With \displayoptval{per-row}{1}, the \meta{row-num} will correspond to
the \env{tabular} (or \env{longtable}) row of data, excluding
the header and any rows inserted by hooks. So the first row
following the header will have \meta{row-num} equal to 1. If all
rows in the database are included, then this will also correspond to
the database row index. However, if some rows are excluded via the
filter function, then the \meta{row-num} may be less than the
corresponding row index.

Similarly, the \meta{col-num} will correspond to the \env{tabular}
(or \env{longtable}) column number. So \meta{col-num} will be 1 for
the first displayed column but this may not be the first column in
the database.

It becomes more complicated if \displayopt{per-row} is greater than
1, as the column number \meta{col-num} will be reset to 1 at the
start of each included database row. The row number \meta{row-num}
is incremented at the start of each included database row. So the
first line of the table after the header row will start with
\meta{row-num} equal to 1 but then \meta{row-num} will be 2 at the
start of the next block of data, which is on the same line of the
table.

This means that if you want to redefine \gls{DTLdisplaydbAddItem} to
insert content at the start of a row, you can test if \meta{col-num}
is 1 if you know that \displayoptval{per-row}{1} but if you want to
take into account multiple rows of data per tabular row then you
need to use the following (which requires \LaTeX3 syntax enabled):
\cmddef{datatoolifrowstart:nn}
If \displayoptval{per-row}{1} then this just tests if \meta{col-num}
is 1, otherwise it will perform modulo arithmetic on \meta{row-num}
to determine if \meta{col-num} corresponds to the first column.

The \displayopt{per-row} option sets the integer variable
\gls{ldatatooldisplayperrowint}, which may be used in the definition
of \gls{DTLdisplaydbAddItem} for more complex requirements.
(See \exampleref{ex:displaydbstripyrepeatcols} in 
\sectionref{sec:displaydbstripyrepeatcols}.)

A token list variable \meta{align-token-tl} is used to contain the
alignment specification that will then be passed to the alignment
argument of the \env{tabular} or \env{longtable} environment. For
each column to be shown in the table (omitting any that have been
filter by the options), the following command is used to append to
\meta{align-token-tl}:
\cmddef{dtladdalign}
The \meta{type} is the numeric identifier indicating the column data
type, \meta{col-num} is the (\env{tabular} or \env{longtable}) column number
(not the column index) and \meta{max-cols} is the total number of
columns to be displayed.

\begin{information}
The \gls{dtladdalign} command won't be used if \displayopt{align-specs} 
is set to a non-empty value. Instead, \meta{align-token-tl} will be
set to the value of \displayopt{align-specs}.
\end{information}

The \meta{type} argument determines whether to append the expansion
text of \gls{dtlstringalign}, \gls{dtlintalign}, \gls{dtlrealalign} or
\gls{dtlcurrencyalign} to \meta{align-token-tl}.

The last two arguments determine whether to add the expansion text
of \gls{dtlbeforecols} ($\meta{col-num}=1$), \gls{dtlaftercols}
($\meta{col-num}=\meta{max-cols}$) or \gls{dtlbetweencols}
($1<\meta{col-num}\leq\meta{max-cols}$). Note that
\gls{dtlaftercols} is placed after the alignment specifier, so that
it occurs at the end, whereas \gls{dtlbeforecols} and
\gls{dtlbetweencols} are placed before.

\cmddef{DTLdisplaydbAddBegin}
Used by \gls{DTLdisplaydb} to add the beginning of the \env{tabular}
environment to the \meta{content-tl-var} token list variable. The
\meta{align-spec} argument is the content of the
\meta{align-token-tl} token list variable containing
the column alignment specification (created with \gls{dtladdalign}),
and the \meta{header} argument is the token list 
containing the header row (where each column header is encapsulated
with \gls{dtlheaderformat}).

The tokens added to \meta{content-tl-var} will be in the form:
\begin{compactcodebox}
\cbeg{\meta{tab-env}}\oargm{v-align}\margm{align-spec}
\meta{pre-header} \meta{header} \meta{post-head} \meta{cr}
\meta{after-head}
\end{compactcodebox}
where \meta{tab-env} is the expansion of \gls{dtldisplaydbenv}, 
\meta{v-align} is the expansion text of
\gls{dtldisplayvalign}, \meta{pre-header} is the
expansion text of \gls{dtldisplaystarttab}, \meta{cr} is
the expansion text of \gls{dtldisplaycr}, and \meta{after-head} is
the expansion text of \gls{dtldisplayafterhead}. 
The \oargm{v-align} optional argument will be omitted if \gls{dtldisplayvalign} is
empty.

\begin{information}
The \displayopt{align-specs} option can be used to set
\meta{align-spec} explicitly, the \displayopt{header-row} option can
be used to set \meta{header} explicitly, and the
\displayopt{no-header} option will omit 
\meta{pre-header} \meta{header} \meta{post-head} \meta{cr}
\meta{after-head}.
\end{information}

\cmddef{DTLdisplaydbAddEnd}
Adds the end \env{tabular} code to \meta{content-tl-var} for
\gls{DTLdisplaydb}. This consists of:
\begin{compactcodebox}
\meta{final-content}\cend{\meta{tab-env}}
\end{compactcodebox}
where \meta{final-content} is the expansion text of
\gls{dtldisplayendtab}, and \meta{tab-env} is the expansion of
\gls{dtldisplaydbenv}, 

For example, if you want to use \env{tblr} (provided by
\sty{tabularray}) instead of \env{tabular} and you don't need all
the hooks:
\begin{codebox*}
\cmd{RenewDocumentCommand}\gls{DTLdisplaydbAddBegin}\marg{mmm}\marg{\comment{}
 \gls{appto}\#1\marg{\cbeg{tblr}\marg{\#2}\#3\gls{cs.bksl}}\comment{}
}
\cmd{RenewDocumentCommand}\gls{DTLdisplaydbAddEnd}\marg{m}\marg{\comment{}
 \gls{appto}\#1\marg{\cend{tblr}}\comment{}
}
\end{codebox*}

\cmddef{DTLdisplaylongdbAddBegin}
Analogous to \gls{DTLdisplaydbAddBegin} but used by
\gls{DTLdisplaylongdb} to add the start of the \env{longtable}
environment to \meta{content-tl-var}. This is more complicated than
\gls{DTLdisplaydbAddBegin} as it also inserts the caption, label and
footer, according to the \displayopt{caption},
\displayopt{short-caption}, \displayopt{cont-caption},
\displayopt{label}, \displayopt{foot}, and \displayopt{last-foot}
options.

\cmddef{DTLdisplaylongdbAddEnd}
Adds the end \env{longtable} code to \meta{content-tl-var} for
\gls{DTLdisplaylongdb}. This consists of:
\begin{compactcodebox}
\meta{final-content}\cend{longtable}
\end{compactcodebox}
where \meta{final-content} is the expansion text of
\gls{dtldisplayendtab}.

\cmddef{DTLdisplayTBrowidxmap}
Provided for use with \displayopt{row-idx-map-function},
this command expands to a row index that will arrange data rows from
top to bottom instead of left to right when \displayopt{per-row} is
greater than 1. Note that this is only designed to work when no rows
are omitted.

The following variables require \LaTeX3 syntax enabled and are used
in some of the above commands.

\cmddef{ldatatoolcaptiontl}
A token list assigned by the \displayopt{caption} key.

\cmddef{ldatatoolshortcaptiontl}
A token list assigned by the \displayopt{short-caption} key.

\cmddef{ldatatoolcontcaptiontl}
A token list assigned by the \displayopt{cont-caption} key.

\cmddef{ldatatoollabeltl}
A token list assigned by the \displayopt{label} key.

\cmddef{ldatatoolfoottl}
A token list assigned by the \displayopt{foot} key.

\cmddef{ldatatoollastfoottl}
A token list assigned by the \displayopt{last-foot} key.

\cmddef{ldatatoolpostheadtl}
A token list assigned by the \displayopt{post-head} key.

\cmddef{ldatatoolincludeheaderbool}
A boolean variable corresponding to the inverse of the
\displayopt{no-header} key.

\cmddef{ldatatooldisplayperrowint}
Set by the \displayopt{per-row} option.

\cmddef{ldatatooldisplaytabrowsint}
This integer variable is set to the number of rows in the database
divided by \gls{ldatatooldisplayperrowint} rounded up. Bare in mind
that this doesn't take any filtering into account. It's used in
\gls{DTLdisplayTBrowidxmap} to calculate the loop index to row index
mapping.%
\glsendrange{DTLdisplaydb,DTLdisplaydb*,DTLdisplaylongdb}%

\subsection{Examples}
\label{sec:displaydbexs}

\subsubsection{Changing the Alignment}
\label{sec:displaydbalignspecs}

\mExampleref{ex:displaydbalignspecs} uses the \qt{product} database
(see \sectionref{sec:productdb}).
This database is short enough to be produced on a single
page within a \env{tabular} environment:
\begin{codebox}
\gls{DTLdisplaydb}\marg{products}
\end{codebox}
The database has five columns and some of the titles (in the first
column) are quite long, which can lead to an overly wide table. It
would be better to allow line wrapping. This can be done by changing
the string column alignment (\displayopt{string-align}) but this
would also affect the second and third columns. In this case, it's
simpler to use \displayopt{align-specs} to override the default
alignments for all the columns. \Exampleref{ex:displaydbalignspecs}
has:
\begin{codebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{align-specs}{p\marg{0.4\cmd{linewidth}}llrr}}\marg{products}
\end{codebox}
\begin{resultbox}[float]
\createexample*[label=ex:displaydbalignspecs,
 tag={product},link={sec:displaydbalignspecs},
 title={Display Data with Custom Alignment},
 description={Example document illustrating how to display data in a
\envfmt{tabular} environment with custom column alignment}
]
{%
 \cmd{usepackage}\marg{datatool}\nl
\productdb
}
{%
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{align-specs}{p\marg{0.4\cmd{linewidth}}llrr}}\marg{products}
}
\end{resultbox}

\subsubsection{Omitting Columns}
\label{sec:displaydbomit}

\examplemarginref{ex:displaydbomit}
\begin{information}
\Exampleref{ex:displaydbomit} uses the \qt{product} database
(see \sectionref{sec:productdb}).
\end{information}

The unstarred version of \gls{DTLdisplaydb} has an optional argument that must be a
comma-separated list of column keys that identify which columns
to omit. For example, if I want to omit the Quantity and Price
columns:
\begin{codebox}
\gls{DTLdisplaydb}\oarg{Quantity,Price}\marg{products}
\end{codebox}
With the starred version, the optional argument is a \keyval\ list:
\begin{codebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{omit-keys}{Quantity,Price}}\marg{products}
\end{codebox}
Alternatively:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptvalm{options}{\displayoptvalm{omit-keys}{Quantity,Price}}}\marg{\action{display}}
\end{codebox}
These all produce the table shown in \exampleref{ex:displaydbomit}.
\begin{resultbox}[float]
\createexample*[label=ex:displaydbomit,
 tag={product},link={sec:displaydbomit},
 title={Display Data in a Table Omitting Columns},
 description={Example document illustrating how to display data in a
\envfmt{tabular} environment with two columns omitted}
]
{%
 \cmd{usepackage}\marg{datatool}\nl
\productdb
}
{%
\gls{DTLaction}\oarg{\actionoptvalm{options}{\displayoptvalm{omit-keys}{Quantity,Price}}}\marg{\action{display}}
}
\end{resultbox}

\subsubsection{Column Inclusion List}
\label{sec:displaydbonly}

\examplemarginref{ex:displaydbonly}
\begin{information}
\Exampleref{ex:displaydbonly} uses the \qt{product} database
(see \sectionref{sec:productdb}).
\end{information}

As an alternative to the previous example, you may prefer to list the 
columns you want (an
inclusion list). The following indicates that the Author, Title and
Price columns should be include. The other columns will be omitted:
\begin{codebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{only-keys}{Author,Title,Price}}\marg{products}
\end{codebox}
Or:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptvalm{options}{\displayoptvalm{only-keys}{Author,Title,Price}}}\marg{\action{display}}
\end{codebox}
These all produce the table shown in \exampleref{ex:displaydbonly}.
\begin{resultbox}[float]
\createexample*[label=ex:displaydbonly,
 tag={product},link={sec:displaydbonly},
 title={Display Data in a Table with Named Columns},
 description={Example document illustrating how to display data in a
\envfmt{tabular} environment with the specified columns}
]
{%
 \cmd{usepackage}\marg{datatool}\nl
\productdb
}
{%
\gls{DTLaction}\oarg{\actionoptvalm{options}{\displayoptvalm{only-keys}{Author,Title,Price}}}\marg{\action{display}}
}
\end{resultbox}

Note that with \displayopt{only-keys} and \displayopt{only-columns}, the
table column order will match the listed columns. Whereas with
\displayopt{omit-keys} and \displayopt{omit-columns}, the table
column order will be in the order that the columns were added to the
database.

\subsubsection{Skipping Rows}
\label{sec:displaydbcond}

\examplemarginref{ex:displaydbcond}
\begin{information}
\Exampleref{ex:displaydbcond} uses the \qt{product} database
(see \sectionref{sec:productdb}).
\end{information}

The \displayopt{row-condition-inline} option provides a way to omit rows.
If the condition is quite complicated, you may prefer to define a
handler function and reference it with
\displayopt{row-condition-function}. 

In \exampleref{ex:displaydbcond}, a command called
\csfmt{productfilter} is defined which fetches the value from the
\qt{Quantity} column from the \idx{current-row} and only includes rows
where that value is greater than zero: 
\begin{codebox}
\cmd{newcommand}\marg{\cmd{productfilter}}[3]\marg{\comment{}
 \gls{dtlgetentryfromcurrentrow}
   \marg{\cmd{theQuantity}}\comment{}
   \marg{\gls{dtlcolumnindex}\marg{\gls{dtldbname}}\marg{Quantity}}\comment{}
  \gls{DTLifnumgt}\marg{\cmd{theQuantity}}\marg{0}\marg{\#3}\marg{}\comment{} 
}
\end{codebox}
This command can now be used as the filter function:
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptvalm{options}{
   \displayoptval{row-condition-function}{\cmd{productfilter}},
   \displayoptvalm{only-keys}{Title,Quantity,Price}
 }
}\marg{\action{display}}
\end{codebox} 

\begin{resultbox}[float]
\createexample*[label=ex:displaydbcond,
 tag={product},link={sec:displaydbcond},
 title={Display Data in a Table with Filtered Rows},
 description={Example document illustrating how to display data in a
\envfmt{tabular} environment without certain rows}
]
{%
\cmd{usepackage}\marg{datatool}\nl
\productdb
\codepar
\cmd{newcommand}\marg{\cmd{productfilter}}[3]\marg{\comment{}
 \gls{dtlgetentryfromcurrentrow}\nlsp
   \marg{\cmd{theQuantity}}\comment{}
   \marg{\gls{dtlcolumnindex}\marg{\gls{dtldbname}}\marg{Quantity}}\comment{}
  \gls{DTLifnumgt}\marg{\cmd{theQuantity}}\marg{0}\marg{\#3}\marg{}\comment{}%
}
}
{%
\gls{DTLaction}\oarg{\nlsp
 \actionoptvalm{options}{\nldbsp
   \displayoptval{row-condition-function}{\cmd{productfilter}},\nldbsp
   \displayoptvalm{only-keys}{Title,Quantity,Price}\nlsp
 }\nl
}\marg{\action{display}}
}
\end{resultbox}

\subsubsection{Referencing Rows}
\label{sec:displayrowref}

\examplemarginref{ex:displayrowref}
\begin{information}
\Exampleref{ex:displayrowref} uses the \qt{marks} database
(see \sectionref{sec:marks}).
\end{information}

Unlike \gls{DTLforeach}, there is no associated row counter for the display commands. 
However, you can borrow the \gls{DTLforeach} counters as long as there is no conflict. 
\Exampleref{ex:displayrowref} does this to number and label each row. Note that labels
must be unique. This can be achieved if the database has a column that contains unique 
values. For the marks database, this is the student number.

The \gls{DTLdisplaydbAddItem} hook can be redefined to increment the counter
and insert the label at the start of each row. The start of the row is determined
by testing if the seventh argument of \gls{DTLdisplaydbAddItem} (\meta{col-num})
is one. The \action{current-row-values} action can be used to fetch the student number
for the \idx{current-row}.

This can either be done using \LaTeX3 syntax:
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} 
  \marg{ m m m m m m m m } 
\marg{
  \cmd{int\_compare:nNnT} \marg{ \#7 } = \marg{ \cmd{c\_one\_int} }
   \marg{
    \gls{DTLaction}\oarg{ \actionoptvalm{return}{ \cmd{StudentNo} = StudentNo } }
      \marg{ \glslink{opt.actionname.current-row-values}{current \idx*{l3sp} row \idx*{l3sp} values} }
    \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{DTLrowincr} \gls{label} }
    \cmd{tl\_put\_right:Nx} \#1 \marg{ \marg{ \cmd{StudentNo} } }
   }
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
}
\gls{ExplSyntaxOff}
\end{codebox}
or with \sty{etoolbox} commands:
\begin{codebox}
\cmd{RenewDocumentCommand}\gls{DTLdisplaydbAddItem}\marg{ m m m m m m m m }\marg{\comment{}
 \cmd{ifnum} \#7 = 1
   \gls{DTLaction}\oarg{\actionoptvalm{return}{\cmd{StudentNo} = StudentNo}}
     \marg{\action{current-row-values}}\comment{}
   \cmd{appto}\#1\marg{\gls{DTLrowincr}\gls{label}}\comment{}
   \cmd{eappto}\#1\marg{\marg{\cmd{StudentNo}}}\comment{}
 \cmd{fi}
 \cmd{appto}\#1\marg{\#3\marg{\#2}}\comment{}
}
\end{codebox}
In either case, this modification ensures that the first column of each row starts with:
\begin{compactcodebox}
\gls{DTLrowincr}\gls{label}\margm{StudentNo}
\end{compactcodebox}
where \meta{StudentNo} is the value of the \optfmt{StudentNo} entry for the \idx{current-row}.

Note that it's not necessary for the student number to be displayed in the table.
The information is obtained by looking up the value with the \action{current-row-values} action.
An alternative method is to find out which column the student number is in and insert the code
into the start of that column. This can either be done by referencing the display column number
argument (\meta{col-num}) or the database column index argument (\meta{col-idx}).

The counter needs to be reset before the data is displayed:
\begin{codebox*}
\gls{DTLrowreset}
\end{codebox*}
The data can then be displayed:
\begin{codebox}
\gls{DTLaction}\marg{\action{display}}
\end{codebox}
and a particular row can be referenced:
\begin{codebox}
Row \gls{ref}\marg{103569} shows the details for student 103569.
\end{codebox}
Or if you need to look up the registration number from the student's name:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{assign}{
    \cmd{Surname}=Surname,
    \cmd{Forename}=Forename,
    \cmd{StudentNo}=StudentNo
  },
  \actionoptvalm{options}{
    \actionfindoptvalm{inline}{\comment{}
     \gls{DTLifstringeq}\marg{\cmd{Surname}}\marg{Brown}
     \marg{\gls{DTLifstringeq}\marg{\cmd{Forename}}\marg{Andy}\marg{\#1}\marg{}}\marg{}\comment{}
    }
  }
}\marg{\action{find}}
Row \gls{ref}\marg{\cmd{StudentNo}} shows the details for Andy Brown.
\end{codebox}
(This method can't be used for Jane Brown, as there are two students with that name.)

\begin{resultbox}
\createexample*
 [label={ex:displayrowref},arara={pdflatex,pdflatex,pdfcrop},
  title={Referencing Rows from Displayed Data},
  tag={marks},link={sec:displayrowref},
  description={An example document that loads data from a CSV file
and references a row}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
\gls{ExplSyntaxOn}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \nlsp
  \marg{ m m m m m m m m }\nl 
\marg{\nlsp
  \cmd{int\_compare:nNnT} \marg{ \#7 } = \marg{ \cmd{c\_one\_int} }\nlsp
   \marg{\nldbsp
    \gls{DTLaction}\oarg{ \actionoptvalm{return}{ \cmd{StudentNo} = StudentNo } }\nldbsp
      \marg{ current ~ row ~ values }\nldbsp
    \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{DTLrowincr} \gls{label} }\nldbsp
    \cmd{tl\_put\_right:Nx} \#1 \marg{ \marg{ \cmd{StudentNo} } }\nlsp
   }\nlsp
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nl
}\nl
\gls{ExplSyntaxOff}
}
{%
\gls{DTLrowreset}\nl
\gls{DTLaction}\marg{\action{display}}
\codepar
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    \cmd{Surname}=Surname,\nldbsp
    \cmd{Forename}=Forename,\nldbsp
    \cmd{StudentNo}=StudentNo\nlsp
  },\nlsp
  \actionoptvalm{options}{\nldbsp
    \actionfindoptvalm{inline}{\comment{}\dbspace
     \gls{DTLifstringeq}\marg{\cmd{Surname}}\marg{Brown}\nldbsp
     \marg{\gls{DTLifstringeq}\marg{\cmd{Forename}}\marg{Andy}\marg{\#1}\marg{}}\marg{}\comment{}\dbspace
    }\nlsp
  }\nl
}\marg{\action{find}}\nl
Row \gls{ref}\marg{\cmd{StudentNo}} shows the details for Andy Brown.
}
\end{resultbox}

Note that this example doesn't show the value of the counter. This can be added with 
a slight adjustment to the code in the modified \gls{DTLdisplaydbAddItem}
to show the counter value after it has been incremented. For the 
\LaTeX3 version, the change is:
\begin{codebox}
\cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{DTLrowincr} \gls{DTLtherow}. \idx{l3sp} \gls{label} }
\end{codebox}
For the \sty{etoolbox} version, the change is:
\begin{codebox}
\cmd{appto}\#1\marg{\gls{DTLrowincr}\gls{DTLtherow}. \gls{label}}\comment{}
\end{codebox}
This puts the value at the start of the surname column. \Exampleref{sec:displayinsertcol}
below places the value in a separate column.

\subsubsection{Inserting an Extra Column at the Start}
\label{sec:displayinsertcol}

\examplemarginref{ex:displayinsertcol}
\begin{information}
\Exampleref{ex:displayinsertcol} uses the \qt{marks} database
(see \sectionref{sec:marks}).
\end{information}

The previous \exampleref{ex:displayrowref} incremented a counter at the start of each
row with \gls{refstepcounter} and added a label, but the value of the counter wasn't 
shown, although a modification was suggested that would put the value at the start of 
the first column (which contains the surname).

\Exampleref{ex:displayinsertcol} modifies \exampleref{ex:displayrowref} to insert 
an extra column at the start that has the counter value. This means that the alignment
and header information will need to be adjusted.

First, \gls{DTLdisplaydbAddItem} needs to insert an extra alignment. For the \LaTeX3
code, the modification is:
\begin{codebox}
\cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{DTLrowincr} \gls{label} }
\cmd{tl\_put\_right:Nx} \#1 \marg{ \marg{ \cmd{StudentNo} } }
\cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{DTLtherow} \idx{amp} }
\end{codebox}
For the \sty{etoolbox} version, the change is:
\begin{codebox}
\cmd{appto}\#1\marg{\gls{DTLrowincr}\gls{label}}\comment{}
\cmd{eappto}\#1\marg{\marg{\cmd{StudentNo}}}\comment{}
\cmd{appto}\#1\marg{\gls{DTLtherow} \idx{amp}}\comment{}
\end{codebox}
The extra column can be added to the alignment specifier using \displayopt{pre-col}
and a corresponding header (possibly empty) needs to be inserted into the header row:
\begin{codebox}
\gls{DTLrowreset}
\gls{DTLaction}\oarg{
 \actionoptvalm{options}{
   \displayoptvalm{pre-col}{r},
   \displayoptvalm{pre-head}{\cmd{bfseries} Row \idx{amp}}
 }
}\marg{\action{display}}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:displayinsertcol},arara={pdflatex,pdflatex,pdfcrop},
  title={Inserting a Column at the Start of Displayed Data},
  tag={marks},link={sec:displayinsertcol},
  description={An example document that loads data from a CSV file
and inserts a column at the start showing the row number which can be referenced}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
\gls{ExplSyntaxOn}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \nlsp
  \marg{ m m m m m m m m }\nl 
\marg{\nlsp
  \cmd{int\_compare:nNnT} \marg{ \#7 } = \marg{ \cmd{c\_one\_int} }\nlsp
   \marg{\nldbsp
    \gls{DTLaction}\oarg{ \actionoptvalm{return}{ \cmd{StudentNo} = StudentNo } }\nldbsp
      \marg{ current ~ row ~ values }\nldbsp
     \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{DTLrowincr} \gls{label} }\nldbsp
     \cmd{tl\_put\_right:Nx} \#1 \marg{ \marg{ \cmd{StudentNo} } }\nldbsp
     \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{DTLtherow} \string& }\nlsp
   }\nlsp
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nl
}\nl
\gls{ExplSyntaxOff}
}
{%
\gls{DTLrowreset}\nl
\gls{DTLaction}\oarg{\nlsp
 \actionoptvalm{options}{\nldbsp
   \displayoptvalm{pre-col}{r},\nldbsp
   \displayoptvalm{pre-head}{\cmd{bfseries} Row \string&}\nlsp
 }\nl
}\marg{\action{display}}
\codepar
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    \cmd{Surname}=Surname,\nldbsp
    \cmd{Forename}=Forename,\nldbsp
    \cmd{StudentNo}=StudentNo\nlsp
  },\nlsp
  \actionoptvalm{options}{\nldbsp
    \actionfindoptvalm{inline}{\comment{}\dbspace
     \gls{DTLifstringeq}\marg{\cmd{Surname}}\marg{Brown}\nldbsp
     \marg{\gls{DTLifstringeq}\marg{\cmd{Forename}}\marg{Andy}\marg{\#1}\marg{}}\marg{}\comment{}\dbspace
    }\nlsp
  }\nl
}\marg{\action{find}}\nl
Row \gls{ref}\marg{\cmd{StudentNo}} shows the details for Andy Brown.
}
\end{resultbox}

\subsubsection{Adding an Extra Column at the End}
\label{sec:displaydbpostrow}

\examplemarginref{ex:displaydbpostrow}
\begin{information}
\Exampleref{ex:displaydbpostrow} uses the \qt{product} database
(see \sectionref{sec:productdb}).
\end{information}

The previous \exampleref{ex:displayinsertcol} inserted an extra column at the
start.  Extra columns can be added to the end using a similar manner.
\Exampleref{ex:displaydbpostrow} uses a slightly different approach that uses
the post-row function and explicitly sets the alignment specification
(\displayopt{align-specs}) and appends the extra column header with
\displayopt{post-head}.

\Exampleref{ex:displaydbpostrow} has an extra column with the header
\qt{Total} that contains the value obtained by multiplying the
quantity by the price. The \sty{booktabs} package is required for
the horizontal rules.

\begin{codebox*}
\cmd{newcommand}\marg{\cmd{productappendtotal}}[2]\marg{\comment{}
 \gls{DTLaction}\oarg{
   \actionoptvalm{return}{
     \cmd{theQuantity}=Quantity,
     \cmd{thePrice}=Price
   }
 }\marg{\action{current-row-values}}\comment{}
  \gls{DTLmul}\marg{\cmd{theTotal}}\marg{\cmd{theQuantity}}\marg{\cmd{thePrice}}\comment{}
  \gls{DTLround}\marg{\cmd{theTotal}}\marg{\cmd{theTotal}}\marg{2}\comment{}
  \gls{appto}\#1\marg{\idx{amp}}\comment{}
  \gls{eappto}\#1\marg{\gls{expandonce}\cmd{theTotal}}\comment{}
  \gls{DTLadd}\marg{\cmd{runningtotal}}\marg{\cmd{runningtotal}}\marg{\cmd{theTotal}}\comment{}
}
\gls{DTLaction}\oarg{
 \actionoptvalm{options}{
   \displayoptvalm{only-keys}{Title,Quantity,Price},
   \displayoptvalm{pre-head}{\gls{toprule}},
   \displayoptvalm{after-head}{\gls{midrule}},
   \displayoptvalm{align-specs}{lrrr},
   \displayoptvalm{post-head}{\idx{amp} \gls{dtlcolumnheader}\marg{c}\marg{Total}},
   \displayoptvalm{init}{\cmd{def}\cmd{runningtotal}\marg{0}},
   \displayoptval{post-row-function}{\cmd{productappendtotal}},
   \displayoptvalm{foot}{\gls{midrule} \idx{amp} \idx{amp} \idx{amp} \cmd{runningtotal}}
 }
}\marg{\action{display}}
\end{codebox*} 

\begin{resultbox}[float]
\createexample*[label=ex:displaydbpostrow,
 tag={product},link={sec:displaydbpostrow},
 title={Display Data in a Table with an Extra Column},
 description={Example document illustrating how to display data in a
\envfmt{tabular} environment with a custom column appended}
]
{%
\cmd{usepackage}\marg{booktabs}\nl
\cmd{usepackage}\marg{datatool}\nl
\productdb
\codepar
\cmd{newcommand}\marg{\cmd{productappendtotal}}[2]\marg{\comment{}
 \gls{DTLaction}\oarg{\nlsp
   \actionoptvalm{return}{
     \cmd{theQuantity}\dequals Quantity,
     \cmd{thePrice}\dequals Price
   }\nlsp
 }\marg{\action{current-row-values}}\comment{}
  \gls{DTLmul}\marg{\cmd{theTotal}}\marg{\cmd{theQuantity}}\marg{\cmd{thePrice}}\comment{}
  \gls{DTLround}\marg{\cmd{theTotal}}\marg{\cmd{theTotal}}\marg{2}\comment{}
  \gls{appto}\#1\marg{&}\comment{}
  \gls{eappto}\#1\marg{\gls{expandonce}\cmd{theTotal}}\comment{}
  \gls{DTLadd}\marg{\cmd{runningtotal}}\marg{\cmd{runningtotal}}\marg{\cmd{theTotal}}\comment{}%
}
}
{%
\gls{DTLaction}\oarg{\nlsp
 \actionoptvalm{options}{\nldbsp
   \displayoptvalm{only-keys}{Title,Quantity,Price},\nldbsp
   \displayoptvalm{pre-head}{\gls{toprule}},\nldbsp
   \displayoptvalm{after-head}{\gls{midrule}},\nldbsp
   \displayoptvalm{align-specs}{lrrr},\nldbsp
   \displayoptvalm{post-head}{&
\gls{dtlcolumnheader}\marg{c}\marg{Total}},\nldbsp
   \displayoptvalm{init}{\cmd{def}\cmd{runningtotal}\marg{0}},\nldbsp
   \displayoptval{post-row-function}{\cmd{productappendtotal}},\nldbsp
   \displayoptvalm{foot}{\gls{midrule}  & & &
\cmd{runningtotal}}\nlsp
 }\nl
}\marg{\action{display}}
}
\end{resultbox}

\subsubsection{Altering Individual Cell Formatting}
\label{sec:balancesheet}

\examplemarginref{ex:balancesheet}
\begin{information}
\Exampleref{ex:balancesheet} uses the \qt{balance} database
(see \sectionref{sec:balancecsv}).
\end{information}

The \qt{balance} database contains numeric data.
Since the numbers will be repeatedly parsed, it's best to switch on
the \opt{store-datum} setting. A default name for
the database can be set at the same time:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{balance}}
\end{codebox}
Suppose now that the negative numbers should be shown in red. This
can be done by redefining \gls{dtlrealformat}:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{dtlrealformat}}[1]\marg{\gls{DTLiflt}\marg{\#1}\marg{0}\marg{\gls{color}\marg{red}}\marg{}\#1}
\end{codebox}
An alternative method is to redefine \gls{DTLdisplaydbAddItem} to
perform the test for a particular column, in this case column 4 (the
balance). This also conveniently provides a way to total the
incoming and outgoing columns (columns 2 and~3).
Note that some cells are empty so these are skipped.
\begin{codebox}
\cmd{newcommand}\marg{\cmd{theInTotal}}\marg{0}
\cmd{newcommand}\marg{\cmd{theOutTotal}}\marg{0}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }
\marg{\comment{}
 \gls{DTLifnullorempty}\marg{\#2}\marg{}\comment{skip null or empty}
 \marg{\comment{}
  \gls{dtlifnumeq}\marg{\#8}\marg{4}\comment{balance column}
  \marg{\comment{}
    \gls{DTLifnumlt}\marg{\#2}\marg{0}\marg{\gls{appto}\#1\marg{\gls{color}\marg{red}}}\marg{}\comment{}
  }\comment{}
  \marg{\comment{}
    \gls{dtlifnumeq}\marg{\#8}\marg{2}\comment{in column}
    \marg{\gls{DTLadd}\marg{\cmd{theInTotal}}\marg{\cmd{theInTotal}}\marg{\#2}}\comment{}
    \marg{\comment{}
      \gls{dtlifnumeq}\marg{\#8}\marg{3}\comment{out column}
       \marg{\gls{DTLadd}\marg{\cmd{theOutTotal}}\marg{\cmd{theOutTotal}}\marg{\#2}}\marg{}\comment{}
    }\comment{}
  }\comment{}
  \gls{appto}\#1\marg{\#3\marg{\#2}}\comment{}
 }\comment{}
}
\end{codebox}
The totals can then be appended with the \displayopt{foot} option.
As with the previous example, I've added rules provided by
\sty{booktabs}:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptvalm{options}{
   \displayoptvalm{after-head}{\cmd{midrule}},
   \displayoptvalm{foot}{\cmd{midrule} Totals \idx{amp} \cmd{theInTotal} \idx{amp} \cmd{theOutTotal} \idx{amp}}
 }
}\marg{\action{display}}
\end{codebox}

Note that the eighth argument of \gls{DTLdisplaydbAddItem}
(\meta{col-idx}) is the column index, which will always be an
integer, so an integer comparison can be used instead of
the decimal \gls{dtlifnumeq}. (Likewise for the \meta{type}, \meta{row-num},
\meta{row-idx} and \meta{col-num} arguments.) Since the
\opt{store-datum} option has been set, the second argument
(\meta{item}) will be in the \idx{datumitem} format except where
it's empty or null, so the actual numeric value can be obtained with
\gls{datatooldatumvalue:Nnnnn}, which will require \LaTeX3 syntax
and the \meta{type} argument can be checked to ensure that the
supplied value is numeric.  If you switch on \LaTeX3 syntax, you may
as well directly use the \styfmt{l3int} and \styfmt{l3fp} commands:

\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{fp\_new:N} \cmd{l\_my\_in\_total\_fp}
\cmd{fp\_new:N} \cmd{l\_my\_out\_total\_fp}
\cmd{newcommand}\marg{\cmd{theInTotal}}\marg{
 \cmd{fp\_to\_decimal:N} \cmd{l\_my\_in\_total\_fp}
}
\cmd{newcommand}\marg{\cmd{theOutTotal}}\marg{
 \cmd{fp\_to\_decimal:N} \cmd{l\_my\_out\_total\_fp}
}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }
\marg{
  \cmd{int\_compare:nNnT} \marg{ \#4 } > \marg{ \gls{cdatatoolstringint} }
   \marg{
    \cmd{int\_case:nn} \marg{ \#8 }
    \marg{
       \marg{ 2 }
        \marg{ 
          \cmd{fp\_add:Nn} \cmd{l\_my\_in\_total\_fp}
            \marg{ \gls{datatooldatumvalue:Nnnnn} \#2 }
        }
       \marg{ 3 }
        \marg{ 
          \cmd{fp\_add:Nn} \cmd{l\_my\_out\_total\_fp}
            \marg{ \gls{datatooldatumvalue:Nnnnn} \#2 }
        }
       \marg{ 4 }
        \marg{
          \cmd{fp\_compare:nNnT}
            \marg{ \gls{datatooldatumvalue:Nnnnn} \#2 } < \marg{ \cmd{c\_zero\_fp} }
           \marg{
             \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{color} \marg{ red } }
           }
        }
     }
   }
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
}
\gls{ExplSyntaxOff}
\end{codebox}
Note that this relies on the data being stored as \idxpl{datumitem}.
If you're not sure if this is the case, you can use \gls{DTLparse},
which will check and convert if required.

\begin{resultbox}
\createexample*
 [label={ex:balancesheet},
  tag={balance},link={sec:balancesheet},titleskip=small,
  title={Adjusting the Item Hook to Calculate Totals and Show Negative Numbers in Red},
  description={Example document that displays a balance sheet as a
table with red negative numbers and an appended row with total incomings and outgoings}
 ]
{%
\exfile{balance.csv}\balancecsv
\cmd{usepackage}\marg{booktabs}\nl
\cmd{usepackage}\marg{color}\nl
\cmd{usepackage}\marg{datatool}
\codepar
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{balance}}
\codepar
\gls{DTLread}\oarg{\nlsp
   \iooptvalm{headers}{\nldbsp
     Description,\nldbsp
     in (\gls{pounds}),\nldbsp
     Out (\gls{pounds}),\nldbsp
     Balance (\gls{pounds})\nlsp
   }\nl
}\marg{balance.csv}
\codepar
\cmd{newcommand}\marg{\cmd{theInTotal}}\marg{0}\nl
\cmd{newcommand}\marg{\cmd{theOutTotal}}\marg{0}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem}
 \marg{ m m m m m m m m }\nl
{\comment{}
  \gls{DTLifnullorempty}\marg{\#2}\marg{}\comment{skip null or empty}
  \marg{\comment{}
  \gls{dtlifnumeq}\marg{\#8}\marg{4}\comment{balance column}
  \marg{\comment{}\dbspace
    \gls{DTLifnumlt}\marg{\#2}\marg{0}\marg{\gls{appto}\#1\marg{\gls{color}\marg{red}}}\marg{}\comment{}
  }\comment{}
  {\comment{}\dbspace
    \gls{dtlifnumeq}\marg{\#8}\marg{2}\comment{in column}\dbspace
    \marg{\gls{DTLadd}\marg{\cmd{theInTotal}}\marg{\cmd{theInTotal}}\marg{\#2}}\comment{}
    \marg{\comment{}\dbspace
      \gls{dtlifnumeq}\marg{\#8}\marg{3}\marg{\gls{DTLadd}\marg{\cmd{theOutTotal}}\marg{\cmd{theOutTotal}}\marg{\#2}}\marg{}\comment{out column}
    }\comment{}
  }\comment{}
  \gls{appto}\#1\marg{\#3\marg{\#2}}\comment{}
  }\comment{}
}
}
{%
\gls{DTLaction}\oarg{\nlsp
 \actionoptvalm{options}{\nldbsp
   after-head={\cmd{midrule}},\nldbsp
   foot={\cmd{midrule} Totals & \cmd{theInTotal} 
   & \cmd{theOutTotal} &}\nlsp
 }\nl
}\marg{display}
}
\end{resultbox}

\subsubsection{Two Database Rows Per Tabular Row (Left to Right)}
\label{sec:displaydbrepeatcols}

\examplemarginref{ex:displaydbrepeatcols}
\begin{information}
\Exampleref{ex:displaydbrepeatcols} uses the \qt{scores} database
(see \sectionref{sec:studentscoresdb}).
\end{information}

To make it clearer how the data is arranged,
\exampleref{ex:displaydbrepeatcols} sorts the data
by surname and then first name.  Since the data contains
\idx{utf8} characters, localisation support is used:
\begin{codebox}
\cmd{usepackage}\oarg{\optval{locales}{en}}\marg{datatool}
\end{codebox}
This requires \sty{datatool-english}, which needs to be installed
separately. The sorting is performed with the \action{sort} action:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptvalm{assign}{surname,forename}}\marg{\action{sort}}
\end{codebox}

In order to save space, you may want two database rows per tabular
row. This can be done with the \displayopt{per-row} option.
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{options}{
    \displayoptval{per-row}{2},
    \displayoptvalm{only-keys}{forename,surname,score}
  }
}\marg{display}
\end{codebox}
This results in the data tabulated with (below the header) 
database row one (Zoë Adams) and two (Roger Brady) on the first line, 
three (Andy Brown) and four (Jane Brown) on the second line, 
five (Quinn Ó Coinn) and six (Evelyn O'Leary) on the third line, and 
seven (John Smith, Jr) and eight (Clare Vernon) on the fourth line. 
That is, the data is arranged from left to
right, shifting down a line every other block of data.
For a top to bottom arrange, see \exampleref{ex:displaydbttb}.

\begin{resultbox}
\createexample*
 [label={ex:displaydbrepeatcols},
  title={Display Two Database Rows Per Tabular Row},
  tag={studentscores},link={sec:displaydbrepeatcols},
  description={An example document that defines data in the document
and displays two rows of data in one tabular row}
]
{%
\cmd{usepackage}\oarg{\optval{locales}{en}}\marg{datatool}\nl
\studentscoresdb
}
{%
\gls{DTLaction}\oarg{\actionoptvalm{assign}{surname,forename}}\marg{\action{sort}}\nl
\gls{DTLaction}\oarg{\nlsp
  options={\nldbsp
    per-row=2,\nldbsp
    only-keys={forename,surname,score}\nlsp
  }\nl
}\marg{display}
}
\end{resultbox}

\subsubsection{Two Database Rows Per Tabular Row (Top to Bottom)}
\label{sec:displaydbttb}

\examplemarginref{ex:displaydbttb}
\begin{information}
\Exampleref{ex:displaydbttb} uses the \qt{scores} database
(see \sectionref{sec:studentscoresdb}).
\end{information}

\Exampleref{ex:displaydbttb} is an alternative to 
\exampleref{ex:displaydbrepeatcols} that has two database rows per
tabular row, but they are now arranged from top to bottom instead of
from left to right.

\begin{warning}
This example won't work if rows are omitted.
\end{warning}

\Exampleref{ex:displaydbttb} is as \exampleref{ex:displaydbrepeatcols}
except that it uses the \displayopt{row-idx-map-function} option to
change the mapping from the loop index to the selected row index:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{options}{
    \displayoptval{per-row}{2},
    \displayoptval{row-idx-map-function}{\gls{DTLdisplayTBrowidxmap}},
    \displayoptvalm{only-keys}{forename,surname,score}
  }
}\marg{display}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:displaydbttb},
  title={Display Two Database Rows Per Tabular Row (Top to Bottom)},
  tag={studentscores},link={sec:displaydbttb},
  description={An example document that defines data in the document
and displays two rows of data in one tabular row arranged from top
to bottom}
]
{%
\cmd{usepackage}\oarg{\optval{locales}{en}}\marg{datatool}\nl
\studentscoresdb
}
{%
\gls{DTLaction}\oarg{\actionoptvalm{assign}{surname,forename}}\marg{\action{sort}}\nl
\gls{DTLaction}\oarg{\nlsp
  options={\nldbsp
    per-row=2,\nldbsp
    row-idx-map-function=\gls{DTLdisplayTBrowidxmap},\nlsp
    only-keys={forename,surname,score}\nlsp
  }\nl
}\marg{display}
}
\end{resultbox}

\subsubsection{Stripy Table}
\label{sec:displaydbstripytable}

\examplemarginref{ex:displaydbstripytable}
\begin{information}
\Exampleref{ex:displaydbstripytable} uses the \qt{marks} database
(see \sectionref{sec:marks}).
\end{information}

The new row command (\gls{tabularnewline} or \gls{cs.bksl}) is
inserted at the start of each row, except for the first row. This is
done after filtering (applied with \displayopt{row-condition-inline}
or \displayopt{row-condition-function}). It can't be done at the end
of the previous row as there's no way of telling at that point if
there will be another row.

This means that although you can use the filter function to insert
code into the content token list variable, that code will be
inserted at the end of the previous row before the new line command.
Therefore, if you want to insert content at the start of a row, it
needs to be done in the \gls{DTLdisplaydbAddItem} command. The
seventh argument of that command is the \env{tabular} (or
\env{longtable}) column number. This may be different from the
eighth argument, which is the database column index. This means that
if you want to insert content at the start of a row, you need to
test if the seventh argument is 1.

\begin{important}
This example assumes the default \displayoptval{per-row}{1}.
See \exampleref{ex:displaydbstripyrepeatcols} for
\displayoptval{per-row}{2}.
\end{important}

The default definition of  \gls{DTLdisplaydbAddItem} uses a \LaTeX3
\styfmt{l3tl} command:
\begin{compactcodebox}
\cmd{NewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }
\marg{
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
}
\end{compactcodebox}
The first argument is the content token list variable, the second
argument is the column content \meta{item} and the third argument is the
formatting command \meta{fmt-cs}. The above definition simply
appends \code{\meta{fmt-cs}\margm{item}} to the token list. This is
equivalent to:
\begin{compactcodebox}
\cmd{NewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }
\marg{\gls{appto}\#1\marg{\#3\marg{\#2}}}
\end{compactcodebox}

\Exampleref{ex:displaydbstripytable} creates a stripy table with
rows alternately coloured blue and green. The \sty{colortbl} package
provides \gls{rowcolor}:
\begin{codebox}
\cmd{usepackage}\marg{colortbl}
\end{codebox}
In order to insert \gls{rowcolor} at the start of a row,
\gls{DTLdisplaydbAddItem} needs to be redefined to test if the
seventh argument is equal to one. The fifth argument is the row
number (excluding the header), so the simplest way to alternate is
to test if that value is odd or even. For example:
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }
\marg{
  \cmd{int\_compare:nNnT} \marg{ \#7 } = \marg{ \cmd{c\_one\_int} }
   \marg{ \comment{first column}
     \cmd{int\_if\_odd:nTF} \marg{ \#5 }
      \marg{ \comment{odd row}
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ blue } }
      }
      \marg{ \comment{even row}
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ green } }
      }
   }
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
}
\gls{ExplSyntaxOff}
\end{codebox}
The data can simply be displayed using the \action{display} action:
\begin{codebox}
\gls{DTLaction}\marg{display}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:displaydbstripytable},
  title={Display Data in a Stripy Table},
  tag={marks},link={sec:displaydbstripytable},
  description={An example document that loads data from a CSV file
and displays the data with alternate blue and green rows}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{colortbl}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
\gls{ExplSyntaxOn}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }\nl
\marg{\nlsp
  \cmd{int\_compare:nNnT} \marg{ \#7 } = \marg{ \cmd{c\_one\_int} }\nlsp
   \marg{ \commentdbsp{first column}
     \cmd{int\_if\_odd:nTF} \marg{ \#5 }\nldbsp
      \marg{ \commentdbsp{odd row}
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ blue } }\nldbsp
      }\nldbsp
      \marg{ \commentdbsp{even row}
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ green } }\nldbsp
      }\nldbsp
   }\nlsp
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nl
}\nl
\gls{ExplSyntaxOff}
}
{%
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\subsubsection{Stripy Two Database Rows Per Tabular Row}
\label{sec:displaydbstripyrepeatcols}

\examplemarginref{ex:displaydbstripyrepeatcols}
\begin{information}
\Exampleref{ex:displaydbstripyrepeatcols} uses the \qt{scores} database
(see \sectionref{sec:studentscoresdb}).
\end{information}

Suppose now that you want both a stripy table (like
\exampleref{ex:displaydbstripytable}) and two database rows per
tabular row (like \exampleref{ex:displaydbrepeatcols}).  Simply
adding the option \displayoptval{per-row}{2} to
\exampleref{ex:displaydbstripytable} will cause a problem as the
\meta{col-num} argument of \gls{DTLdisplaydbAddItem} will loop
round, which will result in \gls{rowcolor} being inserted in the
middle of the \env{tabular} row.

\Exampleref{ex:displaydbstripyrepeatcols} adjusts the redefinition
of \gls{DTLdisplaydbAddItem} to use \condcsT{datatoolifrowstart:nn}
instead of simply testing if the seventh argument is 1.
Bear in mind that the \meta{row-num} argument will also increment
mid \env{tabular} row as a new row of data is fetched. This means
that \meta{row-num} will always have an odd value at the start of
each \env{tabular} row, so it's now not as simple as testing if
\meta{row-num} is odd:
\begin{codebox}
\gls{ExplSyntaxOn}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }
\marg{
  \condcsT{datatoolifrowstart:nn} \marg{ \#5 } \marg{ \#7 } 
   \marg{ \commentdbsp{first column}
     \cmd{int\_compare:nNnTF}
        \marg{ \cmd{int\_mod:nn} { \#5 } { 2 * \gls{ldatatooldisplayperrowint} } }
        = { \cmd{c\_one\_int} }
      \marg{ 
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ blue } }
      }
      \marg{ 
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ green } }
      }
   }
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
}
\gls{ExplSyntaxOff}
\end{codebox}
The data is display with:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{options}{
    \displayoptval{per-row}{2},
    \displayoptval{only-keys}{forename,surname,score}
  }
}\marg{display}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:displaydbstripyrepeatcols},
  title={Display Stripy Two Database Rows Per Tabular Row},
  tag={studentscores},link={sec:displaydbstripyrepeatcols},
  description={An example document that defines data in the document
and displays two rows of data in one tabular row with each row
colour alternating between blue and green}
]
{%
\cmd{usepackage}\marg{colortbl}\nl
\cmd{usepackage}\marg{datatool}\nl
\studentscoresdb\nl
\gls{ExplSyntaxOn}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \marg{ m m m m m m m m }\nl
\marg{\nlsp
  \cmd{datatool\_if\_row\_start:nnT} \marg{ \#5 } \marg{ \#7 } \nlsp
   \marg{ \commentdbsp{first column}
     \cmd{int\_compare:nNnTF}
        \marg{ \cmd{int\_mod:nn} { \#5 } { 2 * \gls{ldatatooldisplayperrowint} } }
        = { \cmd{c\_one\_int} }\nldbsp
      \marg{ 
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ blue } }\nldbsp
      }\nldbsp
      \marg{ 
        \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{ green } }\nldbsp
      }\nldbsp
   }\nlsp
  \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nl
}\nl
\gls{ExplSyntaxOff}
}
{%
\gls{DTLaction}\oarg{\nlsp
  options={\nldbsp
    per-row=2,\nldbsp
    only-keys={forename,surname,score}\nlsp
  }\nl
}\marg{display}
}
\end{resultbox}

\subsubsection{Two Fields in One Column}
\label{sec:displaydbmergefields}

\examplemarginref{ex:displaydbmergefields}
\begin{information}
\Exampleref{ex:displaydbmergefields} uses the \qt{marks} database
(see \sectionref{sec:marks}).
\end{information}

The marks database has a Surname and a Forename column.
\Exampleref{ex:displaydbmergefields} redefines
\gls{DTLdisplaydbAddItem} to show both the surname and forename in
the same column. The other columns show the student registration
(which disambiguates the students with the same name) and the
assignment marks. This requires the header row to be set with
\displayoptval{header-row} to override the default (which would only
show \qt{Surname} in the first column): 
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptvalm{options}{
  \displayoptvalm{only-keys}{Surname,StudentNo,Assign1,Assign2,Assign3},
  \displayoptvalm{header-row}{Name \idx{amp} Reg.\gls{cs.space}No., \idx{amp} Mark 1 \idx{amp} Mark 2 \idx{amp} Mark 3}
 }
}\marg{\action{display}}
\end{codebox}
The \gls{DTLdisplaydbAddItem} command is redefined to test for the
first column (as in the earlier \exampleref{sec:displaydbstripytable}). 
Remember that the \env{tabular} column number is in
the seventh argument, whereas the database column index is in the
eighth argument. In this case, the Surname column is both the first
column in the table and also the first column in the database. The
example tests if the column number is equal to one and, if true,
fetches the forename from the \idx{current-row} (using the
\action{current-row-values} action), and stores it in one of
the public scratch token list variables (\csfmt{l\_tmpa\_tl}). This uses
\LaTeX3 commands, so the syntax needs to be switched on temporarily.
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} 
  \marg{ m m m m m m m m } 
\marg{
  \cmd{int\_compare:nNnTF} \marg{ \#7 } = \marg{ \cmd{c\_one\_int} }
  \marg{
    \gls{DTLaction}\oarg{ \actionoptvalm{return}{ \cmd{l\_tmpa\_tl} = Forename } }
      \marg{ \glslink{opt.actionname.current-row-values}{current \idx*{l3sp} row \idx*{l3sp} values} }
    \gls{datatoolifnullorempty:N} \cmd{l\_tmpa\_tl}
     \marg{
       \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
     }
     \marg{
       \cmd{tl\_put\_right:Nx} \#1
        \marg{
          \cmd{exp\_not:N} \#3 \marg{ \cmd{exp\_not:n} \marg{ \#2 } ,
            \idx{l3sp} \cmd{exp\_not:V} \cmd{l\_tmpa\_tl} }
        }
     }
  }
  \marg{
    \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
  }
}
\gls{ExplSyntaxOff}
\end{codebox}
The test for null or empty (see \sectionref{sec:null}) isn't necessary
in this example, as there are no null values in the example database.
It's provided so that the example can be adapted for other databases.

\begin{information}
This example has nested actions. The new definition of
\gls{DTLdisplaydbAddItem} uses the \action{current-row-values}
action and this will be used within the \action{display} action.
However, the underlying display function introduces a scope to limit
the effects of the display options, but that scoping also prevents
the inner action from interfering with the return values of the
outer action.
\end{information}

Note that the scratch variable must be expanded before being added
to the content token list variable as its value changes at each
iteration. However, if there's a possibility that full expansion
will cause a problem for the formatting command, surname or
forename then they should be protected from expansion (which is
achieved with \csfmt{exp\_not:N}, \csfmt{exp\_not:n} and
\csfmt{exp\_not:V} in the above).

If you prefer not to use \LaTeX3 commands, the above can be
rewritten with \gls{appto}, \gls{eappto} and \gls{expandonce},
which are provided by \sty{etoolbox}, \gls{noexpand} (a \TeX\
primitive) and \gls{unexpanded} (an \eTeX\ primitive).
\begin{codebox}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} 
  \marg{ m m m m m m m m } 
\marg{
  \cmd{ifnum} \#7 = 1
    \gls{DTLaction}\oarg{return=\marg{\cmd{Forename}=Forename}}
      \marg{\action{current-row-values}}
    \gls{DTLifnullorempty}\marg{\cmd{Forename}}\comment{}
     \marg{\comment{}
       \gls{appto}\#1\marg{\#3\marg{\#2}}\comment{}
     }\comment{}
     \marg{\comment{}
       \gls{eappto}\#1\marg{\gls{noexpand}\#3\marg{\gls{unexpanded}\marg{\#2},
        \gls{expandonce}\cmd{Forename}}}\comment{}
     }\comment{}
  \cmd{else}
    \gls{appto}\#1\marg{\#3\marg{\#2}}\comment{}
  \cmd{fi}
}
\end{codebox}


\begin{resultbox}
\createexample*
 [label={ex:displaydbmergefields},
  title={Display Two Fields in One Column},
  tag={marks},link={sec:displaydbmergefields},
  description={An example document that loads data from a CSV file
and displays the data with the forename and surname in a single column}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
\gls{ExplSyntaxOn}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \nlsp
  \marg{ m m m m m m m m } \nl
\marg{\nlsp
  \cmd{int\_compare:nNnTF}\nldbsp
   \marg{ \#7 } = { \cmd{c\_one\_int} }\nlsp
  \marg{\nldbsp
    \gls{DTLaction}\oarg{ return=\marg{\cmd{l\_tmpa\_tl}=Forename} }\nldbsp
     \marg{ current \string~ row \string~ values }\nldbsp
    \gls{datatoolifnullorempty:N} \cmd{l\_tmpa\_tl}\nldbsp
     \marg{\nldbsp
       \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nldbsp\space
     }\nldbsp
     \marg{\nldbsp\space
       \cmd{tl\_put\_right:Nx} \#1 \nldbsp\dbspace
        \marg{ \cmd{exp\_not:N} \#3 \marg{ \cmd{exp\_not:n} \marg{ \#2 }, \string~ \cmd{exp\_not:V} \cmd{l\_tmpa\_tl} } }\nldbsp
     }\nldbsp
  }\nlsp
  \marg{\nldbsp
    \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nlsp
  }\nl
}\nl
\gls{ExplSyntaxOff}
}
{%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{options}{\nldbsp
    only-keys=\marg{Surname,StudentNo,Assign1,Assign2,Assign3},\nldbsp
    header-row=\marg{Name \string& Reg.\string\ No., \string& Mark 1 \string& Mark 2 \string& Mark 3}\nldbsp
  }\nlsp
 }\marg{display}
}
\end{resultbox}

\subsubsection{Calculations, Filtering and Row Highlighting}
\label{sec:displaydbaverages}

\examplemarginref{ex:displaydbaverages}
\begin{information}
\Exampleref{ex:displaydbaverages} uses the \qt{marks} database
(see \sectionref{sec:marks}).
\end{information}

This example combines elements from previous examples to show the
student surname and forename in the same column 
(as \exampleref{ex:displaydbmergefields}), calculates the average
score which is appended in an extra column (similar to
\exampleref{ex:displaydbpostrow}), filters out the rows where the average is below 50
(similar to \exampleref{ex:displaydbcond}) and highlights the rows
where the average is above 70 (similar to \exampleref{sec:displaydbstripytable}).

The \sty{colortbl} package is needed for this example as it uses
\gls{rowcolor} to highlight rows.
\begin{codebox}
\cmd{usepackage}\marg{colortbl}
\end{codebox}
Since this example will perform arithmetic calculations and
comparisons, the marks database is loaded with the \opt{store-datum}
setting on.
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}
\gls{DTLread}\marg{studentmarks.csv}
\end{codebox}

The row condition may be used to skip rows, in a similar way to
\exampleref{ex:displaydbcond} but in this case the average needs to
be calculated, which can be done with the
\action{current-row-aggregate} action.
\begin{codebox}
\cmd{newcommand}\marg{\cmd{rowfilter}}\oarg{3}\marg{\comment{}
 \gls{DTLaction}\oarg{
  \actionoptvalm{options}{mean},\actionoptvalm{datum}{\actiondatumoptval{round}{1}},
  \actionoptvalm{keys}{Assign1-},
  \actionoptvalm{return}{\cmd{AverageScore}=mean}
 }\marg{\action{current-row-aggregate}}\comment{calculate average}
 \gls{DTLifnumlt}\marg{\cmd{AverageScore}}\marg{50}\comment{}
 \marg{}\comment{skip if average less than 50}
 \marg{\#3}\comment{}
}
\end{codebox}

The redefinition of \gls{DTLdisplaydbAddItem}
is similar to that for \exampleref{ex:displaydbmergefields} described in
\sectionref{sec:displaydbmergefields}. However, a check is added to
determine if the average is above 70 so that \gls{rowcolor} can be
added to the content. Note that it can't be added in the custom
\cmd{rowfilter} hook as it will end up before \gls{tabularnewline},
which will be inserted at the start of the code provided in the
third argument of the filter function.  

\begin{information}
If you want to redefine \gls{DTLdisplaydbAddItem} in order to 
insert content at the start of a row, make sure to test if the seventh
argument (the \env{tabular} column number) is 1 rather than the eighth
argument (the database column index).
\end{information}

The definition used in \sectionref{sec:displaydbmergefields} already
tests the column number rather than the column index, so only a
small addition is required. Note that since the \actionopt{datum}
action option was set, the result (\cmd{AverageScore}) will be a
\idx{datumcs} so the actual numerical value can be obtained as a
\idx{plainnumber} with \gls{DTLdatumvalue}, which means that
\csfmt{fp\_compare:nNnT} can be used instead of \gls{DTLifgt}.
With \LaTeX3 commands, the definition is now:
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} 
  \marg{ m m m m m m m m } 
\marg{
  \cmd{int\_compare:nNnTF} \marg{ \#7 } = \marg{ \cmd{c\_one\_int} }
  \marg{
   \comment{insert highlight if average greater than 70}
   \cmd{fp\_compare:nNnT}
      \marg{ \gls{DTLdatumvalue} \cmd{AverageScore} } > \marg{ 70 }
     \marg{ 
      \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{yellow} }
     }
    \gls{DTLaction}\oarg{ \actionoptvalm{return}{\cmd{l\_tmpa\_tl}=Forename} }
      \marg{ \glslink{opt.actionname.current-row-values}{current \idx{l3sp} row \idx{l3sp} values} }
    \gls{datatoolifnullorempty:N} \cmd{l\_tmpa\_tl}
     \marg{
       \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
     }
     \marg{
       \cmd{tl\_put\_right:Nx} \#1
         \marg{
           \cmd{exp\_not:N} \#3 \marg{ \cmd{exp\_not:n} \marg{ \#2 } ,
             \idx{l3sp} \cmd{exp\_not:V} \cmd{l\_tmpa\_tl} }
         }
     }
  }
  \marg{
    \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }
  }
}
\gls{ExplSyntaxOff}
\end{codebox}
Alternatively, if you prefer to use the \sty{etoolbox} commands:
\begin{codebox}
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} 
  \marg{ m m m m m m m m } 
\marg{
 \cmd{ifnum} \#7 = 1
\comment{highlight if average greater than 70}
   \gls{DTLifnumgt}\marg{\cmd{AverageScore}}\marg{70}\comment{}
    \marg{\gls{appto}\#1\marg{\gls{rowcolor}\marg{yellow}}}\marg{}\comment{}
   \gls{DTLaction}\oarg{return=\marg{\cmd{Forename}=Forename}}
     \marg{\action{current-row-values}}
   \gls{DTLifnullorempty}\marg{\cmd{Forename}}\comment{}
    \marg{\gls{appto}\#1\marg{\#3\marg{\#2}}}\comment{}
    \marg{\comment{}
      \gls{eappto}\#1\marg{\gls{noexpand}\#3\marg{\gls{unexpanded}\marg{\#2},
       \gls{expandonce}\cmd{Forename}}}\comment{}
    }\comment{}
  \cmd{else}
    \gls{appto}\#1\marg{\#3\marg{\#2}}\comment{}
  \cmd{fi}
}
\end{codebox}

The \displayopt{post-row-function} can be used to append the
average (which should still be available with the custom
\cmd{AverageScore} calculated in the above) in a similar manner to 
\exampleref{ex:displaydbpostrow}.
\begin{codebox}
\cmd{newcommand}\marg{\cmd{appendaverage}}[2]\marg{\comment{}
 \gls{appto}\#1\marg{\idx{amp}}\comment{}
 \gls{eappto}\#1\marg{\gls{expandonce}\cmd{AverageScore}}\comment{}
}
\end{codebox}
The data is again displayed with the \action{display} action, but
this time there are only three columns: the student's name, the
student number and the average score. As with
\exampleref{ex:displaydbpostrow}, the \env{tabular} alignment
specification must be provided with \displayopt{align-specs}.
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptvalm{options}{
   \displayoptvalm{only-keys}{Surname,StudentNo},
   \displayoptvalm{align-specs}{lrr},
   \displayoptval{post-row-function}{\cmd{appendaverage}},
   \displayoptval{row-condition-function}{\cmd{rowfilter}},
   \displayoptvalm{header-row}{Name \idx{amp} Reg.\gls{cs.space}No. \idx{amp} Average}\nldbsp
 }\nlsp
}\marg{\action{display}}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:displaydbaverages},
  title={Displaying Data with Calculations, Filtering and Row Highlighting},
  tag={marks},link={sec:displaydbaverages},
  description={An example document that loads data from a CSV file
and displays the data with the forename and surname in a single
column and the average mark in the second column with rows
highlighted in yellow where the average is above 70}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{colortbl}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
\gls{ExplSyntaxOn}\nl
\cmd{RenewDocumentCommand} \gls{DTLdisplaydbAddItem} \nlsp
  \marg{ m m m m m m m m } \nl
\marg{\nlsp
  \cmd{int\_compare:nNnTF}\nldbsp
   \marg{ \#7 } = { \cmd{c\_one\_int} }\nlsp
  \marg{\nldbsp
   \commentdbsp{insert highlight if average greater than 70}
   \cmd{fp\_compare:nNnT}\nldbsp
      \marg{ \gls{DTLdatumvalue} \cmd{AverageScore} } > \marg{ 70 }\nldbsp
    \marg{ \nldbsp
      \cmd{tl\_put\_right:Nn} \#1 \marg{ \gls{rowcolor} \marg{yellow} }\nldbsp
     }\nldbsp
    \gls{DTLaction}\oarg{ return=\marg{\cmd{l\_tmpa\_tl}=Forename} }\nldbsp
     \marg{ current \string~ row \string~ values }\nldbsp
    \gls{datatoolifnullorempty:N} \cmd{l\_tmpa\_tl}\nldbsp
     \marg{\nldbsp
       \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nldbsp\space
     }\nldbsp
     \marg{\nldbsp\space
       \cmd{tl\_put\_right:Nx} \#1 \nldbsp\dbspace
        \marg{ \cmd{exp\_not:N} \#3 \marg{ \cmd{exp\_not:n} \marg{ \#2 }, \string~ \cmd{exp\_not:V} \cmd{l\_tmpa\_tl} } }\nldbsp
     }\nldbsp
  }\nlsp
  \marg{\nldbsp
    \cmd{tl\_put\_right:Nn} \#1 \marg{ \#3 \marg{ \#2 } }\nlsp
  }\nl
}\nl
\gls{ExplSyntaxOff}
\codepar
\cmd{newcommand}\marg{\cmd{rowfilter}}\oarg{3}\marg{\comment{}
 \gls{DTLaction}\oarg{\nldbsp
  options=\marg{mean},datum={round=1},\nldbsp
  keys=\marg{Assign1-},\nldbsp
  return=\marg{\cmd{AverageScore}=mean}\nldbsp
 }\marg{current row aggregate}\comment{calculate average}
 \gls{DTLifnumlt}\marg{\cmd{AverageScore}}\marg{50}\comment{}
 \marg{}\comment{skip if average less than 50}
 \marg{\#3}\comment{include this row otherwise}%
}
\codepar
\cmd{newcommand}\marg{\cmd{appendaverage}}[2]\marg{\comment{}
 \gls{appto}\#1\marg{\string&}\comment{}
 \gls{eappto}\#1\marg{\gls{expandonce}\cmd{AverageScore}}\comment{}%
}
}
{%
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{options}{\nldbsp
    only-keys=\marg{Surname,StudentNo},\nldbsp
    align-specs=\marg{lrr},\nldbsp
    post-row-function=\marg{\cmd{appendaverage}},\nldbsp
    row-condition-function=\marg{\cmd{rowfilter}},\nldbsp
    header-row=\marg{Name \string& Reg.\string\ No. \string& Average}\nldbsp
  }\nlsp
 }\marg{display}
}
\end{resultbox}

\section{Iterating Through a Database}
\label{sec:dbloops}

\begin{warning}
Iteration is problematic within \env{tabular}-like environments.
If you really need to have a loop within a \env{tabular}-like
environment, use \gls{DTLforeach} not \gls{DTLmapdata}. However,
be aware of its limitations. Consider constructing the \env{tabular}
contents to move the loop outside of the \env{tabular} body.
(See \sectionref{sec:tabular}.)
\end{warning}

The newer command, \gls{DTLmapdata}, is described in 
\sectionref{sec:mapdata}.
The older command \gls{DTLforeach} is described in 
\sectionref{sec:dbforeach}.
Both can be used to iterate over rows of a database and both
have a setting that allows the database to be edited.
In the case of \gls{DTLmapdata}, the edits are locally added to a
pending buffer and only applied at the end of \gls{DTLmapdata}
and may be discarded with \starredcs{DTLmapdatabreak}.
Note that it's also possible to edit a database outside of a loop.
See \sectionref{sec:editdb} for those commands.

\subsection{Iterating Over Rows with \glsfmttext{DTLmapdata}}
\label{sec:mapdata}

\glsstartrange{DTLmapdata}%
\cmddef{DTLmapdata}
Iterates over the data in a database, performing \meta{loop-body} at
each iteration. The available options are:
\optiondef{mapdata.name}
Identifies the database.  If omitted, the default name is assumed
(as given by the \opt{default-name} option).

\optiondef{mapdata.read-only}
If true, this setting switches on read-only mode. If false, the
database may be edited using the commands described in
\sectionref{sec:mapdataedit}, such as \gls{DTLsetentry}
and \gls{DTLrmrow}. Note that the \idx!{current-row} editing commands for use with
\gls{DTLforeach} are not compatible with \gls{DTLmapdata}.

\optiondef{mapdata.allow-edits}
This option is an antonym of \mapdataopt{read-only}. If true,
this setting switches off read-only mode.

The \meta{loop-body} argument of \gls{DTLmapdata} (which may
contain paragraph breaks) is performed at each iteration. Unlike
\gls{DTLforeach}, which has an optional argument to implement
filtering, if you want to skip a row, you will need to add the
appropriate conditional within the loop body.

If you have a long loop, you may prefer to use an environment
instead.
\envdef{DTLenvmapdata}
This just uses \gls{DTLmapdata} on the environment body. 
See \exampleref{ex:mailmerge} in \sectionref{sec:mailmergeex} which uses
\env{DTLenvmapdata} for mail merging with the supplementary \sty{person} package.

\begin{information}
The \env{DTLenvmapdata} environment automatically trims leading and 
trailing spaces from the loop body, but \gls{DTLmapdata} doesn't.
\end{information}

In both cases, the command \gls{dtldbname} will be defined to expand
to the database name, and, at the start of each iteration, the current row
number is stored in the \gls{dtlrownum} register. Unlike \gls{DTLforeach}, 
there is no associated row counter. However, you can borrow the \gls{DTLforeach}
counters as long as there is no conflict. This simplest method is to use
\gls{DTLrowreset} before the start of \gls{DTLmapdata} and use
\gls{DTLrowincr} in the loop body. Alternatively, you can define your own counter.

The loop may be prematurely terminated with:
\cmddef{DTLmapdatabreak}
The loop will terminate at this point, not at the end of the current
iteration. (This is different to breaking out of \gls{DTLforeach}
with \gls{dtlbreak}, which will cause the loop to terminate at the
end of the current iteration.)

With the default \mapdataoptval{read-only}{true}, there's
no difference between the starred and unstarred version of
\gls{DTLmapdatabreak}. Otherwise, the starred version will discard any edits as
well as breaking out of the loop, whereas the unstarred version
will break out of the loop but still apply the edits.

Note that since \gls{DTLmapdatabreak} will skip all following
content in the rest of the loop iteration, it can't be placed within
a primitive \csfmt{if\ldots} \ldots\ \csfmt{fi} conditional as the
closing \csfmt{fi} will be lost. Similarly, it can't occur within a
non-expandable or scoped context.

\begin{information}
If you need to nest \gls{DTLmapdata}, you must scope the inner loop
to prevent conflict. Note that \csfmt{begin} implicitly creates a
group, so the \env{DTLenvmapdata} environment will automatically be
scoped.
\end{information}

\mExampleref{ex:mapdata} uses the student scores database
(see \sectionref{sec:studentscoresdb})
and simply iterates over each row, printing the
database name and row index. The loop will terminate on the
third row. Note that the environment body has the leading and
trailing spaces trimmed so \qt{(after break)} at the end of one loop
runs into \qt{scores} at the start of the next.
\begin{codebox}
Command: \gls{DTLmapdata}\marg{ 
 \gls{dtldbname}: row \cmd{the}\gls{dtlrownum}.
 \gls{dtlifnumeq}\marg{\gls{dtlrownum}}\marg{3}\marg{\gls{DTLmapdatabreak}}\marg{}
 (after break)
}
\codepar
Environment:
\cbeg{DTLenvmapdata}
 \gls{dtldbname}: row \cmd{the}\gls{dtlrownum}.
 \gls{dtlifnumeq}\marg{\gls{dtlrownum}}\marg{3}\marg{\gls{DTLmapdatabreak}}\marg{}
 (after break)
\cend{DTLenvmapdata}
\end{codebox}
\begin{resultbox}
\createexample*[label={ex:mapdata},
 tag={studentscores},
 title={Iterating Over Rows with \cmd{DTLmapdata} and \envfmt{DTLenvmapdata}},
 description={Example document demonstrating simple iteration with
no value lookup}
]
{%
 \cmd{usepackage}\marg{datatool}\nl
 \studentscoresdb
}
{%
Command: \gls{DTLmapdata}\marg{\nlsp
 \gls{dtldbname}: row \cmd{the}\gls{dtlrownum}.\nlsp
 \gls{dtlifnumeq}\marg{\gls{dtlrownum}}\marg{3}\marg{\gls{DTLmapdatabreak}}\marg{}\nlsp
 (after break)\nl
}
\codepar
\comment{Note that the leading and trailing spaces are stripped in
the environment body}%
Environment:\nl
\cbeg{DTLenvmapdata}\nlsp
 \gls{dtldbname}: row \cmd{the}\gls{dtlrownum}.\nlsp
 \gls{dtlifnumeq}\marg{\gls{dtlrownum}}\marg{3}\marg{\gls{DTLmapdatabreak}}\marg{}\nlsp
 (after break)\nl
\cend{DTLenvmapdata}
}
\end{resultbox}

\subsubsection{Accessing Data in the Current Row of \glsfmttext{DTLmapdata}}
\label{sec:mapdataget}

Within the loop body of \gls{DTLmapdata}, you can access values in 
the current iteration row using:
\cmddef{DTLmapget}
The argument is a \keyval\ list. Allowed options are listed below.
Either \mapgetopt{key} or \mapgetopt{column} is required to identify
the value by its column label or index. If both are used, they will
override each other.

\optiondef{mapget.key}
The value should be the label used to identify the required column.

\optiondef{mapget.column}
The numeric value should be the index used to identify the required column.

\optiondef{mapget.return}
If set to a non-empty value, the value should be a command which
will be defined to the value obtained from the column (identified by
\mapgetopt{key} or \mapgetopt{column}). If the value is empty or
omitted (the default), the value will simply be inserted into the
document.

If \mapgetoptval{return}{cs} is set, you can test if \meta{cs} is null
with \gls{DTLifnull}. For example:
\begin{codebox}
\cbeg{DTLenvmapdata}
Dear
\gls{DTLmapget}\marg{\mapgetoptval{key}{title},\mapgetoptval{return}{\cmd{Title}}}\comment{fetch title}
\gls{DTLifnull}\cmd{Title}\marg{}\marg{\cmd{Title} }\comment{ignore title if not set}
\gls{DTLmapget}\marg{\mapgetoptval{key}{forename}} \gls{DTLmapget}\marg{\mapgetoptval{key}{surname}}
\codepar
\comment{\ldots}
\cend{DTLenvmapdata}
\end{codebox}
In the above, if the title isn't set, it will be omitted, but if the
forename or surname columns aren't set, they will appear as \qt{NULL}.
(Note that a null value is not the same as an empty value, see
\sectionref{sec:null}.)

\begin{information}
If you used the \opt{store-datum} option to store values in the
database as \idxpl{datumitem}, then \meta{cs} will be a \idx{datumcs}.
You will then be able to use datum commands such as \gls{DTLdatumvalue} and
\gls{DTLdatumtype}. (See \sectionref{sec:datatypes} for further
details.) Similarly for \meta{cs} in \gls{DTLmaprow}, and
likewise for assignments in \gls{DTLforeach} and similar commands.
\end{information}

Rather than repeatedly using \gls{DTLmapget} for each column, you
can instead use:
\cmddef{DTLmaprow}
This command may only be used within the loop body of \gls{DTLmapdata}
(or \env{DTLenvmapdata}) and iterates over the columns in 
the current (\gls{DTLmapdata}) iteration row. At the
start of each iteration, the register \gls{dtlcolumnnum} is set to
the column index and \meta{cs} is defined to the column value. Then
\meta{body} is done. You can prematurely break the loop with:
\cmddef{DTLmaprowbreak}
This will stop the current \gls{DTLmaprow} loop at that point but
won't stop the \gls{DTLmapdata} loop. As with \gls{DTLmapdatabreak},
this command should not be placed inside a primitive conditional or
within a non-expandable or scoped context.

Alternatively, if you prefer the \meta{cs}\dequals\meta{col-key}
syntax used with \gls{DTLforeach}:
\cmddef{DTLmapgetvalues}
The \idx{assign-list} argument should be a comma-separated list
of \meta{cs}\dequals\meta{col-key} where \meta{cs} is a command
and \meta{col-key} is the label identifying the required column.

If there is no value matching the given column key then the
placeholder command \meta{cs} will be assigned to null (which can be
tested with \gls{DTLifnull}).  The unstarred 
\gls{DTLmapgetvalues} will trigger an error if the database has no column
defined with the given label \meta{col-key} (as opposed to the
column being defined for the database but no value set in that
column for the given row), whereas the starred
\starredcs{DTLmapgetvalues} for won't and will simply set \meta{cs}
to null.

For example:
\begin{codebox}
\gls{DTLmapgetvalues}\marg{\cmd{thePrice}=Price,\cmd{theQuantity}=Quantity}
\end{codebox}
This is essentially equivalent to:
\begin{codebox}
\gls{DTLmapget}\marg{\mapgetoptval{key}{Price},\mapgetoptval{return}{\cmd{thePrice}}}
\gls{DTLmapget}\marg{\mapgetoptval{key}{Quantity},\mapgetoptval{return}{\cmd{theQuantity}}}
\end{codebox}

\subsubsection{Editing Rows}
\label{sec:mapdataedit}

If \mapdataoptval{read-only}{false} (or
\mapdataoptval{allow-edits}{true}), the following commands are
available for use in the loop body of \gls{DTLmapdata} (or within
the body of the \env{DTLenvmapdata} environment).

All edits are saved in a local buffer and are only applied to the database
at the end of \gls{DTLmapdata}. This means that any change applied
within a scope in the loop body will be lost once the scope is
ended. However, the final update to the database at the end will be
applied according to the current \opt{global} setting. Pending edits
can be discarded by breaking out of the loop with
\starredcs{DTLmapdatabreak}.

\begin{information}
The final updates to the database are only performed after the loop
has finished. For example, if the database has 4 rows at the start of
the loop and 1 row is removed with \gls{DTLrmrow}, then
\gls{DTLrowcount} will still expand to 4 until \gls{DTLmapdata} has
completed. Edits to the current iteration row will be picked up by any
following \gls{DTLmapget}, but \gls{DTLmaprow} will only pick up any
changes made before the \gls{DTLmaprow} loop starts.
\end{information}

Some of the edit commands may take a \keyval\ argument. Common
options are:

\optiondef*{mapdataedit.column}
Identifies a column by its numeric index. The column does not have
to exist if appending is allowed, but the index must be greater than 0.

\optiondef*{mapdataedit.key}
Identifies a column by its key. Some commands may allow both
\mapdataeditopt{column} and \mapdataeditopt{key}. If the column
exists, they must both reference the same column. If the column
doesn't exist, then \mapdataeditopt{column} is taken as the column
reference and \mapdataeditopt{key} provides a key for that column if
a new column needs to be defined.

\optiondef*{mapdataedit.value}
Identifies a value, where one is required.

\optiondef*{mapdataedit.expand-value}
As \mapdataeditopt{value} but will fully expand the value.

\optiondef*{mapdataedit.expand-once-value}
As \mapdataeditopt{value} but will expand the value once.

\cmddef{DTLrmrow}
Removes the current iteration row. Note that this won't affect the row indexes
of the following iterations or the total row count, as the edit
won't take effect until the loop terminates.

\cmddef{DTLrmentry}
Removes the entry in the column identified by either
\mapdataeditopt{column} or \mapdataeditopt{key}. Note that this
won't delete the entire column but any reference to this 
column for the given row will result in a null value (see
\sectionref{sec:null}).

For example:
\begin{codebox}
\gls{DTLmapdata}\oarg{\mapdataopt{allow-edits}}\marg{\gls{DTLrmentry}\marg{\mapdataeditopt{column}{4}}}
\end{codebox}
This will remove the entry in column~4 for every row, but column~4
will still be defined.

\cmddef{DTLsetentry}
Sets the column identified by either \mapdataeditopt{column}
or \mapdataeditopt{key} to the value identified by
\mapdataeditopt{value} or \mapdataeditopt{expand-value} or
\mapdataeditopt{expand-once-value}. Note that the general
\opt{new-value-expand} and \opt{store-datum} settings will be
respected, but the expansion with \mapdataeditopt{expand-value} or
\mapdataeditopt{expand-once-value} occurs before the
\opt{new-value-expand} setting is implemented.

If the current iteration row already has a value in the given column, the
existing value will be replaced with the new value. If the current
row doesn't have a value in the given column, the new value will be
added. If the desired column doesn't exist, you will need to
identify it with \mapdataeditopt{column}. If you also set
\mapdataeditopt{key} that will be used as the label for the new
column, otherwise it will be given the default label (obtained from
\code{\gls{dtldefaultkey} \meta{col-idx}}).

\begin{information}
Since the database doesn't get updated until the loop has
terminated, you can use
\code{\mapdataeditoptvalm{column}{\gls{DTLcolumncount}\marg{\gls{dtldbname}}+1}}
to append a column. However, it's simpler to create the new column
first, as in \exampleref{ex:mapdataedit}.
\end{information}

\mExampleref{ex:mapdataedit} loads the \qt{marks} database (see
\sectionref{sec:marks}) and uses \gls{DTLmapdata} to iterate over
each row and append a column containing the average marks for each
assignment. The \action{row-aggregate} action may be used within
\gls{DTLmapdata} to calculate the average. For example:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Average}}\marg{\action{add-column}}
\gls{DTLmapdata}\oarg{allow-edits}\marg{\comment{}
  \gls{DTLaction}\oarg{
    \actionoptvalm{keys}{Assign1,Assign2,Assign3},
    \actionoptvalm{options}{mean},
    \actionoptvalm{datum}{\actiondatumoptval{round}{1}},\comment{round the result}
    \actionoptvalm{return}{\cmd{Mean}=mean}
  }
  \marg{\action{row-aggregate}}
  \gls{DTLifnull}\marg{\cmd{Mean}}\comment{test the return value}
  \marg{}\comment{row aggregate failed!}
  \marg{\comment{average calculated successfully}
   \gls{DTLsetentry}\marg{\mapdataeditoptval{key}{Average},\mapdataeditoptval{expand-value}{\cmd{Mean}}}
  }
}
\end{codebox}
A range may be used in \actionoptval{keys}, which may be more
convenient:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{keys}{Assign1-Assign3},
  \actionoptvalm{options}{mean},
  \actionoptvalm{datum}{\actiondatumoptval{round}{1}},\comment{round the result}
  \actionoptvalm{return}{\cmd{Mean}=mean}
}
\end{codebox}
Since the new column will have a null value at this point (which
will be skipped by the \action{row-aggregate} action), an open
ended range may be used instead:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{keys}{Assign1-},
  \actionoptvalm{options}{mean},
  \actionoptvalm{datum}{\actiondatumoptval{round}{1}},\comment{round the result}
  \actionoptvalm{return}{\cmd{Mean}=mean}
}
\end{codebox}

The database can then be sorted by the average mark and displayed:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptvalm{assign}{\marg{Average=\sortdatacolumnopt{desc}}}}\marg{\action{sort}}
\gls{DTLaction}\marg{\action{display}}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:mapdataedit},
  title={Iterating Over Rows with \cmd{DTLmapdata} to Append a
Column},
  tag={marks},
  description={An example document that loads data from a CSV file
and appends a new column}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
\gls{DTLaction}\oarg{\actionoptval{key}{Average}}\marg{\action{add-column}}\nl
\gls{DTLmapdata}\oarg{allow-edits}\marg{\comment{}
\comment{an open-ended range may be used as the new column is
currently missing from this row:}
  \gls{DTLaction}\oarg{\nldbsp
    \actionoptvalm{keys}{Assign1-},\nldbsp
    \actionoptvalm{options}{mean},\nldbsp
    \actionoptvalm{datum}{\actiondatumoptval{round}{1}},\comment{round the result}\dbspace
    \actionoptvalm{return}{\cmd{Mean}=mean}\nlsp
  }\nlsp
  \marg{\action{row-aggregate}}\nlsp
  \gls{DTLifnull}\marg{\cmd{Mean}}\comment{test the return value}
  \marg{}\comment{row aggregate failed!}
  \marg{\comment{average calculated successfully}
   \gls{DTLsetentry}\marg{\mapdataeditoptval{key}{Average},\mapdataeditoptval{expand-value}{\cmd{Mean}}}\nlsp
  }\nl
}
\codepar
\gls{DTLaction}\oarg{\actionoptvalm{assign}{\marg{Average=\sortdatacolumnopt{desc}}}}\marg{\action{sort}}\nl
\gls{DTLaction}\marg{\action{display}}
}
\end{resultbox}
\glsendrange{DTLmapdata}%

\subsection{Iterating Over Rows with \glsfmttext{DTLforeach}}
\label{sec:dbforeach}

\glsstartrange{DTLforeach}%
The newer command \gls{DTLmapdata}, described
in \sectionref{sec:mapdata}, locally sets internal variables at each
iteration. This means that it can't be used within a
\env{tabular}-like environment where the loop body contains \idx{amp}
or \gls{cs.bksl} as internal variables will be lost when the scope
changes between columns and rows.

The commands and environments in this section are older
and have extra overhead. They were designed to work in
\env{tabular}-like environments, so they perform global assignments
to workaround the automatic scoping within cells. However, alignment
can be sensitive to certain commands occurring at the start of a
cell or row that can trigger \qt{\idx{misplacednoalign}} errors.
In which case, it may be better to use the method suggested in
\sectionref{sec:tabular}.

\cmddef{DTLforeach}
Iterates over each row of the database identified by \meta{db-name}.
This command may be nested up to three times. The starred version is
read-only and therefore faster. The unstarred version allows the
database to be edited within the loop. 

Corresponding environments are also available.
\envdef{DTLenvforeach}
This is equivalent to:
\begin{compactcodebox}
\gls{DTLforeach}\oargm{condition}\margm{db-name}\marg{\idx{assign-list}}\margm{content}
\end{compactcodebox}
\envdef{DTLenvforeach*}
This is equivalent to:
\begin{compactcodebox}
\starredcs{DTLforeach}\oargm{condition}\margm{db-name}\marg{\idx{assign-list}}\margm{content}
\end{compactcodebox}
Any commands applicable to \gls{DTLforeach} are also applicable to
the corresponding \env{DTLenvforeach} environment.

\begin{important}
Verbatim content can't be used in \meta{body} for either the command
or environment.
\end{important}

After \gls{DTLforeach} (or \env{DTLenvforeach}), the final loop
index may be saved with:
\cmddef{DTLsavelastrowcount}
This will locally define \meta{cs} to the final index of the last
\gls{DTLforeach} loop. Note that this refers to the counter
increment at each iteration where the \meta{condition} evaluates to
true, and so may not be the database row count. If used within the
body of a \gls{DTLforeach} loop, it will refer to the last
\gls{DTLforeach} loop at the next level up. Where the level index is
obtained from the following:

\cmddef{dtlforeachlevel}
The current level register is incremented at the start of
\gls{DTLforeach} and corresponds to the level index. This will be 1
in the outermost \gls{DTLforeach}, 2 within the first nested
\gls{DTLforeach}, and 3 within the second nested \gls{DTLforeach}.
Each level has an associated row counter, which is incremented with
\gls{refstepcounter}, which means you can use \gls{label} at the
start of \meta{body} in order to reference a row number, but
obviously some method will be needed to make the label unique,
see \exampleref{ex:foreachinsertcol} in \sectionref{sec:foreachinsertcol}.

\begin{information}
Ideally \gls{label} should occur as soon as possible after \gls{refstepcounter},
and it must be within the same scope. Therefore if you need to label the rows,
ensure that \gls{label} occurs right at the start of \meta{body}.
\end{information}

\ctrdef{DTLrowi}
The \ctr{DTLrowi} counter keeps track of the current row for the
first level.

\ctrdef{DTLrowii}
The \ctr{DTLrowii} counter keeps track of the current row for the
second level.

\ctrdef{DTLrowiii}
The \ctr{DTLrowiii} counter keeps track of the current row for the
third level.

\begin{important}
The counter corresponding to the current level is only incremented
for rows where the \meta{condition} is satisfied. This means that if
the counter is referenced in \meta{condition} it will still have its
value from the previous row.
\end{important}

\ctrdef{DTLrow}
To avoid duplicate hypertargets with \sty{hyperref}, there is a level~0 
counter \ctr{DTLrow} that is incremented at the start of every \gls{DTLforeach}.
This ensures that \theHctr{DTLrowi}, \theHctr{DTLrowii} and \theHctr{DTLrowiii}
expand to unique values.

These counters may be used in other contexts, such as with \gls{DTLmapdata}, but 
take care that such use doesn't conflict with \gls{DTLforeach}. Bear in mind 
that these counters don't have automatic resets (that is, they are not defined with 
a parent counter). For convenience, the following commands are provided to minimise conflict.

\cmddef{DTLrowreset}
Increments \ctr{DTLrow} and resets the counter \ctrfmt{DTLrow\meta{n}} where \meta{n}
is one more than \gls{dtlforeachlevel}.

\cmddef{DTLrowincr}
Increments the counter \ctrfmt{DTLrow\meta{n}} where \meta{n}
is one more than \gls{dtlforeachlevel}.

\cmddef{DTLtherow}
Uses \csmetafmt{theDTLrow}{n}{} where \meta{n}
is one more than \gls{dtlforeachlevel}.

At the start of each iteration, the assignments given in
\idx{assign-list} are made. This argument should be a
\code{\meta{cs}\dhyphen\meta{col-key}} comma-separated list, where
\meta{cs} is a command and \meta{col-key} is the key uniquely
identifying a column.

\begin{important}
Each placeholder command \meta{cs} will be \strong{globally} defined
to the value in the column identified by \meta{col-key} (or null, if
not set) of the current row. There is no test to ensure that the
command isn't already defined.
\end{important}

The \meta{condition} provided in the optional argument is tested using 
\gls{ifthenelse} (so the commands in \sectionref{sec:ifthen} may be
used). If the condition evaluates to true, the row counter for the
current level is incremented, and the \meta{body} of the loop is
performed. The placeholder commands in \idx{assign-list} may be
referenced within the \meta{condition}. If the optional argument is
omitted, \code{\cmd{boolean}\marg{true}} is assumed.

The following commands are defined for use in \meta{body}.
Additionally, the \gls{dtlcurrentrow} token register is set to the
special internal database markup for the \idx{current-row}. Commands or
actions that are designed for use with that register, such as the
\action{current-row-aggregate} action, may be used in \meta{body}, but
avoid the editing commands described in \sectionref{sec:currentrow}
that alter \gls{dtlcurrentrow}. Instead, use the commands described
in \sectionref{sec:dbforeachedit} to modify the \idx{current-row}.

\cmddef{DTLcurrentindex}
This will expand to the numeric value of the current row counter.

\cmddef{dtlbreak}
If used within \meta{body}, this command will cause the loop to
terminate at the end of the current iteration. Note that this is
different to \gls{DTLmaprowbreak}, which breaks out of the current
loop immediately.

\cmddef{DTLiffirstrow}
Expands to \meta{true}, if this row is the first (that satisfies the
condition).
That is, if the corresponding \ctrfmt{DTLrow\meta{I}} counter is 1.
Otherwise, it expands to \meta{false}. Bear in mind that this tests
the loop index not the database row index.

\cmddef{DTLiflastrow}
Expands to \meta{true}, if this row is the last (that satisfies the
condition). Prior to version 3.0, this would never evaluate to
\meta{true} if any rows had been filtered. As from version 3.0, this
compares the corresponding \ctrfmt{DTLrow\meta{I}} counter with the
total number of rows in the database less the number of omitted
rows.

\cmddef{DTLifoddrow}
Expands to \meta{true}, if the loop index (that is, the value of the
corresponding \ctrfmt{DTLrow\meta{I}} counter) is odd.

\gls{DTLforeachkeyinrow}
Iterates over each column in the current row of \gls{DTLforeach},
globally defines \meta{cs} to the value in that column, and does \meta{code}.
This internally iterates through the column metadata with
\gls{dtlforeachkey}, assigning \inlineglsdef{dtlkey}, \inlineglsdef{dtlcol},
\inlineglsdef{dtltype} and \inlineglsdef{dtlheader} to the column key, column index,
column type and column header, respectively.

\subsubsection{Editing the Current Row within \glsfmttext{DTLforeach}}
\label{sec:dbforeachedit}

If the read-only \starredcs{DTLforeach} is used, no changes can be
made to the database. With the editable unstarred version, the
current row may be changed using the commands below, and the
database will be updated after each iteration. This makes it slower
than the read-only version.

\begin{information}
This is a different approach to the \mapdataopt{allow-edits} mode
for \gls{DTLmapdata}, which stores pending edits in a buffer and only updates
the database after the loop has terminated.
\end{information}

With the editable unstarred \gls{DTLforeach}, the following commands
may be used to modify the current row of the database. These
commands will trigger an error with the read-only version.

\begin{warning}
These commands don't follow the \opt{global}, \opt{new-value-expand} or
\opt{store-datum} settings. They always perform a global change,
expand the given value, if applicable, and don't use the
\idxc{datumitem}{datum format}.
\end{warning}

\cmddef{DTLappendtorow}
Appends an entry with the protected expansion of \meta{value} to 
the current row for the column identified by
\meta{col-key}. The row must not already have that column set. 

\cmddef{DTLreplaceentryforrow}
Replaces the entry for the column identified by
\meta{col-key} in the current row with the protected expansion of
\meta{value}.

\cmddef{DTLremoveentryfromrow}
Removes the entry in the column identified by \meta{col-key} from the current
row. An error will occur if the given column isn't set.

\cmddef{DTLremovecurrentrow}
Removes the current row from the database. Note that this is
different from removing all entries from the row with
\gls{DTLremoveentryfromrow}, which would result in a blank row.
%
\glsendrange{DTLforeach}%

\subsubsection{Examples}
\label{sec:dbforeachexs}

Most of these examples can now be performed with either
\gls{DTLdisplaydb*} or \gls{DTLmapdata}.

\paragraph{Displaying Data}
\label{sec:foreachdisplay}

\mExampleref{ex:foreachdisplay} is an alternative to \exampleref{ex:displaydbonly}
(see \sectionref{sec:displaydbonly})
that uses \starredcs{DTLforeach} instead of \gls{DTLdisplaydb}. Note that the use of
\gls{DTLdisplaydb} is simpler and less problematic (see \sectionref{sec:tabular}).
\begin{codebox}
\cbeg{tabular}\marg{llr}
\cmd{bfseries} Author \idx{amp} \cmd{bfseries} Title \idx{amp}
\cmd{bfseries} Price (\gls{cs.dollar})\comment{}%
\starredcs{DTLforeach}\marg{products}\comment{}%
\marg{\cmd{Author}=Author,\cmd{Title}=Title,\cmd{Price}=Price}\comment{}
\marg{\gls{cs.bksl}\comment{start new row}
 \cmd{Author} \idx{amp} \cmd{Title} \idx{amp} \cmd{Price}
}
\cend{tabular}
\end{codebox}
Note that the new row command \gls{cs.bksl} has been placed at the start of the
final argument. This is necessary as placing it at the end of the argument will
cause an unwanted row at the end of the table. This is a feature of the loop
mechanism.

\begin{resultbox}[float]
\createexample*[label=ex:foreachdisplay,
 tag={product},link={sec:foreachdisplay},
 title={Display Data in a Table with \cmd{DTLforeach}},
 description={Example document illustrating how to display data in a
\envfmt{tabular} environment with a loop}
]
{%
 \cmd{usepackage}\marg{datatool}\nl
\productdb
}
{%
\cbeg{tabular}\marg{llr}\nl
\cmd{bfseries} Author \string&\nl
\cmd{bfseries} Title \string&\nl
\cmd{bfseries} Price (\gls{cs.dollar})\comment{}%
\starredcs{DTLforeach}\marg{products}\comment{database}%
 \marg{\cmd{Author}=Author,\cmd{Title}=Title,\cmd{Price}=Price}\comment{assignment list}
 \marg{\gls{cs.bksl}\comment{start new row}
 \cmd{Author} \string& \cmd{Title} \string& \cmd{Price}\nl
}\nl
\cend{tabular}
}
\end{resultbox}

\paragraph{Stripy Table}
\label{sec:foreachstripy}

\mExampleref{ex:foreachstripy} is an alternative to
\exampleref{ex:displaydbstripytable} in \sectionref{sec:displaydbstripytable}
that alternately colours the rows of data blue or green.

\begin{important}
Take care when using a conditional to deal with any alignment. The conditional must be
expandable. In this case, \gls{DTLifoddrow} is used, which is expandable.
\end{important}

This example requires the \sty{colortbl} package which provides \gls{rowcolor}.
\begin{codebox}
\cbeg{tabular}\marg{llrrrr}
\cmd{bfseries} Surname \idx{amp} \cmd{bfseries} Forename \idx{amp}
\cmd{bfseries} StudentNo \idx{amp} \cmd{bfseries} Assign1 \idx{amp}
\cmd{bfseries} Assign2 \idx{amp} \cmd{bfseries} Assign3\comment{}
\starredcs{DTLforeach}\marg{marks}
\marg{\cmd{Surname}=Surname, \cmd{Forename}=Forename,
 \cmd{StudentNo}=StudentNo, \cmd{AssignI}=Assign1,
 \cmd{AssignII}=Assign2, \cmd{AssignIII}=Assign3}
\marg{\comment{}
 \gls{DTLifoddrow}\marg{\gls{cs.bksl}\gls{rowcolor}\marg{blue}}\marg{\gls{cs.bksl}\gls{rowcolor}\marg{green}} 
 \cmd{Surname} \idx{amp} \cmd{Forename} \idx{amp}
 \cmd{StudentNo} \idx{amp} \cmd{AssignI} \idx{amp}
 \cmd{AssignII} \idx{amp} \cmd{AssignIII}
}\comment{}
\cend{tabular}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:foreachstripy},
  title={Using \cmd{DTLforeach} to Display a Stripy Table},
  tag={marks},link={sec:foreachstripy},
  description={An example document that loads data from a CSV file
and displays rows of data with alternate background colours}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{colortbl}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
}
{%
\cbeg{tabular}\marg{llrrrr}\nl
\cmd{bfseries} Surname \string&\nl
\cmd{bfseries} Forename \string&\nl
\cmd{bfseries} StudentNo \string&\nl
\cmd{bfseries} Assign1 \string&\nl
\cmd{bfseries} Assign2 \string&\nl
\cmd{bfseries} Assign3\comment{}%
\starredcs{DTLforeach}\marg{marks}\nl
\marg{\cmd{Surname}=Surname, \cmd{Forename}=Forename, \cmd{StudentNo}=StudentNo,\nl
\cmd{AssignI}=Assign1, \cmd{AssignII}=Assign2, \cmd{AssignIII}=Assign3}\nl
\marg{\comment{}
 \gls{DTLifoddrow}\marg{\gls{cs.bksl}\gls{rowcolor}\marg{blue}}\marg{\gls{cs.bksl}\gls{rowcolor}\marg{green}} 
 \cmd{Surname} \string&\nlsp
 \cmd{Forename} \string&\nlsp
 \cmd{StudentNo} \string&\nlsp
 \cmd{AssignI} \string&\nlsp
 \cmd{AssignII} \string&\nlsp
 \cmd{AssignIII}\nl
}\comment{}%
\cend{tabular}
}
\end{resultbox}

\Exampleref{ex:displaydbaverages} in \sectionref{sec:displaydbaverages}, which
highlights rows after computing the average score, may seem similar to this
example, but \gls{DTLifnumlt} is a robust command and will therefore cause a
problem. Either use the method provided in \exampleref{ex:displaydbaverages}
or in \exampleref{ex:constructtab}.

\paragraph{Displaying the Data with an Extra Column at the Start}
\label{sec:foreachinsertcol}

\mExampleref{ex:foreachinsertcol} is an alternative to 
\exampleref{ex:displayinsertcol} that inserts the row index and label in 
a separate column at the start.
\begin{codebox}
\cbeg{tabular}\marg{rllrrrr}
\cmd{bfseries} Row \idx{amp} \cmd{bfseries} Surname \idx{amp}
\cmd{bfseries} Forename \idx{amp} \cmd{bfseries} StudentNo \idx{amp}
\cmd{bfseries} Assign1 \idx{amp} \cmd{bfseries} Assign2 \idx{amp}
\cmd{bfseries} Assign3\comment{}
\starredcs{DTLforeach}\marg{marks}
\marg{\cmd{Surname}=Surname, \cmd{Forename}=Forename,
 \cmd{StudentNo}=StudentNo, \cmd{AssignI}=Assign1,
 \cmd{AssignII}=Assign2, \cmd{AssignIII}=Assign3}
\marg{\comment{}
 \gls{label}\marg{\cmd{StudentNo}}
 \gls{cs.bksl} \thectr{DTLrowi} \idx{amp}
 \cmd{Surname} \idx{amp} \cmd{Forename} \idx{amp}
 \cmd{StudentNo} \idx{amp} \cmd{AssignI} \idx{amp}
 \cmd{AssignII} \idx{amp} \cmd{AssignIII}
}\comment{}
\cend{tabular}
\end{codebox}
Note that the \gls{label} must occur in the same scope as \gls{refstepcounter}. This
means that it has to go before the new row \gls{cs.bksl} which automatically starts
a new scope.

As with \exampleref{ex:displayinsertcol}, the student number for the referenced
row is obtained with the \action{find} action.

\begin{resultbox}
\createexample*
 [label={ex:foreachinsertcol},arara={pdflatex,pdflatex,pdfcrop},
  title={Displaying Data with Row Numbers Using \cmd{DTLforeach}},
  tag={marks},link={sec:foreachinsertcol},
  description={An example document that loads data from a CSV file
and inserts a column at the start showing the row number which can be referenced}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
}
{%
\cbeg{tabular}\marg{rllrrrr}\nl
\cmd{bfseries} Row \string&\nl
\cmd{bfseries} Surname \string&\nl
\cmd{bfseries} Forename \string&\nl
\cmd{bfseries} StudentNo \string&\nl
\cmd{bfseries} Assign1 \string&\nl
\cmd{bfseries} Assign2 \string&\nl
\cmd{bfseries} Assign3\comment{}%
\starredcs{DTLforeach}\marg{marks}\nl
\marg{\cmd{Surname}=Surname, \cmd{Forename}=Forename, \cmd{StudentNo}=StudentNo,\nl
\cmd{AssignI}=Assign1, \cmd{AssignII}=Assign2, \cmd{AssignIII}=Assign3}\nl
\marg{\comment{}
 \gls{label}\marg{\cmd{StudentNo}}\nlsp
 \gls{cs.bksl} \thectr{DTLrowi} \string&\nlsp
 \cmd{Surname} \string&\nlsp
 \cmd{Forename} \string&\nlsp
 \cmd{StudentNo} \string&\nlsp
 \cmd{AssignI} \string&\nlsp
 \cmd{AssignII} \string&\nlsp
 \cmd{AssignIII}\nl
}\comment{}%
\cend{tabular}
\codepar
\gls{DTLaction}\oarg{\nlsp
  \actionoptvalm{assign}{\nldbsp
    \cmd{Surname}=Surname,\nldbsp
    \cmd{Forename}=Forename,\nldbsp
    \cmd{StudentNo}=StudentNo\nlsp
  },\nlsp
  \actionoptvalm{options}{\nldbsp
    \actionfindoptvalm{inline}{\comment{}\dbspace
     \gls{DTLifstringeq}\marg{\cmd{Surname}}\marg{Brown}\nldbsp
     \marg{\gls{DTLifstringeq}\marg{\cmd{Forename}}\marg{Andy}\marg{\#1}\marg{}}\marg{}\comment{}\dbspace
    }\nlsp
  }\nl
}\marg{\action{find}}\nl
Row \gls{ref}\marg{\cmd{StudentNo}} shows the details for Andy Brown.
}
\end{resultbox}

\paragraph{Displaying the Data with an Extra Column at the End}
\label{sec:foreachextracol}

\mExampleref{ex:foreachextracol} is an alternative to
\exampleref{ex:displaydbpostrow} (see \sectionref{sec:displaydbpostrow}) that
uses \starredcs{DTLforeach} instead of \gls{DTLdisplaydb} to display the data with an
extra column showing the total (quantity times price) as well as the running
total at the end. Note that the scoping introduced by the cells in the
\env{tabular} environment means that the running total must be globally
updated.

As with \exampleref{ex:displaydbpostrow}, the \sty{booktabs} package is used
for horizontal rules at the start and end of the table. 

\begin{codebox}
\cmd{newcommand}\marg{\cmd{runningtotal}}\marg{0}
\cbeg{tabular}\marg{lrrr}
\gls{toprule}
\cmd{bfseries} Title \idx{amp} \cmd{bfseries} Quantity \idx{amp}
\cmd{bfseries} Price \idx{amp} \cmd{bfseries} Total\comment{}
\starredcs{DTLforeach}\marg{products}\comment{database}
\marg{\cmd{theTitle}=Title, \cmd{theQuantity}=Quantity,
 \cmd{thePrice}=Price}\comment{}
\marg{\comment{}
 \gls{DTLiffirstrow}\marg{\gls{cs.bksl}\gls{midrule}}\marg{\gls{cs.bksl}}\cmd{theTitle} \idx{amp}
 \cmd{theQuantity} \idx{amp} \cmd{thePrice} \idx{amp}
 \gls{DTLmul}\marg{\cmd{theTotal}}\marg{\cmd{theQuantity}}\marg{\cmd{thePrice}}\comment{}
 \gls{DTLround}\marg{\cmd{theTotal}}\marg{\cmd{theTotal}}\marg{2}\comment{}
 \gls{DTLgadd}\marg{\cmd{runningtotal}}\marg{\cmd{runningtotal}}\marg{\cmd{theTotal}}\comment{}
 \cmd{theTotal}
}\comment{}
\gls{cs.bksl}\gls{midrule} \idx{amp} \idx{amp} \idx{amp} \cmd{runningtotal}
\cend{tabular}
\end{codebox}

Note that this example has a conditional (\gls{DTLiffirstrow}) that determines
whether to just start a new row with \code{\gls{cs.bksl}} or to start a new row
and insert a horizontal rule with \code{\gls{cs.bksl}\gls{midrule}}. If you
need something like this in your document, the conditional command must be
expandable otherwise you will get an error (see \sectionref{sec:tabular}).

\begin{resultbox}[float]
\createexample*[label=ex:foreachextracol,
 tag={product},link={sec:foreachextracol},
 title={Using \cmd{DTLforeach} to Display Data in a Table with a Running Total Column},
 description={Example document illustrating how to show data in a
\envfmt{tabular} environment with a custom column appended using a loop}
]
{%
\cmd{usepackage}\marg{booktabs}\nl
\cmd{usepackage}\marg{datatool}\nl
\productdb
}
{%
\cmd{newcommand}\marg{\cmd{runningtotal}}\marg{0}\nl
\cbeg{tabular}\marg{lrrr}\nl
\gls{toprule}\nl
\cmd{bfseries} Title \string&\nl
\cmd{bfseries} Quantity \string&\nl
\cmd{bfseries} Price \string&\nl
\cmd{bfseries} Total\comment{}
\starredcs{DTLforeach}\marg{products}\comment{database}%
\marg{\cmd{theTitle}=Title,\cmd{theQuantity}=Quantity,\cmd{thePrice}=Price}\comment{assignments}%
\marg{\comment{}
 \gls{DTLiffirstrow}\marg{\gls{cs.bksl}\gls{midrule}}\marg{\gls{cs.bksl}}\cmd{theTitle} \string&
 \cmd{theQuantity} \string& \cmd{thePrice} \string&
 \gls{DTLmul}\marg{\cmd{theTotal}}\marg{\cmd{theQuantity}}\marg{\cmd{thePrice}}\comment{}
 \gls{DTLround}\marg{\cmd{theTotal}}\marg{\cmd{theTotal}}\marg{2}\comment{}
 \gls{DTLgadd}\marg{\cmd{runningtotal}}\marg{\cmd{runningtotal}}\marg{\cmd{theTotal}}\comment{}
 \cmd{theTotal}
}\comment{}%
\gls{cs.bksl}\gls{midrule} \string& \string& \string& \cmd{runningtotal}\nl
\cend{tabular}
}
\end{resultbox}

\paragraph{Editing Rows}
\label{sec:foreachedit}

\mExampleref{ex:foreachedit} is an alternative to \exampleref{ex:mapdataedit}
(see \sectionref{sec:mapdataedit})
that uses \gls{DTLforeach} instead of \gls{DTLmapdata} to edit the database.
With \gls{DTLmapdata}, the row aggregates are computed with the
\action{row-aggregate} action, but with \gls{DTLforeach} the
\action{current-row-aggregate} action must be used instead.
\begin{codebox}
\gls{DTLforeach}\marg{marks}\marg{}\marg{\comment{}
  \gls{DTLaction}\oarg{
    \actionoptvalm{keys}{Assign1-},
    \actionoptvalm{options}{mean},
    \actionoptvalm{datum}{\actiondatumoptval{round}{1}},\comment{round the result}
    \actionoptvalm{return}{\cmd{Mean}=mean}
  }
  \marg{\action{current-row-aggregate}}
  \gls{DTLifnull}\marg{\cmd{Mean}}\comment{test the return value}
  \marg{}\comment{row aggregate failed!}
  \marg{\comment{average calculated successfully}
   \gls{DTLappendtorow}\marg{Average}\marg{\cmd{Mean}}\comment{}
  }
}
\end{codebox}
The database can then be sorted by the average mark and displayed:
\begin{codebox}
\gls{DTLsortdata}\marg{marks}\marg{Average=desc}
\gls{DTLdisplaydb}\marg{marks}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:foreachedit},
  title={Editing a Database with \cmd{DTLforeach}},
  tag={marks},link={sec:foreachedit},
  description={An example document that loads data from a CSV file
and appends a new column}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
\gls{DTLforeach}\marg{marks}\marg{}\marg{\comment{}
  \gls{DTLaction}\oarg{\nldbsp
    \actionoptvalm{keys}{Assign1-},\nldbsp
    \actionoptvalm{options}{mean},\nldbsp
    \actionoptvalm{datum}{\actiondatumoptval{round}{1}},\comment{round the result}\dbspace
    \actionoptvalm{return}{\cmd{Mean}=mean}\nlsp
  }\nlsp
  \marg{\action{current-row-aggregate}}\nlsp
  \gls{DTLifnull}\marg{\cmd{Mean}}\comment{test the return value}
  \marg{}\comment{row aggregate failed!}
  \marg{\comment{average calculated successfully}
   \gls{DTLappendtorow}\marg{Average}\marg{\cmd{Mean}}\comment{}
  }\nl
}
\codepar
\gls{DTLsortdata}\marg{marks}\marg{Average=desc}\nl
\gls{DTLdisplaydb}\marg{marks}
}
\end{resultbox}


\section{Loops and Conditionals with \envtext{tabular}-like Environments}
\label{sec:tabular}

It can be problematic using loops and conditionals with the
\env{tabular} environment or any similar alignment environment, such
as \env{longtable}. Each cell within a row has implicit scoping.
This allows you to conveniently use declarations, such as
\csfmt{bfseries}, at the start of a cell without affecting the rest
of the row. For example:
\begin{coderesult}
\cbeg{tabular}\marg{cr}
\csfmt{bfseries} A \idx{amp} B\gls{cs.bksl}
\csfmt{itshape} C \idx{amp} D
\cend{tabular}
\tcblower
\begin{tabular}{cr}
\bfseries A & B\\
\itshape C & D
\end{tabular}
\end{coderesult}
In the above, only \qt{A} is bold and only \qt{C} is
italic because of the implicit scope that localises the effect of
the font change.

Suppose now that you want to keep track of the row numbers. Using
the older \TeX\ route, you could define a count register and
increment it at the start of each row. However a local increment
will only have an effect within the current scope. For example:
\begin{coderesult}
\cmd{newcount}\cmd{myrowctr}
\cbeg{tabular}\marg{cr}
\cmd{advance}\cmd{myrowctr} by 1\cmd{relax}
 A \idx{amp} B (\cmd{the}\cmd{myrowctr})\gls{cs.bksl}
\cmd{advance}\cmd{myrowctr} by 1\cmd{relax}
 C \idx{amp} D (\cmd{the}\cmd{myrowctr})
\cend{tabular}
\tcblower
\myrowctr=0\relax
\begin{tabular}{cr}
\advance\myrowctr by 1\relax A & B (\the\myrowctr)\\
\advance\myrowctr by 1\relax C & D (\the\myrowctr)
\end{tabular}
\end{coderesult}
The local increment within a cell means that the change is lost.
You can prefix \csfmt{advance} with \csfmt{global} to make the
change global, but a higher-level more \LaTeX\ solution is to define 
a counter and increment it with \gls{stepcounter} (or
\gls{refstepcounter}), which will make the change global. For
example:
\begin{coderesult}
\cmd{newcounter}\marg{myrowctr}
\cbeg{tabular}\marg{cr}
\gls{stepcounter}\marg{myrowctr} A \idx{amp} B (\cmd{themyrowctr})\gls{cs.bksl}
\gls{stepcounter}\marg{myrowctr} C \idx{amp} D (\cmd{themyrowctr})
\cend{tabular*}
\tcblower
\setcounter{myrowctr}{0}%
\begin{tabular}{cr}
\stepcounter{myrowctr} A & B (\themyrowctr)\\
\stepcounter{myrowctr} C & D (\themyrowctr)
\end{tabular}
\end{coderesult}
This is what \gls{DTLforeach} does and, to allow it to be nested,
there are three counters (\ctr{DTLrowi}, \ctr{DTLrowii} and
\ctr{DTLrowiii}) associated with each level. These counters are
incremented globally (with \gls{refstepcounter}). The placeholder
commands also need to be globally defined, as well as various other
commands that need to change at each iteration.

This means that \gls{DTLforeach} can, to a limited extent, be used
within a \env{tabular}-like context but \gls{DTLmapdata}, which only
locally defines or changes variables, can't. This means that
\gls{DTLmapdata} can be scoped to prevent any local assignments or
changes conflicting with other content, whereas \gls{DTLforeach}
can't.

Problems arise when more complex operations are needed at the start of
a row or cell that interferes with the column alignment.
Suppose now that I want to include a test at the start of each row
to insert a horizontal rule above every other row:
\begin{badcodebox}
\cmd{newcounter}\marg{myrowctr}
\cmd{newcommand}\marg{\cmd{myrowhook}}\marg{\comment{}
 \gls{stepcounter}\marg{myrowctr}\comment{}
 \gls{ifthenelse}\marg{\cmd{isodd}\marg{\cmd{value}\marg{myrowctr}}}\marg{}\marg{\gls{hline}}\comment{}
}
\cbeg{tabular}\marg{cr}
\cmd{myrowhook} A \idx{amp} B (\cmd{themyrowctr})\gls{cs.bksl}
\cmd{myrowhook} C \idx{amp} D (\cmd{themyrowctr})
\cend{tabular}
\end{badcodebox}
This now causes a \qt{\idx{misplacednoalign}} error.

The best way to avoid this in complex situations where the
\env{tabular} content requires various conditionals to adjust rows
or cells is to construct the content in a temporary command 
(a token list variable) so that the problematic code is shifted outside of the
\env{tabular} environment. This is the method now used by
\gls{DTLdisplaydb} and \gls{DTLdisplaylongdb}.

Using a more traditional \LaTeXe\ method, you can define the
variable with \csfmt{newcommand} and append to it using commands
provided by \sty{etoolbox}. For example, first define the counter
and the command that will be used to store the content of the
\env{tabular} environment:
\begin{codebox}
\cmd{newcounter}\marg{myrowctr}
\cmd{newcommand}\marg{\cmd{mytabcontent}}\marg{}
\end{codebox}
Provide a command to initialise the above (in case multiple tables
are needed):
\begin{codebox}
\cmd{newcommand}\marg{\cmd{InitTabContent}}\marg{\comment{}
 \cmd{renewcommand}\marg{\cmd{mytabcontent}}\marg{\cbeg{tabular}\marg{cr}}\comment{}
 \cmd{setcounter}\marg{myrowctr}\marg{0}\comment{}
}
\end{codebox}
Provide a command to finish off:
\begin{codebox*}
\cmd{newcommand}\marg{\cmd{FinishTabContent}}\marg{\comment{}
 \gls{appto}\cmd{mytabcontent}\marg{\cend{tabular}}\comment{}
}
\end{codebox*}
Now a command is needed to add a row. Note that the row separator
\gls{cs.bksl} needs to be inserted at the end of all but the last
row, which is the same as inserting it at the start of all but the
first row. So this first checks if the counter is 0 before incrementing it 
to determine whether or not to insert \gls{cs.bksl}.
A horizontal line is inserted every even row (after the counter has
been incremented). Alternatively, this could be modified to insert
\gls{hline} before the counter is incremented when it's odd. The two
arguments provided are appended without expansion to the content
(separated by \idx{amp}). However, the value of the row counter must be expanded 
when it's added so \gls{eappto} is required.
\begin{codebox*}
\cmd{newcommand}\marg{\cmd{AddRow}}[2]\marg{\comment{}
 \gls{ifthenelse}\marg{\cmd{value}\marg{myrowctr}=0}\marg{}\marg{\gls{appto}\cmd{mytabcontent}\marg{\gls{cs.bksl}}}\comment{}
 \gls{stepcounter}\marg{myrowctr}\comment{}
 \gls{ifthenelse}\marg{\cmd{isodd}\marg{\cmd{value}\marg{myrowctr}}}\marg{}\comment{}
  \marg{\gls{appto}\cmd{mytabcontent}\marg{\gls{hline}}}\comment{even row}
 \gls{appto}\cmd{mytabcontent}\marg{\#1 \idx{amp} \#2}\comment{}
 \gls{eappto}\cmd{mytabcontent}\marg{ (\cmd{themyrowctr})}\comment{}
}
\end{codebox*}
Once the custom commands have been defined, they can be used:
\begin{codebox}
\cmd{InitTabContent}
\cmd{AddRow}\marg{A}\marg{B}\comment{add first row}
\cmd{AddRow}\marg{C}\marg{D}\comment{add second row}
\cmd{FinishTabContent}
\end{codebox}
This doesn't actually display the tabular content, but at the end of
the above, the replacement text of the custom command
\csfmt{mytabcontent} now contains the content of the \env{tabular}
environment without the awkward conditionals. You can confirm this with:
\begin{codebox*}
\gls{show}\cmd{mytabcontent}
\end{codebox*}
This will show the content in the transcript or terminal when you
run \LaTeX:
\begin{transcript}
> \cmd{mytabcontent}=macro:
->\cmd{begin} \marg{tabular}\marg{cr}A \idx{amp} B (1)\gls{cs.bksl}\gls{hline} C \idx{amp} D (2)\cmd{end} \marg{tabular}.
\end{transcript}
You can now go ahead and put \csfmt{mytabcontent} where you want
your table.

If you prefer to use \LaTeX3, you can instead use the commands
provided by the \styfmt{l3tl} package (token lists) and the
\styfmt{l3int} package (integers), which are now part of the
\LaTeX\ kernel so they don't need loading. For example, first switch
on \LaTeX3 syntax and define the variables:
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{int\_new:N} \cmd{l\_my\_row\_int} \comment{new integer variable}
\cmd{tl\_new:N} \cmd{l\_my\_content\_tl} \comment{new token list variable}
\end{codebox}
The custom command to initialise these variables is now provided as
a document command, which is robust:
\begin{codebox}
\cmd{NewDocumentCommand} \cmd{InitTabContent} \marg{ }
\marg{
 \cmd{tl\_set:Nn} \cmd{l\_my\_content\_tl} \marg{ \cbeg{tabular} \marg{ cr } }
 \cmd{int\_zero:N} \cmd{l\_my\_row\_int}
}
\end{codebox}
Similarly for the command that finishes off:
\begin{codebox}
\cmd{NewDocumentCommand} \cmd{FinishTabContent} \marg{ }
\marg{
 \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \cend{tabular} }
}
\end{codebox}
And for the command that adds values to the first and second columns
of the current row:
\begin{codebox}
\cmd{NewDocumentCommand} \cmd{AddRow} \marg{ m m }
\marg{
 \cmd{int\_if\_zero:nF} \marg{ \cmd{l\_my\_row\_int} }
  \marg{ \comment{row index not zero}
   \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \gls{cs.bksl} }
  }
 \cmd{int\_incr:N} \cmd{l\_my\_row\_int}
 \cmd{int\_if\_even:nT} \marg{ \cmd{l\_my\_row\_int} }
  \marg{ \comment{row index even}
   \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \gls{hline} }
  }
 \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \#1 \idx{amp} \#2 }
 \cmd{tl\_put\_right:Nx} \cmd{l\_my\_content\_tl} 
  \marg{ \idx{l3sp} ( \cmd{int\_use:N} \cmd{l\_my\_row\_int} ) }
}
\gls{ExplSyntaxOff}
\end{codebox}
The rest is as before:
\begin{codebox}
\cmd{InitTabContent}
\cmd{AddRow}\marg{A}\marg{B}\comment{add first row}
\cmd{AddRow}\marg{C}\marg{D}\comment{add second row}
\cmd{FinishTabContent}
\end{codebox}

This may seem very convoluted, and certainly is for the above
trivial case, but when using a loop to construct the contents, it
can avoid the headaches of \idx{misplacednoalign} errors.

\mExampleref{ex:constructtab} uses \gls{DTLmapdata} to iterate over
the data in the \qt{marks} database (see \sectionref{sec:marks}).
The average mark is calculated using the \action{row-aggregate}
action and a row is only appended if the average is 50 or above. Any
row that has an average above 70 is highlighted using \gls{rowcolor}
(which requires the \sty{colortbl} package).

\begin{information}
\Exampleref{ex:constructtab} is provided to demonstrate the
technique described in this chapter. The same output can be more
compactly achieved using the hooks provided with \gls{DTLdisplaydb}
(which internally applies a similar method). See
\exampleref{ex:displaydbaverages} in
\sectionref{sec:displaydbaverages}, which produces almost the same
but has an extra column showing the student number.
\end{information}

First some variables are defined:
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{int\_new:N} \cmd{l\_my\_row\_int}
\cmd{tl\_new:N} \cmd{l\_my\_content\_tl}
\cmd{tl\_new:N} \cmd{l\_my\_forename\_tl}
\cmd{tl\_new:N} \cmd{l\_my\_surname\_tl}
\cmd{tl\_new:N} \cmd{l\_my\_mean\_tl}
\end{codebox}
The initialisation command is the same as before but now its an
internal command:
\begin{codebox}
\cmd{cs\_new:Nn} \cmd{my\_init\_content:} 
 \marg{
  \cmd{tl\_set:Nn} \cmd{l\_my\_content\_tl} \marg{ \cbeg{tabular} \marg{ lr } }
  \cmd{int\_zero:N} \cmd{l\_my\_row\_int}
 }
\end{codebox}
Similarly for the command to finish off:
\begin{codebox}
\cmd{cs\_new:Nn} \cmd{my\_finish\_content:} 
 \marg{
  \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \cend{tabular} }
 }
\end{codebox}
The command that adds a row is different. The first argument will be
the student's name and the second argument will be the average
score. These will be supplied with placeholder commands so the
values will need to be expanded when they are appended to the token
list variable. The command starts off with a test to determine if
the mean is greater than or equal to 50. This test is actually done in
reverse (that is, the code is only done if $\text{mean} < 50$ is
false).
\begin{codebox}
\cmd{cs\_new:Nn} \cmd{my\_add\_row:nn} 
 \marg{
  \cmd{fp\_compare:nNnF} \marg{ \#2 } < \marg{ 50 }
   \marg{
    \cmd{int\_if\_zero:nF} \marg{ \cmd{l\_my\_row\_int} }
     \marg{
      \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \gls{cs.bksl} }
     }
    \cmd{int\_incr:N} \cmd{l\_my\_row\_int}
    \cmd{fp\_compare:nNnT} \marg{ \#2 } > { 70 } 
     \marg{
      \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl}
        \marg{ \gls{rowcolor} \marg{ yellow } }
     }
   \cmd{tl\_put\_right:Nx} \cmd{l\_my\_content\_tl} \marg{ \#1 \idx{amp} \#2 }
  }
 }
\end{codebox}
The document command iterates over the default database.
(Alternatively, you can adapt this to provide an argument with the
database name.) The surname and forename are fetched using
\gls{DTLmapgetvalues} and the mean is obtained with the
\action{row-aggregate} function. Be careful with actions with spaces
in their name when you have \LaTeX3 syntax on as spaces are ignored. 
You will need to use \idx{l3sp} where a space must actually occur.
\begin{codebox}
\cmd{NewDocumentCommand} \marg{ \cmd{meanscorestab} } { } 
\marg{
 \cmd{my\_init\_content:}
 \gls{DTLmapdata}
 \marg{
  \gls{DTLmapgetvalues}
    \marg{
     \cmd{l\_my\_surname\_tl} = Surname ,
     \cmd{l\_my\_forename\_tl} = Forename
    }
  \gls{DTLaction}
   \oarg{
    \actionoptvalm{keys}{Assign1-},
    \actionoptvalm{datum}{round=1},
    \actionoptvalm{return}{ \cmd{l\_my\_mean\_tl} = mean },
    \actionoptval{options}{mean}
   }
   \marg{ \glslink{opt.actionname.row-aggregate}{row \string~ aggregate} }
  \cmd{my\_add\_row:nn}
    \marg{ \cmd{l\_my\_forename\_tl} \cmd{c\_space\_tl} \cmd{l\_my\_surname\_tl} }
    \marg{ \cmd{l\_my\_mean\_tl} }
 }
 \cmd{my\_finish\_content:}
\comment{expand the content:}
 \cmd{l\_my\_content\_tl}
}
\gls{ExplSyntaxOff}
\end{codebox}
This custom command can now be used in the document at the point
where the table is required.

The \qt{marks} database used by \exampleref{ex:constructtab} has two
Jane Browns who both have an average above 70, so both their rows
are highlighted in yellow. The students with an average below 50 aren't
listed.

\begin{resultbox}
\createexample*
 [label={ex:constructtab},
  tag={marks},
  title={Loops and Alignment},
  description={Example document demonstrating constructing a tabular
within a loop to avoid alignment issues}
 ]
{%
\comment{sample CSV file:}%
\exfile{studentmarks.csv}\markscsv\nl
\cmd{usepackage}{colortbl}\nl
\cmd{usepackage}\marg{datatool}
\codepar
\comment{Load data from studentmarks.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}\nl
\comment{Commands to construct the tabular content:}%
\gls{ExplSyntaxOn}\nl
\comment{define variables:}%
\cmd{int\_new:N} \cmd{l\_my\_row\_int}\nl
\cmd{tl\_new:N} \cmd{l\_my\_content\_tl}\nl
\cmd{tl\_new:N} \cmd{l\_my\_forename\_tl}\nl
\cmd{tl\_new:N} \cmd{l\_my\_surname\_tl}\nl
\cmd{tl\_new:N} \cmd{l\_my\_mean\_tl}\nl
\comment{command to initialise:}%
\cmd{cs\_new:Nn} \cmd{my\_init\_content:} \nl
\marg{\nlsp
 \cmd{tl\_set:Nn} \cmd{l\_my\_content\_tl} \marg{ \cbeg{tabular} \marg{ lr } }\nlsp
 \cmd{int\_zero:N} \cmd{l\_my\_row\_int}\nl
}\nl
\comment{command to finish off:}%
\cmd{cs\_new:Nn} \cmd{my\_finish\_content:} \nlsp
 \marg{\nldbsp
  \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \cend{tabular} }\nlsp
 }\nl
\comment{command to append a row:}%
\cmd{cs\_new:Nn} \cmd{my\_add\_row:nn} \nl
\marg{\nlsp
  \cmd{fp\_compare:nNnF} \marg{ \#2 } < \marg{ 50 } \nlsp
  \marg{
  \cmd{int\_if\_zero:nF} \marg{ \cmd{l\_my\_row\_int} }\nlsp
  \marg{\nldbsp
    \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \gls{cs.bksl} }\nldbsp
  }\nldbsp
  \cmd{int\_incr:N} \cmd{l\_my\_row\_int}\nldbsp
  \cmd{fp\_compare:nNnT} \marg{ \#2 } > { 70 } \nldbsp
  \marg{\nldbsp
    \cmd{tl\_put\_right:Nn} \cmd{l\_my\_content\_tl} \marg{ \gls{rowcolor} \marg{ yellow } }\nldbsp
  }\nldbsp
   \cmd{tl\_put\_right:Nx} \cmd{l\_my\_content\_tl} \marg{ \#1 \string& \#2 }\nldbsp
 }\nl
}\nl
\comment{define document command:}%
\cmd{NewDocumentCommand} \marg{ \cmd{meanscorestab} } { } \nl
\marg{\nl
\comment{construct tabular:}
 \cmd{my\_init\_content:}\nl
\comment{iterate over the default database:}
 \gls{DTLmapdata}\nlsp
 \marg{\nl
\commentdbsp{get the surname and forename for the current row:}%
  \gls{DTLmapgetvalues}\nldbsp
   \marg{\nldbsp
    \cmd{l\_my\_surname\_tl} = Surname ,\nldbsp
    \cmd{l\_my\_forename\_tl} = Forename\nldbsp
    }\nl
\commentdbsp{calculate the mean:}
  \gls{DTLaction}\nldbsp
   \oarg{\nldbsp
    \actionoptvalm{keys}{Assign1-},\nldbsp
    \actionoptvalm{datum}{round=1},\nldbsp
    \actionoptvalm{return}{ \cmd{l\_my\_mean\_tl} = mean },\nldbsp
    \actionoptval{options}{mean}\nldbsp
   }\nldbsp
   \marg{row \string~ aggregate}\nldbsp
  \cmd{my\_add\_row:nn}\nldbsp
    \marg{ \cmd{l\_my\_forename\_tl} \cmd{c\_space\_tl} \cmd{l\_my\_surname\_tl} }\nldbsp
    \marg{ \cmd{l\_my\_mean\_tl} }\nldbsp
 }\nl
\comment{finish construction:}
 \cmd{my\_finish\_content:}
\comment{expand the content:}
 \cmd{l\_my\_content\_tl}
}\nl
\gls{ExplSyntaxOff}
}
{%
 \cmd{meanscorestab}
}
\end{resultbox}

\section{Null Values}
\label{sec:null}

Certain commands, such as \gls{DTLmapget}, provide a way to fetch a
value from a row in a database. Return values for actions can also
be fetched using the \actionopt{return} option or with \gls{DTLget}.
In either case, if you try to fetch a value that \emph{hasn't been
set} then you will get a \emph{null value}.

\begin{important}
A null value is not the same as an empty value. Empty
values can be tested using \sty{etoolbox}['s] \gls{ifdefempty} or
similar.
\end{important}

For example, the \qt{customers} database
described in \sectionref{sec:customers} can either be read from a
\idx{CSV} file or defined in the document.
However, there is a slight difference between the two approaches.

When data is loaded from a \idx{CSV} file, null values can only
occur where final columns are missing. When data is loaded from a
DTLTEX or DBTEX file (see
\sectionsref{sec:dtltexfiles,sec:dbtexfiles}) or when the database
is constructed in the document (see
\sectionsref{sec:dbactionnames,sec:newdb}) then null values can also
occur in intermediate columns. 

The \filefmt{customers.csv} data has null values where the final columns have
been completely omitted in a row (that is, there are no trailing
separators with empty elements between or after them), but the missing
mid-column values are empty because there's no way of completely
omitting them without interfering with the \idx{CSV} syntax. So
those values are empty, not null. See the examples in
\sectionref{sec:nullexs}.


If you have assigned a value to a placeholder command, for example
with \gls{DTLmapgetvalues} or with the \mapgetopt{return} option in
\gls{DTLmapget}, then you can test if that command
represents a null value with:
\cmddef{DTLifnull}
This will do \meta{true} if the first argument is a single token that
represents null and \meta{false} otherwise. Note that if the
argument is empty or is a command whose expansion text is empty,
this will do \meta{false}, because null isn't the same as empty.

If you want to test for null or empty, use:
\cmddef{DTLifnullorempty}
This will do \meta{true} if the argument is empty or if the argument
is a single token whose value is empty or represents null, otherwise
it will do \meta{false}.

\begin{important}
No trimming is performed in the null or empty tests.
\end{important}

Null values will cause different output to empty values when
displaying data (see the examples in \sectionref{sec:nullexs}), but
they can also produce different results in other functions, such as
sorting (see \exampleref{ex:sortdbrepl}), where a null value can
trigger alternative behaviour but an empty value won't.

\subsection{Examples}
\label{sec:nullexs}

\mExampleref{ex:nullcsv} loads the customers database (see
\sectionref{sec:customers}) from the \idx{CSV} file \filefmt{customers.csv}.
\begin{codebox}
\gls{DTLsetup}\marg{\optval{default-name}{customers}}
\gls{DTLread}\marg{customers.csv}
\end{codebox}

This file has some missing final columns but also has some empty
values. For example:
\begin{compactcodebox}
5,,Duck,Dickie,dd@example.com,
\end{compactcodebox}
This has an \emph{empty} value in the second column (Organisation, a string
column) and in the final column (Age, a numeric column). If these
values are fetched from the database, they will expand to empty.
By way of contrast, the next line is missing the final column:
\begin{compactcodebox}
6,Newt Fellowship,Axolotl,Lizzie,la@example.com
\end{compactcodebox}
The difference is subtle (there's no trailing comma) but in this
case, if the age is fetched from this row, a null value will be
returned.

The data is displayed in tabular form using the \action{display} action:
\begin{codebox}
\gls{DTLaction}\marg{display}
\end{codebox}
String null values show as \qt{NULL} and numeric null values show as~0.
Whereas empty values show nothing.


\begin{resultbox}[float]
\createexample*
 [label={ex:nullcsv},
  title={CSV Data Containing Empty Cells and Missing Final Cells},
  tag={customers},
  description={An example document that loads data from a CSV file
and displays the content in a table}
]
{
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers.csv}
}
{%
Empty values show as a blank.
Missing values show as NULL in string columns and 0 in
numeric columns.
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\mExampleref{ex:nulldb}, in contrast, constructs the database in the
document with actions (see \sectionref{sec:customers}). In this case, the syntax
does allow for mid-columns to be omitted when setting the values for
a row. For example:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{assign}{
    Id = 5, Surname = \marg{Duck}, Forename = \marg{Dickie}, 
    Email = {dd@example.com}
  }
 }\marg{\action{new-row}}
\end{codebox}
In this case, the Organisation and Age column aren't set for this
row. This means that if an attempt is made to fetch those values,
null will be returned. Compare this with another row:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionoptvalm{assign}{
    Id = 9, Organisation = \marg{},
    Surname = \marg{Mander}, Forename = \marg{Sally}
  }
 }\marg{\action{new-row}}
\end{codebox}
Here, the Age and Email columns are missing but the
Organisation column is set to empty. This means that if an attempt
is made to fetch the Age or Email from this row, null will be
returned, but an attempt to fetch the Organisation will return an
empty value.

\begin{resultbox}[float]
\createexample*
 [label={ex:nulldb},
  title={Constructed Data With Missing (Null) Values},
  tag={customers},
  description={An example document that constructs a database in
the document with missing values and one empty value
and displays the content in a table}
]
{
\cmd{usepackage}\marg{datatool}\nl
\customersdb
}
{%
Empty values show as a blank.
Missing values show as NULL in string columns and 0 in
numeric columns.
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\mExampleref{ex:displaydbnullmissing} modifies \exampleref{ex:nulldb}
to provide a custom command that tests if its argument is null and
will show a dash if so, otherwise it just does the argument:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{checkmissing}}[1]\marg{\gls{DTLifnull}\marg{\#1}\marg{---}\marg{\#1}}
\end{codebox}

The \action{display} action uses the same underlying function as
\gls{DTLdisplaydb} which encapsulates strings with
\gls{dtlstringformat}, integers with \gls{dtlintformat}, decimals
with \gls{dtlrealformat} and currency with \gls{dtlcurrencyformat}.
The numeric formatting commands all internally use
\gls{dtlnumericformat}, so only \gls{dtlstringformat} and
\gls{dtlnumericformat} need to be redefined to use the custom
command:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{dtlstringformat}}[1]\marg{\cmd{checkmissing}\marg{\#1}}
\cmd{renewcommand}\marg{\gls{dtlnumericformat}}[1]\marg{\cmd{checkmissing}\marg{\#1}}
\end{codebox}
Note that the empty Organisation field is still shown as empty not
as a dash. Use \gls{DTLifnullorempty} if you want to check for empty
as well.

\begin{resultbox}[float]
\createexample*
 [label={ex:displaydbnullmissing},
  title={Display Data With Missing (Null) Values Shown as a Dash},
  tag={customers},
  description={An example document that constructs a database in
the document and displays the content in a table with missing values 
shown as a dash}
]
{
\cmd{usepackage}\marg{datatool}\nl
\customersdb\nl
\comment{Empty values are not the same as null values!}%
\cmd{newcommand}\marg{\cmd{checkmissing}}[1]\marg{\gls{DTLifnull}\marg{\#1}\marg{---}\marg{\#1}}\nl
\cmd{renewcommand}\marg{\gls{dtlstringformat}}[1]\marg{\cmd{checkmissing}\marg{\#1}}\nl
\cmd{renewcommand}\marg{\gls{dtlnumericformat}}[1]\marg{\cmd{checkmissing}\marg{\#1}}
}
{%
Missing values are shown as a dash.
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\mExampleref{ex:mapnullemptymissing} has a slightly different version
of the custom command that also checks for empty and will produce
\emph{Missing} instead of a dash:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{checkmissing}}[1]\marg{\comment{}
 \gls{DTLifnullorempty}\marg{\#1}\marg{\cmd{emph}\marg{Missing}}\marg{\#1}}
\end{codebox}
The database is iterated over using \gls{DTLmapdata}.  
The forename, surname and organisation can be shown 
for each customer:
\begin{codebox}
\gls{DTLmapdata}\marg{
  \gls{DTLmapgetvalues}\marg{\cmd{Surname}=Surname,\cmd{Organisation}=Organisation}
  Forename: \gls{DTLmapget}\marg{\mapgetoptval{key}{Forename}}.
  Surname: \cmd{checkmissing}\marg{\cmd{Surname}}.
  Organisation: \cmd{checkmissing}\marg{\cmd{Organisation}}.
  \cmd{par}
}
\end{codebox}
Note that it won't work if you use \gls{DTLmapget} in the argument
of \gls{DTLifnull} or \gls{DTLifnullorempty} as the command
\gls{DTLmapget}\margm{options} doesn't represent null.
Either use \gls{DTLmapgetvalues} (as above) or get the value with
\mapgetopt{return}. The actual code used in
\exampleref{ex:mapnullemptymissing} has a second custom command that
both fetches and tests the value:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{showvalue}}[1]\marg{\comment{}
 \gls{DTLmapget}\marg{\mapgetoptval{key}{\#1},\mapgetoptval{return}{\cmd{myReturnVal}}}\comment{fetch value}
 \cmd{checkmissing}\marg{\cmd{myReturnVal}}\comment{}
}
\gls{DTLmapdata}\marg{
  Forename: \cmd{showvalue}\marg{Forename}.
  Surname: \cmd{showvalue}\marg{Surname}.
  Organisation: \cmd{showvalue}\marg{Organisation}.
  \cmd{par}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:mapnullemptymissing},
  title={Iterating Through Data with Empty or Missing Values},
  tag={customers},
  description={An example document that constructs a database in
the document and iterates over the contents}
]
{
\cmd{usepackage}\marg{datatool}\nl
\customersdb\nl
\cmd{newcommand}\marg{\cmd{checkmissing}}[1]\marg{\comment{}
 \gls{DTLifnullorempty}\marg{\#1}\marg{\cmd{emph}\marg{Missing}}\marg{\#1}}\nl
\cmd{newcommand}\marg{\cmd{showvalue}}[1]\marg{\comment{}
 \gls{DTLmapget}\marg{\mapgetoptvalm{key}{\#1},\mapgetoptval{return}{\cmd{myReturnVal}}}\comment{fetch value}
 \cmd{checkmissing}\marg{\cmd{myReturnVal}}\comment{}%
}
}
{%
\gls{DTLmapdata}\marg{\nlsp
  \cmd{showvalue}\marg{Forename}.\nlsp
  Surname: \cmd{showvalue}\marg{Surname}.\nlsp
  Organisation: \cmd{showvalue}\marg{Organisation}.\nlsp
  \cmd{par}\nl
}
}
\end{resultbox}

\subsection{Advanced Commands}
\label{sec:nullbase}

The following commands are actually provided by \sty{datatool-base}
rather than \sty{datatool} as they are used in datum tests or by the
\sty{person} package (which can be loaded without \sty{datatool}).

The actual null command is:
\cmddef{dtlnovalue}
This command should not be redefined and is provided for testing
purposes. It's not intended to be typeset in the document.

In general, it shouldn't be necessary to use this command, as you
can test with \gls{DTLifnull}, but you can do a simple test against
\gls{dtlnovalue}. For example, with \csfmt{ifdefequal} (provided by
\sty{etoolbox}). The difference is that \gls{DTLifnull} will also
test for the string null and number null commands, below.

When fetching values from a database, some commands (such as
\gls{DTLdisplaydb}) will set the placeholder that stores the value
of the current row and column to a \qt{string null} or \qt{numeric
null} according to the column type. So the \gls{DTLifnull} and
\gls{DTLifnullorempty} tests for null will also compare their first
argument against the following.

\cmddef{DTLstringnull}
Represents null for values that are expected to be strings.
This command should not be redefined but may be tested against to
determine if a placeholder command represents a null string.

\cmddef{DTLnumbernull}
Represents null for values that are expected to be numeric. This
will fully expand to 0 if used in calculations.
This command should not be redefined but may be tested against to
determine if a placeholder command represents a null number.

\cmddef{datatoolifnull:N}
Tests if the given token list variable represents null. This will test
\meta{tl var} for equality with \gls{dtlnovalue}, \gls{DTLstringnull}
and \gls{DTLnumbernull}.

\cmddef{datatoolifnullorempty:N}
Tests if the given token list variable is empty or represents null. This will test
\meta{tl var} for equality with \gls{dtlnovalue}, \gls{DTLstringnull}
and \gls{DTLnumbernull} and the empty datum constant \gls{cdatatoolemptydatumtl}
as well as testing if the token list variable has an empty value.

\cmddef{datatoolifnull:n}
If the argument is a single token, this will return the same result as
\gls{datatoolifnull:N} otherwise the result will be false.
The higher level user command \gls{DTLifnull} now simply uses
\gls{datatoolifnull:n}.

\cmddef{datatoolifnullorempty:n}
If the argument is a single token, this will return the same result as
\gls{datatoolifnullorempty:N} otherwise it will be true if the
argument is empty and false otherwise.
The higher level user command
\gls{DTLifnullorempty} now simply uses \gls{datatoolifnullorempty:n}.

\begin{information}
If \meta{tl} isn't a single token, \gls{datatoolifnullorempty:n}
won't test for the string or numeric null values represented by
\gls{DTLstringnull} and \gls{DTLnumbernull}.
\end{information}

\section{Special Values}
\label{sec:specialvalue}

A special value is an entry that's added to a database where the value starts with:
\cmddef{dtlspecialvalue}
This simply expands to its argument but its presence at the start
of a value indicates that special treatment is required for that entry
when adding the entry to the database and when writing the database to a DBTEX
file. When adding a value that starts with this command to a
database, the \opt{new-value-trim}, \opt{new-value-expand} and
\opt{store-datum} options will be ignored.

\begin{important}
If you use an action to add the value, such as the
\action{new-entry} action, the \actionopt{expand-value}
and \actionopt{expand-once-value} will remove the special command
and it won't be considered a special value.
\end{important}

When writing the database to an external DBTEX file with \gls{DTLwrite},
any entry starting with \gls{dtlspecialvalue} will be allowed to
expand, regardless of the I/O \ioopt{expand} setting. Note that if there
is any trailing content after the argument of \gls{dtlspecialvalue}
that will also expand. This doesn't apply to any of the other file
formats. For example, if you export to DTLTEX or \idx{CSV} then 
\gls{dtlspecialvalue} will be included with \iooptval{expand}{none}.

This command was added for the benefit of the \sty{datagidx} package
to encapsulate values in internal columns such as \optfmt{Used} 
to allow them to be reset for use at the start of the next
\LaTeX\ run when the database saved at the end of the previous run
is read in the preamble of the next.

\begin{warning}
You can't perform a quick lookup by value (for example, with the
\action{select-row} action) where the entry has the
\gls{dtlspecialvalue} command.
\end{warning}

\section{Editing Database Rows}
\label{sec:editdb}

Rows can be edited whilst looping through a database with \gls{DTLmapdata}
with the \mapdataopt{allow-edits} option set (see \sectionref{sec:mapdataedit}
and \exampleref{ex:mapdataedit}) or with the unstarred \gls{DTLforeach} (see
\sectionref{sec:dbforeachedit} and \exampleref{ex:foreachedit}).

It's also possible to edit a single row of the database outside of those loop
commands. In order to do this, it's first necessary to select the required row
and set it as the \idx{current-row}.  This stores the row information in the
\gls{dtlcurrentrow} token register, the preceding rows in the
\gls{dtlbeforerow} token register, and the following rows in the
\gls{dtlafterrow} token register.

Modifications can then be performed on the \gls{dtlcurrentrow} register using the
commands described in \sectionref{sec:currentrow}. Once all the required changes have
been made, the database contents can then be updated using \gls{dtlrecombine} or,
if the row should be deleted, \gls{dtlrecombineomitcurrent}.

\begin{information}
If you need to modify a number of rows, it's simpler to use \gls{DTLmapdata}
with \mapdataopt{allow-edits}.
\end{information}

The \idx{current-row} can be setup using commands such as \gls{dtlgetrow} or you can use the
\action{select-row} action (or the \action{find} action with the option 
\actionfindoptval{select}{true}).  

Note that although iterative commands such as \gls{DTLdisplaydb} and
\gls{DTLforeach} set the \idx{current-row}, if you use and of the editing commands
described in \sectionref{sec:currentrow} within the loop body, they will cause
interference.  Within \gls{DTLforeach}, use the designated commands described
in \sectionref{sec:dbforeachedit}.

Within \gls{DTLdisplaydb}, the \idx{current-row} is only set to allow querying values
from the hooks while the \env{tabular} contents are being constructed (for
example, to fetch an entry from the \idx{current-row} or to compute aggregates with
the \action{current-row-values} or \action{current-row-aggregate} actions).

\mExampleref{ex:selectandeditrow} selects the row from the \qt{customers} database 
(see \sectionref{sec:customers}) where the \optfmt{Id} column is equal to 9.
This happens to be the ninth row, so the row could
be selected by its row index with \gls{dtlgetrow}:
\begin{codebox}
\gls{dtlgetrow}\marg{customers}\marg{9}
\end{codebox}
If it's possible that the row index may not be the same as the \optfmt{Id} value, 
\gls{dtlgetrowforvalue} may be used (since the Id column has unique values).
The column index (not the key) is needed in the reference. In this case the 
\optfmt{Id} column has index 1:
\begin{codebox}
\gls{dtlgetrowforvalue}\marg{customers}\marg{1}\marg{9}
\end{codebox}
If the index isn't known, it can be obtained with \gls{dtlcolumnindex}:
\begin{codebox}
\gls{dtlgetrowforvalue}\marg{customers}
\marg{\gls{dtlcolumnindex}\marg{customers}\marg{Id}}\comment{column index}
\marg{9}\comment{value}
\end{codebox}
Alternatively, the \action{select-row} action may be used:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Id},\actionoptval{value}{9}}\marg{\action{select-row}}
\end{codebox}
If a more complex selection criteria is required, the \action{find} action can be used.
Remember that the \actionfindopt{select} option should be set if the \action{find} action 
should select the \idx{current-row}.

The customer with \optfmt{Id} set to 9 has an empty \optfmt{Organisation} column. This
means that the column has actually been set in the \idx{current-row}, so it needs to be
replaced rather than set:
\begin{codebox*}
\gls{dtlreplaceentryincurrentrow}
\marg{Newt Fellowship}\comment{new value}
\marg{\gls{dtlcolumnindex}\marg{customers}\marg{Organisation}}\comment{column index}
\end{codebox*}
This row doesn't have the Age and Email columns set. These can be appended, but note
that in this case the column key rather than column index is supplied. This is because 
a new column will be created if it hasn't already been defined for the database.
\begin{codebox*}
\gls{dtlappendentrytocurrentrow}
\marg{Email}\comment{column key}
\marg{s@example.com}\comment{value}
\end{codebox*}
Alternatively, \gls{dtlupdateentryincurrentrow} may be used to update an entry
if the column is already set or append it otherwise. This again takes the key rather
than the column index as the first argument:
\begin{codebox}
\gls{dtlupdateentryincurrentrow}
\marg{Age}\comment{column key}
\marg{23}\comment{value}
\end{codebox}

Once all modifications have been made, the \gls{dtlbeforerow}, \gls{dtlcurrentrow}
and \gls{dtlafterrow} content needs to be recombined in order to finish the updates:
\begin{codebox*}
\gls{dtlrecombine}
\end{codebox*}

Suppose now, the customer with Id~2 needs to be remove. The required row again 
needs to be selected first:
\begin{codebox}
\gls{dtlgetrowforvalue}\marg{customers}
\marg{\gls{dtlcolumnindex}\marg{customers}\marg{Id}}\comment{column index}
\marg{2}\comment{value}
\end{codebox}
The database now needs to be reconstructed without this row:
\begin{codebox*}
\gls{dtlrecombineomitcurrent}
\end{codebox*}
\Exampleref{ex:selectandeditrow} then redisplays the data after these modifications.
(Compare with the original data shown in \exampleref{ex:nullcsv}.)

\begin{resultbox}[float]
\createexample*
 [label={ex:selectandeditrow},
  title={Editing a Row of Data},
  tag={customers},
  description={An example document that loads data from a CSV file, edits a row
and displays the content in a table}
]
{
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers.csv}
}
{%
\comment{Edit ID 9}%
\gls{DTLaction}\oarg{\actionoptval{key}{Id},\actionoptval{value}{9}}\marg{\action{select-row}}\nl
\gls{dtlreplaceentryincurrentrow}\nl
\marg{Newt Fellowship}\comment{new value}%
\marg{\gls{dtlcolumnindex}\marg{customers}\marg{Organisation}}\comment{column index}%
\gls{dtlappendentrytocurrentrow}\nl
\marg{Email}\comment{column key}%
\marg{sally.mander@example.com}\comment{value}%
\gls{dtlupdateentryincurrentrow}\nl
\marg{Age}\comment{column key}%
\marg{23}\comment{value}%
\gls{dtlrecombine}
\codepar
\comment{Remove ID 2}%
\gls{dtlgetrowforvalue}\marg{customers}
\marg{\gls{dtlcolumnindex}\marg{customers}\marg{Id}}\comment{column index}%
\marg{2}\comment{value}%
\gls{dtlrecombineomitcurrent}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\section{Arithmetical Computations on Database Entries}
\label{sec:dbarith}

\begin{information}
The \action{aggregate} action (see \sectionref{sec:action}) provides
a way of aggregating numeric data in one or two columns of a
database. Alternatively, you can use the commands listed here. Aside
from \gls{DTLcomputebounds}, the aggregate commands in this section
return \idxpl{formattednumber}.  Additionally, rows may be filtered
according to a condition.  This is different to the
\action{aggregate} action which returns \idxpl{plainnumber} with the
default \actionoptval{datum}{false} action setting (see \exampleref{ex:actiondatum}).
\end{information}

The commands described in \sectionref{sec:fp} may be used on
database values. Remember that if you database contains
\idxpl{formattednumber} rather than \idxpl{plainnumber}, you will
need to use the commands in \sectionref{sec:formattedfp} to parse
the formatted number to obtain the numeric value.

\begin{information}
If you need to repeatedly parse numeric values in a database, 
you can increase efficiency by setting \optval{store-datum}{true}
before loading or creating a database.
\end{information}

The commands described in \sectionref{sec:fp} are dependent on the
\opt{math} processor. As from version 3.0, the aggregate commands
described here directly use the \styfmt{l3fp} library after converting
\idxpl{formattednumber} to reduce the parsing overhead.

\cmddef{DTLsumforkeys}
Sums all numeric values in the columns identified by the keys in the
comma-separated \meta{key list} for all databases listed in the
comma-separated \meta{db list} and assigns \meta{cmd} to the total
as a \idx{formattednumber}. If \optval{store-datum}{true},
\meta{cmd} will be a \idx{datumcs}, otherwise \meta{cmd} will simply
expand to the \idx{formattednumber}.

The first optional argument \meta{condition} may be set to a boolean
that's suitable for use in the first argument of \gls{ifthenelse}.
The second optional argument \idx{assign-list} may be set to the
\code{\meta{cs}\dequals\meta{key}} assignment list suitable for use
in \gls{DTLmapgetvalues} so that the placeholder commands \meta{cs}
may be referenced in \meta{condition}. If the condition evaluates
to false, the row will be omitted from the total. Note that any
non-numeric values will automatically be skipped.

A quicker alternative in the case of only one database, one column
and no condition is:
\cmddef{DTLsumcolumn}
This sums over all numeric items in the column with the label 
\meta{key} of the database identified by \meta{db} and stores
the result as a \idx{formattednumber} in the control sequence
\meta{cmd}. If \optval{store-datum}{true},
\meta{cmd} will be a \idx{datumcs}, otherwise \meta{cmd} will simply
expand to the \idx{formattednumber}.

\cmddef{DTLmeanforkeys}
Computes the mean (average) of all numeric values in the columns
identified by the keys in the comma-separated \meta{key list} for
all databases listed in the comma-separated \meta{db list} and
assigns \meta{cmd} to the result as a \idx{formattednumber}. If
\optval{store-datum}{true}, \meta{cmd} will be a \idx{datumcs},
otherwise \meta{cmd} will simply expand to the
\idx{formattednumber}. The optional arguments are as for
\gls{DTLsumforkeys}.

A quicker alternative in the case of only one database, one column
and no condition is:
\cmddef{DTLmeanforcolumn}
This computes the mean over all numeric items in the column with the label 
\meta{key} of the database identified by \meta{db} and stores
the result as a \idx{formattednumber} in the control sequence
\meta{cmd}. If \optval{store-datum}{true},
\meta{cmd} will be a \idx{datumcs}, otherwise \meta{cmd} will simply
expand to the \idx{formattednumber}.

\cmddef{DTLvarianceforkeys}
Computes the variance of all numeric values in the columns
identified by the keys in the comma-separated \meta{key list} for
all databases listed in the comma-separated \meta{db list} and
assigns \meta{cmd} to the result as a \idx{formattednumber}. If
\optval{store-datum}{true}, \meta{cmd} will be a \idx{datumcs},
otherwise \meta{cmd} will simply expand to the
\idx{formattednumber}. The optional arguments are as for
\gls{DTLsumforkeys}.

A quicker alternative in the case of only one database, one column
and no condition is:
\cmddef{DTLvarianceforcolumn}
This computes the variance of all numeric items in the column with the label 
\meta{key} of the database identified by \meta{db} and stores
the result as a \idx{formattednumber} in the control sequence
\meta{cmd}. If \optval{store-datum}{true},
\meta{cmd} will be a \idx{datumcs}, otherwise \meta{cmd} will simply
expand to the \idx{formattednumber}.

\cmddef{DTLsdforkeys}
Computes the standard deviation of all numeric values in the columns
identified by the keys in the comma-separated \meta{key list} for
all databases listed in the comma-separated \meta{db list} and
assigns \meta{cmd} to the result as a \idx{formattednumber}. If
\optval{store-datum}{true}, \meta{cmd} will be a \idx{datumcs},
otherwise \meta{cmd} will simply expand to the
\idx{formattednumber}. The optional arguments are as for
\gls{DTLsumforkeys}.

A quicker alternative in the case of only one database, one column
and no condition is:
\cmddef{DTLsdforcolumn}
This computes the standard deviation of all numeric items in the
column with the label \meta{key} of the database identified by
\meta{db} and stores the result as a \idx{formattednumber} in the
control sequence \meta{cmd}. If \optval{store-datum}{true},
\meta{cmd} will be a \idx{datumcs}, otherwise \meta{cmd} will simply
expand to the \idx{formattednumber}.

\cmddef{DTLminforkeys}
Determines the minimum value over all numeric values in the columns
identified by the keys in the comma-separated \meta{key list} for
all databases listed in the comma-separated \meta{db list} and
assigns \meta{cmd} to the result as a \idx{formattednumber}. If
\optval{store-datum}{true}, \meta{cmd} will be a \idx{datumcs},
otherwise \meta{cmd} will simply expand to the
\idx{formattednumber}. The optional arguments are as for
\gls{DTLsumforkeys}.

A quicker alternative in the case of only one database, one column
and no condition is:
\cmddef{DTLminforcolumn}
This determines the minimum value over all numeric items in the
column with the label \meta{key} of the database identified by
\meta{db} and stores the result as a \idx{formattednumber} in the
control sequence \meta{cmd}. If \optval{store-datum}{true},
\meta{cmd} will be a \idx{datumcs}, otherwise \meta{cmd} will simply
expand to the \idx{formattednumber}.

\cmddef{DTLmaxforkeys}
Determines the maximum value over all numeric values in the columns
identified by the keys in the comma-separated \meta{key list} for
all databases listed in the comma-separated \meta{db list} and
assigns \meta{cmd} to the result as a \idx{formattednumber}. If
\optval{store-datum}{true}, \meta{cmd} will be a \idx{datumcs},
otherwise \meta{cmd} will simply expand to the
\idx{formattednumber}. The optional arguments are as for
\gls{DTLsumforkeys}.

A quicker alternative in the case of only one database, one column
and no condition is:
\cmddef{DTLmaxforcolumn}
This determines the maximum value over all numeric items in the
column with the label \meta{key} of the database identified by
\meta{db} and stores the result as a \idx{formattednumber} in the
control sequence \meta{cmd}. If \optval{store-datum}{true},
\meta{cmd} will be a \idx{datumcs}, otherwise \meta{cmd} will simply
expand to the \idx{formattednumber}.

If you need the sum, mean, standard deviation, minimum and maximum
values for a column of just one database, it's more efficient to use
the \action{aggregate} action. Note, however, that specifying two
columns in the \action{aggregate} action indicates two separate sets
of data, whereas two columns with commands like \gls{DTLsumforkeys}
treats both columns as a single block of data.

\cmddef{DTLcomputebounds}
Computes the maximum and minimum $x$ and $y$ values over all the
databases listed in the comma-separated \meta{db-list}, where the
$x$ values are in the column identified by the label \meta{x-key}
and the $y$ values are in the column identified by the label 
\meta{y-key}.

The optional \meta{condition} may be used to filter rows. If
provided \meta{condition} should be in the form suitable for use in
the first argument of \gls{ifthenelse}. Only values in rows where the
conditional evaluates to true will be referenced.

The results are stored as \idxpl{plainnumber} in the control
sequences \meta{minX cmd} (the minimum $x$ value),
\meta{minY cmd} (the minimum $y$ value),
\meta{maxX cmd} (the maximum $x$ value), and
\meta{maxY cmd} (the maximum $y$ value).

If you only have one database and no condition, you may prefer to
use the \action{aggregate} action:
\begin{compactcodebox}
\gls{DTLaction}
\oargm{
 \actionoptval{key}{\meta{x-key}}, 
 \actionoptval{key2}{\meta{y-key}}, 
 \actionoptvalm{options}{min,max}
}\marg{\action{aggregate}}
\gls{DTLget}\oarg{min}\margm{minX cmd}
\gls{DTLget}\oarg{min2}\margm{minY cmd}
\gls{DTLget}\oarg{max}\margm{maxX cmd}
\gls{DTLget}\oarg{max2}\margm{maxY cmd}
\end{compactcodebox}

\section{Sorting a Database}
\label{sec:sort}

\begin{important}
If you have a large database, it's much more efficient to sort using
\app{datatooltk} or some other external tool which can save to a
file format that \sty{datatool} can load.
\end{important}

If your database isn't too large and you are unable to include an
external tool into your document to perform sorting, then it's
possible to sort a database with the commands described in this
section.

Version 3.0 has introduced a new command \gls{DTLsortdata}
(described in \sectionref{sec:DTLsortdata}), which is
analogous to \gls{DTLsortwordlist}. It's more efficient and more flexible than the
older \gls{dtlsort} (described in \sectionref{sec:dtlsort}).

\subsection{Sorting with \glsfmttext{DTLsortdata}}
\label{sec:DTLsortdata}

\cmddef{DTLsortdata}
This command sorts the data (in the database identified by
\meta{db-name}) according to the given criteria. It uses
the same underlying methodology as \gls{DTLsortwordlist}, in that it
first converts all the sort values into byte sequences using a
handler function, such as \gls{DTLsortwordhandler}, and then sorts
the byte sequences. This makes sorting faster as it doesn't have to
repeatedly parse each sort value.

\begin{information}
The modification to the database will match the \opt{global}
setting.
\end{information}

The \meta{db-name} argument may be empty, which indicates that the
default database (identified with \opt{default-name} in
\gls{DTLsetup}) should be sorted. Available \meta{options} are
described in \sectionref{sec:DTLsortdataopts} and the 
\meta{criteria} argument is described in
\sectionref{sec:DTLsortdatacolumnopts}.

\subsubsection{\glsfmttext{DTLsortdata} Options}
\label{sec:DTLsortdataopts}

The optional argument \meta{options} of \gls{DTLsortdata} should be 
a \keyval\ list of any of the following:
\optiondef{sortdata.function}
The handler function to use (see \sectionref{sec:dtlsortwordlistcmds}).

\optiondef{sortdata.encap}
The value should be a command that takes three arguments:
\code{\margm{value}\margm{col-idx}\margm{db-name}}. 
If set, all non-null values will be encapsulated with this
command and expanded before being passed to the handler function. The first
argument \meta{value} is the actual value, the second \meta{col-idx}
is the column index from which the value was obtained, and
\meta{db-name} is the database name. 

\begin{important}
The value will expand differently with \sortdataopt{encap} set. Be
careful of fragile commands in the database if this option is used.
\end{important}

An empty setting \sortdataoptvalm{encap}{} indicates no encapsulation.
\Exampleref{ex:sortauthor} in \sectionref{sec:sortauthorex} uses
this option to encapsulate values with \gls{DTLbibsortencap}.

\optiondef{sortdata.replace}
This determines whether or not a missing value should be replaced
(if the \sortdatacolumnopt{replacements} column option is set). The
value may be either \optfmt{null}, which will only replace null
values, or \optfmt{null or empty}, which will replace null or empty
values.

\optiondef{sortdata.missing-column-action}
This option indicates what to do if a column key referenced in the
sort criteria doesn't exist. The value may be one of: \optfmt{error}
(trigger an error), \optfmt{warn} (issue a warning) or
\optfmt{ignore} (ignore the reference).

\optiondef{sortdata.save-group-key}
If this option is set to a non-empty value, \gls{DTLsortdata} will
obtain the letter group (using \gls{DTLassignlettergroup}) from the
sort value and save it in the column identified by \meta{col-key}.
If the column doesn't exist, it will be created.
After obtaining the letter group, the value will be post-processed
by:
\cmddef{datatoolpostprocesslettergroup:N}
This requires \LaTeX3 syntax and does nothing by default. The
argument is the token list variable used to store the letter group.

\optiondef{sortdata.save-group-column}
As \sortdataopt{save-group-key} but identifies the column by its
index. Note that in this case, the column must either exist or be
one more than the database's column count.

\optiondef{sortdata.save-group}
A shortcut for \sortdataoptval{save-group-key}{group}.

\optiondef{sortdata.save-sort-key}
If this option is set to a non-empty value, \gls{DTLsortdata} will
save the sort value in the column identified by \meta{col-key}. 
If the column doesn't exist, it will be created.  This
is primarily intended for debugging. If the resulting order is
unexpected, this can be used to check that the sort values were
correctly set. Alternatively, you can use the \opt{verbose} package
option to view the information in the transcript.

\optiondef{sortdata.save-sort-column}
As \sortdataopt{save-sort-key} but identifies the column by its
index. Note that in this case, the column must either exist or be
one more than the database's column count.

\optiondef{sortdata.save-sort}
A shortcut for \sortdataoptval{save-sort-key}{sort}.

\subsubsection{\glsfmttext{DTLsortdata} Column Options}
\label{sec:DTLsortdatacolumnopts}

The \meta{criteria} argument of \gls{DTLsortdata}
should be a comma-separated list where each item is in the form
\code{\meta{column-key}\dequals\margm{column-options}} where
\meta{column-key} is the label identifying a column to sort and
\meta{column-options} is a \keyval\ list of options that apply to
that column.

The \code{=\margm{column-options}} part may be omitted if
the default options should be used. If present, the following
options are available:
\optiondef{sortdata.column.ascending}
If this boolean option is true, the sort will be in ascending order.
For columns with a numerical data type, this will be in ascending
numerical order, otherwise it will be in ascending lexicographic
order.

\optiondef{sortdata.column.asc}
A valueless shortcut for \sortdatacolumnoptval{ascending}{true}.

\optiondef{sortdata.column.descending}
An antonym of \sortdatacolumnopt{ascending}. If true, the sort
will be in descending order.

\optiondef{sortdata.column.desc}
A valueless shortcut for \sortdatacolumnoptval{descending}{true}.

\optiondef{sortdata.column.replacements}
If set, the value should be a comma-separated list of column keys to
use as a replacement if a missing value (as determined by
\sortdataopt{replace}) is encountered.

The first \meta{column-key} in the criteria list is the primary sort
column. If there are any identical values in that column, then the
sort values from the second \meta{column-key} will be used, and so
on. For example, the \qt{marks} database (\sectionref{sec:marks})
has three students with the surname \qt{Brown} and two of them have
the surname \qt{Jane}.  The student number disambiguates them. So
the following will first sort by surname, then (for identical
surnames) by forename, and finally (for identical surname and
forename) by student number:
\begin{codebox}
\gls{DTLsortdata}\marg{marks}\marg{Surname,Forename,StudentNo}
\end{codebox}

If a column has missing (null) values, then those values will be
treated as empty for string columns or 0 for numeric columns. This
means that sorting a string column in ascending order will place all
the null values at the top with the empty values. The secondary sort
columns in the criteria list will then determine their relative
order.

If you want to specify an alternative column to use if a value is
missing, then you need to identify the replacement column
with the \sortdatacolumnopt{replacements} option in \meta{column-options}.
Whether or not an empty value (as opposed to a null value) is
considered missing is determined by the \sortdataopt{replace}
option, which may be supplied in the optional argument of
\gls{DTLsortdata}.

\subsubsection{\glsfmttext{DTLsortdata} Examples}
\label{sec:DTLsortdatacolumnexs}

\mExampleref{ex:sortcsvnorepl} loads the \qt{customers} database from the
\filefmt{customers.csv} file (see \sectionref{sec:customers}), which has some
empty values in the Organisation column. This data is then sorted with:
\begin{codebox}
\gls{DTLsortdata}\marg{customers}\marg{Organisation,Surname,Forename}
\end{codebox}
In this case, no replacement columns are provided, so the sort value
for the Organisation column in the Polly Parrot, Dickie Duck and
Sally Mander rows will be empty and those rows will be placed at the
start. Their relative order is then determined by their Surname, so
the Dickie Duck row comes first. (Compare \exampleref{ex:sortcsvnorepl} with the
near identical \exampleref{ex:sortlocale} which has localisation
support.)

The null values are shown as \qt{NULL} (for string columns) or 0
(for numeric columns) by \gls{DTLdisplaydb}. Whereas empty values
show as empty. This is why Dickie Duck's age is blank in the Age
column, because it was set to empty, but the missing ages (where
there was no trailing comma at the end of the line in the \idx{CSV}
file) show as~0.

\begin{resultbox}
\createexample*
 [label={ex:sortcsvnorepl},
  title={Sorting CSV Data Using \cmd{DTLsortdata} by Organisation, Surname and Forename With
No Replacements},
  tag={customers},
  description={An example document that loads data from a CSV file
and sorts it according to the Organisation, Surname and Forename
from each row}
]
{
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\cmd{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers.csv}
}
{%
\comment{sort data by Organisation, then Surname, then Forename}%
\gls{DTLsortdata}\marg{customers}\marg{Organisation,Surname,Forename}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\mExampleref{ex:sortcsvrepl}, in contrast, has:
\begin{codebox}
\gls{DTLsortdata}\marg{customers}
\marg{
  Organisation=\marg{\sortdatacolumnoptvalm{replacements}{Surname,Forename}},
  Surname=\marg{\sortdatacolumnoptvalm{replacements}{Forename}},
  Forename
}
\end{codebox}
In this case, if the sort value is missing from the designated
column, the first column within the corresponding
\sortdatacolumnopt{replacements} list that doesn't have a missing
value will be used.

\begin{description}
\item[Primary] In this example, the primary sort value is obtained
from the Organisation column. If that value is missing, the primary
sort value will be obtained from the Surname column, but if that is
also missing then the primary sort value will be obtained from the
Forename column. If that is also missing, then the primary sort
value will be empty.

\item[Secondary] The secondary sort value is only used if the
primary sort values are identical when comparing two rows.
In this case, the secondary sort value is obtained from the Surname
column. If that value is missing, the secondary sort value will be
obtained from the Forename column. If that value is also missing,
the secondary sort value will be empty.

\item[Tertiary] The tertiary sort value is only used if both the
primary and secondary sort values are identical when comparing two
rows. In this case, the tertiary sort value is obtained from the
Forename column. However, no replacement columns have been identified, so
if the Forename column is empty, the tertiary sort value will be
empty.
\end{description}

\begin{resultbox}
\createexample*
 [label={ex:sortcsvrepl},
  title={Sorting CSV Data Using \cmd{DTLsortdata} by Organisation, Surname and Forename With Replacements},
  tag={customers},
  description={An example document that loads data from a CSV file
and sorts it according to the Organisation, Surname and Forename
from each row with replacements for the missing elements}
]
{%
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\cmd{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers.csv}
}
{%
\gls{DTLsortdata}\marg{customers}\nl
\marg{\nlsp
  Organisation=\marg{\sortdatacolumnoptvalm{replacements}{Surname,Forename}},\nlsp
  Surname=\marg{\sortdatacolumnoptvalm{replacements}{Forename}},\nlsp
  Forename\nl
}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\mExampleref{ex:sortdbrepl} defines the customer data in the document
using action commands instead of loading the data from a \idx{CSV}
file (see \sectionref{sec:customers}). This
means that some of the rows have a missing Organisation column,
which can't occur with the \idx{CSV} file (except where missing
columns are occur at the end). The default 
\sortdataoptvalm{replace}{null or empty} setting will treat empty
values as missing, so in \exampleref{ex:sortdbrepl}
\begin{codebox}
\gls{DTLsortdata}\oarg{\sortdataoptval{replace}{null or empty}}\marg{customers}
\marg{
  Organisation=\marg{\sortdatacolumnoptvalm{replacements}{Surname,Forename}},
  Surname=\marg{\sortdatacolumnoptvalm{replacements}{Forename}},
  Forename
}
\end{codebox}
the resulting order is the same as for \exampleref{ex:sortcsvrepl}.
However, changing the setting so that only null (not empty) values
are treated as missing results in a different order.
\begin{codebox}
\gls{DTLsortdata}\oarg{\sortdataoptval{replace}{null}}\marg{customers}
\marg{
  Organisation=\marg{\sortdatacolumnoptvalm{replacements}{Surname,Forename}},
  Surname=\marg{\sortdatacolumnoptvalm{replacements}{Forename}},
  Forename
}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:sortdbrepl},
  title={Sorting Data Using \cmd{DTLsortdata} With Replacements (Null vs Empty)},
  tag={customers},
  description={An example document that defines data with missing
columns and sorts it according to the Organisation, Surname and Forename
from each row with replacements for the missing elements. In the
first case both null and empty values are considered missing. In the
second case only null values are considered missing}
]
{
\cmd{usepackage}\marg{datatool}\nl
\customersdb
}
{%
\marg{\comment{scope to limit the change}
\DTLsetup{\optval{global}{false}}\nl
Sort replacing null or empty values.\nl
\gls{DTLsortdata}\oarg{\sortdataoptval{replace}{null or empty}}\marg{customers}\nl
\marg{\nlsp
  Organisation=\marg{\sortdatacolumnoptvalm{replacements}{Surname,Forename}},\nlsp
  Surname=\marg{\sortdatacolumnoptvalm{replacements}{Forename}},\nlsp
  Forename\nl
}
\codepar
\gls{DTLdisplaydb}\marg{customers}\nl
}
\codepar
Sort replacing null (not empty) values.\nl
\gls{DTLsortdata}\oarg{\sortdataoptval{replace}{null}}\marg{customers}\nl
\marg{\nlsp
  Organisation=\marg{\sortdatacolumnoptvalm{replacements}{Surname,Forename}},\nlsp
  Surname=\marg{\sortdatacolumnoptvalm{replacements}{Forename}},\nlsp
  Forename\nl
}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\begin{information}
In all the above examples, \qt{É} comes after \qt{Z} because the
examples haven't used any localisation support.
\end{information}

\mExampleref{ex:sortlocale} adapts \exampleref{ex:sortcsvnorepl} to
use the GB English localisation support. This requires \sty{datatool-english}
to also be installed. The only difference in the document code between 
the two examples is the locale identification:
\begin{codebox}
\cmd{usepackage}[\optval{locales}{en-GB}]\marg{datatool}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:sortlocale},
  title={Sorting CSV Data Using \cmd{DTLsortdata} With Language Support},
  tag={customers},
  description={An example document that loads data from a CSV file
and sorts it according to the Organisation, Surname and Forename
from each row using the GB English localisation support}
]
{
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}[\optval{locales}{en-GB}]\marg{datatool}\nl
\cmd{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers.csv}
}
{%
\comment{sort data by Organisation, then Surname, then Forename}%
\gls{DTLsortdata}\marg{customers}\marg{Organisation,Surname,Forename}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\Examplesref{ex:sortcsvage,ex:sortdbage} both sort the data first by
the Age column (which is numerical) and then by the Surname column:
\begin{codebox}
\gls{DTLsortdata}\marg{customers}\marg{Age,Surname}
\end{codebox}
The difference between the two is that \mexampleref{ex:sortcsvage}
uses data from the \idx{CSV} file, which has an empty age element as
well as missing age elements, whereas \mexampleref{ex:sortdbage}
uses the data created within the document via action commands, which
has missing but not empty age elements. (There is an empty
Organisation element, but that column isn't contributing to the
sort.)

\begin{resultbox}
\createexample*
 [label={ex:sortcsvage},
  title={Sorting Data Using \cmd{DTLsortdata} on Age then Surname (Empty or Null Values)},
  tag={customers},
  description={An example document that defines data with missing or
empty Age elements and sorts it according to the Age and then Surname columns}
]
{
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\cmd{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers.csv}
}
{%
\gls{DTLsortdata}\marg{customers}\marg{Age,Surname}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\begin{resultbox}
\createexample*
 [label={ex:sortdbage},
  title={Sorting Data Using \cmd{DTLsortdata} on Age then Surname (No Empty Sort Values)},
  tag={customers},
  description={An example document that defines data with missing
but not empty Age elements and sorts it according to the Age and
then Surname columns}
]
{
\cmd{usepackage}\marg{datatool}\nl
\customersdb
}
{%
\gls{DTLsortdata}\marg{customers}\marg{Age,Surname}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\mExampleref{ex:sortmarksdes} sorts the \qt{marks} database (see
\sectionref{sec:marks}) in descending order of marks for the first
assignment column (\optfmt{Assign1}). The secondary sort (where the marks are
identical) is by the Surname column in ascending order:
\begin{codebox}
\gls{DTLsortdata}\marg{marks}
\marg{
 Assign1=\marg{\sortdatacolumnoptval{descending}{true}},
 Surname=\marg{\sortdatacolumnoptval{ascending}{true}}
}
\end{codebox}
This means that the students who obtained the same mark
for assignment 1 are listed in alphabetical order relative to each
other.

Since \sortdatacolumnoptval{ascending}{true} is the default, that
may be omitted for the Surname column, and \sortdatacolumnoptval{descending}{true}
may have the value omitted if it's true, so the \optfmt{Assign1} column
criteria can be written as \code{Assign1\dequals\marg{\sortdatacolumnopt{descending}}}
and since the part after the equals (\code{=}) doesn't contain any
commas or equals the outer bracing may be omitted. So the above can
be written more succinctly as:
\begin{codebox}
\gls{DTLsortdata}\marg{marks}\marg{Assign1=\sortdatacolumnopt{descending},Surname}
\end{codebox}
Since \sortdatacolumnopt{desc} is a synonym of
\sortdatacolumnoptval{descending}{true}, this can also be written
as:
\begin{codebox}
\gls{DTLsortdata}\marg{marks}\marg{Assign1=\sortdatacolumnopt{desc},Surname}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:sortmarksdes},
  title={Sorting Data Using \cmd{DTLsortdata} by Descending Numeric and Ascending String
Values},
  tag={marks},
  description={An example document that sorts data first by
assignment mark in descending numerical order and then by surname in 
ascending lexicographical order}
]
{
\exfile{studentmarks.csv}{\markscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
\gls{DTLsortdata}\marg{marks}\marg{Assign1=descending,Surname}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\subsection{Sorting with \glsfmttext{dtlsort}}
\label{sec:dtlsort}

The older \gls{dtlsort} command is less efficient than the newer \gls{DTLsortdata},
although \gls{dtlsort} has been rewritten in version 3.0 to use \LaTeX3's sequence sorting.

\cmddef{dtlsort}
Sorts the database identified by \meta{db-name} using the given
\meta{handler-cs} function for the comparisons, which should be
of the type described in \sectionref{sec:compare}. Unlike \gls{DTLsortdata}, 
the \meta{db-name} argument can't be empty.

\begin{information}
The modification to the database will match the \opt{global}
setting.
\end{information}

The \meta{criteria} argument should be a comma-separated list of column keys, 
where each item in the list may be just the key or in the form
\code{\meta{col-key}\dequals\meta{order}}. The \meta{order} may be 
\optfmt{ascending} or \optfmt{descending}. If omitted, \optfmt{ascending} is assumed.

\begin{information}
Unlike \gls{DTLsortdata}, where you may specify more information with
\code{\meta{col-key}\dequals\margm{options}}, with \gls{dtlsort}, only the
keywords \qtt{ascending} or \qtt{descending} may be used.
\end{information}

The other difference between \gls{dtlsort} and \gls{DTLsortdata} is that with
\gls{DTLsortdata}, the list of replacements is set for specific columns,
whereas with \gls{dtlsort}, a single list of replacement columns may be
provided in the optional argument, which will be used if any of the columns
listed in \meta{criteria} have a missing value.
Also with \gls{dtlsort}, the replacements are only used for null values (see \sectionref{sec:null})
not for empty values.

If any listed column in either \meta{criteria} or \meta{replacements} is
undefined, a warning will occur and the column will be dropped from the list.
(Unlike \gls{DTLsortdata}, there's no option to suppress the warning.) The list
of replacements may be omitted or empty but the \meta{criteria} argument must
have at least one defined column.

If any column has been identified as a numeric column, a numerical comparison
will be used (with \gls{DTLnumcompare}). In the event that two numeric values
are deemed equivalent, their string value will be compared using the provided
handler.

For example,
\begin{codebox}
\gls{dtlsort}\oarg{Editor,Title}\marg{Author}\marg{books}
  \marg{\gls{dtlwordindexcompare}}
\end{codebox}
This will sort the \qt{books} database on the \qt{Author} column (in ascending order).
Any row that doesn't have the Author column set will have the sort value obtained from the
\qt{Editor} column instead. If that column also isn't set, the sort value will be obtained from
the \qt{Title} column.

Compare this with:
\begin{codebox}
\gls{dtlsort}\oarg{Title}\marg{Author,Series,Volume}\marg{books}
  \marg{\gls{dtlwordindexcompare}}
\end{codebox}
In this case, the database will be sorted by the \qt{Author} column first. If
that column isn't set for a particular row, the sort value will be obtained
from the \qt{Title} column. If the sort value (Author, if set, or Editor
otherwise) is equivalent to the other row being compared (that is, the sort
handler returns 0), then the two rows will be compared on the \qt{Series}
column.  If that column isn't set, the Title will be used for the comparison
instead. If this secondary comparison is also considered equivalent, the two
rows will then be compared on the \qt{Volume} column.

This means that if the Author, Series and Volume columns are all missing for a particular row,
then the primary, secondary and tertiary sort values will all be the value from the Title column.
Contrast this with the more flexible \gls{DTLsortdata}:
\begin{codebox}
\gls{DTLsortdata}\marg{books}\marg{
  Author=\marg{\sortdatacolumnoptvalm{replacements}{Editor,Organisation}},
  Series=\marg{\sortdatacolumnoptvalm{replacements}{Title}},
  Volume
}
\end{codebox}

\cmddef{DTLsort}
A shortcut command that uses \gls{dtlsort}. The starred version uses
\gls{dtlicompare} as the handler function, and the unstarred version
uses \gls{dtlcompare}.

\mExampleref{ex:dtlsortcsvrepl} is the closest equivalent to \exampleref{ex:sortcsvrepl}
that uses \gls{dtlsort} instead of \gls{DTLsortdata}:
\begin{codebox}
\gls{dtlsort}\oarg{Surname,Forename}\comment{replacements}
  \marg{Organisation,Surname,Forename}\comment{sort criteria}
  \marg{customers}\comment{database}
  \marg{\gls{dtlwordindexcompare}}\comment{handler}
\end{codebox}
Note that this has produced a different result to \exampleref{ex:sortcsvrepl}
because with \gls{dtlsort} the replacements are only used for null values not for empty values.
Remember that in both examples, localisation support will need to be added to correctly
order values that contain non-\gls{ascii} characters.

\begin{resultbox}
\createexample*
 [label={ex:dtlsortcsvrepl},
  title={Sorting CSV Data Using \cmd{dtlsort} by Organisation, Surname and Forename With Replacements},
  tag={customers},
  description={An example document that loads data from a CSV file
and sorts it according to the Organisation, Surname and Forename
but the replacements are not used for empty values}
]
{%
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\cmd{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers.csv}
}
{\comment{replacements are only used for null not empy values. Compare with example "ex:sortcsvrepl" that uses \gls{DTLsortdata}}%
\gls{dtlsort}\oarg{Surname,Forename}\marg{Organisation,Surname,Forename}\marg{customers}\marg{\gls{dtlwordindexcompare}}
\codepar
\gls{DTLaction}\marg{display}
}
\end{resultbox}


\section{Database Files (I/O)}
\label{sec:io}

The data stored in the database can be saved to an external file
with \gls{DTLwrite}, described in \sectionref{sec:savedb}, or
a new database can be created by reading in a file with 
\gls{DTLread}, described in \sectionref{sec:loaddb}.

\subsection{File Formats}
\label{sec:fileformats}

There are essentially two different types of file format according
to how that data can be read into a \LaTeX\ document: 

\begin{itemize}
\item plain text which needs to be parsed and converted into a 
\sty{datatool} database (\idx{CSV} and \idx{TSV});
\item \LaTeX\ code which can simply be input into the document to
recreate the database.
\end{itemize}

In the second case, the file extension would ordinarily be \ext+{tex}
but there is a danger with \gls{DTLwrite} of accidentally overwriting a required
document file, so the default file extension is either \ext+{dtltex}
(for files containing user commands, such as \gls{DTLnewdb})
or \ext+{dbtex} (for files containing special internal commands that
aren't designed to be edited by hand). 

The \ext+{dtltex} files are easier to read and edit, but are slower
to load. The \ext+{dbtex} format has two versions: 2.0, which is
very hard to read but is the fastest to load, and 3.0, which is
easier to read and still much faster that the \ext+{dtltex} file
format. Note that \app{datatooltk} version 1.9 can read \ext+{dbtex}
v2.0 but not v3.0 (which was only introduced to \sty{datatool}
v3.0). The pending (at the time of writing) \app{datatooltk} version 2.0 will be able to read
the newer format. \idxc+{datumitem}{Datum markup} is only preserved for
\ioopteqvalref{format}{dbtex-3}. It will be stripped when writing
to all other formats.

Note that, while it is also possible to create a file containing 
a set of \gls+{DTLaction} commands that define a database, this is
slower to load than the \ext+{dtltex} formats. If you want to load
such a file, just use \gls{input} or \gls{InputIfFileExists} as
usual. There's no provision to save a file in this form.

\begin{warning}
Be aware that if a database contains values with characters that
don't have their usual category code, this information will be lost
when writing the database to an external file. This is particularly
a problem for the \ext+{dtltex} and \ext+{dbtex} files.
\end{warning}

The format is specified with the \ioopt{format} setting in the
optional argument of \gls{DTLread} and \gls{DTLwrite} or within the
\opt{io} value in \gls{DTLsetup}. The default is
\ioopteqvalref{format}{csv}.

\subsubsection{CSV and TSV Files}
\label{sec:csvfiles}

The default file format for both \gls{DTLwrite} and \gls{DTLread} is
\idx{CSV}. The only difference between \ioopteqvalref{format}{csv} and
\ioopteqvalref{format}{tsv} is the default file extension (\ext+{csv} or
\ext+{tsv}), and \ioopteqvalref{format}{tsv} will additionally implement
\gls{DTLsettabseparator} to set the separator to a \idx{tabchar} and
change the category code of the \idx{tabchar} to 12 (other).

If the file contains \LaTeX\ code, for example:
\begin{compactcodebox}
Product,Price (\gls{cs.dollar})
Book,\gls{cs.dollar}
\end{compactcodebox}
the use the \ioopteqvalref{csv-content}{tex} option. If the file
contains characters that are normally special to \LaTeX\ but need to
be treated literally then use the \ioopteqvalref{csv-content}{literal}
option. For example:
\begin{compactcodebox}
Product,Price (\idx{dollar})
Book,\idx{dollar}
\end{compactcodebox}

The default separator for the \iooptvalref{format}{csv} format is a
comma (\idx{commasep}), and can be changed with the \ioopt{separator} option.  Note
that if \ioopt{separator} comes after \ioopteqvalref{format}{tsv}
in the same option list, this will change the separator but leave
the default extension as \ext{tsv}.

The default separator is a double-quote (\idx{dblqdelim}), and can
be changed with the \ioopt{delimiter} option. The delimiter will
always be searched for when loading a \idx{CSV}\slash \idx{TSV} file
with \gls{DTLread}, but you can control whether or not the delimiter
is written with \gls{DTLwrite} with the \ioopt{add-delimiter}
option.

Spaces between the separator and delimiter are always trimmed. Leading and
trailing spaces inside the delimiter, or when there is no delimiter
present, is determined by the general \opt{new-value-trim} option. 
This needs to be set in \gls{DTLsetup}, not in
the optional argument of \gls{DTLread}. For example, to switch off
trimming:
\begin{codebox}
\gls{DTLsetup}\marg{\optval{new-value-trim}{false}}
\end{codebox}

Datum markup is not preserved when writing to a \idx{CSV} or
\idx{TSV} file nor is the database name.

\subsubsection{DTLTEX Files}
\label{sec:dtltexfiles}

The \ext+{dtltex} files are simply \LaTeX\ files that contain the
user level commands required to define a database. These are easier
to read and edit by hand, but are slower to load. There are two
supported formats: 

\begin{description}
\item[2.0] (\ioopteqvalref{format}{dtltex-2})
This has the database name hardcoded in the
file and will always try to define the database. This format contains
commands like \gls{DTLnewdb} but \gls{DTLread} locally sets the
\opt{global} option to true (as the internal workings of
\gls{DTLread} need to be scoped). If you need a local definition,
you can simply input the file, with a command such as \gls{input}.

\item[3.0]  (\ioopteqvalref{format}{dtltex-3})
This has the database name identified near the start of
the file but it's designed to allow the \ioopt{name} option to
override it and the \ioopteqvalref{load-action}{append} option will
prevent the database from being created (to allow the content to be
appended to another database).
\end{description}

\idxc+{datumitem}{Datum markup} is not preserved for either version. 

\begin{important}
The remainder of this section is for advanced users who want to
understand the file format.
\end{important}

When written by \gls{DTLwrite}, both start with the line:
\begin{compactcodebox}
\% DTLTEX \meta{version} \meta{encoding}
\end{compactcodebox}
where \meta{version} identifies the DTLTEX version number 
(either \code{2.0} or \code{3.0}), and \meta{encoding} is the
document encoding (obtained by expanding \gls{TrackLangEncodingName}). 
Note that this will be incorrect if the encoding changes are
\sty{datatool} is loaded. There's no way of knowing if the encoding
was changed after the database was created. In general it's best to
establish the document encoding as early as possible.

The next comment line provides information about file creator and
creation date. In the case of a file created by \sty{datatool}, this 
will have the \sty{datatool} version details. The creation date will
be obtained by expanding \gls{DTMnow} (provided by the
\sty{datetime2} package), if that command has been defined, otherwise
\gls{today} will be used.

DTLTEX version 2.0 was designed to work with \gls{input}, so it only
contains normal user-level commands that have an argument to
identify the database name (see \sectionref{sec:newdb}): \gls{DTLnewdb},
\gls{DTLnewrow}, and \gls{DTLnewdbentry}. The column headers will then be 
set with \gls{DTLsetheader} (regardless of the \ioopt{no-header} option). 
Finally, \gls{dtllastloadeddb} is defined to the database name:
\begin{compactcodebox}
\cmd{def}\gls{dtllastloadeddb}\margm{db-name}
\end{compactcodebox}
(This line was introduced in \sty{datatool} v2.15, so any file that
matches the rest of the format but omits this line should be
considered DTLTEX v1.0.)
Note that although \csfmt{def} is used, \gls{DTLread} will change
this to a global definition. Note that since these are all
document-level commands, the file can simply be loaded with
\gls{input}. This method can be used to locally define the database
(provided \optval{global}{false} is set).

DTLTEX version 3.0 defines the database with the commands listed
below. These are only intended for use within \gls{DTLread},
although the file can simply be \gls{input}.
\cmddef{DTLdbProvideData}
If the file is input within \gls{DTLread}, this command will 
locally set the \opt{default-name} to either the \ioopt{name} value, if
set, or \meta{db-name}, otherwise, and will create the database if
required by \ioopt{load-action}.

If \gls{DTLdbProvideData} is used outside of the context of
\gls{DTLread}, it will set the \opt{default-name} to
\meta{db-name} and define the database if it doesn't already exist.

In either case, both \gls{dtllastloadeddb} is defined to the database
name, and the \meta{default-name} is also set to the same value to
allow the database to be referenced in the following commands:
\cmddef{DTLdbNewRow}
Equivalent to:
\begin{compactcodebox}
\starredcs{DTLnewrow}\margm{default-name}
\end{compactcodebox}

\cmddef{DTLdbNewEntry}
Equivalent to
\begin{compactcodebox}
\starredcs{DTLnewdbentry}\margm{default-name}\margm{col key}\margm{value}
\end{compactcodebox}

Unless suppressed by \ioopt{no-header}, \gls{DTLwrite} will also
include code to set the header for each column with:
\cmddef{DTLdbSetHeader}
This is equivalent to
\begin{compactcodebox}
\starredcs{DTLsetheader}\margm{default-name}\margm{col key}\margm{header}
\end{compactcodebox}
Note that this is different to DTLTEX v2.0, which always has the
header code.

\subsubsection{DBTEX Files}
\label{sec:dbtexfiles}

The \ext+{dbtex} files are \LaTeX\ files that contain 
internal commands required to define a database. These are harder
to read and edit by hand, but are faster to load than the other file
formats. There are two supported formats: 

\begin{description}
\item[2.0] (\ioopteqvalref{format}{dbtex-2})
This has the database name hardcoded in the
file and will always try to define the database. 

Datum markup is not preserved. Any spaces at the start of an element
value will be lost.

\item[3.0] (\ioopteqvalref{format}{dbtex-3})
This has the database name identified near the start of
the file but it's designed to allow the \ioopt{name} option to
override it.

Datum markup is preserved.
\end{description}

The \ioopteqvalref{load-action}{append} option is not supported for
this format (for either version). 

\begin{important}
The remainder of this section is for advanced users who want to
understand the file format.
\end{important}

As with the DTLTEX format, \gls{DTLwrite} will start the file with 
comment lines. The first identifies the format:
\begin{compactcodebox}
\% DBTEX \meta{version} \meta{encoding}
\end{compactcodebox}
where \meta{version} identifies the DTLTEX version number 
(either \code{2.0} or \code{3.0}), and \meta{encoding} is the
document encoding, as for DTLTEX. The second comment line is the
creation information, as for DTLTEX.

The v2.0 format then starts with a check for the existence of the
database and exits the file input if it already exists:
\begin{compactcodebox}
\gls{DTLifdbexists}\margm{db-name}\%
\marg{\cmd{PackageError}\marg{datatool}\marg{Database `\meta{db-name}' already exists}\marg{}\%
\cmd{aftergroup}\cmd{endinput}}\marg{}\%
\end{compactcodebox}
The rest of the file consists of low-level internal commands that define the
underlying registers and commands used to store the database information. 
This means that \idx{@} needs to have its category code set to \qt{letter}.
A local scope is introduced to limit the effect of
\csfmt{makeatletter} and a message will be written to the transcript
if \opt{verbose} mode is on:
\begin{compactcodebox}
\cmd{bgroup}\cmd{makeatletter}
\cmd{dtl@message}\marg{Reconstructing database `\meta{db-name}'}\%
\end{compactcodebox}
This means that the internal commands used to store the database
information must be globally defined. (Note that \csfmt{global} is
redundant as all registers are globally defined, but this is now
part of the DBTEX v2.0 file format.) The column meta data is stored
in a token register, which needs to be defined and then set:
\begin{compactcodebox}
\cmd{expandafter}\cmd{global}\cmd{expandafter}
\cmd{newtoks}\cmd{csname} dtlkeys@\meta{db-name}\cmd{endcsname}
\cmd{expandafter}\cmd{global}
\cmd{csname} dtlkeys@\meta{db-name}\cmd{endcsname}=\margm{header markup}
\end{compactcodebox}
Similarly, the database content is stored in a token register, which
needs to be defined and then set:
\begin{compactcodebox}
\cmd{expandafter}\cmd{global}\cmd{expandafter}
\cmd{newtoks}\cmd{csname} dtldb@\meta{db-name}\cmd{endcsname}
\cmd{expandafter}\cmd{global}
\cmd{csname} dtldb@\meta{db-name}\cmd{endcsname}=\margm{body markup}
\end{compactcodebox}
The total number of rows is stored in a count register that needs to
be defined and set:
\begin{compactcodebox}
\cmd{expandafter}\cmd{global}
 \cmd{expandafter}\cmd{newcount}\cmd{csname} dtlrows@\meta{db-name}\cmd{endcsname}
\cmd{expandafter}\cmd{global}
 \cmd{csname} dtlrows@\meta{db-name}\cmd{endcsname}=\meta{num-rows}\gls{relax}
\end{compactcodebox}
Similarly, the total number of columns is stored in a count register that needs to
be defined and set:
\begin{compactcodebox}
\cmd{expandafter}\cmd{global}
 \cmd{expandafter}\cmd{newcount}\cmd{csname} dtlcols@\meta{db-name}\cmd{endcsname}
\cmd{expandafter}\cmd{global}
 \cmd{csname} dtlcols@\meta{db-name}\cmd{endcsname}=\meta{num-columns}\gls{relax}
\end{compactcodebox}
The column key to index mapping is implemented by defining:
\begin{compactcodebox}
\cmd{expandafter}
 \cmd{gdef}\cmd{csname} dtl@ci@\meta{db-name}@\meta{key}\cmd{endcsname}\margm{column-idx}\%
\end{compactcodebox}
This is done for each column. Finally, the local scope is ended and
\gls{dtllastloadeddb} is defined:
\begin{compactcodebox}
\cmd{egroup}
\cmd{def}\gls{dtllastloadeddb}\margm{db-name}\%
\end{compactcodebox}
Note that \gls{dtllastloadeddb} was only introduced in
\sty{datatool} v2.15, so if the last line is omitted, the file
should be considered DBTEX v1.0.

The \meta{header markup} consists of sub-blocks that contain the
meta data for each column in the form:
\begin{compactcodebox}
\cmd{db@plist@elt@w}
\cmd{db@col@id@w} \meta{column-idx}\comment{}
\cmd{db@col@id@end@} \comment{}
\cmd{db@key@id@w} \meta{key}\comment{}
\cmd{db@key@id@end@} \comment{}
\cmd{db@type@id@w} \meta{type}\comment{}
\cmd{db@type@id@end@} \comment{}
\cmd{db@header@id@w} \meta{header}\comment{}
\cmd{db@header@id@end@} \comment{}
\cmd{db@col@id@w} \meta{column-idx}\comment{}
\cmd{db@col@id@end@} \comment{}
\cmd{db@plist@elt@end@} \comment{}
\end{compactcodebox}
These commands are quarks and have no meaning. Unpredictable results
can occur in loops if the header blocks aren't in order of the column index.
It depends on whether the loop iterates over the column index or
maps over the header blocks.

Note that \gls{DTLwrite} automatically inserts the comment character
at the end of most lines, even though they are not always required.
If you are writing a tool that reads DBTEX files, remember to
discard the comments.

The \meta{body markup} is more complicated but has a similar
design.\footnote{Thanks to Morten~H\o gholm for the design.} This
consists of sub-blocks (\meta{row-markup}) that contain the data for each row:
\begin{compactcodebox}
\cmd{db@row@elt@w} \% 
\cmd{db@row@id@w} \meta{row-idx}\%
\cmd{db@row@id@end@} \%
\cmd{db@row@elt@w} \% 
\meta{entry markup}
\cmd{db@row@elt@w} \%
\cmd{db@row@id@w} \meta{row-idx}\%
\cmd{db@row@id@end@} \%
\end{compactcodebox}
Again, these commands are quarks and have no meaning, and unpredictable results
can occur if the blocks aren't ordered according to the row index.
The \meta{entry markup} consists of sub-blocks (\meta{entry column
markup}) that contain the data for each entry in the given row and
column:
\begin{compactcodebox}
\cmd{db@col@id@w} \meta{column-idx}\%
\cmd{db@col@id@end@} \%
\cmd{db@col@elt@w} \meta{value}\%
\cmd{db@col@elt@end@} \%
\cmd{db@col@id@w} \meta{column-idx}\%
\cmd{db@col@id@end@} \%
\end{compactcodebox}
where \meta{column-idx} is the column index and \meta{value} is the
value for that column.
Again, these commands are quarks and have no meaning, and unpredictable results
can occur if the blocks aren't ordered according to the column index.

Note that with DBTEX v2.0, as mentioned earlier, \csfmt{makeatletter} is used to allow
internal commands, which means that \idx{@} will have a letter
category code. This will affect any data contained in the database
that includes the \idx{@} character (for example, if the database
has an email column). See \exampleref{ex:loadcustomers}.  Although
the quarks have no meaning, spaces following those commands are
ignored. This means that if an entry starts with a space that space
will be lost.

It's not possible to switch to \LaTeX3 syntax for a new file format
as the data will likely contain one or more of the characters that
have their category code changed by \gls{ExplSyntaxOn} (most notably
the space character). Therefore, the \idxpl+{datumitem} markup is
stripped by \gls{DTLwrite}, since it contains \LaTeX3 commands.  The
only way to retain it is via DBTEX v3.0, which hides the \LaTeX3
syntax within its custom reconstruction commands, which expand the content
before setting the underlying token registers. This is faster than
constructing the content with \gls{DTLnewdbentry}, but not as fast
as explicitly setting the token register, as is done with DBTEX v2.0.

\begin{important}
Although DBTEX v2.0 is the fastest format to load, you need to
be aware of its limitations.
\end{important}

The DBTEX v3.0 format, starts with the same command as for DTLTEX
v3.0:
\begin{compactcodebox*}
\gls{DTLdbProvideData}\margm{db-name}
\end{compactcodebox*}
This sets up the \meta{default-name} to either the \ioopt{name}
setting, if provided, or \meta{db-name}, otherwise.  This allows the
appropriate name to be used in the subsequent commands. Note that
this command also defines \gls{dtllastloadeddb} to the database
name, but within \gls{DTLread} it doesn't define the database with
the DBTEX formats as the database internals are either explicitly
defined (\ioopteqvalref{format}{dbtex-2}), or they are constructed by
the following command:

\cmddef{DTLreconstructdatabase}
This creates a database with \meta{num-rows} rows and
\meta{num-columns} columns, where the content of the internal token
register used to store the header markup is obtained by expanding
\meta{header code}, and the content of the internal token register
used to store the database body is obtained by expanding \meta{body
code}. The \meta{key-index code} is the code required to reconstruct
the mapping from column key to column index.

The \meta{header code} should only consist of an ordered series of:
\cmddef{dtldbheaderreconstruct}
where \meta{column-idx} is the column index (starting from~1),
\meta{key} is the unique column key, \meta{type} is the data type numeric
identifier (0: string, 1: integer, 2: decimal, 3: currency), and
\meta{header}. Note that \meta{header code} is designed to
expand to the explicit \meta{header markup}, describe above for
DBTEX v2.0.

The \meta{index-key code} is a reverse mapping from column key to
column index, which consists of a series of:
\cmddef{dtldbreconstructkeyindex}
(This corresponds to defining the commands
\csmetametafmt{dtl@ci@}{db-name}{@}{key}{} to expand to
\meta{column-idx}, described above for DBTEX v2.0.)

Every column in \meta{header code} must have a corresponding key to
index mapping. For example:
\begin{compactcodebox}
\gls{DTLreconstructdatabase}
\margm{num-rows}\marg{4}\%
\marg{\comment{Header}
\gls{dtldbheaderreconstruct}\marg{1}\marg{Name}\marg{0}\marg{Name}\%
\gls{dtldbheaderreconstruct}\marg{2}\marg{Age}\marg{1}\marg{Age}\%
\gls{dtldbheaderreconstruct}\marg{3}\marg{Score}\marg{2}\marg{Score (\cmd{\%})}\%
\gls{dtldbheaderreconstruct}\marg{4}\marg{Award}\marg{2}\marg{Award (\cmd{protect} \gls{cs.dollar})}\%
}\comment{ End of Header}
\margm{body code}
\marg{\comment{Key to index}
\gls{dtldbreconstructkeyindex}\marg{Name}\marg{1}\%
\gls{dtldbreconstructkeyindex}\marg{Age}\marg{2}\%
\gls{dtldbreconstructkeyindex}\marg{Score}\marg{3}\%
\gls{dtldbreconstructkeyindex}\marg{Award}{4}\%
}\comment{End of key to index}
\end{compactcodebox}
The \meta{body code} is more complicated, but is designed to
expand to the explicit \meta{body markup}, describe above for
DBTEX v2.0.

The \meta{body code} consists of an ordered
set of row blocks, where each block is identified with:
\cmddef{dtldbrowreconstruct}
(This is designed to expand to the \meta{row-markup} sub-block,
described above.)
The \meta{row-idx} argument is the row index (starting from~1) and
\meta{row code} is the row content, which should consist of an
ordered set of column blocks:
\cmddef{dtldbcolreconstruct}
(This is designed to expand to the \meta{entry column markup}, described
above.)
The \meta{column-idx} argument is the column index and \meta{content} is
the content for the given column in the given row. This may be the
actual content which will be encapsulated with:
\cmddef{dtldbvaluereconstruct}
or it could be a \idx+{datumitem}, in which case
\meta{content} will be in the form:
\cmddef{dtldbdatumreconstruct}
where \meta{string} is the original value (such as
\code{\gls{cs.dollar}12,500}), \meta{numeric} is the
\idx{plainnumber} numeric value (for example, \code{12500}) or
empty if the value is a string, \meta{currency} is the currency
symbol (for example, \code{\gls{cs.dollar}}), and \meta{type} is the
numeric data type identifier.

\subsection{I/O Settings}
\label{sec:iosettings}

Data can be loaded from an external file using \gls{DTLread},
described in \sectionref{sec:loaddb}, and saved to an external file
using \gls{DTLwrite}, described in \sectionref{sec:savedb}. Both
commands have an optional argument with the settings that govern the
format. Some of the settings are only applicable to a particular
format or to either reading or writing a file.

When passed to the optional argument of \gls{DTLread} or
\gls{DTLwrite}, these settings only have a local effect within
the read or write action. You can set up defaults with
the \opt{io} option in \gls{DTLsetup}. For example:
\begin{codebox}
\gls{DTLsetup}\marg{
  \opt{io}=\marg{
    \ioopt{separator} = \marg{;},
    \ioopt{delimiter} = \marg{'},
    \ioopt{format} = \marg{csv}
  }
}
\end{codebox}

If a column key can't be obtained (either from the file or from the
\ioopt{keys} option) when reading a \iooptvalref{format}{csv} or
\iooptvalref{format}{tsv} file, then a default key will be used with
the column index prefixed with:
\cmddef{dtldefaultkey}
So the default key for a column with index \meta{n} is obtained by
expanding \code{\gls{dtldefaultkey} \meta{n}} (for example,
the default key for column 4 will be \qt{Column4}).

% OPTION: add-delimiter

\optiondef{io.add-delimiter}
This option is only applicable with \gls{DTLwrite}, and
determines whether or not to use the delimiter when writing to a
\iooptvalref{format}{csv} or \iooptvalref{format}{tsv} file. 
This option has no effect on other formats.
The value may be one of the following.

\optionvaldef{io.add-delimiter}{always}
Always add the delimiter.

\optionvaldef{io.add-delimiter}{never}
Never add the delimiter.

\optionvaldef{io.add-delimiter}{detect}
Only add the delimiters if the separator is found in the value.

% OPTION: auto-keys

\optiondef{io.auto-keys}
The column keys will be the default key (obtained by expanding
\code{\gls{dtldefaultkey} \meta{n}}), regardless of whether or not
the file has a header row. This option overrides any previous
\ioopt{keys} setting and is only applicable when reading a
\iooptvalref{format}{csv} or \iooptvalref{format}{tsv} file.

% OPTION: autokeys

\optiondef{io.autokeys}
Equivalent to \ioopt{auto-keys}.

% OPTION: convert-numbers

\optiondef{io.convert-numbers}
Any columns that have had their data type identified as an integer,
decimal or currency, will have the value read from the
\idx{CSV} or \idx{TSV} file converted to the current localisation
settings using \gls{DTLdecimaltolocale} or
\gls{DTLdecimaltocurrency}, respectively.
Any other type of column will be parsed as usual (except in the case of
\iooptval{csv-content}{no-parse}).
See \exampleref{ex:loadxynoparsedecimalcurrconvert}.

Only has an effect when \gls{DTLread} parses
\ioopteqvalref{format}{csv} or \ioopteqvalref{format}{tsv} files.
This option is ignored by the other formats. If all columns are
\idxpl{plainnumber} you may want to consider using this option with
\iooptval{csv-content}{no-parse} and \optval{store-datum}{true}.

\begin{information}
This setting should be used with \ioopt{data-types}, and the values
in the indicated columns should be \idxpl{plainnumber}.
The column data type will be updated if a value in that column is found to be
incompatible with the identified type (except in the case
of \iooptval{csv-content}{no-parse}).
\end{information}

% OPTION: csv-blank

\optiondef{io.csv-blank}
This option is only applicable with \gls{DTLread} and determines how
to act if an empty line is encountered in a \iooptvalref{format}{csv} and
\iooptvalref{format}{tsv} file.
This option has no effect with other formats.

Note that a blank line means an empty line in the file unless it
occurs within grouped content with \ioopteqvalref{csv-content}{tex}.

\optionvaldef{io.csv-blank}{ignore}
Blank lines are ignored.

\optionvaldef{io.csv-blank}{empty-row}
Blank lines will be treated as an empty row to be added to the
database.

\optionvaldef{io.csv-blank}{end}
A blank line indicates that parsing should stop. Any following
content is ignored.

% OPTION: csv-content
\optiondef{io.csv-content}
This option is only applicable with \gls{DTLread} and determines how
the content of \iooptvalref{format}{csv} and
\iooptvalref{format}{tsv} files should be interpreted.
This option has no effect with other formats.

If you don't intend to use any numerical operations on the data or
if the data consists only of \idxpl{plainnumber} or text that either
has no \LaTeX\ special characters or has valid \LaTeX\ syntax, then the
fastest method of loading a \idx{CSV} file is with
\iooptval{csv-content}{no-parse}. The other options will parse the
elements in each row to determine the data type.

For example, if the first two lines of the file consist of:
\begin{compactcodebox}
Name ,Score (\gls{cs.percent}),\marg{Award 
(\gls{cs.dollar})}
\end{compactcodebox}
Then with \iooptval{csv-content}{tex} this will be read in as a
single header row. The grouping allows an element value to be split
across multiple lines. The first column will have the header
\code{Name}, the second column will have the header
\code{Score (\gls{cs.percent})} and the third column will have the
header \code{Award (\gls{cs.dollar})}.

Whereas with \iooptval{csv-content}{literal} this will be read in
as a header row on line~1 and a row containing a single column on
line~2.  The header for the first column is again \code{Name}, but
the header for the second column will be \code{Score
(\gls{textbackslash} \gls{cs.percent})}, and the header for the
third column will be \code{\gls{cs.openbrace}Award}. The entry of
the first column in the first row will be \code{(\gls{textbackslash}
\gls{cs.dollar})\gls{cs.closebrace}}.

Note that in both case, the column keys would need to be set with
\ioopt{auto-keys} or \ioopt{keys} as the headers for the second
and third columns are inappropriate for keys.

Suppose now that the next line is:
\begin{compactcodebox}
"Chlo\cmd{"}e",89,5.50
\end{compactcodebox}
In this case, the result depends on the \ioopt{csv-escape-chars}
setting, which determines whether or not to strip the backslash in
front of the double-quote. With
\ioopteqvalref{csv-escape-chars}{none} the backslash isn't removed,
so the value with \ioopteqvalref{csv-content}{literal} will end up
as \code{Chlo\gls{textbackslash} "e} (Chlo\textbackslash "e). Whereas with
\ioopteqvalref{csv-content}{tex} the value will end up as
\code{Chlo\cmd{"}e} (Chlo\"e). With the other
\ioopt{csv-escape-chars} settings, the backslash will be removed in
both cases, and the value will be \code{Chlo"e}.
Since the category code for the delimiter is automatically set to 12
(other) at the start of \gls{DTLread}, that's the category code it
will have in the value.

\optionvaldef{io.csv-content}{tex}
The content includes \LaTeX\ markup. These means that grouping can
also be used to delimit values. The file is read line by line, but
any line break occurring within a group will ensure that subsequent
lines are appended until the grouping is balanced. Once the line has
been read, it will then be split on the \ioopt{separator} and the
\ioopt{delimiter} pairs will be removed.  Any escape backslashes
(\idx{esc}) will be stripped according to \ioopt{csv-escape-chars}.

\optionvaldef{io.csv-content}{no-parse}
This is similar to \iooptval{csv-content}{tex} but the items are not
parsed to determine their data type. If \ioopt{data-types} has not
been set then each item will be assumed a string (even if it's empty).
If \ioopt{data-types} is set, then if the current column type
is numerical then the item is expected to be a \idx{plainnumber}
(even if the data type is currency). If the current column number is
greater than the number of items in \ioopt{data-types} then the
final data type listed will be assumed for all remaining columns.
See \exampleref{ex:loadxynoparsedecimal}.

For example, if you have a \idx{CSV} file with six columns of
\idxpl{plainnumber} then the file can be read with:
\begin{codebox}
\gls{DTLsetup}\marg{store-datum}
\gls{DTLread}\oarg{
  \iooptval{format}{csv},
  \iooptval{csv-content}{no-parse},
  \iooptval{data-types}{decimal},
 }\marg{data.csv}
\end{codebox}
Note that this won't check that the values are actually numerical
(unless you have \ioopt{convert-numbers} on).
If they're not and you try performing a numerical operation with
them, you will get an error.

If you do intend using the values in a numerical operation that
expects \idxpl{formattednumber} (including plotting) then switch on
the \opt{store-datum} setting before loading the data, otherwise the
values will be parsed during the numerical operation according to
the current localisation settings.

If you specify a column as currency, each item in that column must still be a
\idx{plainnumber} without a currency symbol. In this case, the
string part of the element will be set to the given item
encapsulated with \gls{DTLcurrency} unless you also have the
\ioopt{convert-numbers} setting on, in which case
\gls{DTLdecimaltocurrency} will be used instead.

If \ioopt{convert-numbers} is on, the \idxpl{plainnumber} will be
converted according to the data type for the current column.

\optionvaldef{io.csv-content}{literal}
The content should be interpreted literally. Each line in the file
is read in as a detokenized string, which is then split according to
the \ioopt{separator} and \ioopt{delimiter}. Each element is then
processed according to the following steps:
\begin{enumerate}
\item strip any backslashes according to \ioopt{csv-escape-chars};

\item perform a \qt{replace all cases} regular expression which
substitutes the sequences \gls{n}, \gls{r} and \gls{f} with a
space character, the sequence \gls{t} with a \idx{tabchar} and
the \TeX\ special characters with \LaTeX\ commands (see \tableref{tab:rawmappings});

\item rescan the value to ensure all tokens have their correct
category code according to the current setting;

\item apply user mappings.
\end{enumerate}
The regular expression in the second step uses
\gls{regexreplacecaseall:nN} with the cases provided in the token
list variable:
\cmddef{ldatatoolstrcsvregexcasestl}
The default substitutions are listed in \tableref{tab:rawmappings}.
If you want to redefine this token list, remember that the input
string will only contain \qt{other} and space tokens when the
substitution is performed.

\begin{table}[htbp]
\caption{Mappings Used with \iooptval{csv-content}{literal} Before
Re-Scanning}
\label{tab:rawmappings}
\centering
\begin{tabular}{cl}
\bfseries Original & \bfseries Substituted\\
\idx{hash} & \gls{cs.hash}\\
\idx{dollar} & \gls{cs.dollar}\\
\idx{percent} & \gls{cs.percent}\\
\idx{amp} & \gls{cs.amp}\\
\idx{bksl} & \gls{textbackslash}\\
\idx{circum} & \gls{textasciicircum}\\
\idx{underscore} & \gls{cs.underscore}\\
\idx{openbrace} & \gls{cs.openbrace}\\
\idx{closebrace} & \gls{cs.closebrace}\\
\idx{tilde} & \gls{textasciitilde}\\
\gls{f} & \emph{space}\\
\gls{n} & \emph{space}\\
\gls{r} & \emph{space}\\
\gls{t} & \emph{\idx{tabchar}}\\
\end{tabular}
\end{table}

The final user mappings are applied after the value has been
rescanned. There are none by default, but mappings can be added
with:
\cmddef{DTLrawmap}
This indicates that all instances of \meta{original} should be
replaced by \meta{replacement}. Note that this appends the mapping.
It won't override an existing mapping for \meta{original}. This
command was originally provided for use with \gls{DTLloadrawdb} and
is retained for backward-compatibility.

% OPTION: csv-escape-chars

\optiondef{io.csv-escape-chars}
Determines if a literal instance of the delimiter should simply be
doubled (the standard for \idx{CSV} files) or whether or not the
backslash (\idx{esc}) and \ioopt{delimiter} characters that occur
within a value in a \idx{CSV} or \idx{TSV} file should be escaped.
(That is, the character should have a backslash inserted in front of
it.)

This setting is only applicable with \ioopteqvalref{format}{csv}
and \ioopteqvalref{format}{tsv}. Note that if a value contains the
\ioopt{separator} character, it should be delimited.

\optionvaldef{io.csv-escape-chars}{double-delim}
The delimiter should be doubled.

\optionvaldef{io.csv-escape-chars}{delim}
Only the delimiter should be escaped. \gls{DTLwrite} will insert a
leading backslash and \gls{DTLread} will strip a leading backslash
from the \ioopt{delimiter} character but not from a backslash
character.

\optionvaldef{io.csv-escape-chars}{delim+bksl}
Both the \ioopt{delimiter} and backslash characters should be escaped.
\gls{DTLwrite} will insert a leading backslash and \gls{DTLread}
will strip a leading backslash from the \ioopt{delimiter} and
backslash characters.

\optionvaldef{io.csv-escape-chars}{none}
No escaping. \gls{DTLwrite} won't insert a leading backslash or
double the delimiter and \gls{DTLread} won't strip a leading backslash
or convert a double delimiter to a single instance.

% OPTION: csv-skip-lines

\optiondef{io.csv-skip-lines}
The value may be the keyword \code{false} (which is equivalent to
\iooptval{csv-skip-lines}{0}) or a non-negative integer. If the value
is greater than zero, then \gls{DTLread} will skip the first
\meta{n} lines in a \ioopteqvalref{format}{csv} or
\ioopteqvalref{format}{tsv} file where \meta{n} is the supplied value.
This option has no effect on other formats.

Note that with \ioopteqvalref{csv-content}{tex}, a \qt{line} may
actually cover multiple lines if a line break occurs within a group.
For example, if the file starts with:
\begin{compactcodebox}
Name ,Score (\gls{cs.percent}),\marg{Award 
(\gls{cs.dollar})}
"Chlo\cmd{"}e",89,5.50
\end{compactcodebox}
Then with \ioopteqvalref{csv-content}{literal} and
\iooptval{csv-skip-lines}{1} then the first line to be parsed
will be the line:
\begin{compactcodebox}
(\gls{cs.dollar})\}
\end{compactcodebox}
whereas with \ioopteqvalref{csv-content}{tex} and
\iooptval{csv-skip-lines}{1}, the first line to be parsed will
be the line:
\begin{compactcodebox}
"Chlo\cmd{"}e",89,5.50
\end{compactcodebox}

% OPTION: data-types

\optiondef{io.data-types}
The value should be a comma-separated list of keywords that identify 
the corresponding column data type. The keywords may be one of:
\optfmt{unknown}, \optfmt{string}, \optfmt{integer},
\optfmt{decimal}, \optfmt{currency}, \optfmt{datetime},
\optfmt{date}, or \optfmt{time}.
Only has an effect when \gls{DTLread} parses
\ioopteqvalref{format}{csv} or \ioopteqvalref{format}{tsv} files.
This option is ignored by the other formats.

\begin{information}
The column data type will be updated if a value in that column is found to be
incompatible with the identified type (except in the case of
\iooptval{csv-content}{no-parse}).
\end{information}

If there are more columns than are listed in \ioopt{data-types} then
\iooptval{csv-content}{no-parse} will assume all remaining columns
have the same type as the last listed (or string if the list is
empty). With the other \ioopt{csv-content} settings, any remaining
columns will updated as usual, according to the data type identified
from parsing the items in the column.
See \exampleref{ex:loadxynoparsedecimal}.

% OPTION: delimiter

\optiondef{io.delimiter}
Sets the delimiter for \ioopteqvalref{format}{csv} and 
\ioopteqvalref{format}{tsv} files to \meta{char},
which must be a single token.
This setting is ignored by \ioopteqvalref{format}{dbtex} and 
\ioopteqvalref{format}{dtltex} files.

The default delimiter may also be set via the \opt{delimiter}
package option or with:
\cmddef{DTLsetdelimiter}
If you don't want a delimiter when saving a file, use the
\ioopteqvalref{add-delimiter}{never} option.

% OPTION: expand

\optiondef{io.expand}
This option governs element expansion when the data is written to
the file for all formats. This option also changes
\opt{new-value-expand}, which affects element expansion when data
is read in from a file, except for the \ext+{dbtex} formats where no
expansion is applied to the values. If the value is omitted,
\ioopteqvalref{expand}{protected} is assumed.

The default setting for \gls{DTLwrite} is
\ioopteqvalref{expand}{none}. The default for \gls{DTLread} is the
current \opt{new-value-expand} setting. If the value is omitted,
\ioopteqvalref{expand}{protected} is assumed.
The value may be one of the following.

\optionvaldef{io.expand}{none}
No expansion. Automatically implements
\optval{new-value-expand}{false}.

\optionvaldef{io.expand}{protected}
Protected expansion, except for the \ext+{dbtex} formats where this
option is equivalent to \ioopteqvalref{expand}{none}. 
Automatically implements \optval{new-value-expand}{true}.

\optionvaldef{io.expand}{full}
Full expansion. Make sure that the database doesn't contain fragile
commands with this setting.
Automatically implements \optval{new-value-expand}{true}.

Bear in mind that if you add content to databases that contain
characters that should have non-standard category codes, this
information may be lost unless it's hidden inside a robust command
that ensures the correct category codes are used. Normally with
\iooptval{expand}{none}, \gls{DTLwrite} will prevent expansion of an
element while writing to a file. However, with the DBTEX formats, if
a database element starts with the special \idx+{datumitem} markup or
if the element starts with the command
\gls{dtlspecialvalue} then the \idx{datumitem} will be
stripped in DBTEX v2.0 and \gls{dtlspecialvalue} will be allowed to
expand.  (The \sty{datagidx} package uses this to clear the
\qt{Used} and \qt{Location} columns when writing the index\slash
glossary database to a file for the next run.)


% OPTION: format

\optiondef{io.format}
Indicates the file format for both \gls{DTLread} and \gls{DTLwrite}.
The default setting is \ioopteqvalref{format}{csv} (even if you
have separately set the separator to the \idx{tabchar}).
The format may be one of the following values:

\optionvaldef{io.format}{csv}
The \idx{CSV} file format with the separator given by the
\ioopt{separator} option and the delimiter given by the
\ioopt{delimiter} option. The default file extension is set to
\ext+{csv}. Note that the designated separator and delimiter will
have their category code set to \qt{other}.

\optionvaldef{io.format}{tsv}
The \idx{TSV} file format with a \idx{tabchar} separator and 
the delimiter given by the \ioopt{delimiter} option. The default
file extension is set to \ext+{csv}. 

If the \ioopt{separator} option is specified \emph{after} this option, then that
separator will be used instead, but the file extension will still
default to \ext+{tsv}.

\begin{important}
The following formats are all files that contain \LaTeX\ code and
all use the same underlying function with \gls{DTLread}.  The file
is input as per a normal \LaTeX\ file with
\optval{global}{true} and scoping to limit the effect of the options
and some local redefinitions.  In terms of \gls{DTLread}, the
difference between the specific \ioopt{format} values simply
determines the default file extension.
\end{important}

\optionvaldef{io.format}{dtltex-2}
This indicates DTLTEX v2.0 format (see \sectionref{sec:dtltexfiles}).
The default file extension is set to \ext+{dtltex}. 

When used with \gls{DTLwrite}, the data will be written to the
file with document level user commands that include the database
name, such as \gls{DTLnewdb}.

\optionvaldef{io.format}{dtltex-3}
This indicates DTLTEX v3.0 format (see \sectionref{sec:dtltexfiles}).
The default file extension is set to \ext+{dtltex}.

When used with \gls{DTLwrite}, the data will be written to the
file with v3.0 document level user commands described in \sectionref{sec:dtltexfiles}. 

\optionvaldef{io.format}{dtltex}
The latest DTLTEX format. This is currently equivalent to
\iooptval{format}{dtltex-3}.

\optionvaldef{io.format}{dbtex-2}
This indicates DBTEX v2.0 format (see \sectionref{sec:dbtexfiles}).
The default file extension is set to \ext+{dbtex}.

When used with \gls{DTLwrite}, the data will be written to the
file in DBTEX v2.0 format, which uses low-level internal commands to
define and set the registers used to store the data. Note that this
will cause any instance of \idx{@} in the database to have a letter
category code (see \exampleref{ex:loadcustomers}) and leading spaces
at the start of database elements will be lost. The DBTEX v3.0
format is better. 

\optionvaldef{io.format}{dbtex-3}
This indicates DBTEX v3.0 format (see \sectionref{sec:dbtexfiles}).
The default file extension is set to \ext+{dbtex}.

When used with \gls{DTLwrite}, the data will be written to the
file in DBTEX v3.0 format, which uses higher level internal commands. 

\optionvaldef{io.format}{dbtex}
The latest DBTEX format. This is currently equivalent to
\iooptval{format}{dbtex-3}.

% OPTION: headers

\optiondef{io.headers}
Identifies the column headers to be used when \gls{DTLread} parses
\ioopteqvalref{format}{csv} or \ioopteqvalref{format}{tsv} files.
This option is ignored by the other formats.

\begin{information}
Leading and trailing spaces and empty elements in
\meta{list} will be stripped, regardless of the \listsopt{trim}
and \listsopt{skip-empty} settings. If you specifically want to
retain these, you will need to use braces around the item.
\end{information}

If \ioopt{headers} is set to empty (the default), or there is no
item in the \meta{list} that corresponds to a given column, then
that column header will be the same as the column key.

For example:
\begin{codebox}
\gls{DTLread}\marg{\iooptvalm{headers}{ Name ,,Email,\marg{},Notes,}}
\margm{csv-file}
\end{codebox}
This is equivalent to:
\begin{codebox}
\gls{DTLread}\marg{\iooptvalm{headers}{Name,Email,\marg{},Notes}}
\margm{csv-file}
\end{codebox}
The first column will be given the header \qt{Name} and the second
column will be given the header \qt{Email}. The third column will
have an empty header, and the fourth column will be given the header
\qt{Notes}. If a fifth column is found in the file, the header for
that column will be the same as the key for that column.

% OPTION: keys

\optiondef{io.keys}
Identifies the column keys to be used when \gls{DTLread} parses
\ioopteqvalref{format}{csv} or \ioopteqvalref{format}{tsv} files.
This option is ignored by the other formats.

\begin{information}
Leading and trailing spaces and empty elements in
\meta{list} will be stripped, regardless of the \listsopt{trim}
and \listsopt{skip-empty} settings. If you specifically want to
retain these, you will need to use braces around the item.
\end{information}

If \ioopt{keys} is set to empty and \iooptval{auto-keys}{false}
(the default), then the keys will be the column headers supplied in
the file.  If there are no column headers (\iooptval{no-header}{true})
or the header is empty for a given column, then the corresponding
key in \meta{list} will be used. If there is no corresponding key in
\meta{list}, or if the corresponding key is empty, then the default
key is used.

\begin{information}
If \ioopt{keys} is used with a non-empty list (after stripping
extraneous spaces and commas) then it will automatically implement
\iooptval{auto-keys}{false}. If \iooptval{auto-keys}{true} is
subsequently used, it will override the \ioopt{keys} setting.
\end{information}

For example:
\begin{codebox}
\gls{DTLread}\marg{\iooptvalm{keys}{ Name ,,Email,\marg{},Notes,}}
\margm{csv-file}
\end{codebox}
This is equivalent to:
\begin{codebox}
\gls{DTLread}\marg{\iooptvalm{keys}{Name,Email,\marg{},Notes}}
\margm{csv-file}
\end{codebox}
This will set the key to \qt{Name} for the first column and
\qt{Email} for the second. The third column will either pick up the
key from the header row in the file or, if that is missing, the key
will be \code{\gls{dtldefaultkey} \meta{n}} (\qt{Column3}). The
fourth column will have the key \qt{Notes}. If additional columns
are found in the file, they will act as for an empty element in the
list. So a fifth column will either pick up the
key from the header row in the file or, if that is missing, the key
will be \code{\gls{dtldefaultkey} \meta{n}} (\qt{Column5}).

% OPTION: load-action

\optiondef{io.load-action}
Determines whether or not \gls{DTLread} should create a new
database or append to an existing one. This append setting does not
support \ioopteqvalref{format}{dtltex-2} or any \ext+{dbtex} format.

\begin{important}
Remember that the database name depends on the \ioopt{name} setting and the
format.
\end{important}

\optionvaldef{io.load-action}{detect}
Detects the appropriate action: if a database with the given name
exists, it behaves as \ioopteqvalref{load-action}{append}, otherwise
it behaves as \ioopteqvalref{load-action}{create}.

\optionvaldef{io.load-action}{create}
A new database will be created. If a database already exists, an
error will occur.

\optionvaldef{io.load-action}{append}
A new database won't be created. If the database doesn't already
exist, an error will occur.  Appended data will match on the column
key not the index.  This may cause null values in the database if
there are extra or missing columns in the appended data.

\optionvaldef{io.load-action}{overwrite}
If the database with the given name already exists, it will be
cleared first instead of attempting to define it.

\optionvaldef{io.load-action}{old-style}
For backward-compatibility with old versions of \sty{datatool}, this
setting will test the conditional:
\cmddef{ifDTLnewdbonload}
If true, this behaves like \ioopteqvalref{load-action}{create}
otherwise it behaves like \ioopteqvalref{load-action}{append}.

% OPTION: name

\optiondef{io.name}
The database name. This option is supported by \gls{DTLwrite} for
all formats, and identifies the database to save. If
omitted, the general \opt{default-name} setting will be used. 

Note that the argument is expanded when the option is set.
For example:
\begin{codebox}
\cmd{newcommand}\marg{\cmd{mydatacmd}}\marg{mydata}
\gls{DTLsetup}\marg{\optvalm{io}{\iooptval{name}{\cmd{mydatacmd}}}}
\cmd{renewcommand}\marg{\cmd{mydatacmd}}\marg{otherdata}
\end{codebox}
In the above, the database name remains \qt{mydata} after
\csfmt{mydatacmd} is redefined.

With \gls{DTLread}, this option identifies the database name but
isn't supported by all formats.  This option is ignored by
\iooptvalref{format}{dtltex-2} and \iooptvalref{format}{dbtex-2}.
If omitted, the default behaviour depends on the format:
\iooptvalref{format}{csv} and \iooptvalref{format}{tsv} will fallback on
the \opt{default-name} setting, but \iooptvalref{format}{dbtex-3} and
\iooptvalref{format}{dtltex-3} will use the name provided in the file.

% OPTION: no-header

\optiondef{io.no-header}
A boolean option that determines if \gls{DTLwrite} should omit
header information in the file. This option has no effect with
\ioopteqvalref{format}{dtltex-2}, \ioopteqvalref{format}{dbtex-2}
and \ioopteqvalref{format}{dbtex-3}.

With \gls{DTLread}, this option only has an effect with the
\ioopteqvalref{format}{csv} and \ioopteqvalref{format}{tsv} formats.
If \iooptval{no-header}{true}, then there's no header row in the
file (taking into account any offset introduced with
\ioopt{csv-skip-lines}). The column keys will either be obtained
from the \ioopt{keys} setting or will be set to the default for the
given column index. The column headers will either be obtained from
the \ioopt{headers} setting or will be set to the key.

With \ext+{dtltex} files, this option will locally redefine the
underlying command used by \gls{DTLsetheader} to do nothing, unless
a corresponding value is found in the \ioopt{headers} option. This
means that the header will be the same as the column key unless the
\ioopt{headers} value supplies an alternative.

With \gls{DTLwrite}, this option will omit the header line for the
\ioopteqvalref{format}{csv} and \ioopteqvalref{format}{tsv} formats.
So the database content will start on the first line of the file.
With \ioopteqvalref{format}{dtltex-3}, this will omit the code that sets
the column headers (but the column keys will still be used).

% OPTION: noheader

\optiondef{io.noheader}
A synonym of \ioopt{no-header}.

% OPTION: only-reformat-columns

\optiondef{io.only-reformat-columns}
Similar to the \numericopt{auto-reformat} numeric option and
the \datetimeopt{auto-reformat} datetime option.
The value should be a comma-separated list of column index numbers.

This option identifies the indexes of the columns that should be automatically
reformatted (but only for data types identified by
\opt{auto-reformat-types}) when \gls{DTLread} parses
\ioopteqvalref{format}{csv} or \ioopteqvalref{format}{tsv} files.
This option is ignored by the other formats.

\begin{information}
The option simply locally switches on the corresponding
\numericopt{auto-reformat} numeric option and
the \datetimeopt{auto-reformat} datetime option
when parsing a column that's included in the 
\ioopt{only-reformat-columns} list.
If the list is empty, then no change will be made, so whatever
setting was in effect before the file was opened will be obeyed.
\end{information}

% OPTION: omitlines

\optiondef{io.omitlines}
Provided for backward compatibility, this option is like 
\ioopt{csv-skip-lines} but doesn't allow the keyword
\code{false} and doesn't trigger an error for negative values.

% OPTION: overwrite

\optiondef{io.overwrite}
A boolean option that governs whether or not an existing file should
be overwritten.  Only applicable with \gls{DTLwrite}.  The value may
be one of the following.

\optionvaldef{io.overwrite}{error}
Trigger an error and don't allow the file to be overwritten.

\optionvaldef{io.overwrite}{warn}
Trigger a warning and don't allow the file to be overwritten.

\optionvaldef{io.overwrite}{allow}
Allow the file to be overwritten.

% OPTION: separator

\optiondef{io.separator}
Sets the separator for \idx{CSV} files to \meta{char},
which must be a single token.

The default separator may also be set with:
\cmddef{DTLsetseparator}
The \idx{tabchar} in \idx{TSV} files is awkward as the \idx{tabchar}
is usually treated the same as a space by \LaTeX. This means that in
order to read a \idx{tabchar} correctly, the category code first
needs to be changed. The following command:
\cmddef{DTLsettabseparator}
changes the category code of the \idx{tabchar} to 12 (\qt{other})
and then sets the \idx{tabchar} as the separator. Note that this
will affect any \idxpl{tabchar} in the document code unless the
change is localised. The simplest method is to use the 
setting \ioopteqvalref{format}{tsv}.

% OPTION: trim

\optiondef{io.trim}
Equivalent to
\code{\gls{DTLsetup}\marg{\optval{new-value-trim}{\meta{boolean}}}}.
Only applicable with \gls{DTLread} but not for
the \ext+{dbtex} formats.

\subsection{Loading a Database from an External File}
\label{sec:loaddb}

\cmddef{DTLread}
Loads the data from the file given by \meta{filename} and globally
defines a database containing that data.
If the file extension is omitted, the default extension associated
with the format will be used.  The options are as for those listed
in \sectionref{sec:iosettings} that are identified as working with
\gls{DTLread}.

The \idx{CSV} and \idx{TSV} files don't have the database name
included in the file, so the \ioopt{name} option may be used to
specify the database name to override the \opt{default-name}
setting. The \ioopt{name} option may also be used to override the
name supplied in DBTEX~3.0 and DTLTEX~3.0 files, but the name is
hardcoded in DBTEX~2.0 and DTLTEX~2.0 files, so the \ioopt{name}
option will have no effect (other than to generate a warning).

After the file has been read, the command
\inlineglsdef{dtllastloadeddb} is defined to expand to the database
name.

For example, the \qt{xydata} database described in
\sectionref{sec:xydatacsv} is in a \idx{CSV}
file with two columns of numbers with decimal points. Since there
are no special characters to worry about, if the current
\idx{decimalchar} is a decimal point then either
\iooptval{csv-content}{literal} or \iooptval{csv-content}{tex} may be
used, but \iooptval{csv-content}{tex} is faster, since it doesn't
need to convert any characters. However, since these are all
\idxpl{plainnumber}, it's even faster to load with
\iooptval{csv-content}{no-parse}.

\mExampleref{ex:loadxynoparse} loads the data with
\iooptval{csv-content}{no-parse} but doesn't identify the data as
decimal values:
\begin{codebox}
\gls{DTLread}\oarg{
 \iooptval{name}{xydata},
 \iooptval{format}{csv},
 \iooptval{csv-content}{no-parse}
}\marg{xydata.csv}
\end{codebox}
This will assume that all content is just text, which becomes
evident when the data is sorted and displayed:
\begin{codebox}
\gls{DTLsortdata}\marg{xydata}\marg{Y}
\gls{DTLdisplaydb}\marg{xydata}
\end{codebox}
Because the columns are identified as having the string data type,
the sorting uses a string comparison and \gls{DTLdisplaydb} uses
left alignment.

\begin{resultbox}
\createexample*
 [label={ex:loadxynoparse},
  title={Loading Data With No Parsing},
  tag={xydata}, 
  description={An example document loads X/Y data without parsing}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\comment{This will assume that all data is just text:}%
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse}
}\marg{xydata.csv}
}
{\comment{since the columns are identified as strings, this just
does a string sort:}%
\gls{DTLsortdata}\marg{xydata}\marg{Y}\nl
\gls{DTLdisplaydb}\marg{xydata}
}
\end{resultbox}

\mExampleref{ex:loadxynoparsedecimal} identifies the data as
decimal values and also sets \opt{store-datum} beforehand, which
means that values won't have to be parsed later:
\begin{codebox}
\gls{DTLsetup}\marg{store-datum}
\gls{DTLread}\oarg{
 \iooptval{name}{xydata},
 \iooptval{format}{csv},
 \iooptval{csv-content}{no-parse},
 \iooptval{data-types}{decimal}
}\marg{xydata.csv}
\end{codebox}
Again the data is sorted (on column~Y) and displayed as
before, but now the sorting is numerical and the columns are right
aligned.  Note that with \iooptval{csv-content}{no-parse}, the
\ioopt{data-types} setting doesn't need a type for each column.  The
type for just the first column is set and following columns are
assumed to have the same type. This is different from the behaviour
of \ioopt{data-types} when parsing is on.

\begin{resultbox}
\createexample*
 [label={ex:loadxynoparsedecimal},
  title={Loading Data With No Parsing and Columns Identified as
Decimal},
  tag={xydata}, 
  description={An example document loads X/Y data without parsing
but columns are identified as decimal}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{store-datum}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{xydata.csv}
}
{%
\gls{DTLsortdata}\marg{xydata}\marg{Y}\nl
\gls{DTLdisplaydb}\marg{xydata}
}
\end{resultbox}

\mExampleref{ex:loadxynoparsedecimalcurr} identifies the data in the
first column as decimal and the data in the second column as
currency. Note that with \iooptval{csv-content}{no-parse}, columns
identified as currency must also be \idxpl{plainnumber} without a
currency symbol (as is the case here):
\begin{codebox}
\gls{DTLsetup}\marg{store-datum}
\gls{DTLread}\oarg{
 \iooptval{name}{xydata},
 \iooptval{format}{csv},
 \iooptval{csv-content}{no-parse},
 \iooptvalm{data-types}{decimal,currency}
}\marg{xydata.csv}
\end{codebox}
Again the data is sorted (on column~Y) and displayed as
before. Note that the second column has the original value
encapsulated with \gls{DTLcurrency}. Since \opt{store-datum} is on,
the actual value provided in the \idx{CSV} file is embedded in the
data for easy access.

\begin{resultbox}
\createexample*
 [label={ex:loadxynoparsedecimalcurr},
  title={Loading Data With No Parsing and Columns Identified as
Decimal and Currency},
  tag={xydata}, 
  description={An example document loads X/Y data without parsing
but the two columns are identified as decimal and currency}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{store-datum}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptvalm{data-types}{decimal,currency}\nl
}\marg{xydata.csv}
}
{%
\gls{DTLsortdata}\marg{xydata}\marg{Y}\nl
\gls{DTLdisplaydb}\marg{xydata}
}
\end{resultbox}

\mExampleref{ex:loadxynoparsedecimalcurrconvert} has the
localisation settings on. (This will require \sty{datatool-regions}
and \sty{datatool-english} to also be installed.)
\begin{codebox}
\cmd{usepackage}\oarg{\optval{locales}{en-BE}}\marg{datatool}
\end{codebox}
This means that the \idx{decimalchar} is now a comma not a decimal
point, but this isn't a problem because
\iooptval{csv-content}{no-parse} is used. However, the
\ioopt{convert-numbers} option will reformat the values according to
the current localisation setting.
(Note that the \numericopt{auto-reformat} option isn't applicable
with \iooptval{csv-content}{no-parse} as no parsing takes place.)
\begin{codebox}
\gls{DTLsetup}\marg{store-datum}
\gls{DTLread}\oarg{
 \iooptval{name}{xydata},
 \iooptval{format}{csv},
 \iooptval{csv-content}{no-parse},
 \iooptvalm{data-types}{decimal,currency},
 \ioopt{convert-numbers}
}\marg{xydata.csv}
\end{codebox}
Again the data is sorted (on column~Y) and displayed as before.

\begin{resultbox}
\createexample*
 [label={ex:loadxynoparsedecimalcurrconvert},
  title={Loading Data With No Parsing and Columns Identified as
Decimal and Currency with Reformatting},
  tag={xydata}, 
  description={An example document loads X/Y data without parsing
but the two columns are identified as decimal and currency and
reformatted according to the localisation settings}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\comment{requires datatool-english and datatool-regions to also be
installed:}%
\cmd{usepackage}[locales=\marg{en-BE}]\marg{datatool}\nl
\gls{DTLsetup}\marg{store-datum}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptvalm{data-types}{decimal,currency},\nlsp
 \ioopt{convert-numbers}\nl
}\marg{xydata.csv}
}
{%
\gls{DTLsortdata}\marg{xydata}\marg{Y}\nl
\gls{DTLdisplaydb}\marg{xydata}
}
\end{resultbox}

\cmddef{DTLloaddbtex}
Inputs the file identified by \meta{filename} and defines the
control sequence \meta{cs} to expand to the database name.
In \sty{datatool} v3.0, this command has been rewritten to simply do:
\begin{compactcodebox}
\gls{DTLread}\oarg{\iooptvalm{name}{},\ioopteqvalref{format}{dbtex}}\margm{filename}
\cmd{let}\meta{cs}\gls{dtllastloadeddb}
\end{compactcodebox}

\cmddef{DTLloaddb}
This deprecated command now simply does:
\begin{compactcodebox}
\gls{DTLread}\oarg{\iooptvalm{name}{\meta{db-name}},\ioopteqvalref{format}{csv},\ioopteqvalref{csv-content}{tex},\meta{options}}\margm{filename}
\end{compactcodebox}

\cmddef{DTLloadrawdb}
This deprecated command now simply does:
\begin{compactcodebox}
\gls{DTLread}\oarg{\iooptvalm{name}{\meta{db-name}},\ioopteqvalref{format}{csv},\ioopteqvalref{csv-content}{literal},\meta{options}}\margm{filename}
\end{compactcodebox}

\subsection{Saving a Database to an External File}
\label{sec:savedb}

\cmddef{DTLwrite}
Saves the data from a database to the file given by \meta{filename}.
If the file extension is omitted, the default extension associated
with the format will be used. The options are as for those listed
in \sectionref{sec:iosettings} that are identified as working with
\gls{DTLread}.  The \ioopt{name} option identifies
the database. If that setting isn't provided, the \opt{default-name}
is assumed.

\cmddef{DTLsavedb}
This deprecated command now simply does:
\begin{compactcodebox}
\gls{DTLwrite}\oarg{\iooptvalm{name}{\meta{db-name}},\ioopteqvalref{overwrite}{warn},\ioopteqvalref{format}{csv},\ioopteqvalref{expand}{none},\ioopteqvalref{add-delimiter}{detect}}\margm{filename}
\end{compactcodebox}

\cmddef{DTLsaverawdb}
This deprecated command now simply does:
\begin{compactcodebox}
\gls{DTLwrite}\oarg{\iooptvalm{name}{\meta{db-name}},\ioopteqvalref{overwrite}{warn},\ioopteqvalref{format}{dbtex-2},\ioopteqvalref{expand}{full}}\margm{filename}
\end{compactcodebox}

\cmddef{DTLprotectedsaverawdb}
This deprecated command now simply does:
\begin{compactcodebox}
\gls{DTLwrite}\oarg{\iooptvalm{name}{\meta{db-name}},\ioopteqvalref{overwrite}{warn},\ioopteqvalref{format}{dbtex-2},\ioopteqvalref{expand}{none}}\margm{filename}
\end{compactcodebox}

\cmddef{DTLsavetexdb}
This deprecated command now simply does:
\begin{compactcodebox}
\gls{DTLwrite}\oarg{\iooptvalm{name}{\meta{db-name}},\ioopteqvalref{overwrite}{warn},\ioopteqvalref{format}{dtltex-2},\ioopteqvalref{expand}{full}}\margm{filename}
\end{compactcodebox}

\subsection{I/O Examples}
\label{sec:ioexs}

\examplemarginref{ex:loadcustomers}%
The \qt{customers} database (see \sectionref{sec:customers}) may be
loaded from the \idx{CSV} file \filefmt{customers.csv}:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{name}{customers},\iooptval{format}{csv}}\marg{customers.csv}
\end{codebox}
Alternatively, you can setup the default database name first, to
avoid having to repeatedly specify it. The file extension may also
be omitted, as can \iooptval{format}{csv} which is the default:
\begin{codebox}
\gls{DTLsetup}\marg{\optval{default-name}{customers}}
\gls{DTLread}\marg{customers}\comment{parse customers.csv}
\end{codebox}
\Exampleref{ex:loadcustomers} does this in the preamble. Setting the
default name makes it easier to use actions without having to
repeatedly write the database name.

The \action{select-row} action can be used to find the row
where the \optfmt{Email} column is set to the email address 
\code{fc@example.com}. If successful, 
the row index can be accessed with \gls{dtlrownum}.
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Email},\actionoptval{value}{fc@example.com}}
\marg{\action{select-row}}
Row: \cmd{number}\gls{dtlrownum}.
\end{codebox}
The database hasn't been modified, but it can be saved to the DBTEX
v3.0 format with:
\begin{codebox}
\gls{DTLwrite}\oarg{\iooptval{format}{dbtex-3},\iooptval{overwrite}{allow}}
 \marg{customers-v3}
\end{codebox}
(The \ioopt{overwrite} setting allows the test document to be
re-compiled afterwards without triggering an error.) This will
create a file called \filefmt{customers-v3.dbtex}.
(If you try this example, compare the DBTEX v3.0 file with and
without the \opt{store-datum} setting on.)

\Exampleref{ex:loadcustomers} then reads this new file back in with:
\begin{codebox}
\gls{DTLread}\oarg{\iooptval{format}{dbtex},\iooptval{name}{customers-v3}}
 \marg{customers-v3}
\end{codebox}
Note that although the DBTEX v3.0 file format includes the database
name (which will be \qt{customers} in this example), this can be
overridden with the \ioopt{name} option (but not with
\opt{default-name}, which can't be used to override the database
name if it's hard-coded in the file).

This has created a second identical database called
\qt{customers-v3}. The \action{select-row} action is again used to
look up the row with the email \code{fc@example.com} but note that
the database name now needs to be specified, since it's not the
default:
\begin{codebox}
\gls{DTLaction}\oarg{
 \actionoptval{name}{customers-v3},
 \actionoptval{key}{Email},\actionoptval{value}{fc@example.com}
}\marg{\action{select-row}}
Row: \cmd{number}\gls{dtlrownum}.
\end{codebox}

\Exampleref{ex:loadcustomers} then re-saves the original
\qt{customers} database in the DBTEX v2.0 format. (The default name
is still set to \qt{customers}.)
\begin{codebox}
\gls{DTLwrite}\oarg{\iooptval{format}{dbtex-2},\iooptval{overwrite}{allow}}
 \marg{customers-v2}
\end{codebox}
This creates a file called \filefmt{customers-v2.dbtex}.

The DBTEX v2.0 format has the database name hard-coded in the file and
doesn't allow it to be changed (even if the \ioopt{name} option is
used) nor does it support any load action other than
\iooptvalm{load-action}{create}. This means that the \qt{customers}
database must be deleted before this new file can be loaded:
\begin{codebox}
\gls{DTLaction}\marg{\action{delete}}
\gls{DTLread}\oarg{\iooptval{format}{dbtex}}\marg{customers-v2}
\end{codebox}
This should in theory still be identical to the original but it's
not because the DBTEX v2.0 file format requires the category code of \idx{@}
to be set to \qt{letter}. This means that the row look up will now
fail.
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptval{key}{Email},\actionoptval{value}{fc@example.com}}
\marg{\action{select-row}}
Row: \cmd{number}\gls{dtlrownum}.
\end{codebox}
This results in \qt{Row: 0} (without an error) indicating that no
match was found because the \idx{@} character in
\code{\actionoptval{value}{fc@example.com}} has its usual \qt{other}
category code, but the \code{fc@example.com} within the database has
the letter category code.

\begin{resultbox}
\createexample*
 [label={ex:loadcustomers},
  title={Loading and Saving Data (Be Careful of Category Codes)},
  tag={customers},link={sec:ioexs},
  description={An example document that loads data from a CSV file
and saves it to a different format}
]
{%
\exfile{customers.csv}{\customerscsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\optval{default-name}{customers}}\nl
\gls{DTLread}\marg{customers}
}
{%
\gls{DTLaction}\oarg{\actionoptval{key}{Email},\actionoptval{value}{fc@example.com}}\marg{\action{select-row}}\nl
Row: \cmd{number}\gls{dtlrownum}.\nl
\comment{Save as DBTEX v3.0:}%
\gls{DTLwrite}\oarg{\iooptval{format}{dbtex-3},\iooptval{overwrite}{allow}}\marg{customers-v3}
\codepar
\comment{Read this new file back:}%
\gls{DTLread}\oarg{\iooptval{format}{dbtex},\iooptval{name}{customers-v3}}\marg{customers-v3}\nl
\gls{DTLaction}\oarg{\nlsp
 \actionoptval{name}{customers-v3},\nlsp
 \actionoptval{key}{Email},\actionoptval{value}{fc@example.com}\nl
}\marg{\action{select-row}}\nl
Row: \cmd{number}\gls{dtlrownum}.\nl
\codepar
\comment{Save original as DBTEX v2.0:}%
\gls{DTLwrite}\oarg{\iooptval{format}{dbtex-2},\iooptval{overwrite}{allow}}\marg{customers-v2}
\codepar
\comment{`customers' database needs to be deleted as DBTEX v2.0 has
the name hard-coded:}%
\gls{DTLaction}\marg{\action{delete}}\nl
\comment{Read this new file back:}%
\gls{DTLread}\oarg{\iooptval{format}{dbtex}}\marg{customers-v2}\nl
\comment{Row will no longer be found as DBTEX v2.0 changes category
code of `@':}%
\gls{DTLaction}\oarg{\actionoptval{key}{Email},\actionoptval{value}{fc@example.com}}\marg{\action{select-row}}\nl
Row: \cmd{number}\gls{dtlrownum}.
}
\end{resultbox}

\examplemarginref{ex:loadtsv}%
As described in \sectionref{sec:growthtsv}, 
the \qt{growthdata} database can be obtained by parsing the example file
\filefmt{growth.tsv} as follows:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{growthdata}}
\gls{DTLread}\oarg{
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},
 \iooptval{csv-content}{no-parse},
 \iooptval{data-types}{decimal}
 }\marg{growth}
\end{codebox}
This is done in \exampleref{ex:loadtsv} and the data is then
displayed using the \action{display} action:
\begin{codebox}
\gls{DTLaction}\marg{\action{display}}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:loadtsv},
  title={Loading a TSV File},
  tag={growthtsv},
  description={An example document that loads data from a TSV file,
omitting the first line}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\cmd{usepackage}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{growthdata}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}
}%
{%
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\examplemarginref{ex:auto-reformat-csv}%
As described in \sectionref{sec:profitscsv}, 
the \qt{profits} database can be obtained by parsing the example file
\filefmt{profits.csv}. This has three columns, \qt{Year} (integers),
\qt{Profit} (currency) and \qt{Units} (integers).
For this example, I have the localisation support set to
\qt{en-US}, which matches the dollar symbol used in the
\qt{Profit} column.
\begin{codebox}
\cmd{usepackage}\oarg{\optvalm{locales}{en-US}}\marg{datatool}
\end{codebox}

Some of the later examples that use this database (see \sectionref{sec:databar}) need the
numerical values, so it's useful to switch on the \opt{store-datum}
setting to prevent repeated parsing, and I've also set the default
name:
\begin{codebox}
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}
\end{codebox}

The second column is a little untidy as it has a mix of
some negative currency with the negative sign before the currency
symbol and some with the sign after the symbol.
The third column is also missing the \idxpl{numbergroupchar}.

The \numericopt{auto-reformat} numeric option can be set before 
reading the \idx{CSV} file, but that will also reformat the first
column, which contains integers, but as they represent years they
shouldn't be converted to \idxpl{formattednumber}.

The \opt{auto-reformat-types} option could be used to omit integers
from being reformatted, but that would prevent the \optfmt{Unit} column
(which also contains integers) from being reformatted.
In this case, the \ioopt{only-reformat-columns} option can be used
to indicate that only columns~2 and~3 should be reformatted:

\begin{codebox}
\gls{DTLread}\oarg{
 \iooptval{format}{csv},
 \iooptval{csv-content}{tex},
 \iooptvalm{only-reformat-columns}{2,3},
}\marg{profits.csv}
\end{codebox}

With localisation support, this reformatting will use the formatting
commands that are sensitive to the region's currency settings.

\begin{information}
The \idx{numbergroupchar} and \idx{decimalchar} need to be
established before parsing. Reformatting will insert the relevant
characters, and they won't be affected by any later change.
\end{information}

This means that the currency style can be modified:
\begin{codebox}
\gls{DTLsetLocaleOptions}\marg{US}\marg{currency-symbol-sep=thin-space}
\end{codebox}

The data is then displayed using the \action{display} action:
\begin{codebox}
\gls{DTLaction}\marg{\action{display}}
\end{codebox}

\begin{resultbox}
\createexample*
 [label={ex:auto-reformat-csv},
  title={Automatically Reformatting Data While Loading a CSV file},
  tag={profits},
  description={An example document that loads data from a TSV file,
omitting the first line}
]
{%
\extabfile{profits.csv}{\profitscsv}\nl
\comment{This document additionally required datatool-english and
datatool-regions to be installed}
\cmd{usepackage}\oarg{\optvalm{locales}{en-US}}\marg{datatool}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{tex},\nlsp
 \iooptvalm{only-reformat-columns}{2,3},\nl
}\marg{profits.csv}\nl
\gls{DTLsetLocaleOptions}\marg{US}\marg{currency-symbol-sep=thin-space}
}%
{%
\gls{DTLaction}\marg{display}
}
\end{resultbox}

\section{Advanced Database Commands}
\label{sec:advanced}

\cmddef{dtlgetrowindex}
Gets the row index for the first row in the database identified
by \meta{db-name} where the entry in the column given by its index
\meta{col idx} exactly matches the given \meta{value}. If
successful, \meta{row-cs} will be defined to expand to the row
index, otherwise it will be set to the null value.

\cmddef{DTLgetrowindex}
The starred version simply does \gls{dtlgetrowindex}. The unstarred version triggers
an error if not found. (That is, if \meta{row-cs} is set to null.)

\cmddef{xdtlgetrowindex}
As \gls{dtlgetrowindex} but expands the value.

\begin{important}
If \optval{store-datum}{true} was set when the database was
constructed, remember that the elements in the database will be
\idxpl{datumitem} which means that the value must be in the same
format.
\end{important}

\cmddef{DTLgetvalue}
Gets the element in the row identified by \meta{row idx}
for the column identified by its index \meta{col idx} in the
database identified by \meta{db-name} and defines the control
sequence \meta{cs} to expand to the element's value.

\cmddef{DTLgetlocation}
Defines the control sequences \meta{row-cs} and
\meta{col-cs} to expand to the row and column indexes, respectively,
of the first entry in the database identified by \meta{db-name} that
matches the given \meta{value}.

\cmddef{DTLassignfirstmatch}
This internally uses \gls{dtlgetrowindex} to find the row where the
entry in the column identified by its label \meta{col key} exactly
matches the given value and (globally) performs the placeholder assignments in
\idx{assign-list}, which should be a comma-separated
\code{\meta{cs}\dequals\meta{key}} assignment list. 
Unlike \gls{DTLassign}, this command doesn't change
the \idx!{current-row}.

\begin{information}
For historical reasons, some of the older commands, such as
\gls{DTLassignfirstmatch}, perform global
assignments when setting the placeholder commands. This is because
the underlying code is shared by \gls{DTLforeach}, which was
designed to work within \env{tabular}-like environments and so had
to make global assignments to avoid the scoping created by the cells
within the \env{tabular} body (see \sectionref{sec:tabular}). 
Be aware that this can cause problems.
\end{information}

If you need to fetch more than one entry for a particular row, you can use 
the \action{find} action to find the required row and make the assignments.
Alternatively, you can select a row to identify it as the current row and then 
use the \qt{current row} functions. For example, the \action{current-row-aggregate}
may be used to aggregate the data in the current row, or the row editing commands 
may be used to edit the current row (see \sectionref{sec:editdb}).

\cmddef{dtlswaprows}
Swaps the rows identified by their row index. No check is performed
to determine if the database exists or if the indexes are in range.

\subsection{Operating on Current Row}
\label{sec:currentrow}

\glsstartrange{idx.current-row}%
Some iterative commands, such as \gls{DTLdisplaydb}, fetch the
content of the \idx{current-row} and store it in the token register:
\cmddef{dtlcurrentrow}
The content is in a special format that makes it easier to access
elements within the row. The preceding rows are stored in the token
register:
\cmddef{dtlbeforerow}
and the following rows are stored in the token register:
\cmddef{dtlafterrow}
The row index will be stored in the count register:
\cmddef{dtlrownum}

\begin{information}
Commands like \gls{DTLdisplaydb} set \gls{dtlrownum} to the filtered
row index. If rows have been omitted, \gls{dtlrownum} will be less
than the actual database row index.
\end{information}

The placeholder command:
\cmddef{dtldbname}
is defined to expand to the current database name.

Individual entries in the current row can be fetched with:
\cmddef{dtlgetentryfromcurrentrow}
This gets the value from the \gls{dtlcurrentrow} register for the
column with the index \meta{col num} and stores the value in
the control sequence \meta{cs}. If you only know the column key, you
can obtain the column index with \gls{dtlcolumnindex}.

Multiple entries in the current row can be fetched with:
\cmddef{DTLassignfromcurrentrow}
The \idx{assign-list} argument should be a comma-separated
\code{\meta{cs}\dequals\meta{key}} list, where \meta{cs} is a
placeholder command (token list variable) and \meta{key} is the
column key. Each \meta{cs} will be defined to the entry
in the column identified by \meta{key} or to null if the column
isn't set in the current row.

\begin{information}
It's also possible to fetch the row information using
\gls{DTLaction} with the \action{current-row-values}
or \action{current-row-aggregate} actions.
\end{information}

If you're not within one of the iterative commands that sets up the
\gls{dtlcurrentrow} and associated registers, you can select the
current row by its index with:
\cmddef{dtlgetrow}

\begin{important}
Before using \gls{dtlgetrow}, check that the database exists and
contains the required row number. This can be done with
\gls{DTLifdbexists} (to test for existence) and test that the row
index is between 1 and the row count (which can be obtained with
\gls{DTLrowcount}).
\end{important}

If you don't know the applicable row index, you can also set the
current row with:
\cmddef{dtlgetrowforvalue}
This is similar to \gls{dtlgetrow}, but gets the row where the entry
in the column with the given \meta{column index} exactly matches the given
\meta{value}. Internally \gls{dtlgetrowforvalue} uses \gls{dtlgetrowindex} to
first fetch the row index. If the result is null then there was no
match and an error will occur, otherwise the row index is then used
to select the current row with \gls{dtlgetrow}.

No expansion is performed on \meta{value}. If you want \meta{value} to
be expanded before comparison, use:
\gls{edtlgetrowforvalue}
This performs a protected expansion and then uses
\gls{dtlgetrowforvalue} on the expanded value.

\begin{important}
If \optval{store-datum}{true} was set when the database was
constructed, remember that the elements in the database will be
\idxpl{datumitem} which means that the value must be in the same
format.
\end{important}

\cmddef{DTLassign}
This essentially performs:
\begin{compactcodebox}
\gls{dtlgetrow}\margm{db-name}\margm{row-idx}
\gls{DTLassignfromcurrentrow}\marg{\idx{assign-list}}
\end{compactcodebox}
but the assignments are global. This first selects the current row
by its row index and then performs the assignments. If you prefer
local assignments, then select the row and use \gls{DTLassignfromcurrentrow}
instead. Alternatively, consider using the \action{select-row}
action.

The following commands alter the contents of the \gls{dtlcurrentrow}
token register. You will then need to recombine \gls{dtlbeforerow},
\gls{dtlcurrentrow} and \gls{dtlafterrow} in order to reconstruct
the database with the amendments.
\cmddef{dtlrecombine}
This will update the database by merging the contents of \gls{dtlbeforerow},
\gls{dtlcurrentrow} and \gls{dtlafterrow}. The \opt{global} option
is checked to determine if the change should be global.

\cmddef{dtlrecombineomitcurrent}
This will update the database by merging the contents of
\gls{dtlbeforerow} with the rows in \gls{dtlafterrow}, where the row
indexes are adjusted to account for the omitted current row.

\begin{warning}
Recombining the database while iterating over it can cause problems
if the row count or row indexes change. 
If you are using \gls{DTLforeach}, use the commands described in 
\sectionref{sec:dbforeach} to alter the current row of the database,
not these ones.
\end{warning}

\cmddef{dtlreplaceentryincurrentrow}
Replaces the entry for the column identified by the index
\meta{col idx} in \gls{dtlcurrentrow} with the given value \meta{new
value}. The column data is updated according to the new value
honouring the \opt{global} option (but \gls{dtlcurrentrow} will only
be locally changed).

\cmddef{dtlappendentrytocurrentrow}
Appends an entry with the given \meta{value} to 
\gls{dtlcurrentrow} for the column identified by \meta{col key}.
The row must not already contain an element in the given column.
The column data is updated according to \meta{value}.

\cmddef{dtlupdateentryincurrentrow}
Appends the entry, as per \gls{dtlappendentrytocurrentrow}, if there is no
entry for the given column in the current row, otherwise updates the entry.

\cmddef{dtlremoveentryincurrentrow}
Removes the entry for the column identified by the index
\meta{col idx} from \gls{dtlcurrentrow}.

\cmddef{dtlswapentriesincurrentrow}
Swaps the values in the columns identified by their
index, \meta{col1 num} and \meta{col2 num}, in \gls{dtlcurrentrow}.
\glsendrange{idx.current-row}%

\cmddef{dtlmapcurrentrow}
Iterates over the columns of the current row. At each iteration, \meta{cs} is
defined to the current column value and \meta{body} is performed.

\subsection{Advanced Iteration}
\label{sec:advancediter}

In addition to the iteration commands described in \sectionref{sec:dbloops},
the following are also available.

\cmddef{dtlforeachkey}
Iterates over each column in the database identified by
\meta{db-name}, and at each iteration defines \meta{key-cs} to
expand to the column key, \meta{col-cs} to expand to the column
index, \meta{type-cs} to expand to the data type, and
\meta{header-cs} to expand to the column header, and then does
\meta{body}. Note that this globally defines the loop variables.
The loop may be broken with \gls{dtlbreak}.

If you have \LaTeX3 syntax enabled, you may prefer the following instead.

\cmddef{datatoolmapkeysfunction:nN}
Maps over all the columns in the given database, applying the 
function to each set of column meta data. The function should have
four arguments \code{\margm{key}\margm{col-idx}\margm{type}\margm{header}} 
where \meta{key} is the column key, \meta{col-idx} is the column index,
\meta{type} is the data type ($-1$ for unknown) and \meta{header} is the column header.

\cmddef{datatoolmapkeysinline:nn}
Maps over all the columns in the given database, applying the inline
function to each set of column meta data. Within \meta{def}, 
\code{\#1} references the column key, \code{\#2} references the column index,
\code{\#3} references the data type ($-1$ for unknown) and \code{\#4}
references the column header.

\cmddef{dtlforcolumn}
Loops through the column identified by \meta{key} in the database identified
by \meta{db-name} and, for each iteration, defines \meta{cs} to the value of
the entry in the row. The starred version doesn't check if the database exists.
The loop may be broken with \gls{dtlbreak}.

\cmddef{dtlforcolumnidx}
Loops through the column with index \meta{col-idx} in the database identified
by \meta{db-name} and, for each iteration, defines \meta{cs} to the value of
the entry in the row. The starred version doesn't check if the database exists.
The loop may be broken with \gls{dtlbreak}.

The following commands are actually provided by \sty{datatool-base}, but are listed here
for completeness.

\cmddef{dtlforint}
Integer iteration from \meta{start} to \meta{end}, incrementing by \meta{incr}
using \meta{count-reg} as the loop variable. This command is retained for
backward-compatibility but \LaTeX3 now provides integer step functions.
The loop may be broken with \gls{dtlbreak}.

\cmddef{dtlgforint}
As \gls{dtlgforint} but globally sets the count register.
There are environment versions, but note that the environment body can't contain any verbatim.

\envdef{dtlenvgforint}
Performs \gls{dtlgforint} where the iteration body is obtained from the environment
content with leading and trailing spaces trimmed.

\envdef{dtlenvgforint*}
As \env{dtlenvgforint} but doesn't trim the environment body.

\chapter{Pie Charts (\stytext{datapie} package)}
\label{sec:datapie}

\pkgdef{datapie}
The \sty{datapie} package can be used to draw a pie chart
obtained from a column in a database. This
package automatically loads the \sty{datatool} package. 

Any package options provided when loading \sty{datapie} will be passed to
\sty{datatool}. If \sty{datatool} has already been loaded, any
options will be passed to \gls{DTLsetup} instead (which means that
you would only be able to use options that can be set after
\sty{datatool} has been loaded).

The \sty{datapie} package additionally loads the \sty{tikz}
package.

\begin{information}
The \sty{datapie} package was rewritten in version 3.0 to use
\LaTeX3 commands. The \sty{xkeyval} package has been dropped and the
use of \gls{DTLforeach} has been replaced with \gls{DTLmapdata}. A
number of bugs have also been fixed, which may cause some
differences in the output.
\end{information}

Rollback to version 2.32 is available:
\begin{codebox}
\cmd{usepackage}\marg{datapie}[=2.32]
\end{codebox}
Note that if \sty{datatool} hasn't already been loaded, this will
also apply rollback to \sty{datatool}. Problems may occur if a newer
release of \sty{datatool} has already been loaded.

The principle command provided by \sty{datapie} is:
\cmddef{DTLpiechart}
This draws a pie chart using data provided in the database
identified by \meta{db-name}. The \meta{db-name} argument may be
empty to indicate the default database.
The \meta{settings list} argument may
be a \keyval\ list of options to override the default. See
\sectionref{sec:piesettings} for available settings.

\begin{important}
The \pieopt{variable} setting must be provided to identify the
column of data to plot.
\end{important}

The \idx{assign-list} argument should be a
\code{\meta{cs}\dequals\meta{key}} list of placeholder command
assignments suitable for use in \gls{DTLmapgetvalues}. The
\pieopt{variable} setting must be set to the applicable \meta{cs}.
Additional assignments may be added if required for the segment
inner or outer labels.

The \meta{condition} optional argument allows filtering to be
applied. This should be in the syntax allowed for the first argument
of \gls{ifthenelse} (see \sectionref{sec:ifthen}). Note that if this
option is provided, it will override the \pieopt{include-if}\Slash
\pieopt{include-if-fn} setting.

There is also a corresponding action, which has optional settings:
\actionopt{name} (for the database name), \actionopt{assign} (for
the assignment list corresponding to the \idx{assign-list} argument
of \gls{DTLpiechart}), and \actionopt{options} (for the pie chart
settings corresponding to the \meta{settings-list} argument).

\actiondef{pie-chart}
The \action{pie-chart} action is equivalent to using \gls{DTLpiechart}.  
If you include the \actionopt{key} or \actionopt{column} action option
to identify the column to use for the variable then you can omit
\pieopt{variable} in the \actionopt{options} setting.
See \exampleref{ex:piechartaction} for a simple example.

\begin{information}
If \pieopt{variable} is included in \actionopt{options}, it will override
the action \actionopt{key} or \actionopt{column} setting. However,
if \pieopt{variable} has been previous set within the \opt{pie}
option in \gls{DTLsetup} and does not occur in the action
\actionopt{options} then the action \actionopt{key} or \actionopt{column} setting
will be used (if provided).
\end{information}

If you identify the required column of data with \actionopt{key} or
\actionopt{column} then a temporary placeholder command will be
created and added to the assignment list. If you don't need to use
any of the database values in hooks or options (such as the segment
labels) then you may omit the \actionopt{assign} action option or
just assign the placeholders required for the labels. You will still
be able to use \gls{DTLpievariable} or \gls{DTLpiepercent}.

The examples in this chapter use the \qt{fruit} database (see
\sectionref{sec:fruitcsv}), which has two columns
identified by the labels \qt{Name} and \qt{Quantity}. The Quantity
column is numeric and so can be used to create a pie chart. 

\mExampleref{ex:piechart} uses the following code to create a simple pie chart:
\begin{codebox}
\gls{DTLpiechart}
 \marg{\pieoptval{variable}{\cmd{Quantity}}}\comment{\pieopt{variable} required}
 \marg{fruit}\comment{database}
 \marg{\cmd{Quantity}=Quantity}\comment{assignment list}
\end{codebox}
The segment colours are the default. See
\exampleref{ex:piechartcolors} for an example that changes the
default colours. Note that in this case, only the Quantity column
needs to be referenced so only one assignment is made in the final
argument. See \exampleref{ex:piechartlabels} for an example
that changes the inner and outer labels, with an extra assignment
to allow the corresponding Name item to be shown.

\begin{resultbox}[float]
\createexample*
 [label=ex:piechart,title={Pie Chart},
  tag={fruit},
  description={Example document demonstrating a simple pie chart}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nlsp
\marg{\pieoptval{variable}{\cmd{Quantity}}}\comment{\pieopt{variable} required}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity}\comment{assignment list}
}
\end{resultbox}

\mExampleref{ex:piechartaction} creates the same chart as
\exampleref{ex:piechart} using the \action{pie-chart} action instead
of \gls{DTLpiechart}:
\begin{codebox}
\gls{DTLaction}
 \oarg{
   \actionoptval{key}{Quantity} \comment{variable}
 }
 \marg{\action{pie-chart}}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartaction,title={Pie Chart (Action `pie chart')},
  tag={fruit},
  description={Example document demonstrating a simple pie chart
using the action command}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLaction}\nlsp
 \oarg{\nldbsp
   \actionoptval{key}{Quantity}\comment{variable}
 }\nlsp
 \marg{pie chart}
}
\end{resultbox}

\section{Package Options}
\label{sec:piestyopts}

The options listed here may be passed as package options when
loading \sty{datapie}. Unless otherwise stated, these options can't
be used in \gls{DTLsetup}. Additional options that may be set with
\gls{DTLsetup} are listed in \sectionref{sec:piesettings}.

\optiondef{datapie.color}
Initialises the default colour list to: red, green, blue,
yellow, magenta, cyan, orange, white. This package option is equivalent
to \pieopt{segment-default-colors} and is the default.

\optiondef{datapie.gray}
Initialises the default colour list to eight shades of grey. 
This package option is equivalent to \pieopt{segment-default-gray}.

\optiondef{datapie.rotateinner}
Indicates that inner labels should be rotated. This package option
is equivalent to the \pieoptval{rotateinner}{true} setting.

\optiondef{datapie.norotateinner}
Indicates that inner labels should not be rotated. This package option
is equivalent to the \pieoptval{rotateinner}{false} setting and is
the default.

\optiondef{datapie.rotateouter}
Indicates that outer labels should be rotated. This package option
is equivalent to the \pieoptval{rotateouter}{true} setting.

\optiondef{datapie.norotateouter}
Indicates that outer labels should not be rotated. This package option
is equivalent to the \pieoptval{rotateouter}{false} setting and is
the default.

\section{Settings}
\label{sec:piesettings}

These settings may be set with the \inlineoptdef{pie} option in
\gls{DTLsetup}. For example:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{pie}{\pieopt{rotate-inner},\pieopt{rotate-outer}}}
\end{codebox}

\subsection{Pie Chart Data}
\label{sec:piedatasettings}

\optiondef{pie.variable}
This specifies the control sequence used to construct the pie chart.
The control sequence \meta{cs} must be included in the assignment
list provided in the final argument of \gls{DTLpiechart}.
This setting is required by \gls{DTLpiechart}.

\optiondef{pie.include-if}
The value should be the definition (expansion text) for a command
that takes a single argument. The definition should do \code{\#1} 
for any row that should have its \pieopt{variable} value
included in the pie chart, and do nothing otherwise.
See \exampleref{ex:piechartcondition}.

\optiondef{pie.include-if-fn}
An alternative to \pieopt{include-if} where a function (identified
by \meta{cs}) is provided instead of providing an inline definition.

\begin{information}
The \pieopt{include-if} and \pieopt{include-if-fn} override each
other, but both
will be ignored if the \meta{condition} optional
argument is provided with \gls{DTLpiechart}. Either use one form or the
other. Don't use both.
\end{information}


\subsection{Pie Chart Style}
\label{sec:piestylesettings}

These settings determine the pie chart's radius, outline and segment
colours. See \examplesref{ex:piechartcutaway,
ex:piechartcutaway2,
ex:piechartcutaway3}.

\optiondef{pie.cutaway}
A list of cutaway segments. Each listed segment will be offset from
the centre of the pie chart (the cutaway offset). The value should
be a comma-separated list of individual numbers or number ranges
(separated by a hyphen). The numbers refer to the segment index,
starting from 1. For example, \code{\pieoptvalm{cutaway}{1,3}} will
separated the first and third segments, whereas \code{\pieoptvalm{cutaway}{1-3}}
will separate the first three segments. An empty list, indicates no
cutaway segments.

\optiondef{pie.cutawayratio}
The cutaway offset is calculated as the given \meta{value} multiplied
by the radius. Alternatively, use \pieopt{cutawayoffset} to set the
offset explicitly.

\optiondef{pie.cutaway-ratio}
A synonym of \pieopt{cutawayratio}.

\optiondef{pie.cutawayoffset}
The cutaway offset (not dependent on the radius).
This is the distance from the centre of the pie chart to the point
of the cutaway segments. The default value is obtained from the
\pieopt{cutawayratio} multiplied by the \pieopt{radius}.
Note that this option overrides \pieopt{cutawayratio} but will itself
be overridden by \pieopt{radius}. If you also need to change the
radius, either set \pieopt{radius} first or use \pieopt{radius*}.

\optiondef{pie.cutaway-offset}
A synonym of \pieopt{cutawayoffset}.

\optiondef{pie.outline-width}
Sets the width of the line drawn around the segments.
The outline will only be drawn if the given dimension is greater
than 0pt.

\optiondef{pie.outline-color}
Sets the colour to draw the segment outlines. (To omit the outline,
set the outline width to 0pt.) The given value should be a valid
colour suitable for use in the mandatory argument of \gls{color}.

\optiondef{pie.radius}
Sets the radius of the pie chart. This will also set the inner,
outer and cutaway offsets according to the current
\pieopt{innerratio}, \pieopt{outerratio} and \pieopt{cutawayratio}.

\optiondef{pie.radius*}
Sets the radius of the pie chart without altering the offsets.

\optiondef{pie.segment-colors}
Sets the segment colours. The supplied value should be a
comma-separated list of colours suitable for use in the mandatory
argument of \gls{color}. Note that if any segment colours have
previously been assigned and this list is smaller, this will only
override the given subset.

For example,
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{pie}{
 \pieoptvalm{segment-colors}{pink,red,orange,green},
 \pieoptvalm{segment-colors}{cyan,magenta},
}}
\end{codebox}
This will assign cyan and magenta to the first two segments, but the
third segment will be orange and the fourth green. Given the default
settings, the fifth segment will also be magenta, the sixth segment
will also be cyan, the seventh segment will be orange and the eighth
segment will be white. Alternatively, you can use
\gls{DTLsetpiesegmentcolor} to set the colour of a specific segment.

\optiondef{pie.segment-default-colors}
Resets the first eight segment colours to the default colour set: red, green,
blue, yellow, magenta, cyan, orange, white. Any additional segment
colours will be unchanged.

\optiondef{pie.segment-default-gray}
Resets the first eight segment colours to the default set of eight shades of
grey. Any additional segment colours will be unchanged.

\optiondef{pie.start}
Sets the starting angle of the first segment (in degrees).

\subsection{Pie Chart Labels}
\label{sec:pielabelsettings}

The inner labels are drawn inside each segment, offset from the
segment point by the \emph{inner offset}. The outer labels are drawn
outside each segment, offset by the \emph{outer offset}. The labels
will typically include the placeholder commands, which will change
with each segment. If the placeholder commands aren't used, the
labels will be the same for every segment.

The default behaviour is to show the variable value in the inner
label and nothing in the outer label. See 
\examplesref{ex:piechartlabels,ex:piechartrotatelabels}.


\optiondef{pie.innerlabel}
The inner label, which should be displayed inside each segment,
offset from the segment point by the inner offset.
The default inner label is obtained from the \gls{DTLpievariable}
placeholder, which shows the actual value. You can change this to
\gls{DTLpiepercent} to show the percentage value instead, as in
\exampleref{ex:piechartlabels}.

\optiondef{pie.inner-label}
A synonym of \pieopt{innerlabel}.

\optiondef{pie.innerratio}
The inner offset is calculated as the given \meta{value} multiplied
by the radius. Alternatively, use \pieopt{inneroffset} to set the
offset explicitly.

\optiondef{pie.inner-ratio}
A synonym of \pieopt{innerratio}.

\optiondef{pie.inneroffset}
The inner offset (not dependent on the radius).
This is the distance from the centre of the pie chart (before the
cutaway shift) to the point where the inner label is placed.
Note that this option overrides \pieopt{innerratio} but will itself
be overridden by \pieopt{radius}. If you also need to change the
radius, either set \pieopt{radius} first or use \pieopt{radius*}.

\optiondef{pie.inner-offset}
A synonym of \pieopt{inneroffset}.

\optiondef{pie.outerlabel}
The outer label, which should be displayed inside each segment,
offset from the segment point by the outer offset.

\optiondef{pie.outer-label}
A synonym of \pieopt{outerlabel}.

\optiondef{pie.outeroffset}
The outer offset (not dependent on the radius).
This is the distance from the centre of the pie chart (before the
cutaway shift) to the point where the outer label is placed.
Note that this option overrides \pieopt{outerratio} but will itself
be overridden by \pieopt{radius}. If you also need to change the
radius, either set \pieopt{radius} first or use \pieopt{radius*}.

\optiondef{pie.outer-offset}
A synonym of \pieopt{outeroffset}.

\optiondef{pie.rotateinner}
If true, this indicates that inner labels should be rotated.
Otherwise the inner labels will be horizontal.

\optiondef{pie.rotate-inner}
A synonym of \pieopt{rotateinner}.

\optiondef{pie.rotateouter}
If true, this indicates that outer labels should be rotated.
Otherwise the outer labels will be horizontal.

\optiondef{pie.rotate-outer}
A synonym of \pieopt{rotateouter}.

\optiondef{pie.round}
Sets the number of digits used to round the percentage value in 
\gls{DTLpiepercent}.

\optiondef{pie.outerratio}
The outer offset is calculated as the given \meta{value} multiplied
by the radius. Alternatively, use \pieopt{outeroffset} to set the
offset explicitly.

\optiondef{pie.outer-ratio}
A synonym of \pieopt{outerratio}.

\section{Pie Chart Examples}
\label{sec:pieexs} 

These examples use the \qt{fruit} database (see \sectionref{sec:fruitcsv}).

\subsection{Pie Chart Filtering Examples}
\label{sec:piefilterexs} 

\mExampleref{ex:piechartcondition} modifies
\exampleref{ex:piechart} to skip the \qt{Pears} row using
the \pieopt{include-if} setting:
\begin{codebox}
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},\comment{\pieopt{variable} required}
  \pieoptvalm{include-if}{\gls{DTLifstringeq}\marg{\cmd{Name}}\marg{Pears}\marg{}\marg{\#1}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}
This uses \gls{DTLifstringeq}, which expands its arguments, to test value of
the placeholder command. Note that while you can use
\sty{etoolbox}['s] \gls{ifdefstring} with the default
\optval{store-datum}{false}, it won't work with
\optval{store-datum}{true} as then \csfmt{Name} will be a
\idx{datumcs}.

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartcondition,title={Pie Chart (Filtering)},
  tag={fruit},link={sec:piefilterexs},
  description={Example document demonstrating a simple pie chart
with a row omitted using the condition setting}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\comment{\pieopt{variable} required}
  \pieoptvalm{include-if}{\gls{DTLifstringeq}\marg{\cmd{Name}}\marg{Pears}\marg{}\marg{\#1}}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

The same result can also be achieved with the optional argument, but
bear in mind that you can't use both the optional argument and the
\pieopt{include-if} setting. The optional argument, if set, will
always override the \pieopt{include-if}\Slash \pieopt{include-if-fn} setting.
\begin{codebox}
\gls{DTLpiechart}
\oarg{\cmd{equal}\marg{\cmd{Name}}\marg{Pears}}
\marg{
 \pieoptval{variable}{\cmd{Quantity}}\comment{\pieopt{variable} required}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}
You can provide your own
custom command for use with the \pieopt{include-if} or
\pieopt{include-if-fn} settings. For example:
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{NewDocumentCommand} \cmd{PieChartNameFilter} \marg{ m m }
\marg{
  \condcsF{datatoolifvalueeq:Nn} \cmd{Name} \marg{ \#1 } \marg{ \#2 }
}
\gls{ExplSyntaxOff}
\codepar
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},\comment{\pieopt{variable} required}
  \pieoptvalm{include-if}{\cmd{PieChartNameFilter}\marg{Pears}\marg{\#1}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}
Alternatively:
\begin{codebox}
\gls{ExplSyntaxOn}
\cmd{NewDocumentCommand} \cmd{PearFilter} \marg{ m }
\marg{
   \condcsF{datatoolifvalueeq:Nn} \cmd{Name} \marg{ Pears } \marg{ \#1 }
}
\gls{ExplSyntaxOff}
\codepar
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},\comment{\pieopt{variable} required}
  \pieoptvalm{include-if-fn}{\cmd{PearFilter}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}

\subsection{Pie Chart Styles Examples}
\label{sec:piestyleexs} 

\mExampleref{ex:piechartcutaway} adapts
\exampleref{ex:piechart} so that the first and third segments are
offset from the centre of the pie chart. The starting angle has also
been changed to 45 degrees and the radius to 3cm. Each segment is
outlined.
\begin{codebox}
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},
  \pieoptval{outer-label}{\cmd{Name}},
  \pieoptvalm{cutaway}{1,3},
  \pieoptval{start}{45},
  \pieoptval{radius}{3cm},
  \pieoptval{outline-width}{1pt}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartcutaway,title={Separating Segments from a Pie Chart},
  tag={fruit},link={sec:piestyleexs},
  description={Example document demonstrating a pie chart with the
first and third segments offset}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}},\nlsp
  \pieoptvalm{cutaway}{1,3},\nlsp
  \pieoptval{start}{45},\nlsp
  \pieoptval{radius}{3cm},\nlsp
  \pieoptval{outline-width}{1pt}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

Note the difference between \exampleref{ex:piechartcutaway2} which
has a range:
\begin{codebox}
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},
  \pieoptval{outer-label}{\cmd{Name}},
  \pieoptvalm{cutaway}{\strong{1-2}},
}
\marg{fruit}\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
\end{codebox}
and \exampleref{ex:piechartcutaway3} which has separate consecutive
segments:
\begin{codebox}
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},
  \pieoptval{outer-label}{\cmd{Name}},
  \pieoptvalm{cutaway}{\strong{1,2}}
}
\marg{fruit}\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartcutaway2,title={Separating a Range of Segments from a Pie Chart},
  tag={fruit},link={sec:piestyleexs},
  description={Example document demonstrating a pie chart with the
first two segments offset in a single block}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}},\nlsp
  \pieoptvalm{cutaway}{1-2}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartcutaway3,title={Separating Individual Consecutive Segments from a Pie Chart},
  tag={fruit},link={sec:piestyleexs},
  description={Example document demonstrating a pie chart with the
first two segments offset independently}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}},\nlsp
  \pieoptvalm{cutaway}{1,2}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

\subsection{Pie Chart Labels Examples}
\label{sec:pielabelsexs} 

The default behaviour is to show the variable value in the inner
label and nothing in the outer label. \mExampleref{ex:piechartlabels}
changes the inner label to the percentage and the outer label to the
corresponding value of the \qt{Name} column. This is achieved with a
slight modification to \exampleref{ex:piechart}:
\begin{codebox}
\gls{DTLpiechart}
\marg{
 \pieoptval{variable}{\cmd{Quantity}},
 \pieoptval{inner-label}{\gls{DTLpiepercent}},
 \pieoptval{outer-label}{\cmd{Name}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
\end{codebox}
Note that this has added an extra assignment in the final argument
to provide a placeholder command for the corresponding item in the
\qt{Name} column. See also \exampleref{ex:piechartpercentlabels}
which includes the percentage symbol in the inner label and appends
the actual value to the outer label.

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartlabels,title={Pie Chart (Inner and Outer Labels)},
  tag={fruit},link={sec:pielabelsexs},
  description={Example document demonstrating a simple pie chart
with custom inner and outer labels}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieoptval{inner-label}{\gls{DTLpiepercent}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
}
\end{resultbox}

\mExampleref{ex:piechartrotatelabels} adapts
\exampleref{ex:piechartlabels} to rotate the inner and outer labels:
\begin{codebox}
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},
  \pieopt{rotate-inner},
  \pieopt{rotate-outer},
  \pieoptval{inner-label}{\gls{DTLpiepercent}},
  \pieoptval{outer-label}{\cmd{Name}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartrotatelabels,title={Pie Chart (Labels Rotated)},
  tag={fruit},
  description={Example document demonstrating a simple pie chart
with custom inner and outer labels that are rotated}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieopt{rotate-inner},\nlsp
  \pieopt{rotate-outer},\nlsp
  \pieoptval{inner-label}{\gls{DTLpiepercent}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
}
\end{resultbox}

\subsection{Pie Chart Placeholder Example}
\label{sec:pievarexs} 

\mExampleref{ex:piechartpercentlabels} adapts
\exampleref{ex:piechartlabels} to append the actual value in the outer
label. The inner label is adjusted to include the percent symbol and
the percentage is rounded to the nearest whole number.
\begin{codebox}
\gls{DTLpiechart}
\marg{
  \pieoptval{variable}{\cmd{Quantity}},
  \pieoptval{round}{0},
  \pieoptval{inner-label}{\gls{DTLpiepercent}\gls{cs.percent}},
  \pieoptval{outer-label}{\cmd{Name}\cmd{\space}(\gls{DTLpievariable})}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartpercentlabels,title={Pie Chart (Percentage Rounding)},
  tag={fruit},link={sec:pievarexs},
  description={Example document demonstrating a simple pie chart
with custom inner and outer labels that show the name and actual
value in the outer label and the percentage in the inner label}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieoptval{round}{0},\nlsp
  \pieoptval{inner-label}{\gls{DTLpiepercent}\gls{cs.percent}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}\cmd{\space}(\gls{DTLpievariable})}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
}
\end{resultbox}

\subsection{Pie Chart Label Formatting Example}
\label{sec:pielabelfmtexs} 

\mExampleref{ex:piechartlabelfmt} adapts
\exampleref{ex:piechartpercentlabels} to format the outer labels in
sans-serif and the inner labels in a pale grey bold font:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLdisplayinnerlabel}}\oarg{1}\marg{\comment{}
  \cmd{textcolor}\marg{lightgray}\marg{\cmd{bfseries} \#1}\comment{}
}
\cmd{renewcommand}\marg{\gls{DTLdisplayouterlabel}}\oarg{1}\marg{\cmd{textsf}\marg{\#1}}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartlabelfmt,title={Pie Chart (Changing the Label
Format)},
  tag={fruit},link={sec:pielabelfmtexs},
  description={Example document demonstrating a simple pie chart
with custom formatting for the inner and outer labels}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}\nl
\comment{customize the label format:}%
\cmd{renewcommand}\marg{\gls{DTLdisplayinnerlabel}}\oarg{1}\marg{\comment{}
  \cmd{textcolor}\marg{lightgray}\marg{\cmd{bfseries} \#1}\comment{}%
}\nl
\cmd{renewcommand}\marg{\gls{DTLdisplayouterlabel}}\oarg{1}\marg{\cmd{textsf}\marg{\#1}}
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieoptval{round}{0},\nlsp
  \pieoptval{inner-label}{\gls{DTLpiepercent}\gls{cs.percent}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}\cmd{\space}(\gls{DTLpievariable})}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}
}
\end{resultbox}

\subsection{Pie Chart Colour Example}
\label{sec:piecolourexs} 

\mExampleref{ex:piechartcolors} adapts
\exampleref{ex:piechartlabelfmt}. The third and fourth segment
colours are set to yellow and pink:
\begin{codebox}
\gls{DTLsetpiesegmentcolor}\marg{3}\marg{yellow}
\gls{DTLsetpiesegmentcolor}\marg{4}\marg{pink}
\end{codebox}
The outline width is set to 2pt. This can either be
done by explicitly changing \gls{DTLpieoutlinewidth}:
\begin{codebox*}
\gls{setlength}\marg{\gls{DTLpieoutlinewidth}}\marg{2pt}
\end{codebox*}
or implicitly via the \pieopt{outline-width} option:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{pie}{\pieoptval{outline-width}{2pt}}}
\end{codebox}
Alternatively, \pieopt{outline-width} may be set in the settings argument of
\gls{DTLpiechart} if it's only applicable for that chart.

The outer label format is changed to match the text to the segment
colour:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLdisplayouterlabel}}\oarg{1}\marg{\comment{}
 \gls{DTLdocurrentpiesegmentcolor}
 \cmd{textsf}\marg{\cmd{shortstack}\marg{\#1}}}
\end{codebox}
I've used \csfmt{shortstack} to compact the outer label by putting
the value below the name:
\begin{codebox}
\pieoptval{outer-label}{\cmd{Name}\gls{cs.bksl}(\gls{DTLpievariable})}
\end{codebox}
After the pie chart, a key is created with the \env{tabular}
environment. Note the limitations of \gls{DTLmapdata} within a
\env{tabular} context, so \gls{DTLforeach} is used instead:
\begin{codebox}
\cbeg{tabular}\oarg{b}\marg{ll}
\gls{DTLforeach}\marg{fruit}\marg{\cmd{Name}=Name}\marg{\comment{}
 \gls{DTLiffirstrow}\marg{}\marg{\gls{cs.bksl}}\comment{}
 \gls{DTLdocurrentpiesegmentcolor}
 \cmd{rule}\marg{10pt}\marg{10pt} \&
 \cmd{Name}
}
\cend{tabular}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:piechartcolors,title={Pie Chart (Changing and
Referencing the Segment Colours)},
  tag={fruit},link={sec:piecolourexs},
  description={Example document demonstrating a simple pie chart
with custom segment colours and a legend}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{datapie}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}\nl
\comment{change the colours for the third and fourth segments:}%
\gls{DTLsetpiesegmentcolor}\marg{3}\marg{yellow}\nl
\gls{DTLsetpiesegmentcolor}\marg{4}\marg{pink}\nl
\comment{customize the label format:}%
\cmd{renewcommand}\marg{\gls{DTLdisplayinnerlabel}}\oarg{1}\marg{\comment{}
  \cmd{textcolor}\marg{lightgray}\marg{\cmd{bfseries} \#1}\comment{}%
}\nl
\cmd{renewcommand}\marg{\gls{DTLdisplayouterlabel}}\oarg{1}\marg{\comment{}
 \gls{DTLdocurrentpiesegmentcolor}\nlsp
 \cmd{textsf}\marg{\cmd{shortstack}\marg{\#1}}}\nl
}
{%
\gls{DTLpiechart}\nl
\marg{\nlsp
  \pieoptval{variable}{\cmd{Quantity}},\nlsp
  \pieoptval{outline-width}{2pt},\nlsp
  \pieoptval{round}{0},\nlsp
  \pieoptval{inner-label}{\gls{DTLpiepercent}\gls{cs.percent}},\nlsp
  \pieoptval{outer-label}{\cmd{Name}\gls{cs.bksl}(\gls{DTLpievariable})}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\nl
\comment{legend:}%
\cbeg{tabular}\oarg{b}\marg{ll}\nl
\gls{DTLforeach}\marg{fruit}\marg{\cmd{Name}=Name}\marg{\comment{}
 \gls{DTLiffirstrow}\marg{}\marg{\gls{cs.bksl}}\comment{}
 \gls{DTLdocurrentpiesegmentcolor} \nlsp
 \cmd{rule}\marg{10pt}\marg{10pt} \string& \nlsp
 \cmd{Name}\nl
}\nl
\cend{tabular}
}
\end{resultbox}


\section{Pie Chart Variables}
\label{sec:pievariables} 

\cmddef{DTLpievariable}
The expansion text of this command should be the control sequence
used to identify the column of data used to compute the size of each
segment. The \pieoptval{variable}{\meta{cs}} option simply defines 
\gls{DTLpievariable} to \meta{cs}. The \gls{DTLpievariable} command
is simply a convenient wrapper that allows the definition of the
inner or outer label to reference the segment value without needing
to know the assignment list used in the final argument of
\gls{DTLpiechart}, and also identifies the required column to use
for the numeric value if multiple fields are assignment.

\cmddef{DTLpiepercent}
When each segment is drawn, this command is defined to the
percentage value of the variable, rounded to the number of digits
given by the following counter:
\ctrdef{DTLpieroundvar}
This placeholder command may then be used in the inner or outer
label to show the percentage value instead of the actual numeric value.
See \exampleref{ex:piechartpercentlabels}.

\begin{information}
\gls{DTLpiepercent} will expand to a \idx{plainnumber} without a
trailing percent symbol.
\end{information}

\section{Pie Chart Label Formatting}
\label{sec:pielabelformat} 

\cmddef{DTLdisplayinnerlabel}
This governs how the inner label is formatted, where \meta{text} is
the inner label text. The default definition simply expands to
\meta{text}.

\cmddef{DTLdisplayouterlabel}
This governs how the outer label is formatted, where \meta{text} is
the outer label text. The default definition simply expands to
\meta{text}. See \exampleref{ex:piechartlabelfmt}.

\section{Pie Chart Colours}
\label{sec:piecolours}

The \sty{datapie} package predefines colours for the first eight
segments of the pie chart. If you require more than eight segments
or if you want to change the default colours, you can either use the
\pieopt{segment-colors} option to supply a list or use:
\cmddef{DTLsetpiesegmentcolor}
This will set the colour to the \meta{n}th segment (starting from 1 for
the first segment). The second argument should be a valid colour
that can be used in the mandatory argument of \gls{color}.
See \exampleref{ex:piechartcolors}.

\begin{information}
It's useful to set the colours so that each segment colour is
somehow relevant to whatever the segment represents. For example, in
the previous example pie charts depicting quantities of fruit, some
of the default colours were inappropriate. Whilst red is reasonable
for apples and green for pears, blue doesn't really correspond to
lemons or limes.
\end{information}

With the default \opt{datapie.color} package option, the first eight
segments are initialised to the colours: red, green, blue,
yellow, magenta, cyan, orange, and white. With the
\opt{datapie.gray} package option, the first eight segments are
initialised to eight different shades of grey. In both cases, only
the first eight segments have an associated colour. Bear in mind
that the \opt{datapie.gray} package option simply sets the first
eight segments. It doesn't enforce greyscale for any subsequent
segment colour changes.

For example:
\begin{codebox}
\cmd{usepackage}\oarg{\opt{datapie.gray}}\marg{datapie}
\gls{DTLsetup}\marg{\optvalm{pie}{\pieoptvalm{segment-colors}{pink,,green}}}
\gls{DTLsetpiesegmentcolor}\marg{6}\marg{purple}
\gls{DTLsetpiesegmentcolor}\marg{9}\marg{teal}
\end{codebox}
This starts by initialising the first eight segment colours to
shades of grey, then the first two segment colours are changed to
pink and green (empty items are skipped when the \idx{CSV} list is
parsed), then the sixth segment colour is changed to purple, and the
ninth segment colour (which hasn't yet been set) is set to teal.
Segments 3, 4, 5, 7, and~8 are still shades of grey.

\cmddef{DTLdopiesegmentcolor}
This sets the current colour (with \gls{color}) to that of the
\meta{n}th segment. Issues a warning and does nothing if no colour
has been set for that segment.

\cmddef{DTLgetpiesegmentcolor}
Expands to the colour for the \meta{n}th segment or to \code{white} if
not set. (This ensures that no error occurs if used in an expandable
context when no colour has been assigned to the given segment.)
Since the page colour is typically white, this will give the
appearance of an unfilled segment but bear in mind that it will
obscure anything drawn in the same position first (for example, by
the \gls{DTLpieatbegintikz} hook).

\cmddef{DTLdocurrentpiesegmentcolor}
This command is intended for use within \gls{DTLpiechart} as a
shortcut that will set the current text colour to that of the
current segment. However, it may also be used within
\gls{DTLmapdata} or \gls{DTLforeach} and will use the current row
index as the segment index but, to avoid ambiguity, use
\gls{DTLdocurrentpiesegmentcolor} in the inner or outer labels
and \gls{DTLdopiesegmentcolor} elsewhere.

\cmddef{DTLpieoutlinecolor}
This command should expand to the colour specification for the
segment outline. The \pieopt{outline-color} setting simply redefines
\gls{DTLpieoutlinecolor} to the supplied value.

\cmddef{DTLpieoutlinewidth}
This length register stores the line width of the segment outline.
The \pieopt{outline-width} setting sets this register to the
supplied value. The outline is only draw if the dimension is greater
than 0pt.


\section{Pie Chart Hooks}
\label{sec:piehooks} 

\cmddef{DTLpieatsegment}
This hook is used after each segment and its associated inner and
outer labels are drawn, before the end of the current scope (which
applies the shift transformation for cutaway segments). Note that
the shift means that (0,0) corresponds to the segment point, which
won't be the centre of the pie chart for cutaway segments.

The arguments are as follows:
\begin{itemize}

\item \meta{index}: the segment index, which may be used to
reference the segment colour with \gls{DTLdopiesegmentcolor}.

\item \meta{total}: the decimal (\idx{plainnumber}) total
for the column used as the pie chart variable (omitting any rows
skipped by the filter condition). 

\item \meta{start angle}: the starting angle of the segment.

\item \meta{mid angle}: the mid way angle.

\item \meta{end angle}: the end angle of the segment.

\item \meta{shift angle}: the angle part of the segment offset polar
co-ordinate.

\item \meta{shift offset}: the radius part of the segment offset polar
co-ordinate.

\item \meta{inner offset}: the offset to the inner label.

\item \meta{outer offset}: the offset to the outer label.

\end{itemize}


\cmddef{DTLpieatbegintikz}
This hook is used at the start of the \env{tikzpicture} environment,
allowing you to change the \env{tikzpicture} settings. Does nothing by default.
For example, this hook may be redefined to scale the pie chart. This
hook may also be used to insert additional content but note that
it may be obscured by the chart if it overlaps.

\cmddef{DTLpieatendtikz}
This hook is used at the end of the \env{tikzpicture} environment,
allowing you to add additional content, which may overlap the chart.
Does nothing by default.

\chapter{Bar Charts (\stytext{databar} package)}
\label{sec:databar}

\pkgdef{databar}
The \sty{databar} package can be used to draw bar charts from data
obtain from a database. This package automatically loads the
\sty{dataplot} package as it shares some functions (such as the
default tick point generation).

Any package options provided when loading \sty{databar} will be passed to
\sty{datatool}. If \sty{datatool} has already been loaded, any
options will be passed to \gls{DTLsetup} instead (which means that
you would only be able to use options that can be set after
\sty{datatool} has been loaded). Note that the \sty{dataplot}
package will then be loaded afterwards without passing any options
to it.

\begin{information}
The \sty{databar} package was rewritten in version 3.0 to use
\LaTeX3 commands. The \sty{xkeyval} package has been dropped and the
use of \gls{DTLforeach} has been replaced with \gls{DTLmapdata}. A
number of bugs have also been fixed, which may cause some
differences in the output.
\end{information}

Rollback to version 2.32 is available:
\begin{codebox}
\cmd{usepackage}\marg{databar}[=2.32]
\end{codebox}
Note that if \sty{datatool} hasn't already been loaded, this will
also apply rollback to \sty{datatool} and \sty{dataplot}. Problems
may occur if a newer release of \sty{datatool} or \sty{dataplot} has
already been loaded.

\begin{information}
In this chapter, the terms \qt{upper}, \qt{lower}, \qt{width},
\qt{height}, \qt{x} and \qt{y} are relative to the chart's
orientation. With the default \baroptval{verticalbars}{true}
setting, the $x$ axis is horizontal (vertical bars ordered from left to
right) and the $y$ axis is vertical (increasing values from bottom
to top). With \baroptval{verticalbars}{false}, the $x$ axis is
vertical (horizontal bars ordered from bottom to top) and the $y$ axis is
horizontal (increasing values from left to right).  

The \qt{width} is the fixed distance of the bar along the $x$ axis
(\baropt{barwidth}) which is equal to 1 $x$ unit, and the
\qt{height} is the variable length along the $y$ axis (indicating
the value). \qt{Lower} is the $y=0$ end of the bar, and \qt{upper}
is the other end of the bar, which will be above (vertical) or to
the right (horizontal) for positive values or below (vertical) or to
the left (horizontal) for negative values.
\end{information}

The \sty{databar} package provides two commands to draw bar charts.
\cmddef{DTLbarchart}
Draws a bar chart from the data given in the database
identified by \meta{db-name}. The \meta{db-name} argument may be
empty to indicate the default database.
The \meta{settings list} argument may
be a \keyval\ list of options to override the default. See
\sectionref{sec:barsettings} for available settings and
\exampleref{ex:barchartfruit} for a simple example.

\begin{important}
The \baropt{variable} setting must be provided with \gls{DTLbarchart} to identify the
column of data to plot. This should be set to the applicable placeholder
command in \idx{assign-list}.
\end{important}

\cmddef{DTLmultibarchart}
This command is similar to \gls{DTLbarchart} but plots groups of bars, where
each bar in the group has its numeric value obtained from the
corresponding placeholder command in the \baropt{variables} list.
See \exampleref{ex:barchartmarks} for a simple example.

\begin{important}
The \baropt{variables} setting must be provided with
\gls{DTLmultibarchart} to identify the columns of data to plot. This
should be set to a comma-separated list of the applicable
placeholder commands in \idx{assign-list}.
\end{important}

For both \gls{DTLbarchart} and \gls{DTLmultibarchart},
the \idx{assign-list} argument should be a
\code{\meta{cs}\dequals\meta{key}} list of placeholder command
assignments suitable for use in \gls{DTLmapgetvalues}.
Additional assignments may be added if required for the bar
lower or upper labels.

The \meta{condition} optional argument allows filtering to be
applied. This should be in the syntax allowed for the first argument
of \gls{ifthenelse} (see \sectionref{sec:ifthen}). Note that if this
option is provided, it will override the \baropt{include-if}\Slash
\baropt{include-if-fn} setting.

There are also corresponding actions. Both have optional settings:
\actionopt{name} (for the database name), \actionopt{assign} (for
the assignment list corresponding to the \idx{assign-list} argument
of \gls{DTLbarchart} and \gls{DTLmultibarchart}), and
\actionopt{options} (for the bar chart settings corresponding to the
\meta{settings-list} argument).

\actiondef{bar-chart}
The \action{bar-chart} action is equivalent to using \gls{DTLbarchart}.  
If you include the \actionopt{key} or \actionopt{column} action option
to identify the column to use for the $y$ values then you can omit
\baropt{variable} in the \actionopt{options} setting.
See \exampleref{ex:barchartfruitaction} for a simple example.

\begin{information}
If \baropt{variable} is included in \actionopt{options}, it will override
the action \actionopt{key} or \actionopt{column} setting. However,
if \baropt{variable} has been previous set within the \opt{bar}
option in \gls{DTLsetup} and does not occur in the action
\actionopt{options} then the action \actionopt{key} or \actionopt{column} setting
will be used (if provided).
\end{information}

If you identify the required column of data with \actionopt{key} or
\actionopt{column} then a temporary placeholder command will be
created and added to the assignment list. If you don't need to use
any of the database values in hooks or options (such as the bar
labels) then you may omit the \actionopt{assign} action option or
just assign the placeholders required for the labels. You will still
be able to use \gls{DTLbarvariable} or \gls{DTLbarvalue}.

\actiondef{multibar-chart}
The \action{multibar-chart} action is equivalent to using 
\gls{DTLmultibarchart}. You can either set the list of bar chart
variable placeholder commands in the \baropt{variables} option
within the action \actionopt{options} setting or you can use the
action settings \actionopt{keys} or \actionopt{columns} (or a
combination of both) to identify the required columns.
See \exampleref{ex:barchartmarksaction} for a simple example.

As with the \action{bar-chart} action, if you select the columns
using the action settings rather than the \baropt{variables}
option, you may omit the corresponding placeholder commands in the
\actionopt{assign} list.
 

For example, the \qt{fruit} database (see \sectionref{sec:fruitcsv})
has two columns identified by the labels \optfmt{Name} and
\optfmt{Quantity}. The Quantity column is numeric and so can be used to
create a bar chart. 

\mExampleref{ex:barchartfruit} creates a simple bar chart using the fruit database:
\begin{codebox}
\gls{DTLbarchart}
 \marg{\baroptval{variable}{\cmd{Quantity}}}\comment{\baropt{variable} required}
 \marg{fruit}\comment{database name}
 \marg{\cmd{Quantity}=Quantity}\comment{assignment list}
\end{codebox}
Note that this has the same syntax as \gls{DTLpiechart} (see
\exampleref{ex:piechart}) which makes it simple to swap between a
bar and pie chart if you change your mind about the chart type.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartfruit,title={Vertical Bar Chart},
  tag={fruit},
  description={Example document demonstrating a simple vertical bar chart}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLbarchart}\nlsp
\marg{\baroptval{variable}{\cmd{Quantity}}}\comment{\baropt{variable} required}%
\marg{fruit}\comment{database name}%
\marg{\cmd{Quantity}=Quantity}\comment{assignment list}
}
\end{resultbox}

\mExampleref{ex:barchartfruitaction} is the same as 
\exampleref{ex:barchartfruit} but uses the \action{bar-chart}
action. Note that this doesn't need to reference the database name.
\begin{codebox}
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\optval{default-name}{fruit}}
\gls{DTLread}\marg{fruit.csv}
\gls{DTLaction}\oarg{\actionoptval{key}{Quantity}}\marg{\action{bar-chart}}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartfruitaction,
  title={Vertical Bar Chart (Action `bar chart')},
  tag={fruit},
  description={Example document demonstrating a simple vertical bar
chart created using the bar chart action}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
 \gls{DTLaction}\oarg{\actionoptval{key}{Quantity}}\marg{\action{bar-chart}}
}
\end{resultbox}

The \qt{profits} database (see \sectionref{sec:profitscsv})
has columns identified by the labels \optfmt{Year} and
\optfmt{Profit}. The Profit column has some negative values, which
will result in downward bars, with the default vertical setting, or
leftward bars with the horizontal setting.

\mExampleref{ex:barchartprofits} creates a bar chart 
which has horizontal bars.
Note that the bar width now refers to the vertical length.
\begin{codebox}
\gls{DTLbarchart}
 \marg{
  \baroptval{variable}{\cmd{theProfit}},
  \baropt{horizontal},
  \baroptval{bar-width}{20pt} 
 }
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,
 \cmd{theProfit}=Profit
 }
\end{codebox}
(See \exampleref{ex:barchartnegcol} to make all positive bars blue
and all negative bars red.)

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartprofits,title={Horizontal Bar Chart},
  tag={profits},
  description={Example document demonstrating a horizontal bar chart}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{bar-width}{20pt} \nlsp
 }\nl
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}%
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nlsp
 }
}
\end{resultbox}

The \qt{marks} database (see \sectionref{sec:marks}) has data
containing marks for three assignments given in columns labelled
\optfmt{Assign1}, \optfmt{Assign2} and \optfmt{Assign3}. 
\mExampleref{ex:barchartmarks} displays this data
as a multi bar chart with three-bar groups for each student:
\begin{codebox}
\gls{DTLmultibarchart}
 \marg{ 
  \baroptvalm{variables}{\cmd{assignI},\cmd{assignII},\cmd{assignIII}},
  \baroptval{barwidth}{10pt}
 } 
 \marg{marks}\comment{database name}
 \marg{
   \cmd{assignI}=Assign1,
   \cmd{assignII}=Assign2,
   \cmd{assignIII}=Assign3
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartmarks,title={Multi Bar Chart},
  tag={marks},
  description={Example document demonstrating a multi bar chart}]
{%
\comment{sample CSV file:}%
\exfile{studentmarks.csv}\markscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from studentmarks.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
\gls{DTLmultibarchart}\nl
 \marg{\nlsp 
  \baroptvalm{variables}{\cmd{assignI},\cmd{assignII},\cmd{assignIII}},\nlsp
  \baroptval{barwidth}{10pt}\nl
 }\nl 
 \marg{marks}\comment{database name}%
 \marg{\nlsp
   \cmd{assignI}=Assign1,\nlsp
   \cmd{assignII}=Assign2,\nlsp
   \cmd{assignIII}=Assign3\nl
}
}
\end{resultbox}

\mExampleref{ex:barchartmarksaction} is the same as 
\exampleref{ex:barchartmarks} but uses the \action{multibar-chart}
action.
\begin{codebox}
\gls{DTLaction}
\oarg{
 \actionoptvalm{keys}{Assign1,Assign2,Assign3},
 \actionoptvalm{options}{ 
  \baroptval{barwidth}{10pt}
 } 
}
\marg{\action{multibar-chart}}
\end{codebox}
Alternatively, rather than listing every column key, a column
range may be used:
\begin{codebox}
\gls{DTLaction}
\oarg{
 \actionoptvalm{columns}{4-},\comment{column 4 onwards}
 \actionoptvalm{options}{ 
  \baroptval{barwidth}{10pt}
 } 
}
\marg{\action{multibar-chart}}
\end{codebox}
This identifies column~4 onwards.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartmarksaction,title={Multi Bar Chart (Action `multibar chart')},
  tag={marks},
  description={Example document demonstrating a multi bar chart
using the multibar chart action}]
{%
\comment{sample CSV file:}%
\exfile{studentmarks.csv}\markscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from studentmarks.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
\gls{DTLaction}\nl
\oarg{\nlsp
\comment{either:}
\actionoptvalm{keys}{Assign1,Assign2,Assign3},
\comment{or:}
\comment{ \actionoptvalm{columns}{4-},}
 \actionoptvalm{options}{\nldbsp 
  \baroptval{barwidth}{10pt}\nlsp
 }\nl 
}\nl
\marg{\action{multibar-chart}}
}
\end{resultbox}

\section{Package Options}
\label{sec:barstyopts}

The options listed here may be passed as package options when
loading \sty{databar}. Unless otherwise stated, these options can't
be used in \gls{DTLsetup}. Additional options that may be set with
\gls{DTLsetup} are listed in \sectionref{sec:barsettings}.

\optiondef{databar.color}
Initialises the default colour list to: red, green, blue,
yellow, magenta, cyan, orange, white. This package option is equivalent
to \baropt{bar-default-colors} and is the default.

\optiondef{databar.gray}
Initialises the default colour list to eight shades of grey. 
This package option is equivalent to \baropt{bar-default-gray}.

\optiondef{databar.verticalbars}
If set to true, the bars will be vertical, otherwise they will be
horizontal.

\optiondef{databar.vertical}
Equivalent to \optval{databar.verticalbars}{true}.

\optiondef{databar.horizontal}
Equivalent to \optval{databar.verticalbars}{false}.

\section{Settings}
\label{sec:barsettings}

These settings may be set with the \inlineoptdef{bar} option in
\gls{DTLsetup}. For example:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{bar}{\baropt{horizontal},\baroptval{round}{0}}}
\end{codebox}

Most of the settings can be used instead of redefining or setting associated
commands (such as \gls{DTLbarXlabelalign}) or registers (such as
\gls{DTLbarlabeloffset} or \ctr{DTLbarroundvar}). For other
commands, such as \gls{DTLbardisplayYticklabel}, you can put the
redefinition code within \baroptvalm{init}{code} to localise the
effect.

\optiondef{bar.init}
The value should be code to be performed at the start of
\gls{DTLbarchart} or \gls{DTLmultibarchart} after the
\meta{settings} argument has been parsed. This code will be scoped.
\Exampleref{ex:barcharteverybar} uses \baropt{init} to locally
redefine \gls{DTLeverybarhook}.

\optiondef{bar.pre-init}
This is similar to \baropt{init} but is processed before all other
options in the same set (see \exampleref{ex:barchartclearcols}).

\begin{warning}
Unlike some options, such as \baropt{bar-colors}, the
\baropt{init} and \baropt{pre-init} options are processed within the local scope of 
\gls{DTLbarchart} or \gls{DTLmultibarchart}. This means that if you
set the options in \gls{DTLsetup} rather than in the applicable bar
chart command, the effect of \baropt{pre-init} may occur too late.
\end{warning}

For example, to set the colour list to exactly cyan, yellow, magenta
for a particular bar chart (as in
\exampleref{ex:barchartclearcols}):
\begin{codebox}
\gls{DTLbarchart}
\marg{
  \baroptval{variable}{\cmd{Quantity}},
  \baroptval{bar-label}{\cmd{Name}},
  \baroptvalm{pre-init}{\gls{DTLclearbarcolors}},
  \baroptval{outline-width}{1pt},
  \baroptvalm{bar-colors}{cyan,magenta,yellow}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}
However, if the settings are moved into \gls{DTLsetup}:
\begin{codebox}
\gls{DTLsetup}\marg{
 \optvalm{bar}{
   \baroptvalm{pre-init}{\gls{DTLclearbarcolors}},
   \baroptval{outline-width}{1pt},
   \baroptvalm{bar-colors}{cyan,magenta,yellow}
 }
}
\gls{DTLbarchart}
\marg{
  \baroptval{variable}{\cmd{Quantity}},
  \baroptval{bar-label}{\cmd{Name}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}
This will result in white bars as the colour list is set in
\gls{DTLsetup} but the \baropt{pre-init} code isn't done until
\gls{DTLbarchart}, at which point it will clear the colour list.
In this case, the solution is simply to put \gls{DTLclearbarcolors}
before \gls{DTLsetup}:
\begin{codebox}
\gls{DTLclearbarcolors}
\gls{DTLsetup}\marg{
 \optvalm{bar}{
  \baroptval{outline-width}{1pt},
  \baroptvalm{bar-colors}{cyan,magenta,yellow}
 }
}
\end{codebox}

\subsection{Bar Chart Data}
\label{sec:bardatasettings}

\optiondef{bar.variable}
This specifies the placeholder command used to construct the bar chart
with \gls{DTLbarchart}.  The command \meta{cs} must be
included in the assignment list provided in the final argument of
\gls{DTLbarchart}.  This setting is required by \gls{DTLbarchart}.

\optiondef{bar.variables}
This specifies a comma-separated list of placeholder commands used
to construct the bar chart with \gls{DTLmultibarchart}.  Each
command in the list must be included in the assignment list provided
in the final argument of \gls{DTLmultibarchart}.  This setting is
required by \gls{DTLmultibarchart}.

Certain rows in the database may be omitted from the bar chart
either with the optional \meta{condition} argument (of
\gls{DTLbarchart} or \gls{DTLmultibarchart}) or by using one of the
filtering options below.

\begin{information}
If \gls{dtlrownum} is used in
\gls{DTLeverybarhook} or \gls{DTLeverybargrouphook} it will be set
to the current database row index, which doesn't take the filtering
into account (see \exampleref{ex:barcharteverybar}).
\end{information}

\optiondef{bar.include-if}
The value should be the definition (expansion text) for a command
that takes a single argument. The command should do \code{\#1} 
for any row that should be included in the bar chart, and do nothing
otherwise. \Exampleref{ex:barchartcondition} 
demonstrates filtering with the \baropt{include-if} setting.

\optiondef{bar.include-if-fn}
An alternative to \baropt{include-if} where a function (identified
by \meta{cs}) is provided instead of providing an inline definition.

\begin{information}
The \baropt{include-if} and \baropt{include-if-fn} override each
other, but both will be ignored if the \meta{condition} optional
argument is provided with \gls{DTLbarchart} or
\gls{DTLmultibarchart}. Either use one form or the other. Don't use
both.
\end{information}

\subsection{Bar Chart Style}
\label{sec:barstylesettings}

These settings determine the bar chart's orientation, size, outline
and bar colours. Examples in
\sectionsref{sec:exbarchartlowerlabels,
sec:exbarchartupperlabels,
sec:exbarchartcolours} 
demonstrate the chart upper and lower labels.

\optiondef{bar.verticalbars}
If set to true, the bars will be vertical, otherwise they will be
horizontal.

\optiondef{bar.vertical}
Equivalent to \baroptval{verticalbars}{true}.
This is the default setting (see \exampleref{ex:barchartfruit}).

\optiondef{bar.horizontal}
Equivalent to \baroptval{verticalbars}{false}.
\Exampleref{ex:barchartprofits} uses this setting to create a chart
with horizontal bars.

\optiondef{bar.lower-label-style}
Specifies the positioning and alignment of the lower bar label.
This option will redefine \gls{DTLbarXlabelalign}
and \gls{DTLbarXneglabelalign}.

\optionvaldef{bar.lower-label-style}{opposite}
Lower labels will be on the opposite side of the $x$-axis
to the bar (that is, above the axis for negative values and below the 
axis for positive values).
\Exampleref{ex:barchartlabelsdefalign} illustrates this
style.

\optionvaldef{bar.lower-label-style}{same}
Lower labels will be on the same side of the $x$-axis
to the bar (that is, above the axis for positive values and below the 
axis for negative values). This means that the labels will appear
inside the bar. Note that this will result in protrusion over the far end of
the bar if the label text is longer than the length of the bar,
which can collide with the upper label, if present.
\Exampleref{ex:barchartlabelsalignsame} illustrates this
style.

\optionvaldef{bar.lower-label-style}{above}
Lower labels will be above the $x$-axis regardless of the bar value.
Again, this may result in protrusion over the far end of the bar,
where the bar is also above the axis.
\Exampleref{ex:barchartlabelsalignabove} illustrates this
style.

\optionvaldef{bar.lower-label-style}{below}
Lower labels will be below the $x$-axis regardless of the bar value.
Again, this may result in protrusion over the far end of the bar,
where the bar is also below the axis.
\Exampleref{ex:barchartlabelsalignbelow} illustrates this
style.

\optiondef{bar.upper-label-align}
Sets the alignment for the bar upper labels where \meta{+ve align}
is the alignment for bars with positive values and \meta{-ve align},
if provided, is the alignment for bars with negative values. The default is:
\begin{compactcodebox}
\baroptval{upper-label-align}{
 \oarg{\gls{ifDTLverticalbars} bottom,center\cmd{else} left\cmd{fi}}
 \marg{\gls{ifDTLverticalbars} top,center\cmd{else} right\cmd{fi}}
}
\end{compactcodebox}
If \meta{-ve align} is omitted, only the alignment for bars with
positive values will be changed. The grouping around \meta{+ve
align} is optional. For example,
\baroptval{upper-label-align}{\oarg{left}right} is equivalent to
\baroptval{upper-label-align}{\oarg{left}\marg{right}}.
See \sectionref{sec:exbarchartupperlabels} for an example.

\optiondef{bar.length}
The length (as a dimension) of the bar chart. (That is, the total length of the $y$
axis.) The length of the $x$-axis is governed by the number of bars,
the bar width, and (for multi bar charts) the group gap.

\optiondef{bar.barwidth}
Sets the width (as a dimension) of each bar.

\optiondef{bar.bar-width}
A synonym of \baropt{barwidth}.

\optiondef{bar.bargap}
The gap between bars in terms of multiples of a bar width. (For
example, a value of 1 indicates a gap of one bar whereas a value
of 0.5 indicates a gap of half a bar.)
Note that with \gls{DTLmultibarchart} this
gap is only between bars within a group and does not affect the gap
between groups.

\optiondef{bar.bar-gap}
A synonym of \baropt{bargap}.

\optiondef{bar.groupgap}
For use with \gls{DTLmultibarchart}, this
sets the gap between each group of bars for \gls{DTLmultibarchart}.
The default value of 1 indicates a gap of one bar width so, for
example, \baroptval{groupgap}{0.5} indicates a gap of half a bar.

\optiondef{bar.group-gap}
A synonym of \baropt{groupgap}.

\optiondef{bar.color-style}
Determines which colour in the bar colour list should be used to
fill the bar with the corresponding index.

\optionvaldef{bar.color-style}{default}
The default setting will set the \meta{i}th bar fill colour to the
\meta{i}th element of the bar colour list. If there is no such
element or if \meta{i} exceeds the maximum list index then
\optfmt{white} will be used. Note that if the background is also
white, the white bars will only be visible if they have an outline (see
\exampleref{ex:barchartclearcols}).

\optionvaldef{bar.color-style}{single}
The first colour in the colour list will be used for all bars.

\optionvaldef{bar.color-style}{cycle}
This setting will cycle through the elements of the bar colour list.
If an element is missing, \optfmt{white} will be used. For example,
suppose the colour list is cleared, and then only colours are set
for index 1, 2 and~4:
\begin{codebox}
\gls{DTLclearbarcolors}
\gls{DTLsetbarcolor}\marg{1}\marg{blue}
\gls{DTLsetbarcolor}\marg{2}\marg{red}
\gls{DTLsetbarcolor}\marg{4}\marg{green}
\end{codebox}
Then the first bar will be blue, the second red, the third white,
and the fourth green. If there are additional bars, they will cycle back to
the beginning with the fifth bar blue, the sixth red, the seventh
white and the eighth green, etc. See \exampleref{ex:barchartcyclecols}.

\optiondef{bar.bar-colors}
Sets the bar colours. Each item in the list is passed to
\gls{DTLsetbarcolor} with the item's index within the list as the
bar index. Remember that the \keyval\ parser trims leading an
trailing spaces and the \idx{CSV} parser used for the argument
removes empty items. This means that if you intend an empty item
(to indicate no fill for that bar) then you need \marg{} to indicate
this. Bear in mind that if you don't provide a fill colour you will
need to set \baropt{outline-width} to ensure the outline is drawn
(or redefine \gls{DTLBarStyle}).

\begin{warning}
If any bar colours have previously been assigned and this list is
smaller, this will only override the given subset. Multiple
instances of \baropt{bar-colors} within the same option list 
will only override the previous instance if the list is the same
length or longer.
\end{warning}

For example,
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{bar}{
 \baroptvalm{bar-colors}{pink,red,orange,green},
 \baroptvalm{bar-colors}{cyan,magenta},
}}
\end{codebox}
This will assign cyan and magenta to the first two bars, but the
third bar will be orange and the fourth green. Given the default
settings, the fifth bar will also be magenta, the sixth bar
will also be cyan, the seventh bar will be orange and the eighth
bar will be white. Alternatively, you can use
\gls{DTLsetbarcolor} to set the colour of a specific segment.

You can clear the list with \gls{DTLclearbarcolors} or reset the
list with \baropt{bar-default-colors} or \baropt{bar-default-gray}.
See \exampleref{ex:barchartclearcols}.

\optiondef{bar.bar-default-colors}
Resets the first eight bar colours to the default colour set: red, green,
blue, yellow, magenta, cyan, orange, white. Any additional bar
colours will be unchanged.

\optiondef{bar.bar-default-gray}
Resets the first eight bar colours to the default set of eight shades of
grey. Any additional bar colours will be unchanged.

\optiondef{bar.negative-bar-colors}
Sets the negative bar colour list.
Any bar with a negative value will first consult the negative colour
list. If there's no element for the required index, the default
colour list will be consulted instead.
See \exampleref{ex:barchartnegcol} for a bar chart with a different
colour set for negative bars.

\optiondef{bar.negative-color-style}
Determines which colour in the negative bar colour list should be used to
fill the bar with the corresponding index.

\optionvaldef{bar.negative-color-style}{single}
The first colour in the negative colour list will be used for all bars.
If the negative colour list is empty, the first colour in the
default list will be used instead.

\optionvaldef{bar.negative-color-style}{cycle}
This setting will cycle through the elements of the negative bar colour list.

\optionvaldef{bar.negative-color-style}{default}
This setting will follow the same style as \baropt{color-style}.

\optiondef{bar.outline-width}
Sets the width of the outline draw around each bar. The outline will
only be drawn if the value is greater than 0pt. 
See \exampleref{ex:barchartclearcols}.

\optiondef{bar.outline-color}
Sets the bar outline colour. If the value is empty then the outline
won't be drawn.

If you prefer, you can redefine \gls{DTLBarStyle} rather than
setting \baropt{outline-width} and \baropt{outline-color}. For
example, for a dotted outline that will be drawn even if
\baroptval{outline-width}{0pt}:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLBarStyle}}\marg{draw,dotted}
\end{codebox}

\subsection{Bar Chart Labels}
\label{sec:barlabelsettings}

Each bar may have a label at either end. The lower label is the
label along the $x$-axis. The upper label is at the opposite end of
the bar. For $y$ tick labels, see \sectionref{sec:baraxessettings}.

\optiondef{bar.barlabel}
This sets the lower bar label to \meta{value}, which will typically include a
placeholder command provided in the \idx{assign-list} argument of 
\gls{DTLbarchart} or the \sty{databar} placeholders
\gls{DTLbarvariable} or \gls{DTLbarvalue}.
See examples in \sectionref{sec:exbarchartlowerlabels}.

With \gls{DTLmultibarchart}, this setting provides the group label.
Use \baropt{multibarlabels} for the individual lower bar labels in a
multi-bar chart.

\optiondef{bar.bar-label}
Synonym for \baropt{barlabel}.

\optiondef{bar.upperbarlabel}
For use with \gls{DTLbarchart}, this sets
the upper bar label to \meta{value}, which will typically include a
placeholder command provided in the \idx{assign-list} argument of 
\gls{DTLbarchart} or the \sty{databar} placeholders 
\gls{DTLbarvariable} or \gls{DTLbarvalue}.

\begin{information}
The upper bar label is ignored by \gls{DTLmultibarchart}.
\end{information}

\optiondef{bar.upper-bar-label}
Synonym for \baropt{upperbarlabel}.

\optiondef{bar.multibarlabels}
For use with \gls{DTLmultibarchart}, the value should be a
comma-separated list, where each item will be used as the lower label for
the corresponding bar within a bar group.

\optiondef{bar.multi-bar-labels}
Synonym for \baropt{multibarlabels}.

\begin{information}
The multi-bar labels are ignored by \gls{DTLbarchart}.
\end{information}

\optiondef{bar.uppermultibarlabels}
For use with \gls{DTLmultibarchart}, the value should be a
comma-separated list, where each item will be used as the upper label for
the corresponding bar within a bar group.

\optiondef{bar.upper-multi-bar-labels}
Synonym for \baropt{uppermultibarlabels}.

\optiondef{bar.group-label-align}
For use with \gls{DTLmultibarchart}, the value should be
the \gls{pgftext} alignment for the bar group labels.
The default is to use the same alignment as for the lower bar
labels.

\optiondef{bar.label-offset}
The distance from the $x$-axis to the lower bar label. The value
should be a dimension. (This option sets the \gls{DTLbarlabeloffset}
length register.) Note that the direction is dependent on
\baropt{lower-label-style}.

\optiondef{bar.upper-label-offset}
The distance from the outer edge of the bar (that is, the edge
furthest from the $x$-axis) to the upper bar label. This may be
given in terms of \gls{DTLbarlabeloffset}. If you change this to a
negative value (which will cause the upper bar label to shift inside
the end of the bar) then you will also need to change the alignment.
For example:
\begin{codebox}
\baroptval{upper-label-offset}{-\gls{DTLbarlabeloffset}},
\baroptval{upper-label-align}{\oarg{left}right}
\end{codebox}

\subsection{Bar Chart Axes}
\label{sec:baraxessettings}

The bar chart $x$ axis is horizontal for vertical bars and vertical
for horizontal bars. The $y$ axis corresponds to the bar data value.
The $y$-axis may have tick marks. The $x$-axis doesn't (but may
have labels at either end of each bar, see \sectionref{sec:barlabelsettings}).
The $y$ tick marks follow the same algorithm as those for
\sty{dataplot} (see \sectionref{sec:plotaxessettings}).

\optiondef{bar.axes}
Determines whether or not to display the axes.

\optionvaldef{bar.axes}{both}
Switches on $x$ and $y$ axes and $y$ ticks.

\optionvaldef{bar.axes}{none}
Switches off $x$ and $y$ axes and $y$ ticks.

\optionvaldef{bar.axes}{x}
Switches on $x$ axis, and
switches off $y$ axis and $y$ ticks.

\optionvaldef{bar.axes}{y}
Switches on $y$ axis and $y$ ticks, and
switches off $x$ axis.

\optiondef{bar.y-axis}
Switches the $y$ axis on (\baroptval{y-axis}{true}) or off
(\baroptval{y-axis}{false}) without affecting the $x$ axis setting.

\optiondef{bar.yaxis}
Synonym of \baropt{y-axis}.

\optiondef{bar.y-ticks}
Indicates whether or not to draw $y$ ticks.
If true, this option will automatically set \baroptval{y-axis}{true}.
If false, no change will be made to the $y$ axis setting.
Tick marks will only be drawn if the axis is also drawn so, for
example, \code{\baroptval{y-ticks}{true}, \baroptval{y-axis}{false}}
won't show any tick marks.

\optiondef{bar.ytics}
Synonym of \baropt{y-ticks}.

\optiondef{bar.round}
Sets the \ctr{DTLbarroundvar} counter, which is used to round the
variable value when setting the \gls{DTLbarvalue} placeholder
command. It will also be used to round the $y$ tick labels unless
\baropt{y-tick-round} is set.

\optiondef{bar.y-tick-round}
Sets the rounding used in default $y$ tick labels.
If not set, this will match the \baropt{round} option.
If the supplied value is empty or missing, it will revert back to
using the \ctr{DTLbarroundvar} counter.

\optiondef{bar.ytic-round}
Synonym of \baropt{y-tick-round}.

\optiondef{bar.ylabel}
The label for the $y$ axis.

\optiondef{bar.ylabel-position}
Sets the $x$ position of the $y$ label where the value may be one of
the following keywords.

\optionvaldef{bar.ylabel-position}{center}
Sets the $x$ position of the $y$ label to the centre of
the $x$ axis.

\optionvaldef{bar.ylabel-position}{zero}
Sets the $x$ position of the $y$ label to 0 (see 
\exampleref{ex:barchartrotateyticlabels}).

\optionvaldef{bar.ylabel-position}{min}
Sets the $x$ position of the $y$ label to the minimum $x$
axis value.

\optionvaldef{bar.ylabel-position}{max}
Sets the $x$ position of the $y$ label to the maximum $x$
axis value.

\optiondef{bar.max}
The maximum extent of the $y$ axis (as a \idx{plainnumber} in data
units). If an empty \meta{value} is supplied, the maximum extent
will be the maximum non-negative value found in the data (or 0 if no
non-negative values found).

\optiondef{bar.maxdepth}
The negative extent of the bar chart. The value must be a 
\idx{plainnumber} in data co-ordinates less than or equal to 0. If an empty
\meta{value} is supplied, the negative extent will be the lowest
(closest to $-\infty$) negative value found in the data or 0 if 
there are no negative values.

\optiondef{bar.max-depth}
Synonym of \baropt{maxdepth}.

\optiondef{bar.y-tick-gap}
Sets the gap between $y$ tick marks. This option automatically sets
\baroptval{y-ticks}{true} and \baroptval{y-axis}{true}. If both
\baropt{y-tick-gap} and \baropt{y-tick-points} are omitted, the $y$ tick
marks (if \baroptval{y-ticks}{true}) will be calculated according to
the minimum and maximum values and the minimum tick gap length
\gls{DTLmintickgap}.

\begin{information}
You can't set both \baropt{y-tick-gap} and \baropt{y-tick-points}.
\end{information}

\optiondef{bar.yticgap}
Synonym of \baropt{y-tick-gap}.

\optiondef{bar.y-tick-points}
A comma-separated list of points for the $y$ ticks. This option
automatically sets \baroptval{y-ticks}{true} and \baroptval{y-axis}{true}.
Tick marks outside the $y$ range (from \baropt{maxdepth} to
\baropt{max}) will be omitted.

\optiondef{bar.yticpoints}
Synonym of \baropt{y-tick-points}.

\optiondef{bar.y-tick-labels}
A comma-separated list of labels for the $y$ ticks. This option automatically sets
\baroptval{y-ticks}{true} and \baroptval{y-axis}{true}. If omitted and
\baroptval{y-ticks}{true}, the $y$ tick value will be used. Note that
if there are more items in \baroptval{y-tick-points} than in
\baroptval{y-tick-labels} then the default tick labels will be used for
the missing items.

\optiondef{bar.yticlabels}
Synonym of \baropt{y-tick-labels}.

\optiondef{bar.y-tic-label-align}
Sets the $y$-tick label alignment. The value should be able to expand to 
a \gls{pgftext} alignment specifier. (The expansion occurs within
\gls{DTLbarchart} and \gls{DTLmultibarchart} not when the option is
set.)

\optiondef{bar.ytic-label-align}
Synonym of \baropt{y-tic-label-align}.

\optiondef{bar.y-tick-label-align}
Another synonym of \baropt{y-tic-label-align}.

\section{Bar Chart Examples}
\label{sec:barchartexs}

\subsection{Labels}
\label{sec:exbarchartlabels}

\mExampleref{ex:barchartfruitlabels} adapts
\exampleref{ex:barchartfruit} to label each bar of the chart.
The placeholder commands may be used within the labels.
In this case, the fruit name is placed in the lower label and the
quantity is placed in the upper label, which can be done by adding
an extra assignment in the final argument:
\begin{codebox}
\gls{DTLbarchart}
\marg{
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptval{bar-label}{\cmd{Name}},
  \baroptval{upper-bar-label}{\cmd{Quantity}},
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartfruitlabels,title={Bar Chart With Labels},
  tag={fruit},link={sec:exbarchartlabels},
  description={Example document demonstrating a simple bar chart
where each bar has a label below identifying the bar and above
providing the data value}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLbarchart}\nl
\marg{\nlsp
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptval{bar-label}{\cmd{Name}},\nlsp
  \baroptval{upper-bar-label}{\cmd{Quantity}},\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

The placeholder commands are assigned using \gls+{DTLmapgetvalues}
(since the drawing code for each bar is constructed within the body
of \gls{DTLmapdata}) so they will expand as they would ordinarily if
\gls{DTLmapgetvalues} is used explicitly within \gls{DTLmapdata}.
If you want the value to be rounded, then use \gls{DTLbarvalue} with
the \baropt{round} option instead. For example:
\begin{codebox}
\gls{DTLbarchart}
\marg{
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptval{bar-label}{\cmd{Name}},
  \baroptval{round}{0},
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}

The \gls{DTLbarvalue} command is also useful with \action{bar-chart}
and \action{multibar-chart} actions where the column (or columns,
for \action{multibar-chart}) can simply be identified by key or
index rather than assigning a placeholder command. 

\mExampleref{ex:barchartfruitactionlabels} adapts
\exampleref{ex:barchartfruitaction} and uses \gls{DTLmapget}
and \gls{DTLbarvalue} to avoid the need to assign any placeholder
commands.
\begin{codebox}
\gls{DTLaction}
\oarg{
  \actionoptval{key}{Quantity},
  \actionoptvalm{options}{
    \baroptvalm{bar-label}{\gls{DTLmapget}\marg{\mapgetoptval{key}{Name}}},
    \baroptval{upper-bar-label}{\gls{DTLbarvalue}}
 }
}
\marg{\action{bar-chart}}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartfruitactionlabels,
  title={Bar Chart With Labels (Action `bar chart')},
  tag={fruit},
  description={Example document demonstrating a simple bar chart
(created with the bar chart action)
where each bar has a label below identifying the bar and above
providing the data value}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}%
\codepar
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLaction}\nl
\oarg{\nlsp
  \actionoptval{key}{Quantity},\nlsp
  \actionoptvalm{options}{\nldbsp
    \baroptvalm{bar-label}{\gls{DTLmapget}\marg{\mapgetoptval{key}{Name}}},\nldbsp
    \baroptval{upper-bar-label}{\gls{DTLbarvalue}}\nlsp
 }\nl
}\nl
\marg{\action{bar-chart}}
}
\end{resultbox}

\subsection{Filtering}
\label{sec:exbarchartcondition}

\mExampleref{ex:barchartcondition} modifies
\exampleref{ex:barchartfruit} to skip the \qt{Pears} row using
the \baropt{include-if} setting:
\begin{codebox}
\gls{DTLbarchart}
\marg{
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptval{bar-label}{\cmd{Name}},
  \baroptvalm{include-if}{\gls{DTLifstringeq}\marg{\cmd{Name}}\marg{Pears}\marg{}\marg{\#1}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}
This uses \gls{DTLifstringeq} to test value of
the placeholder command.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartcondition,title={Bar Chart (Filtering)},
  tag={fruit},link={sec:exbarchartcondition},
  description={Example document demonstrating a simple bar chart
with a row omitted using the condition setting}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLbarchart}\nl
\marg{\nlsp
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptval{bar-label}{\cmd{Name}},\nlsp
  \baroptvalm{include-if}{\gls{DTLifstringeq}\marg{\cmd{Name}}\marg{Pears}\marg{}\marg{\#1}}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

Compare \exampleref{ex:barchartcondition} with \exampleref{ex:piechartcondition}
which is identical except that one uses \gls{DTLbarchart} and the
other one uses \gls{DTLpiechart}.
As with \exampleref{ex:piechartcondition},
the same result can also be achieved with the optional argument
instead of \baropt{include-if} or you can use \baropt{include-if-fn},
but bear in mind that you can't use
both the optional argument and the \baropt{include-if}\Slash
\baropt{include-if-fn} setting. 

\subsection{Lower Label Alignment}
\label{sec:exbarchartlowerlabels}

\mExampleref{ex:barchartlabelsdefalign} adapts \exampleref{ex:barchartprofits}
to include upper and lower labels. This uses the default settings
for \baropt{lower-label-style} and \baropt{upper-label-align}. The
lower bar label is the year (obtained from the \optfmt{Year} column
which is assigned to the \csfmt{theYear} placeholder command). The
upper bar label is the value (profit or loss). This can be
referenced with the placeholder command \csfmt{theProfit} or with
\gls{DTLbarvariable}, but this will show the value as given in the
database (which includes the currency symbol and has inconsistently
formatted negative values, see \sectionref{sec:profitscsv}). With
\gls{DTLbarvalue}, the value will be shown as a
\idx{formattednumber} without the currency symbol, rounded according
to the \baropt{round} setting.
\begin{codebox}
\gls{DTLbarchart}
 \marg{
  \baroptval{variable}{\cmd{theProfit}},
  \baropt{horizontal},
  \baroptval{bar-width}{20pt},
  \baroptval{bar-label}{\cmd{theYear}},
  \baroptval{round}{0},
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},
 }
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,
 \cmd{theProfit}=Profit
 }
\end{codebox}
An alternative is to reformat the values while the data is read
from the file, as is done in \exampleref{ex:auto-reformat-csv}.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartlabelsdefalign,
  title={Horizontal Bar Chart with Labels (Default Alignment)},
  tag={profits},link={sec:exbarchartlowerlabels},
  description={Example document demonstrating a horizontal bar chart
with inner labels on the opposite side of the x-axis to the bar}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{bar-width}{20pt}, \nlsp
  \baroptval{bar-label}{\cmd{theYear}},\nlsp
  \baroptval{round}{0},\nlsp
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}}\nl
 }\nl
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

\mExampleref{ex:barchartlabelsalignsame} has a minor modification to
\exampleref{ex:barchartlabelsdefalign} that sets
\baroptval{lower-label-style}{same}, which puts the lower label on
the same side of the $x$ axis as the bar. Note that this causes a
clash with the upper bar labels for short bars.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartlabelsalignsame,
  title={Horizontal Bar Chart with Labels 
  (\optfmt{lower-label-style=same})},
  tag={profits},link={sec:exbarchartlowerlabels},titleskip=small,
  description={Example document demonstrating a horizontal bar chart
with inner labels overlapping the start of each bar}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
Beware of short bars!
\codepar
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{bar-width}{20pt}, \nlsp
  \baroptval{bar-label}{\cmd{theYear}},\nlsp
  \baroptval{round}{0},\nlsp
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},\nlsp
  \baroptval{lower-label-style}{same}\nl
 }\nl
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

\mExampleref{ex:barchartlabelsalignbelow} has a minor modification to
\exampleref{ex:barchartlabelsdefalign} that sets
\baroptval{lower-label-style}{below}, which puts the lower label
below the $x$ axis as the bar (where below means $y<0$, which is to
the left for horizontal charts).  This means that it overlaps bars with
negative values which again causes a
clash with the upper bar labels for short bars.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartlabelsalignbelow,
  title={Horizontal Bar Chart with Labels
(\optfmt{lower-label-style=below})},
  tag={profits},link={sec:exbarchartlowerlabels},titleskip=small,
  description={Example document demonstrating a horizontal bar chart
with inner labels in the negative plane which causes overlapping the start of each
negative bar}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
Beware of short bars!
\codepar
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{bar-width}{20pt}, \nlsp
  \baroptval{bar-label}{\cmd{theYear}},\nlsp
  \baroptval{round}{0},\nlsp
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},\nlsp
  \baroptval{lower-label-style}{below}\nl
 }\nl
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

\mExampleref{ex:barchartlabelsalignabove} has a minor modification to
\exampleref{ex:barchartlabelsdefalign} that sets
\baroptval{lower-label-style}{above}, which puts the lower label
above the $x$ axis as the bar (where above means $y>0$, which is to
the right for horizontal charts).  This means that it overlaps bars
with positive values which again causes a clash with the upper bar
labels for short bars.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartlabelsalignabove,titleskip=small,
  title={Horizontal Bar Chart with Labels
(\optfmt{lower-label-style=above})},
  tag={profits},link={sec:exbarchartlowerlabels},
  description={Example document demonstrating a horizontal bar chart
with inner labels in the positive plane which causes overlapping the start of each
positive bar}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
Beware of short bars!
\codepar
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{bar-width}{20pt}, \nlsp
  \baroptval{bar-label}{\cmd{theYear}},\nlsp
  \baroptval{round}{0},\nlsp
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},\nlsp
  \baroptval{lower-label-style}{above}\nl
 }\nl
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

\subsection{Upper Label Alignment}
\label{sec:exbarchartupperlabels}

The examples in \sectionref{sec:exbarchartlowerlabels} demonstrate
the default style for upper labels. 
\mExampleref{ex:barchartupperlabelsalign} modifies
\exampleref{ex:barchartlabelsdefalign} to shift the upper labels
inwards so that they overlap the bars:
\begin{codebox}
\gls{DTLbarchart}
 \marg{
  \baroptval{variable}{\cmd{theProfit}},
  \baropt{horizontal},
  \baroptval{bar-width}{20pt},
  \baroptval{bar-label}{\cmd{theYear}},
  \baroptval{round}{0},
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},
  \baroptvalm{upper-label-offset}{ -\gls{DTLbarlabeloffset} },
  \baroptval{upper-label-align}{[left]right}
 }
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,
 \cmd{theProfit}=Profit
 }
\end{codebox}
This sets \baropt{upper-label-offset} to a negative dimension to shift the upper label
inwards (towards the $x$-axis). Note that this shifts the upper labels for 
negative bars to the right and for the positive bars to the left.
This now means that the node alignment has to be changed for the
upper labels: \optfmt{left} for the negative upper labels and
\optfmt{right} for the positive upper labels. Again, this can cause
a problem for short bars.

Bear in mind that if you switch to vertical bars the node alignment will need to
be changed to \baroptval{upper-label-align}{[above]below}.
(Alternatively, include the \gls{ifDTLverticalbars} conditional in
the value to allow for either orientation.)

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartupperlabelsalign,
  title={Horizontal Bar Chart with Upper Labels Over the Bars
(negative \optfmt{upper-label-offset})},
  tag={profits},link={sec:exbarchartupperlabels},
  description={Example document demonstrating a horizontal bar chart
with upper labels overlapping the bars}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
Beware of short bars!
\codepar
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{bar-width}{20pt}, \nlsp
  \baroptval{bar-label}{\cmd{theYear}},\nlsp
  \baroptval{round}{0},\nlsp
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},\nlsp
  \baroptvalm{upper-label-offset}{ -\gls{DTLbarlabeloffset} },\nlsp
  \baroptvalm{upper-label-align}{[left]right}\nl
 }\nl
 \marg{profits}\comment{database name}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

\subsection{Multi Bar Chart Labels}
\label{sec:exbarchartmultilabels}

In addition to lower and upper bar labels, multi bar charts created
with \gls{DTLmultibarchart} also
have group labels. The upper labels are positioned at the bar end,
as for \gls{DTLbarchart}, and the lower labels are positioned at the
bar start (near the $x$-axis). However, the lower labels should now be
specified with \baropt{multibarlabels} (or \baropt{multi-bar-labels})
and the upper labels with \baropt{uppermultibarlabels} (or
\baropt{upper-multi-bar-labels}). These options take comma-separated
lists for their values, where each item in the list corresponds to
the bar within the group.

\begin{information}
Each set of bars within a group corresponds to one row of the
database. This means that the placeholder commands set in the
\idx{assign-list} final argument of \gls{DTLmultibarchart} 
will be the same for each bar label within the group.
\end{information}

The group label normally is positioned at the mid point of the group below the
lower bar labels (if present). \mExampleref{ex:barchartgrouplabel}
adapts \exampleref{ex:barchartmarks} so that the student marks are
shown at the end of the bar (the upper label). The lower label
indicates the assignment (A1 for assignment 1, A2 for assignment 2,
and A3 for assignment 3) and uses the default alignment (rotated for
vertical bars). Below that, for each group, is the group
label, which is set to the student's initials. The group label
alignment is changed so that the group labels aren't rotated.
\begin{codebox}
\gls{DTLmultibarchart}
 \marg{ 
  \baroptvalm{variables}{\cmd{assignI},\cmd{assignII},\cmd{assignIII}},
  \baroptval{round}{0},
  \baroptval{bar-width}{12pt},
  \baroptvalm{group-label-align}{center,top},
  \baroptvalm{bar-label}{\gls{xDTLinitials}\marg{\cmd{Forename}}\gls{xDTLinitials}\marg{\cmd{Surname}}},
  \baroptvalm{multi-bar-labels}{A1,A2,A3},
  \baroptvalm{upper-multi-bar-labels}{\gls{DTLbarvalue},\gls{DTLbarvalue},\gls{DTLbarvalue}},
 } 
 \marg{marks}\comment{database name}
 \marg{
   \cmd{assignI}=Assign1,
   \cmd{assignII}=Assign2,
   \cmd{assignIII}=Assign3,
   \cmd{Surname}=Surname,
   \cmd{Forename}=Forename
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartgrouplabel,
  title={Multi Bar Chart With Group Labels},
  tag={marks},link={sec:exbarchartmultilabels},
  description={Example document demonstrating a multi bar chart with
upper, lower and group labels}]
{%
\comment{sample CSV file:}%
\exfile{studentmarks.csv}\markscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from studentmarks.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
\gls{DTLmultibarchart}\nl
 \marg{\nlsp 
  \baroptvalm{variables}{\cmd{assignI},\cmd{assignII},\cmd{assignIII}},\nlsp
  \baroptval{round}{0},\nlsp
  \baroptval{bar-width}{12pt},\nlsp
  \baroptvalm{group-label-align}{center,top},\nlsp
  \baroptvalm{bar-label}{\gls{xDTLinitials}\marg{\cmd{Forename}}\gls{xDTLinitials}\marg{\cmd{Surname}}},\nlsp
  \baroptvalm{multi-bar-labels}{A1,A2,A3},\nlsp
  \baroptvalm{upper-multi-bar-labels}{\gls{DTLbarvalue},\gls{DTLbarvalue},\gls{DTLbarvalue}},\nl
 }\nl 
 \marg{marks}\comment{database name}%
 \marg{\nlsp
   \cmd{assignI}=Assign1,\nlsp
   \cmd{assignII}=Assign2,\nlsp
   \cmd{assignIII}=Assign3,\nlsp
   \cmd{Surname}=Surname,\nlsp
   \cmd{Forename}=Forename\nl
}
}
\end{resultbox}

This leads to a cluttered chart. A better solution would be to add
a $y$-axis with tick marks to show the values and a legend
associating each bar colour with the corresponding assignment
(see \exampleref{ex:barchartgrouplegend}).

\subsection{Axes}
\label{sec:exbarchartaxes}

\mExampleref{ex:barchartaxes} adapts
\exampleref{ex:barchartprofits} to include axes and $y$ tick labels.
Note that the rounding for the $y$ tick labels and in the definition
of the \gls{DTLbarvalue} placeholder are set differently.
The bar width (which for a horizontal bar chart is in fact the
height) is set to 20pt and the bar gap is set to 0.5, which is half
a bar width (and therefore 10pt).
\begin{codebox}
\gls{DTLbarchart}
 \marg{
  \baroptval{variable}{\cmd{theProfit}},
  \baropt{horizontal},
  \baroptval{color-style}{single},
  \baroptval{max-depth}{-5000},
  \baroptval{max}{10000},
  \baroptval{bar-width}{20pt},\baroptval{bar-gap}{0.5},
  \baropt{axes},\baropt{y-ticks},\baroptval{y-tick-gap}{2500},
  \baroptval{ylabel}{Profits},
  \baroptval{bar-label}{\cmd{theYear}},
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},
  \baroptval{round}{2},
  \baroptval{y-tick-round}{0}
 }
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,
 \cmd{theProfit}=Profit
 }
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartaxes,
  title={Bar Chart With Axes},
  tag={profits},link={sec:exbarchartaxes},
  description={Example document demonstrating a bar chart with
axes}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{color-style}{single},\nlsp
  \baroptval{max-depth}{-5000},\nlsp
  \baroptval{max}{10000},\nlsp
  \baroptval{bar-width}{20pt},\baroptval{bar-gap}{0.5},\nlsp
  \baropt{axes},\baropt{y-ticks},\baroptval{y-tick-gap}{2500},\nlsp
  \baroptval{ylabel}{Profits},\nlsp
  \baroptval{bar-label}{\cmd{theYear}},\nlsp
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},\nlsp
  \baroptval{round}{2},\nlsp
  \baroptval{y-tick-round}{0}\nl
 }\nl
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

Note that the $y$ axis label (\qt{Profits}) is aligned at the mid
point of the $x$ axis, below the $y$ tick labels. This can look
strangely off-centre if the origin isn't in the middle of the $x$
axis (as in this case, since the absolute value of the negative
extent is smaller than the maximum positive extent.)

\mExampleref{ex:barchartrotateyticlabels} adapts
\exampleref{ex:barchartaxes} to align the $y$ label at $x=0$
(using \baropteqvalref{ylabel-position}{zero}).
The tick gap has also been made smaller, which would cause the tick
labels to overlap, so \gls{DTLbardisplayYticklabel} has been
redefined to rotate the tick label. The alignment for the
\gls{pgftext} command is also modified to allow for the rotation:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLbardisplayYticklabel}}[1]\marg{\cmd{rotatebox}\marg{45}\marg{\#1}}
\gls{DTLbarchart}
 \marg{
  \baroptval{variable}{\cmd{theProfit}},
  \baropt{horizontal},
  \baroptval{color-style}{single},
  \baroptval{max-depth}{-5000},
  \baroptval{max}{10000},
  \baroptval{bar-width}{20pt},\baroptval{bar-gap}{0.5},
  \baropt{axes},\baropt{y-ticks},\baroptval{y-tick-gap}{1000},
  \baroptval{ylabel}{Loss / Profits},
  \baropteqvalref{ylabel-position}{zero},
  \baroptval{bar-label}{\cmd{theYear}},
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},
  \baroptval{round}{2},
  \baroptval{y-tick-round}{0},
  \baroptvalm{ytic-label-align}{right,top}
 }
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,
 \cmd{theProfit}=Profit
 }
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartrotateyticlabels,
  title={Bar Chart With Rotated Tick Labels},
  tag={profits},
  description={Example document demonstrating a bar chart with
axes and y tick labels that have been rotated 45 degrees}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
\cmd{renewcommand}\marg{\gls{DTLbardisplayYticklabel}}[1]\marg{\cmd{rotatebox}\marg{45}\marg{\#1}}\nl
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{color-style}{single},\nlsp
  \baroptval{max-depth}{-5000},\nlsp
  \baroptval{max}{10000},\nlsp
  \baroptval{bar-width}{20pt},\baroptval{bar-gap}{0.5},\nlsp
  \baropt{axes},\baropt{y-ticks},\baroptval{y-tick-gap}{1000},\nlsp
  \baroptvalm{ylabel}{Loss / Profits},\nlsp
  \baropteqvalref{ylabel-position}{zero},\nlsp
  \baroptvalm{bar-label}{\cmd{theYear}},\nlsp
  \baroptvalm{upper-bar-label}{\gls{DTLbarvalue}},\nlsp
  \baroptval{round}{2},\nlsp
  \baroptval{y-tick-round}{0},\nlsp
  \baroptvalm{ytic-label-align}{right,top}\nl
 }\nl
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

\subsection{Bar Colours}
\label{sec:exbarchartcolours}

\mExampleref{ex:barchartclearcols} adapts
\exampleref{ex:barchartfruit} so that bar colour list is locally
cleared and set to just three colours. Since there are more than
three bars, the remaining bars are white with the default setting.
Note that without the outline those bars won't be visible.
\begin{codebox}
\gls{DTLbarchart}
\marg{
  \baroptval{variable}{\cmd{Quantity}},
  \baroptval{bar-label}{\cmd{Name}},
  \baroptvalm{pre-init}{\gls{DTLclearbarcolors}},
  \baroptval{outline-width}{1pt},
  \baroptvalm{bar-colors}{cyan,magenta,yellow}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}
Remember to use \baropt{pre-init} rather than \baropt{init} in this
case to ensure that the colour list is cleared before the
\baropt{bar-colors} option is processed.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartclearcols,
  title={Bar Chart With a Limited Set of Custom Colours},
  tag={fruit},link={sec:exbarchartcolours},
  description={Example document demonstrating a simple bar chart
with an insufficient colour set for all bars so only the first three
have a colour}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLbarchart}\nl
\marg{\nlsp
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptval{bar-label}{\cmd{Name}},\nlsp
  \baroptvalm{pre-init}{\gls{DTLclearbarcolors}},\nlsp
  \baroptval{outline-width}{1pt},\nlsp
  \baroptvalm{bar-colors}{cyan,magenta,yellow}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

If there are insufficient colours, you can cycle round the set.
\mExampleref{ex:barchartcyclecols} adapts \exampleref{ex:barchartclearcols}
so that the fourth bar uses the first colour in the set, and the
fifth bar uses the second colour.
\begin{codebox}
\gls{DTLbarchart}
\marg{
  \baroptval{variable}{\cmd{Quantity}},
  \baroptval{bar-label}{\cmd{Name}},
  \baroptvalm{pre-init}{\gls{DTLclearbarcolors}},
  \baroptvalm{bar-colors}{cyan,magenta,yellow},
  \baroptval{color-style}{cycle},
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartcyclecols,
  title={Bar Chart Cycling through the Colour Set},
  tag={fruit},
  description={Example document demonstrating a simple bar chart
with the bars cycling through the colour set}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLbarchart}\nl
\marg{\nlsp
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptval{bar-label}{\cmd{Name}},\nlsp
  \baroptvalm{pre-init}{\gls{DTLclearbarcolors}},\nlsp
  \baroptvalm{bar-colors}{cyan,magenta,yellow},\nlsp
  \baroptval{color-style}{cycle},\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

By default, the negative bars will use the same colour set as the
positive bars (see \exampleref{ex:barchartprofits}).
\mExampleref{ex:barchartnegcol} adapts
\exampleref{ex:barchartprofits} so that bars with
positive values are blue and bars with negative values are red:
\begin{codebox}
\gls{DTLbarchart}
 \marg{
  \baroptval{variable}{\cmd{theProfit}},
  \baroptval{horizontal},
  \baroptval{bar-width}{20pt}, 
  \baroptval{bar-label}{\cmd{theYear}}, 
  \baroptval{upper-bar-label}{\gls{DTLbarvalue}},
  \baroptval{round}{0}, 
  \baroptval{color-style}{single},
  \baroptval{bar-colors}{blue},
  \baroptval{negative-bar-colors}{red}
 }
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,
 \cmd{theProfit}=Profit
 }
\end{codebox}
Note that without \baroptval{negative-bar-colors}{red}, all bars
would be blue with \code{\baroptval{color-style}{single},
\baroptval{bar-colors}{blue}}.

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartnegcol,
  title={Single Colours for Positive and Negative Bars},
  tag={profits},
  description={Example document demonstrating a bar chart with blue
positive bars (extending right) and red negative bars (extending
left)}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{bar-width}{20pt}, \nlsp
  \baroptvalm{bar-label}{\cmd{theYear}}, \nlsp
  \baroptvalm{upper-bar-label}{\gls{DTLbarvalue}}, \nlsp
  \baroptval{round}{0},\nlsp
  \baroptval{color-style}{single},\nlsp
  \baroptvalm{bar-colors}{blue},\nlsp
  \baroptvalm{negative-bar-colors}{red}\nl
 }\nl
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

Each bar is drawn using \sty{tikz}['s] \gls{path} command with the
option list including \code{fill=\meta{colour}} if a non-empty
colour specification has been set for the bar colour and
\code{draw=\meta{colour}} if the \baropt{outline-color} is non-empty
and the \baropt{outline-width} is greater than 0pt. This will then
be followed by the full expansion of \gls{DTLBarStyle}, which can be
used to make further adjustments.

\mExampleref{ex:barcharteverybarshading} adapts
\exampleref{ex:barchartaxes} to shade each bar with a gradient
from red on the left to blue on the right. The normal fill action is
disabled by setting the fill colour for the first bar to empty
and using \baroptval{color-style}{single} to use that setting for all
bars. The actual bar style is then obtained from \gls{DTLBarStyle}
which has the shading settings to be passed to \gls{path}:
\begin{codebox}
\cmd{renewcommand}\gls{DTLBarStyle}\marg{\comment{}
 draw,shade,shading=axis,left color=red,right color=blue
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barcharteverybarshading,
  title={Shaded Bar},
  tag={profits},
  description={Example document demonstrating a bar chart with
shaded bars}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
\cmd{renewcommand}\gls{DTLBarStyle}\marg{\comment{}
 draw,shade,shading=axis,left color=red,right color=blue\nlsp
}\nl
\gls{DTLsetbarcolor}\marg{1}\marg{}\comment{no fill for bar 1}
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{color-style}{single},\nlsp
  \baroptval{max-depth}{-5000},\nlsp
  \baroptval{max}{10000},\nlsp
  \baroptval{bar-width}{20pt},\baroptval{bar-gap}{0.5},\nlsp
  \baropt{axes},\baropt{y-ticks},\baroptval{y-tick-gap}{2500},\nlsp
  \baroptvalm{ylabel}{Profits},\nlsp
  \baroptvalm{bar-label}{\cmd{theYear}},\nlsp
  \baroptvalm{upper-bar-label}{\gls{DTLbarvalue}},\nlsp
  \baroptval{round}{2},\nlsp
  \baroptval{y-tick-round}{0}\nl
 }\nl
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}

If the \gls{DTLBarStyle} content needs to be constructed according
to each bar variable, then you can redefine
\gls{DTLeveryprebarhook} to redefine \gls{DTLBarStyle} as
applicable.

\subsection{Hooks}
\label{sec:exbarcharthooks}

\mExampleref{ex:barcharteverybarpts} adapts
\exampleref{ex:barchartprofits} to set all bars to a single colour
(pink) and uses the after every bar hook to draw a line from the
start point (\gls{DTLstartpt}) to the end point (\gls{DTLendpt})
and draw a circle at the start, middle (\gls{DTLmidpt}), and end
points:
\begin{codebox}
\cmd{renewcommand}\gls{DTLeverybarhook}\marg{\comment{}
  \cmd{pgfpathmoveto}\marg{\gls{DTLstartpt}}
  \cmd{pgfpathlineto}\marg{\gls{DTLendpt}}
  \cmd{pgfpathcircle}\marg{\gls{DTLstartpt}}{2pt}
  \cmd{pgfpathcircle}\marg{\gls{DTLmidpt}}{2pt}
  \cmd{pgfpathcircle}\marg{\gls{DTLendpt}}{2pt}
  \cmd{pgfusepath}\marg{draw}
}\comment{}%
\gls{DTLbarchart}
 \marg{
  \baroptval{variable}{\cmd{theProfit}},
  \baropt{horizontal},
  \baroptval{color-style}{single},
  \baroptval{bar-colors}{pink},
 }
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,
 \cmd{theProfit}=Profit
 }
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barcharteverybarpts,
  title={Hook at Every Bar},
  tag={profits},link={sec:exbarcharthooks},
  description={Example document demonstrating a bar chart with
extra information added to the bars}]
{%
\comment{sample CSV file:}%
\exfile{profits.csv}\profitscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from profits.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{profits}}\nl
\gls{DTLread}\oarg{\iooptval{csv-content}{tex}}\marg{profits.csv}
}
{%
\cmd{renewcommand}\gls{DTLeverybarhook}\marg{\comment{}
  \cmd{pgfpathmoveto}\marg{\gls{DTLstartpt}}\nlsp
  \cmd{pgfpathlineto}\marg{\gls{DTLendpt}}\nlsp
  \cmd{pgfpathcircle}\marg{\gls{DTLstartpt}}{2pt}\nlsp
  \cmd{pgfpathcircle}\marg{\gls{DTLmidpt}}{2pt}\nlsp
  \cmd{pgfpathcircle}\marg{\gls{DTLendpt}}{2pt}\nlsp
  \cmd{pgfusepath}\marg{draw}\nl
}\comment{}%
\gls{DTLbarchart}\nl
 \marg{\nlsp
  \baroptval{variable}{\cmd{theProfit}},\nlsp
  \baropt{horizontal},\nlsp
  \baroptval{color-style}{single},\nlsp
  \baroptvalm{bar-colors}{pink},\nl
 }\nl
 \marg{profits}\comment{database}
 \marg{\comment{assignment list}
 \cmd{theYear}=Year,\nlsp
 \cmd{theProfit}=Profit\nl
 }
}
\end{resultbox}


\mExampleref{ex:barcharteverybar} modifies \exampleref{ex:barchartcondition}
to show the bar index (\gls{DTLbarindex}) and the row index number
(\gls{dtlrownum}) in the centre of each bar. The second
row (Pears) has been skipped so the row index numbering is: 1, 3, 4 and 5.
Compare this with the bar index numbering: 1, 2, 3, and 4.
\begin{codebox}
\gls{DTLbarchart}
\marg{
 \baroptvalm{init}{\cmd{renewcommand}\marg{\gls{DTLeverybarhook}}\marg{\comment{}
  \gls{pgftext}\oarg{at=\gls{DTLmidpt}}\marg{\gls{DTLbarindex}/\cmd{number}\gls{dtlrownum}}}},
 \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
 \baroptval{bar-label}{\cmd{Name}},
 \baroptvalm{include-if}{\gls{DTLifstringeq}\marg{\cmd{Name}}\marg{Pears}\marg{}\marg{\#1}}
}
\marg{fruit}\comment{database}
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barcharteverybar,title={Every Bar Hook (Filtering)},
  tag={fruit},
  description={Example document demonstrating a simple bar chart
with a row omitted using the condition setting and the corresponding
row index in the middle of each bar}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLbarchart}\nl
\marg{\nlsp
  \baroptvalm{init}{\cmd{renewcommand}\marg{\gls{DTLeverybarhook}}\marg{\gls{pgftext}\oarg{at=\gls{DTLmidpt}}\marg{\gls{DTLbarindex}/\cmd{number}\gls{dtlrownum}}}},\nlsp
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baroptvalm{bar-label}{\cmd{Name}},\nlsp
  \baroptvalm{include-if}{\gls{DTLifstringeq}\marg{\cmd{Name}}\marg{Pears}\marg{}\marg{\#1}}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

\gls{DTLeverybarhook} can be used to gather information for use in
the end hook \gls{DTLbaratendtikz}. This is done in
\mexampleref{ex:barchartlegend} which modifies
\exampleref{ex:barchartfruit} to move the labels into a legend.
\begin{codebox}
\gls{DTLbarchart}
\marg{
 \baroptvalm{init}{\comment{}
  \cmd{def}\cmd{mychartlegend}\marg{}\comment{}
  \cmd{renewcommand}\marg{\gls{DTLeverybarhook}}\marg{\comment{}
   \gls{ifdefempty}\marg{\cmd{mychartlegend}}\marg{}\marg{\cmd{appto}\cmd{mychartlegend}{\gls{cs.bksl}}}\comment{}
   \gls{eappto}\cmd{mychartlegend}\marg{\comment{}
     \marg{\cmd{noexpand}\gls{DTLdobarcolor}\marg{\gls{DTLbarindex}}
     \cmd{noexpand}\cmd{rule}\marg{\cmd{noexpand}\gls{DTLbarwidth}}\marg{\cmd{noexpand}\gls{DTLbarwidth}}}
     \gls{expandonce}\cmd{Name}
   }\comment{}
  }\comment{}
  \cmd{renewcommand}\marg{\gls{DTLbaratendtikz}}\marg{\comment{}
   \cmd{node}[at={(\gls{DTLbarchartwidth},0pt)},anchor=south west]
    \marg{
    \cbeg{tabular}\marg{l}
    \cmd{mychartlegend}
    \cend{tabular}
   };
  }\comment{}
 },
 \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
 \baropt{y-ticks},\baroptval{ylabel}{Quantity}
}
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartlegend,title={Bar Chart With a Legend},
  tag={fruit}, 
  description={Example document demonstrating a simple bar chart
with a legend}]
{%
\comment{sample CSV file:}%
\exfile{fruit.csv}\fruitcsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from fruit.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{fruit}}\nl
\gls{DTLread}\marg{fruit.csv}
}
{%
\gls{DTLbarchart}\nl
\marg{\nlsp
  \baroptvalm{init}{\comment{}
   \cmd{def}\cmd{mychartlegend}\marg{}\comment{}
   \cmd{renewcommand}\marg{\gls{DTLeverybarhook}}\marg{\comment{}\dbspace
     \gls{ifdefempty}\marg{\cmd{mychartlegend}}\marg{}\marg{\cmd{appto}\cmd{mychartlegend}{\gls{cs.bksl}}}\comment{}\dbspace
     \gls{eappto}\cmd{mychartlegend}\marg{\comment{}\dbdbspace
       \marg{\cmd{noexpand}\gls{DTLdobarcolor}\marg{\gls{DTLbarindex}}\nldbdbsp
       \cmd{noexpand}\cmd{rule}\marg{\cmd{noexpand}\gls{DTLbarwidth}}\marg{\cmd{noexpand}\gls{DTLbarwidth}}}\nldbdbsp
       \gls{expandonce}\cmd{Name}\nldbsp
     }\comment{}\dbspace
   }\comment{}
   \cmd{renewcommand}\marg{\gls{DTLbaratendtikz}}\marg{\comment{}
    \cmd{node}[at={(\gls{DTLbarchartwidth},0pt)},anchor=south west]
\nldbsp
     \marg{\nldbdbsp
     \cbeg{tabular}\marg{l}\nldbdbsp
     \cmd{mychartlegend}\nldbdbsp
     \cend{tabular}\nldbsp
    };\nldbsp
   }\comment{}
  },\nlsp
  \baroptval{variable}{\cmd{Quantity}},\comment{\baropt{variable} required}
  \baropt{y-ticks},\baroptval{ylabel}{Quantity}\nl
}\nl
\marg{fruit}\comment{database}%
\marg{\cmd{Quantity}=Quantity,\cmd{Name}=Name}\comment{assignment list}
}
\end{resultbox}

For a multi bar chart, the colours change for each bar within the
group. If the above \gls{DTLeverybarhook} code is used
for the student scores database multi bar chart then the legend would end
up with the number of students times the number of assignments bars.

\mExampleref{ex:barchartgrouplegend} modifies
\exampleref{ex:barchartgrouplabel} to include a legend rather than
labelling every bar. In this case, the number of bars is known as 
the information is required for the \baropt{variables} list.
\begin{codebox}
\gls{DTLmultibarchart}
 \marg{
  \baroptvalm{init}{
    \cmd{renewcommand}\marg{\gls{DTLbaratendtikz}}\marg{\comment{}
      \cmd{node}[at={(\gls{DTLbarchartwidth},0pt)},anchor=south west]
      \marg{\cbeg{tabular}\marg{l}
        \marg{\gls{DTLdobarcolor}\marg{1}\cmd{rule}\marg{\gls{DTLbarwidth}}\marg{\gls{DTLbarwidth}}}
        Assignment 1\gls{cs.bksl}
        \marg{\gls{DTLdobarcolor}\marg{2}\cmd{rule}\marg{\gls{DTLbarwidth}}\marg{\gls{DTLbarwidth}}}
        Assignment 2\gls{cs.bksl}
        \marg{\gls{DTLdobarcolor}\marg{3}\cmd{rule}\marg{\gls{DTLbarwidth}}\marg{\gls{DTLbarwidth}}}
        Assignment 3
       \cend{tabular}};
    }
  },
  \baroptvalm{variables}{\cmd{assignI},\cmd{assignII},\cmd{assignIII}},
  \baroptval{bar-width}{12pt},
  \baroptvalm{group-label-align}{center,top},
  \baroptvalm{bar-label}{\gls{xDTLinitials}\marg{\cmd{Forename}}\gls{xDTLinitials}\marg{\cmd{Surname}}},
  \baropt{y-ticks},\baroptval{axes}{both}
 } 
 \marg{marks}\comment{database name}%
 \marg{
   \cmd{assignI}=Assign1,
   \cmd{assignII}=Assign2,
   \cmd{assignIII}=Assign3,
   \cmd{Surname}=Surname,
   \cmd{Forename}=Forename
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label=ex:barchartgrouplegend,
  title={Multi Bar Chart With a Legend},
  tag={marks}, 
  description={Example document demonstrating a multi bar chart with
a legend}]
{%
\comment{sample CSV file:}%
\exfile{studentmarks.csv}\markscsv
\codepar
\cmd{usepackage}\marg{databar}\nl
\comment{Load data from studentmarks.csv file:}%
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{marks}}\nl
\gls{DTLread}\marg{studentmarks.csv}
}
{%
\gls{DTLmultibarchart}\nl
 \marg{\nlsp 
  \baroptvalm{init}{\nldbsp
    \cmd{renewcommand}\marg{\gls{DTLbaratendtikz}}\marg{\comment{}\dbdbspace
      \cmd{node}[at={(\gls{DTLbarchartwidth},0pt)},anchor=south west]
\nldbdbsp
      \marg{\cbeg{tabular}\marg{l}\nldbdbdbsp
        \marg{\gls{DTLdobarcolor}\marg{1}\cmd{rule}\marg{\gls{DTLbarwidth}}\marg{\gls{DTLbarwidth}}}\nldbdbdbsp
         Assignment 1\gls{cs.bksl}\nldbdbdbsp
        \marg{\gls{DTLdobarcolor}\marg{2}\cmd{rule}\marg{\gls{DTLbarwidth}}\marg{\gls{DTLbarwidth}}}\nldbdbdbsp
         Assignment 2\gls{cs.bksl}\nldbdbdbsp
        \marg{\gls{DTLdobarcolor}\marg{3}\cmd{rule}\marg{\gls{DTLbarwidth}}\marg{\gls{DTLbarwidth}}}\nldbdbdbsp
         Assignment 3\nldbdbdbsp
       \cend{tabular}};\nldbdbsp
    }\nldbsp
  },\nlsp
  \baroptvalm{variables}{\cmd{assignI},\cmd{assignII},\cmd{assignIII}},\nlsp
  \baroptval{bar-width}{12pt},\nlsp
  \baroptvalm{group-label-align}{center,top},\nlsp
  \baroptvalm{bar-label}{\gls{xDTLinitials}\marg{\cmd{Forename}}\gls{xDTLinitials}\marg{\cmd{Surname}}},\nlsp
  \baropt{y-ticks},\baroptval{axes}{both}\nl
 }\nl 
 \marg{marks}\comment{database name}%
 \marg{\nlsp
   \cmd{assignI}=Assign1,\nlsp
   \cmd{assignII}=Assign2,\nlsp
   \cmd{assignIII}=Assign3,\nlsp
   \cmd{Surname}=Surname,\nlsp
   \cmd{Forename}=Forename\nl
}
}
\end{resultbox}

\section{Bar Chart Associated Commands}
\label{sec:barcommands} 

\subsection{Axes}
\label{sec:baraxescommands} 

\cmddef{ifDTLverticalbars}
This conditional is set by the \baropt{verticalbars} setting, which
additionally changes the label alignment. (If you change this
conditional explicitly, you will also need to redefine the alignment
commands.) This conditional may be referenced in hooks to determine
the chart orientation. 

\cmddef{DTLbarchartlength}
A length register used to set the total bar chart $y$-axis length. This may be changed
with \gls{setlength} or via the \baropt{length} option.

\cmddef{DTLbarmax}
This command should either be defined to expand to nothing, in which
case the maximum extend will be obtained from the data, or it should
be defined to the maximum $y$ value. This command is redefined by
the \baropt{max} setting.

\cmddef{DTLnegextent}
This command should either be defined to expand to nothing, in which
case the negative will be obtained from the data, or it should
be defined to the negative extent (which must be a decimal value
less than or equal to~0). This command is redefined by the 
\baropt{maxdepth} setting.

\cmddef{DTLBarXAxisStyle}
The expansion text of this command should be the \sty{tikz} line
style specifier for drawing the $x$-axis. The \baropt{x-axis-style}
option redefines this command.

\cmddef{DTLBarYAxisStyle}
The expansion text of this command should be the \sty{tikz} line
style specifier for drawing the $y$-axis. The \baropt{y-axis-style}
option redefines this command.

\cmddef{DTLBarStyle}
This command is fully expanded and then appended to the list of
options for \gls{path} when each bar is drawn.

\subsection{Textual}
\label{sec:bartextcommands} 

\ctrdef{DTLbarroundvar}
Counter used to govern the number of digits to round to for display
purposes. Note that changing the counter with \gls{setcounter} will
globally change the value. To locally change it, use the
\baropt{round} setting. The \baropt{y-tick-round} setting is
initialised to use this counter value, so if you change this counter
or set \baropt{round} but don't set \baropt{y-tick-round} then the
default $y$ tick labels will use the same rounding that's applied to
the definition of \gls{DTLbarvalue}.

\cmddef{DTLbarvariable}
Placeholder command that may be used in lower or upper labels to
show the bar value (as the value appears in the database).

\cmddef{DTLbarvalue}
Placeholder command that may be used in lower or upper labels to
show the bar value as a \idx{formattednumber} that has been rounded
according to the \baropt{round} setting. This command will actually
be a decimal \idx{datumcs}. The numeric value part will include the rounding.

For example, if the original value in the database column labelled
\optfmt{Profit} for the current bar is
\code{-\gls{cs.dollar}12,345.62} and the settings include
\baroptval{variable}{\cmd{theProfit}} with the assignment list
\code{\cmd{theProfit}\dhyphen Profit}, then \gls{DTLbarvariable}
will expand to the supplied \baropt{variable} \cmd{theProfit}, which in
turn will expand to \code{-\gls{cs.dollar}12,345.01}, but 
\gls{DTLbarvalue} will expand to the rounded localised decimal
value. For example, with \baroptval{round}{0} this will be
\code{-12,345} (without the currency symbol).

\cmddef{DTLbarindex}
Placeholder command that expands to the current bar index (starting
from 1). Note that with \gls{DTLmultibarchart}, this index is reset
at the start of each group.

\cmddef{DTLbargroupindex}
Placeholder command that expands to the current bar group index (starting
from 1). Note that with \gls{DTLbarchart}, this will expand to \code{0}.

\cmddef{DTLbarwidth}
A length register used to store the bar width. This may be changed
with \gls{setlength} or via the \baropt{barwidth} option.

\cmddef{DTLbarlabeloffset}
A length register used to store the distance from the $x$-axis to
the lower bar label. This may be changed
with \gls{setlength} or via the \baropt{label-offset} option.

\cmddef{DTLbarXlabelalign}
This command should expand to the \gls{pgftext} alignment 
specifications for the $x$-axis lower bar labels for positive values. 
As from v3.0, the
\gls{ifDTLverticalbars} conditional has been moved into the
definition of \gls{DTLbarXlabelalign} as it is now fully expanded
before being passed to the \sty{pgf} parser. The default definition
is now:
\begin{compactcodebox}
\cmd{newcommand}\gls{DTLbarXlabelalign}\marg{\comment{}
 \gls{ifDTLverticalbars} left,rotate=-90\cmd{else} right\cmd{fi}
}
\end{compactcodebox}
This command is redefined by the \baropt{lower-label-style} setting.

\cmddef{DTLbarXneglabelalign}
This command should expand to the \gls{pgftext} alignment 
specifications for the $x$-axis lower bar labels for negative values. 
The default definition is:
\begin{compactcodebox}
\cmd{newcommand}\gls{DTLbarXneglabelalign}\marg{\comment{}
 \gls{ifDTLverticalbars} right,rotate=-90\cmd{else} left\cmd{fi}
}
\end{compactcodebox}
This command is redefined by the \baropt{lower-label-style} setting.

\cmddef{DTLbarXupperlabelalign}
This command should expand to the \gls{pgftext} alignment specifications for
the upper bar labels. The default definition is:
\begin{compactcodebox}
\cmd{newcommand}\gls{DTLbarXupperlabelalign}\marg{\comment{} 
 \gls{ifDTLverticalbars} bottom,center\cmd{else} left\cmd{fi}
}
\end{compactcodebox}
The \baroptval{upper-label-align}{\oargm{-ve align}\margm{+ve
align}} option redefines this command to \meta{+ve align}.

\cmddef{DTLbarXnegupperlabelalign}
This command should expand to the \gls{pgftext} alignment specifications for
the upper bar labels. The default definition is:
\begin{compactcodebox}
\cmd{newcommand}\gls{DTLbarXnegupperlabelalign}\marg{\comment{}
 \gls{ifDTLverticalbars} top,center\cmd{else} right\cmd{fi}
}
\end{compactcodebox}
The \baroptval{upper-label-align}{\oargm{-ve
align}\margm{+ve align}} option redefines this command to \meta{-ve
align}, if provided.

\cmddef{DTLbarsetupperlabelalign}
This command is used by the \baroptval{upper-label-align} to
redefine \gls{DTLbarXupperlabelalign} and optionally redefine
\gls{DTLbarXnegupperlabelalign}.

\cmddef{DTLbargrouplabelalign}
This command should expand to the \gls{pgftext} alignment specification for
the group label alignment (\gls{DTLmultibarchart} only).
The \baropt{group-label-align} option redefines this command.

\cmddef{DTLbarYticklabelalign}
This command should expand to the \gls{pgftext} alignment 
specifications for the $y$-axis tick labels. As from v3.0, the
\gls{ifDTLverticalbars} conditional has been moved into the
definition of \gls{DTLbarYticklabelalign} as it is now fully expanded
before being passed to the \sty{pgf} parser. The default definition
is now:
\begin{compactcodebox}
\cmd{newcommand}\gls{DTLbarYticklabelalign}\marg{\comment{}
 \gls{ifDTLverticalbars} right\cmd{else} top,center\cmd{fi}
}
\end{compactcodebox}
This command is
redefined by the \baropt{y-tick-label-align} setting.

\cmddef{DTLbardisplayYticklabel}
This command encapsulates the $y$-tick labels. By default, this
simply expands to its argument. Note that if the tick labels are
automatically generated from the data (rather than by specifying
them with \baropt{y-tick-labels}) then the argument will be a
\idx{datumitem} where the string part is the \idx{formattednumber}.
If you prefer a \idx{plainnumber} you can redefine \gls{DTLbardisplayYticklabel}
to use \gls{datatooldatumvalue:Nnnnn} (which requires \LaTeX3 syntax
on).

\cmddef{DTLdisplaylowerbarlabel}
This command encapsulates the lower bar labels with \gls{DTLbarchart}. 
By default, this simply expands to its argument.

\cmddef{DTLdisplaybargrouplabel}
This command encapsulates the group bar labels with \gls{DTLmultibarchart}. 
By default, this simply expands to its argument.

\cmddef{DTLdisplaylowermultibarlabel}
This command encapsulates the lower bar labels for
\gls{DTLmultibarchart}. By default, this
simply expands to its argument.

\cmddef{DTLdisplayupperbarlabel}
This command encapsulates the upper bar labels with \gls{DTLbarchart}.
By default, this simply expands to its argument.

\cmddef{DTLdisplayuppermultibarlabel}
This command encapsulates the upper bar labels for
\gls{DTLmultibarchart}. By default, this
simply expands to its argument.

\subsection{Bar Colours}
\label{sec:barcolours} 

\cmddef{DTLbaroutlinecolor}
This command should expand to the bar colour (suitable for use in
the mandatory argument of \gls{color}). This command is redefined by
the \baropt{outline-color} option. If this command is redefined to
empty then the outline won't be drawn.

\cmddef{DTLbaroutlinewidth}
This length register should be set to the required line thickness
for the bar outline. Zero or negative values indicate that the
outline should not be drawn. This register is set by the
\baropt{outline-width} option.

\cmddef{DTLsetbarcolor}
Sets the colour for the given index in the general bar colour list.
This command is used by \baropt{bar-colors},
\baropt{bar-default-colors}, and \baropt{bar-default-gray}.

\begin{information}
The argument of \gls{DTLsetbarcolor} may be empty. This is different
to the colour not being set for the given index. An empty value
indicates that the bar should not be filled. Whereas an unset value
may default to white, depending on the style. Most of the time there
will be no visual difference, but if there is content behind the
bar, a white filled bar will obscure it but an unfilled bar won't.
\end{information}

\cmddef{DTLclearbarcolors}
Clears the general bar colour list. All bars will be filled white unless 
a new colour list is set (and therefore won't be visible without an
outline).

\cmddef{DTLsetnegbarcolor}
Sets the colour for the given index in the negative bar colour list.
Any bars with negative values will first reference this list before
using the general bar colour list.

\cmddef{DTLclearnegbarcolors}
Clears the negative bar colour list. Any bars with negative values
will use the general bar colour list instead.

\cmddef{DTLgetbarcolor}
Expands to the general bar colour specification for the given
\meta{index} or to \optfmt{white} if not set.

\cmddef{DTLgetnegbarcolor}
Expands to the negative bar colour specification for the given
\meta{index}, if set, otherwise behaves like \gls{DTLgetbarcolor}.

\cmddef{DTLdobarcolor}
Does \code{\gls{color}\margm{colour}} where \meta{colour} will be
obtained from \code{\gls{DTLgetnegbarcolor}\margm{index}} if the
supplied \meta{value} is negative, otherwise from 
\code{\gls{DTLgetbarcolor}\margm{index}}. If the \meta{value} is
omitted, a non-negative number is assumed.
Does nothing if an empty colour specification has been applied
to the given bar index

\cmddef{DTLdocurrentbarcolor}
May be used in \gls{DTLeverybarhook} to do
\code{\gls{DTLdobarcolor}\margm{index}} where
\meta{index} is the current bar index. This command can also be
used in \gls{DTLmapdata} or \gls{DTLforeach} (in which case the row
index will be used as the bar index), but without access to
the current bar value it will assume a non-negative value.

\subsection{Hooks}
\label{sec:barhooks} 

The placeholder commands assigned in the \idx{assign-list} final
argument of \gls{DTLbarchart} and \gls{DTLmultibarchart} may be used
in hooks to add information from the current row. Bear in mind that
with \gls{DTLmultibarchart}, those placeholder commands will expand
to the same content for every bar within the same bar group. They
will also be unavailable in the start and end hooks
(\gls{DTLbaratbegintikz} and \gls{DTLbaratendtikz}).
Placeholder commands such as \gls{DTLbarvariable} and
\gls{DTLbarvalue} are updated for every bar.

\begin{information}
If you want to add any drawing code in the hooks, remember that the
$x$ co-ordinates are in units of a bar width and the $y$
co-ordinates are in data units.
\end{information}

Since both \gls{DTLbarchart} and \gls{DTLmultibarchart} internally
use \gls{DTLmapdata}, you can reference the current row index within
hooks with \gls{dtlrownum}. Note that this is the database row index which may
not correspond to the bar or group number if filtering has been
applied. Instead, use \gls{DTLbarindex} for the bar index or 
\gls{DTLbargroupindex} for the bar group index. 
See \sectionref{sec:exbarcharthooks}.

\cmddef{DTLeverybarhook}
Hook implemented after each bar is drawn. 

\cmddef{DTLeveryprebarhook}
Hook implemented before each bar is drawn. 

The following three commands expand to the start point, mid point
and end point of the main mid-axis through the current bar. 
Each point is expressed as a \sty{pgf}
point \gls{pgfpointxy}. Below, $s$ is the starting point of the bar,
$b/2$ is half a bar width and $v$ is
variable value for the current bar (see \exampleref{ex:barcharteverybarpts}).

\cmddef{DTLstartpt}
Expands to \code{\gls{pgfpointxy}\marg{$s+b/2$}\marg{0}} for
vertical bars and to \code{\gls{pgfpointxy}\marg{0}\marg{$s+b/2$}}
for horizontal bars.

\cmddef{DTLmidpt}
Expands to \code{\gls{pgfpointxy}\marg{$s+b/2$}\marg{$v/2$}} for
vertical bars and to \code{\gls{pgfpointxy}\marg{$v/2$}\marg{$s+b/2$}}
for horizontal bars.

\cmddef{DTLendpt}
Expands to \code{\gls{pgfpointxy}\marg{$s+b/2$}\marg{$v$}} for
vertical bars and to \code{\gls{pgfpointxy}\marg{$v$}\marg{$s+b/2$}}
for horizontal bars.

\cmddef{DTLeverybargrouphook}
Hook implemented after every bar group is drawn with
\gls{DTLmultibarchart}. Note that the above point placeholder
commands will be set for the last bar in the group.

\cmddef{DTLbaratbegintikz}
Hook implemented at the start of the \env{tikzpicture} environment.

\cmddef{DTLbaratendtikz}
Hook implemented at the end of the \env{tikzpicture} environment.

In any of these hooks you can access the total bar chart $x$-axis
length with:
\cmddef{DTLbarchartwidth}
This expands to the bar chart width in $x$-units (without any unit).
To obtain the actual dimension, multiply this value by
\gls{DTLbarwidth}. The width takes the group gap into account for
multi-bar charts, but it does not take into account the space taken
up by the $y$-ticks or $y$ axis label (if present).
Expands to nothing outside of the bar chart commands.

With \gls{DTLmultibarchart}, you can also access the width of each bar group:
\cmddef{DTLbargroupwidth}
This expands to the bar group width in $x$-units (without any unit).

\cmddef{DTLtotalbars}
This expands to the total number of bars in the current chart (and
to nothing outside of the bar chart commands). For
\gls{DTLbarchart}, this is the number of rows that contribute to the
chart (which will be less than or equal to the total number of rows
in the database). For \gls{DTLmultibarchart}, this will be the
number of contributing rows multiplied by the number of bars in each
group.

\cmddef{DTLbartotalvariables}
For \gls{DTLmultibarchart} only, this expands to the number of
variables (that is, the number of bars in each group). Expands 
to nothing outside of \gls{DTLmultibarchart}.

\cmddef{DTLtotalbargroups}
For \gls{DTLmultibarchart} only, this expands to the total number of
bar groups in the current chart. Expands to nothing outside of
\gls{DTLmultibarchart}. The number of bar groups is equal to the
number of rows that contribute to the chart (which will be less than
or equal to the total number of rows in the database).


\chapter{Scatter and Line Plots (\stytext{dataplot} package)}
\label{sec:dataplot}

\pkgdef{dataplot}
The \sty{dataplot} package can be used to draw scatter or line
diagrams obtained from columns in one or more databases. This
package automatically loads the \sty{datatool} package. 

Any package options provided when loading \sty{dataplot} will be passed to
\sty{datatool}. If \sty{datatool} has already been loaded, any
options will be passed to \gls{DTLsetup} instead (which means that
you would only be able to use options that can be set after
\sty{datatool} has been loaded).

The \sty{dataplot} package additionally loads the \sty{tikz} package
and also the \sty{tikz} plot libraries \styfmt{plotmarks},
\styfmt{plothandlers} and \styfmt{calc}.

\begin{information}
The \sty{dataplot} package was rewritten in version 3.0 to use
\LaTeX3 commands. The \sty{xkeyval} package has been dropped and the
use of \gls{DTLforeach} has been replaced with \gls{DTLmapdata}. A
number of bugs have also been fixed, which may cause some
differences in the output.
\end{information}

Rollback to version 2.32 is available:
\begin{codebox}
\cmd{usepackage}\marg{dataplot}[=2.32]
\end{codebox}
Note that if \sty{datatool} hasn't already been loaded, this will
also apply rollback to \sty{datatool}. Problems may occur if a newer
release of \sty{datatool} has already been loaded.

The principle command provided by \sty{dataplot} is:
\cmddef{DTLplot}
This draws data from the listed databases as a scatter plot or line
diagram. The \meta{db-list} argument should be a comma-separated
list of database labels. The \keyvallist\ argument should be a
\keyval\ list of settings. Available settings are listed in
\sectionref{sec:plotsettings}. The \plotopt{x} and \plotopt{y}
settings are required. The other settings are optional.

The \meta{condition} optional argument allows filtering to be
applied. This should be in the syntax allowed for the first argument
of \gls{ifthenelse} (see \sectionref{sec:ifthen}). Note that if this
option is provided, it will override the \plotopt{include-if} or
\plotopt{include-if-fn} setting.

The \plotopt{x} and \plotopt{y} settings should be a comma-separated
list of column keys identifying the columns to use for the $x$ and
$y$ co-ordinates. They must both have at least one element, and the
number of elements in \plotopt{x} must be less than or equal to the
number of elements in \plotopt{y}. Spaces and empty items are
skipped. For example, \code{\plotoptvalm{y}{ Exp1,, Exp2 ,}}
is equivalent to \code{\plotoptvalm{y}{Exp1,Exp2}}. However,
\code{\plotoptvalm{y}{Exp1,\marg{},Exp2}} specifies an empty key in the
second item which is invalid.

There is also a corresponding action:
\actiondef{plot}
The \actionopt{name} should be set to the database name or list of
names \meta{db-list}, and \actionopt{options} should be the
\keyvallist\ plot settings. If the \actionopt{name} is omitted, the
default database is assumed.
\begin{compactcodebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{\meta{db-list}},\actionoptvalm{options}{\keyvallist}}\marg{\action{plot}}
\end{compactcodebox}
The above is equivalent to:
\begin{compactcodebox}
\gls{DTLplot}\margm{db-list}\marg{\keyvallist}
\end{compactcodebox}
Note that you can't use any of the
usual action column identifiers, such as \actionopt{keys}, as they
need to be separated into the \plotopt{x} and \plotopt{y} lists.

The primary return value is the total number of plot streams. This
will be 0 if an error occurred. The secondary return values will
only be set if no errors occurred while parsing the settings:
\begin{itemize}
\item \optfmt{min-x}: the value of \gls{DTLminX} within the plot; 
\item \optfmt{min-y}: the value of \gls{DTLminY} within the plot;
\item \optfmt{max-x}: the value of \gls{DTLmaxX} within the plot; 
\item \optfmt{max-y}: the value of \gls{DTLmaxY} within the plot; 
\item \optfmt{stream-count}: the total number of plot streams (same
as the primary return value);
\item \optfmt{x-count}: the total number of \plotopt{x} column keys;
\item \optfmt{y-count}: the total number of \plotopt{y} column keys;
\item \optfmt{name-count}: the total number of databases provided in
the \actionopt{name} option.
\end{itemize}

For both \gls{DTLplot} and the \action{plot} action,
each plot stream is constructed in the following order:
\begin{enumerate}
\item For each database listed in \meta{db-list}:

\item If the \plotopt{group-styles} setting indicates that the marker or
line styles or colours should apply to each database, the next style in the
sequence will be selected, as applicable. Otherwise, if the
corresponding \plotopt{style-resets} option is on, the setting will
be reset back to the applicable \plotopt{marks}, \plotopt{lines},
\plotopt{mark-colors} or \plotopt{line-colors} value.

  \begin{enumerate}
    \item For each \meta{y-key} in \plotopt{y}:

    \begin{enumerate}
      \item If the \meta{pending-x} list is empty, it's repopulated
      with the \plotopt{x} list of column keys. (This means you can
      have a single \plotopt{x} column plotted against multiple
      \plotopt{y} columns. However, be careful if you have more
      than one element in the \plotopt{x} list but less than the total number
      of elements in the \plotopt{y} list, see
      \exampleref{ex:growthscatter6col2db2x3y}.)

     \item The first \meta{x-key} is popped off the \meta{pending-x}
       list.

     \item A plot stream is constructed from the $(x,y)$
     co-ordinates supplied by the \meta{x-key} and \meta{y-key}
     columns, omitting any that don't match the provided conditional
     or filter function and any that lie outside the plot bounds.

     \item If the \plotopt{group-styles} setting indicates that the marker or
     line styles or colours should be applied to each stream,
     the next setting in the sequence is selected. (See the examples
     in \sectionref{sec:plotstyleexs}.)

     \item The stream will be drawn with lines, if applicable.

     \item The stream will be drawn with markers, if applicable.

     \item If applicable, the stream will be added to the legend with the label
     obtained from the corresponding item in the \plotopt{legend-labels}
     option or the default label, if omitted. Note that an empty
     label will cause the corresponding plot stream to be omitted
     from the legend, but bear in mind that the \keyval\ list parser
     will strip empty items, so you will need to explicitly group
     the empty value, if applicable. See
     \sectionref{sec:plotlegendexs} for examples.

    \end{enumerate}
  \end{enumerate}
\end{enumerate}

The bounding box, grid, axes, tick marks, tick labels and axis labels
are drawn first, if applicable. The legend is drawn last, if
applicable. The hook \gls{DTLplotatbegintikz} occurs at the start,
and \gls{DTLplotatendtikz} at the end.

\section{Plot Settings}
\label{sec:plotsettings}

The plot settings may be provided in the final \meta{settings}
argument of \gls{DTLplot} or the \actionopt{options} value for the
\action{plot} action or set with the \inlineoptdef{plot} option in
\gls{DTLsetup}. For example, to set defaults:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{plot}{\plotopt{grid},\plotoptval{tick-dir}{in}}}
\end{codebox}
To override the defaults for a specific plot:
\begin{codebox}
\gls{DTLplot}\marg{mydata}\marg{\plotoptval{x}{Time},\plotoptval{y}{Temperature},\plotopt{legend}}
\end{codebox}
Alternatively, using the \action{plot} action:
\begin{codebox}
\gls{DTLaction}\oarg{
  \actionopt{name}{mydata},
  \actionoptvalm{options}{\plotoptval{x}{Time},\plotoptval{y}{Temperature},\plotopt{legend}}
}
\marg{\action{plot}}
\end{codebox}

\subsection{Database Content}
\label{sec:plotdbsettings}

\optiondef{plot.x}
The list of column keys to use for $x$ co-ordinates. This setting is
required. There must be at least one item and no more than the total
number of items in \plotopt{y}.

\optiondef{plot.y}
The list of column keys to use for $y$ co-ordinates. This setting is
required. There must be at least one item.

\optiondef{plot.extra-assign}
If set, the \idx{assign-list} will be passed to \gls+{DTLmapgetvalues} when
\gls{DTLplot} loops through each row of the database using
\gls{DTLmapdata}. The placeholder commands identified in the
assignment list can be used in the filter condition.
Alternatively, you can simply use \gls{DTLmapget} in the filter
function \plotopt{include-if} or \plotopt{include-if-fn} (but not in
the optional \meta{condition} argument of \gls{DTLplot} which needs
to expand).

\optiondef{plot.include-if}
The value should be the definition (expansion text) for a command
that takes a single argument. The command should do \code{\#1} 
for any row that should have its $x$ and $y$ values
included in the plot, and do nothing otherwise.

\optiondef{plot.include-if-fn}
An alternative to \plotopt{include-if}, this sets the filter
function to \meta{cs} rather than providing the function definition.

\begin{information}
The \plotopt{include-if} and \plotopt{include-if-fn} override each
other, but both
will be ignored if the \meta{condition} optional
argument is provided with \gls{DTLplot}. Either use one form or the
other. Don't use both.
\end{information}

For example, suppose the database \qt{results} has columns with
labels \qt{Time}, \qt{Temperature} and \qt{Notes} where the notes
column is set to \qt{Incorrect} for rows where the measurement was
incorrect. These rows can be excluded:
\begin{codebox}
\gls{DTLplot}\marg{results}
\marg{
  \plotoptval{x}{Time},
  \plotoptval{y}{Temperature},
  \plotoptvalm{extra-assign}{\cmd{Notes}=Notes},
  \plotoptvalm{include-if}{
   \gls{DTLifstringeq}\marg{\cmd{Notes}}\marg{Incorrect}\marg{}\marg{\#1}
  }
}
\end{codebox}
This uses \gls{DTLifstringeq}, which expands its arguments, to test value of
the placeholder command. Note that while you can use
\sty{etoolbox}['s] \gls{ifdefstring} with the default
\optval{store-datum}{false}, it won't work with
\optval{store-datum}{true} as then \csfmt{Notes} will be a
\idx{datumcs}.

\subsection{Plot Size}
\label{sec:plotsizesettings}

\optiondef{plot.width}
The total width of the plot.

\optiondef{plot.height}
The total height of the plot.

\optiondef{plot.bounds}
The plot bounds. If not set, the bounds will be determined by the
data. Instead of setting all the bounds in one go, you can also set
them individually using the following options. Any missing options
will be calculated from the data.

\optiondef{plot.min-x}
The lower $x$ bound.

\optiondef{plot.minx}
A synonym of \plotopt{min-x}.

\optiondef{plot.min-y}
The lower $y$ bound.

\optiondef{plot.miny}
A synonym of \plotopt{min-y}.

\optiondef{plot.max-x}
The upper $x$ bound.

\optiondef{plot.maxx}
A synonym of \plotopt{max-x}.

\optiondef{plot.max-y}
The upper $x$ bound.

\optiondef{plot.maxy}
A synonym of \plotopt{max-y}.

\subsection{Marker and Line Styles}
\label{sec:plotstylesettings}

Note that the \keyval\ parser strips leading and trailing spaces and
empty items so for example, \code{blue, red,,green,} is converted to
\code{blue,red,green}. This means that if you explicitly need an
empty item, you must group it. For example:
\code{blue,red,\marg{},green}.

The default colour indicates the default for \env{tikzpicture}. This
can be changed in the \gls{DTLplotatbegintikz} hook.

\optiondef{plot.legend}
Indicates where to draw the legend. The value may be one of:
\optfmt{none} (no legend), \optfmt{north}, \optfmt{northeast},
\optfmt{east}, \optfmt{southeast}, \optfmt{south},
\optfmt{southwest}, \optfmt{west}, \optfmt{northwest} or
\optfmt{custom}. If you use \plotoptval{legend}{custom}, you will
need to redefine \gls{DTLcustomlegend} to position the legend in the
required place.

\optiondef{plot.legend-labels}
Comma-separated list of text to supply for each row of the plot
legend. If omitted, the legend text will be formed from the database
name or column key, depending on how many databases or columns have
been selected for the plot. Note that an empty
label will cause the corresponding plot stream to be omitted
from the legend, but bear in mind that the \keyval\ list parser
will strip empty items, so you will need to explicitly group
the empty value, if applicable. For example, in the following:
\begin{compactcodebox}
\plotoptvalm{legendlabels}{Experiment1,,Experiment2}
\end{compactcodebox}
the empty item will be stripped by the parser and it will be
equivalent to:
\begin{compactcodebox}
\plotoptvalm{legendlabels}{Experiment1,Experiment2}
\end{compactcodebox}
However, with the following:
\begin{compactcodebox}
\plotoptvalm{legendlabels}{Experiment1,\marg{},Experiment2}
\end{compactcodebox}
The first and third plot streams will be added to the legend but the
second won't.

\optiondef{plot.legendlabels}
A synonym of \plotopt{legend-labels}.

\optiondef{plot.legend-offset}
The legend offset may be a single value, in which case it applies to both
$x$ and $y$ offsets, or two values: the $x$ offset and $y$ offset.

\optiondef{plot.style}
Indicates whether to show markers, draw lines or both.
Available values: \optfmt{markers} (only markers, no lines),
\optfmt{lines} (only lines, no markers), or \optfmt{both} (lines and
markers).

If you want some plot streams within the same \gls{DTLplot} to have
markers only and some to have lines only, then use
\plotoptval{style}{both} and use \gls{relax} or \code{\marg{}} for the
corresponding item in \plotopt{marks} or \plotopt{lines}.
For example:
\begin{codebox*}
\plotoptval{style}{both},
\plotoptvalm{lines}{
  \gls{pgfsetdash}\marg{}\marg{0pt},\comment{solid line}
  \gls{relax},\comment{no line}
  \gls{pgfsetdash}\marg{\marg{10pt}\marg{5pt}}\marg{0pt},\comment{dashed}
  \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}}\marg{0pt},\comment{dashed}
  \gls{relax},\comment{no line}
  \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}\marg{1pt}\marg{5pt}}\marg{0pt},\comment{dash dot}
 },
\plotoptvalm{marks}{
   \gls{relax},\comment{no marker}
   \gls{pgfuseplotmark}\marg{o},\comment{circle marker}
   \gls{pgfuseplotmark}\marg{x},\comment{cross marker}
   \gls{relax},\comment{no marker}
   \gls{pgfuseplotmark}\marg{+},\comment{plus marker}
   \gls{pgfuseplotmark}\marg{asterisk},\comment{asterisk marker}
 }
\end{codebox*}

\optiondef{plot.style-resets}
If \plotopt{group-styles} setting isn't on for a particular style
(line style, line colour, marker style or marker colour), then the style will
either cycle through the corresponding list, wrapping round whenever
the end of the list is reached, or will reset at the start of each
database, according to the \plotopt{style-resets} setting.

This is a multiple choice setting so you can combine allowed values
in \meta{settings}.

\optionvaldef{plot.style-resets}{none}
None of the styles will be reset at the start of each database.

\optionvaldef{plot.style-resets}{all}
All of the styles will be reset at the start of each database unless
the \plotopt{group-styles} setting applies.

This setting is equivalent to \plotoptvalm{style-resets}
{\plotstyleresetval{mark-style}, 
\plotstyleresetval{mark-color}, 
\plotstyleresetval{line-style}, 
\plotstyleresetval{line-color}}.

\optionvaldef{plot.style-resets}{mark-style}
The plot marks listed in \plotopt{marks} will be reset at the start
of each database, unless \plotgroupstyleval{mark-style} has been
set.

\optionvaldef{plot.style-resets}{mark-color}
The plot mark colours listed in \plotopt{mark-colors} will
be reset at the start of each database, unless
\plotgroupstyleval{mark-color} has been set.

\optionvaldef{plot.style-resets}{line-style}
The line styles listed in \plotopt{lines} will be reset at
the start of each database, unless \plotgroupstyleval{line-style}
has been set.

\optionvaldef{plot.style-resets}{line-color}
The line colours listed in \plotopt{line-colors} will be
reset at the start of each database, unless
\plotgroupstyleval{line-color} has been set.

\optiondef{plot.group-styles}
Indicates whether each item the marker and line styles should be
the same for each database.

This is a multiple choice setting so you can combine allowed values
in \meta{settings}.

\optionvaldef{plot.group-styles}{none}
None of the styles are applied per-database. Each style setting
(\plotopt{marks}, \plotopt{mark-colors}, \plotopt{lines} and
\plotopt{line-colors}) will be reset or cycled round for each plot stream
according to the \plotopt{style-resets} setting.

\optionvaldef{plot.group-styles}{all}
All of the styles are applied per-database. Multiple plot streams from a single
database will have the same styles.

This setting is equivalent to \plotoptvalm{group-styles}
{\plotgroupstyleval{mark-style}, 
\plotgroupstyleval{mark-color}, 
\plotgroupstyleval{line-style}, 
\plotgroupstyleval{line-color}}.

\optionvaldef{plot.group-styles}{line-style}
The line style will be applied per-database. Multiple plot streams
from a single database will use the same line style.

\optionvaldef{plot.group-styles}{line-color}
The line colour will be applied per-database. Multiple plot streams
from a single database will use the same line colour.

\optionvaldef{plot.group-styles}{mark-style}
The marker style will be applied per-database. Multiple plot streams
from a single database will use the same marker.

\optionvaldef{plot.group-styles}{mark-color}
The marker colour will be applied per-database. Multiple plot streams
from a single database will use the same marker colour.

\optiondef{plot.colors}
Equivalent to \plotoptval{line-colors}{\meta{colour-list}},
\plotoptval{mark-colors}{\meta{colour-list}}.

\optiondef{plot.line-colors}
The value should be a comma-separated list of colour names (suitable
for use in the argument of \gls{color}) to apply to the
corresponding plot line style given in \plotopt{lines}. An empty item
\marg{} or \gls{relax} indicates that no colour change should
apply to that line (so the line will be black unless the default
colour is changed). This setting simply redefines
\gls{DTLplotlinecolors} to the supplied value.

This setting has no effect if no plot lines should be shown
(\plotoptval{style}{markers}).

\optiondef{plot.linecolors}
A synonym of \plotopt{line-colors}.

\optiondef{plot.lines}
The value should be a comma-separated list of line styles (specified
with \gls{pgfsetdash}). An empty item \marg{} or \gls{relax}
indicates that lines should be omitted for the corresponding plot
stream. This setting simply redefines \gls{DTLplotlines} to the
supplied value.

This setting has no effect if no plot lines should be shown
(\plotoptval{style}{markers}).

\optiondef{plot.mark-colors}
The value should be a comma-separated list of colour names (suitable
for use in the argument of \gls{color}) to apply to the
corresponding plot mark given in \plotopt{marks}. An empty item
\marg{} or \gls{relax} indicates that no colour change should
apply to that marker (so the marker will be black unless the default
colour is changed). This setting simply redefines
\gls{DTLplotmarkcolors} to the supplied value.

This setting has no effect if no plot markers should be shown
(\plotoptval{style}{lines}).

\optiondef{plot.markcolors}
A synonym of \plotopt{mark-colors}.

\optiondef{plot.marks}
The value should be a comma-separated list of plot markers
(specified with \gls{pgfuseplotmark}). An empty item
\marg{} or \gls{relax} indicates that markers should be omitted
for the corresponding plot stream. This setting simply redefines
\gls{DTLplotmarks} to the supplied value.

This setting has no effect if no plot markers should be shown
(\plotoptval{style}{lines}).

\subsection{Axes}
\label{sec:plotaxessettings}

By default, the tick marks will be automatically generated from the
data bounds (which will either be determined from the maximum and
minimum values in the data or by options such as \plotopt{bounds}).
If no gap is explicitly set (with \plotopt{x-tick-gap} or
\plotopt{y-tick-gap})
then the gap between major tick marks is calculated according to an
algorithm that's based on the maximum and minimum values and the
minimum gap length (as an absolute dimension) given by
\gls{DTLmintickgap}. There is a similar length
\gls{DTLminminortickgap} for the suggested minimum distance between
minor tick marks.

If an exact set of the major tick marks is required, the desired co-ordinates
can be set with \plotopt{x-tick-points} (for the $x$-axis) and
\plotopt{y-tick-points} (for the $y$-axis). These should be a
comma-separated list of \idxpl{plainnumber} in data units. This will
override the above tick mark algorithm and the gap setting will be
ignored. The minor minimum distance will still be referenced if minor tick
marks are required.

The tick mark labels will then be obtained from the tick mark values
and converted to decimal \idxpl{datumitem}, where the string part is the
\idxpl{formattednumber} corresponding to the tick mark value (with
rounding applied according to the applicable rounding setting).

The $x$-tick mark labels will be encapsulated with
\gls{DTLplotdisplayXticklabel}, and the $x$-tick mark labels will be
encapsulated with \gls{DTLplotdisplayYticklabel}. Both these
commands default to using \gls{DTLplotdisplayticklabel} so only that
command needs redefining if the same formatting should be used for
both $x$ and $y$ tick labels.

\begin{important}
If you override the tick mark labels with \plotopt{x-tick-labels}
or \plotopt{y-tick-labels} then the tick labels will no longer be
\idxpl{datumitem}, but will be the corresponding label in the
supplied setting. The tick label will still be encapsulated with the
corresponding formatting command.
\end{important}

\optiondef{plot.axes}
Determines whether or not to display the axes.

\optionvaldef{plot.axes}{both}
Switches on $x$ and $y$ axes and $x$ and $y$ ticks.

\optionvaldef{plot.axes}{none}
Switches off $x$ and $y$ axes and $x$ and $y$ ticks.

\optionvaldef{plot.axes}{x}
Switches on $x$ axis and $x$ ticks, and
switches off $y$ axis and $y$ ticks.

\optionvaldef{plot.axes}{y}
Switches on $y$ axis and $y$ ticks, and
switches off $x$ axis and $x$ ticks.

\optiondef{plot.omit-zero-label}
If either axis includes a tick mark at zero, this option determines
whether or not that tick mark should have a label.

\begin{warning}
If you explicitly set the tick labels and this option is set to omit zero,
then the tick label corresponding to zero will be ignored, but must still be
set to prevent the labels from shifting out of sync.
\end{warning}

\optionvaldef{plot.omit-zero-label}{auto}
Determines whether or not to show the zero tick labels based on
whether the axes cross at zero. Note that this doesn't take the axis
extensions into account.

\optionvaldef{plot.omit-zero-label}{both}
Omit the tick labels at $x=0$ and $y=0$.

\optionvaldef{plot.omit-zero-label}{x}
Omit the tick label at $x=0$. If there happens to be a tick mark at
$y=0$, the $y=0$ label will be shown.

\optionvaldef{plot.omit-zero-label}{y}
Omit the tick label at $y=0$. If there happens to be a tick mark at
$x=0$, the $x=0$ label will be shown.

\optionvaldef{plot.omit-zero-label}{false}
Don't omit the tick label at $x=0$ and $y=0$, if there are tick
marks at those locations.

\optiondef{plot.side-axes}
If true, the axes will be drawn at the minimum plot bounds
(not taking the axis extension into account). If false, the axes
will intersect at zero if that is within the plot bounds, otherwise
the axes will be drawn at the minimum plot bounds.

If zero doesn't lie within the plot bounds, then setting will only
make a difference if you have the \plotopt{box} and tick marks. 
With \plotopt{side-axes}{true}, tick marks will be drawn along the
top and right sides of the box. This will only be noticeable if
you have extended the axes. With \plotopt{side-axes}{false},
tick marks will be drawn along all sides of the box.

\optiondef{plot.x-axis-style}
Sets the line style for the $x$-axis. The given \meta{value} should
be valid \sty{tikz} options. For example,
\plotoptvalm{x-axis-style}{->,thick} for a thick line with an arrow
head.

\optiondef{plot.y-axis-style}
Sets the line style for the $y$-axis. The given \meta{value} should
be valid \sty{tikz} options.

\optiondef{plot.axis-style}
Shortcut that sets the line style for both the $x$-axis and
$y$-axis. This is equivalent to
\code{\plotoptvalm{x-axis-style}{\meta{value}},
\plotoptvalm{y-axis-style}{\meta{value}}}.

\optiondef{plot.extend-x-axis}
Extends the $x$ axis by the given values beyond the plot bounds.
If only one value is provided, the axis is extended by the same
amount at both ends. Otherwise, the axis is extended to the left by
\meta{lower extent} and to the right by \meta{upper extent}.

This option affects the length of the $x$-axis, the location of the
lower and upper $x$ labels, and the size of the
encapsulating box if \plotoptval{box}{true}. The values should
be in data co-ordinates. A positive value extends the axis. 
A negative value shortens it.

\begin{warning}
If you shorten the axis with the tick mark setting on, this may
result in detached tick marks beyond the shortened axis.
The $x$-axis length will end up less than \gls{DTLplotwidth} (set
with \plotopt{width}).

Extending the axis may result in it overlapping a tick label.
The $x$-axis length will end up greater than \gls{DTLplotwidth}.
\end{warning}

\optiondef{plot.extend-y-axis}
Extends the $y$ axis by the given values beyond the plot bounds.
If only one value is provided, the axis is extended by the same
amount at both ends. Otherwise, the axis is extended to the left by
\meta{lower extent} and to the right by \meta{upper extent}.

This option affects the length of the $y$-axis, the location of the
lower and upper $y$ labels, and the size of the
encapsulating box if \plotoptval{box}{true}. The values should
be in data co-ordinates. A positive value extends the axis. 
A negative value shortens it.

\begin{warning}
If you shorten the axis with the tick mark setting on, this may
result in detached tick marks beyond the shortened axis.
The $y$-axis length will end up less than \gls{DTLplotheight} (set
with \plotopt{height}).

Extending the axis may result in it overlapping a tick label.
The $y$-axis length will end up greater than \gls{DTLplotheight}.
\end{warning}

\optiondef{plot.extend-axes}
Equivalent to:
\begin{codebox}
\plotoptvalm{extend-x-axis}{\meta{lower extent},\meta{upper extent}}, 
\plotoptvalm{extend-y-axis}{\meta{lower extent},\meta{upper extent}}
\end{codebox}
Again a single value may be supplied if the lower and upper extent
are the same.

\optiondef{plot.box}
If true, the plot will be enclosed in a box. This takes the axis
extensions into account.

\optiondef{plot.box-ticks}
If \plotoptval{box}{true}, this setting determines which direction
to draw the tick marks.

\begin{warning}
If tick marks are drawn, they don't take the axis extensions into
account. This can lead to detached tick marks outside of the box if
the axes have been shortened.
\end{warning}

\optionvaldef{plot.box-ticks}{none}
Don't draw tick marks on the box.

\optionvaldef{plot.box-ticks}{match-axes}
Match the tick direction used on the axes. That is, if the axis tick
marks point inwards then so will the tick marks on the box.

\optionvaldef{plot.box-ticks}{in}
The tick marks on the box will point inwards.

\optionvaldef{plot.box-ticks}{out}
The tick marks on the box will point outwards.

\optiondef{plot.grid}
If true, the plot will have a grid in the background.
The minor grid lines will only be drawn if the corresponding minor
tick mark setting is also on and \gls{DTLminorgridstyle}
(\plotopt{minor-grid-style}) has a non-empty definition.

\optiondef{plot.major-grid-style}
Sets the style for the major grid lines. The given \meta{value} should
be valid \sty{tikz} options. This option simply redefines
\gls{DTLmajorgridstyle} to the given \meta{value}.

\optiondef{plot.minor-grid-style}
Sets the style for the minor grid lines. The given \meta{value} should
be valid \sty{tikz} options. This option simply redefines
\gls{DTLminorgridstyle} to the given \meta{value}.

\optiondef{plot.xlabel}
Sets the mid $x$-axis label. This label is positioned mid-way (using
the plot bounds not including the axis extension) along
the $x$-axis, below the tick labels.

\optiondef{plot.x-label}
Synonym of \plotopt{xlabel}.

\optiondef{plot.ylabel}
Sets the mid $y$-axis label. This label is positioned mid-way (using
the plot bounds not including the axis extension) along
the $y$-axis, to the left of the tick labels.

\optiondef{plot.y-label}
Synonym of \plotopt{ylabel}.

\optiondef{plot.min-x-label}
Sets the text for the lower $x$-axis label. This is positioned at the
minimum end of the $x$-axis, taking the axis extension into account.

\optiondef{plot.min-x-label-style}
Sets the \sty{tikz} node style for the lower $x$-axis label.

\optiondef{plot.max-x-label}
Sets the text for the upper $x$-axis label. This is positioned at the
maximum end of the $x$-axis, taking the axis extension into account.

\optiondef{plot.max-x-label-style}
Sets the \sty{tikz} node style for the upper $x$-axis label.

\optiondef{plot.min-y-label}
Sets the text for the lower $y$-axis label. This is positioned at the
minimum end of the $y$-axis, taking the axis extension into account.

\optiondef{plot.min-y-label-style}
Sets the \sty{tikz} node style for the lower $y$-axis label.

\optiondef{plot.max-y-label}
Sets the text for the upper $y$-axis label. This is positioned at the
maximum end of the $y$-axis, taking the axis extension into account.

\optiondef{plot.max-y-label-style}
Sets the \sty{tikz} node style for the upper $y$-axis label.

\optiondef{plot.round}
Equivalent to \code{\plotoptval{round-x}{\meta{}n},
\plotoptval{round-y}{\meta{}n}}.

\optiondef{plot.round-x}
Sets the number of digits to round the $x$ tick labels (when no
label provide with \plotopt{x-tick-labels}).

\optiondef{plot.round-y}
Sets the number of digits to round the $y$ tick labels (when no
label provide with \plotopt{y-tick-labels}).

\optiondef{plot.ticks}
A shortcut for \code{\plotoptval{x-ticks}{\meta{boolean}},
\plotoptval{y-ticks}{\meta{boolean}}}.

\optiondef{plot.tics}
Synonym for \plotopt{ticks}.

\optiondef{plot.minor-ticks}
A shortcut for \code{\plotoptval{x-minor-ticks}{\meta{boolean}},
\plotoptval{y-minor-ticks}{\meta{boolean}}}.

\optiondef{plot.minortics}
Synonym for \plotopt{minor-ticks}.

\optiondef{plot.tick-label-style}
A shortcut for:
\begin{compactcodebox}
\plotoptvalm{x-tick-label-style}{\meta{value}},
\plotoptvalm{y-tick-label-style}{anchor\dequals east, \meta{value}}
\end{compactcodebox}

\optiondef{plot.tic-label-style}
Synonym of \plotopt{tick-label-style}.

\optiondef{plot.tick-label-offset}
Sets the offset for the tick labels. This option simply changes the
value of the length register \gls{DTLticklabeloffset}.

\optiondef{plot.tick-dir}
A shortcut for \code{\plotoptval{x-tick-dir}{\meta{value}},
\plotoptval{y-tick-dir}{\meta{value}}}.

\optiondef{plot.ticdir}
Synonym for \plotopt{tick-dir}.

\optiondef{plot.tick-gap}
A shortcut for \code{\plotoptval{x-tick-gap}{\meta{value}},
\plotoptval{y-tick-gap}{\meta{value}}}.

\optiondef{plot.ticgap}
Synonym for \plotopt{tick-gap}.

\optiondef{plot.x-ticks}
Indicates whether or not to draw $x$ ticks.

\optiondef{plot.xtics}
Synonym for \plotopt{x-ticks}.

\optiondef{plot.x-tick-label-style}
Sets the \sty{tikz} node style for the $x$-axis tick labels.

\optiondef{plot.x-tic-label-style}
Synonym for \plotopt{x-tick-label-style}.

\optiondef{plot.x-minor-ticks}
Indicates whether or not to draw minor $x$ ticks.
Note that \plotoptval{x-minor-ticks}{true} also implements 
\plotoptval{x-ticks}{true}, but \plotoptval{x-minor-ticks}{false}
doesn't alter the \plotopt{x-ticks} setting.

\optiondef{plot.xminortics}
Synonym for \plotopt{x-minor-ticks}.

\optiondef{plot.x-tick-dir}
Indicates whether the $x$ ticks should be drawn inwards
(\plotoptval{x-tick-dir}{in}) or outwards (\plotoptval{x-tick-dir}{out}).

\optiondef{plot.xticdir}
Synonym for \plotopt{x-tick-dir}.

\optiondef{plot.x-tick-gap}
Sets the gap (in data co-ordinates) for the $x$-tick marks. If the
value is not empty, 
this option will automatically enable $x$-ticks and the $x$-axis.
Note that \plotopt{x-tick-points} overrides
this option.

\optiondef{plot.xticgap}
Synonym for \plotopt{x-tick-gap}.

\optiondef{plot.x-tick-labels}
A list of labels for the $x$-ticks. If the value is not empty, 
this option will automatically enables $x$ ticks and the $x$-axis. 
Note that the parser will automatically
trim spaces and remove empty items, so if you want some tick marks
to be unlabelled then you will need an empty group. For example,
\plotoptvalm{x-tick-labels}{0,\marg{},2,\marg{},4}.

\optiondef{plot.xticlabels}
Synonym for \plotopt{x-tick-labels}.

\optiondef{plot.x-tick-points}
A comma-separated list of \idxpl{plainnumber} in data co-ordinates
for the $x$ tick marks. If the value is non-empty, this option will
automatically enable $x$-ticks and the $x$-axis 
and will override the \plotopt{x-tick-gap} setting.

\begin{information}
Any tick marks in \plotopt{x-tick-points} that are outside of the plot
bounds (\plotopt{minx} and \plotopt{maxx}) will be omitted.
\end{information}

\optiondef{plot.xticpoints}
Synonym for \plotopt{x-tick-points}.

\optiondef{plot.y-ticks}
Indicates whether or not to draw $y$ ticks.

\optiondef{plot.ytics}
Synonym for \plotopt{y-ticks}.

\optiondef{plot.y-tick-label-style}
Sets the \sty{tikz} node style for the $y$-axis tick labels.

\optiondef{plot.y-tic-label-style}
Synonym for \plotopt{y-tick-label-style}.

\optiondef{plot.y-minor-ticks}
Indicates whether or not to draw minor $y$ ticks.
Note that \plotoptval{y-minor-ticks}{true} also implements 
\plotoptval{y-ticks}{true}, but \plotoptval{y-minor-ticks}{false}
doesn't alter the \plotopt{y-ticks} setting.

\optiondef{plot.yminortics}
Synonym for \plotopt{y-minor-ticks}.

\optiondef{plot.y-tick-dir}
Indicates whether the $y$ ticks should be drawn inwards
(\plotoptval{y-tick-dir}{in}) or outwards (\plotoptval{y-tick-dir}{out}).

\optiondef{plot.yticdir}
Synonym for \plotopt{y-tick-dir}.

\optiondef{plot.y-tick-gap}
Sets the gap (in data co-ordinates) for the $y$-tick marks. If the
value is not empty, 
this option will automatically enable $y$ tick marks and the
$y$-axis. Note that \plotopt{y-tick-points} overrides
this option.

\optiondef{plot.yticgap}
Synonym for \plotopt{y-tick-gap}.

\optiondef{plot.y-tick-labels}
A list of labels for the $y$-ticks. If the value is not empty, 
this option will automatically enable $y$ tick marks and the
$y$-axis. Note that the parser will automatically
trim spaces and remove empty items, so if you want some tick marks
to be unlabelled then you will need an empty group. For example,
\plotoptvalm{y-tick-labels}{0,\marg{},2,\marg{},4}.

\optiondef{plot.yticlabels}
Synonym for \plotopt{y-tick-labels}.

\optiondef{plot.y-tick-points}
A comma-separated list of \idxpl{plainnumber} in data co-ordinates
for the $y$ tick marks. If the value is non-empty, this option will
automatically set enable $y$-tick marks and the $y$-axis and will
override the \plotopt{y-tick-gap} setting.

\begin{information}
Any tick marks in \plotopt{y-tick-points} that are outside of the plot
bounds (\plotopt{miny} and \plotopt{maxy}) will be omitted.
\end{information}

\optiondef{plot.yticpoints}
Synonym for \plotopt{y-tick-points}.

\section{Plot Examples}
\label{sec:plotexs}

The examples in this section use the \qt{time to growth} data,
described in \sectionsref{sec:growthcsv,sec:growthtsv}, and the
\qt{xydata} database, described in \sectionref{sec:xydatacsv}. 

The time to growth data represents hypothetical microbiological
experiments observing microbial populations after certain time
intervals at a particular temperature. The population figures are
actually recorded as the log count, rather than the actual count.
The \sty{dataplot} package does support logarithmic axes. The sample
data is simply a list of numbers to demonstrate how to use
\gls{DTLplot}.

\subsection{Basic Examples}
\label{sec:scatterplotexs}

The examples in this section demonstrate basic use.  They set the
$x$-axis label with \plotopt{x-label} and the $y$-axis label with
\plotopt{y-label}.  The width and height are also set to produce a
smaller image than the default setting. 

For examples demonstrating how to adjust the legend text or move it
to a different position, see \sectionref{sec:plotlegendexs}. For
examples demonstrating how to have line plots or change the colours,
see \sectionref{sec:plotstyleexs}.

\subsubsection{One Database}
\label{sec:scatterplot1dbex}

\mExampleref{ex:growthscatter1} plots the data from
the \qt{growth1} database (see \sectionref{sec:growthcsv}). The
horizontal $x$-axis
corresponds to the \optfmt{Time} column. The vertical $y$-axis corresponds
to the \optfmt{Experiment~1} and \optfmt{Experiment~2} columns which
has the observations at the given point in time. The
\plotopt{legend} setting helps to distinguish between the two
data streams.
\begin{codebox}
\gls{DTLplot}\marg{growth1}\marg{
 \plotoptval{x}{Time}, \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter1},
  title={Scatter Plot (One Database)},
  tag={growth}, link={sec:scatterplot1dbex},
  description={An example document that plots data of time against
observations from two experiments}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}
}
{
\gls{DTLplot}\marg{growth1}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Two Databases, One X Column}
\label{sec:scatterplot2db1xcolex}

\mExampleref{ex:growthscatter2} modifies
\exampleref{ex:growthscatter1} to include the \qt{growth2} data as
well.
\begin{codebox}
\gls{DTLplot}\marg{growth1,growth2}\marg{
 \plotoptval{x}{Time}, \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter2},
  title={Scatter Plot (Two Databases)},
  tag={growth},link={sec:scatterplot2db1xcolex},
  description={An example document that plots data of time against
observations from two experiments}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2}\marg{growth2.csv}
}
{
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Plot Action}
\label{sec:scatterplotactionex}

\mExampleref{ex:growthscatteraction} is an alternative to
\exampleref{ex:growthscatter2} that uses the \action{plot} action
instead of explicitly using \gls{DTLplot}.
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{growth1,growth2},
 \actionoptvalm{options}{
  \plotoptval{x}{Time}, \plotoptvalm{y}{Experiment 1,Experiment 2},
  \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
  \plotopt{legend}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
 }
}\marg{\action{plot}}
\end{codebox}
The return values can then be accessed:
\begin{codebox}
Number of streams: \gls{DTLuse}\marg{stream-count}.
Minimum X: \gls{DTLuse}\marg{min-x}.
Minimum Y: \gls{DTLuse}\marg{min-y}.
Maximum X: \gls{DTLuse}\marg{max-x}.
Maximum Y: \gls{DTLuse}\marg{max-y}.
\end{codebox}
Alternatively, you can use the \actionopt{return} setting:
\begin{codebox}
\gls{DTLaction}\oarg{\actionoptvalm{name}{growth1,growth2},
 \actionoptvalm{options}{
  \plotoptval{x}{Time},
  \plotoptvalm{y}{Experiment 1,Experiment 2},
  \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
  \plotopt{legend}, \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
 },
 \actionoptvalm{return}{
  \cmd{theMinX}=min-x, \cmd{theMinY}=min-y,
  \cmd{theMaxX}=max-x, \cmd{theMaxY}=max-y,
  \cmd{NumStreams}=stream-count
 }
}\marg{\action{plot}}
\codepar
Number of streams: \cmd{NumStreams}.
Minimum X: \cmd{theMinX}.  Minimum Y: \cmd{theMinY}.
Maximum X: \cmd{theMaxX}.  Maximum Y: \cmd{theMaxY}.
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatteraction},
  title={Scatter Plot (Action)},
  tag={growth},link={sec:scatterplotactionex},
  description={An example document that plots data of time against
observations from two experiments using the plot action}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}
}
{%
\gls{DTLaction}\oarg{\actionoptvalm{name}{growth1,growth2},\nlsp
 \actionoptvalm{options}{\nldbsp
  \plotoptval{x}{Time},\nldbsp
  \plotoptvalm{y}{Experiment 1,Experiment 2},\nldbsp
  \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log
Count},\nldbsp
  \plotopt{legend},\nldbsp
  \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nlsp
 }\nl
}\marg{\action{plot}}
\codepar
Number of streams: \gls{DTLuse}\marg{stream-count}.\nl
\codepar
Minimum X: \gls{DTLuse}\marg{min-x}.\nl
Minimum Y: \gls{DTLuse}\marg{min-y}.\nl
Maximum X: \gls{DTLuse}\marg{max-x}.\nl
Maximum Y: \gls{DTLuse}\marg{max-y}.\nl
}
\end{resultbox}

\subsubsection{One Database, Two X and Y Columns}
\label{sec:scatterplot1db2xycolex}

\mExampleref{ex:growthscatter4col} plots the data from the
\qt{growthdata} database (see \sectionref{sec:growthtsv})
which is read from a \idx{TSV} file that has four columns.
The first two (\optfmt{Exp1Time} and \optfmt{Exp1Count})
are the time and log count data from the first experiment and
the last two (\optfmt{Exp2Time} and \optfmt{Exp2Count})
are the time and log count data from the second experiment.
The two sets of data can be plotted with:
\begin{codebox}
\gls{DTLplot}\marg{growthdata}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time}, \plotoptvalm{y}{Exp1Count,Exp2Count},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter4col},
  title={Scatter Plot (One Database, Two Sets of Data)},
  tag={growthtsv}, link={sec:scatterplot1db2xycolex},
  description={An example document that plots data of time against
observations from two experiments in data from a single file}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{growthdata}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}
}
{
\gls{DTLplot}\marg{growthdata}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Two Databases, Two X and Y Columns}
\label{sec:scatterplot2db2xycolex}

\mExampleref{ex:growthscatter4col2db} makes a minor modification to
\exampleref{ex:growthscatter4col} so that both the \qt{growthdata}
and \qt{growthdata2} databases are loaded (see
\sectionref{sec:growthtsv}) and included in the plot.
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count},
 \plotopt{legend}, \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}
This results in a very cluttered diagram where the legend obscures
a large part of the plot.

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter4col2db},
  title={Scatter Plot (Two Databases, Two Sets of Data)},
  tag={growthtsv}, link={sec:scatterplot2db2xycolex},
  description={An example document that plots data of time against
observations from two experiments in data from two files. The legend
is so cluttered it obscures a large part of the plot}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
}
{
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Two Databases, Three X and Y Columns}
\label{sec:scatterplot2db3xycolex}

Note that the \qt{growthdata2} database actually has six columns,
rather than four.
\mExampleref{ex:growthscatter6col2db} modifies
\exampleref{ex:growthscatter4col2db} to include those two extra
columns in the list:
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}
The unknown columns will be skipped for the first database. If you
switch on \opt{verbose} mode, messages should be shown in the
transcript. Those messages will turn into a warning if there are
unknown columns when only one database is specified.

For debugging purposes, it's useful to show the column keys in the
legend instead of the column headers. This can be done as follows:
\begin{codebox}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendx} \marg{ O\marg{0} m O\marg{0} m }\marg{\#4}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendy} \marg{ O\marg{0} m O\marg{0} m }\marg{\#4}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2db},
  title={Scatter Plot (Two Databases, Multiple Sets of Data)},
  tag={growthtsv}, link={sec:scatterplot2db3xycolex},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The legend shows the column keys but
is so cluttered it obscures nearly half of the plot}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nl
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
}
{\comment{useful for debugging, this will show the column keys
instead of the headers in the legend:}%
\cmd{RenewDocumentCommand} \gls{DTLplotlegendx} \marg{ O\marg{0} m O\marg{0} m }\marg{\#4}\nl
\cmd{RenewDocumentCommand} \gls{DTLplotlegendy} \marg{ O\marg{0} m O\marg{0} m }\marg{\#4}\nl
\codepar
\comment{now draw the plot:}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

The legend is now so large it obscures half of the plot.
Examples that adjust the legend settings are in
\sectionref{sec:plotlegendexs}.

\subsubsection{Two Databases, Two X and Three Y Columns}
\label{sec:scatterplot2db2x3ycolex}

In general, it's best to either have a single key in the \plotopt{x}
setting or the same number of keys as for the \plotopt{y} setting.
To demonstrate what happens when the \plotopt{x} list has more than
one key but less than the total number of \plotopt{y} keys,
\mexampleref{ex:growthscatter6col2db2x3y}
modifies \exampleref{ex:growthscatter6col2db} to have two
\plotopt{x} keys and three \plotopt{y} keys. 
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}
Again, \gls{DTLplotlegendx} and \gls{DTLplotlegendy} are redefined to show
the column keys, and, again, the legend obscures the plot, but it's
the legend that is of interest as it shows the combinations of the
\plotopt{x} and \plotopt{y} columns used to generate the plot.

The plot streams for the second database are obtained from the X/Y
pairs: Exp1Time\slash Exp1Count, Exp2Time\slash Exp2Count and
Exp1Time\slash Exp3Count. Once the end of the \plotopt{x} list is
reached, it cycles back until all the \plotopt{y} columns have been
iterated over. This method allows a single \plotopt{x} column to be
plotted against multiple \plotopt{y} columns, but also allows a list
of \plotopt{x} columns to be plotted against a matching element from
a list of \plotopt{y} columns.

In general, it's better to repeat a column key in \plotopt{x} than
to have this situation.

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2db2x3y},
  title={Scatter Plot With Mismatched X and Y Columns},
  tag={growthtsv}, link={sec:scatterplot2db2x3ycolex},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another but the X and Y keys are mismatched.}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
}
{\comment{useful for debugging, this will show the column keys
instead of the headers in the legend:}%
\cmd{RenewDocumentCommand} \gls{DTLplotlegendx} \marg{ O\marg{0} m O\marg{0} m }\marg{\#4}\nl
\cmd{RenewDocumentCommand} \gls{DTLplotlegendy} \marg{ O\marg{0} m O\marg{0} m }\marg{\#4}\nl
\codepar
\comment{now draw the plot:}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}


\subsection{Legend Examples}
\label{sec:plotlegendexs}

If the \plotopt{legend} option is set then each plot stream for a
given \plotopt{x} and \plotopt{y} pair for a given database will add
a row to the legend (as demonstrated in the previous examples).
There are user hooks available (see
\sectionref{sec:plothooks}) but essentially each row in the legend
starts with the plot mark or line (or both) used by the plot stream
followed by text in the form:
\begin{compactcodebox}
\meta{name} \meta{x-header} / \meta{y-header}
\end{compactcodebox}
If there is only one database the \meta{name} part will be omitted
(unless there is also only one \plotopt{x} and \plotopt{y}),
and if there is only one \plotopt{x} column the \meta{x-header} and
following slash separator will be omitted.

The \meta{x-header} part defaults to
the column header for the corresponding \plotopt{x} column, 
which is obtained with \gls{DTLplotlegendx}, and
the \meta{y-header} part defaults to
the column header for the corresponding \plotopt{y} column,
which is obtained with \gls{DTLplotlegendy}.
This means that each set of data is labelled \qt{Time / Log Count} in
\examplesref{ex:growthscatter4col,ex:growthscatter4col2db}, since
the column headers are repeated for each x/y pair. 

\subsubsection{Custom Legend Text With \optfmt{legend-labels}}
\label{sec:scatterplotlegendlabelsex}

\mExampleref{ex:growthscatter4col-legend}
has a minor change to \exampleref{ex:growthscatter4col} 
that explicitly sets the legend labels with the
\plotopt{legend-labels} option:
\begin{codebox}
\gls{DTLplot}\marg{growthdata}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \strong{\plotoptvalm{legend-labels}{Experiment 1,Experiment 2},}
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter4col-legend},
  title={Scatter Plot with Custom Legend Labels (One Database, Two Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotlegendlabelsex},
  description={An example document that plots data of time against
observations from two experiments in data from a single file with
the legend labels explicitly set}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{growthdata}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}
}
{
\gls{DTLplot}\marg{growthdata}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptvalm{legend-labels}{Experiment 1,Experiment 2},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Subset Custom Legend Text With
\optfmt{legend-labels}}
\label{sec:scatterplotsubsetlegendlabelsex}

If you don't provide enough items in \plotopt{legend-labels}, the defaults will be
used for the missing ones. \mExampleref{ex:growthscatter4col-legend2}
modifies \exampleref{ex:growthscatter4col-legend} so that only one
legend label is supplied:
\begin{codebox}
\gls{DTLplot}\marg{growthdata}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptvalm{legend-labels}{Experiment 1},
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}
This only occurs when the \plotopt{legend-labels} list is shorter
than the total number of plot streams. It's not possible to have the
default for the first and specify a label for the second with
\plotopt{legend-labels}.

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter4col-legend2},
  title={Scatter Plot with Custom and Default Legend Labels (One Database, Two Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotsubsetlegendlabelsex},
  description={An example document that plots data of time against
observations from two experiments in data from a single file with
one legend label explicitly set and the other uses the default}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{growthdata}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}
}
{
\gls{DTLplot}\marg{growthdata}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptvalm{legend-labels}{Experiment 1},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

The \keyval\ parser discards empty elements, so
\code{\plotoptvalm{legend-labels}{Experiment 1,}} (with a trailing
comma) is equivalent to \code{\plotoptvalm{legend-labels}{Experiment
1}}. If an empty value is required, the empty value needs to be
grouped.

\subsubsection{Omitting Stream from Legend With
\optfmt{legend-labels}}
\label{sec:scatterplotlegendlabelsomitex}

\mExampleref{ex:growthscatter4col-legend3} modifies
\exampleref{ex:growthscatter4col-legend2} so that the second label
is explicitly set to empty:
\begin{codebox}
\gls{DTLplot}\marg{growthdata}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptvalm{legend-labels}{Experiment 1\strong{,\marg{}}},
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}
This causes the second stream to be omitted from the legend.

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter4col-legend3},
  title={Scatter Plot with an Omitted Legend Label (One Database, Two Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotlegendlabelsomitex},
  description={An example document that plots data of time against
observations from two experiments in data from a single file with
one legend label explicitly set and the other is omitted}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum},\optval{default-name}{growthdata}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}
}
{
\gls{DTLplot}\marg{growthdata}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\plotoptvalm{legend-labels}{Experiment 1,\marg{}},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Legend Database Mapping}
\label{sec:scatterplotlegendnamemapex}

The use of \plotopt{legend-labels} may be sufficient for a small
number of plot streams, as in
\exampleref{ex:growthscatter4col-legend}, but it can become more
complicated with additional files. The earlier \exampleref{ex:growthscatter2}
which had two files, showed the database names in the legend
(\qt{growth1} and \qt{growth2}). Let's suppose that the experiments
in the first database were conducted at a temperature of 6~degrees
and the experiments in the second database were conducted at a
temperature of 8~degrees.

The \sty{siunitx} package conveniently provides a way of typesetting
temperature, so the legend labels could be set using:
\begin{codebox}
\plotoptvalm{legend-labels}{
 \cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}} Experiment 1,
 \cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}} Experiment 2,
 \cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}} Experiment 1,
 \cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}} Experiment 2
}
\end{codebox} 
However, this can get quite cumbersome (particularly for
\exampleref{ex:growthscatter6col2db}, which has two pairs of x/y
data in one database and three in the other).

\mExampleref{ex:growthscatter2namemap}
modifies \exampleref{ex:growthscatter2} to set up mappings to supply
in place of the database name in the legend.
\begin{codebox}
\gls{DTLplotlegendsetname}\marg{growth1}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}
\gls{DTLplotlegendsetname}\marg{growth2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}
\end{codebox}
This needs to be done before \gls{DTLplot}. The rest of
\exampleref{ex:growthscatter2namemap} is as
\exampleref{ex:growthscatter2} (but remember to include \sty{siunitx}).

\begin{information}
The mappings are used by \gls{DTLplotlegendname}, which is only present
if there are multiple databases.
\end{information}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter2namemap},
  title={Scatter Plot (Two Databases with Name Map)},
  tag={growth}, link={sec:scatterplotlegendnamemapex},
  description={An example document that plots data of time against
observations from two experiments where the legend uses a database
name mapping}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}\nl
\codepar
\gls{DTLplotlegendsetname}\marg{growth1}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetname}\marg{growth2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}
}
{
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptval{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Legend Column Key Mapping}
\label{sec:scatterplotlegendkeymapex}

\mExampleref{ex:growthscatter6col2dbmap} modifies 
\exampleref{ex:growthscatter6col2db} in a similar manner, but also
establishes a mapping for the column keys. Remember to remove the
redefinitions of \gls{DTLplotlegendx} and \gls{DTLplotlegendy} from
that example otherwise the mappings will be ignored.
\begin{codebox}
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}
\gls{DTLplotlegendsetxlabel}\marg{Exp1Time}\marg{\$t\_1\$}
\gls{DTLplotlegendsetxlabel}\marg{Exp2Time}\marg{\$t\_2\$}
\gls{DTLplotlegendsetxlabel}\marg{Exp3Time}\marg{\$t\_3\$}
\gls{DTLplotlegendsetylabel}\marg{Exp1Count}\marg{\$N\_1\$}
\gls{DTLplotlegendsetylabel}\marg{Exp2Count}\marg{\$N\_2\$}
\gls{DTLplotlegendsetylabel}\marg{Exp3Count}\marg{\$N\_3\$}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbmap},
  title={Scatter Plot with Legend Label Mappings (Two Databases, Multiple Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotlegendkeymapex},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The legend text is obtained from mappings}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp1Time}\marg{\$t\_1\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp2Time}\marg{\$t\_2\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp3Time}\marg{\$t\_3\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp1Count}\marg{\$N\_1\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp2Count}\marg{\$N\_2\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp3Count}\marg{\$N\_3\$}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Customising the X/Y Legend}
\label{sec:scatterplotlegendcustxyex}

The slash separator can be changed by redefining \gls{DTLplotlegendxysep}
but \mexampleref{ex:growthscatter6col2dbmapxy} instead modifies
\exampleref{ex:growthscatter6col2dbmap} to include a redefinition of
\gls{DTLplotlegendxy} that doesn't use \gls{DTLplotlegendxysep} but
instead uses a comma and parentheses:
\begin{codebox}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m O\marg{0} m O\marg{0} m }
\marg{\comment{}
 (\gls{DTLplotlegendx}\oarg{\#1}{\#2}\oarg{\#3}\marg{\#4}, 
 \gls{DTLplotlegendy}\oarg{\#1}{\#2}\oarg{\#5}\marg{\#6})\comment{}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbmapxy},
  title={Scatter Plot with Legend Label Mappings and Custom
  formatting (Two Databases, Multiple Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotlegendcustxyex},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The legend text is obtained from mappings
and shows the x and y legend labels in parentheses}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp1Time}\marg{\$t\_1\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp2Time}\marg{\$t\_2\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp3Time}\marg{\$t\_3\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp1Count}\marg{\$N\_1\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp2Count}\marg{\$N\_2\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp3Count}\marg{\$N\_3\$}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m
O\marg{0} m O\marg{0} m }\nl
\marg{\comment{}
  (\gls{DTLplotlegendx}\oarg{\#1}{\#2}\oarg{\#3}\marg{\#4}, \nlsp
  \gls{DTLplotlegendy}\oarg{\#1}{\#2}\oarg{\#5}\marg{\#6})\comment{}
}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Customising the Legend, No X Label}
\label{sec:scatterplotlegendcustnoxex}

\mExampleref{ex:growthscatter6col2dbmap2} uses an alternative
approach to \exampleref{ex:growthscatter6col2dbmapxy} that redefines
\gls{DTLplotlegendxy} to omit the $x$ text, which means that
only the database name and \plotopt{y} column key mappings are
needed:
\begin{codebox}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m O\marg{0} m O\marg{0} m }
\marg{\comment{}
  \gls{DTLplotlegendy}\oarg{\#1}\marg{\#2}\oarg{\#5}\marg{\#6}\comment{}
}
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\$T=6\$}
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\$T=8\$}
\gls{DTLplotlegendsetylabel}\marg{Exp1Count}\marg{Experiment 1}
\gls{DTLplotlegendsetylabel}\marg{Exp2Count}\marg{Experiment 2}
\gls{DTLplotlegendsetylabel}\marg{Exp3Count}\marg{Experiment 3}
\end{codebox}
In this case, since each \plotopt{y} label needs to be in the form
\qt{Experiment \meta{y-index}}, this can be simplified further:
\begin{codebox}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m O\marg{0} m O\marg{0} m }
\marg{\comment{}
  \gls{DTLplotlegendy}\oarg{\#1}\marg{\#2}\oarg{\#5}\marg{\#6}\comment{}
}
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\$T=6\$}
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\$T=8\$}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendy} \marg{ O\marg{0} m O\marg{0} m }
\marg{Experiment \#3}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbmap2},
  title={Scatter Plot with Custom Legend Labels (Two Databases, Multiple Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotlegendcustnoxex},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The legend text is obtained from mappings
but the x column key is ignored}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m O\marg{0} m O\marg{0} m }\nl
\marg{\comment{}
  \gls{DTLplotlegendy}\oarg{\#1}\marg{\#2}\oarg{\#5}\marg{\#6}\comment{}%
}\nl
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\$T=6\$}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\$T=8\$}\nl
\cmd{RenewDocumentCommand} \gls{DTLplotlegendy} \marg{ O\marg{0} m O\marg{0} m }\marg{Experiment \#3}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Shifting the Legend}
\label{sec:scatterplotshiftlegendex}

The examples so far have simply used \plotopt{legend} without a
value. This is equivalent to \plotoptval{legend}{northwest}. This
positions the legend in the north west (top right) of the plot at an
offset given by the lengths \gls{DTLlegendxoffset} and
\gls{DTLlegendyoffset}. These can be more conveniently set with
the \plotopt{legend-offset} option. The default value for both
offsets is 10pt. Note that this is an absolute length not in data
co-ordinates. A negative offset will position the legend outside of
the plot.

\mExampleref{ex:growthscatter6col2dbmap2shiftlegend} makes a minor
modification to \exampleref{ex:growthscatter6col2dbmap2} to shift
the legend to the right of the plot:
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend},\strong{\plotoptvalm{legend-offset}{-10pt,0pt},}
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbmap2shiftlegend},
  title={Scatter Plot with Shifted Legend (Two Databases, Multiple Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotshiftlegendex},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The legend text is obtained from mappings
but the x column key is ignored. A negative offset is used to move
the legend outside of the plot}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m O\marg{0} m O\marg{0} m }\nl
\marg{\comment{}
  \gls{DTLplotlegendy}\oarg{\#1}\marg{\#2}\oarg{\#5}\marg{\#6}\comment{}%
}\nl
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\$T=6\$}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\$T=8\$}\nl
\cmd{RenewDocumentCommand} \gls{DTLplotlegendy} \marg{ O\marg{0} m O\marg{0} m }\marg{Experiment \#3}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend},\plotoptvalm{legend-offset}{-10pt,0pt},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Custom Legend Position}
\label{sec:scatterplotcustomlegendposex}

Instead of using one of the pre-defined legend locations,
you can use the \plotoptval{legend}{custom} setting and
redefine \gls{DTLcustomlegend} to position the legend exactly where
you want it.
\mExampleref{ex:growthscatter6col2dbmap2customlegend} modifies
\exampleref{ex:growthscatter6col2dbmap2shiftlegend} to use the
\sty{tikz} \code{shapes.callouts} library:
\begin{codebox}
\cmd{usetikzlibrary}\marg{shapes.callouts}
\end{codebox}
and redefines \gls{DTLcustomlegend} to position the legend at
(\meta{W},\meta{H}/4) where \meta{W} is the plot width and
\meta{H} is the plot height:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLcustomlegend}}[1]\marg{\comment{}
 \cmd{node}
  \oarg{rectangle callout,fill=green!10,anchor=west,outer sep=10pt,
   callout relative pointer=\marg{(-40pt,10pt)}
  } at (\gls{DTLplotwidth},0.25\gls{DTLplotheight})
  \marg{\#1} ;
}
\end{codebox}
Note that this definition doesn't include \gls{DTLformatlegend} but
instead uses the \csfmt{node} options to set the shape and
background colour.

The plot now needs the \plotopt{legend} option adjusting:
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotoptval{legend}{custom},
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbmap2customlegend},
  title={Scatter Plot with Custom Legend (Two Databases, Multiple Sets of Data)},
  tag={growthtsv}, link={sec:scatterplotcustomlegendposex},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The legend text is obtained from mappings
but the x column key is ignored. The custom legend setting is used
to show the legend in a pale green rectangle callout shape pointing
at the plot}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\cmd{usetikzlibrary}\marg{shapes.callouts}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m O\marg{0} m O\marg{0} m }\nl
\marg{\comment{}
  \gls{DTLplotlegendy}\oarg{\#1}\marg{\#2}\oarg{\#5}\marg{\#6}\comment{}%
}\nl
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\$T=6\$}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\$T=8\$}\nl
\cmd{RenewDocumentCommand} \gls{DTLplotlegendy} \marg{ O\marg{0} m O\marg{0} m }\marg{Experiment \#3}
\comment{for the custom legend:}
\cmd{renewcommand}\marg{\gls{DTLcustomlegend}}[1]\marg{\comment{}
 \cmd{node}\nlsp
  \oarg{rectangle callout,fill=green!10,anchor=west,outer sep=10pt,\nlsp
   callout relative pointer=\marg{(-40pt,10pt)}\nlsp
  } at (\gls{DTLplotwidth},0.25\gls{DTLplotheight})\nlsp
  \marg{\#1} ;\nl
}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotoptval{legend}{custom},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsection{Plot Style Examples}
\label{sec:plotstyleexs}

The examples so far have only shown markers with the default mark
style and colours. The plot can have the style changed to show both
lines and markers with \plotoptval{style}{both} or only lines with
\plotoptval{style}{lines}.

\subsubsection{Line and Scatter Plot}
\label{sec:plotstylebothexs}

\mExampleref{ex:growthscatterboth} is a simple modification of
\exampleref{ex:growthscatter2} which includes lines as well as plot
marks. This is done by setting \plotoptval{style}{both}:
\begin{codebox}
\gls{DTLplot}\marg{growth1,growth2}\marg{
 \strong{\plotoptval{style}{both},}
 \plotoptval{x}{Time}, \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}
Note that the legend has also been shifted, as per
\exampleref{ex:growthscatter6col2dbmap2shiftlegend}.

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatterboth},
  title={Line and Scatter Plot (Two Databases)},
  tag={growth}, link={sec:plotstylebothexs},
  description={An example document that plots data of time against
observations from two experiments using plot marks and lines}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}
}
{
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{style}{both},\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Changing the Colours and Styles}
\label{sec:plotstylechangeexs}

\mExampleref{ex:growthscatter6col2dbstyles} modifies
\exampleref{ex:growthscatter6col2dbmapxy} to show lines as well as
markers but also sets the line and marker colours and the line
style and plot marks (again the legend
is shifted):
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptval{style}{both},\comment{lines and markers}
 \plotoptvalm{line-colors}{brown,blue,lime,black,orange},
 \plotoptvalm{mark-colors}{magenta,teal,green,violet,cyan},
 \plotoptvalm{lines}{
   \gls{pgfsetdash}\marg{}\marg{0pt},\comment{solid line}
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{3pt}}\marg{0pt},
   \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}\marg{1pt}\marg{5pt}}\marg{0pt},
   \gls{pgfsetdash}\marg{\marg{4pt}\marg{2pt}}\marg{0pt},
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{1pt}\marg{2pt}\marg{2pt}\marg{2pt}\marg{1pt}}\marg{0pt}
  },
 \plotoptvalm{marks}{
   \gls{pgfuseplotmark}\marg{o},
   \gls{pgfuseplotmark}\marg{square},
   \gls{pgfuseplotmark}\marg{diamond},
   \gls{pgfuseplotmark}\marg{asterisk},
   \gls{pgfuseplotmark}\marg{star}
  },
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbstyles},
  title={Scatter Plot with Custom Colours and
Styles (Two Databases, Multiple Sets of Data)},
  tag={growthtsv},link={sec:plotstylechangeexs},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The plot marks and lines colours are set to
change the default}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp1Time}\marg{\$t\_1\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp2Time}\marg{\$t\_2\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp3Time}\marg{\$t\_3\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp1Count}\marg{\$N\_1\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp2Count}\marg{\$N\_2\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp3Count}\marg{\$N\_3\$}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m
O\marg{0} m O\marg{0} m }\nl
\marg{\comment{}
  (\gls{DTLplotlegendx}\oarg{\#1}{\#2}\oarg{\#3}\marg{\#4}, \nlsp
  \gls{DTLplotlegendy}\oarg{\#1}{\#2}\oarg{\#5}\marg{\#6})\comment{}
}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptval{style}{both},\comment{lines and markers}
 \plotoptvalm{line-colors}{brown,blue,lime,black,orange},\nlsp
 \plotoptvalm{mark-colors}{magenta,teal,green,violet,cyan},\nlsp
 \plotoptvalm{lines}{\nldbsp
   \gls{pgfsetdash}\marg{}\marg{0pt},\comment{solid line}\dbspace
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{3pt}}\marg{0pt},\nldbsp
   \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}\marg{1pt}\marg{5pt}}\marg{0pt},\nldbsp
   \gls{pgfsetdash}\marg{\marg{4pt}\marg{2pt}}\marg{0pt},\nldbsp
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{1pt}\marg{2pt}\marg{2pt}\marg{2pt}\marg{1pt}}\marg{0pt}\nlsp
  },\nlsp
 \plotoptvalm{marks}{\nldbsp
   \gls{pgfuseplotmark}\marg{o},\nldbsp
   \gls{pgfuseplotmark}\marg{square},\nldbsp
   \gls{pgfuseplotmark}\marg{diamond},\nldbsp
   \gls{pgfuseplotmark}\marg{asterisk},\nldbsp
   \gls{pgfuseplotmark}\marg{star}\nlsp
  },\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{One Line Colour Per Database}
\label{sec:plotstylegrouplinecolexs}

The \plotopt{group-styles} option may be used to only change a
particular style per database, rather than using each style per plot
stream. \mExampleref{ex:growthscatter6col2dbgroupstyles} modifies
\exampleref{ex:growthscatter6col2dbstyles} to use the same line
colour for each stream in a given database:
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptval{style}{both}, \strong{\plotoptvalm{group-styles}{line-color},}
 \plotoptvalm{line-colors}{brown,blue,lime,black,orange},
 \plotoptvalm{mark-colors}{magenta,teal,green,violet,cyan},
 \plotoptvalm{lines}{
   \gls{pgfsetdash}\marg{}\marg{0pt},\comment{solid line}
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{3pt}}\marg{0pt},
   \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}\marg{1pt}\marg{5pt}}\marg{0pt},
   \gls{pgfsetdash}\marg{\marg{4pt}\marg{2pt}}\marg{0pt},
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{1pt}\marg{2pt}\marg{2pt}\marg{2pt}\marg{1pt}}\marg{0pt}
  },
 \plotoptvalm{marks}{
   \gls{pgfuseplotmark}\marg{o},
   \gls{pgfuseplotmark}\marg{square},
   \gls{pgfuseplotmark}\marg{diamond},
   \gls{pgfuseplotmark}\marg{asterisk},
   \gls{pgfuseplotmark}\marg{star}
  },
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}
Note that the other styles (line style, marker style and marker
colour) still cycle round the given lists.

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbgroupstyles},
  title={Scatter Plot with the Same Line Colour for Each Stream in
a Given Database (Two Databases, Multiple Sets of Data)},
  tag={growthtsv}, link={sec:plotstylegrouplinecolexs},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The line colour is brown for each plot from the first
database and blue for the second}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp1Time}\marg{\$t\_1\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp2Time}\marg{\$t\_2\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp3Time}\marg{\$t\_3\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp1Count}\marg{\$N\_1\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp2Count}\marg{\$N\_2\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp3Count}\marg{\$N\_3\$}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m
O\marg{0} m O\marg{0} m }\nl
\marg{\comment{}
  (\gls{DTLplotlegendx}\oarg{\#1}{\#2}\oarg{\#3}\marg{\#4}, \nlsp
  \gls{DTLplotlegendy}\oarg{\#1}{\#2}\oarg{\#5}\marg{\#6})\comment{}
}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptval{style}{both}, \plotoptvalm{group-styles}{line-color},\nlsp
 \plotoptvalm{line-colors}{brown,blue,lime,black,orange},\nlsp
 \plotoptvalm{mark-colors}{magenta,teal,green,violet,cyan},\nlsp
 \plotoptvalm{lines}{\nldbsp
   \gls{pgfsetdash}\marg{}\marg{0pt},\comment{solid line}\dbspace
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{3pt}}\marg{0pt},\nldbsp
   \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}\marg{1pt}\marg{5pt}}\marg{0pt},\nldbsp
   \gls{pgfsetdash}\marg{\marg{4pt}\marg{2pt}}\marg{0pt},\nldbsp
   \gls{pgfsetdash}\marg{\marg{1pt}\marg{1pt}\marg{2pt}\marg{2pt}\marg{2pt}\marg{1pt}}\marg{0pt}\nlsp
  },\nlsp
 \plotoptvalm{marks}{\nldbsp
   \gls{pgfuseplotmark}\marg{o},\nldbsp
   \gls{pgfuseplotmark}\marg{square},\nldbsp
   \gls{pgfuseplotmark}\marg{diamond},\nldbsp
   \gls{pgfuseplotmark}\marg{asterisk},\nldbsp
   \gls{pgfuseplotmark}\marg{star}\nlsp
  },\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Resetting the Style for Each Database}
\label{sec:plotstyleresetexs}

\mExampleref{ex:growthscatter6col2dbresetstyles}
modifies \exampleref{ex:growthscatter6col2dbgroupstyles} so that the
plot marks are reset at the start of each database, and
the only available line style is solid.
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptval{style}{both}, \plotoptvalm{group-styles}{line-color},
 \strong{\plotoptvalm{style-resets}{mark-style},}
 \plotoptvalm{line-colors}{brown,blue,lime,black,orange},
 \plotoptvalm{mark-colors}{magenta,teal,green,violet,cyan},
 \plotoptvalm{lines}{
   \gls{pgfsetdash}\marg{}\marg{0pt}\comment{solid line}
  },
 \plotoptvalm{marks}{
   \gls{pgfuseplotmark}\marg{o},
   \gls{pgfuseplotmark}\marg{square},
   \gls{pgfuseplotmark}\marg{diamond},
   \gls{pgfuseplotmark}\marg{asterisk},
   \gls{pgfuseplotmark}\marg{star}
  },
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}
}
\end{codebox}
This means that a solid line will always be used (with either
\plotoptval{style}{both} or \plotoptval{style}{lines}) regard of
the \plotopt{group-styles} or \plotopt{style-resets} options.
The first database has brown lines and the second database has blue
lines. Experiment~1 for each database has circle markers,
Experiment~2 has square markers and Experiment~3 (which is only in
the second database) has diamond markers. The other listed markers
aren't used. Note, however, that the marker colours still cycle
through the entire \plotopt{mark-colors} list.

\begin{resultbox}[float]
\createexample*
 [label={ex:growthscatter6col2dbresetstyles},
  title={Scatter Plot with Plot Marks Reset (Two Databases, Multiple Sets of Data)},
  tag={growthtsv},link={sec:plotstyleresetexs},
  description={An example document that plots data of time against
observations from two experiments in data from a file and three
experiments in another. The line colour is brown for each plot from the first
database and blue for the second. The plot marks are reset for each
database}
]
{%
\extabfile{growth.tsv}{\growthItsv}\nl
\extabnextfile{growth2.tsv}{\growthIItsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\cmd{usepackage}\marg{siunitx}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth}\comment{growth.tsv}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{growthdata2},
 \iooptval{format}{tsv},\iooptval{csv-skip-lines}{1},\nlsp
 \iooptvalm{keys}{Exp1Time,Exp1Count,Exp2Time,Exp2Count,Exp3Time,Exp3Count},\nlsp
 \iooptval{csv-content}{no-parse},\nlsp
 \iooptval{data-types}{decimal}\nl
}\marg{growth2}\comment{growth2.tsv}
\codepar
\gls{DTLplotlegendsetname}\marg{growthdata}\marg{\cmd{qty}\marg{6}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetname}\marg{growthdata2}\marg{\cmd{qty}\marg{8}\marg{\cmd{degreeCelsius}}}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp1Time}\marg{\$t\_1\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp2Time}\marg{\$t\_2\$}\nl
\gls{DTLplotlegendsetxlabel}\marg{Exp3Time}\marg{\$t\_3\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp1Count}\marg{\$N\_1\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp2Count}\marg{\$N\_2\$}\nl
\gls{DTLplotlegendsetylabel}\marg{Exp3Count}\marg{\$N\_3\$}
\cmd{RenewDocumentCommand} \gls{DTLplotlegendxy} \marg{ O\marg{0} m
O\marg{0} m O\marg{0} m }\nl
\marg{\comment{}
  (\gls{DTLplotlegendx}\oarg{\#1}{\#2}\oarg{\#3}\marg{\#4}, \nlsp
  \gls{DTLplotlegendy}\oarg{\#1}{\#2}\oarg{\#5}\marg{\#6})\comment{}
}
}
{%
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{\nlsp
 \plotoptval{style}{both}, \plotoptvalm{group-styles}{line-color},\nlsp
 \plotoptvalm{style-resets}{mark-style},\nlsp
 \plotoptvalm{line-colors}{brown,blue,lime,black,orange},\nlsp
 \plotoptvalm{mark-colors}{magenta,teal,green,violet,cyan},\nlsp
 \plotoptvalm{lines}{\nldbsp
   \gls{pgfsetdash}\marg{}\marg{0pt}\comment{solid line}\dbspace
  },\nlsp
 \plotoptvalm{marks}{\nldbsp
   \gls{pgfuseplotmark}\marg{o},\nldbsp
   \gls{pgfuseplotmark}\marg{square},\nldbsp
   \gls{pgfuseplotmark}\marg{diamond},\nldbsp
   \gls{pgfuseplotmark}\marg{asterisk},\nldbsp
   \gls{pgfuseplotmark}\marg{star}\nlsp
  },\nlsp
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},\nlsp
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)},\plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptvalm{legend-offset}{-10pt,0pt},\nlsp
 \plotoptval{width}{2.5in},\plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsection{Plot Axes Examples}
\label{sec:plotaxesexs}

\subsubsection{Setting the Bounds}
\label{sec:plotaxesboundsexs}

The examples so far have the plot bounds automatically calculated.
This means that the $y$ tick marks look a little strange as they
don't start from a whole or half number. The $x$ tick marks look
more even as the sample data happens to have convenient $x$ values.
The examples in this section demonstrate how to set the upper and
lower bounds.

\mExampleref{ex:plotbounds} modifies
\exampleref{ex:growthscatter2} to set upper and lower bounds for the
$y$ axis. Since only two of the bounds need changing, it's
simpler to use \plotopt{min-y} and \plotopt{max-y} rather than use
\plotopt{bounds}. This doesn't show the legend and switches to lines
rather than plot marks.
\begin{codebox}
\gls{DTLplot}\marg{growth1,growth2}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \strong{\plotoptval{min-y}{3},\plotoptval{max-y}{6},}
 \plotoptval{style}{lines}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:plotbounds},
  title={Setting the Plot Bounds},
  tag={growth},link={sec:plotaxesboundsexs},
  description={An example document that plots data of time against
observations from two experiments, with the y-axis bounds explicitly
set. The x-axis bounds are calculated from the data}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}
}
{
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Tick Label Rounding}
\label{sec:plotroundtickexs}

\mExampleref{ex:plotround} modifies
\exampleref{ex:plotbounds} to round the $x$ tick labels to whole
numbers and round the $y$ tick labels to one decimal place.
\begin{codebox}
\gls{DTLplot}\marg{growth1,growth2}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},
 \strong{\plotoptval{round-x}{0}, \plotoptval{round-y}{1},}
 \plotoptval{style}{lines}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:plotround},
  title={Rounding the Tick Labels},
  tag={growth},link={sec:plotroundtickexs},
  description={An example document that plots data of time against
observations from two experiments, with the y-axis labels rounded to
1 decimal place and the x-axis labels rounded to whole numbers}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}
}
{%
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},\nlsp
 \plotoptval{round-x}{0}, \plotoptval{round-y}{1},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Axis Style}
\label{sec:plotaxisexs}

The \sty{tikz} line drawing style of the $x$ and $y$ axes can be
changed with the \plotopt{axis-style} option.

\mExampleref{ex:plotaxisstyle} modifies
\exampleref{ex:plotround} to include an arrow head and also makes
the lines thicker using \plotoptvalm{axis-style}{->,thick}.
The tick direction is also changed to outside of the plot using
\plotopt{tick-dir}{out} and the minor tick marks are included with
\plotopt{minor-ticks}.
\begin{codebox}
\gls{DTLplot}\marg{growth1,growth2}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},
 \plotoptval{round-x}{0}, \plotoptval{round-y}{1},
 \strong{\plotoptval{tick-dir}{out}, \plotopt{minor-ticks}, \plotoptvalm{axis-style}{->,thick},}
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{2.5in}
}
\end{codebox}
Note that the arrow heads overlap the end tick marks. This can be
dealt with by extending the axes using \plotopt{extend-x-axis} and
\plotopt{extend-y-axis} (see \sectionref{sec:plotextendaxesexs}).
This is different to changing the plot bounds as it extends the axes
without adding additional tick marks.

\begin{resultbox}[float]
\createexample*
 [label={ex:plotaxisstyle},
  title={Changing the Axis Style},
  tag={growth},link={sec:plotaxisexs},
  description={An example document that plots data of time against
observations from two experiments, with thick axis lines that have
an arrow at the maximum end}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}
}
{%
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},\nlsp
 \plotoptval{round-x}{0}, \plotoptval{round-y}{1},\nlsp
 \plotoptval{tick-dir}{out}, \plotopt{minor-ticks}, \nl
\comment{this will add an arrow head at the end of the axes but it
will clash with the end tick mark:}
 \plotoptvalm{axis-style}{->,thick},\nl
\comment{extend the axes to avoid a clash:}
\comment{\plotoptval{extend-x-axis}{0.5}, \plotoptval{extend-y-axis}{0.5},}
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Grid}
\label{sec:plotgridexs}

The \plotopt{grid} option draws a grid in the background before
drawing the plot streams. \mExampleref{ex:plotgrid} modifies
\exampleref{ex:plotround} to show the grid. As with
\exampleref{ex:plotaxisstyle}, the minor tick marks are also
enabled. If minor tick marks aren't enabled, only the major grid
lines will be drawn.
\begin{codebox}
\gls{DTLplot}\marg{growth1,growth2}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},
 \plotoptval{round-x}{0}, \plotoptval{round-y}{1},
 \strong{\plotopt{grid}, \plotopt{minor-ticks},}
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:plotgrid},
  title={Grid},
  tag={growth},link={sec:plotgridexs},
  description={An example document that plots data of time against
observations from two experiments, with a grid}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}
}
{%
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},\nlsp
 \plotoptval{round-x}{0}, \plotoptval{round-y}{1},\nlsp
 \plotopt{grid}, \plotopt{minor-ticks},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

The style of the major grid lines is obtained by expanding
\gls{DTLmajorgridstyle}, and the style of the minor grid lines
is obtained by expanding \gls{DTLminorgridstyle}. These can be
redefined as required but should expand to valid \sty{tikz} options.
If \gls{DTLminorgridstyle} is redefined to expand to nothing then
the minor grid lines won't be drawn even if the tick marks are
enabled. For example:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLmajorgridstyle}}\marg{gray,ultra thick}
\cmd{renewcommand}\marg{\gls{DTLminorgridstyle}}\marg{}
\end{codebox}
Instead of explicitly redefining those commands, you can
use the \plotopt{major-grid-style} and
\plotopt{minor-grid-style} options.

\mExampleref{ex:plotcustomgrid} modifies 
\exampleref{ex:plotgrid} to change the grid style, but rather than
explicitly redefining the commands, as above, the plot options are
used instead:
\begin{codebox}
\gls{DTLplot}\marg{growth1,growth2}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotoptval{min-y}{3},\plotoptval{max-y}{6}, \plotopt{minor-ticks},
 \plotoptval{round-x}{0}, \plotoptval{round-y}{1},
 \plotopt{grid}, \strong{\plotoptvalm{major-grid-style}{gray,ultra thick}, \plotoptvalm{minor-grid-style}{}},
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{2.5in}
}
\end{codebox}
This results in thick major grid lines and no minor grid lines (even
though the minor ticks are on).

\begin{resultbox}[float]
\createexample*
 [label={ex:plotcustomgrid},
  title={Custom Grid Lines},
  tag={growth},
  description={An example document that plots data of time against
observations from two experiments, with a grid. Thi grid has thick
grey lines along the major tick marks and no minor grid lines}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\exfile{growth2.csv}{\timetogrowthIIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}\nl
\gls{DTLread}\oarg{name=growth2,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth2.csv}
}
{%
\gls{DTLplot}\marg{growth1,growth2}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{6},\nlsp
 \plotoptval{round-x}{0}, \plotoptval{round-y}{1},\nlsp
 \plotopt{grid}, \plotoptvalm{major-grid-style}{gray,ultra thick}, \plotoptvalm{minor-grid-style}{}, \nlsp
 \plotopt{minor-ticks},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Box}
\label{sec:plotboxexs}

The \plotopt{box} option encapsulates the (extended) plot bounds
with a box. Note that this doesn't include the tick labels and axis
labels unless they also happen to lie within those bounds.
\mExampleref{ex:plotbox} adapts \exampleref{ex:growthscatter1} to
include tick rounding, an adjustment to the plot bounds, and the
encapsulating box.
\begin{codebox}
\gls{DTLplot}\marg{growth1}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{round}{0}, \plotopt{minor-ticks}, 
 \plotoptval{min-y}{3},\plotoptval{max-y}{5},\plotoptval{y-tick-gap}{1},
 \plotoptval{tick-label-offset}{0pt}, \strong{\plotopt{box},}
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:plotbox},
  title={Plot Encapsulated in a Box},
  tag={growth}, link={sec:plotboxexs},
  description={An example document that plots data of time against
observations from two experiments. The y plot bounds are set to
[3,5] and the entire plot, not including the axis mid-labels, is enclosed in a box
with tick marks along the top right edges}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}
}
{%
\gls{DTLplot}\marg{growth1}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptval{round}{0}, \plotopt{minor-ticks}, \nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{5},\plotoptval{y-tick-gap}{1},\nlsp
 \plotoptval{tick-label-offset}{0pt},\plotopt{box},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

By default, the box will have tick marks that match the axes tick
marks. This can be changed with the \plotopt{box-ticks} option.
\mExampleref{ex:plotboxticksnone} modifies \exampleref{ex:plotbox}
so that the box doesn't have tick marks.
\begin{codebox}
\gls{DTLplot}\marg{growth1}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{round}{0}, \plotopt{minor-ticks}, 
 \plotoptval{min-y}{3},\plotoptval{max-y}{5},\plotoptval{y-tick-gap}{1},
 \plotoptval{tick-label-offset}{0pt}, \strong{\plotopt{box}, \plotoptval{box-ticks}{none},}
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

Note that extending the axes and the \plotopt{side-axes} option has
an effect on the \plotopt{box} option. See
\sectionref{sec:plotsideaxesexs}.

\begin{resultbox}[float]
\createexample*
 [label={ex:plotboxticksnone},
  title={Plot Encapsulated in a Box Without Ticks},
  tag={growth}, link={sec:plotboxexs},
  description={An example document that plots data of time against
observations from two experiments. The y plot bounds are set to
[3,5] and the entire plot, not including the axis mid-labels, is enclosed in a box
without the default tick marks along the top right edges}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}
}
{%
\gls{DTLplot}\marg{growth1}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptval{round}{0}, \plotopt{minor-ticks}, \nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{5},\plotoptval{y-tick-gap}{1},\nlsp
 \plotoptval{tick-label-offset}{0pt},\nlsp
 \plotopt{box}, \plotoptval{box-ticks}{none},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\subsubsection{Negative Axes}
\label{sec:plotnegativeaxesexs}

The examples so far have all had non-negative $x$ and $y$ values.
The \qt{xydata} database (see \sectionref{sec:xydatacsv}) has some
negative values that can be used to demonstrate a graph with axes
that stretch from positive to negative.
\mExampleref{ex:plotxy} uses this data to plot a line graph. The tick direction is
changed from the default inwards to outwards, which means that the
$x$ ticks extend below the $x$-axis (instead of above) and the
$y$ ticks extend to the left of the $y$-axis (instead of to the
right). The tick labels are rounded to 1 decimal place.
\begin{codebox}
\gls{DTLplot}\marg{xydata}\marg{
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},
 \strong{\plotoptval{tick-dir}{out}, \plotoptval{round}{1}}
 \plotoptvalm{x-label}{\$x\$}, \plotoptvalm{y-label}{\$y\$},
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}
}
\end{codebox}
The labels in \exampleref{ex:plotxy} are very untidy as they
overlap. This can be addressed by rounding the tick label values and moving
the axis labels to the end (see \exampleref{ex:plotxyextend}).

\begin{resultbox}[float]
\createexample*
 [label={ex:plotxy},
  title={Positive and Negative Axes},
  tag={xydata}, link={sec:plotnegativeaxesexs},
  description={An example document that plots X against Y for values
that cover all four positive and negative quadrants. The tick marks
and axis labels are overlapping as there is insufficient space}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse}\nlsp,
 \iooptval{data-types}{decimal}\nl
}\marg{xydata.csv}
}
{Beware of narrow tick gaps!
\codepar
\gls{DTLplot}\marg{xydata}\marg{\nlsp
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},\nlsp
 \plotoptval{tick-dir}{out},\nlsp
\comment{consider switching to max-x-label and max-y-label instead
in the following to reduce overlap:}
 \plotoptvalm{x-label}{\$x\$}, \plotoptvalm{y-label}{\$y\$},\nlsp
\comment{consider changing the tick label offset and font size to reduce clutter:}
\comment{\plotoptvalm{tick-label-style}{font=\cmd{small}}, \plotoptval{tick-label-offset}{0pt},}
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}\nl
}
}
\end{resultbox}

\subsubsection{Extending the Axes}
\label{sec:plotextendaxesexs}

\mExampleref{ex:plotxyextend} modifies \exampleref{ex:plotxy} so that
the $x$ and $y$ axis are extended and the axis labels are moved to
the maximum end.  Choosing a wider gap for the $x$ ticks can also
help reduce the clutter.
\begin{codebox}
\gls{DTLplot}\marg{xydata}\marg{
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},
 \plotoptval{tick-dir}{out}, \plotoptval{x-tick-gap}{1}, \plotoptval{round-x}{0}, \plotoptval{round-y}{1},
 \plotoptvalm{extend-x-axis}{0,1}, \plotoptvalm{extend-y-axis}{0,0.5},
 \plotoptvalm{tick-label-style}{font=\cmd{small}}, \plotoptval{tick-label-offset}{0pt},
 \plotoptvalm{max-x-label}{\$x\$}, \plotoptvalm{max-y-label}{\$y\$},
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}
}
\end{codebox}
Note that even though the tick label offset has been set to zero,
there is still a slight gap between the tick mark and the label.
This is due to \sty{tikz}['s] default \optfmt{inner sep} for nodes.

\begin{resultbox}[float]
\createexample*
 [label={ex:plotxyextend},
  title={Extending the Axes},
  tag={xydata}, link={sec:plotextendaxesexs},
  description={An example document that plots X against Y for values
that cover all four positive and negative quadrants. The maximum
ends of the x and y axes are extended beyond the plot bounds}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse}\nlsp,
 \iooptval{data-types}{decimal}\nl
}\marg{xydata.csv}
}
{
\gls{DTLplot}\marg{xydata}\marg{\nlsp
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},\nlsp
 \plotoptval{tick-dir}{out}, \plotoptval{x-tick-gap}{1}, \plotoptval{round-x}{0}, \plotoptval{round-y}{1},\nlsp
 \plotoptvalm{extend-x-axis}{0,1}, \plotoptvalm{extend-y-axis}{0,0.5},\nlsp
 \plotoptvalm{tick-label-style}{font=\cmd{small}}, \plotoptval{tick-label-offset}{0pt},\nlsp
 \plotoptvalm{max-x-label}{\$x\$}, \plotoptvalm{max-y-label}{\$y\$},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}\nl
}
}
\end{resultbox}

\subsubsection{Changing the Tick Label Node Style}
\label{sec:plottickstyleexs}

\Examplesref{ex:plotxy,ex:plotxyextend} used
\plotopt{tick-label-style} to change the font to a smaller size:
\begin{codebox}
\plotoptvalm{tick-label-style}{font=\cmd{small}}
\end{codebox}
This is equivalent to:
\begin{codebox}
\plotoptvalm{x-tick-label-style}{font=\cmd{small}},
\plotoptvalm{y-tick-label-style}{anchor=east,font=\cmd{small}}
\end{codebox}
Note that the \plotopt{y-tick-label-style} includes the node anchor.
\mExampleref{ex:plotxynodestyle} changes these two values separately
so that they both use a small font, but the $y$-tick labels are
additionally rotated, and the \optfmt{inner opt} is set to 1pt to
bring the $y$-tick label closer to the tick mark.
\begin{codebox}
\gls{DTLplot}\marg{xydata}\marg{
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},
 \plotoptval{tick-dir}{out}, \plotoptval{x-tick-gap}{1}, \plotoptval{round-x}{0}, \plotoptval{round-y}{1},
 \plotoptvalm{extend-x-axis}{0,1}, \plotoptvalm{extend-y-axis}{0,0.5},
 \plotoptvalm{x-tick-label-style}{font=\cmd{small}},
 \plotoptvalm{y-tick-label-style}{anchor=south east, inner sep=1pt, rotate=45, font=\cmd{small}},
 \plotoptval{tick-label-offset}{0pt},
 \plotoptvalm{max-x-label}{\$x\$}, \plotoptvalm{max-y-label}{\$y\$},
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}
}
\end{codebox}
Additionally, \gls{DTLplotdisplayticklabel} is redefined to ensure
that the tick labels are in math mode:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLplotdisplayticklabel}}\oarg{1}\marg{\cmd{ensuremath}\marg{\#1}}
\end{codebox}
This shows the negative numbers with a correct minus sign rather
than a hyphen.

\begin{resultbox}[float]
\createexample*
 [label={ex:plotxynodestyle},
  title={Changing the Tick Label Node Style},
  tag={xydata}, link={sec:plottickstyleexs},
  description={An example document that plots X against Y for values
that cover all four positive and negative quadrants. The y tick
labels are rotated 45 degrees}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse}\nlsp,
 \iooptval{data-types}{decimal}\nl
}\marg{xydata.csv}
\codepar
\cmd{renewcommand}\marg{\gls{DTLplotdisplayticklabel}}\oarg{1}\marg{\cmd{ensuremath}\marg{\#1}}
}
{
\gls{DTLplot}\marg{xydata}\marg{\nlsp
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},\nlsp
 \plotoptval{tick-dir}{out}, \plotoptval{x-tick-gap}{1}, \plotoptval{round-x}{0}, \plotoptval{round-y}{1},\nlsp
 \plotoptvalm{extend-x-axis}{0,1}, \plotoptvalm{extend-y-axis}{0,0.5},\nlsp
 \plotoptvalm{x-tick-label-style}{font=\cmd{small}},\nlsp
 \plotoptvalm{y-tick-label-style}{anchor=south east,inner sep=1pt,rotate=45,font=\cmd{small}},\nlsp
 \plotoptval{tick-label-offset}{0pt},\nlsp
 \plotoptvalm{max-x-label}{\$x\$}, \plotoptvalm{max-y-label}{\$y\$},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}\nl
}
}
\end{resultbox}

\subsubsection{Side Axes}
\label{sec:plotsideaxesexs}

The default \plotoptval{side-axes}{false} setting will draw the axes
crossing at zero, if zero lies within the plot bounds. If zero
doesn't lie within the plot bounds, the axes will be on the side
with the $x$ and $y$-axis meeting at $(x_{\min},y_{\min})$. That is,
the minimum $x$ and $y$ of the bounds plots.

\mExampleref{ex:plotxysideaxes} plots the \qt{xydata} from the previous
examples with \plotoptval{side-axes}{true}. This draws the axes at
the side (lower left bounds) rather than intersecting at the origin.
\begin{codebox}
\gls{DTLplot}\marg{xydata}\marg{
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},
 \plotoptval{tick-gap}{1}, \plotoptval{round}{0},
 \plotoptvalm{tick-label-style}{font=\cmd{small}},
 \plotoptval{tick-label-offset}{0pt},
 \plotopt{minor-ticks}, \strong{\plotopt{side-axes},}
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}
}
\end{codebox}

As with \exampleref{ex:plotxynodestyle}, the tick label style is
redefined to use math mode:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLplotdisplayticklabel}}\oarg{1}\marg{\cmd{ensuremath}\marg{\#1}}\nl
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:plotxysideaxes},
  title={Side Axes},
  tag={xydata}, 
  description={An example document that plots X against Y for values
that cover all four positive and negative quadrants. The axes are
drawn at the side along the lower left bounds of the plot}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse}\nlsp,
 \iooptval{data-types}{decimal}\nl
}\marg{xydata.csv}
\codepar
\cmd{renewcommand}\marg{\gls{DTLplotdisplayticklabel}}\oarg{1}\marg{\cmd{ensuremath}\marg{\#1}}\nl
}
{%
\gls{DTLplot}\marg{xydata}\marg{\nlsp
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},\nlsp
 \plotoptval{tick-gap}{1}, \plotoptval{round}{0},\nlsp
 \plotoptvalm{tick-label-style}{font=\cmd{small}},\nlsp
 \plotoptval{tick-label-offset}{0pt},\nlsp
 \plotopt{minor-ticks}, \plotopt{side-axes},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}\nl
}
}
\end{resultbox}

The \qt{time to growth} data (see \sectionref{sec:growthcsv}) 
used in earlier examples happens to have 0 as the minimum $x$ value
(which in this case is the time $t$ value). The $y$ values are all
non-negative, which means that the axes will be on the side
regardless of the \plotopt{side-axes} setting.

In this case, the
difference between \plotoptval{side-axes}{true} and
\plotoptval{side-axes}{false} is only noticeable when the axes are
extended beyond the minimum bounds and the \plotopt{box} option is
set. This is illustrated in
\examplesref{ex:plotboxextendedsideaxes,ex:plotboxextendednosideaxes}
which adapt \exampleref{ex:plotbox} to extend both axes. The difference
between them is the \plotopt{side-axes} setting.

\mExampleref{ex:plotboxextendedsideaxes} has the following options:
\begin{codebox}
\gls{DTLplot}\marg{growth1}\marg{
 \plotoptval{x}{Time},
 \plotoptvalm{y}{Experiment 1,Experiment 2},
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},
 \plotopt{legend}, \plotoptval{round}{0}, \plotopt{minor-ticks}, 
 \plotoptval{min-y}{3},\plotoptval{max-y}{5},\plotoptval{y-tick-gap}{1},
 \plotoptval{tick-label-offset}{0pt}, \plotopt{box},
 \strong{\plotopt{side-axes},
 \plotoptvalm{extend-x-axis}{5},
 \plotoptvalm{extend-y-axis}{0.5},}
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}
}
\end{codebox}

\mExampleref{ex:plotboxextendednosideaxes} is the same except for
\plotoptval{side-axes}{false}. With \plotoptval{side-axes}{true},
the bottom and left edges of the box don't have tick marks. With
\plotoptval{side-axes}{false}, all sides of the box have tick marks.

\begin{resultbox}[float]
\createexample*
 [label={ex:plotboxextendedsideaxes},
  title={Side-Axes, Extended Axes and Boxed},
  tag={growth}, 
  description={An example document that plots data of time against
observations from two experiments. The y plot bounds are set to
[3,5] and the axes are extended. The entire plot, including extended
axes but not including the axis mid-labels, is enclosed in a box
with tick marks along the top right edges}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}
}
{%
\gls{DTLplot}\marg{growth1}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptval{round}{0}, \plotopt{minor-ticks},\nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{5},\plotoptval{y-tick-gap}{1},\nlsp
 \plotoptval{tick-label-offset}{0pt}, \plotopt{box},\nlsp
 \plotopt{side-axes},\nlsp
 \plotoptvalm{extend-x-axis}{5},\nlsp
 \plotoptvalm{extend-y-axis}{0.5},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}


\begin{resultbox}[float]
\createexample*
 [label={ex:plotboxextendednosideaxes},
  title={No Side-Axes, Extended Axes and Boxed},
  tag={growth}, 
  description={An example document that plots data of time against
observations from two experiments. The y plot bounds are set to
[3,5] and the axes are extended. The entire plot, including extended
axes but not including the axis mid-labels, is enclosed in a box
with tick marks along all edges}
]
{%
\exfile{growth1.csv}{\timetogrowthIcsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{name=growth1,\nlsp
 csv-content=no-parse,\nlsp
 data-types=decimal\nl
}\marg{growth1.csv}
}
{%
\gls{DTLplot}\marg{growth1}\marg{\nlsp
 \plotoptval{x}{Time},\nlsp
 \plotoptvalm{y}{Experiment 1,Experiment 2},\nlsp
 \plotoptvalm{x-label}{Time (\$t\$)}, \plotoptvalm{y-label}{Log Count},\nlsp
 \plotopt{legend}, \plotoptval{round}{0}, \plotopt{minor-ticks},\nlsp
 \plotoptval{min-y}{3},\plotoptval{max-y}{5},\plotoptval{y-tick-gap}{1},\nlsp
 \plotoptval{tick-label-offset}{0pt}, \plotopt{box},\nlsp
 \plotoptval{side-axes}{false},\comment{default}
 \plotoptvalm{extend-x-axis}{5},\nlsp
 \plotoptvalm{extend-y-axis}{0.5},\nlsp
 \plotoptval{width}{2.5in}, \plotoptval{height}{2.5in}\nl
}
}
\end{resultbox}

\begin{information}
The tick marks only go up to the plot bounds. They don't go on the
extended parts. This means that the ends of the axes and the corners of the box in 
\examplesref{ex:plotboxextendedsideaxes,ex:plotboxextendednosideaxes}
don't have tick marks. If you want the tick marks to go all the way
to the end then you need to change the plot \plotopt{bounds} not the
axis extension options.
\end{information}

The $x$ and $y$ axis labels are independent of the axis extensions. 
In
\examplesref{ex:plotboxextendedsideaxes,ex:plotboxextendednosideaxes},
the $x$ label is inside the box because the $y$ extension is large
enough to include it, but the $y$ label is outside of the box
because the $x$ extension isn't large enough to include it.

\subsection{Begin and End Hooks}
\label{sec:plothooksexs}

Additional information can be added to the plot with the start and
end hooks.
\Examplesref{ex:plotxy,ex:plotxyextend,ex:plotxynodestyle} don't
show the tick label at $(0,0)$ because of the default
\plotoptval{omit-zero-label}{auto} setting. Changing this setting to
\plotoptval{omit-zero-label}{false} would show 0 at both $x=0$ and
$y=0$. However, this will result in the axes passing
through the 0 labels.

\mExampleref{ex:plotxyhooks} adds 0 at the origin (shifted below
right) by redefining the start hook:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLplotatbegintikz}}\marg{
 \cmd{draw} (0,0) node[anchor=north east] \marg{0};
}
\end{codebox}
The end hook is also redefined to show the minimum and maximum $y$
values, for illustrative purposes.
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLplotatendtikz}}\marg{
 \cmd{draw}[blue,dotted] (\gls{DTLminX},\gls{DTLminY}) -- (\gls{DTLmaxX}, \gls{DTLminY})
   node[right] \marg{\$y\_\marg{\cmd{min}} = \gls{DTLminY}\$};
 \cmd{draw}[blue,dotted] (\gls{DTLminX},\gls{DTLmaxY}) -- (\gls{DTLmaxX}, \gls{DTLmaxY})
   node[right] \marg{\$y\_\marg{\cmd{max}} = \gls{DTLmaxY}\$};
}
\end{codebox}
The plot options are similar to previous examples in
\sectionref{sec:plotaxesexs} but the $x$ and $y$ tick settings are
made the same for simplicity. Both axes are extend at their maximum
end and drawn with thick lines and an arrow head at the end.
\begin{codebox}
\gls{DTLplot}\marg{xydata}\marg{
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},
 \plotoptval{tick-dir}{out}, \plotoptval{tick-gap}{1}, \plotoptval{round}{0},
 \plotoptvalm{extend-x-axis}{0,0.5}, \plotoptvalm{extend-y-axis}{0,0.5},
 \plotoptvalm{tick-label-style}{font=\cmd{small}},
 \plotoptval{tick-label-offset}{0pt},
 \plotoptvalm{axis-style}{->,thick},
 \plotoptvalm{max-x-label}{\$x\$}, \plotoptvalm{max-y-label}{\$y\$},
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}
}
\end{codebox}

\begin{resultbox}[float]
\createexample*
 [label={ex:plotxyhooks},
  title={Redefining the Start and End Hooks},
  tag={xydata}, link={sec:plothooksexs},
  description={An example document that plots X against Y for values
that cover all four positive and negative quadrants. The start hook
has been used to put 0 by the origin and the end hook has been used
to draw an annotated horizontal line at the maximum and minimum y values}
]
{%
\exfile{xydata.csv}{\xydatacsv}\nl
\cmd{usepackage}\marg{dataplot}\nl
\gls{DTLsetup}\marg{\opt{store-datum}}\nl
\gls{DTLread}\oarg{\nlsp
 \iooptval{name}{xydata},\nlsp
 \iooptval{format}{csv},\nlsp
 \iooptval{csv-content}{no-parse}\nlsp,
 \iooptval{data-types}{decimal}\nl
}\marg{xydata.csv}
\codepar
\cmd{renewcommand}\marg{\gls{DTLplotdisplayticklabel}}\oarg{1}\marg{\cmd{ensuremath}\marg{\#1}}\nl
\cmd{renewcommand}\marg{\gls{DTLplotatbegintikz}}\marg{\cmd{draw}
(0,0) node[anchor=north east] \marg{0};}\nl
\cmd{renewcommand}\marg{\gls{DTLplotatendtikz}}\marg{\nlsp
 \cmd{draw}[blue,dotted] (\gls{DTLminX},\gls{DTLminY}) --
(\gls{DTLmaxX}, \gls{DTLminY})\nlsp
   node[right] \marg{\$y\_\marg{\cmd{min}} = \gls{DTLminY}\$};\nlsp
 \cmd{draw}[blue,dotted] (\gls{DTLminX},\gls{DTLmaxY}) --
(\gls{DTLmaxX}, \gls{DTLmaxY})\nlsp
   node[right] \marg{\$y\_\marg{\cmd{max}} = \gls{DTLmaxY}\$};\nlsp
}
}
{%
\gls{DTLplot}\marg{xydata}\marg{\nlsp
 \plotoptval{x}{X}, \plotoptvalm{y}{Y},\nlsp
 \plotoptval{tick-dir}{out}, \plotoptval{tick-gap}{1}, \plotoptval{round}{0},\nlsp
 \plotoptvalm{extend-axes}{0,0.5}, \nlsp
 \plotoptvalm{tick-label-style}{font=\cmd{small}},\nlsp
 \plotoptval{tick-label-offset}{0pt},\nlsp
 \plotoptvalm{axis-style}{->,thick},\nlsp
 \plotoptvalm{max-x-label}{\$x\$}, \plotoptvalm{max-y-label}{\$y\$},\nlsp
 \plotoptval{style}{lines}, \plotoptval{width}{3in}, \plotoptval{height}{3in}\nl
}
}
\end{resultbox}


\section{Supplementary Plot Commands}
\label{sec:plothooks}

\gls{DTLplot} internally starts and ends the \env{tikzpicture}
environment. The following hooks are provided to add additional
content.

\cmddef{DTLplotatbegintikz}
This hook occurs at the start of the \env{tikzpicture} environment.

\cmddef{DTLplotatendtikz}
This hook occurs at the end of the \env{tikzpicture} environment.


\begin{information}
A transformation will be applied to provide a convenient way of
referencing co-ordinates using the plot data units. For example, if
your data has $x$ and $y$ values 1234 and 567 then you can reference
that point with the \sty{tikz} co-ordinate \code{(1234,567)}.
\end{information}

The transformation used by \gls{DTLplot} can cause plot marks or
other content to appeared skewed. If necessary, you can reset the
transformation matrix with \sty{pgf}['s] \gls{pgftransformreset} but
make sure that \gls{DTLplot}['s] transformation matrix is restored
before the end of \gls{DTLplotatbegintikz}. This can either be done
by scoping \gls{pgftransformreset} or by using:
\cmddef{dataplotapplypgftransform:}
Note that this command requires \LaTeX3 syntax to be on, which can
interfere with \sty{tikz}['s] syntax.

\subsection{General Functions and Variables}
\label{sec:plotgeneralhooks}

\cmddef{DTLminX}
When used within the \gls{DTLplot} hooks, this command will expand
to the minimum $x$ value of the plot bounds. Since the plot code is
scoped, it can't be referenced outside of the plot hooks. However,
if you use the \action{plot} action, you can access this value with
the \optfmt{min-x} secondary return value.

\cmddef{DTLminY}
When used within the \gls{DTLplot} hooks, this command will expand
to the minimum $y$ value of the plot bounds. Since the plot code is
scoped, it can't be referenced outside of the plot hooks. However,
if you use the \action{plot} action, you can access this value with
the \optfmt{min-y} secondary return value.

\cmddef{DTLmaxX}
When used within the \gls{DTLplot} hooks, this command will expand
to the maximum $x$ value of the plot bounds. Since the plot code is
scoped, it can't be referenced outside of the plot hooks. However,
if you use the \action{plot} action, you can access this value with
the \optfmt{max-x} secondary return value.

\cmddef{DTLmaxY}
When used within the \gls{DTLplot} hooks, this command will expand
to the maximum $y$ value of the plot bounds. Since the plot code is
scoped, it can't be referenced outside of the plot hooks. However,
if you use the \action{plot} action, you can access this value with
the \optfmt{max-y} secondary return value.

The total number of keys provided in the \plotopt{x} and \plotopt{y}
lists and the total number of databases can be obtained with the
following macros, which simply use \csfmt{seq\_count:N} or
\csfmt{clist\_count:N} on the internal variables used to store those
lists.

\cmddef{dataplotxkeycount:}
May be used with \gls{DTLplot} hooks to return the total number of 
items given in the \plotopt{x} list. If you use the \action{plot}
action, this value can also be accessed after the plot using the
\optfmt{x-count} secondary return value.

\cmddef{dataplotykeycount:}
May be used with \gls{DTLplot} hooks to return the total number of 
items given in the \plotopt{y} list. If you use the \action{plot}
action, this value can also be accessed after the plot using the
\optfmt{y-count} secondary return value.

\cmddef{dataplotdbcount:}
May be used with \gls{DTLplot} hooks to return the total number of 
database names. If you use the \action{plot} action, this value can
also be accessed after the plot using the \optfmt{name-count}
secondary return value.

\subsection{Stream Functions and Variables}
\label{sec:plotstreamfns}

\cmddef{DTLaddtoplotlegend}
This command is used by \gls{DTLplot} to add the current plot stream to the
legend. The \meta{marker} is the marker code and may be empty or
\gls{relax} to indicate no marker. The \meta{line style} is the line
style code and may be empty or \gls{relax} to indicate no line. The
\meta{text} is the legend text associated with the current plot
stream. Note that \meta{marker} and \meta{line style} should include
the associated colour change, if applicable. The marker or line
code is encapsulated in a \env{pgfpicture} environment with the line
style scoped so that any colour change doesn't affect the marker.

If you want to redefine \gls{DTLaddtoplotlegend} to change the style
of the legend, you will need to switch to \LaTeX3 syntax. The legend
is constructed by appending content to:
\cmddef{ldataplotlegendtl}
This is a token list variable which by the end of \gls{DTLplot} (but
before \gls{DTLplotatendtikz}) should contain the code to typeset
the plot legend.

At the end of each stream, the legend text is obtained and, if not
empty, \gls{DTLaddtoplotlegend} is used to add the current stream
information to the legend. If \plotopt{legend-labels} has been used,
the legend text is obtained from the corresponding item in that
list. Otherwise it's obtained using the following command.

\cmddef{dataplotgetdefaultlegend:Nnnnn}
Gets the default legend label (the text supplied to
\gls{DTLaddtoplotlegend}) when there is no corresponding label
provided by \plotopt{legendlabels}, and stores it in the token list
variable \meta{tl-var}. The \meta{x-key} and \meta{y-key} arguments
are the column keys for the current $x$ and $y$ plot stream. The
default behaviour for each row of the legend depends on the number
of databases and \plotopt{x} and \plotopt{y} variables.

The token list variable is cleared before passing it to this
function. If the function is redefined so that it doesn't modify the
token list variable then the current plot stream won't be added to
the legend.

The default behaviour of \gls{dataplotgetdefaultlegend:Nnnnn} and
its associated commands is described in more detail in 
\sectionref{sec:plotpoststreamhooks}.

If you need to access other information about the current plot
stream, you can do so with the following integer variables, but bear
in mind that while {ldataplotstreamindexint}, \gls{ldataplotxkeyint}
and \gls{ldataplotykeyint} can be used in
\gls{dataplotgetdefaultlegend:Nnnnn} they shouldn't be added to the
token list variable provided in the first argument as their values
will have changed by the time the token list variable content is
added to the input stream. This means they also shouldn't be
referenced within commands like \gls{DTLplotlegendx} which are added
unexpanded to the token list variable. This is why their expanded
values are passed in the optional arguments of the legend hooks.

\cmddef{ldataplotstreamindexint}
Integer variable that keeps track of the current stream index
(starting from 1). In \gls{dataplotgetdefaultlegend:Nnnnn}, this can be used to
reference current stream index. In the end hook, it may be used to
reference the final stream index, which will be the total number of
streams. (In the start hook, it will be zero.) The \action{plot}
action assigns the primary return value (and the secondary
\optfmt{stream-count}) value to the value of this integer.

\cmddef{ldataplotxkeyint}
Used by \gls{DTLplot} to keep track of the current $x$ column key.
That is, the index (starting from 1) of the current item in the
\plotopt{x} comma-separated list.

\cmddef{ldataplotykeyint}
Used by \gls{DTLplot} to keep track of the current $y$ column key.
That is, the index (starting from 1) of the current item in the
\plotopt{y} comma-separated list.

\subsection{Post-Stream Hooks}
\label{sec:plotpoststreamhooks}

\cmddef{DTLformatlegend}
The legend code is encapsulated with \gls{DTLformatlegend}. The
default is to draw the legend in a colour box with a white
background and a black border. Note that this will cause the legend
to blank out the region of the plot drawn behind it.
The default definition simply does:
\begin{compactcodebox*}
\gls{setlength}\marg{\gls{fboxrule}}\marg{1.1pt}\comment{sets the border width}
\gls{fcolorbox}\marg{black}\marg{white}\margm{legend}
\end{compactcodebox*}

\cmddef{DTLcustomlegend}
This command is used to position the legend with the
\plotoptval{legend}{custom} setting. By default, this simply does:
\begin{compactcodebox}
\cmd{node} \marg{\gls{DTLformatlegend}\margm{legend code}};
\end{compactcodebox} 
This should be redefined as applicable to position the legend in the
required place. The command should expand to valid \sty{tikz} (or \sty{pgf}) code.
See \exampleref{ex:growthscatter6col2dbmap2customlegend}.


\cmddef{dataplotlegendaddbegin:}
Adds the beginning legend code to \gls{ldataplotlegendtl}. By
default, this inserts the beginning of a \env{tabular} environment:
\begin{compactcodebox}
\csfmt{cs\_new:Nn} \gls{dataplotlegendaddbegin:}
\marg{
  \csfmt{tl\_put\_left:Nn} \gls{ldataplotlegendtl}
   \marg{ \csfmt{begin} \marg{ tabular } \marg{ c l } }
}
\end{compactcodebox}

\cmddef{dataplotlegendaddend:}
Adds the end legend code to \gls{ldataplotlegendtl}. By
default, this inserts the end of a \env{tabular} environment:
\begin{compactcodebox}
\csfmt{cs\_new:Nn} \gls{dataplotlegendaddend:}
\marg{
  \csfmt{tl\_put\_right:Nn} \gls{ldataplotlegendtl}
   \marg{ \csfmt{end} \marg{ tabular } }
}
\end{compactcodebox}

As described in \sectionref{sec:plotstreamfns}, the default legend text is obtained
with \gls{dataplotgetdefaultlegend:Nnnnn}. This constructs the
legend text according to the number of items in the database list
\meta{db-list}, the \plotopt{x} list, and the \plotopt{y} list.
The applicable commands (described below) are added unexpanded to
the legend token list variable but their arguments are expanded to
ensure that the correct values are present when the legend is
finally drawn.

In the following legend commands, \meta{db-index} is the index of the
database name in the \meta{db-list} supplied to \gls{DTLplot}, \meta{x-index}
is the index of the \meta{x-key} within the \plotopt{x} list, and
\meta{y-index} the index of the \meta{y-key} within the \plotopt{y} list.
This is not the same as the column index (which can be obtained
with \code{\gls{dtlcolumnindex}\margm{db-name}\margm{key}}). For example,
with the following:
\begin{codebox}
\gls{DTLplot}\marg{growthdata,growthdata2}\marg{
 \plotoptvalm{x}{Exp1Time,Exp2Time,Exp3Time},
 \plotoptvalm{y}{Exp1Count,Exp2Count,Exp3Count},
 \plotopt{legend}
}
\end{codebox}
The \meta{db-index} of \qt{growthdata2} is~2 as it's the second in
the list \code{growthdata,growthdata2}, the \meta{x-index} of
\qt{Exp1Time} is 1 as it's the first in the \plotopt{x} list
(coincidentally that also happens to be its column index),
and the \meta{y-index} of \qt{Exp3Count} is 3 as it's the third in
the \plotopt{y} list (but its column index is 6). Where the indexes
are optional, the default value is 0.

If data is obtained from more than one database and more than one
column for the \plotopt{x} variable, then the legend row will be in
the form:
\begin{compactcodebox}
\meta{name} \meta{x-header} / \meta{y-header}
\end{compactcodebox}
If there is only one database, the name will be omitted:
\begin{compactcodebox}
\meta{x-header} / \meta{y-header}
\end{compactcodebox}
If there is only one \plotopt{x} variable then the \meta{x-header}
and separator will be omitted, so with more than one database and
more than one \plotopt{y} variable:
\begin{compactcodebox}
\meta{name} \meta{y-header}
\end{compactcodebox}
If there is only one database and only one \plotopt{x} variable,
then only the \meta{y-header} will be used if the \plotopt{y} option
contained more than one key otherwise only the \meta{name} will be
shown.

The above \meta{name}, \meta{x-header}, \meta{y-header} and
slash separator are obtained with the commands described below.
However, bear in mind that although
\gls{dataplotgetdefaultlegend:Nnnnn} is used at the end of each plot
stream (and so, can reliably access variables such as
\gls{ldataplotstreamindexint}), the legend commands below are only
expanded when the legend is drawn after all the streams have been
plotted, at which point it's too late to access stream variables.

\cmddef{DTLplotlegendname}
This produces the \meta{name} part of the legend (the optional
argument is ignored), and
which defaults to the database name \meta{db-name} unless you have
supplied a mapping for \meta{db-name} with:
\cmddef{DTLplotlegendsetname}
This will make \gls{DTLplotlegendname} use \meta{text} instead of
\meta{db-name}. This command is simply a user-level interface that
puts the mapping in the following property list:
\cmddef{ldataplotlegendnamesprop}
If you have \LaTeX3 syntax on, you can access this property list
directly. A token list variable is defined specifically for
accessing values in this property list:
\cmddef{ldataplotlegendnametl}

If the legend includes \meta{name} and at least
\meta{y-header}, \gls{DTLplotlegendname} will be followed by:
\cmddef{DTLplotlegendnamesep}
This defaults to a space.

\cmddef{DTLplotlegendxy}
This command is used to produce the 
\code{\meta{x-header} / \meta{y-header}} part where there are
multiple \plotopt{x} column keys. The default definition is:
\begin{compactcodebox}
\gls{DTLplotlegendx}\oargm{db-index}\margm{db-name}\oargm{x-index}\margm{x-key}\comment{}
\gls{DTLplotlegendxysep}
\gls{DTLplotlegendy}\oargm{db-index}\margm{db-name}\oargm{y-index}\margm{y-key}
\end{compactcodebox}

\cmddef{DTLplotlegendx}
The \meta{x-header} text, which defaults to the header for the column identified
by the given key (the optional arguments are ignored) unless you have supplied 
a mapping with:
\cmddef{DTLplotlegendsetxlabel}
This will make \gls{DTLplotlegendx} use \meta{text} instead of the
column header for the given column key. This command is simply 
a user-level interface that
puts the mapping in the following property list:
\cmddef{ldataplotlegendxlabelsprop}
If you have \LaTeX3 syntax on, you can access this property list
directly. A token list variable is defined specifically for
accessing values in this property list:
\cmddef{ldataplotlegendxlabeltl}

\cmddef{DTLplotlegendxysep}
The separator between the \meta{x-header} and \meta{y-header}. This
defaults to a slash \code{/} with a space on either side.

\cmddef{DTLplotlegendy}
The \meta{y-header} text, which defaults to the header for the column identified
by the given key (the optional arguments are ignored) unless you have supplied a mapping with:
\cmddef{DTLplotlegendsetylabel}
This will make \gls{DTLplotlegendy} use \meta{text} instead of the
column header for the given column key. This command is simply 
a user-level interface that
puts the mapping in the following property list:
\cmddef{ldataplotlegendylabelsprop}
If you have \LaTeX3 syntax on, you can access this property list
directly. A token list variable is defined specifically for
accessing values in this property list:
\cmddef{ldataplotlegendylabeltl}

\section{Conditionals} 
\label{sec:plotconds}

The following conditionals are defined by \sty{dataplot}. These are
\TeX\ style \csmetafmt{if}{name}{} conditionals that can be switched
on or off with the corresponding \csmetafmt{}{name}{true} and
\csmetafmt{}{name}{false} commands. There are corresponding settings
that do this, such as \plotopt{box} and \plotopt{grid}.

\cmddef{ifDTLbox}
Determines whether or not to enclose the plot in a box. This
conditional may be changed with the \plotopt{box} setting.

\cmddef{ifDTLgrid}
Determines whether or not to draw a grid. This
conditional may be changed with the \plotopt{grid} setting.

\cmddef{ifDTLshowlines}
Determines whether or not to use plot lines.
This conditional is changed by the \plotopt{style} setting.

\cmddef{ifDTLshowmarkers}
Determines whether or not to use plot markers.
This conditional is changed by the \plotopt{style} setting.

\begin{information}
The \plotopt{style} setting doesn't provide an option which switches
both \gls{ifDTLshowlines} and \gls{ifDTLshowmarkers} to false, since that
combination makes no sense. If you explicitly change these
conditionals, make sure you don't set them both to false.
\end{information}

\cmddef{ifDTLxaxis}
Determines whether or not to display the $x$ axis. This conditional
is changed by the \plotopt{axes} setting.

\cmddef{ifDTLxminortics}
Determines whether or not to display the $x$ axis minor tick marks.
This conditional may be changed with the \plotopt{x-minor-ticks} setting.

\cmddef{ifDTLxticsin}
Determines whether or not to display the $x$ axis tick marks inwards
or outwards (if they should be displayed).  This conditional may be
changed with the \plotopt{x-tick-dir} setting, where
\plotoptval{x-tick-dir}{in} is equivalent to setting the conditional to
true and \plotoptval{x-tick-dir}{out} is equivalent to setting the
conditional to false.

\cmddef{ifDTLxtics}
Determines whether or not to display the $x$ axis tick marks.
This conditional may be changed with the \plotopt{x-ticks} setting.

\cmddef{ifDTLyaxis}
Determines whether or not to display the $y$ axis. This conditional
is changed by the \plotopt{axes} setting.

\cmddef{ifDTLyminortics}
Determines whether or not to display the $y$ axis minor tick marks.
This conditional may be changed with the \plotopt{y-minor-ticks} setting.

\cmddef{ifDTLyticsin}
Determines whether or not to display the $y$ axis tick marks inwards
or outwards (if they should be displayed).  This conditional may be
changed with the \plotopt{y-tick-dir} setting, where
\plotoptval{y-tick-dir}{in} is equivalent to setting the conditional to
true and \plotoptval{y-tick-dir}{out} is equivalent to setting the
conditional to false.

\cmddef{ifDTLytics}
Determines whether or not to display the $y$ axis tick marks.
This conditional may be changed with the \plotopt{y-ticks} setting.

\subsection{Lengths}
\label{sec:plotlengths}

The following length registers are defined by \sty{dataplot}.
They may be changed with \gls{setlength} or, if available, via a
setting.

\cmddef{DTLlegendxoffset}
The $x$ offset from the border of the plot and the legend.
This register is changed by the \plotopt{legend-offset} setting.

\cmddef{DTLlegendyoffset}
The $y$ offset from the border of the plot and the legend.
This register is changed by the \plotopt{legend-offset} setting.

\cmddef{DTLminminortickgap}
The suggested minimum distance between minor tick marks.

\cmddef{DTLminorticklength}
The minor tick mark length.

\cmddef{DTLmintickgap}
The suggested minimum distance between tick marks when the gap is
not specified. Ignored for the applicable axis if \plotopt{x-tick-gap}, 
\plotopt{y-tick-gap}, \plotopt{x-tick-points} or \plotopt{y-tick-points} are
specified.

\cmddef{DTLplotheight}
The plot height. This register is set by the \plotopt{height} option.

\cmddef{DTLplotwidth}
The plot width. This register is set by the \plotopt{width} option.

\cmddef{DTLticklabeloffset}
The offset from the axis to the tick label.

\cmddef{DTLticklength}
The tick mark length.

\subsection{Counters}
\label{sec:plotcounters}

The following counters are defined by \sty{dataplot}. They can be
globally changed with \gls{setcounter} or locally changed with the
corresponding setting.

\ctrdef{DTLplotroundXvar}
The rounding value for default $x$ tick mark labels. This value is
ignored if the labels are explicitly provided with
\plotopt{x-tick-labels} or if \plotoptval{x-ticks}{false}.
The corresponding setting is \plotopt{round-x}.

\ctrdef{DTLplotroundYvar}
The rounding value for default $y$ tick mark labels. This value is
ignored if the labels are explicitly provided with
\plotopt{y-tick-labels} or if \plotoptval{y-ticks}{false}.
The corresponding setting is \plotopt{round-y}.

\subsection{Macros}
\label{sec:plotmacros}

\cmddef{DTLplotlinecolors}
The expansion text of this command should be a comma-separated list
of colours (suitable for use in the argument of \gls{color}).
The \plotopt{line-colors} option redefines this command. The default
definition is:
\begin{compactcodebox}
\cmd{newcommand}\marg{\gls{DTLplotlinecolors}}\marg{red, green, blue, yellow,
 magenta, cyan, orange, black, gray}
\end{compactcodebox}
Note that spaces and empty items will be removed. Use \code{\marg{}} or
\gls{relax} to indicate the default colour.

\cmddef{DTLplotlines}
The expansion text of this command should be a comma-separated list of 
line styles. The \plotopt{lines} option redefines this command. The default
definition is:
\begin{compactcodebox*}
\cmd{newcommand}\marg{\gls{DTLplotlines}}\marg{
  \gls{pgfsetdash}\marg{}\marg{0pt},\comment{solid line}
  \gls{pgfsetdash}\marg{\marg{10pt}\marg{5pt}}\marg{0pt},
  \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}}\marg{0pt},
  \gls{pgfsetdash}\marg{\marg{1pt}\marg{5pt}}\marg{0pt},
  \gls{pgfsetdash}\marg{\marg{5pt}\marg{5pt}{1pt}{5pt}}\marg{0pt},
  \gls{pgfsetdash}\marg{\marg{1pt}\marg{3pt}}\marg{0pt}
}
\end{compactcodebox*}
Note that spaces and empty items will be removed. Use \code{\marg{}} or
\gls{relax} to indicate the line should be omitted for the
corresponding plot stream.

\cmddef{DTLplotmarkcolors}
The expansion text of this command should be a comma-separated list
of colours (suitable for use in the argument of \gls{color}).
The \plotopt{mark-colors} option redefines this command. The default
definition is:
\begin{compactcodebox}
\cmd{newcommand}\marg{\gls{DTLplotmarkcolors}}\marg{red, green, blue, 
 yellow, magenta, cyan, orange, black, gray}
\end{compactcodebox}
Note that spaces and empty items will be removed. Use \code{\marg{}} or
\gls{relax} to indicate the default colour.

\cmddef{DTLplotmarks}
The expansion text of this command should be a comma-separated list of 
plot marks.  The \plotopt{marks} option redefines this command. The default
definition is:
\begin{compactcodebox*}
\cmd{newcommand}*\marg{\gls{DTLplotmarks}}\marg{
  \gls{pgfuseplotmark}\marg{o},
  \gls{pgfuseplotmark}\marg{x},
  \gls{pgfuseplotmark}\marg{+},
  \gls{pgfuseplotmark}\marg{square},
  \gls{pgfuseplotmark}\marg{triangle},
  \gls{pgfuseplotmark}\marg{diamond},
  \gls{pgfuseplotmark}\marg{pentagon},
  \gls{pgfuseplotmark}\marg{asterisk},
  \gls{pgfuseplotmark}\marg{star}
}
\end{compactcodebox*}
Note that spaces and empty items will be removed. Use \marg{} or
\gls{relax} to indicate the marker should be omitted for the
corresponding plot stream.

\cmddef{DTLplotdisplayticklabel}
Both \gls{DTLplotdisplayXticklabel} and \gls{DTLplotdisplayYticklabel}
are initially defined to simply use \gls{DTLplotdisplayticklabel} to
encapsulate the tick labels. This means that if you want the same
formatting for both $x$ and $y$ tick labels, you can redefine this
command instead of redefining both 
\gls{DTLplotdisplayXticklabel} and \gls{DTLplotdisplayYticklabel}.
For example:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLplotdisplayticklabel}}\oarg{1}\marg{\cmd{ensuremath}\marg{\#1}}
\end{codebox}
Alternatively, you can use the \plotopt{tick-label-style} option to
change the node style (see \exampleref{ex:plotxynodestyle}).

Note that if the tick labels are automatically generated from the
data (rather than by specifying them with \plotopt{x-tick-labels} or
\plotopt{y-tick-labels}) then the argument will be a \idx{datumitem}
where the string part is the \idx{formattednumber}.  If you prefer a
\idx{plainnumber} you can redefine \gls{DTLplotdisplayticklabel} to
use \gls{datatooldatumvalue:Nnnnn} (which requires \LaTeX3 syntax
on).

\cmddef{DTLplotdisplayXticklabel}
This command encapsulates the $x$-tick labels.

\cmddef{DTLplotdisplayYticklabel}
This command encapsulates the $y$-tick labels.

\cmddef{DTLXAxisStyle}
This command should expand to the \sty{tikz} options that set the
line style for the $x$-axis. The \plotopt{x-axis-style} and
\plotopt{axis-style} options redefine this command.

\cmddef{DTLYAxisStyle}
This command should expand to the \sty{tikz} options that set the
line style for the $y$-axis. The \plotopt{y-axis-style} and
\plotopt{axis-style} options redefine this command.

\cmddef{DTLmajorgridstyle}
This command should expand to the \sty{tikz} options that set the
line style for the major grid. The
\plotopt{major-grid-style} option redefines this command.

\cmddef{DTLminorgridstyle}
This command should expand to the \sty{tikz} options that set the
line style for the minor grid. If this command is redefined to
nothing, the minor grid won't be drawn. The
\plotopt{minor-grid-style} option redefines this command.

\section{Adding to a Plot Stream at the Start or End}
\label{sec:plotstreamhooks}

These commands are provided for use in the start and end hooks to
add extra plot streams. However, they are largely redundant now that
\gls{DTLplot} can take a comma-separated list of \plotopt{y} values.

\cmddef{dtlplothandlermark}
Only for use within the hooks, this command essentially does:
\begin{compactcodebox}
\gls{pgftransformreset}
\gls{pgfplothandlermark}\margm{mark code}
\end{compactcodebox}
and ensures that \gls{dataplotapplypgftransform:} occurs after the
hook. You can use \gls{pgfplothandlermark} directly but remember
that the plot marks will be distorted by the \gls{DTLplot} transformation
matrix if it is still in effect.

\cmddef{DTLplotstream}
Adds data from the columns identified by the keys \meta{x-key} and
\meta{y-key} in the database \meta{db-name} to the current \sty{pgf}
plot stream. The \meta{condition} argument is as for \gls{DTLplot}.

\chapter{Converting a \BibTeX\ database
into a \stytext{datatool} database (\stytext{databib} package)}
\label{sec:databib}

\pkgdef{databib}
The \sty{databib} package was added to the \sty{datatool} bundle in
version 1.01 (2007-08-17) and provides a way of converting \BibTeX\ data
into a \sty{datatool} database. Note that this still requires the
document to be compiled with \app{bibtex}.

\begin{information}
If you want a flexible system for managing bibliographies, consider
using \sty{biblatex} and \app{biber}, which is far more efficient
than using \sty{databib}. I don't intend to develop \sty{databib} any
further as it's far quicker to use \sty{biblatex} and \app{biber}.
\end{information}

The \sty{databib} package was rewritten in version 3.0 to use
\LaTeX3 commands. The \sty{xkeyval} package has been dropped.
Rollback to version 2.32 is available:
\begin{codebox}
\cmd{usepackage}\marg{databib}[=v2.32]
\end{codebox}
Note that if \sty{datatool} hasn't already been loaded, this will
also apply rollback to \sty{datatool}. Problems may occur if a newer
release of \sty{datatool} has already been loaded.

The \sty{databib} package works by using \BibTeX\ with the custom
\inlinefiledef{databib.bst} style file to create a \ext+{bbl} file
that contains commands to construct the \sty{datatool} database (as
opposed to the more typical behaviour of writing the bibliography
typesetting commands to the \ext{bbl} file). The commands
\gls{DTLloadbbl} or \gls{DTLloadmbbl} are provided to set the
bibliography style to \optfmt{databib}, identify the required
\ext+{bib} file (or files), create the database and input the
\ext{bbl} file.  See \sectionref{sec:dtlbibnew} for further details.

Once the database has been created, it can then be sorted using
\gls{DTLsortdata} or \gls{DTLsort}. Bear in mind that a column may
not be created if there was no selected reference with the
corresponding field set in the \ext{bib} file.

Whilst the database can be iterated over with \gls{DTLmapdata} or
\gls{DTLforeach}, a wrapper command \gls{DTLforeachbibentry} is
provided (see \sectionref{sec:foreachbib}) for custom loops, and
\gls{DTLbibliography} (see \sectionref{sec:thebib}) may be used to
display the contents of the database in a format similar the
basic \optfmt{plain}, \optfmt{abbrv} and \optfmt{alpha} \app{bibtex}
styles.

\begin{information}
An \qt{entry} in the context of \sty{databib}, means the row of data
in the database corresponding to the information obtained from a
\ext{bib} entry. An entry field is one of the special \sty{databib}
database column keys, and the field value is the value for that
column in the current row. The column keys that should always be set
are \databibcolkey{CiteKey} (the label used in \gls{cite} that uniquely
identifies the entry) and \databibcolkey{EntryType} (the \BibTeX\ entry type
in lowercase, without the leading \code{@}). The other fields are
listed in \sectionref{sec:databibfields}.
\end{information}

\section{Package Options}
\label{sec:databibpkgopts}

The \sty{databib} package will automatically load \sty{datatool}, if
it has not already been loaded. The \sty{databib} package has the
following options:

\optiondef{databib.style}
This option sets the bibliography style to \meta{name}, which may be
one of: \optfmt{plain}, \optfmt{abbrv} or \optfmt{alpha} (see
\sectionref{sec:bibstyle}).  The style can be also be set with
\gls{DTLbibliographystyle} after \sty{databib} has loaded.

\optiondef{databib.auto}
If true, \app{bibtex} will be run from the shell escape. When this
is set, \gls{DTLloadbbl} may only be used in the preamble.

\begin{information}
These package options can't be used in \gls{DTLsetup}.
There is no sub-key corresponding to \sty{databib}.
\end{information}

All other options will be passed to \sty{datatool}, if it hasn't
already been loaded, or will be set with \gls{DTLsetup} (if
allowed) otherwise.

\section{\BibTeX: An Overview}
\label{sec:bibtex}

This document assumes that you have at least some passing
familiarity with \BibTeX, but here follows a brief refresher.

\BibTeX\ is an external application used in conjunction with \LaTeX.
When you run \BibTeX, you need to specify the name of the document's
auxiliary (\ext+{aux}) file. \BibTeX\ then reads
this file and looks for the commands \gls{bibstyle} (which indicates
which bibliography style (\ext+{bst}) file to load), \gls{bibdata}
(which indicates which bibliography database (\ext+{bib}) files to
load) and \gls{citation} (produced by \gls{cite} and \gls{nocite}, which
indicates which entries should be included in the bibliography).
\BibTeX\ then creates a file with the extension \ext+{bbl} which
contains the bibliography, formatted according to the layout defined
in the bibliography style file.

In general, given a document called, say, \filefmt{mydoc.tex}, you
will have to perform the following steps to ensure that the
bibliography and all citations are up-to-date (replace
\appfmt{latex} with \appfmt{pdflatex}, \appfmt{xelatex} or
\appfmt{lualatex}, as applicable):
\begin{enumerate}
\item Run \LaTeX:
\begin{terminal}
latex mydoc
\end{terminal}
This writes the citation information to the auxiliary file.
The bibliography currently doesn't exists, so it isn't displayed.
Citations will appear in the document as [\idx{unknowncite}] since the internal
cross-references don't exist yet (similar to \idx{unknownref} which
marks unknown references).

\item Run \BibTeX:
\begin{terminal}
bibtex mydoc
\end{terminal}
This reads the auxiliary file, and creates a file with the extension
\ext+{bbl} which typically contains the typeset bibliography.

\item Run \LaTeX:
\begin{terminal}
latex mydoc
\end{terminal}
Now that the \ext{bbl} file exists, the bibliography can be input
into the document. The internal cross-referencing information for the 
bibliography can now be written to the auxiliary file.

\item Run \LaTeX:
\begin{terminal}
latex mydoc
\end{terminal}
The cross-referencing information can be read from the auxiliary
file.
\end{enumerate}

\subsection{\BibTeX\ database}
\label{sec:bibdatabase}

The bibliographic data required by \BibTeX\ must be stored in 
a file with the extension \ext+{bib}, where each entry is stored
in the form:
\begin{compactcodebox}
@\meta{entry-type}\marg{\meta{cite-key},
  \meta{field} = \meta{value},
  \mbox{}\vdots
  \meta{field} = \meta{value}
}
\end{compactcodebox}
The \meta{value} may be delimited with braces or double-quotes or
may be a number or a predefined string. For example:
\begin{compactcodebox}
@STRING\marg{TUGBOAT = \marg{TUGboat}}

@article\marg{brown2022,
 author = "Mary-Jane Brown",
 title = \marg{An interesting paper},
 journal = TUGBOAT,
 year = 2022
}
\end{compactcodebox}
The above first defines a string constant (\qtt{TUGBOAT}) that may
be used instead of a literal string in the field value. Note that
the constant isn't delimited by braces or double-quotes when
referenced in the field value.

The entry type, given by \meta{entry-type} above, indicates the
type of document. This depends on which ones are supported by the
\ext{bst} bibliography style file, but the standard ones are:
\optfmt{article}, \optfmt{book}, \optfmt{booklet}, \optfmt{inbook},
\optfmt{incollection}, \optfmt{inproceedings} (with synonym
\optfmt{conference}), \optfmt{manual}, \optfmt{mastersthesis},
\optfmt{misc}, \optfmt{phdthesis}, \optfmt{proceedings},
\optfmt{techreport} or \optfmt{unpublished}.

The \meta{cite-key} above is a unique label identifying this entry,
and is the label used in the argument of \gls{cite} or \gls{nocite}.
The available fields depends on the entry type (and the \ext{bst}
file), for example, the field \optfmt{journal} is required for the
\optfmt{article} entry type, but is ignored for the
\optfmt{inproceedings} entry type. The standard fields are:
\optfmt{address}, \optfmt{author}, \optfmt{booktitle},
\optfmt{chapter}, \optfmt{edition}, \optfmt{editor},
\optfmt{howpublished}, \optfmt{institution}, \optfmt{journal},
\optfmt{key}, \optfmt{month}, \optfmt{note}, \optfmt{number},
\optfmt{organization}, \optfmt{pages}, \optfmt{publisher},
\optfmt{school}, \optfmt{series}, \optfmt{title}, \optfmt{type},
\optfmt{volume} and \optfmt{year}.

\begin{information}
The \sty{databib} package was developed in 2007 and designed to work with
\BibTeX, which is now quite old and has little localisation support.
The newer \app{biber}, which was initially released in 2009 and is
used with \sty{biblatex}, provides more flexible support and 
a less rigid name syntax.
\end{information}

With \BibTeX, author and editor names must be entered in one of the following
ways:
\begin{enumerate}
\item \meta{First names} \meta{von part} \meta{Surname}, \meta{Jr part}

The \meta{von part} is optional and is identified by the name(s)
starting with lowercase letters. The final comma followed by 
\meta{Jr part} is also optional. Examples:
\begin{compactcodebox}
author = "Henry James de Vere"
\end{compactcodebox}
In the above, the first names are Henry James, the \qt{von part} is
\qt{de} and the surname is \qt{Vere}. There is no \qt{junior part}.
\begin{compactcodebox}
author = "Mary-Jane Brown, Jr"
\end{compactcodebox}
In the above, the first name is Mary-Jane, there is no von part,
the surname is Brown and the junior part is Jr.
\begin{compactcodebox}
author = "Peter \marg{Murphy Allen}"
\end{compactcodebox}
In the above, the first name is Peter, and the surname is Murphy 
Allen.  Note that in this case, the surname must be grouped, otherwise
Murphy would be considered part of the forename.
\begin{compactcodebox}
author = "Maria Eliza \marg{\gls{MakeUppercase}\marg{d}e La} Cruz"
\end{compactcodebox}
In the above, the first name is Maria Eliza, the von part is
De La, and the surname is Cruz. In this case, the von part starts
with an uppercase letter, but specifying:
\begin{compactcodebox}
author = "Maria Eliza De La Cruz"
\end{compactcodebox}
would make \BibTeX\ incorrectly classify \qt{Maria Eliza De La} as
the first names, and the von part would be empty. Since \BibTeX\
doesn't understand \LaTeX\ commands, using
\code{\marg{\gls{MakeUppercase}\marg{d}e La}}
will trick \BibTeX\ into thinking that it starts with a 
lowercase letter.

\item \meta{von part} \meta{Surname}, \meta{Forenames}

Again the \meta{von part} is optional, and is determined by the
case of the first letter. For example:
\begin{compactcodebox}
author = "de Vere, Henry James"
\end{compactcodebox}
\end{enumerate}

Multiple authors or editors should be separated by the key word
\optfmt{and}, for example:
\begin{compactcodebox}
author = "Michel Goossens and Frank Mittlebach and Alexander Samarin"
\end{compactcodebox}

Below is an example of a book entry:
\begin{compactcodebox}
@book\marg{latexcomp,
  title     = "The \cmd{LaTeX}\gls{cs.space}Companion",
  author    = "Michel Goossens and Frank Mittlebach and 
               Alexander Samarin",
  publisher = "Addison-Wesley",
  year      = 1994
}
\end{compactcodebox}
Note that numbers may be entered without delimiters, as in \code{year = 1994}.
There are also some predefined strings, including those for the month
names. It's best to use these strings instead of the actual
month name, as the way the month name is displayed depends on the
bibliography style. For example:
\begin{compactcodebox}
@article\marg{Cawley2007b,
author = "Gavin C. Cawley and Nicola L. C. Talbot",
title  = "Preventing over-fitting in model selection via \marg{B}ayesian
          regularisation of the hyper-parameters",
journal = "Journal of Machine Learning Research",
volume  = 8,
pages   = "841--861",
month   = APR,
year    = 2007
}
\end{compactcodebox}

You can concatenate strings using the \verb"#" character, for example:
\begin{compactcodebox}
month  = JUL \# "\idx{nbsp}31\idx{nbsp}--\idx{nbsp}" \# AUG \# "\idx{nbsp}4",
\end{compactcodebox}
Depending on the bibliography style, this may be displayed as:
July~31~--~August~4, or it may be displayed as:
Jul~31~--~Aug~4.

\subsection{Column Keys (Fields)}
\label{sec:databibfields}

Each row of a \sty{databib} database corresponds to an entry in the
\ext{bib} file. The custom \file{databib.bst} file ensures that
\BibTeX\ creates a file where each selected citation is added as a
new row to the database, and each column in that row corresponds to
a \ext{bib} field supported by \file{databib.bst}. Note that
although \BibTeX\ fields are case-insensitive, the \sty{datatool}
column keys are case-sensitive.
These case-sensitive column keys are described below.

\optiondef{databibcolkey.CiteKey}
This column will always be set and corresponds to the entry \meta{cite-key},
that is the label used in \gls{cite} that uniquely
identifies the entry. The value in this field will match the \meta{cite-key}
given in the \ext{bib} file.

\optiondef{databibcolkey.EntryType}
This column will always be set to the \BibTeX\ entry type in
lowercase, without the leading \code{@}. For example, an entry
defined with \code{@ARTICLE} in the \ext{bib} file will have the
\databibcolkey{EntryType} column set to \code{article}.

The remaining columns correspond to the field provided by
\file{databib.bst} and will be null if not set or not supported by the
entry type. The columns will only be added to the database if the
field was found by \BibTeX\ (that is, the field is present in the
\ext{bib} file and supported by the entry type).

\optiondef{databibcolkey.Abstract}
Corresponds to the \optfmt{abstract} \ext{bib} field.

\optiondef{databibcolkey.Address}
Corresponds to the \optfmt{address} \ext{bib} field.

\optiondef{databibcolkey.Author}
Corresponds to the \optfmt{author} \ext{bib} field.

\optiondef{databibcolkey.BookTitle}
Corresponds to the \optfmt{booktitle} \ext{bib} field.

\optiondef{databibcolkey.Chapter}
Corresponds to the \optfmt{chapter} \ext{bib} field.

\optiondef{databibcolkey.Citations}
Corresponds to the \optfmt{citations} \ext{bib} field. This is
intended for use in CV style documents to show the number of times
the reference has been cited by others. It's not a count of the
number of times the reference has been cited in the current
document.

\optiondef{databibcolkey.Date}
Corresponds to the \optfmt{date} \ext{bib} field. This may be used
instead of the \optfmt{year} and \optfmt{month} fields.

\optiondef{databibcolkey.DOI}
Corresponds to the \optfmt{doi} \ext{bib} field. Note that the DOI
can contain awkward characters. Whilst the \csfmt{doi} command
provided by the \styfmt{doi} package is designed to support such
identifiers, that command can't be used in the argument of another
command. Therefore this field will be set with
\gls{DTLnewbibliteralitem} instead of \gls{DTLnewbibitem}.
Note that any braces within the value must be balanced.

\optiondef{databibcolkey.Edition}
Corresponds to the \optfmt{edition} \ext{bib} field.

\optiondef{databibcolkey.Editor}
Corresponds to the \optfmt{editor} \ext{bib} field.

\optiondef{databibcolkey.EID}
Corresponds to the \optfmt{eid} \ext{bib} field.

\optiondef{databibcolkey.Eprints}
Corresponds to the \optfmt{eprints} or \optfmt{eprint} \ext{bib} field.
Since this may contain problematic characters, this field will be set with
\gls{DTLnewbibliteralitem} instead of \gls{DTLnewbibitem}.

\optiondef{databibcolkey.EprintType}
Corresponds to the \optfmt{eprinttype} \ext{bib} field.
(Only set if \optfmt{eprints} or \optfmt{eprint} is also set.)

\optiondef{databibcolkey.File}
Corresponds to the \optfmt{file} \ext{bib} field.
Since this may contain problematic characters, this field will be set with
\gls{DTLnewbibliteralitem} instead of \gls{DTLnewbibitem}.

\optiondef{databibcolkey.HowPublished}
Corresponds to the \optfmt{howpublished} \ext{bib} field.

\optiondef{databibcolkey.Institution}
Corresponds to the \optfmt{institution} \ext{bib} field.

\optiondef{databibcolkey.ISBN}
Corresponds to the \optfmt{isbn} \ext{bib} field.

\optiondef{databibcolkey.ISSN}
Corresponds to the \optfmt{issn} \ext{bib} field.

\optiondef{databibcolkey.Journal}
Corresponds to the \optfmt{journal} \ext{bib} field.

\optiondef{databibcolkey.Key}
Corresponds to the \optfmt{key} \ext{bib} field.

\optiondef{databibcolkey.Month}
The month is obtained from the \optfmt{month} \ext{bib} field, but
predefined strings are available that will use \gls{DTLmonthname} to
make sorting easier.

\optiondef{databibcolkey.Note}
Corresponds to the \optfmt{note} \ext{bib} field.

\optiondef{databibcolkey.Number}
Corresponds to the \optfmt{number} \ext{bib} field.

\optiondef{databibcolkey.Organization}
Corresponds to the \optfmt{organization} \ext{bib} field.

\optiondef{databibcolkey.Pages}
Corresponds to the \optfmt{pages} \ext{bib} field.

\optiondef{databibcolkey.Publisher}
Corresponds to the \optfmt{publisher} \ext{bib} field.

\optiondef{databibcolkey.PubMed}
Corresponds to the \optfmt{pubmed} \ext{bib} field.

\optiondef{databibcolkey.School}
Corresponds to the \optfmt{school} \ext{bib} field.

\optiondef{databibcolkey.Series}
Corresponds to the \optfmt{series} \ext{bib} field.

\optiondef{databibcolkey.Title}
Corresponds to the \optfmt{title} \ext{bib} field.

\optiondef{databibcolkey.Type}
Corresponds to the \optfmt{type} \ext{bib} field.

\optiondef{databibcolkey.Url}
Corresponds to the \optfmt{url} \ext{bib} field.
Since this may contain problematic characters, this field will be set with
\gls{DTLnewbibliteralitem} instead of \gls{DTLnewbibitem}.

\optiondef{databibcolkey.UrlDate}
Corresponds to the \optfmt{urldate} \ext{bib} field.
(Only set if \optfmt{url} is also present.)

\optiondef{databibcolkey.Volume}
Corresponds to the \optfmt{volume} \ext{bib} field.

\optiondef{databibcolkey.Year}
Corresponds to the \optfmt{year} \ext{bib} field.

\section{Loading a \stytext{databib} database}
\label{sec:loadbbl}

The \sty{databib} package always requires the \file{databib.bst}
bibliography style file (which is supplied with \sty{datatool}).
This ensures that the \ext{bbl} file will be in the format required
for \gls{DTLloadbbl}. That is, the \ext{bbl} file will contain the
commands that construct the database with the bibliographic data
(see \sectionref{sec:dtlbibnew}).

You need to use \gls{cite} or \gls{nocite} as usual. If you want to
add all entries in the \ext+{bib} file to the \sty{datatool} database,
you can use \code{\gls{nocite}\marg{*}}.

\cmddef{DTLloadbbl}
The \meta{db-name} argument may be empty to indicate the
\opt{default-name}.
This command performs several functions:

\begin{enumerate}
\item writes the following line in the auxiliary file:
\begin{compactcodebox*}
\gls{bibstyle}\marg{databib}
\end{compactcodebox*}
which tells \BibTeX\ to use the \file{databib.bst}
\BibTeX\ style file; 

\item writes \code{\gls{bibdata}\margm{bib list}} to the
auxiliary file, which tells \BibTeX\ which \ext{bib} files to
use;

\item creates a \sty{datatool} database called \meta{db name};

\item loads the file \meta{bbl file} if it exists. (If the optional
\meta{bbl file} argument is omitted, the value
defaults to \code{\gls{jobname}.bbl}, which is the usual name for
a \ext{bbl} file.) If the \ext{bbl} file doesn't exist, the
database \meta{db name} will remain empty.
\end{enumerate}

You then need to compile your document with \LaTeX\
and then run \BibTeX\ on the auxiliary file, as described in
\sectionref{sec:bibtex}. This will create a \ext{bbl} file which
contains all the commands required to add the bibliography information
to the \sty{datatool} database called \meta{db name}. The next
time you \LaTeX\ your document, this file will be read, and the
information will be added to the database \meta{db name}. 

\begin{important}
Note that \gls{DTLloadbbl} doesn't generate any text.
Once you have loaded the data, you can display the bibliography using
\gls{DTLbibliography} (described in \sectionref{sec:thebib}) or you
can iterate through it with \gls{DTLforeachbibentry} described in
\sectionref{sec:foreachbib}.
\end{important}

Note that the \file{databib.bst} \BibTeX\ style file provides
additional fields (see \sectionref{sec:databibfields}) that are not
supported by the basic \BibTeX\ styles, and so are ignored by the
three predefined \sty{databib} styles (\optfmt{plain},
\optfmt{abbrv} and \optfmt{alpha}). If you want these fields to be
displayed in the bibliography you will need to modify the
bibliography style (see \sectionref{sec:modbibstyle}). The simplest
method is to added the extra information in the \gls{DTLendbibitem}
hook.

If you use the standard \BibTeX\ month abbreviations (\optfmt{JAN},
\optfmt{FEB}, etc), the \file{databib.bst} style will convert those
to:
\cmddef{DTLmonthname}
The definition varies depending on the \opt{databib.style} and also
on whether or not any localisation support has been provided.

\section{The \stytext{databib} Database Construction Commands}
\label{sec:dtlbibnew}

The \ext+{bbl} file created by the \file{databib.bst} \BibTeX\ style
file contains database construction commands rather than code to
typeset the bibliography. These commands don't have the database
name included in an argument (since the \file{databib.bst} style
file doesn't have that information). Instead, they rely on the
following placeholder command:
\cmddef{DTLBIBdbname}
This should expand to the \sty{databib} database name.

This file is input by \gls{DTLloadbbl} and
\gls{DTLloadmbbl}, but note that there's no database creation
command within the \ext{bbl} file. The database creation is
performed by \gls{DTLnewdb} within the definition of
\gls{DTLloadbbl} and \gls{DTLloadmbbl}. 

This means that it's possible to append to an existing database by
simply inputting the \ext{bbl} file (with a check for existence).
However, you must make sure that the \optfmt{databib} bibliography
style is set and that \gls{DTLBIBdbname} is defined to expand to the
database name.

\cmddef{DTLnewbibrow}
Appends a new row to the database. This essentially just does:
\begin{compactcodebox}
\starredcs{DTLnewrow}\marg{\gls{DTLBIBdbname}}
\end{compactcodebox}
Note that this is the starred form that doesn't test for the
database existence.

\cmddef{DTLnewbibitem}
Adds a new entry to the final row of the database. This essentially
just does:
\begin{compactcodebox}
\starredcs{DTLnewdbentry}\marg{\gls{DTLnewbibitem}}\margm{col-key}\margm{item}
\end{compactcodebox}
Again, the starred form is used which doesn't test for the database
existence.

\cmddef{DTLnewbibliteralitem}
This command is used for fields with literal values, such as
\databibcolkey{Url} and \databibcolkey{DOI}. The \meta{item} will
be detokenized before being added to the final row of the database.
Note that any braces within \meta{item} must be balanced.

\begin{important}
Remember that the category code of tokens within database items will
be lost when a database is written to a file with \gls{DTLwrite}.
This means that these literal fields may cause a problem if you
choose to save the database. The best solution in this case is to
save to a \idx{CSV} file which can then be loaded with
\iooptval{csv-content}{literal}.
\end{important}

\section{Sorting a \stytext{databib} database}
\label{sec:bibsort}

Once a database has been loaded with \gls{DTLloadbbl} (or
\gls{DTLloadmbbl}), it can be sorted using \gls{DTLsortdata} or
\gls{DTLsort} (see \sectionref{sec:sort}).
The \sty{databib} package automatically does:
\begin{compactcodebox*}
\gls{dtlSortWordCommands}\marg{\cmd{let}\gls{DTLmonthname}\cmd{@firstofone}}
\end{compactcodebox*}
This means that \gls{DTLmonthname} will expand to its numeric
argument when the sort values are created, which makes it easier to
sort chronologically. Just make sure to use the \BibTeX\ month
strings (\optfmt{JAN}, \optfmt{FEB}, etc) as in the examples in 
\sectionref{sec:databibexs}.

For example, to sort in reverse chronological order:
\begin{codebox}
\gls{DTLsortdata}\oarg{\sortdataoptval{missing-column-action}{ignore}}
 \marg{mybib}\comment{database name}
 \marg{\databibcolkey{Date}=\sortdatacolumnopt{descending},\databibcolkey{Year}=\sortdatacolumnopt{descending},\databibcolkey{Month}=\sortdatacolumnopt{descending}}
\end{codebox}
This allows for dates to be specified in either the
\databibcolkey{Date} field or in the \databibcolkey{Year} and
\databibcolkey{Month} fields.

If you want to sort by \databibcolkey{Author} or \databibcolkey{Editor}, remember
that those fields will contain comma-separated lists where each
element is in the form
\code{\margm{von}\margm{surname}\margm{jr}\margm{forenames}}.
For example, if a \ext{bib} entry has:
\begin{compactcodebox}
author = \marg{von Parrot, Jr, Ann and José Arara}
\end{compactcodebox}
then the \databibcolkey{Author} field for the corresponding row in the
\sty{databib} database will be:
\begin{compactcodebox}
\marg{von}\marg{Parrot}\marg{Jr}\marg{Ann},\marg{}\marg{Arara}\marg{}\marg{José}
\end{compactcodebox}
This means that if the database is sorted by \databibcolkey{Author}:
\begin{compactcodebox}
\gls{DTLsortdata}\marg{mybib}\marg{Author}
\end{compactcodebox}
then the sort value will be:
\begin{compactcodebox}
vonParrotJrAnn,AraraJosé
\end{compactcodebox}
This may or may not be sufficient, depending on your requirements.

To make it easier to adjust the sort value for the \databibcolkey{Author}
and \databibcolkey{Editor} fields, \sty{databib} provides:
\cmddef{DTLbibsortencap}
This may be used as the sort \sortdataopt{encap} function. This command
tests if \meta{col-idx} corresponds to the column index for the
\databibcolkey{Author} or \databibcolkey{Editor} keys. If it doesn't, it
will simply expand to \meta{value}. If it does, it will expand the
comma-separated value so that each element is
separated with:
\cmddef{DTLbibsortnamesep}
and each element is encapsulated with:
\cmddef{DTLbibsortname}
which, by default, does:
\begin{codebox}
\cmd{tl\_if\_empty:nF} \margm{von} \marg{ \meta{von} \idx{l3sp} }
\meta{surname}
\cmd{tl\_if\_empty:nF} \margm{jr} \marg{ , \idx{l3sp} \meta{jr} }
\gls{datatoolpersoncomma}
\meta{forename}
\end{codebox}
This means that the earlier example will expand to:
\begin{compactcodebox}
von Parrot, Jr\gls{datatoolpersoncomma} Ann\gls{DTLbibsortnamesep}
Arara\gls{datatoolpersoncomma} José
\end{compactcodebox}
This produces a better result where there are multiple authors. You
can redefine \gls{DTLbibsortname} if a different sort value is
required. For example, to ignore the \meta{von} and \meta{jr} parts:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLbibsortname}}[4]\marg{\comment{}
 \#2\gls{datatoolpersoncomma} \#4}
\end{codebox}
Remember that the definition must be expandable.

For example, the following sorts by \databibcolkey{Author}, but if the
\databibcolkey{Author} field hasn't been set it will sort by
\databibcolkey{Editor}, and if the \databibcolkey{Editor} hasn't been set, it will
sort by \databibcolkey{Title}. In the event that there are duplicate
primary values, the secondary sort will be by the \databibcolkey{Title}:
\begin{codebox}
\gls{DTLsortdata}\oarg{\sortdataoptval{encap}{\gls{DTLbibsortencap}}}
 \marg{mybib}\marg{Author=\marg{\sortdatacolumnoptvalm{replacements}{Editor,Title}},Title}
\end{codebox}

\section{Displaying a \stytext{databib} database}
\label{sec:thebib}

A \sty{databib} database which has been loaded using 
\gls{DTLloadbbl} (described in \sectionref{sec:loadbbl}) can be 
displayed using:
\cmddef{DTLbibliography}
where \meta{db name} is the name of the database. This command
internally iterates over the database, formatting each row that
matches \meta{condition} according to the current style. It's
provided as a convenient shortcut that does:
\begin{compactcodebox}
\cbeg{DTLthebibliography}\oargm{condition}\margm{db-name}
\starredcs{DTLforeachbibentry}\oargm{condition}\margm{db-name}\marg{\comment{}
 \gls{DTLbibitem} \gls{DTLformatbibentry} \gls{DTLendbibitem}
}\comment{}
\cend{DTLthebibliography}
\end{compactcodebox}

Within the optional argument \meta{condition}, you may use any of the 
commands that may be used within the optional argument of
\gls{DTLforeach} (that is, any condition that may be used in
\gls{ifthenelse}, see \sectionref{sec:ifthen}).
\emph{In addition}, you may use the following commands, which
reference values in the current row.

\cmddef{DTLbibfieldexists}
This tests whether the field with the given label exists and is not
null for the current entry.  The field label is the column key of
the database.

For example, suppose you have loaded a \sty{databib} database
called \qt{mybib} using \gls{DTLloadbbl} (described in 
\sectionref{sec:loadbbl}) then the following bibliography will only
include those entries which have a \databibcolkey{Year} field:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldexists}\marg{Year}}\marg{mybib}
\end{codebox}

\cmddef{DTLbibfieldiseq}
This tests whether the value of the field given by 
\meta{field label} equals \meta{value}. If the field doesn't
exist for the current entry, this evaluates to false.
For example, the following will produce a bibliography which
only contains entries which have the \databibcolkey{Year} field set to 2004:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldiseq}\marg{Year}\marg{2004}}\marg{mybib}
\end{codebox}

\cmddef{DTLbibfieldcontains}
This tests whether the value of the field given by \meta{field label}
contains \meta{value}. For example, the following will produce
a bibliography which only contains entries where the author field
contains the name \qt{Knuth}:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldcontains}\marg{Author}\marg{Knuth}}\marg{mybib}
\end{codebox}

\cmddef{DTLbibfieldislt}
This tests whether the value of the field given by \meta{field label}
is lexicographically less than \meta{value}. If the field doesn't exist for the
current entry, this evaluates to false.
For example, the following will produce a bibliography which only
contains entries whose \databibcolkey{Year} field is less than 1983:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldislt}\marg{Year}\marg{1983}}\marg{mybib}
\end{codebox}

\cmddef{DTLbibfieldisle}
This tests whether the value of the field given by \meta{field label}
is lexicographically less than or equal to \meta{value}. If the field doesn't exist 
for the current entry, this evaluates to false.
For example, the following will produce a bibliography which only
contains entries whose \databibcolkey{Year} field is less than or equal to 1983:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldisle}\marg{Year}\marg{1983}}\marg{mybib}
\end{codebox}

\cmddef{DTLbibfieldisgt}
This tests whether the value of the field given by \meta{field label}
is lexicographically greater than \meta{value}. If the field doesn't exist for the
current entry, this evaluates to false.
For example, the following will produce a bibliography which only
contains entries whose \databibcolkey{Year} field is greater than 1983:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldisgt}\marg{Year}\marg{1983}}\marg{mybib}
\end{codebox}

\cmddef{DTLbibfieldisge}
This tests whether the value of the field given by \meta{field label}
is lexicographically greater than or equal to \meta{value}. If the field doesn't exist 
for the current entry, this evaluates to false.
For example, the following will produce a bibliography which only
contains entries whose \databibcolkey{Year} field is greater than or equal to 1983:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldisge}\marg{Year}\marg{1983}}\marg{mybib}
\end{codebox}

Note that \gls{DTLbibliography} uses \gls{DTLforeachbibentry}
(described in \sectionref{sec:foreachbib}) so you may also 
test the value of the counter \ctr{DTLbibrow} within
\meta{conditions} (as in \exampleref{ex:topnbib}), but bear in mind
that the counter is only incremented after testing the condition
(and then only if the condition evaluates to true). 
You may also use the boolean commands defined
by the \sty{ifthen} package, such as \csfmt{not}.

\section{Changing the bibliography style}
\label{sec:bibstyle}

The style of the bibliography produced using \gls{DTLbibliography} 
may be set with the \opt{databib.style} package option, or with:
\cmddef{DTLbibliographystyle}
Note that this is \emph{not} the same as \gls{bibliographystyle},
as the \sty{databib} package uses its custom \file{databib.bst}
bibliography style file.

For example:
\begin{codebox}
\cmd{usepackage}[\optval{databib.style}{plain}]\marg{databib}
\end{codebox}
or
\begin{codebox}
\gls{DTLbibliographystyle}\marg{plain}
\end{codebox}
Both of the above set the \optfmt{plain} bibliography style. This is, in fact, the
default style, so it need not be specified.

Available styles are: \optfmt{plain}, \optfmt{abbrv} and
\optfmt{alpha}. These are similar to the standard \BibTeX\ styles of
the same name, but are by no means identical. The most notable
difference is that these styles do not sort the bibliography. It is
up to you to sort the bibliography using \gls{DTLsortdata} or
\gls{DTLsort} (described in \sectionref{sec:sort}).

\subsection{Modifying an existing style}
\label{sec:modbibstyle}

You can use \gls{DTLforeachbibentry} and format each row according
to your particular requirements. However, the predefined styles used
by \gls{DTLbibliography}, \gls{DTLmbibliography}, and
\gls{DTLformatthisbibentry} provide a more convenient method if they are
sufficient for your needs. The hooks described in this section allow
you to make minor adjustments the selected style.

\begin{information}
Some of the commands described here do more than simply typeset the
required text. They also perform some internal checks to keep track
of the end of a sentence to determine whether or not a period needs
to be inserted or if the spacefactor needs adjusting. 
\end{information}

\cmddef{DTLformatauthor}
Formats an author's name.
\cmddef{DTLformateditor}
Formats an editor's name.
\cmddef{DTLformatsurnameonly}
Formats the name, omitting the forenames.

The list of authors and editors are stored in the \sty{databib}
database as a comma separated list where each item is in the form \margm{von
part}\margm{surname}\margm{jr part}\margm{forenames}. This assists
with sorting by author or editor (but this may require adjustment,
see \sectionref{sec:bibsort}). Each element of the
list can then be passed to \gls{DTLformatauthor} or
\gls{DTLformateditor} or \gls{DTLformatsurnameonly} for formatting. 

Within the definitions of \gls{DTLformatauthor} and \gls{DTLformateditor}, you may
use the following commands.
\cmddef{DTLformatforenames}
This is used by the \optfmt{plain} and \optfmt{alpha} styles to display the author's
forenames.

\cmddef{DTLformatabbrvforenames}
This is used by the \optfmt{abbrv} style to just show 
the author's initials, which are obtained from \meta{forenames} by
\gls{DTLstoreinitials} (see \sectionref{sec:initials}).

\cmddef{DTLformatsurname}
This is used to format the surname.

\cmddef{DTLformatvon}
If the \meta{von part} is empty, this command does nothing,
otherwise it displays its argument followed by:
\cmddef{DTLpostvon}
This expands to a non-breaking space by default.

\cmddef{DTLformatjr}
If the \meta{jr part} is empty, this command displays nothing, 
otherwise it does a comma and space followed by its argument.

For example, suppose you want the author's surname to appear
first in small capitals, followed by a comma and the forenames. This
can be achieved with:
\begin{codebox}
\cmd{renewcommand}*\marg{\gls{DTLformatauthor}}[4]\marg{\comment{}
 \gls+{textsc}\marg{\gls{DTLformatvon}\marg{\#1}\gls{DTLformatsurname}\marg{\#2}\gls{DTLformatjr}\marg{\#3}},
 \gls{DTLformatforenames}\marg{\#4}\comment{}
}
\end{codebox}

\ctrdef{DTLmaxauthors}
The counter \ctr{DTLmaxauthors} is used to determine the
maximum number of authors to display for a given entry. If the
author list contains more than that number of authors,
\gls{etalname} is used.

\ctrdef{DTLmaxeditors}
The \ctr{DTLmaxeditors} counter is analogous to the
\ctr{DTLmaxauthors} counter. It is used to determine the
maximum number of editor names to display.

\cmddef{DTLformatauthorlist}
Used by styles to format the list of author names (which
will be obtained from the \databibcolkey{Author} field). Each name is
formatted with to \gls{DTLformatauthor}.

\cmddef{DTLformateditorlist}
Used by styles to format the list of editor names (which
will be obtained from the \databibcolkey{Editor} field). Each name is
formatted according to \gls{DTLformateditor}. The list is followed
by a comma and space and either \gls{editorname} or \gls{editorsname},
depending on whether the list contains one or more elements.

The above two list commands internally use:
\cmddef{DTLformatbibnamelist}
This formats a list of names, where each name in the list must be in the form
\code{\margm{von}\margm{surname}\margm{jr}\margm{forenames}} and
\meta{fmt-cs} must have those four arguments for its syntax. If
the list has more than \meta{max} items, it will be truncated with
\gls{etalname}.

Within a list of names, the separators used are:
\cmddef{DTLandlast}
Placed between two names when the list contains more than two names.
\cmddef{DTLandnotlast}
Placed between all except the last two names when the list contains 
more than two names.
\cmddef{DTLtwoand}
Placed between the two names when the list only contains two names.
The definitions of \gls{DTLandlast} and \gls{DTLtwoand} use
\gls{DTLlistand} for \qt{and}.

\cmddef{DTLformatdate}
This is used by the styles to insert the date. It first tests if the
\databibcolkey{Date} field is set. If so, it will format that field
with \gls{DTLbibdatefield}. Otherwise, it tests if the
\databibcolkey{Year} and \databibcolkey{Month} fields are set.

\cmddef{DTLformatpages}
This is used by the styles to insert the page or page range. If 
the \databibcolkey{Pages} field is set, this will be displayed
preceded by the language-sensitive \inlineglsdef{pagename} or 
\inlineglsdef{pagesname}. The textual tag and the contents of the
\databibcolkey{Pages} field are separated with:
\cmddef{DTLpostpagename}
which expands to a non-breakable space by default.

\cmddef{DTLbibitem}
Used at the start of each bibliography item within
\gls{DTLbibliography}. It uses \gls{bibitem} to provide a marker,
such as [1], and writes the citation information to the \ext+{aux}
file in order to resolve references on the next \LaTeX\ run.

\cmddef{DTLmbibitem}
Used at the start of each bibliography item within
\gls{DTLmbibliography}, and is analogous to \gls{DTLbibitem}.

\cmddef{DTLendbibitem}
A hook used by \gls{DTLbibliography} and \gls{DTLmbibliography} that
does nothing by default, but may be redefined to include additional
content at the end of the current entry.

Within the definition command, you
may use the commands \gls{DTLbibfield}, \gls{DTLifbibfieldexists}
and \gls{DTLifanybibfieldexists}, which are described in 
\sectionref{sec:foreachbib}. For example, if you have used the
\optfmt{abstract} field in any of your entries, you can display the
abstract as follows:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLendbibitem}}\marg{\comment{}
 \gls{DTLifbibfieldexists}\marg{Abstract}\marg{\gls{DTLpar}\cmd{textbf}\marg{Abstract}
 \cbeg{quote}\gls{DTLbibfield}\marg{Abstract}\cend{quote}}\marg{}\comment{}
}
\end{codebox}

\cmddef{DTLbibformatdigital}
This command is not used by any of the styles but may be added to
the definition of \gls{DTLendbibitem} to include the digital
information. The result varies depending on whether or not
the \sty{hyperref} or \sty{url} packages have been loaded.
The content will be included in the following order:

\begin{itemize}
  \item If the \databibcolkey{PubMed} field is set, this will be displayed
with \gls{DTLbibpubmed}.

  \item If the \databibcolkey{DOI} field is set, this will be
displayed with \gls{DTLbibdoi}.

  \item If the \databibcolkey{Url} field is set, this will be
displayed with \gls{DTLbiburl}, and if the \databibcolkey{UrlDate}
field is also set, this will be displayed with \gls{DTLbiburldate}.

  \item If the \databibcolkey{Eprints} field is set, this will be
displayed with \gls{DTLbibeprints}, where the second argument will
either be the content of the \databibcolkey{EprintType} field (if
set) or \qtt{eprint} otherwise.
\end{itemize}

The commands used by \gls{DTLbibformatdigital}, described below, may be
redefined to customize the output.

\cmddef{DTLbibpubmed}
This is used to format the \databibcolkey{PubMed} field. The field
content is passed as the argument.
If the \sty{hyperref} package has been loaded, the \meta{pmid} will be a
hyperlink.

\cmddef{DTLbibpubmedtag}
The tag used at the start of \gls{DTLbibpubmed}. By default, this
simply expands to \code{\gls+{textsc}\marg{pmid}:\visiblespace}.

\cmddef{DTLbibpubmedhome}
Used by \gls{DTLbibpubmed} in the formation of the hyperlink, if
applicable.

\cmddef{DTLbibdoi}
This is used to format the \databibcolkey{DOI} field. The field
content is passed as the argument. Remember that this field is set
with \gls{DTLnewbibliteralitem} which detokenizes the content before
adding it to the database. This means that \gls{DTLbibdoi} doesn't
make any category code changes as it expects the argument to be
detokenized already.

If the \sty{hyperref} package has been loaded, the DOI will be a
hyperlink otherwise it will simply be displayed in a monospaced
font with \gls{url} (if defined) or \csfmt{texttt} otherwise.
If \sty{hyperref} isn't required but the DOI needs better
formatting, try loading the \sty{url} package.

\cmddef{DTLbibdoitag}
The tag used at the start of \gls{DTLbibdoi}. By default, this
simply expands to \code{\gls+{textsc}\marg{doi}:\visiblespace}.

\cmddef{DTLbibdoihome}
Used by \gls{DTLbibdoi} in the formation of the hyperlink, if
applicable.

\cmddef{DTLbibeprints}
This command is used to format the \databibcolkey{Eprints} field.
The field content is passed as the first argument. The second
argument is set by \gls{DTLbibformatdigital} to either the value of
the \databibcolkey{EprintType} field, if set, or \qtt{eprint}
otherwise.

\begin{information}
The content of the \databibcolkey{Eprints} field is assumed to be a
URL. If not, you will need to redefine \gls{DTLbibeprints} as
applicable.
\end{information}

If \sty{hyperref} has been loaded, a hyperlink will be created with
the second argument as the link text, otherwise the first argument
will be displayed in a monospaced font, prefixed by the second
argument.

\cmddef{DTLbiburl}
This command is used to format the \databibcolkey{Url} field.
The field content is passed as the argument. If \gls{url} has been
defined (for example, by loading \sty{hyperref} or the \sty{url}
package) then that will be used to format the argument otherwise it
will simply be typeset in a monospaced font.

\cmddef{DTLbiburldate}
This command is used to format the \databibcolkey{UrlDate} field.
The argument provided by \gls{DTLbibformatdigital} will be:
\begin{compactcodebox}
\gls{DTLbibdatefield}\marg{\databibcolkey{UrlDate}}
\end{compactcodebox}
The definition of \gls{DTLbiburldate} is:
\begin{compactcodebox}
\cmd{space} (\gls{DTLbibaccessedname}: \meta{date})
\end{compactcodebox}
which places the date in parentheses prefixed with:
\cmddef{DTLbibaccessedname}

\section{Iterating through a \stytext{databib} database}
\label{sec:foreachbib}

The hooks described in \sectionref{sec:modbibstyle} to adjust the
format of \gls{DTLbibliography} may still
not meet your needs. For example, you may be required
to list journal papers and conference proceedings in separate
sections. In which case, you may find it easier to iterate through
the bibliography using:
\cmddef{DTLforeachbibentry}
This iterates through the database identified by
\meta{db-name} and does \meta{body} if \meta{condition} is met.
The starred version uses the read-only \starredcs{DTLforeach} and
the unstarred version uses the unstarred \gls{DTLforeach}. This
means that you can use \gls{dtlbreak} in \meta{body} to terminate
the loop after the current iteration. Note that you can't have
explicit paragraph breaks in \meta{body} (that is, \gls{par} or a blank line in
your source code). If you need a paragraph break, use \gls{DTLpar}.

Although \gls{DTLforeach} makes global changes,
\gls{DTLforeachbibentry} only makes local assignments for the
placeholder commands, which means that it's unsuitable to display the references
in a~\env{tabular}-like environment.
\cmddef{gDTLforeachbibentry}
This is as \gls{DTLforeachbibentry} but the placeholder commands are
globally assigned.

For each row of the database, the following commands are set:
\begin{itemize}
\item \inlineglsdef{DBIBcitekey} This is the
unique label which identifies the current entry (as used in the
argument of \gls{cite} and \gls{nocite}).

\item \inlineglsdef{DBIBentrytype} This is the current entry type 
(converted to lowercase), and will be one of: \optfmt{article}, \optfmt{book}, 
\optfmt{booklet}, \optfmt{inbook}, \optfmt{incollection}, \optfmt{inproceedings},
\optfmt{manual}, \optfmt{mastersthesis}, \optfmt{misc}, \optfmt{phdthesis}, \optfmt{proceedings}, 
\optfmt{techreport} or \optfmt{unpublished}. (Note that even if you used the
entry type \optfmt{conference} in your \ext{bib} file, its entry type
will be set to \optfmt{inproceedings}).
\end{itemize}

The remaining fields may be accessed using:
\cmddef{DTLbibfield}
where \meta{field label} may be any of those listed in
\sectionref{sec:databibfields}.

If you want to encapsulate a field with a command, you can simply
include \code{\gls{DTLbibfield}\margm{field name}} in the command's
argument. For example:
\begin{codebox}
\cmd{strong}\marg{\gls{DTLbibfield}\marg{Year}}
\end{codebox}

However, it's also possible to use:
\cmddef{DTLencapbibfield}
This is similar to \code{\gls{DTLbibfield}\margm{field name}} but
encapsulates the field value with \meta{cs}. For example:
\begin{codebox}
\gls{DTLencapbibfield}\marg{\cmd{strong}}\marg{Year}
\end{codebox}
The difference is that in this case the field value will be directly
passed to the formatting command. Also if the field isn't set, the
command won't be used in the second case but will be used in the
first. For example, \gls{DTMdate} (provided by the \sty{datetime2}
package) requires its argument to be in the form
\code{\meta{YYYY}-\meta{MM}-\meta{DD}} (there are some other formats
as well, see the \sty{datetime2} manual for further details).
This means that it's not possible to do, say:
\begin{badcodebox}
\gls{DTMdate}\marg{\gls{DTLbibfield}\marg{Date}}
\end{badcodebox}
Instead use:
\begin{codebox}
\gls{DTLencapbibfield}\marg{\gls{DTMdate}}\marg{Date}
\end{codebox}

\begin{information}
Both \gls{DTLbibfield} and \gls{DTLencapbibfield} expand to nothing if
the field isn't set or doesn't exist.
\end{information}

\cmddef{DTLbibdatefield}
This command is used \gls{DTLformatdate} and \gls{DTLbibformatdigital} to format
the \databibcolkey{Date} and \databibcolkey{UrlDate} fields,
respectively. The default definition simply uses \gls{DTLbibfield}
but may be redefined to format the date.


Alternatively, you can assign the value of a field to a control
sequence \meta{cs} using:
\cmddef{DTLbibfieldlet}

You can determine if a field exists for a given entry using
\cmddef{DTLifbibfieldexists}
If the field given by \meta{field label} exists for the current
bibliography entry, it does \meta{true part}, otherwise it
does \meta{false part}.

\cmddef{DTLifanybibfieldexists}
This is similar to \gls{DTLifbibfieldexists} except that the
first argument is a list of field names. If one or more of
the fields given in \meta{field label list} exists for the
current bibliography item, this does \meta{true part}, otherwise
it does \meta{false part}.

\cmddef{DTLformatbibentry}
This formats the bibliography entry for the current row. It
checks for the existence of the command 
\csmetafmt{DTLformat}{entry-type}{}, where \meta{entry-type}
is given by \gls{DBIBentrytype}. These commands are defined
by the bibliography style. There is also a~version for use with
\gls{gDTLforeachbibentry}:
\cmddef{gDTLformatbibentry}
It's also possible to use \gls{DTLformatbibentry} for a specific key,
rather than using it within \gls{DTLforeachbibentry}.
\cmddef{DTLformatthisbibentry}
This formats the row identified by \meta{cite key} in the database
\meta{db-name} using the same format as \gls{DTLformatbibentry}.

Note that none of the above three commands use
\gls{bibitem}. You can manually insert 
\code{\gls{bibitem}\margm{cite key}}
in front of the command, or you can use:
\cmddef{DTLcustombibitem}
This is like \gls{bibitem}\oargm{text}\margm{cite key} except that it uses
\meta{item code} instead of \gls{item}\oargm{text} and 
\meta{ref text} instead of \code{\cmd{the}\cmd{value}\marg{\cmd{@listctr}}}.

\cmddef{DTLcomputewidestbibentry}
This computes the widest bibliography entry over all entries
satisfying \meta{condition} in the database \meta{db-name},
where the label is given by \meta{bib-label}, and the result
is stored in \meta{cs}, which may then be used in the
argument of the \env{thebibliography} environment. The
optional \meta{condition} argument should be suitable for use in
\gls{ifthenelse}, and you may use. any of the 
commands that may be used within the optional argument of
\gls{DTLbibliography}, described in \sectionref{sec:thebib}

\ctrdef{DTLbibrow}
The counter \ctr{DTLbibrow} keeps track of the current
bibliography entry. This is reset at the start of each
\gls{DTLforeachbibentry} and is incremented if \meta{condition}
is met.

\section{Multiple Bibliographies}
\label{sec:multibib}

It is possible to have more than one bibliography in a document,
but it then becomes necessary to have a separate auxiliary (\ext+{aux}) file
for each bibliography, and each auxiliary file must then be
passed to \BibTeX. In order to do this, you need to use
\cmddef{DTLmultibibs}
where \meta{list} is a comma separated list of names. 
For each \meta{name} in the list, this command creates an
auxiliary file called \metafilefmt{}{name}{.aux}.

\begin{important}
In the following commands, the \meta{mbib} argument must be 
one of the names listed in \gls{DTLmultibibs}.
\end{important}

When you want to cite an entry for a given bibliography named
in \gls{DTLmultibibs}, you must use:
\cmddef{DTLcite}
This is analogous to \code{\gls{cite}\oargm{text}\margm{label-list}}, 
but writes the \gls{citation} command to \metafilefmt{}{mbib}{.aux} instead
of to the document's main auxiliary file. It also ensures that
the cross-referencing labels are based on \meta{mbib}, to allow
you to have the same reference in more than one bibliography
without incurring a \qt{multiply defined} warning message. Note
that you can still use \gls{cite} to add citation information to
the main auxiliary file.

If you want to add an entry to the bibliography without producing
any text, you can use
\cmddef{DTLnocite}
which is analogous to \code{\gls{nocite}\margm{label-list}}, where
again the citation information is written to \metafilefmt{}{mbib}{.aux}
instead of the document's main auxiliary file.

\cmddef{DTLloadmbbl}
This is similar to \gls{DTLloadbbl},
described in \sectionref{sec:loadbbl}. This creates
a new \sty{datatool} database called \meta{db-name} and inputs
\metafilefmt{}{mbib}{.bbl} (if it exists), which should contain the
commands required to construct the database.

\cmddef{DTLmbibliography}
This is similar to \gls{DTLbibliography},
but is required when displaying a bibliography in which elements have
been cited using \gls{DTLcite} and \gls{DTLnocite}. 
As \gls{DTLbibliography}, it iterates over the database using
\starredcs{DTLforeachbibentry}.

\section{Examples}
\label{sec:databibexs}

The examples here use one or both of the following sample files.
The first file, \filefmt{sample1.bib}, contains some of my own
publications with a mixture of entry types:
\begin{compactcodebox}[breakable]
\sampleIbib
\end{compactcodebox}
The second file, \filefmt{sample2.bib}, contains fictitious
references:
\begin{compactcodebox}[breakable]
\sampleIIbib
\end{compactcodebox}
Note that the \ext{bib} entry types and field names are
case-insensitive. I've used a mixture of cases above.

\subsection{Sort by Author}
\label{sec:sortauthorex}

\mExampleref{ex:sortauthor} demonstrates the basic use of \sty{databib}.
The \optfmt{abbrv} style is set with the \opt{databib.style} 
package option. I've also set the locale to English. This requires
\sty{datatool-english}, which should be installed separately.
\begin{codebox}
\cmd{usepackage}[\optval{databib.style}{abbrv},\optval{locales}{en}]\marg{databib}
\end{codebox}
Next is the instruction to \BibTeX\ to select all the citations in the 
\ext{bib} file:
\begin{codebox}
\gls{nocite}\marg{*}
\end{codebox}
The following line will add the appropriate code in the
\ext{aux} file to instruct \BibTeX\ to fetch the data from
\filefmt{sample2.bib} and create a \ext{bbl} file (according to the
format specified by \file{databib.bst}), which will then be input, if
it exists:
\begin{codebox}
\gls{DTLloadbbl}\marg{mybib}\marg{sample2}
\end{codebox}
This will do the following:
\begin{enumerate}
\item Writes the line:
\begin{compactcodebox}
\gls{bibstyle}\marg{databib}
\end{compactcodebox}
to the auxiliary file. This tells \BibTeX\ to use \file{databib.bst}
(which is supplied with this package). You therefore shouldn't
use \gls{bibliographystyle}.

\item Writes the line:
\begin{compactcodebox}
\gls{bibdata}\marg{sample2}
\end{compactcodebox}
to the auxiliary file. This tells \BibTeX\ that the bibliography
data is stored in the file \filefmt{sample2.bib}.

\item Creates a \sty{datatool} database called \optfmt{mybib} (using
\gls{DTLnewdb}).

\item If the \ext{bbl} file exists, \gls{DTLloadbbl} will input the
file (which contains code to add the bibliography data to the
database), otherwise it does nothing further.

\end{enumerate}
The database is then sorted by author (or title, if there's no author) and then by
title. This can be done with
\gls{DTLsortdata} (see \sectionref{sec:DTLsortdata}):
\begin{codebox}
\gls{DTLsortdata}\marg{mybib}\marg{Author=\marg{\sortdatacolumnoptval{replacements}{Title}},Title}
\end{codebox}
However, bear in mind that the \databibcolkey{Author} field will contain a
comma-separated list of names, with each item in the form
\code{\margm{von}\margm{surname}\margm{jr}\margm{forenames}}.
This means that the names will all be merged together in the sort
value. The \sortdataopt{encap} option can be used to separate the names:
\begin{codebox}
\gls{DTLsortdata}\oarg{\sortdataoptval{encap}{\gls{DTLbibsortencap}}}
 \marg{mybib}\marg{Author=\marg{\sortdatacolumnoptval{replacements}{Title}},Title}
\end{codebox}
This will encapsulate each name in the author list with
\gls{DTLbibsortname}. With the default definition, \qt{von Duck}
will have a sort value starting with \qt{v}. If the \qt{von} should
be ignored when sorting, just redefine \gls{DTLbibsortname} to omit
it (or place it after the surname).

The bibliography is then displayed with:
\begin{codebox}
\gls{DTLbibliography}\marg{mybib}
\end{codebox}

Suppose I save this file as \filefmt{myDoc.tex}, then I need to do:
\begin{terminal}
latex myDoc
bibtex myDoc
latex myDoc
\end{terminal}
The result is shown in \exampleref{ex:sortauthor}.

\begin{resultbox}[float]
\createexample*
[label={ex:sortauthor}, link={sec:sortauthorex},
 title={Bibliography Sorted by Author},
 arara={pdflatex,bibtex,pdflatex,pdfcrop},
 description={Example document that shows a bibliography}
]
{%
\exfile{sample2.bib}{\sampleIIbib}%
\cmd{usepackage}[\optval{databib.style}{abbrv},\optval{locales}{en}]\marg{databib}
}
{%
\gls{nocite}\marg{*}\nl
\gls{DTLloadbbl}\marg{mybib}\marg{sample2}\nl
\gls{DTLsortdata}\oarg{\sortdataoptval{encap}{\gls{DTLbibsortencap}}}\nlsp
 \marg{mybib}\marg{Author=\marg{\sortdatacolumnoptval{replacements}{Title}},Title}\nl
\gls{DTLbibliography}\marg{mybib}
}
\end{resultbox}

\subsection{Tabulate Bib Data}
\label{sec:bibtableex}

Note that it's not necessary to actually display the bibliography if
it's not required (but it would be required if any entries are
referenced with \gls{cite}). If the required entries are simply
selected with \gls{nocite} then this simply provides a convenient
way to convert the data from the \ext{bib} file into a format
compatible with \sty{datatool}. 

\mExampleref{ex:bibtable} makes a minor modification to \exampleref{ex:sortauthor}
so that, instead of using \code{\gls{DTLbibliography}\marg{mybib}}, it displays
the \databibcolkey{Author} and \databibcolkey{Title} values in a table. This can
be done with \gls{DTLdisplaydb} but the \databibcolkey{Author} field will
be a comma-separated list with each element in the form
\code{\margm{von}\margm{surname}\margm{jr}\margm{forenames}}, which
will result in the name elements running together. This can be dealt
with by adjusting \gls{DTLdisplaydbAddItem} so that it encapsulates
the \databibcolkey{Author} value with \gls{DTLformatbibnamelist} (if
it's not null). This assumes the \databibcolkey{Author} column is the first
column in the table (which it will be if it's the first item in the
\displayopt{only-keys} list):
\begin{codebox}
\cmd{RenewDocumentCommand}\gls{DTLdisplaydbAddItem}\marg{ m m m m m m m m }
\marg{\comment{}
 \gls{DTLifnull}\marg{\#2}\comment{}
 \marg{\gls{appto}\#1\marg{---}}\comment{do a dash if null}
 \marg{\comment{}
   \cmd{ifnum}\#7=1
    \gls{appto}\#1\marg{\gls{DTLformatbibnamelist}\marg{\#2}\marg{\cmd{value}\marg{\ctr{DTLmaxauthors}}}\marg{\gls{DTLformatauthor}}}\comment{}
   \cmd{else}
    \gls{appto}\#1\marg{\#3\marg{\#2}}\comment{}
   \cmd{fi}
 }\comment{}
}
\end{codebox}
Note that the above won't work if \opt{store-datum} has been set,
which it isn't by default. The data can now be displayed:
\begin{codebox}
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{only-keys}{Author,Title}}\marg{mybib}
\end{codebox}
The document build is the same as before as \BibTeX\ is still needed
to fetch the data from the \ext{bib} file. Since
\gls{DTLformatauthor} is set by the style and the style has been set
to \optfmt{abbrv}, the forenames are abbreviated.  The result is shown in
\exampleref{ex:bibtable}.

\begin{resultbox}[float]
\createexample*
[label={ex:bibtable}, link={sec:bibtableex},fontsize=10,
 title={Tabulate Bib Data},
 arara={pdflatex,bibtex,pdflatex,pdfcrop},
 description={Example document that shows information from the
bibliography in a table}
]
{%
\exfile{sample2.bib}{\sampleIIbib}%
\cmd{usepackage}[\optval{databib.style}{abbrv},\optval{locales}{en}]\marg{databib}
}
{%
\gls{nocite}\marg{*}\nl
\gls{DTLloadbbl}\marg{mybib}\marg{sample2}\nl
\gls{DTLsortdata}\marg{mybib}\marg{Author=\marg{\sortdatacolumnoptval{replacements}{Title}},Title}\nl
\cmd{RenewDocumentCommand}\gls{DTLdisplaydbAddItem}\marg{ m m m m m m m m }\nl
\marg{\comment{}
 \gls{DTLifnull}\marg{\#2}\comment{}
 \marg{\gls{appto}\#1\marg{---}}\comment{do a dash if null}
 \marg{\commentdbsp{}
   \cmd{ifnum}\#7=1 \nldbdbsp
    \gls{appto}\#1\marg{\gls{DTLformatbibnamelist}
      \marg{\#2}\marg{\cmd{value}\marg{\ctr{DTLmaxauthors}}}\marg{\gls{DTLformatauthor}}}\commentdbsp{}
   \cmd{else} \nldbdbsp
    \gls{appto}\#1\marg{\#3\marg{\#2}}\commentdbsp{}
   \cmd{fi} \nlsp
 }\comment{}%
}\nl
\gls{DTLdisplaydb*}\oarg{\displayoptvalm{only-keys}{Author,Title}}\marg{mybib}
}
\end{resultbox}


\subsection{Publications Since a Given Year}
\label{sec:bibsinceex}

\examplemarginref{ex:bibsince}%
Suppose my boss has asked me to produce a list of my 
publications in reverse chronological order, but doesn't want any 
publications published prior 
to the year 2013. I have a file which contains
all my publications which I keep in my personal \code{TEXMFHOME} tree 
\metafilefmt{}{TEXMFHOME}{/bibtex/bib/}. I could look through this file,
work out the labels for all the publications whose year field
is greater or equal to 2013, and
create a file with a \gls{nocite} command containing all those labels
in a comma separated list in reverse chronological order, 
but I really can't be bothered to do that.
Instead, I can use \sty{databib} to convert my publication data into
a \sty{datatool} database:
\begin{codebox}
\cmd{documentclass}\marg{article}
\cmd{usepackage}\marg{databib}
\end{codebox}
Next is the instruction to \BibTeX\ to select all the citations in the 
\ext{bib} file:
\begin{codebox}
\gls{nocite}\marg{*}
\end{codebox}
Since my own \ext{bib} file isn't available (and is too
long to include), I'm going to use the \filefmt{sample1.bib} file:
\begin{codebox}
\gls{DTLloadbbl}\marg{mybib}\marg{sample1}
\end{codebox}
The database is then sorted in reverse chronological order:
\begin{codebox}
\gls{DTLsortdata}\marg{mybib}\marg{Year=\sortdatacolumnopt{descending},Month=\sortdatacolumnopt{descending}}
\end{codebox}
If the bibliography database is large, sorting and creating
the bibliography may take a while. For large
\ext{bib} files or complex requirements, consider using
\sty{biblatex} and \app{biber} instead.

The data is then displayed with filtering applied, so that only the
entries where the row is greater than or equal to 2013 are shown:
\begin{codebox}
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldisge}\marg{Year}\marg{2013}}\marg{mybib}
\end{codebox}
This is a string comparison, rather than a numerical
comparison, but since all the years are four digits it's sufficient.
The result is shown in \exampleref{ex:bibsince}.

\begin{resultbox}[float]
\createexample*
[label={ex:bibsince}, link={sec:bibsinceex},
 title={List of Publications Since a Given Year},
 arara={pdflatex,bibtex,pdflatex,pdfcrop},
 description={Example document that shows a bibliography in reverse
chronological order}
]
{%
\exfile{sample1.bib}{\sampleIbib}%
\cmd{usepackage}\marg{databib}
}
{%
\gls{nocite}\marg{*}\nl
\gls{DTLloadbbl}\marg{mybib}\marg{sample1}\nl
\gls{DTLsortdata}\marg{mybib}\marg{Year=descending,Month=descending}\nl
\gls{DTLbibliography}\oarg{\gls{DTLbibfieldisge}\marg{Year}\marg{2013}}\marg{mybib}
}
\end{resultbox}

\subsection{Five Most Recent Publications}
\label{sec:topnbibex}

\examplemarginref{ex:topnbib}%
Suppose my boss has asked me to produce a list of my five most 
recent publications (in reverse chronological order). 
I can create the required
document with just a minor modification to \exampleref{ex:bibsince}:
\begin{codebox}
\gls{DTLbibliography}\oarg{\cmd{value}\marg{DTLbibrow}<5}\marg{mybib}
\end{codebox}
This is just a different condition in the optional argument. Note
that the condition is evaluated before the \ctr{DTLbibrow} counter
is incremented (as it's only incremented if the condition is true). 

In addition, to demonstrate the end item hook, I've redefined 
\gls{DTLendbibitem} to show the 
\databibcolkey{ISBN} and \databibcolkey{Url} fields, if they have been set:
\begin{codebox}
\cmd{renewcommand}\marg{\gls{DTLendbibitem}}\marg{\comment{}
 \gls{DTLifbibfieldexists}\marg{ISBN}\comment{}
 \marg{ ISBN: \gls{DTLbibfield}\marg{ISBN}.}\marg{}\comment{}
 \gls{DTLifbibfieldexists}\marg{Url}\comment{}
 \marg{ \gls{DTLencapbibfield}\marg{\gls{url}}\marg{Url}}\marg{}\comment{}
}
\end{codebox}
Note that this will require a package that defines \gls{url}. In
this case, I've used the \sty{url} package, but this may be replaced
with \sty{hyperref} if hyperlinks are required.
The result is shown in \exampleref{ex:topnbib}.

\begin{resultbox}[float]
\createexample*
[label={ex:topnbib}, link={sec:topnbibex},
 title={Five Most Recent Publications},
 arara={pdflatex,bibtex,pdflatex,pdfcrop},
 description={Example document that shows a bibliography in reverse
chronological order showing the five most recent publications}
]
{%
\exfile{sample1.bib}{\sampleIbib}%
\cmd{usepackage}\marg{databib}\nl
\cmd{usepackage}\marg{url}\nl
\gls{DTLloadbbl}\marg{mybib}\marg{sample1}\nl
\gls{DTLsortdata}\marg{mybib}\marg{Year=descending,Month=descending}\nl
\cmd{renewcommand}\marg{\gls{DTLendbibitem}}\marg{\comment{}
 \gls{DTLifbibfieldexists}\marg{ISBN}\comment{}
 \marg{ ISBN: \gls{DTLbibfield}\marg{ISBN}.}\marg{}\comment{}
 \gls{DTLifbibfieldexists}\marg{Url}\comment{}
 \marg{ \gls{DTLencapbibfield}\marg{\gls{url}}\marg{Url}}\marg{}\comment{}
}
}
{%
\gls{nocite}\marg{*}\nl
\gls{DTLbibliography}\oarg{\cmd{value}\marg{DTLbibrow}<5}\marg{mybib}
}
\end{resultbox}

Note that, although \exampleref{ex:topnbib} only shows five items,
the loop iterates over all entries in the database.
It's more efficient (particularly for large databases) to 
terminate the loop after the fifth row with \gls{dtlbreak}. This is done by replacing
\gls{DTLbibliography} with:
\begin{codebox}
\cbeg{DTLthebibliography}\marg{mybib}
 \gls{DTLforeachbibentry}\marg{mybib}
 \marg{\comment{}
   \gls{DTLbibitem} \gls{DTLformatbibentry} \gls{DTLendbibitem}
   \gls{ifthenelse}\marg{\cmd{value}\marg{DTLbibrow}=5}\marg{\gls{dtlbreak}}\marg{}\comment{terminate after row 5}
 }
\cend{DTLthebibliography}
\end{codebox}

\subsection{Compact Bibliography}
\label{sec:compactbibex}

\examplemarginref{ex:compactbib}%
Suppose I don't have much space in my document, and I need to
produce a compact bibliography. Firstly, I can use the
bibliography style \optfmt{abbrv}, either through the package option:
\begin{codebox}
\cmd{usepackage}[\optval{databib.style}{abbrv}]\marg{databib}
\end{codebox}
or using:
\begin{codebox}
\gls{DTLbibliographystyle}\marg{abbrv}
\end{codebox}
Note that in the second case, the style must be set before the
bibliography is displayed, otherwise they will have no effect.

Once I have set the style, I can further modify it thus:
\begin{codebox}
\cmd{renewcommand}*\marg{\gls{DTLtwoand}}\marg{ \gls{cs.amp} }
\cmd{renewcommand}*\marg{\gls{DTLandlast}}\marg{, \gls{cs.amp} }
\cmd{renewcommand}*\marg{\gls{editorname}}\marg{ed.}
\cmd{renewcommand}*\marg{\gls{editorsname}}\marg{eds.}
\cmd{renewcommand}*\marg{\gls{pagesname}}\marg{pp.}
\cmd{renewcommand}*\marg{\gls{pagename}}\marg{p.}
\cmd{renewcommand}*\marg{\gls{volumename}}\marg{vol.}
\cmd{renewcommand}*\marg{\gls{numbername}}\marg{no.}
\cmd{renewcommand}*\marg{\gls{editionname}}\marg{ed.}
\cmd{renewcommand}*\marg{\gls{techreportname}}\marg{T.R.}
\cmd{renewcommand}*\marg{\gls{mscthesisname}}\marg{MSc thesis}
\end{codebox}
Now I can load the bibliography. For this example, I'm
using both sample files (described earlier):
\begin{codebox}
\gls{DTLloadbbl}\marg{mybib}\marg{sample1,sample2}
\end{codebox}
This time the database is sorted alphabetically by the title:
\begin{codebox}
\gls{DTLsortdata}\marg{mybib}\marg{Title}
\end{codebox}
Remember that the required references need to be cited with
\gls{cite} or \gls{nocite}. For simplicity, I have again used:
\begin{codebox}
\gls{nocite}\marg{*}
\end{codebox}
to select them all. As with the previous examples, the bibliography
is displayed with:
\begin{codebox}
\gls{DTLbibliography}\marg{mybib}
\end{codebox}
The first page is shown in \exampleref{ex:compactbib}.

\begin{resultbox}[float]
\createexample*
[label={ex:compactbib}, link={sec:compactbibex},
 title={Compact Bibliography},pages={1},fontsize=10,
 graphicsopts={height=0.9\textheight},
 arara={pdflatex,bibtex,pdflatex,pdfcrop},
 description={Example document that shows a compact bibliography
ordered by title}
]
{%
\exfile{sample1.bib}{\sampleIbib}%
\exfile{sample2.bib}{\sampleIIbib}%
\cmd{usepackage}[\optval{databib.style}{abbrv}]\marg{databib}\nl
\cmd{renewcommand}*\marg{\gls{DTLtwoand}}\marg{ \string\& }\nl
\cmd{renewcommand}*\marg{\gls{DTLandlast}}\marg{, \string\& }\nl
\cmd{renewcommand}*\marg{\gls{editorname}}\marg{ed.}\nl
\cmd{renewcommand}*\marg{\gls{editorsname}}\marg{eds.}\nl
\cmd{renewcommand}*\marg{\gls{pagesname}}\marg{pp.}\nl
\cmd{renewcommand}*\marg{\gls{pagename}}\marg{p.}\nl
\cmd{renewcommand}*\marg{\gls{volumename}}\marg{vol.}\nl
\cmd{renewcommand}*\marg{\gls{numbername}}\marg{no.}\nl
\cmd{renewcommand}*\marg{\gls{editionname}}\marg{ed.}\nl
\cmd{renewcommand}*\marg{\gls{techreportname}}\marg{T.R.}\nl
\cmd{renewcommand}*\marg{\gls{mscthesisname}}\marg{MSc thesis}\nl
\gls{DTLloadbbl}\marg{mybib}\marg{sample1,sample2}\nl
\gls{DTLsortdata}\marg{mybib}\marg{Title}
}
{%
\gls{nocite}\marg{*}\nl
\gls{DTLbibliography}\marg{mybib}
}
\end{resultbox}

\subsection{Highlight a Given Author}
\label{sec:highlightauthorex}

\examplemarginref{ex:highlightauthor}%
Suppose my boss wants me to produce a list of all my publications
(from the file \filefmt{sample1.bib}, as in 
\exampleref{ex:bibsince}). In my real file \filefmt{nlct.bib}, most of my 
publications have multiple co-authors, but suppose my boss would
like me to highlight my name in bold so that when he skims through
the document, he can easily see my name in the list of 
co-authors. I can do this by redefining \gls{DTLformatauthor}
so that it checks if the given surname matches mine. (This 
assumes that none of the other co-author's share my surname.)
\begin{codebox}
\cmd{renewcommand}*\marg{\gls{DTLformatauthor}}[4]\marg{\comment{}
 \marg{\comment{scope the font change}
  \gls{DTLifstringeq}\marg{\#2}\marg{Talbot}\marg{\cmd{bfseries} }\marg{}\comment{}
  \gls{DTLformatforenames}\marg{\#4}
  \gls{DTLformatvon}\marg{\#1}\comment{}
  \gls{DTLformatsurname}\marg{\#2}\comment{}
  \gls{DTLformatjr}\marg{\#3}\comment{}
 }\comment{}
}
\end{codebox}
I have used \gls{DTLifstringeq} (described in 
\sectionref{sec:ifconditions}) to perform the string comparison.

If one or more of my co-authors shared the same surname as
me, I would also have had to check the first name, however there
is regrettably a lack of consistency in my \ext{bib} file when
it comes to my forenames. Sometimes my name is given as
\qt{Nicola L. C. Talbot}, sometimes the middle initials
are omitted, \qt{Nicola Talbot}, or sometimes, just initials
are used, \qt{N. L. C. Talbot}. This can cause problems
when checking the forenames, but as long as the other authors
who share the same surname as me, don't also share the same
first initial, I can use \gls{DTLifStartsWith} or \gls{DTLisPrefix},
which are described in \sectionref{sec:strif} and
\sectionref{sec:ifthen}, respectively. The following uses the first
approach:
\begin{codebox}
\cmd{renewcommand}*\marg{\gls{DTLformatauthor}}[4]\marg{\comment{}
 \marg{\comment{scope font change}
  \gls{DTLifstringeq}\marg{\#2}\marg{Talbot}\marg{\gls{DTLifStartsWith}\marg{\#4}\marg{N}\marg{\cmd{bfseries} }\marg{}}\marg{}\comment{}
  \gls{DTLformatforenames}\marg{\#4}
  \gls{DTLformatvon}\marg{\#1}\comment{}
  \gls{DTLformatsurname}\marg{\#2}\comment{}
  \gls{DTLformatjr}\marg{\#3}\comment{}
 }\comment{}
}
\end{codebox}
The data is loaded and sorted as for \exampleref{ex:bibsince}:
\begin{codebox}
\gls{DTLloadbbl}\marg{mybib}\marg{sample1}
\gls{DTLsortdata}\marg{mybib}\marg{Year=\sortdatacolumnopt{descending},Month=\sortdatacolumnopt{descending}}
\gls{nocite}\marg{*}
\end{codebox}
In this case there's no filtering:
\begin{codebox}
\gls{DTLbibliography}\marg{mybib}
\end{codebox}
The result is shown in \exampleref{ex:highlightauthor}.

\begin{resultbox}[float]
\createexample*
[label={ex:highlightauthor}, link={sec:highlightauthorex},
 title={Highlighting a given author},
 arara={pdflatex,bibtex,pdflatex,pdfcrop},
 description={Example document that shows a bibliography with a
particular author highlighted}
]
{%
\exfile{sample1.bib}{\sampleIbib}%
\cmd{usepackage}\marg{databib}\nl
\cmd{renewcommand}*\marg{\gls{DTLformatauthor}}[4]\marg{\comment{}
 \marg{\comment{scope the font change}
  \gls{DTLifstringeq}\marg{\#2}\marg{Talbot}\marg{\cmd{bfseries} }\marg{}\comment{}
  \gls{DTLformatforenames}\marg{\#4}
  \gls{DTLformatvon}\marg{\#1}\comment{}
  \gls{DTLformatsurname}\marg{\#2}\comment{}
  \gls{DTLformatjr}\marg{\#3}\comment{}
 }\comment{}%
}\nl
\gls{DTLloadbbl}\marg{mybib}\marg{sample1}\nl
\gls{DTLsortdata}\marg{mybib}\marg{Year=descending,Month=descending}
}
{%
\gls{nocite}\marg{*}\nl
\gls{DTLbibliography}\marg{mybib}
}
\end{resultbox}

\subsection{Separate Bib Types}
\label{sec:jcbibex}

\examplemarginref{ex:jcbib}%
Suppose now my boss has decided that I need to produce a list
of all my publications, but they need to be separated so that
all the journal papers appear in one section, and all the
conference papers appear in another section. The journal papers
need to be labelled [J1], [J2] and so on, while the conference
papers need to be labelled [C1], [C2] and so on. (My boss isn't
interested in any of my other publications!) Again, I'm going to use
the \filefmt{sample1.bib} sample file, with the data sorted in
reverse chronological order (newest to oldest):
\begin{codebox}
\gls{DTLloadbbl}\marg{mybib}\marg{sample1}
\gls{DTLsortdata}\marg{mybib}\marg{Year=\sortdatacolumnopt{descending},Month=\sortdatacolumnopt{descending}}
\end{codebox}
All entries are selected by \BibTeX:
\begin{codebox}
\gls{nocite}\marg{*}
\end{codebox}
The journal papers are in the first section. I'm using the
\clsfmt{article} class, which provides \csfmt{refname} for the
bibliography title, so that can be redefined as applicable:
\begin{codebox}
\cmd{renewcommand}*\marg{\cmd{refname}}\marg{Journal Papers}
\end{codebox}
Next the widest label is computed for all entries that have
\optfmt{article} in the \databibcolkey{EntryType} column:
\begin{codebox*}
\gls{DTLcomputewidestbibentry}\marg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{article}}
\marg{mybib}\marg{J\thectr{DTLbibrow}}\marg{\cmd{widest}}
\end{codebox*}
This will define my custom \csfmt{widest} command to the widest
label, which can then be passed to the \env{thebibliography}
environment.
\begin{codebox*}
\cbeg{thebibliography}\marg{\cmd{widest}}
\gls{DTLforeachbibentry}\oarg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{article}}\marg{mybib}\marg{\comment{}
\gls{bibitem}\oarg{J\thectr{DTLbibrow}}\marg{\gls{DBIBcitekey}} \gls{DTLformatbibentry}}
\cend{thebibliography}
\end{codebox*}
Similarly for the conference papers:
\begin{codebox}
\cmd{renewcommand}*\marg{\cmd{refname}}\marg{Conference Papers}
\gls{DTLcomputewidestbibentry}\marg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{inproceedings}}
\marg{mybib}\marg{C\thectr{DTLbibrow}}\marg{\cmd{widest}}
\cbeg{thebibliography}\marg{\cmd{widest}}
\gls{DTLforeachbibentry}\oarg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{inproceedings}}\marg{mybib}\marg{\comment{}
\gls{bibitem}\oarg{C\thectr{DTLbibrow}}\marg{\gls{DBIBcitekey}} \gls{DTLformatbibentry}}
\cend{thebibliography}
\end{codebox}
The result is shown in \exampleref{ex:jcbib}. Note that this
involves multiple iterations over the database. It would be more
efficient to gather the required information (that is, testing and calculating
the widest labels) in one iteration. However, that's more
complicated to code.

\begin{resultbox}[float]
\createexample*
[label={ex:jcbib}, link={sec:jcbibex},
 title={Separate List of Journals and Conference Papers},
 arara={pdflatex,bibtex,pdflatex,pdfcrop},
 description={Example document that shows separate lists of journal
and conference papers}
]
{%
\exfile{sample1.bib}{\sampleIbib}%
\cmd{usepackage}\marg{databib}\nl
\gls{DTLloadbbl}\marg{mybib}\marg{sample1}\nl
\gls{DTLsortdata}\marg{mybib}\marg{Year=descending,Month=descending}
}
{%
\gls{nocite}\marg{*}\nl
\cmd{renewcommand}*\marg{\cmd{refname}}\marg{Journal Papers}\nl
\gls{DTLcomputewidestbibentry}\marg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{article}}\nl
\marg{mybib}\marg{J\thectr{DTLbibrow}}\marg{\cmd{widest}}\nl
\cbeg{thebibliography}\marg{\cmd{widest}}\nl
\gls{DTLforeachbibentry}\oarg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{article}}\marg{mybib}\marg{\comment{}
\gls{bibitem}\oarg{J\thectr{DTLbibrow}}\marg{\gls{DBIBcitekey}} \gls{DTLformatbibentry}}\nl
\cend{thebibliography}
\codepar
\cmd{renewcommand}*\marg{\cmd{refname}}\marg{Conference Papers}\nl
\gls{DTLcomputewidestbibentry}\marg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{inproceedings}}\nl
\marg{mybib}\marg{C\thectr{DTLbibrow}}\marg{\cmd{widest}}\nl
\cbeg{thebibliography}\marg{\cmd{widest}}\nl
\gls{DTLforeachbibentry}\oarg{\cmd{equal}\marg{\gls{DBIBentrytype}}\marg{inproceedings}}\marg{mybib}\marg{\comment{}
\gls{bibitem}\oarg{C\thectr{DTLbibrow}}\marg{\gls{DBIBcitekey}} \gls{DTLformatbibentry}}\nl
\cend{thebibliography}
}
\end{resultbox}

\subsection{Multiple Bibliographies}
\label{sec:multibibex}

\examplemarginref{ex:multibib}%
Suppose I need to create a document which contains a section listing
all my publications, but I also need to have separate sections
covering my fiction and non-fiction work, with a mini-bibliography
at the end of each section. As in the earlier examples, I'm using
the \filefmt{sample1.bib} file. 
Note that there will be some duplication as the
references in the mini-bibliographies will also appear in the
main bibliography at the end of the document, but using
\gls{DTLcite} and \gls{DTLmbibliography} ensures that all the
cross-referencing labels (and hyperlinks if they are enabled)
are unique. As with the previous examples, I'm using the
\clsfmt{article} class to keep it simple. The \opt{databib.auto}
option can be used to automatically run \BibTeX:
\begin{codebox}
\cmd{usepackage}\oarg{\opt{databib.auto}}\marg{databib}
\end{codebox}
The following preamble command will create the files
\filefmt{nonfiction.aux} and \filefmt{fiction.aux}:
\begin{codebox}
\gls{DTLmultibibs}\marg{nonfiction,fiction}
\end{codebox}
The \ext{bbl} files may be loaded anywhere before the databases need
to be referenced:
\begin{codebox}
\gls{DTLloadmbbl}\marg{nonfiction}\marg{nonfictionDB}\marg{sample1}
\gls{DTLloadmbbl}\marg{fiction}\marg{fictionDB}\marg{sample1}
\gls{DTLloadbbl}\marg{fullDB}\marg{sample1}
\end{codebox}
The databases can then be sorted, if required. In this case, the full
bibliography is sorted chronologically, but the other databases
aren't sorted, so they will be in order of citation:
\begin{codebox}
\gls{DTLsortdata}\marg{fullDB}\marg{Year,Month}
\end{codebox}
The document is as follows:
\begin{codebox}
\cmd{section}\marg{Non Fiction}
In this section I'm going to describe some \cmd{LaTeX} work, 
and in the process I'm going to cite some related
papers \gls{DTLcite}\marg{nonfiction}\marg{tugboat2016,Talbot2012a}.
\codepar
\gls{DTLmbibliography}\marg{nonfiction}\marg{nonfictionDB}
\codepar
\cmd{section}\marg{Fiction}
In this section I'm going to describe my fiction, and in the process, I'm going
to cite some books \gls{DTLcite}\marg{fiction}\marg{Talbot2013b,Talbot2012b}
\codepar
\gls{DTLmbibliography}\marg{fiction}\marg{fictionDB}
\end{codebox}
Finally, all entries are selected for the main list:
\begin{codebox}
\gls{nocite}\marg{*}
\cmd{renewcommand}\marg{\cmd{refname}}\marg{Complete List of Publications}
\gls{DTLbibliography}\marg{fullDB}
\end{codebox}
If the document source is in \filefmt{myDoc.tex}, then the build
process with the default \optval{databib.auto}{false} is:
\begin{terminal}
pdflatex myDoc
bibtex myDoc
bibtex nonfiction
bibtex fiction
pdflatex myDoc
pdflatex myDoc
\end{terminal}
With \optval{databib.auto}{true}, the shell escape is required.
Since \app{bibtex} is normally on the restricted list and the
restricted shell escape is normally on by default, the build process
is then:
\begin{terminal}
pdflatex myDoc
pdflatex myDoc
pdflatex myDoc
\end{terminal}
The resulting document is shown in \exampleref{ex:multibib}.

\begin{resultbox}[float]
\createexample*
[label={ex:multibib}, link={sec:multibibex},
 title={Multiple Bibliographies},pages={1,2},
 arara={pdflatex,pdflatex,pdflatex},
 description={Example document with mini bibliographies after each
section and a full bibliography at the end}
]
{%
\exfile{sample1.bib}{\sampleIbib}%
\cmd{usepackage}[auto]\marg{databib}\nl
\gls{DTLmultibibs}\marg{nonfiction,fiction}\nl
\gls{DTLloadmbbl}\marg{nonfiction}\marg{nonfictionDB}\marg{sample1}\nl
\gls{DTLloadmbbl}\marg{fiction}\marg{fictionDB}\marg{sample1}\nl
\gls{DTLloadbbl}\marg{fullDB}\marg{sample1}\nl
\gls{DTLsortdata}\marg{fullDB}\marg{Year,Month}
}
{%
\cmd{section}\marg{Non Fiction}\nl
In this section I'm going to describe some \cmd{LaTeX} work, \nl
and in the process I'm going to cite some related\nl
papers \gls{DTLcite}\marg{nonfiction}\marg{tugboat2016,Talbot2012a}.
\codepar
\gls{DTLmbibliography}\marg{nonfiction}\marg{nonfictionDB}
\codepar
\cmd{section}\marg{Fiction}\nl
In this section I'm going to describe my fiction, and in the
process, I'm going\nl
to cite some books \gls{DTLcite}\marg{fiction}\marg{Talbot2013b,Talbot2012b}
\codepar
\gls{DTLmbibliography}\marg{fiction}\marg{fictionDB}
\codepar
\gls{nocite}\marg{*}\nl
\cmd{renewcommand}\marg{\cmd{refname}}\marg{Complete List of Publications}\nl
\gls{DTLbibliography}\marg{fullDB}
}
\end{resultbox}

\section{Localisation}
\label{sec:databiblang}

As described in \sectionref{sec:localisation}, the
\sty{datatool-base} package (which will automatically be loaded by
the \sty{databib} package, if not already loaded) provides
localisation support via the \sty{tracklang} interface. The
\sty{databib} package uses the same interface to load the file
\metafilefmt{databib\dhyphen}{locale}{.ldf} for each tracked locale
if that file is installed on \TeX's path.

The supplementary \sty{datatool-english} package (which needs to be
installed separately), described in \sectionref{sec:addlang}, 
includes \inlinefiledef{databib-english.ldf}, which provides English
localisation support for the \sty{databib} package. This file may be
used as a template for other languages.

Any localisation options specific to \sty{databib} should be
identified by \code{\meta{locale} / databib}. For example,
\file{databib-english.ldf} provides the option 
\optfmt{short-month-style}, which may have the value \optfmt{dotted}
(abbreviated month names are followed by a dot) or
\optfmt{dotless} (three letter abbreviation month names with no dot).
For example, to switch to \optfmt{dotless}:
\begin{codebox}
\gls{DTLsetLocaleOptions}\oarg{en}\marg{databib}\marg{short-month-style=dotless}
\end{codebox}
Or:
\begin{codebox}
\gls{DTLsetLocaleOptions}\marg{en/databib}\marg{short-month-style=dotless}
\end{codebox}

\chapter{Creating an index, glossary or list of abbreviations
(\stytext{datagidx} package)}
\label{sec:datagidx}

\pkgdef{datagidx}

The \sty{datagidx} package can be used to generate indexes or
glossaries as an alternative to packages such as \sty{glossaries}.
It was written in 2013 before I added \gls{printnoidxglossary} to
the \sty{glossaries} package in 2014 (which uses \TeX\ to sort and
collate) and \gls{printunsrtglossary} to the \sty{glossaries-extra}
package in 2016 (which doesn't sort or collate).  To avoid
duplication of effort, I don't intend providing new features for
\sty{datagidx}. The most flexible solution is to use
\sty{glossaries-extra} and \app{bib2gls}, see the \gallery{Dickimaw
Books Gallery} for examples.

\begin{information}
If you are considering \sty{datagidx} because you are having
difficulty running an external indexing application, see
\dickimawhref{latex/buildglossaries/}{Incorporating
\appfmt{makeglossaries} or \appfmt{makeglossaries-lite} or
\appfmt{bib2gls} into the document build}.
\end{information}

The \sty{datagidx} package was rewritten in version 3.0 to use
\LaTeX3 commands. The \sty{xkeyval} and \sty{afterpage}
packages have been dropped and the
use of \gls{DTLforeach} has been replaced with \gls{DTLmapdata}. A
number of bugs have also been fixed, which may cause some
differences in the output. You may need to delete the temporary
files before rebuilding after upgrading to v3.0.
Rollback to version 2.32 is available:
\begin{codebox}
\cmd{usepackage}\marg{datagidx}[=2.32]
\end{codebox}
Note that if \sty{datatool} hasn't already been loaded, this will
also apply rollback to \sty{datatool}. Problems may occur if a newer
release of \sty{datatool} has already been loaded.

\begin{warning}
The \sty{datagidx} package is incompatible with the \sty{glossaries}
package.
\end{warning}

The \sty{datagidx} package works by having a predefined database
called \code{datagidx} which contains a list of each index\slash
glossary with its associated settings. Whenever you define a new
index\slash glossary database with \gls{newgidx} (see
\sectionref{sec:newgidx}), a new row is added to the \code{datagidx}
database and a new database is created in which to store each entry
associated with the particular index or glossary.

Whenever a term is referenced using a command such as \gls{useentry}
the relevant information is looked up in the database. A mapping
exists between the entry label and the index\slash glossary database
label to ensure that the correct database is referenced. Unlike some
of the other supplementary packages provided with \sty{datatool}, the
\sty{datagidx} package doesn't use the \opt{default-name} setting,
but instead has its own way of identifying the default index\slash
glossary database, which is independent of \opt{default-name}.

The list of referenced terms can then be displayed with
\gls{printterms}, which firsts sorts the database using
\gls{DTLsortdata}.


\begin{important}
Don't expect \sty{datagidx} to perform as efficiently as an
application that is designed specifically to sort and collate entries.
\end{important}

\section{Options}
\label{sec:datagidxoptions}

Any options that may be passed to \sty{datatool} can also be passed
to \sty{datagidx} (unless \sty{datatool} has already been loaded and
the option isn't permitted in \gls{DTLsetup}).  Additionally, the
package options described in \sectionref{sec:datagidxstyoptions} are
specific to \sty{datagidx}.

The \sty{datagidx} package provides the \gls{DTLsetup} option
\inlineoptdef{index}:
\begin{compactcodebox}
\gls{DTLsetup}\marg{\optvalm{index}{\meta{options}}}
\end{compactcodebox}
This may be used to set any of the options listed
\sectionref{sec:gidxsetupopts}.

\subsection{Package Options}
\label{sec:datagidxstyoptions}

\subsubsection{Global Options}
\label{sec:datagidxglobaloptions}

\optiondef{datagidx.optimize}
This setting may only be passed as a package option, and sets the optimization mode. 
The value must be one of:
\optfmt{off} (no optimization), \optfmt{low} (some optimization),
or \optfmt{high} (highest level). If you want to optimize
some glossaries but not others, switch on the optimize function
and clear the \gidxopt{sort} option for the relevant glossaries and manually
sort using \gls{DTLsortdata} or \gls{dtlsort} before the glossary is displayed.
See \sectionref{sec:optimize} for further details.

\optiondef{datagidx.draft}
This valueless setting may only be passed as a package option, and
switches on draft mode, which displays additional information, such
as target names.

\optiondef{datagidx.final}
This valueless setting (which is the default) may only be passed as
a package option, and switches off draft mode.

The following options are also considered global options but may be
changed after the package has been loaded.

\optiondef{datagidx.nowarn}
This setting may only be passed as a package option, and, if true,
will switch off \sty{datagidx} warnings. If you want to change the
setting again later, you can use the \gidxopt{warn} option in the
\opt{index} sub-setting.

\optiondef{datagidx.compositor}
Sets the location compositor (see \sectionref{sec:locations}). This
value may also be set after the package has loaded with the
\gidxopt{compositor} option.

\optiondef{datagidx.counter}
Sets the location counter (see \sectionref{sec:locations}). This
value may also be set after the package has loaded with the
\gidxopt{counter} option.

\subsubsection{Style Options}
\label{sec:datagidxstyleoptions}

These options relate to the way the index or glossary is
formatted by \gls{printterms}.

\optiondef{datagidx.columns}
Sets the number of columns in \gls{printterms}. This value may also be set after the
package has loaded with the \gidxopt{columns} option.

\optiondef{datagidx.child}
Sets the child style used in \gls{printterms}, where the value may be
\optfmt{named} (show the child's name) or \optfmt{noname} (only show
the numeric label, as given by \gls{DTLgidxChildCountLabel}, not the child's
name). This value may also be set after the package has loaded with
the \gidxopt{child} option.

\optiondef{datagidx.namecase}
Sets the name case style used in \gls{printterms}, where the value may be
\optfmt{nochange}, \optfmt{uc}, \optfmt{lc}, \optfmt{firstuc}
or \optfmt{capitalise}. This value may also be set after the
package has loaded with the \gidxopt{namecase} or \gidxopt{name-case} option.

\optiondef{datagidx.postname}
Sets the code to insert after the name used in \gls{printterms}.
This value may also be set after the package has loaded with the
\gidxopt{postname} or \gidxopt{post-name} option.

\optiondef{datagidx.postdesc}
Sets the post-description style used in \gls{printterms}, where the
value may be one of: \optfmt{none} or \optfmt{dot}. This value may
also be set after the package has loaded with the \gidxopt{postdesc}
or \gidxopt{post-desc} option.

\optiondef{datagidx.prelocation}
Sets the style of the pre-location content used in \gls{printterms},
where the value may be \optfmt{none}, \optfmt{enspace},
\optfmt{space}, \optfmt{dotfill} or \optfmt{hfill}. This value may
also be set after the package has loaded with the
\gidxopt{prelocation} or \gidxopt{pre-location} option.

\optiondef{datagidx.location}
Sets the location list style used in \gls{printterms}, where the
value may be one of: \optfmt{hide}, \optfmt{list} or \optfmt{first}.
This value may also be set after the package has loaded with the
\gidxopt{location} option.

\optiondef{datagidx.see}
Sets the \qt{see} style used in \gls{printterms}, where the
value may be one of: \optfmt{comma}, \optfmt{brackets},
\optfmt{dot}, \optfmt{space}, \optfmt{nosep}, \optfmt{semicolon},
or \optfmt{location}. This value may also
be set after the package has loaded with the \gidxopt{see}
option.

\optiondef{datagidx.symboldesc}
Sets the symbol-description style used in \gls{printterms}, where the
value may be one of: \optfmt{symbol}, \optfmt{desc},
\optfmt{(symbol) desc}, \optfmt{desc (symbol)}, \optfmt{symbol desc}, 
or \optfmt{desc symbol}. This value may also be set after the
package has loaded with the \gidxopt{symboldesc} or
\gidxopt{symbol-desc} option.

\subsection{Post-Package Options}
\label{sec:gidxsetupopts}

The following options may be set after the \sty{datagidx} package
has been loaded with the \opt{index} setting.
For example:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{index}{\gidxoptval{style}{gloss},\gidxoptval{columns}{1}}}
\end{codebox}

\subsubsection{General}
\label{sec:gidxgenopts}

These settings may be localised but they apply to all index or glossary databases.
They can't be set in the optional argument of \gls{newgidx} or
\gls{printterms}. Ideally they should be set in the preamble.

\optiondef{gidx.compositor}
Sets the location compositor (see \sectionref{sec:locations}). 
This setting may also be passed as a package option.

\optiondef{gidx.counter}
Sets the location counter (see \sectionref{sec:locations}). 
This setting may also be passed as a package option.

\optiondef{gidx.warn}
If true, switches on \sty{datagidx} warnings, otherwise switches
them off. The \opt{datagidx.nowarn} package option is an antonym
of this setting.

\subsubsection{Database Creation and Display}
\label{sec:gidxnewprintopts}

These options are applicable to both \gls{newgidx} and
\gls{printterms}. They may be set in the optional arguments of those
commands or set with \opt{index} in \gls{DTLsetup}.  
If used in the optional argument of \gls{newgidx}, they set the default for
that database, which can then be overridden by the optional argument
of \gls{printterms}, if necessary. Any options not explicitly set in
\gls{newgidx} will use the current setting.

\optiondef{gidx.balance}
If true and the \gidxopt{columns} value is greater than 1, balance columns.
That is, the unstarred \env{multicols} environment (provided by the
\sty{multicol} package) will be used.
If \gidxoptval{balance}{false}, then \gls{twocolumn} will be used
if \gidxoptval{columns}{2} or, if more than two columns, the \starredenv{multicols} 
environment will be used. The \gidxopt{balance} option has no
effect with \gidxoptval{columns}{1}.

\optiondef{gidx.heading}
Sets the index\slash glossary heading.

\optiondef{gidx.post-heading}
Sets the content to insert after the heading.

\optiondef{gidx.postheading}
Synonym of \gidxopt{post-heading}.

\optiondef{gidx.show-groups}
If true, visually separate the letter groups. This requires the
\optfmt{LetterGroup} column to be set, which is done by the default
\gidxopt{sort} code.

\optiondef{gidx.showgroups}
Synonym of \gidxopt{show-groups}.

\optiondef{gidx.sort}
The value should be the code to sort the database at the start of
\gls{printterms}. The default is:
\begin{compactcodebox}
\gls{DTLsortdata}
 \oarg{ \sortdataoptval{save-group-key}{LetterGroup} }
 \marg{\gls{DTLgidxCurrentdb}}
 \marg{HierSort=\marg{\sortdatacolumnoptvalm{replacements}{Sort}},FirstId}
\end{compactcodebox}
The \code{\sortdataoptval{save-group-key}{LetterGroup}} option is
needed to support letter groups. If you omit it from \gls{DTLsortdata}
(or if you use \gls{dtlsort} instead) then no letter group information will be
available. See \sectionref{sec:datagidxstructure} for the list of
column keys, which may be referenced in \gls{DTLsortdata}.

\optiondef{gidx.style}
Sets the style to be used by \gls{printterms} (see \sectionref{sec:indexstyles}).

\subsubsection{Display Only}
\label{sec:gidxprintopts}

These options are only applicable to \gls{printterms}. They can't be
passed in the optional argument of \gls{newgidx}. If not provided in
\gls{printterms}, the current settings will be used.

\optiondef{gidx.child}
Sets the child style. The value may be one of: \optfmt{named} (show
the child's name) or \optfmt{noname} (only show the numeric label, as given
by \gls{DTLgidxChildCountLabel}, not the child's name).
This setting may also be passed as a package option.

\optiondef{gidx.child-sort}
If this boolean option is true, the child sub-lists should follow
the ordering from the database (which will be the sort order, if the
database has been sorted), otherwise they will follow the order of
the comma-separated list in \gidxvar{Children} (which will be the
order of definition).

\optiondef{gidx.childsort}
Synonym of \gidxopt{child-sort}.

\optiondef{gidx.columns}
The number of columns. If the value is greater than 1, the
\env{multicols} or \starredenv{multicols} environment will be used,
depending on the \gidxopt{balance} setting, except where both
\gidxoptval{columns}{2} and \gidxoptval{balance}{false}, in which
case \gls{twocolumn} will be used.
This setting may also be passed as a package option.

If the \gidxopt{columns} setting is used as a package option or
within the \opt{index} setting, it's equivalent to setting the
number of columns with \gls{DTLgidxSetColumns}. If passed as an
option to \gls{printterms} the effect is localised.

\optiondef{gidx.condition}
Only include rows that satisfy the condition, where
\meta{condition} must be suitable for use in \gls{ifthenelse} (see
\sectionref{sec:ifthen}). Note that
\gidxoptvalm{condition}{\meta{condition}} is equivalent to:
\begin{compactcodebox}
\gidxoptvalm{include-if}{\gls{ifthenelse}\margm{condition}\marg{\#1}\marg{}}
\end{compactcodebox}

\optiondef{gidx.database}
Specifies the \sty{datagidx} database name. If used within the
\opt{index} setting, this is equivalent to setting the default
database with \gls{DTLgidxSetDefaultDB}. If passed as an option to
\gls{printterms} the effect is localised. If no default has been
set, \gls{newgidx} will automatically set
the default to its \meta{db-name} argument. So if you only have one
database, there is no need to explicitly set the default.

\begin{information}
If a database is loaded from an external file with
\gls{loadgidx}, then the default database will automatically be set to
\gls{dtllastloadeddb}.
\end{information}

\optiondef{gidx.include-if}
An alternative to the \gidxopt{condition} option, this defines the
filter command used by \gls{printterms} to \meta{definition}, which
should expand to its sole argument (\code{\#1}) if the given row of data should be
included in the list and do nothing otherwise. This may be used as
an alternative to \gidxopt{include-if-fn} or \gidxopt{condition}.

\optiondef{gidx.include-if-fn}
An alternative to the \gidxopt{condition} option, this
sets the filter command, which should take one argument, to the
given \meta{cs}. The definition of \meta{cs} should
expand to its argument if the given row of data should be included
in \gls{printterms} and do nothing otherwise. 

\begin{information}
The options \gidxopt{condition}, \gidxopt{include-if} and
\gidxopt{include-if-fn} all override each other.
\end{information}

\optiondef{gidx.location}
Sets the location style. The value must be one of:
\optfmt{hide} (don't show the location list), \optfmt{list}
(show the location list), or \optfmt{first} (only show the first
location). 
This setting may also be passed as a package option.

\optiondef{gidx.location-width}
Sets the space to allocate for each location list. If zero or negative, the
location list just occupies its natural width. This setting changes the
\gls{datagidxlocationwidth} dimension.

\optiondef{gidx.locationwidth}
Synonym of \gidxopt{location-width}.

\optiondef{gidx.name-case}
Specifies the case-change to apply to the name. The value
must be one of: \optfmt{nochange} (no change), \optfmt{uc}
(convert to uppercase), \optfmt{lc} (convert to lowercase),
\optfmt{firstuc} (convert to sentence case with \gls{xmakefirstuc}), 
or \optfmt{capitalise} (capitalise each word with
\gls{xcapitalisewords}). See the \sty{mfirstuc} documentation for
further details of the last two. This setting redefines
\gls{DTLgidxNameCase} to use the applicable command.

\optiondef{gidx.namecase}
Synonym of \gidxopt{name-case}.
This setting (but not \gidxopt{name-case}) may also be passed as a package option.

\optiondef{gidx.name-font}
The font declaration or text block command to apply to
the name. The code may contain multiple declarations. Only the final
token may be a text block command. This setting redefines
\gls{DTLgidxNameFont}:
\begin{compactcodebox}
\cmd{renewcommand}*\marg{\gls{DTLgidxNameFont}}[1]\marg{\marg{\meta{code}\marg{\#1}}}
\end{compactcodebox}

\optiondef{gidx.namefont}
Synonym of \gidxopt{name-font}.
This setting (but not \gidxopt{name-font}) may also be passed as a package option.

\optiondef{gidx.post-name}
Content to insert after the name. This setting redefines
\gls{DTLgidxPostName} to the given \meta{value}.

\optiondef{gidx.postname}
Synonym of \gidxopt{post-name}.
This setting (but not \gidxopt{post-name}) may also be passed as a package option.

\optiondef{gidx.post-desc}
The value may be one of: \optfmt{none} (no content to insert after
the description) or \optfmt{dot} (insert a period\slash full stop
after the description). This setting redefines
\gls{DTLgidxPostDescription} according to the given value.

\optiondef{gidx.postdesc}
Synonym of \gidxopt{post-desc}.
This setting (but not \gidxopt{post-desc}) may also be passed as a package option.

\optiondef{gidx.pre-location}
Indicates the type of padding that should be inserted before the
location list. The value may be one of: \optfmt{none} (nothing),
\optfmt{enspace} (an en-space, created with \gls{enspace}),
\optfmt{space} (a normal space), \optfmt{dotfill} (dotted leader,
created with \gls{dotfill}), \optfmt{hfill} (filled space, created
with \gls{hfill}). This setting redefines \gls{DTLgidxPreLocation}
according to its value.

\optiondef{gidx.prelocation}
Synonym of \gidxopt{pre-location}.
This setting (but not \gidxopt{pre-location}) may also be passed as a package option.

\optiondef{gidx.see}
Sets the \qt{see} cross-reference style. 
This setting may also be passed as a package option.
The value must be one of:
\optfmt{comma} (insert a comma and space, followed by the
cross-reference), 
\optfmt{dot} (insert a period\slash full stop and space, followed by the
cross-reference), 
\optfmt{semicolon} (insert a semi-colon and space, followed by the
cross-reference), 
\optfmt{brackets} (insert a space followed by the cross-reference in
parentheses),
\optfmt{space} (insert a space followed by the
cross-reference), 
\optfmt{location} (insert \gidxopt{pre-location} content followed by the
cross-reference), or 
\optfmt{nosep} (insert the
cross-reference without any leading punctuation or space).
In all cases, the cross-reference is obtained with:
\begin{compactcodebox}
\gls{DTLgidxFormatSee}\marg{\gls{seename}}\marg{\gidxvar{See}}
\end{compactcodebox}

\optiondef{gidx.symbol-desc}
Specifies how the symbol and description should be displayed. The
value must be one of the following:
\begin{itemize}
\item \code{symbol}: symbol only;
\item \code{desc}: description only;
\item \code{(symbol) desc}: the symbol in parentheses followed by the
description;
\item \code{desc (symbol)}: the description followed by the symbol in parentheses;
\item \code{symbol desc}: the symbol followed by the
description;
\item \code{desc symbol}: the description followed by the symbol.
\end{itemize}

\optiondef{gidx.symboldesc}
Synonym of \gidxopt{symbol-desc}.
This setting (but not \gidxopt{symbol-desc}) may also be passed as a package option.

\optiondef{gidx.symbol-width}
Sets the space to allocate for each symbol. If zero or negative, the
symbol just occupies its natural width. This setting changes the
\gls{datagidxsymbolwidth} dimension.

\optiondef{gidx.symbolwidth}
Synonym of \gidxopt{symbol-width}.

\section{Defining Index/Glossary Databases}
\label{sec:newgidx}

Before you define any terms, you need to create the database in
which to store the information. This is done with:
\cmddef{newgidx}
This creates a new database called \meta{db-name}, which has an
associated title (\meta{title}) for use with \gls{printterms}.
For example:
\begin{codebox}
\gls{newgidx}\marg{index}\marg{Index of Terms}
\gls{newgidx}\marg{abbr}\marg{Abbreviations}
\end{codebox}
The optional argument is a \keyval\ list of options, which may be
any of those described in \sectionref{sec:gidxnewprintopts}.

This does more than simply create the database with \gls{DTLnewdb}
as it also adds a line to the cataloguing database with the provided
\meta{title} and all applicable settings (see
\sectionref{sec:datagidxstructure} for further details).
It also takes into account the \opt{datagidx.optimize} setting (see
\sectionref{sec:optimize}).

\begin{information}
If no \sty{datagidx} default database has yet been specified, \gls{newgidx}
will automatically set the default to \meta{db-name} (so you won't
need to specify \gidxopt{database} in \gls{printterms} if you only
have one database). Note that this isn't the same as the
\sty{datatool} \opt{default-name} setting.
\end{information}

\section{Loading Data Created by \apptext{datatooltk}}
\label{sec:loadgidx}

If you have edited and sorted a \sty{datagidx} database in \app{datatooltk}, 
you can then just load it using:
\cmddef{loadgidx}
where \meta{filename} is the name of the DBTEX file saved by
\app{datatooltk}. The remaining arguments \meta{options} and
\meta{title} are the same as for \gls{newgidx}, described in
\sectionref{sec:newgidx}. This command automatically sets the
default database to the loaded database. You can change the default
database using \gls{DTLgidxSetDefaultDB} or with the \gidxopt{database}
setting.

Since \gls{loadgidx} is intended for use with presorted databases,
this implements \gidxoptvalm{sort}{} which means that
\gls{printterms} won't sort the database.

\begin{information}
Both \app{datatooltk} and \app{bib2gls} are Java applications.
If you're going to use an external helper application, you're better
off using \app{bib2gls} with \sty{glossaries-extra} than using
\app{datatooltk} with \sty{datagidx}.
\end{information}

\section{Defining Terms}
\label{sec:newterm}

A new term may be defined in the preamble with:
\cmddef{newterm}
(For abbreviations, see \sectionref{sec:gidxabbr}.) This defines a
term with the given \meta{name}, which is the text to display in the
list typeset with \gls{printterms}. The optional argument is a
\keyval\ list of options, described below. 
(See \sectionref{sec:gidxcustomfields} if you want additional fields
with associated options.)

If \sty{datatool-base}['s] \opt{verbose} mode is on, \gls{newterm}
will write a confirmation line in the transcript. This may be used
to double-check the default values for the \newtermopt{label},
\newtermopt{database} and \newtermopt{sort} settings.

\optiondef{newterm.database}
The label of the database in which this term should be stored. If
omitted, the \sty{datagidx} default database is assumed.

\optiondef{newterm.label}
The term's label.
Each term must have a unique label that identifies it, so that it
can be referenced by commands like \gls{useentry} and \gls{gls}. If
hyperlinks are required, the label is also used to construct the
anchor. If a label is not provided in the optional argument, the
label will be created as described in \sectionref{sec:gidxlabel}.

\optiondef{newterm.parent}
The label of the term's parent, if a hierarchical structure is required. 
The parent must belong to the same database as the child entry.

\optiondef{newterm.text}
The text to use by commands like \gls{gls}. If omitted, the
\meta{name} is used.

\optiondef{newterm.plural}
The text to use by commands like \gls{glspl}. If omitted, the
plural is constructed by appending \qt{s} to the \newtermopt{text}
value.

\optiondef{newterm.symbol}
The text to use by commands like \gls{glssym}. It may also be shown
in \gls{printterms}, depending on the \gidxopt{symbol-desc} setting.

\optiondef{newterm.description}
The term's description to be displayed in \gls{printterms}, if
applicable.

\optiondef{newterm.see}
If the term should have a \qt{see} cross-reference in
\gls{printterms}, the label of the cross-reference term should be
set with the \newtermopt{see} option. The value may also be a
comma-separated list of cross-referenced labels.

\optiondef{newterm.seealso}
If the term should have a \qt{see also} cross-reference in
\gls{printterms}, the label of the cross-reference term should be
set with the \newtermopt{seealso} option. The value may also be a
comma-separated list of cross-referenced labels.

\optiondef{newterm.sort}
The term's sort value. If omitted, the value is obtained by
processing the \meta{name}, as described in
\sectionref{sec:gidxsortcmds}.

The sort value is stored in the database's \optfmt{Sort} column,
which is referenced in the default \gidxopt{sort} code at the start of
\gls{printterms}. If you change the \gls{printterms} \gidxopt{sort} 
code, use \optfmt{Sort} as the column key to reference this value.
However, if you have child entries, you may prefer to sort by the
\optfmt{HierSort} column first with the \optfmt{Sort} column as the
replacement.

The term's hierarchical sort value, which is stored in the
\optfmt{HierSort} column and only set for child entries, is obtained by
appending the sort value to the parent's \optfmt{HierSort}
value (or the parent's \optfmt{Sort} value, if the parent doesn't have a
parent), separated by:
\begin{compactcodebox}
\gls{datatoolctrlboundary} \gls{datatoolasciistart}
\end{compactcodebox}

The following options are provided for use by \gls{newacro}, which
internally uses \gls{newterm}.  Whilst they can be explicitly used
in \gls{newterm}, \gls{newacro} is a convenient wrapper that will
encapsulate the short and long forms in the provided abbreviation
style commands. See \sectionref{sec:gidxabbr} for further details.

\optiondef{newterm.short}
The short (abbreviated) form.

\optiondef{newterm.shortplural}
The plural short form. If omitted, it will be obtained by appending
\qt{s} to the \newtermopt{short} value.

\optiondef{newterm.long}
The long form.

\optiondef{newterm.longplural}
The plural long form. If omitted, it will be obtained by appending
\qt{s} to the \newtermopt{long} value.

\subsection{Markup Commands for Terms}
\label{sec:gidxmarkupcmds}

The commands described below may be used in the term's name but
expand differently depending on the context. 
Remember that if the \newtermopt{text}, \newtermopt{label} or \newtermopt{sort} values
aren't provided, they will be obtained from the name.
These commands may be nested. For example:
\begin{codebox}
\gls{newterm}\marg{\comment{}
 \gls{DTLgidxOffice}
 \marg{bishop \gls{DTLgidxParticle}\marg{of}\marg{Bayeux}}\comment{office}
 \marg{\gls{DTLgidxName}\marg{Henry}{\gls{DTLgidxParticle}\marg{de}\marg{Beaumont}}}\comment{name}
}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
 \newtermoptvalm{label}{deBeaumont},
 \newtermoptvalm{sort}{Beaumont.\gls{datatoolpersoncomma}
   Henry\gls{datatoolpersoncomma} bishop Bayeux.}
}\marg{\comment{}
 \gls{DTLgidxOffice}
 \marg{bishop \gls{DTLgidxParticle}\marg{of}\marg{Bayeux}}\comment{office}
 \marg{\gls{DTLgidxName}\marg{Henry}{\gls{DTLgidxParticle}\marg{de}\marg{Beaumont}}}\comment{name}
}
\end{compactcodebox}

\cmddef{DTLgidxName}
Normally this expands to \meta{forename} \meta{surname}, but it expands
differently within \gls{printterms} and also in the construction of the
default \newtermopt{label} and \newtermopt{sort} values. For
example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxName}\marg{John}\marg{Smith}}
\end{codebox}
This is essentially like:
\begin{compactcodebox}
\gls{newterm}\oarg{
 \newtermoptvalm{label}{Smith},
 \newtermoptvalm{sort}{Smith\gls{datatoolpersoncomma} John},
 \newtermoptvalm{text}{John Smith}
}\marg{Smith, John}
\end{compactcodebox}

\cmddef{DTLgidxNameNum}
Designed to markup a name ordinal (such as for a monarch). This
normally expands to the uppercase Roman numeral of the given number,
but will expand to \meta{num} zero-padded to two digits when
creating the default \newtermopt{sort} value. For
example:
\begin{codebox}
\gls{newterm}\marg{James\idx{nbsp}\gls{DTLgidxNameNum}\marg{6}}
\end{codebox}
This is essentially like:
\begin{compactcodebox}
\gls{newterm}\oarg{
 \newtermoptvalm{label}{James VI},
 \newtermoptvalm{sort}{James 06},
 \newtermoptvalm{text}{James\idx{nbsp}VI}
}\marg{James\idx{nbsp}VI}
\end{compactcodebox}

\cmddef{DTLgidxPlace}
Used to format a place, this normally expands to just its second
argument \meta{town/city}, but it expands differently within
\gls{printterms} and also in the construction of the default
\newtermopt{label} and \newtermopt{sort} values.
For example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxPlace}\marg{USA}\marg{New York}}
\end{codebox}
This is essentially like:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{New York USA},
  \newtermoptvalm{sort}{New York\gls{datatoolplacecomma} USA},
  \newtermoptvalm{text}{New York}
}\marg{New York, USA}
\end{compactcodebox}

\cmddef{DTLgidxSubject}
Used to format a subject, this normally expands to just its second
argument \meta{category}, but it expands differently within
\gls{printterms} and also in the construction of the default
\newtermopt{label} and \newtermopt{sort} values.
For example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxSubject}\marg{population}\marg{New York}}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{New York population},
  \newtermoptvalm{sort}{New York\gls{datatoolsubjectcomma} population}
}\marg{\gls{DTLgidxSubject}\marg{population}\marg{New York}}
\end{compactcodebox}
which is essentially like:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{New York population},
  \newtermoptvalm{sort}{New York\gls{datatoolsubjectcomma} population},
  \newtermoptvalm{text}{New York}
}\marg{New York, population}
\end{compactcodebox}
In this case, this leads to a long label, so you may prefer to set
a shorter label explicitly. If you redefine \gls{DTLgidxSubject}, it
will only affect how the text appears in the main body of the
document, not within \gls{printterms}.

\cmddef{DTLgidxOffice}
Used to markup a person's office, this normally expands to 
\code{\meta{name} (\meta{office})}, but it expands differently within
\gls{printterms} and also in the construction of the default
\newtermopt{label} and \newtermopt{sort} values. For example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxOffice}\marg{Rollo}\marg{ruler of Normandy}}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{ruler of Normandy},
  \newtermoptvalm{sort}{ruler of Normandy\gls{datatoolpersoncomma} Rollo}
}\marg{\gls{DTLgidxOffice}\marg{Rollo}\marg{ruler of Normandy}}
\end{compactcodebox}
which is essentially like:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{ruler of Normandy},
  \newtermoptvalm{sort}{ruler of Normandy\gls{datatoolpersoncomma} Rollo},
  \newtermoptvalm{text}{Rollo (ruler of Normandy)}
}\marg{ruler of Normandy, Rollo}
\end{compactcodebox}
If you redefine \gls{DTLgidxOffice}, it
will only affect how the text appears in the main body of the
document, not within \gls{printterms}.

\cmddef{DTLgidxRank}
Used to markup a person's rank, this normally expands to 
\code{\meta{rank}\idx{nbsp}\meta{forename(s)/initial(s)}}, 
but it expands differently within the construction of the default
\newtermopt{label} and \newtermopt{sort} values.
For example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxRank}\marg{Sir}\marg{John}}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{Sir John},
  \newtermoptvalm{sort}{John.}
}\marg{\gls{DTLgidxRank}\marg{Sir}\marg{John}}
\end{compactcodebox}
Note that this doesn't have a different definition within
\gls{printterms}.

\cmddef{DTLgidxParticle}
Used to markup a surname with a particle (such as \qt{of} or \qt{de}), 
this normally expands to 
\code{\meta{particle}\idx{nbsp}\meta{surname}}, 
but it expands differently within the construction of the default
\newtermopt{label} and \newtermopt{sort} values.
For example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxParticle}\marg{de}\marg{Winter}}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{deWinter},
  \newtermoptvalm{sort}{Winter.}
}\marg{\gls{DTLgidxParticle}\marg{de}\marg{Winter}}
\end{compactcodebox}
Note that this doesn't have a different definition within
\gls{printterms}.

\cmddef{DTLgidxMac}
Used to markup \qt{Mac}/\qt{Mc} prefix at the start of a surname. Normally
this simply expands to its argument, but will expand to \qt{Mac}
when creating the sort value, regardless of the argument.
For example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxMac}\marg{Mc}Coy}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{McCoy},
  \newtermoptvalm{sort}{MacCoy}
}\marg{\gls{DTLgidxMac}\marg{Mc}Coy}
\end{compactcodebox}

\cmddef{DTLgidxSaint}
Used to markup \qt{Saint}/\qt{St} prefix. Normally
this simply expands to its argument, but will expand to \qt{Saint}
when creating the sort value, regardless of the argument.
For example:
\begin{codebox}
\gls{newterm}\marg{\gls{DTLgidxSaint}\marg{St}\idx{nbsp}James}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{St James},
  \newtermoptvalm{sort}{Saint James}
}\marg{\gls{DTLgidxSaint}\marg{St}\idx{nbsp}James}
\end{compactcodebox}

\cmddef{DTLgidxParen}
Used to markup parenthetical material, this normally expands to
a space followed by its argument in parentheses, 
but it discard its argument within the construction of the default
\newtermopt{label}.
For example:
\begin{codebox}
\gls{newterm}\marg{0\gls{DTLgidxParen}\marg{zero}}
\end{codebox}
This is equivalent to:
\begin{codebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{0},
  \newtermoptvalm{sort}{0\gls{datatoolparenstart} zero}
}\marg{0\gls{DTLgidxParen}\marg{zero}}
\end{codebox}

\cmddef{DTLgidxIgnore}
Used to markup content that should be stripped from the default
\newtermopt{sort} value. Expands to its
argument normally. For example:
\begin{codebox}
\gls{newterm}\marg{de\gls{DTLgidxIgnore}\marg{-}escalate}
\end{codebox}
This is equivalent to:
\begin{compactcodebox}
\gls{newterm}\oarg{
  \newtermoptvalm{label}{de-escalate},
  \newtermoptvalm{sort}{deescalate},
}\marg{de\gls{DTLgidxIgnore}\marg{-}escalate}
\end{compactcodebox}
Note that in this case, the letter sort handler \gls{DTLsortletterhandler}
can be used to strip hyphens.

\cmddef{DTLgidxStripBackslash}
This expands to the command name without the leading backslash. As
from version~3.0, this simply uses \csfmt{cs\_to\_str:N}.


\subsection{Commands to Assist Label Creation}
\label{sec:gidxlabel}

All defined terms must be supplied a unique label in order to
reference them. For example:
\begin{codebox}
\gls{newterm}\oarg{\newtermoptval{label}{duck}}\marg{duck}
\end{codebox}
If the name doesn't contain any markup, as in the above example, it
can be a bit repetitive to have to explicitly set the label. To
avoid this repetition, \gls{newterm} will create a label based on
the name if the \newtermopt{label} option isn't set. If you want to
double-check the label value, switch on \opt{verbose} mode and
\gls{newterm} will write information, including the label, to the transcript.

The automatic label creation locally redefines certain commands,
performs a protected expansion, strips awkward characters and
purifies the result. This means that the above example can simply be
written as:
\begin{codebox}
\gls{newterm}\marg{duck}
\end{codebox}
If the name contains fragile
commands, either explicitly set the \newtermopt{label} value or
redefine \gls{newtermlabelhook} to locally change the fragile
commands to expand to nothing or to something suitable for a label.

The steps are described in more detail below.
\begin{enumerate}
\item Local redefinitions of common formatting commands.

The command \gls{glsadd} will be redefined to ignore its argument.
Various commands are redefined to \gls{DTLgidxNoFormat}, which
simply expands to its argument. This is largely redundant now, since
the purification step will strip any non-expandable commands.
Commands such as \gls{cs.amp} are replaced via
\gls{datagidxconvertchars}.

\item Local redefinitions of special markup commands.

Some of the markup commands described in \sectionref{sec:gidxmarkupcmds}
are redefined. These are: \gls{DTLgidxParen} (discards its
argument), \gls{DTLgidxName} and \gls{DTLgidxOffice} (expands to
just the second argument), \gls{DTLgidxPlace} and
\gls{DTLgidxSubject} (inverted), and \gls{DTLgidxParticle} (expands
both arguments without any separator).

\item Local redefinitions of standard math-Greek commands (such as
\gls{alpha}) to words (via \gls{datagidxwordifygreek}).

\item User hook.

\item Protected expansion of the supplied name.

\item Commas and equal signs are stripped (as they can interfere
with syntax parsing).

\item The remaining content is expanded and purified.
\end{enumerate}

The user hook is:
\cmddef{newtermlabelhook}
This does nothing by default. It may be redefined to perform any
additional local redefinitions.

\subsection{Commands to Assist Sorting}
\label{sec:gidxsortcmds}

If the \newtermopt{sort} value isn't set, it will be obtained from
the name. For example:
\begin{codebox}
\gls{newterm}\marg{duck}
\end{codebox}
is equivalent to:
\begin{codebox}
\gls{newterm}\oarg{\newtermoptval{sort}{duck}}\marg{duck}
\end{codebox}
Some processing is performed on the name to assist the creation of a
missing \newtermopt{sort} value. If the name contains fragile
commands, either explicitly set the \newtermopt{sort} value or
redefine \gls{newtermsorthook} to locally change the fragile
commands to expand to nothing or to something suitable for sorting.
If you want to double-check the sort value, switch on \opt{verbose}
mode and \gls{newterm} will write information, including the sort
value, to the transcript.

\begin{information}
The sort handler function may perform additional changes to the sort
value, regardless of whether \newtermopt{sort} is set explicitly or
obtained from the name.
\end{information}

The steps to create the missing \newtermopt{sort} value are similar 
to those for the label, but there are some slight differences.
\begin{enumerate}
\item Local redefinitions of common formatting commands.

The command \gls{glsadd} will be redefined to ignore its argument.
Various commands are redefined to \gls{DTLgidxNoFormat}, which
simply expands to its argument. This is largely redundant now, since
the purification step will strip any non-expandable commands.
Commands such as \gls{cs.amp} are replaced via
\gls{datagidxconvertchars}.

\item Local redefinitions of special markup commands.

The markup commands described in \sectionref{sec:gidxmarkupcmds}
are redefined: 

\begin{itemize}
  \item \code{\gls{DTLgidxName}\margm{arg1}\margm{arg2}} and 
  \code{\gls{DTLgidxOffice}\margm{arg1}\margm{arg2}} expand to
  \code{\meta{arg2}\gls{datatoolpersoncomma} \meta{arg1}};

  \item \code{\gls{DTLgidxPlace}\margm{arg1}\margm{arg2}} expands to
  \code{\meta{arg2}\gls{datatoolplacecomma} \meta{arg1}};

  \item \code{\gls{DTLgidxSubject}\margm{arg1}\margm{arg2}} expands to
  \code{\meta{arg2}\gls{datatoolsubjectcomma} \meta{arg1}};

  \item \code{\gls{DTLgidxParen}\margm{arg}} expands to
   \code{\gls{datatoolparenstart} \meta{arg}};

  \item \code{\gls{DTLgidxMac}\margm{arg}} expands to \qt{Mac},
   ignoring its argument; 

  \item \code{\gls{DTLgidxSaint}\margm{arg}} expands to \qt{Saint},
  ignoring its argument; 

  \item \code{\gls{DTLgidxIgnore}\margm{arg}} expands to nothing;

  \item \code{\gls{DTLgidxRank}\margm{arg1}\margm{arg2}} and 
  \code{\gls{DTLgidxParticle}\margm{arg1}\margm{arg2}} expand to
  \code{\meta{arg2}.}\ (that is, they ignore their first argument 
  and insert \qtt{.} after the second argument);

  \item \code{\gls{DTLgidxNameNum}\margm{n}} expands to its numeric argument
zero-padded to two digits.

\end{itemize}

\item Local redefinitions of standard math-Greek commands (such as
\gls{alpha}) to words (via \gls{datagidxwordifygreek}).

\item User hook.

\item Protected expansion of the supplied name.

\end{enumerate}

The user hook is:
\cmddef{newtermsorthook}
This does nothing by default. It may be redefined to perform any
additional local redefinitions.

\section{Referencing Terms}
\label{sec:useentry}

Terms that have been defined with \gls{newterm} can be referenced in
the document with:
\cmddef{useentry}
This robust command fetches the given field (the value in the column labelled
\meta{col-key}) for the term identified by \meta{label}, displays it
(in a hyperlink, if applicable),
and marks the term as having been used. 

\begin{information}
See \sectionref{sec:datagidxtermdatabases} for a list of the default
column keys. Additional fields (see
\sectionref{sec:gidxcustomfields}) can also be referenced if they
were present when the term was defined.
\end{information}

For example, suppose I have
previously (in the preamble) defined the term \qt{reptile} using:
\begin{codebox}
\gls{newterm}\marg{reptile}
\end{codebox}
I can now reference this term in the document:
\begin{codebox}
\gls{useentry}\marg{reptile}\marg{Text}
\end{codebox}
or if I want the plural, I can use:
\begin{codebox}
\gls{useentry}\marg{reptile}\marg{Plural}
\end{codebox}
There is also a sentence case command:
\cmddef{Useentry}
This makes the first letter of the field value uppercase (using the \sty{mfirstuc}
package) or for all caps:
\cmddef{USEentry}
This converts all the text obtained from the field to uppercase.

If the \sty{hyperref} package is loaded, the above commands will
automatically create hyperlinks to the relevant entry in the
index/glossary (produced with \gls{printterms}). You can 
suppress this action for individual cases by using one of the
following analogous commands instead. (To suppress all hyperlinks,
use \gls{DTLgidxDisableHyper}.)

\cmddef{useentrynl}
As \gls{useentry} but with no hyperlink. If the \sty{hyperref} package
hasn't been loaded, this is equivalent to \gls{useentry}.

The sentence case version is:
\cmddef{Useentrynl}
This is as \gls{Useentry} but with no hyperlink. If the \sty{hyperref} package
hasn't been loaded, this is equivalent to \gls{Useentry}.

The all caps version is:
\cmddef{USEentrynl}
This is as \gls{USEentry} but with no hyperlink. If the \sty{hyperref} package
hasn't been loaded, this is equivalent to \gls{USEentry}.

You can also specify your own custom text:
\cmddef{glslink}
This behaves like \gls{useentry} but displays the provided text instead of
the value of a field.

In all the above commands, the \meta{label} argument may optionally
start with \oargm{format}, where \meta{format} is the name of a control
sequence name \emph{without} the preceding backslash. This command will be
applied to this location in the entry's location list when it's
displayed in the index/glossary (produced with \gls{printterms}).

For example:
\begin{codebox}
\gls{useentry}\marg{[textbf]reptile}\marg{Text}
\end{codebox}
Note that the command (\csfmt{textbf} in the above example) should take
one argument (the location). If you attempt to use a
declaration (such as \csfmt{bfseries}) the effect won't be localised.

You can simply display the value of a field using:
\cmddef{glsdispentry}
This robust command is like \gls{useentry} but it doesn't index or create a
hyperlink.

The sentence case version is:
\cmddef{Glsdispentry}
This robust command is like \gls{Useentry} but it doesn't index or create a
hyperlink.

The above commands aren't expandable. If you want to fetch a value
without displaying or using it, you can use:
\cmddef{DTLgidxFetchEntry}
where \meta{cs} is a control sequence, \meta{label} is the label
that uniquely identifies the entry and \meta{col-key} is column key
identifying the required field. The command \meta{cs} is defined to
expand to the value of that field. If the value isn't found, an
error will be triggered and \meta{cs} will be null (see
\sectionref{sec:null}). 

\begin{information}
Remember that you can also simply use the
general purpose database commands or actions, such as
\gls{DTLassignfirstmatch} or \action{select-row}, to fetch
information. However, you will need to specify the database name,
which isn't required with \gls{DTLgidxFetchEntry} (since it uses the
label to database mapping created by \gls{newterm}).
\end{information}

You can add an entry to the index/glossary without displaying any
text using:
\cmddef{glsadd}
This simply indexes the term.
As with \gls{useentry}, \meta{label} maybe in the form
\code{\oargm{format}\margm{label}} where \meta{format} is the name of a
control sequence \emph{without} the leading backslash.

You can also add all entries from a particular database using:
\cmddef{glsaddall}
This essentially iterates over all rows of the database identified
by \meta{db-name}, indexing each entry with a blank location.

\begin{information}
Unlike the commands of the same name provided by the
\sty{glossaries} package, here there is a difference between
\gls{glsaddall} and using \gls{glsadd} on all entries in the database.
In the case of \gls{glsadd} a location is added to the location list
for that entry. However in the case of \gls{glsaddall} no location is
added to each entry's location list, but the location list is set to
non-null so the entry will appear in the index/glossary.
\end{information}

\subsection{Shortcut Commands}
\label{sec:gidxshortcuts}

There are some shortcuts to common fields (if you are used to the
\sty{glossaries} package, note that these commands have different
syntax to the commands provided by \sty{glossaries} with the same
name):
\cmddef{gls}
This is equivalent to \code{\gls{useentry}\margm{label}\marg{Text}}.

\cmddef{glspl}
This is equivalent to \code{\gls{useentry}\margm{label}\marg{Plural}}.

\cmddef{glsnl}
This is equivalent to \code{\gls{useentrynl}\margm{label}\marg{Text}}.

\cmddef{glsplnl}
This is equivalent to \code{\gls{useentrynl}\margm{label}\marg{Plural}}.

\cmddef{Gls}
This is equivalent to \code{\gls{Useentry}\margm{label}\marg{Text}}.

\cmddef{Glspl}
This is equivalent to \code{\gls{Useentry}\margm{label}\marg{Plural}}.

\cmddef{Glsnl}
This is equivalent to \code{\gls{Useentrynl}\margm{label}\marg{Text}}.

\cmddef{Glsplnl}
This is equivalent to \code{\gls{Useentrynl}\margm{label}\marg{Plural}}.

\cmddef{glssym}
This is equivalent to \code{\gls{useentry}\margm{label}\marg{Symbol}}.

\cmddef{Glssym}
This is equivalent to \code{\gls{Useentry}\margm{label}\marg{Symbol}}.

\subsection{Locations}
\label{sec:locations}

Each location shown in \gls{printterms} is, by default, the page number on 
which the term was referenced.
The counter used for the location is obtained by expanding:
\cmddef{DTLgidxCounter}
If redefined, this must expand to a valid counter name. The
\gidxopt{counter} option redefines \gls{DTLgidxCounter} to the given
value (with a check to determine that the supplied name is valid).

\begin{information}
It's not possible to have different counters for different
databases. If you want that flexibility, use the \sty{glossaries}
package instead. The most flexible solution for esoteric numbering
systems that need to work with \sty{hyperref} is to use 
\sty{glossaries-extra} with the \code{record\dhyphen nameref}
package option and \app{bib2gls}.
\end{information}

Each location is saved in the \ext+{aux} file and added to the
\optfmt{Location} field list for the relevant row of the database on
the next run. The location list is then displayed (if supported by
the style) at the end of the relevant row in \gls{printterms} using
\gls{DTLgidxLocation} (which is modified by the \gidxopt{location}
option). The entire content of the \optfmt{Location}
field is encapsulated with the special marker \gls{dtlspecialvalue}.

A location may be in the form \meta{prefix}\meta{c}\meta{num} where
\meta{c} is a character used to separate components of the location.
This character is the \emph{compositor}. The default compositor is a
period\slash full stop but may be changed with the
\gidxopt{compositor} option or with:
\cmddef{DTLgidxSetCompositor}
The argument should be a single character. For most documents, the
page numbers are a simply unprefixed number, in which case this
setting may be ignored. However, if you change the location counter,
for example to \ctrfmt{section}, you may need to take the compositor
into account.

\section{Adding Extra Fields}
\label{sec:gidxcustomfields}

If you want additional fields, you need to create a new column in
the database and a corresponding option for use in \gls{newterm}.
This can be done with:
\cmddef{newtermaddfield}
For each database listed in the comma-separated list of database
labels \meta{db list}, this will create a new column with the key
\meta{column key} (with the given \meta{data type} if set, see 
\sectionref{sec:datatypes}). If the \meta{db list} argument is
missing, all databases that have been defined with \gls{newgidx}
will be iterated over.

The \meta{placeholder cs} argument should be a
command to use as the placeholder. This will be added to the
assignment list \gls{DTLgidxAssignList}. If \meta{placeholder cs} is
omitted, it will be formed from the column key. Note that the
command must not already be defined.

The \meta{new term key} argument is the option name
for use in \gls{newterm} (or \gls{newacro}) to set the new field,
and \meta{default value} is the default value to use if the new
option isn't provided. Note that this will only affect subsequent
instances of \gls{newterm} or \gls{newacro}.

Within \meta{default value}, you can reference another value with:
\cmddef{field}
The \meta{key} argument should be the \gls{newterm} option name (not the
database column key).

For example, suppose I want to be able to specify an alternative
plural. I can add a new field like this:
\begin{codebox}
\gls{newtermaddfield}\marg{AltPlural}\marg{altplural}\marg{}
\end{codebox}
This adds a new column with the label \optfmt{AltPlural} to each
defined index/glossary database and adds a new key called
\optfmt{altplural} that I can now use in the optional argument of \gls{newterm}. 
The default is set to empty. Now I can define terms with an alternative plural:
\begin{codebox}
\gls{newterm}\oarg{altplural=kine}\marg{cow}
\end{codebox}
In the document, I can use \code{\gls{gls}\marg{cow}} to display
\qt{cow},
\code{\gls{glspl}\marg{cow}} to display \qt{cows} and
\code{\gls{useentry}\marg{cow}\marg{AltPlural}} to display \qt{kine}. To make life a
little easier, I can define a new command to save typing:
\begin{codebox}
\cmd{newcommand}*\marg{\cmd{glsaltpl}}[1]\marg{\gls{useentry}\marg{\#1}\marg{AltPlural}}
\end{codebox}
Now I can just do \code{\cmd{glsaltpl}\marg{cow}} to display \qt{kine}.

Here's another example. Suppose I want to add a field that produces
the past tense of a verb. In this case, the default should be formed
by appending \qt{ed} to the \newtermopt{text} value. The new
field can be defined as follows:
\begin{codebox}
\gls{newtermaddfield}\marg{Ed}\marg{ed}\marg{\gls{field}\marg{text}ed}
\end{codebox}
This adds a new column labelled \optfmt{Ed} and defines a new key called
\optfmt{ed} that can be used with \gls{newterm}. Now I can define some
verbs:
\begin{codebox}
\gls{newterm}\marg{jump}
\gls{newterm}\oarg{ed=went}\marg{go}
\end{codebox}

Let's define a shortcut command to access this field:
\begin{codebox}
\cmd{newcommand}*\marg{\cmd{glsed}}[1]\marg{\gls{useentry}\marg{\#1}\marg{Ed}}
\end{codebox}
This new field can now be referenced in the document:
\begin{coderesult}
He \cmd{glsed}\marg{jump} over the gate.
She \cmd{glsed}\marg{go} to the shop.
\tcblower
He jumped over the gate. 
She went to the shop.
\end{coderesult}

\section{Abbreviations}
\label{sec:gidxabbr}

You may have noticed that you can specify \newtermopt{short} and
\newtermopt{long} values when you define a new term. There is a
convenient shortcut command which uses \gls{newterm} to define an
abbreviation:
\cmddef{newacro}
This is a shortcut for:
\begin{compactcodebox}
\gls{newterm}
 \oarg{
  \newtermoptvalm{description}{\gls{capitalisewords}\margm{long}},
  \newtermoptvalm{short}{\gls{acronymfont}\margm{short}},
  \newtermoptvalm{long}{\meta{long}},
  \newtermoptvalm{text}{\gls{DTLgidxAcrStyle}\margm{long}\marg{\gls{acronymfont}\margm{short}}},
  \newtermoptvalm{plural}{\gls{DTLgidxAcrStyle}\marg{\meta{long}s}\marg{\gls{acronymfont}\marg{\meta{short}s}}},
  \newtermoptvalm{sort}{\meta{short}},
  \meta{options}
 }
 \margm{SHORT}
\end{compactcodebox}
where \meta{SHORT} is \meta{short} converted to uppercase, and
\gls{capitalisewords} is defined in \sty{mfirstuc} (which is automatically
loaded by \styfmt{datagidx}).

\cmddef{acronymfont}
By default this just typesets its argument but can be redefined if
the abbreviations need to be typeset in a certain style (such as small
caps).

\cmddef{DTLgidxAcrStyle}
This governs how the abbreviation is typeset in the \newtermopt{text}
value. This defaults to: \meta{long} (\meta{short}).

\begin{information}
The plural form is obtained by appending \qt{s} to the \meta{long}
and \meta{short} form. If this is inappropriate you will need to 
set the \newtermopt{plural}, \newtermopt{shortplural} and
\newtermopt{longplural} values in the optional argument of
\gls{newacro}.
\end{information}

The \sty{datagidx} package only provides a very basic abbreviation
style. For more complex requirements, consider using the
\sty{glossaries-extra} package. See
\gallerypage{sample-abbr-styles}{Gallery: Abbreviation Styles} for
examples.

\subsection{Using Abbreviations}
\label{sec:gidxuseabbr}

You can use terms that represent abbreviations via commands such as
\gls{useentry}. For example, if you define the following in the
preamble:
\begin{codebox}
\gls{newacro}\marg{css}\marg{cascading style sheet}
\end{codebox}
then later in the text you can use:
\begin{codebox}
\gls{useentry}\marg{css}\marg{Short}
\end{codebox}
to access the short form and
\begin{codebox}
\gls{useentry}\marg{css}\marg{Long}
\end{codebox}
to access the long form. You can also use
\begin{codebox}
\gls{useentry}\marg{css}\marg{Text}
\end{codebox}
(or \code{\gls{gls}\marg{css}}) to access the full version. However with
abbreviations, you may prefer to have only the full form on first use and just
the short form on subsequent use. The following commands are
provided to do that. The singular form is obtained using:
\cmddef{acr}
This robust command does:
\begin{compactcodebox}
\gls{ifentryused}\margm{label}\marg{\gls{useentry}\margm{label}\marg{Short}}
\marg{\gls{DTLgidxFormatAcr}\margm{label}\marg{Long}\marg{Short}}
\end{compactcodebox}

The plural form is obtained using:
\cmddef{acrpl}
This robust command does:
\begin{compactcodebox}
\gls{ifentryused}\margm{label}\marg{\gls{useentry}\margm{label}\marg{ShortPlural}}
\marg{\gls{DTLgidxFormatAcr}\margm{label}\marg{LongPlural}\marg{ShortPlural}}
\end{compactcodebox}

Note that, unlike the \sty{glossaries} package, \gls{acr} isn't the
same as \gls{gls}. With \sty{datagidx}, \gls{gls} always references
the \optfmt{Text} value. There is no \qt{first} field.

\begin{important}
Take care when using \gls{acr} and \gls{acrpl} with \cls{beamer}. Using overlays can
cause problems with first use expansions.
\end{important}

As a general rule, it's not consider appropriate to capitalise the first
letter of an abbreviation (especially if it is displayed in small caps)
but if you need to you, for example, first use occurs at the start
of a sentence, can use the following commands.

\cmddef{Acr}
This robust command does:
\begin{compactcodebox}
\gls{ifentryused}\margm{label}\marg{\gls{Useentry}\margm{label}\marg{Short}}
\marg{\gls{DTLgidxFormatAcrUC}\margm{label}\marg{Long}\marg{Short}}
\end{compactcodebox}

\cmddef{Acrpl}
This robust command does:
\begin{compactcodebox}
\gls{ifentryused}\margm{label}\marg{\gls{Useentry}\margm{label}\marg{ShortPlural}}
\marg{\gls{DTLgidxFormatAcrUC}\margm{label}\marg{LongPlural}\marg{ShortPlural}}
\end{compactcodebox}

The commands used for formatting and indexing the first use form
are:
\cmddef{DTLgidxFormatAcr}
This does:
\begin{compactcodebox}
\gls{DTLgidxAcrStyle}
 \marg{\gls{glsdispentry}\margm{label}\margm{long-field}}
 \marg{\gls{useentry}\margm{label}\margm{short-field}}
\end{compactcodebox}

\cmddef{DTLgidxFormatAcrUC}
This does:
\begin{compactcodebox}
\gls{DTLgidxAcrStyle}
 \marg{\gls{Glsdispentry}\margm{label}\margm{long-field}}
 \marg{\gls{useentry}\margm{label}\margm{short-field}}
\end{compactcodebox}
Note that \gls{DTLgidxFormatAcrUC} will need to be redefined if
\gls{DTLgidxAcrStyle} is redefined to show the short form first.

\subsection{Unsetting and Resetting Abbreviations}
\label{sec:gidxunset}

You can reset a term so it's marked as not used with:
\cmddef{glsreset}
or you can unset a term so it's marked as used with:
\cmddef{glsunset}
These commands change the value stored in the \optfmt{Used} field
(see \sectionref{sec:datagidxtermdatabases}).

You can reset all the terms defined in a given database using:
\cmddef{glsresetall}
or unset all the terms defined in a given database using:
\cmddef{glsunsetall}
where \meta{db-name} is the name of the database as supplied when
the database was defined using \gls{newgidx}.

\section{Displaying the Index or Glossary}
\label{sec:printterms}

A database created by \gls{newgidx} can be displayed with:
\cmddef{printterms}
The optional argument is a \keyval\ list that may be used to
override the default settings (available options are described in
\sectionsref{sec:gidxnewprintopts,sec:gidxprintopts}).
To allow the hooks to reference the current database,
\gls{printterms} defines:
\cmddef{DTLgidxCurrentdb}
This will expand to the database's name (as identified by
\gidxopt{database}).

The heading and style is obtained from the special \optfmt{datagidx}
catalogue database (see \sectionref{sec:datagidxstructure}), but
this may be overridden by the options provided to \gls{printterms}.
The style is set with \gls{datagidxsetstyle}. Note that this means
that any redefinitions of style commands made before
\gls{printterms} will be overridden.

The code supplied by the \gidxopt{sort} option is used to sort the
database (which should be referenced with \gls{DTLgidxCurrentdb}).
The special markup commands \gls{DTLgidxName}, \gls{DTLgidxPlace},
\gls{DTLgidxSubject}, and \gls{DTLgidxOffice} are redefined to
invert their arguments (see \sectionref{sec:gidxmarkupcmds}).

Then \gls{printterms} will then iterate over the database
using \gls{DTLgidxForeachEntry}
where the \meta{body} argument is simply \gls{datagidxitem}, which is set by
the style.

The placeholder commands set by \gls{DTLgidxForeachEntry} (which
are obtained by expanding \gls{DTLgidxAssignList}) may be referenced in the
\gidxopt{condition} option or the \gidxopt{include-if} or
\gidxopt{include-if-fn} definitions to filter rows from the database.
However, note that \gls{DTLgidxForeachEntry} automatically filters
out any row that has a non-null \gidxvar{Parent} regardless of the
condition. Other rows will also be automatically filtered if they
have null \optfmt{Location}, \optfmt{See} and \optfmt{SeeAlso}
fields (that is, the term hasn't been indexed).

\begin{information}
The \optfmt{LetterGroup} column is filled by the default
\gidxopt{sort} code, which uses
\sortdataoptval{save-group-key}{LetterGroup} to obtain and save the
letter group. If the \gidxopt{sort} code is changed to omit this
option then \gls{datagidxcurrentgroup} will be null (see
\sectionref{sec:null} for information about null values).
\end{information}

If the \gidxopt{show-groups} (or \gidxopt{showgroups}) setting is on,
\gls{datagidxcurrentgroup} will be expanded at the start of each
iteration and, at the end of the iteration (after \meta{body}), 
the expanded value will be saved in \gls{datagidxprevgroup}.

This allows the styles to compare \gls{datagidxcurrentgroup}
with \gls{datagidxprevgroup} to determine if the letter group has
changed. If the values have changed, a
letter group heading can be inserted where the group title is obtained with:
\cmddef{DTLgidxGroupHeaderTitle}
This will expand to \csmetafmt{datagidx}{group}{name}, if it exists,
or simply \meta{group} otherwise.

Note that \gls{printterms} does:
\begin{compactcodebox}
\gls{DTLgidxForeachEntry}\marg{\gls{datagidxitem}}
\end{compactcodebox}
This will format each entry that both satisfies \gidxopt{condition}
(or \gidxopt{include-if} or \gidxopt{include-if-fn}) and
has a null \gidxvar{Parent} according to the current style.
It's up to the style to determine whether or not to display the
child entries along with their parent entry. (The list of child
labels can be obtained by expanding \gidxvar{Children}).

Finally, \gls{printterms} does \gls{datagidxend}, which is again
defined by the style and should close any groups that were opened
with \gls{datagidxstart}. If \gls{twocolumn} was issued by a
combination of \gidxoptval{columns}{2} and
\gidxoptval{balance}{false}, and two-column mode wasn't already in
effect before \gls{printterms}, then one column mode will be
restored with:
\cmddef{printtermsrestoreonecolumn}
This is simply defined to do \gls{onecolumn}.

\subsection{Hooks and Associated Commands}
\label{sec:printtermhooks}

The commands described here are independent of the style, that is
the style may use them but should not redefine them. They may
be redefined explicitly, but some of these commands are redefined by
a setting, such as \gidxopt{child} or \gidxopt{post-name}.

\cmddef{DTLgidxSetColumns}
Locally sets the default number of columns in the index/glossary. The
\gidxopt{columns} option uses this command. The value must be
greater than 0.

\cmddef{DTLgidxNameCase}
This command encapsulates the \gidxvar{Name} placeholder, and is
intended for case change. If redefined, it should take into account
that its argument will be a command not the actual text. The
\gidxopt{name-case} option redefines \gls{DTLgidxNameCase} to use
the applicable command. The default definition simply expands to its
argument (that is, not case-change is applied).

\cmddef{DTLgidxNameFont}
This command encapsulates
\code{\gls{DTLgidxNameCase}\marg{\gidxvar{Name}}} and is used to
apply a font change. The \gidxopt{name-font} option redefines 
\gls{DTLgidxNameFont}. The default definition is to use
\csfmt{textnormal}.

The name, including the case-changing and font-changing commands,
will be encapsulated with \gls{datagidxtarget}, which will create a
hyper-target, if supported. After that will be the post-name hook.

\cmddef{DTLgidxPostName}
This command is the post-name hook inserted after the name for
entries that have a null \gidxvar{Parent}. The \gidxopt{post-name} option
redefines \gls{DTLgidxPostName}.

\cmddef{DTLgidxPostChildName}
This command is the post-name hook inserted after the name for
child entries (that is, entries that have a non-null
\gidxvar{Parent}). The default definition is simply \gls{DTLgidxPostName}.


\cmddef{DTLgidxChildStyle}
Encapsulates the child's name (including \gls{DTLgidxNameFont} and
\gls{DTLgidxNameCase}) and post-name hook
(\gls{DTLgidxPostChildName}). The default definition simply expands
to its argument. The \gidxoptval{child}{noname} setting redefines
\gls{DTLgidxChildStyle} to ignore its argument and expand to
\gls{DTLgidxChildCountLabel}. The \gidxoptval{child}{noname} setting redefines
\gls{DTLgidxChildStyle} to expand to its argument (that is, back to
its original definition).

\cmddef{DTLgidxChildCountLabel}
Expands to \code{\thectr{DTLgidxChildCount})\visiblespace} (that is,
the value of the child counter, followed by a closing parenthesis
and space).

The symbol and description (if not null and not empty) may be shown,
depending on the \gidxopt{symbol-desc} setting.

\cmddef{DTLgidxSymDescSep}
Separator to place between the symbol and description if both are
present.

\cmddef{DTLgidxFormatDesc}
Encapsulates the description, if applicable. Note that the argument
will be the \gidxvar{Description} placeholder.

\cmddef{DTLgidxPostDescription}
Inserted after the description, if applicable.

\cmddef{DTLgidxEndItem}
Inserted at the end of each item (after the location list, child list and
cross-references, if applicable). The default definition is
\code{\cmd{par} \cmd{smallskip}} (which creates a paragraph break
and a small vertical gap).

The location list may or may not be shown, depending on the
\gidxopt{location} setting. The \gidxoptval{location}{hide} setting
will omit the location list and the pre and post location hooks.

\cmddef{DTLgidxPreLocation}
Inserted before the location, if applicable. The
\gidxopt{pre-location} setting redefines this command.

\cmddef{DTLgidxPostLocation}
Inserted after the location, if applicable.

\cmddef{DTLgidxFormatSee}
Used to format the \qt{see} cross-reference list. The \meta{tag} is the
textual prefix, and the \meta{label-list} argument is the
comma-separated list of labels, obtained from expanding the
\gidxvar{See} placeholder.

\cmddef{DTLgidxFormatSeeAlso}
Used to format the \qt{see also} cross-reference list. This has a
similar definition to \gls{DTLgidxFormatSee} but a pre hook before
the tag and a post hook after the list, which are determined by the
style.

\cmddef{DTLgidxSeeTagFont}
Encapsulates the \meta{tag} part in the definition of \gls{DTLgidxFormatSee}
and \gls{DTLgidxFormatSeeAlso}.
By default, this uses \csfmt{emph}.

Each item label in the cross-reference list is encapsulated with:
\cmddef{DTLidxFormatSeeItem}
This fetches the corresponding name from the database and, if
supported, creates a hyperlink to the referenced label.

\cmddef{DTLidxSeeLastSep}
Inserted between the final two items in the cross-reference list.

\cmddef{DTLidxSeeSep}
Inserted between all except the final two items in the cross-reference list.

\cmddef{seename}
Used for the tag in \gls{DTLgidxFormatSee}, this command is defined
by language packages, such as \sty{babel}, but will be provided by
\sty{datagidx} if not already defined.

\cmddef{seealsoname}
Used for \qt{see also} references, if not already defined it will be
defined to \gls{alsoname}, if that command exists, or to \qt{see
also} otherwise.

\cmddef{datagidxsymbolwidth}
This dimension is set with the \gidxopt{symbol-width} option, but
may also be changed with \csfmt{setlength}. If zero or negative, the
symbol will just occupy its natural space, otherwise the styles that
support this setting will allocate this width for the location list.

\cmddef{datagidxlocationwidth}
This dimension is set with the \gidxopt{location-width} option, but
may also be changed with \csfmt{setlength}. If zero or negative, the
location list will just occupy its natural space, otherwise the
styles that support this setting will allocate this width for the location
list.

\cmddef{datagidxsymalign}
Alignment of the symbol if the symbol width dimension has
been set to a positive value.

\cmddef{datagidxlocalign}
Alignment of the location list if the location width dimension has
been set to a positive value.

\subsection{Index or Glossary Styles}
\label{sec:indexstyles}

The style used by \gls{printterms} is specified with the \gidxopt{style} option.
The default is \gidxoptval{style}{index}.

\subsubsection{index}
\label{sec:gidxstyleindex}

The default \optfmt{index} style is a basic style for indexes, but the symbol
and description will be shown if set, and it will follow
the \gidxopt{symbol-width} and \gidxopt{location-width} settings.

\subsubsection{indexalign}
\label{sec:gidxstyleindexalign}

The \optfmt{indexalign} style is similar to the \optfmt{index} style but
aligns the descriptions. This requires an initial iteration over the
database to calculate the alignment.

\subsubsection{align}
\label{sec:gidxstylealign}

The \optfmt{align} style aligns the fields. It will follow
the \gidxopt{symbol-width} and \gidxopt{location-width} settings,
but will require an initial iteration over the
database to calculate the alignment.

\subsubsection{gloss}
\label{sec:gidxstylegloss}

The \optfmt{gloss} style is a basic style for glossaries.

\cmddef{DTLgidxChildSep}
Separator between child entries.

\cmddef{DTLgidxPostChild}
Hook inserted at the end of the list of child entries.

\subsubsection{dict}
\label{sec:gidxstyledict}

The \optfmt{dict} style is a dictionary style, for a hierarchical
structure where the top level entries have a name. The next level is
used to indicate a category, such as \qt{adjective} or \qt{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
\optfmt{Child} column is ignored by this style. The symbol is ignored. The
location and symbol widths are also ignored.

If \gidxoptval{show-groups}{true}, the group headers will be
inserted with \gls{DTLgidxDictHead}.

\cmddef{DTLgidxDictPostItem}
Inserted at the end of each item.

\cmddef{datagidxdictindent}
Indentation used by the \optfmt{dict} style. Note that this isn't a
register, so it should be changed with \csfmt{renewcommand}.

\cmddef{DTLgidxDictHead}
Inserts the group header. This will use \csfmt{chapter} if it has
been defined or \csfmt{section} otherwise. The title is obtained
with \gls{DTLgidxGroupHeaderTitle}.

\cmddef{DTLgidxCategoryNameFont}
Encapsulates the \qt{category} child names. Just expands to its
argument by default.

\cmddef{DTLgidxCategorySep}
Separator used between the category entries.

\cmddef{DTLgidxSubCategorySep}
Separator used between child entries whose parent entry is a
category.

\subsection{Sorting the Index or Glossary Database}
\label{sec:indexsort}

When displaying the list, \gls{printterms} will automatically sort
the database according to the \gidxopt{sort} option. The default
code is:
\begin{compactcodebox*}
\gls{DTLsortdata}
 \oarg{\sortdataoptval{save-group-key}{LetterGroup}}
 \marg{\gls{DTLgidxCurrentdb}}\comment{current database}
 \marg{HierSort=\marg{\sortdatacolumnoptval{replacements}{Sort}},FirstId}
\end{compactcodebox*}
This sorts by the \optfmt{HierSort} column first. If the value isn't
set, the value from the \optfmt{Sort} column will be used.
In the event that two rows being compared have identical sort
values, the \optfmt{FirstId} column will be compared.
Note that \gls{DTLgidxCurrentdb} is used to identify the database.

\begin{information}
Remember that \gls{DTLsortdata} is influenced by the available
localisation support.
\end{information}

Prior to version 3.0, the default \gidxopt{sort} code was:
\begin{compactcodebox*}
\gls{dtlsort}\marg{Sort,FirstId}\marg{\gls{DTLgidxCurrentdb}}\marg{\gls{dtlwordindexcompare}}
\end{compactcodebox*}
Note that this is less efficient than using the newer 
\gls{DTLsortdata} and there was no \optfmt{HierSort} column.
However, if you want to revert back to this behaviour without using
rollback, you can do:
\begin{codebox}
\gls{printterms}\oarg{\gidxoptval{sort}{
\gls{dtlsort}\marg{Sort,FirstId}\marg{\gls{DTLgidxCurrentdb}}\marg{\gls{dtlwordindexcompare}}
}}
\end{codebox}

If you don't want the database sorted, just set \gidxopt{sort} to an
empty value:
\begin{codebox}
\gls{printterms}\oarg{\gidxoptval{sort}{}}
\end{codebox}

\subsubsection{Optimization}
\label{sec:optimize}

Version 3.0 has improved sorting times by switching to
the more efficient \styfmt{l3seq} sorting function. However, for a
large database, you may still want to switch on the optimization
settings.

If you have used indexing applications, such as \appfmt{makeindex},
you'll be familiar with the document creation process. The document
is first compiled, then the indexing application is run to sort and
collate the entries, then the document is compiled again (and
possibly once more). This involves two (or three) runs and one sort
and collate run (with the process possibly repeated in the event of
complex documents with shifting page numbers). With the
\sty{datagidx} package, the sorting and collation is done every
\LaTeX\ run. For a large index, this can be quite slow. If you're
not editing the index or glossary, you might prefer not to have to
keep sorting the database whenever you update the document. To
assist this, \sty{datagidx} provides the \opt{datagidx.optimize}
package option. This may take the following values:

\optionvaldef{datagidx.optimize}{off}

Don't use the optimize facility. The index\slash glossary databases
will be sorted every run, unless the sorting is switched off
by setting the \gidxoptval{sort} key to empty.

\optionvaldef{datagidx.optimize}{low}

Use the \qt{low} optimize setting. This only sorts the index\slash
glossary databases on every run. This is assuming that the sorting
is done via the \gls{printterms} \gidxoptval{sort} key, rather than
by explicitly sorting the database with commands like
\gls{DTLsortdata} somewhere else in the document.

\begin{warning}
Don't use the \optval{datagidx.optimize}{low} setting if sorting the
databases makes the document out of date. For example, the group
headers use sectioning commands.
\end{warning}

\optionvaldef{datagidx.optimize}{high}

Use the \qt{high} optimize setting. This sorts the index/glossary
databases on the first run, then writes the sorted databases to
external files, which are read in on subsequent runs. Again this
assumes that sorting is done via the 
\gls{printterms} \gidxoptval{sort} key. Don't use this option if you
want to edit the index\slash glossary database.

\section{Supplementary Commands}
\label{sec:gidxsuppl}

\cmddef{DTLgidxEnableHyper}
Enables hyperlinks, if supported. This redefines \gls{datagidxtarget}
and \gls{datagidxlink} back to their
default behaviour, which tests for the existence of \gls{hypertarget}
and \gls{hyperlink}.

\cmddef{DTLgidxDisableHyper}
Disables hyperlinks. This redefines \gls{datagidxtarget}
and \gls{datagidxlink} to simply expand to their \meta{text}
argument.

\subsection{Conditionals and Loops}
\label{sec:gidxcond}

\cmddef{iftermexists}
Expands to \meta{true} if a term has been defined with the given
label, otherwise expands to \meta{false}.

\cmddef{ifentryused}
This is a robust command that does \meta{true} if term identified by
the given \meta{label} has been marked as used. (That is, the value
for the \optfmt{Used} column for the associated row is set to 1.)

\cmddef{DTLgidxForeachEntry}
Iterates over the current database (obtained by expanding
\gls{DTLgidxCurrentdb}) using \gls{DTLmapdata} with
\mapdataoptval{read-only}{true}. This command is primarily provided for use
within \gls{printterms}. If you want to use it explicitly, make sure
that \gls{DTLgidxCurrentdb} expands to the required database name.

The \meta{body} argument is done
for each row where all of the following apply:
\begin{itemize}
  \item the \optfmt{Parent} field is null;

  \item the \optfmt{Location} or \optfmt{See} or \optfmt{SeeAlso} fields is non-null
and non-empty;

  \item the entry has been marked as used;

  \item the condition evaluated by the current \gidxopt{condition}
  or \gidxopt{include-if} or \gidxopt{include-if-fn} setting is true.
\end{itemize}

If \meta{body} is done, the value of \gidxvar{Label} will be added
to a global list of referenced labels, which is used at the end of the
document to check if a rerun is required.

After \meta{body} is done, the current letter group information is
saved in:
\cmddef{datagidxprevgroup}
This allows the styles to compare \gls{datagidxcurrentgroup}
with \gls{datagidxprevgroup} to determine if the letter group has
changed.

The placeholder commands are assigned by expanding:
\cmddef{DTLgidxAssignList}
The default expansion is:
\begin{compactcodebox}[breakable]
\inlineglsdef{gidxvar.Name}=Name,
\inlineglsdef{gidxvar.Description}=Description,
\inlineglsdef{gidxvar.Used}=Used,
\inlineglsdef{gidxvar.Symbol}=Symbol,
\inlineglsdef{gidxvar.Long}=Long,
\inlineglsdef{gidxvar.Short}=Short,
\inlineglsdef{gidxvar.LongPlural}=LongPlural,
\inlineglsdef{gidxvar.ShortPlural}=ShortPlural,
\inlineglsdef{gidxvar.Location}=Location,
\inlineglsdef{gidxvar.See}=See,
\inlineglsdef{gidxvar.SeeAlso}=SeeAlso,
\inlineglsdef{gidxvar.Text}=Text,
\inlineglsdef{gidxvar.Plural}=Plural,
\inlineglsdef{gidxvar.CurrentLocation}=CurrentLocation,
\inlineglsdef{gidxvar.Label}=Label,
\inlineglsdef{gidxvar.Parent}=Parent,
\inlineglsdef{gidxvar.Children}=Child,
\inlineglsdef{gidxvar.FirstId}=FirstId,
\inlineglsdef{gidxvar.HierSort}=HierSort,
\inlineglsdef{gidxvar.Sort}=Sort,
\inlineglsdef{datagidxcurrentgroup}=LetterGroup
\end{compactcodebox}
If new fields are added with \gls{newtermaddfield}, the supplied
placeholder command will be added to the assignment list. If you
manually add columns, using commands like \gls{DTLaddcolumn}, you
can append your own custom placeholders to this list if they need to
be referenced.

\begin{warning}
If you redefine \gls{DTLgidxAssignList} so that it omits the essential
placeholder commands referenced by \gls{printterms} and its
underlying hooks, errors will occur.
\end{warning}

\cmddef{datagidxmapdata}
This command is similar to \gls{DTLgidxForeachEntry} but is provided
for use by the styles to iterate over all entries in the current
database (typically to calculate the width of certain field values).
Unlike \gls{DTLgidxForeachEntry}, the letter group
commands aren't updated and the list of referenced labels isn't
updated.

\subsection{New Terms}
\label{sec:gidxnewtermsupp}

There is a hook implemented at the end of \gls{newterm}:
\cmddef{postnewtermhook}
This expands to nothing by default. Just before this hook,
\gls{newterm} will define:
\cmddef{datagidxlastlabel}
to expand to the term's label. This may be used to reference the
term within the hook.

When \gls{newterm} automatically generates the
\newtermopt{label} and
\newtermopt{sort} values (if omitted, see
\sectionsref{sec:gidxlabel,sec:gidxsortcmds}) certain commands are
locally set to:
\cmddef{DTLgidxNoFormat}
This simply expands to its argument by default (equivalent to
\csfmt{@firstofone}).
\cmddef{DTLgidxGobble}
This simply expands to nothing (equivalent to
\csfmt{@gobble}).

Certain commands, such as \gls{cs.amp}, are converted with:
\cmddef{datagidxconvertchars}
This is largely redundant with the new \LaTeX3 commands and
\sty{datatool-base}['s] localisation support, but is retained for
backward-compatibility. There is a similar command for converting
commands such as \gls{alpha}:
\cmddef{datagidxwordifygreek}

\subsection{Styles}
\label{sec:gidxstylesextra}

\cmddef{datagidxsetstyle}
This is implemented by \gls{printterms} to set the current style,
which means that any redefinitions of the style commands listed
below will be overridden.  If you want to make any adjustments to
these commands, you will need to define a new style.
\cmddef{datagidxnewstyle}
This defines a new style called \meta{style-name}. The
\meta{definitions} argument may start with
\code{\gls{datagidxsetstyle}\margm{other-style}} if
only minor modifications to an existing style (\meta{other-style}) are required.

In order to support hyperlinks, the entry name (including the
case-changing and font changing commands) should be placed in the
second argument of:
\cmddef{datagidxtarget}
The first argument will be the \gidxvar{Label} placeholder. This
will generate a hypertarget with the label as the
target name, if supported, and display \meta{text}.

\cmddef{datagidxlink}
If hyperlinks are support, creates a hyperlink with
\meta{text} as the link text, otherwise just does \meta{text}.

\begin{information}
If the labels used are likely to cause a conflict with other
hyperlinks in the document, redefine \gls{datagidxtarget} and 
\gls{datagidxlink} to insert a prefix.
\end{information}

\ctrdef{DTLgidxChildCount}
This counter should typically not be explicitly changed.
The provided styles reset the \ctr{DTLgidxChildCount} counter to 0 at the
start of each child list and increment it for each child entry. The
\gidxoptval{child}{noname} setting redefines \gls{DTLgidxChildStyle}
to use \gls{DTLgidxChildCountLabel}, ignoring its argument.

\section{Database Structures}
\label{sec:datagidxstructure}

There are two types of databases recognised by \sty{datagidx}: the
catalogue database, and the databases used to store the terms.

\subsection{The Catalogue Database}
\label{sec:datagidxcatalogue}

The \sty{datagidx} package automatically creates a database called
\optfmt{datagidx}. This database keeps track of all the databases
that are created by \gls{newgidx} along with their particular
settings. The \optfmt{datagidx} database has the following column
keys:
\begin{itemize}
\item \optfmt{Glossary}: this column stores the label of the
database created with \optfmt{datagidx} (the \meta{db-name} argument
of \gls{newgidx});

\item \optfmt{Title}: this column stores the title to be used by
\gls{printterms} (the \meta{title} argument
of \gls{newgidx});

\item \optfmt{Heading}: this column stores the heading to be used by
\gls{printterms} (which can be set with the \gidxopt{heading} option);

\item \optfmt{PostHeading}: this column stores the post-heading
content to be used by \gls{printterms} (which can be set with the 
\gidxopt{post-heading} option);

\item \optfmt{MultiCols}: this column stores the environment name to
use by \gls{printterms} for multiple columns
(\gidxoptval{balance}{true} sets this value to \starredenv{multicols}
and \gidxoptval{balance}{false} sets this value to
\env{multicols});

\item \optfmt{Sort}: this column stores the code that
\gls{printterms} should use to sort the data before displaying it
(which can be set with the \gidxopt{sort} option);

\item \optfmt{Style}: this column stores the style name that
\gls{printterms} should use to displaying the data
(which can be set with the \gidxopt{style} option);

\item \optfmt{ShowGroups}: this column stores the
\gidxopt{show-groups} setting (that is, \optfmt{true} or
\optfmt{false}).

\end{itemize}

\subsection{The Term Databases}
\label{sec:datagidxtermdatabases}

Each database created with \gls{newgidx} contains each defined term
or abbreviation associated with that database. The column keys used 
to store the information are
listed below. The placeholder commands used in the column value assignments 
in the expansion text of the default definition of \gls{DTLgidxAssignList}
are shown in parentheses.
\begin{itemize}
\item \optfmt{Label} (\gidxvar{Label}): the unique label that
identifies the entry;

\item \optfmt{Text} (\gidxvar{Text}): the entry's text for use by
commands like \gls{gls};

\item \optfmt{Plural} (\gidxvar{Plural}): the entry's plural text
for use by commands like \gls{glspl};

\item \optfmt{Symbol} (\gidxvar{Symbol}): the entry's symbol for use by
commands like \gls{glssym}, if applicable;

\item \optfmt{Short} (\gidxvar{Short}): the entry's short
(abbreviated) form for use by commands like \gls{acr}, if applicable;

\item \optfmt{ShortPlural} (\gidxvar{ShortPlural}): the entry's short
plural form for use by commands like \gls{acrpl}, if applicable;

\item \optfmt{Long} (\gidxvar{Long}): the entry's long form for use by
commands like \gls{acr}, if applicable;

\item \optfmt{LongPlural} (\gidxvar{LongPlural}): the entry's long
plural form for use by commands like \gls{acrpl}, if applicable;
\end{itemize}
The following columns are primarily intended for use in
\gls{printterms}:
\begin{itemize}
\item \optfmt{Name} (\gidxvar{Name}): the entry's name, as it
should appear in \gls{printterms};

\item \optfmt{Description} (\gidxvar{Description}): the entry's
description, as it should appear in \gls{printterms},
if applicable;

\item \optfmt{See} (\gidxvar{See}): the entry's \qt{see} cross-reference, 
if applicable;

\item \optfmt{SeeAlso} (\gidxvar{SeeAlso}): the entry's \qt{see also} cross-reference, 
if applicable;

\item \optfmt{Parent} (\gidxvar{Parent}): the entry's parent label,
if applicable;

\item \optfmt{Child} (\gidxvar{Children}): a comma-separated list of
child labels, which is updated whenever a new entry is defined
identifying this entry as its parent;

\item \optfmt{Location} (\gidxvar{Location}): the location list
obtained from the previous run;

\item \optfmt{LetterGroup} (\gls{datagidxcurrentgroup}): the entry's 
letter group, as obtained by \gls{DTLsortdata} with the default
\gidxopt{sort} setting.

\end{itemize}
The following are considered internal fields, but may be referenced
in the sorting or filtering code.
\begin{itemize}

\item \optfmt{Sort} (\gidxvar{Sort}): the entry's sort value (which
normally defaults to the name but may be explicitly set with the
\newtermopt{sort} option);

\item \optfmt{HierSort} (\gidxvar{HierSort}): the entry's 
hierarchical sort value, if applicable, which is obtained from the sort value
appended the parent's hierarchical sort value;

\item \optfmt{FirstId} (\gidxvar{FirstId}): a numeric value
corresponding to the first reference (indexing) of the term, so sorting by this
column will normally result in an order of use listing;

\item \optfmt{Used} (\gidxvar{Used}): a column that will contain
either 0 (unused) or 1 (used) marked up as a special value (see
\sectionref{sec:specialvalue}) to indicate whether or not the entry
has been used in the current run.
\end{itemize}

The following are considered worker fields that will typically not
be needed in hooks or styles.
\begin{itemize}

\item \optfmt{CurrentLocation} (\gidxvar{CurrentLocation}): the location list
obtained from the current run, which may be one off due to the
delayed output routine;

\item \optfmt{UnsafeLocation}: the value of the
\optfmt{CurrentLocation} from the previous run, which may be one off due to the
delayed output routine (the current and previous unsafe locations
are compared to determine if the locations have changed). This
field isn't included in \gls{DTLgidxAssignList} as it's only used to
check if the location list has changed from the previous run to
determine whether or not to issue a rerun warning.
\end{itemize}

\section{Examples}
\label{sec:datagidxexs}

\mExampleref{ex:index} uses the \sty{datagidx} package to create an
index. Note that I've specified English as the locale. This means
that I also need to have \sty{datatool-english} installed.
\begin{codebox}
\cmd{usepackage}\oarg{\optval{locales}{en}}\marg{datagidx}
\end{codebox}
The \sty{hyperref} package is also used:
\begin{codebox}
\cmd{usepackage}[colorlinks]\marg{hyperref}
\end{codebox}
The database is created and populated in the preamble:
\begin{codebox}
\gls{newgidx}\marg{index}{Index}\comment{define a database for the index}%
\gls{DTLgidxSetDefaultDB}\marg{index}\comment{set this as the default}%
\gls{newterm}\marg{macédoine}
\gls{newterm}\marg{macramé}
\gls{newterm}\marg{élite}
\gls{newterm}\marg{reptile}
\gls{newterm}\oarg{\newtermoptval{seealso}{reptile}}{crocodylian}
\gls{newterm}\oarg{\newtermoptval{parent}{crocodylian}}{crocodile}
\gls{newterm}\oarg{\newtermoptval{parent}{crocodylian}}{alligator}
\gls{newterm}\oarg{
 \newtermoptval{parent}{crocodylian},
 \newtermoptvalm{description}{(also cayman)}
}
{caiman}
\gls{newterm}\oarg{\newtermoptval{see}{caiman}}{cayman}
\end{codebox}
The document text consists of:
\begin{codebox}
Here are some words containing accents: \gls{gls}\marg{macédoine},
\gls{gls}\marg{macramé} and \gls{gls}\marg{élite}. \gls{Gls}\marg{élite} starts with an uppercase
letter. A \gls{gls}\marg{crocodylian} is the family of 
\gls{glspl}\marg{reptile} that includes \gls{glspl}\marg{crocodile}, \gls{glspl}\marg{alligator}
and \gls{glspl}\marg{caiman}.
\end{codebox}
The index is displayed with:
\begin{codebox}
\gls{printterms}
 \oarg{
   \gidxoptvalm{heading}{\cmd{section}*},
   \gidxoptval{database}{index},
   \gidxoptval{prelocation}{dotfill},
   \gidxopt{showgroups}
 }
\end{codebox}

This requires two \LaTeX\ runs to ensure that the index is up to
date.

\begin{resultbox}[float]
\createexample*[label={ex:index},
 arara={pdflatex,pdflatex,pdfcrop},
 title={Creating an Index},
 description={Example document demonstrating creating an index}
]
{%
\cmd{usepackage}\oarg{\optval{locales}{en}}\marg{datagidx}\comment{requires datatool-english}
\cmd{usepackage}[colorlinks]\marg{hyperref}\nl
\gls{newgidx}\marg{index}{Index}\comment{define a database for the index}%
\gls{DTLgidxSetDefaultDB}\marg{index}\comment{set this as the default}%
\gls{newterm}\marg{macédoine}\nl
\gls{newterm}\marg{macramé}\nl
\gls{newterm}\marg{élite}\nl
\gls{newterm}\marg{reptile}\nl
\gls{newterm}\oarg{\newtermoptval{seealso}{reptile}}{crocodylian}\nl
\gls{newterm}\oarg{\newtermoptval{parent}{crocodylian}}{crocodile}\nl
\gls{newterm}\oarg{\newtermoptval{parent}{crocodylian}}{alligator}\nl
\gls{newterm}\oarg{\nlsp
 \newtermoptval{parent}{crocodylian},\nlsp
 \newtermoptvalm{description}{(also cayman)}\nl
}\nl
{caiman}\nl
\gls{newterm}\oarg{\newtermoptval{see}{caiman}}{cayman}
}
{%
Here are some words containing accents: \gls{gls}\marg{macédoine},\nl
\gls{gls}\marg{macramé} and \gls{gls}\marg{élite}. \gls{Gls}\marg{élite} starts with an uppercase\nl
letter. A \gls{gls}\marg{crocodylian} is the family of \nl
\gls{glspl}\marg{reptile} that includes \gls{glspl}\marg{crocodile}, \gls{glspl}\marg{alligator}\nl
and \gls{glspl}\marg{caiman}.
\codepar
\gls{printterms}\nl
 \oarg{\nlsp
   \gidxoptvalm{heading}{\cmd{section}*},\nlsp
   \gidxoptval{database}{index},\nlsp
   \gidxoptval{prelocation}{dotfill},\nlsp
   showgroups\nl
 }
}
\end{resultbox}

\mExampleref{ex:abbrev} uses the \sty{datagidx} package to create a
list of abbreviations. The \sty{hyperref} package is also used:
\begin{codebox}
\cmd{usepackage}\marg{datagidx}
\cmd{usepackage}[colorlinks]\marg{hyperref}
\end{codebox}
The database is created and populated in the preamble:
\begin{codebox}
\gls{newgidx}\marg{abbreviations}{Abbreviations}
\gls{DTLgidxSetDefaultDB}\marg{abbreviations}
\gls{newacro}\marg{html}\marg{hyper-text markup language}
\gls{newacro}\marg{css}\marg{cascading style sheet}
\end{codebox}
The following overrides the default description:
\begin{codebox}
\gls{newacro}\oarg{\newtermoptvalm{description}{eXtensible Markup Language}}
 \marg{xml}\marg{extensible markup language}
\end{codebox}
The document text is:
\begin{codebox}
First use: \gls{acr}\marg{xml} and \gls{acr}\marg{css}.
\codepar
Next use: \gls{acr}\marg{xml} and \gls{acr}\marg{css}.
\codepar
Full form: \gls{gls}\marg{xml} and \gls{gls}\marg{css}.
\end{codebox}
The list of abbreviations is displayed with:
\begin{codebox}
\gls{printterms}
 \oarg{
   \gidxoptval{postdesc}{dot},\comment{put a full stop after the description}
   \gidxoptval{columns}{1},\comment{one column page layout}
   \gidxoptvalm{namefont}{\cmd{textbf}},\comment{put the name (i.e. the abbreviation) in bold}
   \gidxoptval{namecase}{uc},\comment{make the name upper case}
   \gidxoptval{style}{align}\comment{use the 'align' style}
 }
\end{codebox}

\begin{resultbox}[float]
\createexample*[label={ex:abbrev},
 arara={pdflatex,pdflatex,pdfcrop},
 title={Creating a List of Abbreviations},
 description={Example document demonstrating creating a list of
abbreviations}
]
{%
\cmd{usepackage}\marg{datagidx}\nl
\cmd{usepackage}[colorlinks]\marg{hyperref}\nl
\gls{newgidx}\marg{abbreviations}{Abbreviations}\comment{define a database for the abbreviations}
\gls{DTLgidxSetDefaultDB}\marg{abbreviations}\comment{set this as the default}
\comment{define abbreviations:}
\gls{newacro}\marg{html}\marg{hyper-text markup language}\nl
\gls{newacro}\marg{css}\marg{cascading style sheet}\nl
\comment{The following overrides the default description:}
\gls{newacro}\oarg{\newtermoptvalm{description}{eXtensible Markup Language}}
 \marg{xml}\marg{extensible markup language}
}
{
First use: \gls{acr}\marg{xml} and \gls{acr}\marg{css}.
\codepar
Next use: \gls{acr}\marg{xml} and \gls{acr}\marg{css}.
\codepar
Full form: \gls{gls}\marg{xml} and \gls{gls}\marg{css}.
\codepar
\gls{printterms}
 \oarg{\nl
   \gidxoptval{postdesc}{dot},\comment{put a full stop after the description}
   \gidxoptval{columns}{1},\comment{one column page layout}
   \gidxoptvalm{namefont}{\cmd{textbf}},\comment{put the name (i.e. the abbreviation) in bold}
   \gidxoptval{namecase}{uc},\comment{make the name upper case}
   \gidxoptval{style}{align}\comment{use the 'align' style}
 }
}
\end{resultbox}

\chapter{Referencing People (\stytext{person} package)}
\label{sec:person}

\pkgdef{person}
The \sty{person} package can be used to define (\sectionref{sec:persondefundef}) 
and reference people (\sectionref{sec:refperson}). This
package automatically loads the \sty{datatool} package, since it's
primarily intended for use with databases (for example, for mail
merging). However, you can simply define an individual or a list of
people without needing a database. If you don't require
\sty{datatool}, use the \personstyopt{base-only} package option, which
will only load \sty{datatool-base} rather than \sty{datatool}.
Examples are provided in \sectionref{sec:personexs}.

The \sty{person} package was rewritten in version 3.0 to use
\LaTeX3 commands. The internal list of labels is now stored as a
sequence variable, which means that loop commands, such as
\gls{foreachperson}, no longer use \gls{@for}. This will only make a
difference if you have used the \sty{xfor} commands to break the
loop.

\begin{warning}
Some commands that have the potential to conflict with commands from
other packages have been replaced. In most cases, the deprecated
command will be provided in v3.0 (if not already defined) with a warning, but may be
removed in future. Two commands have been completely removed:
\gls{malelabels} and \gls{femalelabels}. They have been replaced
with comma-separated list variables. Use \gls{PersonSetMaleLabels}
and \gls{PersonSetFemaleLabels} to replace the lists if required.
\end{warning}

If there are any backward-compatibility issues, rollback to version
2.32 is available:
\begin{codebox}
\cmd{usepackage}\marg{person}[=2.32]
\end{codebox}
Note that if \sty{datatool} hasn't already been loaded, this will
also apply rollback to \sty{datatool}. Problems may occur if a newer
release of \sty{datatool} has already been loaded.

The \sty{person} package now has the provision for \sty{tracklang} 
localisation support, using the same localisation settings as for
the underlying \sty{datatool-base} package. The
\sty{datatool-english} package (distributed separately) includes
the file \file{person-english.ldf} which provides the
English localisation support for the \sty{person} package. This
simply needs to be installed on \TeX's path and will be loaded
automatically if required (see \sectionref{sec:personlang}).

Any options recognised by \sty{datatool-base} may also be passed to
the \sty{person} package. Similarly for \sty{datatool} if that
should also be loaded.
For example:
\begin{codebox}
\cmd{usepackage}\oarg{\optval{locales}{en-GB}}\marg{person}
\end{codebox}

\section{Package Options}
\label{sec:personstyopts}

The following options may be passed to the \sty{person} package when
it loads. They can't be used in \gls{DTLsetup}.

\optiondef{personsty.base-only}
Only load \sty{datatool-base}, not \sty{datatool} (if not already
loaded). You may additionally pass any options to \sty{person} that
are recognised by \sty{datatool-base}.

\optiondef{personsty.datatool}
Load \sty{datatool} (unless it has already been loaded). You may
additionally pass any options to \sty{person} that are recognised by
\sty{datatool}. This is the default.

\optiondef{personsty.shortcuts}
Defines the shortcut commands listed in \tableref{tab:shortcuts}. 
If not passed as a package option, 
this option may also be used within the \opt{person} option of
\gls{DTLsetup}:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{person}{\personopt{shortcuts}}}
\end{codebox}

\section{Other Options}
\label{sec:personopts}

These options may be used within the \opt{person} option of
\gls{DTLsetup}. For example:
\begin{codebox}
\gls{DTLsetup}\marg{\optvalm{person}{\personopt{global}}}
\end{codebox}

\optiondef{person.local}
A boolean option that determines whether commands such as
\gls{newperson} have a local effect.

\optiondef{person.global}
Antonym of \personopt{local}. That is, \personoptval{global}{true}
is equivalent to \personoptval{local}{false}.

\optiondef{person.shortcuts}
Defines the shortcut commands listed in \tableref{tab:shortcuts}. 
If this option or the \opt{personsty.shortcuts}
package option has already used, this does nothing.

\section{Defining and Undefining People}
\label{sec:persondefundef}

The effect of these commands may be scoped
\personoptval{local}{true}. Otherwise they will be global.

\cmddef{newperson}
Defines a new person with the given full name (\meta{full name}) and familiar or first
name (\meta{name}) who can be identified with the given label
\meta{person-label}. The mandatory arguments will all be fully
expanded and trimmed, so this is equivalent to:
\begin{compactcodebox}
\gls{newperson*}\oargm{person-label}\marg{
 \newpersonoptvalm{expand-fullname}{\meta{full name}},
 \newpersonoptvalm{expand-name}{\meta{name}},
 \newpersonoptvalm{gender}{\meta{gender-label}}
}
\end{compactcodebox}
See the descriptions of the \newpersonopt{fullname}, \newpersonopt{name}
and \newpersonopt{gender} options for further details.

If the \meta{person-label} optional argument is omitted, \optfmt{anon} will be
used. This is the default label for commands such as
\gls{personname} so with the \personopt{local} setting on, this is
useful in a scoped context to create a temporary person without the
need to assign a new label.

\cmddef{newperson*}
The starred version is new to version 3.0 and has a \keyval\ list
argument, which makes it more flexible and allows for additional
information to be supplied. The optional argument
\meta{person-label} is as for the unstarred \gls{newperson}.
There are no required settings. If all are omitted, then the person
will have an empty name and unknown gender.

Available options:
\optiondef{newperson.fullname}
The person's full name. If omitted or empty, the full name will be
constructed as follows:
\begin{itemize}
\item if \newpersonopt{forenames} is set then, if the surname is
also set, the full name will be
set to the forenames followed by a space and then the surname,
otherwise the full name will be just the forenames;
\item if \newpersonopt{name} is set then, if the surname is also
set, the full name with be
set to the name followed by a space and then the surname,
otherwise the full name will be just the name;
\item if the \newpersonopt{surname} is set then, if the \newpersonopt{title}
is also set, the full name will be the title followed by \gls{persontitlesurnamesep}
and then the title, otherwise the full name will be set to just the
surname.
\end{itemize}

\optiondef{newperson.expand-fullname}
As \newpersonopt{fullname} but fully expands the value.

\optiondef{newperson.expand-once-fullname}
As \newpersonopt{fullname} but expands the first token once.

\optiondef{newperson.name}
The person's familiar or first name.

\optiondef{newperson.expand-name}
As \newpersonopt{name} but fully expands the value.

\optiondef{newperson.expand-once-name}
As \newpersonopt{name} but expands the first token once.

\optiondef{newperson.forenames}
The person's forenames. If omitted or empty, this will be set to the
\newpersonopt{name}.

\optiondef{newperson.expand-forenames}
As \newpersonopt{forenames} but fully expands the value.

\optiondef{newperson.expand-once-forenames}
As \newpersonopt{forenames} but expands the first token once.

\optiondef{newperson.surname}
The person's surname.

\optiondef{newperson.expand-surname}
As \newpersonopt{surname} but fully expands the value.

\optiondef{newperson.expand-once-surname}
As \newpersonopt{surname} but expands the first token once.

\optiondef{newperson.title}
The person's title (form of address).

\optiondef{newperson.expand-title}
As \newpersonopt{title} but fully expands the value.

\optiondef{newperson.expand-once-title}
As \newpersonopt{title} but expands the first token once.

\optiondef{newperson.gender}
The person's gender. The value \meta{gender-label} will first be
tested for null (see \sectionref{sec:null}) using 
\gls{datatoolifnullorempty:n}. If it's null, \optfmt{unknown} will
be assumed, otherwise \meta{gender-label} will be fully expanded
and tested against the recognised gender labels (see
\sectionref{sec:persongender}).  If \meta{gender-label} is omitted or
expands to empty, \optfmt{unknown} will be assumed.

\cmddef{PersonTotalCount}
Expands to the total number of defined people.

\cmddef{removeperson}
Removes the person identified by \meta{person-label} from the
list of known people and undefines the underlying commands.

\cmddef{removepeople}
Removes each person identified by their label in the given
comma-separated list.

\cmddef{removeallpeople}
Removes all defined people.

\section{Genders}
\label{sec:persongender}

\begin{warning}
If you have localisation support for the \sty{person} package, be
aware that changing the language may result in resetting
the gender labels back to the default for that language.
\end{warning}

When defining a new person, you can identify the person's gender
using a label. There are four categories:
\begin{deflist}
\itemtitle{Male}
\begin{itemdesc}
The internal label used to identify the male gender is
\optfmt{male}. This label, which is used in the construction of
underlying language-sensitive commands, may always be used in \gls{newperson} or
for the \newpersonopt{gender} option in \gls{newperson*} (regardless
of whether or not it is included in the allowed list of alternative
male labels).

Alternative male labels, which may be used to reference the gender
in \gls{newperson}, may be provided as a comma-separated list in the
argument of:
\cmddef{PersonSetMaleLabels}
The default list is: \optfmt{Male}, \optfmt{MALE}, \optfmt{M} and
\optfmt{m}. You can append to this list using:
\cmd{PersonAddMaleLabel}
This will expand the label before adding it to the internal list.
Both commands have a global effect, regardless of the
\personopt{local} setting.

The list may be set by a localisation file or you can
set or append to it before you define new people.

\begin{important}
Command names have changed in version 3.0 to reduce conflict
with other packages. The older command \inlineglsdef{addmalelabel} is now
deprecated and will do \gls{PersonAddMaleLabel}. The older command
\inlineglsdef{malelabels} which stored the list has been replaced
with \inlineglsdef{gpersonmalelabelclist}. If you have a pre-v3.0
document that redefined \gls{malelabels}, replace the redefinition
with \gls{PersonSetMaleLabels}.
\end{important}
\end{itemdesc}

\itemtitle{Female}
\begin{itemdesc}
The internal label used to identify the female gender is
\optfmt{female}. This label, which is used in the construction of
underlying language-sensitive commands, may always be used in \gls{newperson} or
for the \newpersonopt{gender} option in \gls{newperson*} (regardless
of whether or not it is included in the allowed list of alternative
female labels).

Alternative female labels, which may be used to reference the gender
in \gls{newperson}, may be provided as a comma-separated list in the
argument of:
\cmddef{PersonSetFemaleLabels}
The default list is: \optfmt{Female}, \optfmt{FEMALE}, \optfmt{F} and
\optfmt{f}. You can append to this list using:
\cmd{PersonAddFemaleLabel}
This will expand the label before adding it to the internal list.
Both commands have a global effect, regardless of the
\personopt{local} setting.

The list may be set by a localisation file or you can
set or append to it before you define new people.

\begin{important}
Command names have changed in version 3.0 to reduce conflict
with other packages. The older command \inlineglsdef{addfemalelabel} is now
deprecated and will do \gls{PersonAddFemaleLabel}. The older command
\inlineglsdef{femalelabels} which stored the list has been replaced
with \inlineglsdef{gpersonfemalelabelclist}. If you have a pre-v3.0
document that redefined \gls{femalelabels}, replace the redefinition
with \gls{PersonSetFemaleLabels}.
\end{important}
\end{itemdesc}

\itemtitle{Non-Binary}
\begin{itemdesc}
The internal label used to identify non-binary is
\optfmt{nonbinary}. This label, which is used in the construction of
underlying language-sensitive commands, may always be used in \gls{newperson} or
for the \newpersonopt{gender} option in \gls{newperson*} (regardless
of whether or not it is included in the allowed list of alternative
non-binary labels).

Alternative non-binary labels, which may be used to reference the gender
in \gls{newperson}, may be provided as a comma-separated list in the
argument of:
\cmddef{PersonSetNonBinaryLabels}
The default list is: \optfmt{non-binary}, \optfmt{Nonbinary},
\optfmt{Non-Binary}, \optfmt{NONBINARY}, \optfmt{N} and
\optfmt{n}. You can append to this list using:
\cmd{PersonAddNonBinaryLabel}
This will expand the label before adding it to the internal list.
Both commands have a global effect, regardless of the
\personopt{local} setting.

The list may be set by a localisation file or you can
set or append to it before you define new people.
\end{itemdesc}

\itemtitle{Unknown}
\begin{itemdesc}
The internal label used to identify an unknown gender is
\optfmt{unknown}. This label is used in the construction of
language-sensitive commands. When defining a person with \gls{newperson}, the
gender label may be set to \optfmt{unknown} or empty. There are no
alternative labels as this category is provided for instances where
the information isn't provided.
\end{itemdesc}

\end{deflist}

If you want to test if a label is a recognised gender label, you can
use the following commands. The \meta{gender-label} argument will
have the first token expanded once. The expansion will first be
compared against the internal label and then tested if it's in the
relevant comma-separated list. These commands are robust.

\cmddef{PersonIfMaleLabel}
Does \meta{true} if the one-level expansion of \meta{gender-label}
is recognised as a male gender identifier. (This replaces the older,
deprecated \inlineglsdef{ifmalelabel}.)

\cmddef{PersonIfFemaleLabel}
Does \meta{true} if the one-level expansion of \meta{gender-label}
is recognised as a female gender identifier. (This replaces the older,
deprecated \inlineglsdef{iffemalelabel}.)

\cmddef{PersonIfNonBinaryLabel}
Does \meta{true} if the one-level expansion of \meta{gender-label}
is recognised as a non-binary gender identifier.
Note that this does not include \qt{unknown}.

\cmddef{PersonMaleCount}
Expands to the total number of people defined with the gender set to
male.

\cmddef{PersonFemaleCount}
Expands to the total number of people defined with the gender set to
female.

\cmddef{PersonNonBinaryCount}
Expands to the total number of people defined with the gender set to
non-binary.

\cmddef{PersonUnknownGenderCount}
Expands to the total number of people defined with the gender set to
unknown.

\section{Displaying Information}
\label{sec:refperson}

The commands below that start with \csfmt{person} show the
applicable language-sensitive text according to the gender of the
person identified by the label. If the label is omitted,
\optfmt{anon} is assumed. The commands that start with
\csfmt{Person} are the sentence case equivalents.

The commands that start with \csfmt{people} show the plural form
according to the gender of the group of all defined people. If all
people were defined with the same gender, then the plural form for
that gender is used, otherwise the plural form for the unknown
gender will be used. If only one person has been defined, then
resulting text will be equivalent to the analogous \csfmt{person}
command. The commands that start with
\csfmt{People} are the sentence case equivalents.

The text produced by these commands can be changed with
\gls{PersonSetLocalisation}. For example:
\begin{codebox}
\gls{PersonSetLocalisation}\marg{unknown}\marg{pronoun2}\marg{thou}
\gls{PersonSetLocalisation}\marg{unknown}\marg{objpronoun2}\marg{thee}
\gls{PersonSetLocalisation}\marg{unknown}\marg{possadj2}\marg{thy}
\gls{PersonSetLocalisation}\marg{unknown}\marg{posspronoun2}\marg{thine}
\end{codebox}

\subsubsection{Grammar}
\label{sec:persongrammar}

Some of the commands listed here are a bit cumbersome. The
\personopt{shortcuts} option will define shorter synonyms for some
of the commands. These are listed in \tableref{tab:shortcuts}.

\begin{table}[htbp]
\caption{Synonyms provided by the \glsfmttext{opt.personsty.shortcuts} package option}
\label{tab:shortcuts}
\centering
\begin{tabular}{ll}
\bfseries Shortcut Command & \bfseries Equivalent Command\\
\inlineglsdef{they} & \gls{peoplepronoun}\\
\inlineglsdef{They} & \gls{Peoplepronoun}\\
\inlineglsdef{them} & \gls{peopleobjpronoun}\\
\inlineglsdef{Them} & \gls{Peopleobjpronoun}\\
\inlineglsdef{their} & \gls{peoplepossadj}\\
\inlineglsdef{Their} & \gls{Peoplepossadj}\\
\inlineglsdef{theirs} & \gls{peopleposspronoun}\\
\inlineglsdef{Theirs} & \gls{Peopleposspronoun}\\
\inlineglsdef{you} & \gls{peoplepronounii}\\
\inlineglsdef{You} & \gls{Peoplepronounii}\\
\inlineglsdef{thee} & \gls{peopleobjpronounii}\\
\inlineglsdef{Thee} & \gls{Peopleobjpronounii}\\
\inlineglsdef{your} & \gls{peoplepossadjii}\\
\inlineglsdef{Your} & \gls{Peoplepossadjii}\\
\inlineglsdef{yours} & \gls{peopleposspronounii}\\
\inlineglsdef{Yours} & \gls{Peopleposspronounii}\\
\inlineglsdef{children} & \gls{peoplechild}\\
\inlineglsdef{Children} & \gls{Peoplechild}\\
\inlineglsdef{parents} & \gls{peopleparent}\\
\inlineglsdef{Parents} & \gls{Peopleparent}\\
\inlineglsdef{siblings} & \gls{peoplesibling}\\
\inlineglsdef{Siblings} & \gls{Peoplesibling}
\end{tabular}
\end{table}

\cmddef{personpronoun}
Displays the third person singular subjective pronoun according to
the gender of the person identified by the label. The subjective
pronoun is the pronoun used as the subject of the sentence. For
example, \qt{she sees the duck} starts with the female third person
singular subject pronoun:
\begin{codebox}
\gls{newperson*}\marg{\newpersonoptval{name}{Zoë},\newpersonoptval{gender}{female}}
\gls{personpronoun}\cmd{ }sees the duck
\end{codebox}

\cmddef{Personpronoun}
As \gls{personpronoun} but starts with a capital.

\cmddef{peoplepronoun}
Displays the third person plural subjective pronoun according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personpronoun}.
With the \personopt{shortcuts} option, you can use \gls{they}
instead.

\cmddef{Peoplepronoun}
As \gls{peoplepronoun} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{They}
instead.

\cmddef{personpronounii}
Displays the second person singular subjective pronoun according to
the gender of the person identified by the label. In English, this
is \qt{you} regardless of gender.

\cmddef{Personpronounii}
As \gls{personpronounii} but starts with a capital.

\cmddef{peoplepronounii}
Displays the second person plural subjective pronoun according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personpronounii}.
With the \personopt{shortcuts} option, you can use \gls{you}
instead.

\cmddef{Peoplepronounii}
As \gls{peoplepronounii} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{You}
instead.

\cmddef{personobjpronoun}
Displays the third person singular objective pronoun according to
the gender of the person identified by the label. The objective
pronoun is the pronoun used as the object of the sentence. For
example, \qt{the duck sees her} ends with the female third person
singular objective pronoun:
\begin{codebox}
\gls{newperson*}\marg{\newpersonoptval{name}{Zoë},\newpersonoptval{gender}{female}}
the duck sees \gls{personobjpronoun} 
\end{codebox}

\cmddef{Personobjpronoun}
As \gls{personobjpronoun} but starts with a capital.

\cmddef{peopleobjpronoun}
Displays the third person plural objective pronoun according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personobjpronoun}.
With the \personopt{shortcuts} option, you can use \gls{them}
instead.

\cmddef{Peopleobjpronoun}
As \gls{peopleobjpronoun} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Them}
instead.

\cmddef{personobjpronounii}
Displays the second person singular objective pronoun according to
the gender of the person identified by the label. In English, this
is \qt{you} regardless of gender.

\cmddef{Personobjpronounii}
As \gls{personobjpronounii} but starts with a capital.

\cmddef{peopleobjpronounii}
Displays the second person plural objective pronoun according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personobjpronounii}.
With the \personopt{shortcuts} option, you can use \gls{thee}
instead (as opposed to \gls{you} for the subjective pronoun).

\cmddef{Peopleobjpronounii}
As \gls{peopleobjpronounii} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Thee}
instead (as opposed to \gls{You} for the subjective pronoun).

\cmddef{personpossadj}
Displays the third person singular possessive adjective according to
the gender of the person identified by the label. A possessive
adjective indicates that something belongs to someone. For
example, \qt{her book} starts with the female third person
singular possessive adjective:
\begin{codebox}
\gls{newperson*}\marg{\newpersonoptval{name}{Zoë},\newpersonoptval{gender}{female}}
\gls{personpossadj}\cmd{ }book 
\end{codebox}

\cmddef{Personpossadj}
As \gls{personpossadj} but starts with a capital.

\cmddef{peoplepossadj}
Displays the third person plural possessive adjective according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personpossadj}.
In English, there's no difference between singular and plural
possessive adjectives.
With the \personopt{shortcuts} option, you can use \gls{their}
instead.

\cmddef{Peoplepossadj}
As \gls{peoplepossadj} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Their}
instead.

\cmddef{personpossadjii}
Displays the second person singular possessive adjective according to
the gender of the person identified by the label.

\cmddef{Personpossadjii}
As \gls{personpossadjii} but starts with a capital.

\cmddef{peoplepossadjii}
Displays the second person plural possessive adjective according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personpossadjii}.
In English, there's no difference between singular and plural
possessive adjectives.
With the \personopt{shortcuts} option, you can use \gls{your}
instead.

\cmddef{Peoplepossadjii}
As \gls{peoplepossadjii} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Your}
instead.

\cmddef{personposspronoun}
Displays the third person singular possessive pronoun according to
the gender of the person identified by the label. A possessive
pronoun indicates ownership. For
example, \qt{the book is hers} ends with the female third person
singular possessive pronoun:
\begin{codebox}
\gls{newperson*}\marg{\newpersonoptval{name}{Zoë},\newpersonoptval{gender}{female}}
the book is \gls{personposspronoun}
\end{codebox}

\cmddef{Personposspronoun}
As \gls{personposspronoun} but starts with a capital.

\cmddef{peopleposspronoun}
Displays the third person plural possessive pronoun according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personposspronoun}.
With the \personopt{shortcuts} option, you can use \gls{theirs}
instead.

\cmddef{Peopleposspronoun}
As \gls{peopleposspronoun} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Theirs}
instead.

\cmddef{personposspronounii}
Displays the second person singular possessive pronoun according to
the gender of the person identified by the label.

\cmddef{Personposspronounii}
As \gls{personposspronounii} but starts with a capital.

\cmddef{peopleposspronounii}
Displays the second person plural possessive pronoun according to
the gender of all defined people. If only one person has been
defined, this produces the same text as \gls{personposspronounii}.
With the \personopt{shortcuts} option, you can use \gls{yours}
instead.

\cmddef{Peopleposspronounii}
As \gls{peopleposspronounii} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Yours}
instead.

\subsubsection{Relationships}
\label{sec:personrelationships}

\cmddef{personchild}
Displays the person's relationship to their parents (son,
daughter or child).

\cmddef{Personchild}
As \gls{personchild} but starts with a capital.

\cmddef{peoplechild}
Displays the relationship of the defined people to their collective
parents (sons, daughters or children). If only one person is
defined, the result is the same as \gls{personchild}.
With the \personopt{shortcuts} option, you can use \gls{children}
instead.

\cmddef{Peoplechild}
As \gls{peoplechild} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Children}
instead.

\cmddef{personparent}
Displays the person's relationship to their child (father,
mother or parent).

\cmddef{Personparent}
As \gls{personparent} but starts with a capital.

\cmddef{peopleparent}
Displays the relationship of the defined people to their collective
children (fathers, mothers or parents). If only one person is
defined, the result is the same as \gls{personparent}.
With the \personopt{shortcuts} option, you can use \gls{parents}
instead.

\cmddef{Peopleparent}
As \gls{peopleparent} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Parents}
instead.

\cmddef{personsibling}
Displays the person's relationship to their sibling (brother,
sister or sibling).

\cmddef{Personsibling}
As \gls{personsibling} but starts with a capital.

\cmddef{peoplesibling}
Displays the relationship of the defined people to their collective
siblings (brothers, sisters or siblings). If only one person is
defined, the result is the same as \gls{personsibling}.
With the \personopt{shortcuts} option, you can use \gls{siblings}
instead.

\cmddef{Peoplesibling}
As \gls{peoplesibling} but starts with a capital.
With the \personopt{shortcuts} option, you can use \gls{Siblings}
instead.

\subsection{Accessing Individual Information}
\label{sec:personinfo}

The information provided when defining a person can be accessed with
these commands. Where the label identifying the person is optional,
\optfmt{anon} will be used if omitted.

\cmddef{personfullname}
Displays the person's full name (corresponding to the
\newpersonopt{fullname} option). Use \gls{peoplefullname} 
if you want a list of all
defined people showing their full name.

\cmddef{personname}
Displays the person's familiar or first name (corresponding to the
\newpersonopt{name} option). 
Use \gls{peoplename} if you want a list of all
defined people showing their name.

\cmddef{personforenames}
Displays the person's forenames (corresponding to the
\newpersonopt{forenames} option). 
Use \gls{peopleforenames} if you want a list of all
defined people showing their forenames.

\cmddef{personsurname}
Displays the person's surname (corresponding to the
\newpersonopt{surname} option). 
Use \gls{peoplesurname} if you want a list of all
defined people showing their surname.

\cmddef{persontitlesurname}
Displays the person's title and surname separated by
\cmddef{persontitlesurnamesep}
If the person has no title then the full name will be used instead.
Use \gls{peopletitlesurname} if you want a list of all
defined people showing their title and surname.

\cmddef{persongender}
Displays the given person's gender using localisation. This maps the
internal gender label to the corresponding language-sensitive text.

\cmddef{getpersongender}
Defines \meta{cs} to expand to the language-sensitive text
identifying the given person's gender.

\cmddef{getpersongenderlabel}
Defines \meta{cs} to the internal gender label associated with the
given person.

\cmddef{getpersonname}
Defines \meta{cs} to expand to the person's name.

\cmddef{getpersonforenames}
Defines \meta{cs} to expand to the person's forenames.

\cmddef{getpersonsurname}
Defines \meta{cs} to expand to the person's surname.

\cmddef{getpersonfullname}
Defines \meta{cs} to expand to the person's full name.

\cmddef{getpersontitle}
Defines \meta{cs} to expand to the person's title.

\subsection{List People}
\label{sec:personlists}

The commands in this section produce a list of all the defined
people. The separators are given by:
\cmddef{twopeoplesep}
Inserted between the people when the list only contains two
elements. This is simply defined to \gls{DTLlistformatlastsep}.
\cmddef{personlastsep}
Inserted between the final pair when the list contains more that two
elements. This is defined to:
\begin{compactcodebox*}
\gls{DTLlistformatoxford}
\gls{DTLlistformatlastsep}
\end{compactcodebox*}
\cmddef{personsep}
Inserted between people for all but the last pair. This is simply defined
to \gls{DTLlistformatsep}.

\cmddef{peoplefullname}
Displays all the defined people, showing the full name for
each person. Use \gls{personfullname} for an individual.

\cmddef{peoplename}
Displays all the defined people, showing the name for
each person. Use \gls{personname} for an individual.

\cmddef{peopleforenames}
Displays all the defined people, showing the forenames for
each person. Use \gls{personforenames} for an individual.

\cmddef{peoplesurname}
Displays all the defined people, showing the surname for
each person. Use \gls{personsurname} for an individual.

\cmddef{peopletitlesurname}
Displays all the defined people, showing the title and surname for
each person. Use \gls{persontitlesurname} for an individual.


\section{Examples}
\label{sec:personexs}

\subsection{Mail Merging}
\label{sec:mailmergeex}

Sometimes when mail-merging, it may be necessary to reference a
person by their pronoun, but it's inappropriate to make an
assumption and the impersonal \qt{he\slash she}
construct is not only cumbersome but also dated. By defining a
person with a gender (male, female or non-binary), the commands
described in \sectionref{sec:refperson} may be used to insert a
language-sensitive pronoun.

\mExampleref{ex:mailmerge} uses the \qt{scores} database (see
\sectionref{sec:studentscoresdb}) to write a letter to the parent of
each student in the database, informing them of the student's score
and award. The \envfmt{letter} environment implicitly adds scoping,
so with the default \personoptval{local}{true} setting, the
\optfmt{anon} label can be reused for each iteration.

For simplicity, the \clsfmt{letter} class is used:
\begin{codebox}
\cmd{documentclass}\marg{letter}
\end{codebox}
The \personstyopt{shortcuts} option is used to provide the simpler
shortcut commands:
\begin{codebox}
\cmd{usepackage}[\personstyopt{shortcuts}]\marg{person}
\end{codebox}
The data is iterated over using \gls{DTLmapdata}. I've used a
mixture of \gls{DTLmapgetvalues} and \gls{DTLmapget}. You may prefer
to get the parent, score and award values within \gls{DTLmapgetvalues} along
with the other values.
\begin{codebox}
\cbeg{DTLenvmapdata}
\cbeg{letter}\marg{}
\gls{DTLmapgetvalues}\marg{
 \cmd{Forename}=forename, \cmd{Surname}=surname, \cmd{Gender}=gender
}
\gls{newperson*}\marg{
  \newpersonoptval{expand-once-name}{\cmd{Forename}},
  \newpersonoptval{expand-once-surname}{\cmd{Surname}},
  \newpersonoptval{gender}{\cmd{Gender}}
}
\cmd{opening}\marg{Dear \gls{DTLmapget}\marg{\mapgetoptval{key}{parent}}}
\codepar
Your \gls{personchild}\gls{cs.space}\gls{personfullname}\gls{cs.space}
received a score of \gls{DTLmapget}\marg{\mapgetoptval{key}{score}} 
and was awarded a scholarship of
\gls{DTLmapget}\marg{\mapgetoptval{key}{award}}. We look forward to seeing
\gls{them}\gls{cs.space}on \gls{their}\gls{cs.space}arrival.
\codepar
\cmd{closing}\marg{Yours Sincerely}
\cend{letter}
\cend{DTLenvmapdata}
\end{codebox}
The \gls{personfullname} command can be replaced with
\code{\cmd{Forename}\gls{cs.space}\cmd{Surname}}. The advantage of
the \sty{person} package is that the gender-dependent text can more
easily be produced.

\Exampleref{ex:mailmerge} shows the first four pages. Download the
PDF to view the complete document. Note that the student Quinn
doesn't have the gender field set in the database so the placeholder
\csfmt{Gender} command will be null on that iteration. The
\newpersonopt{gender} option will detect this and set the gender to
\optfmt{unknown}. By way of contrast, the student Evelyn has the
gender set to one of the non-binary labels, which means that the
gender will be set to \optfmt{nonbinary}. This doesn't make a
noticeable difference between the two letters (aside from their 
names, the names of their parents, the score and award) as the 
language-sensitive text is the same in both cases.

\begin{resultbox}[float]
\createexample*[label={ex:mailmerge},
 class=letter, tag={studentscores},pages={1,2,3,4},pagesperrow={2},
 title={Mail Merging},link={sec:mailmergeex},
 description={Example document demonstrating mail merging}
]
{%
 \cmd{usepackage}[shortcuts]\marg{person}\nl
 \studentscoresdb
}
{%
\cbeg{DTLenvmapdata}\nl
 \cbeg{letter}\marg{}\nlsp
 \gls{DTLmapgetvalues}\marg{\nldbsp
 \cmd{Forename}=forename,\nldbsp
 \cmd{Surname}=surname,\nldbsp
 \cmd{Gender}=gender\nlsp
}\nlsp
 \gls{newperson*}\marg{\nldbsp
   \newpersonoptval{expand-once-name}{\cmd{Forename}},\nldbsp
   \newpersonoptval{expand-once-surname}{\cmd{Surname}},\nldbsp
   \newpersonoptval{gender}{\cmd{Gender}}\nlsp
 }\nlsp
  \cmd{opening}\marg{Dear \gls{DTLmapget}\marg{\mapgetoptval{key}{parent}}}
\codepar
Your \gls{personchild}\ \gls{personfullname}\ received a score of\nldbsp
\gls{DTLmapget}\marg{\mapgetoptval{key}{score}} and was awarded a scholarship of\nldbsp
\gls{DTLmapget}\marg{\mapgetoptval{key}{award}}. We look forward to seeing\nldbsp
\gls{them}\ on \gls{their}\ arrival.
\codepar
  \cmd{closing}\marg{Yours Sincerely}\nlsp
 \cend{letter}\nl
\cend{DTLenvmapdata}
}
\end{resultbox}

\subsection{Order of Service}
\label{sec:orderofserviceex}

Defining a person with a name and gender can also be useful for
other non-database documents, such as an
order of service for a baptism or funeral. Since the
document is much the same from one person to the next, documents of
this nature are frequently simply copied and a search and replace
edit is used to change the relevant text.  However this can lead to
errors (especially if the previous person's name was Mary!) With
the \sty{person} package, you need only change the definition of
the person by modifying the arguments of \gls{newperson}.

\mExampleref{ex:memorial} doesn't use a database so there's no need
for the \sty{datatool} package so the \personstyopt{base-only}
option is used so that only \sty{datatool-base} not \sty{datatool}
is loaded:
\begin{codebox}
\cmd{usepackage}\oarg{\personstyopt{base-only}}\marg{person}
\end{codebox}
Only one person is defined so the default \optfmt{anon} label can be
used, which means there's no need to supply the label.
\begin{codebox}
\gls{newperson*}\marg{
  \newpersonoptval{forenames}{Mary Jane},
  \newpersonoptval{name}{Mary},
  \newpersonoptval{surname}{Doe},
  \newpersonoptval{gender}{f}
}
\end{codebox}
This is a simple document for demonstration purposes. A real
document would benefit from a custom class that provides better
styling. This is just to illustrate the \sty{person} package
commands:
\begin{codebox}
\cbeg{center}
\cmd{Large}
In Memory of \gls{personfullname}
\cend{center}
\codepar
We are gathered here to remember our 
\gls{personsibling}\gls{cs.space}\gls{personname}.
\gls{Personpronoun}\gls{cs.space}will be much missed, and 
\gls{personpossadj}\gls{cs.space}family are in our prayers.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:memorial},
  title={Memorial Order of Service},link={sec:orderofserviceex},
  description={Example document using the person package to define
and reference a person}
]
{%
\comment{base-only means that only datatool-base.sty is needed
(datatool.sty won't be loaded)}%
\cmd{usepackage}\oarg{base-only}\marg{person}\nl
\gls{newperson*}\marg{\nlsp
  \newpersonoptval{forenames}{Mary Jane},\nlsp
  \newpersonoptval{name}{Mary},\nlsp
  \newpersonoptval{surname}{Doe},\nlsp
  \newpersonoptval{gender}{f}\nl
}
}
{%
\cbeg{center}\nl
\cmd{Large}\nl
In Memory of \gls{personfullname}\nl
\cend{center}
\codepar
We are gathered here to remember our \gls{personsibling}\ \gls{personname}.\nl
\gls{Personpronoun}\ will be much missed, and \gls{personpossadj}\ \nl
family are in our prayers.
}
\end{resultbox}

\begin{information}
Remember that the plural commands will behave like the singular ones
if only one person has been defined so, for example,
\gls{Peoplepronoun} may be used instead of \gls{Personpronoun} even
if only one person has been defined.
\end{information}

\mExampleref{ex:memorial2} produces the same result as \exampleref{ex:memorial}
but it uses the \personstyopt{shortcuts} package option:
\begin{codebox}
\cmd{usepackage}\oarg{\personstyopt{base-only},\personstyopt{shortcuts}}\marg{person}
\end{codebox}
This allows the use of the plural shortcut commands, which makes the
code slightly more readable:
\begin{codebox}
\cbeg{center}
\cmd{Large}
In Memory of \gls{peoplefullname}
\cend{center}
\codepar
We are gathered here to remember our 
\gls{siblings}\gls{cs.space}\gls{peoplename}.
\gls{They}\gls{cs.space}will be much missed, and 
\gls{their}\gls{cs.space}family are in our prayers.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:memorial2},
  title={Memorial Order of Service (Shortcuts)},
  description={Example document using the person package to define
and reference a person using the shortcut commands}
]
{%
\comment{base-only means that only datatool-base.sty is needed
(datatool.sty won't be loaded)}%
\cmd{usepackage}\oarg{base-only,shortcuts}\marg{person}\nl
\gls{newperson*}\marg{\nlsp
  \newpersonoptval{forenames}{Mary Jane},\nlsp
  \newpersonoptval{name}{Mary},\nlsp
  \newpersonoptval{surname}{Doe},\nlsp
  \newpersonoptval{gender}{f}\nl
}
}
{%
\cbeg{center}\nl
\cmd{Large}\nl
In Memory of \gls{peoplefullname}\nl
\cend{center}
\codepar
We are gathered here to remember our \gls{siblings}\ \gls{peoplename}.\nl
\gls{They}\ will be much missed, and \gls{their}\ \nl
family are in our prayers.
}
\end{resultbox}


\mExampleref{ex:baptism} also doesn't use a database:
\begin{codebox}
\cmd{usepackage}\oarg{\personstyopt{base-only}}\marg{person}
\end{codebox}
In this case, two people are defined. This means that unique labels need to be
supplied:
\begin{codebox}
\gls{newperson*}\oarg{john}\marg{
 \newpersonoptval{forenames}{John Joseph},
 \newpersonoptval{name}{John},
 \newpersonoptval{gender}{male}
}\nl
\gls{newperson*}\oarg{jane}\marg{
  \newpersonoptval{forenames}{Jane Mary},
  \newpersonoptval{name}{Jane},
  \newpersonoptval{gender}{female}
}
\end{codebox}
Again, this is a simple document for demonstration purposes where
I've used \csfmt{title} and \csfmt{author} with \csfmt{maketitle} to
show the title. A real
document would benefit from a custom class that provides better
styling. This is just to illustrate the \sty{person} package
commands:
\begin{codebox}
\cmd{title}\marg{Baptism of}
\cmd{author}\marg{\gls{peopleforenames}}
\cmd{maketitle}
\codepar
Today we welcome \gls{peoplename}\gls{cs.space}
into God's family, may He guide
and protect \gls{peopleobjpronoun}.
\end{codebox}
Note that \gls{cs.space} (backslash space) is required after
\gls{peoplename} to force a space.

\begin{resultbox}
\createexample*[label={ex:baptism},
  title={Baptism Order of Service},
  description={Example document using the person package to define
and reference two people}
]
{%
\cmd{usepackage}\oarg{
  base-only, \comment{datatool-base.sty only, no datatool.sty}
\comment{uncomment for localisation support (requires datatool-english):}
  \comment{locales=en}
 }\marg{person}\nl
\gls{newperson*}\oarg{john}\marg{
 \newpersonoptval{forenames}{John Joseph},\nlsp
 \newpersonoptval{name}{John},\nlsp
 \newpersonoptval{gender}{male}\nl
}\nl
\gls{newperson*}\oarg{jane}\marg{
  \newpersonoptval{forenames}{Jane Mary},\nlsp
  \newpersonoptval{name}{Jane},\nlsp
  \newpersonoptval{gender}{female}\nl
}\nl
\cmd{title}\marg{Baptism of}\nl
\cmd{author}\marg{\gls{peopleforenames}}
}
{%
\cmd{maketitle}
\cmd{thispagestyle}\marg{empty}
\codepar
Today we welcome \gls{peoplename}\ into God's family, may He guide
and protect \gls{peopleobjpronoun}.
}
\end{resultbox}

Note that this has the ampersand character (\&) rather than the
textual \qt{and}. Add localisation support if text is preferred. If
localisation support is available but the ampersand character is
preferred, then use \listsoptval{and}{symbol} to switch.

Again the
\personstyopt{shortcuts} option may be used to enable the shorter,
more readable, commands.\examplemarginref{ex:baptism2}%
\begin{codebox}
\cmd{usepackage}\oarg{
 \personstyopt{base-only}, \comment{no datatool.sty}
 \optval{locales}{en-GB}, \comment{(requires datatool-english)}
 \personstyopt{shortcuts}
}\marg{person}
\end{codebox}
The \sty{datetime2} package also uses \sty{tracklang} for its
localisation support. This means that if it's loaded as well, and
\sty{datetime2-english} is also installed, then it can also pick
up the localisation but beware of the ordering.

For example, load \sty{datetime2} first with regional support:
\begin{codebox}
\cmd{usepackage}\oarg{en-GB}\marg{datetime2}
\cmd{usepackage}\oarg{
 \personstyopt{base-only}, \comment{no datatool.sty}
 \personstyopt{shortcuts}
}\marg{person}
\end{codebox}
or load \sty{person} first with regional support:
\begin{codebox}
\cmd{usepackage}\oarg{
 \personstyopt{base-only}, \comment{no datatool.sty}
 \optval{locales}{en-GB}, \comment{(requires datatool-english)}
 \personstyopt{shortcuts}
}\marg{person}
\cmd{usepackage}\oarg{useregional}\marg{datetime2}
\end{codebox}
Alternatively:
\begin{codebox}
\cmd{documentclass}\oarg{en-GB}\marg{article}
\cmd{usepackage}\oarg{useregional}\marg{datetime2}
\cmd{usepackage}\oarg{
 \personstyopt{base-only}, \comment{no datatool.sty}
 \personstyopt{shortcuts}
}\marg{person}
\end{codebox}
Or:
\begin{codebox}
\cmd{documentclass}\marg{article}
\cmd{usepackage}\oarg{british}\marg{babel}
\cmd{usepackage}\oarg{useregional}\marg{datetime2}
\cmd{usepackage}\oarg{
 \personstyopt{base-only}, \comment{no datatool.sty}
 \personstyopt{shortcuts}
}\marg{person}
\end{codebox}

\Exampleref{ex:baptism2} makes this modification to
\exampleref{ex:baptism}, along with:
\begin{codebox}
Today we welcome \gls{peoplename}\gls{cs.space}
into God's family, may He guide
and protect \gls{them}.
\end{codebox}

\begin{resultbox}
\createexample*[label={ex:baptism2},
  title={Baptism Order of Service (Shortcuts and Localisation)},
  link={sec:orderofserviceex},
  description={Example document using the person package to define
and reference two people with shortcut commands and localisation}
]
{%
\comment{requires both datetime2-english and datatool-english}
\cmd{usepackage}\oarg{en-GB}\marg{datetime2}\nl
\cmd{usepackage}\oarg{\nlsp
  base-only, \comment{datatool-base.sty only, no datatool.sty}
  shortcuts\nl
}\marg{person}\nl
\gls{newperson*}\oarg{john}\marg{\nlsp
 \newpersonoptval{forenames}{John Joseph},\nlsp
 \newpersonoptval{name}{John},\nlsp
 \newpersonoptval{gender}{male}\nl
}\nl
\gls{newperson*}\oarg{jane}\marg{\nlsp
  \newpersonoptval{forenames}{Jane Mary},\nlsp
  \newpersonoptval{name}{Jane},\nlsp
  \newpersonoptval{gender}{female}\nl
}\nl
\cmd{title}{Baptism of}\nl
\cmd{author}{\gls{peopleforenames}}
}
{%
\cmd{maketitle}\nl
\cmd{thispagestyle}\marg{empty}
\codepar
\comment{Note that if only one person is defined, the singular form
will be used instead so this works regardless of one or more people.}%
Today we welcome \gls{peoplename}\ into God's family, may He guide
and protect \gls{them}.
}
\end{resultbox}

\section{Advanced Commands}
\label{sec:personadvanced}

You can alter or set an attribute for a given person using:
\cmddef{personsetattribute:nnn}
Note that this doesn't test for existence of either the label or the
attribute name, nor does it test the validity of the value. 
The change is governed by the \personopt{local}
setting. The following attributes are set by \gls{newperson}:
\begin{itemize}
\item \optfmt{name}: the person's familiar or first (corresponding
to the \newpersonopt{name} option);
\item \optfmt{surname}: the person's surname (corresponding
to the \newpersonopt{surname} option);
\item \optfmt{title}: the person's title or form of address
(corresponding to the \newpersonopt{title} option);
\item \optfmt{fullname}: the person's formal or full name
(corresponding to the \newpersonopt{fullname} option);
\item \optfmt{gender}: the internal gender label (which is obtained
from the \newpersonopt{gender} option and mapped to the applicable
constant).
\end{itemize}

You can get an attribute with:
\cmddef{persongetattribute:nn}
which expands to the value of the attribute, or
\cmddef{persongetattribute:Nnn}
which sets the token list variable to the value of the attribute.
Again, there's no test if the label or attribute exists.

You can undefine an attribute with:
\cmddef{personunsetattribute:nn}
The change is governed by the \personopt{local} setting.
This command is primarily provided for use in the
\gls{personremoveappto:n} code.

\begin{warning}
If you undefine the \optfmt{name} attribute, the existence
test will fail.
\end{warning}

\subsection{Conditionals}
\label{sec:personcond}

\cmddef{ifpersonexists}
If a person has been identified with the given label, this does
\meta{true} otherwise it does \meta{false}. The argument is trimmed
and expanded before testing.

\cmddef{PersonIfMale}
If the person identified by the label is male, this does \meta{true}, 
otherwise it does \meta{false}.

\cmddef{PersonIfAllMale}
If all the listed people are male, this does \meta{true}, 
otherwise it does \meta{false}. If the option argument is missing,
this will simply compare \gls{PersonTotalCount} with
\gls{PersonMaleCount}.

\cmddef{PersonIfFemale}
If the person identified by the label is female, this does \meta{true}, 
otherwise it does \meta{false}.

\cmddef{PersonIfAllFemale}
If all the listed people are female, this does \meta{true}, 
otherwise it does \meta{false}.  If the option argument is missing,
this will simply compare \gls{PersonTotalCount} with
\gls{PersonFemaleCount}.

\cmddef{PersonIfNonBinary}
If the person identified by the label is non-binary, this does \meta{true}, 
otherwise it does \meta{false}. Note that this does \meta{false} of
the gender is unknown.

\cmddef{PersonIfAllNonBinary}
If all the listed people are non-binary, this does \meta{true}, 
otherwise it does \meta{false}. If the option argument is missing,
this will simply compare \gls{PersonTotalCount} with
\gls{PersonNonBinaryCount}.

\cmddef{PersonIfUnknownGender}
If the person identified by the label has the gender set to unknown,
this does \meta{true}, otherwise it does \meta{false}.

\cmddef{PersonIfAllUnknownGender}
If all the listed people have the gender set to unknown, this does \meta{true}, 
otherwise it does \meta{false}. If the option argument is missing,
this will simply compare \gls{PersonTotalCount} with
\gls{PersonUnknownGenderCount}.

If you have \LaTeX3 syntax enabled, you can use the following
commands.
\cmddef{personifexist:n}
Conditional and predicate that tests if a person has been defined
with the given label.

The following commands test a label, which may be
supplied as a token list variable or as a token list, 
against the recognised internal gender labels.
\cmddef{persongendercase:Nnnnnn}
Compares the given token list variable (using
\csfmt{tl\dsb if\dsb eq:NNTF}) against the constants
\gls{cpersonmalelabeltl}, \gls{cpersonfemalelabeltl},
\gls{cpersonnonbinarylabeltl}, and \gls{cpersonunknownlabeltl}
and does the applicable case or \meta{invalid-case} if no match.

\cmddef{persongendercase:nnnnnn}
As above but compares a token list.

\cmddef{persongendercase:Nnnnn}
A shortcut that uses \gls{persongendercase:Nnnnnn}. The invalid case
triggers an error and does the same as the unknown case.

\cmddef{persongendercase:nnnnn}
As above but compares a token list.

In the event that you only need to know if the label is valid, you
can use:
\cmddef{persondoifvalidgender:nT}
This will do the true part if the label is valid, otherwise it will
trigger an error.

The following command simply compares \gls{PersonTotalCount} with 
\gls{PersonMaleCount}, \gls{PersonFemaleCount} and
\gls{PersonNonBinaryCount}.
\cmddef{personallgendercase:nnnn}
Tests if all defined people have the same gender. This will do
\meta{all-male-case} if all defined people have been 
identified as male, \meta{all-female-case} if all defined
people have been identified as female, 
\meta{all-non-binary-case} if all defined people have been
identified as non-binary, and \meta{other-case} otherwise (that
is, a mixture of genders or all defined people have no gender
specified).

\subsection{Iterating Through Defined People}
\label{sec:personloop}

The loop commands have changed in version 3.0 to map over a
sequence variable instead of using \gls{@for}. This means that you
can no longer break out of the loop using the methods provided by
\sty{xfor}. Instead you can break the loop with:
\cmddef{foreachpersonbreak}
This simply uses \csfmt{seq\_break:} or \csfmt{clist\_break:}
depending on the context.

\begin{information}
The following commands will need to be scoped if nested.
\end{information}

\cmddef{forallpeople}
Loops through the list of people and, at each iteration, defines
\meta{label-cs} to the current label and does \meta{body}. If the
optional argument is omitted, the list of all
defined people is assumed.
 
\cmddef{foreachperson}
Iterates through the list of people and, at each
iteration, assigns \meta{name-cs} to the person's name,
\meta{full-name-cs} to the person's full name, \meta{gender-cs} to
the language-sensitive gender text, and \meta{label-cs} to the
person's label, and then does \meta{body}. The
\code{\csfmt{in}\margm{label-list}} is optional. If omitted
the list of all defined people is assumed.

\subsection{Localisation}
\label{sec:personlang}

As described in \sectionref{sec:localisation}, the
\sty{datatool-base} package (which will automatically be loaded by
the \sty{person} package, if not already loaded) provides
localisation support via the \sty{tracklang} interface. The
\sty{person} package uses the same interface to load the file
\metafilefmt{person\dhyphen}{locale}{.ldf} for each tracked locale
if that file is installed on \TeX's path.

The supplementary \sty{datatool-english} package (which needs to be
installed separately), described in \sectionref{sec:addlang}, 
includes \inlinefiledef{person-english.ldf}, which provides English
localisation support for the \sty{person} package. This file may be
used as a template for other languages.

If the localisation support provides options (which \file{person-english.ldf}
currently doesn't), the sub-module should be \qt{person} when using
\gls{DTLsetLocaleOptions}.

\cmddef{PersonSetLocalisation}
Sets the localisation text for the given gender label for the given
type. The \meta{gender-label} must be one of the internal labels:
\optfmt{male}, \optfmt{female}, \optfmt{nonbinary} or
\optfmt{unknown}. The \meta{value} argument is the localised text.
For example, \file{person-english.ldf} defines the
subjective third person pronouns as follows:
\begin{codebox}
\gls{PersonSetLocalisation}\marg{male}\marg{pronoun}\marg{he}
\gls{PersonSetLocalisation}\marg{female}\marg{pronoun}\marg{she}
\gls{PersonSetLocalisation}\marg{nonbinary}\marg{pronoun}\marg{they}
\gls{PersonSetLocalisation}\marg{unknown}\marg{pronoun}\marg{they}
\gls{PersonSetLocalisation}\marg{male}\marg{pluralpronoun}\marg{they}
\gls{PersonSetLocalisation}\marg{female}\marg{pluralpronoun}\marg{they}
\gls{PersonSetLocalisation}\marg{nonbinary}\marg{pluralpronoun}\marg{they}
\gls{PersonSetLocalisation}\marg{unknown}\marg{pluralpronoun}\marg{they}
\end{codebox}
The \meta{type} argument is essentially a property name where the
plural alternative is as the singular but prefixed with
\qt{plural}.

\begin{important}
If there is no value set for a particular gender,
commands that use localisation text will fallback first on
\qt{unknown} and then on \qt{nonbinary}. This means that the
\sty{person} package only defines \qt{unknown} in certain cases to avoid redundancy.
However, localisation files need to take multilingual documents into
account and should therefore set the values for all genders, even if
they are duplicates, otherwise only the ones that are set will
change when the language changes.
\end{important}

Recognised values of \meta{type} are listed below.
\begin{itemize}
\item \optfmt{pronoun}:
The third person singular subjective pronoun.

\item \optfmt{pluralpronoun}:
The third person plural subjective pronoun.

\item \optfmt{pronoun2}:
The second person singular subjective pronoun.

\item \optfmt{pluralpronoun2}:
The second person plural subjective pronoun.

\item \optfmt{objpronoun}:
The third person singular objective pronoun.

\item \optfmt{pluralobjpronoun}:
The third person plural objective pronoun.

\item \optfmt{objpronoun2}:
The second person singular objective pronoun.

\item \optfmt{pluralobjpronoun2}:
The second person plural objective pronoun.

\item \optfmt{possadj}:
The third person singular possessive adjective.

\item \optfmt{pluralpossadj}:
The third person plural possessive adjective.

\item \optfmt{possadj2}:
The second person singular possessive adjective.

\item \optfmt{pluralpossadj2}:
The second person plural possessive adjective.

\item \optfmt{posspronoun}:
The third person singular possessive pronoun.

\item \optfmt{pluralposspronoun}:
The third person plural possessive pronoun.

\item \optfmt{posspronoun2}:
The second person singular possessive pronoun.

\item \optfmt{pluralposspronoun2}:
The second person plural possessive pronoun.

\item \optfmt{child}:
Noun indicating the person's relationship to their parents
(that is, son, daughter or child).

\item \optfmt{pluralchild}:
The plural form of the above
(that is, sons, daughters or children).

\item \optfmt{parent}:
Noun indicating the person's relationship to their children
(that is, father, mother or parent).

\item \optfmt{pluralparent}:
The plural form of the above
(that is, fathers, mothers or parents).

\item \optfmt{sibling}:
Noun indicating the person's relationship to their sibling
(that is, brother, sister or sibling).

\item \optfmt{pluralsibling}:
The plural form of the above
(that is, brothers, sisters or siblings).

\item \optfmt{gender}:
The person's gender. Note that this isn't a gender identifying label
for \gls{newperson} but is used by \gls{foreachperson},
\gls{getpersongender}, \gls{persongender} and \gls{Persongender}.

\end{itemize}

The localisation file should also use \gls{PersonSetMaleLabels},
\gls{PersonSetFemaleLabels} and \gls{PersonSetNonBinaryLabels} to
the locale gender labels for use in \gls{newperson}.

You can add support for other types, but make sure you document that
those types are only available for your localisation support. The
language text can be obtained with the following commands. In each
case, the \meta{person-label} argument is used to fetch the gender
label for the given person in order to obtain the correct text.

\cmddef{personlanguagetext:nn}
Expands to the localisation text for the given \meta{type}
for the gender label associated with the given person.
For example, \gls{personpronoun} is defined as:
\begin{compactcodebox}
\cmd{NewDocumentCommand} \gls{personpronoun} \marg{ O\marg{anon} }
\marg{
  \gls{personlanguagetext:nn} \marg{ \#1 } \marg{ pronoun }
}
\end{compactcodebox}

\cmddef{personLanguagetext:nn}
As above, but converts the text to sentence case.
For example, \gls{Personpronoun} is defined as:
\begin{compactcodebox}
\cmd{NewDocumentCommand} \gls{Personpronoun} \marg{ O\marg{anon} }
\marg{
  \gls{personLanguagetext:nn} \marg{ \#1 } \marg{ pronoun }
}
\end{compactcodebox}

\cmddef{personlanguagealltext:n}
The \meta{type} argument should be the singular type. If more than
one person has been defined, this uses the text for the type given
by \code{plural\meta{type}} according to the group gender
(\optfmt{unknown} for a mixture); if only one person is defined,
this uses the text for \meta{type} according to the gender of that
person; otherwise it triggers a warning and uses the plural.
For example, \gls{peoplepronoun} is defined as:
\begin{compactcodebox}
\cmd{NewDocumentCommand} \gls{peoplepronoun} \marg{ }
\marg{
 \gls{personlanguagealltext:n} \marg{ pronoun }
}
\end{compactcodebox}

\cmddef{personLanguagealltext:n}
As above, but converts the text to sentence case.
For example, \gls{Peoplepronoun} is defined as:
\begin{compactcodebox}
\cmd{NewDocumentCommand} \gls{Peoplepronoun} \marg{ }
\marg{
 \gls{personLanguagealltext:n} \marg{ pronoun }
}
\end{compactcodebox}


\subsection{Hooks}
\label{sec:personhooks}

There are hooks available when defining a new person.

\cmddef{lpersonlabeltl}
This token list variable will expand to the current label in the
following hooks.

\cmddef{personnewapptostart:n}
Appends \meta{code} to a hook used at the start of \gls{newperson}.

\cmddef{personnewapptoend:n}
Appends \meta{code} to a hook used at the end of \gls{newperson}
(after the label has been added to the internal sequence, and after
the internal integer variables used to keep track of totals are incremented).
Within \meta{code} you can set an attribute with
\gls{personsetattribute:nnn}.

\cmddef{personremoveappto:n}
Appends \meta{code} to the hook used by \gls{removeperson} and also
for each iteration in \gls{removepeople} and \gls{removeallpeople}.
You can use \gls{personunsetattribute:nn} in \meta{code} to undefine
a custom attribute. Note that \gls{removeallpeople} zeroes the
internal integer variables and clears the internal sequence at the end, whereas
\gls{removepeople} decrements the variables and pops the label off
the sequence at each iteration.

If you want to add any extra keys for use with \gls{newperson*}, the
keys are defined with \csfmt{keys\_define:nn} (\styfmt{l3keys}) and
module \code{datatool/person}. For example, to add a key to set the
person's date of birth (replace \code{mypkg} as applicable):
\begin{codebox}
\cmd{tl\_new:N} \cmd{l\_\_mypkg\_dob\_tl}
\gls{personnewapptostart:n}
\marg{
 \cmd{tl\_clear:N} \cmd{l\_\_mypkg\_dob\_tl}
}
\gls{personnewapptoend:n}
\marg{
 \expfunc{personsetattribute:nnn}{nnV}
  \gls{lpersonlabeltl} \marg{ dob } \cmd{l\_\_mypkg\_dob\_tl}
}
\gls{personremoveappto:n}
\marg{
  \gls{personunsetattribute:nn}
    \gls{lpersonlabeltl} \marg{ dob }
}
\cmd{keys\_define:nn} \marg{ datatool/person }
\marg{
  dob .tl\_set:N = \cmd{l\_\_mypkg\_dob\_tl}
}
\end{codebox}

\chapter{Acknowledgements}
\label{sec:acknowledgements}

Many thanks to Morten~H\o gholm for providing a much more
efficient way of storing the information in databases which
has significantly improved the time it takes to \LaTeX\ documents
containing large databases.

\part{Summaries and Index}
\label{summaries}

\backmatter 
\printterms
\printsummary
\printuserguideindex
\end{document}
