From abf0cff974f4b3e51f8beddfd842a58b08ef3458 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Wed, 11 Jan 2006 23:52:03 +0000 Subject: trunk/Master/texmf-dist/source/latex/csvtools git-svn-id: svn://tug.org/texlive/trunk@207 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/source/latex/csvtools/csvtools.dtx | 2436 ++++++++++++++++++++ .../texmf-dist/source/latex/csvtools/csvtools.ins | 17 + 2 files changed, 2453 insertions(+) create mode 100644 Master/texmf-dist/source/latex/csvtools/csvtools.dtx create mode 100644 Master/texmf-dist/source/latex/csvtools/csvtools.ins (limited to 'Master') 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} +% +%\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} +% +% \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} +% +% \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 + +if ($#ARGV != 1) +{ + die "Syntax : $0 \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 () +{ + if (/\\c@([a-zA-Z]+)=\\count/) + { + $counter{$1} = 0; + } +} + +$counter{csvrownumber} = 0; + +close LOGFILE; + +open OUTPUT, ">$OUTPUT" or die; + +%data = (); + +while () +{ + $restofline = $_; + + while ($restofline=~/\\stepcounter(.*)/) + { + $line = $_; + + ($ctr,$restofline,$done) = getnextgroup($1); + + $startline=$.; + + while (!$done) + { + if ($nextline = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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 = ) + { + $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= ) + { + $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= ) + { + $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= ) + { + $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= ) + { + $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 () + { + 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 () + { + 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 () + { + 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 () + { + 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; +% +% \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 -- cgit v1.2.3