doafter.dtx 17 KB

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