From e0c6872cf40896c7be36b11dcc744620f10adf1d Mon Sep 17 00:00:00 2001 From: Norbert Preining Date: Mon, 2 Sep 2019 13:46:59 +0900 Subject: Initial commit --- macros/latex/contrib/textmerg/textmerg.dtx | 890 +++++++++++++++++++++++++++++ macros/latex/contrib/textmerg/textmerg.ins | 63 ++ macros/latex/contrib/textmerg/textmerg.pdf | Bin 0 -> 252804 bytes 3 files changed, 953 insertions(+) create mode 100644 macros/latex/contrib/textmerg/textmerg.dtx create mode 100644 macros/latex/contrib/textmerg/textmerg.ins create mode 100644 macros/latex/contrib/textmerg/textmerg.pdf (limited to 'macros/latex/contrib/textmerg') diff --git a/macros/latex/contrib/textmerg/textmerg.dtx b/macros/latex/contrib/textmerg/textmerg.dtx new file mode 100644 index 0000000000..58befcbfa2 --- /dev/null +++ b/macros/latex/contrib/textmerg/textmerg.dtx @@ -0,0 +1,890 @@ +% \iffalse meta-comment +% \begin{macrocode} +%<*textmerg|plain> +\def\fileversion{2.01} +\def\filedate{1994/06/20} +\def\filename{textmerg.dtx} +\def\Copyright{Copyright (C) 1992,1994 Mike Piff, University of Sheffield, England} +% +% \end{macrocode} +% +% This file is placed in the public domain. No provision is made for +% support of the use of the facilities herein. +% +% For updates, contact your nearest CTAN site. +% +% \fi +% +% \changes{2.01}{1994/06/20}{First version for LaTeX2e} +% \changes{2.01a}{2000/08/25}{rf10@cam.ac.uk --- relaxation of licence +% terms} +% +%\CheckSum{349} +% +%\title{Text merges in \TeX\ and \LaTeX\thanks{This article originally +%appeared in TUGboat Vol 13(4), 1992, p518--523.}} +%\author{Mike Piff} +%\maketitle +%\thispagestyle{headings} +%\begin{abstract} +% In this article the author explains how to do some standard +% and not so standard word processor text merges in \TeX\ documents, +% using no other tools than \TeX\ itself. +% A common application is to the mail merge or form letter, +% where names and addresses are +% stored in a file, together with other bits of information, and a standard +% letter with variable fields embedded in it is customized for every name +% from this file. +% Another application is to the pretty-printing of the contents of a database. +% +% The macros described in |textmerg.sty| work equally +% in both plain \TeX\ and \LaTeX. However, this has meant heavy use +% of |\def| where |\newcommand| would have been preferable. +%\end{abstract} +% +%\tableofcontents +% +%\section{Introduction} +%It is often said that although \LaTeX\ is good at typesetting +%mathematics, it is wholly unsuitable for common word processor functions +%such as mail merges. +%The latter are easy to achieve in most ordinary word processors, +%but in its raw state \LaTeX\ is incapable of doing a mail merge, or, indeed, of +%generating the same block of text over and over again but with different +%parameters in each block, those parameters having been read from a subsidiary +%merge file. +%The latter file might possibly be the output from a database or any other +%program. +% +%This article aims to show the reader that such a repetitive task need not be +%as difficult as it at first appears. In \TeX, it is possible to hide many +%details of a facility inside a subsidiary style file, so that the user is +%unaware of what fearful processes are going on in the background. +%It is then possible to present the end-user with an extremely simple +%interface, perhaps simpler and more powerful than is available in other +%systems. +% +%In earlier TUGboat articles +%\cite{Bell:TB8-1-54,Garavelli:TB8-1-53,Lee:TB7-3-187,% +%McKinstry:TB8-1-60} it was shown how a standard letter could be +%customized by adding names and addresses from a separate file. I aim to show +%that it is possible to achieve far more than this with a fairly compact +%but general set of macros. +% +%\section{A simple example} +%Suppose that we have a list of student names and examination grades, one +%per student, and that we wish to send a letter to each student giving +%his/her exam grade. +%We must decide first what bits of information must be prepared in +%our subsidiary file, by looking at an example letter and finding out which +%items change from letter to letter. +% +%Suppose that one instance of our letter is the following, +%a \LaTeX\ example. +%\begin{verbatim} +%\begin{letter}{Miss Iusta Mo\\ +% 34 Winchester Road\\ +% Sheffield\\ +% England} +% \opening{Dear Miss Mo,} +% This letter is to inform you +% that you obtained grade A in +% your recent examinations. +% \closing{Yours faithfully,} +%\end{letter} +%\end{verbatim} +%We can see that we need to know the student's title, forename(s), surname, +%address and grade to compose such a letter. +% +%One of the simplest ways of achieving this effect is to prepare a file +%with lines of the form +%\begin{verbatim} +%\MyLetter{Mr}...{C} +%\end{verbatim} +%for each student and then simply |\input| it into a \LaTeX\ file in which +%|\MyLetter| has been defined as having five parameters. +%A problem with this approach is that we may not be able to coax the student +%database into producing such a file. +%Another problem is that we need something more subtle if there are fifty +%parameters. For example, we might want to print out the +%contents of the student database with one page per student, but it could be +%that there are fifty information fields per student. Even worse, +%the number of pieces of information per student might not be a +%constant number, because, say, we are printing out fields from a related +%file in which marks on individual examination papers are held. +% +%We shall tackle our simple example in a way that lends itself +%to more generality later on, and in a form that most database programs +%should be capable of handling. +% +%We thus prepare a subsidiary file |results.dat| +%with records of five fields in it. +%Each student is represented by five lines of this file, +% \begin{macrocode} +%<*results> +Miss +Iusta +Mo +34 Winchester Road\\Sheffield\\England +A +Mr +Arthur +Minit +43 Sheffield Road\\Winchester\\England +C +% +% \end{macrocode} +%and the student records appear one after another in this file. +%Thus both the field and record separators are carriage returns. +% +%\DescribeMacro{\Merge} +%\DescribeMacro{\Fields} +%\TeX\ itself needs to know three bits of information: +%\begin{enumerate} +% \item the name of the subsidiary file, +% \item the fields to read, and +% \item the template of the letter. +%\end{enumerate} +%We pass it this information in the following form +% \begin{macrocode} +%<*examp> +\documentclass[12pt]{letter} +\usepackage{textmerg} +\begin{document} +\Fields{\Title\Forenames\Surname + \Address\Grade} +\Merge{results.dat}{% +\begin{letter}{\Title\ \Forenames\ + \Surname\\\Address} + \opening{Dear \Title\ \Surname,} + This letter is to inform you + that you obtained grade \Grade\ in + your recent examinations. + \closing{Yours faithfully,} +\end{letter}} +\end{document} +% +% \end{macrocode} +%\LaTeX\ should +%open the subsidiary file and, for each set of five parameters, +%generate a letter in the |dvi| file. When it reaches the end of +%the merge file, \LaTeX\ should terminate execution of the |\Merge| +%command and presumably finish the document. +% +%\section{A few complications} +% +%Looking at the above example in a bit more generality, +%we see that we are reading +%records of $n$ fields from the merge file and placing them into a \TeX\ document +%in such a way that they replace $n$ preassigned control sequences. +%However, it may happen that the merge file is prepared by humans, who might +%possibly have inserted some extra blank lines into the file. Again, it +%could be that certain sorts of fields might be blank, +%whereas others can never be blank. +%Perhaps it would be better to build in some degree of error recovery. +% +%\DescribeMacro{\Fields} +%We shall make the assumption that the first field in any record is definitely +%a non-blank one and that we know beforehand whether each +%of the others might conceivably be blank. +%We make a modification to our |\Fields| statement. +%It can contain not only +%the field name control sequences but also the tokens |+| and~|-|, +%with the following interpretation. A |+| indicates that all following +%fields should be re-read until a non-blank result is obtained. +%A |-| indicates that any following fields could conceivably be blank, +%subject to the restriction that the very first field is always non-blank. +% +%Thus the command +%\begin{verbatim} +%\Fields{\a+\b\c-\d} +%\end{verbatim} +%would indicate that only |\d| is allowed to be blank, because the +%|+| token has no effect. +%In +%\begin{verbatim} +%\Fields{-\a\b+-\c+\d} +%\end{verbatim} +%the initial |-| token enables blank reading of data tokens, but the very +%first data token is not permitted to be blank anyway. +%Thus |\a| is read as a non-blank token and |\b| as a +%possibly blank token. +%The sequence |+-| now switches non-blank reading on and off again, +%so |\c| is read as possibly blank. +%Finally |\d| is non-blank. +% +%Another complication we allow is that the |\Fields| command can +%appear several times in our file. The interpretation is that +%the last occurrence of |\Fields| before we encounter the |\Merge| +%command will indicate the fields to be read for every record. Any +%occurrences of |\Fields| within the merged text indicate a new list +%of fields to be read when that command is encountered. This lets us +%do some conditional processing, such as\footnote{It is assumed that +%{\tt\string\Mrs} expands to {\tt Mrs}.} +%\begin{verbatim} +% \ifx\Title\Mrs +% \Fields{\MaidenName} +% \fi +%\end{verbatim} +%and also gives us some flexibility about the field order later on. +% +%It should also be stressed that the undefined control sequences +%appearing in the template need not +%correspond exactly to the fields in the subsidiary file. +%An example might be that the subsidiary file contains the text +%\begin{verbatim} +%Spriggs, Mr Abraham L +%\end{verbatim} +%and one field read is |\FullName|. +%\TeX\ would then have to pre-process this +%name to generate its several components as used in the template. +%The command |\PreProcess| could be included at the start of the template. +%\begin{verbatim} +%\def\parse#1, #2 #3\endparse{% +% \def\Surname{#1}\def\Title{#2}% +% \def\Forenames{#3}} +%\def\PreProcess{\expandafter +% \parse\FullName\endparse} +%\end{verbatim} +% +%An alternative and simpler looking approach to reading fields from a file +%|\fil| might be to define each such field as +%follows. +%\begin{verbatim} +%\def\Field#1{\def#1{\read\fil to#1#1}} +%\Field\Name \Field\Address \Field\Mark +%\end{verbatim} +%The first time |\Name| is encountered, it reads its own expansion +%from |\fil| and then expands itself. +%Henceforth, it has acquired its new expansion. +%The disadvantage is that |\Name| must appear in the +%text before any subsidiary field such as |\Surname| +%can be used. +% +%Finally we should consider the possibility that the second parameter of +%|\Merge| might be too large to fit into memory. We can clearly handle +%this problem by allowing the second parameter merely to consist of the text +%|\input template|, so that the root file handles two subsidiary +%files, one containing the template and the other containing the fields. +% +% +%\section{A complicated example} +% +%We will next look at an example in which the template contains a table +%of indeterminate length, albeit fixed width. So far our macros work +%in either plain \TeX\ or in \LaTeX, but the way in which these +%two packages handle +%tables is slightly different. However, the only difference that need +%concern us is that \LaTeX\ uses |\\| where plain \TeX\ uses |\cr|. +% +%\DescribeMacro{\MultiRead} +%The example given here is in \LaTeX, but our style will work equally well +%in plain \TeX. In our student letter we wish to insert a table of course +%codes and marks. Since each student did a different number of courses, we +%need some way of recognizing the end of the course list in the merge file. +%The default will be to insert a blank line at the end of such a sub-list. +%Thus, the following text appears before the close of the letter template. +%\begin{verbatim} +%Here are your marks on individual papers. +%\begin{center} +% \begin{tabular}{|lr|}\hline +% Code&Mark\\\hline +% \MultiRead{2}\\\hline +% \end{tabular} +%\end{center} +%\end{verbatim} +%The merge file now has the following structure. +%\begin{verbatim} +%Title +%... +%Grade +%Code +%Mark +%... +%Code +%Mark +%\end{verbatim} +%$\langle${\it blank\/}$\rangle$ +%\begin{verbatim} +%Title +%... +%\end{verbatim} +% +%\DescribeMacro{\MarkEnd} +%In other applications some of the fields in the table might possibly be blank. +%We then let the user change the $\langle${\it blank\/}$\rangle$ +%line marking the end of a list to some other string of his own choosing. +%\begin{verbatim} +%\MarkEnd{***} +%\end{verbatim} +% +%There might be multiple tables in the same template, +%with their data intermingled in the merge file with main fields. +%The generalized |\Fields| command allows us +%to order the merge file however we want. Thus we could have main fields, then +%a table, followed by more main fields, and so on. +% +%\DescribeMacro{\Process} +%A final complication is that the fields appearing in a table are essentially +%anonymous. By this I mean that they are transferred into the table as +%they are, without any pre-processing possible through appearing +%in the template as control sequences. If we wish what appears in +%the table to be different from what appears in the file, a mechanism is needed +%to tell \TeX\ that a certain column has to be treated in a certain way. +%The command +%\begin{verbatim} +%\Process{n}{\foo} +%\end{verbatim} +%will replace every field $\langle f\rangle$ read into column $n$ +%by |\foo{|$\langle f\rangle$|}|. +%It is even possible to do some numerical calculations by this method. +% +%Here is a \LaTeX\ example to illustrate the table processing +%features of |textmerg.sty|. +% \begin{macrocode} +%<*example> +\documentclass[12pt]{article} +\usepackage{textmerg} +\MarkEnd{***} +\Process{2}{\Advance} +\def\Advance#1{#1\addtocounter{page}{#1}} +\Fields{+\Name\Verb} +\begin{document} +\Merge{silly.dat}{% + Dear \Name,\par + Here is a table to \Verb\ at: + \Fields{\Width}% + \begin{tabular}{*{\Width}c} + \MultiRead\Width + \end{tabular}.\par + \Fields{\Adj}% + That was \Adj! + \clearpage} +\end{document} +% +% \end{macrocode} +%The effect of this file is not apparent until we see |silly.dat|. +%It is listed here. +% \begin{macrocode} +%<*silly> +Mike +look +3 +1 +2 +3 +11 +12 +13 +*** +good +Shelagh +gaze +2 +21 +22 +23 +24 +*** +horrid +% +% \end{macrocode} +% +% The same can be done in plain \TeX. +% \begin{macrocode} +%<*plainexample> +\input textmerg +\MarkEnd{***} +\Process{2}{\Advance} +\def\Advance#1{#1\global\advance\count0by#1} +\Fields{+\Name\Verb} +\Merge{silly.dat}{% + Dear \Name,\par + Here is a table to \Verb\ at: + \Fields{\Width}% + \vbox{\halign{\hfil{} ## {}\hfil&&\hfil{} ## {}\hfil\cr + \MultiRead\Width\cr + }}.\par + \Fields{\Adj}% + That was \Adj! + \vfill\eject} +\end + +% +% \end{macrocode} +% +% +%\StopEventually{ +%\begin{thebibliography}{GHWW84} +%\bibitem[{Bel}87]{Bell:TB8-1-54} +%Edwin~V. {Bell, II}. +%\newblock {{AutoLetter: A \TeX\ form letter procedure}}. +%\newblock {\em TUGBoat}, 8(1):54, April 1987. +% +%\bibitem[Gar87]{Garavelli:TB8-1-53} +%John~S. Garavelli. +%\newblock {{Form letter macros}}. +%\newblock {\em TUGBoat}, 8(1):53, April 1987. +% +%\bibitem[Lee86]{Lee:TB7-3-187} +%John Lee. +%\newblock {{Form letters}}. +%\newblock {\em TUGBoat}, 7(3):187, October 1986. +% +%\bibitem[McK87]{McKinstry:TB8-1-60} +%Graeme McKinstry. +%\newblock {{Form letters}}. +%\newblock {\em TUGBoat}, 8(1):60, April 1987. +%\end{thebibliography} +%} +% +% \section{Identification} +% +% This package can only be used with \LaTeXe, so +% an appropriate message is displayed when another +% format is used\footnote{However, some code is inserted +% to allow its use with plain \protect\TeX}. +% \begin{macrocode} +%<*textmerg> +\NeedsTeXFormat{LaTeX2e}[1994/01/01] +% \end{macrocode} +% +% Announce the package name and its version: +% \begin{macrocode} +\ProvidesPackage{textmerg}[\filedate] +% \end{macrocode} +% +% And display it on the terminal (and the log file): +% \begin{macrocode} +\typeout{Package `textmerg' <\filedate>.} +\typeout{\Copyright} +% +% \end{macrocode} +% +% The plain \TeX\ version will simply |\input| this package file. Thus +% we need to know that it will understand everything in the file. +% \begin{macrocode} +%<*plain> +\def\NeedsTeXFormat#1[#2]{} +\def\ProvidesPackage#1[#2]{} +\def\typeout#1{\immediate\write0{#1}} +\input textmerg.sty +% +% \end{macrocode} +% +% +%\section{Implementation of the simple case} +% +% \begin{macro}{\glet} +%For convenience we define a frequently used combination here. +% \begin{macrocode} +%<*textmerg> +\def\glet{\global\let} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\MergeFile} +% \begin{macro}{\InputFile} +%The subsidiary merge file is defined next. A macro is then defined that +%attempts to open it for reading. If that is unsuccessful, the file is +%closed and an error message is issued. +% \begin{macrocode} +\newread\MergeFile +\def\InputFile#1{% + \openin\MergeFile=#1 + \ifeof\MergeFile + \errmessage{Empty merge file}% + \closein\MergeFile + \long\def\MakeTemplate##1{% + \def\Template{}}% + \else\GetInput\fi} +% \end{macrocode} +% \end{macro} +% \end{macro} +%The command |\MakeTemplate| will be used later to generate the body +%of the form into which fields are inserted. We redefine it if the file +%is empty so that it produces no text. +% +% \begin{macro}{\GetInput} +%Because the conditional |\ifeof| does not return true until after an +%unsuccessful read operation, a mechanism of looking ahead is used which is +%similar to that found in Pascal. +% \begin{macrocode} +\def\GetInput{{\endlinechar=-1 + \global\read\MergeFile to\InputBuffer}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\SeeIfEof} +% \begin{macro}{\LookAgain} +%We set up a mechanism for deciding whether or not we have +%exhausted the merge file. It forces |\ifeof| to return true +%by skipping over blank lines. +% \begin{macrocode} +\def\SeeIfEof{% + \let\NextLook\relax + \ifeof\MergeFile + \else + \ifx\InputBuffer\empty + \LookAgain + \fi + \fi + \NextLook} +\def\LookAgain{\GetInput + \let\NextLook\SeeIfEof} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ifNonBlank} +% \begin{macro}{\AllowBlank} +% \begin{macro}{\DontAllowBlank} +%We can now prepare to read actual fields from the merge file. A conditional +%is used to indicate whether or not the field we are about to read is +%allowed to be blank. We also set up a mechanism for changing its value. +% \begin{macrocode} +\newif\ifNonBlank \NonBlankfalse +\def\AllowBlank{\global\NonBlankfalse} +\def\DontAllowBlank{\global\NonBlanktrue} +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ReadIn} +% \begin{macro}{\MissingField} +%Fields are actually read by means of the following command. Its only +%parameter is the name of the control sequence into which the field is +%read. +% \begin{macrocode} +\def\ReadIn#1{% + \ifNonBlank\SeeIfEof\fi + \ifeof\MergeFile + \gdef#1{??}\MissingField + \else + \glet#1\InputBuffer + \GetInput + \fi} +\def\MissingField{% + \message{Missing field in file}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\GlobalFields} +% \begin{macro}{\Fields} +%The |\Fields| command places its parameter into a token +%register called |\GlobalFields|. +%This command will be redefined by the |\Merge| command. +% \begin{macrocode} +\newtoks\GlobalFields +\def\Fields#1{\GlobalFields{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ParseFields} +% \begin{macro}{\EndParseFields} +%When a field token list is read, +%each individual token within it must be either +%read as a field or interpreted as a blank/nonblank switch. +%The next token is then read by tail recursion. +%It is assumed that the final token in the list is |\EndParseFields|. +%This must be defined to expand to something unlikely to be read as a +%value of one of the fields, and so we |\let| it to |\ParseFields|. +% \begin{macrocode} +\def\ParseFields#1{% + \ifx#1\EndParseFields + \let\NextParse\relax + \else + \let\NextParse\ParseFields + \ifx#1+\DontAllowBlank + \else + \ifx#1-\AllowBlank + \else\ReadIn#1 + \fi + \fi + \fi\NextParse} +\let\EndParseFields\ParseFields +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\ReadFields} +%We apply this command to our token register after expanding it. +% \begin{macrocode} +\def\ReadFields#1{\expandafter\ParseFields + \the#1\EndParseFields + \AllowBlank} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\Merge} +% \begin{macro}{\MakeTemplate} +%At long last we are ready to define the |\Merge| command itself. +%The first parameter is the filename of the subsidiary file and the second +%is the template or form into which fields are inserted. +%Since a |\Fields| command within the |\Merge| text is meant +%to act immediately on the token list that follows it, we redefine it +%to operate in a different way. +% \begin{macrocode} +\long\def\Merge#1#2{\begingroup% + \InputFile{#1}% + \def\Fields##1{% + \ParseFields##1\EndParseFields}% + \MakeTemplate{#2}\Iterate} +\long\def\MakeTemplate#1{\def\Template{#1}} +% \end{macrocode} +% \end{macro} +% \end{macro} +%The grouping keeps any changes to the definition of |\MakeTemplate| +%local to this merge. +%Thus several consecutive merges can be handled +%within one document. +%The |\endgroup| is supplied by the macro |\Iterate| +%when the merge file has been exhausted. +% +% \begin{macro}{\Iteratecounter} +% \begin{macro}{\Iterate} +%|\Iterate| must read the fields which were declared before it was entered, +%substitute them into its template and repeat itself using tail recursion +%if the end of the merge file has not been encountered. +% \begin{macrocode} +\countdef\Iteratecounter=2 +\Iteratecounter=0 +\def\Iterate{% + \global\advance\Iteratecounter by1 + \ReadFields\GlobalFields + \Template + \SeeIfEof + \ifeof\MergeFile + \def\NextIteration{% + \endgroup\closein\MergeFile}% + \else + \let\NextIteration\Iterate + \fi + \NextIteration} +% \end{macrocode} +% \end{macro} +% \end{macro} +%The point of the use of counter 2 in the above is that it is accessible to +%the print driver for page selection. +%Anyone who has started printing 150 letters, all with page number~1, +%only to run out of paper half way, will appreciate the use of this artifice! +% +%\section{Implementation of merged tables} +% +% \begin{macro}{\MultiCount} +% \begin{macro}{\MaxCount} +% \begin{macro}{\ifStartOfList} +%We set up two counters, one for the column we are reading and the +%other for the total number of columns in the table. +%We also need a conditional to mark the start of the table, so that +%we terminate each row correctly with |\\| or |\cr|, or nothing at all +%at the beginning of the first row. +% \begin{macrocode} +\newcount\MultiCount \newcount\MaxCount +\newif\ifStartOfList +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\MultiRead} +%The parameter to |\MultiRead| is the number of columns to read at a +%time. This command passes control to |\NextRead| after initializing +%certain parameters. +% \begin{macrocode} +\def\MultiRead#1{% + \ifnum#1>0 + \SelectCR + \MakeEmpty{#1}% + \global\StartOfListtrue + \glet\NextRead\MRead + \AllowBlank + \global\MaxCount=#1 + \NextRead + \fi} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\Emptyctr} +% \begin{macro}{\MakeEmpty} +%The command |\MakeEmpty| is required by the pre-pro\-cess\-ing +%of each field. +%The idea is that the command |\csname pr|$nn$|\endcsname|, +%which we will loosely call |\pr|$nn$, +%is executed on each field in column $nn$. However, most of these commands +%will be undefined, and so we equate each of those that has not been +%defined to |\empty|. +% \begin{macrocode} +\newcount\Emptyctr +\def\MakeEmpty#1{\Emptyctr=0 + \loop + \advance\Emptyctr by1 + \expandafter\ifx\csname + pr\the\Emptyctr\endcsname\relax + \expandafter\glet\csname + pr\the\Emptyctr\endcsname\empty + \fi + \ifnum\Emptyctr<#1 + \repeat} +% \end{macrocode} +% \end{macro} +% \end{macro} +%Note that, because of the way we are accessing it via |\csname|, +%the first time |\pr|$nn$ is encountered it equates to |\relax|. +% +% \begin{macro}{\Process} +%The command |\Process#1#2| defines |\pr#1| to mean |#2|. +% \begin{macrocode} +\def\Process#1#2{% + \expandafter\def\csname + pr#1\endcsname##1{#2{##1}}} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\MarkEnd} +%We need to know how the last row is to be recognized. The default is an +%empty line in the merge file. +% \begin{macrocode} +\def\MarkEnd#1{\gdef\EndMarker{#1}} +\MarkEnd{} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\NextLine} +% \begin{macro}{\NextField} +%We collect each row in a token register. The full row is assembled +%in |\NextLine| before being passed back to \TeX. Each field is +%read in |\TempField| and then placed temporarily into +%|\NextField|. +% \begin{macrocode} +\newtoks\NextLine \newtoks\NextField +% \end{macrocode} +% \end{macro} +% \end{macro} +%It is not necessary to do things this way; |\edef| can be used +%instead, but that approach might expand tokens prematurely. +% +% \begin{macro}{\AppendNextField} +%After the next field has been read, it is appended to |\NextLine|. +% \begin{macrocode} +\def\AppendNextField{% + \global\advance\MultiCount1 + \NextField=\expandafter{\TempField}% + \edef\Append{\NextLine= + {\the\NextLine&\csname + pr\the\MultiCount\endcsname + {\the\NextField}}}% + \Append} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\EndLine} +% \begin{macro}{\FinishLine} +%We need to insert the correct end marker after each row of the table. +%The token |\cr| must be disguised a little before it is acceptable +%in a \LaTeX\ document. +% \begin{macrocode} +\def\SelectCR{\glet\EndLine\\}% +% +%\def\SelectCR{\gdef\EndLine{\cr}}% +%<*textmerg> +\def\FinishLine{% + \ifStartOfList + \global\StartOfListfalse + \else\EndLine\fi} +% \end{macrocode} +% \end{macro} +% \end{macro} +%This makes the assumption that if |\array| is defined then we must be +%in \LaTeX. +% +% \begin{macro}{\StopProcessing} +%We need a command to finish off a table. This should reset |\NextRead| +%to |\AllowBlank| to terminate the tail recursion, +%and also do some +%error recovery in case the file ends prematurely in the middle of a row. +% \begin{macrocode} +\def\StopProcessing{% + \global\MultiCount\MaxCount + \glet\NextRead\AllowBlank} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\MRead} +%The command |\MRead| prepares to read a row of a table. It reads a +%field from the merge file and checks to see whether the table has been +%exhausted. +% \begin{macrocode} +\def\MRead{% + \global\MultiCount=1 + \ReadIn\TempField + \ifx\TempField\EndMarker + \StopProcessing + \else + \FinishLine + \NextField=\expandafter{\TempField}% + \edef\StartLine{\NextLine={\csname + pr1\endcsname{\the\NextField}}}% + \StartLine + \ConstructNextRow + \fi + \NextRead} +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\ConstructNextRow} +%Command |\ConstructNextRow| does most of the work of assembling a row of +%the table. +%It assembles |\MaxCount| fields +%at a time into |\NextLine| unless an error is encountered. +% \begin{macrocode} +\def\ConstructNextRow{% + \ifnum\MultiCount<\MaxCount + \loop + \ReadIn\TempField + \ifx\TempField\EndMarker + \glet\TempField\empty + \StopProcessing + \MissingField + \else + \ifeof\MergeFile + \glet\TempField\empty + \StopProcessing + \MissingField + \fi + \fi + \AppendNextField + \ifnum\MultiCount<\MaxCount + \repeat + \fi + \the\NextLine} +% +% \end{macrocode} +% \end{macro} +% +% +% \section{The documentation driver file} +% +% This is the driver file that produces this documentation. +% We use the document class provided by the \LaTeXe\ distribution +% for producing the documentation. +% \begin{macrocode} +%<*driver> +\documentclass{ltxdoc} +\RecordChanges +\begin{document} + \DocInput{textmerg.dtx} + \PrintIndex + \PrintChanges +\end{document} +% +% \end{macrocode} +% +% +% +%\Finale +% +%\endinput diff --git a/macros/latex/contrib/textmerg/textmerg.ins b/macros/latex/contrib/textmerg/textmerg.ins new file mode 100644 index 0000000000..f2e83d2abf --- /dev/null +++ b/macros/latex/contrib/textmerg/textmerg.ins @@ -0,0 +1,63 @@ +%% +%% This file will generate fast loadable files and documentation +%% driver files from the doc files in this package when run through +%% LaTeX or TeX. +%% +%% --------------- start of docstrip commands ------------------ +%% +\def\batchfile{textmerg.ins} +\input docstrip.tex +\preamble + +Copyright (C) 1992,1994 Mike Piff, University of Sheffield, England + +This file is now placed in the public domain. You are encouraged to +distribute it together with the sources from which it was generated. + +\endpreamble + +\keepsilent + +\Msg{*** Generating the package file ***} + +\generateFile{textmerg.sty}{f}{\from{textmerg.dtx}{textmerg}} + +\Msg{*** Generating the plain TeX file ***} + +\generateFile{textmerg.tex}{f}{\from{textmerg.dtx}{plain}} + +\preamble +\endpreamble + +\Msg{*** Generating the documentation driver ***} + +\generateFile{textmerg.drv}{f}{\from{textmerg.dtx}{driver}} + +\Msg{*** Generating example files ***} + +\generateFile{tmexamp1.tex}{f}{\from{textmerg.dtx}{examp}} +\generateFile{tmexamp2.tex}{f}{\from{textmerg.dtx}{example}} +\generateFile{tmexampp.tex}{f}{\from{textmerg.dtx}{plainexample}} + +\Msg{*** Generating data files ***} +%%These must be verbatim copies, so... +\makeatletter +\let\WritePreamble\@gobble +\let\WritePostamble\@gobble + +\generateFile{results.dat}{f}{\from{textmerg.dtx}{results}} +\generateFile{silly.dat}{f}{\from{textmerg.dtx}{silly}} + + +\ifToplevel{% +\Msg{***********************************************************} +\Msg{*} +\Msg{* To finish the installation you have to move the files} +\Msg{* textmerg.sty and textmerg.tex into a directory searched by TeX.} +\Msg{* To produce the documentation, run the file textmerg.drv through LaTeX.} +\Msg{* To see examples, run the files tmexamp1.tex and tmexamp2.tex LaTeX,} +\Msg{* or tmexampp.tex through plain TeX.} +\Msg{***********************************************************} +} + +\endinput diff --git a/macros/latex/contrib/textmerg/textmerg.pdf b/macros/latex/contrib/textmerg/textmerg.pdf new file mode 100644 index 0000000000..f50465e0d9 Binary files /dev/null and b/macros/latex/contrib/textmerg/textmerg.pdf differ -- cgit v1.2.3