summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2008-04-29 17:18:51 +0000
committerKarl Berry <karl@freefriends.org>2008-04-29 17:18:51 +0000
commit1bb1fcb353daeee517c22ad1ecc8912942c493b4 (patch)
tree8d132b8dcb564cfc362679f487754d75a1466a7e
parent1cd62a262eb0789c37a72a517c82fe276b360e6f (diff)
restore csvtools, since we cannot eliminate all from ctan:/obsolete anyway
git-svn-id: svn://tug.org/texlive/trunk@7722 c570f23f-e606-0410-a88d-b1316a301751
-rw-r--r--Master/texmf-dist/doc/latex/csvtools/CHANGES29
-rw-r--r--Master/texmf-dist/doc/latex/csvtools/README39
-rw-r--r--Master/texmf-dist/doc/latex/csvtools/csvtools.pdfbin0 -> 225188 bytes
-rwxr-xr-xMaster/texmf-dist/doc/latex/csvtools/csvtools.pl1995
-rw-r--r--Master/texmf-dist/doc/latex/csvtools/manual.html1615
-rw-r--r--Master/texmf-dist/source/latex/csvtools/csvtools.dtx2536
-rw-r--r--Master/texmf-dist/source/latex/csvtools/csvtools.ins23
-rw-r--r--Master/texmf-dist/tex/latex/csvtools/csvpie.sty207
-rw-r--r--Master/texmf-dist/tex/latex/csvtools/csvsort.sty322
-rw-r--r--Master/texmf-dist/tex/latex/csvtools/csvtools.sty346
-rwxr-xr-xMaster/tlpkg/bin/ctan2tds3
-rw-r--r--Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc1
-rw-r--r--Master/tlpkg/tlpsrc/csvtools.tlpsrc2
13 files changed, 7116 insertions, 2 deletions
diff --git a/Master/texmf-dist/doc/latex/csvtools/CHANGES b/Master/texmf-dist/doc/latex/csvtools/CHANGES
new file mode 100644
index 00000000000..9e3d1a52846
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/csvtools/CHANGES
@@ -0,0 +1,29 @@
+Version 1.24:
+Added csvsort.sty (requires xfor package and \'Eamonn McManus'
+compare.tex)
+
+Version 1.23:
+\par can now be used in entries (but all entries for a given
+row must be on the same line, so you can't use a blank line
+to indicate a paragraph break.)
+
+Version 1.22:
+\applyCSVfile now resets each field to nothing before scanning each
+row so that if a column is missing for a given row, that entry will
+be blank. (Note that this does not apply to the starred version, as
+the header row is used to determine the maximum number of columns.)
+\csvSaveEntry has an additional optional argument to supply text if
+that entry is omitted.
+
+Version 1.21:
+ Fixed problem caused when first field starts with repeated
+character
+
+Version 1.2:
+ added csvpie.sty
+ data separator can now be user defined
+ entries enclosed within double quotes are now parsed correctly
+
+Version 1.1 has the new command \CSVtolongtable (analogous to \CSVtotabular)
+and a Perl script. See documentation for details.
+
diff --git a/Master/texmf-dist/doc/latex/csvtools/README b/Master/texmf-dist/doc/latex/csvtools/README
new file mode 100644
index 00000000000..d0e9175ea0c
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/csvtools/README
@@ -0,0 +1,39 @@
+LaTeX Package : csvtools v 1.24
+
+Last Modified : 3 July 2007
+
+Author : Nicola Talbot
+
+Files : csvtools.dtx - documented source file
+ csvtools.ins - installation script
+ csvtools.pl - Perl script
+
+The csvtools package allows you to repeatedly perform
+a set of LaTeX commands on data in each row
+of a comma separated variable (CSV) file.
+This can be used for mail merging, generating
+tables etc. Examples given in documentation.
+
+To extract the code, do:
+
+latex csvtools.ins
+
+This will create the files csvtools.sty, csvpie.sty and csvsort.sty.
+These files should be place somewhere on TeX's search path.
+
+To extract the documentation, do:
+
+latex csvtools.dtx
+latex csvtools.dtx
+
+(If you want the documented source code as well, remove the command
+\OnlyDescription from csvtools.dtx)
+
+Alternatively, if you use pdflatex instead of latex, the documentation will
+have hyperlinks.
+
+This material is subject to the LaTeX Project Public License.
+See http://www.ctan.org/tex-archive/help/Catalogue/licenses.lppl.html for
+details of that license.
+
+http://theoval.cmp.uea.ac.uk/~nlct
diff --git a/Master/texmf-dist/doc/latex/csvtools/csvtools.pdf b/Master/texmf-dist/doc/latex/csvtools/csvtools.pdf
new file mode 100644
index 00000000000..3e05495d31e
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/csvtools/csvtools.pdf
Binary files differ
diff --git a/Master/texmf-dist/doc/latex/csvtools/csvtools.pl b/Master/texmf-dist/doc/latex/csvtools/csvtools.pl
new file mode 100755
index 00000000000..131134124e7
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/csvtools/csvtools.pl
@@ -0,0 +1,1995 @@
+#!/usr/bin/perl -w
+
+# File : csvtools.pl
+# Author : Dr Nicola Talbot
+# Date : 26 June 2007
+# Description : Perl script to accompany csvtools.sty
+# : Allows you to substitute \CSVtotabular, \CSVtolongtable and \applyCSVfile commands with the appropriate LaTeX code
+# Version : 0.6b (1 September 2006).
+
+# usage : csvtools <in-file> <out-file>
+
+if ($#ARGV != 1)
+{
+ die "Syntax : $0 <in-file> <out-file>\n";
+}
+
+($FILENAME,$OUTPUT) = @ARGV;
+
+open FILENAME or die "Can't open '$FILENAME'\n";
+
+$ext = substr($FILENAME, -4);
+
+if (($ext eq ".tex") or ($ext eq ".dtx") or ($ext eq ".ltx"))
+{
+ $LOGFILE = substr($FILENAME,0,length($FILENAME)-4) . ".log";
+}
+else
+{
+ $LOGFILE = $FILENAME . ".log";
+}
+
+open LOGFILE or die "Can't open log file '$LOGFILE'. Make sure you run LaTeX before using $0\n";
+
+while (<LOGFILE>)
+{
+ if (/\\c@([a-zA-Z]+)=\\count/)
+ {
+ $counter{$1} = 0;
+ }
+}
+
+$counter{'csvrownumber'} = 0;
+
+close LOGFILE;
+
+open OUTPUT, ">$OUTPUT" or die;
+
+# global csvsort options
+
+$globalsort{'verbose'}=1;
+$globalsort{'sort'}='alphabetical ascending';
+$globalsort{'variable'}='\field{1}';
+$globalsort{'sfirstdataline'}=1;
+$globalsort{'firstdataline'}=2;
+
+$keyvaldefaults{'verbose'}='true';
+
+$csvpieouterlabel="\\field{1}";
+$csvpieinnerlabel="\\field{2}\\%";
+$separator=",";
+
+while (<FILENAME>)
+{
+ $restofline = $_;
+ local($comment) = "";
+
+ if ($restofline=~m/(\\*)%/)
+ {
+ $n = length($1);
+
+ if ($n%2 == 0)
+ {
+ $restofline = "$`$1";
+ $comment = "%$'";
+ $_ = $restofline;
+ }
+ }
+
+ if ($restofline=~/\\setcsvseparator\s*{([^}]*)}/)
+ {
+ $separator=$1 if defined($1);
+ }
+
+ if ($restofline=~/\\renewcommand\*?\s*{?\\csvpieinnerlabel}?/)
+ {
+ print OUTPUT $`;
+
+ $restofline=$';
+ $lineno=$.;
+
+ ($csvpieinnerlabel,$restofline,$done)=&getnextgroup($restofline);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $restofline .= $nextline;
+ ($csvpieinnerlabel,$restofline,$done)=&getnextgroup($restofline);
+ }
+ else
+ {
+ die "Unexpected EOF while parsing \\renewcommand on line $lineno\n";
+ }
+ }
+
+ $_ = $restofline;
+ }
+
+ if ($restofline=~/\\renewcommand\*?\s*{?\\csvpieouterlabel}?/)
+ {
+ print OUTPUT $`;
+
+ $restofline=$';
+ $lineno=$.;
+
+ ($csvpieouterlabel,$restofline,$done)=&getnextgroup($restofline);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $restofline .= $nextline;
+ ($csvpieouterlabel,$restofline,$done)=&getnextgroup($restofline);
+ }
+ else
+ {
+ die "Unexpected EOF while parsing \\renewcommand on line $lineno\n";
+ }
+ }
+
+ $_ = $restofline;
+ }
+
+ while ($restofline=~/\\stepcounter(.*)/)
+ {
+ $line = $_;
+
+ ($ctr,$restofline,$done) = &getnextgroup($1);
+
+ $startline=$.;
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($ctr,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning first argument to \\stepcounter on line $startline\n";
+ }
+ }
+
+ $counter{$ctr}++;
+
+ $_ = $line;
+ }
+
+ $restofline = $_;
+
+ while ($restofline=~/\\refstepcounter(.*)/)
+ {
+ $line = $_;
+
+ ($ctr,$restofline,$done) = &getnextgroup($1);
+
+ $startline=$.;
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($ctr,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning first argument to \\stepcounter on line $startline\n";
+ }
+ }
+
+ $counter{$ctr}++;
+
+ $_ = $line;
+ }
+
+ $restofline = $_;
+
+ while ($restofline=~/\\setcounter(.*)/)
+ {
+ $line = $_;
+
+ ($ctr,$restofline,$done) = &getnextgroup($1);
+
+ $startline=$.;
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($ctr,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning first argument to \\stepcounter on line $startline\n";
+ }
+ }
+
+ ($num,$restofline,$done) = &getnextgroup($restofline);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($num,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning second argument to \\stepcounter on line $startline\n";
+ }
+ }
+
+ $num=~s/\\value{(.+)}/$counter{$1}/;
+
+ $counter{$ctr} = $num;
+
+ $_ = $line;
+ }
+
+ $restofline = $_;
+
+ while ($restofline=~/\\addtocounter(.*)/)
+ {
+ $line = $_;
+
+ ($ctr,$restofline,$done) = &getnextgroup($1);
+
+ $startline=$.;
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($ctr,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning first argument to \\stepcounter on line $startline\n";
+ }
+ }
+
+ ($num,$restofline,$done) = &getnextgroup($restofline);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($num,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning second argument to \\stepcounter on line $startline\n";
+ }
+ }
+
+ $num=~s/\\value{(.+)}/$counter{$1}/;
+
+ $counter{$ctr} = $counter{$ctr} + $num;
+
+ $_ = $line;
+ }
+
+ $restofline = $_;
+
+ while ($restofline=~/^(.*)\\csvGetEntry(.*)$/)
+ {
+ $start = $1;
+ $restofline = $2;
+
+ ($ctr,$restofline,$done) = &getnextgroup($restofline);
+
+ $startline=$.;
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $restofline = $restofline . $nextline;
+
+ ($ctr,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning first argument to \\csvGetEntry on line $startline\n";
+ }
+ }
+
+ ($entry,$restofline,$done) = &getnextgroup($restofline);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $restofline = $restofline . $nextline;
+
+ ($entry,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning first argument to \\csvGetEntry on line $startline\n";
+ }
+ }
+ $_ = $start . "\\csname $entry\\roman{$ctr}\\endcsname" . $restofline;
+ #$_ = $start. $data{$entry}[$counter{$ctr}] . $restofline;
+ }
+
+ $restofline = $_;
+
+ while ($restofline=~/\\usepackage(.*)/)
+ {
+ $line = $_;
+
+ $startline=$.;
+
+ $restofline = $1;
+
+ $options = '';
+
+ if ($restofline=~/^\s*\[/)
+ {
+ ($options,$restofline,$done) = &getnextoptionalgroup($restofline);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($options,$restofline,$done) = &getnextoptionalgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning optional argument to \\usepackage on line $startline\n";
+ }
+ }
+ }
+
+
+ ($package,$restofline,$done) = &getnextgroup($restofline);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ $restofline = $restofline . $nextline;
+
+ ($package,$restofline,$done) = &getnextgroup($restofline);
+ }
+ else
+ {
+ die "EOF found whilst scanning argument to \\usepackage on line $startline\n";
+ }
+ }
+
+ if ($package eq 'csvsort' and $options)
+ {
+ %hash = &getKeyValues($options,%keyvaldefaults);
+
+ foreach $key (keys(%hash))
+ {
+ $globalsort{$key}=$hash{$key};
+ }
+ }
+
+ $_ = $line;
+ }
+
+ $restofline = $_;
+
+ if (/^(.*)\\CSVtotabular(.*)$/)
+ {
+ print OUTPUT "$1$comment";
+ $comment="";
+
+ $line = $2;
+ $lineno = $.;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for CVS filename on line $lineno\n";
+ }
+ }
+
+ $csvname=~s/\\csname (.*)\\roman{(.*)}\\endcsname/$data{$1}[$counter{$2}]/;
+
+ $line = $restofline;
+
+ ($alignment,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($alignment,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for CVS column alignment on line $lineno\n";
+ }
+ }
+
+ $line = $restofline;
+
+ ($FIRST,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($FIRST,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\CSVtotabular third argument on line $lineno\n";
+ }
+ }
+
+ $line = $restofline;
+
+ ($MIDDLE,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($MIDDLE,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\CSVtotabular fourth argument on line $lineno\n";
+ }
+ }
+
+ $line = $restofline;
+
+ ($LAST,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($LAST,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\CSVtotabular fifth argument on line $lineno\n";
+ }
+ }
+
+ &csvtotabular($csvname, $alignment, $FIRST, $MIDDLE, $LAST,
+ "tabular");
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\CSVtolongtable(.*)$/)
+ {
+ print OUTPUT "$1$comment";
+ $comment="";
+
+ $line = $2;
+ $lineno = $.;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $line . $nextline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for CVS filename on line $lineno\n";
+ }
+ }
+
+ $csvname=~s/\\csname (.*)\\roman{(.*)}\\endcsname/$data{$1}[$counter{$2}]/;
+
+ $line = $restofline;
+
+ ($alignment,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($alignment,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for CVS column alignment on line $.\n";
+ }
+ }
+
+ $line = $restofline;
+
+ ($FIRST,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($FIRST,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\CSVtolongtable third argument on line $.\n";
+ }
+ }
+
+ $line = $restofline;
+
+ ($MIDDLE,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($MIDDLE,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\CSVtolongtable fourth argument on line $.\n";
+ }
+ }
+
+ $line = $restofline;
+
+ ($LAST,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline = <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($LAST,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\CSVtolongtable fifth argument on line $.\n";
+ }
+ }
+
+ &csvtotabular($csvname, $alignment, $FIRST, $MIDDLE, $LAST,
+ "longtable");
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\applyCSVfile(\*)?(.*)$/)
+ {
+ print OUTPUT "$1$comment";
+ $comment="";
+
+ $starred = defined($2);
+
+ $restofline = $3;
+ $lineno = $.;
+
+ $restofline = &eatinitialspaces($restofline);
+ $restofline = &eatcomments($restofline);
+
+ $startrow = $starred ? 1 : 2;
+
+ if (/^\[([0-9]+)\](.*)/)
+ {
+ $startrow = $1;
+
+ $restofline = $2;
+ }
+
+ $line=$restofline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\applyCSVfile*[$startrow] first argument on line $lineno\n";
+ }
+ }
+
+ $csvname=~s/\\csname (.*)\\roman{(.*)}\\endcsname/$data{$1}[$counter{$2}]/;
+
+ $line=$restofline;
+
+ ($body,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($body,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\applyCSVfile*[$startrow] second argument on line $lineno\n";
+ }
+ }
+
+ if ($starred)
+ {
+ &applyCSVfilestar($csvname, $body, $startrow);
+ }
+ else
+ {
+ &applyCSVfile($csvname, $body, $startrow);
+ }
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\sortapplyCSVfile(\*)?(.*)$/)
+ {
+ print OUTPUT "$1$comment";
+ $comment="";
+
+ $starred = defined($2);
+
+ $restofline = $3;
+ $lineno = $.;
+
+ $restofline = &eatinitialspaces($restofline);
+ $restofline = &eatcomments($restofline);
+
+ $line=$restofline;
+
+ $options = '';
+
+ if ($restofline=~/^\s*\[/)
+ {
+ ($options,$restofline,$done) = &getnextoptionalgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($options,$restofline,$done) = &getnextoptionalgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortapplyCSVfile optional argument on line $lineno\n";
+ }
+ }
+ }
+
+ $line=$restofline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortapplyCSVfile argument on line $lineno\n";
+ }
+ }
+
+ $csvname=~s/\\csname (.*)\\roman{(.*)}\\endcsname/$data{$1}[$counter{$2}]/;
+
+ $line=$restofline;
+
+ ($body,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($body,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortapplyCSVfile argument on line $lineno\n";
+ }
+ }
+
+ if ($starred)
+ {
+ &sortapplyCSVfilestar($csvname, $body, $options);
+ }
+ else
+ {
+ &sortapplyCSVfile($csvname, $body, $options);
+ }
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\sortCSVto(tabular|longtable)(.*)$/)
+ {
+ print OUTPUT "$1$comment";
+ $comment="";
+
+ $envname = $2;
+ $restofline = $3;
+ $lineno = $.;
+
+ $restofline = &eatinitialspaces($restofline);
+ $restofline = &eatcomments($restofline);
+
+ $line=$restofline;
+
+ $options = '';
+
+ if ($restofline=~/^\s*\[/)
+ {
+ ($options,$restofline,$done) = &getnextoptionalgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($options,$restofline,$done) = &getnextoptionalgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortCSVto$envname first argument on line $lineno\n";
+ }
+ }
+ }
+
+ $line=$restofline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortCSVto$envname argument on line $lineno\n";
+ }
+ }
+
+ $csvname=~s/\\csname (.*)\\roman{(.*)}\\endcsname/$data{$1}[$counter{$2}]/;
+
+ $line=$restofline;
+
+ ($align,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($align,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortCSVto$envname argument on line $lineno\n";
+ }
+ }
+
+ $line=$restofline;
+
+ ($headrow,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($headrow,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortCSVto$envname argument on line $lineno\n";
+ }
+ }
+
+ $line=$restofline;
+
+ ($midrows,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($midrows,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortCSVto$envname argument on line $lineno\n";
+ }
+ }
+
+ $line=$restofline;
+
+ ($lastrow,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($lastrow,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\sortCSVto$envname argument on line $lineno\n";
+ }
+ }
+
+ &sortCSVtotabular($csvname,$align,$headrow,$midrows,$lastrow,
+ $envname,$options);
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\csvpiechart(\*)?(.*)$/)
+ {
+ print OUTPUT "$1$comment";
+ $comment="";
+
+ $lineno = $.;
+
+ $starred = defined($2);
+
+ $restofline = $3;
+
+ $restofline = &eatinitialspaces($restofline);
+ $restofline = &eatcomments($restofline);
+
+ $startrow= $starred ? 1 : 2;
+
+ $line=$restofline;
+
+ ($options,$restofline,$done) = &getnextoptionalgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($options,$restofline,$done) = &getnextoptionalgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\csvpiechart optional argument on line $lineno\n";
+ }
+ }
+
+ $line=$restofline;
+
+ ($label,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($label,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\csvpiechart second argument on line $lineno\n";
+ }
+ }
+
+ $line=$restofline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+
+ while (!$done)
+ {
+ if ($nextline= <FILENAME>)
+ {
+ $line = $restofline . $nextline;
+
+ ($csvname,$restofline,$done) = &getnextgroup($line);
+ }
+ else
+ {
+ die "EOF found whilst scanning for \\csvpiechart second argument on line $lineno\n";
+ }
+ }
+
+ print OUTPUT "\\csvpiesetkeys{$options}%\n";
+
+ if ($options=~m/firstrow\s*=\s*(\d+)/)
+ {
+ $startrow=$1;
+ }
+
+ if ($starred)
+ {
+ &csvpiechartstar($label, $csvname, $startrow);
+ }
+ else
+ {
+ &csvpiechart($label, $csvname, $startrow);
+ }
+
+ print OUTPUT "$restofline\n";
+ }
+ else
+ {
+ print OUTPUT "$_$comment";
+ }
+}
+
+sub doapplyCSV{
+ local($csvrow, $body, @idx, %HoH) = @_;
+ local($row, $entry);
+
+ $counter{'csvrownumber'} = 0;
+ print OUTPUT "\\setcounter{csvrownumber}{0}\\relax\n";
+
+ foreach ($row=1; $row <= $csvrow; $row++)
+ {
+ print ".";
+
+ local($THISROW) = $body;
+
+ $THISROW = &csvSaveEntry($THISROW,$row,%HoH);
+
+ foreach $entry ( keys %{$HoH[$row]})
+ {
+ $replacementval=$HoH[$row]{$entry};
+
+ $THISROW =~ s/\\insertbyname{$entry}/$replacementval/g;
+
+ $THISROW =~ s/\\insert$entry/$replacementval/g;
+
+ local($column) = $idx{$entry}+1;
+
+ $THISROW =~ s/\\field{(\d+)}/$1eq$column?$replacementval:$&/emg;
+
+ $THISROW = &ifnextrowlast($THISROW, ($row==$csvrow-1));
+ }
+
+ print OUTPUT "\\refstepcounter{csvrownumber}\\relax\n$THISROW";
+ $counter{'csvrownumber'}++;
+ }
+}
+
+sub doapplyCSVstar{
+ local($body, $csvrow, $numcols, @entry) = @_;
+ local($row,$column);
+
+ print OUTPUT "\\setcounter{csvrownumber}{0}\\relax\n";
+ $counter{'csvrownumber'} = 0;
+
+ for ($row=0; $row < $csvrow; $row++)
+ {
+ print ".";
+
+ $THISROW = $body;
+
+ for ($column=0; $column < $numcols; $column++)
+ {
+ $replacementval=$entry[$row][$column];
+
+ $THISROW =~ s/\\field{(\d+)}/$1eq$column+1?$replacementval:$&/emg;
+
+ $THISROW = &ifnextrowlast($THISROW, ($row==$csvrow-1));
+ }
+
+ print OUTPUT "\\refstepcounter{csvrownumber}$THISROW";
+ $counter{'csvrownumber'}++;
+ }
+
+}
+
+sub getCSVvalues{
+ local($CSVFILE, $startrow) = @_;
+ local(@idx, %HoH, @fields);
+
+ open FH, $CSVFILE or die "Can't open file '$CSVFILE'\n";
+
+ local ($csvrow)=0;
+
+ while (<FH>)
+ {
+ if ($. == 1)
+ {
+ # get header row
+
+ chop;
+
+ @fields = &getEntries($_);
+
+ local($numcols) = 0;
+
+ foreach $field (@fields)
+ {
+ $idx{$field} = $numcols;
+
+ $numcols++;
+ }
+ }
+ elsif ($. >= $startrow)
+ {
+ next unless /$separator/;
+
+ chop;
+
+ $csvrow++;
+ $rec = {};
+
+ $HoH[$csvrow] = $rec;
+
+ local(@entries) = &getEntries($_);
+
+ local ($i) = 0;
+
+ foreach $e (@entries)
+ {
+ $rec->{$fields[$i]} = $e;
+ $i++;
+ }
+ }
+ }
+
+ close FH;
+
+ return ($csvrow, @idx, %HoH);
+}
+
+sub getCSVvaluesstar
+{
+ local($CSVFILE, $startrow) = @_;
+ open FH, $CSVFILE or die "Can't open file '$CSVFILE'\n";
+
+ $csvrow=0;
+
+ while (<FH>)
+ {
+ if ($. >= $startrow)
+ {
+ chop;
+
+ @fields = &getEntries($_);
+
+ $numcols = 0;
+
+ foreach $field (@fields)
+ {
+ $entry[$csvrow][$numcols] = $field;
+
+ $numcols++;
+ }
+
+ $csvrow++;
+ }
+ }
+
+ close FH;
+
+ return ($csvrow, $numcols, @entry);
+}
+
+sub csvpiechart
+{
+ local($value, $CSVFILE, $startrow) = @_;
+
+ print "Converting \\csvpiechart[$options]{$label}{$csvname}\n";
+ print OUTPUT "% \\csvpiechart[$options]{$label}{$csvname} converted using csvtools.pl\n";
+ print OUTPUT "%>> START INSERT\n";
+
+ # read in data from CSV file
+ local($csvrow, @idx, %HoH) = &getCSVvalues($CSVFILE,$startrow);
+
+ # first compute parameters
+
+ print OUTPUT "\\edef\\csvstartang{\\thecsvstartangle}\\relax\n";
+ $body = "\\csvsetsegmentparams{\\thecsvrownumber}{$value}\\relax\n";
+
+ &doapplyCSV($csvrow, $body, @idx, %HoH);
+
+ print OUTPUT "\\setcounter{csvstartangle}{\\csvstartang}\\relax\n";
+
+ # compute offsets for cutaway segments
+
+ print OUTPUT "\\ifthenelse{\\equal{\\csvpiecutaways}{}}{}{\\csvcomputeoffsets}\\relax\n";
+
+ # now do the pie chart
+
+ print OUTPUT "\\begin{tikzpicture}\n";
+
+ $body = "\\renewcommand*{\\csvpieinnerlabel}{$csvpieinnerlabel}\n";
+ $body .= "\\renewcommand*{\\csvpieouterlabel}{$csvpieouterlabel}\n";
+ $body .= "\\csvpiesegment{$value}\n";
+
+ &doapplyCSV($csvrow, $body, %HoH);
+
+ print OUTPUT "\\end{tikzpicture}";
+ print OUTPUT "%<< END INSERT\n";
+ print "\n";
+}
+
+sub csvpiechartstar
+{
+ local($value, $CSVFILE, $startrow) = @_;
+
+ print "Converting \\csvpiechart*[$options]{$label}{$csvname}\n";
+ print OUTPUT "% \\csvpiechart*[$options]{$label}{$csvname} converted using csvtools.pl\n";
+ print OUTPUT "%>> START INSERT\n";
+
+ local($csvrow, $numcols, @entry) = &getCSVvaluesstar($CSVFILE, $startrow);
+
+ # first compute parameters
+
+ print OUTPUT "\\edef\\csvstartang{\\thecsvstartangle}\\relax\n";
+ $body = "\\csvsetsegmentparams{\\thecsvrownumber}{$value}\\relax\n";
+
+ &doapplyCSVstar($body, $csvrow, $numcols, @entry);
+
+ print OUTPUT "\\setcounter{csvstartangle}{\\csvstartang}\\relax\n";
+
+ # compute offsets for cutaway segments
+
+ print OUTPUT "\\ifthenelse{\\equal{\\csvpiecutaways}{}}{}{\\csvcomputeoffsets}\\relax\n";
+
+ $body = "\\renewcommand*{\\csvpieinnerlabel}{$csvpieinnerlabel}\\relax\n";
+ $body .= "\\renewcommand*{\\csvpieouterlabel}{$csvpieouterlabel}\\relax\n";
+ $body .= "\\csvpiesegment{$value}\\relax\n";
+
+ print OUTPUT "\\begin{tikzpicture}\n";
+
+ &doapplyCSVstar($body, $csvrow, $numcols, @entry);
+
+ print OUTPUT "\\end{tikzpicture}";
+ print OUTPUT "%<< END INSERT\n";
+ print "\n";
+}
+
+sub applyCSVfile
+{
+ my ($CSVFILE,$body,$startrow) = @_;
+
+ print "Converting \\applyCSVfile{$CSVFILE}";
+ print OUTPUT "\% \\applyCSVfile{$CSVFILE}... converted using csvtools.pl\n";
+ print OUTPUT "\%>> START INSERT\n";
+
+ # read in data from CSV file
+ local($csvrow, @idx, %HoH) = &getCSVvalues($CSVFILE,$startrow);
+
+ # apply data
+
+ &doapplyCSV($csvrow, $body, @idx, %HoH);
+
+ print "\n";
+
+ print OUTPUT "\%<< END INSERT\n";
+}
+
+sub sortapplyCSVfile
+{
+ my ($CSVFILE,$body,$options) = @_;
+
+ print "Converting \\sortapplyCSVfile{$CSVFILE}";
+ print OUTPUT "\% \\sortapplyCSVfile{$CSVFILE}... converted using csvtools.pl\n";
+ print OUTPUT "\%>> START INSERT\n";
+
+ # get options
+ %hash = &getKeyValues($options) if $options;
+
+ local($startrow) = defined($hash{'firstdataline'})
+ ? $hash{'firstdataline'}
+ : $globalsort{'firstdataline'};
+
+ local ($sortorder) = $hash{'sort'};
+
+ # read in data from CSV file
+ local($csvrow, @idx, %HoH) = &getCSVvalues($CSVFILE,$startrow);
+
+ # get sort variable
+
+ local($variable) = defined($hash{'variable'})
+ ? $hash{'variable'}
+ : $globalsort{'variable'};
+
+ local(@rowdata)=();
+
+ print OUTPUT "\\bgroup\n";
+
+ # set field labels
+
+ foreach $entry (keys %{$HoH[1]})
+ {
+ print OUTPUT "\\setcsvfieldlabel{";
+ print OUTPUT ($idx{$entry}+1).'}{';
+ print OUTPUT "$entry}%\n";
+ }
+
+ print OUTPUT "\\def\\csvsortlist{%\n";
+
+ # construct list
+
+ foreach ($row=1; $row <= $csvrow; $row++)
+ {
+ print ".";
+
+ local($sortkey) = $variable;
+
+ $sortkey = &csvSaveEntry($sortkey,$row,%HoH);
+
+ foreach $entry ( keys %{$HoH[$row]})
+ {
+ $replacementval=$HoH[$row]{$entry};
+
+ $sortkey =~ s/\\insertbyname{$entry}/$replacementval/g;
+
+ $sortkey =~ s/\\insert$entry/$replacementval/g;
+
+ local($column) = $idx{$entry}+1;
+
+ $rowdata[$idx{$entry}] = $replacementval;
+
+ $sortkey =~ s/\\field{(\d+)}/$1eq$column?$replacementval:$&/emg;
+ }
+
+ print OUTPUT "{$sortkey}{".join($separator,@rowdata)."}";
+
+ print OUTPUT ($row == $csvrow ? "%\n" : ",%\n");
+ }
+
+ print OUTPUT "}%\n";
+
+ print OUTPUT "\\sortapplyCSVdata";
+
+ if (defined($sortorder))
+ {
+ print OUTPUT "[$sortorder]";
+ }
+
+ print OUTPUT "{\\csvsortlist}{%\n";
+
+ print OUTPUT "$body}%\n";
+
+ print OUTPUT "\\egroup\n";
+ print OUTPUT "\%<< END INSERT\n";
+
+ print "\n";
+}
+
+sub sortapplyCSVfilestar
+{
+ my ($CSVFILE,$body,$options) = @_;
+
+ print "Converting \\sortapplyCSVfile*{$CSVFILE}";
+ print OUTPUT "\% \\sortapplyCSVfile*{$CSVFILE}... converted using csvtools.pl\n";
+ print OUTPUT "\%>> START INSERT\n";
+
+ # get options
+ %hash = &getKeyValues($options) if $options;
+
+ local($startrow) = defined($hash{'sfirstdataline'})
+ ? $hash{'sfirstdataline'}
+ : $globalsort{'sfirstdataline'};
+
+ local ($sortorder) = $hash{'sort'};
+
+ local($csvrow, $numcols, @entry) = &getCSVvaluesstar($CSVFILE, $startrow);
+
+ # get sort variable
+
+ local($variable) = defined($hash{'variable'})
+ ? $hash{'variable'}
+ : $globalsort{'variable'};
+
+ local(@rowdata)=();
+
+ print OUTPUT "\\bgroup\n";
+
+ print OUTPUT "\\def\\csvsortlist{%\n";
+
+ # construct list
+
+ for ($row=0; $row < $csvrow; $row++)
+ {
+ print ".";
+
+ local($sortkey) = $variable;
+
+ for ($column=0; $column < $numcols; $column++)
+ {
+ $replacementval=$entry[$row][$column];
+
+ $sortkey =~ s/\\field{(\d+)}/$1eq$column+1?$replacementval:$&/emg;
+ $rowdata[$column] = $replacementval;
+ }
+
+ print OUTPUT "{$sortkey}{".join($separator,@rowdata)."}";
+
+ print OUTPUT ($row == $csvrow-1 ? "%\n" : ",%\n");
+ }
+
+ print OUTPUT "}%\n";
+
+ print OUTPUT "\\sortapplyCSVdata*";
+
+ if (defined($sortorder))
+ {
+ print OUTPUT "[$sortorder]";
+ }
+
+ print OUTPUT "{\\csvsortlist}{%\n";
+
+ print OUTPUT "$body}%\n";
+
+ print OUTPUT "\\egroup\n";
+
+ print "\n";
+
+ print OUTPUT "\%<< END INSERT\n";
+}
+
+sub sortCSVtotabular
+{
+ my ($CSVFILE,$align,$headrow,$midrows,$lastrow,$envname,$options) = @_;
+
+ print "Converting \\sortCSVto${envname}{$CSVFILE}";
+ print OUTPUT "\% \\sortCSVto${envname}{$CSVFILE}... converted using csvtools.pl\n";
+ print OUTPUT "\%>> START INSERT\n";
+
+ # get options
+ %hash = &getKeyValues($options) if $options;
+
+ local($startrow) = defined($hash{'firstdataline'})
+ ? $hash{'firstdataline'}
+ : $globalsort{'firstdataline'};
+
+ local ($sortorder) = $hash{'sort'};
+
+ # read in data from CSV file
+ local($csvrow, @idx, %HoH) = &getCSVvalues($CSVFILE,$startrow);
+
+ # get sort variable
+
+ local($variable) = defined($hash{'variable'})
+ ? $hash{'variable'}
+ : $globalsort{'variable'};
+
+ local(@rowdata)=();
+
+ print OUTPUT "\\bgroup\n";
+
+ # set field labels
+
+ foreach $entry (keys %{$HoH[1]})
+ {
+ print OUTPUT "\\setcsvfieldlabel{";
+ print OUTPUT ($idx{$entry}+1).'}{';
+ print OUTPUT "$entry}%\n";
+ }
+
+ print OUTPUT "\\def\\csvsortlist{%\n";
+
+ # construct list
+
+ foreach ($row=1; $row <= $csvrow; $row++)
+ {
+ print ".";
+
+ local($sortkey) = $variable;
+
+ $sortkey = &csvSaveEntry($sortkey,$row,%HoH);
+
+ foreach $entry ( keys %{$HoH[$row]})
+ {
+ $replacementval=$HoH[$row]{$entry};
+
+ $sortkey =~ s/\\insertbyname{$entry}/$replacementval/g;
+
+ $sortkey =~ s/\\insert$entry/$replacementval/g;
+
+ local($column) = $idx{$entry}+1;
+
+ $rowdata[$idx{$entry}] = $replacementval;
+
+ $sortkey =~ s/\\field{(\d+)}/$1eq$column?$replacementval:$&/emg;
+ }
+
+ print OUTPUT "{$sortkey}{".join($separator,@rowdata)."}";
+
+ print OUTPUT ($row == $csvrow ? "%\n" : ",%\n");
+ }
+
+ print OUTPUT "}%\n";
+
+ if (defined($sortorder))
+ {
+ print OUTPUT "\\setkeys{csvsort.sty}{sort=$sortorder}";
+ }
+
+ print OUTPUT "\\sortCSVdatatotabular";
+
+ print OUTPUT "{$csvrow}{\\csvsortlist}{$align}%\n";
+ print OUTPUT "{$headrow}%\n";
+ print OUTPUT "{$midrows}%\n";
+ print OUTPUT "{$lastrow}%\n";
+ print OUTPUT "{$envname}%\n";
+
+ print OUTPUT "\\egroup\n";
+ print OUTPUT "\%<< END INSERT\n";
+
+ print "\n";
+}
+
+sub csvSaveEntry
+{
+ my ($STR,$row,%HoH) = @_;
+
+ $rowctr = "csvrownumber";
+
+ while (($pos = index($STR, "\\csvSaveEntry")) > -1)
+ {
+ $start = substr($STR,0,$pos);
+ $restofline = substr($STR,$pos+13);
+
+ $restofline = &eatcomments($restofline);
+ $restofline = &eatinitialspaces($restofline);
+
+ if (substr($restofline,0,1) eq "[")
+ {
+ if (($i = index($restofline,"]")) > -1)
+ {
+ $rowctr = substr($restofline, 1, $i-1);
+
+ $restofline = substr($restofline, $i+1);
+ }
+ else
+ {
+ die "unmatched [ in \\csvSaveEntry\n";
+ }
+
+ $row = $counter{$rowctr};
+ }
+
+ ($group,$restofline,$done) = &getnextgroup($restofline);
+
+ if (!$done)
+ {
+ die "argument to \\csvSaveEntry[$rowctr] not found in >>$restofline<<\n";
+ }
+
+ $val = $HoH[$row]{$group};
+
+ $STR = $start . "\\expandafter\\gdef\\csname $group\\roman{$rowctr}\\endcsname{$val}" . $restofline;
+
+ $data{$group}[$row] = $HoH[$row]{$group};
+ }
+
+ return $STR;
+}
+
+sub applyCSVfilestar
+{
+ my ($CSVFILE,$body,$startrow) = @_;
+
+ print "Converting \\applyCSVfile*{$CSVFILE}";
+
+ $counter{'csvrownumber'} = 0;
+ local($csvrow, $numcols, @entry) = &getCSVvaluesstar($CSVFILE, $startrow);
+
+ &doapplyCSVstar($body, $csvrow, $numcols, @entry);
+
+ print "\n";
+
+ print OUTPUT "\%<< END INSERT\n";
+}
+
+sub csvtotabular
+{
+ my ($CSVFILE,$ALIGN,$START,$MID,$END,$environment) = @_;
+
+ print "Converting \\CSVtotabular{$CSVFILE}";
+
+ print OUTPUT "\% \\CSVtotabular{$CSVFILE}... converted using $0\n";
+ print OUTPUT "\%>> START INSERT\n";
+
+ # read in data from CSV file
+ local($csvrow, @idx, %HoH) = &getCSVvalues($CSVFILE,2);
+
+ print OUTPUT "\\setcounter{csvrownumber}{0}%\n";
+ $counter{csvrownumber} = 0;
+ print OUTPUT "\\begin{$environment}{$ALIGN}\n";
+
+ print OUTPUT "$START";
+
+ foreach ($row=1; $row <= $csvrow; $row++ )
+ {
+ print ".";
+
+ if ($row == $csvrow)
+ {
+ $THISROW=$END;
+ }
+ else
+ {
+ $THISROW=$MID;
+ }
+
+ foreach $entry ( keys %{$HoH[$row]})
+ {
+ $replacementval=$HoH[$row]{$entry};
+
+ $THISROW =~ s/\\insertbyname{$entry}/$replacementval/g;
+
+ $THISROW =~ s/\\insert$entry/$replacementval/g;
+
+ $column = $idx{$entry};
+
+ $THISROW =~ s/\\field{$column}/$replacementval/g;
+
+ $THISROW = &ifnextrowlast($THISROW, ($row==$csvrow-1));
+ }
+
+ print OUTPUT "\\refstepcounter{csvrownumber}$THISROW";
+ $counter{csvrownumber}++;
+ }
+
+ print OUTPUT "\\end{$environment}";
+ print OUTPUT "\%<< END INSERT\n";
+
+ print "\n";
+}
+
+sub ifnextrowlast
+{
+ my ($STR, $nextislast) = @_;
+
+ if (($pos = index($STR, "\\ifnextrowlast")) > -1)
+ {
+ $strbegin = substr($STR,0,$pos);
+ $strend = substr($STR,$pos+14);
+
+ ($firstarg,$strend,$done) = &getnextgroup($strend);
+
+ if (!$done)
+ {
+ die "Can't find first argument to \\ifnextrowlast\n";
+ }
+
+ ($secondarg,$strend,$done) = &getnextgroup($strend);
+
+ if (!$done)
+ {
+ die "Can't find second argument to \\ifnextrowlast\n";
+ }
+
+ if ($nextislast)
+ {
+ $STR = $strbegin . $firstarg . $strend;
+ }
+ else
+ {
+ $STR = $strbegin . $secondarg . $strend;
+ }
+ }
+
+ return $STR;
+}
+
+sub eatcomments
+{
+ local ($_) = @_;
+
+ if (m/(\\{1}%[^%]*)*(\\*)%/)
+ {
+ $pre = $`;
+ $pre .= $1 if defined($1);
+ $pre .= $2;
+
+ local($n) = length($2);
+
+ if ($n%2 == 0)
+ {
+ $_ = $pre;
+ }
+ }
+
+ return $_;
+}
+
+sub eatinitialspaces
+{
+ local ($_) = @_;
+
+# while (substr($STR,0,1) eq " " or substr($STR,0,1) eq "\n"
+# or substr($STR,0,1) eq "\r" or substr($STR,0,1) eq "\t")
+# {
+# $STR = substr($STR,1);
+# }
+
+ s/^(\s)*//sg;
+
+ return $_;
+}
+
+sub getnextgroup
+{
+ my($curline) = @_;
+
+ $curline = &eatcomments($curline);
+
+ $curline = &eatinitialspaces($curline);
+
+ # check to see if current string is blank
+
+ if ($curline!~/[^\s]+/m)
+ {
+ return ("",$curline,0);
+ }
+
+ if (($group = substr($curline,0,1)) ne "{")
+ {
+ # next group hasn't been delimited with braces
+ # return first non-whitespace character
+
+ $curline = substr($curline,1);
+
+ # unless it's a backslash, in which case get command name
+
+ if ($group eq "\\")
+ {
+ if ($curline=~/([a-zA-Z]+)(^[a-zA-Z].*)/m)
+ {
+ $group = $1;
+
+ $curline = $2;
+ }
+ else
+ {
+ # command is made up of backslash followed by symbol
+
+ $curline=~/([\W_0-9\s\\])(.*)/m;
+
+ $group = $1;
+
+ $curline = $2;
+ }
+ }
+
+ return ($group,$curline,1);
+ }
+
+ my $pos=index($curline, "{");
+ my $startpos=$pos;
+ my $posopen=0;
+ my $posclose=0;
+
+ my $bracelevel = 1;
+
+ my $done=0;
+
+ while (!$done)
+ {
+ $pos++;
+
+ $posopen = index($curline, "{", $pos);
+
+ # check to make sure it's not a \{
+
+ while ((substr($curline, $posopen-1,1) eq "\\") and ($posopen > 0))
+ {
+ # count how many backlashes come before it.
+
+ $i = $posopen-1;
+
+ $numbs = 1;
+
+ while ((substr($curline, $i-1,1) eq "\\") and ($i > 0))
+ {
+ $numbs++;
+ $i--;
+ }
+
+ # is $numbs is odd, we have a \{, otherwise we have \\{
+
+ if ($numbs%2 == 0)
+ {
+ last;
+ }
+ else
+ {
+ $posopen = index($curline, "{", $posopen+1);
+ }
+ }
+
+ $posclose= index($curline, "}", $pos);
+
+ # check to make sure it's not a \}
+
+ while ((substr($curline, $posclose-1,1) eq "\\") and ($posclose > 0))
+ {
+ # count how many backlashes come before it.
+
+ $i = $posclose-1;
+
+ $numbs = 1;
+
+ while ((substr($curline, $i-1,1) eq "\\") and ($i > 0))
+ {
+ $numbs++;
+ $i--;
+ }
+
+ # is $numbs is odd, we have a \}, otherwise we have \\}
+
+ if ($numbs%2 == 0)
+ {
+ last;
+ }
+ else
+ {
+ $posclose = index($curline, "}", $posclose+1);
+ }
+ }
+
+ if (($posopen==-1) and ($posclose==-1))
+ {
+ $done=1;
+ }
+ elsif ($posopen==-1)
+ {
+ $pos=$posclose;
+
+ $bracelevel--;
+
+ if ($bracelevel==0)
+ {
+ $group = substr($curline, $startpos+1, $pos-$startpos-1);
+
+ $curline = substr($curline, $pos+1);
+
+ return ($group,$curline,1);
+ }
+ }
+ elsif ($posclose==-1)
+ {
+ $pos=$posopen;
+
+ $bracelevel++;
+ }
+ elsif ($posopen<$posclose)
+ {
+ $pos=$posopen;
+
+ $bracelevel++;
+ }
+ elsif ($posclose<$posopen)
+ {
+ $pos=$posclose;
+
+ $bracelevel--;
+
+ if ($bracelevel==0)
+ {
+ $group = substr($curline, $startpos+1, $pos-$startpos-1);
+
+ $curline = substr($curline, $pos+1);
+
+ return ($group,$curline,1);
+ }
+ }
+ }
+
+ # closing brace must be on another line
+
+ return ("", $curline, 0);
+}
+
+sub getnextoptionalgroup
+{
+ my($curline) = @_;
+
+ $curline = &eatcomments($curline);
+
+ $curline = &eatinitialspaces($curline);
+
+ # check to see if current string is blank
+
+ if ($curline!~/[^\s]+/m)
+ {
+ return ("","",0);
+ }
+
+ if (($group = substr($curline,0,1)) ne "[")
+ {
+ # no optional argument present
+ return ("", $curline, 1);
+ }
+
+ $posopen = index($curline, "[");
+
+ # search for first occurance of ]
+
+ $posclose = index($curline, "]");
+
+ if ($posclose < 0)
+ {
+ # closing bracket not on this line
+ return ("", $curline, 0);
+ }
+
+ # is there a { in the substring?
+
+ $group = substr($curline, $posopen, $posclose+1);
+ $contents = $group;
+ $restofline = substr($curline, $posclose+$posopen+1);
+
+ while (($idx=index($group, "{")) > 0)
+ {
+ $post = substr($group, $idx);
+
+ $subgroup="";
+ ($subgroup,$remainder,$done) = &getnextgroup($post);
+
+ if ($done)
+ {
+ $group = $remainder;
+ }
+ else
+ {
+ # ] is in a group, so look for next one
+ $posclose = index($restofline, "]");
+
+ if ($posclose < 0)
+ {
+ # closing bracket not on this line
+ return ("", $curline, 0);
+ }
+ else
+ {
+ $contents .= substr($restofline,0,$posclose);
+ $group = $contents;
+ }
+ }
+ }
+
+ $contents=~s/^\[(.*)\]$/$1/;
+
+ return ($contents, $restofline, 1);
+}
+
+# get all entries in a row
+# modified version of code given in Perl FAQ
+
+sub getEntries{
+ local($row)=@_;
+
+ @entries = ();
+ push(@entries, $+) while $row =~ m{
+ "([^\"\\]*(?:\\.[^\"\\]*)*)"$separator? # groups the phrase inside the quotes
+ | ([^$separator]+)$separator?
+ | $separator
+ }gx;
+ push(@entries, undef) if substr($row,-1,1) eq $separator;
+
+ @entries;
+}
+
+# extract key=value pairs from list
+
+sub getKeyValues{
+ local($list,%defaults)=@_;
+ local(%hash)=();
+
+ # remove leading commas and spaces
+
+ $list=~s/^[\s,]*//;
+
+ while ($list=~/^\s*([^,=]+)\s*/)
+ {
+ $key=$1;
+
+ $value = '';
+
+ if ($list=~s/^\s*$key\s*=\s*{/{/)
+ {
+ ($value,$list,$done) = &getnextgroup($list);
+ }
+ elsif ($list=~s/^\s*$key\s*=\s*([^,]*)\s*//)
+ {
+ $value = $1;
+ }
+ elsif ($list=~s/^\s*$key\s*(,|$)//)
+ {
+ if (defined($defaults{$key}))
+ {
+ $value = $defaults{$key};
+ }
+ else
+ {
+ print "don't know default value for $key key\n";
+ }
+ }
+
+ $hash{$key} = $value;
+
+ # remove trailing commas
+
+ $list=~s/^[\s,]*//;
+ }
+
+ %hash;
+}
+
+1;
diff --git a/Master/texmf-dist/doc/latex/csvtools/manual.html b/Master/texmf-dist/doc/latex/csvtools/manual.html
new file mode 100644
index 00000000000..ad8a6fe9396
--- /dev/null
+++ b/Master/texmf-dist/doc/latex/csvtools/manual.html
@@ -0,0 +1,1615 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+
+<!--Converted with LaTeX2HTML 2002 (1.67)
+original version by: Nikos Drakos, CBLU, University of Leeds
+* revised and updated by: Marcus Hennecke, Ross Moore, Herb Swan
+* with significant contributions from:
+ Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
+<HTML>
+<HEAD>
+<TITLE>csvtools v1.24 : A LaTeX2e Package Providing Access to Data Saved in a CSV File</TITLE>
+<META NAME="description" CONTENT="csvtools v1.24 : A LaTeX2e Package Providing Access to Data Saved in a CSV File">
+<META NAME="keywords" CONTENT="manual">
+<META NAME="resource-type" CONTENT="document">
+<META NAME="distribution" CONTENT="global">
+
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+<META NAME="Generator" CONTENT="LaTeX2HTML v2002">
+<META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css">
+
+
+</HEAD>
+
+<BODY >
+
+
+ <H1 ALIGN="CENTER">csvtools v1.24 : A LaTeX2e Package Providing Access to Data Saved in a CSV File</H1>
+<P ALIGN="CENTER"><STRONG>Nicola Talbot</STRONG></P>
+<P ALIGN="CENTER"><STRONG>26th June 2007</STRONG></P>
+ <BR>
+
+<H2><A NAME="SECTION00010000000000000000">
+Contents</A>
+</H2>
+<!--Table of Contents-->
+
+<UL>
+<LI><A NAME="tex2html49"
+ HREF="manual.html#SECTION00030000000000000000">Introduction</A>
+<LI><A NAME="tex2html50"
+ HREF="manual.html#SECTION00040000000000000000">Mail Merging and Similar Applications</A>
+<LI><A NAME="tex2html51"
+ HREF="manual.html#SECTION00050000000000000000">Converting data in a CSV file into a tabular environment</A>
+<LI><A NAME="tex2html52"
+ HREF="manual.html#SECTION00060000000000000000">Converting CSV file into longtable environment</A>
+<LI><A NAME="tex2html53"
+ HREF="manual.html#SECTION00070000000000000000">Associated Counters</A>
+<LI><A NAME="tex2html54"
+ HREF="manual.html#SECTION00080000000000000000">Cross-Referencing</A>
+<LI><A NAME="tex2html55"
+ HREF="manual.html#SECTION00090000000000000000">Saving Entries</A>
+<LI><A NAME="tex2html56"
+ HREF="manual.html#SECTION000100000000000000000">Pie Charts (csvpie.sty)</A>
+<LI><A NAME="tex2html57"
+ HREF="manual.html#SECTION000110000000000000000">Sorting Data (csvsort.sty)</A>
+<LI><A NAME="tex2html58"
+ HREF="manual.html#SECTION000120000000000000000">The csvtools.pl Perl Script</A>
+<UL>
+<LI><A NAME="tex2html59"
+ HREF="manual.html#SECTION000122000000000000000">Notes</A>
+</UL>
+<BR>
+<LI><A NAME="tex2html60"
+ HREF="manual.html#SECTION000130000000000000000">Bugs/Drawbacks/``Features''</A>
+<LI><A NAME="tex2html61"
+ HREF="manual.html#SECTION000140000000000000000">Contact Details</A>
+</UL>
+<!--End of Table of Contents-->
+<P>
+
+<H1><A NAME="SECTION00020000000000000000">
+List of Examples</A>
+</H1>
+
+<P>
+
+
+<OL>
+<LI><A HREF="manual.html#ex:mail">Mail Merging</A>
+</LI>
+<LI><A HREF="manual.html#ex:ps">Multiple Figures</A>
+</LI>
+<LI><A HREF="manual.html#ex:field">Mail Merging using <TT>&#92;field</TT></A>
+</LI>
+<LI><A HREF="manual.html#ex:tab1">Aligning Data from a CSV file</A>
+</LI>
+<LI><A HREF="manual.html#ex:tab2">Adding Lines</A>
+</LI>
+<LI><A HREF="manual.html#ex:tab3">Added Complexity</A>
+</LI>
+<LI><A HREF="manual.html#ex:long">Using a longtable environment</A>
+</LI>
+<LI><A HREF="manual.html#ex:stripy">Stripy Table</A>
+</LI>
+<LI><A HREF="manual.html#ex:mailref">More Mail Merging</A>
+</LI>
+<LI><A HREF="manual.html#ex:ref1">Labelling within <TT>&#92;applyCSVfile</TT></A>
+</LI>
+<LI><A HREF="manual.html#ex:ref2">Labelling within <TT>&#92;applyCSVfile</TT></A>
+</LI>
+<LI><A HREF="manual.html#ex:timetogrowth">Labelling within <TT>&#92;CSVtotabular</TT></A>
+</LI>
+<LI><A HREF="manual.html#ex:tablabel">Labelling within <TT>&#92;CSVtotabular</TT></A>
+</LI>
+<LI><A HREF="manual.html#ex:index">Saving Entries</A>
+</LI>
+<LI><A HREF="manual.html#ex:piechart">A Pie Chart</A>
+</LI>
+<LI><A HREF="manual.html#ex:perl">csvtools.pl -- Aligning Data</A>
+</LI>
+</OL>
+
+<P>
+
+<H1><A NAME="SECTION00030000000000000000">
+Introduction</A>
+</H1>
+ The <TT>csvtools</TT> package allows you to repeatedly perform
+ a set of LaTeX commands on data in each row
+ of a comma separated variable (CSV) file.
+ This can be used for mail merging, generating
+ tables etc.
+
+<P>
+As from version 1.2, you can specify a different separator.
+To change the separator, use the command:
+<BR>
+<BR><TT>&#92;setcsvseparator</TT>{<I>separator</I>}
+<BR>
+<BR>
+For example, if your data is separated by colons instead of
+commas, do:
+<PRE>
+\setcsvseparator{:}
+</PRE>
+If your separator occurs within an entry, the entry must be
+enclosed in double quotes, for example:
+<PRE>
+Name,Address,Telephone
+A.N. Other,"1 The Street,The Town",0123456789
+</PRE>
+Be careful of T<SMALL>E</SMALL>X special characters occuring within a CSV
+file, for example:
+<PRE>
+Name,Address,Telephone
+Jack \&amp; Jill,"2 The Street,The Town",0123456789
+</PRE>
+
+<P>
+
+<H1><A NAME="SECTION00040000000000000000">
+Mail Merging and Similar Applications</A>
+</H1>
+
+<P>
+
+ <TT>&#92;applyCSVfile</TT>[<I>n</I>]{<I>filename</I>}{<I>text</I>}
+<BR> <TT>&#92;applyCSVfile*</TT>[<I>n</I>]{<I>filename</I>}{<I>text</I>}
+<BR>
+<BR>
+Letters can be generated using data given in
+ each line from <I>filename</I>.
+ If the CSV file contains a header row, the
+ unstarred version of <TT>&#92;applyCSVfile</TT> should
+ be used, otherwise the starred version <TT>&#92;applyCSVfile*</TT>
+ should be used. The optional argument <I>n</I>
+ specifies on which line the actual data (not header line)
+ starts. The unstarred version defaults to line 2
+ (the header row is always assumed to be on line 1)
+ and the starred version defaults to 1.
+
+<P>
+With the unstarred version, the entries in the header row
+ are used to generate commands of the form
+ <TT>&#92;insert</TT><I>identifier</I><A NAME="tex2html1"
+ HREF="#foot869"><SUP>1</SUP></A> to access corresponding elements
+ in the row currently being processed. For example,
+ suppose the first line of the CSV file looks like:
+<PRE>
+Name,Address,Time,Date
+</PRE>
+ then the commands <TT>&#92;insertName</TT>, <TT>&#92;insertAddress</TT>,
+ <TT>&#92;insertTime</TT> and <TT>&#92;insertDate</TT> are
+ created, allowing you to use the entries in the first,
+ second, third and fourth columns of the current row.
+ If the header text contains non-alphabetical characters,
+ e.g. <TT>Full Name</TT>, then you will need to use
+ <TT>&#92;insertbyname{</TT><I>text</I><TT>}</TT>,
+ e.g. <code>\insertbyname{Full Name}</code>.
+
+<P>
+Alternatively, you can use the
+<TT>&#92;field</TT>{<I>col</I>} command, where
+<I>col</I> is the column number of the entry, so <code>\field{1}</code>
+indicates the first entry in the current row and <code>\field{2}</code>
+indicates the second entry in the current row.
+
+<P>
+<A NAME="ex:mail"></A>
+<H2><A NAME="SECTION00041000000000000000">
+Example 1 (Mail Merging)</A>
+</H2>
+ Suppose there is a file called <TT>details.csv</TT> that has the
+ following contents:
+<PRE>
+Name,Address,Time,Date
+Miss A. Person,1 The Road\\The Town\\AB1 2XY,15.00,4th May 2004
+Mr A. N. Other,2 The Road\\The Town\\AB1 2XY,15.30,11th May 2004
+</PRE>
+then the following code can be used to generate a letter for each
+person in the CSV file<A NAME="tex2html2"
+ HREF="#foot150"><SUP>2</SUP></A>:
+<PRE>
+\applyCSVfile{details.csv}{%
+\begin{letter}{\insertName\\\insertAddress}
+\opening{Dear \insertName}
+
+You are invited to an interview at \insertTime\ on the \insertDate.
+
+\closing{Yours Sincerely}
+\end{letter}}
+</PRE>
+ Note that you could also use <code>\insertbyname{Name}</code> etc instead
+ of <TT>&#92;insertName</TT> etc. Also note that you need to specify the
+ file extension when specifying the filename.
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+<A NAME="ex:ps"></A>
+<H2><A NAME="SECTION00042000000000000000">
+Example 2 (Multiple Figures)</A>
+</H2>
+ Suppose <TT>sample3.csv</TT> looks like:
+<PRE>
+File,Caption
+circle.ps,A Circle
+rectangle.ps,A Rectangle
+triangle.ps,A Triangle
+</PRE>
+ Assuming that the files <TT>circle.ps</TT>, <TT>rectangle.ps</TT>
+ and <TT>triangle.ps</TT> exist, then the following code will
+ generate a figure for each graphics file<A NAME="tex2html3"
+ HREF="#foot870"><SUP>3</SUP></A>:
+<PRE>
+\applyCSVfile{sample3.csv}{
+\begin{figure}
+\centerline{\includegraphics{\insertFile}}
+\caption{\insertCaption}
+\end{figure}}
+</PRE>
+ Note that in this example, you can't use <code>\insertbyname{File}</code>.
+ (See Note&nbsp;<A HREF="manual.html#itm:psbyname">3</A> in Section&nbsp;<A HREF="manual.html#sec:drawbacks">11</A>.)
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+<A NAME="ex:field"></A>
+<H2><A NAME="SECTION00043000000000000000">
+Example 3 (Mail Merging using <TT>&#92;field</TT>)</A>
+</H2>
+ Suppose there is a file called <TT>details.csv</TT> that has the
+ following contents:
+<PRE>
+Miss A. Person,1 The Road\\The Town\\AB1 2XY,15.00,4th May 2004
+Mr A. N. Other,2 The Road\\The Town\\AB1 2XY,15.30,11th May 2004
+</PRE>
+In this case the data has no header file, so the starred version
+of <TT>&#92;applyCSVfile</TT> must be used. Since there is no header
+file, you must use <TT>&#92;field</TT> to access the entries:
+<PRE>
+\applyCSVfile*{details.csv}{%
+\begin{letter}{\field{1}\\\field{2}}
+\opening{Dear \field{1}}
+
+You are invited to an interview at \field{3}\ on the \field{4}.
+
+\closing{Yours Sincerely}
+\end{letter}}
+</PRE>
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+
+<H1><A NAME="SECTION00050000000000000000">
+Converting data in a CSV file into a tabular environment</A>
+</H1>
+
+ <TT>&#92;CSVtotabular</TT>{<I>filename</I>}{<I>col-align</I>}{<I>first</I>}{<I>middle</I>}{<I>last</I>}
+<BR>
+<BR> <I>filename</I> is the name of the CSV file which must have a header row on line&nbsp;1,
+ <I>col-align</I> is the column alignment argument that gets passed
+ to the <TT>tabular</TT> environment, <I>first</I>
+ is the code for the first line, <I>middle</I> is the code
+ for the middle lines and <I>last</I> is the code for the last line.
+ This is best demonstrated with an example.
+
+<P>
+<A NAME="ex:tab1"></A>
+<H2><A NAME="SECTION00051000000000000000">
+Example 4 (Aligning Data from a CSV file)</A>
+</H2>
+ Suppose the file <TT>sample.csv</TT> looks like:
+<PRE>
+Name,Assignment 1,Assignment 2,Total
+A. Smith,80,70,150
+B. Jones,60,80,140
+J. Doe,85,75,160
+,75,75,150
+</PRE>
+ then the following code can be used to align the data:
+<PRE>
+\CSVtotabular{sample.csv}{lccc}{%
+\bfseries Name &amp;
+\bfseries Assignment 1&amp;
+\bfseries Assignment 2&amp;
+\bfseries Total\\}{%
+\insertName &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal\\}{%
+ &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal}
+</PRE>
+ The result of this code is shown in
+ Table&nbsp;<A HREF="manual.html#tab:ex1">1</A><A NAME="tex2html4"
+ HREF="#foot872"><SUP>4</SUP></A>.
+<BR><P></P>
+<DIV ALIGN="CENTER">
+
+<A NAME="tab:ex1"></A>
+<BR>
+<BR>
+<DIV ALIGN="CENTER">
+<A NAME="873"></A>
+<TABLE CELLPADDING=3>
+<CAPTION><STRONG>Table 1:</STRONG>
+Example&nbsp;<A HREF="manual.html#ex:tab1">4</A></CAPTION>
+<TR><TH ALIGN="LEFT"><B>Name </B></TH>
+<TH ALIGN="CENTER"><B>Assignment 1 </B></TH>
+<TH ALIGN="CENTER"><B>Assignment 2 </B></TH>
+<TH ALIGN="CENTER"><B>Total</B></TH>
+</TR>
+<TR><TD ALIGN="LEFT">A. Smith</TD>
+<TD ALIGN="CENTER">80</TD>
+<TD ALIGN="CENTER">70</TD>
+<TD ALIGN="CENTER">150</TD>
+</TR>
+<TR><TD ALIGN="LEFT">B. Jones</TD>
+<TD ALIGN="CENTER">60</TD>
+<TD ALIGN="CENTER">80</TD>
+<TD ALIGN="CENTER">140</TD>
+</TR>
+<TR><TD ALIGN="LEFT">J. Doe</TD>
+<TD ALIGN="CENTER">85</TD>
+<TD ALIGN="CENTER">75</TD>
+<TD ALIGN="CENTER">160</TD>
+</TR>
+<TR><TD ALIGN="LEFT">&nbsp;</TD>
+<TD ALIGN="CENTER">75</TD>
+<TD ALIGN="CENTER">75</TD>
+<TD ALIGN="CENTER">150</TD>
+</TR>
+</TABLE></DIV>
+
+</DIV>
+<BR>
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+<BR>
+<BR>
+
+ <TT>&#92;ifnextrowlast</TT>{<I>last-code</I>}{<I>not-last-code</I>}
+<BR>
+<BR>
+The command <TT>&#92;ifnextrowlast</TT> can be used to vary what happens
+ on the last but one row. The following example illustrates
+ this by placing <TT>&#92;hline&#92;hline</TT> after the penultimate row.
+
+<P>
+<A NAME="ex:tab2"></A>
+<H2><A NAME="SECTION00052000000000000000">
+Example 5 (Adding Lines)</A>
+</H2>
+<PRE>
+\CSVtotabular{sample.csv}{|l|ccc|}{%
+\hline\bfseries Name &amp;
+\bfseries Assignment 1&amp;
+\bfseries Assignment 2&amp;
+\bfseries Total\\\hline\hline}{%
+\insertName &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal
+\ifnextrowlast{\\\hline\hline}{\\}}{%
+ &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal\\\hline}
+</PRE>
+See the PDF version (<TT><A NAME="tex2html7"
+ HREF="csvtools.pdf">csvtools.pdf</A></TT>) of this
+documentation for an illustration of the results.
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+<A NAME="ex:tab3"></A>
+<H2><A NAME="SECTION00053000000000000000">
+Example 6 (Added Complexity)</A>
+</H2>
+ In this example, <TT>&#92;multicolumn</TT> is used to override
+ the column specifier for the first column in the
+ last row.
+<PRE>
+\CSVtotabular{sample2.csv}{|l|ccc|}{%
+\hline\bfseries Name &amp;
+\bfseries Assignment 1 &amp;
+\bfseries Assignment 2 &amp;
+\bfseries Total\\\hline\hline
+}{%
+\insertName &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal
+\ifnextrowlast{\\\hline\multicolumn{1}{l|}{}}{\\}
+}{%
+ &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal\\\cline{2-4}
+}
+</PRE>
+ Notice that instead of placing <code>\multicolumn{1}{l|}{}</code>
+ at the start of the final argument, it is instead
+ placed in the first argument to <TT>&#92;ifnextrowlast</TT><A NAME="tex2html8"
+ HREF="#foot877"><SUP>5</SUP></A>.
+See the PDF version (<TT><A NAME="tex2html10"
+ HREF="csvtools.pdf">csvtools.pdf</A></TT>) of this
+manual for an illustration of the results.
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+
+<H1><A NAME="SECTION00060000000000000000">
+Converting CSV file into longtable environment</A>
+</H1>
+
+The command <TT>&#92;CSVtolongtable</TT> works in the same way as <TT>&#92;CSVtotabular</TT> but
+ creates a <TT>longtable</TT> environment instead of a <TT>tabular</TT> environment.
+
+<P>
+<A NAME="ex:long"></A>
+<H2><A NAME="SECTION00061000000000000000">
+Example 7 (Using a longtable environment)</A>
+</H2>
+Suppose the CSV file in the previous example, contains, say, 100 entries.
+This will no longer fit onto one page, so it would be better to use
+<TT>CSVtolongtable</TT> instead. For example:
+<PRE>
+\CSVtolongtable{sample.csv}{|l|ccc|}{%
+\caption{Student Marks}\label{tab:students}\\
+\hline
+\bfseries Name &amp;
+\bfseries Assignment 1 &amp;
+\bfseries Assignment 2 &amp;
+\bfseries Total\\\hline
+\endfirsthead
+\caption[]{Student Marks}\\
+\hline
+\bfseries Name &amp;
+\bfseries Assignment 1 &amp;
+\bfseries Assignment 2 &amp;
+\bfseries Total\\\hline
+\endhead
+\hline
+\multicolumn{3}{r}{\em Continued on next page}
+\endfoot
+\hline
+\endlastfoot}{%
+\insertName &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal
+\ifnextrowlast{\\\hline\hline}{\\}}{%
+ &amp; \insertbyname{Assignment 1} &amp;
+ \insertbyname{Assignment 2} &amp;
+\insertTotal\\}
+</PRE>
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+
+<H1><A NAME="SECTION00070000000000000000">
+Associated Counters</A>
+</H1>
+
+<P>
+Within the <TT>&#92;CSVtotabular</TT>, <TT>&#92;CSVtolongtable</TT> and
+<TT>&#92;applyCSVfile</TT> commands, there are two
+ counters, <TT>csvlinenum</TT> and <TT>csvrownumber</TT>.
+ The former, <TT>csvlinenum</TT>, is the current line number in the CSV
+ file, whereas the latter, <TT>csvrownumber</TT>, is the current
+ data row. Of the two counters, <TT>csvrownumber</TT> is likely to be
+ the most useful.
+
+<P>
+<A NAME="ex:stripy"></A>
+<H2><A NAME="SECTION00071000000000000000">
+Example 8 (Stripy Table)</A>
+</H2>
+David&nbsp;Carlisle's <TT>colortbl</TT> package defines the command
+<TT>&#92;rowcolor</TT> which enables you to specify the row colour.
+Suppose you want a stripy table<A NAME="tex2html11"
+ HREF="#foot297"><SUP>6</SUP></A>,
+ this can be achieved as follows:
+<PRE>
+\CSVtotabular{sample2.csv}{lccc}{%
+\rowcolor{green}\bfseries Name &amp;
+\bfseries Assignment 1 &amp;
+\bfseries Assignment 2 &amp;
+\bfseries Total\\\rowcolor{blue}
+}{%
+\insertName &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal
+\ifthenelse{\isodd{\value{csvrownumber}}}{%
+\\\rowcolor{green}}{\\\rowcolor{blue}}
+}{%
+ &amp;
+\insertbyname{Assignment 1} &amp;
+\insertbyname{Assignment 2} &amp;
+\insertTotal
+}
+</PRE>
+See the PDF version (<TT><A NAME="tex2html13"
+ HREF="csvtools.pdf">csvtools.pdf</A></TT>)
+for an illustration of the resulting table.
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+<A NAME="ex:mailref"></A>
+<H2><A NAME="SECTION00072000000000000000">
+Example 9 (More Mail Merging)</A>
+</H2>
+This is an example of mail merging where the letter reference
+is generated from the value of <TT>csvrownumber</TT>. The CSV file
+is as used in Example&nbsp;<A HREF="manual.html#ex:mail">1</A>.
+<PRE>
+\applyCSVfile{details.csv}{%
+\begin{letter}{\insertName\\\insertAddress}
+\opening{Dear \insertName}
+
+\textbf{Ref : } interview.\thecsvrownumber
+
+You are invited to an interview at \insertTime\ on the \insertDate.
+
+\closing{Yours Sincerely}
+\end{letter}}
+</PRE>
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+
+<H1><A NAME="SECTION00080000000000000000">
+Cross-Referencing</A>
+</H1>
+
+<P>
+Labels can be generated using the standard
+ <TT>&#92;label</TT> command, but you will need some way
+ to make each label unique. Example&nbsp;<A HREF="manual.html#ex:ref1">10</A>
+ does this by using <TT>&#92;thecsvrownumber</TT>,
+ whereas Example&nbsp;<A HREF="manual.html#ex:ref2">11</A> uses <TT>&#92;insert</TT><I>identifier</I>.
+
+<P>
+<A NAME="ex:ref1"></A>
+<H2><A NAME="SECTION00081000000000000000">
+Example 10 (Labelling within <TT>&#92;applyCSVfile</TT>)</A>
+</H2>
+ Example&nbsp;<A HREF="manual.html#ex:ps">2</A> can be modified to
+ label each figure:
+<PRE>
+\applyCSVfile{sample3.csv}{
+\begin{figure}
+\centerline{\includegraphics{\insertFile}}
+\caption{\insertCaption}
+\label{fig:pic\thecsvrownumber}
+\end{figure}}
+</PRE>
+ This example uses
+ <code>\label{fig:pic\thecsvrownumber}</code>, so the first figure
+generated by this <TT>&#92;applyCSVfile</TT> command will have the
+label <TT>fig:pic1</TT>, the second <TT>fig:pic2</TT> etc.
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+<A NAME="ex:ref2"></A>
+<H2><A NAME="SECTION00082000000000000000">
+Example 11 (Labelling within <TT>&#92;applyCSVfile</TT>)</A>
+</H2>
+ Modifying the previous example, we now have:
+<PRE>
+\applyCSVfile{sample3.csv}{
+\begin{figure}
+\centerline{\includegraphics{\insertFile}}
+\caption{\insertCaption}
+\label{fig:\insertFile}
+\end{figure}}
+</PRE>
+ The labels for each figure are now:
+ <TT>fig:circle.ps</TT>, <TT>fig:rectangle.ps</TT>
+ and <TT>fig:triangle.ps</TT>, respectively.
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+<A NAME="ex:timetogrowth"></A>
+<H2><A NAME="SECTION00083000000000000000">
+Example 12 (Labelling within <TT>&#92;CSVtotabular</TT>)</A>
+</H2>
+ This example is slightly more complicated.
+ The CSV file, <TT>data.csv</TT> looks like:
+<PRE>
+Incubation Temperature,Incubation Time,Time to Growth
+40,120,40
+40,90,60
+35,180,20
+</PRE>
+The following code generates a table using the data
+ with an additional column that generates the experiment
+ number. (See note&nbsp;<A HREF="manual.html#itm:csvrownumber">8</A>.)
+<PRE>
+\begin{table}
+\caption{Time to Growth Experiments}
+\label{tab:exp}
+\vspace{10pt}
+\centering
+\CSVtotabular{data.csv}{cccc}{%
+ % Header Row
+\bfseries Experiment &amp;
+\bfseries \begin{tabular}{c}Incubation\\Temperature\end{tabular} &amp;
+\bfseries \begin{tabular}{c}Incubation\\Time\end{tabular} &amp;
+\bfseries \begin{tabular}{c}Time\\to\\Growth\end{tabular}\\}{%
+ % Middle Rows
+\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+\thecsvrownumber &amp;
+\insertbyname{Incubation Temperature} &amp;
+\insertbyname{Incubation Time} &amp;
+\insertbyname{Time to Growth} \\}{%
+ % Final Row
+\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+\thecsvrownumber &amp;
+\insertbyname{Incubation Temperature} &amp;
+\insertbyname{Incubation Time} &amp;
+\insertbyname{Time to Growth}}
+\par
+\end{table}
+
+It can be seen from Table~\ref{tab:exp}, that
+Experiment~\ref{exp:35:180} had the shortest time to growth.
+</PRE>
+ In this example, each experiment has the corresponding label
+ <TT>exp:</TT><I>Incubation Temperature</I><TT>:</TT><I>Incubation Time</I>
+ so the first experiment has label <TT>exp:40:120</TT>, the
+ second experiment has the label <TT>exp:40:90</TT> and the
+ third experiment has the label <TT>exp:35:180</TT>.
+
+<P>
+Table&nbsp;<A HREF="manual.html#tab:timetogrowth">2</A> shows the resulting table for
+ this example.
+ <BR><P></P>
+<DIV ALIGN="CENTER">
+
+<A NAME="tab:timetogrowth"></A>
+<BR>
+<BR>
+<DIV ALIGN="CENTER"><A NAME="384"></A>
+<TABLE CELLPADDING=3>
+<CAPTION><STRONG>Table 2:</STRONG>
+Time to Growth Experiments</CAPTION>
+<TR><TH ALIGN="CENTER"><B>Experiment </B></TH>
+<TH ALIGN="CENTER"><B><TABLE CELLPADDING=3>
+<TR><TH ALIGN="CENTER">Incubation</TH>
+</TR>
+<TR><TH ALIGN="CENTER">Temperature</TH>
+</TR>
+</TABLE> </B></TH>
+<TH ALIGN="CENTER"><B><TABLE CELLPADDING=3>
+<TR><TH ALIGN="CENTER">Incubation</TH>
+</TR>
+<TR><TH ALIGN="CENTER">Time</TH>
+</TR>
+</TABLE> </B></TH>
+<TH ALIGN="CENTER"><B><TABLE CELLPADDING=3>
+<TR><TH ALIGN="CENTER">Time</TH>
+</TR>
+<TR><TH ALIGN="CENTER">to</TH>
+</TR>
+<TR><TH ALIGN="CENTER">Growth</TH>
+</TR>
+</TABLE></B></TH>
+</TR>
+<TR><TD ALIGN="CENTER">1</TD>
+<TD ALIGN="CENTER">40</TD>
+<TD ALIGN="CENTER">120</TD>
+<TD ALIGN="CENTER">40</TD>
+</TR>
+<TR><TD ALIGN="CENTER">2</TD>
+<TD ALIGN="CENTER">40</TD>
+<TD ALIGN="CENTER">90</TD>
+<TD ALIGN="CENTER">60</TD>
+</TR>
+<TR><TD ALIGN="CENTER">3</TD>
+<TD ALIGN="CENTER">35</TD>
+<TD ALIGN="CENTER">180</TD>
+<TD ALIGN="CENTER">20</TD>
+</TR>
+</TABLE>
+</DIV>
+<P>
+<DIV ALIGN="CENTER"></DIV>
+</DIV>
+<BR>
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+The following example is more refined in that it
+ takes advantage of the fact that the time to growth data consists
+ of integers only, so the experiment with the maximum growth can be
+ determined by LaTeX.
+
+<P>
+<A NAME="ex:tablabel"></A>
+<H2><A NAME="SECTION00084000000000000000">
+Example 13 (Labelling within <TT>&#92;CSVtotabular</TT>)</A>
+</H2>
+<PRE>
+\newcounter{maxgrowth}
+\newcounter{incT} % incubation temperature
+\newcounter{inct} % incubation time
+
+\begin{table}
+\caption{Time to Growth Experiments}
+\label{tab:exp}
+\vspace{10pt}
+\centering
+\CSVtotabular{data.csv}{cccc}{%
+ % Header row
+\bfseries Experiment &amp;
+\bfseries \begin{tabular}{c}Incubation\\Temperature\end{tabular} &amp;
+\bfseries \begin{tabular}{c}Incubation\\Time\end{tabular} &amp;
+\bfseries \begin{tabular}{c}Time\\to\\Growth\end{tabular}\\}{%
+ % Middle rows
+\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+\thecsvrownumber &amp;
+\insertbyname{Incubation Temperature} &amp;
+\insertbyname{Incubation Time} &amp;
+\insertbyname{Time to Growth}%
+\ifthenelse{\value{maxgrowth}&lt;\insertbyname{Time to Growth}}{%
+\setcounter{maxgrowth}{\insertbyname{Time to Growth}}%
+\setcounter{incT}{\insertbyname{Incubation Temperature}}%
+\setcounter{inct}{\insertbyname{Incubation Time}}}{}%
+\\}{%
+ % Last row
+\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+\thecsvrownumber &amp;
+\insertbyname{Incubation Temperature} &amp;
+\insertbyname{Incubation Time} &amp;
+\insertbyname{Time to Growth}%
+\ifthenelse{\value{maxgrowth}&lt;\insertbyname{Time to Growth}}{%
+\setcounter{maxgrowth}{\insertbyname{Time to Growth}}%
+\setcounter{incT}{\insertbyname{Incubation Temperature}}%
+\setcounter{inct}{\insertbyname{Incubation Time}}}{}%
+}
+\par
+\end{table}
+
+As can be seen from Table~\ref{tab:exp},
+Experiment~\ref{exp:\theincT:\theinct}
+had the maximum time to growth, with
+incubation time \theinct,
+incubation temperature \theincT\ and
+time to growth, \themaxgrowth.
+</PRE>
+
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+
+<H1><A NAME="SECTION00090000000000000000">
+Saving Entries</A>
+</H1>
+ Entries can be saved using the command:
+<BR>
+<BR>
+
+ <TT>&#92;csvSaveEntry</TT>[<I>counter</I>]{<I>identifier</I>}[<I>empty text</I>]
+<BR>
+<BR>
+where <I>counter</I> is a LaTeX counter, by default
+<TT>csvrownumber</TT>,
+ and <I>identifier</I> is the header entry. The entry
+ can then be used with the command:
+<BR>
+<BR>
+ <TT>&#92;csvGetEntry</TT>{<I>counter</I>}{<I>identifier</I>}
+<BR>
+<BR>
+The final optional argument <I>empty text</I> to
+<TT>&#92;csvSaveEntry</TT> is the text to use if the entry is blank.
+For example, <code>\csvSaveEntry{Time}[MISSING DATA]</code> will
+print MISSING DATA if the Time field is blank.
+
+<P>
+The following example illustrates the use of these commands.
+
+<P>
+<A NAME="ex:index"></A>
+<H2><A NAME="SECTION00091000000000000000">
+Example 14 (Saving Entries)</A>
+</H2>
+ This example illustrates how you can use one CSV
+ file to access data in other CSV files.
+ This example has several CSV files:
+<BR>
+<BR>
+File <TT>index.csv</TT>:
+<PRE>
+File,Temperature,NaCl,pH
+exp25a.csv,25,4.7,0.5
+exp25b.csv,25,4.8,1.5
+exp30a.csv,30,5.12,4.5
+</PRE>
+ File <TT>exp25a.csv</TT>:
+<PRE>
+Time,Logcount
+0,3.75
+23,3.9
+45,4.0
+</PRE>
+ File <TT>exp25b.csv</TT>:
+<PRE>
+Time,Logcount
+0,3.6
+60,3.8
+120,4.0
+</PRE>
+ File <TT>exp30a.csv</TT>:
+<PRE>
+Time,Logcount
+0,3.73
+23,3.67
+60,4.9
+</PRE>
+
+<P>
+It is not possible to nest <TT>&#92;CSVtotabular</TT>,
+<TT>&#92;CSVtolongtable</TT> and <TT>&#92;applyCSVfile</TT>,
+ so if you need to go through <TT>index.csv</TT> and use each file
+ named in there, you can first go through <TT>index.csv</TT>
+storing the information using <TT>&#92;csvSaveEntry</TT> as follows:
+<PRE>
+\newcounter{maxexperiments}
+\applyCSVfile{sample5.csv}{%
+\stepcounter{maxexperiments}
+\csvSaveEntry{File}
+\csvSaveEntry{Temperature}
+\csvSaveEntry{NaCl}
+\csvSaveEntry{pH}
+}
+</PRE>
+ The counter <TT>maxexperiments</TT> simply counts the number of
+ entries in <TT>index.csv</TT>.
+ The entries can now be used to generate a table for each
+ file listed in <TT>index.csv</TT> (the <TT>&#92;whiledo</TT> command
+is defined in the <TT>ifthen</TT> package):
+<PRE>
+\newcounter{experiment}
+\whiledo{\value{experiment}&lt;\value{maxexperiments}}{%
+\stepcounter{experiment}
+\begin{table}
+\caption{Temperature = \protect\csvGetEntry{experiment}{Temperature},
+NaCl = \protect\csvGetEntry{experiment}{NaCl},
+pH = \protect\csvGetEntry{experiment}{pH}}
+\vspace{10pt}
+\centering
+\CSVtotabular{\csvGetEntry{experiment}{File}}{ll}{%
+Time &amp; Log Count\\}{%
+\insertTime &amp; \insertLogcount\\}{%
+\insertTime &amp; \insertLogcount}
+
+\end{table}
+}
+</PRE>
+ Note that <TT>&#92;csvGetEntry</TT> needs to be <TT>&#92;protect</TT>ed
+within the <TT>&#92;caption</TT> command.
+
+<P>
+This example can be modified if, say, you only want the
+ tables where the temperature is 25:
+<PRE>
+\setcounter{experiment}{0}
+\whiledo{\value{experiment}&lt;\value{maxexperiments}}{%
+\stepcounter{experiment}
+\ifthenelse{\equal{\csvGetEntry{experiment}{Temperature}}{25}}{%
+\begin{table}
+\caption{Temperature = \protect\csvGetEntry{experiment}{Temperature},
+NaCl = \protect\csvGetEntry{experiment}{NaCl},
+pH = \protect\csvGetEntry{experiment}{pH}}
+\vspace{10pt}
+\centering
+\CSVtotabular{\csvGetEntry{experiment}{File}}{ll}{%
+Time &amp; Log Count\\}{%
+\insertTime &amp; \insertLogcount\\}{%
+\insertTime &amp; \insertLogcount}\par
+\end{table}}{}
+}
+</PRE>
+
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+
+<H1><A NAME="SECTION000100000000000000000">
+Pie Charts (csvpie.sty)</A>
+</H1>
+
+<P>
+If you want to create a pie chart from data stored in a CSV file,
+you can use the <TT>csvpie</TT> package, distributed with the
+<TT>csvtools</TT> package. A basic pie chart can be created
+using the command:
+<BR>
+<BR>
+<TT>&#92;csvpiechart</TT>[<I>options</I>]{<I>variable</I>}{<I>filename</I>}
+<BR>
+<BR>
+where <I>filename</I> is the name of the CSV file containing the
+data, and <I>variable</I> is the command indicating the entry that
+contains the value for the given segment.
+The starred version of <TT>&#92;csvpiechart</TT> should be used if
+the CSV file has no header row.
+
+<P>
+The pie charts have ``inner'' labels on the segment, and
+``outer'' labels outside the chart. The labels are given by the
+commands <TT>&#92;csvpieinnerlabel</TT>
+and <TT>&#92;csvpieouterlabel</TT>.
+The default definitions are:
+<PRE>
+\newcommand{\csvpieouterlabel}{\field{1}}
+\newcommand{\csvpieinnerlabel}{\field{2}\%}
+</PRE>
+This assumes that the second column contains the data, and the
+first column contains a description, but can be redefined
+as necessary.
+
+<P>
+The pie chart display can be modified using the optional
+argument to <TT>&#92;csvpiechart</TT>.
+This argument should be a <I>key</I>=<I>value</I> list.
+The available keys are as follows:
+<DL>
+<DT><STRONG>start</STRONG></DT>
+<DD>This should be an integer specifying the starting angle
+of the first segment. This is 0 by default.
+
+<P>
+</DD>
+<DT><STRONG>total</STRONG></DT>
+<DD>This should be an integer specifying the sum of all
+the segment values. This is 100 by default.
+
+<P>
+</DD>
+<DT><STRONG>radius</STRONG></DT>
+<DD>This should be a length specifying the radius of the
+pie chart. (Default: 2cm)
+
+<P>
+</DD>
+<DT><STRONG>inner</STRONG></DT>
+<DD>This should be a fraction specifying the relative distance
+along the radius to start the inner label. (Default: 0.25)
+
+<P>
+</DD>
+<DT><STRONG>outer</STRONG></DT>
+<DD>This should be a fraction specifying the relative distance
+along the radius to start the outer label. (Default: 1.25)
+
+<P>
+</DD>
+<DT><STRONG>cutaway</STRONG></DT>
+<DD>This should be a comma-separated list of numbers
+corresponding to the segments that should be cut away from the
+rest of the pie chart. Since the value may contain commas, the value
+should always be enclosed in braces. Ranges may also be used.
+If a range is used, all the segments in the given range are
+kept together, so, for example, <code>cutaway={1,2}</code> will separate
+the first two segments from the pie chart, and the two segments
+will also be separated from each other, whereas <code>cutaway={1-2}</code>
+will separate the first two segments from the pie chart, but will
+keep the two segments together.
+
+<P>
+</DD>
+<DT><STRONG>offset</STRONG></DT>
+<DD>This should be a fraction specifying the
+relative distance along the radius to shift the cut away
+segments. (Default: 0.1)
+
+<P>
+</DD>
+<DT><STRONG>firstrow</STRONG></DT>
+<DD>This should be the number of the first row
+containing the actual data. This is equivalent to the optional
+argument of <TT>&#92;applyCSVfile</TT> or <TT>&#92;applyCSVfile*</TT>.
+</DD>
+</DL>
+
+<P>
+Note that T<SMALL>E</SMALL>X performs integer arithmetic. Although the CSV
+file may contain decimal numbers, rounding will occur when
+constructing the pie charts.
+
+<P>
+The colours for the pie chart segments can be set using the
+command:
+<BR>
+<BR><TT>&#92;csvpiesegmentcol</TT>{<I>n</I>}{<I>colour</I>}
+<BR>
+<BR>
+where <I>n</I> is the segment number, and <I>colour</I> is a
+defined colour name. For example, if you want the first segment
+in the pie chart to be yellow, do:
+<PRE>
+\csvpiesegmentcol{1}{yellow}
+</PRE>
+There are 8 predefined segment colours, if your pie chart has
+more than 8 segments, you will need to specify the remainder.
+
+<P>
+You can obtain the colour name for a given segment
+using:
+<BR>
+<BR><TT>&#92;csvpiesegcolname</TT>{<I>n</I>}
+<BR>
+<BR>
+where <I>n</I> is the segment number. The <TT>&#92;csvpiechart</TT>
+command uses <TT>&#92;applyCSVfile</TT>, so the <TT>csvrownumber</TT>
+counter can be used. This means that you can change the text
+colour of the outer label to match the segment. For example:
+<PRE>
+\renewcommand{\csvpieouterlabel}{%
+\color{\csvpiesegcolname{\value{csvrownumber}}}\field{2}}
+</PRE>
+Note that <TT>&#92;value</TT> must be used since <I>n</I> has to be
+a number.
+
+<P>
+If you want grey pie charts, either use the <TT>monochrome</TT>
+package option:
+<PRE>
+\usepackage[monochrome]{csvpie}
+</PRE>
+or use the command <TT>&#92;colorpiechartfalse</TT> prior to using <TT>&#92;csvpiechart</TT>.
+To switch back to colour pie charts, use
+<TT>&#92;colorpiecharttrue</TT>.
+
+<P>
+<A NAME="ex:piechart"></A>
+<H2><A NAME="SECTION000101000000000000000">
+Example 15 (A Pie Chart)</A>
+</H2>
+Given a CSV file
+(called <TT>fruit.csv</TT>) containing:
+<PRE>
+Name,Value
+Apples,20
+Pears,15
+"lemons,limes",30.5
+Peaches,24.5
+Cherries,10
+</PRE>
+Then the value for each segment is given by the second column, so
+<I>variable</I> should be <code>\field{2}</code> or <code>\insertValue</code>.
+The following code creates a figure containing two
+pie charts from the above data (for an image, see the
+PDF version of the manual, <TT><A NAME="tex2html15"
+ HREF="csvtools.pdf">csvtools.pdf</A></TT>):
+<PRE>
+ % Change the way the labels are displayed
+\renewcommand{\csvpieinnerlabel}{\sffamily\insertValue\%}
+\renewcommand{\csvpieoutlabel}{%
+\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily\insertName}
+
+\begin{figure}
+\begin{center}
+\begin{tabular}{cc}
+\csvpiechart[start=45,cutaway={1,2}]{\insertValue}{fruit.csv} &amp;
+\csvpiechart[start=45,cutaway={1-2}]{\insertValue}{fruit.csv} \\
+(a) &amp; (b)
+\end{tabular}
+\end{center}
+\caption{Pie Chart Example (a) cutaway=\{1,2\} (b) cutaway=\{1-2\}}
+\end{figure}
+</PRE>
+The inner and outer labels have been
+redefined to use a sans-serif font, and the outer label is in
+the same colour as its corresponding segment.
+Both pie charts have a starting angle of 45 degrees, and they
+have the first two segments cutaway, but in (a)
+the first two segments are separated from each other, whereas in
+(b), the first two segments are joined, although separated
+from the rest of the pie chart.
+
+<P>
+If the CSV file has no header row, the starred version should be
+used, e.g.:
+<PRE>
+\csvpiechart*[cutaway={1-2}]{\field{2}}{fruit.csv}
+</PRE>
+
+<P>
+
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+
+<H1><A NAME="SECTION000110000000000000000">
+Sorting Data (csvsort.sty)</A>
+</H1>
+
+<P>
+The <TT>csvsort</TT> package (which forms part of the
+<TT>csvtools</TT> bundle) provides analogous commands to
+those provided by <TT>csvtools</TT>, but the data is first
+sorted. The <TT>csvsort</TT> package needs to be loaded
+separately in order to access the necessary commands. The package
+options should be a list of key=value pairs, where the available
+keys are:
+<DL>
+<DT><STRONG>verbose</STRONG></DT>
+<DD>Verbose mode. This is a boolean key. If set, the
+comparisons performed by the insertion sort code are printed to
+the screen. (Default: <TT>verbose=true</TT>.)
+
+<P>
+</DD>
+<DT><STRONG>sort</STRONG></DT>
+<DD>This key specifies how to sort the data. It may take
+one of the following values:
+
+<UL>
+<LI><TT>alphabetical ascending</TT> (or just <TT>alphabetical</TT>)
+</LI>
+<LI><TT>alphabetical descending</TT>
+</LI>
+<LI><TT>numerical ascending</TT> (or just <TT>numerical</TT>)
+</LI>
+<LI><TT>numerical descending</TT>
+</LI>
+</UL>
+(Default: <TT>sort=alphabetical ascending</TT>)
+
+<P>
+</DD>
+<DT><STRONG>variable</STRONG></DT>
+<DD>The sort variable. (Default: <code>sort=\field{1}</code>)
+
+<P>
+</DD>
+<DT><STRONG>sfirstdataline</STRONG></DT>
+<DD>The line on which the data starts in a data
+file without a header row. (Default: <TT>sfirstdataline=1</TT>.)
+
+<P>
+</DD>
+<DT><STRONG>firstdataline</STRONG></DT>
+<DD>The line on which the data starts in a data
+file with a header row. (Default: <TT>firstdataline=2</TT>.)
+</DD>
+</DL>
+
+<P>
+Note that the <TT>csvsort</TT> package requires &#201;amonn McManus'
+<TT>compare.tex</TT> file. The <TT>csvsort</TT> package uses
+an insertion sort method to sort the data, so large amounts of data
+may slow processing time. The following commands are provided
+by <TT>csvsort</TT>:
+
+<P>
+
+ <TT>&#92;sortapplyCSVfile</TT>optionsfilenametext
+<P>
+<TT>&#92;sortapplyCSVfile*</TT>optionsfilenametext
+<BR>
+<BR>
+These commands are analogous to <TT>&#92;applyCSVfile</TT> and
+<TT>&#92;applyCSVfile*</TT>, except that the data is first sorted.
+The optional argument is a key=value list. The keys are the same
+as those used in the package options, described above. These options
+only apply to the given instance of the command, whereas the
+package options apply to all <TT>csvsort</TT> commands, unless
+overridden in <I>options</I>. Example, suppose you have a file
+called <TT>unsorted.csv</TT> which looks like:
+<PRE>
+First Name,Surname,Age
+Zephram,Lang,60
+Fred,Lang,10
+Barney,Langley,25
+Jane,Brown,5
+Adam,Smith,24
+Bert,Jones,18
+</PRE>
+Then
+<PRE>
+\sortapplyCSVfile[sort=alphabetical,variable=\insertSurname]{unsorted.csv}{%
+\insertSurname, \insertbyname{First Name}. Age: \insertAge\par}
+</PRE>
+will produce the following output:
+<P>
+Brown, Jane. Age:5
+<P>
+Jones, Bart. Age:18
+<P>
+Lang, Zephram. Age:60
+<P>
+Lang, Fred. Age:10
+<P>
+Langley, Barney. Age:25
+<P>
+Smith, Adam. Age: 24
+<P>
+Note that the data has only been sorted according to the surname.
+To sort first by surname, then by first name, you can
+do something like:
+<PRE>
+\sortapplyCSVfile[sort=alphabetical,
+variable={\insertSurname,\insertbyname{First Name}}]{unsorted.csv}{%
+\insertSurname, \insertbyname{First Name}. Age: \insertAge\par}
+</PRE>
+As with <TT>&#92;applyCSVfile</TT>, you must use <TT>&#92;field</TT> if
+you use the starred version:
+<PRE>
+\sortapplyCSVfile*[sort=alphabetical,
+variable={\field{2},\field{1}}]{unsorted.csv}{%
+\field{2}, \field{1}. Age: \field{3}\par}
+</PRE>
+
+<P>
+The commands:
+<BR>
+<BR>
+<TT>&#92;sortCSVtotabular</TT>optionsfilenamecol-specfirst rowall but last rowlast row
+<BR>
+<TT>&#92;sortCSVtolongtable</TT>optionsfilenamecol-specfirst rowall but last rowlast row
+<BR>
+Are analogous to <TT>&#92;CSVtotabular</TT> and <TT>&#92;CSVtolongtable</TT>,
+where, again, <I>options</I> is a list of key=value pairs, the same
+as <TT>&#92;sortapplyCSVfile</TT>. Using the same example data as above,
+the following command will sort the data according to age (in
+numerical order) and place in a tabular environment:
+<PRE>
+\sortCSVtotabular[sort=numerical,variable=\insertAge]{unsorted.csv}{llr}{%
+\bfseries Surname &amp; \bfseries First Name &amp; \bfseries Age\\}{%
+\insertSurname &amp; \insertbyname{First Name} &amp; \insertAge\\}{%
+\insertSurname &amp; \insertbyname{First Name} &amp; \insertAge}
+</PRE>
+
+<P>
+Note that the counter <TT>csvlinenum</TT> has no meaning in the
+commands provided by the <TT>csvsort</TT> package. The
+<TT>csvrownumber</TT> counter corresponds to the sorted data row.
+
+<P>
+
+<H1><A NAME="SECTION000120000000000000000">
+The csvtools.pl Perl Script</A>
+</H1>
+
+<P>
+Suppose you have several large CSV files, and you have included
+the information into your document using <TT>&#92;applyCSVfile</TT>,
+<TT>&#92;CSVtolongtable</TT>, <TT>&#92;CSVtotabular</TT> or
+<TT>&#92;csvpiechart</TT>, which has
+made life so much easier for you, but you are now required by a
+journal to submit your source code in a single <TT>.tex</TT> file.
+ They don't want all your CSV files, so what do you do? If you
+have Perl installed on your system you can use the
+<TT>csvtools.pl</TT> Perl script. This has the following syntax:
+<BR>
+<BR> <TT>csvtools.pl</TT> <I>in-file</I> <I>out-file</I>
+<BR>
+<BR>
+where <I>in-file</I> is the name of your file that contains the
+<TT>&#92;applyCSVfile</TT>, <TT>&#92;CSVtotabular</TT> etc
+ commands, and <I>out-file</I> is a new file which will be created by <TT>csvtools.pl</TT>. This new
+ file will be the same as <I>in-file</I> except that all
+occurances of <TT>&#92;applyCSVfile</TT>, <TT>&#92;CSVtolongtable</TT>,
+<TT>&#92;CSVtotabular</TT> and <TT>&#92;csvpiechart</TT> will be replaced
+by the relevant data extracted from the named CSV files.
+
+<P>
+<A NAME="ex:perl"></A>
+<H2><A NAME="SECTION000121000000000000000">
+Example 16 (csvtools.pl -- Aligning Data)</A>
+</H2>
+ Suppose the file <TT>mydoc.tex</TT> contains the code given in
+Example&nbsp;<A HREF="manual.html#ex:tab1">4</A>, with the associated CSV file
+<TT>sample.csv</TT> also given in that example. Then if you do:
+<PRE>
+csvtools.pl mydoc.tex mydocnew.tex
+</PRE>
+the file <TT>mydocnew.tex</TT> will be created which will be
+identical to <TT>mydoc.tex</TT> except the lines
+ containing the code <code>\CSVtotabular{sample.csv}{lccc}{</code>...<code>}{</code>...<code>}{</code>...<code>}</code> will be replaced
+with the lines:
+<PRE>
+ % \CSVtotabular{sample.csv}... converted using csvtools.pl
+ %&gt;&gt; START INSERT
+ \begin{tabular}{lccc}
+ \bfseries Name &amp;
+ \bfseries Assignment 1 &amp;
+ \bfseries Assignment 2 &amp;
+ \bfseries Total\\
+ A. Smith&amp;80&amp;70&amp;150\\
+ B. Jones&amp;60&amp;80&amp;140\\
+ J. Doe&amp;85&amp;75&amp;160\\
+ &amp;75&amp;75&amp;150
+ \end{tabular}%&lt;&lt; END INSERT
+</PRE>
+<P>
+<DIV ALIGN="CENTER">
+</DIV>
+
+<P>
+
+<P>
+Similarly, <TT>csvtools.pl</TT> will substitute all occurrances
+of <TT>&#92;CSVtolongtable</TT>, <TT>&#92;applyCSVfile</TT>
+and <TT>&#92;csvpiechart</TT>.
+
+<P>
+
+<H2><A NAME="SECTION000122000000000000000">
+Notes</A>
+</H2>
+
+<OL>
+<LI>If perl is located in a directory other than <TT>/usr/bin/</TT>
+you will need to edit the first line of <TT>csvtools.pl</TT> as
+appropriate. You can find the location using the command:
+<PRE>
+which perl
+</PRE>
+
+<P>
+</LI>
+<LI>If you can't directly execute a Perl script,
+ you can do:
+<BR>
+<BR> <TT>perl csvtools.pl</TT> <I>in-file</I> <I>out-file</I>
+
+<P>
+</LI>
+<LI>You must first LaTeX your document before using
+<TT>csvtools.pl</TT> as it checks the log file for any counters
+that have been defined.
+
+<P>
+</LI>
+<LI><TT>csvtools.pl</TT> only knows about a very limited set
+of LaTeX commands. It should be able to understand:
+<PRE>
+\CSVtotabular{\csvGetEntry{experiment}{File}}{ll}{...
+</PRE>
+(see Example&nbsp;<A HREF="manual.html#ex:index">14</A>), but it won't be able to understand,
+say,
+<PRE>
+\newcommand{\filename}{\csvGetEntry{experiment}{File}}
+\CSVtotabular{\filename}{ll}{...
+</PRE>
+It can pick up on <TT>&#92;addtocounter</TT>, <TT>&#92;stepcounter</TT>,
+<TT>&#92;refstepcounter</TT> and <TT>&#92;setcounter</TT> but only if
+they are used explicitly in the named <TT>.tex</TT> file. (It
+ignores any files that have been included using
+<TT>&#92;input</TT>, <TT>&#92;include</TT> etc.)
+
+<P>
+</LI>
+<LI>This Perl script has only been tested under Linux, but it
+ought to work under other systems.
+</LI>
+</OL>
+
+<P>
+
+<H1><A NAME="SECTION000130000000000000000"></A><A NAME="sec:drawbacks"></A>
+<BR>
+Bugs/Drawbacks/``Features''
+</H1>
+
+<OL>
+<LI><A NAME="itm:insert"></A> The package doesn't check to see whether
+<TT>&#92;insert</TT><I>identifier</I> exists, otherwise you would not
+be able to use multiple CSV files with the same headers, as in
+Example&nbsp;<A HREF="manual.html#ex:index">14</A>. Therefore it is recommended that
+ you check to make sure that the command does not already exist.
+ For example, the T<SMALL>E</SMALL>X commands <TT>&#92;insert</TT> and
+<TT>&#92;insertpenalties</TT> already exist, so a blank header or a
+header named <TT>penalties</TT> would cause problems. (These two
+will now cause an error as from version 1.1, but it's something
+bear in mind.)
+
+<P>
+</LI>
+<LI>Note also that <TT>&#92;insertbyname</TT> doesn't check
+ if you've given a valid label, so if no text appears,
+ check you've spelt it correctly, checking punctuation, spaces and case.
+
+<P>
+</LI>
+<LI><A NAME="itm:psbyname"></A> Note that in Example&nbsp;<A HREF="manual.html#ex:ps">2</A>, replacing line&nbsp;3 with:
+<PRE>
+\centerline{\includegraphics{\insertbyname{File}}}
+</PRE>
+ will cause an error, as <code>\insertbyname{File}</code> doesn't get
+ fully expanded by the time it gets passed to
+ <TT>&#92;includegraphics</TT>, and will prevent
+<TT>&#92;includegraphics</TT> from
+ finding the file. It is possible to get around this using
+ T<SMALL>E</SMALL>X's <TT>&#92;edef</TT> command:
+<PRE>
+\edef\psfilename{\insertbyname{File}}
+\centerline{\includegraphics{\psfilename}}
+</PRE>
+
+<P>
+</LI>
+<LI><A NAME="itm:noalign"></A> You can't have commands like
+<TT>&#92;hline</TT>, <TT>&#92;cline</TT> and <TT>&#92;multicolumn</TT> in the
+first column of the <I>middle</I> or <I>last</I> code of
+<TT>&#92;CSVtotabular</TT> or <TT>&#92;CSVtolongtable</TT>. If you do,
+it will generate a <code>misplaced \noalign</code> error, instead you
+need to put it at the end of the <I>first</I> or <I>middle</I>
+code. (See Example&nbsp;<A HREF="manual.html#ex:tab3">6</A>.)
+
+<P>
+</LI>
+<LI>You can't have nested <TT>&#92;applyCSVfile</TT>,
+<TT>&#92;CSVtolongtable</TT> and <TT>&#92;CSVtotabular</TT>
+ commands. Nor can you have <TT>&#92;csvpiechart</TT> within
+one of these commands (See Example&nbsp;<A HREF="manual.html#ex:index">14</A>)
+
+<P>
+</LI>
+<LI>If the CSV file has a header row, it must be on the first
+line.
+
+<P>
+</LI>
+<LI>It is possible for T<SMALL>E</SMALL>X to run out of memory if you use
+ <TT>&#92;csvSaveEntry</TT> on a large file.
+
+<P>
+</LI>
+<LI><A NAME="itm:csvrownumber"></A> In version 1.0, there was an
+inconsistency with <TT>csvrownumber</TT> within
+<TT>&#92;applyCSVfile</TT> and <TT>&#92;CSVtotabular</TT>. In the
+former it excluded the header row, whereas the latter
+included it. This has been changed in version 1.1 so that within
+<TT>&#92;applyCSVfile</TT>, <TT>&#92;CSVtotabular</TT> and
+<TT>&#92;CSVtolongtable</TT>, <TT>csvrownumber</TT> refers to the
+data row (excluding header row.) I hope this doesn't cause
+problems, but it makes more sense that they should be
+consistent. So if you have no blank lines in your CSV file,
+<TT>csvrownumber</TT> should always be 1 more than
+<TT>csvlinenumber</TT>.
+
+<P>
+</LI>
+</OL>
+
+<P>
+
+<H1><A NAME="SECTION000140000000000000000">
+Contact Details</A>
+</H1>
+
+<P>
+Dr Nicola Talbot
+<BR>
+School of Computing Sciences
+<BR>
+University of East Anglia
+<BR>
+Norwich. NR4 7TJ. England.
+ <BR>
+<BR> <TT><A NAME="tex2html17"
+ HREF="http://theoval.cmp.uea.ac.uk/~nlct/">http://theoval.cmp.uea.ac.uk/~nlct/</A></TT>
+<P>
+
+<P>
+
+<BR><HR><H4>Footnotes</H4>
+<DL>
+<DT><A NAME="foot869">...identifier</A><A
+ HREF="manual.html#tex2html1"><SUP>1</SUP></A></DT>
+<DD>See Note&nbsp;<A HREF="manual.html#itm:insert">1</A> in Section&nbsp;<A HREF="manual.html#sec:drawbacks">11</A>
+
+</DD>
+<DT><A NAME="foot150">... file</A><A
+ HREF="manual.html#tex2html2"><SUP>2</SUP></A></DT>
+<DD>Remeber to use a letter type of
+class file
+
+</DD>
+<DT><A NAME="foot870">... file</A><A
+ HREF="manual.html#tex2html3"><SUP>3</SUP></A></DT>
+<DD>The
+ <TT>graphics</TT> or <TT>graphicx</TT> package will be
+needed.
+
+</DD>
+<DT><A NAME="foot872">...tab:ex1</A><A
+ HREF="manual.html#tex2html4"><SUP>4</SUP></A></DT>
+<DD>Note that <TT>&#92;CSVtotabular</TT> only
+ puts the data in a <TT>tabular</TT> environment not in a table
+
+</DD>
+<DT><A NAME="foot877">...&#92;ifnextrowlast</A><A
+ HREF="manual.html#tex2html8"><SUP>5</SUP></A></DT>
+<DD>See
+ Note&nbsp;<A HREF="manual.html#itm:noalign">4</A> in Section&nbsp;<A HREF="manual.html#sec:drawbacks">11</A>
+
+</DD>
+<DT><A NAME="foot297">... table</A><A
+ HREF="manual.html#tex2html11"><SUP>6</SUP></A></DT>
+<DD>This is designed as an
+example of how to use the package, not incouragement to produce
+garish tables!
+
+</DD>
+</DL>
+<BR><HR>
+<ADDRESS>
+<A href=http://theoval.cmp.uea.ac.uk/~nlct/>Nicola L. C. Talbot</A>.
+<A HREF=http://www.cmp.uea.ac.uk/>School of Computing Sciences</A>.
+<A HREF=http://www.uea.ac.uk/>University of East Anglia.</A>
+Last Modified: 2007-06-26
+</ADDRESS>
+</BODY>
+</HTML>
diff --git a/Master/texmf-dist/source/latex/csvtools/csvtools.dtx b/Master/texmf-dist/source/latex/csvtools/csvtools.dtx
new file mode 100644
index 00000000000..f11d5e4452c
--- /dev/null
+++ b/Master/texmf-dist/source/latex/csvtools/csvtools.dtx
@@ -0,0 +1,2536 @@
+%\iffalse
+% csvtools.dtx generated using makedtx version 0.91b (c) Nicola Talbot
+% Command line args:
+% -src "csvtools\.sty\Z=>csvtools.sty"
+% -src "csvpie\.sty\Z=>csvpie.sty"
+% -src "csvsort\.sty\Z=>csvsort.sty"
+% -doc "manual.tex"
+% -author "Nicola Talbot"
+% -dir "source"
+% csvtools
+% Created on 2007/7/3 10:24
+%\fi
+%\iffalse
+%<*package>
+%% \CharacterTable
+%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+%% Digits \0\1\2\3\4\5\6\7\8\9
+%% Exclamation \! Double quote \" Hash (number) \#
+%% Dollar \$ Percent \% Ampersand \&
+%% Acute accent \' Left paren \( Right paren \)
+%% Asterisk \* Plus \+ Comma \,
+%% Minus \- Point \. Solidus \/
+%% Colon \: Semicolon \; Less than \<
+%% Equals \= Greater than \> Question mark \?
+%% Commercial at \@ Left bracket \[ Backslash \\
+%% Right bracket \] Circumflex \^ Underscore \_
+%% Grave accent \` Left brace \{ Vertical bar \|
+%% Right brace \} Tilde \~}
+%</package>
+%\fi
+% \iffalse
+% Doc-Source file to use with LaTeX2e
+% Copyright (C) 2007 Nicola Talbot, all rights reserved.
+% \fi
+% \iffalse
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage[colorlinks,
+ bookmarks,
+ hyperindex=false,
+ pdfauthor={Nicola Talbot},
+ pdftitle={csvtools: A LaTeX2e Package Providing Access to Data Saved in a CSV File},
+ pdfkeywords={LaTeX,package,csv}]{hyperref}
+\usepackage{csvpie}
+\usepackage{colortbl}
+
+
+\renewcommand{\usage}[1]{\hyperpage{#1}}
+\renewcommand{\main}[1]{\hyperpage{#1}}
+\newcommand{\see}[2]{\emph{see} #1}
+\makeatletter
+\def\index@prologue{\section*{Index}}
+\makeatother
+\RecordChanges
+\PageIndex
+\CheckSum{1878}
+\OnlyDescription
+\newcommand{\stynamefmt}[1]{\textsf{#1}}
+\newcommand{\envname}[1]{\textsf{#1}}
+
+
+\newcommand{\cmdname}[1]{\texttt{\symbol{92}#1}}
+
+\iffalse
+ Doc-Source file to use with LaTeX2e
+ Copyright (C) 2003 Nicola Talbot, all rights reserved.
+\fi
+
+
+ \newcounter{example}
+ \newenvironment{example}[2]{\refstepcounter{example}\label{#2}%
+\subsection*{Example \theexample\ (#1)}%
+\addcontentsline{loe}{section}{\protect\numberline{\theexample}#1}}{\par\centerline{\rule{2in}{1pt}}\par}
+
+\begin{document}
+\DocInput{csvtools.dtx}
+\end{document}
+%</driver>
+%\fi
+% \DeleteShortVerb{\|}
+% \MakeShortVerb{"}
+% \title{csvtools v1.24 : A \LaTeXe\ Package Providing Access to Data Saved in a CSV File}
+% \author{Nicola Talbot}
+% \date{3rd July 2007}
+% \maketitle
+% \tableofcontents
+%
+%\section*{List of Examples}
+%
+%\makeatletter\@starttoc{loe}\makeatother
+%
+% \section{Introduction}
+% The \stynamefmt{csvtools} package allows you to repeatedly perform
+% a set of \LaTeX\ commands on data in each row
+% of a comma separated variable (CSV) file.
+% This can be used for mail merging, generating
+% tables etc.
+%
+%\changes{1.2}{2006 Sept 1}{separator can now be changed}%
+%As from version 1.2, you can specify a different separator.
+%To change the separator, use the command:\\[10pt]
+%\DescribeMacro{\setcsvseparator}\cmdname{setcsvseparator}\{\meta{separator}\}\\[10pt]
+%For example, if your data is separated by colons instead of
+%commas, do:
+%\begin{verbatim}
+%\setcsvseparator{:}
+%\end{verbatim}
+%\changes{1.2}{2006 Sept 1}{entries can be delimited with double quotes}%
+%If your separator occurs within an entry, the entry must be
+%enclosed in double quotes, for example:
+%\begin{verbatim}
+%Name,Address,Telephone
+%A.N. Other,"1 The Street,The Town",0123456789
+%\end{verbatim}
+%Be careful of \TeX\ special characters occuring within a CSV
+%file, for example:
+%\begin{verbatim}
+%Name,Address,Telephone
+%Jack \& Jill,"2 The Street,The Town",0123456789
+%\end{verbatim}
+%
+% \section{Mail Merging and Similar Applications}
+%
+%\DescribeMacro{\applyCSVfile}\noindent
+% \cmdname{applyCSVfile}[\meta{n}]\{\meta{filename}\}\{\meta{text}\}\\
+% \cmdname{applyCSVfile*}[\meta{n}]\{\meta{filename}\}\{\meta{text}\}\\[10pt]
+% Letters can be generated using data given in
+% each line from \meta{filename}.
+% If the CSV file contains a header row, the
+% unstarred version of \cmdname{applyCSVfile} should
+% be used, otherwise the starred version \cmdname{applyCSVfile*}
+% should be used. The optional argument \meta{n}
+% specifies on which line the actual data (not header line)
+% starts. The unstarred version defaults to line 2
+% (the header row is always assumed to be on line 1)
+% and the starred version defaults to 1.
+%
+% With the unstarred version, the entries in the header row
+% are used to generate commands of the form
+% \DescribeMacro{\insert...}\cmdname{insert}\meta{identifier}\footnote{See Note~\ref{itm:insert} in Section~\ref{sec:drawbacks}}
+% to access corresponding elements
+% in the row currently being processed. For example,
+% suppose the first line of the CSV file looks like:
+%\begin{verbatim}
+%Name,Address,Time,Date
+%\end{verbatim}
+% then the commands \cmdname{insertName}, \cmdname{insertAddress},
+% \cmdname{insertTime} and \cmdname{insertDate} are
+% created, allowing you to use the entries in the first,
+% second, third and fourth columns of the current row.
+% If the header text contains non-alphabetical characters,
+% e.g.\ \texttt{Full Name}, then you will need to use
+% \DescribeMacro{\insertbyname}\cmdname{insertbyname}\texttt{\{}\meta{text}\texttt{\}},
+% e.g.\ \verb'\insertbyname{Full Name}'.
+%
+%Alternatively, you can use the
+%\DescribeMacro{\field}\cmdname{field}\{\meta{col}\} command, where
+%\meta{col} is the column number of the entry, so \verb"\field{1}"
+%indicates the first entry in the current row and \verb"\field{2}"
+%indicates the second entry in the current row.
+%
+% \begin{example}{Mail Merging}{ex:mail}
+% Suppose there is a file called \texttt{details.csv} that has the
+% following contents:
+%\begin{verbatim}
+%Name,Address,Time,Date
+%Miss A. Person,1 The Road\\The Town\\AB1 2XY,15.00,4th May 2004
+%Mr A. N. Other,2 The Road\\The Town\\AB1 2XY,15.30,11th May 2004
+%\end{verbatim}
+%then the following code can be used to generate a letter for each
+%person in the CSV file\footnote{Remeber to use a letter type of
+%class file}:
+%\begin{verbatim}
+%\applyCSVfile{details.csv}{%
+%\begin{letter}{\insertName\\\insertAddress}
+%\opening{Dear \insertName}
+%
+%You are invited to an interview at \insertTime\ on the \insertDate.
+%
+%\closing{Yours Sincerely}
+%\end{letter}}
+%\end{verbatim}
+% Note that you could also use \verb'\insertbyname{Name}' etc instead
+% of \cmdname{insertName} etc. Also note that you need to specify the
+% file extension when specifying the filename.
+%\end{example}
+%
+% \begin{example}{Multiple Figures}{ex:ps}
+% Suppose \texttt{sample3.csv} looks like:
+%\begin{verbatim}
+%File,Caption
+%circle.ps,A Circle
+%rectangle.ps,A Rectangle
+%triangle.ps,A Triangle
+%\end{verbatim}
+% Assuming that the files \texttt{circle.ps}, \texttt{rectangle.ps}
+% and \texttt{triangle.ps} exist, then the following code will
+% generate a figure for each graphics file\footnote{The
+% \stynamefmt{graphics} or \stynamefmt{graphicx} package will be
+%needed.}:
+%\begin{verbatim}
+%\applyCSVfile{sample3.csv}{
+%\begin{figure}
+%\centerline{\includegraphics{\insertFile}}
+%\caption{\insertCaption}
+%\end{figure}}
+%\end{verbatim}
+% Note that in this example, you can't use \verb'\insertbyname{File}'.
+% (See Note~\ref{itm:psbyname} in Section~\ref{sec:drawbacks}.)
+%\end{example}
+%
+% \begin{example}{Mail Merging using \cmdname{field}}{ex:field}
+% Suppose there is a file called \texttt{details.csv} that has the
+% following contents:
+%\begin{verbatim}
+%Miss A. Person,1 The Road\\The Town\\AB1 2XY,15.00,4th May 2004
+%Mr A. N. Other,2 The Road\\The Town\\AB1 2XY,15.30,11th May 2004
+%\end{verbatim}
+%In this case the data has no header file, so the starred version
+%of \cmdname{applyCSVfile} must be used. Since there is no header
+%file, you must use \cmdname{field} to access the entries:
+%\begin{verbatim}
+%\applyCSVfile*{details.csv}{%
+%\begin{letter}{\field{1}\\\field{2}}
+%\opening{Dear \field{1}}
+%
+%You are invited to an interview at \field{3}\ on the \field{4}.
+%
+%\closing{Yours Sincerely}
+%\end{letter}}
+%\end{verbatim}
+%\end{example}
+%
+% \section{Converting data in a CSV file into a tabular environment}
+% \DescribeMacro{\CSVtotabular}
+% \cmdname{CSVtotabular}\{\meta{filename}\}\{\meta{col-align}\}\{\meta{first}\}\{\meta{middle}\}\{\meta{last}\}\\[10pt]
+% \meta{filename} is the name of the CSV file which must have a header row on line~1,
+% \meta{col-align} is the column alignment argument that gets passed
+% to the \envname{tabular} environment, \meta{first}
+% is the code for the first line, \meta{middle} is the code
+% for the middle lines and \meta{last} is the code for the last line.
+% This is best demonstrated with an example.
+%
+% \begin{example}{Aligning Data from a CSV file}{ex:tab1}
+% Suppose the file \texttt{sample.csv} looks like:
+%\begin{verbatim}
+%Name,Assignment 1,Assignment 2,Total
+%A. Smith,80,70,150
+%B. Jones,60,80,140
+%J. Doe,85,75,160
+%,75,75,150
+%\end{verbatim}
+% then the following code can be used to align the data:
+%\begin{verbatim}
+%\CSVtotabular{sample.csv}{lccc}{%
+%\bfseries Name &
+%\bfseries Assignment 1&
+%\bfseries Assignment 2&
+%\bfseries Total\\}{%
+%\insertName &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal\\}{%
+% &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal}
+%\end{verbatim}
+% The result of this code is shown in
+% Table~\ref{tab:ex1}\footnote{Note that \cmdname{CSVtotabular} only
+% puts the data in a \envname{tabular} environment not in a table}.
+%\begin{table}
+%\caption{Example~\ref{ex:tab1}}
+%\label{tab:ex1}
+%\vspace{10pt}
+%\centerline{%
+%\begin{tabular}{lccc}
+%\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\
+%A. Smith&80&70&150\\
+%B. Jones&60&80&140\\
+%J. Doe&85&75&160\\
+% &75&75&150
+%\end{tabular}}
+%\end{table}
+%\end{example}
+%
+% \vspace{10pt}
+% \DescribeMacro{\ifnextrowlast}
+% \cmdname{ifnextrowlast}\{\meta{last-code}\}\{\meta{not-last-code}\}\\[10pt]
+% The command \cmdname{ifnextrowlast} can be used to vary what happens
+% on the last but one row. The following example illustrates
+% this by placing \cmdname{hline}\cmdname{hline} after the penultimate row.
+%
+% \begin{example}{Adding Lines}{ex:tab2}
+%\begin{verbatim}
+%\CSVtotabular{sample.csv}{|l|ccc|}{%
+%\hline\bfseries Name &
+%\bfseries Assignment 1&
+%\bfseries Assignment 2&
+%\bfseries Total\\\hline\hline}{%
+%\insertName &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal
+%\ifnextrowlast{\\\hline\hline}{\\}}{%
+% &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal\\\hline}
+%\end{verbatim}
+%This result of this code is shown in Table~\ref{tab:ex2}.\begin{table}
+%\caption{Example~\ref{ex:tab2}}
+%\label{tab:ex2}
+%\vspace{10pt}
+%\begin{center}
+%\begin{tabular}{|l|ccc|}
+%\hline\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\\hline\hline
+%A. Smith&80&70&150\\
+%B. Jones&60&80&140\\
+%J. Doe&85&75&160\\\hline\hline
+% &75&75&150\\\hline
+%\end{tabular}
+%\end{center}
+%\end{table}
+%\end{example}
+%
+% \begin{example}{Added Complexity}{ex:tab3}
+% In this example, \cmdname{multicolumn} is used to override
+% the column specifier for the first column in the
+% last row.
+%\begin{verbatim}
+%\CSVtotabular{sample2.csv}{|l|ccc|}{%
+%\hline\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\\hline\hline
+%}{%
+%\insertName &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal
+%\ifnextrowlast{\\\hline\multicolumn{1}{l|}{}}{\\}
+%}{%
+% &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal\\\cline{2-4}
+%}
+%\end{verbatim}
+% Notice that instead of placing \verb'\multicolumn{1}{l|}{}'
+% at the start of the final argument, it is instead
+% placed in the first argument to \cmdname{ifnextrowlast}\footnote{See
+% Note~\ref{itm:noalign} in Section~\ref{sec:drawbacks}}.
+%The result of this code is shown in Table~\ref{tab:ex3}.\begin{table}
+%\caption{Example~\ref{ex:tab3}}
+%\label{tab:ex3}
+%\vspace{10pt}
+%\begin{center}
+%\begin{tabular}{|l|ccc|}
+%\hline\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\\hline\hline
+%A. Smith&80&70&150\\
+%B. Jones&60&80&140\\
+%J. Doe&85&75&160\\\hline
+% \multicolumn{1}{l|}{}&75&75&150\\\cline{2-4}
+%\end{tabular}
+%\end{center}
+%\end{table}
+%\end{example}
+%
+% \section{Converting CSV file into longtable environment}
+%\DescribeMacro{\CSVtolongtable}
+%The command \cmdname{CSVtolongtable} works in the same way as \cmdname{CSVtotabular} but
+% creates a \envname{longtable} environment instead of a \envname{tabular} environment.
+%
+%\begin{example}{Using a longtable environment}{ex:long}
+%Suppose the CSV file in the previous example, contains, say, 100 entries.
+%This will no longer fit onto one page, so it would be better to use
+%\envname{CSVtolongtable} instead. For example:
+%\begin{verbatim}
+%\CSVtolongtable{sample.csv}{|l|ccc|}{%
+%\caption{Student Marks}\label{tab:students}\\
+%\hline
+%\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\\hline
+%\endfirsthead
+%\caption[]{Student Marks}\\
+%\hline
+%\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\\hline
+%\endhead
+%\hline
+%\multicolumn{3}{r}{\em Continued on next page}
+%\endfoot
+%\hline
+%\endlastfoot}{%
+%\insertName &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal
+%\ifnextrowlast{\\\hline\hline}{\\}}{%
+% & \insertbyname{Assignment 1} &
+% \insertbyname{Assignment 2} &
+%\insertTotal\\}
+%\end{verbatim}
+%\end{example}
+%
+% \section{Associated Counters}
+%
+% Within the \cmdname{CSVtotabular}, \cmdname{CSVtolongtable} and
+%\cmdname{applyCSVfile} commands, there are two
+% counters, \DescribeMacro{csvlinenum}\DescribeMacro{csvrownumber}%
+% \texttt{csvlinenum} and \texttt{csvrownumber}.
+% The former, \texttt{csvlinenum}, is the current line number in the CSV
+% file, whereas the latter, \texttt{csvrownumber}, is the current
+% data row. Of the two counters, \texttt{csvrownumber} is likely to be
+% the most useful.
+%
+% \begin{example}{Stripy Table}{ex:stripy}
+%David~Carlisle's \stynamefmt{colortbl} package defines the command
+%\cmdname{rowcolor} which enables you to specify the row colour.
+%Suppose you want a stripy table\footnote{This is designed as an
+%example of how to use the package, not incouragement to produce
+%garish tables!},
+% this can be achieved as follows:
+%\begin{verbatim}
+%\CSVtotabular{sample2.csv}{lccc}{%
+%\rowcolor{green}\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\\rowcolor{blue}
+%}{%
+%\insertName &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal
+%\ifthenelse{\isodd{\value{csvrownumber}}}{%
+%\\\rowcolor{green}}{\\\rowcolor{blue}}
+%}{%
+% &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal
+%}
+%\end{verbatim}
+%The resulting table is illustrated in Table~\ref{tab:stripy}.
+%\begin{table}[htb]
+%\caption{Stripy Table Example}
+%\label{tab:stripy}
+%\vspace{10pt}
+%\setcounter{csvrownumber}{0}
+%\begin{tabular}{lccc}
+%\rowcolor{green}\bfseries Name &
+%\bfseries Assignment 1 &
+%\bfseries Assignment 2 &
+%\bfseries Total\\\rowcolor{blue}
+%\refstepcounter{csvrownumber}A. Smith &
+%80 &
+%70 &
+%150
+%\ifthenelse{\isodd{\value{csvrownumber}}}{\\\rowcolor{green}}{\\\rowcolor{blue}}
+%\refstepcounter{csvrownumber}B. Jones &
+%60 &
+%80 &
+%140
+%\ifthenelse{\isodd{\value{csvrownumber}}}{\\\rowcolor{green}}{\\\rowcolor{blue}}
+%\refstepcounter{csvrownumber}J. Doe &
+%85 &
+%75 &
+%160
+%\ifthenelse{\isodd{\value{csvrownumber}}}{\\\rowcolor{green}}{\\\rowcolor{blue}}
+%\refstepcounter{csvrownumber} &
+%75 &
+%75 &
+%150
+%\end{tabular}
+%\end{table}
+%\end{example}
+%
+%\begin{example}{More Mail Merging}{ex:mailref}
+%This is an example of mail merging where the letter reference
+%is generated from the value of \texttt{csvrownumber}. The CSV file
+%is as used in Example~\ref{ex:mail} on page~\pageref{ex:mail}.\begin{verbatim}
+%\applyCSVfile{details.csv}{%
+%\begin{letter}{\insertName\\\insertAddress}
+%\opening{Dear \insertName}
+%
+%\textbf{Ref : } interview.\thecsvrownumber
+%
+%You are invited to an interview at \insertTime\ on the \insertDate.
+%
+%\closing{Yours Sincerely}
+%\end{letter}}
+%\end{verbatim}
+%\end{example}
+%
+% \section{Cross-Referencing}
+%
+% Labels can be generated using the standard
+% \cmdname{label} command, but you will need some way
+% to make each label unique. Example~\ref{ex:ref1}
+% does this by using \cmdname{thecsvrownumber},
+% whereas Example~\ref{ex:ref2} uses \cmdname{insert}\meta{identifier}.
+%
+% \begin{example}{Labelling within \cmdname{applyCSVfile}}{ex:ref1}
+% Example~\ref{ex:ps} on page~\pageref{ex:ps} can be modified to label each figure:
+%\begin{verbatim}
+%\applyCSVfile{sample3.csv}{
+%\begin{figure}
+%\centerline{\includegraphics{\insertFile}}
+%\caption{\insertCaption}
+%\label{fig:pic\thecsvrownumber}
+%\end{figure}}
+%\end{verbatim}
+% This example uses
+% \verb'\label{fig:pic\thecsvrownumber}', so the first figure
+%generated by this \cmdname{applyCSVfile} command will have the
+%label \texttt{fig:pic1}, the second \texttt{fig:pic2} etc.
+%\end{example}
+%
+% \begin{example}{Labelling within \cmdname{applyCSVfile}}{ex:ref2}
+% Modifying the previous example, we now have:
+%\begin{verbatim}
+%\applyCSVfile{sample3.csv}{
+%\begin{figure}
+%\centerline{\includegraphics{\insertFile}}
+%\caption{\insertCaption}
+%\label{fig:\insertFile}
+%\end{figure}}
+%\end{verbatim}
+% The labels for each figure are now:
+% \texttt{fig:circle.ps}, \texttt{fig:rectangle.ps}
+% and \texttt{fig:triangle.ps}, respectively.
+%\end{example}
+%
+%\begin{example}{Labelling within \cmdname{CSVtotabular}}{ex:timetogrowth}
+% This example is slightly more complicated.
+% The CSV file, \texttt{data.csv} looks like:
+%\begin{verbatim}
+%Incubation Temperature,Incubation Time,Time to Growth
+%40,120,40
+%40,90,60
+%35,180,20
+%\end{verbatim}
+%The following code generates a table using the data
+% with an additional column that generates the experiment
+% number. (See note~\ref{itm:csvrownumber}.)
+%\begin{verbatim}
+%\begin{table}
+%\caption{Time to Growth Experiments}
+%\label{tab:exp}
+%\vspace{10pt}
+%\centering
+%\CSVtotabular{data.csv}{cccc}{%
+% % Header Row
+%\bfseries Experiment &
+%\bfseries \begin{tabular}{c}Incubation\\Temperature\end{tabular} &
+%\bfseries \begin{tabular}{c}Incubation\\Time\end{tabular} &
+%\bfseries \begin{tabular}{c}Time\\to\\Growth\end{tabular}\\}{%
+% % Middle Rows
+%\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+%\thecsvrownumber &
+%\insertbyname{Incubation Temperature} &
+%\insertbyname{Incubation Time} &
+%\insertbyname{Time to Growth} \\}{%
+% % Final Row
+%\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+%\thecsvrownumber &
+%\insertbyname{Incubation Temperature} &
+%\insertbyname{Incubation Time} &
+%\insertbyname{Time to Growth}}
+%\par
+%\end{table}
+%
+%It can be seen from Table~\ref{tab:exp}, that
+%Experiment~\ref{exp:35:180} had the shortest time to growth.
+%\end{verbatim}
+% In this example, each experiment has the corresponding label
+% \texttt{exp:}\meta{Incubation Temperature}\texttt{:}\meta{Incubation Time}
+% so the first experiment has label \texttt{exp:40:120}, the
+% second experiment has the label \texttt{exp:40:90} and the
+% third experiment has the label \texttt{exp:35:180}.
+%
+% Table~\ref{tab:timetogrowth} shows the resulting table for
+% this example.
+% \begin{table}
+%\caption{Time to Growth Experiments}
+%\label{tab:timetogrowth}
+%\vspace{10pt}
+%\centering
+%\begin{tabular}{cccc}
+%\bfseries Experiment &
+%\bfseries \begin{tabular}{c}Incubation\\Temperature\end{tabular} &
+%\bfseries \begin{tabular}{c}Incubation\\Time\end{tabular} &
+%\bfseries \begin{tabular}{c}Time\\to\\Growth\end{tabular}\\
+% 1 & 40 & 120 & 40\\
+% 2 & 40 & 90 & 60\\
+% 3 & 35 & 180 & 20
+%\end{tabular}
+%\par
+% \end{table}
+%\end{example}
+%
+% The following example is more refined in that it
+% takes advantage of the fact that the time to growth data consists
+% of integers only, so the experiment with the maximum growth can be
+% determined by \LaTeX.
+%
+% \begin{example}{Labelling within \cmdname{CSVtotabular}}{ex:tablabel}
+%\begin{verbatim}
+%\newcounter{maxgrowth}
+%\newcounter{incT} % incubation temperature
+%\newcounter{inct} % incubation time
+%
+%\begin{table}
+%\caption{Time to Growth Experiments}
+%\label{tab:exp}
+%\vspace{10pt}
+%\centering
+%\CSVtotabular{data.csv}{cccc}{%
+% % Header row
+%\bfseries Experiment &
+%\bfseries \begin{tabular}{c}Incubation\\Temperature\end{tabular} &
+%\bfseries \begin{tabular}{c}Incubation\\Time\end{tabular} &
+%\bfseries \begin{tabular}{c}Time\\to\\Growth\end{tabular}\\}{%
+% % Middle rows
+%\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+%\thecsvrownumber &
+%\insertbyname{Incubation Temperature} &
+%\insertbyname{Incubation Time} &
+%\insertbyname{Time to Growth}%
+%\ifthenelse{\value{maxgrowth}<\insertbyname{Time to Growth}}{%
+%\setcounter{maxgrowth}{\insertbyname{Time to Growth}}%
+%\setcounter{incT}{\insertbyname{Incubation Temperature}}%
+%\setcounter{inct}{\insertbyname{Incubation Time}}}{}%
+%\\}{%
+% % Last row
+%\label{exp:\insertbyname{Incubation Temperature}:\insertbyname{Incubation Time}}
+%\thecsvrownumber &
+%\insertbyname{Incubation Temperature} &
+%\insertbyname{Incubation Time} &
+%\insertbyname{Time to Growth}%
+%\ifthenelse{\value{maxgrowth}<\insertbyname{Time to Growth}}{%
+%\setcounter{maxgrowth}{\insertbyname{Time to Growth}}%
+%\setcounter{incT}{\insertbyname{Incubation Temperature}}%
+%\setcounter{inct}{\insertbyname{Incubation Time}}}{}%
+%}
+%\par
+%\end{table}
+%
+%As can be seen from Table~\ref{tab:exp},
+%Experiment~\ref{exp:\theincT:\theinct}
+%had the maximum time to growth, with
+%incubation time \theinct,
+%incubation temperature \theincT\ and
+%time to growth, \themaxgrowth.
+%\end{verbatim}
+% \end{example}
+%
+% \section{Saving Entries}
+% Entries can be saved using the command:\\[10pt]
+% \DescribeMacro{\csvSaveEntry}
+%\changes{1.22}{2007 January 3}{added final optional argument to 'csvSaveEntry}
+% \cmdname{csvSaveEntry}[\meta{counter}]\{\meta{identifier}\}[\meta{empty text}]\\[10pt]
+% where \meta{counter} is a \LaTeX\ counter, by default
+%\texttt{csvrownumber},
+% and \meta{identifier} is the header entry. The entry
+% can then be used with the command:\\[10pt]
+% \DescribeMacro{\csvGetEntry}
+% \cmdname{csvGetEntry}\{\meta{counter}\}\{\meta{identifier}\}\\[10pt]
+%The final optional argument \meta{empty text} to
+%\cmdname{csvSaveEntry} is the text to use if the entry is blank.
+%For example, \verb|\csvSaveEntry{Time}[MISSING DATA]| will
+%print MISSING DATA if the Time field is blank.
+%
+%The following example illustrates the use of these commands.
+%
+% \begin{example}{Saving Entries}{ex:index}
+% This example illustrates how you can use one CSV
+% file to access data in other CSV files.
+% This example has several CSV files:
+%\\[10pt]
+% File \texttt{index.csv}:
+%\begin{verbatim}
+%File,Temperature,NaCl,pH
+%exp25a.csv,25,4.7,0.5
+%exp25b.csv,25,4.8,1.5
+%exp30a.csv,30,5.12,4.5
+%\end{verbatim}
+% File \texttt{exp25a.csv}:
+%\begin{verbatim}
+%Time,Logcount
+%0,3.75
+%23,3.9
+%45,4.0
+%\end{verbatim}
+% File \texttt{exp25b.csv}:
+%\begin{verbatim}
+%Time,Logcount
+%0,3.6
+%60,3.8
+%120,4.0
+%\end{verbatim}
+% File \texttt{exp30a.csv}:
+%\begin{verbatim}
+%Time,Logcount
+%0,3.73
+%23,3.67
+%60,4.9
+%\end{verbatim}
+%
+% It is not possible to nest \cmdname{CSVtotabular},
+%\cmdname{CSVtolongtable} and \cmdname{applyCSVfile},
+% so if you need to go through \texttt{index.csv} and use each file
+% named in there, you can first go through \texttt{index.csv}
+%storing the information using \cmdname{csvSaveEntry} as follows:
+%\begin{verbatim}
+%\newcounter{maxexperiments}
+%\applyCSVfile{sample5.csv}{%
+%\stepcounter{maxexperiments}
+%\csvSaveEntry{File}
+%\csvSaveEntry{Temperature}
+%\csvSaveEntry{NaCl}
+%\csvSaveEntry{pH}
+%}
+%\end{verbatim}
+% The counter \texttt{maxexperiments} simply counts the number of
+% entries in \texttt{index.csv}.
+% The entries can now be used to generate a table for each
+% file listed in \texttt{index.csv} (the \cmdname{whiledo} command
+%is defined in the \stynamefmt{ifthen} package):
+%\begin{verbatim}
+%\newcounter{experiment}
+%\whiledo{\value{experiment}<\value{maxexperiments}}{%
+%\stepcounter{experiment}
+%\begin{table}
+%\caption{Temperature = \protect\csvGetEntry{experiment}{Temperature},
+%NaCl = \protect\csvGetEntry{experiment}{NaCl},
+%pH = \protect\csvGetEntry{experiment}{pH}}
+%\vspace{10pt}
+%\centering
+%\CSVtotabular{\csvGetEntry{experiment}{File}}{ll}{%
+%Time & Log Count\\}{%
+%\insertTime & \insertLogcount\\}{%
+%\insertTime & \insertLogcount}
+%
+%\end{table}
+%}
+%\end{verbatim}
+% Note that \cmdname{csvGetEntry} needs to be \cmdname{protect}ed
+%within the \cmdname{caption} command.
+%
+% This example can be modified if, say, you only want the
+% tables where the temperature is 25:
+%\begin{verbatim}
+%\setcounter{experiment}{0}
+%\whiledo{\value{experiment}<\value{maxexperiments}}{%
+%\stepcounter{experiment}
+%\ifthenelse{\equal{\csvGetEntry{experiment}{Temperature}}{25}}{%
+%\begin{table}
+%\caption{Temperature = \protect\csvGetEntry{experiment}{Temperature},
+%NaCl = \protect\csvGetEntry{experiment}{NaCl},
+%pH = \protect\csvGetEntry{experiment}{pH}}
+%\vspace{10pt}
+%\centering
+%\CSVtotabular{\csvGetEntry{experiment}{File}}{ll}{%
+%Time & Log Count\\}{%
+%\insertTime & \insertLogcount\\}{%
+%\insertTime & \insertLogcount}\par
+%\end{table}}{}
+%}
+%\end{verbatim}
+% \end{example}
+%
+%\section{Pie Charts (csvpie.sty)}
+%
+%\changes{1.2}{2006 Sept 1}{csvpie.sty added}
+%If you want to create a pie chart from data stored in a CSV file,
+%you can use the \stynamefmt{csvpie} package, distributed with the
+%\stynamefmt{csvtools} package. A basic pie chart can be created
+%using the command:\\[10pt]
+%\DescribeMacro{\csvpiechart}\noindent
+%\cmdname{csvpiechart}[\meta{options}]\{\meta{variable}\}\{\meta{filename}\}\\[10pt]
+%where \meta{filename} is the name of the CSV file containing the
+%data, and \meta{variable} is the command indicating the entry that
+%contains the value for the given segment.
+%The starred version of \cmdname{csvpiechart} should be used if
+%the CSV file has no header row.
+%
+%The pie charts have ``inner'' labels on the segment, and
+%``outer'' labels outside the chart. The labels are given by the
+%commands \DescribeMacro{\csvpieinnerlabel}\cmdname{csvpieinnerlabel}
+%and \DescribeMacro{\csvpieouterlabel}\cmdname{csvpieouterlabel}.
+%The default definitions are:
+%\begin{verbatim}
+%\newcommand{\csvpieouterlabel}{\field{1}}
+%\newcommand{\csvpieinnerlabel}{\field{2}\%}
+%\end{verbatim}
+%This assumes that the second column contains the data, and the
+%first column contains a description, but can be redefined
+%as necessary.
+%
+%The pie chart display can be modified using the optional
+%argument to \cmdname{csvpiechart}.
+%This argument should be a \meta{key}=\meta{value} list.
+%The available keys are as follows:
+%\begin{description}
+%\item[start] This should be an integer specifying the starting angle
+%of the first segment. This is 0 by default.
+%
+%\item[total] This should be an integer specifying the sum of all
+%the segment values. This is 100 by default.
+%
+%\item[radius] This should be a length specifying the radius of the
+%pie chart. (Default: 2cm)
+%
+%\item[inner] This should be a fraction specifying the relative distance
+%along the radius to start the inner label. (Default: 0.25)
+%
+%\item[outer] This should be a fraction specifying the relative distance
+%along the radius to start the outer label. (Default: 1.25)
+%
+%\item[cutaway] This should be a comma-separated list of numbers
+%corresponding to the segments that should be cut away from the
+%rest of the pie chart. Since the value may contain commas, the value
+%should always be enclosed in braces. Ranges may also be used.
+%If a range is used, all the segments in the given range are
+%kept together, so, for example, \verb"cutaway={1,2}" will separate
+%the first two segments from the pie chart, and the two segments
+%will also be separated from each other, whereas \verb"cutaway={1-2}"
+%will separate the first two segments from the pie chart, but will
+%keep the two segments together.
+%
+%\item[offset] This should be a fraction specifying the
+%relative distance along the radius to shift the cut away
+%segments. (Default: 0.1)
+%
+%\item[firstrow] This should be the number of the first row
+%containing the actual data. This is equivalent to the optional
+%argument of \cmdname{applyCSVfile} or \cmdname{applyCSVfile*}.
+%\end{description}
+%
+%Note that \TeX\ performs integer arithmetic. Although the CSV
+%file may contain decimal numbers, rounding will occur when
+%constructing the pie charts.
+%
+%The colours for the pie chart segments can be set using the
+%command\DescribeMacro{\csvpiesegmentcol}:\\[10pt]
+%\cmdname{csvpiesegmentcol}\{\meta{n}\}\{\meta{colour}\}\\[10pt]
+%where \meta{n} is the segment number, and \meta{colour} is a
+%defined colour name. For example, if you want the first segment
+%in the pie chart to be yellow, do:
+%\begin{verbatim}
+%\csvpiesegmentcol{1}{yellow}
+%\end{verbatim}
+%There are 8 predefined segment colours, if your pie chart has
+%more than 8 segments, you will need to specify the remainder.
+%
+%You can obtain the colour name for a given segment
+%using\DescribeMacro{\csvpiesegcolname}:\\[10pt]
+%\cmdname{csvpiesegcolname}\{\meta{n}\}\\[10pt]
+%where \meta{n} is the segment number. The \cmdname{csvpiechart}
+%command uses \cmdname{applyCSVfile}, so the \texttt{csvrownumber}
+%counter can be used. This means that you can change the text
+%colour of the outer label to match the segment. For example:
+%\begin{verbatim}
+%\renewcommand{\csvpieouterlabel}{%
+%\color{\csvpiesegcolname{\value{csvrownumber}}}\field{2}}
+%\end{verbatim}
+%Note that \cmdname{value} must be used since \meta{n} has to be
+%a number.
+%
+%If you want grey pie charts, either use the \texttt{monochrome}
+%package option:
+%\begin{verbatim}
+%\usepackage[monochrome]{csvpie}
+%\end{verbatim}
+%or use the command \DescribeMacro{\colorpiechartfalse}\cmdname{colorpiechartfalse} prior to using \cmdname{csvpiechart}.
+%To switch back to colour pie charts, use
+%\DescribeMacro{\colorpiecharttrue}\cmdname{colorpiecharttrue}.
+%
+%\begin{example}{A Pie Chart}{ex:piechart}
+%Given a CSV file
+%(called \texttt{fruit.csv}) containing:
+%\begin{verbatim}
+%Name,Value
+%Apples,20
+%Pears,15
+%"lemons,limes",30.5
+%Peaches,24.5
+%Cherries,10
+%\end{verbatim}
+%Then the value for each segment is given by the second column, so
+%\meta{variable} should be \verb"\field{2}" or \verb|\insertValue|.
+%The pie charts shown in Figure~\ref{fig:piechart} can be created
+%using:
+%\begin{verbatim}
+% % Change the way the labels are displayed
+%\renewcommand{\csvpieinnerlabel}{\sffamily\insertValue\%}
+%\renewcommand{\csvpieoutlabel}{%
+%\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily\insertName}
+%
+%\begin{figure}
+%\begin{center}
+%\begin{tabular}{cc}
+%\csvpiechart[start=45,cutaway={1,2}]{\insertValue}{fruit.csv} &
+%\csvpiechart[start=45,cutaway={1-2}]{\insertValue}{fruit.csv} \\
+%(a) & (b)
+%\end{tabular}
+%\end{center}
+%\caption{Pie Chart Example (a) cutaway=\{1,2\} (b) cutaway=\{1-2\}}
+%\end{figure}
+%\end{verbatim}
+%The inner and outer labels have been
+%redefined to use a sans-serif font, and the outer label is in
+%the same colour as its corresponding segment.
+%Both pie charts have a starting angle of $45^\circ$, and theyhave the first two segments cutaway, but in (a)
+%the first two segments are separated from each other, whereas in
+%(b), the first two segments are joined, although separated
+%from the rest of the pie chart.
+%
+%If the CSV file has no header row, the starred version should be
+%used, e.g.:
+%\begin{verbatim}
+%\csvpiechart*[cutaway={1-2}]{\field{2}}{fruit.csv}
+%\end{verbatim}
+%
+%\begin{figure}[htbp]
+%\begin{center}
+%\begin{tabular}{cc}
+%\csvpiesetkeys{start=45,cutaway={1,2}}%
+%\edef\csvstartang{\thecsvstartangle}\relax
+%\setcounter{csvrownumber}{0}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{20}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{15}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{30.5}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{24.5}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{10}\relax
+%\setcounter{csvstartangle}{\csvstartang}\relax
+%\ifthenelse{\equal{\csvpiecutaways}{}}{}{\csvcomputeoffsets}\relax
+%\begin{tikzpicture}
+%\setcounter{csvrownumber}{0}\relax
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily20\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Apples}
+%\csvpiesegment{20}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily15\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Pears}
+%\csvpiesegment{15}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily30.5\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%lemons,limes}
+%\csvpiesegment{30.5}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily24.5\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Peaches}
+%\csvpiesegment{24.5}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily10\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Cherries}
+%\csvpiesegment{10}
+%\end{tikzpicture}
+% &
+%\csvpiesetkeys{start=45,cutaway={1-2}}%
+%\edef\csvstartang{\thecsvstartangle}\relax
+%\setcounter{csvrownumber}{0}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{20}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{15}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{30.5}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{24.5}\relax
+%\stepcounter{csvrownumber}\relax
+%\csvsetsegmentparams{\thecsvrownumber}{10}\relax
+%\setcounter{csvstartangle}{\csvstartang}\relax
+%\ifthenelse{\equal{\csvpiecutaways}{}}{}{\csvcomputeoffsets}\relax
+%\begin{tikzpicture}
+%\setcounter{csvrownumber}{0}\relax
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily20\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Apples}
+%\csvpiesegment{20}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily15\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Pears}
+%\csvpiesegment{15}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily30.5\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%lemons,limes}
+%\csvpiesegment{30.5}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily24.5\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Peaches}
+%\csvpiesegment{24.5}
+%\stepcounter{csvrownumber}\relax
+%\renewcommand*{\csvpieinnerlabel}{\sffamily10\%}
+%\renewcommand*{\csvpieouterlabel}{\color{\csvpiesegcolname{\value{csvrownumber}}}\sffamily
+%Cherries}
+%\csvpiesegment{10}
+%\end{tikzpicture}
+% \\
+%(a) & (b)
+%\end{tabular}
+%\end{center}
+%\caption{Pie Chart Example (a) cutaway=\{1,2\}
+%(b) cutaway=\{1-2\}}
+%\label{fig:piechart}
+%\end{figure}
+%\end{example}
+%
+%\section{Sorting Data (csvsort.sty)}
+%
+%The \stynamefmt{csvsort} package (which forms part of the
+%\stynamefmt{csvtools} bundle) provides analogous commands to
+%those provided by \stynamefmt{csvtools}, but the data is first
+%sorted. The \stynamefmt{csvsort} package needs to be loaded
+%separately in order to access the necessary commands. The package
+%options should be a list of key=value pairs, where the available
+%keys are:
+%\begin{description}
+%\item[verbose] Verbose mode. This is a boolean key. If set, the
+%comparisons performed by the insertion sort code are printed to
+%the screen. (Default: \texttt{verbose=true}.)
+%
+%\item[sort] This key specifies how to sort the data. It may take
+%one of the following values:
+%\begin{itemize}
+%\item \texttt{alphabetical ascending} (or just \texttt{alphabetical})
+%\item \texttt{alphabetical descending}
+%\item \texttt{numerical ascending} (or just \texttt{numerical})
+%\item \texttt{numerical descending}
+%\end{itemize}
+%(Default: \texttt{sort=alphabetical ascending})
+%
+%\item[variable] The sort variable. (Default: \verb|sort=\field{1}|)
+%
+%\item[sfirstdataline] The line on which the data starts in a data
+%file without a header row. (Default: \texttt{sfirstdataline=1}.)
+%
+%\item[firstdataline] The line on which the data starts in a data
+%file with a header row. (Default: \texttt{firstdataline=2}.)
+%\end{description}
+%
+%Note that the \stynamefmt{csvsort} package requires
+%the \stynamefmt{xfor} package and \'Eamonn McManus'
+%\texttt{compare.tex} file. The \stynamefmt{csvsort} package uses
+%an insertion sort method to sort the data, so large amounts of data
+%may slow processing time. The following commands are provided
+%by \stynamefmt{csvsort}:
+%
+%\DescribeMacro{\sortapplyCSVfile}\noindent
+% \cmdname{sortapplyCSVfile}\oarg{options}\marg{filename}\marg{text}\par
+% \cmdname{sortapplyCSVfile*}\oarg{options}\marg{filename}\marg{text}\\[10pt]
+%These commands are analogous to \cmdname{applyCSVfile} and
+%\cmdname{applyCSVfile*}, except that the data is first sorted.
+%The optional argument is a key=value list. The keys are the same
+%as those used in the package options, described above. These options
+%only apply to the given instance of the command, whereas the
+%package options apply to all \stynamefmt{csvsort} commands, unless
+%overridden in \meta{options}. Example, suppose you have a file
+%called \texttt{unsorted.csv} which looks like:
+%\begin{verbatim}
+%First Name,Surname,Age
+%Zephram,Lang,60
+%Fred,Lang,10
+%Barney,Langley,25
+%Jane,Brown,5
+%Adam,Smith,24
+%Bert,Jones,18
+%\end{verbatim}
+%Then
+%\begin{verbatim}
+%\sortapplyCSVfile[sort=alphabetical,variable=\insertSurname]{unsorted.csv}{%
+%\insertSurname, \insertbyname{First Name}. Age: \insertAge\par}
+%\end{verbatim}
+%will produce the following output:\par
+%Brown, Jane. Age:5\par
+%Jones, Bart. Age:18\par
+%Lang, Zephram. Age:60\par
+%Lang, Fred. Age:10\par
+%Langley, Barney. Age:25\par
+%Smith, Adam. Age: 24\par
+%Note that the data has only been sorted according to the surname.
+%To sort first by surname, then by first name, you can
+%do something like:
+%\begin{verbatim}
+%\sortapplyCSVfile[sort=alphabetical,
+%variable={\insertSurname,\insertbyname{First Name}}]{unsorted.csv}{%
+%\insertSurname, \insertbyname{First Name}. Age: \insertAge\par}
+%\end{verbatim}
+%As with \cmdname{applyCSVfile}, you must use \cmdname{field} if
+%you use the starred version:
+%\begin{verbatim}
+%\sortapplyCSVfile*[sort=alphabetical,
+%variable={\field{2},\field{1}}]{unsorted.csv}{%
+%\field{2}, \field{1}. Age: \field{3}\par}
+%\end{verbatim}
+%
+%The commands:\\[10pt]\DescribeMacro{\sortCSVtotabular}
+%\cmdname{sortCSVtotabular}\oarg{options}\marg{filename}\marg{col-spec}\marg{first row}\marg{all but last row}\marg{last row}\\
+%\DescribeMacro{\sortCSVtolongtable}
+%\cmdname{sortCSVtolongtable}\oarg{options}\marg{filename}\marg{col-spec}\marg{first row}\marg{all but last row}\marg{last row}\\
+%Are analogous to \cmdname{CSVtotabular} and \cmdname{CSVtolongtable},
+%where, again, \meta{options} is a list of key=value pairs, the same
+%as \cmdname{sortapplyCSVfile}. Using the same example data as above,
+%the following command will sort the data according to age (in
+%numerical order) and place in a tabular environment:
+%\begin{verbatim}
+%\sortCSVtotabular[sort=numerical,variable=\insertAge]{unsorted.csv}{llr}{%
+%\bfseries Surname & \bfseries First Name & \bfseries Age\\}{%
+%\insertSurname & \insertbyname{First Name} & \insertAge\\}{%
+%\insertSurname & \insertbyname{First Name} & \insertAge}
+%\end{verbatim}
+%
+%Note that the counter \texttt{csvlinenum} has no meaning in the
+%commands provided by the \stynamefmt{csvsort} package. The
+%\texttt{csvrownumber} counter corresponds to the sorted data row.
+%
+%\section{The csvtools.pl Perl Script}
+%
+% Suppose you have several large CSV files, and you have included
+%the information into your document using \cmdname{applyCSVfile},
+%\cmdname{CSVtolongtable}, \cmdname{CSVtotabular} or
+%\cmdname{csvpiechart}, which has
+%made life so much easier for you, but you are now required by a
+%journal to submit your source code in a single \texttt{.tex} file.
+% They don't want all your CSV files, so what do you do? If you
+%have Perl installed on your system you can use the
+%\texttt{csvtools.pl} Perl script. This has the following syntax:\\[5pt]
+% \texttt{csvtools.pl} \meta{in-file} \meta{out-file}\\[5pt]
+% where \meta{in-file} is the name of your file that contains the
+%\cmdname{applyCSVfile}, \cmdname{CSVtotabular} etc
+% commands, and \meta{out-file} is a new file which will be created by \texttt{csvtools.pl}. This new
+% file will be the same as \meta{in-file} except that all
+%occurances of \cmdname{applyCSVfile}, \cmdname{CSVtolongtable},
+%\cmdname{CSVtotabular} and \cmdname{csvpiechart} will be replaced
+%by the relevant data extracted from the named CSV files.
+%
+%\begin{example}{csvtools.pl --- Aligning Data}{ex:perl}
+% Suppose the file \texttt{mydoc.tex} contains the code given in
+%Example~\ref{ex:tab1}, with the associated CSV file
+%\texttt{sample.csv} also given in that example. Then if you do:
+%\begin{verbatim}
+%csvtools.pl mydoc.tex mydocnew.tex
+%\end{verbatim}
+%the file \texttt{mydocnew.tex} will be created which will be
+%identical to \texttt{mydoc.tex} except the lines
+% containing the code \verb'\CSVtotabular{sample.csv}{lccc}{'\ldots\verb/}{/\dots\verb!}{!\ldots\verb+}+ will be replaced
+%with the lines:
+%\begin{verbatim}
+% % \CSVtotabular{sample.csv}... converted using csvtools.pl
+% %>> START INSERT
+% \begin{tabular}{lccc}
+% \bfseries Name &
+% \bfseries Assignment 1 &
+% \bfseries Assignment 2 &
+% \bfseries Total\\
+% A. Smith&80&70&150\\
+% B. Jones&60&80&140\\
+% J. Doe&85&75&160\\
+% &75&75&150
+% \end{tabular}%<< END INSERT
+%\end{verbatim}
+%\end{example}
+%
+%Similarly, \texttt{csvtools.pl} will substitute all occurrances
+%of \cmdname{CSVtolongtable}, \cmdname{applyCSVfile}
+%and \cmdname{csvpiechart}.
+%
+%\subsection{Notes}
+%\begin{enumerate}
+%\item If perl is located in a directory other than \texttt{/usr/bin/}
+%you will need to edit the first line of \texttt{csvtools.pl} as
+%appropriate. You can find the location using the command:
+%\begin{verbatim}
+%which perl
+%\end{verbatim}
+%
+%\item If you can't directly execute a Perl script,
+% you can do:\\[5pt]
+% \texttt{perl csvtools.pl} \meta{in-file} \meta{out-file}
+%
+%\item You must first \LaTeX\ your document before using
+%\texttt{csvtools.pl} as it checks the log file for any counters
+%that have been defined.
+%
+%\item \texttt{csvtools.pl} only knows about a very limited set
+%of \LaTeX\ commands. It should be able to understand:
+%\begin{verbatim}
+%\CSVtotabular{\csvGetEntry{experiment}{File}}{ll}{...
+%\end{verbatim}
+%(see Example~\ref{ex:index}), but it won't be able to understand,
+%say,
+%\begin{verbatim}
+%\newcommand{\filename}{\csvGetEntry{experiment}{File}}
+%\CSVtotabular{\filename}{ll}{...
+%\end{verbatim}
+%It can pick up on \cmdname{addtocounter}, \cmdname{stepcounter},
+%\cmdname{refstepcounter} and \cmdname{setcounter} but only if
+%they are used explicitly in the named \texttt{.tex} file. (It
+%ignores any files that have been included using
+%\cmdname{input}, \cmdname{include} etc.)
+%
+%\item This Perl script has only been tested under Linux, but it
+%ought to work under other systems.
+%\end{enumerate}
+%
+% \section{Bugs/Drawbacks/``Features''}\label{sec:drawbacks}
+% \begin{enumerate}
+% \item\label{itm:insert}
+% The package doesn't check to see whether
+%\cmdname{insert}\meta{identifier} exists, otherwise you would not
+%be able to use multiple CSV files with the same headers, as in
+%Example~\ref{ex:index}. Therefore it is recommended that
+% you check to make sure that the command does not already exist.
+% For example, the \TeX\ commands \cmdname{insert} and
+%\cmdname{insertpenalties} already exist, so a blank header or a
+%header named \texttt{penalties} would cause problems. (These two
+%will now cause an error as from version 1.1, but it's something
+%bear in mind.)
+%
+% \item Note also that \cmdname{insertbyname} doesn't check
+% if you've given a valid label, so if no text appears,
+% check you've spelt it correctly, checking punctuation, spaces and case.
+%
+% \item\label{itm:psbyname}
+% Note that in Example~\ref{ex:ps}, replacing line~3 with:
+%\begin{verbatim}
+%\centerline{\includegraphics{\insertbyname{File}}}
+%\end{verbatim}
+% will cause an error, as \verb/\insertbyname{File}/ doesn't get
+% fully expanded by the time it gets passed to
+% \cmdname{includegraphics}, and will prevent
+%\cmdname{includegraphics} from
+% finding the file. It is possible to get around this using
+% \TeX's \cmdname{edef} command:
+%\begin{verbatim}
+%\edef\psfilename{\insertbyname{File}}
+%\centerline{\includegraphics{\psfilename}}
+%\end{verbatim}
+%
+% \item\label{itm:noalign} You can't have commands like
+%\cmdname{hline}, \cmdname{cline} and \cmdname{multicolumn} in the
+%first column of the \meta{middle} or \meta{last} code of
+%\cmdname{CSVtotabular} or \cmdname{CSVtolongtable}. If you do,
+%it will generate a \verb/misplaced \noalign/ error, instead you
+%need to put it at the end of the \meta{first} or \meta{middle}
+%code. (See Example~\ref{ex:tab3}.)
+%
+% \item You can't have nested \cmdname{applyCSVfile},
+%\cmdname{CSVtolongtable} and \cmdname{CSVtotabular}
+% commands. Nor can you have \cmdname{csvpiechart} within
+%one of these commands (See Example~\ref{ex:index})
+%
+% \item If the CSV file has a header row, it must be on the first
+%line.
+%
+% \item It is possible for \TeX\ to run out of memory if you use
+% \cmdname{csvSaveEntry} on a large file.
+%
+% \item\label{itm:csvrownumber} In version 1.0, there was an
+%inconsistency with \texttt{csvrownumber} within
+%\cmdname{applyCSVfile} and \cmdname{CSVtotabular}. In the
+%former it excluded the header row, whereas the latter
+%included it. This has been changed in version 1.1 so that within
+%\cmdname{applyCSVfile}, \cmdname{CSVtotabular} and
+%\cmdname{CSVtolongtable}, \texttt{csvrownumber} refers to the
+%data row (excluding header row.) I hope this doesn't cause
+%problems, but it makes more sense that they should be
+%consistent. So if you have no blank lines in your CSV file,
+%\texttt{csvrownumber} should always be 1 more than
+%\texttt{csvlinenumber}.
+%
+%\end{enumerate}
+%
+% \section{Contact Details}
+%
+% Dr Nicola Talbot\\
+% School of Computing Sciences\\
+% University of East Anglia\\
+% Norwich. NR4 7TJ. England.
+% \\[10pt]
+% \url{http://theoval.cmp.uea.ac.uk/~nlct/}
+%
+%\StopEventually{\PrintIndex\addcontentsline{toc}{section}{Index}}
+%
+%
+%
+%\section{The Code}
+%\iffalse
+% \begin{macrocode}
+%<*csvtools.sty>
+% \end{macrocode}
+%\fi
+%\subsection{csvtools.sty}
+% Declare package
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{csvtools}[2007/07/03 v1.24 (NLCT)]
+% \end{macrocode}
+% Required packages
+% \begin{macrocode}
+\RequirePackage{ifthen}
+\RequirePackage{longtable}
+% \end{macrocode}
+% Define command to set the separator character.
+% \begin{macrocode}
+\newcommand*{\@csvseparator}{,}
+\newcommand*{\setcsvseparator}[1]{%
+\renewcommand*{\@csvseparator}{#1}%
+\construct@lopoff{#1}%
+\@construct@qlopoff{#1}%
+\@construct@lopoff{#1}}
+% \end{macrocode}
+% Define command to remove first element from list. CSV files
+% usually use double quote characters to enclose entries containing
+% a comma. The first argument is the control sequence containing
+% the list, the second argument is the control sequence to
+% contain the first item in the list.
+% \begin{macrocode}
+\newcommand*{\extractentry}[2]{%
+\expandafter\csvlopoff#1\to{#1}{#2}}
+% \end{macrocode}
+% The definitions are constructed on the fly to allow for
+% different separators. The argument is the separator.
+%\changes{1.23}{2007 May 23}{'csvlopoff changed to a long command}
+% \begin{macrocode}
+\edef\construct@lopoff#1{%
+\noexpand\long\noexpand\def\noexpand\csvlopoff#1##1##2\noexpand\to##3##4{%
+\noexpand\ifx"##1\noexpand\relax
+\noexpand\@csv@qlopoff#1##1##2\noexpand\to##3##4\relax
+\noexpand\else
+\noexpand\@csv@lopoff#1##1##2\noexpand\to##3##4\relax
+\noexpand\fi
+}}
+% \end{macrocode}
+% Command to contruct control sequence to be used when the
+% entry is surrounded by double quotes.
+%\changes{1.23}{2007 May 23}{'@csv@qlopoff changed to a long command}
+% \begin{macrocode}
+\edef\@construct@qlopoff#1{%
+\noexpand\long\noexpand\def\noexpand\@csv@qlopoff#1"##1"#1##2\noexpand\to##3##4{%
+\noexpand\def##4{##1}\noexpand\def##3{#1##2}}}
+% \end{macrocode}
+% Command to construct control sequence to be used when the
+% entry isn't surrounded by double quotes.
+%\changes{1.23}{2007 May 23}{'@csv@lopoff changed to a long command}
+% \begin{macrocode}
+\edef\@construct@lopoff#1{%
+\noexpand\long\noexpand\def\noexpand\@csv@lopoff#1##1#1##2\noexpand\to##3##4{%
+\noexpand\def##4{##1}\noexpand\def##3{#1##2}}}
+% \end{macrocode}
+% Set the default separator:
+% \begin{macrocode}
+\setcsvseparator{,}
+% \end{macrocode}
+% Define some variables
+% \begin{macrocode}
+\newread\csvfile
+\newif\ifmore
+\newcount\c@field
+\newcount\c@maxfields
+\newcounter{csvlinenum}
+\newcount\maxlines
+\newcount\csvlastbutone
+\newcounter{csvrownumber}
+\toksdef\csv@tb=2
+% \end{macrocode}
+% Define commands to access element in current row.
+% Access element by column number:
+% \begin{macrocode}
+\newcommand{\field}[1]{\csname @field\romannumeral#1\endcsname}
+% \end{macrocode}
+% Set field (header) label, the first argument is the index, second argument is the header for that column.)
+% \begin{macrocode}
+\newcommand{\setcsvfieldlabel}[2]{%
+\expandafter\def\csname @fieldlabel\romannumeral#1\endcsname{#2}}
+% \end{macrocode}
+% Access element by header:
+% \begin{macrocode}
+\newcommand{\insertbyname}[1]{\csname insert#1\endcsname}
+% \end{macrocode}
+% Define command to trim trailing space (caused by EOL) in argument.
+% Argument should be a command name containing the current line.
+% \begin{macrocode}
+\newcommand{\trim}[1]{\def\@trmstr{}%
+\def\csv@trmarg{#1}%
+\if\par\csv@trmarg
+\else
+\expandafter\@trim#1\end
+\let#1\@trmstr
+\fi
+}
+\long\def\@trim#1 \end{\def\@trmstr{#1}}
+% \end{macrocode}
+% Define "\applyCSVfile"
+% \begin{macrocode}
+\newcommand{\applyCSVfile}{\@ifstar\@sapplyCSVfile\@applyCSVfile}
+% \end{macrocode}
+% Starred version of "\applyCSVfile":
+% \begin{macrocode}
+\newcommand{\@sapplyCSVfile}[3][1]{%
+\IfFileExists{#2}{%
+\openin\csvfile=#2
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+{\c@csvlinenum=1\relax
+\global\c@csvrownumber=0\relax
+\loop
+\read\csvfile to\csvline
+\advance\c@csvlinenum by 1\relax
+\ifnum\c@csvlinenum>#1\relax
+\trim{\csvline}%
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator} \and
+\not\equal{\@csvlin@}{\@csvseparator\@csvseparator} \and
+\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\csv@tb}%
+}%
+\ifthenelse{\not\equal{\csvline}{\par} \and
+\not\equal{\csvline}{}}{%
+\refstepcounter{csvrownumber}\relax
+#3}{}%
+\fi
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat}%
+\closein\csvfile
+\fi
+}{\PackageError{csvtools}{Can't find file '#2'}{}}%
+}
+% \end{macrocode}
+% Unstarred version:
+% \begin{macrocode}
+\newcommand{\@applyCSVfile}[3][2]{%
+\ifnum#1<2\relax
+\PackageError{csvtools}{Header line required}{The optional
+argument to `\string\applyCSVfile' needs to be > 1. The header
+line should be on line 1}%
+\else
+\IfFileExists{#2}{%
+\openin\csvfile=#2
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\global\c@csvlinenum=1\relax
+\global\c@csvrownumber=0\relax
+\global\c@maxfields=0\relax
+{\loop
+\read\csvfile to\csvline
+\trim{\csvline}%
+\ifnum\c@csvlinenum=1\relax
+\ifthenelse{\not\equal{\csvline}{\par} \and
+\not\equal{\csvline}{}}{%
+\csv@tb=\expandafter{\csvline}\relax
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\advance\c@field by 1\relax
+\csv@tb=\expandafter{\param}\relax
+\expandafter
+\xdef\csname @fieldlabel\romannumeral\c@field\endcsname{\the\csv@tb}%
+}%
+\c@maxfields=\c@field
+}{%
+\PackageError{csvtools}{Header line missing in file #2}{Header
+line required on line 1}}%
+\fi
+\c@field=0\relax
+\whiledo{\c@field < \c@maxfields}{%
+\advance\c@field by 1\relax
+\expandafter\let\csname @field\romannumeral\c@field\endcsname\relax%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\ifthenelse{\equal{\@fieldlabel}{}
+\TE@or \equal{\@fieldlabel}{penalties}
+\TE@or \equal{\@fieldlabel}{byname}}{\PackageError{csvtools}{%
+\string\insert\@fieldlabel \space already defined}{%
+You can't have the label '\@fieldlabel' in your header row.}}{}%
+\expandafter\let\csname insert\@fieldlabel\endcsname\relax%
+}%
+\advance\c@csvlinenum by 1\relax
+\ifnum\c@csvlinenum>#1\relax
+\csv@tb=\expandafter{\csvline}\relax
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}\relax
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname @field\romannumeral\c@field\endcsname{\the\csv@tb}%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\ifthenelse{\equal{\@fieldlabel}{}
+\TE@or \equal{\@fieldlabel}{penalties}
+\TE@or \equal{\@fieldlabel}{byname}}{\PackageError{csvtools}{%
+\string\insert\@fieldlabel \space already defined}{%
+You can't have the label '\@fieldlabel' in your header row.}}{}%
+\expandafter\xdef\csname insert\@fieldlabel\endcsname{\the\csv@tb}%
+}%
+\ifthenelse{\not\equal{\csvline}{\par}
+\and \not\equal{\csvline}{}}{%
+\global\advance\c@csvrownumber by 1\relax
+#3}{}%
+\fi
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat}%
+\closein\csvfile
+\fi
+}{\PackageError{csvtools}{Can't find file '#2'}{}}%
+\fi
+}
+% \end{macrocode}
+% Define "\CSVtotabular". Inserts contents of csv file into a tabular
+% environment.
+% \begin{macrocode}
+\newcommand{\CSVtotabular}[5]{%
+\openin\csvfile=#1
+\c@csvlinenum=0\relax
+\loop
+\advance\c@csvlinenum by 1\relax
+\read\csvfile to\csvline
+\expandafter
+\xdef\csname @csvline\romannumeral\c@csvlinenum\endcsname{\csvline}%
+\ifthenelse{\not\equal{\csvline}{\par}}{\trim{\csvline}}{}%
+\ifnum\c@csvlinenum=1\relax
+\csv@tb=\expandafter{\csvline}
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}%
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}%
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname insert\the\csv@tb\endcsname{%
+\noexpand\field{\the\c@field}}%
+}%
+\fi
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname @l\romannumeral\c@csvlinenum @field\romannumeral\c@field\endcsname{\the\csv@tb}%
+}%
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat
+\closein\csvfile
+{%
+\def\field##1{%
+\csname @l\romannumeral\c@csvlinenum @field\romannumeral##1\endcsname}%
+\def\@r@wh{\begin{tabular}{#2}#3}%
+\def\@r@w{#4}%
+\def\@r@wl{#5\end{tabular}}%
+\maxlines=\c@csvlinenum
+\advance\maxlines by -1\relax
+\csvlastbutone=\maxlines
+\advance\csvlastbutone by -1\relax
+\c@csvlinenum=1\relax
+\setcounter{csvrownumber}{0}\relax
+\whiledo{\not{\c@csvlinenum>\maxlines}}{%
+\ifthenelse{\expandafter\equal{%
+\csname @csvline\romannumeral\c@csvlinenum\endcsname}{\par}}%
+{\relax}{%
+\ifnum\c@csvlinenum=1\relax
+\@r@wh
+\else
+\refstepcounter{csvrownumber}%
+\ifnum\c@csvlinenum=\maxlines\@r@wl\else\@r@w\fi
+\fi}%
+\global\advance\c@csvlinenum by 1\relax
+}\relax
+}}
+% \end{macrocode}
+% Define "\CSVtolongtable". Similar to the above, but uses a
+% longtable environment.
+% \begin{macrocode}
+\newcommand{\CSVtolongtable}[5]{%
+\openin\csvfile=#1
+\c@csvlinenum=0\relax
+\loop
+\advance\c@csvlinenum by 1\relax
+\read\csvfile to\csvline
+\expandafter
+\xdef\csname @csvline\romannumeral\c@csvlinenum\endcsname{\csvline}%
+\ifthenelse{\not\equal{\csvline}{\par}}{\trim{\csvline}}{}%
+\ifnum\c@csvlinenum=1\relax
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname insert\the\csv@tb\endcsname{%
+\noexpand\field{\the\c@field}}%
+}%
+\fi
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname @l\romannumeral\c@csvlinenum @field\romannumeral\c@field\endcsname{\the\csv@tb}%
+}%
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat
+\closein\csvfile
+{\def\field##1{%
+\csname @l\romannumeral\c@csvlinenum @field\romannumeral##1\endcsname}%
+\def\@r@wh{\begin{longtable}{#2}#3}%
+\def\@r@w{#4}%
+\def\@r@wl{#5\end{longtable}}%
+\maxlines=\c@csvlinenum
+\advance\maxlines by -1\relax
+\csvlastbutone=\maxlines
+\advance\csvlastbutone by -1\relax
+\c@csvlinenum=1\relax
+\setcounter{csvrownumber}{0}\relax
+\whiledo{\not{\c@csvlinenum>\maxlines}}{%
+\ifthenelse{\expandafter\equal{%
+\csname @csvline\romannumeral\c@csvlinenum\endcsname}{\par}}%
+{\relax}{%
+\ifnum\c@csvlinenum=1\relax
+\@r@wh
+\else
+\refstepcounter{csvrownumber}%
+\ifnum\c@csvlinenum=\maxlines\@r@wl\else\@r@w\fi
+\fi}%
+\global\advance\c@csvlinenum by 1\relax
+}\relax
+}}
+% \end{macrocode}
+% Define a command to determine if on the penultimate row
+% \begin{macrocode}
+\newcommand{\ifnextrowlast}[2]{%
+\ifnum\c@csvlinenum=\csvlastbutone#1\else#2\fi}
+% \end{macrocode}
+% Define means to store entry for later use
+% \begin{macrocode}
+\newcommand{\csvSaveEntry}[2][csvrownumber]{%
+\@ifnextchar[{\@csvSaveEntry{#1}{#2}}{%
+\@csvSaveEntry{#1}{#2}[\insertbyname{#2}]}%
+}
+% \end{macrocode}
+% \begin{macrocode}
+\def\@csvSaveEntry#1#2[#3]{%
+\edef\@csv@tmp{\insertbyname{#2}}%
+\if\relax\@csv@tmp\relax
+\edef\@entry{#3}%
+\else
+\edef\@entry{\insertbyname{#2}}%
+\fi
+\expandafter
+\xdef\csname #2\romannumeral\value{#1}\endcsname{\@entry}}
+% \end{macrocode}
+% Define means to access stored entry.
+% \begin{macrocode}
+\newcommand{\csvGetEntry}[2]{%
+\csname #2\romannumeral\value{#1}\endcsname}
+% \end{macrocode}
+%\iffalse
+% \begin{macrocode}
+%</csvtools.sty>
+% \end{macrocode}
+%\fi
+%\iffalse
+% \begin{macrocode}
+%<*csvpie.sty>
+% \end{macrocode}
+%\fi
+%\subsection{csvpie.sty}
+% Declare package.
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{csvpie}[2006/09/01 v1.0]
+% \end{macrocode}
+% Declare options.
+% \begin{macrocode}
+\newif\ifcolorpiechart
+\colorpiecharttrue
+\DeclareOption{color}{\colorpiecharttrue}
+\DeclareOption{monochrome}{\colorpiechartfalse}
+% \end{macrocode}
+% Process options
+% \begin{macrocode}
+\ProcessOptions
+% \end{macrocode}
+% Specify required packages
+% \begin{macrocode}
+\RequirePackage{csvtools}
+\RequirePackage{tikz}
+\RequirePackage{calc}
+\RequirePackage{keyval}
+% \end{macrocode}
+% Define some variables
+% \begin{macrocode}
+\newlength\csvradius
+\newlength\csvinner
+\newlength\csvouter
+\newlength\csvcutawayoffset
+\newcounter{csvstartangle}
+\newcounter{csvendangle}
+\newcounter{csvangle}
+\newcounter{csvpietotal}
+% \end{macrocode}
+% Set default values.
+% \begin{macrocode}
+\newcommand*{\csvpiedefaults}{radius=2cm,inner=0.25,outer=1.25,%
+cutaway={},total=100,start=0,offset=0.1}
+% \end{macrocode}
+% Define command to specify inner and outer labels.
+% The default puts the entry in column 1 (usually the label)
+% in the outer area, and the entry in column 2 (usually the
+% value) in the inner area. These can be redefined by the user
+% to use other variables, or change the format etc.
+% \begin{macrocode}
+\newcommand{\csvpieouterlabel}{\field{1}}
+\newcommand{\csvpieinnerlabel}{\field{2}\%}
+% \end{macrocode}
+% Define command to store list of row numbers corresponding to
+% cut away segments. (Segments that have been offset from the
+% pie chart.) By default, none of the segments should be cut away.
+% \begin{macrocode}
+\newcommand*{\csvpiecutaways}{}
+% \end{macrocode}
+% Define a command to assign colour name "#2" to segment number "#1"
+% \begin{macrocode}
+\newcommand*{\csvpiesegmentcol}[2]{%
+\expandafter\def\csname csvpie@segcol\romannumeral#1\endcsname{#2}}
+% \end{macrocode}
+% Define command to get colour name assigned to segment number "#1"
+% \begin{macrocode}
+\newcommand*{\csvpiesegcolname}[1]{%
+\csname csvpie@segcol\romannumeral#1\endcsname}
+% \end{macrocode}
+% Set default colours. These can be changed by the user. More colours
+% can be added in a similar manner if there are more than 8 segments.
+% \begin{macrocode}
+\ifcolorpiechart
+\csvpiesegmentcol{1}{red}
+\csvpiesegmentcol{2}{green}
+\csvpiesegmentcol{3}{blue}
+\csvpiesegmentcol{4}{yellow}
+\csvpiesegmentcol{5}{magenta}
+\csvpiesegmentcol{6}{cyan}
+\csvpiesegmentcol{7}{orange}
+\csvpiesegmentcol{8}{white}
+\else
+\csvpiesegmentcol{1}{black!15}
+\csvpiesegmentcol{2}{black!25}
+\csvpiesegmentcol{3}{black!35}
+\csvpiesegmentcol{4}{black!45}
+\csvpiesegmentcol{5}{black!55}
+\csvpiesegmentcol{6}{black!65}
+\csvpiesegmentcol{7}{black!75}
+\csvpiesegmentcol{8}{black!85}
+\fi
+% \end{macrocode}
+% Define keys for "\csvpiechart" optional argument
+% \begin{macrocode}
+\define@key{csvpie}{start}{\setcounter{csvstartangle}{#1}}
+\define@key{csvpie}{total}{\setcounter{csvpietotal}{#1}}
+\define@key{csvpie}{radius}{\setlength{\csvradius}{#1}}
+\define@key{csvpie}{inner}{\setlength{\csvinner}{#1\csvradius}}
+\define@key{csvpie}{outer}{\setlength{\csvouter}{#1\csvradius}}
+\define@key{csvpie}{offset}{\setlength{\csvcutawayoffset}{#1\csvradius}}
+\define@key{csvpie}{cutaway}{\renewcommand*{\csvpiecutaways}{#1}}
+\providecommand*{\csv@startrow}{1}
+\define@key{csvpie}{firstrow}{\renewcommand*{\csv@startrow}{#1}}
+% \end{macrocode}
+% Define "\csvpiechart". The starred version uses "\applyCSVfile*",
+% the unstarred version uses "\applyCSVfile".
+% \begin{macrocode}
+\newcommand{\csvpiechart}{%
+\@ifstar{\def\@@pieapplyCSVfile{\applyCSVfile*}%
+\def\csv@startrow{1}%
+\@csvpiechart}{%
+\def\@@pieapplyCSVfile{\applyCSVfile}%
+\def\csv@startrow{2}%
+\@csvpiechart}%
+}
+% \end{macrocode}
+% Set the keys for pie chart:
+% \begin{macrocode}
+\newcommand*{\csvpiesetkeys}[1]{%
+\edef\csv@piesk{\noexpand\setkeys{csvpie}{\csvpiedefaults,#1}}%
+\csv@piesk}
+% \end{macrocode}
+% The main body of "\csvpiechart".
+% \begin{macrocode}
+\newcommand{\@csvpiechart}[3][]{%
+{\csvpiesetkeys{#1}%
+\edef\csv@startang{\number\c@csvstartangle}%
+\csv@computeangles{#2}{#3}%
+\setcounter{csvstartangle}{\csv@startang}%
+\begin{tikzpicture}%
+\@@pieapplyCSVfile[\csv@startrow]{#3}{%
+\csvpiesegment{#2}}%
+\end{tikzpicture}%
+}}
+% \end{macrocode}
+% Do individual segment in pie chart.
+% \begin{macrocode}
+\newcommand*{\csvpiesegment}[1]{%
+\setcounter{csvstartangle}{%
+\csname csv@sang@\romannumeral\c@csvrownumber\endcsname}%
+\setcounter{csvangle}{%
+\csname csv@angle@\romannumeral\c@csvrownumber\endcsname}%
+\setcounter{csvendangle}{\value{csvangle} + \value{csvstartangle}}%
+\setcounter{csvangle}{%
+\csname csv@cut@angle\romannumeral\c@csvrownumber\endcsname}%
+\ifthenelse{\value{csvangle}>180}{\addtocounter{csvangle}{-360}}{}%
+\edef\@csv@shift{(\number\c@csvangle:%
+\csname csv@cut@len\romannumeral\c@csvrownumber\endcsname)}%
+\setcounter{csvangle}{%
+\csname csv@angle@\romannumeral\c@csvrownumber\endcsname/2
++\value{csvstartangle}}%
+\begin{scope}[shift={\@csv@shift}]%
+\fill[color=\csvpiesegcolname\c@csvrownumber] (0,0) --
+(\thecsvstartangle:\csvradius)
+arc (\thecsvstartangle:\thecsvendangle:\csvradius) -- cycle;
+% if 90 < csvangle < 270, the text will look upside-down, so
+% adjust accordingly. Reusing csvstartangle, to save defining
+% a new counter, as it's no longer required
+\ifthenelse{\(\value{csvangle}>90 \and \value{csvangle}<270\)
+\TE@or \value{csvangle}<-90}{%
+\setcounter{csvstartangle}{\value{csvangle}-180}%
+\draw (\thecsvangle:\csvinner)
+node[left,rotate=\thecsvstartangle]{\csvpieinnerlabel};
+\draw (\thecsvangle:\csvouter)
+node[left,rotate=\thecsvstartangle]{\csvpieouterlabel};
+}{%
+\draw (\thecsvangle:\csvinner)
+node[right,rotate=\thecsvangle]{\csvpieinnerlabel};
+\draw (\thecsvangle:\csvouter)
+node[right,rotate=\thecsvangle]{\csvpieouterlabel};
+}%
+\end{scope}%
+}
+% \end{macrocode}
+% Compute the angles for each segment. First argument is
+% variable, second argument is the name
+% of the CSV file.
+% \begin{macrocode}
+\newcommand*{\csv@computeangles}[2]{%
+\@@pieapplyCSVfile[\csv@startrow]{#2}{%
+\csvsetsegmentparams{\c@csvrownumber}{#1}%
+}%
+\ifthenelse{\equal{\csvpiecutaways}{}}{}{\csvcomputeoffsets}}
+% \end{macrocode}
+% Compute offset angles for cutaway segments.
+% "\csv@row" should either be a single number (e.g.\ "2")
+% or a number range (e.g.\ "1-2")
+% \begin{macrocode}
+\newcommand*{\csvcomputeoffsets}{%
+\@for\csv@row:=\csvpiecutaways\do{%
+\expandafter\@csv@set@off\csv@row-\relax
+}}
+% \end{macrocode}
+% Set the offset angle.
+% \begin{macrocode}
+\def\@csv@set@off#1-#2\relax{%
+\ifthenelse{\equal{#2}{}}{%
+\@@csv@set@off{#1}}{%
+\@@csv@set@offr#1-#2\relax}%
+}
+% \end{macrocode}
+% Set offset for individual segment:
+% \begin{macrocode}
+\newcommand*{\@@csv@set@off}[1]{%
+\setcounter{csvangle}{%
+\csname csv@angle@\romannumeral#1\endcsname/2
++ \csname csv@sang@\romannumeral#1\endcsname}%
+\expandafter\xdef\csname csv@cut@angle\romannumeral#1\endcsname{%
+\number\c@csvangle}%
+\expandafter
+\gdef\csname csv@cut@len\romannumeral\csv@row\endcsname{%
+\csvcutawayoffset}%
+}
+% \end{macrocode}
+% Set offset for range of segments:
+% \begin{macrocode}
+\newcount\@csv@seg
+\def\@@csv@set@offr#1-#2-\relax{%
+\ifnum#1>#2\relax
+\PackageError{csvpie}{Segment ranges must go in ascending
+order}{Try #2-#1 instead of #1-#2}%
+\else
+\setcounter{csvangle}{0}%
+\@csv@seg=#1\relax
+\whiledo{\not\(\@csv@seg > #2\)}{%
+\addtocounter{csvangle}{%
+\csname csv@angle@\romannumeral\@csv@seg\endcsname}%
+\advance\@csv@seg by 1}%
+\setcounter{csvangle}{\value{csvangle}/2
++ \csname csv@sang@\romannumeral#1\endcsname}%
+\@csv@seg=#1\relax
+\whiledo{\not\(\@csv@seg > #2\)}{%
+\expandafter\xdef\csname csv@cut@angle\romannumeral\@csv@seg\endcsname{%
+\number\c@csvangle}%
+\expandafter
+\gdef\csname csv@cut@len\romannumeral\@csv@seg\endcsname{%
+\csvcutawayoffset}%
+\advance\@csv@seg by 1}%
+\fi
+}
+% \end{macrocode}
+% Set the relevent variables required for "\csvpiesegment":
+% The first argument is the segment number, the second argument
+% is the variable. The "csvstartangle" counter is updated.
+% This command should be called sequentially, and is provided
+% for the convenience of \texttt{csvtools.pl}.
+% \begin{macrocode}
+\newcommand*{\csvsetsegmentparams}[2]{%
+\ifthenelse{\value{csvstartangle}>180}{%
+\addtocounter{csvstartangle}{-360}}{}%
+\ifthenelse{\value{csvstartangle}<-180}{%
+\addtocounter{csvstartangle}{360}}{}%
+\expandafter
+\xdef\csname csv@sang@\romannumeral#1\endcsname{%
+\number\c@csvstartangle}%
+\setcounter{csvangle}{360*\real{#2}/\value{csvpietotal}}%
+\addtocounter{csvstartangle}{\value{csvangle}}%
+\expandafter
+\xdef\csname csv@angle@\romannumeral#1\endcsname{%
+\number\c@csvangle}%
+\expandafter
+\gdef\csname csv@cut@angle\romannumeral#1\endcsname{0}%
+\expandafter
+\gdef\csname csv@cut@len\romannumeral#1\endcsname{0cm}%
+}
+% \end{macrocode}
+%\iffalse
+% \begin{macrocode}
+%</csvpie.sty>
+% \end{macrocode}
+%\fi
+%\iffalse
+% \begin{macrocode}
+%<*csvsort.sty>
+% \end{macrocode}
+%\fi
+%\subsection{csvsort.sty}
+% Declare package:
+% \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{csvsort}[2007/07/03 v1.0 (NLCT)]
+% \end{macrocode}
+% If \cmdname{compare} hasn't been defined, use compare.tex
+% \begin{macrocode}
+\@ifundefined{compare}{\input{compare}}{}
+% \end{macrocode}
+% Define comparison commands. Each of the comparison commands must
+% set the boolean \cmdname{if@csv@ishigher}
+% \begin{macrocode}
+\newif\if@csv@ishigher
+% \end{macrocode}
+% Alphabetical ascending comparison:
+% \begin{macrocode}
+\newcommand{\csv@alphaascendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\csvsort@verbose{Comparing \@csv@keya\space and \@csv@keyb}%
+\edef\@csvsrt@result{\noexpand\compare{\@csv@keya}{\@csv@keyb}}%
+\ifnum\@csvsrt@result=1\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+% \end{macrocode}
+% Alphabetical descending comparison:
+% \begin{macrocode}
+\newcommand{\csv@alphadescendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\csvsort@verbose{Comparing \@csv@keya\space and \@csv@keyb}%
+\edef\@csvsrt@result{\noexpand\compare{\@csv@keya}{\@csv@keyb}}%
+\ifnum\@csvsrt@result=-1\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+% \end{macrocode}
+% Numerical ascending comparison:
+% \begin{macrocode}
+\newcommand{\csv@numericascendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\if\relax\@csv@keya\relax\def\@csv@keya{0}\fi
+\if\relax\@csv@keyb\relax\def\@csv@keyb{0}\fi
+\csvsort@verbose{Comparing \number\@csv@keya\space and \number\@csv@keyb}%
+\ifnum\@csv@keya>\@csv@keyb\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+% \end{macrocode}
+% Numerical descending comparison:
+% \begin{macrocode}
+\newcommand{\csv@numericdescendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\if\relax\@csv@keya\relax\def\@csv@keya{0}\fi
+\if\relax\@csv@keyb\relax\def\@csv@keyb{0}\fi
+\csvsort@verbose{Comparing \number\@csv@keya\space and \number\@csv@keyb}%
+\ifnum\@csv@keya<\@csv@keyb\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+% \end{macrocode}
+% The sort key needs to be extracted from the data (3rd argument
+% must be a control sequence):
+% \begin{macrocode}
+\def\@csv@extractkey#1#2#3{\def#3{#1}}
+% \end{macrocode}
+% Conversely, extract the data and ignore the sort key:
+% \begin{macrocode}
+\def\@csv@extractdata#1#2#3{\def#3{#2}}
+% \end{macrocode}
+% The command \cmdname{csv@compare} should be set to the
+% appropriate comparison command (\cmdname{csv@alphaascendingcompare}
+% by default.)
+% \begin{macrocode}
+\let\csv@compare\csv@alphaascendingcompare
+% \end{macrocode}
+% The package options are a comma-separated list of key=value
+% pairs, so need the \stynamefmt{xkeyval} package.
+% \begin{macrocode}
+\RequirePackage{xkeyval}
+% \end{macrocode}
+% Package options. Verbose mode:
+% \begin{macrocode}
+\define@boolkey{csvsort.sty}[csvsrt]{verbose}[true]{}
+% \end{macrocode}
+% Default is verbose:
+% \begin{macrocode}
+\csvsrtverbosetrue
+% \end{macrocode}
+% Define command to display message if verbose option is set:
+% \begin{macrocode}
+\newcommand{\csvsort@verbose}[1]{%
+\ifcsvsrtverbose\typeout{#1}\fi}
+% \end{macrocode}
+% Sort type (can be either numerical or alphabetical, ascending
+% or descending):
+% \begin{macrocode}
+\define@choicekey{csvsort.sty}{sort}[\val\nr]{alphabetical,numerical,%
+alphabetical ascending,numerical ascending,%
+alphabetical descending,numerical descending,%
+alphabeticalascending,alphabeticaldescending,%
+numericalascending,numericaldescending}{%
+\ifcase\nr
+ % alphabetical (ascending)
+ \let\csv@compare\csv@alphaascendingcompare
+ \or
+ % numerical (ascending)
+ \let\csv@compare\csv@numericascendingcompare
+ \or
+ % alphabetical ascending
+ \let\csv@compare\csv@alphaascendingcompare
+ \or
+ % numerical ascending
+ \let\csv@compare\csv@numericascendingcompare
+ \or
+ % alphabetical descending
+ \let\csv@compare\csv@alphadescendingcompare
+ \or
+ % numerical descending
+ \let\csv@compare\csv@numericdescendingcompare
+ \or
+ % alphabeticalascending
+ \let\csv@compare\csv@alphaascendingcompare
+ \or
+ % alphabetical descending
+ \let\csv@compare\csv@alphadescendingcompare
+ \or
+ % numericalascending
+ \let\csv@compare\csv@numericascendingcompare
+ \or
+ % numericaldescending
+ \let\csv@compare\csv@numericdescendingcompare
+\fi}
+% \end{macrocode}
+% The variable used to sort is given by:
+% \begin{macrocode}
+\newcommand{\csv@sortvariable}{\field{1}}
+% \end{macrocode}
+% A different variable can be set using the variable package option:
+% \begin{macrocode}
+\define@key{csvsort.sty}{variable}{%
+\renewcommand{\csv@sortvariable}{#1}}
+% \end{macrocode}
+% The first data line in CSV files with no headers is given by
+% \begin{macrocode}
+\newcounter{sfirstdataline}
+% \end{macrocode}
+% and defaults to line 1:
+% \begin{macrocode}
+\setcounter{sfirstdataline}{1}
+% \end{macrocode}
+% This value can be set using the "sfirstdataline" option:
+% \begin{macrocode}
+\define@key{csvsort.sty}{sfirstdataline}{%
+\setcounter{sfirstdataline}{#1}}
+% \end{macrocode}
+% The first data line in CSV files with headers is given by
+% \begin{macrocode}
+\newcounter{firstdataline}
+% \end{macrocode}
+% and defaults to line 2:
+% \begin{macrocode}
+\setcounter{firstdataline}{2}
+% \end{macrocode}
+% This value can be set using the "firstdataline" option:
+% \begin{macrocode}
+\define@key{csvsort.sty}{firstdataline}{%
+\setcounter{firstdataline}{#1}}
+% \end{macrocode}
+% Process package options:
+% \begin{macrocode}
+\ProcessOptionsX
+% \end{macrocode}
+% Required packages:
+% \begin{macrocode}
+\RequirePackage{csvtools}
+\RequirePackage{xfor}
+% \end{macrocode}
+% Insertion sort macro. The argument is a comma-separated list
+% in the form \marg{sort-key1}\marg{data1},\ldots,%
+%\marg{sort-keyN}\marg{dataN}. The list is sorted according to
+% \cmdname{csv@compare}
+%\begin{macro}{\csv@insertionsort}
+% \begin{macrocode}
+\newcommand{\csv@insertionsort}[1]{%
+\let\@csv@sortedlist\relax
+\@for\@csv@listelement:=#1\do{%
+\if\@csv@sortedlist\relax
+ \expandafter\toks@\expandafter{\@csv@listelement}%
+ \edef\@csv@sortedlist{\the\toks@}%
+\else
+ \expandafter\@csv@insert@into\expandafter
+ {\@csv@listelement}{\@csv@sortedlist}%
+\fi}\let#1\@csv@sortedlist}
+% \end{macrocode}
+%\end{macro}
+% Insert element (first argument) into a sorted list (second argument)
+% Each element must be in the form \marg{sort-key}\marg{data}, where
+% \cmdname{csv@compare} sorts according to \meta{sort-key}. The
+% insertion code ignores \meta{data}.
+%\begin{macro}{\@csv@insertinto}
+% \begin{macrocode}
+\newcommand\@csv@insert@into[2]{%
+\let\@csv@tmplist\relax
+\@for\@sort@list@element:=#2\do{%
+ \expandafter\csv@compare\expandafter{\@sort@list@element}{#1}%
+ \if@csv@ishigher
+ \toks@{#1}%
+ \if\relax\@csv@tmplist
+ \edef\@csv@tmplist{\the\toks@,\@sort@list@element}%
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\the\toks@,\@sort@list@element}%
+ \fi
+ \@endfortrue
+ \else
+ \if\relax\@csv@tmplist
+ \edef\@csv@tmplist{\@sort@list@element}%
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\@sort@list@element}%
+ \fi
+ \fi
+}%
+\if@endfor
+ \ifx\@forremainder\@empty
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\@forremainder}%
+ \fi
+\else
+ \toks@{#1}%
+ \if\relax\@csv@tmplist
+ \edef\@csv@tmplist{\the\toks@}%
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\the\toks@}%
+ \fi
+\fi
+\@endforfalse
+\let#2\@csv@tmplist
+}
+% \end{macrocode}
+%\end{macro}
+% Define \cmdname{sortapplyCSVfile}. This is akin to \stynamefmt{csvtools}'
+% \cmdname{applyCSVfile}, except it stores each data row in a list,
+% sorts the list, and then iterates through the sorted list. As
+% with, \cmdname{applyCSVfile}, the starred version should be used
+% for a file that doesn't contain a header row, and the un-starred
+% version should be used for a file that has a header row. Both
+% forms take an optional argument, which should be a key=value list,
+% the same as the package options, but they only apply to the
+% current instance of \cmdname{sortapplyCSVfile}.
+%\begin{macro}{\sortapplyCSVfile}
+% \begin{macrocode}
+\newcommand{\sortapplyCSVfile}{%
+\@ifstar\@ssortapplyCSVfile\@sortapplyCSVfile}
+% \end{macrocode}
+%\end{macro}
+% Starred version (see above):
+%\begin{macro}{\@ssortapplyCSVfile}
+% \begin{macrocode}
+\newcommand{\@ssortapplyCSVfile}[3][]{%
+\bgroup
+\setkeys{csvsort.sty}{#1}%
+\def\@csv@list{}%
+\@sapplyCSVfile[\c@sfirstdataline]{#2}{%
+\edef\csv@key{\csv@sortvariable}%
+\if\relax\@csv@list\relax
+\protected@xdef\@csv@list{{\csv@key}{\csvline}}%
+\else
+\protected@xdef\@csv@list{\@csv@list,{\csv@key}{\csvline}}%
+\fi
+}%
+\@ssortapplyCSVdata{\@csv@list}{#3}%
+\egroup}
+% \end{macrocode}
+%\end{macro}
+% Unstarred version (see above):
+%\begin{macro}{\@sortapplyCSVfile}
+% \begin{macrocode}
+\newcommand{\@sortapplyCSVfile}[3][]{%
+\bgroup
+\setkeys{csvsort.sty}{#1}%
+\def\@csv@list{}%
+\@applyCSVfile[\c@firstdataline]{#2}{%
+\edef\csv@key{\csv@sortvariable}%
+\if\relax\@csv@list\relax
+\protected@xdef\@csv@list{{\csv@key}{\csvline}}%
+\else
+\protected@xdef\@csv@list{\@csv@list,{\csv@key}{\csvline}}%
+\fi
+}%
+\@sortapplyCSVdata{\@csv@list}{#3}%
+\egroup}
+% \end{macrocode}
+%\end{macro}
+% \cmdname{sortapplyCSVdata}\oarg{sort type}\marg{cmd}\marg{text}
+% will sort the data given by \meta{cmd}, which should contain
+% a comma separated
+% list of the form \marg{sort1}\marg{data1},\ldots\marg{sortN}\marg{dataN}
+% and the applies \meta{text} to each data element of the list.
+% The sort ordering is specified by \meta{sort type}, which should
+% have the same values as the sort key used by
+% \cmdname{sortapplyCSVfile}.
+% The starred version doesn't permit
+% \cmdname{insert}\meta{label} commands. First argument is the list,
+% the second argument specifies what to do for each data element.
+% (Note, these commands are primarily provided for the
+% benefit of \texttt{csvtools.pl}, which is why they're not
+% documented in the main part of the \stynamefmt{csvtools} manual.)
+%\begin{macro}{\sortapplyCSVdata}
+% \begin{macrocode}
+\newcommand{\sortapplyCSVdata}{%
+\@ifstar\@ssortapplyCSVdata\@sortapplyCSVdata}
+% \end{macrocode}
+%\end{macro}
+% Starred version:
+%\begin{macro}{\@ssortapplyCSVdata}
+% \begin{macrocode}
+\newcommand{\@ssortapplyCSVdata}[3][\relax]{%
+\bgroup
+\if\relax#1\relax\else\setkeys{csvsort.sty}{sort=#1}\fi
+\csv@insertionsort{#2}%
+\c@csvrownumber=0\relax
+\@for\@csv@element:=#2\do{%
+\expandafter\@csv@extractdata\@csv@element\csvline
+\expandafter\toks@\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\toks@\@csvseparator}%
+\long\edef\@csvlin@{\@csvseparator\csvline\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\expandafter\toks@\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\toks@}%
+}%
+\ifthenelse{\not\equal{\csvline}{}}{%
+\refstepcounter{csvrownumber}%
+#3}{}%
+}%
+\egroup
+}
+% \end{macrocode}
+%\end{macro}
+% Unstarred version (field labels will need to be set (using
+% \cmdname{setcsvfieldlabel}) before using this macro.)
+%\begin{macro}{\@sortapplyCSVdata}
+% \begin{macrocode}
+\newcommand{\@sortapplyCSVdata}[3][\relax]{%
+\bgroup
+\if\relax#1\relax\else\setkeys{csvsort.sty}{sort=#1}\fi
+\csv@insertionsort{#2}%
+\c@csvrownumber=0\relax
+\@for\@csv@element:=#2\do{%
+\expandafter\@csv@extractdata\@csv@element\csvline
+\expandafter\toks@\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\toks@\@csvseparator}%
+\long\edef\@csvlin@{\@csvseparator\csvline\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\expandafter\toks@\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\toks@}%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\expandafter\xdef\csname insert\@fieldlabel\endcsname{\the\toks@}%
+}%
+\ifthenelse{\not\equal{\csvline}{}}{%
+\refstepcounter{csvrownumber}%
+#3}{}%
+}%
+\egroup
+}
+% \end{macrocode}
+%\end{macro}
+% Define \cmdname{sortCSVtotabular}. This is akin to \stynamefmt{csvtools}'
+% \cmdname{CSVtotabular}, but sorts the data. Takes an optional
+% argument that is a key=value list which is that same as the
+% package options, but only applies to this instance of
+%\cmdname{sortCSVtotabular}. This command first loads all the data
+% into a list, sorts the list, and then puts it in a tabular
+% environment. The total number of data rows is stored in
+% \cmdname{maxlines}.
+%\begin{macro}{\sortCSVtotabular}
+% \begin{macrocode}
+\newcommand{\sortCSVtotabular}[6][]{%
+\@sortCSVtotabular[#1]{#2}{#3}{#4}{#5}{#6}{tabular}}
+% \end{macrocode}
+%\end{macro}
+% As above, but use longtable environment instead:
+%\begin{macro}{\sortCSVtolongtable}
+% \begin{macrocode}
+\newcommand{\sortCSVtolongtable}[6][]{%
+\@sortCSVtotabular[#1]{#2}{#3}{#4}{#5}{#6}{longtable}}
+% \end{macrocode}
+%\end{macro}
+% The final argument specifies which tabular-like environment
+% to use:
+%\begin{macro}{\@sortCSVtotabular}
+% \begin{macrocode}
+\newcommand{\@sortCSVtotabular}[7][]{%
+\bgroup
+\setkeys{csvsort.sty}{#1}%
+% \end{macrocode}
+% Read all data into \cmdname{@csv@list}:
+% \begin{macrocode}
+\def\@csv@list{}%
+\@applyCSVfile[\c@firstdataline]{#2}{%
+\edef\csv@key{\csv@sortvariable}%
+\if\relax\@csv@list\relax
+\protected@xdef\@csv@list{{\csv@key}{\csvline}}%
+\else
+\protected@xdef\@csv@list{\@csv@list,{\csv@key}{\csvline}}%
+\fi
+}%
+% \end{macrocode}
+% Sort data, and put in required tabular-like environment
+% \begin{macrocode}
+\sortCSVdatatotabular{\c@csvrownumber}{\@csv@list}{#3}{#4}{#5}{#6}{#7}%
+\egroup
+}
+% \end{macrocode}
+%\end{macro}
+% \cmdname{sortCSVdatatotabular}\marg{n}\marg{list}\marg{col-align}\marg{header-row}\marg{all but last rows}\marg{last row}\marg{env-name}\par
+% This command sorts the data specified by \meta{list} (which has
+% \meta{n} elements) and puts in a tabular-like environment called
+% \meta{env-name}. This command is mainly provided for the benefit
+% of \texttt{csvtools.pl}, which is why it is not documented in the
+% main part of the \stynamefmt{csvtools} manual. Field names must be
+% set prior to use (using \cmdname{setcsvfieldlabel}.)
+%\begin{macro}{\sortCSVdatatotabular}
+% \begin{macrocode}
+\newcommand{\sortCSVdatatotabular}[7]{%
+% \end{macrocode}
+% Set \cmdname{maxlines} (total number of data rows, not including
+% header row).
+% \begin{macrocode}
+\maxlines=#1\relax
+% \end{macrocode}
+% Sort the data:
+% \begin{macrocode}
+\csv@insertionsort{#2}%
+% \end{macrocode}
+% Set \cmdname{csvlastbutone} to \cmdname{maxlines}$-1$:
+% \begin{macrocode}
+\csvlastbutone=\maxlines
+\advance\csvlastbutone by -1\relax
+% \end{macrocode}
+% Reset \cmdname{c@csvrownumber}:
+% \begin{macrocode}
+\c@csvrownumber=0\relax
+\c@csvlinenum=0\relax
+% \end{macrocode}
+% Initialise first row, last row and middle rows (in case not enough
+% data)
+% \begin{macrocode}
+\def\@r@wh{#4}\def\@r@w{}\def\@r@wl{}%
+% \end{macrocode}
+% Iterate through each element of sorted list
+% \begin{macrocode}
+\@for\@csv@element:=#2\do{%
+% \end{macrocode}
+% Extract data from the current list element (ignoring sort key)
+% and store in \cmdname{csvline}:
+% \begin{macrocode}
+\expandafter\@csv@extractdata\@csv@element\csvline
+% \end{macrocode}
+% Extract each field of \cmdname{csvline}:
+% \begin{macrocode}
+\expandafter\toks@\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\toks@\@csvseparator}%
+\long\edef\@csvlin@{\@csvseparator\csvline\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+% \end{macrocode}
+% Store field in \cmdname{toks@}
+% \begin{macrocode}
+\expandafter\toks@\expandafter{\param}%
+% \end{macrocode}
+% Increment field counter
+% \begin{macrocode}
+\advance\c@field by 1\relax
+% \end{macrocode}
+% Define \cmdname{field}\meta{n} and associated
+% \cmdname{insert}\meta{label}
+% \begin{macrocode}
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\toks@}%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\expandafter\xdef\csname insert\@fieldlabel\endcsname{\the\toks@}%
+}%
+% \end{macrocode}
+% Increment row counter.
+% \begin{macrocode}
+\refstepcounter{csvrownumber}%
+\refstepcounter{csvlinenum}%
+% \end{macrocode}
+% Check to see if this is the first row, last row, of somewhere in
+% between
+% \begin{macrocode}
+\ifnum\c@csvrownumber=\maxlines
+ \protected@edef\@r@wl{#6}%
+\else
+ \expandafter\toks@\expandafter{\@r@w}
+ \protected@edef\@r@w{\the\toks@#5}%
+\fi
+}%
+% \end{macrocode}
+% Now do tabular environment:
+% \begin{macrocode}
+\begin{#7}{#3}%
+\@r@wh
+\@r@w
+\@r@wl
+\end{#7}%
+}
+% \end{macrocode}
+%\end{macro}
+%\iffalse
+% \begin{macrocode}
+%</csvsort.sty>
+% \end{macrocode}
+%\fi
+%\Finale
+\endinput
diff --git a/Master/texmf-dist/source/latex/csvtools/csvtools.ins b/Master/texmf-dist/source/latex/csvtools/csvtools.ins
new file mode 100644
index 00000000000..a4b96b0cd8e
--- /dev/null
+++ b/Master/texmf-dist/source/latex/csvtools/csvtools.ins
@@ -0,0 +1,23 @@
+% csvtools.ins generated using makedtx version 0.91b 2007/7/3 10:24
+\input docstrip
+
+\preamble
+Copyright (C) 2007 Nicola Talbot, all rights reserved.
+If you modify this file, you must change its name first.
+You are NOT ALLOWED to distribute this file alone. You are NOT
+ALLOWED to take money for the distribution or use of either this
+file or a changed version, except for a nominal charge for copying
+etc.
+\endpreamble
+
+\askforoverwritefalse
+
+\generate{\file{csvpie.sty}{\usepreamble\defaultpreamble
+\usepostamble\defaultpostamble\from{csvtools.dtx}{csvpie.sty,package}}
+\file{csvsort.sty}{\usepreamble\defaultpreamble
+\usepostamble\defaultpostamble\from{csvtools.dtx}{csvsort.sty,package}}
+\file{csvtools.sty}{\usepreamble\defaultpreamble
+\usepostamble\defaultpostamble\from{csvtools.dtx}{csvtools.sty,package}}
+}
+
+\endbatchfile
diff --git a/Master/texmf-dist/tex/latex/csvtools/csvpie.sty b/Master/texmf-dist/tex/latex/csvtools/csvpie.sty
new file mode 100644
index 00000000000..ef2da7e00ea
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/csvtools/csvpie.sty
@@ -0,0 +1,207 @@
+%%
+%% This is file `csvpie.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% csvtools.dtx (with options: `csvpie.sty,package')
+%% Copyright (C) 2007 Nicola Talbot, all rights reserved.
+%% If you modify this file, you must change its name first.
+%% You are NOT ALLOWED to distribute this file alone. You are NOT
+%% ALLOWED to take money for the distribution or use of either this
+%% file or a changed version, except for a nominal charge for copying
+%% etc.
+%% \CharacterTable
+%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+%% Digits \0\1\2\3\4\5\6\7\8\9
+%% Exclamation \! Double quote \" Hash (number) \#
+%% Dollar \$ Percent \% Ampersand \&
+%% Acute accent \' Left paren \( Right paren \)
+%% Asterisk \* Plus \+ Comma \,
+%% Minus \- Point \. Solidus \/
+%% Colon \: Semicolon \; Less than \<
+%% Equals \= Greater than \> Question mark \?
+%% Commercial at \@ Left bracket \[ Backslash \\
+%% Right bracket \] Circumflex \^ Underscore \_
+%% Grave accent \` Left brace \{ Vertical bar \|
+%% Right brace \} Tilde \~}
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{csvpie}[2006/09/01 v1.0]
+\newif\ifcolorpiechart
+\colorpiecharttrue
+\DeclareOption{color}{\colorpiecharttrue}
+\DeclareOption{monochrome}{\colorpiechartfalse}
+\ProcessOptions
+\RequirePackage{csvtools}
+\RequirePackage{tikz}
+\RequirePackage{calc}
+\RequirePackage{keyval}
+\newlength\csvradius
+\newlength\csvinner
+\newlength\csvouter
+\newlength\csvcutawayoffset
+\newcounter{csvstartangle}
+\newcounter{csvendangle}
+\newcounter{csvangle}
+\newcounter{csvpietotal}
+\newcommand*{\csvpiedefaults}{radius=2cm,inner=0.25,outer=1.25,%
+cutaway={},total=100,start=0,offset=0.1}
+\newcommand{\csvpieouterlabel}{\field{1}}
+\newcommand{\csvpieinnerlabel}{\field{2}\%}
+\newcommand*{\csvpiecutaways}{}
+\newcommand*{\csvpiesegmentcol}[2]{%
+\expandafter\def\csname csvpie@segcol\romannumeral#1\endcsname{#2}}
+\newcommand*{\csvpiesegcolname}[1]{%
+\csname csvpie@segcol\romannumeral#1\endcsname}
+\ifcolorpiechart
+\csvpiesegmentcol{1}{red}
+\csvpiesegmentcol{2}{green}
+\csvpiesegmentcol{3}{blue}
+\csvpiesegmentcol{4}{yellow}
+\csvpiesegmentcol{5}{magenta}
+\csvpiesegmentcol{6}{cyan}
+\csvpiesegmentcol{7}{orange}
+\csvpiesegmentcol{8}{white}
+\else
+\csvpiesegmentcol{1}{black!15}
+\csvpiesegmentcol{2}{black!25}
+\csvpiesegmentcol{3}{black!35}
+\csvpiesegmentcol{4}{black!45}
+\csvpiesegmentcol{5}{black!55}
+\csvpiesegmentcol{6}{black!65}
+\csvpiesegmentcol{7}{black!75}
+\csvpiesegmentcol{8}{black!85}
+\fi
+\define@key{csvpie}{start}{\setcounter{csvstartangle}{#1}}
+\define@key{csvpie}{total}{\setcounter{csvpietotal}{#1}}
+\define@key{csvpie}{radius}{\setlength{\csvradius}{#1}}
+\define@key{csvpie}{inner}{\setlength{\csvinner}{#1\csvradius}}
+\define@key{csvpie}{outer}{\setlength{\csvouter}{#1\csvradius}}
+\define@key{csvpie}{offset}{\setlength{\csvcutawayoffset}{#1\csvradius}}
+\define@key{csvpie}{cutaway}{\renewcommand*{\csvpiecutaways}{#1}}
+\providecommand*{\csv@startrow}{1}
+\define@key{csvpie}{firstrow}{\renewcommand*{\csv@startrow}{#1}}
+\newcommand{\csvpiechart}{%
+\@ifstar{\def\@@pieapplyCSVfile{\applyCSVfile*}%
+\def\csv@startrow{1}%
+\@csvpiechart}{%
+\def\@@pieapplyCSVfile{\applyCSVfile}%
+\def\csv@startrow{2}%
+\@csvpiechart}%
+}
+\newcommand*{\csvpiesetkeys}[1]{%
+\edef\csv@piesk{\noexpand\setkeys{csvpie}{\csvpiedefaults,#1}}%
+\csv@piesk}
+\newcommand{\@csvpiechart}[3][]{%
+{\csvpiesetkeys{#1}%
+\edef\csv@startang{\number\c@csvstartangle}%
+\csv@computeangles{#2}{#3}%
+\setcounter{csvstartangle}{\csv@startang}%
+\begin{tikzpicture}%
+\@@pieapplyCSVfile[\csv@startrow]{#3}{%
+\csvpiesegment{#2}}%
+\end{tikzpicture}%
+}}
+\newcommand*{\csvpiesegment}[1]{%
+\setcounter{csvstartangle}{%
+\csname csv@sang@\romannumeral\c@csvrownumber\endcsname}%
+\setcounter{csvangle}{%
+\csname csv@angle@\romannumeral\c@csvrownumber\endcsname}%
+\setcounter{csvendangle}{\value{csvangle} + \value{csvstartangle}}%
+\setcounter{csvangle}{%
+\csname csv@cut@angle\romannumeral\c@csvrownumber\endcsname}%
+\ifthenelse{\value{csvangle}>180}{\addtocounter{csvangle}{-360}}{}%
+\edef\@csv@shift{(\number\c@csvangle:%
+\csname csv@cut@len\romannumeral\c@csvrownumber\endcsname)}%
+\setcounter{csvangle}{%
+\csname csv@angle@\romannumeral\c@csvrownumber\endcsname/2
++\value{csvstartangle}}%
+\begin{scope}[shift={\@csv@shift}]%
+\fill[color=\csvpiesegcolname\c@csvrownumber] (0,0) --
+(\thecsvstartangle:\csvradius)
+arc (\thecsvstartangle:\thecsvendangle:\csvradius) -- cycle;
+\ifthenelse{\(\value{csvangle}>90 \and \value{csvangle}<270\)
+\TE@or \value{csvangle}<-90}{%
+\setcounter{csvstartangle}{\value{csvangle}-180}%
+\draw (\thecsvangle:\csvinner)
+node[left,rotate=\thecsvstartangle]{\csvpieinnerlabel};
+\draw (\thecsvangle:\csvouter)
+node[left,rotate=\thecsvstartangle]{\csvpieouterlabel};
+}{%
+\draw (\thecsvangle:\csvinner)
+node[right,rotate=\thecsvangle]{\csvpieinnerlabel};
+\draw (\thecsvangle:\csvouter)
+node[right,rotate=\thecsvangle]{\csvpieouterlabel};
+}%
+\end{scope}%
+}
+\newcommand*{\csv@computeangles}[2]{%
+\@@pieapplyCSVfile[\csv@startrow]{#2}{%
+\csvsetsegmentparams{\c@csvrownumber}{#1}%
+}%
+\ifthenelse{\equal{\csvpiecutaways}{}}{}{\csvcomputeoffsets}}
+\newcommand*{\csvcomputeoffsets}{%
+\@for\csv@row:=\csvpiecutaways\do{%
+\expandafter\@csv@set@off\csv@row-\relax
+}}
+\def\@csv@set@off#1-#2\relax{%
+\ifthenelse{\equal{#2}{}}{%
+\@@csv@set@off{#1}}{%
+\@@csv@set@offr#1-#2\relax}%
+}
+\newcommand*{\@@csv@set@off}[1]{%
+\setcounter{csvangle}{%
+\csname csv@angle@\romannumeral#1\endcsname/2
++ \csname csv@sang@\romannumeral#1\endcsname}%
+\expandafter\xdef\csname csv@cut@angle\romannumeral#1\endcsname{%
+\number\c@csvangle}%
+\expandafter
+\gdef\csname csv@cut@len\romannumeral\csv@row\endcsname{%
+\csvcutawayoffset}%
+}
+\newcount\@csv@seg
+\def\@@csv@set@offr#1-#2-\relax{%
+\ifnum#1>#2\relax
+\PackageError{csvpie}{Segment ranges must go in ascending
+order}{Try #2-#1 instead of #1-#2}%
+\else
+\setcounter{csvangle}{0}%
+\@csv@seg=#1\relax
+\whiledo{\not\(\@csv@seg > #2\)}{%
+\addtocounter{csvangle}{%
+\csname csv@angle@\romannumeral\@csv@seg\endcsname}%
+\advance\@csv@seg by 1}%
+\setcounter{csvangle}{\value{csvangle}/2
++ \csname csv@sang@\romannumeral#1\endcsname}%
+\@csv@seg=#1\relax
+\whiledo{\not\(\@csv@seg > #2\)}{%
+\expandafter\xdef\csname csv@cut@angle\romannumeral\@csv@seg\endcsname{%
+\number\c@csvangle}%
+\expandafter
+\gdef\csname csv@cut@len\romannumeral\@csv@seg\endcsname{%
+\csvcutawayoffset}%
+\advance\@csv@seg by 1}%
+\fi
+}
+\newcommand*{\csvsetsegmentparams}[2]{%
+\ifthenelse{\value{csvstartangle}>180}{%
+\addtocounter{csvstartangle}{-360}}{}%
+\ifthenelse{\value{csvstartangle}<-180}{%
+\addtocounter{csvstartangle}{360}}{}%
+\expandafter
+\xdef\csname csv@sang@\romannumeral#1\endcsname{%
+\number\c@csvstartangle}%
+\setcounter{csvangle}{360*\real{#2}/\value{csvpietotal}}%
+\addtocounter{csvstartangle}{\value{csvangle}}%
+\expandafter
+\xdef\csname csv@angle@\romannumeral#1\endcsname{%
+\number\c@csvangle}%
+\expandafter
+\gdef\csname csv@cut@angle\romannumeral#1\endcsname{0}%
+\expandafter
+\gdef\csname csv@cut@len\romannumeral#1\endcsname{0cm}%
+}
+\endinput
+%%
+%% End of file `csvpie.sty'.
diff --git a/Master/texmf-dist/tex/latex/csvtools/csvsort.sty b/Master/texmf-dist/tex/latex/csvtools/csvsort.sty
new file mode 100644
index 00000000000..4dad7d27e20
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/csvtools/csvsort.sty
@@ -0,0 +1,322 @@
+%%
+%% This is file `csvsort.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% csvtools.dtx (with options: `csvsort.sty,package')
+%% Copyright (C) 2007 Nicola Talbot, all rights reserved.
+%% If you modify this file, you must change its name first.
+%% You are NOT ALLOWED to distribute this file alone. You are NOT
+%% ALLOWED to take money for the distribution or use of either this
+%% file or a changed version, except for a nominal charge for copying
+%% etc.
+%% \CharacterTable
+%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+%% Digits \0\1\2\3\4\5\6\7\8\9
+%% Exclamation \! Double quote \" Hash (number) \#
+%% Dollar \$ Percent \% Ampersand \&
+%% Acute accent \' Left paren \( Right paren \)
+%% Asterisk \* Plus \+ Comma \,
+%% Minus \- Point \. Solidus \/
+%% Colon \: Semicolon \; Less than \<
+%% Equals \= Greater than \> Question mark \?
+%% Commercial at \@ Left bracket \[ Backslash \\
+%% Right bracket \] Circumflex \^ Underscore \_
+%% Grave accent \` Left brace \{ Vertical bar \|
+%% Right brace \} Tilde \~}
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{csvsort}[2007/07/03 v1.0 (NLCT)]
+\@ifundefined{compare}{\input{compare}}{}
+\newif\if@csv@ishigher
+\newcommand{\csv@alphaascendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\csvsort@verbose{Comparing \@csv@keya\space and \@csv@keyb}%
+\edef\@csvsrt@result{\noexpand\compare{\@csv@keya}{\@csv@keyb}}%
+\ifnum\@csvsrt@result=1\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+\newcommand{\csv@alphadescendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\csvsort@verbose{Comparing \@csv@keya\space and \@csv@keyb}%
+\edef\@csvsrt@result{\noexpand\compare{\@csv@keya}{\@csv@keyb}}%
+\ifnum\@csvsrt@result=-1\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+\newcommand{\csv@numericascendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\if\relax\@csv@keya\relax\def\@csv@keya{0}\fi
+\if\relax\@csv@keyb\relax\def\@csv@keyb{0}\fi
+\csvsort@verbose{Comparing \number\@csv@keya\space and \number\@csv@keyb}%
+\ifnum\@csv@keya>\@csv@keyb\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+\newcommand{\csv@numericdescendingcompare}[2]{%
+\@csv@extractkey#1{\@csv@keya}%
+\@csv@extractkey#2{\@csv@keyb}%
+\if\relax\@csv@keya\relax\def\@csv@keya{0}\fi
+\if\relax\@csv@keyb\relax\def\@csv@keyb{0}\fi
+\csvsort@verbose{Comparing \number\@csv@keya\space and \number\@csv@keyb}%
+\ifnum\@csv@keya<\@csv@keyb\relax
+ \@csv@ishighertrue
+\else
+ \@csv@ishigherfalse
+\fi}
+\def\@csv@extractkey#1#2#3{\def#3{#1}}
+\def\@csv@extractdata#1#2#3{\def#3{#2}}
+\let\csv@compare\csv@alphaascendingcompare
+\RequirePackage{xkeyval}
+\define@boolkey{csvsort.sty}[csvsrt]{verbose}[true]{}
+\csvsrtverbosetrue
+\newcommand{\csvsort@verbose}[1]{%
+\ifcsvsrtverbose\typeout{#1}\fi}
+\define@choicekey{csvsort.sty}{sort}[\val\nr]{alphabetical,numerical,%
+alphabetical ascending,numerical ascending,%
+alphabetical descending,numerical descending,%
+alphabeticalascending,alphabeticaldescending,%
+numericalascending,numericaldescending}{%
+\ifcase\nr
+ % alphabetical (ascending)
+ \let\csv@compare\csv@alphaascendingcompare
+ \or
+ % numerical (ascending)
+ \let\csv@compare\csv@numericascendingcompare
+ \or
+ % alphabetical ascending
+ \let\csv@compare\csv@alphaascendingcompare
+ \or
+ % numerical ascending
+ \let\csv@compare\csv@numericascendingcompare
+ \or
+ % alphabetical descending
+ \let\csv@compare\csv@alphadescendingcompare
+ \or
+ % numerical descending
+ \let\csv@compare\csv@numericdescendingcompare
+ \or
+ % alphabeticalascending
+ \let\csv@compare\csv@alphaascendingcompare
+ \or
+ % alphabetical descending
+ \let\csv@compare\csv@alphadescendingcompare
+ \or
+ % numericalascending
+ \let\csv@compare\csv@numericascendingcompare
+ \or
+ % numericaldescending
+ \let\csv@compare\csv@numericdescendingcompare
+\fi}
+\newcommand{\csv@sortvariable}{\field{1}}
+\define@key{csvsort.sty}{variable}{%
+\renewcommand{\csv@sortvariable}{#1}}
+\newcounter{sfirstdataline}
+\setcounter{sfirstdataline}{1}
+\define@key{csvsort.sty}{sfirstdataline}{%
+\setcounter{sfirstdataline}{#1}}
+\newcounter{firstdataline}
+\setcounter{firstdataline}{2}
+\define@key{csvsort.sty}{firstdataline}{%
+\setcounter{firstdataline}{#1}}
+\ProcessOptionsX
+\RequirePackage{csvtools}
+\RequirePackage{xfor}
+\newcommand{\csv@insertionsort}[1]{%
+\let\@csv@sortedlist\relax
+\@for\@csv@listelement:=#1\do{%
+\if\@csv@sortedlist\relax
+ \expandafter\toks@\expandafter{\@csv@listelement}%
+ \edef\@csv@sortedlist{\the\toks@}%
+\else
+ \expandafter\@csv@insert@into\expandafter
+ {\@csv@listelement}{\@csv@sortedlist}%
+\fi}\let#1\@csv@sortedlist}
+\newcommand\@csv@insert@into[2]{%
+\let\@csv@tmplist\relax
+\@for\@sort@list@element:=#2\do{%
+ \expandafter\csv@compare\expandafter{\@sort@list@element}{#1}%
+ \if@csv@ishigher
+ \toks@{#1}%
+ \if\relax\@csv@tmplist
+ \edef\@csv@tmplist{\the\toks@,\@sort@list@element}%
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\the\toks@,\@sort@list@element}%
+ \fi
+ \@endfortrue
+ \else
+ \if\relax\@csv@tmplist
+ \edef\@csv@tmplist{\@sort@list@element}%
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\@sort@list@element}%
+ \fi
+ \fi
+}%
+\if@endfor
+ \ifx\@forremainder\@empty
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\@forremainder}%
+ \fi
+\else
+ \toks@{#1}%
+ \if\relax\@csv@tmplist
+ \edef\@csv@tmplist{\the\toks@}%
+ \else
+ \edef\@csv@tmplist{\@csv@tmplist,\the\toks@}%
+ \fi
+\fi
+\@endforfalse
+\let#2\@csv@tmplist
+}
+\newcommand{\sortapplyCSVfile}{%
+\@ifstar\@ssortapplyCSVfile\@sortapplyCSVfile}
+\newcommand{\@ssortapplyCSVfile}[3][]{%
+\bgroup
+\setkeys{csvsort.sty}{#1}%
+\def\@csv@list{}%
+\@sapplyCSVfile[\c@sfirstdataline]{#2}{%
+\edef\csv@key{\csv@sortvariable}%
+\if\relax\@csv@list\relax
+\protected@xdef\@csv@list{{\csv@key}{\csvline}}%
+\else
+\protected@xdef\@csv@list{\@csv@list,{\csv@key}{\csvline}}%
+\fi
+}%
+\@ssortapplyCSVdata{\@csv@list}{#3}%
+\egroup}
+\newcommand{\@sortapplyCSVfile}[3][]{%
+\bgroup
+\setkeys{csvsort.sty}{#1}%
+\def\@csv@list{}%
+\@applyCSVfile[\c@firstdataline]{#2}{%
+\edef\csv@key{\csv@sortvariable}%
+\if\relax\@csv@list\relax
+\protected@xdef\@csv@list{{\csv@key}{\csvline}}%
+\else
+\protected@xdef\@csv@list{\@csv@list,{\csv@key}{\csvline}}%
+\fi
+}%
+\@sortapplyCSVdata{\@csv@list}{#3}%
+\egroup}
+\newcommand{\sortapplyCSVdata}{%
+\@ifstar\@ssortapplyCSVdata\@sortapplyCSVdata}
+\newcommand{\@ssortapplyCSVdata}[3][\relax]{%
+\bgroup
+\if\relax#1\relax\else\setkeys{csvsort.sty}{sort=#1}\fi
+\csv@insertionsort{#2}%
+\c@csvrownumber=0\relax
+\@for\@csv@element:=#2\do{%
+\expandafter\@csv@extractdata\@csv@element\csvline
+\expandafter\toks@\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\toks@\@csvseparator}%
+\long\edef\@csvlin@{\@csvseparator\csvline\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\expandafter\toks@\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\toks@}%
+}%
+\ifthenelse{\not\equal{\csvline}{}}{%
+\refstepcounter{csvrownumber}%
+#3}{}%
+}%
+\egroup
+}
+\newcommand{\@sortapplyCSVdata}[3][\relax]{%
+\bgroup
+\if\relax#1\relax\else\setkeys{csvsort.sty}{sort=#1}\fi
+\csv@insertionsort{#2}%
+\c@csvrownumber=0\relax
+\@for\@csv@element:=#2\do{%
+\expandafter\@csv@extractdata\@csv@element\csvline
+\expandafter\toks@\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\toks@\@csvseparator}%
+\long\edef\@csvlin@{\@csvseparator\csvline\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\expandafter\toks@\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\toks@}%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\expandafter\xdef\csname insert\@fieldlabel\endcsname{\the\toks@}%
+}%
+\ifthenelse{\not\equal{\csvline}{}}{%
+\refstepcounter{csvrownumber}%
+#3}{}%
+}%
+\egroup
+}
+\newcommand{\sortCSVtotabular}[6][]{%
+\@sortCSVtotabular[#1]{#2}{#3}{#4}{#5}{#6}{tabular}}
+\newcommand{\sortCSVtolongtable}[6][]{%
+\@sortCSVtotabular[#1]{#2}{#3}{#4}{#5}{#6}{longtable}}
+\newcommand{\@sortCSVtotabular}[7][]{%
+\bgroup
+\setkeys{csvsort.sty}{#1}%
+\def\@csv@list{}%
+\@applyCSVfile[\c@firstdataline]{#2}{%
+\edef\csv@key{\csv@sortvariable}%
+\if\relax\@csv@list\relax
+\protected@xdef\@csv@list{{\csv@key}{\csvline}}%
+\else
+\protected@xdef\@csv@list{\@csv@list,{\csv@key}{\csvline}}%
+\fi
+}%
+\sortCSVdatatotabular{\c@csvrownumber}{\@csv@list}{#3}{#4}{#5}{#6}{#7}%
+\egroup
+}
+\newcommand{\sortCSVdatatotabular}[7]{%
+\maxlines=#1\relax
+\csv@insertionsort{#2}%
+\csvlastbutone=\maxlines
+\advance\csvlastbutone by -1\relax
+\c@csvrownumber=0\relax
+\c@csvlinenum=0\relax
+\def\@r@wh{#4}\def\@r@w{}\def\@r@wl{}%
+\@for\@csv@element:=#2\do{%
+\expandafter\@csv@extractdata\@csv@element\csvline
+\expandafter\toks@\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\toks@\@csvseparator}%
+\long\edef\@csvlin@{\@csvseparator\csvline\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\expandafter\toks@\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\toks@}%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\expandafter\xdef\csname insert\@fieldlabel\endcsname{\the\toks@}%
+}%
+\refstepcounter{csvrownumber}%
+\refstepcounter{csvlinenum}%
+\ifnum\c@csvrownumber=\maxlines
+ \protected@edef\@r@wl{#6}%
+\else
+ \expandafter\toks@\expandafter{\@r@w}
+ \protected@edef\@r@w{\the\toks@#5}%
+\fi
+}%
+\begin{#7}{#3}%
+\@r@wh
+\@r@w
+\@r@wl
+\end{#7}%
+}
+\endinput
+%%
+%% End of file `csvsort.sty'.
diff --git a/Master/texmf-dist/tex/latex/csvtools/csvtools.sty b/Master/texmf-dist/tex/latex/csvtools/csvtools.sty
new file mode 100644
index 00000000000..87711ecc2e9
--- /dev/null
+++ b/Master/texmf-dist/tex/latex/csvtools/csvtools.sty
@@ -0,0 +1,346 @@
+%%
+%% This is file `csvtools.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% csvtools.dtx (with options: `csvtools.sty,package')
+%% Copyright (C) 2007 Nicola Talbot, all rights reserved.
+%% If you modify this file, you must change its name first.
+%% You are NOT ALLOWED to distribute this file alone. You are NOT
+%% ALLOWED to take money for the distribution or use of either this
+%% file or a changed version, except for a nominal charge for copying
+%% etc.
+%% \CharacterTable
+%% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
+%% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
+%% Digits \0\1\2\3\4\5\6\7\8\9
+%% Exclamation \! Double quote \" Hash (number) \#
+%% Dollar \$ Percent \% Ampersand \&
+%% Acute accent \' Left paren \( Right paren \)
+%% Asterisk \* Plus \+ Comma \,
+%% Minus \- Point \. Solidus \/
+%% Colon \: Semicolon \; Less than \<
+%% Equals \= Greater than \> Question mark \?
+%% Commercial at \@ Left bracket \[ Backslash \\
+%% Right bracket \] Circumflex \^ Underscore \_
+%% Grave accent \` Left brace \{ Vertical bar \|
+%% Right brace \} Tilde \~}
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{csvtools}[2007/07/03 v1.24 (NLCT)]
+\RequirePackage{ifthen}
+\RequirePackage{longtable}
+\newcommand*{\@csvseparator}{,}
+\newcommand*{\setcsvseparator}[1]{%
+\renewcommand*{\@csvseparator}{#1}%
+\construct@lopoff{#1}%
+\@construct@qlopoff{#1}%
+\@construct@lopoff{#1}}
+\newcommand*{\extractentry}[2]{%
+\expandafter\csvlopoff#1\to{#1}{#2}}
+\edef\construct@lopoff#1{%
+\noexpand\long\noexpand\def\noexpand\csvlopoff#1##1##2\noexpand\to##3##4{%
+\noexpand\ifx"##1\noexpand\relax
+\noexpand\@csv@qlopoff#1##1##2\noexpand\to##3##4\relax
+\noexpand\else
+\noexpand\@csv@lopoff#1##1##2\noexpand\to##3##4\relax
+\noexpand\fi
+}}
+\edef\@construct@qlopoff#1{%
+\noexpand\long\noexpand\def\noexpand\@csv@qlopoff#1"##1"#1##2\noexpand\to##3##4{%
+\noexpand\def##4{##1}\noexpand\def##3{#1##2}}}
+\edef\@construct@lopoff#1{%
+\noexpand\long\noexpand\def\noexpand\@csv@lopoff#1##1#1##2\noexpand\to##3##4{%
+\noexpand\def##4{##1}\noexpand\def##3{#1##2}}}
+\setcsvseparator{,}
+\newread\csvfile
+\newif\ifmore
+\newcount\c@field
+\newcount\c@maxfields
+\newcounter{csvlinenum}
+\newcount\maxlines
+\newcount\csvlastbutone
+\newcounter{csvrownumber}
+\toksdef\csv@tb=2
+\newcommand{\field}[1]{\csname @field\romannumeral#1\endcsname}
+\newcommand{\setcsvfieldlabel}[2]{%
+\expandafter\def\csname @fieldlabel\romannumeral#1\endcsname{#2}}
+\newcommand{\insertbyname}[1]{\csname insert#1\endcsname}
+\newcommand{\trim}[1]{\def\@trmstr{}%
+\def\csv@trmarg{#1}%
+\if\par\csv@trmarg
+\else
+\expandafter\@trim#1\end
+\let#1\@trmstr
+\fi
+}
+\long\def\@trim#1 \end{\def\@trmstr{#1}}
+\newcommand{\applyCSVfile}{\@ifstar\@sapplyCSVfile\@applyCSVfile}
+\newcommand{\@sapplyCSVfile}[3][1]{%
+\IfFileExists{#2}{%
+\openin\csvfile=#2
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+{\c@csvlinenum=1\relax
+\global\c@csvrownumber=0\relax
+\loop
+\read\csvfile to\csvline
+\advance\c@csvlinenum by 1\relax
+\ifnum\c@csvlinenum>#1\relax
+\trim{\csvline}%
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator} \and
+\not\equal{\@csvlin@}{\@csvseparator\@csvseparator} \and
+\not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname @field\romannumeral\c@field\endcsname{%
+\the\csv@tb}%
+}%
+\ifthenelse{\not\equal{\csvline}{\par} \and
+\not\equal{\csvline}{}}{%
+\refstepcounter{csvrownumber}\relax
+#3}{}%
+\fi
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat}%
+\closein\csvfile
+\fi
+}{\PackageError{csvtools}{Can't find file '#2'}{}}%
+}
+\newcommand{\@applyCSVfile}[3][2]{%
+\ifnum#1<2\relax
+\PackageError{csvtools}{Header line required}{The optional
+argument to `\string\applyCSVfile' needs to be > 1. The header
+line should be on line 1}%
+\else
+\IfFileExists{#2}{%
+\openin\csvfile=#2
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\global\c@csvlinenum=1\relax
+\global\c@csvrownumber=0\relax
+\global\c@maxfields=0\relax
+{\loop
+\read\csvfile to\csvline
+\trim{\csvline}%
+\ifnum\c@csvlinenum=1\relax
+\ifthenelse{\not\equal{\csvline}{\par} \and
+\not\equal{\csvline}{}}{%
+\csv@tb=\expandafter{\csvline}\relax
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\advance\c@field by 1\relax
+\csv@tb=\expandafter{\param}\relax
+\expandafter
+\xdef\csname @fieldlabel\romannumeral\c@field\endcsname{\the\csv@tb}%
+}%
+\c@maxfields=\c@field
+}{%
+\PackageError{csvtools}{Header line missing in file #2}{Header
+line required on line 1}}%
+\fi
+\c@field=0\relax
+\whiledo{\c@field < \c@maxfields}{%
+\advance\c@field by 1\relax
+\expandafter\let\csname @field\romannumeral\c@field\endcsname\relax%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\ifthenelse{\equal{\@fieldlabel}{}
+\TE@or \equal{\@fieldlabel}{penalties}
+\TE@or \equal{\@fieldlabel}{byname}}{\PackageError{csvtools}{%
+\string\insert\@fieldlabel \space already defined}{%
+You can't have the label '\@fieldlabel' in your header row.}}{}%
+\expandafter\let\csname insert\@fieldlabel\endcsname\relax%
+}%
+\advance\c@csvlinenum by 1\relax
+\ifnum\c@csvlinenum>#1\relax
+\csv@tb=\expandafter{\csvline}\relax
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field=0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}\relax
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname @field\romannumeral\c@field\endcsname{\the\csv@tb}%
+\edef\@fieldlabel{%
+\csname @fieldlabel\romannumeral\c@field\endcsname}%
+\ifthenelse{\equal{\@fieldlabel}{}
+\TE@or \equal{\@fieldlabel}{penalties}
+\TE@or \equal{\@fieldlabel}{byname}}{\PackageError{csvtools}{%
+\string\insert\@fieldlabel \space already defined}{%
+You can't have the label '\@fieldlabel' in your header row.}}{}%
+\expandafter\xdef\csname insert\@fieldlabel\endcsname{\the\csv@tb}%
+}%
+\ifthenelse{\not\equal{\csvline}{\par}
+\and \not\equal{\csvline}{}}{%
+\global\advance\c@csvrownumber by 1\relax
+#3}{}%
+\fi
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat}%
+\closein\csvfile
+\fi
+}{\PackageError{csvtools}{Can't find file '#2'}{}}%
+\fi
+}
+\newcommand{\CSVtotabular}[5]{%
+\openin\csvfile=#1
+\c@csvlinenum=0\relax
+\loop
+\advance\c@csvlinenum by 1\relax
+\read\csvfile to\csvline
+\expandafter
+\xdef\csname @csvline\romannumeral\c@csvlinenum\endcsname{\csvline}%
+\ifthenelse{\not\equal{\csvline}{\par}}{\trim{\csvline}}{}%
+\ifnum\c@csvlinenum=1\relax
+\csv@tb=\expandafter{\csvline}
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}%
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}%
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter\xdef\csname insert\the\csv@tb\endcsname{%
+\noexpand\field{\the\c@field}}%
+}%
+\fi
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname @l\romannumeral\c@csvlinenum @field\romannumeral\c@field\endcsname{\the\csv@tb}%
+}%
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat
+\closein\csvfile
+{%
+\def\field##1{%
+\csname @l\romannumeral\c@csvlinenum @field\romannumeral##1\endcsname}%
+\def\@r@wh{\begin{tabular}{#2}#3}%
+\def\@r@w{#4}%
+\def\@r@wl{#5\end{tabular}}%
+\maxlines=\c@csvlinenum
+\advance\maxlines by -1\relax
+\csvlastbutone=\maxlines
+\advance\csvlastbutone by -1\relax
+\c@csvlinenum=1\relax
+\setcounter{csvrownumber}{0}\relax
+\whiledo{\not{\c@csvlinenum>\maxlines}}{%
+\ifthenelse{\expandafter\equal{%
+\csname @csvline\romannumeral\c@csvlinenum\endcsname}{\par}}%
+{\relax}{%
+\ifnum\c@csvlinenum=1\relax
+\@r@wh
+\else
+\refstepcounter{csvrownumber}%
+\ifnum\c@csvlinenum=\maxlines\@r@wl\else\@r@w\fi
+\fi}%
+\global\advance\c@csvlinenum by 1\relax
+}\relax
+}}
+\newcommand{\CSVtolongtable}[5]{%
+\openin\csvfile=#1
+\c@csvlinenum=0\relax
+\loop
+\advance\c@csvlinenum by 1\relax
+\read\csvfile to\csvline
+\expandafter
+\xdef\csname @csvline\romannumeral\c@csvlinenum\endcsname{\csvline}%
+\ifthenelse{\not\equal{\csvline}{\par}}{\trim{\csvline}}{}%
+\ifnum\c@csvlinenum=1\relax
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname insert\the\csv@tb\endcsname{%
+\noexpand\field{\the\c@field}}%
+}%
+\fi
+\csv@tb=\expandafter{\csvline}%
+\edef\@csvlin@{\@csvseparator\the\csv@tb\@csvseparator}%
+\c@field = 0\relax
+\whiledo{\not\equal{\@csvlin@}{\@csvseparator\par\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator\@csvseparator}
+\and \not\equal{\@csvlin@}{\@csvseparator}}{%
+\extractentry{\@csvlin@}{\param}%
+\csv@tb=\expandafter{\param}%
+\advance\c@field by 1\relax
+\expandafter
+\xdef\csname @l\romannumeral\c@csvlinenum @field\romannumeral\c@field\endcsname{\the\csv@tb}%
+}%
+\ifeof\csvfile\morefalse\else\moretrue\fi
+\ifmore
+\repeat
+\closein\csvfile
+{\def\field##1{%
+\csname @l\romannumeral\c@csvlinenum @field\romannumeral##1\endcsname}%
+\def\@r@wh{\begin{longtable}{#2}#3}%
+\def\@r@w{#4}%
+\def\@r@wl{#5\end{longtable}}%
+\maxlines=\c@csvlinenum
+\advance\maxlines by -1\relax
+\csvlastbutone=\maxlines
+\advance\csvlastbutone by -1\relax
+\c@csvlinenum=1\relax
+\setcounter{csvrownumber}{0}\relax
+\whiledo{\not{\c@csvlinenum>\maxlines}}{%
+\ifthenelse{\expandafter\equal{%
+\csname @csvline\romannumeral\c@csvlinenum\endcsname}{\par}}%
+{\relax}{%
+\ifnum\c@csvlinenum=1\relax
+\@r@wh
+\else
+\refstepcounter{csvrownumber}%
+\ifnum\c@csvlinenum=\maxlines\@r@wl\else\@r@w\fi
+\fi}%
+\global\advance\c@csvlinenum by 1\relax
+}\relax
+}}
+\newcommand{\ifnextrowlast}[2]{%
+\ifnum\c@csvlinenum=\csvlastbutone#1\else#2\fi}
+\newcommand{\csvSaveEntry}[2][csvrownumber]{%
+\@ifnextchar[{\@csvSaveEntry{#1}{#2}}{%
+\@csvSaveEntry{#1}{#2}[\insertbyname{#2}]}%
+}
+\def\@csvSaveEntry#1#2[#3]{%
+\edef\@csv@tmp{\insertbyname{#2}}%
+\if\relax\@csv@tmp\relax
+\edef\@entry{#3}%
+\else
+\edef\@entry{\insertbyname{#2}}%
+\fi
+\expandafter
+\xdef\csname #2\romannumeral\value{#1}\endcsname{\@entry}}
+\newcommand{\csvGetEntry}[2]{%
+\csname #2\romannumeral\value{#1}\endcsname}
+\endinput
+%%
+%% End of file `csvtools.sty'.
diff --git a/Master/tlpkg/bin/ctan2tds b/Master/tlpkg/bin/ctan2tds
index 9395330f0ac..eddf9075ce2 100755
--- a/Master/tlpkg/bin/ctan2tds
+++ b/Master/tlpkg/bin/ctan2tds
@@ -114,8 +114,7 @@ chdir $startdir || die "chdir($startdir) failed: $!"; # back to raw
'coptic', "die 'skipping, it has been replaced by cbcoptic'",
'corridx', "die 'skipping, Pascal source'",
'csplain', "die 'skipping, too hard to automate'",
- 'csvtools', "die 'skipping, obsolete on CTAN'",
-# 'csvtools', "&MAKEflatten",
+ 'csvtools', "&MAKEflatten",
'ctable', "&MAKEflatten",
'ctib', "&MAKEflatten",
'cweb', "die 'skipping, programs'",
diff --git a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
index 07aea466ea5..cc56cacb1d5 100644
--- a/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
+++ b/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
@@ -91,6 +91,7 @@ depend coverpage
depend crossreference
depend crosswrd
depend csquotes
+depend csvtools
depend cuisine
depend currvita
depend cursor
diff --git a/Master/tlpkg/tlpsrc/csvtools.tlpsrc b/Master/tlpkg/tlpsrc/csvtools.tlpsrc
new file mode 100644
index 00000000000..370ee20a8ff
--- /dev/null
+++ b/Master/tlpkg/tlpsrc/csvtools.tlpsrc
@@ -0,0 +1,2 @@
+name csvtools
+category Package