at.dtx 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. % \begin{meta-comment}
  2. %
  3. % $Id$
  4. %
  5. % Allow @-commands
  6. %
  7. % (c) 1995 Mark Wooding
  8. %
  9. %----- Revision history -----------------------------------------------------
  10. %
  11. % $Log$
  12. % Revision 1.1 1998-09-21 10:18:06 michael
  13. % Initial implementation
  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