infra: Expunge revision history clutter.
[mdwtools] / doafter.dtx
1 % \begin{meta-comment}
2 %
3 % $Id: doafter.dtx,v 1.1 2002/02/03 20:49:03 mdw Exp $
4 %
5 % Insert tokens to be read after a group has been processed
6 %
7 % (c) 1996 Peter Schmitt and Mark Wooding
8 %
9 % \end{meta-comment}
10 %
11 % \begin{meta-comment} <general public licence>
12 %%
13 %% doafter package -- insert a token really after a group
14 %% Copyright (c) 1996 Peter Schmitt and Mark Wooding
15 %<*package>
16 %%
17 %% This program is free software; you can redistribute it and/or modify
18 %% it under the terms of the GNU General Public License as published by
19 %% the Free Software Foundation; either version 2 of the License, or
20 %% (at your option) any later version.
21 %%
22 %% This program is distributed in the hope that it will be useful,
23 %% but WITHOUT ANY WARRANTY; without even the implied warranty of
24 %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 %% GNU General Public License for more details.
26 %%
27 %% You should have received a copy of the GNU General Public License
28 %% along with this program; if not, write to the Free Software
29 %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 %</package>
31 %%
32 % \end{meta-comment}
33 %
34 % \begin{meta-comment} <Package preamble>
35 %<+latex2e>\NeedsTeXFormat{LaTeX2e}
36 %<+latex2e>\ProvidesPackage{doafter}
37 %<+latex2e> [1996/05/08 1.2 Aftergroup hacking (PS/MDW)]
38 % \end{meta-comment}
39 %
40 % \CheckSum{259}
41 %\iffalse
42 %<*package>
43 %\fi
44 %% \CharacterTable
45 %% {Upper-case \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
46 %% Lower-case \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
47 %% Digits \0\1\2\3\4\5\6\7\8\9
48 %% Exclamation \! Double quote \" Hash (number) \#
49 %% Dollar \$ Percent \% Ampersand \&
50 %% Acute accent \' Left paren \( Right paren \)
51 %% Asterisk \* Plus \+ Comma \,
52 %% Minus \- Point \. Solidus \/
53 %% Colon \: Semicolon \; Less than \<
54 %% Equals \= Greater than \> Question mark \?
55 %% Commercial at \@ Left bracket \[ Backslash \\
56 %% Right bracket \] Circumflex \^ Underscore \_
57 %% Grave accent \` Left brace \{ Vertical bar \|
58 %% Right brace \} Tilde \~}
59 %%
60 %\iffalse
61 %</package>
62 %\fi
63 %
64 % \begin{meta-comment} <driver>
65 %
66 %<*driver>
67 \input{mdwtools}
68 \describespackage{doafter}
69 \author{Peter Schmitt\thanks{%
70 Peter came up with the basic implementation after I posed the problem
71 in the \texttt{comp.text.tex} newsgroup. I fixed some really piddly little
72 things, to improve it a bit, wrote the documentation, and turned the code
73 into a nice \package{doc}ced package. Then Peter gave me an updated
74 version, and I upgraded this from memory. Then he gave me some more tweaks
75 which I haven't incorporated.}
76 \and Mark Wooding}
77 \def\author#1{}
78 \mdwdoc
79 %</driver>
80 %
81 % \end{meta-comment}
82 %
83 % \section{Description}
84 %
85 % \subsection{What it's all about}
86 %
87 % \DescribeMacro{\doafter}
88 % It's common for the \TeX\ primitive |\aftergroup| to be used to `tidy up'
89 % after a group. For example, \LaTeX's colour handling uses this to insert
90 % appropriate |\special|s when the scope of a colour change ends. This
91 % causes several problems, though; for example, extra grouping must be added
92 % within boxes to ensure that the |\special|s don't `leak' out of their box
93 % and appear in odd places in the document. \LaTeX\ usually solves this
94 % problem by reading the box contents as an argument, although this isn't
95 % particularly desirable. The |\doafter| macro provided here will solve the
96 % problem in a different way, by allowing a macro to regain control after
97 % all the |\aftergroup| things have been processed.
98 %
99 % The macro works like this:
100 % \begin{grammar}
101 % <doafter-cmd> ::= \[[
102 % "\\doafter" <token> <group>
103 % \]]
104 % \end{grammar}
105 % The \<token> can be any token you like, except an explicit braces, since
106 % it's read as an undelimited macro argument. The \<group> is a normal
107 % \TeX\ group, surrounded by either implicit or explicit braces, or by
108 % |\begingroup| and |\endgroup| tokens. Once the final closing token of the
109 % \<group> is read, and any tokens saved up by |\aftergroup| have been
110 % processed, the \<token> is inserted and processed. Under normal
111 % circumstances, this will be a macro.
112 %
113 % There are some subtle problems with the current implementation, which you
114 % may need to be aware of:
115 %
116 % \begin{itemize}
117 %
118 % \item Since we're inserting things after all the |\aftergroup| tokens,
119 % those tokens might read something they're not expecting if they try
120 % to look ahead at the text after the group (e.g., with |\futurelet|).
121 % This is obviously totally unavoidable.
122 %
123 % \item Implicit braces (like |\bgroup| and |\egroup|) inserted using
124 % |\aftergroup| may be turned into \emph{explicit} $|{|_1$ and $|}|_2$
125 % characters within a |\doafter| group. This can cause probems under
126 % very specialised circumstances. The names |\bgroup| and |\egroup|
127 % are treated specially, and they will work normally (remaining as
128 % implicit braces). This should minimise problems caused by this
129 % slight difference. (This only applies to the last |\aftergroup|
130 % token in a group.)
131 %
132 % \item To handle the |\aftergroup| tokens properly, |\doafter| has to insert
133 % some |\aftergroup| tokens of its own. It will then process the
134 % other tokens some more, and set them up to be read again. This does
135 % mean that after the group ends, some assignments and other `stomach
136 % operations' will be performed, which may cause problems in
137 % alignments and similar places.
138 %
139 % \end{itemize}
140 %
141 %
142 % \subsection{Package options}
143 %
144 % There are a fair few \textsf{docstrip} options provided by this packge:
145 %
146 % \begin{description}
147 % \item [driver] extracts the documentation driver. This isn't usually
148 % necessary.
149 % \item [package] extracts the code as a standalone package, formatted for
150 % either \LaTeXe\ or Plain~\TeX.
151 % \item [latex2e] inserts extra identification code for a \LaTeXe\ package.
152 % \item [plain] inserts some extra code for a Plain \TeX\ package.
153 % \item [macro] just extracts the raw code, for inclusion in another package.
154 % \item [test] extracts some code for testing the current implementation.
155 % \end{description}
156 %
157 %
158 % \implementation
159 %
160 % \section{Implementation}
161 %
162 % \subsection{The main macro}
163 %
164 % We start outputting code here. If this is a Plain~\TeX\ package, we must
165 % make \lit{@} into a letter.
166 %
167 % \begin{macrocode}
168 %<*macro|package>
169 %<+plain>\catcode`\@=11
170 % \end{macrocode}
171 %
172 % \begin{macro}{\doafter}
173 %
174 % The idea is to say \syntax{"\\doafter" <token> <group>} and expect the
175 % \synt{token} to be processed after the group has finished its stuff,
176 % even if it contains |\aftergroup| things. My eternal gratitude goes to
177 % Peter Schmitt, who came up with most of the solution implemented here;
178 % I've just tidied up some very minor niggles and things later.
179 %
180 % Let's start with some preamble. I'll save the (hopefully) primitive
181 % |\aftergroup| in a different token.
182 %
183 % \begin{macrocode}
184 \let\@@aftergroup\aftergroup
185 % \end{macrocode}
186 %
187 % Now to define the `user' interface. It takes a normal undelimited
188 % argument, although this must be a single token; otherwise eveything will
189 % go wrong. It assumes that the token following is some kind of group
190 % opening thing (an explicit or implicit character with catcode~1, or
191 % a |\begingroup| token). To make this work, I'll save the token,
192 % together with an |\@@aftergroup| (to save an |\expandafter| later) in
193 % a temporary macro which no-one will mind me using, and then look ahead at
194 % the beginning-group token.
195 %
196 % \begin{macrocode}
197 \def\doafter#1{%
198 \def\@tempa{\@@aftergroup#1}%
199 \afterassignment\doafter@i\let\@let@token%
200 }
201 % \end{macrocode}
202 %
203 % I now have the token in |\@let@token|, so I'll put that in. I'll then
204 % make |\aftergroup| do my thing rather than the normal thing, and queue
205 % the tokens |\@prepare@after| and the |\doafter| argument for later use.
206 %
207 % \begin{macrocode}
208 \def\doafter@i{%
209 \@let@token%
210 \let\aftergroup\@my@aftergroup%
211 \@@aftergroup\@prepare@after\@tempa%
212 }
213 % \end{macrocode}
214 %
215 % \end{macro}
216 %
217 % \begin{macro}{\@my@aftergroup}
218 %
219 % Now the cleverness begins. We keep two macros (Peter's original used
220 % count registers) which keep counts of the numbers of |\aftergroup|s,
221 % both locally and globally. Let's call the local counter~$n$ and the
222 % global one $N$. Every time we get a call to our |\aftergroup| hack,
223 % we set~$n := n+1$ and~$N := n$, and leave the token given to us for later
224 % processing. When we actually process an |\aftergroup| token properly,
225 % set~$N := N-1$ to indicate that it's been handled; when they're all done,
226 % we'll have $N=n$, which is exactly what we'd have if there weren't any
227 % to begin with.
228 %
229 % \begin{macrocode}
230 \def\ag@cnt@local{0 }
231 \let\ag@cnt@global\ag@cnt@local
232 % \end{macrocode}
233 %
234 % Now we come to the definition of my version of |\aftergroup|. I'll just
235 % add the token |\@after@token| before every |\aftergroup| token I find.
236 % This means there's two calls to |\aftergroup| for every one the user makes,
237 % but these things aren't all that common, so it's OK really. I'll also
238 % bump the local counter, and synchronise them.
239 %
240 % \begin{macrocode}
241 \def\@my@aftergroup{%
242 \begingroup%
243 \count@\ag@cnt@local%
244 \advance\count@\@ne%
245 \xdef\ag@cnt@global{\the\count@\space}%
246 \endgroup%
247 \let\ag@cnt@local\ag@cnt@global%
248 \@@aftergroup\@after@token\@@aftergroup%
249 }
250 % \end{macrocode}
251 %
252 % \end{macro}
253 %
254 % Now what does |\@after@token| we inserted above actually do? Well, this
255 % is more exciting. There are actually two different variants of the
256 % macro, which are used at different times.
257 %
258 % \begin{macro}{\@after@token}
259 %
260 % The default |\@after@token| starts a group, which will `catch'
261 % |\aftergroup| tokens which I throw at it. I put the two counters into
262 % some scratch count registers. (There's a slight problem here: Plain \TeX\
263 % only gives us one. For the sake of evilness I'll use |\clubpenalty| as the
264 % other one. Eeeek.) I then redefine |\@after@token| to the second
265 % variant, and execute it. The |\@start@after@group| macro starts the
266 % group, because this code is shared with |\@prepare@after| below.
267 %
268 % \begin{macrocode}
269 \def\@after@token{%
270 \@start@after@group%
271 \@after@token%
272 }
273 \def\@start@after@group{%
274 \begingroup%
275 \count@\ag@cnt@global%
276 \clubpenalty\ag@cnt@local%
277 \let\@after@token\@after@token@i%
278 }
279 % \end{macrocode}
280 %
281 % \end{macro}
282 %
283 % \begin{macro}{\@after@token@i}
284 %
285 % I have $|\count@| = N$ and $|\@tempcnta| = n$. I'll decrement~$N$,
286 % and if I have $N = n$, I know that this is the last token to do, so I
287 % must insert an |\@after@all| after the token. This will close the group,
288 % and maybe insert the original |\doafter| token if appropriate.
289 %
290 % \begin{macrocode}
291 \def\@after@token@i{%
292 \advance\count@\m@ne%
293 \ifnum\count@=\clubpenalty%
294 \global\let\ag@cnt@global\ag@cnt@local%
295 \expandafter\@after@aftertoken\expandafter\@after@all%
296 \else%
297 \expandafter\@@aftergroup%
298 \fi%
299 }
300 % \end{macrocode}
301 %
302 % Finally, establish a default meaning for |\@after@all|.
303 %
304 % \begin{macrocode}
305 \let\@after@all\endgroup
306 % \end{macrocode}
307 %
308 % \end{macro}
309 %
310 % \begin{macro}{\@prepare@after}
311 %
312 % If this group is handled by |\doafter|, then the first |\aftergroup| token
313 % isn't |\@after@token|; it's |\@prepare@after|.
314 %
315 % There are some extra cases to deal with:
316 % \begin{itemize}
317 % \item If $N=n$ then there were no |\aftergroup| tokens, so we have an easy
318 % job. I'll just let the token do its stuff directly.
319 % \item Otherwise, $N>n$, and there are |\aftergroup| tokens. I'll open
320 % the group, and let |\@after@token| do all the handling.
321 % \end{itemize}
322 %
323 % \begin{macrocode}
324 \def\@prepare@after{%
325 \ifx\ag@cnt@local\ag@cnt@global\else%
326 \expandafter\@prepare@after@i%
327 \fi%
328 }
329 \def\@prepare@after@i#1{%
330 \@start@after@group%
331 \def\@after@all{\@@aftergroup#1\endgroup}%
332 }
333 % \end{macrocode}
334 %
335 % \end{macro}
336 %
337 % \begin{macro}{\@after@aftertoken}
338 %
339 % This is where all the difficulty lies. The next token in the stream is
340 % an |\aftergroup| one, which could be more or less anything. We have an
341 % argument, which is some code to do \emph{after} the token has been
342 % |\aftergroup|ed.
343 %
344 % If the token is anything other than a brace (i.e., an explicit character
345 % of category~1 or~2) then I have no problem; I can scoop up the token with
346 % an undelimited macro argument. But the only way I can decide if this token
347 % is a brace (nondestructively) is with |\futurelet|, which makes the token
348 % implicit, so I can't decide whether it's really dangerous.
349 %
350 % There is a possible way of doing this\footnote{Due to Peter Schmitt,
351 % again.} which relates to nobbling the offending token with |\string| and
352 % sifting through the results. The problem here involves scooping up all the
353 % tokens of a |\string|ed control sequence, which may turn out to be
354 % `|\csname\endcsname|' or something equally horrid.
355 %
356 % The solution I've used is much simpler: I'll change |\bgroup| and |\egroup|
357 % to stop them from being implicit braces before comparing.
358 %
359 % \begin{macrocode}
360 \def\@after@aftertoken#1{%
361 \let\bgroup\relax\let\egroup\relax%
362 \toks@{#1}%
363 \futurelet\@let@token\@after@aftertoken@i%
364 }
365 \def\@after@aftertoken@i{%
366 \ifcat\noexpand\@let@token{%
367 \@@aftergroup{%
368 \else\ifcat\noexpand\@let@token}%
369 \@@aftergroup}%
370 \else%
371 \def\@tempa##1{\@@aftergroup##1\the\toks@}%
372 \expandafter\expandafter\expandafter\@tempa%
373 \fi\fi%
374 }
375 % \end{macrocode}
376 %
377 % \end{macro}
378 %
379 %
380 % Phew!
381 %
382 % \begin{macrocode}
383 %<+plain>\catcode`\@=12
384 %</macro|package>
385 % \end{macrocode}
386 %
387 % \subsection{Test code}
388 %
389 % The following code gives |\doafter| a bit of a testing. It's based on
390 % the test suite I gave to comp.text.tex, although it's been improved a
391 % little since then.
392 %
393 % The first thing to do is define a control sequence with an \lit{@} sign
394 % in its name, so we can test catcode changes. This also hides an
395 % |\aftergroup| within a macro, making life more difficult for prospective
396 % implementations.
397 %
398 % \begin{macrocode}
399 %<*test>
400 \catcode`\@=11
401 \def\at@name{\aftergroup\saynine}
402 \def\saynine{\say{ix}}
403 \catcode`\@=12
404 % \end{macrocode}
405 %
406 % Now define a command to write a string to the terminal. The name will
407 % probably be familiar to REXX hackers.
408 %
409 % \begin{macrocode}
410 \def\say{\immediate\write16}
411 % \end{macrocode}
412 %
413 % Test one: This is really easy; it just tests that the thing works at all.
414 % If your implementation fails this, it's time for a major rethink.
415 %
416 % \begin{macrocode}
417 \say{Test one... (1--2)}
418 \def\saytwo{\say{ii}}
419 \doafter\saytwo{\say{i}}
420 % \end{macrocode}
421 %
422 % Test two: Does |\aftergroup| work?
423 %
424 % \begin{macrocode}
425 \say{Test two... (1--4)}
426 \def\saythree{\say{iii}}
427 \def\sayfour{\say{iv}}
428 \doafter\sayfour{\say{i}\aftergroup\saythree\say{ii}}
429 % \end{macrocode}
430 %
431 % Test three: Test braces and |\iffalse| working as they should. Several
432 % proposed solutions based on |\write|ing the group to a file get upset by
433 % this test, although I forgot to include it in the torture test. It also
434 % tests whether literal braces can be |\aftergroup|ed properly. (Added a new
435 % test here, making sure that |\bgroup| is left as an implicit token.)
436 %
437 % \begin{macrocode}
438 \say{Test three... (1--4, `\string\bgroup', 5)}
439 \def\sayfive{\say{v}}
440 \doafter\sayfive{%
441 \say{i}%
442 \aftergroup\say%
443 \aftergroup{%
444 \aftergroup\romannumeral\aftergroup3%
445 \aftergroup}%
446 \iffalse}\fi%
447 \aftergroup\def%
448 \aftergroup\sayfouretc%
449 \aftergroup{%
450 \aftergroup\say%
451 \aftergroup{%
452 \aftergroup i%
453 \aftergroup v%
454 \aftergroup}%
455 \aftergroup\say%
456 \aftergroup{%
457 \aftergroup\string%
458 \aftergroup\bgroup%
459 \aftergroup}%
460 \aftergroup}%
461 \aftergroup\sayfouretc%
462 \say{ii}%
463 }
464 % \end{macrocode}
465 %
466 % Test four: Make sure the implementation isn't leaking things. This just
467 % makes sure that |\aftergroup| is its normal reasonable self.
468 %
469 % \begin{macrocode}
470 \say{Test four... (1--3)}
471 {\say{i}\aftergroup\saythree\say{ii}}
472 % \end{macrocode}
473 %
474 % Test five: Nesting, aftergroup, catcodes, grouping. This is the `torture'
475 % test I gave to comp.text.tex, slightly corrected (oops) and amended. It
476 % ensures that nested groups and |\doafter|s work properly (the latter is
477 % actually more likely than might be imagined).
478 %
479 % \begin{macrocode}
480 \say{Test five... (1--14)}
481 \def\sayten{\say{x}}
482 \def\saythirteen{\say{xiii}}
483 \def\sayfourteen{\say{xiv}}
484 \doafter\sayfourteen\begingroup%
485 \say{i}%
486 {\say{ii}\aftergroup\sayfour\say{iii}}%
487 \def\saynum{\say{viii}}%
488 \doafter\sayten{%
489 \say{v}%
490 \def\saynum{\say{vii}}%
491 \catcode`\@=11%
492 \aftergroup\saynum%
493 \say{vi}%
494 \at@name%
495 \saynum%
496 }%
497 \say{xi}%
498 \aftergroup\saythirteen%
499 \say{xii}%
500 \endgroup
501 \end
502 %</test>
503 % \end{macrocode}
504 %
505 % That's it. All present and correct.
506 %
507 % \Finale
508 %
509 \endinput