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