% Copyright 2000 Frank Mittelbach . % License: LPPL, version 1.3a or newer, according to % http://www.latex-project.org/lppl.txt. % % This work has the LPPL maintenance status `maintained'. % % The Current Maintainer of this work is Werner Lemberg . % % % This is the file dblaccnt.tex which implements support for multiple % accents. % % % The code below handles only the case of % % \acc1 \acc2 ... glyph % % with or without nesting braces. % % \acc1 {\acc2 a} % % etc. will be handled correctly by removing the brace group during % the scanning process. This means in particular that conceptually % any accent command can only handle single token arguments! % % It should also work for combinations generated from inputenc, i.e., % are presented as 8bit tokens or, after passing through something like % an .aux file, as \IeC{\acc1} \IeC{\acc2} ... % % If you use OT1 encoding you have to explicitly reload it (with % \usepackage[OT1]{fontenc}). % % % History % % 1.0 2000/01/27 % % Initial release. % % 1.1 2005/04/21 % % Make it work with LaTeX release 2003/12/01. % Add copyright message and history. % \ProvidesPackage{dblaccnt}[2005/04/21 v1.1 double accent support] \endlinechar \m@ne % We must redefine two internal LaTeX commands to provide hooks for % assembling accents. % Here we test whether #1 (the command to be executed) is \chardef or % #3 (the encoding) is `?'. If both are false, \assemble@accent@cmds % will be used. % % The first case catches \DeclareTextSymbol, the second catches % \ProvideTextCommandDefault. Both checks are ugly hacks which hopefully % disappear in the near future. % \def\@dec@text@cmd#1#2#3{ \ifx#1\chardef \expandafter\def\expandafter#2\expandafter{ \csname#3-cmd\expandafter\endcsname \expandafter#2 \csname#3\string#2\endcsname } \else \ifx#1\chardef@text@cmd \expandafter\def\expandafter#2\expandafter{ \csname#3-cmd\expandafter\endcsname \expandafter#2 \csname#3\string#2\endcsname } \else \if#3? \expandafter\def\expandafter#2\expandafter{ \csname#3-cmd\expandafter\endcsname \expandafter#2 \csname#3\string#2\endcsname } \else \expandafter\def\expandafter#2\expandafter{ % start looking for acc tokens \expandafter\assemble@accent@cmds \csname#3-cmd\expandafter\endcsname \expandafter#2 \csname#3\string#2\endcsname } \fi \fi \fi \let\@ifdefinable\@rc@ifdefinable \expandafter#1\csname#3\string#2\endcsname } % The redefined \@tabacckludge macro below assures that the top-level % definition of the accents (which contains \assemble@accent@cmds) % will be called. % \def\@make@tabacc#1#2{ \expandafter\def\csname @tabacc\string#1\endcsname{#2} } \@make@tabacc{'}{\@acci} \@make@tabacc{`}{\@accii} \@make@tabacc{=}{\@acciii} % Here the redefinition of second internal LaTeX macro. % \def\@tabacckludge#1{ \csname @tabacc\string#1\endcsname } % We only look ahead for further accents if we are to typeset. % \def\assemble@accent@cmds{ \ifx\protect\@typeset@protect \expandafter\assemble@tokensinit \fi } % The init is special as we have to parse over some of the expansion % of the encoding specific command; for example, \^ might expand to % % \assemble@accent@cmds \OT1-cmd \^ \OT1\^ % ^^^^^^ one token % % We start \assemble@tokens with the number of hits so far (\@empty), % zero the actual code for the current, e.g., \OT1\^ in the above % example (resp. the corresponding macro in the current font % encoding), and as a third argument we will pick up the next token % or group in the input stream for testing. % \def\assemble@tokensinit#1#2#3{ % the usual test for availability in the current encoding % similar to the test in \@changed@cmd \@inmathwarn#2 \expandafter\ifx\csname\cf@encoding\string#2\endcsname\relax \expandafter\ifx\csname ?\string#2\endcsname\relax \expandafter\def\csname ?\string#2\endcsname{ \TextSymbolUnavailable#2 } \fi \global\expandafter\let \csname\cf@encoding \string#2\expandafter\endcsname \csname ?\string#2\endcsname \fi % here we substitute the current encoding \expandafter\assemble@tokens@\expandafter\@empty \csname\cf@encoding\string#2\endcsname } % The next commands should be considered only as a proof of concept % -- they can most certainly be streamlined. Here is roughly what % they do: % % \assemble@tokens: If the picked up token is \IeC then get rid of it % and parse the next token (or group) which is expected to be the % argument of \IeC. This is done by restarting the whole process. % Otherwise we have to figure out if the current token (#3) is an % 8-bit from inputenc, i.e., expanding to \IeC{...}. This is % handled by calling \assemble@tokensz passing an expansion of #3 % as well as #3 (or more exactly, its first token since the braces % get removed in this process) itself. % % \assemble@tokensz: Test if the expansion start with \IeC in which % case it is assumed that it comes from an inputenc 8bit; the next % token will be considered as its argument and used for further % processing in \assemble@tokensx. Otherwise the unexpanded #3 % from above is used. % % \assemble@tokensx: If this cmd is called its third argument should % contain a normalized token from the input stream, i.e. % % {..} -> .. % \IeC{..} -> .. % ^^xx (expanding to) \IeC{..} -> .. % % Now all :-) that remains is testing whether the expansion of this % token starts with \assemble@accent@cmds, since in this case we have % found another accent cmd. % % #1 is the number of hits, #2 is the real definition in that % encoding, and #3 is the next token (or group). % % The macros \assemble@tokens@ and \assemble@tokens@@ are % intermediate steps to test whether #3 is empty; if yes, we simply % expand #2. % \def\assemble@tokens@#1#2#3{ \assemble@tokens@@{#1}{#2}{#3}{#3\@empty} } \def\assemble@tokens@@#1#2#3#4{ \ifx#4\@empty \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi {#2{}} {\assemble@tokens{#1}{#2}{#3}} } \def\assemble@tokens#1#2#3{ \ifx\IeC#3 \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi % try again but pick up argument of \IeC {\assemble@tokens@{#1}{#2}} % this will get rid of a group argument -- nasty :-) {\expandafter\assemble@tokensz#3\relax\assemble@tokensz{#1}{#2}#3} } \def\assemble@tokensz#1#2\assemble@tokensz#3#4#5{ \ifx#1\IeC \expandafter\@firstoftwo \else \expandafter\@secondoftwo \fi {\assemble@tokensx{#3}{#4}#2} {\assemble@tokensx{#3}{#4}#5} } % \assemble@tokensx: This passes an expanded and unexpanded version % of #3 to \ifassemble@tokens to do the actual processing. % % \ifassemble@tokens: If we have found another accent command then % keep its name and record that we had another hit and restart the % scanning via \assemble@tokens, i.e., we append an `x' to the % ``hit'' argument that we carry around for no good reason, and we % append the official name of the accent command (which was picked % up as part of the expansion of the input token) to the argument, % storing the list of accents found so far. Note that we do use % the official name, e.g. `\"', not `\OT1\"' -- the latter is only % used for the very first accent! % % If it turns out that we don't have an accent command here it is % time to stop the scanning and do some processing. Now finally the % ``hit'' argument and the list of collected accents comes into play: % We construct a command which name consists of the string % ``handle@accent'', followed by a number of `x's each for each hit % earlier on. Thus in a situation like \"\^a we would execute % \handle@accentx and in case of \"a \handle@accent. This command % gets as its arguments the collected accents followed by the token % which stopped the scanning proccess, e.g. % % \handle@accentx \OT1\" \^ {a} % % and its purpose is to determine how to produce a glyph from it % (e.g. as a composite or as a part composite or ...) % \def\assemble@tokensx#1#2#3{ \expandafter \ifassemble@tokens#3\@empty\@empty\@empty\ifassemble@tokens{#1}{#2}{#3}} \def\ifassemble@tokens#1#2#3#4\ifassemble@tokens#5#6#7{ % next token was defined via \DeclareText... \ifx#1\assemble@accent@cmds % thus #3 is its official name \expandafter\assemble@tokens@ \else % execute what has been assembled and exit \csname handle@accent#5\endcsname#6{#7} \expandafter\@gobbletwo \fi % first two args to \assemble@tokens on next pass {#5x}{#6#3} } % Depending on the number of accents found, \handle@accent[x[x]] will % be called. % ONLY ONE: We check whether \#1-#2 is a known command (a composite) % and execute it, otherwise try to execute #1{#2} as an accent % command. % \def\handle@accent#1#2{ \expandafter\ifx\csname\string#1-\string#2\endcsname\relax #1{#2} \else \csname\string#1-\string#2\endcsname \fi } % TWO IN A ROW: We check for \#1-#2-#3. If undefined, we apply #1 to % whatever is the result of #2{#3}. One could think of a more % complex algorithm here, e.g., if #1-#2 is known as a composite % modifier (whatever that is) apply that before trying the above but % this is probably not necessary. % \def\handle@accentx#1#2#3{ \expandafter\ifx\csname\string#1-\string#2-\string#3\endcsname\relax #1{#2{#3}} \else \csname\string#1-\string#2-\string#3\endcsname \fi } % MORE THAN TWO: (Not handled so far.) If there are more than three, % then the parsing will die at some point when \handle@accentxx... % will turn out to be \relax, and then one accent will become an % argument of another -- too bad. % \def\handle@accentxx#1#2#3#4{ % catch more than two accents in a row \errmessage{Too many accents, dropping first} #2#3#4 } % This is simpler now. % \def\DeclareTextCompositeCommand#1#2#3#4{ \expandafter\def\csname\expandafter\string\csname #2\endcsname\string#1-\string#3\endcsname{#4} } % This is new. % \def\DeclareTextDoubleCompositeCommand#1#2#3#4#5{ \expandafter\def\csname\expandafter\string\csname #2\endcsname\string#1-\string#3-\string#4\endcsname{#5} } % This also. % \catcode\z@=11\relax \def\DeclareTextDoubleComposite#1#2#3#4#5{ \def\reserved@a{\DeclareTextDoubleCompositeCommand#1{#2}{#3}{#4}} \bgroup \lccode\z@#5 \lowercase{ \egroup \reserved@a ^^@} } \catcode\z@=15\relax % Now we reinitialize the \@acc... macros to use our new definitions. % \AtBeginDocument{ \let\@acci \' \let\@accii \` \let\@acciii \= } \endlinechar `\^^M \endinput % end of dblaccnt.tex