86f6a31e |
1 | % \begin{meta-comment} |
2 | % |
3 | % $Id: at.dtx,v 1.1 2002/02/03 20:49:02 mdw Exp $ |
4 | % |
5 | % Allow @-commands |
6 | % |
7 | % (c) 1995 Mark Wooding |
8 | % |
86f6a31e |
9 | % \end{meta-comment} |
10 | % |
11 | % \begin{meta-comment} <general public licence> |
12 | %% |
13 | %% at package -- support for `@' commands' |
14 | %% Copyright (c) 1996 Mark Wooding |
15 | %% |
16 | %% This program is free software; you can redistribute it and/or modify |
17 | %% it under the terms of the GNU General Public License as published by |
18 | %% the Free Software Foundation; either version 2 of the License, or |
19 | %% (at your option) any later version. |
20 | %% |
21 | %% This program is distributed in the hope that it will be useful, |
22 | %% but WITHOUT ANY WARRANTY; without even the implied warranty of |
23 | %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
24 | %% GNU General Public License for more details. |
25 | %% |
26 | %% You should have received a copy of the GNU General Public License |
27 | %% along with this program; if not, write to the Free Software |
28 | %% Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
29 | %% |
30 | % \end{meta-comment} |
31 | % |
32 | % \begin{meta-comment} <Package preamble> |
33 | %<+package>\NeedsTeXFormat{LaTeX2e} |
34 | %<+package>\ProvidesPackage{at} |
35 | %<+package> [1996/05/02 1.3 @-command support (MDW)] |
36 | % \end{meta-comment} |
37 | % |
38 | % \CheckSum{355} |
39 | %% \CharacterTable |
40 | %% {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 |
41 | %% 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 |
42 | %% Digits \0\1\2\3\4\5\6\7\8\9 |
43 | %% Exclamation \! Double quote \" Hash (number) \# |
44 | %% Dollar \$ Percent \% Ampersand \& |
45 | %% Acute accent \' Left paren \( Right paren \) |
46 | %% Asterisk \* Plus \+ Comma \, |
47 | %% Minus \- Point \. Solidus \/ |
48 | %% Colon \: Semicolon \; Less than \< |
49 | %% Equals \= Greater than \> Question mark \? |
50 | %% Commercial at \@ Left bracket \[ Backslash \\ |
51 | %% Right bracket \] Circumflex \^ Underscore \_ |
52 | %% Grave accent \` Left brace \{ Vertical bar \| |
53 | %% Right brace \} Tilde \~} |
54 | %% |
55 | % |
56 | % \begin{meta-comment} <driver> |
57 | % |
58 | %<*driver> |
59 | \input{mdwtools} |
60 | \describespackage{at} |
61 | \aton |
62 | \atlet p=\package |
63 | \atdef at{\package{at}} |
64 | \atdef={\mbox{-}} |
65 | \atdef-{@@@=} |
66 | \atlet.=\syntax |
67 | \mdwdoc |
68 | %</driver> |
69 | % |
70 | % \end{meta-comment} |
71 | % |
72 | % \section{User guide} |
73 | % |
74 | % The @at\ package is an attempt to remove a lot of tedious typing that |
75 | % ends up in \LaTeX\ documents, by expanding the number of short command |
76 | % names available. The new command names begin with the `|@|' character, |
77 | % rather than the conventional `|\|', so you can tell them apart. |
78 | % |
79 | % The package provides some general commands for defining @-commands, and |
80 | % then uses them to define some fairly simple ones which will be useful to |
81 | % most people. |
82 | % |
83 | % The rules for @-command names aren't terribly complex: |
84 | % \begin{itemize} |
85 | % \item If the first character of the name is a letter, then the command name |
86 | % consists of all characters up to, but not including, the first |
87 | % nonletter. Spaces following the command name are ignored. |
88 | % \item If the first character of the name is a backslash, then the @-command |
89 | % name consists of the control sequence introduced by the backslash. |
90 | % \item Otherwise, the command name consists only of that first character. |
91 | % Spaces following the name are not ignored, unless that character |
92 | % was itself a space character. |
93 | % \end{itemize} |
94 | % |
95 | % Usually, digits are not considered to be letters. However, the |
96 | % \package{at} package will consider digits to be letters if you give it the |
97 | % \textsf{digits} option in the |\usepackage| command. (Note that this |
98 | % only affects the \package{at} package; it won't change the characters |
99 | % allowed in normal command names.) |
100 | % |
101 | % \DescribeMacro{\atallowdigits} |
102 | % \DescribeMacro{\atdisallowdigits} |
103 | % You can enable and disable digits being considered as letters dynamically. |
104 | % The |\atallowdigits| command allows digits to be used as letters; |
105 | % |\atdisallowdigits| prevents this. Both declarations follow \LaTeX's |
106 | % usual scoping rules. Both of these commands have corresponding |
107 | % environments with the same names (without the leading `|\|', obviously). |
108 | % |
109 | % \subsection{Defining @-commands} |
110 | % |
111 | % \DescribeMacro{\newatcommand} |
112 | % \DescribeMacro{\renewatcommand} |
113 | % The |\newatcommand| command will define a new @-command using a syntax |
114 | % similar to |\newcommand|. For example, you could define |
115 | % \begin{listing} |
116 | %\newatcommand c[1]{\chapter{#1}} |
117 | % \end{listing} |
118 | % to make @.{"@c{"<name>"}"} equivalent to @.{"\\chapter{"<name>"}"}. |
119 | % |
120 | % A |\renewatcommand| is also provided to redefine existing commands, should |
121 | % the need arise. |
122 | % |
123 | % \DescribeMacro{\atdef} |
124 | % For \TeX\ hackers, the |\atdef| command defines @-commands using a syntax |
125 | % similar to \TeX's built-in |\def|. |
126 | % |
127 | % As an example, the following command makes @.{"@/"<text>"/"} write its |
128 | % argument \<text> in italics: |
129 | % \begin{listing} |
130 | %\atdef/#1/{\textit{#1}} |
131 | % \end{listing} |
132 | % The real implementation of the |@/|\dots|/| command is a bit more |
133 | % complex, and is given in the next section. |
134 | % |
135 | % You can use all of \TeX's features for defining the syntax of your |
136 | % command. (See chapter~20 of @/The \TeX book/ for more details.) |
137 | % |
138 | % \DescribeMacro{\atlet} |
139 | % Since |\atdef| is provided to behave similarly to |\def|, @at\ provides |
140 | % |\atlet| which works similarly to |\let|. For example you can say |
141 | % \begin{listing} |
142 | %\atlet!=\index |
143 | % \end{listing} |
144 | % to allow the short |@!| to behave exactly like |\index|. |
145 | % |
146 | % Note that all commands defined using these commands are robust even if you |
147 | % use fragile commands in their definitions. Unless you start doing very |
148 | % strange things, @-commands never need |\protect|ing. |
149 | % |
150 | % \subsection{Predefined @-commands} |
151 | % |
152 | % A small number of hopefully useful commands are provided by default. |
153 | % These are described in the table below: |
154 | % |
155 | % \bigskip \begin{center} \begin{tabular}{lp{3in}} \hline |
156 | % \bf Command & \bf Meaning \\ \hline |
157 | % @.{"@@"} & Typesets an `@@' character. \\ |
158 | % @.{"@/"<text>"/"} & In text (LR or paragraph) mode, typesets its |
159 | % argument emphasised. In maths mode, it |
160 | % always chooses italics. \\ |
161 | % @.{"@*"<text>"*"} & Typesets its argument \<text> in bold. \\ |
162 | % @.{"@i{"<text>"}"} & Equivalent to `@.{"\\index{"<text>"}"}'. \\ |
163 | % @.{"@I{"<text>"}"} & As for |@i|, but also writes its argument |
164 | % to the document. \\ \hline |
165 | % \end{tabular} \end{center} \bigskip |
166 | % |
167 | % Package writers should not rely on any predefined @-commands -- they're |
168 | % provided for users, and users should be able to redefine them without |
169 | % fear of messing anything up. (This includes the `standard' commands |
170 | % provided by the @at\ package, by the way. They're provided in the vague |
171 | % hope that they might be useful, and as examples.) |
172 | % |
173 | % \implementation |
174 | % |
175 | % \section{Implementation} |
176 | % |
177 | % \begin{macrocode} |
178 | %<*package> |
179 | % \end{macrocode} |
180 | % |
181 | % \subsection{Options handling} |
182 | % |
183 | % We need a switch to say whether digits should be allowed. Since this |
184 | % is a user thing, I'll avoid |\newif| and just define the thing by hand. |
185 | % |
186 | % \begin{macrocode} |
187 | \def\atallowdigits{\let\ifat@digits\iftrue} |
188 | \def\atdisallowdigits{\let\ifat@digits\iffalse} |
189 | % \end{macrocode} |
190 | % |
191 | % Now define the options. |
192 | % |
193 | % \begin{macrocode} |
194 | \DeclareOption{digits}{\atallowdigits} |
195 | \DeclareOption{nodigits}{\atdisallowdigits} |
196 | \ExecuteOptions{nodigits} |
197 | \ProcessOptions |
198 | % \end{macrocode} |
199 | % |
200 | % \subsection{How the commands work} |
201 | % |
202 | % Obviously we make the `@@' character active. It inspects the next |
203 | % character (or argument, actually -- it can be enclosed in braces for |
204 | % longer commands, although this is a bit futile), and builds the command |
205 | % name from that. |
206 | % |
207 | % The |\at| command is equivalent to the active `@@' character always. |
208 | % |
209 | % |
210 | % \subsection{Converting command names} |
211 | % |
212 | % We need to be able to read an @-command name, and convert it to a normal |
213 | % \TeX\ control sequence. First, we declare some control sequences for |
214 | % braces, which we need later. |
215 | % |
216 | % \begin{macrocode} |
217 | \begingroup |
218 | \catcode`\<1 |
219 | \catcode`\>2 |
220 | \catcode`\{12 |
221 | \catcode`\}12 |
222 | \gdef\at@lb<{> |
223 | \gdef\at@rb<}> |
224 | \gdef\at@spc< > |
225 | \endgroup |
226 | % \end{macrocode} |
227 | % |
228 | % I'll set up some helper routines now, to help me read the command |
229 | % names. The way this works is that we |\futurelet| the token into |
230 | % |\@let@token|. These routines will then sort out what to do next. |
231 | % |
232 | % \begin{macro}{\at@test} |
233 | % |
234 | % Given an |\if|\dots\ test, does its first or second argument. |
235 | % |
236 | % \begin{macrocode} |
237 | \def\at@test#1\then{% |
238 | #1\expandafter\@firstoftwo\else\expandafter\@secondoftwo\fi% |
239 | } |
240 | % \end{macrocode} |
241 | % |
242 | % \end{macro} |
243 | % |
244 | % \begin{macro}{\at@ifcat} |
245 | % |
246 | % Checks the category code of the current character. If it matches the |
247 | % argument, it does its second argument, otherwise it does the third. |
248 | % |
249 | % \begin{macrocode} |
250 | \def\at@ifcat#1{\at@test\ifcat#1\noexpand\@let@token\then} |
251 | % \end{macrocode} |
252 | % |
253 | % \end{macro} |
254 | % |
255 | % \begin{macro}{\at@ifletter} |
256 | % |
257 | % This routine tests the token to see if it's a letter, and if so adds |
258 | % it to the token list and does the first argument; otherwise it does the |
259 | % second argument. It accepts digits as letters if the switch is turned |
260 | % on. |
261 | % |
262 | % There's some fun later, so I'll describe this slowly. First, we compare |
263 | % the category code to a letter, and if we have a match, we know we're done; |
264 | % we need to pick up the letter as an argument. If the catcode is `other', |
265 | % we must compare with numbers to see if it's in range. |
266 | % |
267 | % \begin{macrocode} |
268 | \def\at@ifletter#1#2{% |
269 | \at@ifcat x% |
270 | {\at@ifletter@ii{#1}}% |
271 | {\at@ifcat 0% |
272 | {\at@ifletter@i{#1}{#2}}% |
273 | {#2}% |
274 | }% |
275 | } |
276 | % \end{macrocode} |
277 | % |
278 | % Right. It's `other' (so it's safe to handle as a macro argument) and we |
279 | % need to know if it's a digit. This is a little tricky: I use |\if| to |
280 | % compare two characters. The first character is~`1' or~`0' depending on the |
281 | % `digit' switch; the second is~`1' or~`x' depending on whether it's actually |
282 | % a digit. They'll only match if everything's worked out OK. |
283 | % |
284 | % \begin{macrocode} |
285 | \def\at@ifletter@i#1#2#3{% |
286 | \at@test\if% |
287 | \ifat@digits1\else0\fi% |
288 | \ifnum`#3<`0x\else\ifnum`#3>`9x\else1\fi\fi% |
289 | \then% |
290 | {\at@ifletter@ii{#1}{#3}}% |
291 | {#2#3}% |
292 | } |
293 | % \end{macrocode} |
294 | % |
295 | % Right; we have the character, so add it to the list and carry on. |
296 | % |
297 | % \begin{macrocode} |
298 | \def\at@ifletter@ii#1#2{\toks@\expandafter{\the\toks@#2}#1} |
299 | % \end{macrocode} |
300 | % |
301 | % \end{macro} |
302 | % |
303 | % Now we define the command name reading routines. We have @/almost/ the |
304 | % same behaviour as \TeX, although we can't support `|%|' characters for |
305 | % reasons to do with \TeX's tokenising algorithm. |
306 | % |
307 | % \begin{macro}{\at@read@name} |
308 | % |
309 | % The routine which actually reads the command name works as follows: |
310 | % \begin{enumerate} |
311 | % \item Have a peek at the next character. If it's a left or right brace, |
312 | % then use the appropriate character. |
313 | % \item If the character is not a letter, just use the character (or whole |
314 | % control sequence. |
315 | % \item Finally, if it's a letter, keep reading letters until we find one |
316 | % that wasn't. |
317 | % \end{enumerate} |
318 | % |
319 | % First, we do some setting up and read the first character |
320 | % |
321 | % \begin{macrocode} |
322 | \def\at@read@name#1{% |
323 | \let\at@next=#1% |
324 | \toks@{}% |
325 | \futurelet\@let@token\at@rn@i% |
326 | } |
327 | % \end{macrocode} |
328 | % |
329 | % Next, sort out what to do, based on the category code. |
330 | % |
331 | % \begin{macrocode} |
332 | \def\at@rn@i{% |
333 | \def\@tempa{\afterassignment\at@rn@iv\let\@let@token= }% |
334 | \at@ifletter% |
335 | {\futurelet\@let@token\at@rn@iii}% |
336 | {\at@ifcat\bgroup% |
337 | {\toks@\expandafter{\at@lb}\@tempa}% |
338 | {\at@ifcat\egroup% |
339 | {\toks@\expandafter{\at@rb}\@tempa}% |
340 | {\at@ifcat\at@spc% |
341 | {\toks@{ }\@tempa}% |
342 | {\at@rn@ii}% |
343 | }% |
344 | }% |
345 | }% |
346 | } |
347 | % \end{macrocode} |
348 | % |
349 | % Most types of tokens can be fiddled using |\string|. |
350 | % |
351 | % \begin{macrocode} |
352 | \def\at@rn@ii#1{% |
353 | \toks@\expandafter{\string#1}% |
354 | \at@rn@iv% |
355 | } |
356 | % \end{macrocode} |
357 | % |
358 | % We've found a letter, so we should check for another one. |
359 | % |
360 | % \begin{macrocode} |
361 | \def\at@rn@iii{% |
362 | \at@ifletter% |
363 | {\futurelet\@let@token\at@rn@iii}% |
364 | {\@ifnextchar.\at@rn@iv\at@rn@iv}% |
365 | } |
366 | % \end{macrocode} |
367 | % |
368 | % Finally, we need to pass the real string, as an argument, to the |
369 | % macro. We make |\@let@token| relax, since it might be something which will |
370 | % upset \TeX\ later, e.g., a |#| character. |
371 | % |
372 | % \begin{macrocode} |
373 | \def\at@rn@iv{% |
374 | \let\@let@token\relax% |
375 | \expandafter\at@next\csname at.\the\toks@\endcsname% |
376 | } |
377 | % \end{macrocode} |
378 | % |
379 | % \end{macro} |
380 | % |
381 | % \begin{macro}{\at@cmdname} |
382 | % |
383 | % Given a control sequence, work out which @-command it came from. |
384 | % |
385 | % \begin{macrocode} |
386 | \def\at@cmdname#1{\expandafter\at@cmdname@i\string#1\@@foo} |
387 | % \end{macrocode} |
388 | % |
389 | % Now extract the trailing bits. |
390 | % |
391 | % \begin{macrocode} |
392 | \def\at@cmdname@i#1.#2\@@foo{#2} |
393 | % \end{macrocode} |
394 | % |
395 | % \end{macro} |
396 | % |
397 | % \begin{macro}{\at@decode} |
398 | % |
399 | % The |\at@decode| macro takes an extracted @-command name, and tries to |
400 | % execute the correct control sequence derived from it. |
401 | % |
402 | % \begin{macrocode} |
403 | \def\at@decode#1{% |
404 | \at@test\ifx#1\relax\then{% |
405 | \PackageError{at}{Unknown @-command `@\at@cmdname#1'}{% |
406 | The @-command you typed wasn't recognised, so I've ignored it. |
407 | }% |
408 | }{% |
409 | #1% |
410 | }% |
411 | } |
412 | % \end{macrocode} |
413 | % |
414 | % \end{macro} |
415 | % |
416 | % \begin{macro}{\@at} |
417 | % |
418 | % We'd like a measure of compatibility with @p{amsmath}. The @-commands |
419 | % provided by @p{amsmath} work only in maths mode, so this gives us a way of |
420 | % distinguishing. If the control sequence |\Iat| is defined, and we're in |
421 | % maths mode, we'll call that instead of doing our own thing. |
422 | % |
423 | % \begin{macrocode} |
424 | \def\@at{% |
425 | \def\@tempa{\at@read@name\at@decode}% |
426 | \ifmmode\ifx\Iat\not@@defined\else% |
427 | \let\@tempa\Iat% |
428 | \fi\fi% |
429 | \@tempa% |
430 | } |
431 | % \end{macrocode} |
432 | % |
433 | % \end{macro} |
434 | % |
435 | % |
436 | % \subsection{Defining new commands} |
437 | % |
438 | % \begin{macro}{\at@buildcmd} |
439 | % |
440 | % First, we define a command to build these other commands: |
441 | % |
442 | % \begin{macrocode} |
443 | \def\at@buildcmd#1#2{% |
444 | \expandafter\def\csname\expandafter |
445 | \@gobble\string#1@decode\endcsname##1{#2##1}% |
446 | \edef#1{% |
447 | \noexpand\at@read@name% |
448 | \expandafter\noexpand% |
449 | \csname\expandafter\@gobble\string#1@decode\endcsname% |
450 | }% |
451 | } |
452 | % \end{macrocode} |
453 | % |
454 | % \end{macro} |
455 | % |
456 | % \begin{macro}{\newatcommand} |
457 | % \begin{macro}{\renewatcommand} |
458 | % \begin{macro}{\provideatcommand} |
459 | % \begin{macro}{\atdef} |
460 | % \begin{macro}{\atshow} |
461 | % |
462 | % Now we define the various operations on @-commands. |
463 | % |
464 | % \begin{macrocode} |
465 | \at@buildcmd\newatcommand\newcommand |
466 | \at@buildcmd\renewatcommand\renewcommand |
467 | \at@buildcmd\provideatcommand\providecommand |
468 | \at@buildcmd\atdef\def |
469 | \at@buildcmd\atshow\show |
470 | % \end{macrocode} |
471 | % |
472 | % \end{macro} |
473 | % \end{macro} |
474 | % \end{macro} |
475 | % \end{macro} |
476 | % \end{macro} |
477 | % |
478 | % \begin{macro}{\atlet} |
479 | % |
480 | % |\atlet| is rather harder than the others, because we want to allow people |
481 | % to say things like @.{"\\atlet"<name>"=@"<name>}. The following hacking |
482 | % does the trick. I'm trying very hard to duplicate |\let|'s behaviour with |
483 | % respect to space tokens here, to avoid any surprises, although there |
484 | % probably will be some differences. In particular, |\afterassignment| |
485 | % won't work in any sensible way. |
486 | % |
487 | % First, we read the name of the @-command we're defining. We also open |
488 | % a group, to stop messing other people up, and make `@@' into an `other' |
489 | % token, so that it doesn't irritatingly look like its meaning as a control |
490 | % sequence. |
491 | % |
492 | % \begin{macrocode} |
493 | \def\atlet{% |
494 | \begingroup% |
495 | \@makeother\@% |
496 | \at@read@name\atlet@i% |
497 | } |
498 | % \end{macrocode} |
499 | % |
500 | % Put the name into a scratch macro for later use. Now see if there's an |
501 | % equals sign up ahead. If not, this will gobble any spaces in between the |
502 | % @-command name and the argument. |
503 | % |
504 | % \begin{macrocode} |
505 | \def\atlet@i#1{% |
506 | \def\at@temp{#1}% |
507 | \@ifnextchar=\atlet@ii{\atlet@ii=}% |
508 | } |
509 | % \end{macrocode} |
510 | % |
511 | % Now we gobble the equals sign (whatever catcode it is), and peek at the |
512 | % next token up ahead using |\let| with no following space. |
513 | % |
514 | % \begin{macrocode} |
515 | \def\atlet@ii#1{\afterassignment\atlet@iii\global\let\at@gnext=} |
516 | % \end{macrocode} |
517 | % |
518 | % The control sequence |\at@gnext| is now |\let| to be whatever we want the |
519 | % @-command to be, unless it's picked up an `@@' sign. If it has, we've |
520 | % eaten the |@| token, so just read the name and pass it on. Otherwise, |
521 | % we can |\let| the @-command directly to |\at@gnext|. There's some |
522 | % nastiness here to make |\the\toks@| expand before we close the group and |
523 | % restore its previous definition. |
524 | % |
525 | % \begin{macrocode} |
526 | \def\atlet@iii{% |
527 | \if @\noexpand\at@gnext% |
528 | \expandafter\at@read@name\expandafter\atlet@iv% |
529 | \else% |
530 | \expandafter\endgroup% |
531 | \expandafter\let\at@temp= \at@gnext% |
532 | \fi% |
533 | } |
534 | % \end{macrocode} |
535 | % |
536 | % We've read the source @-command name, so just copy the definitions over. |
537 | % |
538 | % \begin{macrocode} |
539 | \def\atlet@iv#1{% |
540 | \expandafter\endgroup% |
541 | \expandafter\let\at@temp=#1% |
542 | } |
543 | % \end{macrocode} |
544 | % |
545 | % \end{macro} |
546 | % |
547 | % |
548 | % \subsection{Robustness of @-commands} |
549 | % |
550 | % We want all @-commands to be robust. We could leave them all being |
551 | % fragile, although making robust @-commands would then be almost impossible. |
552 | % There are two problems which we must face: |
553 | % |
554 | % \begin{itemize} |
555 | % |
556 | % \item The `|\@at|' command which scans the @-command name is (very) |
557 | % fragile. I could have used |\DeclareRobustCommand| for it (and in |
558 | % fact I did in an earlier version), but that doesn't help the other |
559 | % problem at all. |
560 | % |
561 | % \item The `name' of the @-command may contain active characters or control |
562 | % sequences, which will be expanded at the wrong time unless we do |
563 | % something about it now. |
564 | % |
565 | % \end{itemize} |
566 | % |
567 | % We must also be careful not to introduce extra space characters into any |
568 | % files written, because spaces are significant in @-commands. Finally, |
569 | % we have a minor problem in that most auxiliary files are read in with |
570 | % the `@@' character set to be a letter. |
571 | % |
572 | % \begin{macro}{\at} |
573 | % |
574 | % Following the example of \LaTeX's `short' command handling, we'll define |
575 | % |\at| to decide what to do depending on what |\protect| looks like. If |
576 | % we're typesetting, we just call |\@at| (above) and expect it to cope. |
577 | % Otherwise we call |\at@protect|, which scoops up the |\fi| and the |\@at|, |
578 | % and inserts other magic. |
579 | % |
580 | % \begin{macrocode} |
581 | \def\at{\ifx\protect\@typeset@protect\else\at@protect\fi\@at} |
582 | % \end{macrocode} |
583 | % |
584 | % \end{macro} |
585 | % |
586 | % \begin{macro}{\at@protect} |
587 | % |
588 | % Since we gobbled the |\fi| from the above, we must put that back. We then |
589 | % need to do things which are more complicated. If |\protect| is behaving |
590 | % like |\string|, then we do one sort of protection. Otherwise, we assume |
591 | % that |\protect| is being like |\noexpand|. |
592 | % |
593 | % \begin{macrocode} |
594 | \def\at@protect\fi#1{% |
595 | \fi% |
596 | \ifx\protect\string% |
597 | \expandafter\at@protect@string% |
598 | \else% |
599 | \expandafter\at@protect@noexpand% |
600 | \fi% |
601 | } |
602 | % \end{macrocode} |
603 | % |
604 | % \end{macro} |
605 | % |
606 | % \begin{macro}{\at@protect@string} |
607 | % |
608 | % When |\protect| is |\string|, we don't need to be able to recover the |
609 | % original text particularly accurately -- it's for the user to look at. |
610 | % Therefore, we just output a $|@|_{11}$ and use |\string| on the next |
611 | % token. This must be sufficient, since we only allow multi-token command |
612 | % names if the first token is a letter (code~11). |
613 | % |
614 | % \begin{macrocode} |
615 | \def\at@protect@string{@\string} |
616 | % \end{macrocode} |
617 | % |
618 | % \end{macro} |
619 | % |
620 | % \begin{macro}{\at@protect@noexpand} |
621 | % |
622 | % This is a little more complex, since we're still expecting to be executed |
623 | % properly at some stage. However, there's a cheeky dodge we can employ |
624 | % since the |\at| command is thoroughly robustified (or at least it will be |
625 | % by the time we've finished this). All |\@unexpandable@protect| does |
626 | % is confer repeated robustness on a fragile command. Since our command |
627 | % is robust, we don't need this and we can get away with just using a |
628 | % single |\noexpand|, both for the |\@at@| command and the following token |
629 | % (which we must robustify, because no-one else can do it for us -- if |
630 | % anyone tries, they end up using the |@\protect| command which is rather |
631 | % embarassing). |
632 | % |
633 | % I'll give the definition, and then examine how this expands in various |
634 | % cases. |
635 | % |
636 | % \begin{macrocode} |
637 | \def\at@protect@noexpand{\noexpand\@at@ @\noexpand} |
638 | \def\@at@#1{\at} |
639 | % \end{macrocode} |
640 | % |
641 | % A few points, before we go into the main examination of the protection. |
642 | % I've inserted a $|@|_{11}$ token, which is gobbled by |\@at@| when the |
643 | % thing is finally expanded fully. This prevents following space tokens |
644 | % in an |\input| file from being swallowed because they follow a control |
645 | % sequence. (I can't use the normal $|@|_{13}$ token, because when files |
646 | % like the |.aux| file are read in, |@| is given code~11 by |
647 | % |\makeatletter|.) |
648 | % |
649 | % \setbox0\hbox{|@at@|} |
650 | % Now for a description of why this works. When |\at| is expanded, it works |
651 | % out that |\protect| is either |\noexpand| or |\@unexpandable@protect|, and |
652 | % becomes |\at@protect@noexpand|. Because of the |\noexpand| tokens, this |
653 | % stops being expanded once it reaches $\fbox{\box0}\,|@|_{11}\,x$ (where |
654 | % $x$ is the token immediately following the $|@|_{13}$ character). If this |
655 | % is expanded again, for example in another |\edef|, or in a |\write| or a |
656 | % |\mark|, the |\@at@| wakes up, gobbles the following |@| (whatever catcode |
657 | % it is -- there may be intervening |\write| and |\input| commands) and |
658 | % becomes |\at|, and the whole thing can start over again. |
659 | % |
660 | % \end{macro} |
661 | % |
662 | % |
663 | % \subsection{Enabling and disabling @-commands} |
664 | % |
665 | % \begin{macro}{\aton} |
666 | % |
667 | % We define the |\aton| command to enable all of our magic. We store |
668 | % the old catcode in the |\atoff| command, make `@@' active, and make it |
669 | % do the stuff. |
670 | % |
671 | % \begin{macrocode} |
672 | \def\aton{% |
673 | \ifnum\catcode`\@=\active\else% |
674 | \edef\atoff{\catcode`\noexpand\@\the\catcode`\@}% |
675 | \catcode`\@\active% |
676 | \lccode`\~`\@% |
677 | \lowercase{\let~\at}% |
678 | \fi% |
679 | } |
680 | % \end{macrocode} |
681 | % |
682 | % \end{macro} |
683 | % |
684 | % \begin{macro}{\atoff} |
685 | % |
686 | % The |\atoff| command makes `@@' do the stuff it's meant to. We remember |
687 | % the old catcode and revert to it. This is largely unnecessary. |
688 | % |
689 | % \begin{macrocode} |
690 | \def\atoff{\catcode`\@12} |
691 | % \end{macrocode} |
692 | % |
693 | % \end{macro} |
694 | % |
695 | % \begin{macro}{\makeatother} |
696 | % |
697 | % Now we make our active `@@' the default outside of package files. |
698 | % |
699 | % \begin{macrocode} |
700 | \let\makeatother\aton |
701 | % \end{macrocode} |
702 | % |
703 | % \end{macro} |
704 | % |
705 | % And we must make sure that the user can use all of our nice commands. |
706 | % Once the document starts, we allow @-commands. |
707 | % |
708 | % \begin{macrocode} |
709 | \AtBeginDocument{\aton} |
710 | % \end{macrocode} |
711 | % |
712 | % \begin{macro}{\dospecials} |
713 | % \begin{macro}{\@sanitize} |
714 | % |
715 | % We must add the `@@' character to the various specials lists. |
716 | % |
717 | % \begin{macrocode} |
718 | \expandafter\def\expandafter\dospecials\expandafter{\dospecials\do\@} |
719 | \expandafter\def\expandafter\@sanitize\expandafter{% |
720 | \@sanitize\@makeother\@} |
721 | % \end{macrocode} |
722 | % |
723 | % \end{macro} |
724 | % \end{macro} |
725 | % |
726 | % \subsection{Default @-commands} |
727 | % |
728 | % We define some trivial examples to get the user going. |
729 | % |
730 | % \begin{macrocode} |
731 | \expandafter\chardef\csname at.@\endcsname=`\@ |
732 | \atdef*#1*{\ifmmode\mathbf{#1}\else\textbf{#1}\fi} |
733 | \atdef/#1/{\ifmmode\mathit{#1}\else\emph{#1}\fi} |
734 | \atlet i=\index |
735 | \atdef I#1{#1\index{#1}} |
736 | %</package> |
737 | % \end{macrocode} |
738 | % |
739 | % \hfill Mark Wooding, \today |
740 | % |
741 | % \Finale |
742 | % |
743 | \endinput |