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