summaryrefslogtreecommitdiff
path: root/Master
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-11 23:52:03 +0000
committerKarl Berry <karl@freefriends.org>2006-01-11 23:52:03 +0000
commitabf0cff974f4b3e51f8beddfd842a58b08ef3458 (patch)
treed9d4c9b4a348b9df99101904699e1dfd1befca7e /Master
parentf8e01a46c95d1647c326dcec8aa513f1a40591ec (diff)
trunk/Master/texmf-dist/source/latex/csvtools
git-svn-id: svn://tug.org/texlive/trunk@207 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r--Master/texmf-dist/source/latex/csvtools/csvtools.dtx2436
-rw-r--r--Master/texmf-dist/source/latex/csvtools/csvtools.ins17
2 files changed, 2453 insertions, 0 deletions
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..ff7cc5ebd42
--- /dev/null
+++ b/Master/texmf-dist/source/latex/csvtools/csvtools.dtx
@@ -0,0 +1,2436 @@
+%\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 \~}
+%%\CheckSum{833}
+%</package>
+%\fi
+%\def\filedate{19 Oct 2004}
+%\def\fileversion{1.1}
+%\def\filename{csvtools.dtx}
+%\def\docdate{19 October 2004}
+%\iffalse
+% Doc-Source file to use with LaTeX2e
+% Copyright (C) 2003 Nicola Talbot, all rights reserved.
+%\fi
+%
+% \DeleteShortVerb{\|}
+% \MakeShortVerb{"}
+% \newcounter{example}
+% \newenvironment{example}[1][\relax]{\refstepcounter{example}%
+%\subsection*{Example~\theexample\ \ifx#1\relax\else(#1)\ \fi}%
+% \addcontentsline{loe}{section}{\protect\numberline{\theexample}#1}}{\par\centerline{\rule{2in}{1pt}}\par}
+% \title{csvtools.sty v\fileversion\ : A \LaTeXe\ Package Providing Access to Data Saved in a CSV File}
+% \author{Nicola Talbot}
+% \date{\docdate}
+% \maketitle
+% \tableofcontents
+% \section*{List of Examples}\makeatletter\@starttoc{loe}\makeatother
+% \section{Introduction}
+% 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.
+%
+% \section{Mail Merging and Similar Applications}
+%
+%\DescribeMacro{\applyCSVfile}\noindent
+% "\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 "\applyCSVfile" should
+% be used, otherwise the starred version "\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...}"\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 "\insertName", "\insertAddress",
+% "\insertTime" and "\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.\ "Full Name", then you will need to use
+% \DescribeMacro{\insertbyname}"\insertbyname{"\meta{text}"}",
+% e.g.\ "\insertbyname{Full Name}".
+%
+% \begin{example}[Mail Merging]\label{ex:mail}
+% Suppose there is a file called "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:
+%\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 "\insertbyname{Name}" etc instead
+% of "\insertName" etc. Also note that you need to specify the
+% file extension when specifying the filename.
+%\end{example}
+%
+% \begin{example}[Multiple Figures]\label{ex:ps}
+% Suppose "details.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 "circle.ps", "rectangle.ps"
+% and "triangle.ps" exist, then the following code will
+% generate a figure for each graphics file\footnote{The
+% \texttt{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 "\insertbyname{File}".
+% (See Note~\ref{itm:psbyname} in Section~\ref{sec:drawbacks}.)
+%\end{example}
+%
+%\vspace{10pt}%
+%\DescribeMacro{\applyCSVfile*}\noindent
+%"\applyCSVfile*["\meta{n}"]{"\meta{filename}"}{"\meta{text}"}"\\[10pt]
+% In this case the CSV file has no header row, so
+% there are no "\insert"\meta{identifier} or "\insertbyname{"\meta{label}"}" commands available,
+% instead, the command \DescribeMacro{\field}"\field{"\meta{col}"}" should be used,
+% where \meta{col} is the column number.
+%
+% \begin{example}[Mail Merging using \texttt{\textbackslash field}]
+% Suppose there is a file called "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}
+% then the following code can be used to generate a letter for each person
+% in the CSV file:
+%\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 CSV file into a tabular environment}
+% \DescribeMacro{\CSVtotabular}
+% "\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 "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]\label{ex:tab1}
+% Suppose the file "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 \texttt{\textbackslash CSVtotabular} only
+% puts the data in a \texttt{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}
+% "\ifnextrowlast{"\meta{last-code}"}{"\meta{not-last-code}"}"\\[10pt]
+% The command "\ifnextrowlast" can be used to vary what happens
+% on the last but one row. The following example illustrates
+% this by placing "\hline\hline" after the penultimate row.
+%
+% \begin{example}[Adding Lines]\label{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}
+%\centerline{%
+%\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{table}
+%\end{example}
+%
+% \begin{example}[Added Complexity]\label{ex:tab3}
+% In this example, "\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 "\multicolumn{1}{l|}{}"
+% at the start of the final argument, it is instead
+% placed in the first argument to "\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}
+%\centerline{%
+%\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{table}
+%\end{example}
+%
+% \section{Converting CSV file into longtable environment}
+%\DescribeMacro{\CSVtolongtable}
+%The command "\CSVtolongtable" works in the same way as "\CSVtotabular" but
+% creates a "longtable" environment instead of a "tabular" environment.
+%
+%\begin{example}[Using a longtable environment]
+%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
+%"\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 "\CSVtotabular", "\CSVtolongtable" and "\applyCSVfile" commands, there are two
+% counters, \DescribeMacro{csvlinenum}\DescribeMacro{csvrownumber}%
+% "csvlinenum" and "csvrownumber".
+% The former, "csvlinenum", is the current line number in the CSV
+% file, whereas the latter, "csvrownumber", is the current
+% data row. Of the two counters, "csvrownumber" is likely to be
+% the most useful.
+%
+% \begin{example}[Stripy Table]
+% The package "colortbl" defines the command "\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{blue}}{\\\rowcolor{green}}
+%}{%
+% &
+%\insertbyname{Assignment 1} &
+%\insertbyname{Assignment 2} &
+%\insertTotal
+%}
+%\end{verbatim}
+%\end{example}
+%
+%\begin{example}[More Mail Merging]
+% This is an example of mail merging where the letter reference
+% is generated from the value of "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
+% "\label" command, but you will need some way
+% to make each label unique. Example~\ref{ex:ref1}
+% does this by using "\thecsvrownumber",
+% whereas Example~\ref{ex:ref2} uses "\insert"\meta{identifier}.
+%
+% \begin{example}[Labelling within \texttt{\textbackslash applyCSVfile}]\label{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
+% "\label{fig:pic\thecsvrownumber}", so the first figure generated
+% by this "\applyCSVfile" command will have the label "fig:pic1",
+% the second "fig:pic2" etc.
+%\end{example}
+%
+% \begin{example}[Labelling within \texttt{\textbackslash applyCSVfile}]\label{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:
+% "fig:circle.ps", "fig:rectangle.ps"
+% and "fig:triangle.ps", respectively.
+%\end{example}
+%
+%\begin{example}[Labelling within \texttt{CSVtotabular}]\label{ex:timetogrowth}
+% This example is slightly more complicated.
+% The CSV file, "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
+% "exp:"\meta{Incubation Temperature}":"\meta{Incubation Time}
+% so the first experiment has label "exp:40:120", the
+% second experiment has the label "exp:40:90" and the
+% third experiment has the label "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 \texttt{CSVtotabular}]
+%\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}
+% "\csvSaveEntry["\meta{counter}"]{"\meta{identifier}"}"\\[10pt]
+% where \meta{counter} is a \LaTeX\ counter, by default "csvrownumber",
+% and \meta{identifier} is the header entry. The entry
+% can then be used with the command:\\[10pt]
+% \DescribeMacro{\csvGetEntry}
+% "\csvGetEntry{"\meta{counter}"}{"\meta{identifier}"}"\\[10pt]
+% The following example illustrates the use of these commands.
+%
+% \begin{example}[Saving Entries]\label{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 "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 "exp25a.csv":
+%\begin{verbatim}
+%Time,Logcount
+%0,3.75
+%23,3.9
+%45,4.0
+%\end{verbatim}
+% File "exp25b.csv":
+%\begin{verbatim}
+%Time,Logcount
+%0,3.6
+%60,3.8
+%120,4.0
+%\end{verbatim}
+% File "exp30a.csv":
+%\begin{verbatim}
+%Time,Logcount
+%0,3.73
+%23,3.67
+%60,4.9
+%\end{verbatim}
+%
+% It is not possible to nest "\CSVtotabular", "\CSVtolongtable" and "\applyCSVfile",
+% so if you need to go through "index.csv" and use each file
+% named in there, you can first go through "index.csv" storing
+% the information using "\csvSaveEntry" as follows:
+%\begin{verbatim}
+%\newcounter{maxexperiments}
+%\applyCSVfile{sample5.csv}{%
+%\stepcounter{maxexperiments}
+%\csvSaveEntry{File}
+%\csvSaveEntry{Temperature}
+%\csvSaveEntry{NaCl}
+%\csvSaveEntry{pH}
+%}
+%\end{verbatim}
+% The counter "maxexperiments" simply counts the number of
+% entries in "index.csv".
+% The entries can now be used to generate a table for each
+% file listed in "index.csv" (the "\whiledo" command is
+% defined in the "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 "\csvGetEntry" needs to be "\protect"ed within
+% the "\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{The csvtools.pl Perl Script}
+%
+% Suppose you have several large CSV files, and you have included the information into
+% your document using "\applyCSVfile", "\CSVtolongtable" or "\CSVtotabular", 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 ".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 "csvtools.pl" Perl script. This has the following syntax:\\[5pt]
+% "csvtools.pl" \meta{in-file} \meta{out-file}\\[5pt]
+% where \meta{in-file} is the name of your file that contains the "\applyCSVfile", "\CSVtotabular" etc
+% commands, and \meta{out-file} is a new file which will be created by "csvtools.pl". This new
+% file will be the same as \meta{in-file} except that all occurances of "\applyCSVfile", "\CSVtolongtable" and
+% "\CSVtotabular" will be replaced by the relevant data extracted from the named CSV files.
+%
+%\begin{example}[csvtools.pl --- Aligning Data]
+% Suppose the file "mydoc.tex" contains the code given in Example~\ref{ex:tab1}, with the associated
+% CSV file "sample.csv" also given in that example. Then if you do:
+%\begin{verbatim}
+%csvtools.pl mydoc.tex mydocnew.tex
+%\end{verbatim}
+%the file "mydocnew.tex" will be created which will be identical to "mydoc.tex" except the lines
+% containing the code "\CSVtotabular{sample.csv}{lccc}{"\ldots"}{"\dots"}{"\ldots"}" 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, "csvtools.pl" will substitute all occurrances of "\CSVtolongtable" and "\applyCSVfile".
+%
+%\subsection{Notes}
+%\begin{enumerate}
+%\item The "csvtools.pl" file is bundled up with the code and documentation in the file
+% "csvtools.dtx". It will be extracted along with the code when you \LaTeX\ the
+% installation script "csvtools.ins". If you are using UNIX or Linux etc, you will need
+% to set the permissions so that the file can be executed:
+%\begin{verbatim}
+%chmod u+x csvtools.pl
+%\end{verbatim}
+%If perl is located in a directory other than "/usr/bin/" you will need to edit the
+%first line of "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]
+% "perl csvtools.pl" \meta{in-file} \meta{out-file}
+%
+%\item You must first \LaTeX\ your document before using "csvtools.pl" as it checks the
+% log file for any counters that have been defined.
+%
+%\item "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 "\addtocounter", "\stepcounter", "\refstepcounter" and "\setcounter"
+% but only if they are used explicitly in the named ".tex" file. (It ignores any files
+% that have been included using "\input", "\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 "\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 "\insert" and "\insertpenalties"
+% already exist, so a blank header or a header named "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 "\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 "\insertbyname{File}" doesn't get
+% fully expanded by the time it gets passed to
+% "\includegraphics", and will prevent "\includegraphics" from
+% finding the file. It is possible to get around this using
+% \TeX's "\edef" command:
+%\begin{verbatim}
+%\edef\psfilename{\insertbyname{File}}
+%\centerline{\includegraphics{\psfilename}}
+%\end{verbatim}
+%
+% \item\label{itm:noalign} You can't have commands like "\hline", "\cline"
+% and "\multicolumn" in the first column of the
+% \meta{middle} or \meta{last} code of "\CSVtotabular" or "\CSVtolongtable". If you do, it will generate
+% a "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 "\applyCSVfile", "\CSVtolongtable" and "\CSVtotabular"
+% 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
+% "\csvSaveEntry" on a large file.
+%
+% \item Commas within an entry in a CSV file may cause problems. You will need to enclose
+% the entry in braces, e.g.\ "{Joe Smith, Jr}".
+%
+% \item\label{itm:csvrownumber} In version 1.0, there was an inconsistency with "csvrownumber" within
+%"\applyCSVfile" and "\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 "\applyCSVfile", "\CSVtotabular"
+% and "\CSVtolongtable", "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, "csvrownumber" should always be 1 more than "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{}
+% \section{The Code}
+% \iffalse
+% First we have the driver to get the documentation
+% \begin{macrocode}
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage[colorlinks,bookmarks]{hyperref}
+\begin{document}
+\OnlyDescription
+\DocInput{csvtools.dtx}
+\end{document}
+%</driver>
+% \end{macrocode}
+% \fi
+% At the start of the package, specify that the \LaTeXe\ format is
+% required. And specify the package provided.
+% \begin{macrocode}
+%<*package>
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{csvtools}[2003/12/18 v1.0]
+% \end{macrocode}
+% Conditionals will be needed, so include "ifthen" package
+% \begin{macrocode}
+\RequirePackage{ifthen}
+\RequirePackage{longtable}
+% \end{macrocode}
+% The following lines are modified from `The TeXBook' Appendix D
+% \begin{macrocode}
+\def\lop#1\to#2{\expandafter\lopoff#1\lopoff#1#2}
+\long\def\lopoff,#1,#2\lopoff#3#4{\def#4{#1}\def#3{,#2}}
+% \end{macrocode}
+%
+% Define variables needed later
+% \begin{macrocode}
+\newread\csvfile
+\newif\ifmore
+\newcount\c@field
+\newcounter{csvlinenum}
+\toksdef\ta=0 \toksdef\tb=2
+% \end{macrocode}
+% Define "\field" command. Takes a number as the argument.
+% Used to access the nth field. If there is no nth field
+% command has no effect.
+% \begin{macrocode}
+\newcommand{\field}[1]{\csname @field\romannumeral#1\endcsname}
+% \end{macrocode}
+% Instead of doing, say, "\insertAddress", need to be able to
+% do "\insertbyname{Address}". Useful if the field name
+% contains non-alphabetical characters.
+% \begin{macrocode}
+\newcommand{\insertbyname}[1]{\csname insert#1\endcsname}
+% \end{macrocode}
+%
+% "\read" appends a space at the end of the line, so define
+% command to trim final space.
+% \begin{macrocode}
+\newcommand{\trim}[1]{\def\@trmstr{}\expandafter\@trim#1\end\edef#1{\@trmstr}}
+\def\@trim#1 \end{\def\@trmstr{#1}}
+% \end{macrocode}
+%
+% Define starred version of command
+% \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}
+ \tb=\expandafter{\csvline}
+ \edef\@csvlin@{,\the\tb,}
+ \c@field = 0\relax
+ \whiledo{\not\equal{\@csvlin@}{,\par,} \and \not\equal{\@csvlin@}{,,} \and \not\equal{\@csvlin@}{,}}{%
+ \lop\@csvlin@\to\param
+ \tb=\expandafter{\param}
+ \advance\c@field by 1\relax
+ \expandafter\xdef\csname @field\romannumeral\c@field\endcsname{\the\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}
+% Now define unstarred version of the command
+% \begin{macrocode}
+\newcommand{\@applyCSVfile}[3][2]{%
+\ifnum#1<2
+ \PackageError{csvtools}{Header line required}{The optional argument to `\protect\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
+ {\loop
+ \read\csvfile to\csvline
+ \ifnum\c@csvlinenum=1\relax
+%header line
+ \ifthenelse{\not\equal{\csvline}{\par} \and \not\equal{\csvline}{}}{%
+%trim end of line character
+ \trim{\csvline}
+%delimit start and end with commas
+ \tb=\expandafter{\csvline}
+ \edef\@csvlin@{,\the\tb,}
+%read in each entry
+ \c@field = 0\relax
+ \whiledo{\not\equal{\@csvlin@}{,\par,} \and \not\equal{\@csvlin@}{,,} \and \not\equal{\@csvlin@}{,}}{%
+ \lop\@csvlin@\to\param
+ \advance\c@field by 1\relax
+ \tb=\expandafter{\param}
+ %\expandafter\xdef\csname insert\the\tb\endcsname{\field{\the\c@field}}
+ \expandafter\xdef\csname @fieldlabel\romannumeral\c@field\endcsname{\the\tb}
+ }
+ }{\PackageError{csvtools}{Header line missing in file #2}{Header line required on line 1}}
+ \fi
+ \advance\c@csvlinenum by 1\relax
+ \ifnum\c@csvlinenum>#1\relax
+ \tb=\expandafter{\csvline}
+ \edef\@csvlin@{,\the\tb,}
+ \c@field = 0\relax
+ \whiledo{\not\equal{\@csvlin@}{,\par,} \and \not\equal{\@csvlin@}{,,} \and \not\equal{\@csvlin@}{,}}{%
+ \lop\@csvlin@\to\param
+ \tb=\expandafter{\param}
+ \advance\c@field by 1\relax
+ \expandafter\xdef\csname @field\romannumeral\c@field\endcsname{\the\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.}}{}\relax
+ \expandafter\xdef\csname insert\@fieldlabel\endcsname{\the\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 "\applyCSVfile" to call "\@sapplyCSVfile" if starred version
+% and "\@applyCSVfile" if not starred version
+% \begin{macrocode}
+\newcommand{\applyCSVfile}{\@ifstar\@sapplyCSVfile\@applyCSVfile}
+% \end{macrocode}
+% Define command to convert CSV file into tabular environment.
+% Takes one argument that specifies the argument to the
+% tabular environment.
+% \begin{macrocode}
+\newcount\maxlines
+\newcount\csvlastbutone
+\newcounter{csvrownumber}
+\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
+ \tb=\expandafter{\csvline}
+ \edef\@csvlin@{,\the\tb,}
+ \c@field = 0\relax
+ \whiledo{\not\equal{\@csvlin@}{,\par,} \and \not\equal{\@csvlin@}{,,} \and \not\equal{\@csvlin@}{,}}{%
+ \lop\@csvlin@\to\param
+ \tb=\expandafter{\param}
+ \advance\c@field by 1\relax
+ \expandafter\xdef\csname insert\the\tb\endcsname{\noexpand\field{\the\c@field}}
+ }
+ \fi
+ \tb=\expandafter{\csvline}
+ \edef\@csvlin@{,\the\tb,}
+ \c@field = 0\relax
+ \whiledo{\not\equal{\@csvlin@}{,\par,} \and \not\equal{\@csvlin@}{,,} \and \not\equal{\@csvlin@}{,}}{%
+ \lop\@csvlin@\to\param
+ \tb=\expandafter{\param}
+ \advance\c@field by 1\relax
+ \expandafter\xdef\csname @l\romannumeral\c@csvlinenum @field\romannumeral\c@field\endcsname{\the\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
+%header row
+\@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}
+% \begin{macrocode}
+% \end{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
+ \tb=\expandafter{\csvline}
+ \edef\@csvlin@{,\the\tb,}
+ \c@field = 0\relax
+ \whiledo{\not\equal{\@csvlin@}{,\par,} \and \not\equal{\@csvlin@}{,,} \and \not\equal{\@csvlin@}{,}}{%
+ \lop\@csvlin@\to\param
+ \tb=\expandafter{\param}
+ \advance\c@field by 1\relax
+ \expandafter\xdef\csname insert\the\tb\endcsname{\noexpand\field{\the\c@field}}
+ }
+ \fi
+ \tb=\expandafter{\csvline}
+ \edef\@csvlin@{,\the\tb,}
+ \c@field = 0\relax
+ \whiledo{\not\equal{\@csvlin@}{,\par,} \and \not\equal{\@csvlin@}{,,} \and \not\equal{\@csvlin@}{,}}{%
+ \lop\@csvlin@\to\param
+ \tb=\expandafter{\param}
+ \advance\c@field by 1\relax
+ \expandafter\xdef\csname @l\romannumeral\c@csvlinenum @field\romannumeral\c@field\endcsname{\the\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
+%header row
+\@r@wh
+\else
+\refstepcounter{csvrownumber}%
+\ifnum\c@csvlinenum=\maxlines\@r@wl\else\@r@w\fi
+\fi}%
+\global\advance\c@csvlinenum by 1\relax
+}\relax
+}}
+% \begin{macrocode}
+\newcommand{\ifnextrowlast}[2]{\ifnum\c@csvlinenum=\csvlastbutone#1\else#2\fi}
+% \end{macrocode}
+% \begin{macrocode}
+\newcommand{\csvSaveEntry}[2][csvrownumber]{%
+\edef\@entry{\insertbyname{#2}}%
+\expandafter\xdef\csname #2\romannumeral\value{#1}\endcsname{\@entry}}
+
+\newcommand{\csvGetEntry}[2]{%
+\csname #2\romannumeral\value{#1}\endcsname}
+%</package>
+% \end{macrocode}
+% Perl script
+% \begin{macrocode}
+%<*perl>
+#!/usr/bin/perl
+
+# File : csvtools.pl
+# Author : Dr Nicola Talbot
+# Date : 14 Oct 2004
+# Description : Perl script to accompany csvtools.sty
+# : Allows you to substitute \CSVtotabular, \CSVtolongtable and \applyCSVfile commands with the appropriate LaTeX code
+# Version : 0.5b (18 October 2004).
+
+# 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";
+
+%counter = ();
+
+while (<LOGFILE>)
+{
+ if (/\\c@([a-zA-Z]+)=\\count/)
+ {
+ $counter{$1} = 0;
+ }
+}
+
+$counter{csvrownumber} = 0;
+
+close LOGFILE;
+
+open OUTPUT, ">$OUTPUT" or die;
+
+%data = ();
+
+while (<FILENAME>)
+{
+ $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;
+ }
+
+ if (/^(.*)\\CSVtotabular(.*)$/)
+ {
+ print OUTPUT "$1\n";
+
+ $line = $2;
+
+ ($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 $.\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 \\CSVtotabular 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 \\CSVtotabular 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 \\CSVtotabular fifth argument on line $.\n";
+ }
+ }
+
+ csvtotabular($csvname, $alignment, $FIRST, $MIDDLE, $LAST);
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\CSVtolongtable(.*)$/)
+ {
+ print OUTPUT "$1\n";
+
+ $line = $2;
+
+ ($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 $.\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";
+ }
+ }
+
+ csvtolongtable($csvname, $alignment, $FIRST, $MIDDLE, $LAST);
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\applyCSVfile\*(.*)$/)
+ {
+ print OUTPUT $1;
+
+ $restofline = $2;
+
+ $restofline = eatinitialspaces($restofline);
+ $restofline = eatcomments($restofline);
+
+ $startrow=1;
+
+ 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 $.\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 $.\n";
+ }
+ }
+
+ applyCSVfilestar($csvname, $body, $startrow);
+
+ print OUTPUT "$restofline\n";
+ }
+ elsif (/^(.*)\\applyCSVfile(.*)$/)
+ {
+ print OUTPUT $1;
+
+ $restofline = $2;
+
+ $restofline = eatinitialspaces($restofline);
+ $restofline = eatcomments($restofline);
+
+ $startrow=2;
+
+ if ($restofline=~/^\[(\d+)\](.*)/)
+ {
+ $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 $.\n";
+ }
+ }
+
+ $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 $.\n";
+ }
+ }
+
+ applyCSVfile($csvname, $body, $startrow);
+
+ print OUTPUT "$restofline\n";
+ }
+ else
+ {
+ print OUTPUT;
+ }
+}
+
+sub applyCSVfile
+{
+ my ($CSVFILE,$body,$startrow) = @_;
+
+ print "Converting \\applyCSVfile{$CSVFILE}";
+ print OUTPUT "\% \\applyCSVfile{$CSVFILE}... converted using $0\n";
+ print OUTPUT "\%>> START INSERT\n";
+ print OUTPUT "\\setcounter{csvrownumber}{0}";
+ $counter{csvrownumber} = 0;
+
+ open FH, $CSVFILE or die "Can't open file '$CSVFILE'\n";
+
+ $csvrow=0;
+
+ while (<FH>)
+ {
+ if ($. == 1)
+ {
+ # get header row
+
+ chop;
+
+ @fields = split /,/;
+
+ $numcols = 1;
+
+ foreach $field (@fields)
+ {
+ $idx{$field} = $numcols;
+
+ $numcols++;
+ }
+ }
+ elsif ($. >= $startrow)
+ {
+ next unless /,/;
+
+ chop;
+
+ $csvrow++;
+ $rec = {};
+
+ $HoH[$csvrow] = $rec;
+
+ @entries = split /,/;
+
+ $i = 0;
+
+ foreach $e (@entries)
+ {
+ $rec->{$fields[$i]} = $e;
+ $i++;
+ }
+ }
+ }
+
+ close FH;
+
+ foreach ($row=1; $row <= $csvrow; $row++)
+ {
+ print ".";
+
+ $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;
+
+ $column = $idx{$entry};
+
+ $THISROW =~ s/\\field{$column}/$replacementval/g;
+
+ $THISROW = ifnextrowlast($THISROW, ($row==$csvrow-1));
+ }
+
+ print OUTPUT "\\stepcounter{csvrownumber}$THISROW";
+ $counter{csvrownumber}++;
+ }
+
+ print "\n";
+
+ print OUTPUT "\%<< END INSERT\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 ($restofline[0] 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}";
+ print OUTPUT "\\setcounter{csvrownumber}{0}";
+ $counter{csvrownumber} = 0;
+
+ open FH, $CSVFILE or die "Can't open file '$CSVFILE'\n";
+
+ $csvrow=0;
+
+ while (<FH>)
+ {
+ if ($. >= $startrow)
+ {
+ $csvrow++;
+
+ chop;
+
+ @fields = split /,/;
+
+ $numcols = 1;
+
+ foreach $field (@fields)
+ {
+ $entry[$csvrow][$numcols-1] = $field;
+
+ $numcols++;
+ }
+ }
+ }
+
+ close FH;
+
+ for ($row=0; $row < $csvrow; $row++)
+ {
+ print ".";
+
+ $THISROW = $body;
+
+ for ($column=0; $column < $numcols; $column++)
+ {
+ $replacementval=$entry[$row][$column];
+
+ $THISROW =~ s/\\field{$column}/$replacementval/g;
+
+ $THISROW = ifnextrowlast($THISROW, ($row==$csvrow-1));
+ }
+
+ print OUTPUT "\\stepcounter{csvrownumber}$THISROW";
+ $counter{csvrownumber}++;
+ }
+
+ print "\n";
+
+ print OUTPUT "\%<< END INSERT\n";
+}
+
+sub csvtotabular
+{
+ my ($CSVFILE,$ALIGN,$START,$MID,$END) = @_;
+
+ print "Converting \\CSVtotabular{$CSVFILE}";
+
+ print OUTPUT "\% \\CSVtotabular{$CSVFILE}... converted using $0\n";
+ print OUTPUT "\%>> START INSERT\n";
+
+ print OUTPUT "\\setcounter{csvrownumber}{0}\n";
+ $counter{csvrownumber} = 0;
+ print OUTPUT "\\begin{tabular}{$ALIGN}\n";
+
+ open FH, $CSVFILE or die "Can't open file '$CSVFILE'\n";
+
+ $csvrow=0;
+
+ while (<FH>)
+ {
+ if ($. == 1)
+ {
+ # get header row
+
+ chop;
+
+ @fields = split /,/;
+
+ $numcols = 1;
+
+ foreach $field (@fields)
+ {
+ $idx{$field} = $numcols;
+
+ $numcols++;
+ }
+
+ $csvrow++;
+ $rec = {};
+
+ $HoH[$csvrow] = $rec;
+
+ @entries = split /,/;
+
+ $i = 0;
+
+ foreach $e (@entries)
+ {
+ $rec->{$fields[$i]} = $e;
+ $i++;
+ }
+ }
+ elsif ($. > 1)
+ {
+ next unless /,/;
+
+ chop;
+
+ $csvrow++;
+ $rec = {};
+
+ $HoH[$csvrow] = $rec;
+
+ @entries = split /,/;
+
+ $i = 0;
+
+ foreach $e (@entries)
+ {
+ $rec->{$fields[$i]} = $e;
+ $i++;
+ }
+ }
+ }
+
+ close FH;
+
+ foreach ($row=1; $row <= $csvrow; $row++ )
+ {
+ print ".";
+
+ if ($row == 1)
+ {
+ $THISROW=$START;
+ }
+ elsif ($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));
+ }
+
+ if ($row==1)
+ {
+ print OUTPUT "$THISROW";
+ }
+ else
+ {
+ print OUTPUT "\\refstepcounter{csvrownumber}$THISROW";
+ $counter{csvrownumber}++;
+ }
+ }
+
+ print OUTPUT "\\end{tabular}";
+ print OUTPUT "\%<< END INSERT\n";
+
+ print "\n";
+}
+
+sub csvtolongtable
+{
+ my ($CSVFILE,$ALIGN,$START,$MID,$END) = @_;
+
+ print "Converting \\CSVtolongtable{$CSVFILE}";
+
+ print OUTPUT "\% \\CSVtolongtable{$CSVFILE}... converted using $0\n";
+ print OUTPUT "\%>> START INSERT\n";
+
+ print OUTPUT "\\setcounter{csvrownumber}{0}\n";
+ $counter{csvrownumber} = 0;
+ print OUTPUT "\\begin{longtable}{$ALIGN}\n";
+
+ open FH, $CSVFILE or die "Can't open file '$CSVFILE'\n";
+
+ $csvrow=0;
+
+ while (<FH>)
+ {
+ if ($. == 1)
+ {
+ # get header row
+
+ chop;
+
+ @fields = split /,/;
+
+ $numcols = 1;
+
+ foreach $field (@fields)
+ {
+ $idx{$field} = $numcols;
+
+ $numcols++;
+ }
+
+ $csvrow++;
+ $rec = {};
+
+ $HoH[$csvrow] = $rec;
+
+ @entries = split /,/;
+
+ $i = 0;
+
+ foreach $e (@entries)
+ {
+ $rec->{$fields[$i]} = $e;
+ $i++;
+ }
+ }
+ elsif ($. > 1)
+ {
+ next unless /,/;
+
+ chop;
+
+ $csvrow++;
+ $rec = {};
+
+ $HoH[$csvrow] = $rec;
+
+ @entries = split /,/;
+
+ $i = 0;
+
+ foreach $e (@entries)
+ {
+ $rec->{$fields[$i]} = $e;
+ $i++;
+ }
+ }
+ }
+
+ close FH;
+
+ print "csvrow = $csvrow\n";
+
+ for ($row=1; $row <= $csvrow; $row++)
+ {
+ print ".";
+
+ if ($row == 1)
+ {
+ $THISROW=$START;
+ }
+ elsif ($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));
+ }
+
+ if ($row==1)
+ {
+ print OUTPUT "$THISROW";
+ }
+ else
+ {
+ print OUTPUT "\\refstepcounter{csvrownumber}$THISROW";
+ $counter{csvrownumber}++;
+ }
+ }
+
+ print OUTPUT "\\end{longtable}";
+ 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
+{
+ my ($STR) = @_;
+
+ if (substr($STR,0,1) eq "%")
+ {
+ return "";
+ }
+
+ my $pos=1;
+
+ if (($pos = index($STR, "%", 1)) > -1)
+ {
+ if (not (substr($STR, $pos-1,1) eq "\\"))
+ {
+ return substr($STR,0,$pos);
+ }
+
+ while ((substr($STR, $pos-1,1) eq "\\") and ($pos > 0))
+ {
+ # count how many backlashes come before it.
+
+ $i = $pos-1;
+
+ $numbs = 1;
+
+ while ((substr($STR, $i-1,1) eq "\\") and ($i > 0))
+ {
+ $numbs++;
+ $i--;
+ }
+
+ # is $numbs is odd, we have a \%, otherwise we have \\%
+
+ if ($numbs%2 == 0)
+ {
+ # it's a comment
+
+ return substr($STR,0,$pos);
+ }
+ else
+ {
+ # it's not a comment, carry on looking
+
+ $pos = index($STR, "%", $pos+1);
+ }
+ }
+ }
+
+ return $STR;
+}
+
+sub eatinitialspaces
+{
+ my ($STR) = @_;
+
+ while (substr($STR,0,1) eq "\s")
+ {
+ $STR = substr($STR,1);
+ }
+
+ return $STR;
+}
+
+sub getnextgroup
+{
+ 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 "{")
+ {
+ # 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);
+}
+
+1;
+%</perl>
+% \end{macrocode}
+%\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..a8444bb04e9
--- /dev/null
+++ b/Master/texmf-dist/source/latex/csvtools/csvtools.ins
@@ -0,0 +1,17 @@
+\input docstrip
+
+\preamble
+Copyright (C) 2000 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{csvtools.sty}{\from{csvtools.dtx}{package}}
+ \nopreamble\nopostamble\file{csvtools.pl}{\from{csvtools.dtx}{perl}}}
+
+\endbatchfile