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