texlive[51857] Master: csvmerge (10aug19)

commits+karl at tug.org commits+karl at tug.org
Sat Aug 10 23:19:47 CEST 2019


Revision: 51857
          http://tug.org/svn/texlive?view=revision&revision=51857
Author:   karl
Date:     2019-08-10 23:19:47 +0200 (Sat, 10 Aug 2019)
Log Message:
-----------
csvmerge (10aug19)

Modified Paths:
--------------
    trunk/Master/tlpkg/bin/tlpkg-ctan-check
    trunk/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc

Added Paths:
-----------
    trunk/Master/texmf-dist/doc/latex/csvmerge/
    trunk/Master/texmf-dist/doc/latex/csvmerge/README
    trunk/Master/texmf-dist/doc/latex/csvmerge/csvmerge.pdf
    trunk/Master/texmf-dist/source/latex/csvmerge/
    trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.dtx
    trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.ins
    trunk/Master/texmf-dist/tex/latex/csvmerge/
    trunk/Master/texmf-dist/tex/latex/csvmerge/csvmerge.sty
    trunk/Master/tlpkg/tlpsrc/csvmerge.tlpsrc

Added: trunk/Master/texmf-dist/doc/latex/csvmerge/README
===================================================================
--- trunk/Master/texmf-dist/doc/latex/csvmerge/README	                        (rev 0)
+++ trunk/Master/texmf-dist/doc/latex/csvmerge/README	2019-08-10 21:19:47 UTC (rev 51857)
@@ -0,0 +1,19 @@
+----------------------------------------------------------------
+    The csvmerge package
+    ====================
+
+    This package is designed to take a bit of TeX code such as
+    a letter or a line on a table and produce multiple copies
+    of it with parts of it filled in from a csv spreadsheet file. 
+    It is useful for mail merges and making tables. It requires
+    minimal configuration of the csv file and is designed for easy 
+    merging with the TeX code. 
+
+    Run `csvmerge.ins' through LaTeX to produce csvmerge.sty.
+    Run `csvmerge.dtx' through LaTeX to produce the documentation.
+
+E-mail: taylor.2 at nd.edu
+Released under the LaTeX Project Public License v1.3c or later
+See http://www.latex-project.org/lppl.txt
+----------------------------------------------------------------
+


Property changes on: trunk/Master/texmf-dist/doc/latex/csvmerge/README
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/doc/latex/csvmerge/csvmerge.pdf
===================================================================
(Binary files differ)

Index: trunk/Master/texmf-dist/doc/latex/csvmerge/csvmerge.pdf
===================================================================
--- trunk/Master/texmf-dist/doc/latex/csvmerge/csvmerge.pdf	2019-08-10 16:06:35 UTC (rev 51856)
+++ trunk/Master/texmf-dist/doc/latex/csvmerge/csvmerge.pdf	2019-08-10 21:19:47 UTC (rev 51857)

Property changes on: trunk/Master/texmf-dist/doc/latex/csvmerge/csvmerge.pdf
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/pdf
\ No newline at end of property
Added: trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.dtx
===================================================================
--- trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.dtx	                        (rev 0)
+++ trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.dtx	2019-08-10 21:19:47 UTC (rev 51857)
@@ -0,0 +1,1198 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2019 by Laurence R Taylor
+% -----------------------------------
+%
+% This file may be distributed and/or modified under the
+% conditions of the LaTeX Project Public License, either version 1.3 
+% of this license or (at your option) any later version.
+% The latest version of this license is in:
+%
+% http://www.latex-project.org/lppl.txt
+%
+% and version 1.3 or later is part of all distributions of LaTeX
+% version 2005/12/01 or later.
+%
+% \fi
+%
+% \iffalse
+%
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{csvmerge}
+\usepackage{hyperref}
+\hypersetup{
+    colorlinks=true,
+    linkcolor=blue,
+    filecolor=magenta,      
+    urlcolor=cyan,
+}
+\DisableCrossrefs
+\CodelineNumbered
+\RecordChanges
+\CheckSum{525}
+\begin{document}
+\DocInput{csvmerge.dtx} 
+\end{document}
+%</driver>
+% \fi
+%
+% 
+% \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         \~}
+%   
+%
+%
+% \changes{v1.0}{?2019?/?07?/?17?}{Initial version} 
+%    \title{csvmerge}
+%    \author{Laurence R Taylor}
+%    \date{August 8, 2019}
+% \maketitle
+%
+% \begin{abstract}
+%  The package |csvmerge.sty| is designed to take a bit of \TeX\ code such as a letter or a line
+%    in a table and produce
+%    multiple copies of it with parts of each copy filled in from a data file. 
+%    It is invoked in the usual manner from a master-file, that is a standard
+%    \LaTeX\ file with 
+%    
+%    \null\noindent\hskip 1in|\documentclass{whatever}|\\
+%    \null\hskip 1in|\usepackage{csvmerge}|\\
+%    \null\hskip 1.5in$\vdots$
+%
+%    The data source is a standard csv file. 
+%    The bit of \TeX\ code resides in a blueprint file. 
+%    The |\usepackage{csvmerge}| can go anywhere in the preamble. 
+% \end{abstract}
+%   \tableofcontents
+%   \def\Hyperlink#1{\hyperlink{#1Description}{\tt \mm #1}}
+%   \def\Hypertarget#1#2{\hypertarget{#1Description}{#2}}
+%   \xdef\mm{$\backslash\hskip-5pt\backslash$}
+% \section{Introduction}
+%
+%    The |csvmerge.sty| merges \TeX\ code with a data file. 
+%    \begin{itemize}
+%    \item 
+%    The \TeX\ code comes from a blueprint file, which looks like
+%    a standard \TeX\ file except it contains no code which should 
+%    go into the preamble of a normal \TeX\ file. 
+%    The blueprint file should also not contain a |\begin{document}| 
+%    nor an |\end{document}|. This stuff goes in the master-file. 
+%    \item The data file is a standard csv file. 
+%    \end{itemize}
+%    One difference between |csvmerge.sty| and other packages which 
+%    merge |csv| data into a \TeX\ file is that the user does not need to do
+%    much with the |csv|-file. As long as the first row contains reasonable 
+%    entries describing the contents of its column you are good to go.
+%    Extra columns are no problem; subsequent rows can be too short
+%    or too long; characters which are special to \TeX\ such as |$| and |&|
+%    can appear in the data; \dots\ 
+%    \noindent More details concerning the |csv|-file can be found in subsection 2.1. 
+%    
+%    The |tex|-file consists of standard \TeX\ code. Each row of the |csv|-file is processed
+%    and you have access to the values of all the entries on that row as well as the row
+%    number. You also can tell if the entry in a particular column is empty.
+%    \noindent More details concerning the |tex|-file can be found in subsection 2.2. 
+%
+%    The main macro, |\mergeFields|, supports two modes. 
+%    In one mode, \emph{stream mode}, the \TeX\ code from the |tex|-file  
+%    is added to the input stream at the location from which |\mergeFields| is invoked. 
+%    In the second mode, \emph{storage mode}, the code is written to a 
+%    temporary file. You can then use the standard \LaTeX\ |\input| to read the 
+%    temporary file back into the master-file. 
+%    
+%    Good models for the two modes are the following. Most mail-merges can be
+%    done in streaming mode. Because \TeX\ is doing rather complicated things behind
+%    the scenes when it is setting a table or a matrix, you are usually better off using
+%    storage mode with your blueprint file containing the code for one line of your table/matrix. 
+%    After the data is generated you can read it back into your table. 
+%    See \hyperlink{subsubsection.B.3.1}{here} for a typical example. 
+%    
+%  \newpage
+% \section{Usage}
+%
+% \DescribeMacro{\mergeFields}
+%    The main macro is |\mergeFields| which takes one argument. 
+% The format is  
+%\begin{verbatim}
+% \mergeFields{
+%    tex={<tex-file>}
+%    csv = {<csv-file>}
+%    tmp = {<tmp-file>}
+%   }
+%\end{verbatim}
+%    The |tmp| entry is not required. If there is none, |mergeFields| operates in 
+%    \emph{streaming} mode, otherwise it acts in \emph{storage} mode. 
+%    The |<prefix-file>| entry should be a path to the corresponding sort of file. 
+%    If the file name has spaces you will need to quote it: life is easier if there are no
+%    spaces in file names. 
+%    The format |prefix = {<prefix-file>}| is quite forgiving: all leading and trailing spaces 
+%    are stripped out so |prefix  =  { <prefix-file>   }| works. 
+%    The three lines can be in any order and do not even need to be on separate lines. 
+%    The extensions of the three files are irrelevant: the |tex|-file contains \TeX\ code  
+%    but it can have an extension of |.txt| (or anything else or none at all) if you prefer.  
+%    All that matters is that 
+%    when \TeX\ reads the file the contents have the proper content. 
+%    If you have a simple project you may be able to complete it just by looking at 
+%    the examples in \hyperlink{appendix.B}{appendix B}. 
+%
+%    \subsection{The data file}
+%    The data file is a |csv| spreadsheet file.
+%    By default the field delimiter is the comma and the 
+%    text delimiter is the double-quotes character. 
+%    This is default behavior for most spreadsheets when
+%    asked to produce a |cvs| file. 
+%    If there are no {\tt "}'s in your |csv|-file there should be no problems.
+%    In some cases you may need a different set of delimiters
+%    and this is supported. 
+%    See \Hyperlink{setDelimitersTabQuote}\ below for more details. 
+%
+%    The entries in the first row should consist solely of \emph{alphanumeric characters, 
+%    punctuation and spaces}. 
+%    Each entry is a \emph{label} for that column. 
+%    Labels need not be unique although they usually are except sometimes there are
+%    several columns with blank labels.
+%
+%    A \emph{field-name} is extracted from a label by deleting all spaces and making all
+%    characters lowercase: e.g. a column labeled |First Name| has a field-name 
+%    |firstname|. Commas are also deleted so a column label of |Last, First Name| 
+%    becomes a field-name of |lastfirstname|. 
+%    Distinct labels can have the same field-name although again 
+%    this seems unlikely except for blank labels. 
+%
+%    Associated to each field-name is a \emph{field-name-macro}. 
+%    This macro is private: its name is found by prepending |@LRT@@| to the field-name. 
+%    When |\mergeFields| is invoked, the data file is read one row at a time. 
+%    All rows after the first are data. 
+%    When a row is read, each entry is peeled off and placed in the field-name-macro 
+%    whose field-name is the one associated to the label for that column 
+%    with |@LRT@| prepended. 
+%    For example, if row one of some column contains |First Name|, the field-name is |firstname| and
+%    the field-name-macro is |\@LRT@@firstname|. When a row after the first is read, 
+%    |\@LRT@@firstname| will expand to the entry in the |First Name| column on that row. 
+%
+%    When |\mergeFields| has read a row and set the field-name-macros the |tex|-file is 
+%    read and the \TeX\ code evaluated. 
+%    In streaming mode the result is added to the input stream at
+%    the current location whereas in storage mode the result is written to the |tmp|-file. 
+%
+% \DescribeMacro{End of csv-file}\Hypertarget{End of csv-file}
+%    This process continues until the last line in the |csv|-file is processed OR until an entirely 
+%    blank line is encountered. 
+%    \vskip10pt
+%    The request for only alphanumeric, punctuation and blanks for entries in row one is 
+%    not actually enforced but the macro |caselower| from |stringstrings| is used to 
+%    produce lowercase letters and may do weird things to characters not on the requested list. 
+%    Without studying the |stringstrings| manual carefully %
+%    you may not be able to identify the field-names if you insist on weird characters. 
+%    
+%    It is quite possible that several columns can have the same field-name, and hence 
+%    the same field-name-macro. In that case the macro will expand to the contents of the 
+%    column with that field-name which is furthest to the right.
+%
+%    Because of the prepended |@LRT@@| you can not use these field-name-macros directly 
+%    in your |tex|-file. 
+%    The solution is to use \Hyperlink{Field}{}|{field-name}| which will expand correctly. 
+%    See the examples in appendix B.
+%    \subsubsection{Entry issues}
+%    Except for issues discussed here, you should be able to use any 
+%    standard |csv|-file.  
+%    
+%    The data file is read with the usual \TeX\ issues turned off: 
+%    |#|, |$|, |&|, |@|, |%|
+%    , |^|, |~|,  and \verb!|!
+%    can all be in your data file.
+%    \begin{itemize}
+%    \item 
+%    In streaming mode, only |#|, |$|, |&|, |@|, |%|, |^|, |~| print correctly. 
+%    The characters \$, \#, \%, @ and \& often occur in data and they print correctly. 
+%    \TeX\ code will not be rendered correctly so for example, |\$| in the data file produces 
+%    {$``$\tt\$} when \TeX ed. 
+%    As long as you are not too creative in your entries you should get the results you want. 
+%    \item
+%    In storage mode the characters above end up printing correctly in the |tmp|-file
+%    BUT when you |\input| the |tmp|-file back into your master-file these characters
+%    will resume their usual \TeX\ meaning and wreak havoc with your code.  
+%    If you absolutely must have them, writing |\&|, |\$|, |\#|,
+%    etc. in the |csv|-file may save you. 
+%    \end{itemize}
+%    
+%    \DescribeMacro{Delimiters}\null\hskip-\parindent
+%    There is one more issue. For most csv files, the field separator is the comma. 
+%    When a field has a comma in it, the entire field is delimited by double quotes ({\tt"}). 
+%    When the field has a double quote it is converted to a pair of double quotes ({\tt""}) and so on.
+%    If you have both commas and quotes in a field the best case scenario is that 
+%    you will get  |""|'s where you were hoping for |"|'s. This probably is not what you want.  
+%    Even worse, a |",| in a data entry will end the entry prematurely at this point 
+%    and things deteriorate from there. 
+%    
+%    There is a mechanism to deal with this. Most spreadsheets can save csv files with other
+%    field (and text) delimiters. The second most common version of csv has a tab as the 
+%    field delimiter and quotes for fields which have a tab in a field. 
+%
+%    These two cases are supported out of the box. By default you get the comma-quotes version.
+%    If you add |\setDelimitersTabQuote| before calling |\mergeFields| you will get 
+%    the tab-quotes version. 
+%    If you have a second call to |\mergeFields| and the data file is comma-quotes, 
+%    adding |\setDelimitersCommaQuote| before |\mergeFields| will restore comma-quotes.
+%    See \hyperlink{setDelimitersCommaQuoteDescription}{setDelimters\dots} 
+%    for a more thorough discussion. 
+%
+%
+%    \subsection{The blueprint file}
+%    
+%    The blueprint file is a normal \TeX\ file with macros defined as above from the |csv|-file. 
+%    It should not contain a \verb!\begin{document}! or an \verb!\end{document}! 
+%    nor anything that needs to be expanded in the preamble. 
+%    Such things belong in the master file. 
+%    
+%    For mail-merges, the |tex|-file should end with a \verb!\newpage! 
+%    to guarantee that each copy of the message appears on a 
+%    different page. 
+%    If you need custom sizes or headers or you have page numbers that you want to 
+%    reset for each copy, you should do this in the |tex|-file. 
+%    
+%    To use the data from the |csv|-file you need to write |\Field{some-field-name}| wherever 
+%    you want the data in your |tex|-file.
+%    Some field-names may be rather long so if you are going to use them a lot in your 
+%    |tex|-file, feel free to write something like |\def\sfn{\Field{some-field-name}}| at the
+%    top of your |tex|-file and then use |\sfn| thereafter.
+%    
+%    One additional issue occurs in storage mode. You may very well want \TeX\ code in your
+%    |tex|-file. When |mergeFields| reads a line of data, you want the field-name-macros to 
+%    expand to their current values but you often do not want your \TeX\ code to expand. 
+%    It is good practice stick a |\noexpand| in front of each \TeX\ macro. 
+%    Each line is expanded once when the line is written to the |tmp| file, so the |\noexpand|
+%    disappears and you are left with just your \TeX\ macros. 
+%    
+%    If you do define macros like |\sfn| as above, you will need 
+%    to write\\ |\noexpand\def\noexpand\sfn{\Field{some-field-name}}|. 
+% \StopEventually{\PrintIndex}
+%
+% \section{List of public macros}
+%    There are the 6  public macros: links are to descriptions of the |@LRT@|-versions which
+%    actually do the work.
+%
+%   \null\hskip-10pt \begin{tabular}{lll}
+%    \Hyperlink{mergeFields}%
+%    &\Hyperlink{Field}%
+%    &\hbox to 0pt{\Hyperlink{ifFieldEmpty}\hss}%
+%    \\
+%    \Hyperlink{setDelimitersCommaQuote}&\Hyperlink{setDelimitersTabQuote}%
+%    &\Hyperlink{makeMePublic}\\
+%    \end{tabular}
+%   \begin{itemize}
+%    \item |\mergeFields{tex={tex-file}csv={csv-file}}| or
+%    \\|\mergeFields{tex={tex-file}csv={csv-file}{tmp={tmp-file}}|\\
+%     sets up to do the merge. 
+%     \hyperlink{section.2}{Section 2} is devoted to a detailed discussion. 
+%     \item |\Field{field-name}| expands to the current value of the field-name-macro.
+%     \item |\ifFieldEmpty{field-name to test}{do if empty}{do if not}|
+%     \item The two |\setDelimiters| set the delimiters to match those used in the |csv| file: 
+%     comma-quotes is the default.
+%     \item |\makeMePublic| must be immediately followed by |\@LRT@| or you will get a 
+%     |Use of \makeMePublic doesn't match its definition.| error. Then you can write 
+%     |\makeMePublic \@LRT at foo\becomes\Foo| to make the public macro |\Foo| that 
+%     you just define equal to the private macro |\@LRT at foo|. You may not write 
+%     |\makeMePublic{\@LRT at foo}\becomes\Foo| or other variants: the first non-white-space
+%     character \TeX\ sees after |\makeMePublic| needs to be the start of |\@LRT@|. 
+%
+%     As a useful example, 
+%     |\makeMePublic\@LRT at Row\becomes\Row| means you can get your hands on
+%     the row number using |\Row|.
+%    \end{itemize}
+%
+% \section{Implementation}
+%
+% \begin{macro}{Header}
+% First we have the standard package header stuff. 
+% The line numbers in the typeset \jobname.dtx file match the line numbers 
+%  in the \jobname.sty file 
+% generated by \TeX ing the \jobname.ins file.
+%   \setcounter{CodelineNo}{15}
+%    \begin{macrocode}
+\NeedsTeXFormat{LaTeX2e}[2005/12/01]
+\ProvidesPackage{csvmerge}
+      [2019/07/17 v1.0 merges TeX code with csv data]
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{Required Packages}
+% These required packages are part of the standard \href{https://www.tug.org/texlive/}{{\tt TeX Live}} 
+%and \href{https://miktex.org}{{\tt MiKTEX}} distributions. 
+%    \begin{macrocode}
+\RequirePackage{stringstrings}
+\RequirePackage{trimspaces}
+\RequirePackage{etoolbox}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{Options}
+% |csvmerge| supports an option which is rarely needed. All the private macros 
+%    (except \hyperlink{exceptionDescription}{one}) in
+%    this package have |@LRT@| or |@lrt@| somewhere in their name so are very 
+%    unlikely to produce name conflicts. In the very unlikely chance that one or more of
+%    the six public macros has a name conflict, 
+%    this can be alleviated by putting |\usepackage[foo]{csvmerge}|
+%    in your master file. Here |foo| can be any string of alphabetical characters. 
+%    Then the names of all six public macros are invoked with a leading |foo|:
+%    |\mergeFields| no longer exists but becomes |\foomergeFields|. The evident change happens
+%    with the other five macros. 
+%    
+%    The next two lines of code merely save the option for use 
+%    \hyperlink{optionsDescription}{later} at the end.
+%    \begin{macrocode}
+\DeclareOption*{\xdef\@LRT at CO{\CurrentOption}}
+\ProcessOptions\relax
+
+%    \end{macrocode}
+% \end{macro}
+%    \begin{macrocode}
+\makeatletter
+
+%    \end{macrocode}
+% \begin{macro}{\mergeFields}
+%    \Hypertarget{mergeFields}
+%    |\@LRT at mergeFields| actually initiates the work. 
+%    It initializes some macros for later use. 
+%    Then it collects the |prefix={<prefix-file>}| arguments using |\@LRT at getFilePaths|
+%    and checks to be sure it has a |csv|-file
+%    and a |tex|-file. If not it bails. 
+%    Then it checks if it has a |tmp| file and sets the file reading subroutine, 
+%    |\@LRT at Input| to |\@LRT at streaming| is there is no |tmp| file and to 
+%    |\@LRT at storage| if there is. If there is a |tmp| file, it is opened. 
+%   Then |\@LRT at mergeData| is called which actually does the merging. 
+%   Finally, if there is a |tmp| file, it is closed. 
+%    \begin{macrocode}
+\newcommand{\@LRT at mergeFields}[1]{%
+\gdef\@LRT at csv{}%
+\gdef\@LRT at tex{}%
+\gdef\@LRT at tmp{}%
+\setcounter{\@LRT at macroPrefix Row}{2}\relax%
+\gdef\@LRT at csvBlankLine{}%
+\@LRT at getFilePaths#1=@%
+\if at LRT@empty{\@LRT at csv}{\@LRT at missingArgumentMessage{csv}}{}%
+\if at LRT@empty{\@LRT at tex}{\@LRT at missingArgumentMessage{tex}}{}%
+\if at LRT@empty{\@LRT at tmp}%
+{\global\let\@LRT at Input\@LRT at streaming}%
+{\global\let\@LRT at Input\@LRT at storage}%
+\if at LRT@empty{\@LRT at tmp}{}{%
+\immediate\openout\@lrt at tmpFile=\@LRT at tmp\relax}%
+\@LRT at mergeData%
+\if at LRT@empty{\@LRT at tmp}{}{\immediate\closeout\@lrt at tmpFile\relax}%
+}
+
+%    \end{macrocode}
+% \end{macro}
+%  \Hypertarget{macroPrefix}{}
+% \begin{macro}{\@LRT at macroPrefix}
+%    \begin{macrocode}
+\gdef\@LRT at macroPrefix{@LRT@@}
+
+%    \end{macrocode}
+% \end{macro}
+%  \Hypertarget{Field}{}
+% \begin{macro}{\Field}
+%    |\@LRT at Field| is just a wrapper for a |\csname ... \endcsname|. 
+%    Notice it adds the |\@LRT at macroPrefix| prefix to the argument so 
+%    the input is always the field-name and the output is always the value of 
+%    the corresponding field-name-macro. 
+%    Because of the third |@| there is no danger that these macros defined from
+%    entries in the |csv|-file will conflict with other macros defined in this package 
+%    since none of them have a |@@| in their names. 
+%    \begin{macrocode}
+\def\@LRT at Field#1{%
+\csname\@LRT at macroPrefix#1\endcsname%
+}
+
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ifFieldEmpty}
+%  \Hypertarget{ifFieldEmpty}{}
+%    |\ifFieldEmpty| takes three arguments. 
+%    The first argument is a field-name and if the content of the corresponding 
+%    macro is empty then the second argument is executed: otherwise the 
+%    third argument is executed.
+%    
+%    \begin{macrocode}
+\long\gdef\@LRT at ifFieldEmpty#1#2#3{\ifbool{\@LRT at macroPrefix#1}{#2}{#3}}
+
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\setDelimitersCommaQuote}
+%\end{macro}
+% \begin{macro}{\setDelimitersTabQuote}
+%  \Hypertarget{setDelimitersCommaQuote}{}
+%  \Hypertarget{setDelimitersTabQuote}{}
+%    These two |setDelimiters| are similar. 
+%    Recall how delimiters work. A row in a |csv|-file with comma delimiters 
+%    looks like |foo1,foo2,foo3,...| so the delimiter is the comma and if
+%    |\@LRT at getFieldDelimited| is put in front of this string it will peal off 
+%    |foo1|. Since |^^I| is \TeX\ for the tab, 
+%    a row in a csv file with tab delimiters 
+%    looks like |foo1^^Ifoo2^^Ifoo3^^I...| and so the first two lines of 
+%    |\@LRT at setDelimitersCommaQuote| and |\@LRT at setDelimitersTabQuote| 
+%    look the same after switching |,| and |^^I|. 
+%    
+%    There is a wrinkle in the tab case. The tab normally looks to \TeX\ like white space and 
+%    so by the time the line reaches |\@LRT at getFieldDelimited| the line looks like
+%    |foo1foo2foo3...| and there is no way to break off |foo1|. The |\catcode`\^^I12\relax|
+%    insures  |\@LRT at getFieldDelimited| sees the line as |foo1^^Ifoo2^^Ifoo3^^I...|..
+%    This means that the catcode of |^^I| must also be 12 when each line is read and the line
+%    and the macro |\gdef\@LRT at catcodes{|\\|\catcode`\^^I12\relax}| insures this. 
+%    In the comma delimited version no catcode heroics are needed so |\@LRT at catcodes|
+%    is empty. 
+%    
+%    If some field contains one or more |\@LRT at fieldDelimiterBack|'s then the |csv|-file will use 
+%    the text-delimiter at the front and back. When quote is the text delimiter and |foo2| contains 
+%    a comma but |foo1| and |foo3| do not, the comma delimited string looks like 
+%    |foo1,"foo2",foo3,...| and the tab delimited string looks like 
+%     |foo1^^I"foo2"^^Ifoo3^^I...|. 
+%    
+%    The text delimiters have a front one, the double-quotes in both versions, and the back one which is 
+%    the front text delimiter followed by the back field delimiter. 
+%    
+%    The macro |\@LRT at blankFieldItem| is used to construct what a blank line looks like.
+%    In the comma delimited case, you need a string of commas of the same length as  
+%    the number of entries on line one of the |csv|-file. In the tab delimited case, the blank line
+%    turns out to be a blank macro.
+%    
+%    The |\@LRT at catcodes| macro is a collection of catcodes that need to be changed: 
+%    nothing for the comma delimited case and |^^I| for the tab delimited case.
+%
+%    See \hyperlink{newDelimiterAppendix}{Appendix A} for more discussion on writing your own delimiters. 
+%    \begin{macrocode}
+{{%
+\gdef\@LRT at setDelimitersCommaQuote{
+\gdef\@LRT at fieldDelimiterBack{,}
+\gdef\@LRT at getFieldDelimited##1,{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at textDelimiterFront{"}
+\gdef\@LRT at getTextDelimited"##1",{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at blankFieldItem{,}
+\gdef\@LRT at catcodes{}
+}%
+}}
+
+{{\catcode`\^^I12\relax%
+\gdef\@LRT at setDelimitersTabQuote{
+\gdef\@LRT at fieldDelimiterBack{^^I}
+\gdef\@LRT at getFieldDelimited##1^^I{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at textDelimiterFront{"}
+\gdef\@LRT at getTextDelimited"##1"^^I{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at blankFieldItem{}
+\gdef\@LRT at catcodes{\catcode`\^^I12\relax}
+}%
+}}
+
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@LRT at makeMePublic}
+%    \hypertarget{exceptionDescription}{}
+%    \hypertarget{makeMePublicDescription}{}
+%    The next line of code defines the only macro which does not have |@LRT@|
+%    in its name. It seems sufficiently weird that there should be no name conflicts. 
+%    Notice that |\makeatletter| is still in effect so |@| has catcode 11.
+%    
+%    Then we switch to |\makeatother| so |@| has catcode 12. 
+%    The next line expands to |\@LRT at makeMePublic| with the initial 
+%    |\@LRT@| having its |@|'s of catcode 11 so it is a private macro. 
+%    In the |\@LRT@| that you see, the |@|'s have catcode 12 so it is really
+%    the macro |\@| with extra stuff. Since it should never be expanded 
+%    it doesn't really matter. Then we drop back into |\makeatletter| to define
+%    more private macros.
+%    
+%    The net result is that you can write \\
+%    \null\hskip1in |\makeMePublic \@LRT at foo\becomes\newMacro| \\in your master-file and
+%    the private macro |\@LRT at foo| becomes the same as |\newMacro| and you can
+%    use |\newMacro| in your |tex|-file. 
+%    \begin{macrocode}
+\expandafter\gdef\csname1238LRTLRTsvbneLRT\endcsname{@LRT@}
+\makeatother
+\expandafter\gdef\csname\csname1238LRTLRTsvbneLRT\endcsname 
+makeMePublic\endcsname\@LRT@#1\becomes#2{\global\letcs{#2}{@LRT@#1}}%
+\makeatletter
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{private macros}
+% \end{macro}
+% \begin{macro}{\@LRT at Row}
+%  \Hypertarget{Row}{}
+%    The macro |\@LRT at Row| expands to the number of the row of the |csv|-file currently
+%    being read. To get the |\xdef| to expand correctly we needed to define (and did)
+%    |\@LRT at macroPrefix| first. Recall that the first line of actual data is row 2.
+%    \begin{macrocode}
+\xdef\@LRT at Row{\noexpand\number\noexpand\value{\@LRT at macroPrefix Row}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\if at LRT@empty}\Hypertarget{if at LRT@empty}{}
+%  Takes three arguments: if |#1| expands to empty do the code in |#2|; 
+%  otherwise do the code in |#3|. 
+%    \begin{macrocode}
+\newcommand{\if at LRT@empty}[3]{\ifthenelse{\equal{#1}{}}{#2}{#3}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at fieldName}
+%    Takes an alphanumeric string, uses |\caselower| from the |stringstrings| package
+%    to convert the string to all lower case; then it strips the spaces from the answer
+%    using |\convertchar|, also from the |stringstrings| package. Next it strips commas from
+%    the answer. 
+%    The final |\@LRT at TheString| makes the answer global. 
+%    \begin{macrocode}
+\gdef\@LRT at fieldName#1{%
+\caselower[q]{#1}%
+\convertchar[q]{\thestring}{ }{}%
+\convertchar[q]{\thestring}{,}{}%
+\xdef\@LRT at TheString{\thestring}%
+}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at getFilePaths}
+%    |\@LRT at getFilePaths#1=#2@| is a recursive macro which works through the 
+%    |prefix={<prefix-file>}| argument list. 
+%    The first argument, |#1|, picks up one  |prefix={<prefix-file>}| and |#2| contains the rest of the arguments. 
+%    If |#1| is not empty it is passed to |\@LRT at extractKeyValue| which collects the 
+%    prefix and file path.
+%    \begin{macrocode}
+\gdef\@LRT at getFilePaths#1=#2@{%
+\xdef\@LRT at hashKey{\trim at spaces{#1}}%
+\if at LRT@empty{\@LRT at hashKey}{}{
+\def\@LRT at test{tex}\ifthenelse{\equal{\@LRT at hashKey}{\@LRT at test}}{}%
+{\def\@LRT at test{csv}\ifthenelse{\equal{\@LRT at hashKey}{\@LRT at test}}{}%
+{\def\@LRT at test{tmp}\ifthenelse{\equal{\@LRT at hashKey}{\@LRT at test}}{}%
+{\@LRT at unknownArgumentMessage{#1}}}}%
+\@LRT at extractKeyValue#2@%
+\expandafter\@LRT at getFilePaths\@LRT at doWeStillHaveStuffToDo @}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at extractKeyValue}
+%    |\@LRT at hashKey| contains the prefix and |\@LRT at hashValue| contains the file path. 
+%    If the prefix is not one of |tex|, |csv| or |tmp| you will be warned. 
+%    \begin{macrocode}
+\def\@LRT at extractKeyValue#1#2@{%
+\edef\@LRT at hashValue{\trim at spaces{#1}}%
+\xdef\@LRT at doWeStillHaveStuffToDo{\trim at spaces{#2}}%
+\expandafter\xdef\csname @LRT@\@LRT at hashKey\endcsname{\@LRT at hashValue}%
+}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at SecondifFieldEmpty}
+%    |\@LRT at SecondifFieldEmpty| checks for an empty macro directly. 
+%    The previously defined \Hyperlink{ifFieldEmpty} uses a different method so both are needed at
+%    various points in the code.
+%    \begin{macrocode}
+\newcommand{\@LRT at SecondifFieldEmpty}[3]{%
+\edef\@LRT at fieldValue{#1}%
+\ifx\@LRT at fieldValue\@empty\relax{#2}\else{#3}\fi\relax}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at getCommaFieldDelimited}
+%    The macros |\@LRT at getCommaFieldDelimited|and 
+%    |\@LRT at getFieldDelimited| are the same when the field delimiter is the comma. 
+%   The list of field-names is always comma delimited and so
+%   we need a |\@LRT at getCommaFieldDelimited| to iterate through it.
+%    \begin{macrocode}
+\gdef\@LRT at getCommaFieldDelimited#1,{\@LRT at getFirstArg{#1}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{New counter} The counter containing the row number. 
+%    \begin{macrocode}
+\newcounter{\@LRT at macroPrefix Row}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{New read/write's}
+%    \begin{macrocode}
+\newread\@lrt at csvFile%
+\newread\@lrt at texFile%
+\newwrite\@lrt at tmpFile%
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{Messages}
+%    \begin{macrocode}
+\gdef\@LRT at justProcessedMessage{%
+\immediate\typeout{}%
+\immediate\typeout{Just processed row %
+\@LRT at Row\space of the data file.}%
+\immediate\typeout{}%
+\stepcounter{\@LRT at macroPrefix Row}\relax%
+}
+
+\gdef\@LRT at failedToOpenMessage#1{%
+\immediate\typeout{}%
+\immediate\typeout{File #1 failed to open.}%
+\immediate\typeout{}\fi%
+\end{document}%
+}
+
+\gdef\@LRT at NoMoreDataMessage{%
+\immediate\typeout{No more data.}%
+\immediate\typeout{}%
+}
+
+\gdef\@LRT at missingArgumentMessage#1{
+\immediate\typeout{}%
+\immediate\typeout{I was never given a path to the #1 file.}%
+\immediate\typeout{}%
+\end{document}%
+}
+
+\gdef\@LRT at unknownArgumentMessage#1{
+\immediate\typeout{}%
+\immediate\typeout{I do not recognize an argument of type #1.}%
+\immediate\typeout{}%
+}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{Inputs}
+%  When |mergeFields| starts up, it knows immediately whether it is in streaming or in storage
+%  mode. It sets |\@LRT at Input| to |\@LRT at streaming| or  |\@LRT at storage|. 
+%  Each time a new line of data in the |csv|-file is read the 
+%  the macros are updated to reflect that data on the current line.  
+%  |\@LRT at streaming| uses the \LaTeX\ command |\input| to add the |tex|-file to the 
+%  stream. 
+%  |\@LRT at storage| works through the data in the |tex|-file. 
+%  First it opens the |tex| file; then it 
+%  reads the |tex|-file one line at a time; expands that line; and 
+%  writes the answer to a the |tmp|-file. When the |eof| for the |tex|-file is reached, 
+%  the |tex|-file is closed. 
+%    
+%    |\@LRT at catcodeMagic| is used in two places to set the catcodes of certain characters 
+%    to values that won't cause trouble. 
+%    
+%    |\@LRT at texNotAtEOF{#1}| is used to tighten up the code looping over the lines in
+%    the |tex|-file in |\@LRT at storage|.  
+%    \begin{macrocode}
+\gdef\@LRT at streaming{\input{\@LRT at tex}}
+
+\gdef\@LRT at catcodeMagic{%
+\catcode`\^^M9\relax%
+\catcode`\#12\relax
+\catcode`\$12\relax
+\catcode`\&12\relax
+\catcode`\^12\relax
+\catcode`\_12\relax
+\catcode`\%12\relax
+}
+
+\gdef\@LRT at texNotAtEOF#1{%
+\ifeof\@lrt at texFile{\global\booltrue{@LRT at texEOF}}\else{#1}\fi%
+}
+
+\gdef\@LRT at storage{{%
+\@LRT at catcodeMagic%
+\openin\@lrt at texFile=\@LRT at tex\relax%
+\@LRT at texNotAtEOF{\global\boolfalse{@LRT at texEOF}}%
+\unlessboolexpr{bool{@LRT at texEOF}}{%
+\read\@lrt at texFile to \@LRT at preItem%
+\@LRT at texNotAtEOF{%
+\immediate\write\@lrt at tmpFile{\@LRT at preItem}\relax}%
+}{}%
+\immediate\closein\@lrt at texFile%
+}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at dataLineIterator}
+%    This macro looks to see if the next character is |\@LRT at textDelimiterFront|. 
+%    If it is the entry is collected using |\@LRT at getTextDelimited| and if not we collect it 
+%    using |\@LRT at getFieldDelimited|.
+%    \begin{macrocode}
+\gdef\@LRT at dataLineIterator{%
+\expandafter\@ifnextchar\@LRT at textDelimiterFront%
+{\@LRT at getTextDelimited}{\@LRT at getFieldDelimited}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at getFirstArg}
+%    This is the |\@LRT at getFirstArg| from the |\@LRT at getFieldDelimited| and \\
+%    |\@LRT at getTextDelimited| macros. It collects the first field and then 
+%    uses |\@LRT at getSecondArg| to collect the rest of the line from the |csv|-file.
+%    \begin{macrocode}
+\gdef\@LRT at getFirstArg#1{\gdef\@LRT at firstArg{#1}\@LRT at getSecondArg}
+\gdef\@LRT at getSecondArg#1@{\gdef\@LRT at restArg{#1}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at getLOFirstArg}
+%  These next two macros do the same thing with the first line of the |csv|-file. 
+%  The difference is that these two macros put their answers in a different pair of
+%  macros than the previous two so we can iterate along both the first line (field-names)
+%  and the current line of the |csv|-file. 
+%    \begin{macrocode}
+\gdef\@LRT at getLOFirstArg#1{\gdef\@LRT at ffirstArg{#1}\@LRT at getLOSecondArg}
+\gdef\@LRT at getLOSecondArg#1@{\gdef\@LRT at frestArg{#1}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at getLineOne}
+%  This is the version of |\@LRT at getFirstArg| which is used on the first line of the |csv|-file.
+%    \begin{macrocode}
+\gdef\@LRT at fieldNameIterator#1,{\@LRT at getLOFirstArg{#1}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at setFirstLineAndBlankLine}
+%  This macro collects the first line of the |csv|-file and packages it for later use:
+%  |\@lrt at firstline| is the first line when we are done. 
+%  We also construct |\@LRT at csvBlankLine| which is used to check if
+%  a line of the |csv|-file is blank. 
+%    \begin{macrocode}
+\providebool{@LRT at iterator}
+\gdef\@LRT at setFirstLineAndBlankLine#1{%
+\gdef\@lrt at firstline{}%
+\gdef\@LRT at csvBlankLine{}
+\edef\@LRT at restArg{#1\@LRT at fieldDelimiterBack}
+\booltrue{@LRT at iterator}%
+\whileboolexpr{bool{@LRT at iterator}}{%
+\expandafter\@LRT at dataLineIterator\@LRT at restArg @%
+\@LRT at fieldName{\@LRT at firstArg}%
+\xdef\@lrt at firstline{\@lrt at firstline\@LRT at TheString,}%
+\if at LRT@empty{\@LRT at restArg}%
+{\boolfalse{@LRT at iterator}}{\booltrue{@LRT at iterator}}%
+\ifboolexpr{bool{@LRT at iterator}}%
+{\xdef\@LRT at csvBlankLine{\@LRT at csvBlankLine\@LRT at blankFieldItem}}{}%
+}{}%
+}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at getAndProcessNextLine}
+%  This is the recursive macro which processes each line of the |csv|-file 
+%  until there are no more. 
+%  The code in the  first |{{| \dots |}}| pair 
+%  reads a line from the |csv|-file: the last line here converts 
+%  the answer from local to global. 
+%  The code in the second |{{| \dots |}}| pair checks 
+%  if the line is \hyperlink{End of csv-fileDescription}{blank} or not. 
+%  |\@LRT at exitGetAndProcessNextLine| exits the recursion and 
+%  |\@LRT at repeatGetAndProcessNextLine| reloops. 
+%    \begin{macrocode}
+\gdef\@LRT at getAndProcessNextLine{%
+\unlessboolexpr{bool{@LRT at csvEOF}}{%
+{{%
+\@LRT at catcodeMagic%
+\@LRT at catcodes
+\read\@lrt at csvFile to\@LRT at x@nextLine%
+\ifeof\@lrt at csvFile\relax{\global\booltrue{@LRT at csvEOF}}\else%
+{\global\boolfalse{@LRT at csvEOF}}\fi%
+\xdef\@LRT at nextLine{\@LRT at x@nextLine}%
+}}%
+{{%
+\if at LRT@empty{\@LRT at nextLine}%
+{\global\let\@LRT at next\@LRT at exitGetAndProcessNextLine\relax}%
+{\ifx\@LRT at csvBlankLine\@LRT at nextLine\relax%
+{\global\let\@LRT at next\@LRT at exitGetAndProcessNextLine\relax}\else%
+{\global\let\@LRT at next\@LRT at repeatGetAndProcessNextLine\relax}\fi}%
+\@LRT at next%
+}}%
+}{}%
+}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at exitGetAndProcessNextLine}
+%  This just exits.
+%    \begin{macrocode}
+\gdef\@LRT at exitGetAndProcessNextLine{%
+\closein\@lrt at csvFile\relax\global\booltrue{@LRT at csvEOF}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at repeatGetAndProcessNextLine}
+%  This sets up to process the line we just read.
+%    \begin{macrocode}
+\gdef\@LRT at repeatGetAndProcessNextLine{%
+\@LRT at processNextLine{\@LRT at nextLine\@LRT at fieldDelimiterBack}}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at setMacrosForOneEntry}
+%  This bit of code sets the macro and the if-empty boolean for a single item:
+%  \#1 is the field-name and \#2 is the entry in that (row,column).
+%    \begin{macrocode}
+\gdef\@LRT at setMacrosForOneEntry#1#2{%
+\expandafter\xdef\csname\@LRT at macroPrefix#1\endcsname{#2}%
+\@LRT at SecondifFieldEmpty{#2}%
+{\global\booltrue{\@LRT at macroPrefix#1}}%
+{\global\boolfalse{\@LRT at macroPrefix#1}}%
+}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at processNextLine}
+%    This code actually processes the line from the |csv|-file. 
+%    The first three lines are setup. 
+%    The two |\edef|'s do the following: |\@LRT at restArg{#1}| has the entire current row; and
+%    |\@LRT at frestArg| has a comma separated list of field-names. 
+%    Setting |\booltrue{@LRT at iterator}| means the iteration will start.
+%    The two |\expandafter| lines do the iteration: the current values are in |\ffirstArg| for
+%    the field-name and |\firstArg| for the entry in the current row. 
+%   The line |\@LRT at setMacrosForOneEntry| sets the contents of the  field-name-macro. 
+%   Finally the 
+%   |\if at LRT@empty| line checks if we are done. 
+%    
+%    The |\edef| between the two |\expandafter|'s adds a blank entry to the back of 
+%    |\@LRT at restArg| so if the row is too short in the |csv|-file it will still scan correctly.
+%
+%  The |\@LRT at Input| outputs the result either to the stream or to the |tmp|-file
+%  and |\@LRT at justProcessedMessage| writes to the terminal which row was just processed. 
+%    If something suddenly goes wrong you know which row you were working on 
+%    when things messed up.
+%    \begin{macrocode}
+\gdef\@LRT at processNextLine#1{%
+\edef\@LRT at restArg{#1}%
+\edef\@LRT at frestArg{\@lrt at firstline}%
+\booltrue{@LRT at iterator}%
+\whileboolexpr{bool{@LRT at iterator}}{%
+\expandafter\@LRT at fieldNameIterator\@LRT at frestArg @%
+\edef\@LRT at restArgA{\@LRT at restArg\@LRT at fieldDelimiterBack}
+\expandafter\@LRT at dataLineIterator\@LRT at restArgA @%
+\@LRT at setMacrosForOneEntry{\@LRT at ffirstArg}{\@LRT at firstArg}%
+\if at LRT@empty{\@LRT at frestArg}%
+{\boolfalse{@LRT at iterator}}{\booltrue{@LRT at iterator}}%
+}{}%
+\@LRT at Input\relax%
+\@LRT at justProcessedMessage%
+}
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{\@LRT at mergeData}
+%    This macro opens the |csv|-file, reads the first row.  
+%    The code between the |{{ ... }}| makes a comma separated list of field-names
+%    in the order in which they occur in the |csv|-file. It also creates a macro which 
+%    expands to what a blank line in the |csv|-file will look like. It also defines one 
+%    boolean for each field-name. 
+%    This requires an iteration over |\@lrtfirstline|.
+%    
+%    Because \TeX\ |\newif|'s are not global, we need to define the ones we need as soon
+%    as possible, which is right here.
+%
+%    Then |\@LRT at mergeData| calls |\@LRT at getAndProcessNextLine| which  
+%    reads and processes the subsequent lines of the |csv| file. 
+%
+%    Finally it puts out a no-more-data message to let you know |\mergeFields| is finished.
+%    \begin{macrocode}
+\gdef\@LRT at mergeData{%
+\providebool{@LRT at texEOF}%
+\immediate\openin\@lrt at csvFile=\@LRT at csv\relax%
+\providebool{@LRT at csvEOF}%
+\boolfalse{@LRT at csvEOF}%
+\ifeof\@lrt at csvFile\@LRT at failedToOpenMessage{\@LRT at csv}\fi%
+{{\@LRT at catcodes
+\read\@lrt at csvFile to\@lrt at firstlineX%
+\@LRT at setFirstLineAndBlankLine{\@lrt at firstlineX}
+}}%
+\booltrue{@LRT at iterator}
+\edef\@LRT at restArg{\@lrt at firstline}%
+\whileboolexpr{bool{@LRT at iterator}}{%
+\expandafter\@LRT at getCommaFieldDelimited\@LRT at restArg @%
+\providebool{\@LRT at macroPrefix\@LRT at firstArg}%
+\if at LRT@empty{\@LRT at restArg}%
+{\boolfalse{@LRT at iterator}}{\booltrue{@LRT at iterator}}%
+}{}%
+\@LRT at getAndProcessNextLine%
+\@LRT at NoMoreDataMessage%
+}
+
+%    \end{macrocode}
+% \end{macro}
+%  \Hypertarget{options}{}
+% \begin{macro}{Options code}
+%   Here is the code which 
+%    examines the option string and maps the public macro names to the
+%    private codes which actually do the work. 
+%    \begin{macrocode}
+\gdef\@LRT at weirdOption#1{\@ifundefined{@LRT at CO}%
+{\global\csletcs{#1}{@LRT@#1}}{{\global\csletcs{\@LRT at CO #1}{@LRT@#1}}}%
+}
+
+\@LRT at weirdOption{mergeFields}%
+\@LRT at weirdOption{Field}%
+\@LRT at weirdOption{ifFieldEmpty}%
+\@LRT at weirdOption{setDelimitersCommaQuote}%
+\@LRT at weirdOption{setDelimitersTabQuote}%
+\@LRT at weirdOption{makeMePublic}%
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{Set the default delimiters}
+%   Here  \Hypertarget{defaults}{is} 
+%   where the default delimiters are set. 
+%    \begin{macrocode}
+\@LRT at setDelimitersCommaQuote
+
+%    \end{macrocode}
+% \end{macro}
+% \begin{macro}{Finish up}
+%    \begin{macrocode}
+\makeatother
+\endinput
+%    \end{macrocode}
+% \end{macro}
+% \Finale
+%  \newpage
+% \appendix
+% \section{Writing new delimiter macros}\hypertarget{newDelimiterAppendix}{}
+%    If the field delimiter is not something \TeX\ sees as white space, life is fairly easy.
+%    In your master-file, copy and paste one of the code examples below. 
+%    Change to suit your needs.
+%
+%    \noindent***********************************************************************
+%
+%    \begin{verbatim}
+%    {{%
+%    \makeatletter
+%    \gdef\setMyDelimiters{%
+%    \gdef\@LRT at fieldDelimiterBack{,}
+%    \gdef\@LRT at getFieldDelimited##1,{\@LRT at getFirstArg{##1}}
+%    \gdef\@LRT at textDelimiterFront{"}
+%    \gdef\@LRT at textDelimiterBack{",}
+%    \gdef\@LRT at getTextDelimited"##1",{\@LRT at getFirstArg{##1}}
+%    \gdef\@LRT at blankFieldItem{,}
+%    \gdef\@LRT at catcodes{}
+%    }%
+%    \makeatother
+%    }}
+%    \end{verbatim}
+%
+%    \noindent***********************************************************************
+%
+%    Replace all occurrences of {\tt ,} by your field delimiter. Replace all occurrences of {\tt "} 
+%    with your text deliminator
+%    and you should be ready to go. 
+%    Just add |\setMyDelimiters| in your master-file before using |\mergeFields|.
+%    
+%    If the field delimiter is a white space character such as a tab, then copy and paste
+%    the next example
+%
+%    \noindent***********************************************************************
+%    
+%    \begin{verbatim}
+%    \makeatletter
+%    {{\makeatletter
+%    \catcode`\^^I12\relax%
+%    \gdef\@LRT at setDelimitersTabQuote{
+%    \gdef\@LRT at fieldDelimiterBack{^^I}
+%    \gdef\@LRT at getFieldDelimited##1^^I{\@LRT at getFirstArg{##1}}
+%    \gdef\@LRT at textDelimiterFront{"}
+%    \gdef\@LRT at textDelimiterBack{"^^I}
+%    \gdef\@LRT at getTextDelimited"##1"^^I{\@LRT at getFirstArg{##1}}
+%    \gdef\@LRT at blankFieldItem{}
+%    \gdef\@LRT at catcodes{\catcode`\^^I12\relax}
+%    }%
+%    }}
+%    \makeatother
+%    }}
+%    \end{verbatim}
+%
+%    \noindent***********************************************************************
+%
+%    Use Chapter 8 of the \TeX\ book to find how to write your delimiter and replace 
+%    all occurrences of |\^^I| with the code for your delimiter. 
+%    Then replace all occurrences of {\tt "}  with your text deliminator 
+%     and hope for the best. 
+%    Try leaving |\@LRT at blankFieldItem| blank and hope for the best. 
+%    Again add |\setMyDelimiters| in your master-file before using |\mergeFields|.
+%
+% \section{Some examples}
+% \subsection{\TeX\ code in a table}
+%  A typical line in a tabular environment looks like |item1 & item2& item3\\|.
+%    Suppose you have 4 columns in your |csv|-file with entries |Last Name|, 
+%    |First name|, |Numerator| and |Denominator| and you want |item1| to be 
+%    |Last Name|, |item2| to be |First name| and |item3| to be |\frac{Numerator}{Denominator}|.
+%    Here is the needed code in your |tex|-file:
+%
+%    \begin{verbatim}
+%    \Field{lastname}&\Field{firstname}&%
+%    $\noexpand\frac{\Field{numerator}}{\Field{denominator}}$\noexpand\\
+%    \end{verbatim}
+%    You might have expected to see a |\noexpand| in front of the \$'s but remember \$ is one of 
+%    those characters which goes through unscathed to the |tmp|-file. 
+%    It certainly doesn't hurt to write |\noexpand$|. When you read the |tmp|-file back in
+%    you do want |$| to resume its meaning of making math mode and it does. 
+%    
+%    The |\noexpand| in front of the |\frac| and the |\\| are needed. 
+%    You don't want to try to expand either one
+%    until the |tmp|-file is read back in. 
+%    
+%    Assuming that the file |merge.tex| contains the code above and that the file |data.csv| contains your data,
+%    the following code typesets the table.
+%    \begin{verbatim}
+%    \documentclass[12pt]{article}
+%    \RequirePackage{csvmerge}
+%    \begin{document} 
+%    \mergeFields{
+%       tmp={example.tmp}
+%       tex  ={merge.tex}
+%       csv =  {data.csv}
+%       }
+%    \begin{tabular}{lll}
+%    \input{example.tmp}
+%    \end{tabular}
+%    \end{document}
+%    \end{verbatim}
+%    The |csv|-file needs to contain the four field-names that appear in the |tex|-file, 
+%    but it is fine if it contains additional columns.
+%
+%    \subsection{\TeX\ code in a mail-merge}
+%    Here is a snippet of code to do a header in a mail-merge business letter.
+%    The field-names from the |csv|-file should be obvious. The interesting point
+%    is the usage of |\ifFieldEmpty|.  
+%    \begin{verbatim}
+%    \Field{firstname} \ifFieldEmpty{middleinitial}{}
+%    {\Field{middleinitial}.~}\Field{lastname}\par
+%    \ifFieldEmpty{streetline1}{}{\Field{streetline1}\par}
+%    \ifFieldEmpty{streetline2}{}{\Field{streetline2}\par}
+%    \ifFieldEmpty{streetline3}{}{\Field{streetline3}\par}
+%    \Field{city}, \Field{stateprovince} \Field{postalcode}
+%    \end{verbatim}
+%    
+%    The |middleinitial| column is a middle initial with no period. Some recipients will have no middle initial 
+%    but you don't want just a floating period. Also you don't want an additional space. 
+%    Knuth also suggests that names should be \TeX ed with |First M.~Last| [The \TeX\ book, Ch. 6]. 
+%    The |\ifFieldEmpty| with |streetline1| is probably redundant but often |streetline2| will be empty.
+%    If it is not, we want a new line after it, but if it is empty we don't want a blank new line. 
+%    
+%    In storage mode you need a |\noexpand| before the |~|, as well as before the |\par|'s.
+%    \subsection{Some master-files}
+%    \subsubsection{A table}
+%    We are doing a table so we want storage mode. 
+%    We also want a horizontal line after each row of the table. 
+%    The master-file:
+%    \begin{verbatim}
+%    \documentclass[12pt]{amsart}
+%    \RequirePackage{csvmerge} 
+%    \begin{document} 
+%    \mergeFields{
+%    tmp= {	./table.tmp}
+%    csv =  {./data.csv}
+%    tex  ={./table.tex  }
+%    }
+%    \begin{tabular}{|l|l|l|l|l|}
+%    \hline%
+%    \input{./table.tmp}
+%    \end{tabular}
+%    \end{document}
+%    \end{verbatim}
+%    
+%    The |tex|-file |table.tmp|:
+%    \begin{verbatim}
+%    % one table line
+%    \Field{firstname} &\Field{id} & \Field{city}  &\Field{lastname}&   
+%    \Field{postalcode}  \noexpand\\
+%    \noexpand\hline
+%    \end{verbatim}
+%
+%    \subsubsection{A mail-merge}
+%    We are doing a mail-merge so we can use streaming mode. 
+%    Since the |tex|-file name has spaces, we have quoted it.
+%    The master-file:
+%    \begin{verbatim}
+%    \documentclass[12pt]{letter}
+%    \RequirePackage{./csvmerge} 
+%    \begin{document}
+%    \mergeFields{ tex  = {"./Second letter.template"  } 
+%    csv ={  ./Invites.csv}}
+%    \end{document}
+%    \end{verbatim}
+%    
+%    The |tex|-file |Second letter.template|:
+% 
+%    \begin{verbatim}
+%    %First page of letter
+%    \setcounter{page}{1}
+%     
+%    \Field{firstname} \ifFieldEmpty{middleinitial}{}%
+%    {\Field{middleinitial}.~}\Field{lastname}\par
+%    \ifFieldEmpty{streetline1}{}{\Field{streetline1} \par}
+%    \ifFieldEmpty{streetline2}{}{\Field{streetline2}\par}
+%    \ifFieldEmpty{streetline3}{}{\Field{streetline3}\par}
+%    \Field{city}, \Field{stateprovince} \Field{postalcode}
+%    
+%    \vskip.25in
+%    Dear \Field{preferredfirstname},\par
+%    \vskip10pt
+%    How come no RSVP?
+%    \vskip10pt
+%    Bilbo Baggins
+%   \newpage
+%    \end{verbatim}
+%
+%    Here is an equivalent version using storage mode.
+%    The master-file:
+%    \begin{verbatim}
+%    \documentclass[12pt]{letter}
+%    \RequirePackage{./csvmerge} 
+%    \begin{document}
+%    \mergeFields{ tex  = {"./Second letter.template"  } 
+%    csv ={  ./Invites.csv}tmp={letters}}
+%    \input{letters}
+%    \end{document}
+%    \end{verbatim}
+%    
+%    We must adjust the |tex|-file |Second letter.template|:
+% 
+%    \begin{verbatim}
+%    %First page of letter
+%    \noexpand\setcounter{page}{1}
+%     
+%    \Field{firstname} \ifFieldEmpty{middleinitial}{}%
+%    {\Field{middleinitial}.\noexpand~}\Field{lastname}\noexpand\par
+%    \ifFieldEmpty{streetline1}{}{\Field{streetline1} \noexpand\par}
+%    \ifFieldEmpty{streetline2}{}{\Field{streetline2}\noexpand\par}
+%    \ifFieldEmpty{streetline3}{}{\Field{streetline3}\noexpand\par}
+%    \Field{city}, \Field{stateprovince} \Field{postalcode}
+%    
+%    \noexpand\vskip.25in
+%    Dear \Field{preferredfirstname},\par
+%    \noexpand\vskip10pt
+%    How come no RSVP?
+%    \noexpand\vskip10pt
+%    Bilbo Baggins
+%   \noexpand\newpage
+%    \end{verbatim}
+%
+%    Usually using storage mode when you don't need it is wasteful since you have to create and
+%    save a |tmp|-file. It can come in handy if your letter code has lots of field macros and 
+%    you can't get one |tex|-file to not have overfull/underfull boxes and the like after the 
+%    various expansions. The |tmp|-file contains all the letters and you can fine tune each one and
+%    then just do 
+%    \begin{verbatim}
+%    \documentclass[12pt]{letter}
+%    \begin{document}
+%    \input{letters}
+%    \end{document}
+%    \end{verbatim}
+
+
+
+
+
+


Property changes on: trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.dtx
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.ins
===================================================================
--- trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.ins	                        (rev 0)
+++ trunk/Master/texmf-dist/source/latex/csvmerge/csvmerge.ins	2019-08-10 21:19:47 UTC (rev 51857)
@@ -0,0 +1,39 @@
+%% http://texdoc.net/texmf-dist/doc/latex/dtxtut/dtxtut.pdf
+%% Copyright (C) 2019 by Laurence R Taylor
+%%
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3 of this license or (at your option) any later 
+%% version. The latest version of this license is in:
+%%
+%% http://www.latex-project.org/lppl.txt
+%%
+%% and version 1.3 or later is part of all distributions of 
+%% LaTeX version 2005/12/01 or later.
+%%
+\input docstrip.tex
+\keepsilent
+\usedir{} 
+\preamble
+This is a generated file. Copyright (C) 2019 by Laurence R Taylor
+This file may be distributed and/or modified under the
+conditions of the LaTeX Project Public License, either
+version 1.3 of this license or (at your option) any later
+version.  The latest version of this license is in:
+   http://www.latex-project.org/lppl.txt
+and version 1.3 or later is part of all distributions of
+LaTeX version 2005/12/01 or later.
+\endpreamble
+\askforoverwritefalse
+\generate{\file{csvmerge.sty}{\from{csvmerge.dtx}{package}}}
+\Msg{*********************************************************}
+\Msg{*}
+\Msg{* To finish the installation you have to move the}
+\Msg{* following file into a directory searched by TeX:}
+\Msg{*}
+\Msg{* \space\space csvmerge.sty}
+\Msg{*}
+\Msg{* To produce the documentation run the file csvmerge.dtx} \Msg{* through LaTeX.}
+\Msg{*}
+\Msg{*********************************************************}
+\endbatchfile
\ No newline at end of file

Added: trunk/Master/texmf-dist/tex/latex/csvmerge/csvmerge.sty
===================================================================
--- trunk/Master/texmf-dist/tex/latex/csvmerge/csvmerge.sty	                        (rev 0)
+++ trunk/Master/texmf-dist/tex/latex/csvmerge/csvmerge.sty	2019-08-10 21:19:47 UTC (rev 51857)
@@ -0,0 +1,300 @@
+%%
+%% This is file `csvmerge.sty',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% csvmerge.dtx  (with options: `package')
+%% This is a generated file. Copyright (C) 2019 by Laurence R Taylor
+%% This file may be distributed and/or modified under the
+%% conditions of the LaTeX Project Public License, either
+%% version 1.3 of this license or (at your option) any later
+%% version.  The latest version of this license is in:
+%%    http://www.latex-project.org/lppl.txt
+%% and version 1.3 or later is part of all distributions of
+%% LaTeX version 2005/12/01 or later.
+\NeedsTeXFormat{LaTeX2e}[2005/12/01]
+\ProvidesPackage{csvmerge}
+      [2019/07/17 v1.0 merges TeX code with csv data]
+
+\RequirePackage{stringstrings}
+\RequirePackage{trimspaces}
+\RequirePackage{etoolbox}
+
+\DeclareOption*{\xdef\@LRT at CO{\CurrentOption}}
+\ProcessOptions\relax
+
+\makeatletter
+
+\newcommand{\@LRT at mergeFields}[1]{%
+\gdef\@LRT at csv{}%
+\gdef\@LRT at tex{}%
+\gdef\@LRT at tmp{}%
+\setcounter{\@LRT at macroPrefix Row}{2}\relax%
+\gdef\@LRT at csvBlankLine{}%
+\@LRT at getFilePaths#1=@%
+\if at LRT@empty{\@LRT at csv}{\@LRT at missingArgumentMessage{csv}}{}%
+\if at LRT@empty{\@LRT at tex}{\@LRT at missingArgumentMessage{tex}}{}%
+\if at LRT@empty{\@LRT at tmp}%
+{\global\let\@LRT at Input\@LRT at streaming}%
+{\global\let\@LRT at Input\@LRT at storage}%
+\if at LRT@empty{\@LRT at tmp}{}{%
+\immediate\openout\@lrt at tmpFile=\@LRT at tmp\relax}%
+\@LRT at mergeData%
+\if at LRT@empty{\@LRT at tmp}{}{\immediate\closeout\@lrt at tmpFile\relax}%
+}
+
+\gdef\@LRT at macroPrefix{@LRT@@}
+
+\def\@LRT at Field#1{%
+\csname\@LRT at macroPrefix#1\endcsname%
+}
+
+\long\gdef\@LRT at ifFieldEmpty#1#2#3{\ifbool{\@LRT at macroPrefix#1}{#2}{#3}}
+
+{{%
+\gdef\@LRT at setDelimitersCommaQuote{
+\gdef\@LRT at fieldDelimiterBack{,}
+\gdef\@LRT at getFieldDelimited##1,{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at textDelimiterFront{"}
+\gdef\@LRT at getTextDelimited"##1",{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at blankFieldItem{,}
+\gdef\@LRT at catcodes{}
+}%
+}}
+
+{{\catcode`\^^I12\relax%
+\gdef\@LRT at setDelimitersTabQuote{
+\gdef\@LRT at fieldDelimiterBack{^^I}
+\gdef\@LRT at getFieldDelimited##1^^I{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at textDelimiterFront{"}
+\gdef\@LRT at getTextDelimited"##1"^^I{\@LRT at getFirstArg{##1}}
+\gdef\@LRT at blankFieldItem{}
+\gdef\@LRT at catcodes{\catcode`\^^I12\relax}
+}%
+}}
+
+\expandafter\gdef\csname1238LRTLRTsvbneLRT\endcsname{@LRT@}
+\makeatother
+\expandafter\gdef\csname\csname1238LRTLRTsvbneLRT\endcsname
+makeMePublic\endcsname\@LRT@#1\becomes#2{\global\letcs{#2}{@LRT@#1}}%
+\makeatletter
+
+\xdef\@LRT at Row{\noexpand\number\noexpand\value{\@LRT at macroPrefix Row}}
+
+\newcommand{\if at LRT@empty}[3]{\ifthenelse{\equal{#1}{}}{#2}{#3}}
+
+\gdef\@LRT at fieldName#1{%
+\caselower[q]{#1}%
+\convertchar[q]{\thestring}{ }{}%
+\convertchar[q]{\thestring}{,}{}%
+\xdef\@LRT at TheString{\thestring}%
+}
+
+\gdef\@LRT at getFilePaths#1=#2@{%
+\xdef\@LRT at hashKey{\trim at spaces{#1}}%
+\if at LRT@empty{\@LRT at hashKey}{}{
+\def\@LRT at test{tex}\ifthenelse{\equal{\@LRT at hashKey}{\@LRT at test}}{}%
+{\def\@LRT at test{csv}\ifthenelse{\equal{\@LRT at hashKey}{\@LRT at test}}{}%
+{\def\@LRT at test{tmp}\ifthenelse{\equal{\@LRT at hashKey}{\@LRT at test}}{}%
+{\@LRT at unknownArgumentMessage{#1}}}}%
+\@LRT at extractKeyValue#2@%
+\expandafter\@LRT at getFilePaths\@LRT at doWeStillHaveStuffToDo @}}
+
+\def\@LRT at extractKeyValue#1#2@{%
+\edef\@LRT at hashValue{\trim at spaces{#1}}%
+\xdef\@LRT at doWeStillHaveStuffToDo{\trim at spaces{#2}}%
+\expandafter\xdef\csname @LRT@\@LRT at hashKey\endcsname{\@LRT at hashValue}%
+}
+
+\newcommand{\@LRT at SecondifFieldEmpty}[3]{%
+\edef\@LRT at fieldValue{#1}%
+\ifx\@LRT at fieldValue\@empty\relax{#2}\else{#3}\fi\relax}
+
+\gdef\@LRT at getCommaFieldDelimited#1,{\@LRT at getFirstArg{#1}}
+
+\newcounter{\@LRT at macroPrefix Row}
+
+\newread\@lrt at csvFile%
+\newread\@lrt at texFile%
+\newwrite\@lrt at tmpFile%
+
+\gdef\@LRT at justProcessedMessage{%
+\immediate\typeout{}%
+\immediate\typeout{Just processed row %
+\@LRT at Row\space of the data file.}%
+\immediate\typeout{}%
+\stepcounter{\@LRT at macroPrefix Row}\relax%
+}
+
+\gdef\@LRT at failedToOpenMessage#1{%
+\immediate\typeout{}%
+\immediate\typeout{File #1 failed to open.}%
+\immediate\typeout{}\fi%
+\end{document}%
+}
+
+\gdef\@LRT at NoMoreDataMessage{%
+\immediate\typeout{No more data.}%
+\immediate\typeout{}%
+}
+
+\gdef\@LRT at missingArgumentMessage#1{
+\immediate\typeout{}%
+\immediate\typeout{I was never given a path to the #1 file.}%
+\immediate\typeout{}%
+\end{document}%
+}
+
+\gdef\@LRT at unknownArgumentMessage#1{
+\immediate\typeout{}%
+\immediate\typeout{I do not recognize an argument of type #1.}%
+\immediate\typeout{}%
+}
+
+\gdef\@LRT at streaming{\input{\@LRT at tex}}
+
+\gdef\@LRT at catcodeMagic{%
+\catcode`\^^M9\relax%
+\catcode`\#12\relax
+\catcode`\$12\relax
+\catcode`\&12\relax
+\catcode`\^12\relax
+\catcode`\_12\relax
+\catcode`\%12\relax
+}
+
+\gdef\@LRT at texNotAtEOF#1{%
+\ifeof\@lrt at texFile{\global\booltrue{@LRT at texEOF}}\else{#1}\fi%
+}
+
+\gdef\@LRT at storage{{%
+\@LRT at catcodeMagic%
+\openin\@lrt at texFile=\@LRT at tex\relax%
+\@LRT at texNotAtEOF{\global\boolfalse{@LRT at texEOF}}%
+\unlessboolexpr{bool{@LRT at texEOF}}{%
+\read\@lrt at texFile to \@LRT at preItem%
+\@LRT at texNotAtEOF{%
+\immediate\write\@lrt at tmpFile{\@LRT at preItem}\relax}%
+}{}%
+\immediate\closein\@lrt at texFile%
+}}
+
+\gdef\@LRT at dataLineIterator{%
+\expandafter\@ifnextchar\@LRT at textDelimiterFront%
+{\@LRT at getTextDelimited}{\@LRT at getFieldDelimited}}
+
+\gdef\@LRT at getFirstArg#1{\gdef\@LRT at firstArg{#1}\@LRT at getSecondArg}
+\gdef\@LRT at getSecondArg#1@{\gdef\@LRT at restArg{#1}}
+
+\gdef\@LRT at getLOFirstArg#1{\gdef\@LRT at ffirstArg{#1}\@LRT at getLOSecondArg}
+\gdef\@LRT at getLOSecondArg#1@{\gdef\@LRT at frestArg{#1}}
+
+\gdef\@LRT at fieldNameIterator#1,{\@LRT at getLOFirstArg{#1}}
+
+\providebool{@LRT at iterator}
+\gdef\@LRT at setFirstLineAndBlankLine#1{%
+\gdef\@lrt at firstline{}%
+\gdef\@LRT at csvBlankLine{}
+\edef\@LRT at restArg{#1\@LRT at fieldDelimiterBack}
+\booltrue{@LRT at iterator}%
+\whileboolexpr{bool{@LRT at iterator}}{%
+\expandafter\@LRT at dataLineIterator\@LRT at restArg @%
+\@LRT at fieldName{\@LRT at firstArg}%
+\xdef\@lrt at firstline{\@lrt at firstline\@LRT at TheString,}%
+\if at LRT@empty{\@LRT at restArg}%
+{\boolfalse{@LRT at iterator}}{\booltrue{@LRT at iterator}}%
+\ifboolexpr{bool{@LRT at iterator}}%
+{\xdef\@LRT at csvBlankLine{\@LRT at csvBlankLine\@LRT at blankFieldItem}}{}%
+}{}%
+}
+
+\gdef\@LRT at getAndProcessNextLine{%
+\unlessboolexpr{bool{@LRT at csvEOF}}{%
+{{%
+\@LRT at catcodeMagic%
+\@LRT at catcodes
+\read\@lrt at csvFile to\@LRT at x@nextLine%
+\ifeof\@lrt at csvFile\relax{\global\booltrue{@LRT at csvEOF}}\else%
+{\global\boolfalse{@LRT at csvEOF}}\fi%
+\xdef\@LRT at nextLine{\@LRT at x@nextLine}%
+}}%
+{{%
+\if at LRT@empty{\@LRT at nextLine}%
+{\global\let\@LRT at next\@LRT at exitGetAndProcessNextLine\relax}%
+{\ifx\@LRT at csvBlankLine\@LRT at nextLine\relax%
+{\global\let\@LRT at next\@LRT at exitGetAndProcessNextLine\relax}\else%
+{\global\let\@LRT at next\@LRT at repeatGetAndProcessNextLine\relax}\fi}%
+\@LRT at next%
+}}%
+}{}%
+}
+
+\gdef\@LRT at exitGetAndProcessNextLine{%
+\closein\@lrt at csvFile\relax\global\booltrue{@LRT at csvEOF}}
+
+\gdef\@LRT at repeatGetAndProcessNextLine{%
+\@LRT at processNextLine{\@LRT at nextLine\@LRT at fieldDelimiterBack}}
+
+\gdef\@LRT at setMacrosForOneEntry#1#2{%
+\expandafter\xdef\csname\@LRT at macroPrefix#1\endcsname{#2}%
+\@LRT at SecondifFieldEmpty{#2}%
+{\global\booltrue{\@LRT at macroPrefix#1}}%
+{\global\boolfalse{\@LRT at macroPrefix#1}}%
+}
+
+\gdef\@LRT at processNextLine#1{%
+\edef\@LRT at restArg{#1}%
+\edef\@LRT at frestArg{\@lrt at firstline}%
+\booltrue{@LRT at iterator}%
+\whileboolexpr{bool{@LRT at iterator}}{%
+\expandafter\@LRT at fieldNameIterator\@LRT at frestArg @%
+\edef\@LRT at restArgA{\@LRT at restArg\@LRT at fieldDelimiterBack}
+\expandafter\@LRT at dataLineIterator\@LRT at restArgA @%
+\@LRT at setMacrosForOneEntry{\@LRT at ffirstArg}{\@LRT at firstArg}%
+\if at LRT@empty{\@LRT at frestArg}%
+{\boolfalse{@LRT at iterator}}{\booltrue{@LRT at iterator}}%
+}{}%
+\@LRT at Input\relax%
+\@LRT at justProcessedMessage%
+}
+
+\gdef\@LRT at mergeData{%
+\providebool{@LRT at texEOF}%
+\immediate\openin\@lrt at csvFile=\@LRT at csv\relax%
+\providebool{@LRT at csvEOF}%
+\boolfalse{@LRT at csvEOF}%
+\ifeof\@lrt at csvFile\@LRT at failedToOpenMessage{\@LRT at csv}\fi%
+{{\@LRT at catcodes
+\read\@lrt at csvFile to\@lrt at firstlineX%
+\@LRT at setFirstLineAndBlankLine{\@lrt at firstlineX}
+}}%
+\booltrue{@LRT at iterator}
+\edef\@LRT at restArg{\@lrt at firstline}%
+\whileboolexpr{bool{@LRT at iterator}}{%
+\expandafter\@LRT at getCommaFieldDelimited\@LRT at restArg @%
+\providebool{\@LRT at macroPrefix\@LRT at firstArg}%
+\if at LRT@empty{\@LRT at restArg}%
+{\boolfalse{@LRT at iterator}}{\booltrue{@LRT at iterator}}%
+}{}%
+\@LRT at getAndProcessNextLine%
+\@LRT at NoMoreDataMessage%
+}
+
+\gdef\@LRT at weirdOption#1{\@ifundefined{@LRT at CO}%
+{\global\csletcs{#1}{@LRT@#1}}{{\global\csletcs{\@LRT at CO #1}{@LRT@#1}}}%
+}
+
+\@LRT at weirdOption{mergeFields}%
+\@LRT at weirdOption{Field}%
+\@LRT at weirdOption{ifFieldEmpty}%
+\@LRT at weirdOption{setDelimitersCommaQuote}%
+\@LRT at weirdOption{setDelimitersTabQuote}%
+\@LRT at weirdOption{makeMePublic}%
+
+\@LRT at setDelimitersCommaQuote
+
+\makeatother
+\endinput
+%%
+%% End of file `csvmerge.sty'.


Property changes on: trunk/Master/texmf-dist/tex/latex/csvmerge/csvmerge.sty
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Modified: trunk/Master/tlpkg/bin/tlpkg-ctan-check
===================================================================
--- trunk/Master/tlpkg/bin/tlpkg-ctan-check	2019-08-10 16:06:35 UTC (rev 51856)
+++ trunk/Master/tlpkg/bin/tlpkg-ctan-check	2019-08-10 21:19:47 UTC (rev 51857)
@@ -199,7 +199,7 @@
     crossreference crossreftools crossrefware crossword crosswrd
     cryptocode cryst
     cs csbulletin cslatex csplain csquotes csquotes-de
-    css-colors cstypo csvsimple cstex
+    css-colors cstex cstypo csvmerge csvsimple
     ctan-o-mat ctan_chk ctanbib ctanify ctanupload
     ctable ctablestack ctex ctex-faq
     cuprum cursolatex cuisine

Modified: trunk/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc
===================================================================
--- trunk/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc	2019-08-10 16:06:35 UTC (rev 51856)
+++ trunk/Master/tlpkg/tlpsrc/collection-latexextra.tlpsrc	2019-08-10 21:19:47 UTC (rev 51857)
@@ -227,6 +227,7 @@
 depend crossreftools
 depend csquotes
 depend css-colors
+depend csvmerge
 depend csvsimple
 depend cuisine
 depend currency

Added: trunk/Master/tlpkg/tlpsrc/csvmerge.tlpsrc
===================================================================


More information about the tex-live-commits mailing list