diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/generic/formlett |
Initial commit
Diffstat (limited to 'macros/generic/formlett')
-rw-r--r-- | macros/generic/formlett/formlett.sty | 1868 | ||||
-rw-r--r-- | macros/generic/formlett/prog_manual.pdf | bin | 0 -> 198659 bytes | |||
-rw-r--r-- | macros/generic/formlett/prog_manual.tex | 1906 | ||||
-rw-r--r-- | macros/generic/formlett/user_manual.pdf | bin | 0 -> 172966 bytes | |||
-rw-r--r-- | macros/generic/formlett/user_manual.tex | 1113 |
5 files changed, 4887 insertions, 0 deletions
diff --git a/macros/generic/formlett/formlett.sty b/macros/generic/formlett/formlett.sty new file mode 100644 index 0000000000..418dafd360 --- /dev/null +++ b/macros/generic/formlett/formlett.sty @@ -0,0 +1,1868 @@ +% MAKE FORM LETTER for multiple receivers via +% plain TeX, LaTeX 2.09 or LaTeX2e +% +% written by Zhuhan JIANG +% University of Western Sydney +% Parramatta NSW 2150. +% Email: z.jiang@uws.edu.au +% +% FILENAME: formlett.sty +% VERSION: 2.3 May 2003 +% COPYRIGHT: GNU convention preferred. +% +% +% NEW COMMANDS +% \paras \blockparas \addressparas \PAGENO \NOPAGENUMBERS +% \paradefaults \loaddefaultparas \delparadefaults \paranames +% \showparas \preview \previewtrue \previewfalse \existfile +% \localparastrue \localparasfalse \nodefaultstrue \nodefaultsfalse +% \beginpilemode \endpilemode \delimiters \defaultmarks \blockmarks +% \beginblockmode \endblockmode \beginlinemode \endlinemode +% \beginrawblockmode \endrawblockmode \beginrawlinemode \endrawlinemode +% \beginletter \endletter \moreletter \inputletter \inputfile +% \boxmore \textbox \addressbox \ADDRESSBOX \fillzeros +% \beginlist \endlist \beginrawlist \endrawlist \printfile +% \begincomment \endcomment \begincolumns \endcolumns \readstyles +% \beginlabels \endlables \smooth \initstyle \initclass \labelsquit +% \firstread \beginfile \endfile \checkparas \ifemptyparas \cachedata +% \newarray \delarray \readarray \checkARRAYNAME \ifemptydata +% +% +% NOTE +% You only need to know a SMALL portion of the above commands +% in order to use the style file: easy to use is our key purpose! +% +% +% VERSION HISTORY: +% 1.0 8/93 +% 1.2 10/93 major rewriting, only basic mode still +% compatible with 1.0; +% support for raw text list added +% 1.3 fixed a minor bug of 1.2; +% support for commenting out letters added +% 2.0 11/93 compatible with 1.2, 1.3; +% labels utility added; support for fixed number +% of parameter lines added +% 2.03 2/94 TAB char represents 8 spaces instead of 4; +% fixed a bug on multi-columns output +% 2.1 1/95 added parameter checker and dynamic array facilities; +% compatible with LaTeX2e; +% slight name changes: \figbox -->\textbox +% 2.2 1/95 renamed an internal command (\array) to avoid +% conflict with LaTex. +% 2.3 5/2003 separated programmer's manual from the style file, +% added a new user manual. +% +% +% %SIMPLE EXAMPLE in Plain TeX: +% +% \input formlett.sty +% \beginletter \pageno=1 +% \paras--\paras[2]--\paras[3]\par +% \paras[1][2] -- \paras[2][2] -- \paras[4][4] -- \paras[][2] +% \vfill\eject +% \endletter +% \preview +% \moreletter % first letter +% 1-ONE;;;1-FOUR+% +% 2-ONE;2-TWO;2-THREE;++;;;4-FOUR! +% +% \moreletter % second letter +% 1-one;1-two;1-three;1-four +% +2-one;;2-three; ++ ;;;4-four! +% \end +% +% +% %TYPICAL EXAMPLE in LaTeX +% +% \documentstyle[formlett]{article} +% \textwidth=3.2in +% \begin{document} +% +% \beginletter +% \paranames % optional +% \tt<<FULL NAME>>;% +% \tt<<ADDRESS-etc>>;% +% +\tt<<GIVEN NAME>>;% +% \tt<<MISSING ITEM>>;% +% \tt<<PHONE NUMBER>>! +% \loaddefaultparas % optional +% +% \NOPAGENUMBERS\parindent=0pt +% \noindent{\it\paras[1]}\par +% \blockparas[2]\par\bigskip +% +% Dear \paras[1][2],\par\medskip +% We have been looking for +% \paras[2][2] for quite a while +% without any luck, could you help +% us out? If so, please ring +% \paras[3][2]. \par\medskip +% Cheers!\hfill Michael\vfill\eject +% \endletter +% \preview \showparas +% +% \paradefaults % optional +% To whom this may concern +% +Sir or Madam;something;% +% 061-225-9905! +% +% +% %\beginlabels % optional +% % uncomment the above line and its matching +% % \endlabels later on, if you want to get the +% % mailing labels. +% % So one LaTeX run to get all the letters, and +% % an EXTRA run to produce all the labels by +% % activating \beginlabels +% +% +% \blockmarks +% \beginblockmode +% +% Mrs L Stenson +% \#1-20 Sunset Street +% Hillside, Norway +% ------ separate groups +% Louise +% a Bible +% 220-8888 +% ========= separate cluster +% +% ...... force entry next line +% +% Above empty line active +% +% \endblockmode comment ignored +% +% \defaultmarks +% \moreletter +% S Wales,;% +% \addressbox[2in][1em]{% +% University of Manchester Institute +% of Science and Technology, This is +% a long address line: it will be +% wrapped up automatically.}% +% +;a \TeX\ package \gstr\ manual and +% many more (\cstr)! +% +% \beginlinemode +% Z Jiang +% UNE, Arimdale +% +% T Ribbons +% UMIST, Manchester +% \endlinemode +% +% \beginpilemode +% +% C Anderson;42nd Street;USA+Christine;your service invoice! +% +% D Holmes;Flat \#2, Finneybank Rd;London+David;the tax receipt;% +% 071-902 7799! +% +% \endpilemode +% +% %\endlabels +% % uncomment the above line and if its matching +% % \beginlabels is set previously for labels +% +% +% \begincomment{} % this is only a tip +% % Comment out the letters that you already sent +% +% \moreletter parameters for letter one! +% \moreletter letter two! +% +% \endcomment +% +% \end{document} +% +% +%%%%% To run the above examples, remove the first '%' character in each line +% +% +% +% +%BEGINMACROS +% +% +\ifx\ENDINPUT\undefined\else\message{skipped}\endinput\fi +% +\message{2.3 <26/5/2003>}% +% +{\catcode`\@=11\relax \def\temp@macro{\space\space\space\space}% +\wlog{\temp@macro FORMLETT version 2.3 May 2003 By Z Jiang}% +\wlog{\temp@macro University of Western Sydney, Australia}% +\wlog{\temp@macro Email: z.jiang@uws.edu.au}}% +% +% SAVE @'s STATUS +% +\xdef\EntryFormLett{\the\catcode`\@}\catcode`\@=11\relax +\gdef\MAX@CHR@CODE{255}% maximum charcode for saving catcode +% % change it to 127 for TeX 2 +% % may change it to 0 if no raw mode is to be used +% IS LATEX ? +% +\newif\ifISLATEX +\ifx\pageno\undefined@\global\ISLATEXtrue\else\global\ISLATEXfalse\fi +% +% a private \l@@p +\def\l@@p#1\repe@t{\def\b@dy{#1}\iter@te}% +\def\iter@te{\b@dy\let\n@xt=\iter@te \else\let\n@xt=\relax\fi \n@xt}% +\let\repe@t=\fi % +% +% NEW MEASURES etc +% +\def\new@measures{% + \def\temp@@macro##1##2##3{\expandafter\ifx\csname ##3temp##2##1\endcsname + \relax\edef\next{\noexpand\csname new##1\noexpand\endcsname + \csname ##3temp##2##1\endcsname}% + \else\let\next\relax\fi\next}% + \def\temp@macro##1{% + \temp@@macro{##1}{@}{}\temp@@macro{##1}{@@}{}\temp@@macro{##1}{@@@}{}}% + \temp@macro{count}\temp@macro{toks}\temp@macro{box}\temp@macro{read}% + \temp@@macro{if}{@}{if}\temp@@macro{if}{@@}{if}\temp@@macro{if}{@@@}{if}% + \def\temp@@macro##1{\expandafter\ifx\csname temp##1dim\endcsname + \relax\edef\next{\noexpand\csname newdimen\noexpand\endcsname + \csname temp##1dim\endcsname}% + \else\let\next\relax\fi\next}% + \temp@@macro{@}\temp@@macro{@@}\temp@@macro{@@@}% +}% +\let\temp@@@macro=\wlog\def\wlog#1{}\new@measures +% +% +%%% GENERAL STACK +% +\def\make@STKcount{\csname newcount\endcsname + \STKcount\global\STKcount=0\relax}% +\ifx\STKcount\undefined@ + \def\next{\make@STKcount}\else\def\next{}\fi +\next % ensures stack pointer not flushed if this piece of code + % is loaded again +% +\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 % \temp@macro for pop +}% +% +\def\pop{\popnil\temp@macro}% +% +% +%% GET PARAMETERS +% +\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@}% +% +\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}% +% +% +% PARAMETER ASSIGNMENT +% +%% \newcount\temp@count +\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\getp@r@s{\temp@count=\p@r@count +{\loop + \ifnum\temp@count>0 % + \expandafter\let\expandafter + \temp@macro\csname STK\the\STKcount\string~\endcsname + \ifcase\temp@count + \or \global\p@r@one=\expandafter{\temp@macro}% + \or \global\p@r@two=\expandafter{\temp@macro}% + \or \global\p@r@three=\expandafter{\temp@macro}% + \or \global\p@r@four=\expandafter{\temp@macro}% + \or \global\p@r@five=\expandafter{\temp@macro}% + \or \global\p@r@six=\expandafter{\temp@macro}% + \or \global\p@r@seven=\expandafter{\temp@macro}% + \or \global\p@r@eight=\expandafter{\temp@macro}% + \or \global\p@r@nine=\expandafter{\temp@macro}% + \else \errmessage{Parameter capacity exceeded.}% + % this should never happen: TeX's max para no. is 9 + \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}}% +% +\def\clrp@r@s{%GLOBALLY clear +\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={}}% +% The above is the minimum for setting default parametrisation +% +% +% ARRAY STRUCTURE +% +% \newarray\ARRAYNAME +% \delarray\ARRAYNAME +% +% \ARRAYNAME(A1,..,An)={T} +% \readarray{ARRAYNAME}{ B1 & B2 & ... & Bm } +% \dataheight +% +% \data(A1,...,An)=\data( A1 + (A2-1)*\dataheight + +% ... + (An-1)*\dataheight^{n-1} ) +% if \normalindextrue +% =\data( An + (An-1 -1)*\dataheight + +% ... + (A1)*\dataheight^{n-1} ) +% if \normalindexfalse +% +% \checkARRAYNAME(A1,..,An) +% \ifemptydata valid when \checkARRAYNAME is just executed +% \cachedata: keeps the data of \ARRAYNAME(m) +% when \checkARRAYNAME(m) is executed +% +% e.g. +% +% \newarray\Table +% \readarray{Table}{one&two& \unknownmacro && &six} +% \Table(7)={seven} +% \dataheight=0 % or 1 or < 0 +% \Table(7) = \Table(2,6,1) % 7=1+(2-1)+(6-1)+(1-1) +% \normalindexfalse +% \dataheight=3 +% \Table(7) = \Table(1,7) = \Table(3,1) +% \normalindextrue +% \Table(7) = \Table(7,1) = \Table(1,3) +% +% \checkTable(4) \ifemptydata (4)=empty \fi +% \checkTable(5) \ifemptydata\else (5)=nonempty \fi +% \ifx\cachedata\space ={\tt <space>}\fi +% \checkTable(1000) \ifemptydata (1000)=empty \fi +% +% \delarray\Table +% +% +\xdef\EntryArrayJob{\the\catcode`\@}\catcode`\@=11\relax +\newif\ifemptydata \newcount\dataheight +\newif\ifnormalindex \normalindexfalse +% +\newcount\array@width \newcount\index@count \newcount\index@total +\newif\ifone@VEC \newif\if@rev@index +% \newtoks\temp@toks \newcount\temp@count +% \newcount\temp@@count \newcount\temp@@@count +% +\long\def\assign@VEC#1(#2)=#3{\temp@count=#2 \relax +\get@max@count{total@#1}\temp@count +\expandafter\gdef\csname#1#2\string~\endcsname{#3}} +\def\get@VEC#1(#2){\csname#1#2\string~\endcsname} +\def\clrarr@y#1(#2){% + \global\expandafter\let\csname#1#2\string~\endcsname=\undefined@} +% +\def\testarr@y#1(#2){% + \expandafter\let\expandafter\temp@macro\csname#1#2\string~\endcsname + \ifx\temp@macro\relax \def\temp@macro{}\fi}% +% +\def\arr@y#1(#2){\def\check@VEC{% + \ifx=\next@VEC \def\full@VEC####1{\assign@VEC#1(#2)####1}% + \else \def\full@VEC{\get@VEC#1(#2)}\fi \full@VEC}%check@VEC +\futurelet\next@VEC\check@VEC} +% +\def\get@index(#1)#2\safty@mark{\one@VEC#2,\safty@mark + \def\next@@VEC{#1}\ifx\next@@VEC\empty\def\next@@VEC{\array@width}\fi + \if@rev@index + {\temp@count=1 \advance\index@count1 \relax + \ifnum\index@count<\index@total + \loop \multiply\temp@count \next@@VEC + \advance\index@count-1 \relax + \ifnum\index@count>0 \repeat + \fi \global\temp@@count\temp@count }% + \else \multiply\temp@@count \next@@VEC \fi + \ifnum\temp@@count=0 \temp@@count=1 \relax \fi + \advance\temp@count-1 \ifnum\temp@count<0 \temp@count=0 \fi + \multiply\temp@count \temp@@count + \advance\temp@@@count by \temp@count \advance\index@count1 + \ifone@VEC + \def\next@@VEC{\index@total=\index@count \advance\temp@@@count1 }% + \else \one@VEC#2\safty@mark \edef\next@@VEC{\noexpand\get@index(#1)% + \the\temp@toks\noexpand\safty@mark}% + \fi \next@@VEC}% +% +\def\one@VEC#1,#2\safty@mark{\def\temp@macro{#2}\temp@toks={#2}% + \ifx\temp@macro\empty \one@VECtrue \else \one@VECfalse \fi + \temp@count=#1 \relax }% +% +\def\get@all@index(#1)#2\safty@mark{% + \temp@@@count=0 \temp@@count=0 \index@count=0 \@rev@indexfalse + \get@index(#1)#2\safty@mark + \ifnormalindex\else + \temp@@@count=0 \temp@@count=0 \index@count=0 \@rev@indextrue + \get@index(#1)#2\safty@mark \fi }% +% +\def\read@array[#1]#2#3{\temp@count=1 + \def\one@item##1#1##2\safty@mark{\def\temp@macro{##2}\temp@toks={##2}% + \ifx\temp@macro\empty\else + \def\temp@macro{\one@item##2\safty@mark}\fi + {\temp@toks={##1}\def\temp@@macro{\arr@y{#2}(\the\temp@count)=}% + \expandafter\temp@@macro\expandafter{\the\temp@toks}}% + \expandafter\edef\csname total@#2\endcsname{\the\temp@count}% + \advance\temp@count1 \temp@macro}% + \one@item#3#1\safty@mark }% +% +\def\strip@esc#1{\temp@count=\escapechar \escapechar=-1 % + \temp@toks=\expandafter{\string#1}\escapechar\temp@count} +\def\get@max@count#1#2{\edef\temp@macro{\csname #1\endcsname}% + \ifnum\temp@macro<#2 \expandafter\xdef\csname #1\endcsname{\the#2}\fi}% +% +\def\newarray#1{\strip@esc{#1}% + \expandafter\gdef\csname total@\the\temp@toks\endcsname{0}% + \expandafter\edef\csname\the\temp@toks\endcsname(##1)% + {\noexpand\get@all@index(\noexpand\dataheight)##1\noexpand\safty@mark +% \noexpand\get@max@count{total@\the\temp@toks}\noexpand\temp@@@count + \noexpand\arr@y{\the\temp@toks}(\noexpand\the\noexpand\temp@@@count)}% + \expandafter\edef\csname check\the\temp@toks\endcsname(##1)% + {\noexpand\get@all@index(\noexpand\dataheight)##1\noexpand\safty@mark + \noexpand\testarr@y{\the\temp@toks}(\noexpand\the + \noexpand\temp@@@count)\noexpand\let\noexpand\cachedata + \noexpand\temp@macro\noexpand\ifx\noexpand\temp@macro\noexpand\empty + \noexpand\emptydatatrue\noexpand\else\noexpand\emptydatafalse + \noexpand\fi}}% +% +\def\delarray#1{\strip@esc{#1}% delete array globally + \temp@count=0 \temp@@count=\csname total@\the\temp@toks\endcsname + \loop \expandafter\global\expandafter\let + \csname\the\temp@toks\string~\endcsname\undefined@ + \advance\temp@count1 % + \ifnum\temp@count<\temp@@count \repeat % global loop for less memory + \global\expandafter\let\csname total@\the\temp@toks\endcsname\undefined@ + \global\expandafter\let\csname \the\temp@toks\endcsname\undefined@ + \global\expandafter\let\csname check\the\temp@toks\endcsname\undefined@ }% +% +\def\readarray#1#2{\read@array[&]{#1}{#2}}% +% +\catcode`\@=\EntryArrayJob\relax +% +% +% EXIST FILE ? +% +% \temp@iftrue if the file #1 exist when tested via \existfile{#1}% +% \newread\temp@read +\def\existfile#1{\temp@iftrue +\openin\temp@read=#1\relax +\ifeof\temp@read \temp@iffalse \fi \closein\temp@read}% +% +% RAW CHARACTERS +% +\def\raw@chars[#1][#2][#3][#4][#5]{% + % #1=11, #2=\`=12, #3=^^I=10, #4=char32=10, #5=^^M=5 + % all chars of catcode 11 or 12 are NOT changed + \temp@count=-1\relax % + \l@@p \advance\temp@count1\relax % + \temp@@count=\the\catcode\temp@count \relax + \ifnum\temp@@count=11 \else + \ifnum\temp@@count=12 \else + \catcode\temp@count=11\relax \fi\fi + \ifnum\temp@count<\MAX@CHR@CODE\repe@t % + \catcode`\%=#1\catcode`\^=#1\catcode`\_=#1% + \catcode`\&=#1\catcode`\$=#1\catcode`\#=#1% + \catcode`\{=#1\catcode`\}=#1\catcode`\@=#1% + \catcode`\~=#1\catcode`\\=#1% + \catcode`\`=#2\catcode`\^^I=#3\catcode`\ =#4% + \catcode`\^^M=#5\relax % +}% +% +\chardef\temp@char=`\`\catcode`\`=13\relax +\def\rm@ligature{\def`{\null\string`}}% +\catcode\temp@char=12\relax +% +\catcode`\^^I=13\relax% +\def\set@tab{\def^^I{\ \ \ \ \ \ \ \ }}\catcode`\^^I=10\relax% +\catcode`\^^M=13\relax\def\set@cr{\def^^M{\par}}\catcode`\^^M=5\relax% +\catcode`\ =13\relax\def\set@space{\def {\ }}\catcode`\ =10\relax% +% +% TEST EMPTY LINE +% +\catcode`\ =13\relax% space active +% +% Delete leading spaces (catcode=13) +% Throw the rest to \temp@macro +\long\def\del@truespaces#1#2\s@fetymark{\temp@iffalse% +\def\temp@macro{#1}\def\one@space{ }\def\temp@@macro{}% +\ifx\temp@macro\one@space% front spaces not allowed +\def\temp@macro{#2}% +\ifx\temp@macro\empty\temp@iftrue% +\else\def\temp@@macro{\del@truespaces#2\s@fetymark}\fi% +\fi% +\temp@@macro}% +% +\catcode`\ =10\relax% +% +% \temp@iftrue if empty line, +% \temp@macro holds nonspace part (space catcode=13 or normal) +\long\def\is@emptyline#1{\def\one@space{ }% + \def\temp@macro{#1}\def\temp@@macro{}\temp@iftrue + \ifx\temp@macro\empty + \else \ifx\temp@macro\one@space + \else \def\temp@@macro{\del@truespaces#1\s@fetymark}% + \fi + \fi +\temp@@macro}% +% +% TEST STRING +% +%% \newif\iftemp@if \newtoks\temp@toks +% return \iftemp@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 }% +% +% #1 supposed to a toks register +\long\def\test@tokstr#1#2{% #1 =toks + \temp@toks={#2}% + \edef\temp@macro{\noexpand\test@str{#1}{\the\temp@toks}}% + \temp@macro }% +% +% MAKE ESCAPE CHAR +% +% \esc@=the character '\' of catcode 11 +\newtoks\name@endtoks \newtoks\true@endtoks +\catcode`\*=0\relax *catcode`*\=11*relax +*gdef*esc@{\}%*name@endtoks={\endrawlist}% +*catcode`*\=0*relax \catcode`\*=12\relax +% +% +% TWO DIMENSIONAL ARRAY / LETTER PARAMETER STACKS +% +\def\stack@num@twodim[#1]{\temp@count=-1% + \expandafter\ifx\csname #1*0\string~\endcsname\undefined@ + \temp@count=0\fi + \expandafter\ifx\csname #1*0\string~\endcsname\relax + \temp@count=0\fi \relax + \ifnum\temp@count<0 + \temp@count=\csname #1*0\string~\endcsname \relax + \else \expandafter\gdef + \csname #1*0\string~\endcsname{0}% + \fi }% +% +% +\newcount\R@Wcount \R@Wcount=0 +\newcount\R@Dcount \R@Dcount=0 +\newif\ifload@defaults \load@defaultsfalse % i.e. to LET stack (not DEF) +% +\long\def\rowpush#1{% +\ifload@defaults % for default para stack + \ifnum\R@Dcount>0\else \global\R@Dcount=1 \fi + \stack@num@twodim[DEF\the\R@Dcount]% + \advance\temp@count1\relax + \expandafter\gdef + \csname DEF\the\R@Dcount*\the\temp@count\string~\endcsname{#1}% + \expandafter\xdef\csname DEF\the\R@Dcount*0\string~\endcsname + {\the\temp@count}% +\else + \ifnum\R@Wcount>0\else \global\R@Wcount=1 \fi + \stack@num@twodim[LET\the\R@Wcount]% + \advance\temp@count1\relax + \expandafter\gdef + \csname LET\the\R@Wcount*\the\temp@count\string~\endcsname{#1}% + \expandafter\xdef\csname LET\the\R@Wcount*0\string~\endcsname + {\the\temp@count}% +\fi +}% +% +\def\clr@row{% +\ifload@defaults % for default para stack + \stack@num@twodim[DEF\the\R@Dcount]% + {\loop \ifnum\temp@count>0\relax + \global\expandafter\let + \csname DEF\the\R@Dcount*\the\temp@count\string~\endcsname=\undefined@% + \advance\temp@count-1\relax \fi + \ifnum\temp@count>0 \repeat}% + \global\expandafter\let + \csname DEF\the\R@Dcount*0\string~\endcsname=\undefined@ +\else + \stack@num@twodim[LET\the\R@Wcount]% + {\loop \ifnum\temp@count>0\relax + \global\expandafter\let + \csname LET\the\R@Wcount*\the\temp@count\string~\endcsname=\undefined@% + \advance\temp@count-1\relax \fi + \ifnum\temp@count>0 \repeat}% + \global\expandafter\let + \csname LET\the\R@Wcount*0\string~\endcsname=\undefined@ +\fi +}% +% +\def\clr@allrows{% +\ifload@defaults +% for default para stack + {\loop \ifnum\R@Dcount>0\relax {\clr@row}% + \global\advance\R@Dcount-1\relax \fi + \ifnum\R@Dcount>0 \repeat}% + \global\R@Dcount=0\relax +\else + {\loop \ifnum\R@Wcount>0\relax {\clr@row}% + \global\advance\R@Wcount-1\relax \fi + \ifnum\R@Wcount>0 \repeat}% + \global\R@Wcount=0\relax +\fi +}% +% +% LOAD DEFAULT +% update paras in LET array with defaults in DEF array +% +% \newtoks\temp@toks +\newif\ifnodefaults \nodefaultsfalse +\def\sub@loop{% \sub@loop is always called via {\sub@loop} + \loop % inner loop: reverse order + \temp@@count=0 % flag -> not counter: 0=no need for updating + \expandafter\ifx\csname LET\the\temp@@@count*\the\temp@count + \string~\endcsname\undefined@ \temp@@count=1\fi + \expandafter\ifx\csname LET\the\temp@@@count*\the\temp@count + \string~\endcsname\relax \temp@@count=1\fi\relax + % + \expandafter\ifx\csname LET\the\temp@@@count*\the\temp@count + \string~\endcsname\trivi@l \temp@@count=1\fi\relax + % + \ifnum\temp@@count>0 + \expandafter\let\expandafter\temp@macro + \csname DEF\the\temp@@@count*\the\temp@count\string~\endcsname + \temp@toks=\expandafter{\temp@macro}% + \ifx\temp@macro\relax \global\expandafter\let + \csname LET\the\temp@@@count*\the\temp@count\string~\endcsname + =\undefined@ + \else \expandafter\xdef + \csname LET\the\temp@@@count*\the\temp@count\string~\endcsname + {\the\temp@toks}\fi + \fi + \advance\temp@count-1\relax + \ifnum\temp@count>0 + \repeat}% for speed +% +% above macro not to stand alone +% it is removed from \loaddefaultparas for better speed +% +\def\loaddefaultparas{% +\ifnodefaults\else % active only if \nodefaultsfalse + \def\trivi@l{\b@group\relax\e@group}% == empty parameter + \temp@count=\R@Wcount + {\loop % legalise LET array's extension + \advance\temp@count1\relax + \ifnum\temp@count>\R@Dcount\else + \expandafter\xdef + \csname LET\the\temp@count*0\string~\endcsname{0}\fi + \ifnum\temp@count<\R@Dcount \repeat}% + \ifnum\R@Wcount<\R@Dcount \global\R@Wcount=\R@Dcount \fi +% + \temp@@@count=1 % row counter + {\loop + \stack@num@twodim[DEF\the\temp@@@count]% + \temp@@count=\temp@count\relax + \stack@num@twodim[LET\the\temp@@@count]% + \ifnum\temp@count<\temp@@count \temp@count=\temp@@count\relax \fi + % update LET array's counter + \expandafter\xdef + \csname LET\the\temp@@@count*0\string~\endcsname{\the\temp@count}% + % now \temp@count is current max row width + {\sub@loop}% update a row + \advance\temp@@@count 1\relax + \ifnum\temp@@@count>\R@Wcount\temp@@count=0\else\temp@@count=1\fi + \relax + \ifnum\temp@@count>0 \repeat}% +\fi % of \ifnodefaults +}% +% +% HOUSE KEEPING +% +\newif\ifshowp@r@ \showp@r@true % default mode +\def\show@paras{\showp@r@true\lettercontents}% +\def\showparas{\show@paras}% +% +\def\b@group{\iflocalparas\bgroup\fi}% +\def\e@group{\iflocalparas\egroup\fi}% +% +\long\def\lettercontents{}% +% +\def\inputletter#1{\save@catcodes[OLD][0][\MAX@CHR@CODE][/13/]\beginletter + \save@catcodes[TMP][0][\MAX@CHR@CODE][]\get@catcodes[OLD]\existfile{#1}% + \iftemp@if \input#1% + \else \immediate\write16{Letter File <#1> not found.}\fi + \get@catcodes[TMP]\endletter}% +% +\def\inputfile#1{\relax\existfile{#1}\iftemp@if + \input#1 \else \immediate\write16{File <#1> not found.}\fi + \relax}% +% +\def\preview{\preview@}% +% +% +% PAGE NUMBER +% for both TeX and LaTeX +% +\ifISLATEX + \let\PAGENO=\c@page \def\NOPAGENUMBERS{\pagestyle{empty}}\else + \let\PAGENO=\pageno \let\NOPAGENUMBERS=\nopagenumbers \fi +% +% +% SINGLE PARAMETER +% +\def\paras{\push{% + \edef\next@@{\noexpand\rowcolp@r@s[\the\p@r@two][\the\p@r@one]}% + \popnil\clrp@r@s\next@@}\st@ckparas\left@1\right@\left@1\right@\p@r@end}% +% +% NOTE: +% 1. default parameters are enclosed between \left@ and \right@, +% and is supplied after \st@ckparas. All defaults (may be empty) must +% be supplied. +% 2. \rowcolp@r@s is the name of the macro that doesn't take defaults +% 3. \the\p@r@one, .., \the\p@r@nine represent #1,.., #9 . +% 4. \paras is the new macro that behaves like \rowcolp@r@s but now +% takes defaults +% 5. change accordingly if one wants to implement defaults to other +% existing macros. +% 6. limitation: '[' and ']' are now not allowed as macro parameters. +% +% +\def\rowcolp@r@s[#1][#2]{% + \ifpreview {\leavevmode + \boxmore[1pt]{\boxmore[3pt]{\hbox + {\font\tiny@rm=cmr5\tiny@rm ~#1 -- #2~}}}}\relax + \else \csname LET#1*#2\string~\endcsname \fi}% +% +% +% GET \paras[m][n] AND TEST EMPTYNESS +% \checkparas[m][n]{T} stores true content of \Tm*n~ into \cachedata +% and set \ifemptyparas to true if the content is empty +% +% Typical use: \checkparas[m][n]{LET} \checkparas[m][n]{DEF} +% +\newif\ifemptyparas +\def\check@@paras[#1][#2]#3{% + \expandafter\let\expandafter\cachedata\csname #3#1*#2\string~\endcsname + \ifx\cachedata\relax \def\cachedata{}\else + \temp@toks=\expandafter{\cachedata}% + \def\cachedata\b@group\relax##1\e@group\safty@mark{\def\cachedata{##1}}% + \expandafter\cachedata\the\temp@toks\safty@mark \fi + \ifx\cachedata\empty\emptyparastrue\else\emptyparasfalse\fi}% +\def\check@paras[#1][#2]#{\check@@paras[#1][#2]}% +\def\checkparas{\push{% + \edef\next@@{\noexpand\check@paras[\the\p@r@two][\the\p@r@one]}% + \popnil\clrp@r@s\next@@}\st@ckparas\left@1\right@\left@1\right@\p@r@end}% +% +% +% ADDRESS BOXES +% +% \newbox\temp@box\newdimen\temp@dim +\long\def\fig@box[#1]#2{%#1=width of box + \setbox\temp@box=\vbox{\hsize #1\noindent\strut #2\strut}% + \temp@dim=\ht\temp@box + \advance\temp@dim\dp\temp@box\advance\temp@dim-2ex + \dp\temp@box=\temp@dim\ht\temp@box=2ex\box\temp@box}% +% +\long\def\textbox{\push{% + \edef\next@@{\noexpand\fig@box[\the\p@r@one]}% + \popnil\next@@}\st@ckparas\left@8truecm\right@\p@r@end}% +% +\ifx\figbox\undefined@\let\figbox\textbox\fi % compatibility with ver 2.03 +% +\long\def\box@more[#1]#2{\vbox{\hrule\hbox{\vrule\kern#1\vbox + {\kern#1\hbox{#2}\kern#1}\kern#1\vrule}\hrule}}% +% +\long\def\boxmore{\push{% + \edef\next@@{\noexpand\box@more[\the\p@r@one]}% + \popnil\next@@}\st@ckparas\left@3pt\right@\p@r@end}% +% +\long\def\address@box[#1][#2]#3{% + \noindent\hskip#2\textbox[#1]{\hskip-#2\relax #3}}% +% +\long\def\addressbox{\push{% + \edef\next@@{\noexpand\address@box% + [\the\p@r@one][\the\p@r@two]}% + \popnil\next@@}\st@ckparas\left@8truecm\right@\left@1.5em\right@\p@r@end}% +% +\long\def\ADDRESSBOX#1#2#3{% intended for \blockparas + \noindent\hskip#2\textbox[#1]{\hskip-#2\relax #3}}% +% +% +% BLOCKPARAS and ADDRESSPARAS +% +\newcount\blockC@Lcount \newcount\blockT@Pcount +\long\def\block@paras[#1][#2][#3][#4]{% #2-th group, from #1 to end, + % each para is surrounded by #3 from left and #4 from right + % If #4=\relax, an extra {} is applied to the \paras so that + % #3 may be a macro acting on the \paras + \def\next@one{#2}\def\next@two{#1}\def\next@three{#3}\def\next@four{#4}% + \ifx\next@one\empty\def\next@one{1}\fi + \ifx\next@two\empty\def\next@two{1}\fi + \ifpreview {\leavevmode % three line border box + \boxmore[1pt]{\boxmore[1pt]{\boxmore[3pt]{\hbox + {\font\tiny@rm=cmr5\tiny@rm \font\small@tt=cmtt8% + ~\next@one ~-- \next@two~(+):~ + \small@tt\meaning\next@three + ~<<paras>> \meaning\next@four}}}}}\relax + \else + \blockC@Lcount=-1% + \expandafter\ifx\csname LET\next@one*0\string~\endcsname\undefined@ + \blockC@Lcount=0\fi + \expandafter\ifx\csname LET\next@one*0\string~\endcsname\relax + \blockC@Lcount=0\fi \relax + \ifnum\blockC@Lcount<0 + \blockC@Lcount=\csname LET\next@one*0\string~\endcsname\relax \fi + \blockT@Pcount=\next@two + \advance\blockT@Pcount by-1\relax + \l@@p % not to be grouped + \advance\blockT@Pcount1\relax + \ifnum\blockT@Pcount>\blockC@Lcount\else + \def\temp@macro{\relax}% some overhead, but safer + \ifx\next@four\temp@macro % add {} to \paras, so that a macro can act + % on the whole \paras + \next@three{\csname LET\next@one*\the\blockT@Pcount\string~\endcsname}% + \else + \next@three\csname LET\next@one*\the\blockT@Pcount + \string~\endcsname\next@four + \fi + \fi + \ifnum\blockT@Pcount<\blockC@Lcount\repe@t +\fi}% +% +% +\def\blockparas{\push{% + \edef\next@@{\noexpand\block@paras[\the\p@r@one][\the\p@r@two]% + [\the\p@r@three][\the\p@r@four]}% + \popnil\clrp@r@s\next@@}\st@ckparas\left@1\right@\left@1\right@% + \left@\noindent\right@\left@\par\right@\p@r@end}% +% +% +\long\def\address@paras[#1][#2][#3][#4]{% + \block@paras[#1][#2][\par\noindent\ADDRESSBOX{#3}{#4}][\relax]\par}% +% +\def\addressparas{\push{% + \edef\next@@{\noexpand\address@paras[\the\p@r@one][\the\p@r@two]% + [\the\p@r@three][\the\p@r@four]}% + \popnil\clrp@r@s\next@@}\st@ckparas\left@1\right@\left@1\right@% + \left@8truecm\right@\left@1.5em\right@\p@r@end}% +% +% +% MAIN PROCESSING MACRO +% +\newif\ifconti@one \newif\ifconti@two +\newif\ifl@stline \newif\ifl@stLINE +\newif\ifpreview \previewfalse +\newif\iflocalparas \localparastrue +% +\newtoks\name@paratoks \name@paratoks={;}% +\newtoks\name@grouptoks \name@grouptoks={+}% +\newtoks\name@clustertoks \name@clustertoks={!}% +% +% +\long\def\delimiters#1#2#3{% LONG MACRO +% +%%%% MAIN GET: get a group of parameters from a cluster +% +\long\def\refillst@ck##1#3{\def\d@t@one{##1#3}% + {\loop\conti@onefalse + \ifx\d@t@one\undefined@ \else \@ddoneline\conti@onetrue\fi + \ifconti@one\repeat}}% +% +\long\def\testl@stline##1#2##2#3##3\s@fetymark{% + \def\next{##2}\ifx\next\empty + \l@stlinetrue \else \l@stlinefalse \fi + \def\next{##3}\def\nextsample{#2#3}% + \ifx\next\nextsample\l@stlinefalse\fi}% +% +\long\def\l@stline##1#3{{\sub@fill{##1}}\let\d@t@one=\undefined@}% +\long\def\onem@reline##1#2##2#3{{\sub@fill{##1}}\def\d@t@one{##2#3}}% +% +\long\def\@ddoneline{\temp@toks=\expandafter{\d@t@one}% + \expandafter\testl@stline\the\temp@toks#2#3\s@fetymark + \ifl@stline \expandafter\l@stline\the\temp@toks + \else \expandafter\onem@reline\the\temp@toks \fi}% +% +%%%% SUB GET : get parameters from a group +% +\long\def\sub@fill##1{% + \ifload@defaults \global\advance\R@Dcount by 1\else + \global\advance\R@Wcount by 1\fi\relax + \clr@row\def\d@t@two{\relax##1#3}% %%care: extra \relax added + {\loop\conti@twofalse + \ifx\d@t@two\undefined@ \else \@ddoneLINE\conti@twotrue\fi + \ifconti@two\repeat}}% +% +\long\def\moreletter##1#3{\showp@r@false + \clr@allrows\refillst@ck##1#3\lettercontents\clr@allrows\showp@r@true}% +% +\def\endletter{\relax}% +\long\def\true@letter##1\endletter{\long\def + \lettercontents{\begingroup\catcode`\^^M=5\relax + \def\pstr{#1}\def\gstr{#2}\def\cstr{#3}\relax##1\relax\endgroup}}% +\let\beginletter\true@letter +% +\long\def\testl@stLINE##1#1##2#3##3\s@fetymark{% + \def\next{##2}\ifx\next\empty% + \l@stLINEtrue \else \l@stLINEfalse \fi% + \def\next{##3}\def\nextsample{#1#3}% + \ifx\next\nextsample\l@stLINEfalse\fi}% +% +\long\def\l@stLINE##1#3{% + \rowpush{\b@group##1\e@group}\let\d@t@two=\undefined@}% + \long\def\onem@reLINE##1#1##2#3{% + \rowpush{\b@group##1\e@group}\def\d@t@two{\relax##2#3}}%%care +% +\long\def\@ddoneLINE{\temp@toks=\expandafter{\d@t@two}% + \expandafter\testl@stLINE\the\temp@toks#1#3\s@fetymark% + \ifl@stLINE\expandafter\l@stLINE\the\temp@toks % + \else \expandafter\onem@reLINE\the\temp@toks \fi}% +% +\def\para@names{\ifshowp@r@ + \def\next@@{{\load@defaultsfalse\clr@allrows}\refillst@ck}\else + \long\def\next@@####1#3{\relax}\fi \next@@}% +% +\long\def\para@defaults##1#3{\load@defaultstrue + \clr@allrows\refillst@ck##1#3\load@defaultsfalse}% +% +\def\preview@{{\previewtrue\moreletter #3}}% +% +\long\def\out@letter##1#3{\showp@r@false\clr@allrows + \refillst@ck##1#3\lettercontents\clr@allrows\showp@r@true + \pile@letters}% +% +\name@paratoks={#1}\name@grouptoks={#2}\name@clustertoks={#3}% +% +}% END OF LONG MACRO +% +\long\def\paranames#1!{\ifshowp@r@ + \begingroup\delimiters{;}{+}{!}\para@names#1!\endgroup\fi}% +\long\def\paradefaults#1!{% + \begingroup\delimiters{;}{+}{!}\para@defaults#1!\endgroup}% +% +\def\delparadefaults{{\load@defaultstrue\clr@allrows}}% +% +\def\defaultmarks{\delimiters{;}{+}{!}}% +\def\blockmarks{\delimiters{....}{----}{====}}% +% +% +% TEST MACRO +% +% test if a token is a macro +% \newif\iftemp@if +\def\sub@ismacro#1#2#3#4#5#6#7\s@fetymark{% check only 'm,c,:' + \if#1m\else\temp@iffalse\fi % \if#2a\else\temp@iffalse\fi + \if#3c\else\temp@iffalse\fi % \if#4r\else\temp@iffalse\fi + \if#6:\else\temp@iffalse\fi }% \if#5o\else\temp@iffalse\fi +% +\def\ismacro#1#2\s@fetymark{%\expandafter\ismacro\meaning\token\s@fetymark + \temp@iftrue + \if#1\esc@\else + \sub@ismacro#1#2\s@fetymark + \fi }% +% +\long\def\del@token#1{}% +\def\del@space#1 {}% +% +% PILEMODE: the basic mode +% +\def\pile@letters{% +\def\check@{% + \def\buffer@{\out@letter}% + \def\one@space{ }% + \expandafter\ismacro\meaning\next@\s@fetymark % + \ifx\next@\undefined@\temp@iftrue \fi % + \iftemp@if % + \ifx\par\next@ \def\buffer@{\expandafter\pile@letters\del@token}% + \else \ifx\endpilemode\next@\def\buffer@{}\fi % + \fi % + \else % + \if\one@space\next@% + \def\buffer@{\expandafter\pile@letters\del@space}% + \fi % + \fi\buffer@}% +\futurelet\next@\check@}% +% +\def\beginpilemode{\showp@r@false + \def\preview{}\def\showparas{}\pile@letters}% +\def\endpilemode{% + \def\preview{\preview@}\def\showparas{\show@paras}\showp@r@true}% +% +% +% LINEMODE: cr separate paras, empty line eject letter +% +\catcode`\^^M=13\relax% +% +% remove empty or space only lines, then control to \line@chkline +\long\def\line@curbfront#1^^M{% + \is@emptyline{#1}% + \iftemp@if \def\buffer@{\line@curbfront}% + \else \def\buffer@{\line@chkline#1^^M}% control to \line@chkline + \fi \buffer@ }% +% +% \newtoks\temp@@toks +% \name@endtoks and \true\end@toks must be given on entry +\long\def\line@chkline#1^^M{% + \test@tokstr{\the\name@endtoks}{#1}% + \iftemp@if % + \temp@toks=\expandafter{\first@half}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if\else% + \expandafter\rowpush\expandafter{\expandafter% + \b@group\expandafter\relax\the\temp@toks\e@group}% + \fi% + \temp@toks=\expandafter{\second@half}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if \temp@toks={}\fi% + \iftemp@if\else % + {\is@rawmode9/1/13/13/1/13/32/1/13/96/1/13/0/0/0/% + \iftemp@if \message{<!>}\let\ =\space % + \wlog{(Verbatim: \second@half)}\fi}\fi% + \ifnum\R@Wcount=0\temp@@toks={}\else% + \temp@@toks={\showp@r@false\lettercontents\clr@allrows\showp@r@true}% + \fi% + \edef\buffer@{\the\temp@@toks\the\true@endtoks\the\temp@toks}% + \else % + \temp@toks=\expandafter{\first@half}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if% + \temp@@toks={\showp@r@false\lettercontents\clr@allrows\showp@r@true}% + \edef\buffer@{\the\temp@@toks\noexpand\line@curbfront}% + \else% + \expandafter\rowpush\expandafter{\expandafter% + \b@group\expandafter\relax\the\temp@toks\e@group}% + \let\buffer@=\line@chkline% + \fi% + \fi \buffer@% +}% +% +\catcode`\^^M=5\relax% +% +% NORMAL LINEMODE HANDLER +% +\def\beginlinemode{% + \true@endtoks={\endlinemode}% + \name@endtoks={\endlinemode}\showp@r@false\catcode`\^^M=13\relax % + \def\preview{}\def\showparas{}\clr@allrows\line@curbfront }% +% +\def\endlinemode{\catcode`\^^M=5\relax%\defaultmarks + \def\preview{\preview@}\def\showparas{\show@paras}\showp@r@true }% +% +% RAW TEXT LINEMODE HANDLER +% +\def\endrawlinemode{\get@catcodes[RAW]\showp@r@true}% +\def\beginrawlinemode#{\begin@rawlinemode}% +\def\begin@rawlinemode#1{\save@catcodes[RAW][0][\MAX@CHR@CODE][]% + \def\temp@macro{#1}% #1=token to end the list + \ifx\temp@macro\empty + \temp@toks=\expandafter{\esc@}% + \name@endtoks=\expandafter{\the\temp@toks endrawlinemode}% + \else \name@endtoks={#1}% + \fi + \true@endtoks={\endlinemode\endrawlinemode}% + \rm@ligature\set@space\set@tab\raw@chars[11][13][13][13][13]% + \showp@r@false\clr@allrows\line@curbfront }% +% +% +% BLOCKMODE: cr separate paras +% +% line containing '+' (\name@grouptoks) separates groups +% line containing '!' (\name@clustertoks) separates clusters +% +\catcode`\^^M=13\relax% +% +% remove empty or space only lines, then control to \block@chkline +\long\def\block@curbfront#1^^M{% + \is@emptyline{#1}% + \iftemp@if \let\buffer@=\block@curbfront % + \else \test@tokstr{\the\name@endtoks}{#1}% + \iftemp@if \def\buffer@{\block@chkline#1^^M}% + \else \test@tokstr{\the\name@clustertoks}{#1}% + \iftemp@if \let\buffer@=\block@curbfront% + \else \test@tokstr{\the\name@grouptoks}{#1}% + \iftemp@if \def\buffer@{\block@chkline#1^^M}% + \else \test@tokstr{\the\name@paratoks}{#1}% + \iftemp@if \let\buffer@=\block@chkline% + \else \def\buffer@{\block@chkline#1^^M}% control to \block@chkline + \fi % + \fi % + \fi% + \fi % + \fi \buffer@ }% +% +% \name@endtoks and \true\end@toks must be given on entry +\long\def\block@chkline#1^^M{% + \test@tokstr{\the\name@endtoks}{#1}% + \iftemp@if % + \ifnum\R@Wcount=0% + \temp@toks={\clr@allrows\showp@r@true}% + \else% + \temp@toks={\showp@r@false\lettercontents\clr@allrows\showp@r@true}% + \fi% + \edef\buffer@{\the\temp@toks\the\true@endtoks}% + \else % + \test@tokstr{\the\name@clustertoks}{#1}% + \iftemp@if% + \def\buffer@{\showp@r@false\lettercontents\clr@allrows% + \showp@r@true\block@curbfront}% + \else% + \test@tokstr{\the\name@grouptoks}{#1}% + \iftemp@if% + \ifnum\R@Wcount<1\global\R@Wcount=1\relax\fi % + \global\advance\R@Wcount1\relax% + \else% + \rowpush{\b@group\relax#1\e@group}% + \fi% + \let\buffer@=\block@chkline % + \fi% + \fi \buffer@% +}% +% +\catcode`\^^M=5\relax% +% +% NORMAL BLOCKMODE HANDLER +% +\def\beginblockmode{% + \true@endtoks={\endblockmode}% + \name@endtoks={\endblockmode}\showp@r@false\catcode`\^^M=13\relax % + \def\preview{}\def\showparas{}\clr@allrows\block@curbfront }% +% +\def\endblockmode{\catcode`\^^M=5\relax%\defaultmarks + \def\preview{\preview@}\def\showparas{\show@paras}\showp@r@true }% +% +% RAW TEXT BLOCKMODE HANDLER +% +\def\endrawblockmode{\get@catcodes[RAW]\showp@r@true}% +\def\beginrawblockmode#{\begin@rawblockmode}% +\def\begin@rawblockmode#1{\save@catcodes[RAW][0][\MAX@CHR@CODE][]% + \def\temp@macro{#1}% #1=token to end the list + \ifx\temp@macro\empty + \temp@toks=\expandafter{\esc@}% + \name@endtoks=\expandafter{\the\temp@toks endrawblockmode}% + \else \name@endtoks={#1}% + \fi + \true@endtoks={\endblockmode\endrawblockmode}% + \rm@ligature\set@space\set@tab\raw@chars[11][13][13][13][13]% + \showp@r@false \clr@allrows\block@curbfront }% +% +% +% DATAMODE: every <m> lines eject a letter (raw tex mode) +% +\catcode`\^^M=13\relax % +\newcount\data@count % +% +% \name@endtoks and \true\end@toks must be given on entry +\long\def\data@chkline#1^^M{\test@tokstr{\the\name@endtoks}{#1}% + \iftemp@if % \first@half is raw text + \temp@toks=\expandafter{\first@half}% + \temp@@toks=\expandafter{\second@half}% + \edef\temp@macro{\the\temp@toks\the\temp@@toks}% + \temp@toks=\expandafter{\temp@macro}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if \else\message{<!>}\let\ =\space % + \wlog{(Ignored: \first@half<->\second@half)}\fi % + \ifnum\R@Wcount=0\temp@@toks={}\else% + \ifnum\R@Wcount=\total@data@num\else \message{<!>}% + \wlog{(Number of data lines at odds)}\fi % + \temp@@toks={\showp@r@false\lettercontents\clr@allrows\showp@r@true}% + \fi% + \edef\buffer@{\the\temp@@toks\the\true@endtoks}% + \else % + \temp@toks=\expandafter{\first@half}\advance\data@count1 % + \expandafter\rowpush\expandafter{\expandafter% + \b@group\expandafter\relax\the\temp@toks\e@group}% + \ifnum\data@count<\total@data@num % + \let\buffer@=\data@chkline% + \else \data@count=0 % + \temp@@toks={\showp@r@false\lettercontents\clr@allrows\showp@r@true}% + \edef\buffer@{\the\temp@@toks\noexpand\data@chkline}% + \fi% + \fi \buffer@ }% +% +\def\begindatamode{\push{% + \edef\next@@{\noexpand\begin@datamode[\the\p@r@one]}% + \popnil\next@@}\st@ckparas\left@\right@\p@r@end}% +% +\def\begin@datamode[#1]#{\begin@@datamode[#1]}% +\def\begin@@datamode[#1]#2{\save@catcodes[RAW][0][\MAX@CHR@CODE][]% +% #1=token to end the list, #2=number of lines for each block + \edef\total@data@num{#2}\def\temp@macro{#1}% + \ifx\total@data@num\empty \def\total@data@num{1}\fi % + \ifnum\total@data@num<1 \def\total@data@num{1}\fi % + \ifx\temp@macro\empty % + \temp@toks=\expandafter{\esc@}% + \name@endtoks=\expandafter{\the\temp@toks enddatamode}% + \else \name@endtoks={#1}\fi % + \true@endtoks={\endlinemode\endrawlinemode}% + \rm@ligature\set@space\set@tab\raw@chars[11][13][13][13][13]% + \showp@r@false\clr@allrows\data@count=0 % + \def\temp@macro##1^^M{% + \test@tokstr{\the\name@endtoks}{##1}% + \iftemp@if\else \temp@toks={##1}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if\else \message{<!>}\let\ =\space % + \wlog{(Ignored: ##1)}\fi % + \fi % + \test@tokstr{\the\name@endtoks}{##1}% + \iftemp@if \temp@toks=\expandafter{\first@half}% + \temp@@toks=\expandafter{\second@half}% + \edef\temp@@macro{\noexpand\data@chkline % + \the\temp@toks\the\name@endtoks\the\temp@@toks\noexpand^^M}% + \else\def\temp@@macro{\data@chkline}\fi\temp@@macro }% + \temp@macro }% +% +\catcode`\^^M=5\relax% +% +% +% BASIC SETUP +% +\new@measures +\defaultmarks % set up the default delimiters +% +% +% RAW TEXT LISTING and MORE ON MACRO PARAMETER DEFAULTING +% +% +% FLUSH ZEROS \fillzeros[<WIDTH>]<NUMBER> +% +%% \newcount\temp@count \newcount\temp@@count +\def\fillzeros[#1]#2{\temp@@count=#2\relax + \ifnum\temp@@count<0 \temp@@count=-\temp@@count\fi + \temp@count=1\relax + {\loop\ifnum\temp@@count<10 \else + \global\divide\temp@@count by 10 \global\advance\temp@count by 1 \fi + \ifnum\temp@@count=10\relax\global\temp@@count=11\relax\fi + \ifnum\temp@@count>10 \repeat}% + \ifnum#2<0 \advance\temp@count1\relax-\fi + {\loop\ifnum\temp@count<#1\relax0\advance\temp@count1\fi + \ifnum\temp@count<#1 \repeat}% + \temp@@count=#2\relax\ifnum\temp@@count<0 \temp@@count=-\temp@@count\fi + \the\temp@@count}% +% +% +% BEGINLIST--ENDLIST: activate <space> and <linebreak> +% +\catcode`\^^M=13% +\newcount\linecount\global\linecount=1% +{\obeyspaces\gdef {\ }}% +% +% +% +% \name@endtoks: token to end the list +% \true@endtoks: tokens to be executed at the end +% \name@endtoks and \true@endtoks must be defined on entry +% \no@emptylinefalse: the first or the last line empty +% +\newif\ifno@emptyline % iftemp@if +\newif\ifprint@file \global\print@filefalse % +\def\begin@list[#1][#2][#3][#4][#5][#6]{% + \global\linecount=#1\catcode`\^^M=13\no@emptylinetrue % + \ifprint@file \def^^M{\put@linenumber}\else\def^^M{\par}\fi % + \def\put@linenumber{\par\noindent\hbox to #5{}% + \rlap{\hskip-1em\hskip#6% + \ifnum#3>0\relax\hbox to0em{\hss#4\fillzeros[#3]\linecount~~}\fi}% + \global\advance\linecount#2\relax}% + \def\out@aline{% + \ifno@emptyline % + \expandafter\is@emptyline\expandafter{\first@half}% + \ifprint@file \temp@@iffalse \else\temp@@iftrue \fi % + \else \temp@iffalse \temp@@iftrue % + \fi \no@emptylinefalse% + \iftemp@if \else % + \iftemp@@if \put@linenumber \fi % + \first@half \par % extra \par is absorbed, put here for last line + \fi }% + \def\readyt@quit{\no@emptylinetrue% + {\is@rawmode9/1/13/13/1/13/32/1/13/96/1/13/0/0/0/% + \iftemp@if \expandafter\is@emptyline\expandafter{\second@half}% + \iftemp@if\else\message{<!>}\let\ =\space % + \wlog{(Verbatim: \second@half)}\fi\fi}% + \temp@toks=\expandafter{\first@half}% + \temp@@toks=\expandafter{\second@half}% + \edef\first@half{\the\temp@toks\the\temp@@toks}\out@aline % + \edef\temp@macro{\the\true@endtoks}% + \temp@macro % \second@half removed + }% + \def\moret@get{\out@aline\get@phys@line}% + \long\def\get@phys@line##1^^M{% + \test@tokstr{\the\name@endtoks}{##1}% + \iftemp@if \let\temp@macro=\readyt@quit + \else \let\temp@macro=\moret@get % + \fi % + \temp@macro }% + \catcode`\ =13\relax\get@phys@line% +}% +% +% +\def\endlist{\catcode`\^^M=13% +\catcode`\ =10\let^^M=\par\catcode`\^^M=5}% +\def\beginlist[#1][#2][#3][#4][#5][#6]{% + \name@endtoks={\endlist}\true@endtoks={\endlist}% + \begin@list[#1][#2][#3][#4][#5][#6]}% +% +\catcode`\^^M=5\relax% +% +% +% BEGINRAWLIST -- ENDRAWLIST \beginrawlist [...]{endtoken} +% defaults for [..] supported, last {..} compulsory ({} allowed though) +% +% \beginrawlist [<INICOUNT>][<STEP>][<DIGITS>][<FONT>]% +% [<TEXTSHIFT>][<MARKINGSHIFT>]{<ENDMARK>} +% <INICOUNT>=\linecount: starts with where it is left +% <ENDMARK>= empty: \endrawlist ends the rawlist, otherwise +% <ENDMARK> ends it +% <DIGITS>=0: no line numbering +% Use \leftskip and \rightskip to control the wrapped positions +% +\def\endrawlist{\endgroup}% +\def\begin@@rawlist[#1][#2][#3][#4][#5][#6]#7{\begingroup + \def\temp@macro{#7}% #7=token to end the list + \ifx\temp@macro\empty + \name@endtoks=\expandafter{\esc@ endrawlist}% + \else \name@endtoks={#7}% + \fi + \true@endtoks={\endlist\endrawlist}% + \rm@ligature\set@tab\set@cr\set@space + \raw@chars[11][13][13][13][13]% + \begin@list[#1][#2][#3][#4][#5][#6]}% +% +\def\begin@rawlist[#1][#2][#3][#4][#5][#6]#{% + \begin@@rawlist[#1][#2][#3][#4][#5][#6]}% +% +\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}% +% +% +% +% PRINTFILE verbatim \printfile [...]{filename} +% [...] same as \beginrawlist +% +\catcode`\^^M=13\relax % +\def\print@@file[#1][#2][#3][#4][#5][#6]#7{% + \temp@toks={\bgroup\print@filetrue % + \beginrawlist[#1][#2][#3][#4][#5][#6]{}}% + \existfile{#7}% + \iftemp@if % + \edef\temp@macro##1{\the\temp@toks % + \noexpand\input##1\leavevmode % + \setbox\temp@box=\lastbox\esc@ endrawlist^^M% + \global\advance\linecount-1\relax\egroup\vskip-\baselineskip}% + \else \def\temp@macro##1{\message{(File #7 not found)}}% + \fi % + \temp@macro{#7}}% +\catcode`\^^M=5\relax % +% +\def\print@file[#1][#2][#3][#4][#5][#6]#{% + \print@@file[#1][#2][#3][#4][#5][#6]}% +% +\def\printfile{\push{% + \edef\next@@{\noexpand\print@file + [\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@6\noexpand\right@ + \noexpand\left@\noexpand\tiny@rm\noexpand\right@ + \noexpand\left@0pt\noexpand\right@ + \noexpand\left@-10pt\noexpand\right@}% + \expandafter\st@ckparas\temp@macro\p@r@end}% +% +% +% COMMENT OUT TEXT +% \begincomment{password} <text> \endcomment or password +% +\catcode`\^^M=13% +\def\begin@@comment{\let\par\relax % + \catcode`\^^M=13\message{< Skip}% + \temp@count=0\temp@@count=0\relax% + \long\def\get@phys@line##1^^M{% + \ifnum\temp@@count<500\advance\temp@@count1\else % + \message{\the\temp@count}\temp@@count=1\fi\relax % + \global\advance\temp@count1\relax % + \test@tokstr{\the\name@endtoks}{##1}% + \iftemp@if % + \def\temp@macro{\message{\the\temp@count\space lines}% + \expandafter\is@emptyline\expandafter{\second@half}% + \iftemp@if\message{>}\else % + \message{<!> >}% + \wlog{(Ignored: \second@half)}% + \fi \the\true@endtoks }% + \else \let\temp@macro=\get@phys@line % + \fi \temp@macro }% + \catcode`\ =13\relax\get@phys@line}% +% +\def\end@comment{\catcode`\^^M=13\catcode`\ =10\def^^M{\par}\catcode`\^^M=5}% +\catcode`\^^M=5\relax% +% +\def\endcomment{\endgroup}% \read@buffline\temp@macro +\def\begin@comment#1{\begingroup\nullfont + \tolerance=10000 \hbadness=10000 \vbadness=10000 + \hfuzz=\maxdimen \vfuzz=\maxdimen + \def\temp@macro{#1}% #1=token to end the list + \ifx\temp@macro\empty + \name@endtoks=\expandafter{\esc@ endcomment}% + \else \name@endtoks={#1}% + \fi \true@endtoks={\end@comment\endcomment}% + \rm@ligature\set@tab\set@cr\set@space\def\ { }% + \raw@chars[11][11][11][13][13]\begin@@comment}% +% +\def\begincomment#{\begin@comment}% essentially an \outer macro +% +% SAVE CATCODES +% +\def\toks@of@catcodes#1#2[#3]{{% #3=/13/221/233/ must be increasing,or empty +% return: global \temp@toks=0/0/0/ +% or /startnum/totalnum/catcode/ ... /0/0/0/ + \def\get@triplet/##1/##2\ZZ{\temp@@@count=##1\relax + \def\temp@macro{##2}\ifx\temp@macro\empty\else\def\temp@macro{/##2}\fi}% + \def\temp@macro{#3}\def\temp@@macro{}\temp@count=#1\relax + \loop \temp@@count=#2\relax \temp@@@count=\temp@@count\relax + \ifx\temp@macro\empty \temp@iffalse\else + \expandafter\get@triplet\temp@macro\ZZ % \ZZ is not defined + \ifnum\temp@@@count>#2 \else + \temp@@count=\temp@@@count \advance\temp@@count-1\relax \fi\fi + \edef\temp@@@macro{\noexpand\str@@catcodes + {\the\temp@count}{\the\temp@@count}}\temp@@@macro + \temp@@toks=\expandafter{\temp@@macro}% + \edef\temp@@macro{\the\temp@@toks\the\temp@toks}% + \ifnum\temp@@@count>\temp@@count \temp@count\temp@@@count + \else\temp@count\temp@@count \fi \advance\temp@count1\relax + \ifnum\temp@count>#2 \temp@iffalse \else \temp@iftrue\fi + \iftemp@if \repeat \global\temp@toks=\expandafter{\temp@@macro0/0/0/}}}% +% +\def\str@@catcodes#1#2{\ifnum#1>#2 \global\temp@toks={}\else + {\temp@@@count#1\relax \global\temp@toks={}% result in \temp@toks + \loop \temp@count=0\temp@@count=\the\catcode\temp@@@count\relax + \l@@p \advance\temp@count1\advance\temp@@@count1\relax + \ifnum\temp@@@count>#2\relax\temp@iffalse\else\temp@iftrue\fi + \iftemp@if\ifnum\the\catcode\temp@@@count=\temp@@count + \else\temp@iffalse\fi\fi + \iftemp@if\repe@t + \temp@@count=\temp@@@count \advance\temp@@count-\temp@count\relax + \edef\temp@macro{\the\temp@toks + \the\temp@@count/\the\temp@count/\the\catcode\temp@@count/}% + \global\temp@toks=\expandafter{\temp@macro}% + \ifnum\temp@@@count>#2\relax\temp@iffalse\else\temp@iftrue\fi + \iftemp@if \repeat }\fi}% +% +\def\act@catcodes#1/#2/#3/{% activate catcodes, must be ended by /0/0/0/ + \temp@count=#2\relax + \ifnum\temp@count>0 \let\temp@macro\act@catcodes\temp@@iftrue + \else \let\temp@macro\relax\temp@@iffalse\fi + \temp@count=0 \temp@@count=#1\relax + \iftemp@@if\else\temp@count=#2\relax\fi + \l@@p + \iftemp@@if + \temp@@@count=\the\catcode\temp@@count \relax + \ifnum\temp@@@count=#3\relax\else + \catcode\the\temp@@count=#3\relax\fi + \advance\temp@count1 \advance\temp@@count1\relax + \fi + \ifnum\temp@count<#2 \repe@t \temp@macro}% +% +% +\def\is@rawmode#1/#2/#3/{% chk if catcode is 11 or 12, + % exceptions must be ended by /0/0/0/ + \temp@iftrue\temp@count=#2\relax + \ifnum\temp@count>0 \let\temp@macro\act@catcodes\temp@@iftrue + \else \let\temp@macro\relax\temp@@iffalse\fi + \temp@count=0 \temp@@count=#1\relax + \iftemp@@if\else\temp@count=#2\relax\fi + \l@@p + \iftemp@@if + \temp@@@count=\the\catcode\temp@@count \relax + \ifnum\temp@@@count=#3\relax\else + \ifnum\temp@@@count=11\relax\else + \ifnum\temp@@@count=12\relax\else + \temp@iffalse \fi\fi\fi + \advance\temp@count1 \advance\temp@@count1\relax + \fi + \ifnum\temp@count<#2 \repe@t\temp@macro}% +% +% +% #1=name, #2=1st char, #3=last char, #4=exceptions +\def\save@catcodes[#1][#2][#3][#4]{\toks@of@catcodes{#2}{#3}[#4]% + \expandafter\xdef\csname CAT@#1@CODES\endcsname{\the\temp@toks}}% +% +\def\get@catcodes[#1]{% + \expandafter\let\expandafter\temp@macro\csname CAT@#1@CODES\endcsname + \expandafter\act@catcodes\temp@macro}% +% +% SAVE STATUS +% +\def\save@status{\edef\temp@macro{% status to \temp@macro + \noexpand\pagegoal=\the\pagegoal + \noexpand\hsize=\the\hsize + \noexpand\vsize=\the\vsize + \noexpand\hyphenpenalty=\the\hyphenpenalty + \noexpand\overfullrule=\the\overfullrule + \noexpand\pretolerance=\the\pretolerance + \noexpand\tolerance=\the\tolerance + \noexpand\hbadness=\the\hbadness + \noexpand\vbadness=\the\vbadness + \noexpand\hfuzz=\the\hfuzz + \noexpand\vfuzz=\the\vfuzz + \noexpand\spaceskip=\the\spaceskip + \noexpand\xspaceskip=\the\xspaceskip + \noexpand\looseness=\the\looseness + \noexpand\parfillskip=\the\parfillskip }}% +% +% +% MULTI-COLUMNS +% +\newif\ifwarn@me \newbox\partial@page +\newtoks \old@output@toks +%\newtoks\new@footline +% replacing \footline for a TeX bug if footline is lost +% +% makeshift remedy for LaTeX +% One must define \makefootline etc for realistic export to general LaTeX +\ifx\makeheadline\undefined@ \let\makeheadline\relax\fi +\ifx\makefootline\undefined@ \def\makefootline{}\fi +\ifx\advancepageno\undefined@\def\advancepageno{\global\advance\count0 1}\fi +% +\def\make@headline{{\hsize=\page@width \makeheadline}}% +\def\make@footline{{\hsize=\page@width \makefootline}}% +\def\simple@pageout#1{\shipout\vbox{\make@headline + \vbox to\page@height{#1}\make@footline}\advancepageno}% +% +\def\page@sofar[#1]{\unvbox\partial@page \temp@count=0 % + \loop\ifnum\temp@count<#1 \wd\temp@count=\hsize\advance\temp@count1 \repeat + \temp@count=1 \hbox to\page@width{\box0 % + \loop\ifnum\temp@count<#1 \hfil\box\temp@count + \advance\temp@count by1 \repeat}\temp@count=0 % + \ifx\topins\undefined@\else\ifvoid\topins\else\temp@count=1 \fi\fi + \ifx\footins\undefined@\else\ifvoid\footins\else\temp@count=1 \fi\fi + \ifwarn@me \ifnum\temp@count=1 \message{<!>}% + \wlog{Insertions (e.g. footnotes) may be pushed to later pages. + Try manual pagebreak to overcome possible overfull vbox due to + insertions. I pray for you.}\global\warn@mefalse \fi\fi}% +% +\def\columns@out[#1]{\splittopskip=\topskip\splitmaxdepth=\maxdepth + \temp@dim=\page@height \advance\temp@dim by -\ht\partial@page + \temp@count=0 \loop\ifnum\temp@count<#1 + \ifdim\temp@dim>0pt + \setbox\temp@count=\vsplit255 to\temp@dim + \else \setbox\temp@count=\vbox{}\fi + \advance\temp@count by1 \repeat + \simple@pageout{\page@sofar[#1]}\unvbox255\penalty\outputpenalty}% +% +\def\balance@columns[#1]{\setbox\temp@box=\vbox{\unvbox255}% +%% For materials more than one page but less than two pages + \temp@@dim=\ht\partial@page \temp@dim=\ht\temp@box + \divide\temp@dim by \column@num + \advance\temp@dim by \temp@@dim \advance\temp@dim by \dp\temp@box + \ifdim\temp@dim>\page@height \message{(!)}% + \temp@@@dim=\temp@@dim \advance\temp@@@dim by -\page@height + \advance\temp@@@dim by \baselineskip + \ifdim\temp@@@dim>0pt \message{<!>}% + \wlog{Space left in previous page too narrow.}\else + {\vbadness=10000 \vfuzz=\maxdimen + \predisplaypenalty 0 \postdisplaypenalty 0 % + \splittopskip=\topskip \splitmaxdepth=\maxdepth + \temp@dim=\page@height \advance\temp@dim by -\temp@@dim + \advance\temp@dim by \maxdepth + \temp@count=0 \loop \ifnum\temp@count<#1 % + \setbox\temp@count=\vsplit\temp@box to\temp@dim + \advance\temp@count by1 \repeat + \global\setbox\temp@box\box\temp@box + \simple@pageout{\page@sofar[#1]}}\fi\fi +% push the rest into the next page + \temp@dim=\ht\temp@box \advance\temp@dim by\topskip + \advance\temp@dim by -\baselineskip + \divide\temp@dim by #1 \splittopskip=\topskip + {\vbadness=10000 \vfuzz=\maxdimen \splitmaxdepth=\maxdepth + \loop \setbox\temp@@box=\copy\temp@box + \temp@count=1 \l@@p \ifnum\temp@count<#1 % + \setbox\temp@count=\vsplit\temp@@box to\temp@dim + \advance\temp@count by1 \repe@t + \ifdim\ht\temp@@box>\temp@dim \advance\temp@dim by1pt \repeat + \temp@count=1 \temp@@count=0 + \loop \ifnum\temp@count<#1 % + \setbox\temp@@count=\vbox to\temp@dim{\unvbox\temp@count}% + \advance\temp@count by1 \advance\temp@@count by1 \repeat + \temp@count=#1 \advance\temp@count by-1 % + \setbox\temp@count=\vbox to \temp@dim{\unvbox\temp@@box}\page@sofar[#1]}% + \global\setbox\temp@box=\null\global\setbox\temp@@box=\null}% +% +\def\begincolumns{\push{% + \edef\next@@{\noexpand\begin@columns[\the\p@r@one][\the\p@r@two]}% + \popnil\clrp@r@s\next@@}\st@ckparas\left@2\right@\left@10pt\right@\p@r@end}% +% +\def\begin@columns[#1][#2]{% #1 will be expanded via \edef + \save@status \old@output@toks=\expandafter{\the\output}% + \let\old@entry@status\temp@macro %\begingroup + \edef\column@num{#1}\warn@metrue + \temp@@count=0 \temp@count=\column@num \relax + \ifnum\temp@count>9 \temp@@count=1 \fi + \ifnum\temp@count<1 \temp@@count=1 \fi + \ifnum\temp@@count>0 % + \errhelp{I think a format other than 1-9 columns in a page is crazy. + But if you do have such devious wishes, I can only keep my + fingers crossed for you.}% + \errmessage{Column number \column@num\space is too ambitious!}\fi + \ifISLATEX\edef\page@width{\the\textwidth}\edef\page@height{\the\textheight}% + \else \edef\page@width{\the\hsize}\edef\page@height{\the\vsize}\fi + \tolerance=10000 \hbadness=10000 \vbadness=10000 + \hfuzz=\maxdimen \vfuzz=\maxdimen \overfullrule=0pt + \par\penalty-1 %avoid page loss near the page break margin + \message{(\column@num\space cols|#2)}% + \output={\global\setbox\partial@page=\vbox{\unvbox255\bigskip}}\eject + \output={\columns@out[\column@num]}% + \divide\hsize by \column@num \temp@dim=#2 + \ifnum \temp@dim<0 \message{Intercolumn skip [#2] insensible, reset to 0pt.}% + \else \advance\hsize by -#2 \fi\multiply\vsize by \column@num + \advance\vsize by 1pc}% +% +\def\endcolumns{% + \hbox{}\output={\balance@columns[\column@num]}\eject%\endgroup + \old@entry@status \output=\expandafter{\the\old@output@toks}% + \global\setbox\partial@page=\null}% \pagegoal=\vsize +% +% SMOOTH PASSAGES FOR MULTICOLUMNS +% +\def\smooth{\spaceskip=0.3em plus .8em minus .1em + \xspaceskip=0.6pt plus 1em minus .2em + \pretolerance=10 \tolerance=10000 \looseness=-10000 + \parfillskip=0pt plus10fill\relax}% +% +% MAKE LABELS +% \beginlabels[#1][#2][#3][#4][#5][#6] +% defaults: #1=15pt #2=\sl #3=1 #4=1 #5=2.6in #6=2em +% \endlabels +% +\def\begin@labels[#1][#2][#3][#4][#5][#6]{% + \ifISLATEX \temp@dim=\textwidth \else\temp@dim=\hsize\fi + \temp@@dim=#1 \advance\temp@@dim #5 \def\label@size{#5}% + \advance\temp@@dim\temp@@dim \advance\temp@@dim10pt + \ifdim\temp@@dim<\temp@dim \temp@count=2 + \else \temp@count=1 \temp@dim=0pt \fi\relax + \edef\temp@macro{\noexpand\begincolumns[\the\temp@count][10pt]}% + \temp@macro %\nullfont + \long\def\peudo@letter##1\endletter{% + \def\lettercontents{\begingroup \hbadness=10000 \vbadness=10000 + \hfuzz=\maxdimen \vfuzz=\maxdimen \overfullrule=0pt + \vbox{#2 \par\vskip\baselineskip + \vskip#1\addressparas[#3][#4][#5][#6]\vskip#1 + \hbox{\font\tiny@rm=cmr5 \tiny@rm + \leaders\hbox to .8em{\hss.\hss}\hskip\label@size}\par}% + \endgroup}}% + \let\beginletter\peudo@letter\beginletter\endletter}% +% +\def\beginlabels{\push{% + \edef\next@@{\noexpand\begin@labels[\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@@}\st@ckparas + \left@ 20pt\right@ \left@ \tt\raggedright\right@ + \left@ 1\right@ \left@ 1\right@ + \left@ 2.6in\right@ \left@ 2em\right@ \p@r@end}% +% +\def\endlabels{\endcolumns\let\beginletter\true@letter}% +% +% +% LABELS: make labels via a 2nd read of file +% +\long\def\firstread#1{% nil if read after \labelsquit + \ifx\ENDINPUT\undefined\def\temp@macro{#1}\else\def\temp@macro{}\fi + \temp@macro}% +% +% +\def\initstyle{\push{% + \edef\next@@{\noexpand\init@labels[\the\p@r@one]}% + \popnil\clrp@r@s\next@@}\st@ckparas\left@\right@\p@r@end}% +\let\initlabels\initstyle % for compatibility with version 2.03 +% +\long\def\init@labels[#1]#{\init@@labels[#1]}% +\long\def\init@@labels[#1]#2#{\init@@@labels[#1]#2}% +\long\def\init@@@labels[#1]#2#3{\def\labels@initiated{}\let\next\relax + \ifISLATEX \ifx\ENDINPUT\undefined@ \def\temp@macro{#2}% + \ifx\temp@macro\empty\temp@toks={article}\else\temp@toks={#2}\fi + \temp@@toks={#3}\edef\temp@@macro{\noexpand\documentstyle + [#1]{\the\temp@toks}\the\temp@@toks\noexpand\begin{document}}% + \else\def\temp@@macro{}\fi + \else \def\temp@@macro{}\message{<!>}% + \wlog{(\string\initstyle\space ignored for plain TeX)}\fi + \temp@@macro}% +% +% +\def\initclass{\push{% + \edef\next@@{\noexpand\init@class[\the\p@r@one][\the\p@r@two]}% + \popnil\clrp@r@s\next@@}\st@ckparas\left@\right@\left@\right@\p@r@end}% +% +\long\def\init@class[#1][#2]#{\init@@class[#1][#2]}% +\long\def\init@@class[#1][#2]#3#{\init@@@class[#1][#2]#3}% +\long\def\init@@@class[#1][#2]#3#4{\def\labels@initiated{}\let\next\relax + \ifISLATEX \ifx\ENDINPUT\undefined@ \def\temp@macro{#3}% + \ifx\temp@macro\empty\temp@toks={article}\else\temp@toks={#3}\fi + \temp@@toks={#4}\edef\temp@@macro{\noexpand\documentstyle + [#1]{\the\temp@toks}\the\temp@@toks\noexpand\begin{document}}% + \ifx\documentclass\undefined@\else + \edef\temp@@macro{\noexpand\documentclass[#2]{\the\temp@toks}% + \noexpand\read@style[,]{#1}\the\temp@@toks + \noexpand\begin{document}}% + \fi + \else\def\temp@@macro{}\fi + \else \def\temp@@macro{}\message{<!>}% + \wlog{(\string\initclass\space ignored for plain TeX)}\fi + \temp@@macro}% +% +\def\readstyles#1{\xdef\EntryReadStyle{\the\catcode`\@}\catcode`\@=11\relax + \read@style[,]{#1}\catcode`\@=\EntryReadStyle\relax}% +% +\def\read@style[#1]#2{\def\one@item##1#1##2\safty@mark{\temp@toks={##1}% + \expandafter\input@a@style\the\temp@toks..\safty@mark\def\temp@macro{##2}% + \ifx\temp@macro\empty\else\def\temp@macro{\one@item##2\safty@mark}\fi + \temp@macro}\one@item#2#1\safty@mark }% +\def\input@a@style#1.#2.#3\safty@mark{\def\temp@macro{#2}% + \ifx\temp@macro\empty\def\temp@macro{sty}\fi\def\temp@@macro{#1.}% + \temp@toks=\expandafter\expandafter\expandafter + {\expandafter\temp@@macro\temp@macro}\def\temp@@macro{#1}% + \ifx\temp@@macro\empty\else\ifx\temp@@macro\space\else + \expandafter\inputfile\expandafter{\the\temp@toks}\fi\fi }% +% +% +\def\labelsquit{\push{% + \edef\next@@{\noexpand\labels@quit[\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@@}\st@ckparas + \left@ 20pt\right@ \left@ \tt\raggedright\right@ + \left@ 1\right@ \left@ 1\right@ + \left@ 2.6in\right@ \left@ 2em\right@ \p@r@end}% +% +\def\labels@quit[#1][#2][#3][#4][#5][#6]#{% + \labels@@quit[#1][#2][#3][#4][#5][#6]}% +\def\labels@@quit[#1][#2][#3][#4][#5][#6]#7{% + \ifISLATEX \else\def\labels@initiated{}\fi + \ifx\labels@initiated\undefined + \message{<!>}\wlog{(\string\initstyle\space must be activated first)}% + \let\next\relax + \else \def\temp@macro{#7}% + \ifx\temp@macro\empty\def\temp@macro{\jobname}\fi + \ifx\ENDINPUT\undefined + \temp@toks={[#1][#2][#3][#4][#5][#6]}% + \message{(Re-read \jobname.tex)}% + \edef\next{\noexpand\beginlabels + \the\temp@toks\noexpand\input \temp@macro}% + \else \def\next{\endlabels\end{document}}\fi + \let\ENDINPUT\relax + \fi \next}% +% +% +% WRITE FILE +% +\catcode`\^^M=13\relax % +% +% \temp@read, \name@endtoks and \true\end@toks must be given on entry +\long\def\file@chkline#1^^M{\test@tokstr{\the\name@endtoks}{#1}% + \iftemp@if \temp@toks=\expandafter{\first@half}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if\else \expandafter % + \immediate\write\expandafter\temp@read\expandafter{\first@half}\fi % + \immediate\closeout\temp@read \temp@toks=\expandafter{\second@half}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if \else\message{<!>}\wlog{(Ignored: \the\temp@toks)}\fi % + \edef\buffer@{\the\true@endtoks}% + \else \expandafter\immediate\expandafter % + \write\expandafter\temp@read\expandafter{\first@half}% + \let\buffer@\file@chkline % + \fi \buffer@ }% +% +\def\beginfile{\push{% + \edef\next@@{\noexpand\begin@file[\the\p@r@one]}% + \popnil\next@@}\st@ckparas\left@\right@\p@r@end}% +% +\def\begin@file[#1]#{\begin@@file[#1]}% +\def\begin@@file[#1]#2{\save@catcodes[RAW][0][\MAX@CHR@CODE][]% +% #1=token to end the list, #2=filename + \edef\temp@macro{#2}% + \ifx\temp@macro\empty \def\temp@macro{scr@tch@.tex}\fi % + \wlog{(File <\temp@macro> written)}% + \immediate\openout\temp@read=\temp@macro \def\temp@macro{#1}% + \ifx\temp@macro\empty \temp@toks=\expandafter{\esc@}% + \name@endtoks=\expandafter{\the\temp@toks endfile}% + \else \name@endtoks={#1}\fi\true@endtoks={\endlinemode\endrawlinemode}% + \rm@ligature\set@space\set@tab\raw@chars[11][11][11][13][13]\let\ =\space % + \def\temp@macro##1^^M{% + \test@tokstr{\the\name@endtoks}{##1}% + \iftemp@if\else \temp@toks={##1}% + \expandafter\is@emptyline\expandafter{\the\temp@toks}% + \iftemp@if\else \expandafter\immediate\expandafter % + \write\expandafter\temp@read\expandafter{\the\temp@toks}\fi % + \fi % + \test@tokstr{\the\name@endtoks}{##1}% + \iftemp@if \temp@toks=\expandafter{\first@half}% + \temp@@toks=\expandafter{\second@half}% + \edef\temp@@macro{\noexpand\file@chkline % + \the\temp@toks\the\name@endtoks\the\temp@@toks\noexpand^^M}% + \else\def\temp@@macro{\file@chkline}\fi\temp@@macro }% + \temp@macro }% +% +\catcode`\^^M=5\relax% +% +% +% FONTS +% +%\font\BOLD=cmbx10 at 24.88pt \font\hbold=cmbx10 at 20.74pt +%\font\lbold=cmbx10 at 17.28pt \font\bbold=cmbx10 at 14.4pt +%\font\bold=cmbx10 at 12pt \font\sbold=cmbx8 +%\font\tbold=cmbx5 \font\ssan=cmss8 +%\font\SAN=cmss10 at 24.88pt \font\hsan=cmss10 at 20.74pt +%\font\lsan=cmss10 at 17.28pt \font\bsan=cmss10 at 14.4pt +%\font\san=cmss10 at 12pt \font\nsan=cmss10 +%\font\ROMAN=cmr10 at 24.88pt \font\hroman=cmr10 at 20.74pt +%\font\lroman=cmr10 at 17.28pt \font\broman=cmr10 at 14.4pt +%\font\roman=cmr10 at 12pt \font\sroman=cmr8 +%\font\troman=cmr5 \font\stt=cmtt8 +% +% +% LEAVE MACROS +% +\let\wlog\temp@@@macro\let\temp@@@macro\undefined@ +% +\catcode`\@=\EntryFormLett\relax +\endinput +% +%ENDMACROS diff --git a/macros/generic/formlett/prog_manual.pdf b/macros/generic/formlett/prog_manual.pdf Binary files differnew file mode 100644 index 0000000000..091e0c2142 --- /dev/null +++ b/macros/generic/formlett/prog_manual.pdf diff --git a/macros/generic/formlett/prog_manual.tex b/macros/generic/formlett/prog_manual.tex new file mode 100644 index 0000000000..3cf57fc993 --- /dev/null +++ b/macros/generic/formlett/prog_manual.tex @@ -0,0 +1,1906 @@ +% PROGRAMMER'S MANUAL in Plain TeX + +\input formlett.sty + +% FONTS +\font\hbold=cmbx10 at 17.28pt +\font\lbold=cmbx10 at 14.4pt +\font\bbold=cmbx10 at 12pt +\font\small=cmr8 +\font\tiny=cmr5 +\font\stt=cmtt9 +\catcode`\@=11\relax +% +% +% +% OTHER MACROS +% +\catcode`\~=11\relax \def\t{{\tt ~}} +\catcode`\~=\active\relax +\catcode`\!=0\relax !catcode`!\=11!relax +!def!esc{\}!def!escs{\! } +!catcode`!\=0!relax \catcode`\!=12\relax +\def\rqs{\rq\ } +\def\LaTeX{{\rm L\kern-.36em\raise.3ex\hbox{\font\sc=cmcsc10\sc a}\kern-.15em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +% makeshift macro +\catcode`\^^M=13\relax% +\def\setraw{\bgroup\rm@ligature\set@space\set@tab% +\set@cr\stt\raw@chars[11][13][13][13][13]\def^^M{\strut\par}\setraw@@}% +\edef\temp@macro{% + \noexpand\long\noexpand\def\noexpand\setraw@@\noexpand##1^^M##2% + \esc@ unsetraw{##1##2\noexpand\egroup}}\temp@macro % +\catcode`\^^M=5\relax% + + +\font\ninerm=cmr9 \font\eightrm=cmr8 +\font\ninei=cmmi9 \font\eighti=cmmi8 +\font\ninesy=cmsy9 \font\eightsy=cmsy8 +\font\ninebf=cmbx9 \font\eightbf=cmbx8 +\font\ninett=cmtt9 \font\eighttt=cmtt8 +\font\nineit=cmti9 \font\eightit=cmti8 +\font\ninesl=cmsl9 \font\eightsl=cmsl8 + +\font\sixrm=cmr6 +\font\sixi=cmmi6 +\font\sixsy=cmsy6 +\font\sixbf=cmbx6 + +\skewchar\ninei='177 \skewchar\eighti='177 \skewchar\sixi='177 +\skewchar\ninesy='60 \skewchar\eightsy='60 \skewchar\sixsy='60 +\hyphenchar\ninett=-1 \hyphenchar\eighttt=-1 \hyphenchar\tentt=-1 + +\font\tentex=cmtex10 +\font\inchhigh=cminch +\font\titlefont=cmssdc10 at 40pt % titles in chapter openings +\font\eightss=cmssq8 % quotations in chapter closings +\font\eightssi=cmssqi8 % ditto, slanted +\font\tenu=cmu10 % unslanted te~t italic +\font\manual=manfnt % METAFONT logo and special symbols +\font\magnifiedfiverm=cmr5 at 10pt % to demonstrate magnification + +\newskip\ttglue +\def\eightpoint{\def\rm{\fam0\eightrm}% switch to 8-point type + \textfont0=\eightrm \scriptfont0=\sixrm \scriptscriptfont0=\fiverm + \textfont1=\eighti \scriptfont1=\sixi \scriptscriptfont1=\fivei + \textfont2=\eightsy \scriptfont2=\sixsy \scriptscriptfont2=\fivesy + \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex + \textfont\itfam=\eightit \def\it{\fam\itfam\eightit}% + \textfont\slfam=\eightsl \def\sl{\fam\slfam\eightsl}% + \textfont\ttfam=\eighttt \def\tt{\fam\ttfam\eighttt}% + \textfont\bffam=\eightbf \scriptfont\bffam=\sixbf + \scriptscriptfont\bffam=\fivebf \def\bf{\fam\bffam\eightbf}%, + \tt \ttglue=.5em plus.25em minus.15em + \normalbaselineskip=9pt + \setbox\strutbox=\hbox{\vrule height7pt depth2pt width0pt}% + \let\sc=\sixrm \let\big=\eightbig \normalbaselines\rm} + + +%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%% +% +% END OF EXTRA MACROS AND FONTS +% +%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%% + + + +\message{<<document for programmers>>} +\catcode`\@=11\relax +\PAGENO=1 +\voffset=-0.3in + + +\ifx\pageno\undefined +\errmessage{Please run TeX if you want this article on how to use +<formlett.sty> to be processed as well!} +\fi + + +\parindent=0pt +\hsize=469.75499pt % the default +\vsize=9.6in %8.83in +%\vsize=8.83in + +\def\makefootline{\baselineskip=24pt \line{\the\footline}} +\footline={\lower5pt +\hbox to \hsize + {{\tenrm Jiang Z ~~~{\tensl Formlett: ~for letters to multiple receivers} +\hss \folio}}} + +\leftline{\hbold FORMLETT: ~~~for Letters to Multiple Receivers} +\bigskip + + +{\advance\leftskip by13mm \overfullrule=0pt +\advance\rightskip by 20mm %28mm +\sl +\noindent Zhuhan JIANG\par +\noindent School of Computing and Information Technology, + University of Western Sydney, Victoria Road, Parramatta NSW 2150, Australia. +{\sl ~~Email}:~z.jiang@uws.edu.au\par +\medskip +\rm\smooth +\noindent (Last updated on 26 May 2003)\par +\medskip + +\noindent +In this article, the author explains how to use a form-letter +style {\tt formlett.sty}, designed for plain \TeX\ and \LaTeX +\ or \LaTeX2e. {\tt formlett.sty} supports different parameter input +methods, parameter naming and defaulting mechanism, as well as +facilities for previewing parameter positions and printing +labels. It is written for the purpose of being powerful, robust +and above all easy to use.\par } + + +\begincolumns + +{\lbold Introduction} + +\smallskip + +In this modern world of ours, we often need to send a set of form +letters, personalised or non-personalised, to many receivers at +the same time. Or perhaps we would like to have a collection of +business letters or information brochures which we would like to +call upon {\sl instantly} whenever we need them. + +\medskip + +Our purpose here is therefore to describe a comprehensive +implementation of such a macro system, handling form letters +under \TeX\ or \LaTeX. The main objective is to provide an easy +way to output many form letters with their own parameters, with +or without the use of multiple files. There will be a coherent +and simple format for putting parameters inside a form letter, +with a number of helping facilities for such as naming parameters +and previewing their positions. A minimum support for printing +mailing labels is also provided. + + +\medskip + +The concept of macros [1] for form letters is not new: there +already exist macros in this connection such as {\tt merge}, {\tt +textmerg} and {\tt address} to name a few, see [2,3] for further +details. Our stress here is therefore laid on the ease to use, +along with the power and the robustness of the macros. + +\bigskip +{\lbold Format} + +\smallskip + +In this section, we always assume that the file {\tt formlett.sty} +or {\tt formlett.tex} of version {\tt 2.3} has +already been input. Certain version of {\tt formlett.sty} can be +obtained via anonymous ftp from CTAN sites at +{\tt macros /generic}. + +\medskip + +Essentially, each form letter, or letter format or letter +template, will be included between {\tt \string\beginletter} and +{\tt \string\endletter}. Letter parameters that will be specified +later on for each particular letter can be given by {\tt +\string\paras[<m>][<n>]}, representing the {\tt <m>}-th parameter +of the {\tt<n>}-the parameter group, at the positions you want +them to be. Let a cluster denote a complete collection of +parameters that may be specified for a form letter. Then we can +specify letter parameters group by group for a cluster such that +inside each group the parameters are given {\sl sequentially} and +a termination of one group should not affect the +resynchronisation for the next group. For instance we can keep +the address of a receiver as a single group, as it often contains +different number of (parameter) lines. + + +\medskip +We often want to treat a particular group of letter +parameters somewhat uniformly. This can be achieved by one of the +following commands + +\setraw + \blockparas[<m>][<n>][<pre>][<post>] + \addressparas[<m>][<n>][<width>][<indent>] +\unsetraw + +They represent parameters in the {\tt<n>}-th group, from the {\tt +<m>}-th to the last parameter of that group. For {\tt +\string\blockparas}, tokens {\tt <pre>} and {\tt <post>} are +those to be added in front and behind respectively each of the +legitimate parameters mentioned above. If {\tt <post>} is +{\tt\string\relax}, it will then not be appended at the end. +Instead, each chosen parameter will be put into a {\tt $\{\}$}- +pair before preceded by the token {\tt <pre>}. The reason for +this exception is that while {\tt <pre> and <post>} are meant to +be the front and end macros for each selected parameter, in the +case of {\tt <post>} being {\tt \string\relax}, we may regard +{\tt<pre>} as {\sl acting upon} each chosen parameter. + + +\medskip +The command {\tt \string\addressparas}, however, uses +{\tt \string\blockparas} indirectly and will put the chosen +parameters into a box of width {\tt<width>}. If any selected +parameter is longer than {\tt<width>}, then the line will be +wrapped around, with all wrapped potions being indented by an +{\tt<indent>}. This may be used to deal with very long address +lines. Incidentally, we may use {\tt \string\textbox} or {\tt +\string\addressbox} or {\tt \string\ADDRESSBOX} to control the +width of a single parameter. The general format reads + + +\setraw + \textbox[<width]{<materials>} + \addressbox[<width>][<indent>]{<materials>} + \ADDRESSBOX{<width>}{<indent>}{<materials>} +\unsetraw + +where the meaning of the macro parameters are self-explanatory. + + +\medskip + +For the macro parameters, we have for convenience provided the +following defaults for those in the squared brackets + +\setraw + <m>=1 + <n>=1 + <pre>=\noindent + <post>=\par + <width>= 8truecm + <indent>= 1.5em +\unsetraw + +This way, for instance, {\tt\string\paras[1][1]} is equivalent +to any of the following commands + +\setraw + \paras, \paras[1], \paras[][1], + \paras[1][], \paras[][] +\unsetraw + +and the following three commands are also the same + +\setraw + \addressbox{one address line} + \addressbox[8truecm]{one address line} + \addressbox[][1.5em]{one address line} +\unsetraw + + +\medskip + +Incidentally this is the reason why we used the second parameter +{\tt<n>} to represent the group number: the defaults can often be +dropped off more frequently. By default, all letter parameters +specified will be put into a group environment before putting +them into the form letter, unless {\tt \string\localparasfalse} +is issued beforehand. + +\medskip +To output a new letter entity, i.e a complete letter, +we may use + + +\setraw + \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 ! +\unsetraw + + +where \lq{\tt ;}\rqs separate parameters inside a same group, +\lq{\tt +}\rqs separates groups, \lq{\tt !}\rqs ends a cluster of +parameters, and \lq{\tt ...}\rqs represent further letter +parameters. These three tokens are nothing special: we may change +them to for instance \lq{\tt ....}\rq, \lq{\tt ----}\rqs and +\lq{\tt ====}\rqs respectively by {\tt \string\blockmarks}, and +change them back to \lq{\tt ; + !}\rqs by {\tt +\string\defaultmarks}. For more general case, use + +\setraw + \delimiters{<A>}{<B>}{<C>} +\unsetraw + +where {\tt <A>}, {\tt <B>} and {\tt <C>} are the new toks +replacing \lq{\tt ; + !}\rqs respectively. If we have to use +these three special characters or tokens inside our {\sl letter +parameters}, then use {\tt \string\pstr}, {\tt\string\gstr} and +{\tt\string\cstr} respectively instead. + +\medskip + +For the case of many clusters, we may enclose them, separated by +any white spaces or empty lines, between {\tt +\string\beginpilemode} and {\tt \string\endpilemode} so that we +don't have to put {\tt \string\moreletter} in front of each +cluster of parameters. + + +\medskip +We may also enter letter parameters line by line. In other words, +we may essentially replace \lq{\tt;}\rqs in the {\tt +\string\moreletter} format by a normal line break. In this case, +we shall put clusters of parameters between {\tt +\string\beginblockmode} and {\tt \string\endblockmode}. Thus the +following commands + + +\setraw + \beginblockmode + <para-1-1> + <para-1-2> + + letter one + + <para-2-2> + ! + + <addr-1-1> + <addr-1-2> + ! letter two + \endblockmode +\unsetraw + + +will produce the required form letter for each cluster of +parameters. The general rules are as follows: + +{\parindent=1.5em +\item{$\bullet$} If a line contains {\tt \string\endblockmode} or {\tt !} +or {\tt +}, then everything else on that line is ignored and that +line serves as an end/cluster/group marking line in the given +priority order. + +\item{$\bullet$} Leading and trailing empty lines before or after +a complete cluster will be ignored, unless \lq{\tt ;}\rqs is +there to force the next (empty) line as a starting parameter. +\par } + +Obviously {\tt \string\blockmarks} provides a more sensible +delimiters for the {\tt blockmode}, under which we could have + +\setraw + \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 +\unsetraw + +\medskip +A simpler and perhaps more often encountered scenario is +to use names and addresses only. In this case, there will be +essentially only {\sl one} group of parameters for each cluster. +Thus we may use empty lines to delimit the clusters, and use line +by line mode for the individual parameters. This way, each +block of consecutive nonempty lines in + +\setraw + \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 +\unsetraw + + +will output a new complete letter, corresponding to the specified +letter parameters. + + +\medskip +{\smooth +Ideally, the name--address entries will be produced by a database +utility. Since they often contain special characters such as \lq +{\tt \#}\rqs and \lq{\tt \$}\rqs explicitly, we may wish to +change such characters in the parameters to the normal printable +ones. For this purpose, we could use correspondingly the pair +{\tt \string\beginrawblockmode$\{$<token>$\}$} with {\tt +\string\endrawblockmode} or the pair {\tt +\string\beginrawlinemode$\{$<token>$\}$} with {\tt +\string\endrawlinemode}. If {\tt <token>} is not empty, then we +use {\tt <token>} in place of {\tt \string\endrawblockmode} or +{\tt \string\endrawlinemode}. In other words, {\tt <token>} is +the password to leave the raw text mode. Since database utility +will in general produce a {\sl fixed} number of {\tt <m>} lines +for each cluster of parameters, we may use {\tt +\string\begindatamode[<token>]$\{$<m>$\}$} and {\tt +\string\enddatamode} (or {\tt<token>}) in place of {\tt +\string\beginrawlinemode} and {\tt\string\endrawlinemode} so that +each {\tt<m>} raw text lines, including the empty ones, will eject +a form letter. +} + + +\medskip + +It is often desirable that a letter form or format and the actual +parameters be kept in different files: it will help in archiving +and retrieving form letters. Furthermore, if a letter is quite +long such that the \TeX\ can't hold it in the memory, then we +{\sl have to} keep the letter content in a separate file. +Essentially we need to save everything between +{\tt\string\beginletter} and {\tt \string\endletter} into a +separate file, say, {\tt letter.let}, then later on use +{\tt\string\inputletter$\{$letter.let$\}$} to load in the letter +format. Should one prefer to keep everything inside a {\sl single} +file, however, he may use {\tt\string\beginfile [{\it +password}]$\{${\it file.ext}$\}$} and {\tt\string\endfile} (or +{\it password}) to create files such as {\tt letter.let} +mentioned above as a temporary scratch file. We note that {\tt +letter.let} will not contain {\tt\string\beginletter} and +{\tt\string\endletter} as {\tt \string\inputletter} will add them +properly for us. Also the extension {\tt .let} is preferred in +this connection as it can indicate that this type of format file +should not quite be regarded as the normal \TeX\ files. + +\medskip + +Likewise, it is also desirable to have a separate address or +general letter parameter file. For the address file, we remark +that we have to keep the pairing {\tt \string\beginlinemode} with +{\tt \string\endlinemode} or {\tt\string\beginblockmode} with +{\tt \string\endblockmode} inside the address file, if we are to +use any of them for some content of that file. Moreover, an +extension {\tt .adr} is recommended for such files. Thus for a +letter format or template saved in {\tt letter.let}, we may +choose {\tt letter.adr} as the name for the related address file. + +\medskip +After a letter format is completed for sometime, one may have +difficulty in recalling what those parameters should refer to +when using the form letter again. For this purpose, we provide +a simple mechanism with {\tt\string\paranames} and {\tt +\string\showparas}. To be more precise, if one puts {\tt +\string\paranames\ name-1-1; ...; <etc>!} at the very beginning of +the letter format, then one can use {\tt\string\showparas} +outside to output a letter with its parameters replaced by their +names. + +\medskip + +An alternative way, or rather a way of highlighting the positions +of the letter parameters is to use {\tt\string\preview}. Under +{\tt\string\preview}, or {\tt \string\previewtrue}, all +parameters given by {\tt\string\paras[<m>][<n>]} will be boxed +with double borderlines, similar to {\tt \previewtrue +\paras[3][2]}, the number {\tt<n>-<m>} inside (corresponding to +{\tt 2-3} in the shown box) denotes the {\tt<m>}-th parameter of +the {\tt <n>}-th group. However, the parameters given by +{\tt\string\blockparas} or {\tt\string\addressparas} will be +boxed with triple borderlines. Moreover, the macro parameters +{\tt<pre>} and {\tt <post>} will also be displayed explicitly. +Since {\tt\string\addressparas} is essentially a special way of +using {\tt\string\blockparas}, it is highlighted via that for the +{\tt\string\blockparas}. In particular, +{\tt\string\blockparas[3][6][\string\x][\string\y]} for instance +will display under {\tt \string\preview} the following box + +\smallskip +{\previewtrue \blockparas[3][6][\x][\y]} + + +\medskip + +Sometimes we may want to have each given {\sl empty} letter +parameter automatically replaced by a particular {\sl default} +parameter. This can be easily done by using {\tt +\string\loaddefaultparas} inside your letter format, i.e. +essentially between {\tt \string\beginletter} and {\tt +\string\endletter}, before any calling of the letter parameters +via {\tt \string\paras} etc. Of course, the effect of {\tt +\string\loaddefaultparas} is nil unless a command {\tt +\string\paradefaults} is issued inside or (better still) outside +the letter format. We note that {\tt \string\paradefaults} takes +the macro parameters in the exact way as {\tt \string\paranames} +does. One note of caution: {\tt \string\paradefaults} and {\tt +\string\paranames} always use the default delimiters \lq{\tt ; + +!}\rqs no matter how you changed them via {\tt +\string\delimiters}. This is to avoid unnecessary complications. + +\medskip + +We note that printing labels is no more than designing a special +letter template. The mechanism provided in {\tt formlett} however +is to pick a subblock of parameters as the address. Basically all +the form letter output inside {\tt\string\beginlabels} and +{\tt\string\endlabels} will produce labels instead, taking the +first parameter group as the address by default (see Appendix for +more details). Incidentally, labels can be printed in single or +double columns depending upon the choice of label width. + +\medskip + +To conclude this section, we remark that if you want to put {\tt +\string\input\ {\sl filename} } into a letter parameter, make +sure that there is a {\sl nontrivial} space following the {\sl +filename}. To be on the safe side, always use {\tt +\string\inputfile $\{$\sl filename.ext$\}$} instead. Also {\tt +<!>}, when output to screen, is an invitation to read the log +file for a warning message. + +\bigskip +{\lbold Example} + + +\smallskip + +The following is an example. If you are running plain \TeX, add +{\tt\string\input\ formlett} at the top. But if you are running +\LaTeX, then just add at the top the line + +\linecount=1\relax +\stt\beginrawlist[][][4][][][3.3in]{} + \documentstyle[formlett]{article} + \begin{document} +\endrawlist +\rm + + + +The line numbering on the right hand side is for reference only, +as in the other occurrences later on. The example reads as +follows. + +\medskip + +\stt\beginrawlist[][][4][][][3.3in]{} + \beginletter + \paranames % optional + \tt<<FULL NAME>>;% + \tt<<ADDRESS-etc>>;% + +\tt<<GIVEN NAME>>;% + \tt<<MISSING ITEM>>;% + \tt<<PHONE NUMBER>>! + \loaddefaultparas % optional + + \NOPAGENUMBERS\parindent=0pt + \noindent{\it\paras[1]}\par + \blockparas[2]\par\bigskip + + Dear \paras[1][2],\par\medskip + We have been looking for + \paras[2][2] for quite a while + without any luck, could you help + us out? If so, please ring + \paras[3][2]. \par\medskip + Cheers!\hfill Michael\vfill\eject + \endletter + \preview \showparas +\endrawlist +\rm + + +\medskip + +%%%%%%%%%%%% +% letter top +%%%%%%%%%%%% + + \beginletter +\sl +\hsize=3.1in\relax +\medskip + \paranames % optional + \tt<<FULL NAME>>;% + \tt<<ADDRESS-etc>>;% + +\tt<<GIVEN NAME>>;% + \tt<<MISSING ITEM>>;% + \tt<<PHONE NUMBER>>! + \loaddefaultparas % optional + + \NOPAGENUMBERS\parindent=0pt\overfullrule=0pt + \noindent{\it\paras[1]}\par + \blockparas[2]\par\medskip + + Dear \paras[1][2], + + \smallskip + We have been looking for + \paras[2][2] for quite a while + without any luck, could you help + us out? If so, please ring + \paras[3][2]. \par\medskip + Cheers!\hfill Michael\par %\vfill\eject +\medskip + \endletter + +%%%%%%%%%%%% +% letter end +%%%%%%%%%%%% + + +The above is a typical letter format or form letter. Command +{\tt\string\preview} in the last line gives + +{\preview} + +and, the name of the parameters are displayed via +{\tt\string\showparas} as follows + +\showparas + + +\medskip + +In other words, we can have a good understanding about what a +letter format does {\sl 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 {\tt blockmode}, we may add \par + +\medskip +\stt\beginrawlist[][][4][][][3.3in]{} + \paradefaults % optional + To whom this may concern + +Sir or Madam;something;% + 061-225-9905! + + \blockmarks + \beginrawblockmode{} + + Mrs L Stenson + #1-20 Sunset Street + Hillside, Norway + ------ + Louise + a Bible + 220-8888 + ========= + + ...... + + Above empty line active + + \endrawblockmode +\endrawlist +\rm + +%%%%%%%%%%%% +% 1st letter top +%%%%%%%%%%%% +\paradefaults % optional + To whom this may concern ++Sir or Madam;something;% + 061-225-9905! + +%%%%%%%%%%%% +% 1st letter end +%%%%%%%%%%%% + +\medskip +We note the parameters contain special characters \#. That is +the reason why we used {\tt\string\beginrawblockmode}. Now +suppose we have to wrap a very long address line, we could use +{\tt \string\addressbox} to control an {\sl individual} +parameter. The following is a typical case + +\medskip +\stt\beginrawlist[][][4][][][3.3in]{} + \defaultmarks + \moreletter + S Wales,;% + \addressbox[2in][1em]{% + University of Manchester Institute + of Science and Technology, This is + a long address line: it will be + wrapped up automatically.}% + +;a \TeX\ package \gstr\ manual and + many more (\cstr)! +\endrawlist +\rm + +\medskip +which is manifested in the following output + +%%%%%%%%%%%% +% 2nd letter top +%%%%%%%%%%%% +\defaultmarks +\moreletter + S Wales,;% + \addressbox[2in][1em]{% + University of Manchester Institute + of Science and Technology, This is + a long address line: it will be + wrapped up automatically.}% ++;a \TeX\ package \gstr\ manual and + many more (\cstr)! +%%%%%%%%%%%% +% 2nd letter end +%%%%%%%%%%%% + + +\medskip + +Please note that the default parameters have been used there. In +the case of putting {\sl only} name and address into a form +letter, we may typically use {\tt linemode} via e.g. + +\medskip +\stt\beginrawlist[][][4][][][3.3in]{} + \beginlinemode + Z Jiang + UNE, Arimdale + + T Ribbons + UMIST, Manchester + \endlinemode + \end{document} +\endrawlist +\rm + +\medskip + +If one saves lines 4-22 to file {\tt myletter.let}, lines 25-63 +or simply lines 57-63 to file {\tt myletter.adr}, then we can for +instance produce via \LaTeX\ the form letter for multiple +receivers by + +\setraw + \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} +\unsetraw + +{\smooth + +If one puts commands {\tt\string\beginlables} and +{\tt\string\endlabels} at e.g. immediately after line 2 and 63 +respectively, then one gets all the posting labels instead. If +one puts commands {\tt\string\beginfile$\{$scratch.adr$\}$} and +{\tt\string\endfile} there respectively, then by adding after +{\tt\string\endfile} the commands + +\setraw + \inputfile{scratch.adr} + \beginlabels \inputfile{scratch.adr} \endlabels +\unsetraw + +one gets both form letters and the labels. If one insists on not +writing out auxiliary scratch files, then use {\tt \string\input +\ formlett.sty \string\initstyle\ [{\it styles}]$\{${\tt +article}$\}\{${\it preamble}$\}$} to replace {\tt +\string\documentstyle\ [formlett, {\it styles}]$\{$article$\}$ +{\it preamble} \string\begin$\{$document$\}$}, which will be +valid for \LaTeX\ but ignored for \TeX\ , and will enable one to +use {\tt \string\labelsquit} at the end to read in the current +document again with all the letters there converted into the +corresponding labels. If you only want to execute certain +commands the first time round (i.e. before {\tt +\string\labelsquit} re-reads the file again), use {\tt +\string\firstread$\{${\it commands}$\}$} for this purpose. + +} + + +\bigskip +{\lbold Macros} + + +\smallskip + +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 {\tt STK} that we use is +essentially an user-defined stack, while the two dimensional +arrays {\tt LET} and {\tt DEF} are more like structure or record +in other programming languages. First let us make clear that an +array (or stack) of name, say {\tt ABC}, will contain elements +{\tt \string\ABC\it m\tt\t} for one dimensional and {\tt +\string\ABC\it m\tt*\it n\tt\t} 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, {\tt +\string\ABC1*0\t} for instance will denote the number of elements +in the first raw of a two dimensional array {\tt ABC}. + + +\medskip + +Let us now look at how a mechanism of defaulting {\sl macro} +parameters is formulated. For this purpose, we first define a +stack {\tt STK} and its stack pointer {\tt \string\STKcount} by + +\setraw + \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} +\unsetraw + + +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 +{\tt\string\push$\{anything\}$} and later use {\tt \string\pop} +to recall them or {\tt \string\popnil} to remove one element from +the stack. + + +\medskip +So, how can we make defaults for certain empty macro +parameters? The simplest case is perhaps + + +\setraw + \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@} +\unsetraw + + + +Basically, {\tt\string\get@onepara[<A>][<B>]} will push the +default {\tt <A>} to the stack {\tt STK} unless {\tt <B>} is +nonempty. And {\tt\string \get@para\string \left@<A>\string +\right@} will look at the next token to be read, if it is +character \lq{\tt[}\rq, then reads in a macro parameter in the +form of {\tt [<B>]} and then push {\tt <B>} to the stack {\tt +STK}, otherwise push the default {\tt <A>} to that stack. For the +more general case, we need to define + + +\setraw + \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} +\unsetraw + + +so that {\tt\string\st@ckparas \string\left@<A>\string\right@ +...\penalty -20 \string\left@<B>\string\right@ ... +\string\p@r@end} will look for parameters enclosed in {\tt []} +one by one, exhausting all the defaults paired by +{\tt\string\left@} and {\tt \string\right@}. If future tokens +inside {\tt []} are not found, or empty, the default tokens +inside the corresponding pair {\tt\string\left@ \string\right@} +will be used. The new or default tokens will be pushed to the +general-purpose stack {\tt STK} for a later use, while {\tt +\string\p@r@count} records the total number of the default macro +parameters. We note that on exit of {\tt \string\st@ckparas}, the +control is passed to {\tt\string\runCMD}. + +\medskip +Once all macro parameters are pushed to the stack, we may +transfer them to separate toks {\tt \string\p@r@one} to {\tt +\string\p@r@nine} (an easier-to-use format) defined by + +\setraw + \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={}} +\unsetraw + +where {\tt\string\clrp@r@s} clears all the parameter toks. We can +then retrieve parameters from the stack {\tt STK} to the +parameter toks via {\tt\string \getp@r@s} with the following code + + +\setraw + \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}} +\unsetraw + + + +\medskip +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 {\tt \string\crudemac[<A>][<B>]} which +takes two macro parameters {\tt <A>} and {\tt<B>}, and we want to +define a new macro {\tt \string\smartmac} which behaves like {\tt +\string\crudemac} but will default the macro parameters {\tt <A>} +and {\tt <B>} to for instance 9 and 88 respectively. For this +purpose, we may define {\tt \string\smartmac} via + + + +\setraw + \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} +\unsetraw + +This way, all the followings + +\setraw + \crudemac[9][88], \smartmac[9][88], + \smartmac, \smartmac[], \smartmac[][], + \smartmac[9], \smartmac[9][], \smartmac[][88] +\unsetraw + +are the same under the assumption that we shall not use +characters \lq{\tt[}\rqs and \lq{\tt]}\rqs for the macro +parameters themselves, and that {\tt\string\crudemac} will not +change any {\tt \string\catcode} inside. The reason for this +latter condition lies in the fact that when {\tt\string\smartmac} +looks at the next character, the character is in a sense already +read. If {\tt \string\crudemac} changes the {\tt\string\catcode} +of that particular character, then the one that is already read +via {\tt\string\futurelet} will have a misleading +{\tt\string\catcode}. If one has to change {\tt \string\catcode} +inside but wants to avoid this possible misbehavior, always put +full number of empty brackets \lq{\tt[]}\rqs for the defaults, or +put a {\tt\string\relax} immediately afterwards. Better still, +make the last parameter to appear in a mandatory \lq$\{\}$\rqs form +rather than the \lq{\tt []}\rqs form via the {\tt \#$\{$} mechanism +[1], so that those square brackets can be dropped off. + + +\medskip + + +For example, we as a by-product also defined a 100\% +verbatim mode by + +{\stt +\ \ \string\begin@@rawlist[$A$][$B$][$C$][$D$][$E$][$F$]$G$ }\par +\setraw + <general text> + \endrawlist +\unsetraw + + +where, for the line numbering of the raw text, {\tt $A$}, ..., +{\tt $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, {\tt \string\linecount} records the current +line numbering count. Our purpose is to define {\tt +\string\beginrawlist} so that its format is + +{\stt +\ \ \string\beginrawlist[$A$][$B$][$C$][$D$][$E$][$F$]$\{G\}$}\par + +in which $A$ to $F$ are {\sl optional} while $\{G\}$ is mandatory +even though $G$ can be empty --- implying {\tt +\string\endrawlist} is the password to leave the raw-text mode. +For this purpose, we first define + +\setraw +\def\begin@rawlist[#1][#2][#3][#4][#5][#6]#{% + \begin@@rawlist[#1][#2][#3][#4][#5][#6]}% +\unsetraw + +to make \lq$\{\}$\rqs pair compulsory for {\tt \#7}, then we +provide the defaults for {\tt $A$} to {$F$} as +{\tt\string\linecount}, {\tt 1}, {\tt 0}, {\tt \string\tiny}, +{\tt 0pt} and {\tt 0pt} respectively via + +\setraw +\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}% +\unsetraw + +\medskip + +{\smooth +\relax Likewise, we could also similarly define {\tt \string\printfile +[...]}$\{${\it filename.ext}$\}$ so that \lq{\tt [...]}\rqs takes +a same defaulting scheme. } + + +\medskip +There are several tiny but very useful macros in {\tt formlett} +which are used again and again. One of such macros is for testing +if one string contains another string. The following {\tt +\string\test@str} tests if string {\tt\#1} is contained in string +{\tt\#2} + + +\setraw + \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 }% +\unsetraw + + +The {\tt\string\first@half} will contain the tokens upto but +excluding the substring {\tt\#1}, while the {\tt +\string\second@half} will contain the tokens after the {\sl +first} appearance of {\tt\#1}. Should {\tt\#2} not contain string +{\tt\#1} at all, then {\tt \string\first@half} is the whole +string {\tt\#2} whereas {\tt \string\second@half} is empty. + +\medskip + +The small macros such as the above one and the stack utilities, +though built for the main purpose of {\tt formlett}, provide also +a good \lq infrastructure\rqs 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, {\tt +\string\begincomment$\{$\it password$\}$} will set {\sl all} +characters of code {\tt0} to {\tt \string\MAX@CHR@CODE} +(={\tt255} by default) to catcode 11 or 12, and look for the {\it +password}, or {\tt \string\endcomment} in the absence of a +password, to quit the comment mode. In comparison to a very +compact macro {\tt comment.sty} (currently at version 3.0) +written by Victor Eijkhout, quitting comment mode via a password +here seems more flexible. + + + + +\medskip +As for the other macros in {\tt 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 +\lq{\tt+}\rqs and ended by \lq{\tt!}\rq, i.e. $W$ is like +{\tt<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 + + + +\setraw + \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} +\unsetraw + + + +{\smooth Then the command +{\tt \string\testl@stline} {\tt $W$+!\string\s@fetymark } +will set {\tt \string\l@stlinetrue} if +there is only one parameter left in $W$, and will set {\tt +\string\l@stlinefalse} if otherwise. } + + + +\medskip + +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 {\tt<A>}, then {\tt \string\LET2*3\t} +will contain {\tt \string\b@group \string\relax {\tt<A>}\string\e@group} +right after a cluster is read in. {\tt \string\DEF2*3\string~}, on the +other hand, contains the corresponding default parameter in the same +fashion. Furthermore, the command +{\tt\string\checkparas[$m$][$n$]$\{$LET$\}$} will copy the content of +{\tt\string\paras[$m$][$n$]}, minus the `wrapping' extra tokens +{\tt\string\b@group\string\relax} and {\tt\string\e@group}, to +{\tt\string\cachedata} and set {\tt\string\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 {\tt\string \loaddefaultparas} is executed, then the {\tt +LET} array, when some of its elements are not supplied, will contain the +corresponding elements of the {\tt DEF} array. Hence care must be +exercised under such circumstances, when interpreting the +{\tt\string\cachedata} generated by +{\tt\string\checkparas[$m$][$n$]$\{$LET$\}$}. If necessary, we may use +{\tt\string\delparadefaults} to delete current default parameter array +{\tt DEF} so as to conduct {\tt\string\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. + +%\penalty -50 +\bigskip +{\lbold References} + +\smallskip +{\parindent=2em +\item{[1].} Knuth D E, {\sl The \TeX book}, Reading, Mass., +Addison-Wesley, 1992. \par +\item{[2].} Piff M, Text merges in \TeX\ and \LaTeX, {\sl TUGboad}, +13(4):518, 1993. \par +\item{[3].} Damrau J and Wester M, Form letters with 3-across +labels capacity, {\sl TUGboat}, 13(4):510, 1991. +\par +} + + +\penalty -50\bigskip + +{\lbold Appendix} + + +\smallskip + + +In the followings, we give a brief summary of the new commands +given by {\tt formlett} version 2.3. + +\medskip + +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 \lq{\tt !}\rq, with \lq{\tt;}\rqs separating +parameters inside a same group and \lq{\tt+}\rqs separating +different parameter groups. We moreover denote $R$ by $F$, when +\lq{\tt ; + !}\rqs there can be replaced by \lq$P$ $G$ $C$\rqs +respectively if {\tt \string\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$={\tt 1}, $n$={\tt 1}, $p$={\tt 8truecm}, +$q$={\tt 1.5em}, $r$={\tt 3pt}, $A$={\tt\string\noindent}, +$B$={\tt\string\par}, {\tt\string\previewfalse}, +{\tt\string\localparastrue} and {\tt\string\nodefaultsfalse}. + + +%\penalty-10000 + +\vskip 0pt plus 5cm + + +\newdimen\tempdimone +\newdimen\tempdimtwo +\tempdimone=\hsize +\advance\tempdimone by-0.2pt +\tempdimtwo=\hsize +\advance\tempdimtwo by-1.8in +\def\hruler{\hrule width \tempdimone} +\long\def\entry#1#2{% +\par\hbox to \tempdimone{\noindent + \vrule~\textbox[1.7in]{#1}~\hss + \vrule~\textbox[\tempdimtwo]{\raggedright#2}~\vrule}% + \par} + +\long\def\longentry#1#2#3{% +\par\hbox to \tempdimone{\noindent + \vrule~\textbox[3in]{#1}~\hss~\vrule}\par + {\kern-8pt \advance\tempdimtwo0.10in + \vrule width1.7in height0pt \vrule width\tempdimtwo height 0.4pt \par + \kern-3pt} + \entry{#2}{#3}} + +\long\def\Longentry#1#2#3{% +\par\hbox to \tempdimone{\noindent + \vrule~\textbox[3in]{#1}~\hss~\vrule}\par + {\advance\tempdimtwo0.08in\kern-1pt + \vrule~\hfill\vrule width \tempdimtwo height 0.4pt \vrule\par + \kern-2.5pt}% + \entry{#2}{#3}} + + + +\medskip \penalty-100 +{\eightpoint +\nointerlineskip\parskip=0pt + +\hruler +\entry{{\tt\string\paras[$m$][$n$]}}% + {$m^{th}$ parameter of $n^{th}$ group }% + +\entry{{\tt\string\blockparas[$m$][$n$][$A$][$B$]}}% + {$m^{th}$ to the last parameter of $n^{th}$ group, each +preceded by $A$ and followed by $B$, wrapped by $\{$\penalty +1000$\}$ if +$B$={\tt\string\relax}} + +\entry{{\tt\string\addressparas[$m$][$n$][$p$][$q$]}}% + {$m^{th}$ to the last parameter of $n^{th}$ group, each put +into a box of width $p$ with indent $q$ for wrapped portions} + + +\entry{{\tt\string\loaddefaultparas}}% + {fill empty parameters with defaults} + +\hruler \penalty-1000 +\hruler + + +\entry{{\tt\string\checkparas[$m$][$n$]$\{T\}$}}% + {$m^{th}$ parameter of $n^{th}$ group copied to {\tt\string\cachedata}; + {\tt\string\ifemptyparas} is true if element is empty; $T$ is often + {\tt LET} or {\tt DEF}}% + +\hruler + + +\entry{{\tt\string\moreletter\ $F$}}% + {use parameters $F$ to output a new letter} + + +\entry{{\tt\string\paranames\ $R$}}% + {use $R$ as parameter names} + +\entry{{\tt\string\paradefaults\ $R$}}% + {use $R$ as default parameters} + + +\entry{{\tt\string\delparadefaults}}% + {delete default parameters} + +%\hruler \penalty-1000 +\hruler + + +\entry{{\tt\string\delimiters$\{P\}\{G\}\{C\}$}}% + {use $P$, $G$, $C$ as delimiters} + + +\entry{{\tt\string\defaultmarks}}% + {use \lq{\tt ; + !}\rqs as delimiters} + + +\entry{{\tt\string\blockmarks}}% + {use \lq{\tt ....}\rq, \lq{\tt ----}\rq, \lq{\tt ====}\rqs as delimiters} + +%\hruler \penalty -1000 +\hruler + +\entry{{\tt\string\preview}}% + {highlight parameter positions} + +\entry{{\tt\string\showparas}}% + {display parameter names, if any} + +\entry{{\tt\string\inputletter$\{file.ext\}$}}% + {input letter content} + +\entry{{\tt\string\inputfile$\{file.ext\}$}}% + {input $file.ext$} + +%\hruler \penalty -1000 +\hruler + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginletter}\cr +\hbox{\tt\string\endletter~~}\cr}\right.$ }% + {delimiters for letter content (template)} + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginpilemode}\cr +\hbox{\tt\string\endpilemode~~}\cr}\right.$ }% + {normal letter parameters cluster-wise} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginblockmode}\cr +\hbox{\tt\string\endblockmode~~}\cr}\right.$ }% + {for line-by-line blocks of parameters, empty lines active +within each cluster} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginlinemode}\cr +\hbox{\tt\string\endlinemode~~}\cr}\right.$ }% + {for line-by-line parameters, empty lines delimit clusters} + +%\hruler \penalty-1000 +\hruler + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginrawblockmode$\{T\}$}\cr +\hbox{\tt\string\endrawblockmode\ \ \ \ \ }\cr}\right.$ }% + {raw text mode; nonempty $T$ replaces {\tt\string\endrawblockmode} + to mark end} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginrawlinemode$\{T\}$}\cr +\hbox{\tt\string\endrawlinemode\ \ \ \ \ \ }\cr}\right.$ }% + {raw text parameters and active spaces etc} + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\begindatamode[$T$]$\{m\}$}\cr +\hbox{\tt\string\enddatamode\ \ \ \ \ \ \ \ }\cr}\right.$ }% + {$m$ raw text lines for one form letter} + +\hruler + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\begincolumns[$a$][$b$]}\cr +\hbox{\tt\string\endcolumns\ \ \ \ \ \ \ }\cr}\right.$ }% + {$a$-columns separated by distance $b$} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\begincomment$\{T\}$}\cr +\hbox{\tt\string\endcomment\ \ \ \ \ }\cr}\right.$\par + \ \ \ {\tiny }}% + {comment out lines, nonempty $T$ replaces {\tt +\string\endcomment} to mark last {\sl full line} for comment} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginfile[$T$]$\{{\it +file.ext}\}$}\cr +\hbox{\tt\string\endfile\ \ \ \ \ \ \ \ \ \ \ \ \ }\cr}\right.$\par + \ \ \ {\tiny }}% + {write text verbatim to file {\it file.ext} (empty implies {\tt +scr@tch@.tex}), nonempty $T$ replaces {\tt +\string\endfile} to mark last full line} + + + +\hruler + + +\entry{{\tt\string\PAGENO=1}}% + {page number reset to 1} + + +\entry{{\tt\string\NOPAGENUMBERS}}% + {no page numbers} + + +\entry{{\tt\string\textbox[$p$]$\{text\}$}}% + {$text$ into box of width $p$} + + +\entry{{\tt\string\boxmore[$r$]$\{X\}$}}% + {add borderline to box $X$ at a distance $r$} + + +\entry{{\tt\string\addressbox[$p$][$q$]$\{text\}$}}% + {$text$ into box of width $p$, with wrapped options indented +by $q$} + +\hruler + + +\entry{{\tt\string\previewfalse}}% + {given parameters instead of highlighted boxes will be shown} + + +\entry{{\tt\string\localparastrue}}% + {letter parameters put into $\{\}$ before displayed} + + +\entry{{\tt\string\nodefaultsfalse}}% + {take defaults for empty letter parameters} + +\hruler + +\entry{{\tt\string\previewtrue}}{{\it cf.} above} + + +\entry{{\tt\string\localparasfalse}}{} + + +\entry{{\tt\string\nodefaultstrue}}{} + +\hruler + +\vskip0pt plus 1cm +~\hfill $\underline{\hbox{\sl Table continues in the next page}}$ + +\penalty-5000 +\hruler + + +\Longentry{% +$\left\{\matrix{ \hbox{\tt\string\beginrawlist + [$a$][$b$][$c$][$d$][$e$][$f$]$\{g\}$}\cr + \hbox{\tt\string\endrawlist\hskip3.4cm}\cr}\right.$ }% + {\strut\par{\sl defaults:}\everypar={\hbox{\ \ \ }}\par\par + $a$={\tt\string\linecount},\par + $b$={\tt1}, $c$={\tt0},\par + $d$={\tt\string\tiny@rm}, \par + $e$={\tt0pt}, $f$={\tt0pt}, \par + $g$={\tt\string\endrawlist}}% +{verbatim listing, line count from $a$, step $b$, digits $c$, +font $d$, text position $e$, numbering shift $f$, end mark $g$} + +\hruler \vskip0.5pt +\Longentry{% +$\matrix{\hbox{\tt \string\printfile + [$a$][$b$][$c$][$d$][$e$][$f$]$\{$\it file.ext$\}$}\cr + \hbox{}\cr}$}% + {\strut\par{\sl defaults:} ~~$c$={\tt6} {\it etc}}% + {verbatim listing of {\it file.ext}} + +\hruler + + + +\Longentry{% +$\left\{\matrix{ \hbox{\tt\string\beginlabels + [$a$][$b$][$c$][$d$][$e$][$f$]}\cr + \hbox{\tt\string\endlabels\hskip3cm}\cr}\right.$ }% + {\strut\par{\sl defaults:}\everypar={\hbox{\ \ \ }}\par\par + $a$={\tt 20pt}, \par $b$={\tt\string\tt\string\raggedright}, + \par $c$={\tt1}, $d$={\tt1}, \par + $e$={\tt2.6in}, $f$={\tt2em}}% + {form letters become labels: address taken from $c^{th}$ to +last parameter of $d^{th}$ group, with width $e$, indent +$f$, borderspace $a$ and font toks $b$} + +\hruler + + +\entry{{\tt\string\firstread$\{T\}$}}% + {toks $T$ will not be read if the file is re-read via {\tt + \string\labelsquit}} + + +\entry{{\tt\string\initstyle[$a$]$\{b\}\{c\}$}}% + {initiation for {\tt\string\labelsquit},with styles $a$, + documentstyle $b$ and preamble $c$} + +\entry{{\tt\string\initclass[$a$][$o$]$\{b\}\{c\}$}}% + {similar to {\tt\string\initstyle} ($o$ is \LaTeX2e options), + but retains native \LaTeX2e when applicable} + + +\hruler \vskip0.5pt +\Longentry{% +$\matrix{\hbox{\tt \string\labelsquit + [$a$][$b$][$c$][$d$][$e$][$f$]$\{$\it file.ext$\}$}\cr + \hbox{}\cr}$}% + {\strut\par{\sl defaults:}\everypar={\hbox{\ \ \ }}\par\par + see that for {\tt\string\beginlabels}} + {quit after converting letters to labels by reading the current + document or {\it file.ext}} + +\hruler + + + +\def\ABC{{\tt\esc@}{\it abc}} + + +\entry{{\tt\string\newarray\ABC}}% + {make array named {\it abc} along with + {\tt\ABC} and {\tt\string\check{\it abc}}} + + +\entry{{\tt\string\delarray\ABC}}% + {delete array named {\it abc}} + + +\hruler + + +\entry{{\tt\ABC($m$)=$\{T\}$}}% + {assign tokens $T$ to {\tt\ABC($m$)}; + {\tt\ABC($m$)} $\equiv$ + {\tt\ABC($m_1,...,m_k$)} for + $m$=$1+\sum_1^k (m_i-1)*\hbox{\tt\string\dataheight}^{k-i}$} + + +\entry{{\tt\ABC($m$)}}{value of {\tt\ABC($m$)}, + if not followed by `{\tt=}'} + + +\entry{{\tt\string\dataheight}}{current array dimension: {\it cf.} + {\tt\ABC($m$)}} + + +\entry{{\tt\string\readarray$\{N\}\{a_1 \hbox{\&}\, ..\, \hbox{\&} a_n\}$}}% + {equivalent to {\tt\esc@{\it N}(1)}=$a_1$, .., + {\tt\esc@{\it N}($n$)}=$a_n$} + + + +\entry{{\tt\string\check{\it abc}($m$)}}% + {copy {\tt\ABC($m$)} to {\tt\string\cachedata}; + set {\tt\string\ifemptydata} to true/false accordingly} + + +\hruler + +\entry{{\tt\string\readstyles$\{f_1,...,f_n\}$}}% + {read files $f_1$ to $f_n$ with default extension {\tt .sty}; + {\tt @}'s catcode set to {\tt 11} during input} + +\hruler + + +} + +\footline={\lower5pt +\hbox to \hsize + {{\rm Jiang Z ~~~{\sl Formlett: ~for letters to multiple receivers} + \hss {\sl $\bullet$End of Document$\bullet$} +\hss \folio}}} + +\vskip 8in + +%\vfill\eject +\endcolumns +\vfill\eject + + + +%%%%%%%%%%%%%%%%%% +% MAKE EXAMPLE1.TEX EXAMPLE2.TEX +%%%%%%%%%%%%%%%%%% + + + +\message{Can I create <example1.tex> and <example2.tex> ? (y/n) }% +\read-1 to \reply \def\nono{n }\def\Nono{N }\def\noNo{no }\def\NoNo{NO }% +\def\next{\end{document}}% +\ifx\reply\nono\else\ifx\reply\Nono\else\ifx\reply\noNo\else +\ifx\reply\NoNo\else\let\next\relax +\message{(=== YES ===)}\fi\fi\fi\fi \next + + + + +\beginfile[EndOfExample1]{example1.tex} + +% Example1: EXAMPLE for using scratch files +% under plain TeX or LaTeX +% + +\input formlett.sty +% +%%%% MAKE scr@tch@.let +% +\beginfile{scr@tch@.let} + +% letter content +\boxmore[10pt]{\hbox{\vbox{% BOX FOR BORDERLINE + +\parindent=0pt +\blockparas + +\bigskip\bigskip + +Dear \paras, + +\bigskip + +This part is typically the letter content. Since we are using a +scratch file for our main body of our letter, the letter can be +arbitrarily long, in comparison to using {\tt \string\beginletter} +and {\tt \string\endletter} mechanism. Using a scratch file enables +us to keep everything inside one single file so that it won't be mixed +up with other letters. + +\medskip + +The idea of scratch file can also be applied to creating the address +file, so that the address file can be read for the form letters in the +first time and for mailing labels in the second time. These features are +the purpose of this particular example. + +\medskip +Thanks for using {\tt formlett.sty}. + +}}} % END OF BOX FOR BORDERLINE +\vfill\eject + +\endfile + + +% +%%%% MAKE scr@tch@.adr +% +\beginfile{scr@tch@.adr} +% address file +\beginlinemode +\tt<name> +address line one +address line two +etc + +\tt<NAME> +ADDRESS LINE ONE +ADDRESS LINE TWO +ETC + +\endlinemode +\endfile + + +% +%%% MAIN PROCESSING BODY +% + +\hsize=5in +\initstyle{}{} + % Above line is put here for being + % able to run this file under either TeX or LaTeX. + % It may be deleted for TeX. It may also be replaced + % under LaTeX by \documentstyle{article} \begin{article} + % for instance + +\inputletter{scr@tch@.let} +\inputfile{scr@tch@.adr} % for form letters +\beginlabels +\inputfile{scr@tch@.adr} % for labels +\endlabels + +\end{document} + +EndOfExample1 +% above is password + + + + + + +\beginfile{example2.tex}% + +% Example2: EXAMPLE for self-read +% under plain TeX or LaTeX +% + + +\input formlett.sty +\hsize=3.2in % for plain TeX +\initstyle[]{}{\textwidth=3.2in} % for LaTeX + +% MY LOGO +% +\catcode`\@=11\relax +\def\UWS{{\vbadness=10000 \hbadness=10000 \hfuzz=\maxdimen + \vfuzz=\maxdimen \font\tiny=cmr5 \font\small=cmr7 + \def\today{\number\day\space\ifcase\month\or January\or February\or + March\or April\or May\or June\or July\or August\or September\or + October\or November\or December\fi\space\number\year}% + \def\make@temp@box{\csname newbox\endcsname \temp@box\relax}% + \ifx\temp@box\undefined \def\next{\make@temp@box}\else\def\next{}\fi\next + \font\HUGE=cmss10 at 24.87999pt \noindent + \setbox\temp@box=\hbox{\vbox to 0pt{\hbox{\HUGE + U\hskip6pt W\hskip6pt S}}}% + \def\buffdim{65pt}%\wd\temp@box 61.588pt + \rlap{\copy\temp@box}% + \rlap{\hskip.4pt\copy\temp@box}% + \rlap{\hskip.8pt\copy\temp@box}% + \rlap{\hskip1.2pt\copy\temp@box}% + \rlap{\hskip1.6pt\copy\temp@box}% + \rlap{\hskip2pt\copy\temp@box}% + \rlap{\hskip2.4pt\copy\temp@box}% + \rlap{\hskip2.8pt\copy\temp@box}% + \rlap{\hskip6pt\copy\temp@box}% + \rlap{\lower23pt \hbox to \buffdim{\tiny \hskip4pt The ~~~University~~~ Of}}% + \rlap{\lower25pt \hbox{\hskip2pt + \hbox to \buffdim{\vrule width \buffdim depth .2pt}}}% + \rlap{\lower32pt \hbox to \buffdim{\small \hskip-1pt WESTERN SYDNEY}}% + \setbox\temp@box=\hbox{\vbox{\let\noindent=\hfill + \font\small=cmss8 \baselineskip=8pt %plus 0.5pt minus 0.5pt + \small \parskip=0pt + \noindent School of Computing and IT\par + \noindent University of Western Sydney\par + \noindent Victoria Road, Parramatta\par + \noindent NSW 2150, Australia\par + \medskip + \noindent Email: ~z.jiang@uws.edu.au\par + \noindent Tel: ~(INT-) 61- 2- 96859336\par + \noindent Fax: ~(INT-) 61- 2- 96859245\par + \medskip\bigskip + \noindent \tt\today}}% + \rlap{\lower3.0cm \hbox{\box\temp@box}}% +}\par}\catcode`\@=12\relax +% + +\beginletter +\paranames % optional + \tt<<FULL NAME>>;% + \tt<<ADDRESS-etc>>;% + +\tt<<GIVEN NAME>>;% + \tt<<MISSING ITEM>>;% + \tt<<PHONE NUMBER>>! +\loaddefaultparas % optional + +\NOPAGENUMBERS\parindent=0pt\overfullrule=0pt +\UWS \par\bigskip\bigskip\bigskip +\noindent{\it\paras[1]}\par +\blockparas[2]\par\bigskip + +Dear \paras[1][2],\par\medskip +We have been looking for +\paras[2][2] for quite a while +without any luck, could you help +us out? If so, please ring +\paras[3][2]. \par\medskip +Cheers!\hfill Zhuhan\vfill\eject +\endletter +\preview \showparas +\eject % \eject here is purely for better labels + + +\paradefaults % optional + To whom this may concern + +Sir or Madam;something;% + 061-225-9905! + + +\blockmarks +\beginblockmode + +Mrs L Stenson +\#1-20 Sunset Street +Hillside, Norway +------ separate groups +Louise +a Bible +220-8888 +========= separate cluster + +...... force entry next line + +Above empty line active + +\endblockmode comment ignored + +\defaultmarks +\moreletter + S Wales,;% + \addressbox[2in][1em]{University of Manchester Institute + of Science and Technology, This is + a long address line: it will be + wrapped up automatically.} + +;a \TeX\ package \gstr\ manual and + many more (\cstr)! + +\beginlinemode + S Pan + UNE, Arimdale + + T Ribbons + UMIST, Manchester +\endlinemode + +\beginpilemode + + C Anderson;42nd Street;USA+Christine;your service invoice! + + D Holmes;Flat \#2, Finneybank Rd;London+David;the tax receipt;% + 071-902 7799! + +\endpilemode + +\begindatamode{3} % strictly 3 lines for one letter +data-#1 +data-#2 +data-#3 +data-#4 +data-#5 +\enddatamode + +\ifISLATEX \firstread{\global\textwidth=6in} +\else \firstread{\hsize=6in}\fi % make labels double columns + +\labelsquit{} +\end{document} % redundant +\endfile + + + +\message{Now go and TeX or LaTeX <example1.tex> and <example2.tex>}% + + +\end{document} +% +% +% +%ENDDOCUMENT + + + diff --git a/macros/generic/formlett/user_manual.pdf b/macros/generic/formlett/user_manual.pdf Binary files differnew file mode 100644 index 0000000000..e23ef4bd2b --- /dev/null +++ b/macros/generic/formlett/user_manual.pdf diff --git a/macros/generic/formlett/user_manual.tex b/macros/generic/formlett/user_manual.tex new file mode 100644 index 0000000000..b317848477 --- /dev/null +++ b/macros/generic/formlett/user_manual.tex @@ -0,0 +1,1113 @@ +% USER MANUAL in Plain TeX + +\input formlett.sty + +% FONTS +\font\hbold=cmbx10 at 17.28pt +\font\lbold=cmbx10 at 14.4pt +\font\bbold=cmbx10 at 12pt +\font\small=cmr8 +\font\tiny=cmr5 +\font\stt=cmtt9 +\catcode`\@=11\relax +% +% +% +% OTHER MACROS +% +\catcode`\~=11\relax \def\t{{\tt ~}} +\catcode`\~=\active\relax +\catcode`\!=0\relax !catcode`!\=11!relax +!def!esc{\}!def!escs{\! } +!catcode`!\=0!relax \catcode`\!=12\relax +\def\rqs{\rq\ } +\def\LaTeX{{\rm L\kern-.36em\raise.3ex\hbox{\font\sc=cmcsc10\sc a}\kern-.15em + T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} + +% makeshift macro +\catcode`\^^M=13\relax% +\def\setraw{\bgroup\rm@ligature\set@space\set@tab% +\set@cr\stt\raw@chars[11][13][13][13][13]\def^^M{\strut\par}\setraw@@}% +\edef\temp@macro{% + \noexpand\long\noexpand\def\noexpand\setraw@@\noexpand##1^^M##2% + \esc@ unsetraw{##1##2\noexpand\egroup}}\temp@macro % +\catcode`\^^M=5\relax% + + +\font\ninerm=cmr9 \font\eightrm=cmr8 +\font\ninei=cmmi9 \font\eighti=cmmi8 +\font\ninesy=cmsy9 \font\eightsy=cmsy8 +\font\ninebf=cmbx9 \font\eightbf=cmbx8 +\font\ninett=cmtt9 \font\eighttt=cmtt8 +\font\nineit=cmti9 \font\eightit=cmti8 +\font\ninesl=cmsl9 \font\eightsl=cmsl8 + +\font\sixrm=cmr6 +\font\sixi=cmmi6 +\font\sixsy=cmsy6 +\font\sixbf=cmbx6 + +\skewchar\ninei='177 \skewchar\eighti='177 \skewchar\sixi='177 +\skewchar\ninesy='60 \skewchar\eightsy='60 \skewchar\sixsy='60 +\hyphenchar\ninett=-1 \hyphenchar\eighttt=-1 \hyphenchar\tentt=-1 + +\font\tentex=cmtex10 +\font\inchhigh=cminch +\font\titlefont=cmssdc10 at 40pt % titles in chapter openings +\font\eightss=cmssq8 % quotations in chapter closings +\font\eightssi=cmssqi8 % ditto, slanted +\font\tenu=cmu10 % unslanted te~t italic +\font\manual=manfnt % METAFONT logo and special symbols +\font\magnifiedfiverm=cmr5 at 10pt % to demonstrate magnification + +\newskip\ttglue +\def\eightpoint{\def\rm{\fam0\eightrm}% switch to 8-point type + \textfont0=\eightrm \scriptfont0=\sixrm \scriptscriptfont0=\fiverm + \textfont1=\eighti \scriptfont1=\sixi \scriptscriptfont1=\fivei + \textfont2=\eightsy \scriptfont2=\sixsy \scriptscriptfont2=\fivesy + \textfont3=\tenex \scriptfont3=\tenex \scriptscriptfont3=\tenex + \textfont\itfam=\eightit \def\it{\fam\itfam\eightit}% + \textfont\slfam=\eightsl \def\sl{\fam\slfam\eightsl}% + \textfont\ttfam=\eighttt \def\tt{\fam\ttfam\eighttt}% + \textfont\bffam=\eightbf \scriptfont\bffam=\sixbf + \scriptscriptfont\bffam=\fivebf \def\bf{\fam\bffam\eightbf}%, + \tt \ttglue=.5em plus.25em minus.15em + \normalbaselineskip=9pt + \setbox\strutbox=\hbox{\vrule height7pt depth2pt width0pt}% + \let\sc=\sixrm \let\big=\eightbig \normalbaselines\rm} + + +%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%% +% +% END OF EXTRA MACROS AND FONTS +% +%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%% + + + + +\catcode`\@=11\relax +\PAGENO=1 +\voffset=-0.3in + + +\ifx\pageno\undefined +\errmessage{Please run TeX if you want this article on how to use +<formlett.sty> to be processed as well!} +\fi + + +\parindent=0pt +\hsize=469.75499pt % the default +\vsize=9.6in %8.83in + +\def\makefootline{\baselineskip=24pt \line{\the\footline}} +\footline={\lower5pt +\hbox to \hsize + {{\tenrm Jiang Z ~~~{\tensl Mail merge with the use of formlett.sty} +\hss \folio}}} + +\leftline{\hbold Mail merge with the use of formlett.sty} +\bigskip + + +{\advance\leftskip by13mm \overfullrule=0pt +\advance\rightskip by 20mm %28mm +\sl +\noindent Zhuhan JIANG\par +\noindent School of Computing and Information Technology, + University of Western Sydney, Victoria Road, Parramatta NSW 2150, Australia. +{\sl ~~Email}:~z.jiang@uws.edu.au\par +\medskip +\rm\smooth +\noindent (Last updated on 26 May 2003)\par +\medskip + +\noindent +In this article, the author explains how to use a form-letter or mail +merge style {\tt formlett.sty}, designed for plain \TeX\space and +\LaTeX\space or \LaTeX2e. {\tt formlett.sty} supports different +parameter input methods, parameter naming and defaulting mechanism, as +well as facilities for previewing parameter positions and printing +labels. It is written for the purpose of being powerful, robust and +above all easy to use.\par } + + +\begincolumns + +{\lbold Introduction} + +\smallskip + +Our purpose here is to describe a comprehensive implementation of a +macro system, handling form letters or mail merge under plain \TeX\space +or \LaTeX\space2.09 or \LaTeX2e. The main objective is to provide an +easy way to output many form letters with their own parameters, with or +without the use of multiple files. There will be a coherent and simple +format for putting parameters inside a form letter, with a number of +helping facilities for such as naming parameters and previewing their +positions. A minimum support for printing mailing labels is also +provided. + + +\medskip + +The concept of macros [1] for form letters is not new: there already +exist macros in this connection such as {\tt merge}, {\tt textmerg} and +{\tt address} to name a few, see [2,3] for further details. Our stress +here is therefore laid on the ease to use, along with the power and the +robustness of the macros. + +\bigskip + + +{\lbold Basic format} + + +%%%%%%%%%%%% +% letter top +%%%%%%%%%%%% + + \beginletter +\sl +\hsize=3.1in\relax +\medskip + \paranames % optional + \tt<<FULL NAME>>;% + \tt<<ADDRESS-01>>;% + \tt<<ADDRESS-02>>;% + \tt<<GIVEN NAME>>;% + \tt<<MISSING ITEM>>;% + \tt<<PHONE NUMBER>>! + \loaddefaultparas % optional + + \NOPAGENUMBERS\parindent=0pt\overfullrule=0pt + \paras[1]\par\paras[2]\par\paras[3]\par\medskip + + Dear \paras[4], + + \smallskip + We have been looking for + \paras[5] for quite a while + without any luck, could you help + us out? If so, please ring + \paras[6]. \par\medskip + Cheers!\hfill Michael\par %\vfill\eject +\medskip + \endletter + +%%%%%%%%%%%% +% letter end +%%%%%%%%%%%% + + +Suppose we would like to write a form letter for mail merge in the +following form + +\showparas + +where the text inside the double arrow brackets are to be replaced by +the parameters specific to each individual letter. If we number these +parameters one by one in a single group, then the letter template will +be organised as + +\preview + +and we need just 6 parameters to personalise an individual letter. A +simplest example of supplying a set or a {\sl cluster} of these +parameters to output a merged form letter is to use + +\setraw +\moreletter + Mrs L Stenson;\#1-20 Sunset Street;% + Hills, Norway;Louise;a Bible;220-8888! +\unsetraw + +For more letters to be merged this way, just use again the +command {\tt\string\moreletter} in the above format, in which each +parameter is separated by a semicolon `{\tt ;}' and the whole parameter +cluster is ended by an exclamation mark `{\tt !}'. The actual code in +\LaTeX\space for making the above form letter, along with an extra +merged letter, may read as follows + + +\edef\setrawcount{\stt\noexpand + \beginrawlist[][][4][][][3.3in]{\esc@ unsetraw}} + +\linecount=1\relax +\setrawcount + \documentstyle[formlett]{article} + \begin{document} + \beginletter + \NOPAGENUMBERS\parindent=0pt + \paras[1]\par\paras[2]\par + \paras[3]\par\medskip + Dear \paras[4], \par\medskip + We have been looking for + \paras[5] for quite a while + without any luck, could you help + us out? If so, please ring + \paras[6]. \par\medskip + Cheers!\hfill Michael\vfill\eject + \endletter + + \moreletter % letter one + Mrs L Stenson;\#1-20 Sunset Street;% + Hills, Norway;Louise;a Bible;220-8888! + \moreletter % letter two + S Wales;UMIST;Manchester;Sir or Madam;% + a \TeX\ package{+}manual;225-9905! + \end{document} +\unsetraw +\rm + +The line numbers in the above and later on are for quick reference only: +they are not a part of the program code. The letter template in lines +4-13 is defined by the {\tt\string\beginletter} and {\tt\string\endletter} +pair in line 3 and line 14, with each use of {\tt\string\moreletter} +generating a new merged letter. We note that command {\tt \string\paras[{\it +m}]} represents the $m^{th}$ merged parameter (of the first group, see +later), and the command {\tt\string\NOPAGENUMBERS} +will remove the page numbering for both \LaTeX\space and plain +\TeX. We also note that if one replaces lines 1-2 by +{\tt\string\input\space formlett.sty}, then the program will be +compilable under plain \TeX\space as well. + + +\medskip + +Although the mail merge mechanism in the above will be sufficient for +most simple applications, {\tt formlett} provides in fact many more +features. We shall thus in the followings introduce the main features +one by one, from the most useful to the less likely encountered. + +\medskip + +To start with, we notice that in the above example there are exactly two +parameters to be used for the address. This is inconvenient to say the +least, even if we allocate say three more extra parameters for the +purpose. This naturally calls for the separation of the whole {\sl +cluster} of parameters into several {\sl groups}, so that the numbering +of the parameters in every group will be resynchronised. We thus use +{\tt\string\paras[{\it m}][{\it n}]} to denote the $m^{th}$ parameter of +the $n^{th}$ group of a whole cluster of merging parameters. In fact we +may use {\tt\string\blockparas[{\it m}][{\it n}][{\it pre}][{\it post}]} +to represent parameters in the $n^{th}$ group, from the $m^{th}$ to the +last parameter of that group, where the tokens denoted by {\it pre} and +{\it post} are those to be added in front and behind respectively each +of the legitimate parameters. The defaults for {\it pre} and {\it post} +are {\tt\string\noindent} and {\tt\string\par} respectively. It is +therefore more sensible to specify the merging parameters of the earlier +example via + + +%%%%%%%%%%%% +% letter top +%%%%%%%%%%%% + + \beginletter +\sl +\hsize=3.1in\relax +\medskip + \paranames % optional + \tt<<FULL NAME>>\hfill + \tiny\fillzeros[4]\linecount\global\advance\linecount1\relax\par;% + \tt<<ADDRESS-etc>>\hfill + \tiny\fillzeros[4]\linecount\global\advance\linecount1\relax\par;% + +\tt<<GIVEN NAME>>;% + \tt<<MISSING ITEM>>;% + \tt<<PHONE NUMBER>>! + \loaddefaultparas % optional + + \NOPAGENUMBERS\parindent=0pt\overfullrule=0pt + \noindent{\it\paras[1]}\par + \blockparas[2]\par\medskip + + Dear \paras[1][2], + + \smallskip + We have been looking for + \paras[2][2] for quite a while + without any luck, could you help + us out? If so, please ring + \paras[3][2]. \par\medskip + Cheers!\hfill Michael\par %\vfill\eject +\medskip + \endletter + +%%%%%%%%%%%% +% letter end +%%%%%%%%%%%% + +\showparas + +where {\tt <<ADDRESS-etc>>} will be produced by +{\tt\string\blockparas[2][1]}, i.e. all the parameters of the first +group, starting from the 2nd parameter. We note that the missing +square-bracketed macro parameters for {\tt\string\blockparas} are +automatically provided: in fact macro parameters in {\tt formlett} are +systematically defaulted. Hence for example, {\tt \string\paras[1][1]} +is equivalent to any of the following commands + +\setraw + \paras, \paras[1], \paras[][1], + \paras[1][], \paras[][] +\unsetraw + +As for the more precise position of the merging parameters, they can +always be viewed via the command {\tt\string\preview}, which in this +case gives the following positioning + +\preview + +This way, the mail merge for the above letter template can also be done +(in plain \TeX) in the following more flexible way + +\setrawcount + \input formlett.sty + \beginletter + \NOPAGENUMBERS\parindent=0pt + \noindent{\it\paras[1]}\par + \blockparas[2]\par\bigskip + Dear \paras[1][2],\par\medskip + We have been looking for + \paras[2][2] for quite a while + without any luck, could you help + us out? If so, please ring + \paras[3][2]. \par\medskip + Cheers!\hfill Michael\vfill\eject + \endletter \preview + + \beginpilemode + Mrs L Stenson;\#1-20 Sunset Street + Hills, Norway+Louise;a Bible;220-8888! + + S Wales;UMIST;Manchester+% + Sir or Madam;a \TeX\space + package{+}manual;225-9905! + \endpilemode + \end +\unsetraw +\rm + + +We note that by default we used plus sign `{\tt +}' to separate +different groups inside a cluster of parameters, and each cluster inside +a {\tt\string\beginpilemode} and {\tt\string\endpilemode} pair will +output a merged letter, as if it were produced by command +{\tt\string\moreletter} followed by that cluster of parameters. +The output of the first merged letter in fact reads + +\moreletter + Mrs L Stenson;\#1-20 Sunset Street + Hills, Norway+Louise;a Bible;220-8888! + + +\medskip + +It is often desirable to supply parameters line by line, i.e. one line +as one parameter. Hence the two merged letters produced by lines 25-47 +can also be made by replacing the content included in the +{\tt\string\beginpilemode} and {\tt\string\endpilemode} pair (lines +39-46) by the following new code + +\setrawcount +\blockmarks +\beginblockmode +Mrs L Stenson +\#1-20 Sunset Street +Hills, Norway +----- +Louise +a Bible +220-8888 +====== + +S Wales +UMIST +Manchester +---- +Sir or Madam +a \TeX\ package+manual +225-9905 +==== +\endblockmode +\defaultmarks +\unsetraw +\rm + +where obviously we have used lines with `{\tt----}' to separate groups +and used lines with `{\tt====}' to end a cluster of parameters. This was +done by the use of {\tt\string\blockmarks} which changes the group +delimiter `{\tt +}' and cluster delimiter `{\tt !}' into the above two +new ones, with the {\tt\string\defaultmarks} at the end setting them +back. If the whole cluster of parameters are categorised into a single +(first) group, then we may even use a block of consecutive nonempty +lines to provide the merging parameters. This is done by the use of +command pair {\tt\string\beginlinemode} and {\tt\string\endlinemode}. +Hence we may also conduct the above mail merge in for instance \LaTeX2e +by + + +\setrawcount +\documentclass{article} +\usepackage{formlett} +\begin{document} + \beginletter + \NOPAGENUMBERS\parindent=0pt + \paras[4]\par\blockparas[5] + \par\medskip + Dear \paras[1], \par\medskip + We have been looking for + \paras[2] for quite a while + without any luck, could you help + us out? If so, please ring + \paras[3]. \par\medskip + Cheers!\hfill Michael\vfill\eject + \endletter + +\beginlinemode +Louise +a Bible +220-8888 +Mrs L Stenson +\#1-20 Sunset Street +Hills, Norway + +Sir or Madam +a \TeX\ package+manual +225-9905 +S Wales +UMIST +Manchester +\endlinemode +\end{document} +\unsetraw +\rm + +Notice that we have changed the numbering order of the parameters so +that the number of address lines output by {\tt\string\blockparas} is +more flexible. + + +\bigskip +{\lbold Advanced features} + +The advanced features to be discussed below are mainly for the purpose +of (i) writing {\sl long} form letter; (ii) making {\sl many} different +form letters; (iii) reading mail merge parameters that are in {\sl +crude} ASCII form; and (iv) generating mail labels. + +\medskip + +It is in general better to keep the letter template, i.e. the content +between {\tt\string\beginletter} and {\tt\string\endletter} like those +in lines 4-13, in a separate file, say {\tt myletter.let}, and use +{\tt\string\inputletter$\{$myletter.let$\}$} to load in the letter +template. The advantage of this over the previously used method is that +the letter template can now be arbitrarily large without any risks of +causing computer memory problem. + +\medskip + +Suppose we have a collection of letter templates, we may wish to remind +ourselves what each parameter represents. For this purpose, we may add +at the top of the letter template a command {\tt\string\paranames} {\it +cluster}{\tt !}, where {\it cluster} is a cluster of parameters each +giving a name to the corresponding parameter. Command +{\tt\string\paranames} takes its macro parameters in the same way +{\tt\string\moreletter} does. After a letter template is read in, +command {\tt\string\showparas} will output a form letter with its +parameters replaced by the corresponding names. The mainly italic +passage containing lines 23-24, for instance, is the output of +{\tt\string\showparas} for the letter template in lines 102-109 given +explicitly later on. + +\medskip + +We may also use {\tt\string\paradefaults} {\it cluster}{\tt !} to +provide default parameters, i.e. the parameters to replace the empty or +not entered ones, and use {\tt\string \loaddefaultparas} inside letter +template to activate the parameter defaulting. We note that in general +commands {\tt\string\paranames} and {\tt\string\loaddefaultparas}, if +present, should be at the top of the letter template, with +{\tt\string\loaddefaultparas} below the command {\tt\string\paranames}. +Hence for our previous mail merge, we may re-do it via + + +\setrawcount + \input formlett.sty + \beginletter + \paranames % optional + \tt<<FULL NAME>>;\tt<<ADDRESS-etc>>;% + +\tt<<GIVEN NAME>>;\tt<<MISSING ITEM>>;% + \tt<<PHONE NUMBER>>! + \loaddefaultparas % optional +\unsetraw + +\ \ \ {\it $\{$letter details given in lines 27-36$\}$} +\hfill{\tiny\fillzeros[4]\linecount\global\advance\linecount1\relax} + +\setrawcount + \endletter + \preview \showparas + + \paradefaults % optional + To whom this may concern + +Sir or Madam;something;% + 061-225-9905! + +\blockmarks +\beginrawblockmode{} +Mrs L Stenson +#1-20 Sunset Street +Hills, Norway +------ +Louise +a Bible +220-8888 +========= + +...... + +Above empty line active +\endrawblockmode +\defaultmarks +\end{document} +\unsetraw +\rm + +We note that in {\sl blockmode} with {\tt\string\blockmarks}, a line +with `{\tt ....}' marks the immediate start of a parameter block, +whether or not the lines immediately following it are empty or not. Also +that in {\it rawblockmode} enclosed by {\tt\string \beginrawblockmode} +and {\tt\string\endrawblockmode}, all characters are input in their +original ASCII form. In other words, the special characters for +\TeX\space will be ignored here. + +\medskip + +If the merging parameters are given by exactly $m$ lines per cluster, as +is often the case when they are produced by a database utility, then we +may use the {\tt\string\begindatamode} and {\tt\string\enddatamode} pair +to mark the beginning and the end of the merging parameters. For more +details, see the Appendix at the end. + +\medskip + +We may keep the letter template and the merging parameters in two +separate files. For instance, if we save lines 103-108 to file {\tt +myletter.let}, lines 39-46 or lines 48-68 to file {\tt myletter.adr}, +then we can produce via \LaTeX\ the mail merge by + +\setrawcount + \documentstyle[formlett]{article} + \begin{document} + \inputletter{myletter.let} + \showparas \preview % utility demo + \paradefaults To whom it may concern! + \inputfile{myletter.adr} + \beginlabels % 1st group as address + \inputfile{myletter.adr} % for labels + \endlabels + \end{document} +\unsetraw +\rm + +where the lines 140-142 will generate the address labels using the first +group (as is intended here) of parameters. More precise format of +{\tt\string\beginlabels} and etc can be found in the Appendix. + +\medskip + +Another way of making labels, if no separate files for the parameters +are present, is to re-read the document itself and make labels instead +of merged form letters in the second reading. We may thus use {\tt +\string\input \ formlett.sty \string\initstyle\ [{\it styles}]$\{${\tt +article}$\}\{${\it preamble}$\}$} to replace {\tt \string\documentstyle\ +[formlett, {\it styles}]$\{$article$\}$ {\it preamble} +\string\begin$\{$document$\}$}, which will be valid for \LaTeX\ but +ignored for \TeX\ , and will enable one to use {\tt \string\labelsquit} +at the end to read in the current document again with all the letters +there converted into the corresponding labels. Though +{\tt\string\initstyle} is valid for plain \TeX, \LaTeX2.09 as well as +\LaTeX2e, {\tt\string\initclass} will generate +{\tt\string\documentclass} instead of {\tt\string\documentstyle} when +\LaTeX2e is the processing environment. If you only want to execute +certain commands the first time round (i.e. before {\tt +\string\labelsquit} re-reads the file again), use {\tt +\string\firstread$\{${\it commands}$\}$} for this purpose. For more +detailed use and examples, read the {\sl programmer's document} attached +to the style file {\tt formlett.sty} and the example files it generates. +In fact, many details and extra features that are not contained in this +article may be found there. + +\medskip + +We already noted that if a form letter is large, we have to use +{\tt\string\inputletter} to load in the template. However, it is often +still desirable to keep everything inside a single file, while allowing +it to make new (scratch) files when it is being compiled. We may thus +use for example + +\setraw + \beginfile{myletter.let} +\unsetraw + +\ \ \ {\it $\{$letter template of lines 103-108$\}$} + +\setraw + \endfile +\unsetraw +\rm + +to create a letter template file {\tt myletter.let}. Likewise, the +merging parameters can be saved to another run-time created file {\tt +myletter.adr}. + + +\medskip + +We have so far only used the default delimiters `{\tt ;}', `{\tt +}' and +`{\tt !}' to separate single, group and cluster of parameters, with +temporary change via {\tt\string\blockmarks} to `{\tt ....}', `{\tt +----}' and `{\tt ====}' respectively. However we may change the +delimiters to any characters by {\tt +\string\delimiters$\{S\}\{G\}\{C\}$}, where $S$, $G$ and $C$ are the +tokens to delimit single, group and cluster of parameters respectively, +and change the delimiters back to the default by +{\tt\string\defaultmarks} or equivalently by +{\tt\string\delimiters$\{$;$\}\{$+$\}\{$!$\}$}. + +\medskip + + +To conclude this section, let us finally look below at an `ideal' and +`finished' mail merge application code,. It is currently in a form +compilable under \LaTeX2e, and is also valid for plain \TeX\space if the +first three lines (lines 144-146) are removed. + +\setrawcount +\documentclass{article} +\usepackage{formlett} % LaTeX2e +\begin{document} + +%%%% MAKE file scr@tch@.let +\beginfile{scr@tch@.let} % letter content +\paranames <<name>>;<<address>>+<<items>>! +\loaddefaultparas +\parindent=0pt\blockparas\bigskip\bigskip +Dear \paras, \par\bigskip +This part is typically the letter content. +It now displays all the items in the 2nd +parameter group. They are \par +\blockparas[][2] \vfill\eject +\endfile + +%%%% MAKE file scr@tch@.adr +\beginfile{scr@tch@.adr} % address file +\blockmarks +\beginblockmode +T Teng +UMIST +Manchester M60 1QD +===== + +Z Jiang +UNE +Armidale NSW 2351 +Australia +------ +Email: zhuhan@neumann.une.edu.au +===== +\endblockmode +\defaultmarks +\endfile + +% MAIN BODY +\paradefaults To Whom It May Concern + +No further info available{!}! +\inputletter{scr@tch@.let} +\inputfile{scr@tch@.adr}% for letters +\beginlabels +\inputfile{scr@tch@.adr}% for labels +\endlabels +\end{document} +\unsetraw +\rm + +We note that if we replace lines 144-146 by {\tt\string\input\space +formlett.sty \string\initstyle$\{\}\{\}$}, then the mail merge can be +processed by either plain \TeX\space or \LaTeX\space (including +\LaTeX2e). It is likewise if {\tt\string\initstyle} in the replaced +line is replaced furthermore by {\tt\string\initclass}, except that now +the native \LaTeX2e environment is preserved, when applicable, rather +than turning it into the compatibility mode of \LaTeX2.09. + +\bigskip +{\lbold Programmer's tips} + +\smallskip + +First we note that all the macro parameters that are to appear inside +square brackets of {\tt formlett}'s commands are defaulted, just like +how {\tt\string\paras[$m$][$n$]} is defaulted earlier on. The actual +default values can be found in the Appendix. + +\medskip + +For those wizard users who want to do everything their own way, we point +out that if for instance the 3rd letter parameter of the 2nd group of a +cluster is given as {\tt<A>}, then {\tt \string\LET2*3\t} will contain +{\tt \string\b@group \string\relax {\tt<A>}\string\e@group} right after +a cluster is read in. {\tt \string\DEF2*3\string~}, on the other hand, +contains the corresponding default parameter in the same fashion. +Furthermore, the command {\tt\string\checkparas[$m$][$n$]$\{$LET$\}$} +will copy the content of {\tt\string\paras[$m$][$n$]}, minus the +`wrapping' extra tokens {\tt\string\b@group\string\relax} and +{\tt\string\e@group}, to {\tt\string\cachedata} and set +{\tt\string\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 {\tt\string +\loaddefaultparas} is executed, then the {\tt LET} array, when some of +its elements are not supplied, will contain the corresponding elements +of the {\tt DEF} array. Hence care must be exercised under such +circumstances, when interpreting the {\tt\string\cachedata} generated by +{\tt\string\checkparas[$m$][$n$]$\{$LET$\}$}. If necessary, we may use +{\tt\string\delparadefaults} to delete current default parameter array +{\tt DEF} so as to conduct {\tt\string\checkparas$\{$LET$\}$} more +precisely. + +\medskip + +There are also a number of generic macro utilities in {\tt formlett}, +including a user stack and a multi-dimensional array mechanism. + +\medskip + +{\tt formlett} was written for all \TeX\space dialects, its format is +thus more close to that of plain \TeX. In fact, we deliberately avoided +mixing up {\tt formlett} with the standard letter environment of \LaTeX. +This is largely due to the fact that the limited facilities of +\LaTeX\space letter environment are easy to come by anyway, and are not +really worth writing buckled code to make {\tt formlett} a type of +extension of the environment. Nevertheless, one can still use the letter +environment of \LaTeX\space inside the form letter template. Besides, +the applicability of {\tt formlett} is not restricted for making form +{\sl letters}; it can also be used to merge other type of articles or +passages. + + + + +\bigskip +{\lbold References} + +\smallskip +{\parindent=2em +\item{[1].} Knuth D E, {\sl The \TeX book}, Reading, Mass., +Addison-Wesley, 1992. \par +\item{[2].} Piff M, Text merges in \TeX\ and \LaTeX, {\sl TUGboad}, +13(4):518, 1993. \par +\item{[3].} Damrau J and Wester M, Form letters with 3-across +labels capacity, {\sl TUGboat}, 13(4):510, 1991. +\par +} + + + + +\penalty -50\bigskip + +{\lbold Appendix} + + + +\smallskip + + +In the followings, we give a brief summary of the main commands given by +{\tt formlett} version 2.1. + +\medskip + +Let $m$ and $n$ be numbers, $p$, $q$ and $r$ be dimensions, $A$, +$B$, $S$, $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 \lq{\tt !}\rq, with \lq{\tt;}\rqs separating +parameters inside a same group and \lq{\tt+}\rqs separating +different parameter groups. We moreover denote $R$ by $F$, when +\lq{\tt ; + !}\rqs there can be replaced by \lq$S$ $G$ $C$\rqs +respectively if {\tt \string\delimiters$\{S\}\{G\}\{C\}$} is +issued. In the commands tabulated below, the macro parameters +contained in squared brackets support default. In particular, the +defaults are $m$={\tt 1}, $n$={\tt 1}, $p$={\tt 8truecm}, +$q$={\tt 1.5em}, $r$={\tt 3pt}, $A$={\tt\string\noindent} and +$B$={\tt\string\par}. + + + +\newdimen\tempdimone +\newdimen\tempdimtwo +\tempdimone=\hsize +\advance\tempdimone by-0.2pt +\tempdimtwo=\hsize +\advance\tempdimtwo by-1.8in +\def\hruler{\hrule width \tempdimone} +\long\def\entry#1#2{% +\par\hbox to \tempdimone{\noindent + \vrule~\textbox[1.7in]{#1}~\hss + \vrule~\textbox[\tempdimtwo]{\raggedright#2}~\vrule}% + \par} + +\long\def\longentry#1#2#3{% +\par\hbox to \tempdimone{\noindent + \vrule~\textbox[3in]{#1}~\hss~\vrule}\par + {\kern-8pt \advance\tempdimtwo0.10in + \vrule width1.7in height0pt \vrule width\tempdimtwo height 0.4pt \par + \kern-3pt} + \entry{#2}{#3}} + +\long\def\Longentry#1#2#3{% +\par\hbox to \tempdimone{\noindent + \vrule~\textbox[3in]{#1}~\hss~\vrule}\par + {\advance\tempdimtwo0.08in\kern-1pt + \vrule~\hfill\vrule width \tempdimtwo height 0.4pt \vrule\par + \kern-2.5pt}% + \entry{#2}{#3}} + + + +\bigskip %\bigskip +\penalty-1000 \vskip 0pt plus4in + +{\eightpoint +\nointerlineskip\parskip=0pt + +\hruler +\entry{{\tt\string\paras[$m$][$n$]}}% + {$m^{th}$ parameter of $n^{th}$ group }% + +\entry{{\tt\string\blockparas[$m$][$n$][$A$][$B$]}}% + {$m^{th}$ to the last parameter of $n^{th}$ group, each +preceded by $A$ and followed by $B$, wrapped by $\{$\penalty +1000$\}$ if +$B$={\tt\string\relax}} + +\entry{{\tt\string\addressparas[$m$][$n$][$p$][$q$]}}% + {$m^{th}$ to the last parameter of $n^{th}$ group, each put +into a box of width $p$ with indent $q$ for wrapped portions} + + +\entry{{\tt\string\loaddefaultparas}}% + {fill empty parameters with defaults} + +%\hruler \penalty-1000 +\hruler + + +\entry{{\tt\string\checkparas[$m$][$n$]$\{T\}$}}% + {$m^{th}$ parameter of $n^{th}$ group copied to {\tt\string\cachedata}; + {\tt\string\ifemptyparas} is true if element is empty; $T$ is often + {\tt LET} or {\tt DEF}}% + + +\hruler + + +\entry{{\tt\string\moreletter\ $F$}}% + {use parameters $F$ to output a new letter} + + +\entry{{\tt\string\paranames\ $R$}}% + {use $R$ as parameter names} + +\entry{{\tt\string\paradefaults\ $R$}}% + {use $R$ as default parameters} + +\entry{{\tt\string\delparadefaults}}% + {delete default parameters} + +\hruler + + +\entry{{\tt\string\delimiters$\{S\}\{G\}\{C\}$}}% + {use $S$, $G$, $C$ as delimiters} + + +\entry{{\tt\string\defaultmarks}}% + {use \lq{\tt ; + !}\rqs as delimiters} + + +\entry{{\tt\string\blockmarks}}% + {use \lq{\tt ....}\rq, \lq{\tt ----}\rq, \lq{\tt ====}\rqs as delimiters} + +%\hruler \penalty -1000 +\hruler + +\entry{{\tt\string\preview}}% + {highlight parameter positions} + +\entry{{\tt\string\showparas}}% + {display parameter names, if any} + +\hruler + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginfile[$T$]$\{{\it +file.ext}\}$}\cr +\hbox{\tt\string\endfile\ \ \ \ \ \ \ \ \ \ \ \ \ }\cr}\right.$\par + \ \ \ {\tiny }}% + {write text verbatim to file {\it file.ext} (empty implies {\tt +scr@tch@.tex}), nonempty $T$ replaces {\tt +\string\endfile} to mark last full line} + + + +\entry{{\tt\string\inputletter$\{file.ext\}$}}% + {input letter content} + +\entry{{\tt\string\inputfile$\{file.ext\}$}}% + {input $file.ext$} + +\hruler \penalty -5000 %\vskip0pt plus 1cm +\hruler + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginletter}\cr +\hbox{\tt\string\endletter~~}\cr}\right.$ }% + {delimiters for letter content (template)} + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginpilemode}\cr +\hbox{\tt\string\endpilemode~~}\cr}\right.$ }% + {normal letter parameters cluster-wise} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginblockmode}\cr +\hbox{\tt\string\endblockmode~~}\cr}\right.$ }% + {for line-by-line blocks of parameters, empty lines active +within each cluster} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginlinemode}\cr +\hbox{\tt\string\endlinemode~~}\cr}\right.$ }% + {for line-by-line parameters, empty lines delimit clusters} + +\hruler \penalty-1000 +%\hruler + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginrawblockmode$\{T\}$}\cr +\hbox{\tt\string\endrawblockmode\ \ \ \ \ }\cr}\right.$ }% + {raw text mode; nonempty $T$ replaces {\tt\string\endrawblockmode} + to mark end} + + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\beginrawlinemode$\{T\}$}\cr +\hbox{\tt\string\endrawlinemode\ \ \ \ \ \ }\cr}\right.$ }% + {raw text parameters and active spaces etc} + +\entry{% +$\left\{\matrix{ \hbox{\tt\string\begindatamode[$T$]$\{m\}$}\cr +\hbox{\tt\string\enddatamode\ \ \ \ \ \ \ \ }\cr}\right.$ }% + {$m$ raw text lines for one form letter} + + +%\hruler \penalty-2000 +\hruler + + +\entry{{\tt\string\PAGENO=1}}% + {page number reset to 1} + + +\entry{{\tt\string\NOPAGENUMBERS}}% + {no page numbers} + + +\entry{{\tt\string\textbox[$p$]$\{text\}$}}% + {$text$ into box of width $p$} + + +\entry{{\tt\string\boxmore[$r$]$\{X\}$}}% + {add borderline to box $X$ at a distance $r$} + + +\entry{{\tt\string\addressbox[$p$][$q$]$\{text\}$}}% + {$text$ into box of width $p$, with wrapped options indented +by $q$} + + +\hruler + +\Longentry{% +$\left\{\matrix{ \hbox{\tt\string\beginlabels + [$a$][$b$][$c$][$d$][$e$][$f$]}\cr + \hbox{\tt\string\endlabels\hskip3cm}\cr}\right.$ }% + {\strut\par{\sl defaults:}\everypar={\hbox{\ \ \ }}\par\par + $a$={\tt 20pt}, \par $b$={\tt\string\tt\string\raggedright}, + \par $c$={\tt1}, $d$={\tt1}, \par + $e$={\tt2.6in}, $f$={\tt2em}}% + {form letters become labels: address taken from $c^{th}$ to +last parameter of $d^{th}$ group, with width $e$, indent +$f$, borderspace $a$ and font toks $b$} + +\hruler + + +\entry{{\tt\string\firstread$\{T\}$}}% + {toks $T$ will not be read if the file is re-read via {\tt + \string\labelsquit}} + + +\entry{{\tt\string\initstyle[$a$]$\{b\}\{c\}$}}% + {initiation for {\tt\string\labelsquit},with styles $a$, + documentstyle $b$ and preamble $c$} + + +\entry{{\tt\string\initclass[$a$][$o$]$\{b\}\{c\}$}}% + {similar to {\tt\string\initstyle} ($o$ is \LaTeX2e options), + but retains native \LaTeX2e when applicable} + + +\hruler \vskip0.5pt +\Longentry{% +$\matrix{\hbox{\tt \string\labelsquit + [$a$][$b$][$c$][$d$][$e$][$f$]$\{$\it file.ext$\}$}\cr + \hbox{}\cr}$}% + {\strut\par{\sl defaults:}\everypar={\hbox{\ \ \ }}\par\par + see that for {\tt\string\beginlabels}} + {quit after converting letters to labels by reading the current + document or {\it file.ext}} + +\hruler + +} + +\footline={\lower5pt +\hbox to \hsize + {{\rm Jiang Z ~~~{\sl Mail merge with the use of formlett.sty} + \hss {\sl $\bullet$End of Document$\bullet$} +\hss \folio}}} + + +\vrule height2.9in width0pt depth0pt +\endcolumns +\vfill\eject + + + +\end{document} + + + + |