FORMLETT: for Letters to Multiple Receivers

aa

Introduction

a

Format

\blockparas[<m>][<n>][<pre>][<post>]
\addressparas[<m>][<n>][<width>][<indent>]

{}

\textbox[<width]{<materials>}
\addressbox[<width>][<indent>]{<materials>}
\ADDRESSBOX{<width>}{<indent>}{<materials>}

<m>=1
<n>=1
<pre>=\noindent
<post>=\par
<width>= 8truecm
<indent>= 1.5em
\paras, \paras[1], \paras[][1],
\paras[1][], \paras[][]
\addressbox{one address line}
\addressbox[8truecm]{one address line}
\addressbox[][1.5em]{one address line}

\moreletter
  para-1-1;para-1-2;para-1-3; ...
 +para-2-1;para-2-2;...
 +   ...
 +para-n-1;para-n-2; ... ;para-n-m !
\delimiters{<A>}{<B>}{<C>}

\beginblockmode
   <para-1-1>
   <para-1-2>
     +       letter one
   <para-2-2>
     !
   <addr-1-1>
   <addr-1-2>
     !       letter two
\endblockmode

• •

\blockmarks\beginblockmode
  .......    force next empty line active
 <para-1-2>
 ------- -  mark end of 1st group
 <para-2-2>
 <para-2-3>
 ========   end of cluster
 <other clusters>
\endblockmode

\beginlinemode
  <name-1>
  <address-1-1>
  <address-1-2>
  <name-2>
  <1st part of addr-2-1>  %
  <continued part of line addr-2-1>
  <name-3>      % letter three
\endlinemode

${}{} {}

{}{}

2 – 3

6 – 3 (+): macro:->\x  <<paras>> macro:->\y

{}

Example

a

0001 \documentstyle[formlett]{article}
0002 \begin{document}
The line numbering on the right hand side is
for reference only, as in the other occurrences
later on.  The example reads as follows.

0003 \beginletter
0004 \paranames             % optional
  0005 \tt<<FULL NAME>>;%
  0006 \tt<<ADDRESS-etc>>;%
 0007 +\tt<<GIVEN NAME>>;%
  0008 \tt<<MISSING ITEM>>;%
  0009 \tt<<PHONE NUMBER>>!
0010 \loaddefaultparas      % optional

0011

0012 \NOPAGENUMBERS\parindent=0pt
0013 \noindent{\it\paras[1]}\par
0014 \blockparas[2]\par\bigskip

0015

0016 Dear \paras[1][2],\par\medskip
0017 We have been looking for
0018 \paras[2][2] for quite a while
0019 without any luck, could you help
0020 us out? If so, please ring
0021 \paras[3][2]. \par\medskip
0022 Cheers!\hfill Michael\vfill\eject
0023 \endletter
0024 \preview \showparas

The above is a typical letter format or form
letter.  Command \preview in the last line
gives

1 – 1

1 – 2 (+): macro:->\noindent  <<paras>> macro:->\par

Dear   2 – 1 ,
We have been looking for   2 – 2 for quite a
while without any luck, could you help us out?
If so, please ring   2 – 3 .

Cheers!                                 Michael

and, the name of the parameters are displayed
via \showparas as follows

<<FULL NAME>>
<<ADDRESS-etc>>

Dear <<GIVEN NAME>>,
We have been looking for <<MISSING ITEM>> for
quite a while without any luck, could you help
us out?  If so, please ring <<PHONE NUMBER>>.

Cheers!                                 Michael

In other words, we can have a good
understanding about what a letter format does
without reading its source code, which will be
very handy for archiving and retrieving letter
templates.  To provide defaults for letter
parameters and output new letters via
blockmode, we may add

0025 \paradefaults       % optional
  0026 To whom this may concern
 0027 +Sir or Madam;something;%
  0028 061-225-9905!

0029

0030 \blockmarks
0031 \beginrawblockmode{}

0032

0033 Mrs L Stenson
0034 #1-20 Sunset Street
0035 Hillside, Norway
0036 ------
0037 Louise
0038 a Bible
0039 220-8888
0040 =========

0041

0042 ......

0043

0044 Above empty line active

0045

0046 \endrawblockmode

We note the parameters contain special
characters #.  That is the reason why we used
\beginrawblockmode.  Now suppose we have to
wrap a very long address line, we could use
\addressbox to control an individual parameter.
The following is a typical case

0047 \defaultmarks
0048 \moreletter
   0049 S Wales,;%
   0050 \addressbox[2in][1em]{%
   0051 University of Manchester Institute
   0052 of Science and Technology, This is
   0053 a long address line: it will be
   0054 wrapped up automatically.}%
 0055 +;a \TeX\ package \gstr\ manual and
   0056 many more (\cstr)!

which is manifested in the following output

S Wales,

University of Manchester
  Institute of Science and
  Technology, This is a long
  address line:  it will be
  wrapped up automatically.

Dear Sir or Madam,
We have been looking for a TEX package + manual
and many more (!)  for quite a while without
any luck, could you help us out?  If so, please
ring 061-225-9905.

Cheers!                                 Michael

Please note that the default parameters have
been used there.  In the case of putting only
name and address into a form letter, we may
typically use linemode via e.g.

  0057 \beginlinemode
    0058 Z Jiang
    0059 UNE, Arimdale

0060

    0061 T Ribbons
    0062 UMIST, Manchester
  0063 \endlinemode
  0064 \end{document}

If one saves lines 4-22 to file myletter.let,
lines 25-63 or simply lines 57-63 to file
myletter.adr, then we can for instance produce
via LaTEX the form letter for multiple receivers
by
  \documentstyle[formlett]{article}
  \begin{document}
  \inputletter{myletter.let}
  \showparas \preview
  \paradefaults To whom it may concern!
  \inputfile{myletter.adr}
  \beginlabels % 1st parameter group as address
  \inputfile{myletter.adr} % for labels
  \endlabels
  \end{document}
Ifoneputscommands\beginlablesand\endlabelsat
e.g.immediately after line 2 and 63 respectively,
then one gets all the posting labels instead.
If one puts commands \beginfile{scratch.adr} and
\endfile there respectively, then by adding after
\endfile the commands
 \inputfile{scratch.adr}
 \beginlabels \inputfile{scratch.adr} \endlabels
one  gets  both  form  letters  and  the  labels.
If  one  insists  on  not  writing  out  auxiliary
scratch  files,  then  use  \input  formlett.sty
\initstyle[styles]{article}{preamble} toreplace
\documentstyle   [formlett,    styles]{article}
preamble \begin{document}, which will be valid for
LaTEX but ignored for TEX , and will enable one to
use \labelsquit at the end to read in the current
documentagainwithallthelettersthereconverted
into the corresponding labels. If you only want
to execute certain commands the first time round
(i.e.before \labelsquit re-reads the file again),
use \firstread{commands} for this purpose.

Macros

One of the main technical features of this set
of macros is the extensive use of arrays, both
one dimensional and two dimensional.  The one
dimensional array STK that we use is
essentially an user-defined stack, while the
two dimensional arrays LET and DEF are more
like structure or record in other programming
languages.  First let us make clear that an
array (or stack) of name, say ABC, will contain
elements \ABCm~ for one dimensional and
\ABCm*n~ for two dimensional case, where m and n
are some non-negative integers representing row and
column numbers respectively.  The first element,
if necessary, will be used to denote the length of
that raw.  Thus, \ABC1*0~ for instance will denote
the number of elements in the first raw of a two
dimensional array ABC.

Let us now look at how a mechanism of
defaulting macro parameters is formulated.  For
this purpose, we first define a stack STK and
its stack pointer \STKcount by
  \def\make@STKcount{\csname newcount\endcsname
    \STKcount\global\STKcount=0\relax}
  \ifx\STKcount\undefined@\def\next{%
    \make@STKcount}\else\def\next{}\fi\next
  \long\def\push#1{\global
    \advance\STKcount1\relax
    \expandafter\gdef\csname STK\the
    \STKcount\string~\endcsname{#1}}
  \def\popnil{\expandafter\let
    \expandafter\temp@macro\csname
     STK\the\STKcount\string~\endcsname
    \ifnum\STKcount>0\global\expandafter
      \let\csname STK\the\STKcount
      \string~\endcsname=\undefined@
      \global\advance\STKcount-1%
    \else
      \def\temp@macro{}\global\STKcount=0%
    \fi\relax }
  \def\pop{\popnil\temp@macro}
The first four lines of code will ensure that
the stack pointer will not be flushed if this
useful subset of macros is loaded again by for
instance another style file in the middle of a
TEX document.  With the above code, we can stack
away anything by \push{anything} and later use
\pop to recall them or \popnil to remove one
element from the stack.

So, how can we make defaults for certain empty
macro parameters?  The simplest case is perhaps
  \long\def\get@nepara[#1][#2]{{%
    \def\next@{#2}%
    \ifx\next@\empty\push{#1}\else
    \push{#2}\fi}\ag@in}
  \long\def\get@para\left@#1\right@{%
    \def\check@{%
    \ifx[\next@
    \def\full@####1{\get@nepara[#1]####1}%
    \else
    \def\full@{\get@nepara[#1][#1]}\fi
    \full@}%
  \futurelet\next@\check@}
Basically, \get@onepara[<A>][<B>] will push the
default <A> to the stack STK unless <B> is
nonempty.  And \get@para\left@<A>\right@ will
look at the next token to be read, if it is
character `[', then reads in a macro parameter
in the form of [<B>] and then push <B> to the
stack STK, otherwise push the default <A> to
that stack.  For the more general case, we need
to define
  \long\def\do@nepara
    \left@#1\right@#2\p@r@end{%
    \gdef\p@r@data{#2}\global\advance
    \p@r@count1\get@para\left@#1\right@}
  \def\ag@in{\ifx\p@r@data\empty
    \def\next@{\relax\getp@r@s\run@CMD}%
    \else\def\next@{\expandafter\do@nepara
         \p@r@data\p@r@end}%
    \fi\next@}
  \def\run@CMD{\csname STK\the\STKcount
    \string~\endcsname}
  \newcount\p@r@count
  \long\def\st@ckparas#1\p@r@end{%
    \global\p@r@count=0%
    \gdef\p@r@data{#1}\ag@in}
so that \st@ckparas\left@<A>\right@...
\left@<B>\right@...  \p@r@end will look for
parameters enclosed in [] one by one,
exhausting all the defaults paired by \left@
and \right@.  If future tokens inside [] are
not found, or empty, the default tokens inside
the corresponding pair \left@\right@ will be
used.  The new or default tokens will be pushed
to the general-purpose stack STK for a later
use, while \p@r@count records the total number
of the default macro parameters.  We note that on
exit of \st@ckparas, the control is passed to \runCMD.

Once all macro parameters are pushed to the
stack, we may transfer them to separate toks
\p@r@one to \p@r@nine (an easier-to-use format)
defined by
  \newtoks\p@r@one\newtoks\p@r@two
  \newtoks\p@r@three\newtoks\p@r@four
  \newtoks\p@r@five \newtoks\p@r@six
  \newtoks\p@r@seven\newtoks\p@r@eight
  \newtoks\p@r@nine
  \def\clrp@r@s{\global\p@r@one={}%
   \global\p@r@two={}\global\p@r@three={}%
   \global\p@r@four={}\global\p@r@five={}%
   \global\p@r@six={}\global\p@r@seven={}%
   \global\p@r@eight={}\global\p@r@nine={}}

where \clrp@r@s clears all the parameter toks.
We can then retrieve parameters from the stack
STK to the parameter toks via \getp@r@s with
the following code
  \newcount\temp@count
  \def\getp@r@s{\temp@count=\p@r@count
  {\loop
   \ifnum\temp@count>0
   \expandafter\let\expandafter
   \t@macro\csname STK\the\STKcount
     \string~\endcsname
   \ifcase\temp@count
   \or\global\p@r@one=\expandafter{\t@macro}%
   \or\global\p@r@two=\expandafter{\t@macro}%
   \or\global\p@r@three=\expandafter{\t@macro}%
   \or\global\p@r@four=\expandafter{\t@macro}%
   \or\global\p@r@five=\expandafter{\t@macro}%
   \or\global\p@r@six=\expandafter{\t@macro}%
   \or\global\p@r@seven=\expandafter{\t@macro}%
   \or\global\p@r@eight=\expandafter{\t@macro}%
   \or\global\p@r@nine=\expandafter{\t@macro}%
   \else
    \errmessage
    {Parameter capacity exceeded.}%
   \fi \global\expandafter\let
   \csname STK\the\STKcount
   \string~\endcsname=\undefined@%
   \global\advance\STKcount-1%
   \global\advance\temp@count-1\relax
   \fi
   \ifnum\temp@count>0\repeat}}

We are now ready to use the above mechanism to
default macro parameters for some already
defined macros.  Suppose we have already
defined a macro \crudemac[<A>][<B>] which takes
two macro parameters <A> and <B>, and we want
to define a new macro \smartmac which behaves
like \crudemac but will default the macro
parameters <A> and <B> to for instance 9 and 88
respectively.  For this purpose, we may define
\smartmac via
  \def\smartmac{\push{%
   \edef\next@@{\noexpand
   \crudemac[\the\p@r@one][\the\p@r@two]}%
   \popnil\clrp@r@s\next@@}\st@ckparas
   \left@9\right@\left@88\right@\p@r@end}
This way, all the followings
  \crudemac[9][88], \smartmac[9][88],
  \smartmac, \smartmac[], \smartmac[][],
  \smartmac[9], \smartmac[9][], \smartmac[][88]
are the same under the assumption that we shall
not use characters `[' and `]' for the macro
parameters themselves, and that \crudemac will
not change any \catcode inside.  The reason for
this latter condition lies in the fact that
when \smartmac looks at the next character, the
character is in a sense already read.  If
\crudemac changes the \catcode of that
particular character, then the one that is
already read via \futurelet will have a
misleading \catcode.  If one has to change \catcode
inside but wants to avoid this possible misbehavior,
always put full number of empty brackets `[]' for
the defaults, or put a \relax immediately afterwards.
Better still, make the last parameter to appear in
a mandatory `{}' form rather than the `[]' form via
the #{ mechanism [1], so that those square brackets
can be dropped off.

For example, we as a by-product also defined a
100% verbatim mode by
  \begin@@rawlist[A][B][C][D][E][F]G
   <general text>
  \endrawlist
where, for the line numbering of the raw text,
A, ..., G represent respectively the initial
value, increment step, number of digits, font,
horizontal position of text, horizontal shift
of numbering, and the password to leave raw
text mode.  Incidentally, \linecount records
the current line numbering count.  Our purpose
is to define \beginrawlist so that its format
is
  \beginrawlist[A][B][C][D][E][F]{G}
in which A to F are optional while {G} is
mandatory even though G can be empty ---
implying \endrawlist is the password to leave
the raw-text mode.  For this purpose, we first
define
\def\begin@rawlist[#1][#2][#3][#4][#5][#6]#{%
    \begin@@rawlist[#1][#2][#3][#4][#5][#6]}%
to make `{}' pair compulsory for #7, then we
provide the defaults for A to F as \linecount,
1, 0, \tiny, 0pt and 0pt respectively via
\def\beginrawlist{\push{%
 \edef\next@@{\noexpand\begin@rawlist
 [\the\p@r@one][\the\p@r@two][\the\p@r@three]%
 [\the\p@r@four][\the\p@r@five][\the\p@r@six]}%
 \popnil\clrp@r@s\next@@}%  end of push
 \font\tiny@rm=cmr5%
 \edef\temp@macro{%
  \noexpand\left@\the\linecount\noexpand\right@
  \noexpand\left@1\noexpand\right@
  \noexpand\left@0\noexpand\right@
  \noexpand\left@\noexpand\tiny@rm
           \noexpand\right@
  \noexpand\left@0pt\noexpand\right@
  \noexpand\left@0pt\noexpand\right@}%
  \expandafter\st@ckparas\temp@macro\p@r@end}%

Likewise,   we  could  also  similarly  define
\printfile[...]{filename.ext} so  that  `[...]'
takes a same defaulting scheme.

There are several tiny but very useful macros
in formlett which are used again and again.
One of such macros is for testing if one string
contains another string.  The following
\test@str tests if string #1 is contained in
string #2
  \newif\iftemp@if \newtoks\temp@toks
  % return \temp@iftrue if yes,
  %  \first@half,\second@half are global
  \long\def\test@str#1#2{%
    \long\def\strip@endmark##1\s@fetymarkI
      #1\s@fetymark{\gdef\second@half{##1}}%
    \long\def\strip@markI##1\s@fetymarkI
      \s@fetymark{\gdef\first@half{##1}}%
    \long\def\p@rse##1#1##2\s@fetymark{%
      \gdef\first@half{##1}%
      \gdef\second@half{##2}%
      \ifx\second@half\empty
       \strip@markI##1\s@fetymark\temp@iffalse
      \else
       \strip@endmark##2\s@fetymark\temp@iftrue
      \fi}%
    \temp@toks={#2\s@fetymarkI#1\s@fetymark}%
    \expandafter\p@rse\the\temp@toks }%
The \first@half will contain the tokens upto
but excluding the substring #1, while the
\second@half will contain the tokens after the
first appearance of #1.  Should #2 not contain
string #1 at all, then \first@half is the whole
string #2 whereas \second@half is empty.

The small macros such as the above one and the
stack utilities, though built for the main
purpose of formlett, provide also a good
`infrastructure' for other house-keepings.  One
of the sidekicks of this type is our macro for
commenting out blocks of text inside a TEX file.
Basically, \begincomment{password} will set all
characters of code 0 to \MAX@CHR@CODE (=255 by
default) to catcode 11 or 12, and look for the
password, or \endcomment in the absence of a
password, to quit the comment mode.  In comparison
to a very compact macro comment.sty (currently at
version 3.0) written by Victor Eijkhout, quitting
comment mode via a password here seems more flexible.

As for the other macros in formlett, it is
difficult to explain them without printing out
all of them.  So instead, we shall explain
simply one of the strategies in parsing the
letter parameters.  Suppose W is a list of
parameters separated by `+' and ended by `!',
i.e. W is like <A>+<B>+...+<S>!.  Then it
will be easy to parse all the parameters one by
one (to a stack for instance) if we can know
whether there is precisely one parameter left
over.  To detect it, we use
  \newif\ifl@stline
  \long\def\testl@stline
    #1+#2!#3\s@fetymark{%
   \def\next{#2}\ifx\next\empty
   \l@stlinetrue\else\l@stlinefalse\fi
   \def\next{#3}\def\nextsample{+!}%

   \ifx\next\nextsample\l@stlinefalse\fi}

Then the command \testl@stline W +!\s@fetymark
will  set  \l@stlinetrue  if  there  is  only  one
parameter left in W, and will set \l@stlinefalse
if otherwise.

Finally, for those wizard users who want to do
everything their own way, we just note that if
for instance the 3rd letter parameter of the
2nd group of a cluster is given as <A>, then
\LET2*3~ will contain \b@group\relax<A>\e@group
right after a cluster is read in.  \DEF2*3~, on
the other hand, contains the corresponding
default parameter in the same fashion.
Furthermore, the command
\checkparas[m][n]{LET} will copy the content
of \paras[m][n], minus the `wrapping' extra tokens
\b@group\relax and \e@group, to \cachedata and set
\ifemptyparas to true or false depending on whether
the content is empty or not.  This way, a user may
even change the characteristics of his letter template
by first testing the content of the supplied individual
parameters.  However, we note that if \loaddefaultparas
is executed, then the LET array, when some of its
elements are not supplied, will contain the corresponding
elements of the DEF array.  Hence care must be exercised
under such circumstances, when interpreting the \cachedata
generated by \checkparas[m][n]{LET}.  If necessary,
we may use \delparadefaults to delete current default
parameter array DEF so as to conduct \checkparas{LET}
more precisely.  So if anyone wants to manipulate
furthermore letter parameters inside a letter template,
he or she will now at least know where to look at.

References

[1].  Knuth D E, The TEXbook, Reading, Mass.,
Addison-Wesley, 1992.

[2].  Piff M, Text merges in TEX and LaTEX,
TUGboad, 13(4):518, 1993.

[3].  Damrau J and Wester M, Form letters with
3-across labels capacity, TUGboat, 13(4):510,
1991.

Appendix

In the followings, we give a brief summary of
the new commands given by formlett version 2.3.

Let m and n be numbers, p, q and r be
dimensions, A, B, P, G, C and T be tokens,
and X be a box.  Furthermore, we shall denote
by R a full set of letter parameters ended by
`!', with `;' separating parameters inside a
same group and `+' separating different
parameter groups.  We moreover denote R by F,
when `; + !' there can be replaced by `P G C'
respectively if \delimiters{P }{G}{C} is
issued.  In the commands tabulated below, the
macro parameters contained in squared brackets support
default.  In particular, the defaults are m=1, n=1,
p=8truecm, q=1.5em, r=3pt, A=\noindent, B=\par,
\previewfalse, \localparastrue and \nodefaultsfalse.

=/ℑℑdefaults:

\paras[][]  parameter of group \blockparas[][][][]

to the last parameter of group, each preceded by and followed by , wrapped by if =\relax \addressparas[][][][]

to the last parameter of group, each put into a box of width with indent for wrapped portions \loaddefaultparas

fill empty parameters with defaults \checkparas[][]

parameter of group copied to \cachedata; \ifemptyparas is true if element is empty; is often LET or DEF \moreletter

use parameters to output a new letter \paranames  use as parameter names \paradefaults

use as default parameters \delparadefaults  delete default parameters \delimiters  use , , as delimiters \defaultmarks  use ‘; + !’ as delimiters \blockmarks

use ‘....’, ‘----’, ‘====’ as delimiters \preview

highlight parameter positions \showparas

display parameter names, if any \inputletter  input letter content \inputfile  input

delimiters for letter content (template)

normal letter parameters cluster-wise for line-by-line blocks of parameters, empty lines active within each cluster for line-by-line parameters, empty lines delimit clusters raw text mode; nonempty replaces \endrawblockmode to mark end raw text parameters and active spaces etc raw text lines for one form letter -columns separated by distance comment out lines, nonempty replaces \endcomment to mark last full line for comment write text verbatim to file file.ext (empty implies scr@tch@.tex), nonempty replaces \endfile to mark last full line \PAGENO=1  page number reset to 1 \NOPAGENUMBERS  no page numbers \textbox[]  into box of width \boxmore[]

add borderline to box at a distance \addressbox[][]

into box of width , with wrapped options indented by \previewfalse

given parameters instead of highlighted boxes will be shown \localparastrue

letter parameters put into before displayed \nodefaultsfalse

take defaults for empty letter parameters \previewtrue  cf. above \localparasfalse \nodefaultstrue

=\linecount,

=1, =0,

=\tiny@rm,
=0pt, =0pt,
=\endrawlist

verbatim listing, line count from , step , digits , font , text position , numbering shift , end mark

defaults: =6 etc  verbatim listing of file.ext

defaults:

=20pt,
=\tt\raggedright,

=1, =1,

=2.6in, =2em

form letters become labels: address taken from to last parameter of group, with width , indent , borderspace and font toks

\firstread

toks will not be read if the file is re-read via

\labelsquit
\initstyle[]

initiation for \labelsquit,with styles , documentstyle and preamble

\initclass[][]

similar to \initstyle (

is LaTEX2e options), but retains native LaTEX2e when applicable

defaults:

see that for \beginlabels

quit after converting letters to labels by reading the current document or file.ext

\newarray\abc

make array named abc along with \abc and

\checkabc

\delarray\abc  delete array named abc

\abc()=

assign tokens to \abc(); \abc() \abc() for =

\abc()

value of \abc(), if not followed by ‘=’

\dataheight

current array dimension: cf. \abc()

\readarray

equivalent to \N(1)=, ..,

\N()=
\checkabc()

copy \abc() to

\cachedata; set
\ifemptydata to

true/false accordingly

\readstyles

read files to with default extension .sty; @’s catcode set to 11 during input

=Jiang Z    Formlett:   for letters to multiple receivers •End of Document•