diff options
Diffstat (limited to 'Master/texmf-dist/doc/generic/arobend/AroundTheBend.tex')
-rw-r--r-- | Master/texmf-dist/doc/generic/arobend/AroundTheBend.tex | 7419 |
1 files changed, 7419 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/generic/arobend/AroundTheBend.tex b/Master/texmf-dist/doc/generic/arobend/AroundTheBend.tex new file mode 100644 index 00000000000..ac01d718075 --- /dev/null +++ b/Master/texmf-dist/doc/generic/arobend/AroundTheBend.tex @@ -0,0 +1,7419 @@ +% AroundTheBend.tex concatenation of Around The Bend + +\begin{filecontents}{bend.ist} +% MakeIndex style file bend.ist for use with AroundTheBend.tex + +% @ may be a valid character in the index, use ? instead +actual '?' + +\end{filecontents} + +%\documentclass[draft,openany]{memoir} +\documentclass[openany]{memoir} +\usepackage{comment} +\usepackage{url} +\ifpdf + \usepackage[pdftex, + plainpages=false, + pdfpagelabels, + bookmarksnumbered + ]{hyperref} +\else + \usepackage[%pdf, + plainpages=false, + pdfpagelabels, + bookmarksnumbered + ]{hyperref} +\fi +\usepackage{graphicx} + +\settrimmedsize{11in}{210mm}{*}% min letterpaper/A4 sizes +\setlength{\trimtop}{0pt} +\setlength{\trimedge}{\stockwidth} +\addtolength{\trimedge}{-\paperwidth} +\settypeblocksize{7.75in}{33pc}{*} +\setulmargins{4cm}{*}{*} +\setlrmargins{1.25in}{*}{*} +\setmarginnotes{17pt}{51pt}{\onelineskip} +\setheadfoot{\onelineskip}{2\onelineskip} +\setheaderspaces{*}{2\onelineskip}{*} +\checkandfixthelayout + +%\addtolength{\textwidth}{1in} +%\addtolength{\oddsidemargin}{-0.5in} +%\addtolength{\evensidemargin}{-0.5in} + +\newcommand{\ed}[1]{\emph{(Ed: #1)}} +\newcommand*{\oposted}[1]{Originally posted on #1} +\newcommand*{\arch}[1]{Archived as {\normalfont \ttfamily #1}} +\newenvironment{solution}[1]{% + \begin{description} + \item[#1]\mbox{}}% +% {\par\noindent\textbf{End solution}\end{description}} + {\end{description}\vspace{-0.5\onelineskip}\textbf{End solution}} +\newcommand*{\pfile}[1]{\texttt{#1}}% print a file name +\newfixedcaption{\freetabcaption}{table} +\renewcommand*{\chaptername}{QA} +\renewcommand*{\chaptername}{} + +% \piif{if...} print and index \if... +\newcommand*{\piif}[1]{\cs{#1}\index{#1?\cs{#1}}} +\makeatletter +\newcommand*{\zeroseps}{% + \topsep\z@ + \partopsep\z@ + \parskip\z@} +\newlength{\gparindent} \gparindent 0.5\parindent +\newenvironment{lcode}{\zeroseps + \renewcommand{\verbatim@startline}% + {\verbatim@line{\hskip\gparindent}}% + \small\setlength{\baselineskip}{\onelineskip}\verbatim}% + {\endverbatim + \vspace{-\baselineskip}\noindent} +\makeatother + +\nouppercaseheads +\headstyles{bringhurst} +%\setlength{\beforechapskip}{2\onelineskip} +\chapterstyle{section} +\setlength{\beforechapskip}{2\onelineskip} +\setlength{\beforechapskip}{0pt} +\setlength{\afterchapskip}{1\onelineskip} +\settocdepth{subsubsection} +\setsecnumdepth{subsubsection} + +\makeindex + +%\title{Around The Bend} +%\author{Michael Downes \\ +%(edited by Peter Wilson)} +%\date{} +\newlength{\drop} +\providecommand*{\wb}[2]{\fontsize{#1}{#2}\usefont{U}{webo}{xl}{n}} +\newcommand*{\titleAB}{\begingroup +\drop=4\baselineskip +\centering +\vspace*{\drop} +{\Huge AROUND THE BEND}\\[\drop] +{\hspace*{1.5em}\scalebox{8}[1]{{\wb{10}{12}4}}}\\[\drop] +{\Large\itshape A Collection of TeX Challenges by}\\[\baselineskip] +{\Large MICHAEL DOWNES}\\[\baselineskip] +{\wb{10}{12}4}\\[\baselineskip] +{\Large\itshape edited by}\\[\baselineskip] +{\Large Peter Wilson}\par +\vfill +{\hspace*{1.5em}\scalebox{8}[1]{{\wb{10}{12}4}}}\\[\drop] +{\large The Herries Press}\\ +{July 2008}\par +\vspace*{\drop} +\endgroup} +%% normally \parindent = 1.5em, but 0pt in \titleAB + +\begin{document} +\tightlists +\raggedbottom + +\frontmatter + +%\maketitle +\thispagestyle{empty} +\titleAB +\cleardoublepage +\tableofcontents + +\chapter{Preface} + + In the early 90's the late and much missed Michael Downes (1958--2003) +ran a column in the INFO-TeX mailing list +called \emph{Around The Bend} where he proposed macro-related problems and +then posted +submitted solutions. Although it was archived on CTAN in \url{info/aro-bend} +it is not well known which is a shame as it provides +answers to many problems that keep cropping up. (The archive is now +at \url{info/challenges/aro-bend}). This is an attempt to +make his work more accessible by providing the collection as a single +document. + + As much as possible what follows is what Michael wrote; I have tried to +limit myself to marking up the original ASCII text emails but I have not +repeated administrative elements such as email headers. + + In some cases the +original TeX code was replete with comments explaining what was going on. +Where the comments were long with respect to the code I have set them in +the regular body type so as to make the actual code more obvious; this has a +side effect of slightly decreasing the amount of paper required to +print the document. If you +want to use the code solutions I suggest that you cut and paste them +from the original archived versions. + + I thought that there were eighteen Around the Bends as that is all that +are archived on CTAN. However I googled the Google Groups \url{comp.text.tex} +group +and found three more, nos.~19, 20 and~21. I have included what I could find +of these, but answers to no.~19 appear to be missing, which is a pity as +I think that I could have put them to use. Perhaps some of you might be +willing to take up the challenge on this, or on any of the others. + + + +{\raggedleft \textsc{PW}\\ July, 2008 \par} + +\chapter{Introduction} + +\ed{This is Michael's introduction to his scheme, originally posted on +1991/10/10 as the initial portion of exercise~1.} + + +%%[Exercises 1,2,3 were originally posted together on 10 Oct 91] +\begin{verbatim} +Date: Thu 10 Oct 91 09:51:32-EST +From: Michael Downes <MJD@MATH.AMS.COM> +Subject: Around the bend +To: info-tex@shsu.edu +\end{verbatim} + +Proposal for a regular feature: + + AROUND THE BEND + +With the encouragement of George Greenwade (the INFO-TeX list owner), I +would like to propose a regular department for INFO-TeX, called `Around +the bend'. It will consist of macro-writing challenges on the level of +the dangerous-bend exercises in the \emph{TeXbook}, with interested parties +invited to collaborate and/or compete to find the best solution. My +motivation for doing this is partly selfish: to get more feedback from +other macro writers about some of the interesting macro-writing +problems that I run into. + +I originally approached George for advice about setting up a separate +mailing list, but he thought that INFO-TeX and comp.text.tex readers +would be interested. Since INFO-TeX mail is also channeled to +comp.text.tex, readers of the latter should let me know if they don't +want the extra traffic (although I don't expect it to be that much). I +don't currently have access to read comp.text.tex directly, although +George has been investigating the possibility of piping it through the +INFO-TeX mailing list. So if you object by posting to comp.text.tex, I +may not see your objection; send me mail, instead. + +The sample below should give a pretty good idea of what `Around the +bend' would be like. Solutions should be sent to me instead of to +INFO-TeX or comp.text.tex, on the premise that people usually won't want +to read others' solutions until they've had a chance to try their own +hand. A summary of the results would then be posted to the INFO-TeX +list after two or three weeks; to those who submit solutions before the +deadline, I could forward without delay solutions submitted by other +people, for comparison. + +I will try to keep the difficulty of the exercises down to something +reasonable, let's say, on the level of a homework assignment which a +university student must complete in two weeks, finding time in the +normal way from the usual busy schedule of other homework, class +attendance, sports, and social life. However, be warned that the +challenges will be hard. I'm planning to follow a `hard and fast' +format: one or two hard questions, followed by one or two fast +questions, where if you don't know the answer off the top of your head, +you can either look it up in the \emph{TeXbook} or find it by running a quick +test. + + +\mainmatter + + +\chapter{Expansion} + +\section{Exercise (hard)} + +%%\input{ex001.tex} +% ex001.tex + +\begin{comment} + +(Originally posted on 1991/10/10) + +[Exercises 1,2,3 were originally posted together on 10 Oct 91] +Date: Thu 10 Oct 91 09:51:32-EST +From: Michael Downes <MJD@MATH.AMS.COM> +Subject: Around the bend +To: info-tex@shsu.edu + +Proposal for a regular feature: + + AROUND THE BEND + +With the encouragement of George Greenwade (the INFO-TeX list owner), I +would like to propose a regular department for INFO-TeX, called `Around +the bend'. It will consist of macro-writing challenges on the level of +the dangerous-bend exercises in the TeXbook, with interested parties +invited to collaborate and/or compete to find the best solution. My +motivation for doing this is partly selfish: to get more feedback from +other macro writers about some of the interesting macro-writing +problems that I run into. + +I originally approached George for advice about setting up a separate +mailing list, but he thought that INFO-TeX and comp.text.tex readers +would be interested. Since INFO-TeX mail is also channeled to +comp.text.tex, readers of the latter should let me know if they don't +want the extra traffic (although I don't expect it to be that much). I +don't currently have access to read comp.text.tex directly, although +George has been investigating the possibility of piping it through the +INFO-TeX mailing list. So if you object by posting to comp.text.tex, I +may not see your objection; send me mail, instead. + +The sample below should give a pretty good idea of what `Around the +bend' would be like. Solutions should be sent to me instead of to +INFO-TeX or comp.text.tex, on the premise that people usually won't want +to read others' solutions until they've had a chance to try their own +hand. A summary of the results would then be posted to the INFO-TeX +list after two or three weeks; to those who submit solutions before the +deadline, I could forward without delay solutions submitted by other +people, for comparison. + +I will try to keep the difficulty of the exercises down to something +reasonable, let's say, on the level of a homework assignment which a +university student must complete in two weeks, finding time in the +normal way from the usual busy schedule of other homework, class +attendance, sports, and social life. However, be warned that the +challenges will be hard. I'm planning to follow a `hard and fast' +format: one or two hard questions, followed by one or two fast +questions, where if you don't know the answer off the top of your head, +you can either look it up in the TeXbook or find it by running a quick +test. + +All right, here are the first three. + +\end{comment} + +%********************************************************************** +%*** Exercise 1 (hard): + +\ed{\oposted{1991/10/10}. \arch{exercise.001}.}\\%[0.5\baselineskip] + +Given arbitrary \cmd{\b}, \cmd{\c}, \cmd{\d} (macros without arguments), for example +\begin{lcode} + \def\b{\c\c} \def\c{*} \def\d{\b\c} +\end{lcode} +figure out how to define \cmd{\a} so that its replacement text consists +of \cmd{\b} fully expanded plus \cmd{\c} not expanded plus \cmd{\d} expanded +exactly once. +I.e., with the above definitions the replacement text of \cmd{\a} +should be +\begin{lcode} + **\c\b\c +\end{lcode} +You may not use \cmd{\the} or \cmd{\noexpand} in your solution. This is Exercise +20.16 in the \emph{TeXbook}, except that there's an added restriction: your +answer must also not use the \cmd{\halign}\texttt{\ldots}\cmd{\span} method given in the +answer to 20.16. (Yes, that means you can't use \cmd{\valign} either!) + +Why would anyone want to do such a hard exercise? Answer: advanced +macro writing requires a thorough knowledge of expansion control +principles. + +\begin{comment} +[Exercise 2 moved to exercise.002] + +[Exercise 3 moved to exercise.003] + +Send answers to: + +Michael Downes mjd@math.ams.com (Internet) + +A summary will be posted Friday, October 25, 1991. +\end{comment} + +%%\endinput + + +\section{Answers} + +%%\input{ans001.tex} +% ans001.tex + +\ed{\oposted{1991/10/25}. \arch{answer.001}.}\\ + + +\begin{comment} +[Solutions for exercises 1,2,3 were originally posted together on 25 Oct 91] +Date: Fri 25 Oct 91 15:19:44-EST +From: Michael Downes <MJD@MATH.AMS.COM> +Subject: `Around the bend' #1 solutions +To: info-tex@shsu.edu + +Solutions to the exercises of `Around the bend' #1. + +"*** Exercise 1 (hard): +"Given arbitrary \b, \c, \d (macros without arguments), for example +" +" \def\b{\c\c} \def\c{*} \def\d{\b\c} +" +"figure out how to define \a so that its replacement text consists +"of \b fully expanded plus \c not expanded plus \d expanded exactly once. +"I.e., with the above definitions the replacement text of \a +"should be +" +" **\c\b\c +" +"You may not use \the or \noexpand in your solution. This is Exercise +"20.16 in the TeXbook, except that there's an added restriction: your +"answer must also not use the \halign ... \span method given in the +"answer to 20.16. (Yes, that means you can't use \valign either!) +\end{comment} + +The restrictions leave us with (essentially) three expansion-control +commands: \\ + \cmd{\expandafter}, \cmd{\edef} and \cmd{\def}. + +%\begin{description} +%\item[Solution 1 {[Peter Schmitt]}] \mbox{} +\begin{solution}{Solution 1 (Peter Schmitt)}\index{Schmitt, Peter} +\begin{lcode} + \edef\B{\b} + \def\defA#1{\def\defa##1##2{\def\a{#1##2##1}}} + \expandafter\defA\expandafter{\B} + \expandafter\defa\expandafter{\d}{\c} +\end{lcode} +\end{solution} + +%%>>EndSolution + +%\item[Solution 2 {[Donald Arseneau]}] \mbox{} +\begin{solution}{Solution 2 (Donald Arseneau)}\index{Arseneau, Donald} +\begin{lcode} +\edef\e{\b} +\expandafter \expandafter \expandafter \def\expandafter \expandafter +\expandafter \a\expandafter \expandafter \expandafter {\expandafter +\e\expandafter \c\d} +\end{lcode} +\end{solution} +%%>>EndSolution + +%\item[Solution 3 {[mine]}] \mbox{} +\begin{solution}{Solution 3 (mine)}\index{Downes, Michael} +\begin{lcode} +\edef\a{\b} +\expandafter\expandafter\expandafter\def +\expandafter\expandafter\expandafter\a +\expandafter\expandafter\expandafter{\expandafter\a\expandafter\c\d} +\end{lcode} +\end{solution} +%%>>EndSolution +%\end{description} + +My solution differed from Arseneau's only in using \cmd{\a} rather than \cmd{\e} +in the first step. + +\begin{comment} +[Solution for exercise 2 moved to answer.002] +[Solution for exercise 3 moved to answer.003] + +Michael Downes mjd@math.ams.com (Internet) + +\end{comment} + +%%\endinput + + +\chapter{Empty argument} + +\section{Exercise (hard)} + +%%\input{ex002.tex} +% ex002.tex + +\begin{comment} + +[Posted to info-tex on 10 Oct 91; see exercise.001] +********************************************************************** +*** Exercise 2 (hard): +\end{comment} + +\ed{\oposted{1991/10/10}. \arch{exercise.002}.}\\ + +Define an `ifempty' macro that takes one argument and resolves +essentially to \piif{iftrue} if the argument is empty, and \piif{iffalse} +otherwise. This is useful for handling arguments given by +users to commands defined in a macro package. + +Plain TeX or LaTeX-style solutions are both acceptable, that +is, +\begin{lcode} + \ifempty{...}TRUE CASE\else FALSE CASE\fi +\end{lcode} +or +\begin{lcode} + \ifempty{...}{TRUE CASE}{FALSE CASE} +\end{lcode} + +(In the former case you will need to do something to avoid problems +in the situation +\begin{lcode} + \iffalse ... \ifempty{...} ... \fi ... \fi +\end{lcode} +there +are different possibilities here, so I will refrain from +indicating any particular one.) + +Use the following test suite to verify the robustness of your +solution: + +\begin{lcode} +\long\def\test#1{\begingroup \toks0{[#1]}% + \newlinechar`\/\message{/\the\toks0: +% LaTeX-style solution; modify the following line according +% to the syntax of your solution. + \ifempty{#1}{EMPTY}{NOT empty}% +}\endgroup} + + \test{} \test{ } + \test{aabc} \test{-} + \test{$} \test{\empty} + \test{\endinput} \test{\iftrue a\else b\fi} + \test{\else} \test{#} + \test{\par} \halign{#\cr\test{&}\cr} + \test{\relax} \test{\relax\relax\relax} + \expandafter\iffalse\test{x}\fi \test{{}} +\end{lcode} +%$ + +The two tests on the first line should produce a message `EMPTY' and +the remaining ones, `NOT empty'. The reason for saying that the second +test should return `EMPTY' is that (1) this is the ideal behavior for +the applications I've encountered so far; (2) at least one other person +working independently arrived before me at a solution essentially +identical to mine, including this behavior. The details and credit to +the other guy will be given at solution time. + +%%\endinput + + +\section{Answers} + +%%\input{ans002.tex} +% ans002.tex + +\begin{comment} + +[Posted to info-tex on 25 Oct 91; see answer.001] +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +"*** Exercise 2 (hard): +"Define an "ifempty" macro that takes one argument and resolves +"essentially to \iftrue if the argument is empty, and \iffalse +"otherwise. This is useful for handling arguments given by +"users to commands defined in a macro package such as LaTeX. +" +"Plain TeX or LaTeX-style solutions are both acceptable, that +"is, +" +" \ifempty{...}TRUE CASE\else FALSE CASE\fi +" +"or +" +" \ifempty{...}{TRUE CASE}{FALSE CASE} +\end{comment} + +\ed{\oposted{1991/10/25}. \arch{answer.002}.}\\ + +The LaTeX-style solution that I had prepared was, I thought, pretty +good, but Donald Arseneau\index{Arseneau, Donald} +observed that it fails the test +\begin{lcode} +\test{{\iftrue a\else b\fi}} +\end{lcode} +which was not in my list of tests. + +%\begin{description} +%\item[Solution 1 {[mine]}] \mbox{} +\begin{solution}{Solution 1 (mine)}\index{Downes, Michael} +\begin{lcode} +\catcode`\@=11 +% \@car is actually already defined in latex.tex, but for +% maximum robustness it needs to have the \long prefix: +\long\def\@car#1#2\@nil{#1} +\long\def\@first#1#2{#1} +\long\def\@second#1#2{#2} +\long\def\ifempty#1{\expandafter\ifx\@car#1@\@nil @\@empty + \expandafter\@first\else\expandafter\@second\fi} +\catcode`\@=12 + +\long\def\test#1{\begingroup \toks0{[#1]}% + \newlinechar`\/\message{/\the\toks0: + \ifempty{#1}{EMPTY}{NOT empty}% +}\endgroup} +\end{lcode} +\end{solution} +%%>>EndSolution + +The advantage of using the auxiliary macros \cmd{\@first} and \cmd{\@second}, +together with the \cmd{\expandafter}'s, is that it allows the true and/or +false cases to end with arbitrary things, even macros that require +arguments that have not yet been read (any number of arguments, even +delimited arguments). + +From here it is easy to implement an \piif{ifnotempty} test that has a +null false case. This is often useful in dealing with user-supplied +arguments: `If \#1 is empty, do nothing; otherwise, do the following +with \#1: ...' +\begin{lcode} +\long\def\ifnotempty#1{\ifempty{#1}{}} +\end{lcode} + + +%\item[Solution 2 {[Donald Arseneau]}] +\begin{solution}{Solution 2 (Donald Arseneau)}\index{Arseneau, Donald} +Don Arseneau came up with a plain TeX style solution, using an +ingenious device with \cmd{\then} to pass the test case +\begin{lcode} +\expandafter\iffalse\test{x}\fi +\end{lcode} + The comments in the solution are his. + +\begin{lcode} +% \ifblank{...}\then Test if a parameter is blank (null or spaces). +% Use the inaccessable "letter" @ to separate parameters. The two cases are: +% _text_is_not_blank_ _text_is_blank_ +% #1<- whatever #1<-@ +% #2<- whatever (possibly null) #2<- +% #3<- @ #3<-. +% #4<- .. #4<-. +% \if @.. {false} \if .. {true} +% In the {false} case, the extra period is skipped so it doesn't hurt. + +\catcode`\@=11 % as in plain.tex +\let\then\iftrue +\long\def\ifblank#1\then{\Ifbl@nk#1@@..\then}% +\long\def\Ifbl@nk#1#2@#3#4\then{\if#3#4} +\catcode`\@=12 + +\long\def\test#1{\begingroup \toks0{[#1]}% + \newlinechar`\/\message{/\the\toks0: + \ifblank{#1}\then EMPTY\else NOT empty\fi% +}\endgroup} +\end{lcode} +\end{solution} +%%>>EndSolution + +The good thing about this solution is that it doesn't subject any part +of the user-supplied argument to the \piif{ifx} test. Using @ with category +code of 11 as a delimiter for the user-supplied text is extremely safe +because even in internal code @ doesn't appear by itself, only as part +of control sequence names. In a partial solution, +Peter Schmitt\index{Schmitt, Peter} pushed +the idea a little further by using space with category code 3 as the +delimiter. + +There is another way of handling the problematic \piif{iffalse} test, in a +plain-TeX style solution, by using a suggestion of Donald Knuth that +appeared in TeXhax a while ago, in reply to a query of Stephan von +Bechtolsheim (texhax89, \#38 (post from svb, 17 Apr 89)). + +%\item[Solution 3 {[Arseneau/Knuth]}] \mbox{} +\begin{solution}{Solution 3 (Arseneau/Knuth)}\index{Arseneau, Donald}\index{Knuth, Donald} +\begin{lcode} +% Usage: \if\blank{#1}...\else...\fi + +\catcode`\@=11 % as in plain.tex +\long\def\blank#1{\bl@nk#1@@..\bl@nk}% +\long\def\bl@nk#1#2@#3#4\bl@nk{#3#4} +\catcode`\@=12 + +\long\def\test#1{\begingroup \toks0{[#1]}% + \newlinechar`\/\message{/\the\toks0: + \if\blank{#1}EMPTY\else NOT empty\fi% +}\endgroup} +\end{lcode} +\end{solution} + +%>>EndSolution + +At the end of Exercise 2 I wrote: +\begin{quote} +The two tests on the first line should produce a message `EMPTY' and +the remaining ones, `NOT empty'. The reason for saying that the second +test should return `EMPTY' is that (1) this is the ideal behavior for +the applications I've encountered so far; (2) at least one other person +working independently arrived before me at a solution essentially +identical to mine, including this behavior. The details and credit to +the other guy will be given at solution time. +\end{quote} + +The name of the `other guy' is Michael Wester\index{Wester, Michael}; +a listing of his macros +was published in the preprints for the July 1991 TUG meeting in Dedham, +Massachusetts (`Form Letter in LaTeX with 3-across Mailing Labels +Capability', joint paper with Jackie Damrau). In rereading the preprint +recently, it seems to me the presentation is more different from +Exercise 2 and its solutions than I had previously imagined, but the +essential ideas are there. See \cmd{\wcar}, \cmd{\wcdr} and related macros. + +By the way, if anyone came up with a fully expandable test (suitable +for use inside a \cmd{\message}) for which \verb?\test{ }? came up +false instead of +true, I would be interested to hear about it. I didn't mean to +eliminate that possibility in my original statement of the problem. + +%%\endinput + + +\chapter{Discretionary} + +\section{Exercise (fast)} + +%%\input{ex003.tex} +% ex003.tex + +\ed{\oposted{1991/10/10}. \arch{exercise.003}.}\\ + +\begin{comment} + +[Posted to info-tex on 10 Oct 91; see exercise.001] +********************************************************************** +*** Exercise 3 (fast): +\end{comment} + +What's the most important difference between \cs{-} and +\begin{lcode} +\discretionary{-}{}{} ? +\end{lcode} + +%%********************************************************************** +%%\endinput + + +\section{Answers} + +%%\input{ans003.tex} +% ans003.tex + +\ed{\oposted{1991/10/25}. \arch{answer.003}.}\\ + +\begin{comment} + +[Posted to info-tex on 25 Oct 91; see answer.001] +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +"*** Exercise 3 (fast): +"What's the most important difference between \- and +"\discretionary{-}{}{}? +\end{comment} + +The most important difference between \cs{-} and \cmd{\discretionary}\verb?{-}{}{}? +is that the latter always puts in the character from font position 45 +("2D, '55) of the current font when a word must be broken at the end of +a line; \cs{-} puts in the character from font position \cmd{\hyphenchar} of the +current font, which is NOT NECESSARILY position 45. It would be rather +unusual for \cmd{\hyphenchar} to be something other than 45; in certain +special applications, however (possibly in some foreign languages as +well?) a variant value of \cmd{\hyphenchar} can be useful. I have an idea for +using this in a future exercise\ldots + +Credit to Donald Arseneau\index{Arseneau, Donald} for a correct answer. +Thanks to Peter Schmitt\index{Schmitt, Peter} +for providing the perfect opening for another point I wanted to make: +\begin{quotation} + The \emph{TeXbook} states explicitly: \\ + \cs{-} is equivalent to \verb?\discretionary{-}{}{}? \\ + and both are internal. + + I do not see where to the question aims: +\begin{itemize} +\item control symbol : control sequence +\item no paramaters : three parameters +\item two characters : 21 characters to type +\item ??? +\end{itemize} +\end{quotation} + +Schmitt is quoting from the last page of Chapter 25; the point is, +that in newer versions of the \emph{TeXbook} that sentence has been revised. +I'm not sure what the latest printing says, since I don't have a copy, +but I think it simply refers the reader to Appendix H, where the +significance of \cmd{\hyphenchar} is explained. \cmd{\hyphenchar} is a feature that +was added late in the development of TeX82 (\pfile{TeX82.bug} reveals that is +was not added until May 25, 1983). Even if the source files for the +\emph{TeXbook} were immediately updated by Knuth at that time, the changes did +not appear in the published version being sold to the general public +until some time later when the first revised edition was published, +which was no earlier than October 1984, the date of the \emph{TeXbook} copy +that I have on hand, and probably later. + +The statement of purpose in `Around the bend' \#1 said something +about finding the `best solution', but conspicuously failed to define +what `best' should mean in this context. It was my intention to address +this question in future exercises; for now, let me just say that I +don't intend to arbitrarily rule out of consideration answers such as +Schmitt's `two characters : 21 characters to type', since depending on +how you look at it, it could be argued that this is much more +significant than dumb old \cmd{\hyphenchar} minutiae. I promised that these +exercises would be challenging; that means, among other things, that +they won't always be well-defined, well-bounded, or well-behaved, and +part of the job of finding the `best solution' will be to decide what +parts of the problem need to be specified further, and to examine the +ramifications of alternatives. + +%%\endinput + + +\chapter{What is `best'?} + +\section{Exercise (essay)} + +%%\input{ex004} +% ex004.tex + +\begin{comment} +[Exercises 4,5,6,7 were originally posted together on 4 Nov 91] +Date: Mon 4 Nov 91 16:42:44-EST +From: Michael Downes <MJD@MATH.AMS.COM> +Subject: Around the bend #2 +To: info-tex@shsu.edu +\end{comment} + +\ed{\oposted{1991/11/04}. \arch{exercise.004}.} + +The statement of purpose in `Around the bend' \#1 said something about +finding the `best solution', but failed to define what `best' should +mean when comparing pieces of TeX code. I'll start by throwing out +a few ideas. + +\begin{description} +\item[Simplicity] A good solution gets hold of the essential idea of the +problem and attacks it directly, rather than beating around the bush +and resorting to separate clauses to handle troublesome subcases. + +\item[Economy] If two solutions compare equal in other respects, then the +better solution is the one that uses less of TeX's resources (main +memory, hash table, string pool, and so forth). Therefore I +(immodestly) say that my solution to Exercise 1 was ever so slightly +better than the other two given, because it avoided introducing any +auxiliary macros that were not included in the original statement of +the problem. + +\item[Robustness] If a solution only works under limited friendly +circumstances, and otherwise blows up with an error message, that's not +good. My solution to Exercise 2 was flawed in this respect, since D.A. +found a test case that caused it to go wrong. +\end{description} + +%%*********************************************************************** +*** Exercise 4 (essay): + +What should `best' mean when comparing solutions to an `Around the +bend' exercise? What qualities of a good solution are most important? +Why? How can they be objectively measured? (Or can they?) On the +negative side, what qualities indicate an inferior solution? + +%%*********************************************************************** + +\begin{comment} + +[Exercise 5 moved to exercise.005] +[Exercise 6 moved to exercise.006] +[Exercise 7 moved to exercise.007] + +Send answers to: + +Michael Downes mjd@math.ams.com (Internet) + +A summary will be posted Tuesday, December 4, 1991. However, because of +the difficulty of E7, I will probably procrastinate on posting the +solutions for that exercise until the first or second week of December. +\end{comment} + +Table of special characters, to verify accurate transmission: + +\begin{lcode} +ASCII 33: ! exclamation point ASCII 60: < left elbow +ASCII 34: " double quote ASCII 61: = equals sign +ASCII 35: # number/pound sign ASCII 62: > right elbow +ASCII 36: $ dollar sign ASCII 63: ? question mark +ASCII 37: % percent sign ASCII 64: @ at sign +ASCII 38: & ampersand ASCII 91: [ left square bracket +ASCII 39: ' right quote/apostrophe ASCII 92: \ backslash +ASCII 40: ( left parenthesis ASCII 93: ] right square bracket +ASCII 41: ) right parenthesis ASCII 94: ^ circumflex/hat/caret +ASCII 42: * star/asterisk ASCII 95: _ underscore +ASCII 45: - hyphen ASCII 96: ` left quote +ASCII 47: / slash ASCII 123: { left curly brace +ASCII 58: : colon ASCII 124: | vert bar +ASCII 59: ; semicolon ASCII 125: } right curly brace + ASCII 126: ~ tilde +\end{lcode} +%$ + +%%\endinput + + +\section{Answers} + +%%\input{ans004} +% ans004.tex + +\ed{\oposted{1991/12/10}. \arch{answer.004}.} + +\begin{comment} +[Solutions for exercises 4,5 were originally posted together on 5 Dec 91] +Date: Thu 5 Dec 91 10:26:58-EST +From: Michael Downes <MJD@MATH.AMS.COM> +Subject: `Around the bend' #2 solutions (4,5) +To: info-tex@shsu.edu + +Answers to exercises 4 and 5 of `Around the bend' #2. Discussion of E6 +will follow in a separate post because it is rather lengthy. Discussion +of E7 will follow in another couple of weeks (I'm going to be on +vacation next week.) + +"*********************************************************************** +"*** Exercise 4 (essay): +" +"What should `best' mean when comparing solutions to an `Around the +"bend' exercise? What qualities of a good solution are most important? +"Why? How can they be objectively measured? (Or can they?) On the +"negative side, what qualities indicate an inferior solution? +\end{comment} + +Peter Schmitt\index{Schmitt, Peter} writes: +\begin{quotation} + What is to be rated as `best' clearly depends on the function used to + measure quality. And therefore the question makes sense only with + respect to some particular rating function. Seemingly nothing is gained + by this statement: Instead of discussing what qualities are required + for a good solution one has to discuss how the rating system should be + defined. But nevertheless this shifted point of view has an important + an important advantage. It makes clear that there is no unique answer: + Quality is not an absolute notion but a notion relative to some + (agreed) measure. This measure is not independent of the context --- + under different conditions different rating functions may be used. + + One further important point must not be forgotten: If matters of + personal taste are to be excluded than the measuring function has to be + precisely defined --- demanding simplicity, without giving this notion + a precise (formal) meaning, is not sufficient. + + Therefore I would like to split the original question into two seperate + questions: + + (a) What (formal and informal) rating functions are likely to be + useful, and under what circumstances? + + (b) With respect to some formal rating function, is there always a best + solution? + + Some answers to the first questions are the following (no completeness + claimed or even intended): + + (1) the first solution: + + If some special effect is needed for a single application then the + best solution is the first solution (the solution that can be + realized with the least effort). This is, however, a purely + individual criterion that cannot be formalized. + + (2) the most economic (in some sense) solution: + + Economic considerations are important if a code is used frequently, + Depending on the nature of the applications running time, memory + usage, and others, may be relevant. But the time spent for finding + a good solution still cannot be neglected in a real world + situation. Of course, for theoretical investigations the time spent + for research does not matter. + + (3) the more robust solution: + + If some set of macros is used by a large number of people who not + always know how to use them correctly (or even do not care to know) + then it is certainly an advantage if they are robust, i.e. work in + as many cases (even strange ones) as possible. But again, one has + to decide what price (in terms of resources) is acceptable for this + robustness. (In many cases the item (4) below will be more + important.) + + (4) ease-of-use: + + If a set of macros is used frequently (by one or more persons) then + ease-of-use is certainly a mark of quality: easy to remember + syntax, short commands, natural and good readable embedding into + the surrounding text, and similar criteria, decide about this. + + (5) simplicity: + + Simple solutions certainly have a strong appeal --- but what is a + simple solution? Again this is hard to formalize, since simplicity + basically is an aesthetic value, closely related to the concepts of + elegance and beauty. (This is similar to the situation in + mathematics.) But be careful: Simple is not equivalent to short! + + (6) the shortest solution: + + This may seem to be an easy rating function, but is it? Should + length be measured by the number of characters (probably not!), or + by the number of tokens, or by the number of control sequences? Or + by something else? + + Most of the measures mentioned are difficult to formalize, or cannot be + formalized at all. Only the resources used (in (2)) and the length of a + code (in (6)) can be precisely defined. Therefore, with respect to one + of these cases two solutions of the same problem can be compared. + Furthermore, in many cases it will be possible to proof that an optimal + solution exists. (For instance, since the length of a code (in any + interpretation) is a positive integer, there must exist one or more + solutions with minimal length, provided there is at least one + solution.) But unfortunately this does not imply that one is able to + construct an optimal solution, or to decide whether a given piece of + code is an optimal solution (or at least near to one). And in some + cases it may happen that no optimal solution exists, e.g. if to every + solution there is better --- but longer! --- one. + + What is the conclusion of all this? That there may be a best solution + relative to some side conditions. But that there is no globally best + solution. This statement is, of course, not very satisfying. One + would rather prefer to have at least some notion (even a tentative one) + of a best solution than none at all. I propose therefore the following + informal definition (often subject to personal taste): If some code is + optimal or near-optimal in more than one category then it is probably + as near to a globally optimal solution as this is possible. +\end{quotation} + + +My comments: + +I propose the following list, based on (1) [my interpretation of] +Knuth's ideas about good macro writing as demonstrated in the \emph{TeXbook} +and plain.tex, (2) various articles in TUGboat, (3) Schmitt's comments, +(4) discussions I've had in the past with other macro writers, and so +forth. + +The characteristics of a good solution to an `Around the bend' exercise +are (in order of decreasing importance): + +\begin{enumerate} +\item Robustness +\item Brevity (= minimal usage of TeX's main memory)3 +\item Simplicity +\item Ease of use +\item Suitable commentary +\item Speed +\item Minimal hash table load +\item Minimal save stack load +\item Minimal load in other categories of TeX's memory +\item Comprehensive test suite (when applicable) +\end{enumerate} +Schmitt's\index{Schmitt, Peter} point about 'first solution' is well taken +but does not apply +to `Around the bend' exercises, because of the stated goal of finding a +'best' solution, with the presumption that normally more than one +solution will be found. + +Measurement of these qualities is not too difficult, I think, +except for 3 and 5. Here's how I see the measurements: + +\begin{description} +\item[1. Robustness] A solution is robust if no one who reads it offers a +counterexample that causes it to fail. If two solutions both fail, the +one with more counterexamples is less robust; if two solutions have +different counterexamples, the solution whose counterexample is more +likely to occur in normal use is the less robust solution. + +\item[2. Brevity] Of two different solutions, the one that is +briefer/shorter/more compact is the one that uses less of TeX's main +memory as measured by \cmd{\tracingstats}. + +\item[3. Simplicity] Of two different solutions, the shorter one (in the +sense of the previous item) is usually the simpler one, but not always. +A solution that condenses all the necessary operations into a dense, +incomprehensible Gordian knot is less simple than a longer solution +that lays out the operations in a series of easily comprehended steps. +A solution that relies on arcane dirty tricks is less simple than a +solution that uses better-known techniques in a straightforward +approach. + +\item[4. Ease of use] I believe this will not be extremely hard to measure in +the context of the particular application; it can't sensibly be +discussed out of context. + +\item[5. Suitable commentary] The commentary surrounding a solution should +explicitly mention any necessary assumptions. If the code is complex, +the commentary should give an outline or overview of the intended +algorithm. It should explain the operation of any macro if its +operation is not evident from the code. If an unusual construction is +used where a different construction would normally be expected, the +commentary should give the reason. + +\item[6. Speed] Of two solutions, the speedier one is the one that runs +faster on common computer systems. If one solution runs faster and +slower than another, depending on the system \ldots well, let's not cross +that bridge unless it turns out to be real. + +\item[7,8,9. Minimal hash table load, save stack load, etc.] These can be +measured by \\ +\cmd{\tracingstats}. + +\item[10. Comprehensive test suite] If two solutions are equal in other +respects, the one whose accompanying test suite covers more distinct +cases than the other's is better by that much. +\end{description} + +It may be argued that I have not sufficiently answered the question of +subjectivity. For example, who's to decide what's an 'arcane dirty +trick' and what's not? What does 'suitable' mean in number 5? The +answer is that I will say that something is an 'arcane dirty trick' if +I think so, and anyone else can do the same. In most cases I believe +that there will be general agreement on such a question; if not, and an +ensuing discussion fails to reach a clear settlement, then each of the +solutions in question will be decreed 'subjectively just as good as the +others'. + +Other qualities of a good solution can be expressed in terms of the +ones listed above. For example, self-sufficiency may be considered an +aspect of robustness---if a solution is not entirely self-sufficient, +it can easily be shown to be not robust by giving a counterexample that +exploits the assumption that makes the solution non-self-sufficient. +Elegance? If a solution is simple and easy to use, then I say it is +elegant. A solution doesn't necessarily have to be robust in order to +be elegant, nor even short (although of two solutions that are +otherwise equal, the shorter one is undoubtedly more elegant). + +\begin{comment} + +[Solution for exercise 5 moved to answer.005] + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +Table of special characters (ASCII): + +33: ! exclamation point; 59: ; semicolon; +34: " double quote; 60: < left elbow; +35: # number/pound sign; 61: = equals sign; +36: $ dollar sign; 62: > right elbow; +37: % percent sign; 63: ? question mark; +38: & ampersand; 64: @ at sign; +39: ' right quote/apostrophe; 91: [ left square bracket; +40: ( left parenthesis; 92: \ backslash; +41: ) right parenthesis; 93: ] right square bracket; +42: * star/asterisk; 94: ^ circumflex/hat/caret; +43: + plus sign; 95: _ underscore; +44: , comma; 96: ` left quote; +45: - hyphen; 123: { left curly brace; +46: . period/dot/point; 124: | vert bar; +47: / slash; 125: } right curly brace; +58: : colon; 126: ~ tilde +%$ +Michael Downes mjd@math.ams.com (Internet) + +\end{comment} + +%%\endinput + + +\chapter{\cs{string} tokens} + +\section{Exercise (fast)} + +%%\input{ex005} +% ex005.tex + +\ed{\oposted{1991/11/04}. \arch{exercise.005}.} + +\begin{comment} + +[Posted to info-tex on 4 Nov 91; see exercise.004] +*********************************************************************** +*** Exercise 5 (fast): +\end{comment} + +Assuming a normal value for \cmd{\escapechar} +\begin{lcode} + \string\a +\end{lcode} +produces two character tokens. What is the category code of the second? +Write an experiment (as short as possible) to demonstrate the +correctness of your answer. + +%%%********************************************************************** + +%%\endinput + + +\section{Answers} + +%%\input{ans005} +% ans005.tex + +\ed{\oposted{1991/12/05}. \arch{answer.005}.} + +\begin{comment} + +[Posted to info-tex on 5 Dec 91; see answer.004] +"*********************************************************************** +"*** Exercise 5 (fast): +" +"Assuming a normal value for \escapechar, +" +" \string\a +" +"produces two character tokens. What is the category code of the second? +"Write an experiment (as short as possible) to demonstrate the +"correctness of your answer. +\end{comment} + +The category of the 'a' token is 12. All tokens produced by \cmd{\string} +have category 12, except for space tokens, which have category 10. + +\begin{solution}{Solution 1 (mine)} +\begin{lcode} +\def\answercheck#1#2{\message{#2: \ifcat0#2\else NOT \fi Category 12}} +\expandafter\answercheck\string\a +\answercheck bb +\end{lcode} +This produces on screen the following message: +\begin{lcode} +a: Category 12 b: NOT Category 12 +\end{lcode} +\end{solution} +%%>>EndSolution + +%%>>Solution 2 [Peter Schmitt]: +\begin{solution}{Solution 2 (Peter Schmitt)}\index{Schmitt, Peter} +\begin{lcode} +\def\test#1#2#3{% + \message{\ifcat#2#3 #2 and #3 have the same category code + \else #2 and #3 have not the same category code + \fi}} + +\def\Test#1#2#3{% + \ifcat#2#3 \message{#2 and #3 have the same category code} + \else \message{#2 and #3 have not the same category code} + \fi} + +\catcode`\A12 +\test 1aA +\Test 1aA +\expandafter\test\string\a A +\expandafter\Test\string\a A +\end{lcode} + +Comment: \\ +I have given two essentially equivalent Tests --- \cmd{\test} and \cmd{\Test}. + +(i) \cmd{\test} is slightly more simple because it contains only one \cmd{\message} +command, but I think that \cmd{\Test} is more adequate because it avoids to +perform the test inside the \cmd{\message} --- there might be some side +effect one is not aware off. + +(ii) Both tests are not as short as possible --- the \piif{true} and \piif{false} +cases could be much shorter, e.g. a T (for true) and a F (for false) +would suffice --- the result could be checked in the dvi-file. (I +regard this difference as inessential.) + +Furthermore, setting the catcode of the model character to 12 could +easily be omitted (use some character that is known to be an `other +character'), but I think it should be included: It makes the test +independent of any assumption on the format running. This makes the +solution more closed and selfsufficient, and therefore also simpler and +more elegant (if I may say so). +\end{solution} +%%>>EndSolution +%%\endinput + + +\chapter{Counting arguments} + +\section{Exercise (hard)} + +%%\input{ex006} +\begin{comment} +[Posted to info-tex on 4 Nov 91; see exercise.004] +********************************************************************** +*** Exercise 6 (hard): +\end{comment} + +\ed{\oposted{1991/11/04}. \arch{exercise.006}.} + +Define a macro \cmd{\args} that can be used to fill in the proper number +in the following sentence no matter how \cmd{\foo} is defined (except +you may assume it is not \cmd{\outer}). + + The macro \verb?\tt\string\foo? has \verb?\args\foo? arguments. + +Is it possible to solve this if \cmd{\foo} is \cmd{\outer} also? Is it possible +to make \cmd{\args} fully expandable, so that it could be used in a +message: +\begin{lcode} + \message{The macro \noexpand\foo has \args\foo\space arguments.} +\end{lcode} + +%%********************************************************************** +%%\endinput + +\section{Answers} + +%%\input{ans006} +% ans006.tex +\begin{comment} +Date: Mon 23 Dec 91 11:46:33-EST +From: Michael Downes <MJD@MATH.AMS.COM> +Subject: Answers to 'Around the bend' #2 Exercise 6 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> + +"*** Exercise 6 (hard): +" +"Define a macro \args that can be used to fill in the proper number +"in the following sentence no matter how \foo is defined (except +"you may assume it is not \outer). +" +" The macro {\tt\string\foo} has {\args\foo} arguments. +" +"Is it possible to solve this if \foo is \outer also? Is it possible +"to make \args fully expandable, so that it could be used in a +"message: +" +" \message{The macro \noexpand\foo has \args\foo\space arguments.} +\end{comment} + +\ed{\oposted{1991/12/23}. \arch{answer.006}.} + +This was a tough one. All who sent in answers to this exercise +(counting myself) used the approach of applying \cmd{\meaning} to \cmd{\foo} and +analyzing the resulting string. There are some drawbacks to this. + +(1) In a \cmd{\meaning} string, all characters (other than spaces) have +catcode 12. This means that all occurrences in a \cmd{\meaning} string of +the character \# are indistinguishable, regardless of their true +significance in the parameter text or replacement text of the macro +in question. Consequently, an occurrence of a \# character, not +category 6, followed by a number, in the parameter text of \cmd{\foo} can +potentially make \cmd{\args} report an incorrect number of arguments. For +example, in the following definitions \cmd{\foo} has no arguments, only +delimiter text, in all three cases, but the \cmd{\meaning} string would +appear to show that \cmd{\foo} has one argument: +\begin{lcode} + \def\foo\#1{} + \expandafter\def\expandafter\foo\string #1{} + \catcode`\#=12 \def\foo#1{} +\end{lcode} + +(2) The following two examples produce identical \cmd{\meaning} strings: +\begin{lcode} + \def\foo&1{} % no arguments + \catcode`\&=6 \def\foo&1{} % one argument +\end{lcode} + +(The string is \verb?"macro:&1->"?.) I.e., characters other than \# can +be used to create parameter markers in a macro definition, and +such a parameter marker cannot be distinguished in a \cmd{\meaning} +string from a normal use of the character in question. + +(3) There is no completely general way to isolate the parameter text +of an arbitrary macro from the replacement text. The best you can do +is remove the tail of the \cmd{\meaning} string---everything after the last +occurrence of \verb?->? in the string---and say 'This is not part of the +parameter text'. Likewise, anything preceding the first occurrence of +\verb?->? is certainly part of the parameter text. If there are two or more +occurrences of \verb?->? in the string, however, you cannot say for sure +whether anything between the first and last occurrences is parameter +text or replacement text. This raises a slight additional possibility +that pseudo 'parameter markers' in the replacement text could cause +\cmd{\args} to give an incorrrect result. For example: +\begin{lcode} + \edef\foo #1{\string#2->} +\end{lcode} +defining \cmd{\foo} with one argument, produces a \cmd{\meaning} string of +\begin{lcode} + macro:#1->#2-> +\end{lcode} +which is exactly the same as the \cmd{\meaning} string for +\begin{lcode} + \def\foo#1->#2{} +\end{lcode} +where \cmd{\foo} has two arguments. + + +Speaking practically, however, rather than theoretically, using +\cmd{\meaning} to analyze the number of arguments of an arbitrary macro +works fine. Donald Arseneau's solution, below, is admirably +brief and demonstrates an easy way of handling an outer argument +that I had never seen before. + +\begin{solution}{Solution 1 (Donald Arseneau)}\index{Arseneau, Donald} + +Here is my solution for counting arguments. It is totally expandable, +and relies on the fact that the parameter numbers must be in +increasing order, that they are only single digits, and that there is +no parameter zero. Also important is that \cmd{\meaning} of a macro defined +by \verb?\def\x#{...}? reports a syntax of \verb?{? rather than \#. +\begin{lcode} +{\catcode`\*=6 \catcode`\#=12 % use * for macro parameters while # is "other" +% +\gdef\args{\expandafter\Args\noexpand}% get rid of \outerness +% +\long\gdef\Args*1{\expandafter\countargs \meaning*1:->{}\end}% +% ... \meaning will display the parameter syntax (as "other" characters). +% +\gdef\countargs*1:*2->*3\end{\twoargs#0*2#0}% get just the parameter syntax +% ... in format #0junk#1junk...#njunk#0. \twoargs processes the list to +% ... give "n", the last number before #0. +\end{lcode} + + Here's what tests the parameter numbers, two at a time. (Thus, the two + \verb?#0?'s in \cmd{\countargs}, so there are always at least two +\verb?#n?'s detected.) + When the second number of a comparison isn't zero, \cmd{\twoargs} re-executes + itself to test the next pair; when the second \verb?n? is 0, the first +\verb?n? is the + highest parameter number, so it is output. +\begin{lcode} +\gdef\twoargs*1#*2*3#*4{\ifnum0=*4 *2\else % note the space to end the number + \expandafter\twoargs\expandafter#\expandafter*4\fi} +} +\end{lcode} + +Here is my test suite. The character ``:'' works in a funny way: it +confuses how \cmd{\countargs} reads its parameter list, and another colon +gets into the supposed syntax. But it works because there are no +parameters. The primitive \cmd{\halign} is reported to have no parameters +because it is not a macro. This could be confusing to someone. The +same confusion could arise with \cmd{\args} itself because it doesn't read +the parameter right away. +\begin{lcode} +\def\test#1#{nothing} +\def\Test[#1]#2:{\##1,#2##} +\def\#{haha} + +\show\test \show\Test +\end{lcode} + +(I condensed this test suite---MJD) +\begin{lcode} +\long\def\msg#1{\message{The object \string#1 has \args#1 arguments.}} + +\msg\mathpalette \msg\mathhexbox \msg\par \msg\halign \msg\args +\msg\relax \msg # \msg\# \msg\test \msg\Test \msg : \msg\: \msg\csname +\msg t \msg ~ \msg $ \msg ^ +\end{lcode} + +(Outer macros---MJD) +\begin{lcode} +\message{The object \string\bye\space has \args\bye\space arguments.} +\message{The object \string\newhelp\space has \args\newhelp\space + arguments.} + +\bye % -- Donald Arseneau +\end{lcode} +\end{solution} +%%>>EndSolution + +Although the problem statement only mentioned `macros' Arseneau +earned some thoroughness points by including primitives \cmd{\halign}, +\cmd{\relax}, and \cmd{\csname}, as well as characters \verb?# : t $ ^? +in his tests. +This is of some interest because of the difference in \cmd{\meaning} +strings between macros and non-macros. + +In my solution for this exercise, I amused myself by trying to pack +everything into as few control sequences as possible. Although I got +it down to two, that's really only one less than Arseneau's four, +because one control sequence in his solution is expended to +handle outer macros, something my solution didn't attempt to do. + +%>>Solution 2 (mine) +\begin{solution}{Solution 2 (mine)} +\begin{lcode} +% Use & instead of # temporarily. +\catcode`\&=6 \catcode`\#=12 + +\long\def\args &1{\expandafter\countargs\meaning &1#\args->\countargs 0} +\end{lcode} + + Analysis is restricted to the parameter text by chopping off everything + after \verb?->? in the meaning string (this will leave possibly only part + of the parameter text). + + Then we look in the parameter text for \# followed by a number + (checking to make sure that the thing after \# is a number handles a + few extra possibilities, such as \verb?\#? followed by non-number in the + parameter text). If we find \# plus a number, we pass the number + onward to the next invocation of \cmd{\countargs}, where it will end up as + the returned value (argument \#5) if the next \cmd{\countargs} determines + that the remaining parameter text contains no more parameter markers. +\begin{lcode} +\def\countargs &1#&2&3->&4\countargs &5{% + \ifx\args&2&5% + \else + \ifodd0&21 % Then &2 is a number, carry forward. + \countargs&3#\args->\countargs&2% + \else % &2 not a number---ignore, carry forward last number instead + \countargs&3#\args->\countargs&5% + \fi + \fi} + +\catcode`\#=6 + +\def\test{\message{The macro \noexpand\foo has \args\foo\space + arguments (\meaning\foo).}} + +%\tracingmacros=2 \tracingcommands=2 +% Success: +\def\foo{No args}\test +\def\foo#1{One arg}\test +\def\foo#1#2{Two args}\test +\def\foo./{No args, delimited}\test +\def\foo#1#2#3#4#5#6#7#8#9{Nine args}\test +\def\foo//#1#2#3#4#5#6#7#8#9//{Nine args, delimited}\test +\def\foo#{Weird}\test +\def\foo#1#{Weird, one arg}\test +\def\foo#1#2#3#4#5#6#7#8#9#{Weird, nine args}\test +\def\foo#1 {One arg, space delimited}\test +\def\foo#1 #2 #3 #4 #5 #6 #7 #8 #9 {Nine args, space delimited}\test +\def\foo/{\def\foo} +\foo/ #1{Interesting}\test + +\edef\foo#1#2{\string #3\string #4}\test +\edef\foo{\string #}\test +\expandafter\edef\expandafter\foo + \csname 0\string #\string #\endcsname#1#2{#1#2}\test + +% Failure: +\def\foo->#1->#2->#3->#4->#5->#6->#7->#8->#9->{Nine args, devious + delimiter}\test +\expandafter\edef\expandafter\foo + \csname 0\string #1\string #2\endcsname{...}\test +\let\foo=\bye \test % \outer bomb +\end{lcode} +\end{solution} +%%>>EndSolution + +When I originally posed this problem, I had seen far enough ahead to +suspect that the drawbacks of \cmd{\meaning} mentioned above would be +impossible to overcome. But \cmd{\meaning} is the only way to analyze a +macro that has a nonsimple parameter text---that is, one containing +delimited arguments. Another possibility I had in mind was restricting +the analysis to macros with simple parameter texts---empty or having +only nondelimited arguments---to see what might be done without +\cmd{\meaning}. The best that I could manage in my experiments along these +lines was a definition of \cmd{\args} with an unacceptably cumbersome call +syntax. But it does have the virtue of correctly identifying any +number of nondelimited arguments, no matter whether \cmd{\foo} was +originally defined using \# (category 6) or some other category 6 +character. + +%%>>Solution 3 (mine) +\begin{solution}{Solution 3 (mine)} +\begin{lcode} +% This solution is not fully expandable, hence cannot be used +% inside a \message. + +\def\args{\expandafter\argscontinue} + +\def\argscontinue{\begingroup +\end{lcode} + Make all digits have category 2 (= end of group) so that + they will serve to end the token register assignment + \verb?\global\toks1 ...? +\begin{lcode} + \catcode`\0=2 \catcode`\1=2 \catcode`\2=2 \catcode`\3=2 \catcode`\4=2 + \catcode`\5=2 \catcode`\6=2 \catcode`\7=2 \catcode`\8=2 +\end{lcode} + + We use \cmd{\afterassignment} to put an \cmd{\endgroup} after the + token register assignment, so that numbers will revert to + their ordinary catcodes. And we use \cmd{\aftergroup} to put + a \cmd{\finishup} token after the \cmd{\endgroup}. Thus \cmd{\finishup} can + look ahead to see what numbers are remaining; this information + reveals how many arguments were used up by the \cmd{\foo} macro call. +\begin{lcode} + \aftergroup\finishup \afterassignment\endgroup + \global\toks1\bgroup} +\end{lcode} + + \cmd{\finishup} takes the first digit following it and returns it + as the value of \cmd{\args}; any following numbers are discarded + (note that \#2 is delimited by a space). +\begin{lcode} +\def\finishup#1#2 {%\showthe\toks1 + #1} + +%\tracingmacros=2 \tracingcommands=2 \tracingonline=1 +\def\foo{} +The macro {\tt\string\foo} has \args\foo 00123456789 \ arguments. + +\def\foo#1{} +The macro {\tt\string\foo} has \args\foo 00123456789 \ arguments. + +\edef\foo#1{\string #2\string #3\string #4->\string #4\string #3#1} +The macro {\tt\string\foo} has \args\foo 00123456789 \ arguments. + +\def\foo#1#2#3{a#1b#2c#3} +The macro {\tt\string\foo} has \args\foo 00123456789 \ arguments. + +\def\foo#1#2#3#4#5#6#7#8#9{#1#2#3#5#8bb#9} +The macro {\tt\string\foo} has \args\foo 00123456789 \ arguments. +\end{lcode} +\end{solution} +%%>>EndSolution + +The fourth solution for Exercise 6 is by Peter Schmitt; it gets the +robustness prize for carrying out a diligent analysis of \cmd{\meaning} +strings that enables it to correctly handle a greater variety of +exotic cases than the other solutions. Schmitt's original method of +handling outer macros was effective, but more complicated than +Arseneau's method, incorporated here as noted. Even though my +approach was rather different from Schmitt's, some of the comments in +Schmitt's solution inspired me in turn to improve my solution [2] +from its previous much inferior state. + +%%>>Solution 4 (Peter Schmitt) +\begin{solution}{Solution 4 (Peter Schmitt)}\index{Schmitt, Peter} +\begin{lcode} +% \args <token> expands to: - if <token> is not a macro +% 0..9 according to the number of parameters +% if the <token> is a macro +% \args is fully expandable and accepts outer macros as well. +% It assumes, however, that the tested macro has been defined using the +% standard parameter symbol #, +% and that the current value of \escapechar is the standard backslash \. +\end{lcode} + + The definition of the macros uses the expansion of +\cmd{\meaning}\verb?\cs?: + It is of the form: +\begin{lcode} + [..] macro: [parameter text] -> [replacement text] +\end{lcode} + and consists of `other characters'. + + The macro \cmd{\args} checks: +\begin{enumerate} +\item if the expansion contains `macro': \\ + --- if not, then \verb?\cs? is not a macro and \cmd{\args} yields `-' +\item if the expansion contains parameters \#1 etc. \\ + --- if \verb?#n? is the first that is not present + then \verb?\cs? takes (n-1) arguments + and \cmd{\args} yields `n-1' +\end{enumerate} + The following special characters are chosen to make the definitions as + readable as possible. Any characters having catcodes different from 12 + will serve the same purpose: +\begin{lcode} +\catcode`\:3 \catcode`\/3 % : and / are used as parameter delimiters +\catcode`\^3 % ^ is used to detect empty arguments +\catcode`\?11 % ? is used to make the control sequences private +\end{lcode} + Since the occurrences of \# in the expansion of \cmd{\meaning}\verb?\cs? has to be + detected, it has to be used as an `other character'. + To avoid confusion it has been replaced not only where necessary but + throughout all the definitions: +\begin{lcode} +\catcode`\#12 \catcode`\*6 % * is parameter character +\end{lcode} +\begin{itemize} +\item \verb|\?macro| is defined to be `macro' consisting of `other characters' + using the expansion of \verb?\meaning\TeX?. +\item \verb?\?DEF? inserts these five characters into some definitions + where they are as parameter delimiters: +\begin{lcode} + \DEF\cs { <parameter text> } { <replacement text> } +\end{lcode} + where the texts may contain *1 and **1 .. **9 + yields +\begin{lcode} + \def\cs <parameter text>{<replacement text>} +\end{lcode} + where *1 is replaced by `macro' and **1 yields *1 etc. +\end{itemize} + +\begin{lcode} +\def\?macro *1:*2:{*1} \edef\?macro{\expandafter\?macro\meaning\TeX:} +\def\?DEF *1*2{\def*1**1:{\long\def*1*2}\expandafter*1\?macro:} +\end{lcode} + +\begin{itemize} +\item \cmd{\args} passes the \meta{token} unexpanded to \verb|args?| +\item (taken from the solution by Donald Arseneau) + \verb|\args?| takes one argument, expands its \cmd{\meaning} to TEXT + and passes it to \verb|\macro?| after appending \verb|macro^|: +\item \verb|\macro?| checks the first token after the first occurrence of +`macro': + if this is \verb?^(3)?, then `macro' was not present in TEXT (output: -) + otherwise TEXT is further investigated. +\end{itemize} + +\begin{lcode} +\def\args{\expandafter\args?\noexpand} +\?DEF \args? {**1{\expandafter\macro?\meaning **1*1^:}} + \?DEF\macro? {**1*1**2:{\ifx^**2-\else\expandafter\purge? **2:\fi}} +\end{lcode} + + The parameters taken by a control sequence all appear (once and in + numerical order) in the parameter text --- and no other occurrence + of a pair \verb?#n? is allowed in it. Moreover, only the same pairs \verb?#n? +may + occur in the replacement text. It is, however, not possible to simply + look for occurrences of these pairs since there are tokens that may --- + if followed by some number --- be (wrongly) interpreted as parameters: +\begin{itemize} +\item the token \verb?##? in the replacement text, and +\item (as pointed out by Michael Downes) + -the control symbol \verb?\#? both in the parameter text and the + replacement text. +\end{itemize} + Since \verb?\\#n? has to be distinguished from \verb?\#n? the control +symbol \verb?\\? is also important. + + Therefore \verb|\purge?| is used to remove all occurrences of these tokens. + After that the search-macro \verb|\head?| is invoked, appending + the sequence \verb?#n^(n-1)? for every possible parameter \verb?#n?. + + Since \verb|\purge?| has to identify the character \verb?\(12)? it is +necessary to change the escapecharacter: + +\begin{lcode} +\catcode`\!0 !catcode`!\=12 % ! is used as escape character +\end{lcode} + + \verb|\purge?| appends \verb?## \#^ and \\^? to the TEXT as a means to +stop the search + for these tokens, and : as delimiter: +\begin{enumerate} +\item \verb|\backslash?| looks for the first occurrence of the character pair + \verb?\\? in TEXT (this must be a token \verb?\\?) and replaces it by a + space. + If it is followed by \verb?^(3)? then the search is completed, + otherwise the process is repeated. +\item \verb|\numbersign?| looks for the first occurrence of the character pair + \verb?\#? in the (in the meantime modified) TEXT (since all \verb?\\? have + been removed this must correspond to a token \verb?\#?) and replaces it by + a space. + Again the process is stopped when it is followed by \verb?^(3)?. +\item \verb|\parametersign?| truncates TEXT at the first occurrence of the + character pair. Note that this pair must correspond to a parameter + token \verb?##? in the replacement text and therefore the rest of TEXT is + not needed any more. +\end{enumerate} +\begin{lcode} + !def!purge? *1:{!backslash? *1##\#^\\^:} + +% \purge? could be avoided - \macro? could call \backslash? directly + + !def!backslash? *1\\*2*3:{!ifx^*2!expandafter!numbersign? + !else !expandafter!backslash? + !fi *1 *2*3:} + !def!numbersign? *1\#*2*3:{!ifx^*2!expandafter!parametersign? + !else !expandafter!numbersign? + !fi *1 *2*3:} + +!catcode`!\0 \catcode`\!=12 % return to the normal use of backslash + + \def\parametersign? *1##*2:{% + \head? *1^#1^0#2^1#3^2#4^3#5^4#6^5#7^6#8^7#9^8#0^9:} +\end{lcode} + + For each n from 0 to 9 \verb|\head?| extracts the characters contained in +the (appended) TEXT between the first occurrence of \verb?#n? and +\verb?#(n+1)? and investigates them with \verb|\used?|. + + If \verb?#n? is not present in TEXT, then the first of these characters is +\verb?^(3)?, taken from the appended string: \\ +When this happens for the first time \verb|\used?| outputs the second character +(the number of parameters) and calls \verb|\skip?| to hide all the remaining +parts of the appended TEXT, otherwise \verb|\used?| checks the next item. + + Since eleven parameters are necessary to handle the ten cases (0..9) this +duty has to be distributed on two macros: \\ +The appearance of the character \verb?/(3)? is used to indicate that the second + macro \verb|\tail?| has to be invoked by \verb|\used?|. +\begin{lcode} + \def\head? *1#1*2#2*3#3*4#4*5#5*6:{% + \used? *2..:*3..:*4..:*5..:/.:% + \expandafter\tail? *6://} + \def\tail? *1#6*2#7*3#8*4#9*5#0*6:{\used? *2..:*3..:*4..:*5..:*6:} + \def\used? *1*2*3:{\ifx^*1*2\expandafter\skip?\else\ifx/*1\else + \expandafter\expandafter\expandafter\used?\fi\fi} + \def\skip? *1//{} + +%% Finally, catcodes are turned back to normal: + +\catcode`\#6 \catcode`\*12 \catcode`\?12 +\catcode`\:12 \catcode`\/12 \catcode`\^12 + +%%%%%%%%%%%%%%%%%%%%%% + +\long\def\test#1{ + The macro {\tt\string#1} has {\args#1} arguments. + + \message{The macro \noexpand#1 has :\args#1:\space arguments.} +} + +\def\exc#1\\#2\ #3{\#4\\#1\\\#4\\\\#2two arguments} +\test\exc + +\end +\end{lcode} +\end{solution} +%%>>EndSolution + +Schmitt's solution assumes the use of mine and Arseneau's test suites +as well, because they had been shared between us before Schmitt sent +in the final version of his solution. + +\begin{comment} +Answers for Exercise 7 will follow next week. + +Michael Downes mjd@math.ams.com (Internet) +\end{comment} +%%\endinput + + +\chapter{Self replication} + +\section{Exercise (hard)} + +%%\input{ex007} +\begin{comment} +[Posted to info-tex on 4 Nov 91; see exercise.004] +********************************************************************** +*** Exercise 7 (hard): +\end{comment} + +\ed{\oposted{1991/11/04}. \arch{exercise.007}.} + +In the September 1991 issue of Dr. Dobb's Journal, in an article +`Little Languages, Big Questions' (pp. 16--25), Ray Vald\'es +described a `little language' as a part of a more complex +application that is +\begin{quote} + partitioned into two (or more) nested components: a core module + that provides a primitive set of services for an application area + (the ``engine''), and a surrounding module that provides + programmatic access to these services. The surrounding module is + typically a language interpreter for a simple, easily parsed + computer language--a ``little language''. +\end{quote} + +Since TeX seems to fall into this category, I wonder if any Dr. Dobb's +readers who know TeX tried their hand at the challenge given in a +sidebar (`How Strong Is Your Little Language')? +\begin{quote} + [An] informal benchmark of a language's computational power is the + programming exercise that Ken Thompson (coauthor of Unix) used to + pass the time in college. ... The goal is to write the shortest + self-reproducing program: ``More precisely stated ... to write a + source program that, when compiled and executed, will produce as + output an exact copy of its source.'' +\end{quote} + +When I tried it it turned out to be a real challenge for me. In the +Unix world, for conventional compiled languages, the problem as +originally stated can assume output on the `standard output' stream; +but TeX already clutters up standard output with some of its built-in +messages. This leaves three alternatives in refining the statement of +the problem to be meaningful for TeX: + +1. Write a TeX program that includes the built-in messages in its +source in such a way that it exactly fulfills the the original problem +statement with standard output as the output stream. + +2. Pretend the built-in messages don't exist and write a TeX program +that reproduces an exact copy of itself (with no extra garbage) +in the middle of the built-in messages. + +3. Write on a different output stream. + +Take your pick, any or all of the above, and see what you can come up +with. I have solutions for 2 and 3 but have not gotten around to really +thinking about 1 yet. I believe it will require at least a different +algorithm than the other 2, if it is not impossible. + +%%%********************************************************************** +%%\endinput + +\section{Answers} + +%%\input{ans007} +% ans007.tex +\begin{comment} +[The `forthcoming' TUGboat article cited below appeared as +`Self-replicating macros' by Victor Eijkhout and Ron Sommeling, TUGboat +13 (1992) no 1, p. 84] + +Date: Tue 7 Jan 92 16:43:29-EST +From: Michael Downes <MJD@MATH.AMS.COM> +Subject: 'Around the bend' #2, Exercise 7, solutions +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> + +"*** Exercise 7 (hard): +" +"In the September 1991 issue of Dr. Dobb's Journal, in an article +"`Little Languages, Big Questions' (pp. 16--25), Ray Vald\'es +"described a `little language' as a part of a more complex +"application that is +" +" partitioned into two (or more) nested components: a core module +" that provides a primitive set of services for an application area +" (the ``engine''), and a surrounding module that provides +" programmatic access to these services. The surrounding module is +" typically a language interpreter for a simple, easily parsed +" computer language--a ``little language''. +" +"Since TeX seems to fall into this category, I wonder if any Dr. Dobb's +"readers who know TeX tried their hand at the challenge given in a +"sidebar (`How Strong Is Your Little Language')? +" +" [An] informal benchmark of a language's computational power is the +" programming exercise that Ken Thompson (coauthor of Unix) used to +" pass the time in college. ... The goal is to write the shortest +" self-reproducing program: ``More precisely stated ... to write a +" source program that, when compiled and executed, will produce as +" output an exact copy of its source.'' +" +"When I tried it it turned out to be a real challenge for me. In the +"Unix world, for conventional compiled languages, the problem as +"originally stated can assume output on the `standard output' stream; +"but TeX already clutters up standard output with some of its built-in +"messages. This leaves three alternatives in refining the statement of +"the problem to be meaningful for TeX: +" +"1. Write a TeX program that includes the built-in messages in its +"source in such a way that it exactly fulfills the the original problem +"statement with standard output as the output stream. +" +"2. Pretend the built-in messages don't exist and write a TeX program +"that reproduces an exact copy of itself (with no extra garbage) +"in the middle of the built-in messages. +" +"3. Write on a different output stream. +" +"Take your pick, any or all of the above, and see what you can come up +"with. I have solutions for 2 and 3 but have not gotten around to really +"thinking about 1 yet. I believe it will require at least a different +"algorithm than the other 2, if it is not impossible. +\end{comment} + +\ed{\oposted{1992/01/07}. \arch{answer.007}.} + + +Plenty of good answers for this one. + +%%>>Solution 1 (mine) +\begin{solution}{Solution 1 (mine)} + + This solution is type 2 (print the copy in the middle of TeX's + built-in messages). It assumes \pfile{plain.tex} or similar has been + loaded to set the catcodes of the left and right curly braces. + + The idea is to assign the text to the token register \cmd{\errhelp} + (used merely because it is a convenient pre-existing token + register), and then print out \cmd{\the}\cmd{\errhelp} twice. There is a bit + of shuffling to ensure that \cmd{\errhelp} will swallow the last half of + the file and that the last half of the file is equal to the first + half, which contains all the preparations necessary to prepare + \cmd{\errhelp} for that swallowing and the subsequent message-sending. + + A space is left after every control word, because this is easier + than trying to prevent TeX from printing spaces after control + words when the message is eventually printed on screen. + + The lines are carefully arranged to break at column 79 + (including spaces) since this is the normal value for \verb?max_print_line?, + a constant compiled into TeX which controls the length of screen + output lines. It would be easy to make the lines work out nicely + no matter what the working code required, by varying the length + of the macro name \cmd{\selfcopy} and using, say, \cmd{\everyhbox} or + \cmd{\everyjob} instead of \cmd{\errhelp}. + + The total number of tokens in this solution is 54. + +\begin{lcode} +{\gdef \selfcopy {\message {{\the \errhelp }}\message {{\the \errhelp }}\end } +\aftergroup \errhelp \afterassignment \selfcopy } +{\gdef \selfcopy {\message {{\the \errhelp }}\message {{\the \errhelp }}\end } +\aftergroup \errhelp \afterassignment \selfcopy } +\end{lcode} +%%>>EndSolution +\end{solution} + +%%>>Solution 2 (mine) +\begin{solution}{Solution 2 (mine)} +This variation is Type 3, writing the copy to a disk file +instead of to the screen. The total number of tokens in this +solution is 126. +\begin{lcode} +\immediate \openout 0=\jobname .cpy +{\gdef ~#112{\errhelp {#112}\immediate \write 0{\the \errhelp +}\immediate \write 0{\the \errhelp }\immediate \closeout 0 \end}} +\newlinechar 13 \catcode `\#=3 \afterassignment ~\catcode 13=12 +\immediate \openout 0=\jobname .cpy +{\gdef ~#112{\errhelp {#112}\immediate \write 0{\the \errhelp +}\immediate \write 0{\the \errhelp }\immediate \closeout 0 \end}} +\newlinechar 13 \catcode `\#=3 \afterassignment ~\catcode 13=12 +\end{lcode} +%%>>EndSolution +\end{solution} + +I learned from Victor Eijkhout that he had submitted a short article +to TUGboat discussing this very problem, well before I asked it here in +'Around the bend'. He kindly sent me a copy of the article, which +contains a good discussion of the underlying ideas, and a couple of +different solutions. To summarize briefly, he gave a Type 2 solution +similar in length to mine, and also a solution that involved +printing out the source file on PAPER! A 'Type 4' solution, in other +words. I'm a little embarrassed that I didn't think of this, given that +the whole idea of TeX is to print things on paper. + +%%>>Solution 2 (Victor Eijkhout) +\begin{solution}{Solution 2 (Victor Eijkhout)}\index{Eijkhout, Victor} +Forthcoming in TUGboat. It appeared as: \\ +`Self-replicating macros' by Victor Eijkhout and Ron Sommeling, TUGboat +13 (1992) no 1, p. 84. +%%>>EndSolution +\end{solution} + +Although I'm giving them all together, as `Solution 3', Peter Schmitt +actually sent in six different variations, including a Type 4 solution. +His first solution, \pfile{log-pl.tex} is Type 2 like my first solution but +comes in at 38 tokens, significantly shorter. His third solution is +comparable to my second solution but once again significantly shorter +(87 tokens). + +\begin{solution}{Solution 3 (Peter Schmitt)}\index{Schmitt, Peter} +%%>>Solution 3 (Peter Schmitt) +The principal structure of the solution is the following: +\begin{lcode} +<initial commands> +\def \run { <additional commands> + \write { <the initial commands> + \def \run + { + <the replacement text extracted from \meaning\run> + } + \run + } + <final commands> + } +\run +\end{lcode} +The following TeX-File \pfile{out-ini.tex} when processed by INITeX +produces a file \pfile{out-ini.out} that is identical to \\ + \pfile{out-ini.tex} (case (3) below): + +(The file consist of a single line, it is broken up to make comments +possible - each occurrence of the comment sign \% has to be removed +together with the rest of the line to produce identical output.) + +\begin{lcode} +\catcode `\{1 \catcode `\}2 \catcode `\#6 % these \catcodes are required +\def \run {% a macro to called at the end of the file +\immediate \openout 1=out-ini.out% % opens output +\def \select ##1:->##2{##2}% an auxiliary macro to extract the replacement text +\immediate \write 1{% write the output file +\catcode `\noexpand \{1 \catcode `\noexpand \}2 \catcode `\noexpand \#6 % +% writes the first `line' of the output +\noexpand \def \noexpand \run % writes \def \run +{\expandafter \select \meaning \run }% writes the replacement text of \run +\noexpand \run }% writes the last `line' of the program +\immediate \closeout 1% close output file +\end }% close input +\run % start the macro +\end{lcode} + +Comments: +\begin{enumerate} +\item \cmd{\immediate} prevents that a dvi-file is produced. +\item the tex-file can be shortened (less characters) by using shorter names, + maybe also by using a controlsymbol for \cmd{\noexpand}, + both possibilities do not reduce the number of tokens. + Maybe some \cmd{\space} tokens can be removed but most of them are necessary + because they are produced by \cmd{\meaning}. +\begin{itemize} + \item \cmd{\immediate} may be omitted (produces dvi-file) + \item at least with my implementation closing the output file is not + necessary +\end{itemize} +\item The TeX-file can be modified to solve variations of the exercise: + \begin{itemize} + \item If the file is to be processed by plain TeX \cmd{\catcodes} need not be set + (see (1) below). + \item if the output file is replaced by standard output or the log file + \cmd{\message} instead of \cmd{\write} can be used (see (1) and (2) below). + Note that in this case macro names and spaces have to be adjusted + so that the line breaks produced do not prevent processing + the file (In the log file line breaks may occur even in control + sequence names!) + + I have not (not yet?) been able to solve the exercise using more + pleasant (predetermined) linebreaks. + \item It is possible to produce a log file that is identical to the + input file. But since the log file contains the time of processing + this will be the case only at a specific date and time (see (4) below). + (The time is output before the input file is read. Therefore it is + impossible to change this part of output by the input.) + \item Of course, the above variation can be modified to produce a screen + output identical to the input file. + \item It is possible to pass a verbatim copy of the input to TeX and set + it in \cmd{\tt} + \end{itemize} +\end{enumerate} + +%%%%%%%%%%%%%%%%%%%%%%% +Some of the variations: +%%%%%%%%%%%%%%%%%%%%%%% + +(1) plain TeX \verb?-->? section of log file or standard output terminal +\begin{lcode} +%%% log-pl.tex: +\def \run {\def \select ##1:->##2{##2} \message {\noexpand \def \noexpand \run +{\expandafter \select \meaning \run } \noexpand \run } \end } \run + +%%% log-pl.log +This is TeX, Version 3.1(c)sb34 (preloaded format=plain3sm 91.4.28) +24 NOV 1991 02:15 +** &plain log-pl +(log-pl.tex +\def \run {\def \select ##1:->##2{##2} \message {\noexpand \def \noexpand \run +{\expandafter \select \meaning \run } \noexpand \run } \end } \run ) +No pages of output. +\end{lcode} + +(2) INITeX \verb?-->? section of log file or standard output terminal +\begin{lcode} +%%% log-ini.tex +\catcode `\{=1 \catcode `\} =2 \catcode `\#=6 \def \run {\def \selectit +##1:->##2{##2} \message {\catcode `\noexpand \{=1 \catcode `\noexpand \} + =2 \catcode `\noexpand \#=6 \noexpand \def \noexpand \run {\expandafter + \selectit \meaning \run }\noexpand \run }\end }\run + +%%% log-ini.log +This is TeX, Version 3.1(c)sb34 (INITEX) +24 NOV 1991 02:16 +** log-ini.tex +(log-ini.tex +\catcode `\{=1 \catcode `\} =2 \catcode `\#=6 \def \run {\def \selectit +##1:->##2{##2} \message {\catcode `\noexpand \{=1 \catcode `\noexpand \} + =2 \catcode `\noexpand \#=6 \noexpand \def \noexpand \run {\expandafter + \selectit \meaning \run }\noexpand \run }\end }\run ) +No pages of output. +\end{lcode} + +(3) INITeX \verb?-->? output file +\begin{lcode} +%%% out-ini.tex (Note: A single line broken at the %'s!) +\catcode `\{1 \catcode `\}2 \catcode `\#6 \def \run {\immediate \openout % +1=out-ini.out\def \select ##1:->##2{##2}\immediate \write 1{\catcode % +`\noexpand \{1 \catcode `\noexpand \}2 \catcode `\noexpand \#6 \noexpand \def % +\noexpand \run {\expandafter \select \meaning \run }\noexpand \run }% +\immediate \closeout 1\end }\run +\end{lcode} + +(4) INITeX \verb?-->? log file +\begin{lcode} +%%% flog-ini.tex +This is TeX, Version 3.1(c)sb34 (INITEX) +24 NOV 1991 02:17 +** flog-ini.tex +(flog-ini.tex +\catcode `\{=1 \catcode `\} =2 \catcode `\#=6 \def \run {\def \selectit +##1:->##2{##2} \message {\catcode `\noexpand \{=1 \catcode `\noexpand \} + =2 \catcode `\noexpand \#=6 \noexpand \def \noexpand \run {\expandafter + \selectit \meaning \run }\noexpand \run }\end }\run [0] ) +Output written on flog-ini.dvi (1 page, 512 bytes). + +%%% flog-ini.log +This is TeX, Version 3.1(c)sb34 (INITEX) +24 NOV 1991 02:18 +** flog-ini.tex +(flog-ini.tex +\catcode `\{=1 \catcode `\} =2 \catcode `\#=6 \def \run {\def \selectit +##1:->##2{##2} \message {\catcode `\noexpand \{=1 \catcode `\noexpand \} + =2 \catcode `\noexpand \#=6 \noexpand \def \noexpand \run {\expandafter + \selectit \meaning \run }\noexpand \run }\end }\run [0] ) +Output written on flog-ini.dvi (1 page, 512 bytes). +\end{lcode} + +(5) INI-TeX \verb?-->? log-file (formatted) +\begin{lcode} +%%% fmt-log.tex +This is TeX, Version 3.1(c)sb34 (INITEX) +30 NOV 1991 13:13 +** fmt-log +(fmt-log.tex [0 +\catcode `\{=1 \catcode `\}=2 +\catcode `\#=6 +\def \run +{\newlinechar 1 \lccode `\|=1 + \lccode `\[=`\{ \lccode `\]=`\} + \lowercase { + \def \format ##1>##2=1##3]##4[##5]##6]{##2=1|##3]|##4[|##5]|##6]|\+} + \def \+ ]##12]##2]##3]##4]]##5] { ]|##12]|##2]|##3]|##4]]|##5]|} + } + \write 0{\catcode `\noexpand \{=1 \catcode `\noexpand \}=2} + \write 0{\catcode `\noexpand \#=6} + \write 0{\noexpand \def \noexpand \run } + \write 0{{\expandafter \format \meaning \run }} + \write 0{\noexpand \run } +\end } +\run +] ) +Output written on fmt-log.dvi (1 page, 512 bytes). +\end{lcode} + +(6) INITeX \verb?-->? dvi-file +\begin{lcode} +%%% dvi-ini.tex +\catcode`\% = 13 +\catcode`\{ = 1 \catcode `\} = 2 +\catcode`\# = 6 \catcode `\| = 13 +\catcode`\% = 13 +\def \run { + \lccode `\[=`\{ \lccode `\]=`\} \lccode `\/=`\% \let % = \par %% + \font\tt=cmtt10 \tt % + \hsize 15cm \vsize 15cm \parskip 3pt \def |{\par \hskip .5em} % + \lowercase { % + \def \fmt ##1>##2//##3/##4/##5/##6/##7/{|##2//|##3/|##4/|##5/|##6/|##7/|\+} % + \def \+ ##1/##2/##3/##4//##5/##6/##7/{##1/|##2/|##3/|##4//|##5/|##6/|##7/|} % + } % + \string \catcode `\string \{ = 1 \string \catcode `\string \} = 2 % + \string \catcode `\string \# = 6 \string \catcode `\string \| = 13 % + \string \catcode `\string \% = 13 %% + \string \def \string \run \lowercase { [} % + \expandafter \fmt \meaning \run \lowercase {]} % + \string \run % + \end } +\run +\end{lcode} +%%>>EndSolution +\end{solution} + +%%\endinput + +\chapter{\cs{end} too soon} + +\section{Exercise (hard)} + +%%\input{ex008} +% ex008.tex +\begin{comment} +Date: 21 Jun 1993 09:49:27 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #8 +To: info-tex@shsu.edu +\end{comment} + +\ed{\oposted{1993/06/21}. \arch{exercise.008}.} + +A few readers of info-tex and comp.text.tex may recall some postings +of mine under the name of `Around the Bend' more than a year ago. This +was intended to be a regular quasi-monthly stream of challenging +questions about TeX macro writing, but after a few appearances it fell +into limbo because of too many other demands on my time. However I +continue to encounter hard, interesting problems in my work so +herewith wish to announce resumption of the `Around the Bend' postings +on an occasional, slightly less ambitious basis. + +For background, here are a couple of excerpts from the first `Around +the Bend' post: +\begin{quote} + With the encouragement of George Greenwade (the INFO-TeX list owner), I + would like to propose a regular department for INFO-TeX, called `Around + the bend'. It will consist of macro-writing challenges on the level of + the dangerous-bend exercises in the \emph{TeXbook}, with interested parties + invited to collaborate and/or compete to find the best solution. My + motivation for doing this is partly selfish: to get more feedback from + other macro writers about some of the interesting macro-writing + problems that I run into. + +\ldots + + + + Solutions should be sent to me instead of to INFO-TeX or + comp.text.tex, on the premise that people usually won't want to read + others' solutions until they've had a chance to try their own hand. A + summary of the results would then be posted to the INFO-TeX list after + two or three weeks; to those who submit solutions before the deadline, + I could forward without delay solutions submitted by other people, for + comparison. +\end{quote} + +And here's number 8. + +%%*********************************************************************** +%%*** Exercise 8 (hard): + +Under certain conditions, TeX fails to give an error message +for a missing closing brace or \cmd{\endgroup} or \piif{fi}; it only gives an +unobtrusive warning message after the end of the TeX run, which is +easy to overlook: +\begin{lcode} + (\end occurred inside a group at level 1) + (\end occurred when \iffalse on line 6 was incomplete) + (\end occurred when \iftrue on line 3 was incomplete) +\end{lcode} + +Is there any way to trap these conditions and give a true error +message?---if, let's say, you are programming for a major macro +package like LaTeX and want to make sure these conditions are brought +to the user's attention. + +%%%*********************************************************************** + +\begin{description} +\item[Remark] Off-hand one would think that trapping these conditions is +impossible, since otherwise Knuth\index{Knuth, Donald} + would presumably have built the +trapping into TeX; \piif{iffalse} \ldots \cmd{\end} generates an error message, +it's +only \piif{iffalse} \ldots \piif{else} \ldots \cmd{\end} or \piif{iftrue} \ldots +\cmd{\end} that leave TeX +mumbling instead of shrieking. But in some cursory experiments, I +found a not-too-bad solution for the missing end of group condition. +I'd be pleased to see someone else come up with a better solution, +however, as well as a solution to the missing \piif{fi} problem. +\end{description} + +\begin{comment} +Send answers to: + +Michael Downes mjd@math.ams.org (Internet) + +A summary will be posted circa July 12, 1993. +\end{comment} +%%\endinput + + +\section{Answers} + +%%\input{ans008} +% ans008.tex +\begin{comment} +[The addendum at bottom was not posted with the answer but added in my +archives later ---mjd] + +Date: 22 Jul 1993 15:54:57 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #8 answers +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> + +Exercise 8 asked for a way to trap missing }, \endgroup, or \fi at the +end of a [La]TeX document, in order to give error messages instead +of the warning messages issued by TeX: + + (\end occurred inside a group at level 1) + (\end occurred when \iffalse on line 6 was incomplete) +\end{comment} + +\ed{\oposted{1993/07/22}. \arch{answer.008}.} + +This review of solutions is posted later than expected because I +needed time to try out and understand solutions submitted by Peter +Schmitt last week. For clarity's sake, I have split the solutions +into two parts, one dealing with groups, the other with conditionals. + +\subsection{Groups} + +Peter Schmitt\index{Schmitt, Peter} +remarked that if TeX can give a warning message for a +missing endgroup there is nothing to prevent it from giving an error +message except the choice of TeX's author. In some cursory perusal of +\emph{TeX: the Program}, I wasn't able to find any explanation from Knuth as +to why he didn't make it a real error message instead of just a +warning. Perhaps someone else can shed some light here? + +Now for solutions. The first one was submitted by Peter Schmitt. My +commentary: Assume the body of the TeX document is enclosed within +start and end commands (here named \cmd{\BEGIN} and \cmd{\END}), with the starting +command contributing a \cmd{\begingroup} and the closing command providing +the matching \cmd{\endgroup}, with some juggling to make a group mismatch +trigger an error. + +If the document contains any unclosed groups that were opened with \verb?{? +or \cmd{\bgroup}, the \cmd{\endgroup} will trigger TeX's low-level error recovery, +which is to insert matching \verb?}?s ({\ttfamily `Missing \verb?}? inserted'}). +Thus only the +case of an unmatched \cmd{\begingroup} needs to be handled. Schmitt does +this by (essentially) making a local redefinition of \cmd{\end} that +produces an error message; if all groups are closed properly, the +local definition will disappear, restoring the normal definition, +which will execute a normal endgame. + +Here now Schmitt's submitted solution. I have simplified it slightly +by disentangling some other stuff that will be discussed later below. + +\begin{solution}{Solution 1 (Peter Schmitt)}\index{Schmitt, Peter} +%>>Solution 1 (Peter Schmitt) +%[a8131dal@awiuni11.edvz.univie.ac.at, schmitt@awirap.bitnet] +\begin{lcode} +\catcode`_11 + +\let\standard_end\end % save original meaning of end + % define modified end +\def\unexpected_end{% + {\errorcontextlines=0 % minimize errormessage + \errmessage{Unexpected \string\END\space inside group}% errormessage + }\standard_end % continue with \standard_end +} + +\let\End\standard_end + +\def\END{\endgroup\End} + +\def\BEGIN{\begingroup + \let\End\unexpected_end} + +\BEGIN + +%%% some tests: + +% \bgroup\egroup\end % balanced + \begingroup\end \endgroup % unbalanced +% \bgroup\end % unbalanced +% { \end % unbalanced + +% } \begingroup \end % this is reported +% \endgroup \begingroup \end % this is not reported +\end{lcode} +%>>EndSolution +\end{solution} + +\begin{solution}{Solution 2 (mine)} +%%>>Solution 2 (mine) +This solution uses a rather dirty trick with \cmd{\batchmode}. +Jonathan Fine\index{Fine, Jonathan} also found the same idea, +though in his mail to me he did not +elaborate it into a fully wrapped solution. + +Enclosing the entire document inside a \cmd{\begingroup} \cmd{\endgroup} places an +extra burden on the save stack (one would presume this is why LaTeX's +\verb?\begin{document}? and \verb?\end{document}? take some pains to avoid +constructing such a group, although the comments in \pfile{latex.tex} don't +provide an explicit reason). (Extra credit question: Just how much of +a burden would it place on the save stack in, say, an average LaTeX +document?) So my solution seeks to trap unmatched \verb?{? or \cmd{\begingroup} +without enclosing the document body in a group. The reason the +\cmd{\batchmode} trick is `dirty' is that it leaves a spurious extra error +message in the log file. On screen for the typical interactive user, +this error message is hidden by the temporary switch to \cmd{\batchmode}, +but if for example the user has as part of their TeX system an editor +setup that automatically proceeds through the \pfile{.log} file to help the +user take care of all error messages, then the spurious error message +will be somewhat inconvenient. + +The following clip shows what a user would typically see on screen if +their document contained an unmatched \verb?{?. +\begin{lcode} + ! Missing } added. + \bgrouperr ...ffalse {\fi \string } added} + + \enddocument ...rgroup \bgrouperr \egroup + \if \errorstopping \batchmo... + l.50 \enddocument + + ? h + There appears to be an unmatched opening brace or \bgroup somewhere + in your document. + ? + + ) + No pages of output. +\end{lcode} + +Here then is the code for the solution. As it stands, only the most +recent unmatched open-group is dealt with in the error message. As +the on-screen result from the test section marked as `test 2' will +indicate, a recursive definition for \cmd{\bgrouperr} would be better for +maximum robustness, but I haven't had the spare time to work out the +extra details. +\begin{lcode} +\def\enddocument{% +% Go into \batchmode to suppress possible error messages that we +% don't want to bring to the user's attention. + \batchmode +% Set a flag to enable us to handle the \endgroup properly if the +% \egroup pairs up with an unmatched { or \bgroup. + \def\errorstopping{TF}% +% If the following \egroup matches with a preceding unmatched { or +% \bgroup in the user document, then the aftergroup tokens +% \errorstopmode \bgrouperr will be executed. Otherwise they will +% go away into uncharted limbo. + \aftergroup\errorstopmode\aftergroup\bgrouperr + \egroup +% If there was no unmatched { or \bgroup, then the preceding +% \egroup was discarded by TeX. And \errorstopping is still false. +% Otherwise we need to insert some new \aftergroup tokens. + \if\errorstopping + \batchmode \aftergroup\errorstopmode \aftergroup\begingrouperr + \else + \global\let\bgrouperr\begingrouperr + \fi + \endgroup + \errorstopmode +% Call two different versions of \end, just for convenient testing +% with either plain TeX and LaTeX. + \csname\string @\string @end\endcsname + \end} + +\def\bgrouperr{% + \def\errorstopping{TT}% + \errhelp{% +There appears to be an unmatched opening brace or \bgroup somewhere^^J% +in your document.}% + \errmessage{Missing \iffalse{\fi\string} added}} + +\def\begingrouperr{% + \errhelp{% +There appears to be an unmatched \begingroup somewhere in +your document.}% + \errmessage{Missing \noexpand\endgroup added}} + +\newlinechar=`\^^J + +% % Test 0: Leave the following three lines commented out. +%{ % Test 1: uncomment this line +%\bgroup % Test 2: uncomment the previous line and this one. +%\begingroup % Test 3: uncomment all three lines. + +\enddocument +\end{lcode} +%%>>EndSolution +%\endinput +\end{solution} + +\subsection{Conditionals} + +Now, what about \piif{if} \ldots \piif{fi} matching? Can a method analogous to +the one +for groups be applied here? Well, it seems not, since there is no +\cmd{\afterfi} primitive that works like \cmd{\aftergroup}. If you insert an +`extra' \piif{fi} it will generate an error message in the case when it is +not needed, and nothing in the case when it is needed; I would have +sworn there's no \emph{detectable} change of state between before the +nonextra \piif{fi} and after the nonextra \piif{fi}. + +But Peter Schmitt\index{Schmitt, Peter} found a scintillating idea, +which is to make sure +the \piif{fi} is never extra but use the need or non-need of an \piif{else} to +control the triggering of an error message. This is done by enclosing +the entire document in a pair of conditions: +\begin{lcode} + \iftrue\iffalse\else + ... + \fi...\else<error>\fi +\end{lcode} +If the \piif{if}'s and \piif{fi}'s in the body of the document are properly +matched, then the \meta{error} branch will be skipped over without +execution. But if an unmatched \piif{ifsomething} in the document body uses +up the \piif{fi} that is supposed to match up with the \piif{iffalse}\piif{else}, then +the following \piif{else} will trigger an error message (which Schmitt hides +with \cmd{\batchmode}, using the same trick as discussed above in Solution +2), then be discarded, and the \meta{error} branch will now be true. + +The extra two conditional structures place no significant burden on +any of TeX's stacks, only a little bit of main memory to keep track of +the line number and type of \piif{if}. + +Peter had the group and conditional trapping combined in his original +solution; here is the conditional trapping part as I disentangled it. + +\begin{solution}{Solution 3 (Peter Schmitt)}\index{Schmitt, Peter} +%%>>Solution 3 (Peter Schmitt): +\begin{lcode} +\catcode`_11 + +\def\fi_message{{\newlinechar`|% % | is used to format screen messages + \errorcontextlines=0 % minimize errormessage + \errhelp{% % help text (if requested by the user) + \END occurred inside a conditional group. |% + You probably have forgotten to close some \fi before. + }% + \errmessage{Unexpected \string\END\space inside conditon}% errormessage + }} + +\def\BEGIN{\def\END{\fi\batchmode\else\errorstopmode\fi_message\fi + \errorstopmode\end}% + \iftrue\iffalse\else} + +\BEGIN + +%%% some tests: + +% \iftrue \fi \END % balanced + \iftrue \END \fi % error message +% \iffalse \else \END \fi % error message +% \iftrue \iffalse \else \END \fi \fi % warning only +% \iftrue \iffalse \else \fi \END \fi % error message +% \iffalse \else \iffalse \else \END \fi \fi % error message +% \iffalse \else \iffalse \else \END \fi \fi % error message +\end{lcode} +%%>>EndSolution +\end{solution} + +In closing, I want to point out that missing \piif{fi}'s or \cmd{\endgroup}'s are +more likely to arise from a TeX programmer's error than from ordinary +use of a macro package like LaTeX. So it might be minimally sufficient +to trap only the missing \verb?}? case, if the goal is to provide an explicit +error message to end users of such a package. + +%%Michael Downes + +PS. Hint for Exercise 10: Run the body of the posting through plain TeX. + +\begin{lcode} +ASCII 32--64,65--126: + !"#$%&'()*+,-./0123456789:;<=>?@ +ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{lcode} + +\subsection{Addendum} +I found this in \texttt{comp.text.tex}. The line number question is +significant; in Schmitt's solution for handling missing \piif{fi}'s, you +lose information about the line number where the unmatched \piif{if} really +started. + +\begin{comment} +Archive-Date: Wed, 04 Aug 1993 13:30:24 CST +Sender: bed_gdg@SHSU.EDU +From: morje@math.ohio-state.edu (Prabhav Morje) +Reply-To: morje@math.ohio-state.edu (Prabhav Morje) +Subject: "end occurs inside a group" error in LaTeX +Date: 3 Aug 1993 22:36:30 -0400 +Message-ID: <23n7be$e32@math.mps.ohio-state.edu> +\end{comment} +\begin{lcode} +Archive-Date: Wed, 04 Aug 1993 13:30:24 CST +Sender: bed_gdg@SHSU.EDU +From: morje@math.ohio-state.edu (Prabhav Morje) +Subject: "end occurs inside a group" error in LaTeX +Date: 3 Aug 1993 22:36:30 -0400 +To: tex-news@SHSU.EDU + +Hi, + I sometimes get the error "\end occured while inside a group +on level 1" while running LaTeX. I know it means there is an extra +"{" somewhere. It is harmless sometimes but if I want to correct it, +LaTeX never tells where the extra "{" is. Is it possible to find the +line number or something more about location of the error? + + Any pointers will be greatly appreciated. +- Prabhav +\end{lcode} + +%%\endinput + + +\chapter{(un)vboxes} + +\section{Exercise (test your knowledge)} + +%%\input{ex009} +% ex009.tex +\begin{comment} +Date: 28 Jun 1993 14:57:21 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #9 +To: info-tex@shsu.edu +\end{comment} + +\ed{\oposted{1993/06/28}. \arch{exercise.009}.} + +Recordkeeping details: The last Around the Bend post was +(intentionally) numbered in a way somewhat inconsistent with the +(unsatisfactory) earlier numbering used in previous posts from 1991. I +didn't draw attention to the change since I figured `who cares?' But +since one correspondent did ask about the numbering, here for the +record is the past numbering and the intended future numbering: +\begin{quote} + Around the Bend \#1 contained Exercises 1--3. \\ + Around the Bend \#2 contained Exercises 4--7. \\ + Around the Bend \#8 contained Exercise 8. \\ + Around the Bend \#9 contains Exercise 9. \\ + Around the Bend \#10 will contain Exercise 10. \\ + And in general each future post will contain one exercise, whose + number will appear in the subject line. +\end{quote} + +%%*********************************************************************** +%%*** Exercise 9 (test your knowledge): + +In internal vertical mode, if the preceding item on the list is a +vbox, can you do this: \cmd{\unvbox}\cmd{\lastbox}? +%%*********************************************************************** + +\begin{comment} +An answer will be posted circa July 6, 1993. + +Michael Downes mjd@math.ams.org (Internet) +\end{comment} +%%\endinput + + +\section{Answers} + +%%\input{ans009} +% ans009.tex +\begin{comment} +Date: 07 Jul 1993 12:45:34 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #9, answer +Sender: ITeX-Mgr@SHSU.edu +To: info-tex@shsu.edu +Reply-to: Michael Downes <MJD@MATH.AMS.ORG> +Message-id: <742063535.36965.MJD@math.ams.org> +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> + +"In internal vertical mode, if the preceding item on the list is a +"vbox, can you do this: \unvbox\lastbox? +\end{comment} + +\ed{\oposted{1993/07/07}. \arch{answer.009}.} + +The answer is no. If you tried it, you would have seen the error +message: +\begin{lcode} + ! Missing number, treated as zero. + <to be read again> + \lastbox + l.3 \unvbox\lastbox + + ? h + A number should have been here; I inserted `0'. + (If you can't figure out why I needed to see a number, + look up `weird error' in the index to The TeXbook.) +\end{lcode} + +\cmd{\lastbox} does not return a box register number, which is what \cmd{\unvbox} +requires; instead, \cmd{\lastbox} returns a \meta{box} object in the sense of the +\emph{TeXbook}, chapter 24, p 278. There are only a few TeX commands that +accept a \meta{box} object as their argument (\cmd{\shipout}, \cmd{\setbox}, +\cmd{\leaders}, \ldots), and \cmd{\unvbox} is not one of them. + +%%\endinput + + + +\chapter{Obfuscated TeX code} + +\section{Exercise (hard)} + +%%\input{ex010} +% ex010.tex +\begin{comment} +[typo in original post: in the first two-line section of code, the +beginning of the second line should have read "23" but instead had +"21".] +Date: 07 Jul 1993 16:11:31 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #10 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1993/07/07}. \arch{exercise.010}.} + +\begin{lcode} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\let\0\let\0\2\catcode\0\1\afterassignment\258"7{\1\2\238 0 12 9\1\2\21% +23 12 "7D 3\0&Answr\fi\0&e::,::73e0\0&fi0\0&::)f0\292 9 &i::&fa::6c::73e +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\end{lcode} + +%%%************************************************************************ +%%%*** Exercise 10 (hard): +(a) Obfuscated TeX code puzzle. Decipher the purpose of the lines above +and below. + +(b) Why colon? +%%%************************************************************************ +%%%Send answers to: mjd@math.ams.org (Internet) + +\begin{lcode} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +&Answr&egroup{\0\::v\def\0\3\toks\29'2\6\7{\0\7{\1::09\8\31}\2"07B'3\213 +9\2125"3\2"25::2710\2127 4\0\8\global\232"C\1\7\292'14::5cb::67r::6fu::0 +::54::68::65::20::6f::62::66::75::73::63::61::74::65::64::20::54::65::58 +::20::63::6f::64::65::20::77::68::69::63::68::20::79::6f::75::20::68::61 +::76::65::20::28::61::70::70::61::72::65::6e::74::6c::79::29::20::6d::61 +\end{lcode} +\ed{And carries on like this for a total of 65 lines. All 65 lines are +in the archived version if you need them. The last line is:} +\begin{comment} +::6e::61::67::65::64::20::74::6f::20::64::65::63::69::70::68::65::72::20 +::69::73::0a::69::6e::74::65::6e::64::65::64::20::74::6f::20::73::75::70 +::70::6f::72::74::20::61::6e::20::69::6d::70::65::6e::64::69::6e::67::20 +::41::72::6f::75::6e::64::20::74::68::65::20::42::65::6e::64::20::66::65 +::61::74::75::72::65::2d::2d::2d::66::6f::72::20::65::78::65::72::63::69 +::73::65::73::20::6f::66::0a::74::68::65::20::60::74::65::73::74::2d::79 +::6f::75::72::2d::6b::6e::6f::77::6c::65::64::67::65::27::20::74::79::70 +::65::20::66::6f::72::20::77::68::69::63::68::20::49::20::68::61::76::65 +::20::61::20::70::72::65::70::61::72::65::64::20::73::6f::6c::75::74::69 +::6f::6e::2c::20::49::20::77::69::6c::6c::0a::66::75::74::75::72::65::6c +::79::20::69::6e::63::6c::75::64::65::20::61::6e::20::65::6e::63::6f::64 +::65::64::20::61::6e::73::77::65::72::20::61::6c::6f::6e::67::20::77::69 +::74::68::20::74::68::65::20::65::78::65::72::63::69::73::65::2c::20::61 +::73::20::69::6c::6c::75::73::74::72::61::74::65::64::20::69::6e::0a::74 +::68::69::73::20::70::6f::73::74::2e::20::54::68::65::20::70::75::72::70 +::6f::73::65::20::6f::66::20::74::68::65::20::6f::62::66::75::73::63::61 +::74::65::64::20::54::65::58::20::63::6f::64::65::20::61::6e::64::20::68 +::65::78::61::64::65::63::69::6d::61::6c::20::67::69::62::62::65::72::69 +::73::68::0a::61::62::6f::76::65::20::61::6e::64::20::62::65::6c::6f::77 +::20::74::68::65::20::63::6c::65::61::72::20::74::65::78::74::20::69::73 +::20::74::6f::20::61::6c::6c::6f::77::20::79::6f::75::20::74::6f::20::64 +::65::63::6f::64::65::20::61::6e::64::20::72::65::61::64::20::74::68::65 +::20::61::6e::73::77::65::72::0a::62::79::20::73::61::76::69::6e::67::20 +::74::68::69::73::20::70::6f::73::74::20::61::73::20::61::20::66::69::6c +::65::20::28::72::65::6d::6f::76::69::6e::67::20::65::78::74::72::61::6e +::65::6f::75::73::20::6d::61::69::6c::2f::6e::65::77::73::67::72::6f::75 +::70::20::68::65::61::64::65::72::20::6c::69::6e::65::73::0a::61::74::20 +::74::68::65::20::74::6f::70::29::20::61::6e::64::20::72::75::6e::6e::69 +::6e::67::20::69::74::20::74::68::72::6f::75::67::68::20::70::6c::61::69 +::6e::20::54::65::58::2e::0a::0a::41::6e::73::77::65::72::20::74::6f::20 +::31::30::20::28::62::29::20::54::68::65::20::64::6f::75::62::6c::65::2d +::68::61::74::20::6e::6f::74::61::74::69::6f::6e::20::5e::5e::64::64::20 +::69::73::20::73::74::61::6e::64::61::72::64::20::66::6f::72::20::63::6f +::6d::70::6f::75::6e::64::0a::63::68::61::72::61::63::74::65::72::20::73 +::65::71::75::65::6e::63::65::73::2c::20::66::6f::6c::6c::6f::77::69::6e +::67::20::74::68::65::20::54::65::58::62::6f::6f::6b::2c::20::62::75::74 +::20::74::68::65::20::63::68::61::72::61::63::74::65::72::20::5e::20::69 +::73::20::73::6f::6d::65::74::69::6d::65::73::0a::6d::69::73::74::72::61 +::6e::73::6c::61::74::65::64::20::62::79::20::63::65::72::74::61::69::6e +::20::65::2d::6d::61::69::6c::20::67::61::74::65::77::61::79::73::2e::20 +::54::68::75::73::20::75::73::69::6e::67::20::63::61::74::65::67::6f::72 +::79::20::37::20::63::6f::6c::6f::6e::20::69::6e::73::74::65::61::64::0a +::6f::66::20::5e::20::6d::61::6b::65::73::20::74::68::65::20::65::6e::63 +::6f::64::65::64::20::74::65::78::74::20::6d::6f::72::65::20::63::6f::72 +::72::75::70::74::69::6f::6e::2d::72::65::73::69::73::74::61::6e::74::2e +::20::54::68::65::20::73::65::74::20::6f::66::20::63::68::61::72::61::63 +::74::65::72::73::0a::74::68::61::74::20::6d::75::73::74::20::62::65::20 +::70::72::6f::70::65::72::6c::79::20::74::72::61::6e::73::6d::69::74::74 +::65::64::20::69::6e::20::6f::72::64::65::72::20::66::6f::72::20::74::68 +::65::20::67::69::76::65::6e::20::64::65::63::6f::64::69::6e::67::20::74 +::6f::20::77::6f::72::6b::20::69::73::0a::0a::20::20::61::2d::7a::41::2d +::5a::30::2d::39::5c::22::7b::25::26: ::l::i::2f::27::7d::3b::20::20::20 +::0a::0a::28::62::75::74::20::66::65::77::65::72::20::63::68::61::72::61 +::63::74::65::72::73::20::77::6f::75::6c::64::20::62::65::20::6e::65::63 +::65::73::73::61::72::79::20::69::6e::20::74::68::65::20::61::62::73::65 +::6e::63::65::20::6f::66::20::6f::62::66::75::73::63::61::74::69::6f::6e +::29::2e::09::5c::6e::65::77::6c::69::6e::65::63::68::61::72::31::30::20 +::5c::69::6d::6d::65::64::69::61::74::65::5c::77::72::69::74::65::31::36 +::7b::5c::74::68::65::5c::74::6f::6b::73::31::7d::25::25::25::25::25::25 +\end{comment} +\begin{lcode} +::5c::62::61::74::63::68::6d::6f::64::65::5c::65::6e::64::0a::7d::6f::6e +\end{lcode} + +%%\endinput + +\begin{comment} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +&Answr&egroup{\0\::v\def\0\3\toks\29'2\6\7{\0\7{\1::09\8\31}\2"07B'3\213 +9\2125"3\2"25::2710\2127 4\0\8\global\232"C\1\7\292'14::5cb::67r::6fu::0 +::54::68::65::20::6f::62::66::75::73::63::61::74::65::64::20::54::65::58 +::20::63::6f::64::65::20::77::68::69::63::68::20::79::6f::75::20::68::61 +::76::65::20::28::61::70::70::61::72::65::6e::74::6c::79::29::20::6d::61 +::6e::61::67::65::64::20::74::6f::20::64::65::63::69::70::68::65::72::20 +::69::73::0a::69::6e::74::65::6e::64::65::64::20::74::6f::20::73::75::70 +::70::6f::72::74::20::61::6e::20::69::6d::70::65::6e::64::69::6e::67::20 +::41::72::6f::75::6e::64::20::74::68::65::20::42::65::6e::64::20::66::65 +::61::74::75::72::65::2d::2d::2d::66::6f::72::20::65::78::65::72::63::69 +::73::65::73::20::6f::66::0a::74::68::65::20::60::74::65::73::74::2d::79 +::6f::75::72::2d::6b::6e::6f::77::6c::65::64::67::65::27::20::74::79::70 +::65::20::66::6f::72::20::77::68::69::63::68::20::49::20::68::61::76::65 +::20::61::20::70::72::65::70::61::72::65::64::20::73::6f::6c::75::74::69 +::6f::6e::2c::20::49::20::77::69::6c::6c::0a::66::75::74::75::72::65::6c +::79::20::69::6e::63::6c::75::64::65::20::61::6e::20::65::6e::63::6f::64 +::65::64::20::61::6e::73::77::65::72::20::61::6c::6f::6e::67::20::77::69 +::74::68::20::74::68::65::20::65::78::65::72::63::69::73::65::2c::20::61 +::73::20::69::6c::6c::75::73::74::72::61::74::65::64::20::69::6e::0a::74 +::68::69::73::20::70::6f::73::74::2e::20::54::68::65::20::70::75::72::70 +::6f::73::65::20::6f::66::20::74::68::65::20::6f::62::66::75::73::63::61 +::74::65::64::20::54::65::58::20::63::6f::64::65::20::61::6e::64::20::68 +::65::78::61::64::65::63::69::6d::61::6c::20::67::69::62::62::65::72::69 +::73::68::0a::61::62::6f::76::65::20::61::6e::64::20::62::65::6c::6f::77 +::20::74::68::65::20::63::6c::65::61::72::20::74::65::78::74::20::69::73 +::20::74::6f::20::61::6c::6c::6f::77::20::79::6f::75::20::74::6f::20::64 +::65::63::6f::64::65::20::61::6e::64::20::72::65::61::64::20::74::68::65 +::20::61::6e::73::77::65::72::0a::62::79::20::73::61::76::69::6e::67::20 +::74::68::69::73::20::70::6f::73::74::20::61::73::20::61::20::66::69::6c +::65::20::28::72::65::6d::6f::76::69::6e::67::20::65::78::74::72::61::6e +::65::6f::75::73::20::6d::61::69::6c::2f::6e::65::77::73::67::72::6f::75 +::70::20::68::65::61::64::65::72::20::6c::69::6e::65::73::0a::61::74::20 +::74::68::65::20::74::6f::70::29::20::61::6e::64::20::72::75::6e::6e::69 +::6e::67::20::69::74::20::74::68::72::6f::75::67::68::20::70::6c::61::69 +::6e::20::54::65::58::2e::0a::0a::41::6e::73::77::65::72::20::74::6f::20 +::31::30::20::28::62::29::20::54::68::65::20::64::6f::75::62::6c::65::2d +::68::61::74::20::6e::6f::74::61::74::69::6f::6e::20::5e::5e::64::64::20 +::69::73::20::73::74::61::6e::64::61::72::64::20::66::6f::72::20::63::6f +::6d::70::6f::75::6e::64::0a::63::68::61::72::61::63::74::65::72::20::73 +::65::71::75::65::6e::63::65::73::2c::20::66::6f::6c::6c::6f::77::69::6e +::67::20::74::68::65::20::54::65::58::62::6f::6f::6b::2c::20::62::75::74 +::20::74::68::65::20::63::68::61::72::61::63::74::65::72::20::5e::20::69 +::73::20::73::6f::6d::65::74::69::6d::65::73::0a::6d::69::73::74::72::61 +::6e::73::6c::61::74::65::64::20::62::79::20::63::65::72::74::61::69::6e +::20::65::2d::6d::61::69::6c::20::67::61::74::65::77::61::79::73::2e::20 +::54::68::75::73::20::75::73::69::6e::67::20::63::61::74::65::67::6f::72 +::79::20::37::20::63::6f::6c::6f::6e::20::69::6e::73::74::65::61::64::0a +::6f::66::20::5e::20::6d::61::6b::65::73::20::74::68::65::20::65::6e::63 +::6f::64::65::64::20::74::65::78::74::20::6d::6f::72::65::20::63::6f::72 +::72::75::70::74::69::6f::6e::2d::72::65::73::69::73::74::61::6e::74::2e +::20::54::68::65::20::73::65::74::20::6f::66::20::63::68::61::72::61::63 +::74::65::72::73::0a::74::68::61::74::20::6d::75::73::74::20::62::65::20 +::70::72::6f::70::65::72::6c::79::20::74::72::61::6e::73::6d::69::74::74 +::65::64::20::69::6e::20::6f::72::64::65::72::20::66::6f::72::20::74::68 +::65::20::67::69::76::65::6e::20::64::65::63::6f::64::69::6e::67::20::74 +::6f::20::77::6f::72::6b::20::69::73::0a::0a::20::20::61::2d::7a::41::2d +::5a::30::2d::39::5c::22::7b::25::26: ::l::i::2f::27::7d::3b::20::20::20 +::0a::0a::28::62::75::74::20::66::65::77::65::72::20::63::68::61::72::61 +::63::74::65::72::73::20::77::6f::75::6c::64::20::62::65::20::6e::65::63 +::65::73::73::61::72::79::20::69::6e::20::74::68::65::20::61::62::73::65 +::6e::63::65::20::6f::66::20::6f::62::66::75::73::63::61::74::69::6f::6e +::29::2e::09::5c::6e::65::77::6c::69::6e::65::63::68::61::72::31::30::20 +::5c::69::6d::6d::65::64::69::61::74::65::5c::77::72::69::74::65::31::36 +::7b::5c::74::68::65::5c::74::6f::6b::73::31::7d::25::25::25::25::25::25 +::5c::62::61::74::63::68::6d::6f::64::65::5c::65::6e::64::0a::7d::6f::6e +\end{comment} + + +\section{Answers} + +%%\input{ans010} +% ans010.tex +\begin{comment} +Date: 13 Sep 1993 16:28:51 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #10, answer +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1993/09/13}. \arch{answer.010}.} + +Answer to 10(a). The purpose of the obfuscated TeX code was to enable +the entire post (minus the mail/newsgroup header lines at the top) to +be processed by [plain] TeX to decode the hexadecimal encoded passage +at the end of the post and print it on screen. The contents of that +passage were simply the answers to 10(a) and 10(b). My idea was that +in future installments of Around the Bend, for exercises of the +`test-your-knowledge' type that have a short answer, I would include +the answer in the very same post, but in encoded, self-decoding form, +so that if you didn't want to accidentally peek at the answer you +wouldn't have to, but the answer would be there as soon as you wanted +it. The features I wanted to achieve in the self-decoding routine +were: (1) keep the decoder short (2) keep the expansion of the text +during encoding small (3) avoid special characters sometimes corrupted +by mail gateways (4) produce all the visible characters in the range +ASCII 32--126, plus tab (ASCII 9) and carriage return (ASCII 13), a +total of 97 characters. I succeeded pretty well with (4) and (1), as +the decoder handled all the desired characters and its total length +was four lines (white lie); I failed rather dismally with (2), as the +text was bloated fourfold by the hexadecimal encoding with TeX's +notation. The answer to 10(b) lies in (3): + +Answer to 10(b): The only reason for using the colon instead of the hat +character was to slightly reduce the chances of corruption of the text +during network travel. + +Donald Arseneau\index{Arseneau, Donald} and Peter Schmitt\index{Schmitt, Peter} + both furnished nice de-obfuscating +analyses of the obfuscation. Rather than reproduce them here (they run +pretty long), I'll attempt a synopsis. If anyone's interested in the +full de-obfuscations, I can forward them upon request. + +Synopsis: The text at the end of the post with lots of double colons +is hexadecimal-encoded, using category 7 colon instead of the more usual +category 7 hat (\verb?^?) for TeX's special character notation. The goals are: + +(1) Skip over the clear text part at the top of the post. + +(2) Take the encoded text at the bottom of the post and write it on +screen. + +Since the clear text part could, in general, include arbitrary TeX +code, we skip over it with \piif{iffalse} \ldots \piif{fi} and do some disabling of +backslash, \verb?^^L?, and certain other things. (The closing \piif{fi} is written +with an alternate escape character, \verb?&?, instead of backslash, and a +more unusual name, \verb?&Answr?, is substituted, for reasons too complicated +to go into here.) + +Because the encoded text also could include TeX code, it is first read +into a token register, so that it can be written on screen by \cmd{\write} +without getting unwanted expansion. Catcodes of a few special +characters \verb?\ { } % ~? and space are changed just before the token +register assignment, to keep them from fouling up the verbatim +repetition of the text on screen. + +\begin{comment} +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +%$ +\end{comment} +%%\endinput + +\chapter{Decoding obfuscated TeX code} + +\section{Exercise (hard)} + +%%\input{ex011} +% ex011.tex +\begin{comment} +Date: 15 Sep 1993 16:34:45 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #11 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1993/09/15}. \arch{exercise.010}.} + +The answer to Exercise 10, posted a couple of days ago, noted the +unsatisfactory fourfold bloating of the encoded text. This leads to +Exercise 11, which is rather difficult (double-dangerous bend level). + +%%************************************************************************ +%%*** Exercise 11 (hard): +Write your own decoder to solve the problem I set for myself in +Exercise 10: Using as few lines of TeX code as possible, set up an +Around the Bend post containing a typical exercise so that it can be +processed by plain TeX to (a) skip over the exercise text and (b) +decode an embedded encoded answer. Come up with a better encoding idea +than my previous one, that doesn't increase the size of the text by +300\% during encoding. + +%%************************************************************************ + +Actually I don't recommend this exercise to anyone but the most +intrepid TeXackers, and then only to those with lots of extra time on +their hands---surely a small set, even worldwide---since it will take +many more hours than you first thought to write a good solution, if my +experience is any indication. Issuing the problem now as an exercise +is more to place it on record, since I'm working on it anyway, than to +instigate serious attempts at a solution by other people. + +The answer to Exercise 10 mentioned four design goals: (1) small +decoder (2) minimum expansion of text during encoding (3) avoidance of +special characters that tend to be corrupted by mailers or network +gateways (4) supported character set ASCII 9,13,32--126 in the text to +be encoded. + +However, in my ongoing efforts to wrassle with this problem, I have +since decided to drop ASCII 9 [tab] from (4), and to eliminate (3), +because it seems to be an independent issue: If mistranslated +characters are a problem for the reader then they are a problem for +the unencoded exercise text as well, and not just for the encoded +answer. So now I am assuming that the reader has in hand a reliable +copy of the posting with newlines and all visible ASCII 32---126 +accurately transmitted, and I am using basically a simple translation +table for the encoding and decoding (beware: oversimplification). + +Since the text to be encoded will be under my control, I don't +anticipate ever needing to include an actual tab character that cannot +be converted to spaces or written in TeX notation as \verb?^^I?. + +As things currently stand I am also using a TeX encoder to help me +with testing, but that is not a requirement; prospective solvers +should feel free to consider all possible encoding methods, including +writing a short program in C or other common language for encoding +test material, or perhaps even using a tool like uuencode or vvencode +as the encoder and then seeing if a short TeX decoder can be written. + +A summary of solutions, or more likely, `the' solution (mine), will be +posted December 31, 1993. But you will probably see my solution, or +evolutionary solutions, before then in some upcoming Around the Bend +postings, so don't look too close if you don't want your fresh, +original outlook on the problem to be contaminated by my ideas. + +If any readers do have difficulties with mistranslated characters in +Around the Bend postings, I would like to hear the details. For +checking, I give an ordered list of the ASCII characters 32--126 +below. + +%%Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%mjd@math.ams.org (Internet) +\begin{lcode} +ASCII 32--54,55--126: !"#$%&'()*+,-./0123456789 +:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +%$ +\end{lcode} +%%\endinput + +\section{Answers} + +%%\input{ans011} +% ans011.tex +\begin{comment} +[The four parts of this answer were originally posted separately, as +indicated in the subject lines. Addendum 1 is the full text of Donald +Arseneau's solution, which appeared in abridged form in part 3. Also +addendum 2, containing a companion TeX encoder for my decoder, was not +posted.] + +Date: 17 Aug 1994 16:24:12 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #11, solutions, part 1 of 4 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} +\ed{\oposted{1994/08/17} in four parts. \arch{answer.011}.} + +\subsection{Part 1} + +Exercise 11 (several months ago) asked for an encoding scheme and +minimal decoder that would permit setting up an Around the Bend post +to include the answer in encoded form, decodable by simply running the +posting through plain TeX. Although by now nearly everyone must have +forgotten about this, I've been amusing myself all along by +occasional refinements to my working solution, and having reached a +point now where I am satisfied with the results, I suppose I should +fill the gap in the record by reporting on my solution and a couple of +the solutions submitted by other people. + +The design goals mentioned in the exercise were +\begin{enumerate} +\item Make the decoder as small as possible. + +\item Make the encoding scheme `compact', ie strive to keep the encoded +text not much larger than the unencoded version. + +\item Allow ASCII 13,32--126 (at least) in the text to be encoded. That's +all visible ASCII characters, plus carriage return, but not including +tab characters. (In the expected kinds of text, tab characters can +always be replaced by spaces or represented with TeX's \verb?^^I? or +\verb?^^09? notation.) +\end{enumerate} + +My solution is demonstrated below. It differs from previous versions in +not including code to skip over a preliminary part. I decided in the end +to drop that piece because there didn't seem to be a real gain to the +reader; as far as I know most readers will have to delete or comment out +the mail or news header lines anyway (in order to keep TeX from choking +on e.g. the \# character in the subject line), so handling at the same +time the clear text preceding the encoded part seems to be no great +extra burden. (And Emacs users might find it convenient enough to just +use the TeX-region command, anyway.) + +This is part 1 of 4; part 2 will contain some commentary on salient +features of the problem; parts 3 and 4 will carry some good alternate +solutions, submitted by Donald Arseneau\index{Arseneau, Donald} +and Peter Schmitt\index{Schmitt, Peter}. + +\begin{lcode} +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + +%%%% Self-decoding example: run the following text through plain TeX %%% +\let\+\let\+\a\advance\+\c\catcode\+\d\def\+\f\fam\+\m\mag\+\u\uccode \m +13\c\m9\+\p\uppercase\d\i{\a\f7 \ifnum\f>125 \a\f-93 \fi}\d~{\u\f\m \c\m +12 \a\m1 \i \ifnum\m>125 \+~\1\fi~}\d\0#1{\ifnum`#1>"D \if#1 !\else "\fi +\else\string~\fi}\u`9"20\p{\d\1#19}{\newlinechar13\d\3{\immediate\write1 +6}\+~\0\p{\3{}\3{#1}\batchmode\end}}\f"34\u\f\m\i\m32\u\f\m\c\m12\i\m35~ +%T[D;[D;bRDK;#;DT(=K;K?DK$;?!1=n/K[!M;wn;D[M!#KR=?;p[!?D$;`T[1T;[!1pR8?4 +#pp;KT?;1T#=#1K?=D;[!;KT?;DR//(=K?8;D?K244Q[1T#?p;o(`!?D;PPPPPPPPPPPPPPP +PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP4wb8Sw#KT2#wD2(=M;e5!K?=!?Kl;Z +{h55;UN++c\$cc++GNj);~;~BBIPW^elsz$+29@GNU\cj4qx")07>ELSZahov}'.5<CJQX_f +mt{%,3:AHOV]dkry#*18?FMT[bipw!(/6=DKRY`gnu|&-~4 ")07>ELSZahov}'.5<CJQX_f +\end{lcode} + +\begin{comment} +Date: 17 Aug 1994 16:34:07 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #11, solutions, part 2 of 4 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +%Discussion of Around the Bend \#11; part 2. +\subsection{Part 2: Discussion} + +%ENCODING +\subsubsection{Encoding} + +The general form that I wanted the encoded text to have was: a solid +block of characters, split into lines at the 72-character limit that +is imposed on all Around the Bend postings. Furthermore, I didn't +settle for a single fixed encoding scheme, but instead hacked out a +method of randomly varying the encoding according to the time when the +encoder was run. Thus each encoded posting gets a different cipher. +\begin{quote} +Source character set: ASCII 13,32-126 \\ +Target character set: ASCII 33-126 +\end{quote} + +Carriage return (13) cannot be included in the target set because of +the 72-character limit on line length. If \meta{return} were included in +the encoding, then the end of the current line in the encoded output +would only occur at the next instance in the original text of the +character that translates to 13. And depending on what that character +is, who knows how long the encoded line could be? Perhaps as long as +the entire text. + +Space (32) is not included in the target set for a subtler reason. If +spaces in the encoded text happen to fall at the end of a line, they +will be dropped by TeX during the decoding process, instead of +decoded. So we either must exclude them from the target set, or make +sure that they never fall at the end of a line. + +By excluding space from the target set, we make it possible for the +decoder to use a space as its argument delimiter. If we have only one +space, at the end of the encoded text, it is not so hard to ensure +that it does not fall at the end of a line. But note that the decoder +must make sure to change the catcode of space to something other than +10, so that it will not disappear if it falls at the *beginning* of a +line. + +Note that the target set 33--126 is smaller than the source set +13,32--126. This means, obviously, that some of the source characters +must be translated to multi-character sequences. + +Given that \verb?~? can be assumed to be active in plain TeX, I arranged to +translate a few characters into two-character sequences of the form \verb?~X? +where potentially X is any character in the target set (including \verb?~?). +Then the decoding process can translate back by giving \verb?~? a suitable +definition. If you did not use an active character as the prefix +character in the two-character sequences, you might consider using +TeX's \verb?^^? notation to handle the extra characters in the source set. +Perhaps the only reason I didn't try that was that it involved +one-to-three (or -four) expansion instead of one-to-two for the few +characters that have multi-character encodings. + +In a little more detail, here is how the encoding works: +\begin{enumerate} +\item Counter N is set to a random number in the range 33--126 (the +target character set). Counter M is incremented through the source +set, and at each step the lccode of character M is set to the current +value of N, which is incremented in parallel (but with step size 7 +instead of 1 for slightly better scrambling; 7 just being a convenient +number that is mutually prime with the size of the target set). Then +\begin{lcode} + \lowercase{\immediate\write\outfile{...}} +\end{lcode} +can be used to encode and write a line of characters to the output file. + +When counter N reaches 125, it is wrapped around to 33. Character 126 +(\verb?~?) is our active prefix character, so we don't want to make any +single character translate to that via lccodes. + +\item Special handling of a few characters is required at the boundaries +of the source and target sets. Let I = the initial value of N. Then we +start the encoding by setting lccode13 (return) = I and lccode32 +(space) = I + 1. Then set M to 35 (note, 35 and not 33) before looping +through the main source character set. + +\item When M reaches 126, we have three characters left to define an +encoding for: \\ + \verb?126 ~, 33 !, 34 "?. \\ +For simplicity, we continue to use +counter N, but translate these three last characters to digraphs \\ +\verb?~[N] ~[N+7] ~[N+14]?, \\ + where \verb?[N]? means character N. + +\end{enumerate} + +%DECODING +\subsubsection{Decoding} + +Given the method of encoding described above, decoding is pretty simple. +We just have to set up a suitable uccode table, and apply it. For a few +characters we have to make a suitable definition for \verb?~? so that +\verb?~x, ~y, ~z? (where x y z are random) will be translated back to +\verb?~ ! "?. Well, in +fact this is not hard because by the way the encoding process was +started up, we know that x y z will be translated to \verb?^^M?, space, and \# +by the uppercasing, so we merely have to define \verb?~^^M? to produce +\verb?~?, +\verb?~space? to produce \verb?!?, and \verb?~#? to produce \verb?"?. +(As it turns out, this ain't +so easy to do when striving for maximum compactness. My final version +for this cost me no little work.) + +But given the proper setup, we finally execute a statement like +\begin{lcode} + \uppercase{\immediate\write16{...ENCODED TEXT...}}\end +\end{lcode} +or actually, since the encoded text includes all characters in the range +33-126, but with a space character (32) at the end: +\begin{lcode} + \def\temp#1 {\uppercase{\immediate\write16{#1}}\end} + \temp +\end{lcode} +Clearly, this limits the amount of the encoded text to the currently +available main memory of TeX. This is no real drawback for the limited +application for which this decoder was written: encrypted answers to +Around the Bend exercises. Donald Arseneau mentions in his solution +(part 3, to follow) the idea of decoding line by line. This would not be +too difficult, but would probably slightly increase the length of the +decoder (maybe making it impossible for me to keep my own version of the +decoder stuffed into the current five lines). + +\begin{comment} +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +%$ +Date: 18 Aug 1994 15:37:41 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #11, solutions, part 3 of 4 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\subsection{Part 3} + +Some selections from Donald Arseneau's\index{Arseneau, Donald} solution and commentary. The +entire solution is rather long so I won't post it in full; request it +from Donald or me if you're interested. + +%%======================================================================== +%%Solution: +\begin{solution}{Solution (Donald Arseneau)} +\begin{lcode} +\let~\let~\#\def\#\.{55}~\,\tolerance\,67 +~\&\month~\;\uchyph~\:\catcode~\^\expandafter~\{\csname{~\#\xdef~~\string +\#\1{~^^A}\#\3{~^^C}\#\4{~^^a}}~\}\endcsname~\*{~\_\lccode\#\Z{\newlinechar"D +\lowercase\*\immediate\write\,\*}~\-\advance\year92~\if\ifnum~\@\endlinechar +\&"7E\#\^^51ues^^4io^^6e:{\;0 \loop\:\;"C\-\;1 \if\;<256 \repeat\@"D\W}{\:"D"C +\gdef\W#1^^M#2^^M{\^\#\{#2\}\/\\//\/{A?^^M,Zz\over}\#\X##1^^M{\^\if^^8\{##1\^% +\}\{#2\}\^\Y\else\^\X\fi}\X}}\#\Y{\;35\loop\_\,\;\if\;<\&\-\,\.\-\;1\if\,>\& +\-\,-\year\fi\repeat\:1'0\:3"2\:33'7\_"20`"\_`""20\@-1\Z} + +\Question: +*********************************************************************** +*** Exercise 11 (hard): +Write your own decoder to solve the problem I set for myself in +Exercise 10: Using as few lines of TeX code as possible, set up an +Around the Bend post containing a typical exercise so that it can be +processed by plain TeX to (a) skip over the exercise text and (b) +decode an embedded encoded answer. Come up with a better encoding idea +than my previous one, that doesn't increase the size of the text by +300% during encoding. +*********************************************************************** +U"N5"M5[ZIm~f!!0dU!!0dU")"656"Yk3j"kH"jZ53"I"WZ5~m"I#kf"$Ej"WI34gj +"XmI~~i"3Ij53H5m6x""]kEX!!0dU"$m46"Fk3j54#"FXkYFjm6"Ym"jk"3m46"5j"I +4iWIi"I46"I|k56"jZm"jmYFjIj5k4!!0dU"jk"3Fm46"YkXm"j5Ym"k4"5jx"")"lE +3j"Fk~53Zm6"5j"kHH"jk6Iix!!0dU!!0dU"KZIj")"WkE~6"~5Gm"jk"6k"53,!!0d +U""A"YIGm"jZm"6m[k654#"YI[Xk3"3ZkXjmX"B4kjm"jZIj"54"Yi"HkXYIjf"I~~" +jZm!!0dU""""YI[Xk[k6m"FXm[m6m3"jZm"}Em3j5k4f"WZ5[Z"~kkG3"WkX3m"jZI4 +"ikEX"3k~Ej5k4xy!!0dU""A"93m"I[j5|m"[ZIXI[jmX3"XIjZmX"jZI4"J~kWmX[I +[...] +!!0d!!03!!03!!A{end!!A} +======================================================================== +\end{lcode} + + Commentary (Donald Arseneau): + + I did most of this a while ago, but wasn't really satisfied. Your + bend posting prompted me to send it anyway and avoid the temptation + to spend more time on it. I just polished it off today. + + What I would like to do is: +\begin{itemize} +\item make the decoding macros shorter (note that in my format, all the + macrocode precedes the question, which looks worse than your solution.) +\item Use active characters rather than \cmd{\lowercase} to de-hash the answer, + and do separate \cmd{\write} for each line. That's to avoid memory + overflow. +\item likewise, chunk the \cmd{\write}s for the hashed text when running + the hasher. +\item \ldots +\end{itemize} +%=================================================================== + + This file should be clear! Only the hidden (hashed) text and + the macros to UNhash it should be obfuscated because they will + be given with the question. + +\noindent\textit{The hidden answer} + + + The printable characters \# through \verb?~? (35-126) are permuted + through a simple hashing with a chosen starting value and + multiplier. Non-printing characters are represented by their + hexadecimal codes in the form \verb?!!hh? (where h is a hex digit + [higit?]); the \verb?!? character will act like \verb?^? when the text is + decoded. I don't want spaces in the coded text, but I also + don't want to use \verb?!!20? because there are likely many spaces, so + space is represented by \verb?"? and \verb?"? is represented as \verb?!!20?. + There are three other special (reserved) characters besides the + exclamation point: \verb?^A?, \verb?^B?, \verb?^C? (ascii 1,2,3). + They are used as follows: +\begin{lcode} +% character use coded as +% --------- --------------- ------------- +% ! superscript \1 ( !!A1 ) +% (for hex codes) +% " space !!20 (trades with space) +% ^A escape (\) \2 ( !!A2 ) +% ^B opening ({) \3 ( !!A3 ) +% ^C closing (}) \4 ( !!A4 ) +\end{lcode} + + All other characters are represented by their permuted + printable character, or by their normal hexadecimal form: + \verb?!!15?, \verb?!!0a?, \verb?!!a4?, \verb?!!7f? etc. + + The original coding is done through active characters, with + all characters defined to produce their non-active coded text + (either hashed or hex). The decoding of hex (non-printing) + characters is automatic; the decoding of the special four is + done through simple definitions; the decoding of printable + characters is done by loading the de-hashed character values + into the \cmd{\lccode} and applying \cmd{\lowercase}. + + Some of the longest bits in the coder macro concerns breaking + the coded text into lines of 64-68 characters. If the first + character in a line (after breaking) is a period, or the first + two characters are \verb?--?, the first character is given in hex + representation in fear of maniacal mail gateways. The other + dangerous characters like \verb?^ ` \ ~? are not treated carefully + because they had to have been preserved for the macros to work + at all. + +\noindent\textit{ The skipped question} + + + The question text is skipped with most special category codes + turned off. The only funtioning input is \verb?^M? due to \cmd{\obeylines}. + The active \verb?^M? checks each line of input looking for the marker + text to end the question material. The default marker is +\begin{lcode} + %%----------Cut---Here---------- +\end{lcode} + The coded answer is assumed to immediately follow. + + +\noindent\textit{The coder} + + + \verb? [...] the coder routine [...]? \\ + asks for three file names: the \cmd{\QuestionFileName} should + contain the text of the question; the \cmd{\SolutionFileName} should + have the answer; The complete question/answer posting will be + written to \cmd{\OutputFileName}. (Run this file through plain TeX.) + +\ldots + + There are 92 characters that will be hashed (\verb?35=#? to \verb?126=~?). + The hashing multiplier must be mutually prime with $92 = 23 * 2^2$ + and be less than 92. The start value (seed) can be anything + in the range 35-126. + +\ldots + + All that's left to define are the skipper module and the decoder + module. They both are written into the posting to be execuded + by the receiver. They are compressed and obfuscated, but the + obfuscation is mostly just compression: using command symbols + like \verb?\,? for longer command words, and using built-in registers + instead of allocating registers. Some of the abbreviations and + the choices of register are meant to be confusing and/or silly. + Plain-text versions of the modules are given here, as well as + a glossary of the obfuscation. + + Here is the skipper module. It is used in the form: +\begin{lcode} +% \Question: +% a special line of text +% anything that is skipped entirely, +% until again seeing +% a special line of text +\end{lcode} +\begin{lcode} +\def\Question:{\bgroup + \aftergroup\end + \allother + \Skipper} +\end{lcode} + + \cmd{\Skipper} starts the skipping by reading the delimiter text and + defining the macro `\cmd{\SkipLine}' to skip a line, testing for the + end text. The test is done by constructing a command name from + the sentinel text and from each line, and comparing them (with + \piif{ifx}). +\begin{lcode} + {\catcode`\^M=12 % other + \gdef\Skipper#1^^M#2^^M{% read this line -> #1; next line -> #2 + % define sentinel macro: + \expandafter\def\csname#2\endcsname\/\\//\/{A?^^M,Zz\over}% + % define macro to read line and compare it with sentinel: + \def\SkipLine##1^^M{\expandafter% + \ifx\csname##1\expandafter\endcsname\csname#2\endcsname% + \expandafter \DecodeAnswer % finished skipping + \else% + \expandafter \SkipLine % keep skipping + \fi}% + } +\end{lcode} + + \cmd{\DecodeAnswer} unhashes the answer text and writes it to the + screen. The unprintable characters represented as \verb?!!hh? are left + as they are (i.e., possibly unprintable!) \texttt{Control-M} (\verb?!!0d?) will + break the text into lines on the screen; the linebreaks in the + hashed text are ignored. \cmd{\HS} is set to the seed value before + \cmd{\DecodeAnswer} is invoked. + +\end{solution} + +\begin{comment} +Date: 18 Aug 1994 15:38:30 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #11, solutions, part 4 of 4 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +Here is Peter Schmitt's solution to Around the Bend \#11. + +\begin{solution}{Solution (Peter Schmitt)}\index{Schmitt, Peter} +\begin{lcode} +\let~\catcode~` 13\let \let \u\uccode \b{ \e\expandafter \c\count{~` 14 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\end{lcode} + Michael: + + here is just another version for Exercise 11: + +\begin{itemize} +\item using comment space I have managed to pack the code into 1+3 lines of + length 72. +\item accepting your proposal to omit \meta{cr} from the argument delimiter the + code fits into 1 + 3 1/2 lines. +\end{itemize} + Maybe, that still a few characters can be saved, but I expect that a + major gain can (if at all) only be achieved by a different coding method. + + best wishes, Peter + + P.S.: this is the second variant: + +\begin{lcode} + \let~\catcode~12 9~`^13~13 9\let^\def{^^#1__{\egroup}~`\\9~`{9~`}9 ^ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + text to be skipped + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + __~` 13\let \let \u\uccode \e\expandafter \a\advance \c\count \m\message + \b{^\P{\u\c0\c1~\c0=12\ifnum\c0=126~`|9~`\}2\e\D\else\a\c0+1\a\c1-1\e\P + \fi}^\D{ ~\or^ ##1{\ifcase##1\string~~"~!~{~}{\newlinechar`!\m{!}}\m{~}% + \e\end\fi}\uppercase\b\m\b}\c0`!\c1`}\P + + P.P.S.: I was lazy and have not prepared an updated version of the + coded text. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +} \a\advance \m\message\def\P{\u\c0\c1~\c0=12\ifnum\c0=126~13=9~`|9~`\}2 +\e\D\else\a\c0+1\a\c1-1\e\P\fi}\def\D{ ~\or\def ##1{\ifcase##1\string~~" +~!~{~}{\newlinechar`!\m{!}}\m{~}\e\end\fi}\uppercase\b\m\b}\c0`!\c1=`}\P + jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy j~~B;=| +*;/:9>B@@Rml j~~#B:98B.,9.=,9+35.#B;=*;/:9>BBml~B;=*;/:9>B#ml~B;=*;/:9>B!ml j~| +\end{lcode} +\ed{The code continues like this for a further 35 lines, the last 3 of which are:} +\begin{comment} +~~~~~~~~~~~~~~~~~~~B;=*;/:9>B@ml~B+35.! j~~B;=*;/:9>B@@QmlB:98B+35.{m@@Q??#B97| +,/).!B.,9.=,9+35. jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +yyyyyyyyyy j+35..9:~*9&*~d~+35..507~5+~+*/..9:~<%~*'/~;/0+9;)*5(9~+)<+;,5.* j~| +~~~~~~~~~~~~~~;6=,=;*9,+~=*~*69~<97500507~/8~=~2509~d~?? j90;/:9:~*9&*~d~1)+*~| +90:~/0~/09~,576*~<,=;9~d~! jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +yyyyyyyyyyyyyyyyyyy jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +yyyyyyyyyyyyyyyyyy jyyy~*69~:9;/:507~1=;,/+ jyyy~*69~=;*)=2~1=;,/+~=,9~+2576*2| +%~1/,9~;/1.25;=*9:~*/~=22/'~+6/,*9,~;/:9 jyyy~*69~*9&*~*/~90;/:9~1)+*~90:~/0~8| +/,1899:~v]K[UU~mlu jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +yyyyyyyyyyyyyyyyy jB:98B.,9.=,9#B);;/:9~B;/)0*n~B;/)0*m j~~~~~~~~~~~~~B;=*;/:9| +~B;/)0*n~ml j~~~~~~~~~~~~~B580)1~B;/)0*n~a~mlh j~~~~~~~~~~~~~B;=*;/:9~>B@@Q~e j +~~~~~~~~~~~~~B;=*;/:9~>B"~e j~~~~~~~~~~~~~B;=*;/:9~>B!~l j~~~~~~~~~~~~~~~~~~~~| +B9&.=0:=8*9,B:9;/:9 j~~~~~~~~~~~~~~B92+9~B=:(=0;9~B;/)0*~n~<%~~m j~~~~~~~~~~~~| +~~~~~~~~B=:(=0;9~B;/)0*~m~<%~qm j~~~~~~~~~~~~~~~~~~~~B9&.=0:=8*9,B.,9.=,9 j~~~| +~~~~~~~~~~~~B85! jB:98B:9;/:9#B;=*;/:9>B~B=;*5(9B)..9,;=+9B<7,/).B19++=79B<7,/| +).! jB;/)0*nakl jB;/)0*mamlh jB:98B02##B09'2509;6=,> lB19++=79# l!!B19++=79! j| +B:98 n{m#B58;=+9B+*,507{mB+*,507 nB/, mB/, lB/,#B/,!B02#B/,!B9&.=0:=8*9,B90:B8| +5!y jB.,9.=,9 jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +yyyyyy jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +yyyyy jyyy~*69~90;/:507~1=;,/+ jyyyyyyyyyyyyyyyyyyyyyyy jB5119:5=*9B/.90/)*naB| +4/<0=19p;:: j~~~~~~~~~~~~B;=*;/:9> mB=;*5(9 j~~~~~~~~~~~~B;=*;/:9> lB=;*5(9 jB| +:98B90;/:9~#B);;/:9>B n~a~B;/)0*n j~~~~~~~~~~~~~B);;/:9>B_~a~B;/)0*m j~~~~~~~~| +~~~~~B)..9,;=+9#B:98 n#B=::_m!B;=*;/:9>_B=;*5(9! j~~~~~~~~~~~~~B580)1~B;/)0*na| +mli j~~~~~~~~~~~~~~~~~~~~B:98~ m#B=::#~1!l! j~~~~~~~~~~~~~~~~~~~~B:98~ l#B=::#| +~2!l! j~~~~~~~~~~~~~~~~~~~~B;=*;/:9>~B=;*5(9 j~~~~~~~~~~~~~~~~~~~~B;/)0*nan~B:| +98B2509#! j~~~~~~~~~~~~~~B92+9~B=:(=0;9B;/)0*n~<%~~m j~~~~~~~~~~~~~~~~~~~~B=:(| +=0;9B;/)0*m~<%~qm j~~~~~~~~~~~~~~~~~~~~B9&.=0:=8*9,B90;/:9 j~~~~~~~~~~~~~~~~B8| +5 j~~~~~~~~~~~~~! jB:98B=::{m{l#B580)1~B;/)0*n~`~gf j~~~~~~~~~~~~~~~~~~~~B5119| +:5=*9B',5*9n#B2509! j~~~~~~~~~~~~~~~~~~~~~B:98B2509#{m!~~~~~~B;/)0*na{l j~~~~~| +~~~~~~~~~B92+9~B9:98B2509#B2509{m!~B=:(=0;9B;/)0*n<%{l j~~~~~~~~~~~~~~~B85 j~~| +~~~~~~~~~~~B580)1~B;/)0*n~a~gf~B=::"m~B85 j~~~~~~~~~~~~! jB:98~~ n#B=::#~0!l! j +B:98@@R#B=::#~5!lB5119:5=*9B',5*9n#B2509!B5119:5=*9B;2/+9/)*nB90:! j~~~~~~~~B;| +\end{comment} +\begin{lcode} +=*;/:9>B@@QB=;*5(9~y jB:98@@Q#B=::#~4!l!~~~~~~~~~~~y jB;/)0*nakl~B;/)0*mamlh~B| +90;/:9 jyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +yyyyy j i This is trash: Text not displayed!} More Trash that is not displayed! +\end{lcode} +\end{solution} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%[Addendum 1: Full text of Donald Arseneau's solution. To read the +%commentary you will need to run the text through TeX.] +\subsection{Addendum 1} + +Full text of Donald Arseneau's solution. To read the +commentary you will need to run the text through TeX. + +\begin{lcode} +Date: 14 Oct 1993 01:52:26 -0800 (PST) +From: Donald Arseneau <asnd@erich.triumf.ca> +Subject: Around the bends +To: mjd@MATH.AMS.ORG + +\let~\let~\#\def\#\.{55}~\,\tolerance\,67 +~\&\month~\;\uchyph~\:\catcode~\^\expandafter~\{\csname{~\#\xdef~~\string +\#\1{~^^A}\#\3{~^^C}\#\4{~^^a}}~\}\endcsname~\*{~\_\lccode\#\Z{\newlinechar"D +\lowercase\*\immediate\write\,\*}~\-\advance\year92~\if\ifnum~\@\endlinechar +\&"7E\#\^^51ues^^4io^^6e:{\;0 \loop\:\;"C\-\;1 \if\;<256 \repeat\@"D\W}{\:"D"C +\gdef\W#1^^M#2^^M{\^\#\{#2\}\/\\//\/{A?^^M,Zz\over}\#\X##1^^M{\^\if^^8\{##1\^% +\}\{#2\}\^\Y\else\^\X\fi}\X}}\#\Y{\;35\loop\_\,\;\if\;<\&\-\,\.\-\;1\if\,>\& +\-\,-\year\fi\repeat\:1'0\:3"2\:33'7\_"20`"\_`""20\@-1\Z} + +\Question: +*********************************************************************** +*** Exercise 11 (hard): +Write your own decoder to solve the problem I set for myself in +Exercise 10: Using as few lines of TeX code as possible, set up an +Around the Bend post containing a typical exercise so that it can be +processed by plain TeX to (a) skip over the exercise text and (b) +decode an embedded encoded answer. Come up with a better encoding idea +than my previous one, that doesn't increase the size of the text by +300% during encoding. +*********************************************************************** +U"N5"M5[ZIm~f!!0dU!!0dU")"656"Yk3j"kH"jZ53"I"WZ5~m"I#kf"$Ej"WI34gj +"XmI~~i"3Ij53H5m6x""]kEX!!0dU"$m46"Fk3j54#"FXkYFjm6"Ym"jk"3m46"5j"I +4iWIi"I46"I|k56"jZm"jmYFjIj5k4!!0dU"jk"3Fm46"YkXm"j5Ym"k4"5jx"")"lE +3j"Fk~53Zm6"5j"kHH"jk6Iix!!0dU!!0dU"KZIj")"WkE~6"~5Gm"jk"6k"53,!!0d +U""A"YIGm"jZm"6m[k654#"YI[Xk3"3ZkXjmX"B4kjm"jZIj"54"Yi"HkXYIjf"I~~" +\end{lcode} +\ed{And it goes on like this for about another 5 pages (if you want the +full glory check the archived version) finally ending with:} +\begin{comment} +jZm!!0dU""""YI[Xk[k6m"FXm[m6m3"jZm"}Em3j5k4f"WZ5[Z"~kkG3"WkX3m"jZI4 +"ikEX"3k~Ej5k4xy!!0dU""A"93m"I[j5|m"[ZIXI[jmX3"XIjZmX"jZI4"J~kWmX[I +3m"jk"6mAZI3Z"jZm"I43WmXf!!0dU""""I46"6k"3mFIXIjm"JWX5jm"HkX"mI[Z"~ +54mx""^ZIjg3"jk"I|k56"YmYkXi"k|mXH~kWx!!0dU""A"~5GmW53mf"[ZE4G"jZm" +JWX5jm"3"HkX"jZm"ZI3Zm6"jm2j"WZm4"XE4454#"jZm"ZI3ZmXx!!0dU!!0dU")"~ +5Gm"ikEX"YmjZk6"kH"[kE4j54#"jZm"3Fm[5I~"I[j5|m"[ZIXI[jmX"54"jZm!!0d +U"}Em3j5k4"jm2j!!A4!!A4!!0dU""""AA"*k4I~6!!0dUuuuuuuuuuuuuuuuuuuuuu +uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu!!0dU"^Z53"H5~m"3ZkE~ +6"$m"[~mIX!!A4""_4~i"jZm"Z566m4"BZI3Zm6y"jm2j"I46!!0dU"jZm"YI[Xk3"j +k"9(ZI3Z"5j"3ZkE~6"$m"k$HE3[Ijm6"$m[IE3m"jZmi"W5~~!!0dU"$m"#5|m4"W5 +jZ"jZm"}Em3j5k4x!!0dU!!0dU"^Zm"Z566m4"I43WmX!!0dU"AAAAAAAAAAAAAAAAA +!!0dU!!0dU"^Zm"FX54jI$~m"[ZIXI[jmX3"C"jZXkE#Z"h"Bw-Ae@dy"IXm"FmXYEj +m6!!0dU"jZXkE#Z"I"35YF~m"ZI3Z54#"W5jZ"I"[Zk3m4"3jIXj54#"|I~Em"I46 +!!0dU"YE~j5F~5mXx"(k4AFX54j54#"[ZIXI[jmX3"IXm"XmFXm3m4jm6"$i"jZm5X!!0d +U"Zm2I6m[5YI~"[k6m3"54"jZm"HkXY"!!A4!!A4ZZ"BWZmXm"Z"53"I"Zm2"65#5j +!!0dU"oZ5#5j+%yc"jZm"!!A4"[ZIXI[jmX"W5~~"I[j"~5Gm"\"WZm4"jZm"jm2j"5 +3!!0dU"6m[k6m6x"")"6k4gj"WI4j"3FI[m3"54"jZm"[k6m6"jm2jf"$Ej")"I~3k +!!0dU"6k4gj"WI4j"jk"E3m"!!A4!!A4@."$m[IE3m"jZmXm"IXm"~5Gm~i"YI4i"3FI +[m3f"3k!!0dU"3FI[m"53"XmFXm3m4jm6"$i"!!20"I46"!!20"53"XmFXm3m4jm6"I +3"!!A4!!A4@.x"^ZmXm!!0dU"IXm"jZXmm"kjZmX"3Fm[5I~"BXm3mX|m6y"[ZIXI[j +mX3"$m356m3"jZm!!0dU"m2[~IYIj5k4"Fk54j,"\=f"\tf"\O"BI3[55"ef@fwyx"" +^Zmi"IXm"E3m6"I3!!0dU"Hk~~kW3,!!0dU!!0dU"""""[ZIXI[jmX""""""E3m"""" +"""""""""""[k6m6"I3!!0dU"""""AAAAAAAAA"""AAAAAAAAAAAAAAA""""AAAAAAA +AAAAAA!!0dU"""""""""!!A4"""""""3EFmX3[X5Fj"""""""""Je""B"!!A4!!A4=e +"y!!0dU"""""""""""""""""BHkX"Zm2"[k6m3y!!0dU"""""""""!!20"""""""3FI +[m"""""""""""""""!!A4!!A4@."BjXI6m3"W5jZ"3FI[my!!0dU""""""""\=""""" +""m3[IFm"BJy""""""""""J@""B"!!A4!!A4=@"y!!0dU""""""""\t"""""""kFm45 +4#"B{y"""""""""Jw""B"!!A4!!A4=w"y!!0dU""""""""\O"""""""[~k354#"B1y" +""""""""JR""B"!!A4!!A4=R"y!!0dU!!0dU!!0dU"=~~"kjZmX"[ZIXI[jmX3"IXm" +XmFXm3m4jm6"$i"jZm5X"FmXYEjm6!!0dU"FX54jI$~m"[ZIXI[jmXf"kX"$i"jZm5X +"4kXYI~"Zm2I6m[5YI~"HkXY,!!0dU"!!A4!!A4e-f"!!A4!!A4.If"!!A4!!A4IRf" +!!A4!!A4?H"mj[x!!0dU!!0dU"^Zm"kX5#54I~"[k654#"53"6k4m"jZXkE#Z"I[j5| +m"[ZIXI[jmX3f"W5jZ!!0dU"I~~"[ZIXI[jmX3"6mH54m6"jk"FXk6E[m"jZm5X"4k4 +AI[j5|m"[k6m6"jm2j!!0dU"Bm5jZmX"ZI3Zm6"kX"Zm2yx""^Zm"6m[k654#"kH"Zm +2"B4k4AFX54j54#y!!0dU"[ZIXI[jmX3"53"IEjkYIj5[c"jZm"6m[k654#"kH"jZm" +3Fm[5I~"HkEX"53!!0dU"6k4m"jZXkE#Z"35YF~m"6mH545j5k43c"jZm"6m[k654#" +kH"FX54jI$~m!!0dU"[ZIXI[jmX3"53"6k4m"$i"~kI654#"jZm"6mAZI3Zm6"[ZIXI +[jmX"|I~Em3!!0dU"54jk"jZm"J~[[k6m"I46"IFF~i54#"J~kWmX[I3mx!!0dU!!0d +U"'kYm"kH"jZm"~k4#m3j"$5j3"54"jZm"[k6mX"YI[Xk"[k4[mX43"$XmIG54#!!0d +U"jZm"[k6m6"jm2j"54jk"~54m3"kH"dRAdv"[ZIXI[jmX3x"")H"jZm"H5X3j!!0dU +"[ZIXI[jmX"54"I"~54m"BIHjmX"$XmIG54#y"53"I"FmX5k6f"kX"jZm"H5X3j!!0d +U"jWk"[ZIXI[jmX3"IXm"AAf"jZm"H5X3j"[ZIXI[jmX"53"#5|m4"54"Zm2!!0dU"X +mFXm3m4jIj5k4"54"HmIX"kH"YI45I[I~"YI5~"#IjmWIi3x""^Zm"kjZmX!!0dU"6I +4#mXkE3"[ZIXI[jmX3"~5Gm"\"n"J"h"IXm"4kj"jXmIjm6"[IXmHE~~i!!0dU"$m[I +E3m"jZmi"ZI6"jk"ZI|m"$mm4"FXm3mX|m6"HkX"jZm"YI[Xk3"jk"WkXG!!0dU"Ij" +I~~x!!0dU!!0dU"^Zm"3G5FFm6"}Em3j5k4!!0dU"AAAAAAAAAAAAAAAAAAAA!!0dU +!!0dU"^Zm"}Em3j5k4"jm2j"53"3G5FFm6"W5jZ"Yk3j"3Fm[5I~"[Ijm#kXi"[k6m3 +!!0dU"jEX4m6"kHHx""^Zm"k4~i"HE4j5k454#"54FEj"53"\M"6Em"jk"Jk$mi~54m3 +x!!0dU"^Zm"I[j5|m"\M"[Zm[G3"mI[Z"~54m"kH"54FEj"~kkG54#"HkX"jZm"YIXG +mX!!0dU"jm2j"jk"m46"jZm"}Em3j5k4"YIjmX5I~x""^Zm"6mHIE~j"YIXGmX"53 +!!0dU"UUAAAAAAAAAAOEjAAANmXmAAAAAAAAAA!!0dU"^Zm"[k6m6"I43WmX"53"I33EY +m6"jk"5YYm65Ijm~i"Hk~~kWx!!0dU!!0dU!!0dU"^Zm"[k6mX!!0dU"AAAAAAAAA +!!0dU!!0dU"NmXm"53"jZm"[k6mX"XkEj54mx"")j"53"3EFFk3m6"jk"$m"[~mIXx"") +j!!0dU"I3G3"HkX"jZXmm"H5~m"4IYm3,""jZm"JqEm3j5k4<5~m(IYm"3ZkE~6!!0d +U"[k4jI54"jZm"jm2j"kH"jZm"}Em3j5k4c""jZm"J'k~Ej5k4<5~m(IYm"3ZkE~6 +!!0dU"ZI|m"jZm"I43WmXc""^Zm"[kYF~mjm"}Em3j5k4SI43WmX"Fk3j54#"W5~~"$m +!!0dU"WX5jjm4"jk"J_EjFEj<5~m(IYmx""BLE4"jZ53"H5~m"jZXkE#Z"F~I54"^m&x +y!!0d!!0dJ4mWXmI6Jq<5~m!!0dJ4mWXmI6J'<5~m!!0dJ4mWWX5jmJ_<5~m!!0d!!0d +J4mW~54m[ZIXunT!!0dJYm33I#m{TKZIj"H5~m"[k4jI543"jZm"}Em3j5k4+1!!0d +JXmI6ed"jk"JqEm3j5k4<5~m(IYm!!0dJkFm454Jq<5~muJqEm3j5k4<5~m(IYm!!0d +!!0dJYm33I#m{KZIj"H5~m"[k4jI543"jZm"3k~Ej5k4+1!!0dJXmI6ed"jk"J'k~Ej +5k4<5~m(IYm!!0dJkFm454J'<5~muJ'k~Ej5k4<5~m(IYm!!0d!!0dJYm33I#m{KZIj +"3ZkE~6"jZm"[kYF~mjm"Fk3j54#"$m"WX5jjm4"jk+1!!0dJXmI6ed"jk"J_EjFEj< +5~m(IYm!!0dJ5YYm65IjmJkFm4kEjJ_<5~muJ_EjFEj<5~m(IYm!!0d!!0dJ4mW5HJ5 +H_;!!0d!!0dU"^ZmXm"IXm"Q@"[ZIXI[jmX3"jZIj"W5~~"$m"ZI3Zm6"Bw-uC"jk"e +@duhyx!!0dU"^Zm"ZI3Z54#"YE~j5F~5mX"YE3j"$m"YEjEI~~i"FX5Ym"W5jZ"Q@"u +"@w"T"@\@!!0dU"I46"$m"~m33"jZI4"Q@x""^Zm"3jIXj"|I~Em"B3mm6y"[I4"$m" +I4ijZ54#!!0dU"54"jZm"XI4#m"w-Ae@dx!!0d!!0dJ4mW[kE4jJNM!!0dJ4mW[kE4j +JjmYF!!0dJ[ZIX6mHJjkF["nJh"U"Z5#m3j"ZI3Zm6"[ZIXI[jmX"Be@dy!!0dJ[ZIX +6mHJ$kj["nJC"U"~kWm3j"ZI3Zm6"[ZIXI[jmX"Bw-y!!0dJ4mW[kE4jJXI4#m!!0dJ +XI4#muJjkF["JI6|I4[mJXI4#mAJ$kj["JI6|I4[mJXI4#m"e"U"Q@!!0d!!0dJ6mHJ +L{JXmI6ed"jk"JNI3ZME~j5F~5mX"JNMuJNI3ZME~j5F~5mXJXm~I2!!0d""J_;jXEm +!!0d""J5H4EYJNMPJXI4#m"J_;HI~3mJH5!!0d""J5H4EYJNM">w"J_;HI~3mJH5!!0d +""JjmYFuJNM"J65|56mJjmYF"@w"JYE~j5F~iJjmYF"@w!!0d""J5H4EYJjmYFuJNM +"J_;HI~3m"JH5"U"[Zm[G"[kYYk4"HI[jkX"kH"@w!!0d""JjmYFuJNM"J65|56mJjm +YF"@"JYE~j5F~iJjmYF"@!!0d""J5H4EYJjmYFuJNM"J_;HI~3m"JH5"U"[Zm[G"[kY +Yk4"HI[jkX"kH"@!!0d""J5H_;"Jm~3m"U"HI5~m6xxxXmFXkYFj!!0d"""""JYm33I +#m{:~mI3m"m4jmX"I"4EY$mX"54"jZm"XI4#m"w"A"Q@!!0d""""""""jZIj"53"4kj +"I"YE~j5F~m"kH"@"kX"@wx1JL!!0d""JH51!!0dJL!!0d!!0dJ4mW[kE4jJN'!!0dJ +6mHJL{JXmI6ed"jk"JNI3Z'mm6"JN'uJNI3Z'mm6JXm~I2!!0d""J_;jXEm!!0d""J5 +H4EYJN'"PJjkF["J_;HI~3mJH5!!0d""J5H4EYJN'">J$kj["J_;HI~3mJH5!!0d""J +5H_;"Jm~3m"U"HI5~m6xxxXmFXkYFj!!0d"""JYm33I#m{:~mI3m"m4jmX"I"4EY$mX +"54"jZm"XI4#m!!0d"""""""""J4EY$mXJ$kj[J3FI[m"A"J4EY$mXJjkF[x1JL!!0d +""JH51!!0dJL!!0d!!0dU"(kW"Wm"W5~~"XmI6"jZm"3mFIXIjkX"jm2j"jXmIj54#" +3Fm[5I~"[ZIXI[jmX3!!0dU"I3"kX654IXi"k4m3x""(mm6"jk"6k"jZm"[kYYI463" +54"YI[Xk3"3k"[Ij[k6m!!0dU"[ZI4#m3"6k4gj"ZEXj"jZm"[kYYI463")"WI4j"jk +"6k!!A4!!0d!!0dJ$m#54#XkEF!!0d""Jm3[IFm[ZIXuAeJ26mHJ'mF!!0d""{J3jX5 +4#JUJ3jX54#JUAAAAAAAAAAJ3jX54#JOEjAAAJ3jX54#JNmXmAAAAAAAAAA1!!0d""J +6mHJ6kCe{J[Ij[k6mnCeue@"1!!0d""J6mHJL{{J6k3Fm[5I~3Jm46~54m[ZIXuAe +!!0d""JYm33I#m{^Zm"3mFIXIj5k4"jm2j"53,"nJ'mFgx"1U!!0d""JYm33I#m{a4jmX +"I"XmF~I[mYm4j"kX"lE3j"FXm33"LmjEX4,"T1U!!0d""JXmI6Ae"jk"JjmYF!!0d" +"J5H2JjmYFJmYFji"Jm~3m""J26mHJ'mF{JjmYF1JH511!!0d""JL!!0dJm46#XkEF +!!0d!!0dU"B[Ijm#kX5m3"$I[G"jk"4kXYI~y!!0dU!!0dU"(kW"Wm"IXm"XmI6i"jk" +XmI6"jZm"}Em3j5k4"I46"I43WmXf"I46"WX5jm"jZm!!0dU"kEjFEjx""'54[m"I~~ +"jZ53"53"6k4m"W5jZ"I~~"[ZIXI[jmX3"$m54#!!0dU"nkjZmXgf"6mH54m"YI[Xk3 +"jk"6k"I~~"jZm"FXk[m3354#"$mHkXm"[ZI4#54#!!0dU"I~~"jZm"[Ij[k6m3x!!0d +!!0dJ4mW[kE4jJON!!0d!!0dU"(kjm,"^Z53"YI[Xk"W5~~"I~3k"$m"WX5jjm4"54 +"3ZkXj"HkXY"W5jZ"jZm!!0dU"I43WmX"6m[k6mXx!!0d!!0dJ6mHJI~~kjZmX{JONu +."U"3mj"I~~"[Ij[k6m3"u"nkjZmXg!!0d"J~kkF!!0d"""J[Ij[k6mJONue@!!0dU" +"J~[[k6mJONuJON""U"k4~i"E3m6"HkX"6m[k6mX!!0d"""JI6|I4[mJON"$i"e!!0d +"""J5H4EYJON>@-d!!0d"JXmFmIj!!0d"Jm46~54m[ZIXuew"U"\M!!0d1!!0d!!0dU +"Km"W5~~"4mm6"jk"[kFi"~54m3"HXkY"jZm"}Em3j5k4"H5~m"I46"WX5jm"jZmY +!!0dU"jk"jZm"kEjFEj"H5~m"|mX$Ij5Yx!!0d!!0dJ6mHJOkFiqEm3j5k4{Jm46~54m[ +ZIXAe"J4mW~54m[ZIXAe"JOq1!!0d!!0dJ6mHJOq{U"U"jZ53"#5|m3"mXXkX"k4"4E +~~"54FEj"H5~mx"")j"3ZkE~6!!A4!!0d"JXmI6Jq<5~m"jkJ~54m"U"|mX$Ij5Y"3Z +kE~6"$m"k4"Ij"jZm"YkYm4j!!A4!!0d"J5HmkHJq<5~m"J5YYm65IjmJ[~k3m54Jq< +5~m!!0d"Jm~3m"J5YYm65IjmJWX5jm"J_<5~m"{J~54m1Jm2FI46IHjmX"JOq!!0d"J +H51!!0d!!0d!!0dU"^Z53"YI[Xk"YIGm3"I~~"[ZIXI[jmX3"I[j5|mf"I46"6mH54m +3"jZmY"I3"jZm5X!!0dU"Zm2"[k6m3,"!!A4!!A4ZZx!!0d!!0dJ6mHJ=~~=[jNm2{J +6mHJZm2ON{..1U!!0d""J~kkF!!0d""""J[Ij[k6m!!20JZm2ONuJI[j5|m!!0d"""" +Jm6mHJZm2[Z{J~kWmX[I3m{Jm6mHJ4km2FI46JZm2[Z{JZm2ON111JZm2[Z!!0d"""" +J(EYmX5[I~~iJm6mH{!!20JZm2ON1{!!A4!!A4JZm2[Z1U!!0d""""J5H4EY!!20JZm +2ON>!!20<<!!0d""""""Jm6mHJZm2ON{Jm2FI46IHjmXJ3jmFZm2JZm2ON1U!!0d""J +XmFmIj1!!0d!!0dJ6mHJ(EYmX5[I~~iCeC@{J~[[k6mnJhC@JXm~I2"J~kWmX[I3m{C +eh11!!0d!!0dJ6mHJ3jmFZm2CeC@{J5H[I3m!!20C@"CeeJkX"Ce@JkX"CewJkX"CeR +JkX"Ce-JkX"CedJkX!!0d""Ce?JkX"CevJkX"CeQJkX"Ce=JkX"CetJkX"CeOJkX"Ce +*JkX"CeaJkX"Ce<JkX!!0d"""J5H[I3m!!20Ce"eJkX"@JkX"wJkX"RJkX"-JkX"dJk +X"?JkX"vJkX"QJkX!!0d""""""""=JkX"tJkX"OJkX"*JkX"aJkX"<JkX"e.JH5".JH +51!!0d!!0dU"^Z53"YI[Xk"k|mXX56m3"jZm"!!A4!!A4ZZ"4kjIj5k4"HkX"FX54jI +$~m"[ZIXI[jmX3f!!0dU"I46"6mH54m3"jZmY"I3"jZm5X"ZI3Zm6"[kE4jmXFIXj3x +""JON"53"jZm!!0dU"F~I54Ajm2j"[ZIXI[jmX"4EY$mXf"JjmYF"53"5j3"[k6m6"[ +ZIXI[jmXx!!0d!!0dJ6mHJ(kXYNI3Z{JjmYFuJN'"U"3mm6"|I~Em!!0d""JONuJ$kj +[!!0d""J~kkF!!0d""""J~[[k6mnJhuJON"J~[[k6mnJvuJjmYF!!0d""""J~kWmX[I +3m{Jm6mHh{v11U!!0d""""J5H4EYJON>JjkF[!!0d""""""JI6|I4[m"JjmYF"JNM"" +U"I66"YE~j5F~5mX"jk"ZI3Z"|I~Emf""E354#xxx!!0d""""""J5H4EY"JjmYFPJjk +F["JI6|I4[mJjmYFAJXI4#m"JH5"U"Yk6E~k"IX5jZYmj5[!!0d""""""JI6|I4[mJO +N"e!!0d""JXmFmIj1!!0d!!0dU"(kWf"Wm"6mH54m"jZm"352"m2[mFj5k4"[ZIXI[j +mX3!!0d!!0dJ6mHJa2[mFj{U!!0d""J(EYmX5[I~~iJ6mH{e1{!!A4!!A4=e1U!!0d" +"J(EYmX5[I~~iJ6mH{@1{!!A4!!A4=@1U!!0d""J(EYmX5[I~~iJ6mH{w1{!!A4!!A4 +=w1U!!0d""J(EYmX5[I~~iJ6mH{n!!A41{!!A4!!A4=R1U!!0d""J(EYmX5[I~~iJ6m +H{nJ"1{!!201U!!0d""J(EYmX5[I~~iJ6mH{nJ!!201{!!A4!!A4@.1U!!0d1!!0d +!!0d!!0dU"OkFi"jZm"3k~Ej5k4"HXkY"jZm"3k~Ej5k4"H5~mf"FmXHkXY"jZm"jXI43 +HkXYIj5k43!!0dU"BE354#"Jm6mHyf"I46"WX5jm"kEj"54"IFFXk2x"dRA[ZIXI[jm +X"~54m3x""^Zm"WZk~m!!0dU"3k~Ej5k4"YE3j"H5j"54"YmYkXi"$m[IE3m")"6k4g +j"WI4j"jk"GmmF"[kE4j54#"jZm!!0dU"[ZIXI[jmX3"I46"kEjFEjj54#"jZmY"I"H +mW"Ij"I"j5Ymx"")"6k4gj"3I|m"jZm"WZk~m!!0dU"Ym33"54"k4m"YI[Xk"jZkE#Z +f"$m[IE3m"I6654#"jk"I"~k4#"~53j"#mj3"|mXi"3~kWx!!0d!!0dJ6mHJN56m'k~ +Ej5k4{J6mHJ=~~{1JjmYFue"J4mW~54m[ZIXuew"Jm46~54m[ZIXew!!0d""J~mjJ +!!A4JXm~I2"JN561!!0d!!0dJ6mHJN56{U"U!!0d"JXmI6J'<5~m"jkJ~54m!!0d"J5Hm +kHJ'<5~m!!0d"""J5YYm65IjmJ[~k3m54J'<5~m"Jm2FI46IHjmX"JKX5jm'F~5j!!0d +"Jm~3m!!0d"""Jm6mHJ=~~{J=~~"J!!A4{J4EY$mXJjmYF11U!!0d"""Jm2FI46IHj +mXJm6mHJ[34IYm"rJ4EY$mXJjmYFJm46[34IYm{J~54m1U!!0d"""JI6|I4[mJjmYF" +eJXm~I2!!0d"""Jm2FI46IHjmX"JN56!!0d"JH51!!0d!!0dU"^Zm"4m2j"YI[Xk3"I +Xm"E3m6"jk"3F~5j"I"~53j"kH"[k6m"[ZIXI[jmX3!!0dU"54jk"I$kEj"dR"[ZIXI +[jmX3,""jZm"H5X3j"hdR"54"I"YI[Xk"BCey"IXm!!0dU"WX5jjm4"jk"jZm"kEjFE +j"H5~m"I46"jZm"XmYI546mX"IXm"~mHj"54"jZm!!0dU"YI[Xkx""^Zm"3F~5j"W5~ +~"4kj"54jmXXEFj"I4i"!!A4!!A4ZZ"3m}Em4[m3"BkX!!0dU"jZm"3Fm[5I~"!!A4 +!!A4=w"3m}Em4[m3yx!!0d!!0dJ$m#54#XkEF!!0dJ[Ij[k6mewue@""U!!0dJ#6mHJ[ +jX~Y{\\M1U!!0dJm46#XkEF!!0d!!0dJ6mHJKX5jm'F~5j{U!!0d""J6mHJ!!A4CCe{ +J[34IYm"rCCeJm46[34IYm1U!!0d""Jm6mHJ=~~{J=~~""U"m2FI46"jk"XmI~"[ZIX +I[jmX3!!0d""""!!A4!!A4.w!!A4!!A4.w!!A4!!A4=J3jX54#{m46!!A4!!A4=J3jX +54#11U"I66"jmXY54Ij5k4"[k6m3,!!0d""J6mHJx{1U""""""""""""""""""""""" +""""U""11J[34IYm"m46Jm46[34IYm!!0d""J4mW~54m[ZIXuew"U"\M!!0d""Jm6mH +J=~~{Jm2FI46IHjmXJK'J=~~"JxJxJxJxJxJxJxJxJxJxJm461!!0d""J5YYm65IjmJ +WX5jmJ_<5~m{J=~~1U!!0d""J5YYm65IjmJ[~k3mkEjJ_<5~m!!0d1!!0d!!0dJ6mHJ +K'{JfJfJfJfJfJfJfJfJOEjJXm~I21U"FI33"k|mX"v"T"v"u"dR"[ZIX!!0d!!0dJ6 +mHJfCeJXm~I2"C@CwCRC-CdC?CvCQ{C@CwCRC-CdC?CvCQU"FI33"v"[ZIX!!0d""J5 +H2CQJxJm2FI46IHjmXJm46m6mHJH5CeJXm~I21!!0d!!0dJ6mHJOEjJXm~I2CeC@Cw{ +U")43mXj"~54mHmm6"[ZIXI[jmXf!!0d""J5H2Ce!!A4U"""""""""""U"$Ej"6k4gj +"54jmXXEFj"I4i"!!A4!!A4ZZ!!0d""""J5H2C@!!A4J[jX~Y"CeC@CwJm~3m"CeC@C +wJ[jX~Y"JH5!!0d""Jm~3m!!0d""""J5H2C@!!A4CeJ[jX~YC@CwJm~3m"CeC@J[jX~ +YCwJH5!!0d""JH5"JK'1!!0d!!0dJ6mHJm46m6mHCeJm46{1U"m46"kH"jm2jf"3k"m +46"Jm6mH"I46"#k$$~m"XmYI5454#"lE4G!!0d!!0dU"=~~"jZIjg3"~mHj"jk"6mH5 +4m"IXm"jZm"3G5FFmX"Yk6E~m"I46"jZm"6m[k6mX!!0dU"Yk6E~mx""^Zmi"$kjZ"I +Xm"WX5jjm4"54jk"jZm"Fk3j54#"jk"$m"m2m[E6m6!!0dU"$i"jZm"Xm[m5|mXx""^ +Zmi"IXm"[kYFXm33m6"I46"k$HE3[Ijm6f"$Ej"jZm!!0dU"k$HE3[Ij5k4"53"Yk3j +~i"lE3j"[kYFXm335k4,"E354#"[kYYI46"3iY$k~3!!0dU"~5Gm"Jf"HkX"~k4#mX" +[kYYI46"WkX63f"I46"E354#"$E5~jA54"Xm#53jmX3!!0dU"543jmI6"kH"I~~k[Ij +54#"Xm#53jmX3x""'kYm"kH"jZm"I$$Xm|5Ij5k43"I46!!0dU"jZm"[Zk5[m3"kH"X +m#53jmX"IXm"YmI4j"jk"$m"[k4HE354#"I46SkX"35~~ix!!0dU":~I54Ajm2j"|mX +35k43"kH"jZm"Yk6E~m3"IXm"#5|m4"ZmXmf"I3"Wm~~"I3!!0dU"I"#~k33IXi"kH" +jZm"k$HE3[Ij5k4x!!0dU!!0dU"NmXm"53"jZm"3G5FFmX"Yk6E~mx"")j"53"E3m6" +54"jZm"HkXY,!!0dU"JqEm3j5k4,!!0dU"I"3Fm[5I~"~54m"kH"jm2j!!0dU"I4ijZ +54#"jZIj"53"3G5FFm6"m4j5Xm~if!!0dU"E4j5~"I#I54"3mm54#!!0dU"I"3Fm[5I +~"~54m"kH"jm2j!!0dU!!0dU"J6mHJqEm3j5k4,{J$#XkEF!!0dU"""JIHjmX#XkEFJ +m46!!0dU"""JI~~kjZmX!!0dU"""J'G5FFmX1!!0dU!!0dU"J'G5FFmX"3jIXj3"jZm +"3G5FF54#"$i"XmI654#"jZm"6m~5Y5jmX"jm2j"I46!!0dU"6mH5454#"jZm"YI[Xk +"nJ'G5Fr54mg"jk"3G5F"I"~54mf"jm3j54#"HkX"jZm!!0dU"m46"jm2jx""^Zm"jm +3j"53"6k4m"$i"[k43jXE[j54#"I"[kYYI46"4IYm"HXkY!!0dU"jZm"3m4j54m~"jm +2j"I46"HXkY"mI[Z"~54mf"I46"[kYFIX54#"jZmY"BW5jZ!!0dU"J5H2yx!!0dU!!0d +U"{J[Ij[k6mnJ\\Mue@"U"kjZmX!!0dU"J#6mHJ'G5FFmXCe\\MC@\\M{U"XmI6"jZ +53"~54m"AP"Cec"4m2j"~54m"AP"C@!!0dU"U""6mH54m"3m4j54m~"YI[Xk,!!0dU" +""Jm2FI46IHjmXJ6mHJ[34IYmC@Jm46[34IYmJSJJSSJS{=+\\Mf8DJk|mX1U!!0dU" +U"6mH54m"YI[Xk"jk"XmI6"~54m"I46"[kYFIXm"5j"W5jZ"3m4j54m~,!!0dU"""J6 +mHJ'G5Fr54mCCe\\M{Jm2FI46IHjmXU!!0dU"""""J5H2J[34IYmCCeJm2FI46IHjmX +Jm46[34IYmJ[34IYmC@Jm46[34IYmU!!0dU"""""""Jm2FI46IHjmX"J*m[k6m=43Wm +X"U"H5453Zm6"3G5FF54#!!0dU"""""Jm~3mU!!0dU"""""""Jm2FI46IHjmX"J'G5F +r54m"U"GmmF"3G5FF54#!!0dU"""""JH51U!!0dU"1!!0dU!!0dU"J*m[k6m=43WmX" +E4ZI3Zm3"jZm"I43WmX"jm2j"I46"WX5jm3"5j"jk"jZm!!0dU"3[Xmm4x"^Zm"E4FX +54jI$~m"[ZIXI[jmX3"XmFXm3m4jm6"I3"!!A4!!A4ZZ"IXm"~mHj!!0dU"I3"jZmi" +IXm"B5xmxf"Fk335$~i"E4FX54jI$~m!!A4y"Ok4jXk~AM"B!!A4!!A4.6y"W5~~!!0d +U"$XmIG"jZm"jm2j"54jk"~54m3"k4"jZm"3[Xmm4c"jZm"~54m$XmIG3"54"jZm +!!0dU"ZI3Zm6"jm2j"IXm"5#4kXm6x""JN'"53"3mj"jk"jZm"3mm6"|I~Em"$mHkXm +!!0dU"J*m[k6m=43WmX"53"54|kGm6x!!0dU!!0dU"J6mHJ*m[k6m=43WmX{U"B[kYFIX +m"H5X3j"FIXj"W5jZ"J(kXYNI3Zy!!0dU"""JONuJ$kj["U"H5X3j"[ZIXI[jmX"BF~ +I54"jm2jy!!0dU"""J~kkF"U"k|mX"ZI3Zm6"[ZIXI[jmX3!!0dU"""""J~[[k6mJN' +uJON"U"YIF"[k654#"jk"F~I54"jm2j!!0dU"""""J5H4EYJON>JjkF[!!0dU"""""" +"JI6|I4[m"JN'"JNM""U"I66"YE~j5F~5mX"jk"ZI3Z"|I~Emf""E354#xxx!!0dU"" +"""""JI6|I4[mJON"e"U"jZ53"ZmXm"FXm|m4j3"JN'"HXkY"$m54#"jm3jm6"FXmYI +jEXm~i!!0dU"""""""J5H4EY"JN'PJjkF["JI6|I4[mJN'AJXI4#m"JH5"U"Yk6E~k" +IX5jZYmj5[!!0dU"""JXmFmIj!!0dU"U"*mH54m"m2[mFj5k43x""OkYFIXm"jZ53"F +IXj"W5jZ"Ja2[mFj!!0dU"""J[Ij[k6mnJ\\=u."U"nm3[IFmgf"J!!0dU"U"J[Ij[k +6mnJ\\tue"U"nkFm4gf"{"AA"E44m[m33IXi!!0dU"""J[Ij[k6mnJ\\Ou@"U"n[~k3 +mgf"1!!0dU"""J[Ij[k6mnJ!!A4u?"""U"n3EFmX3[X5Fjgf"\"BHkX"Zm2"54FEjy +!!0dU"""J~[[k6mnJ"unJ!!20!!0dU"""J~[[k6mnJ!!20unJ!!0dU"U!!0dU"""Jm46 +~54m[ZIXuAe"U"5#4kXm"~54m"$XmIG3"54"[k6m6"jm2j!!0dU"""J4mW~54m[ZIXu +nJ\\M!!0dU"""J~kWmX[I3mJ$#XkEFJ5YYm65IjmJWX5jmJN'J$#XkEF!!0dU"1!!0d +U!!0dU"s~k33IXi"kH"I$$Xm|5Ij5k43"I46"k$HE3[Ij5k43!!0dU"AAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA!!0dU!!0dU!!0dU"J~mj""""""""""""""""" +h!!0dU"JN'"""BJjk~mXI4[my"""Jf"""""BJZI3Z"|I~Emy""""""""Ce!!0dU"JNM +""""""""""""""""""Jx"""""BZI3Z"YE~j5F~5mXy""""C@!!0dU"JjkF["""BJYk4 +jZy"""""J0"""""B~I3j"ZI3Zm6"[ZIX,"e@d"hy!!0dU"J$kj["""""""""""""""" +w-"""""BH5X3j"ZI3Zm6"[ZIX,"w-"Cy!!0dU"JXI4#m"""""""""""""JimIX""""B +JjkF[AJ$kj[/e,"Q@y!!0dU"JON"""""BJE[ZiFZy""""Jc"""""BI"[ZIXI[jmX"[k +6my!!0dU"J[Ij[k6m"""""""""""""J,!!0dU"J6mH"""""""""""""""""JC!!0dU" +Jm2FI46IHjmX"""""""""J\!!0dU"J[34IYm""""""""""""""J{!!0dU"Jm46[34IY +m"""""""""""J1!!0dU"J~[[k6m""""""""""""""J7!!0dU"JI6|I4[m"""""""""" +"""JA!!0dU"J$#XkEF""""""""""""""JT!!0dU"J5H4EY"""""""""""""""J5H!!0d +U"Jm46~54m[ZIX"""""""""Jb!!0dU"J5H2"""""""""""""""J5H\\v!!0dU"J'G5 +FFmX"""""""""""""JK!!0dU"J'G5Fr54m""""""""""""J&!!0dU"J*m[k6m=43WmX +""""""""J]!!0dU"J~kWmX[I3mJ$#XkEFJ5YYm65IjmJWX5jmJN'J$#XkEF""""""J8 +!!0dU!!0dU"^Zm3m"I335#4Ym4j3"IXm"WX5jjm4"jk"jZm"kEjFEj"$i"JKX5jm_Ej +FEj"BI[jEI~~i!!0dU"$i"JK'9y"I46"jZm4"jZm"k$HE3[Ijm6"FXk[m3354#"[k6m +"53"WX5jjm4"B#5|m4!!0dU"I3"I"FIXIYmjmX"54356m"B"y"IHjmX"JKX5jm_EjFE +jyx"JKX5jm^ZmLm3j"53!!0dU"IEjkYIj5[I~~i"54|kGm6"jk"[kFi"jZm"}Em3j5k +4"I46"jZm4"jZm"I43WmXx!!0d!!0dJ6mHJKX5jm_EjFEjCeC@{J$m#54#XkEF!!0d" +"J[Ij[k6mnJ\ue@"J4mW~54m[ZIXuew!!0d""Jm6mHJJ{J4km2FI46JK'9{Ce1{C@11 +JJ1!!0d!!0dJ6mHJK'9CeC@{J~mjJJJ3jX54#"U"|mX$Ij5Y53Zf"I|k56"3FI[m3"I +HjmX"[kYYI463!!0d""J5YYm65IjmJWX5jmJ_<5~m!!0d"""{JJJ~mjJJhJJJ~mjJJh +JJJCJJJ6mHJJJCJJJx{C@1JJhJJJfJJJjk~mXI4[mJJJfCe1U!!0d""JI~~kjZmXJ[I +j[k6mnBueJ[Ij[k6mnyu@!!0d""JIHjmXI335#4Ym4jJKX5jm^ZmLm3j!!0d""JjkG3 +.u1!!0d!!0dJ6mHJKX5jm^ZmLm3j{J5YYm65IjmJWX5jmJ_<5~m{JjZmJjkG3.1!!0d +""J[Ij[k6mnBue@J[Ij[k6mnyue@!!0d""J5YYm65IjmJWX5jmJ_<5~m{J3jX54#JqE +m3j5k4,1U!!0d""J5YYm65IjmJWX5jmJ_<5~m{J'mF1U!!0d""JOkFiqEm3j5k4!!0d +""J5YYm65IjmJWX5jmJ_<5~m{J'mF1U!!0d""{J=~~=[jNm2J(kXYNI3ZJa2[mFjJN5 +6m'k~Ej5k41!!0d""Jm46#XkEF1!!0d!!0d!!0dJKX5jm_EjFEj{JjZmJN'1{JjZmJN +MU!!0d1BhJ0JYk4jZhJcJE[ZiFZhJ,J[Ij[k6mhJ\Jm2FI46IHjmXhJ{J[34IYm{hJC +J26mHhhJ3jX54#!!0dJCJe{h\\=1JCJw{h\\O1JCJR{h\\I11hJ1Jm46[34IYmhJT{h +J7J~[[k6mJCJ8{J4mW~54m[ZIX!!20*!!0dJ~kWmX[I3mJTJ5YYm65IjmJWX5jmJfJT +1hJAJI6|I4[mJimIXQ@hJ5HJ5H4EYhJbJm46~54m[ZIX!!0dJ0!!20?aJCJ\\-eEm3\ +\R5k\\dm,{Jc."J~kkFJ,Jc!!20OJAJce"J5HJc>@-d"JXmFmIjJb!!20*JK1{J,!!20 +\end{comment} +\begin{lcode} +*!!20O!!0dJ#6mHJKCe\\MC@\\M{J\JCJ{C@J1JSJJSSJS{=+\\Mf8DJk|mX1JCJ&C +Ce\\M{J\J5H\\vJ{CCeJ\U!!0dJ1J{C@J1J\J]Jm~3mJ\J&JH51J&11JCJ]{Jcw-J~k +kFJ7JfJcJ5HJc>J0JAJfJxJAJceJ5HJfPJ0!!0dJAJfAJimIXJH5JXmFmIjJ,eg.J,w +!!20@J,wwg?J7!!20@.n!!20J7n!!20!!20@.JbAeJ81!!0dy!!0d!!0dJm46!!0d +!!0d!!03!!03!!A{end!!A} +\end{lcode} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%[Addendum 2: TeX encoder for my decoder. (mjd,18-Aug-1994)] +\subsection{Addendum 2} + + TeX encoder for my decoder. (mjd,18-Aug-1994) + + +\begin{lcode} +% Source character set: 13,32-126 = 96 +% +% (Note exclusion of tab. Assumption: Text to be translated will +% always be untabified first.) +% +% Target character set: 33-126. +% +% Carriage return (13) cannot be included in the target set because +% of the constraint to have a maximum line length of 72 in the +% encoded text. If 13 (carriage return) were included in the +% encoding, then the end of the current line would only occur at +% the next instance in the ciphered text of the character that +% translates to 13. And depending on what that character is, who +% knows how long the encoded line could be? Perhaps as long as the +% entire text. +% +% Space (32) are not included in the target set for a subtler +% reason. If spaces in the encoded text happen to fall at the end +% of a line, they will be dropped by TeX during the decoding +% process, instead of decoded. So we either must exclude them from +% the target set, or make sure that they never fall at the end of a +% line. +% +% By excluding space from the target set, we make it possible for +% the decoder to use a space as its argument delimiter. If we have +% only one space, at the end of the encoded text, it is not so hard +% to ensure that it does not fall at the end of a line. But note +% that the decoder must make sure to change the catcode of space to +% something other than 10, so that it will not disappear if it +% falls at the *beginning* of a line. + +\def\colon{:}\def\arrow{->}% +\let\isx\message +%\def\isx#1{} + +\iffalse +% OK, here is how the encoding works. Start with \mag = random (in +% the target range 33-125), first encoding value. Handle two +% special cases first: ^^M encodes to \mag, space encodes to \mag +% +1. Then start normal encoding at \fam = 35 (char 35 = ! encodes +% to \mag +2, and so forth). When \mag reaches 126, we wrap it +% around to 33 (don't want to encode any character to space). +% Finally, when \fam reaches 126, we must handle the last three +% characters (126,33,34: ~!") as digraphs: encode them as ~x~y~z, +% where xyz are obtained by continuing to increment \mag. + +@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ ! "#$%&'()*+,-./0123456789:;<=>? + R S~S~TTUVWXYZ[\]^_`abcdefghijklmnop +@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|} ~ +qrstuvwxyz{|}!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQ~R +\fi % ^^^ + +\def\setup{% + \def\notilde{}% later will be defined to include a tilde + \def\encodeone{% + \catcode\fam\active\lccode126\fam\lccode 48\mag + \lowercase{\edef~{\notilde 0}% +\isx{[\string~\colon \notilde 0\space\number\fam\arrow\number\mag]}% + }% + \advance\mag7 \ifnum\mag>125\advance\mag-93 \fi + \advance\fam1 + }% + \def\do{\encodeone \csname do\ifnum\fam>125 stop\fi\endcsname + }% +% ASSUMPTION: \mag initialized before the call of \setup +% Encode ^^M -> \mag + \fam13 \encodeone +% Encode space -> next \mag + \fam32 \encodeone +% Now encode the rest + \fam35 \let\dostop\relax \do +% Now \fam = 34, \mag = ?. We need to define encoding for +% characters 34,33,126 ("!~) as ~z ~y ~x. But what are convenient +% values for x y z? Why, just the next \mag's in sequence + \edef\notilde{\string ~} + \encodeone \fam33 \encodeone \encodeone +} + +\def\outwrite{\immediate\write15{\outline}% +% If a digraph occurred at the end of the line, carry over the +% second character to the beginning of the next line. + \expandafter\ifx\csname 73\endcsname\relax + \else + \expandafter\let\expandafter\1\csname 73\endcsname + \expandafter\let\csname 73\endcsname\relax + \charnum 1 + \fi + \checkeof} +% For fast looking on screen: +%\def\outwrite{\immediate\write16{\outline}\checkeof} + +\begingroup +\let\0\catcode \0`\0 11 \0`\2 11 \0`\3 11 \0`\4 11 \0`\5 11 +\0`\6 11 \0`\7 11 \0`\8 11 \0`\9 11 \0`\1 11 +\gdef\outline{\1\2\3\4\5\6\7\8\9\10\11\12\13\14\15\16\17\18\19 + \20\21\22\23\24\25\26\27\28\29\30\31\32\33\34\35\36\37\38\39 + \40\41\42\43\44\45\46\47\48\49\50\51\52\53\54\55\56\57\58\59 + \60\61\62\63\64\65\66\67\68\69\70\71\72} +\endgroup + +\newcount\charnum + +\def\checkeof{\futurelet\next\encodemore} + +\def\tildecheck#1#2{\if \string~#1% + \expandafter\def\csname\number\charnum\endcsname{#1}% + \advance\charnum 1 + \expandafter\def\csname\number\charnum\endcsname{#2}% +\fi} + +\def\encodemore{\ifx\next\EOF + \let\next\outwrite \let\checkeof\relax +\global\tracingcommands2\global\tracingmacros2\global\tracingonline0 +% At end of file, assume that there was a ^^M at the end, +% translated to the digraph ~|. Remove it, to reduce the number of +% blank lines that will be produced on screen during decoding. +% BUT, if \charnum = 72, leave the ^^M there to avoid having the +% space at the end of the line. + \ifnum\charnum<72 + \expandafter\def\csname\number\charnum\endcsname{ }% + \else + \def\1{ }% + \fi + \else + \advance\charnum 1 + \ifnum\charnum>72 + \charnum 0 \let\next\outwrite + \else + \let\next\getnextchar + \fi + \fi + \next} + +\def\getnextchar#1{% + \edef\0{#1}% + \expandafter\let\csname\number\charnum\endcsname\0\relax + \expandafter\tildecheck\0\relax\relax + \checkeof}% + +% For this we need just a unique no-op value for \ifx comparison. +\def\EOF{\relax\relax} + +\def\writefile#1{\expandafter\checkeof\input#1 \EOF}% + +\begingroup +% Define \0 to read in the text for \writepreamble. +\def\0#1XXX#2^^JZZZ^^J{\endgroup + \def\writepreamble##1{\begingroup +% Convert ##1 into a hex number. + \newlinechar=10 \chardef\0=##1\def\1####1"{"}% + \immediate\write15{#1\expandafter\1\meaning\0#2}\endgroup}}% +% Now change all special catcodes to 12. We don't use \dospecials +% because we want to do backslash last, in conjunction with +% \afterassignment. +\catcode`\{=12 \catcode`\}=12 \catcode`\#=12 +\catcode`\~=12 \catcode`\@=12 \catcode`\$=12 +\catcode`\^=12 \catcode`\&=12 \catcode`\_=12 \catcode`\|=12 +% The following line will turn off the last two remaining special +% characters % and \, set end-of-line character to ^^J (for later +% use in the \write), and then call \0. ^^M still has category 5 at +% this point and the new value of \endlinechar won't get applied +% until the *next* line is read, so the catcode assignment for \ +% will get terminated properly by the space from ^^M, thus \0 will +% get called before TeX attempts to read the % at the beginning of +% the subsequent line. +\catcode`\%=12 \endlinechar=10 \afterassignment\0 \catcode`\\=12 +%%%% Self-decoding answer: run the following text through plain TeX %%%% +\let\+\let\+\a\advance\+\c\catcode\+\d\def\+\f\fam\+\m\mag\+\u\uccode \m +13\c\m9\+\p\uppercase\d\i{\a\f7 \ifnum\f>125 \a\f-93 \fi}\d~{\u\f\m \c\m +12 \a\m1 \i \ifnum\m>125 \+~\1\fi~}\d\0#1{\ifnum`#1>"D \if#1 !\else "\fi +\else\string~\fi}\u`9"20\p{\d\1#19}{\newlinechar13\d\3{\immediate\write1 +6}\+~\0\p{\3{}\3{#1}\batchmode\end}}\fXXX\u\f\m\i\m32\u\f\m\c\m12\i\m35~ +ZZZ + +\def\encodefile#1{% + \immediate\openout15=encode.out \relax + \begingroup +% Get a random number from \time, normalize it to fall in the range +% 33--125. First set \mag = \time mod 93, then add 33 to make it +% fall in the proper range. + \fam\time \mag\time \divide\fam93 \multiply\fam 93 \advance\mag-\fam + \advance\mag 33 + \message{======= Code shift: time \number\time\space --> + mag \number\mag\space ============================}% + \writepreamble{\number\mag}% +% \setup uses \mag. + \setup \charnum=0 + \immediate\write16{Starting to create file encode.out . . .}% + \writefile{#1}% + \endgroup + \immediate\closeout15 \relax + \immediate\write16{The encoded output is in the file encode.out.}% +} + +\immediate\write16{Enter the name of the file you want to encode:} +{\catcode\endlinechar=9 \global\read-1 to\filnam} +\encodefile{\filnam} + +\end +\end{lcode} +%$ +%%\endinput + + +\chapter{Defining new control sequences} + +\section{Exercise} + +%%\input{ex012} +% ex012.tex +\begin{comment} +Date: 24 Sep 1993 16:11:36 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #12 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +======================================================================== +*** Exercise 12: +\end{comment} +\ed{\oposted{1993/09/24}. \arch{exercise.012}.} + +How many commands are there in plain TeX that can be used to define a +new (i.e., previously undefined) control sequence? + +\begin{comment} +======================================================================== + +E-mail answers to my address, below. A summary will be posted circa +October 15, 1993. + +Michael Downes --------------------------------------------------------- +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ +%%\endinput + +\section{Answers} + +%%\input{ans012} +% ans012.tex +\begin{comment} +[The addendum was not included in the original post but added in my +archives later ---mjd] + +Date: 25 Oct 1993 16:36:43 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #12, answer +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1993/10/25}. \arch{answer.012}.} + +%Exercise 12 asked `How many commands are there in plain TeX that can +%be used to define a new (i.e., previously undefined) control +%sequence?'. +This exercise has latent ambiguities. The parenthetical +remark `(i.e., previously undefined)' was intended as a hint towards +the most comprehensive possible answer. + +There are three main criteria that could be used for `new' status of a +control sequence: +\begin{enumerate} +\item If executed, the control sequence causes an `\texttt{Undefined control +sequence}' error. + +\item The control sequence is \piif{ifx}-equivalent to \cmd{\relax} when constructed +with \cmd{\csname} \texttt{\ldots} \cmd{\endcsname}. This is the basis of the LaTeX +\cmd{\@ifundefined} test. + +\item The control sequence has not yet been entered into the hash table. +\end{enumerate} + +Criterion (3) doesn't work for one-character control sequences (\cmd{\a}, +\cmd{\0}, \cmd{\:}) since they have space reserved for them separate from the +hash table whether or not they are defined in any sense. + +Criterion (2) obviously gives a spurious true result if applied to +\cmd{\relax} or to something like LaTeX's \cmd{\protect} command that spends much +of its time being equivalent to \cmd{\relax}. + +Criterion (1) therefore seems best. Notice that control sequences can +enter into the hash table without becoming defined anywhere along the +way, so a control sequence can be `old' by criterion (3) but still +new by criterion (1). In all of the following examples the control +sequence \cmd{\foo} will get added to the hash table but remain undefined. +\begin{lcode} + \def\x{\foo} + \toks0{\foo} + \string\foo + \noexpand\foo + \gobble\foo (assuming \def\gobble#1{}) + \uppercase{\iffalse\foo\fi} + \show\foo + \meaning\foo +\end{lcode} +Two notable cases where tokenization, but not hash-table-ization, of +\cmd{\foo} occurs are in an \piif{ifx} comparison or on the false branch of an +\piif{if}: +\begin{lcode} + \ifx\foo\something... + \iffalse\foo\fi +\end{lcode} +(\emph{TeXbook}, Appendix D, p384). + +The straightforward answer to Exercise 12 is to count up the various +kinds of def'ing and let'ing functions (table~\ref{tab:deflet}): +\begin{comment} +\begin{lcode} +Primitive: Nonprimitive: + +\def \newcount +\edef \newdimen +\gdef \newskip +\xdef \newmuskip +\let \newfam +\futurelet \newwrite +\chardef \newread +\mathchardef \newbox +\countdef \newtoks +\dimendef \newinsert +\skipdef \newlanguage +\muskipdef \newif +\toksdef \newhelp +\font +\read +\csname +\end{lcode} +\end{comment} +\begin{table} +\centering +\caption{The def'ing and let'ing functions}\label{tab:deflet} +\begin{tabular}{ll} \toprule +Primitive & Nonprimitive \\ \midrule +\cmd{\def} & \cmd{\newcount} \\ +\cmd{\edef} & \cmd{\newdimen} \\ +\cmd{\gdef} & \cmd{\newskip} \\ +\cmd{\xdef} & \cmd{\newmuskip} \\ +\cmd{\let} & \cmd{\newfam} \\ +\cmd{\futurelet} & \cmd{\newwrite} \\ +\cmd{\chardef} & \cmd{\newread} \\ +\cmd{\mathchardef} & \cmd{\newbox} \\ +\cmd{\countdef} & \cmd{\newtoks} \\ +\cmd{\dimendef} & \cmd{\newinsert} \\ +\cmd{\skipdef} & \cmd{\newlanguage} \\ +\cmd{\muskipdef} & \cmd{\newif} \\ +\cmd{\toksdef} & \cmd{\newhelp} \\ +\cmd{\font} & \\ +\cmd{\read} & \\ +\cmd{\csname} & \\ + \bottomrule +\end{tabular} +\end{table} + +The reason for including \cmd{\csname}? After +\begin{lcode} + \csname foobar\endcsname +\end{lcode} +\cmd{\foobar} is no longer undefined; the change in its status is +indistinguishable from the change effected by the statement +\verb?\let\foobar\relax?. \cmd{\endcsname} is not counted separately because +\cmd{\csname} and \cmd{\endcsname} can only be used together. + +So: 16 primitive, 13 non-primitive make 29 total. But to those should +be added two more, since the statement of the Exercise didn't exclude +`private' macros: (i) the internal function \cmd{\alloc@} of plain.tex +that is shared by all the \cmd{\newxxx} macros (except for \cmd{\newif} and +\cmd{\newhelp}), and (ii) the internal function \cmd{\@if} used by \cmd{\newif}. + +That brings the total to 31. + +Beyond that there can be added another, less obvious, class of +commands, if we paraphrase the exercise as follows: +\begin{quote} + Find all commands such that executing command \cmd{\xxx}, with its normal + arguments (if any), causes at least one control sequence to pass + from undefined status to defined status, where undefined status + means that executing the control sequence would generate the error + `Undefined control sequence'. +\end{quote} +For example, the first use of \cmd{\loop} causes \cmd{\body} and \cmd{\next} to become +defined. As it turns out, there are many of these in plain TeX +(table~\ref{tab:user} and~\ref{tab:internal} as well as \verb?'? or \cmd{\rq} +in math mode only). + +\begin{comment} +User functions: +\begin{lcode} +\loop, \t, \smash, \vfootnote, \settabs, \phantom, +\vphantom, \hphantom, \footnote, \multispan, \longleftarrow, +\longrightarrow, \mathstrut, \longmapsto, \matrix, \pmatrix; +\end{lcode} +\verb?'? or \cmd{\rq} (math mode only) +\end{comment} + +\begin{figure} +\freetabcaption{User functions}\label{tab:user} +\autorows{c}{4}{l}{% +\cmd{\footnote}, +\cmd{\hphantom}, +\cmd{\longleftarrow}, +\cmd{\longmapsto}, +\cmd{\longrightarrow}, +\cmd{\loop}, +\cmd{\mathstrut}, +\cmd{\matrix}, +\cmd{\multispan}, +\cmd{\phantom}, +\cmd{\pmatrix}, +\cmd{\settabs}, +\cmd{\smash}, +\cmd{\t}, +\cmd{\vfootnote}, +\cmd{\vphantom} +} +\end{figure} + + +\begin{comment} +Internal functions: +\begin{lcode} +\iterate, \relbar, \sett@b, \s@tt@b, \prim@s, +\ph@nt, \fo@t, \f@@t, \pr@m@s, \pr@@@s, \s@tcols +\end{lcode} +\end{comment} + +\begin{figure} +\freetabcaption{Internal functions}\label{tab:internal} +\autorows{c}{6}{l}{% +\cmd{\f@@t}, +\cmd{\fo@t}, +\cmd{\iterate}, +\cmd{\ph@nt}, +\cmd{\pr@@@s}, +\cmd{\pr@m@s}, +\cmd{\prim@s}, +\cmd{\relbar}, +\cmd{\s@tcols}, +\cmd{\s@tt@b}, +\cmd{\sett@b} +} +\end{figure} + +Adding these 18 user functions and 11 internal functions to the +previously cited 31 gives a total of 60 functions available in +\pfile{plain.tex} that satisfy a strict interpretation of the exercise +statement. + +Credit for the best answer goes to Dan Luecking\index{Luecking, Dan}, +who found 29 of the +primary 31, and did not miss the other two (\cmd{\csname}, \cmd{\@if}) by +overlooking them but by considering them and believing they didn't +satisfy the requirements. + +My own score in that part was 28: I overlooked \cmd{\read}, \cmd{\alloc@}, and +\cmd{\@if} until Luecking and Peter Schmitt\index{Schmitt, Peter} +brought them to my notice. + +Ian Collier\index{Collier, Ian} also submitted a good answer, including +identification of +the secondary class of functions that define scratch macros as a side +effect. + +%%======================================================================== + +Notes: +\begin{itemize} +\item \cmd{\iterate}, \cmd{\settabs}, \cmd{\sett@b}, \cmd{\s@tt@b}, + \cmd{\t}, \cmd{\prim@s}, \cmd{\ph@nt}, \cmd{\smash}, + \cmd{\vfootnote}, \cmd{\fo@t}, \cmd{\f@@t} all define \cmd{\next}. +\item \cmd{\loop} defines \cmd{\body}. +\item \cmd{\pr@m@s} defines \cmd{\nxt}. +\item \cmd{\prim@s} is called by active \verb?'? (mathcode \verb?"8000?) + and by \cmd{\pr@@@s}. +\item \cmd{\iterate} is called by \cmd{\loop}. +\item \cmd{\sett@b} is called by \cmd{\settabs}. +\item \cmd{\s@tt@b} is \emph{conditionally} called by \cmd{\sett@b}. +\item \cmd{\smash} is called by \cmd{\relbar}. +\item \cmd{\ph@nt} is called by \cmd{\phantom}, \cmd{\vphantom}, and + \cmd{\hphantom}. +\item \cmd{\vfootnote} is called by \cmd{\footnote}. +\item \cmd{\fo@t} is called by \cmd{\vfootnote}. +\item \cmd{\f@@t} is \emph{conditionally} called by \cmd{\fo@t}. +\item Active \verb?'? is produced by \cmd{\rq} if used in math mode. +\item \cmd{\pr@@@s} is called by \cmd{\pr@m@s}. +\item \cmd{\loop} is called by \cmd{\multispan} and \cmd{\s@tcols}. +\item \cmd{\relbar} is called by \cmd{\longleftarrow} and \cmd{\longrightarrow}. +\item \cmd{\vphantom} is called by \cmd{\mathstrut}. + +\item \cmd{\pr@m@s} is called by \cmd{\prim@s}. +\item \cmd{\s@tcols} is *conditionally* called by \cmd{\sett@b}. +\item \cmd{\longrightarrow} is called by \cmd{\longmapsto}. +\item \cmd{\mathstrut} is called by \cmd{\matrix}. + +\item \cmd{\matrix} is called by \cmd{\pmatrix}. + +\item \cmd{\prim@s} won't necessarily define \cmd{\next} because it does +a \cmd{\futurelet} +which will leave \cmd{\next} undefined if the next thing happens to be an +undefined control sequence (rather unlikely, however). + +\item \cmd{\vfootnote} and \cmd{\settabs} also do a \cmd{\futurelet} but it is followed by +another macro that ensures that \cmd{\next} does not end up undefined. +\end{itemize} + +\begin{comment} +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\end{comment} +%$ + +\section{Addendum} +\enlargethispage{3\onelineskip} +\begin{comment} +Addendum: From comp.text.tex +=========================================================================== +Archive-Date: Wed, 29 Sep 1993 13:21:40 CST +From: cet1@cus.cam.ac.uk (Chris Thompson) +Subject: Re: Managing Large LaTeX Files. How ?? +Date: Wed, 29 Sep 1993 16:36:23 GMT +To: tex-news@SHSU.EDU +\end{comment} + +From \texttt{comp.text.tex} +\begin{lcode} +From: cet1@cus.cam.ac.uk (Chris Thompson) +Subject: Re: Managing Large LaTeX Files. How ?? +Date: Wed, 29 Sep 1993 16:36:23 GMT +To: tex-news@SHSU.EDU +In article <93265.121206SPIT@EVALUN11.BITNET>, Werenfried Spit <SPIT@EVALUN11.BITNET> +writes: +|> In article <1993Sep20.130331.16568@vax.oxford.ac.uk>, kaye@vax.oxford.ac.uk +|> (Richard Kaye) says: +|> >Has anyone else had save stack overflow when LaTeX read the .aux files? +|> > +|> >[Will a TeX guru please explain it to me? I thought \global\def's could not +|> >cause save stack overflow until I found this problem. If it's a general +|> >problem, it seems a bit silly that LaTeX should try to input so much +|> >information in this way.] +|> > +|> >I fixed it so that the data was read {\it outside} the group (as part of one +|> +|> Could someone explain it to me too? I'm even more puzzled after I tried +|> out Richards solution and played a bit with it. When you put in +|> your input file directly after the \documentstyle command the line +|> \input \jobname.aux +|> LaTeX reads the aux file without its memory getting overflowed; then +|> at \begin{document} it reads the aux file again (as expected), but +|> the memory doesn't overflow this time either. (If you leave out the +|> \input \jobname.aux LaTeX only reads the aux file during \begin{document} +|> and then chokes on an exceedence of the save size.) +\end{lcode} +[Chris Thompson] This was a hard one to track down. I could claim that it was all my fault... + +The entries on the save stack are not the result of the +\cmd{\global}\cmd{\@namedef}, +which as suggested above never needs to use such a thing. They come from +the earlier \cmd{\@ifundefined} call in \cmd{\newlabel}. + +Change \#337 in \pfile{tex82.bug} numbering, applied in TeX 2.9, changed the implicit +setting of an undefined control sequence referenced via \cmd{\csname}...\cmd{\endcsname} +to \cmd{\relax} (\emph{TeXbook}, page 213) from being (sort of) global to being local to +the current group. Don made this change as a direct result of my posting to +TeXhax (year 1987, digest 103) pointing out that the TeXbook didn't correctly +describe what happened. + +The change was a potent source of new bugs, because TeX was not originally +designed to cope with token expansion have side-effects of modifying the +save stack (see in particular change \#371 in tex82.bug). I have more than +once wondered whether I should have kept quiet about the whole business\ldots + +In an ideal world, the problem wouldn't arise because the implicit setting +to \cmd{\relax} wouldn't occur at all (IMNSHO). But everything (especially LaTeX) +relies on it now, so it's (far) too late to change it. Something to be got +right in the next incarnation. + +\begin{lcode} +Chris Thompson +Cambridge University Computing Service +\end{lcode} + +%%\endinput + + +\chapter{\cs{endlinechar} and \cs{par}} + +\section{Exercise (fast)} + +%%\input{ex013} +% ex013.tex +\begin{comment} +Date: 13 Oct 1993 12:31:56 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #13 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1993/10/13}.\arch{exercise.013}.} + +\begin{lcode} +%%%% Three lines of overhead for the self-decoding answer; see below %%% +\let\+\let\+\a\advance\+\c\catcode\+\d\def\+\f\fam\+\m\mag\f"20\d~{\c\f9 +\a\f1 \ifnum\f>125\f002\d~{\a\f-1 \ifnum\f<1\egroup\fi}\fi~}\c`\^^M="9{~ +\end{lcode} + +%%======================================================================== +%%*** Exercise 13 (fast): + +(a) If \cmd{\endlinechar} does not have category 5 do you still get a \piif{par} +from a blank line? + +(b) If \cmd{\endlinechar}=-1 do you still get a \piif{par} from a blank line? + +\begin{comment} +======================================================================== + +Michael Downes ========================================================= +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ + +Self-decoding answer given below. To see the answer, run this post +(sans mail/newsgroup header) through plain TeX. +\begin{lcode} +\d~{\u\f\m\c\m12 \a\m1\a\f1 \ifnum\f>125\f33 \fi\ifnum\m>125\+~\1\fi~}\+ +\u\uccode\+\p\uppercase\d\0#1{\ifnum`#1>"D \if#1 !\else"\fi\else\string~ +\end{lcode} +\ed{There are sixteen lines like this, all of which are in the archived +version if you need them. The last line is:} +\begin{comment} +\fi}\u`9"20\p{\d\1#19}{\newlinechar13 \d\3{\immediate\write16}\+~\0\p{\3 +{}\3{#1}\batchmode\end}}\f"6C\m"0D\u\f\m\a\f"1\m32\u\f\m\c\m12\a\f1\m35~ +/\aeS`amb]m/`]c\RmbVSm0S\Rmn|!(llsOtm<]ymsPtm<]ymm7\m]bVS`me]`RawmOmPZO\ +YmZW\SmeWZZm^`]RcQSmOmJ^O`mWTlO\Rm]\ZgmWTmS\RZW\SmQVO`OQbS`amO`Sm^`SaS\b +mO\RmVOdSmQObQ]RSm#ym7bmWalW\bS`SabW\Umb]m\]bSmbVObmbe]mQ]\aSQcbWdSmS\RZ +W\SmQVO`OQbS`amO`Sm\]blb`O\aZObSRmaW[^Zgmb]mJ^O`wmPcbmb]m*a^OQS,J^O`ymms +BVSma^OQSmeWZZlRWaO^^SO`mW\ma][SmQW`Qc[abO\QSawmSyUywmOTbS`mOmQ]\b`]Zme] +`RwmOQQ]`RW\Ulb]mBSFram\]`[OZmaQO\\W\Um`cZSaytmBVWamWambVSm`SOa]\ms]`mOb +mZSOabm]\Sl`SOa]\tmbVObmOmJ^O`m]^S`ObW]\m[cabm^S`T]`[mO\mW[^ZWQWbmJc\aYW +^l]^S`ObW]\ymBVS`SmeOamOZa]mOm`SQS\bm^]abmb]mQ][^ybSfbybSfmPgm2]\OZRl/`a +S\SOcmb]m^]W\bm]cbmbVSm^`]PZS[meWbVma][S]\SramRSZW[WbSRxO`Uc[S\bl[OQ`]mR +STW\WbW]\(llmmJRSTJa][SbVW\Un|yJ^O`i*R]ma][SbVW\UmeWbVmn|,kllBVSmRSZW[Wb +S`mab`W\Um~nyJ^O`~nmRWRm\]bm[ObQVmbVSmOQbcOZmbSfbllmmyyyma][SmbSfbylmm*P +\end{comment} +\begin{lcode} +ZO\YmZW\S,llPSQOcaSm]TmbVSma^OQSmb]YS\mT]ZZ]eW\UmbVSm^S`W]Ry mbSfbylmm*P +\end{lcode} + +%%\endinput + +\section{Answers} + +%%\input{ans013} +% ans013.tex +\ed{\arch{answer.013}.} + +[This was included as a self-decoding answer in the posting of Exercise +\#13 which is archived as \pfile{exercise.013}.] + + +Answers to Around the Bend \#13: + +(a) No. (b) No. In other words, a blank line will produce a \piif{par} if +and only if endline characters are present and have catcode 5. It is +interesting to note that two consecutive endline characters are not +translated simply to \piif{par}, but to \meta{space}\piif{par}. (The space will +disappear in some circumstances, e.g., after a control word, according +to TeX's normal scanning rules.) This is the reason (or at least one +reason) that a \piif{par} operation must perform an implicit \cmd{\unskip} +operation. There was also a recent post to \pfile{comp.text.tex} by Donald +Arseneau\index{Arseneau, Donald} to point out the problem with someone's +delimited-argument macro definition: +\begin{lcode} + \def\something#1.\par{<do something with #1>} + +The delimiter string ".\par" did not match the actual text + + ... some text. + <blank line> + +because of the space token following the period.. +\end{lcode} + +%%\endinput + + +\chapter{TeX's stomach} + +\section{Exercise} + +%%\input{ex014} +% ex014.tex +\begin{comment} +Date: 26 Oct 1993 09:29:08 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #14 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1993/10/26}. \arch{exercise.014}.} + +\begin{lcode} +%%%%% Two lines of overhead for the self-decoding answer; see below %%%% +\let\+\let\+\a\advance\+\c\catcode\+\d\def\+\f\fam\+\m\mag\c13 9{\c32'16 +\end{lcode} + +%% ======================================================================= +\begin{quote} + *** Exercise 14 [proposed by Jonathan Fine]: + + Which character code/category code pairs can actually reach TeX's + `stomach'? +\end{quote} + +%% ======================================================================= + + This is a refinement of The \emph{TeXbook}'s Exercise 7.3. You need to be a + little careful about your answer. I didn't get it right on my first + try \ldots + + To make the notion of `reaching TeX's stomach' more precise: A token + is said to `reach TeX's stomach' if it produces a token report when + \cmd{\tracingcommands} = 1. And a `token report' is a phrase in braces, + e.g., +\begin{lcode} + {the letter A} + \end{lcode} + as produced by TeX in the log file when tracing commands. + +\begin{comment} + Michael Downes ======================================================== + mjd@math.ams.org ASCII 32--55,56--126: !"#$%&'()*+,-./01234567 + 89:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ + + Self-decoding answer given below. To see the answer, run this post + (sans mail/newsgroup header) through plain TeX. + +\begin{lcode} +}\d~{\u\f\m\c\m12\a\m1\a\f1 \ifnum\f>125\f33 \fi\ifnum\m>125\+~\1\fi~}\+ +\u\uccode\+\p\uppercase\d\0#1{\ifnum`#1>"D \if#1 !\else"\fi\else\string~ +\end{lcode} +\ed{In the archived form there are 20 lines like this, the last being:} +\begin{comment} +\fi}\u`9"20\p{\d\1#19}{\newlinechar13 \d\3{\immediate\write16}\+~\0\p{\3 +{}\3{#1}\batchmode\end}}\f"39\m"0D\u\f\m\a\f"1\m32\u\f\m\c\m12\a\f1\m35~ +Y).2}-:/*:Y-*0)|:/#}:Z})|:;ILR99::[y/{*|}:[#y-:[*|}.::::[y/{*|}:[#y-:[*| +}.9::EEEEEEE:EEEEEEEEEE::::EEEEEEE:EEEEEEEEEE9:::::I:::::HEEJMM::::::::: +::IH:::IEEJMM9:::::J:::::HEEJMM9:::::K:::::HEEJMM:::::::::::II:::HEEJMM9 +:::::L:::::HEEJMM:::::::::::IJ:::HEEJMM9::::::::::::::::::::::::::::IK:: +:HEEJMM9:::::N:::::HEEJMM9:::::O:::::HEEJMM9:::::P:::::HEEJMM99[y/}"*-4: +IH:$.:/#}:}3{}+/$*)y':{y.}F:[y/{*|}EIH:{#y-y{/}-.:2$/#:{#y-y{/}-9{*|}:TV +:KJ:{y):*)'4:z}:+-*|0{}|:z4:t0++}-{y.}Gt'*2}-{y.}:/-${&.:@l}pz**&D9Y++}) +|$3:\AF:k*:/#}:+y$-:{#y-y{/}-:HD:{y/{*|}:IH:$.:)*/:+*..$z'}R:t0++}-{y.}9 +y)|:t'*2}-{y.}:{y))*/:+-*|0{}:y:{#y-y{/}-:H:!-*(:y:)*)EH:{#y-y{/}-F99Y{/ +$1}:{#y-y{/}-.:2$'':/}./:/-0}:!*-:{y/}"*-4:IH:2$/#:t$!{y/:$!:/#}4:y-}9t' +}/:},0y':/*:y:.+y{}:/*&})F:Z0/:$!:/#}:~9:{#y-y{/}-:@.y4A:#y.:z}}):.*9|}! +$)}|D:$/:2$'':)*/:(y/{#:y:.+y{}:$):/#}:|}'$($/}-:/}3/:*!:y:(y{-*:2$/#9|} +'$($/}|:y-"0(})/.F:Y)|:y{{*-|$)":/*:t/-y{$)"{*((y)|.:/#}:(}y)$)":*!:y)9y +{/$1}:/$'|}:/#y/:#y.:z}}):t'}/:},0y':/*:y:.+y{}:$.:~;z'y)&:.+y{}::~;D92# +\end{comment} +\begin{lcode} +}-}y.:/#}:(}y)$)":*!:y:{y/}"*-4EIH:/$'|}:$.:~;z'y)&:.+y{}:~9~;F ::~;D92# +\end{lcode} + +%%\endinput + + +\section{Answers} + +%%\input{ans014} +% ans014.tex + +\ed{\arch{answer.014}.} + +[This was included as a self-decoding answer in the posting of Exercise +\#14, which is archived as \pfile{exercise.014}.] + +\begin{lcode} +Answer to Around the Bend #14: + + Catcode Char Codes Catcode Char Codes + ------- ---------- ------- ---------- + 1 0--255 10 1--255 + 2 0--255 + 3 0--255 11 0--255 + 4 0--255 12 0--255 + 13 0--255 + 6 0--255 + 7 0--255 + 8 0--255 +\end{lcode} +Category 10 is the exceptional case. Catcode-10 characters with character +code $<>$ 32 can only be produced by \cmd{\uppercase}/\cmd{\lowercase} tricks +(\emph{TeXbook}, Appendix D). So the pair character 0, catcode 10 is not +possible: \cmd{\uppercase} +and \cmd{\lowercase} cannot produce a character 0 from a non-0 character. + +Active characters will test true for category 10 with \piif{ifcat} if they are +\cmd{\let} equal to a space token. But if the \verb?~? character (say) has been so +defined, it will not match a space in the delimiter text of a macro with +delimited arguments. And according to \cmd{\tracingcommands} the meaning of an +active tilde that has been \cmd{\let} equal to a space is +\verb?`blank space '? +whereas the meaning of a category-10 tilde is \verb?`blank space ~'?. + +%%\endinput + + +\chapter{Space removal} + +\section{Exercise} + +%%\input{ex015} +% ex015.tex +\begin{comment} +Date: 05 Nov 1993 16:34:28 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #15 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1993/11/05}. \arch{exercise.015}.} + +(a) Write a macro \cmd{\trimspace} that takes another macro as its argument and +removes a trailing space from the replacement text of the macro, if one +is present, and otherwise leaves it unchanged. + +(b) Write a macro \cmd{\trimspaces} that removes a leading space, if +present, and then calls \cmd{\trimspace} to remove a trailing space. + +%%======================================================================== + +Motivation: If a user inadvertently includes an extra space +in a text argument, such as a section heading: +\begin{lcode} + \section{Title of the section } +\end{lcode} +then you must usually take care to remove the space when typesetting +the text. The simple way is to perform an \cmd{\unskip} at the end (if the +text is immediately followed by \piif{par}, the \cmd{\unskip} operation is +built-in) and an \cmd{\ignorespaces} at the beginning, but various +complications can arise, so it would be preferable to be able to apply +a \cmd{\trimspaces} function when an argument is first read, and then have +the information in proper form for all subsequent uses. + +\begin{comment} +Send answers to the address below. A summary will be posted +November 23, 1993 or thereabouts. + +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ +%%\endinput + + +\section{Answers} + +%%\input{ans015} +% ans015.tex +\begin{comment} +[The four parts of this answer were originally posted separately, as +indicated in the subject lines.] + +Date: 16 Dec 1993 16:34:45 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #15, answers +To: info-tex@shsu.edu +\end{comment} + +\ed{\oposted{1993/12/16}. \arch{answer.015}.} + +Exercise 15 asked for a function \cmd{\trimspace} to trim a trailing space +from the replacement text of a macro, and a function \cmd{\trimspaces} to +trim both a leading and a trailing space. At the time of posting the +exercise I had no prepared solution; as luck would have it the problem +was rife with latent complications (including some hard questions +about limiting the domain of application), which propagated an +unusually diverse crop of approaches among the submitted solutions, +and which made the task of preparing a good summary extraordinarily +difficult. Even after breaking down the `summary' into two or three +pieces, to avoid a too formidably large monolith of a posting, I'll +have to leave out some material that I would otherwise have included. + +I'd say Donald Arseneau\index{Arseneau, Donald} deserves credit for +the best analysis, +including an accurate survey of brace-stripping problems. Nearly +everyone, including myself, had missed a lurking flaw of that kind in +the first submitted version of their solution. Another good idea of +Donald's that caught my fancy was to use TeX's built-in scanning +procedures for \meta{optional space} to strip the leading space in +\cmd{\trimspaces}. I managed to work that into my own best solution, much to +my satisfaction. + +Peter Schmitt\index{Schmitt, Peter} came up with perhaps the most +aerodynamic solution, on his second go-round. A solution by +Ian Collier\index{Collier, Ian} differed notably from +the others by using \cmd{\meaning} to look for a leading space. Another +submission, from +Gary McGary\index{McGary, Greg}\index{McGary, Gary|see{McGary, Greg}} +\ed{I think this is a typo for Greg McGary}, contained some +original syntactic ideas, +and explored the more general problem of removing an arbitrary token +pattern at the end of a token list. + +A careless, off-the-cuff remark of mine in the statement of Exercise +15 that after removing a leading space, \cmd{\trimspaces} should call +\cmd{\trimspace} to remove a trailing space, was probably a mistake. In most +cases, at least, \cmd{\trimspaces} can be more elegantly written by letting +the two different space-removal procedures share a few tokens at a +lower level. + +From Donald's\index{Arseneau, Donald} analysis: +\begin{quote} + When I first read the question, I thought `why isn't there an answer + with the question, because that one is easy?' As I started to type + my answer `cold', I realized that what I had used previously to + ignore leading spaces +\begin{lcode} + \def\something#1#2\weird{#1#2} +\end{lcode} + had the bad + side-effect of stripping braces if the parameter began with `\verb?{?'. +\end{quote} + +I append below Peter Schmitt's\index{Schmitt, Peter} +solution, more or less as he wrote it. +The commentary refers to earlier correspondence in a place or two but I +believe there is sufficient context to make everything intelligible. +Test \#5 in the test suite traps the insidious brace-stripping problem +that infested most of the solutions in their first incarnation. + +\begin{comment} +More on Exercise 15 to follow, some time in the next few days. + +Michael Downes, mjd@math.ams.org + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\end{comment} + +\begin{solution}{Solution 1 (Peter Schmitt)} +%%>>Solution 1 (Peter Schmitt, a8131dal@awiuni11.edvz.univie.ac.at) + +Since I wanted to stay with delimited arguments it was clear that one +has to add a token (or tokens) in order to hide braces, which finally +have to be removed again. First I came up with using \cmd{\empty}, as you +did, but then I switched to a not expandable token because this can +more efficiently be used as a parameter delimiter. + +\cmd{\trimspaces} and \cmd{\trimspace} are just used to expand the argument and +add delimiting tokens in front and at the end of it, and set up the +delimiting tokens for \cmd{\Trimspace} and \cmd{\Trimspaces}, too. + +As Donald does, I do not call \cmd{\trimspace} by \cmd{\trimspaces} but rather +\cmd{\Trimspace} by \cmd{\trimspaces}. It would be easy to offer \cmd{\TrimLeft} +\cmd{\TrimRight} and \cmd{\TrimBoth} and also \cmd{\TrimLeftS} \cmd{\TrimRightS} and +\cmd{\TrimBothS} which iterate in the (very unlikely!) case that there are +several consecutive space tokens. + +\cmd{\Trimspaces} and \cmd{\Trimspace} remove leading, respectively trailing, +spaces of the argument, but they both leave the delimiting tokens in +place. These (and outside tokens) are removed by \cmd{\TrimSpace} in the +process of redefining the initial controlsequence. +\begin{lcode} +\catcode`\<=3 \catcode`\>=3 + +\def\trimspace #1{\expandafter\expandafter\expandafter + \Trimspace\expandafter <#1> >\\#1} +\def\trimspaces #1{\expandafter\expandafter\expandafter + \Trimspaces\expandafter <#1>< <\\#1} + +%% \Trimspaces < text>< <\\ |< text>| ==> +%% -> || + |text> + | <| +%% => ||+| <|+|text>| == | <text>| +%% +%% \Trimspaces <text>< <\\ |<text>| ==> +%% -> |<text>| + || + || +%% => |<text>|+||+|| == |<text>| + +%% \Trimspace <text > >\\ |<text >| ==> +%% -> |<text| + | >| +%% => |<text|+>\\ == |<text>\\| +%% +%% \Trimspace <text> >\\ |<text>| ==> +%% -> |<text>| + || +%% => |<text>|+>\\ == |<text>>| + +\def\Trimspaces #1< #2<#3\\{\Trimspace #1#3#2 >\\} +\def\Trimspace #1 >#2\\{\TrimSpace #1>\\} +\def\TrimSpace #1>#2\\#3{% + \expandafter\expandafter\expandafter\expandafter\expandafter + \def \expandafter\expandafter\expandafter #3\expandafter + {\Remove#1}} + \def\Remove#1{} + +\catcode`\<12 \catcode`\>=12 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\def\Test#1{\def\test{#1}\immediate\write0{|\test|}% + \trimspaces\test + \immediate\write0{|\test|}% + } +\let\trim\trimspace +\let\trim\trimspaces + +%%%%%%%%%%%%%%%%%%%%%%%%% + +\Test{} +\Test{ } +\Test{ a } +\Test{ {}{} } +\Test{{braces}} +\Test{ {braces} } +\Test{ { braces } } +\Test{no space and no space} +\Test{no space and a space: } +\Test{ :a space and no space} +\Test{ :a space and a space: } + +\def\test{ \ifx/ }\trimspace\test\show\test +\def\test{ \ifx }\trimspaces\test\show\test + +\end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\end{lcode} + +\end{solution} + +%%\endinput +\begin{comment} +Date: 23 Dec 1993 16:21:21 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #15, answers, 2nd installment +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +Some exposition seems called for here in order to lay out various +considerations running through my mind and the minds of the other +solution-submitters. + + +\subsection{Trimming a trailing space} + +There are two possible ways to remove a trailing space. The first one +is to step through the given text one token at a time, and construct a +new token list in parallel by adding the tokens one by one at the end. +If the next token is a space, delay adding it until the subsequent +token is checked, and if it turns out the text is exhausted, discard +the space instead of adding it. The hard part about this approach is +dealing with braces (character tokens with catcode 1 or 2) because a +lone brace cannot be passed as a macro argument. A recent posting by +\'Eamonn McManus to comp.text.tex on a different sort of problem +showed that the braces can indeed be dealt with, it's just not easy. + +The second, simpler approach is to use TeX's scanning of delimited +macro arguments to scan for the ending space and discard it. If you +merely scan for a space token, however, you end up scanning through +the given text `word' by `word' (word = sequence of non-space +characters or brace-delimited groups) instead of token by token, which +is perhaps if anything even more awkward than the first method above, +since you still must deal with brace complications. + +The key refinement, therefore, is to scan for a pair of tokens: a +space token and some well-chosen bizarre token that can't possibly +occur in the scanned text. If you put the bizarre token at the end of +the text, and if the text has a trailing space, then TeX's delimiter +matching will match at that point and not before, because the earlier +occurrences of space don't have the requisite other member of the pair. + +Next consider the possibility that the trailing space is absent: TeX +will keep on scanning ahead for the pair \meta{space}\meta{bizarre} until either +it finds them or it decides to give up and signal a `Runaway +argument?' error. So you must add a stop pair to catch the runaway +argument possibility: a second instance of the bizarre token, preceded +by a space. If TeX doesn't find a match at the first bizarre token, it +will at the second one. + +Now all that's left is to test somehow where the hit occurred in order +to fork properly. This can be done in various clever ways, as +exhibited in the solutions. + +%%\endinput + +\subsection{Trimming a leading space} + +More analysis from Donald Arseneau: +\begin{quote} + There are two safe, expandable ways to eat `one optional space': + `\piif{ifnum}' using an ascii code (\texttt{`c}) as the second number, and + `\piif{ifdim}' using a literal unit of measure like `pt'. Oh, yes, + it could also be done with parameter syntax too, but more on + that later. +\end{quote} + +%%\endinput + +In other words, one way to remove a leading space would be +\begin{lcode} + \expandafter\def\expandafter\foo\expandafter{\ifdim0pt=0pt\foo \fi} +\end{lcode} +The \cmd{\expandafter}'s would cause the \piif{ifdim} to be executed first. +Execution of the \piif{ifdim} will not terminate until the scanning of the +second `0pt' is finished; therefore TeX will start expanding \cmd{\foo} as +part of the scanning of the `0pt'. Then if a space is the first thing +inside the expansion of \cmd{\foo}, it will be removed by TeX as denoting +the end of the dimension. Otherwise the first non-space token will +terminate the dimension scanning and will be left in place (well, I am +glossing over the problem of an expandable token at the beginning of +\cmd{\foo}, which can be handled by further refinements). + +Notice that as written the trailing \piif{fi} will be included in the +redefinition of \cmd{\foo}. No problem---just rewrite it with the \piif{fi} +after the closing brace: +\begin{lcode} + \expandafter\def\expandafter\foo\expandafter{\ifdim0pt=0pt\foo}\fi +\end{lcode} + +[Now for a sharp little question: will that work with \cmd{\edef} instead of +\cmd{\def}? +\begin{lcode} +\edef\foo{\ifdim0pt=0pt\foo}\fi +\end{lcode} +See if you can guess before +testing it.] + +%%\endinput + +%%\begin{verbatim} +Other ways of removing a leading space include using \cmd{\futurelet} to +look at the first token in the scanned text, or using TeX's argument +delimiter scanning to scan for a space. The latter method is perhaps +most straightforwardly done as a mirror-image of the method for +removing a trailing space: make the delimiter \meta{bizarre}\meta{space}, and +then call the macro (let's say \cmd{\trimx}) by putting \meta{bizarre} before +the +scanned text and a stop pair \meta{bizarre}\meta{space} after it, in case a +leading space is not present: +\begin{lcode} + \trimx<bizarre>#1<bizarre> \endtrimx +\end{lcode} +It would be possible to do without the bizarre token and have the +delimiter consist only of a space, but with some ensuing +complications, I think, that would make it scarcely worthwhile. + +\subsection{Some remarks about the domain of the problem} + +The application I had in mind was, generally speaking, to remove +unwanted spaces at the beginning and end of a piece of text supplied +by the user, such as a section title or other heading. + +Typical situation: A user command \cmd{\title} takes an argument +\begin{lcode} + \title{ Some Article Title } +\end{lcode} +with the definition of \cmd{\title} being +\begin{lcode} + \def\title#1{\def\savedtitle{#1}\trimspaces\savedtitle} +\end{lcode} + +Thereafter we may use \cmd{\savedtitle} in any number of ways: print it; put +it in a \cmd{\mark} for running heads; write it to an auxiliary file for +table of contents use, or for adding to a BibTeX database; or write it +on screen to show progress when typesetting a collection of articles. +For the last two examples in particular trimming spaces with +\cmd{\ignorespaces} or \cmd{\unskip} is undesirable. + +Notice also that \cmd{\unskip} will remove \emph{any} trailing glue, including +\cmd{\leader}'s or explicit \cmd{\hskip}'s that might sometimes be added by +users for their own inscrutable purposes and whose unexpected +removal could be (indeed, has been in true life) the cause of +much consternation. + +If we call \cmd{\trimspaces} in the definition of \cmd{\title}, then leading and +trailing spaces are removed once and for all, and none of the many +functions that later use \cmd{\savedtitle} need to worry about that task. + +With this restricted domain of use in mind for \cmd{\trimspaces}, I screened +the submitted solutions through the following conditions. + +\begin{description} +\item[Condition 1] The text has been stored in a macro. The result of +\cmd{\trimspaces} is a redefinition of the macro. + +This is not exactly a necessary condition, but removal of this +condition would suggest that constructions like +\begin{lcode} + \def\foo#1{... + \message{Your argument "\trimspaces{#1}" makes me laugh}% + ...} +\end{lcode} +should be supported. The full expansion done by \cmd{\message} or other such +commands, however, can't be applied carelessly to arbitrary +user-supplied text. You would need to deactive problematic elements +(by changing catcodes, adding \cmd{\protect}'s, whatever). So supporting +full expansion for the operand of \cmd{\trimspaces} is of low relevance for +the envisioned normal applications. + +\item[Condition 2] It suffices to remove a single space before and after the +text. + +In almost any other programming language, a typical space-trimming +function would need to handle the possibility of multiple consecutive +spaces. But in text supplied by an average user through the normal TeX +lexical conventions, consecutive spaces will be reduced to a single +space before our trimming functions are ever called. + +The next installment of this `summary' will include a recently arrived +solution by Jonathan Fine\index{Fine, Jonathan} +that handles multiple trailing spaces as +easily as a single one, without any extra implementation cost. + +\item[Condition 3] For both the trailing space and the leading space, we +don't know whether or not they are present. + +If we knew for certain that a given space was present, of course, the +procedure for removing it would be easier. +\end{description} + +%%======================================================================== +%%>>Solution 2 (Ian Collier) [Ian.Collier@prg.oxford.ac.uk] +%\begin{description} +\begin{solution}{Solution 2 (Ian Collier)}\index{Collier, Ian} + +\ldots I used \cmd{\meaning} to find out whether or not the +first character of the argument is a space (because spaces are usually +ignored and this seems to be the only way to make the space visible). +I'm fairly sure that `blank space' is the only \cmd{\meaning} beginning with +`bl'. I had rather a lot of trouble with braces, because if the first +character is a brace then \cmd{\meaning} removes it and leaves an unmatched +right brace. However I finally realised that \verb?\iffalse...\fi? could be +used to remove it. +\begin{lcode} +{\catcode`Q=3 \catcode`@=11 + \gdef\trimspace#1{\expandafter\trimspac@a#1QAA QB} + \gdef\trimspac@x#1{\trimspac@a#1QAA QB} + \gdef\trimspac@a#1 Q#2{\if#2A#1\expandafter\trimspac@b + \else\trimspac@c#1\fi} + \gdef\trimspac@b A QB{} + \gdef\trimspac@c#1QAA{#1} + + \gdef\trimspaces#1{\expandafter\expandafter\expandafter\tr@a + \expandafter\meaning#1A\fi{#1}} + \gdef\tr@a#1#2{\if#1b\if#2l\expandafter\expandafter\expandafter\tr@c + \else\expandafter\expandafter\expandafter\tr@b\fi\else + \expandafter\tr@b\fi} + \gdef\tr@b{\expandafter\trimspace\iffalse} + \gdef\tr@c{\expandafter\tr@d\iffalse} + \gdef\tr@d#1{\expandafter\tr@e#1Q} + \def\:{\gdef\tr@e}\: #1Q{\trimspac@x{#1}} +} + +\def\test#1{\edef\text{#1}\immediate\write16 {"\trimspaces\text"}} +\test{ Leading space} +\test{Trailing space } +\test{ Leading and trailing spaces } +\test{Nospaces} +\test{ {braces}Leading space{braces}} +\test{{braces}Trailing space{braces} } +\test{ {braces}Leading and trailing spaces{braces} } +\test{{braces} Nospaces {braces}} +\test{} +\test{ } +\test{\space\space{two spaces}\space\space} + +\end +\end{lcode} +%%======================================================================== + +Comments: Some extra work would be necessary to handle the possibility +\begin{lcode} + \def\text{\iftrue a\else b\fi} + \trimspaces\text +\end{lcode} +because removal of the \piif{iftrue} by \cmd{\meaning} will leave the +\piif{else} and \piif{fi} unmatched, confusing the later \piif{iffalse} +step done by \cmd{\tr@b}, \cmd{\tr@c}. +But such a value for \cmd{\text} is rather unlikely in ordinary +user-supplied arguments. +%\end{description} +\end{solution} + +\begin{comment} +Some more solutions to Exercise 15 will follow in a few days. + +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + +Date: 30 Dec 1993 17:07:17 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #15, answers, 3rd installment +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} +%$ + +I have done some slight condensing in the answers, indicated by +\verb?[...]?. + +Solution 3 by Greg McGary contains an interesting idea for an +alternative syntax of the \cmd{\trimspaces} function: Instead of writing +\begin{lcode} + \def\savedtitle{#1}\trimspaces\savedtitle +\end{lcode} +you would write +\begin{lcode} + \trimmed\def\savetitle{#1} +\end{lcode} +%%======================================================================== +%%>>Solution 3 (Greg McGary, gkm@tmn.com) +%\begin{description} +\begin{solution}{Solution 3 (Greg McGary)}\index{McGary, Greg} +\begin{lcode} +%%% preliminaries: (Mad about those abbreviations!) +\catcode`@=11 +\let\ea=\expandafter +\let\nx=\noexpand +\let\ag=\aftergroup +\def\agg{\ag\ag\ag} +\let\bg=\begingroup +\let\eg=\endgroup + +[...] + +%%% The underlaying tool I use is \trimmed, which is used as a modifier for +%%% macro definitions to trim the trailing space from the body: +%%% \trimmed\def\foo{foo } will set \foo to {foo} +%%% Notice that any form of \def modifier may be interposed between \trimmed +%%% and \def, as in \trimmed\global\long\outer\def\foo{foo } +%%% +%%% As an aside, TeX has no \expanded modifier. Expanded definitions +%%% must be accomplished through use of \edef or \xdef (equivalent to +%%% \global\edef) This is annoying, as we might like to use \trimmed with +%%% expanded definitions and don't want to write a separate \etrimmed. +%%% Luckily, we can easily roll our own \expanded modifier, like so: + +\def\expanded#1\def{#1\edef} + +%%% Other modifiers may optionally be inserted between \expanded and +%%% \def, like so: \def\foo{foo} \outer\expanded\long\def\bar{\foo} + +%%% Here's the definition of \trimmed: + +\long\def\trimmed#1\def#2#3{\bg + \long\def\!##1##2 \!##3\trimmed@{\eg + \ifx\relax##3\relax + \trimmed@{##1}##2% + \else + ##1{##2}% + \fi}% + \!{#1\def#2}#3\! \!\trimmed@} + +\long\def\trimmed@#1#2\!{#1{#2}} + +%%% Notice the use of \begingroup...\endgroup to make the definition of \! +%%% temporary so as not to disturb any previous definition, and so that the +%%% temporary will disappear once we're done with it. Notice that the +%%% \endgroup appears right away in the body of \!, so that the ensuing \def +%%% will occur in the proper group. \! was chosen as a name for the temporary +%%% macro because it is a non-alphabetic (non-catcode-11) character; any other +%%% non-alphabetic would suffice as well. Non-alphabetic macro-names have the +%%% desirable property of preserving any trailing space token. +%%% +%%% If we are really fastidious about keeping clutter out of the global name +%%% space, we can also define \trimmed@ as a temporary alongside \!. We would +%%% also want to use a name that's already defined, to avoid entering a new +%%% name into TeX's hashtable. A non-alphabetic name like \: seems like a +%%% good (though cryptic) choice: + +\long\def\trimmed#1\def#2#3{\bg + \long\def\:##1##2\!{\eg##1{##2}} + \long\def\!##1##2 \!##3\:{% + \ifx\relax##3\relax + \:{##1}##2% + \else + \eg##1{##2}% + \fi}% + \!{#1\def#2}#3\! \!\:} + +%%% Notice that we've had to delay the \endgroup until after our new +%%% temporary \: has been used. +%%% +%%% Anyway, we may now define \trimspace as follows: + +\def\trimspace#1{\ea\trimmed\ea\def\ea#1\ea{#1}} + +%%% Notice that the replacement definition is a normal \def, whereas the +%%% macro we started with could have had any number of modifiers attached, +%%% such as \long, \outer, or \global. A further exercise might be to fix +%%% this problem. +%%% +%%% A more generalized trim might allow any list of tokens to be trimmed off +%%% the tail of another list of tokens. Here, we add an initial argument to +%%% \trimmed specifying those tokens. In order to strip off trailing ".\par" +%%% for instance, we could write: \trimmed{.\par}\outer\long\def\foo{foo.\par} +%%% +%%% Here's the general definition of \trimmed: + +\long\def\trimmed#1#2\def#3#4{\bg + \long\def\:##1##2\!{\eg##1{##2}} + \long\def\!##1##2#1\!##3\:{% + \ifx\relax##3\relax + \:{##1}##2% + \else + \eg##1{##2}% + \fi}% + \!{#2\def#3}#4\!#1\!\:} + +%%% The auxiliary \trimmed@ remains unchanged. Notice that we no longer really +%%% need a non-alphabetic macro name for the temporary macro, since we don't +%%% have to preserve the literal space token following the macro. +%%% +%%% Unfortunately, the literal space token problem doesn't disappear, it's just +%%% pushed up a level. Now we have to give that space as an argument to \trimmed +%%% in the definition of \trimspace, and hop over it with \expandafter! + +\edef\trimspace#1{\nx\ea\nx\trimmed\nx\ea + {\nx\ea\space\nx\ea}\nx\ea\def\nx\ea#1\nx\ea{#1}} + +%%% N.B., The curly braces, "\nx\ea{...\nx\ea}" around the "\nx\ea\space" +%%% are necessary. +%%% +%%% This approach of defining \trimspace in terms of an underlaying \trimmed +%%% \def'inition facility has the advantage of reusing code, but the +%%% disadvantage of forcing a macro redefintion even if there is no trailing +%%% space to remove. We could modify \trimmed to produce a new macro, \trim, +%%% that redefines a macro only if it has the trailing pattern of interest. +%%% (It also happens to be simpler!) + +\long\def\trim#1#2{\bg + \long\def\!##1#1\!##2\:{\eg + \ifx\relax##2\relax \else + \def#2{##1}% + \fi}% + \ea\!#2\!#1\!\:} + +%%% Now, we can define \trimspace in terms of \trim like so: + +\edef\trimspace#1{\nx\ea\nx\trim\nx\ea{\nx\ea\space\nx\ea}\nx\ea#1} + +%%% Ok, let's test it: + +\def\HasTrailingSpace{has trailing space } +\def\NoTrailingSpace{no trailing space} + +\trimspace\HasTrailingSpace \show\HasTrailingSpace +\trimspace\NoTrailingSpace \show\NoTrailingSpace + +%%% While we're at it, let's test another pattern: + +\def\HasTrailingDotPar{has trailing dot par.\par} +\def\NoTrailingDotPar{no trailing dot par} + +\trim{.\par}\HasTrailingDotPar \show\HasTrailingDotPar +\trim{.\par}\NoTrailingDotPar \show\NoTrailingDotPar + +%%% ### Exercise 15(b) +%%% Write a macro \trimspaces that removes a leading space, if +%%% present, and then calls \trimspace to remove a trailing space. + +%%% I'm going to solve this in a quick and dirty way, as it's getting +%%% late and I'm running out of gas! Just use \futurelet sequestered +%%% in a \vbox to inspect the first token. If it's a \space, gobble +%%% the first token and subject the remaining tokens to \trimmed. + +\def\redefSansSp@ce#1 #2\redefSansSp@ce{\def#1{#2}} +\def\redefSansSpace#1{\ea\redefSansSp@ce\ea#1#1\redefSansSp@ce} +\def\trimspaces#1{\bg\setbox0=\vbox{% + \def\maybeRedefSansSpace{\ea\ifx\space\@\agg\redefSansSpace\agg#1\fi}% + \ea\futurelet\ea\@\ea\maybeRedefSansSpace#1}\eg + \trimspace#1} + +%%% \futurelet won't work for the more general case of trimming an +%%% arbitrary leading pattern, as it only looks at one token. +%%% I'll leave solving the general case as an exercise for the reader ;-) +%%% +%%% This is also not the most efficient solution, since we redefine the macro +%%% twice if there is a leading space. Notice that we put the \setbox0 +%%% inside a group, to keep any previous definition of \box0 safe. This +%%% is probably overkill, since \box0 is a temporary register and users +%%% should be aware that it's fair game, but it doesn't hurt to be +%%% courteous... Also note the abbreviation \agg, which pushes its argument +%%% out two groups. + +[...] + +%%% Testing... + +\def\foo{ foo } +\trimspaces\foo \show\foo +\end{lcode} + +\end{solution} + +%%======================================================================== + +In the previous posting I discussed the method of removing a trailing +space by scanning for a token pair \meta{space}\meta{bizarre}. In Schmitt's +solution, for example, the bizarre token was a greater-than character +with catcode 3. And in my solution, I used a letter Q with catcode +3. Solution 4 from Jonathan Fine takes the approach of using a second +\meta{space} token for the \meta{bizarre} token. In practice this works for +typical user-supplied text, as discussed before, since TeX's normal +reduction of multiple spaces to single spaces makes the pair +\meta{space}\meta{space} sufficiently bizarre. I have to admit I like this idea; +those who attempted a solution for this exercise and struggled with +various other delimiter possibilities will, I think, appreciate the +humor of it as I did. + +As I mentioned last week, I found some theoretical interest in the +fact that if multiple space tokens were present at the end of the text +being trimmed, Fine's solution would remove them all, without needing +to use recursion. But another correspondent pointed out since then +that if multiple spaces were present at the end they might also be +presumed possible in the middle of the scanned text, and an occurrence +of multiple spaces in the middle would cause \cmd{\trim} to fail. + + + +\begin{solution}{Solution 4 (Jonathan Fine)}\index{Fine, Jonathan} +\begin{lcode} +%% NOTE: I have benefited from Michael Downes posting of answers, dated +%% 16 December, particularly for stripping the leading space, and the +%% discussion of the hazards of grouped arguments + +\catcode`\@=11 +%% The Solution +\def\trim #1{\expandafter\trim@\expandafter{#1 }#1} +\def\trim@ #1{\trim@@ @#1 @ #1 @ @@} +\def\trim@@ #1@ #2@ #3@@{\trim@@@\empty #2 @} +\def\unbrace#1{#1} +\unbrace{\def\trim@@@ #1 } #2@#3{\expandafter\def + \expandafter #3\expandafter {#1}} + +%% Test Code +\def\Test{\afterassignment\Test@ \def\test} +\def\Test@{\trim\test \afterassignment\Test@@ \def\test@} +\def\Test@@{\message{\ifx\test\test@ Y\else FAIL:|\meaning\test|\fi}} +\catcode`\@=12 + +%% Testing The Solution +\Test{}{} +\Test{ }{} +\Test{ a }{a} +\Test{ {}{} }{{}{}} +\Test{{braces}}{{braces}} +\Test{ {braces} }{{braces}} +\Test{ { braces } }{{ braces }} +\Test{no space and no space}{no space and no space} +\Test{no space and a space: }{no space and a space:} +\Test{ :a space and no space}{:a space and no space} +\Test{ :a space and a space: }{:a space and a space:} +\Test{ \ifx }{\ifx} +\Test{ \ifx/ }{\ifx/} +\end{lcode} +\end{solution} + +\begin{comment} +Since my solution got rather long after I added some commentary I'll +post it separately in a couple of days, rather than double the size of +this post. + +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + +Date: 03 Jan 1994 17:14:14 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #15, answers, 4th (last) installment +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} +%$ + +My solution here is the result of weeks of incremental refinement, +ending only last week, and consequently benefits from analysis of the +other solutions. + +%%======================================================================== +\begin{solution}{Solution 5 (Michael Downes)} +\begin{lcode} +% Here I only solve part (b) of Exercise 15, in an attempt to make +% a solution of utmost compactness (3 control sequences, 45 tokens). +% Also, it seems likely that in actual use \cmd{\trimspaces} can be +% applied without harm whenever \trimspace might be needed. +% +% The method for pausing after each test might be of ancillary +% interest to some readers; unlike the alternative of setting +% \pausing=1, the \test's aren't required to be on separate lines. + +\catcode`\Q=3 + +% \cs{trimspaces}\x redefines \x to have the same replacement text sans +% leading and trailing space tokens. +% +\def\cs{trimspaces}#1{% +% Use grouping to emulate a multi-token afterassignment queue. + \begingroup +% Put `\toks 0 {' into the afterassignment queue. + \aftergroup\toks\aftergroup0\aftergroup{% +% Apply \trimb to the replacement text of #1, adding a leading +% \noexpand to prevent brace stripping and to serve another purpose +% later. + \expandafter\trimb\expandafter\noexpand#1Q Q}% +% Transfer the trimmed text back into #1. + \edef#1{\the\toks0}% +} + +% \trimb removes a trailing space if present, then calls \trimc to +% clean up any leftover bizarre Qs, and trim a leading space. In +% order for \trimc to work properly we need to put back a Q first. +% +\def\trimb#1 Q{\trimc#1Q} + +% Execute \vfuzz assignment to remove leading space; the \noexpand +% will now prevent unwanted expansion of a macro or other expandable +% token at the beginning of the trimmed text. The \endgroup will feed +% in the \aftergroup tokens after the \vfuzz assignment is completed. +% +\def\trimc#1Q#2{\afterassignment\endgroup \vfuzz\the\vfuzz#1} + +\catcode`\Q=11 + +\def\test#1{\errhelp{#1}\message{[\the\errhelp]}% + \edef\x{\the\errhelp}% + \global\tracingcommands2\global\tracingmacros2\global\tracingonline0 + \cs{trimspaces}\x + \global\tracingcommands0\global\tracingmacros0\global\tracingonline0 + \errhelp\expandafter{\x}\message{-> [\the\errhelp]}% + \read16 to\PressReturnToContinue +} + +\test{ x } \test{ xy z } \test{} \test{{}} +\test{{}{}} \test{ {x} } \test{ } \test{{ }} +\test{\AA} \test{\fi} \test{\space x\space} +\test{ #1 } + +\end +\end{lcode} + +Commentary + +Suppose we have a macro \cmd{\x} with replacement text \verb?" {xyz} "?. +The task of +\cmd{\trimspaces} is to construct a statement of the form +\begin{lcode} + \def\x{{xyz}} +\end{lcode} +i.e., to redefine \cmd{\x} with the same replacement text except for removal +of a leading or trailing space. However, a similar statement +\begin{lcode} + \toks0{{xyz}}\edef\x{\the\toks0} +\end{lcode} +is more robust if the replacement text might contain \# tokens. For +example, +\begin{lcode} + \def\x{\def\y##1{}} +\end{lcode} +works OK but after thus defining \cmd{\x}, the statements +\begin{lcode} + \def\trimx#1{\expandafter\def\expandafter\x\expandafter{#1}} + \trimx\x +\end{lcode} +fail with an error message because the `\#1' in the definition of \cmd{\y} is +misinterpreted as a parameter token for the redefinition of \cmd{\x}. + +Although \# tokens seem highly unlikely in average user-supplied text, I +aimed for a statement of the second, robuster kind, as if I were writing +\cmd{\trimspaces} for use in a major macro package with thousands of +prospective users. + +The basic structure of \cmd{\trimspaces} is therefore: First remove a trailing +space, then remove a leading space, then put the remaining text into +\cmd{\toks}\texttt{0}, then transfer the text to \cmd{\x} with \cmd{\edef}. + +For removing the trailing space, I apply a macro scan with delimiter +\verb?<space,10><Q,3>? Here the notation \verb?<c,n>? means the character token +consisting of character code \texttt{c} with catcode \texttt{n}. + +The leading space is removed by executing the assignment +\verb?\vfuzz=\the\vfuzz? at the beginning of the operand text, in order to use +a side effect of the assignment: removal of a following space. (Credit +to Donald Arseneau for this good idea.) The main reason for using +\verb?\the\vfuzz? instead of 0pt is that it's slightly shorter (one token), +although if we did not have the group structure to localize the `change' +to \cmd{\vfuzz}, then using \verb?\the\vfuzz? would also be a good idea for the +sake of preserving the variable's previous value. + +The statement \verb?\vfuzz=\vfuzz? (sans \cmd{\the}), by the way, would not gobble a +following space: when TeX recognizes a suitable variable on the +right-hand side of an assignment, it copies the value directly into the +left-hand side and skips the scanning process entirely. + +Here's a step-by-step breakdown of the operation of \cmd{\trimspaces} through +two possibilities, one where both a leading and a trailing space are +present, and one where neither are present. +\begin{lcode} +------------------------------------------------------------------------ +Case 1 (spaces present) Case 2 (no spaces to be removed) +------------------------------------------------------------------------ +\def\x{ {xyz} } \cs{trimspaces}\x \def\x{{xyz}} \cs{trimspaces}\x + +Step 1: Step 1: +\begingroup... Same as for Case 1. +\expandafter\trimb +\expandafter\noexpand\x Q Q}... + +Step 2: || Step 2: || +\trimb\noexpand {xyz} Q Q... \trimb\noexpand{xyz}Q Q... + ^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^ +Here the row of ^^^ indicates the In this case the first Q is taken +material that is taken as argument up as part of #1, which is passed +#1 of \trimb, and || indicates the to \trimc. The second Q added by +tokens that match the macro \trimb therefore falls after the +delimiter. #1 is now passed to leftover Q instead of before. +\trimc, with another Q token added; +the leftover <space>Q token pair +follows. + +Step 3: | Step 3: | +\trimc\noexpand {xyz}Q Q... \trimc\noexpand{xyz}QQ... + ^^^^^^^^^^^^^^^ ^^ ^^^^^^^^^^^^^^ ^ +Here we have #1, delimiter token Q, The situation at the end of the +and #2. The space before the second trimmed text ends up being the same +Q is skipped by TeX because it's as in Case 1, except for the +looking for a nondelimited argument absence of a space between the Qs. +for #2. + +Step 4: Step 4: +\afterassignment\endgroup \afterassignment\endgroup +\vfuzz\the\vfuzz\noexpand {xyz}}... \vfuzz\the\vfuzz\noexpand{xyz}}... + ^ +Here the ^ marks the leading space +that is to be removed. + +Step 5: \endgroup{xyz}}... Step 5: \endgroup{xyz}}... + +\endgroup is from \afterassignment. + +Step 6: Step 6: +\toks0{{xyz}} \toks0{{xyz}} +^^^^^^^---from \aftergroup ^^^^^^^---from \aftergroup +\edef\x{\the\toks0} \edef\x{\the\toks0} +\end{lcode} + +\end{solution} + +\begin{comment} +======================================================================== + +That's a wrap on Exercise 15. + +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ +%%\endinput + + +\chapter{Assorted numbers, skips, and modes} + +\section{Exercise} + +%%\input{ex016} +% ex016.tex +\begin{comment} +Date: 13 Jan 1994 16:42:27 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #16 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> + +************************************************************************ +*** Exercise 16: +\end{comment} + +\ed{\oposted{1994/01/13}. \arch{exercise.016}.} + +Predict the messages that will be produced by plain TeX for the +following test file. +\begin{lcode} +\catcode`\@=11 \newcount\m +\def\msg#1{\advance\m 1 \message{(\number\m): #1}} +\def\T{\msg{T}}\def\F{\msg{F}} +\mag=1728 \hfuzz=1pt \tabskip=1pt \baselineskip=12pt +\topskip=10pt \lineskiplimit=1pt \lineskip=1pt + +\setbox0\vbox{% +\mag=\time \ifnum\mag>1500 \T\else\F\fi % (1) +\mag=\number\year \ifnum\mag>1500 \T\else\F\fi % (2) +\hfuzz=99pt \ifdim\hfuzz=99pt \T\else \F\fi % (3) +\tabskip=\z@ \ifdim\tabskip<\p@\T\else\F\fi % (4) +\tabskip=\p@ minus2pt \ifdim\tabskip>\z@\T\else\F\fi % (5) +\baselineskip=-\prevdepth \ifdim\baselineskip=12pt \T\else\F\fi % (6) +\advance\baselineskip 2\topskip % (7) + \ifdim\baselineskip>\@m\p@ \T\else\F\fi % +\lineskiplimit=\z@ \ifnum\lineskiplimit>0 \T\else\F\fi % (8) +\lineskip=\z@skip \ifdim\lineskip>\lineskiplimit \T\else\F\fi % (9) +\kern2pc\ifdim\lastkern=2pc \T \else\F\fi % (10) +\hskip1em + \ifvmode\T\else\ifdim\lastskip>\z@\msg{FT}\else\msg{FF}\fi\fi % (11) +\font\cmrtest=cmr10 \ifx\cmrtest\tenrm \T\else\F\fi % (12) +} +\end +\end{lcode} +Where should \cmd{\relax} be inserted? + +\begin{comment} +************************************************************************ + +Answers will be posted circa January 27, 1994. + +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ +%%\endinput + + +\section{Answers} + +%%\input{ans016} +% ans016.tex +\begin{comment} +[There was an error in the first posted version: \twelverm instead of +the first \tenrm in the statement + + \font\tenrm = \fontname\tenrm scaled 1200 + +The posting containing this correction is appended below.] + +Date: 27 Jan 1994 11:59:48 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #16, answers +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1994/01/27}. \arch{answer.016}.} + +Here is my commentary on Around the Bend \#16. +\begin{lcode} +% \mag=1728 \hfuzz=1pt \tabskip=1pt \baselineskip=12pt +% \topskip=10pt \lineskiplimit=1pt \lineskip=1pt + +% \mag=\time \ifnum\mag>1500 \T\else\F\fi % (1) +\end{lcode} +(1): F --- At the time of the \piif{ifnum}, \cmd{\mag} is in the range [0,1440) +depending on what time it was when you ran TeX. + +\begin{lcode} +% \mag=\number\year \ifnum\mag>1500 \T\else\F\fi % (2) +\end{lcode} +(2): F --- At the time of the \piif{ifnum}, \cmd{\mag} still has its previous value +because TeX is still scanning for digits to add on after `1994'. + +\begin{lcode} +% \hfuzz=99pt \ifdim\hfuzz=99pt \T\else \F\fi % (3) +\end{lcode} +(3): T --- Everything fine, dimension scanning terminated with the +space after `99pt'. + +\begin{lcode} +% \tabskip=\z@ \ifdim\tabskip<\p@\T\else\F\fi % (4) +\end{lcode} +(4): F --- \cmd{\z@} is a dimension register, therefore it serves only as the +first part of the glue value that TeX is looking for. At the time of the +\piif{ifdim}, TeX is still looking for `plus' or `minus' and hasn't yet +finished the assignment of \cmd{\tabskip}. + +\begin{lcode} +% \tabskip=\p@ minus2pt \ifdim\tabskip>\z@\T\else\F\fi % (5) +\end{lcode} +(5): T --- Glue value scanning terminated properly. \cmd{\p@} is a dimension +register like \cmd{\z@} but the additional clause `minus 2pt' fills out the +glue value to the required three parts. TeX assumes `plus 0pt' when it +finds a `minus' clause without a preceding `plus' clause. Note that TeX +does \emph{not} continue scanning for a possible `plus' after reading a minus +component. Unlike the height, depth, and width components of a \cmd{\vrule} or +\cmd{\hrule}, the components of a glue value have a required order and each +part can only occur once. + +\begin{lcode} +% \baselineskip=-\prevdepth \ifdim\baselineskip=12pt \T\else\F\fi % (6) +\end{lcode} +(6): T --- At the beginning of a vbox or at the beginning of a TeX run +\cmd{\prevdepth} = -1000pt. So it would seem that \cmd{\baselineskip} should get set +to +1000pt and the test should be False; but \cmd{\prevdepth} is a dimension +register, not a glue register, so following stretch or shrink components +are still possible, and \cmd{\baselineskip} does not yet have its new value at +the time of the test. + +\begin{lcode} +% \advance\baselineskip 2\topskip % (7) +% \ifdim\baselineskip>\@m\p@ \T\else\F\fi % +\end{lcode} +(7): F --- Without the factor 2 in front of \cmd{\topskip}, the test would +be True: \cmd{\topskip} is a glue register so TeX would copy each component of +\cmd{\topskip} to the corresponding component of \cmd{\baselineskip}; then, having plus +and minus components already in hand, TeX would not scan ahead for +`plus' or `minus'. However, a preceding factor for a glue register +causes TeX to use only the first component of the glue register, +multiplied by the given factor, which means that additional scanning is +then attempted for possible stretch or shrink components. + +\begin{lcode} +% \lineskiplimit=\z@ \ifnum\lineskiplimit>0 \T\else\F\fi % (8) +\end{lcode} +(8): F --- Normal termination of dimension scanning. \cmd{\lineskiplimit} +is a dimen register, not a glue register, so the dimen constant \cmd{\z@} is +sufficient to complete the assignment and TeX scans no further. + +\begin{lcode} +% \lineskip=\z@skip \ifdim\lineskip>\lineskiplimit \T\else\F\fi % (9) +\end{lcode} +(9): F --- Normal termination of glue scanning. \cmd{\z@skip} is a glue +register so it suffices to complete the assignment of \cmd{\lineskip}. Compare +to the \cmd{\tabskip} assignments above. + +\begin{lcode} +% \kern2pc\ifdim\lastkern=2pc \T \else\F\fi % (10) +\end{lcode} +(10): F --- At the time of the \piif{ifdim}, TeX is still looking for +an optional final space at the end of the dimension value `2pc'. If it +were \verb?2\p@? instead of \verb?2pc?, the test would evaluate to True. + +\begin{lcode} +% \hskip1em +% \ifvmode\T\else\ifdim\lastskip>\z@\msg{FT}\else\msg{FF}\fi\fi % (11) +\end{lcode} +(11) FF --- TeX enters horizontal mode as soon as the \cmd{\hskip} command +comes along, before it finishes scanning the skip amount. So the +\piif{ifvmode} test is false. The \piif{ifdim} test is also false because scanning +is not yet complete (TeX is looking ahead for a plus or minus component) +so the glue has not yet been entered into the horizontal list, so it is +not accessible to \cmd{\lastskip}. + +For more on the switch into horizontal mode, see `TeX from \cmd{\indent} to +\piif{par}', Marek Ry{\'c}ko and Bogus{\l}aw Jackowski, TUGboat 14/3, October +1993 (1993 Annual Meeting Proceedings), pp. 171--176. + +\begin{lcode} +% \font\cmrtest=cmr10 \ifx\cmrtest\tenrm \T\else\F\fi % (12) +\end{lcode} +(12) F --- Interestingly, the following versions of the \piif{ifx} test are +also false at that point: +\begin{lcode} + \ifx\cmrtest\undefined, \ifx\cmrtest\relax. +\end{lcode} +The reason is that after `\verb?\font\cmrtest?' TeX immediately sets +\verb?\cmrtest = \nullfont?, before scanning the rest of the font assignment. So the test +\verb?\ifx\cmrtest\nullfont? would yield True. According to the \emph{TeXbook}, +the reason for this behavior is to allow statements of the form +\begin{lcode} + \font\cmrtest=cmr10 \cmrtest +\end{lcode} +for switching to the font \cmd{\cmrtest} immediately after it is defined. TeX +does a bit of boomeranging in such a case: +\begin{lcode} + \font\cmrtest % set \cmrtest = \nullfont + =cmr10 % space terminates font name, start looking for + % "at" or "scaled" + \cmrtest % \cmrtest = \nullfont = nonexpandable, not + % "a", not "s"; terminate the font assignment + % and put back the \cmrtest token to be read + % again: + \cmrtest % Now \cmrtest selects the given font +\end{lcode} +Although I sympathize with Knuth's desire to smooth out a potential +problem for naive users, I wonder if it only encourages users to pay +less attention to the nitty-gritty details of scanning and expansion, +and therefore lay themselves open to greater confusion later on when +something similar fails (inconsistently!) to work. I'd have thought it +better to require, and document, proper termination of font assignment +scanning by \cmd{\relax} or whatever. Users would have to be a little more +knowledgeable but they would be rewarded with a more consistent language +to work with. As it stands TeX unnaturally forbids certain +constructions that are perfectly colloquial to anyone who has an ear for +the TeX language, such as +\begin{lcode} + \font\tenrm = \fontname\tenrm\space scaled 1200 +\end{lcode} +I hold a similar opinion for the way \cmd{\chardef} and \cmd{\mathchardef} set their +arguments to \cmd{\relax} before scanning the number on the right-hand-side of +the assignment. Occasionally I would \emph{like} to be able to write +something like +\begin{lcode} + \chardef\foo=\ifcase\foo 1\or 2\else 3\fi +\end{lcode} + but TeX doesn't allow that. + +One could argue that the \cmd{\chardef} behavior should for consistency be +imitated by \cmd{\edef}, \cmd{\xdef} so that if \cmd{\foo} is undefined then +\begin{lcode} + \edef\foo{a\foo} +\end{lcode} +should not give an undefined control-sequence error for the \cmd{\foo} in the +replacement text, but make it temporarily equivalent to \cmd{\relax} and leave +it there. (Of course, this means that executing \cmd{\foo} will then start up +an infinite loop, but my point was that it's the behavior of \cmd{\chardef} +that should be changed to achieve consistency, not the behavior of +\cmd{\edef}.) + +%%%======================================================================== + +At the end of Exercise \#16 there was the question `Where should \cmd{\relax} +should be inserted?' + +\cmd{\relax} should be inserted just before the \piif{if}... in statements (2), (6), +(7), (11), and (12). In statement (4) \cmd{\z@skip} should be used instead of +\cmd{\z@}; then \cmd{\relax} is unnecessary. A space suffices instead of \cmd{\relax} in +(10). I would also tend to put a \cmd{\relax} at the end of the preliminary +assignments to \cmd{\baselineskip} and \cmd{\lineskip}, as a matter of principle; I +like to make sure that scanning is definitely terminated at the end of a +line, so that if any error occurs during the scanning, TeX will show the +line containing the assignment statement and not a later line. This is +particularly relevant for font assignments: If \pfile{foo10.tfm} does not exist +on your system, then the assignment +\begin{lcode} + \font\foo=foo10 + <blank line> +\end{lcode} +will cause TeX to show you the blank line instead of the preceding line +in the error context: +\begin{lcode} + ! Font \foo=foo10 not loadable: Metric (TFM) file not found. + <to be read again> + \par + l.2 +\end{lcode} +And if the following material is some complicated macro instead of a +blank line, TeX will go into the replacement text of the macro, looking +for `at' or `scaled', before giving the error message! + +\begin{comment} +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ + +Date: 28 Jan 1994 08:01:12 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #16, answers, correction +To: info-tex@shsu.edu + +Instead of + + \font\twelverm = \fontname\tenrm\space scaled 1200 + +read + + \font\tenrm = \fontname\tenrm\space scaled 1200 + +The latter line is what I originally wrote but I changed it in an obtuse +moment a day later, forgetting the very point it was supposed to +illustrate. +\end{comment} +%$ +%%\endinput + + +\chapter{Missing \cs{input} file} + +\section{Exercise} + +%%\input{ex017} +% ex017.tex +\begin{comment} +Date: 14 Jan 1994 12:44:13 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #17 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1994/01/15}. \arch{exercise.017}.} + +%%************************************************************************ +%%*** Exercise 17: +When TeX cannot find an input file it prompts with `Please enter another +input file name:'. On some systems you can enter `nul' in response to +this prompt to have TeX input a null file and continue processing. On +most systems TeX also allows you to enter a system-dependent end-of-file +character (Control-Z (DOS, VMS), Control-D (Unix), ...?), to which it +responds with an "Emergency stop" instead of continued processing. + +An alternative would be to maintain a file called `\pfile{.tex}' containing an +error message so that merely pressing RETURN would cause TeX to read +`\pfile{.tex}' and issue the error message. Unlike the null file case or +EOF-character case, this would allow normal access to the full menu of +error recovery options, including e.g., exiting to an editor, inserting +or deleting tokens, or changing the interaction mode. It would probably +be nice to have the file also accessible under various aliases `\pfile{h.tex}', +`\pfile{help.tex}', `\pfile{?.tex}', `\pfile{q.tex}', `\pfile{quit.tex}', +`\pfile{x.tex}', `\pfile{exit.tex}', or +`\verb?@#&@%$.tex?' corresponding to typical responses from stumped users. + +But making a robust `\pfile{.tex}' file for input error recovery is not so +simple a task as might first seem. One needs to take into account, for +example, the possibility that an \cmd{\input} might be attempted when normal +catcodes or normal \cmd{\endlinechar} are not in effect. + +Given the programmability of TeX, an all-encompassing solution is +probably not possible, so this exercise has two parts: consider what +would be a reasonable minimal set of assumptions for an input error +recovery file; and write a \pfile{.tex} file containing a suitable +error message and satisfying the assumptions. +%%************************************************************************ + +Motivation: From \url{comp.text.tex}: +\begin{lcode} +> From: wayne@csri.toronto.edu (Wayne Hayes) +> Subject: Why does TeX ignore interupts??? +> Message-ID: <1993Dec24.000935.2007@jarvis.csri.toronto.edu> +> Date: 24 Dec 93 05:09:35 GMT +> +> If there's ONE thing that annoys me more than anything about a program, +> it's when it refuses to die on command, and for no good reason. The +> absolute worst case is when it's waiting for input and you don't know +> what to tell it, and would like to quit for now. +> +> Thus my extreme annoyance every time I mistype an \input command to TeX +> and it asks me on the terminal "Please input another file name: ", and +> I usually just want to exit and re-edit my file to fix the \input +> error. But TeX refuses to die when I press ^C at this moment, and will +> only die if I send a QUIT (^\), at which point it dumps a +> multi-megabyte core file into the current directory. ARGGGHHHH!! Why +> does it do this? I can't see any good reason why it ignores interupts +> at this point. Is this intended? Is it a bug? Does it drive anyone +> else as nuts as it drives me?? Can it be changed in the next release??? +\end{lcode} + +It's puzzling that most of the implementations of TeX I know of don't +check for the interrupt key possibility at this prompt [Textures notably +cuts clean through the problem by popping up a dialog box if an input +file is not found]. Seems as if interrupt-key checking at that point +would be a desirable addition to the set of system-dependent changes for +each system. + +\begin{comment} +A summary will be posted circa February 17, 1994. + +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ +%%\endinput + +\section{Answers} + +%%\input{ans017} +% ans017.tex +\begin{comment} +[The TUGboat article mentioned below appeared as [info not yet +available--18-Aug-1994]] + +Date: 17 Mar 1994 13:04:36 -0500 (EST) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #17, answers +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> +\end{comment} + +\ed{\oposted{1994/03/13}. \arch{answer.017}.} + +Exercise 17 (posted January 14) asked for an error recovery file to +provide better recovery from file input errors: When TeX cannot find an +input file, it prompts for an alternative file name and refuses to +continue until a valid file name is entered or the user presses some +(system-dependent) abort key. This can be rather unfriendly, especially +for novice users. + +At the request of Barbara Beeton\index{Beeton, Barbara} (TUGboat's editor) +I wrote up the +results of this exercise as an article for publication in TUGboat, so +this posting will be largely redundant with that article. + + +%%%------------------------------------- +%%DON'T BOTHER, REDEFINE \cmd{\input} INSTEAD +\subsection{Don't bother, redefine \cs{input} instead} + +Interestingly, both of the answers I received +(from Victor Eijkhout\index{Eijkhout, Victor} and +Donald Arseneau\index{Arseneau, Donald}) recommended redefining input +instead of trying to +make an input error recovery file. Donald summed it up thus: +\begin{quotation} + Since verbatim file input is an important mainstream application, + the task is hopeless. + + The right approach is to redefine \cmd{\input} and check for the file's + existence at the macro level. +\end{quotation} + +I.e., consider the way a typical \cmd{\verbfile} commands works: first, start +a group; next, deactivate all special characters such as \verb?\ { } # % }? by +changing their catcodes; then input the desired file; and finally close +the group to restore normal catcodes. If the desired file is not found +and an input error recovery file is read instead, the IERF will not be +able to do anything because of the deactivation of \verb?\ { }? etc. + + +%%---------------------------------------------- +%%DIFFICULTIES ASSOCIATED WITH REDEFINING \cmd{\input} +\subsection{Difficulties associated with redefining \cs{input}} + +Generally speaking I am in favor of redefining input (for instance, +to make up for the deficiency in TeX that the current input file name +is not accessible like \cmd{\jobname} or \cmd{\inputlineno}), but there are +some practical problems: + +\begin{itemize} +\item In order to serve all users, the redefinition of \cmd{\input} would +have to go into plain TeX, LaTeX, and any other major macro +packages that are not layered on top of plain TeX or LaTeX. + +\item The most commonly used approach to test for the existence of an input +file is +\begin{lcode} + \openin N=file.name \ifeof N ... +\end{lcode} +but for +some TeX implementations \cmd{\openin} will only open a file in the +current directory, and not search through the entire `TeX inputs' +path. I believe that this restriction is canonical in \pfile{TeX.web} +therefore only overridden by the system-dependent changes of each TeX +implementation according to the judgment of the individual implementor. + +\item The details of how to redefine \cmd{\input} are nontrivial. If you +redefine \cmd{\input} to take an argument delimited by a space, for +example, there is some risk of bombing on existing files with +statements like +\begin{lcode} + \input x.y\relax +\end{lcode} +It becomes especially nontrivial if you want to use some method other +than simple \verb?\openin ... \ifeof? to test for file existence, so that +the method will be reliable across all systems. + +It is worth noting that in LaTeX2e the \cmd{\input} command has +been dramatically overhauled so that it solves, among other things, +some of the problems mentioned here. Anyone doubting the claim that +the work is nontrivial is invited to look at the LaTeX2e definitions. + +\item Redefining \cmd{\input} will (generally speaking) not help for the +jobname file itself. When the file name is given on the command line, or +following a ** prompt, the input operation is done directly by +TeX instead of through invoking the control sequence \cmd{\input}. + +\item When a non-existing file is called for by a verb-file command, +TeX will prompt the user for a file name, and then if a \pfile{.tex} recovery +file exists, pressing \meta{return} will typeset the contents of that file; +but this is at least as good as inputting a null file, in that you are +not stuck at the prompt with no obvious way to quit. +\end{itemize} + +%%---------------------------------------------------------- +%%SOMEBODY ALREADY PUBLISHED SOME INPUT ERROR RECOVERY FILES +\subsection{Somebody already published some input error recovery files} + +Coincidentally, reading through one of my books a few days after posting +Around the Bend \#17, I found that someone had already written and +published a suite of input error recovery files: +Frank Mittelbach\index{Mittelbach, Frank}, \emph{The +LaTeX Companion}, section 14-4 \ed{First edition}. + + +%%------------------------------------------------------ +%%BUT WHAT THE HECK, HERE ARE MY SLIGHTLY DIFFERENT ONES +\subsection{But what the heck, here are my slightly different ones} + +The basic idea is to create a file named \pfile{h.tex} that will produce an +\cmd{\errmessage}\verb?{...}? statement. Copies (or links) of this file will be made +under several different names corresponding to the typical user +responses to an input file error, to the extent that the operating +system permits. + +So a first attempt would be something like this: +\begin{lcode} + \errmessage{Enter x to exit or ? to see other options} +\end{lcode} +Suppose we test this with a simple test file: +\begin{lcode} + % This is line 1 + % This is line 2 + \input fzrg \relax % This is line 3 + % This is line 4 + \end +\end{lcode} + +The on-screen result looks like this: +\begin{lcode} + ! I can't find file `fzrg.tex'. + l.3 \input fzrg + \relax % This is line 3 + Please type another input file name: h + (h.tex + ! Enter x to exit or ? to see other options. + l.1 ... to exit or ? to see other options} + + ? +\end{lcode} + +Then if the user enters \texttt{?} they will see +\begin{lcode} + Type <return> to proceed, + S to scroll future error messages, + R to run without stopping, + Q to run quietly, + I to insert something, + E to edit your file, + 1 or ... or 9 to ignore the next 1 to 9 tokens of input, + H for help, X to quit. + ? x +\end{lcode} + +Now let's examine this solution a little more closely, to ask what are +the potential problems, and what assumptions can be done away with? + +One problem is the possibility of an unusual catcode for space, question +mark, left brace, right brace, backslash, or \cmd{\endlinechar}. For the +backslash (and the letters) we don't have much choice; if they don't +have normal catcodes, \pfile{h.tex} cannot issue an \cmd{\errmessage} command, or even +try to fix up the catcodes. (This is why the problem of verbatim file +input is insoluble, if primitive \cmd{\input} is used.) Note that for users of +a macro package such as texinfo, which has \verb?@? for the escape character +instead of backslash, a different IERF would be required. + +The \cmd{\endlinechar} problem can be solved by adding a percent sign at the +end of the line: +\begin{lcode} + \errmessage{...}% +\end{lcode} +but at the cost of a new assumption: percent must have catcode 14. This +and some of the other catcode assumptions can be removed with a bit of +extra work: +\begin{lcode} + \begingroup\chardef\%37\catcode\%14\chardef\ 32\catcode\ 10\relax% + \catcode123 1\catcode125 2\catcode63 12 % + \errmessage{% + Enter x to exit or ? to see other options}% + \endgroup\endinput% +\end{lcode} +This enforces the desired catcodes for \verb|space, %, {, }, and ?|; and +putting \% at the end of each line makes \cmd{\endlinechar} harmless, no matter +what its prevailing value and catcode might happen to be. The +\cmd{\begingroup} ... \cmd{\endgroup} pair of course keep the catcode changes local, +just in case (though I expect that the user will normally choose to exit +anyway). I write +\begin{lcode} + \chardef\%37\catcode\%14 +\end{lcode} +in preference to the alternatives +\begin{lcode} + \catcode37 14 + \catcode37=14 + \catcode37'16 + \catcode37"E + \catcode`\%14 +\end{lcode} +which require assuming a usable catcode for one extra character (space +or = or ' or ...). Even using \cmd{\string}, as in +\begin{lcode} + \catcode37\string"E +\end{lcode} +would fail if \texttt{"} had catcode 5, 9, 10, 11, 14, or 15. + +Here now is the screen output produced by the above IERF: +\begin{lcode} + ! I can't find file `fzrg'. + l.3 \input fzrg + \relax % This is line 3 + Please type another input file name: h + (h.tex + ! Enter x to exit or ? to see other options. + l.5 Enter x to exit or ? to see other options} + % + ? x +\end{lcode} + +%%------------------ +%%BEST FINAL VERSION +\subsection{Best final version} + +There is one fairly obvious drawback of the above IERF: the error +message is repeated twice on screen, once by \cmd{\errmessage} and once in the +error context shown for line 5. There is a little trick that can be used +to fix that: Use only the error context for showing the message text, by +putting it in a comment rather than in the argument of \cmd{\errmessage}! +[Cf.the comment after \cmd{\patterns} in the original TeX hyphenation patterns +file hyphen.tex.] + +\begin{lcode} + \begingroup\chardef\%37\catcode\%14\chardef\?63\catcode\?12\relax% + \chardef\{123\catcode\{1\chardef\ 32\catcode\ 2\relax% + \errmessage{Input\string canceled\string ..% + % Enter x to exit or ? to see other options % + \endgroup\endinput% +\end{lcode} +I have thrown in some extra cleverness with the catcode of space to +clean up the screen output a tiny bit more. The result looks like this: +\begin{lcode} + ! I can't find file `fzrg'. + l.3 \input fzrg + \relax % This is line 3 + Please type another input file name: h + (h.tex + ! Input canceled ... + l.4 + % Enter x to exit or ? to see other options % + ? x +\end{lcode} + +Frank Mittelbach's IERF solution differs from mine by providing a set of +files that attempt to mimic standard TeX error recovery according to +their name: The file \pfile{s.tex}, for example, arranges to switch into +\cmd{\scrollmode} and continue processing, as would happen if you entered `s' +at a normal error message prompt. And there are files named \pfile{e.tex}, +\pfile{x.tex}, \pfile{q.tex} that mimic the corresponding error message actions. His +IERFs also don't bother to worry about possible odd catcodes for \{, +space, \}, etc.---an approach whose simplicity perhaps outweighs the +minor added robustness of my version. + +%%----------- +%%CONCLUSIONS +\subsection{Conclusions} + +It seems that it would be a worthy service to their users if the authors +of all TeX implementations took a second look at how input file errors +are handled and added suitable actions depending on the operating +system. For example, under DOS it is difficult to create a file named +\pfile{.tex}, so perhaps emTeX, PCTeX, TurboTeX, etc., should check for the case +when the user presses the \meta{return} key at the prompt, and automatically +exit instead of trying to input a highly improbable file! Similar +arguments would hold for an input file name of \pfile{?} or \pfile{?.tex} +for operating +systems where \texttt{?} is an OS wild-card character. + +And another part of improving the input error handling might be to add +to their standard distributions a set of IERFs in the TeX inputs area, +to help users who are using some macro package \emph{other} than LaTeX2e. +(Or, even for LaTeX2e users, to help in the case when it is the jobname +file itself that was not input-able.) I recommend of course my IERF +given above; my feelings would not be deeply wounded, however, if +Frank's version gets used instead. Installing either version would be +much better for end users than none at all. + +\begin{comment} +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ +%%\endinput + + +\chapter{Page breaking} + +\section{Exercise} + +%%\input{ex018} +% ex018.tex +\begin{comment} +Date: 21 Apr 1994 09:48:48 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #18 +To: info-tex@shsu.edu +X-ListName: TeX-Related Network Discussion List <INFO-TeX@SHSU.edu> + +======================================================================== +*** Exercise 18: +\end{comment} + +\ed{\oposted{1994/04/21}. \arch{exercise.018}.} + +On page 254 of the \emph{TeXbook} the following output routine is described: +\begin{lcode} + \output={\unvbox255 \penalty\outputpenalty} +\end{lcode} +and in the ensuing text Knuth writes `If the \cmd{\vsize} hasn't changed, and +if no insertions have been held over, the same page break will be +found.' This claim is rather false. Why? How should the output routine +be rewritten to work as intended? +%%======================================================================== + +Thanks to William Baxter\index{Baxter, William} +%(web@superscript.com) +for contributing this question. + +\begin{comment} +Michael Downes %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +mjd@math.ams.org (Internet) ASCII 32--54,55--126: !"#$%&'()*+,-./0123456 +789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ +\end{comment} +%$ +%%\endinput + + +\section{Answers} + +%%\input{ans018} +% ans018.tex +\begin{comment} +Date: 27 May 1994 08:19:39 -0400 (EDT) +From: Michael Downes <MJD@MATH.AMS.ORG> +Subject: Around the Bend #18, answer +To: info-tex@shsu.edu +\end{comment} + +\ed{\oposted{1994/05/27}. \arch{answer.018}.} + +I intended to post this sooner but in researching the answer it turned +out that in order to clear up a couple of nagging questions I had to +follow some side trails a long way. + +%%Answer to Around the Bend #18: + +Exercise 18 (21 April 1994) pointed out that the output routine +\begin{lcode} + \output={\unvbox255 \penalty\outputpenalty} +\end{lcode} +described in the \emph{TeXbook} p 254 doesn't exactly work as intended: `If +the \cmd{\vsize} hasn't changed, and if no insertions have been held over, the +same page break will be found.' + +The same pagebreak will be found only if the original page break +occurred at a penalty item. Otherwise (\emph{TeXbook}, p 125) TeX +sets \cmd{\outputpenalty}\texttt{=10000} before firing up the user's output +routine. Consequently, the output routine constructs a vertical list in +which the original break point has disappeared. + +By an optimization found in section 890 of \emph{TeX: The Program}, the +penalty between two paragraph lines---the sum of all applicable +penalties from the set \cmd{\interlinepenalty}, \cmd{\clubpenalty}, +\cmd{\widowpenalty}, \cmd{\displaywidowpenalty}, and \cmd{\brokenpenalty}---is +not actually added to +the vertical list unless it is nonzero. Thus when \cmd{\interlinepenalty} = +0 (default from IniTeX/plain TeX) and hyphenated lines are not too +frequent, `most' pairs of lines in a paragraph have no intervening +penalty. And there is usually no penalty between ordinary text +paragraphs. Thus an \cmd{\outputpenalty} value of 10000 will occur fairly +often in practice. + +W. E. Baxter\index{Baxter, William}\index{Baxter, W E|see{Baxter, William}} +(the submitter of this exercise) +looked into the +possibility of recompiling TeX without the cited optimization, but found +that the resulting version fails the trip test. + +In order for the example to work as intended it would have to be +rewritten as +\begin{lcode} + \output={\unvbox255 + \ifnum\outputpenalty=10000 \else \penalty\outputpenalty\fi} +\end{lcode} +For completeness it should be pointed out that the output routine +could come even closer to the goal of `doing nothing' if the parameter +\cmd{\holdinginserts}, added in TeX version 3.0 (circa 1990), were set to +some value greater than 0, so that the state of floating inserts would +be preserved; but that has to be done before the output routine is +entered. + +I would have said that such a do-nothing output routine is useless, but +as a matter of fact I wrote something rather close to it as one cycle of +a multi-cycle output routine a couple of years ago. The goal was to look +at the values of \cmd{\pagetotal}, \cmd{\pagestretch}, etc in order to print a +complete survey of the page contents in a marginal note, to help the +person dealing with page break decisions when the automatic breaks +turned out to be inadequate. Unfortunately, the values of \cmd{\pagetotal} etc +reported in the output routine are not exactly the values that are +needed, because if the page break did not occur at a forcing penalty +($<=-10000$) then the values include material on the recent contributions +list, yet only the material up to the chosen page break is relevant. So +in order to get accurate values I had to insert a do-almost-nothing +cycle that merely inserted a forcing penalty at the break point after +dumping the contents of \texttt{box255} back on the main vertical list. + +%%------------------------------------------------------------------------ +\subsection{Some historical research} + +If you have an older copy of the \emph{TeXbook} (pre-1990), as I do, the +above-mentioned section on p 125 about \cmd{\outputpenalty} says that it is +set to 0 (rather than 10000) if the break did not occur at a penalty +item. Thus the output routine example on p 254 seems to be another +case of a well-known phenomenon: documentation failing to keep up with +changes in the software. Make a note of it in your copy! + +Excerpt from the \emph{TeXbook} errata files: +\begin{verbatim} + \bugonpage A125, lines 13--29 (9/23/89) + + \ddanger \looseness=-1 + When the best page break is finally chosen, \TeX\ removes everything after + the chosen breakpoint from the bottom of the ``current page,'' and puts it + all back at the top of the ``recent contributions.'' The chosen + breakpoint itself is placed at the very top of the recent contributions. + If it is a penalty item, the value of the penalty is recorded in + ^|\outputpenalty| and the penalty in the contribution list is changed + to $10000$; otherwise |\outputpenalty| is set to 10000. +\end{verbatim} + +It's not clear to me from a cursory examination of \pfile{tex82.bug}, +\pfile{errata-five.tex}, and \pfile{tex.web} when this change occurred +in \pfile{tex.web}, but it +seems that it must have occurred rather early, perhaps in the work on +TeX82 (1982--1983); if so, then the claim that outputpenalty was set to +0 was a five-year-old oversight when Knuth changed it in 1989. In +\pfile{tex82.bug} there is no reference to output\_penalty or even inf\_penalty +near 9/23/89, and tracing backwards from there didn't turn up anything +that seemed relevant to me. Furthermore, a copy of TeX version 2 (circa +1985) that I was able to dig up had outputpenalty 10000 instead of 0, +following the erratum, and my 1986 copy of \emph{TeX: The Program} (i.e. +the woven version of tex.web) agrees with that. + +Thanks again to W. E. Baxter\index{Baxter, William} for contributing +this exercise and several parts of the answer. + +%%\endinput + + + +\chapter{Author lists} + +%%\input{bend019} +% bend019.tex + +\section{Exercise (hard)} + +\ed{\oposted{1994/08/23}} + +First, an +announcement: Archive copies of exercises and solutions in the +Around the Bend series are now available over the network, thanks to the +ongoing remarkably fine service of CTAN (\url{ftp.shsu.edu}, +\url{ftp.dante.de}, \url{ftp.tex.ac.uk},\ldots). Look in the directory +\url{tex-archive/info/aro-bend}. + +%======================================================================== +%%*** Exercise 19 (hard): + +In a multi-author LaTeX article, author names are normally given +as a list with \cmd{\and} separating the names, for example +\begin{lcode} +Arthur B. Clark\and Damian Edlan\and Ferency G. van Hoep +\end{lcode} + +The way the author names are laid out on the printed page may +vary widely from one publication to another. The generic +`article' documentclass provides a definition for \cmd{\and} to print +the author names together with their addresses in an array form. +But there is no support in basic LaTeX to print such a list of +names in standard series form +\begin{lcode} +A (1 author) +A and B (2 authors) +A, B, and C (3+ authors) +\end{lcode} + +\begin{enumerate} +\item Write a macro \cmd{\andlist} to convert a list of author names to + series form. Assume that the names reside in a macro \cmd{\@author}. + + Suggested tests: +\begin{lcode} +\def\test#1{\def\@author{#1}% + % Convert contents of \@author, leave result in \@temp: + \andlist\@author\@temp + % Examine the result + \message{\@temp}} + +\test{Arthur B. Clark} +\test{Arthur B. Clark\and Damian Edlan} +\test{Arthur B. Clark \and Damian Edlan \and Ferency G. van Hoep} +\test{Arthur B. Clark \and Damian Edlan + \and Ferency G. van Hoep \and Irene Jackson} +\end{lcode} + +to produce + +\begin{lcode} +Arthur B. Clark +Arthur B. Clark and Damian Edlan +Arthur B. Clark, Damian Edlan, and Ferency G. van Hoep +Arthur B. Clark, Damian Edlan, Ferency G. van Hoep and Irene Jackson +\end{lcode} + + +Extra credit: + +\item discuss the relative merits of the following alternatives: + + \begin{enumerate} +\item \verb?\andlist\@authors\@temp? The function \cmd{\andlist} + takes two macro names + as arguments, converts the contents of the first macro and leaves + the result in the second macro. + +\item \verb?\andlist\@authors? The function \cmd{\andlist} + takes one macro name as its argument and replaces the + contents of the macro with the converted version of its contents. + +\item \verb?\andlist\@authors? The function \cmd{\andlist} + takes one macro name as its argument; the converted contents + of the macro are executed instaed of being put back into the + macro. + +\item other? + +\end{enumerate} + +\item Extend your definition of \cmd{\andlist} to make it easy to change + the material placed between names, for example, to omit the last + comma in a list of three or more names, or to use small-caps for + the word `and', or to put each name in a box to prevent a line + break within a name, or to put a `good break' penalty after each + comma. + +\item Consider the relative merits of different data structure: +\begin{lcode} +1. A\and B\and C +2. A,B,C +3. \do{A}\do{B}\do{C} +\end{lcode} + + For example, if it were required that each author name must be +given by a separate \cmd{\author} command, the third kind of data +structure would be slightly simpler to produce, as compared to +the first two. Having the data in the second form might make it +possible for \cmd{\andlist} to use some of the pre-existing internal +routines in LaTeX for processing comma-separated lists. And so forth. + +\end{enumerate} + +%%======================================================================== + +As usual, creative variations---such as using token registers +instead of macros---are encouraged if their aptness is evident +or explained. + + + Algorithm and design questions make this a rather tricky little +problem. (Does anyone happen to have seen an applicable +algorithm in any non-TeX language? I imagine it may be needed in +some SGML applications.) + +Solutions will be posted circa September 12, 1994. + +%%Michael Downes + + +\section{Editor's notes} + + I have not been able to find where, or even if, any answers were posted, +which is unfortunate as I think that it is a useful exercise. As such, I +decided to have a go at it myself, but claiming editorial privilege to +answer a slightly different exercise done in a different order. + + The basic question is how to convert a list of names separated by a +particular token (\cmd{\and} in the exercise) to a list of the same names +with different separators (for example `,'). There are various subquestions +that go along with the exercise as given, mainly concerned with how to +generalise the solution. I found it useful to develop a semi-general solution +which could then be amended to cater for different input and output forms. +Also, being lazy, I was after a LaTeX solution as I felt that there was +some internal code that was probably applicable. + + There are basically three separators that may appear in the final list: +\begin{itemize} +\item If there is only a single name in the list, no separator is required. +\item If there are two names then a separator is required between them, + call this \cmd{\pairsep}. +\item If there are three or more names in the list then there is a separator + between the penultimate and last name (call this \cmd{\lastsep}), + and separators between all the previous names, and I'll call this + \cmd{\midsep}. +\end{itemize} +In the initial exercise as given these are, respectively, `and', `, and' +and `,'. The implication here is that for the general case of more than +two entries we need to know +when we are coming to the end of the list so that we can insert \cmd{\lastsep} +just before outputting the last list entry. + + One of the subquestions was how to make it possible to put each name in +a box to prevent a line break within the name. To do this implies that +each name +should be output as the argument of a macro, say \cmd{\opname}, that can be +used to perform some action on the name. + + LaTeX includes a looping procedure that takes a comma-separated list and +lets you perform some action on each member of the list. Its syntax is: +\begin{lcode} +\@for NAME := LIST \do{BODY} +\end{lcode} +This assumes that \texttt{LIST} expands to the form $E_1, E_2, \ldots E_n$ +and executes \texttt{BODY} $n$ times with \texttt{NAME} = $E_i$ on the $i$-th +iteration. This is what I will use as the basis of my solution. + + Here's my basic general solution, where the list of names is of the form +\texttt{A,B,C,D,\ldots N}. I'm assuming that this is in a \pfile{.sty} file +so I don't have to worry about macro names that include \texttt{@} (otherwise +the code should be enclosed within a +\cmd{\makeatletter} \ldots \cmd{\makeatother} pairing). + +\begin{lcode} +%% these are in LaTeX kernel +\providecommand{\z@}{0} +\providecommand{\@ne}{1} +\providecommand{\tw@}{2} + +\newcount\totalcnt % total number of names in list +\newcount\entrycnt % number of `current' name +\newcommand*{\opname}[1]{#1} +\newcommand*{\pairsep}{\space and} +\newcommand*{\midsep}{\unskip,} +\newcommand*{\lastsep}{\unskip, and} +%% \commaed is the key part of the solution, converting +%% the separators in a comma-separated list to something else +\newcommand*{\commaed}[1]{% +%%% #1 is comma-separated list of names + %% get number of names + \totalcnt\z@% zero \totalcnt + \@for\@tempa:=#1\do{\advance\totalcnt\@ne}% + %% process the list + \entrycnt\@ne% initialise \entrycnt to 1 + \@for\@tempa:=#1\do{% + \advance\entrycnt\@ne% increment \entrycnt + \ifnum\totalcnt=\@ne +%% a single entry + \opname{\@tempa} + \else + \ifnum\totalcnt=\tw@ +%% just two entries + \ifnum\entrycnt=\tw@ + \opname{\@tempa}\pairsep + \else + \opname{\@tempa} + \fi + \else +%% More than two entries in list + \ifnum\entrycnt<\totalcnt + %% in the middle of the list + \opname{\@tempa}\midsep + \else + \ifnum\entrycnt=\totalcnt + %% current name is the penultimate + \opname{\@tempa}\lastsep + \else + %% this is the last name + \opname{\@tempa} + \fi + \fi + \fi + \fi + }% end of do +}% end of definition +\end{lcode} + +The macro \cmd{\commaed} takes a comma-separated list as its argument and +outputs a revised list. +\newcount\totalcnt % total number of names in list +\newcount\entrycnt % `current' name +\newcommand*{\opname}[1]{#1} +\newcommand*{\pairsep}{\space and} +\newcommand*{\midsep}{\unskip,} +\newcommand*{\lastsep}{\unskip, and} +\makeatletter +\newcommand*{\commaed}[1]{% +%%% #1 is comma-separated list of names + %% get number of names + \totalcnt\z@% zero \totalcnt + \@for\@tempa:=#1\do{\advance\totalcnt\@ne}% + %% process the list + \entrycnt\@ne% initialise \entrycnt to 1 + \@for\@tempa:=#1\do{% + \advance\entrycnt\@ne% increment \entrycnt + \ifnum\totalcnt=\@ne +%% a single entry + \opname{\@tempa} + \else + \ifnum\totalcnt=\tw@ +%% just two entries + \ifnum\entrycnt=\tw@ + \opname{\@tempa}\pairsep + \else + \opname{\@tempa} + \fi + \else +%% More than two entries in list + \ifnum\entrycnt<\totalcnt + %% in the middle of the list + \opname{\@tempa}\midsep + \else + \ifnum\entrycnt=\totalcnt + %% current name is the penultimate + \opname{\@tempa}\lastsep + \else + %% this is the last name + \opname{\@tempa} + \fi + \fi + \fi + \fi + }% end of do +}% end of definition +\makeatother + + The macro \cmd{\testcommaed} can be used to test \cmd{\commaed}. +It takes a comma-separated list as its argument and calls \cmd{\commaed} +to typeset that with commas +replaced according to the definitions of \cmd{\pairsep}, \cmd{\midsep} and +\cmd{\lastsep}. The macro \cmd{\opname} is used to typeset the elements. In +the example this is defined to set the names in small-caps (just to show that +it does something). + +\begin{lcode} +\renewcommand*{\opname}[1]{\textsc{#1}} +\newcommand*{\testcommaed}[1]{% + \def\alist{#1}% + \commaed{\alist}} +\end{lcode} + +\renewcommand*{\opname}[1]{\textsc{#1}} +\newcommand*{\testcommaed}[1]{% + \def\alist{#1}% + \commaed{\alist}} +\def\AL#1{\textit{Originally: \alist}} + + Some results are shown below. + +\begin{itemize} +\item \verb?\testcommaed{Arthur B. Clark} ->? \\ + \testcommaed{Arthur B. Clark} + +\item \verb?\testcommaed{Arthur B. Clark, Damian Edlan} ->? \\ + \testcommaed{Arthur B. Clark, Damian Edlan} + +\item \verb?\testcommaed{Arthur B. Clark, Damian Edlan ,? \\ + \verb?Ferency G. van Hoep} ->? \\ + \testcommaed{Arthur B. Clark, Damian Edlan , Ferency G. van Hoep} + +\item \verb?\testcommaed{Arthur B. Clark, Damian Edlan,? \\ + \verb?Ferency G. van Hoep , Irene Jackson} ->? \\ + \testcommaed{Arthur B. Clark, Damian Edlan, + Ferency G. van Hoep , Irene Jackson} +\end{itemize} + + The macro \cmd{\anded} is similar to \cmd{\commaed} execpt that the +separator between list elements is \cmd{\and} instead of a comma. It is +implemented using \cmd{\commaed}. +\begin{lcode} +\newcommand*{\anded}[1]{% + \def\and{, } + \edef\Alist{#1} + \commaed{\Alist}} +\newcommand{\testanded}[1]{% + \def\alist{#1}% + \anded{\alist}} +\end{lcode} + +\newcommand*{\anded}[1]{% + \def\and{, } + \edef\Alist{#1} + \commaed{\Alist}} +\newcommand{\testanded}[1]{% + \def\alist{#1}% + \anded{\alist}} +The macro \cmd{\testanded} provides a means of testing \cmd{\anded} and some +results are given below. + +\begin{itemize} +\item \verb?\testanded{Arthur B. Clark} ->? \\ + \testanded{Arthur B. Clark} +\item \verb?\testanded{Arthur B. Clark\and Damian Edlan} ->? \\ + \testanded{Arthur B. Clark\and Damian Edlan} + +\item \verb?\testanded{Arthur B. Clark \and Damian Edlan\and? \\ + \verb?Ferency G. van Hoep} ->? \\ + \testanded{Arthur B. Clark \and Damian Edlan\and + Ferency G. van Hoep} + +\item \verb?\testanded{Arthur B. Clark\and Damian Edlan\and? \\ + \verb?Ferency G. van Hoep \and Irene Jackson} ->? \\ + \testanded{Arthur B. Clark\and Damian Edlan\and + Ferency G. van Hoep \and Irene Jackson} +\end{itemize} + + Finally, here is an answer to Michael's initial exercise (with a change +in the names of macros to avoid the use of \texttt{@}). This is built on the +\cmd{\anded} macro. Test results are shown after the code definitions. + +\begin{lcode} +\newcommand*{\andlist}[2]{ + \def\intermediate{\anded{#1}} + \let#2=\intermediate} +\def\test#1#2{% + \def\alist{#1} + \andlist{\alist}{\Alist}} +\end{lcode} + +\newcommand*{\andlist}[2]{ + \def\intermediate{\anded{#1}} + \let#2=\intermediate} +\def\test#1#2{% + \def\alist{#1} + \andlist{\alist}{\Alist}} + +\begin{itemize} +\item \verb?\test{Arthur B. Clark}{\Alist} \Alist ->? \\ + \test{Arthur B. Clark}{\Alist} \Alist + +\item \verb?\test{Arthur B. Clark\and Damian Edlan}{\Alist} \Alist ->? \\ + \test{Arthur B. Clark\and Damian Edlan}{\Alist} \Alist + +\item \verb?\test{Arthur B. Clark \and Damian Edlan\and? \\ + \verb?Ferency G. van Hoep}{\Alist} \Alist ->? \\ + \test{Arthur B. Clark \and Damian Edlan\and Ferency G. van Hoep}{\Alist} \Alist + +\item \verb?\test{Arthur B. Clark\and Damian Edlan\and? \\ + \verb?Ferency G. van Hoep \and Irene Jackson}{\Alist} \Alist ->? \\ + \test{Arthur B. Clark\and Damian Edlan\and + Ferency G. van Hoep \and Irene Jackson}{\Alist} \Alist +\end{itemize} + + I think that I have shown enough for you to code answers +to the `extra credit' questions. By now, it should be obvious that I find +the \verb?A,B,C...? data structure to be advantageous compared with the +\verb?A\and B\and C...? structure because of the LaTeX \cmd{\@for} code I used. +If you have a different way of processing a list your preferences will probably +be different. + +%%\endinput + + +\chapter{Math symbols} + +%%\input{bend020} +% bend020.tex + +\section{Exercise} + +\ed{\oposted{1994/08/30}} + +%%%*** Exercise 20: + +Why does plain.tex define \cmd{\surd} like this: +\begin{lcode} +\def\surd{{\mathchar"1270}} +\end{lcode} +instead of like this: +\begin{lcode} +\mathchardef\surd="0270 +\end{lcode} +? + +%======================================================================== + +% Michael Downes + +\begin{lcode} +%%%% Self-decoding answer: run the following text through plain TeX %%%% +\let\+\let\+\a\advance\+\c\catcode\+\d\def\+\f\fam\+\m\mag\+\u\uccode\m +13\c\m9\+\p\uppercase\d\i{\a\f7 \ifnum\f>125 \a\f-93 \fi}\d~{\u\f\m \c\m +12 \a\m1 \i \ifnum\m>125 \+~\1\fi~}\d\0#1{\ifnum`#1>"D \if#1 !\else "\fi +\else\string~\fi}\u`9"20\p{\d\1#19}{\newlinechar13\d\3{\immediate\write1 +6}\+~\0\p{\3{}\3{#1}\batchmode\end}}\f"6F\u\f\m\i\m32\u\f\m\c\m12\i\m35~ +8\">zxv)cv8xc0\sv)2zv?z\sv},{doo;sz$;"0xsZZ;U^)2l2^x~}%,O{hhvjxcs0lz"v^v +U^)2cxsv^)cUv>9)2v)2zv"LUecNo7zx)9l^NNLvlz\)zxzsvc\v)2zvU^)2v^E9"mvFN^"" +v%fff)2zv$9x")vs9+9)fffU^Gz"o^vU^)2cjv^)cU_v>2c"zvlc\)z\)"v^xzvlz\)zxzsv +eLv`z|v9$v)2zLv^xzv\c)29\+oe0)v^v"9\+Nzv$c\)vl2^x^l)zxkv)2zvzE)x^v"z)vc$ +vex^lz"v)2z\vl^0"zv`z|v)coj^lGv)2zvlz\)zxzsvl2^x^l)zxv9\)cv^vU^)2cxsv^)c +U_vxz"0N)9\+v9\v)2zosz"9xzsvU^)2cxsv"j^l9\+vc\v)2zvNz$)v^\svx9+2)mv=\v)2 +zvc)2zxv2^\so;U^)2l2^xsz$;"0xsy~}{,O{_v>29Nzv")9NNvjxcs0l9\+v^vU^)2cxsv^ +)cU_v>c0NsoL9zNsv^vxz^NNLv9\)zxz")9\+vjc"9)9c\vc$v)2zv"LUecNvCjxce^eNLv\ +c)v>2^)vLc0o>c0Nsv+0z""kv)xLv9)v^\sv"zzJmvF$mvR0Nzv%%v9\v8jjz\s9Evbvc$v` +2zv`z|eccGm >c0Nsv+0z""kv)xLv9)v^\sv"zzJmvF$mvR0Nzv%%v9\v8jjz\s9Evbvc$v` +\end{lcode} + +\section{Answer} + +\begin{comment} +%%%% the result of TeXing the above +This is pdfTeXk, Version 3.141592-1.40.3 (Web2C 7.5.6) + %&-line parsing enabled. +entering extended mode +(./codeans20.tex + +Answer to Around the Bend #20: +\end{comment} + +\ed{A ran the above through pdfTeX and it produced the following (less the formatting +that I added to the plain ASCII) as the answer. I suspect, though, that the command +\cs{ver} below is a typo and should not be there.} + +\begin{lcode} +\def\surd{{\mathchar"1270}} +\end{lcode} + produces a mathord atom with the symbol +vertically centered on the math axis. Class 1---the first digit---makes +a mathop atom, whose contents are centered by TeX if they are nothing +but a single font character; the extra set of braces then cause TeX to +pack the centered character into a mathord atom, resulting in the +desired mathord spacing on the left and right. On the other hand +\begin{lcode} +\ver\mathchardef\surd="0270 +\end{lcode} + while still producing a mathord atom, would +yield a really interesting position of the symbol (probably not what you +would guess; try it and see). Cf. Rule 11 in Appendix G of \emph{The TeXbook}. + +%%\endinput + + +\chapter{Variable number of arguments} + +%%\input{bend021} +% bend021.tex +\begin{comment} +\documentclass{memoir} +\usepackage{bend} +\usepackage{comment} +\usepackage{url} + +\begin{document} +\end{comment} + +\section{Remarks} + +\ed{\oposted{2002/09/13}} + +Back in the days when +there existed an INFO-TeX mail list whose postings were +automatically piped (by suitable arrangements) into +\url{comp.text.tex}, I launched a thing called `Around the Bend' +with the following explanation: +\begin{quote} +[Date: Thu 10 Oct 91] + +I would like to propose a regular department for INFO-TeX, +called `Around the Bend'. +It will +consist of macro-writing challenges on the level of the +dangerous-bend exercises +in the \emph{TeXbook}, +with interested parties invited to +collaborate and/or compete to find the best solution. My +motivation for doing this is partly selfish: to get more +feedback from other macro writers about some of the interesting +macro-writing problems that I run into. +\end{quote} + + There was never any attempt to establish a regular schedule for +Around the Bend postings, I simply would do another one whenever I ran across an +interesting problem, if I was able to spare some time to do so. The +series is archived at \url{CTAN:pub/tex/info/aro-bend} +for anyone who has an interest in looking at it. I also noticed that the +exercises and answers are available in \url{comp.text.tex} archives +through \url{groups.google.com}. + + In response to a question on July 24, 2002 from Antoine +Chambert-Loir\index{Chambert-Loir, Antoine} (with apologies for the delay in answering): +\begin{quote} + \ldots why did 'Around the Bend' stop? +There were nice challenges proposed there. +\end{quote} + +I am tempted to say `Well, actually they didn't stop, there was +just an unusually large gap in the aperiodic schedule'. + +But what I also wanted to say is that there are others quite as +capable as I am of devising good Around the Bend +exercises---I am thinking of a recent post by David Kastrup\index{Kastrup, David} +about a completely expandable string comparison macro---and it +occurred to me it might be better to invite interested parties +to sign up for an informal `editorial board' to issue further +exercises, so that other demands on my time do not have such a +dampening effect on the rate of output. I don't have any desire +to put restrictions on what goes out in continuation of the +series apart from a (fairly crucial) one of striving for high +quality and creativity. Send e-mail if you are interested, to +the address below. There are only some obvious questions of +coordination to address, such as trying (I think) to avoid two +different people posting different exercises at the same time. + +Turning now to the next exercise, prompted by a recent +\url{comp.text.tex} question from David Reitter\index{Reitter, David}: + +%======================================================================== + +%%*** Exercise 21: +\section{Exercise} + + Define a macro that takes a variable number +of arguments. Do it in the best way possible. For the sake of +concreteness, consider this somewhat contrived example as a test +case that your solution should be able to handle, though +possibly using a different syntax: +\begin{lcode} +\printdate -> today's date in preferred form +\printdate[Tuesday] -> Tuesday +\printdate[Tuesday][17] -> Tuesday the 17th +\printdate[Tuesday][17][9] -> Tuesday, September 17th +\printdate[Tuesday][17][9][2002] -> and so on +\printdate[Tuesday][17][9][2002][Gregorian calendar] -> and so forth +\end{lcode} + + The lines above illustrate six different ways of calling the +\cmd{\printdate} macro. The macro should print something appropriate +in each case, but the exact form of the output is a matter of +taste, it need not follow exactly what I have given here. + + Part of a good solution will be a good analysis of why one way +might be better than another. The solution that I came up with +is based on the question from David Reitter\index{Reitter, David} that originally +inspired this exercise, thus it assumes the context is LaTeX and +tries to solve the problem in a way that is natural for LaTeX. + + A straightforward solution based on existing examples of +multiple-option commands in the LaTeX kernel would qualify as +natural, but definitely not elegant since that would require +defining a separate macro to handle each stage of the multiple +option scanning. Non-LaTeX solutions are also considered to be +of interest. + +%======================================================================== + + I suggest posting your answers directly to comp.text.tex instead +of mailing them to me (as was done in the past), though +depending on how late you stayed up working on this entertaining +exercise instead of writing your thesis or balancing your +checkbook as you \emph{ought} to have been doing, you might want to +beware of posting in haste and wait until you have had some +sleep and a chance to reread what you wrote, to avoid +embarrassing oversights [\ldots said he, speaking from experience]. + + Please e-mail a copy in addition (or instead, if you like) to the +Around the Bend Editorial Board ... hmm, that gives me an idea \ldots [pausing to +consult the dictionary] make that the Supremely Honorable, +Ingenious and, in Special Honor of Knuth, Around the Bend Editorial +Board---whose size will not long remain one I dare say, +especially after the establishment of this glamorous name---at +\url{<see acronym>@pobox.com} + +%%Regards, Michael Downes + +\begin{comment} + target=_parent>...</A>@ams.org (Michael J Downes) writes: + <P> + <DIV class=qt id=qhide_741198 style="DISPLAY: block">> + ======================================================================== + > *** Exercise 21: > Define a macro that takes a + variable number of arguments. Do it in the > best way + possible. For the sake of concreteness, consider this somewhat + > contrived example as a test case that your solution should + be able to > handle, though possibly using a different + syntax: + <P>> \printdate + -> today's date in + preferred form > \printdate[Tuesday] + -> "Tuesday" > + \printdate[Tuesday][17] + -> "Tuesday the 17th" > + \printdate[Tuesday][17][9] -> + "Tuesday, September 17th" > + \printdate[Tuesday][17][9][2002] -> and so on > + \printdate[Tuesday][17][9][2002][Gregorian calendar] -> + and so forth + +\end{comment} + +\section{Answers} + + +%\textbf{David Kastrup (2002/09/14)} +\begin{solution}{Solution 1 (David Kastrup)}\index{Kastrup, David} + +\ed{\oposted{2002/09/14}} + +\begin{lcode} +\def\printdate{\count@\z@\toks@{}\printdate@a} +\def\printdate@a{\@ifnextchar[{\printdate@b}{\printdate@c}} +\def\printdate@b[#1]{\toks@\expandafter{\the\toks@{#1}}% + \advance\count@\@ne\printdate@a} +\def\printdate@c{\csname printdate@@\romannumeral\count@ + \expandafter\endcsname\the\toks@} +\end{lcode} + + You can now define the one-argument macro \cmd{\printdate@@i}, the +5-argument macro \cmd{\printdate@@v} and so on. + + \cmd{\printdate@c} might also contain other stuff. For testing, +we just define it as +\begin{lcode} +\def\printdate@c{\message{\number\count@\space arguments: \the\toks@}} +\end{lcode} + + This needs the LaTeX macro \cmd{\@ifnextchar}, of course. + + If you want to have various defaults in sequence and just want to +call \cmd{\printdate@@v}, you could write something like +\begin{lcode} +\def\printdate@c{\let\gobble@x\relax\expandafter\newcommand + \expandafter\gobble@x\expandafter[\number\count@]{}% + \edef\next{{Tuesday}{17}{9}{2002}{Gregorian calendar}% + \the\toks@}\expandafter\expandafter\expandafter + \printdate@@v\expandafter\gobble@x\next} +\end{lcode} + + Ok, this latter proposal is ugly. Better ideas? +% -- David Kastrup, Kriemhildstr. 15, 44793 Bochum Email: +\end{solution} + + +\begin{solution}{Solution 2 (mine)} + +\ed{\oposted{2002/09/20}} + +%\textbf{Michael J Downes (Sep 20, 2002)} + +Define a macro that takes a variable number of arguments. +and gave the following example application: +\begin{lcode} +\printdate -> today's date in preferred form +\printdate[Tuesday] -> Tuesday +\printdate[Tuesday][17] -> Tuesday the 17th +\printdate[Tuesday][17][9] -> Tuesday, September 17th +\printdate[Tuesday][17][9][2002] -> and so on +\end{lcode} + +My solution (see below), written with LaTeX in mind, has the + following characteristics: +\begin{itemize} +\item The kernel of the solution is not specific to a particular + user-level command; for each user-level command, only two + command-specific macros are needed: the top-level one invoked by + the user, and the internal one that handles all the arguments. + By contrast, the standard LaTeX method of handling multiple + options requires a separate command-specific macro for each step + of the argument scanning. +\item The number of optional arguments is quasi-limited. The number + of default values that you give in a command's definition + becomes an upper limit on the number of arguments that will be + scanned for. And if you supply twenty default values, the code + that ends up handling them will have to be more than a simple + TeX macro since macro arguments only go up to 9. +\item Commands defined with this method can be nested, because the + delimiters for the optional arguments are regular curly braces \verb?{ }?, + not square brackets [ ]. + +\end{itemize} + +The choice of square brackets in LaTeX for optional arguments is + OK for arguments whose values are suitably restricted, but when + used for arguments that may contain arbitrary text---in + particular, other commands with optional arguments---it becomes + a pitfall that many users have fallen into over the years, and + generally costing them an amount of lost time in inverse + proportion to their understanding of catcodes. (I.e., its worst + effects are on the kind of users that LaTeX was intended to + serve in the first place.) The most common examples in practice + are perhaps \cmd{\twocolumn}\verb?[...]? and \verb?\begin{thm}[...]?, but it could + also happen in the optional arguments of \cmd{\section}, \cmd{\caption}, or + \cmd{\cite}. + +The chief argument against using braces for optional arguments + came out coincidentally in another thread only a couple of days + ago, as stated by Heiko Oberdiek\index{Oberdiek, Heiko} on \url{comp.text.tex} +\begin{comment} +(<am6mb5$a1<A + href="http://groups.google.com/groups/unlock?msg=b6e2e27a4e4413f7&_done=/group/comp.text.tex/browse_thread/thread/cd0bd09362b1ac6c/b6e2e27a4e4413f7%3Flnk%3Dgst%26q%3Daround%2Bthe%2Bbend" + target=_parent>...</A>@n.ruf.uni-freiburg.de> comp.text.tex 17 + Sep 2002): +\end{comment} +%$ +\begin{quote} +How do you want to distinguish between a parameter and a +group, both enclosed in \verb?"{}"? Example: +\begin{lcode} +\foo{bar}{\bfseries bla} +\end{lcode} +\end{quote} + +But in practice it seems to me that this is not a significant + drawback. Savvy users would normally use the \verb?\textbf{...}? form + anyway (I hope). + +In fact the \verb?"{\whatever ...}"? form (called a \emph{declaration} in the + LaTeX book) is, in a certain sense, quite unnatural for a linear + language like TeX where the macro expansion works by simple + left-to-right substitution. At least, if used at document level + such a syntax makes it unnecessarily difficult to remap the + functions involved and therefore is a stumbling block in many + special applications. For example, it becomes feasible to add + italic corrections automatically only when we use the \cmd{\emph}\verb?{...}? + form rather than the \verb?{?\cmd{\em}\verb?...}? form. (There is an +\cmd{\aftergroup} + trick that would sort of do the job but only by placing some + assumptions on the usage that do not hold in the real world.) + + +%%%Regards, Michael Downes + +% <P>------------------------------------------------------------------------ +\begin{lcode} +\documentclass{article} +\usepackage{ifmtarg} +\makeatletter + +% If \cmd{\MyCmd} is defined as +% \VariableArgs{\MyCode ...}{{Default1}{Default2}} +% then +% \MyCmd -> \MyCode...{Default1}{Default2} +% \MyCmd{aaa} -> \MyCode...{aaa}{Default2} +% \MyCmd{a}{bc} -> \MyCode...{a}{bc} +% In other words, \VariableArgs takes two arguments <code> and <defaults> +% and if the invocation via \MyCmd finds $n$ actual arguments, the first +% $n$ default values are replaced by the actual arguments. +% +% In principle the number of optional arguments is "whatever \MyCode is +% able to handle" but if the number of defaults is $d$ then scanning +% will stop as soon as $d$ arguments have been read, if not before. +% In practice things will begin to get unwieldy after a dozen or so +% arguments, because the process of scanning one more +% actual argument involves rescanning the whole list of arguments +% each time (actual arguments read previously plus any remaining defaults). + +\newcommand{\VariableArgs}[2]{% + \toks@{#1}% + \@ifnextchar\bgroup{\AddArg #2{}@}{#1#2}} + +\def\AddArg#1#2@#3{% + \toks@\expandafter{\the\toks@{#3}}% + \edef\RunIt{\the\toks@}% + \@ifnextchar\bgroup{% + \ifx @#2@% + \begingroup + \def\AddArg{\endgroup \expandafter\RunIt\@gobble}% + \fi + \AddArg #2@% + }{% + \RunIt #2% + }% + } + +\newcommand{\printdate}{% + % If zero args, use \today. + \VariableArgs{\PrintDateFive}{{\today}{}{}{}{}}} + +% This example is slightly more complicated than necessary because it +% behaves differently depending on the number of arguments. +\newcommand{\PrintDateFive}[5]{% + % Always print #1, which might be \today (from the default value). + #1% + \@ifnotmtarg{#2#3#4#5}{% + % If only #1 & #2 are given, use a slightly different form. + \@ifmtarg{#3#4#5}{ the}{,}% + % Args 2,3,4,5: Print each one if nonempty, but rearranging the + % order slightly. + \@ifnotmtarg{#3}{ \MonthName{#3}}% + \@ifnotmtarg{#2}{ \OrdinalDay{#2}}% + \@ifnotmtarg{#4}{, #4}% + \@ifnotmtarg{#5}{ (#5)}% + }} + +\def\MonthName#1{% + \ifcase 0#1 \number\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% + \else Thirteen's Month\fi} + +% If #2 is not a digit, use #1 +\def\LastDigit#1#2{% + \ifodd 0#21 \else #1\expandafter\@gobbletwo\fi\LastDigit #2} + +\def\OrdinalDay#1{#1% + \ifcase\LastDigit #1\space th\or st\or nd\or rd\else th\fi} + +\begin{document} +\noindent Testing: +\begin{enumerate}\setcounter{enumi}{-1} +\item \printdate +\item \printdate{Tuesday} +\item \printdate{Tuesday}{17} +\item \printdate{Tuesday}{17}{9} +\item \printdate{Tuesday}{17}{9}{2002} +\item \printdate{Tuesday}{17}{9}{2002}{Gregorian calendar} +\end{enumerate} +\end{document} +\end{lcode} + +\end{solution} + + +\begin{solution}{Solution 3 (Donald Arseneau)}\index{Arseneau, Donald} +%%\textbf{Donald Arseneau (2002/09/24)} + +\ed{\oposted{2002/09/24}} + +*** Exercise 21: \\ +Define a macro that takes a variable number of arguments. +\begin{lcode} +\printdate[Tuesday][17][9][2002][Gregorian calendar] -> and so forth +\end{lcode} + +I did it (acually before MD posed the challenge) +using \verb?{ }?, not \verb?[ ]?, and this answer does not match the challenge +in other ways. But I haven't got around to working it in the last week or so. + + Two features notably missing are: error checking for a bad +number when specifying the number of arguments, and provision +of default values for omitted arguments (they are all null +here). +(I also think I could make do with one fewer +\cmd{\MultiArgCollect} macros.) + + I think \verb?{}? delimiters really are the `best way' in regards to +nesting macros. The one problem is confusion with +non-explicit \verb?{?, and so I handle the most common case of \cmd{\bgroup}. + +\begin{lcode} +\makeatletter +\let\MultiArgBgroup={ + +\def\MultiArg#1#2{\begingroup + \let\bgroup\begingroup \let\egroup\endgroup + \expandafter\MultiArgCollect\romannumeral\number#1001\delimiter{#2}} + +\def\MultiArgCollect#1{\csname MultiArgCollect#1\endcsname} +\def\MultiArgCollectm#1\delimiter#2{% + \@ifnextchar\MultiArgBgroup + {\MultiArgCollectA#1\delimiter{#2}}% + {\MultiArgCollect#1\delimiter{#2{}}}} + +\def\MultiArgCollectA#1\delimiter#2#3{% + \MultiArgCollect#1\delimiter{#2{#3}}}} + +\def\MultiArgCollecti#1\delimiter#2{\endgroup#2} + +\newcommand\DeclareMultiArgCommand[2]{\expandafter + \Declare@MultiArg@ \csname MA\string_\string#1\endcsname{#1}{#2}} +\def\Declare@MultiArg@#1#2#3{% + \DeclareRobustCommand{#2}{\MultiArg{#3}{#1}} + \newcommand{#1}[#3]} + +\DeclareMultiArgCommand {\printdate}{6}{...} +\end{lcode} + +\end{solution} + +%%\endinput + +\indexintoc +\printindex + +\end{document} + + |