doafter.dtx 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. % \begin{meta-comment}
  2. %
  3. % $Id$
  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$
  12. % Revision 1.1 1998-09-21 10:19:01 michael
  13. % Initial implementation
  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