at.dtx 23 KB

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