2

Background

As has already been made manifest, I am struggling against the limit for declared math fonts. I suspect part of the reason for this lies in part of my package. My package, which has been grown over the past year and a half, is now a very big one, with two ancillary packages. One of those has the following code executed:

\DeclareSymbolFont{pletters}     {OML}{ztmcm}{m}{it}
\DeclareSymbolFont{cletters}{OT1}{cmm}{m}{it}
\DeclareSymbolFont{upletters}{U}{ntxmia}{m}{it}
\SetSymbolFont{upletters}{bold}{U}{ntxmia}{b}{it}
\DeclareFontSubstitution{U}{ntxmia}{m}{it}
\DeclareSymbolFont{coperators}   {OT1}{cmr} {m}{n}

This is because the same subpackage then proceeds to offer options for the choice of greek glyphs from any of these fonts, and the glyphs are chosen one by one, with an option for each letter. Now, obviously I do not mix mathptmx and Computer Modern. The reason for this mixing possibility was that:

  1. The mathptmx glyphs are ill-scaled, that is, they are bigger than the surrounding latin, so I devised commands to scale them, but I got fed up of having to adjust their size frequently;
  2. newtx glyphs solved the scaling problems, but they were worse-looking (IMO) than their mathptmx counterparts, and some of them I really couldn't see.

Then I discovered upright newtx greek, and now I only use that. However, I do not want to delete those options because it took me long to write the code. Now I was thinking of putting those declarations into macros to be executed when a glyph from one of those fonts was chosen, so as to avoid extra font declarations. However, I think it would not be wise -- i.e. I do not like the idea -- to have the fonts declared for every character chosen from them. In my case, that would mean declaring upletters a whopping 24 times, no, actually, 30, because there are 24 letters plus 6 \var forms.

Question

So my question is: is there a way to check if a certain math font with a certain name has already been declared? And if it is the right font -- i.e. so that it will give false if pletters is declared to be something different from {OML}{ztmcm}{m}{it}? And if so, how do I achieve that?

Note: The {coperators}{OT1}{cmr}{m}{n} part is because \omicron is gotten out of the operators font, so to have options for \omicron I needed that font. Just in case anyone is wondering what that was for.

2

Warning: This answer has been completely rewritten. Althought the general idea remains the same as in its first version, the new code differs in many aspects. I am going to add some explanation, too.


The code

The following code defines two commands:

  • \GrabFontIdentifier lets the control sequence passed in its last mandatory argument equal to the font selector bound to the NFSS symbol font name passed in its first mandatory argument. By default, it assumes the binding made for the normal math version, but a different math version (e.g., bold) can be specified in an optional argument. Since it performs an assignment, this command is obviously not purely expandable.

  • \SameFontIdentifier can be used as pseudo-argument to an \if to test whether a given control sequence initialized with \GrabFontIdentifier is or is not the font selector bound to a given NFSS specification (encoding/family/weight/shape). This command is purely expandable.

I think it’s best to look at the code, which, besides defining these two commands, also shows how to use them (it is a complete compilable example):

\documentclass[12pt]{article}

\makeatletter

\newcommand*\GrabFontIdentifier[3][normal]{%
  % #1 <- a NFSS math version name, defaults to "normal"
  % #2 <- a NFSS symbol font name, e.g. "operators"
  % #3 <- a control sequence, e.g. "\next"
  \@ifundefined{sym#2}{%
    \global\let#3\@undefined
  }{%
    \sbox\z@{%
      \mathversion{#1}%
      $%
        \expandafter\global\expandafter\let\expandafter#3%
          \the\textfont\csname sym#2\endcsname
      $%
    }%
  }%
}
\newcommand*\SameFontIdentifier[5]{%
  % #1 <- control sequence to test, e.g. "\next"
  % #2 <- encoding, e.g. "OT1"
  % #3 <- family name, e.g. "cmr"
  % #4 <- weight, e.g. "m"
  % #5 <- shape, e.g. "n"
  TT\fi
  \expandafter\ifx\csname #2/#3/#4/#5/\tf@size\endcsname #1%
}

% Needed in order to make sure "\tf@size" is defined:
\sbox\z@{$$}

\makeatother

\begin{document}

\GrabFontIdentifier[bold]{operators}\next
% Test these ones too:
% \GrabFontIdentifier[bold]{letters}\next
% \GrabFontIdentifier{operators}\next
% \GrabFontIdentifier{letters}\next
% \GrabFontIdentifier{nonExistentName}\next

First test:
\if\SameFontIdentifier\next{OT1}{cmr}{bx}{n}%
  Coincides.
\else
  Does not coincide.
\fi

Second test:
\if\SameFontIdentifier\next{OML}{cmm}{b}{it}%
  Coincides.
\else
  Does not coincide.
\fi

\end{document}

The following enhancements have been introduced in comparison with the previous version of the code:

  • The argument of \SameFontIdentifier (previously named \TestFontIdentifier) devoted to the font size has been eliminated: indeed, the specification of the size is extraneous to the problem at hand. The “text” size is now automatically supplied.

  • As already said, \SameFontIdentifier has been made purely expandable. It was not so before (my mistake).

  • The case of a nonexistent symbol font name is correctly handled. This too was not so before (my mistake again).

The idiom \if\SameFontIdentifier … \else … \fi is typical, and I am not going to discuss it here; I’ll only mention that this construction allows you to have an explicit \if to go with \else and \fi, for the case in which the whole code segment is being skipped over because of an outer false conditional. If you prefer a LaTeX-style conditional, you can go this way instead:

\documentclass[12pt]{article}

\makeatletter

\newcommand*\GrabFontIdentifier[3][normal]{%
  % #1 <- a NFSS math version name, defaults to "normal"
  % #2 <- a NFSS symbol font name, e.g. "operators"
  % #3 <- a control sequence, e.g. "\next"
  \@ifundefined{sym#2}{%
    \global\let#3\@undefined
  }{%
    \sbox\z@{%
      \mathversion{#1}%
      $%
        \expandafter\global\expandafter\let\expandafter#3%
          \the\textfont\csname sym#2\endcsname
      $%
    }%
  }%
}
\newcommand*\IfSameFontIdentifier[5]{% plus two "hidden" arguments
  % #1 <- control sequence to test, e.g. "\next"
  % #2 <- encoding, e.g. "OT1"
  % #3 <- family name, e.g. "cmr"
  % #4 <- weight, e.g. "m"
  % #5 <- shape, e.g. "n"
  % #6 <- TRUE text
  % #7 <- FALSE text
  \expandafter\ifx\csname #2/#3/#4/#5/\tf@size\endcsname #1%
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi
}

% Needed in order to make sure "\tf@size" is defined:
\sbox\z@{$$}

\makeatother

\begin{document}

\GrabFontIdentifier[bold]{operators}\next
% Test these ones too:
% \GrabFontIdentifier[bold]{letters}\next
% \GrabFontIdentifier{operators}\next
% \GrabFontIdentifier{letters}\next
% \GrabFontIdentifier{nonExistentName}\next

First test:
\IfSameFontIdentifier\next{OT1}{cmr}{bx}{n}
  {Coincides.}
  {Does not coincide.}

Second test:
\IfSameFontIdentifier\next{OML}{cmm}{b}{it}
  {Coincides.}
  {Does not coincide.}

\end{document}

Some explanations

The idea is simple: in \GrabFontIdentifier, we first deal with the case of a nonexistent symbol font name: in this case, we \let the target control sequence to be undefined. Otherwise, we typeset a temporary box (which we are not going to use any more) and use a suitable chain of \expandafters to let the target control sequence equal to the expansion of \the\textfontn (for example, of \the\textfont1 in case #2 is letters), where the number n is supplied by \csname sym#2\endcsname.

And what is the expansion of \the\textfontn? The answer is given on the last two lines of page 214 of _The TeXbook:

\the<font> produces a font identifier that selects the specified font.

Moreover, the syntax diagrams on page 271 confirm that \textfont<4-bit number> makes a correct instance of <font>.

On the other hand, NFSS defines control sequences of the form \csname<enc>/<family>/<weight>/<shape>/<size>\endcsname as font identifiers for the font having encoding <enc>, etc.; so, in \SameFontIdentifier, we simply test whether the control sequence constructed in this way from the supplied arguments is \ifx-equal to the control sequence passed in the first argument. And indeed, if you look at the top of page 219, where the conditions for an \ifx test being successful are specified, you will find that:

The condition is true if (a) the two tokens are not macros and they both represent the same (character code, category code) pair or the same TeX primitive or the same \font or \chardef or \countdef, etc.;…

I think that this should be enough to be forgiven for the hasty answer I gave before…

  • I believe your answer should include that this \TestFontIdentifier-\GrabFontIdentifier works because \DeclareSymbolFont essentially defines \sym<#1> to mean the font with the specified encoding-family-weight-shape combination. And I guess there should be no argument for size, since \DeclareSymbolFont doesn't have such an argument. Anyway, I will use your solution in my package, hoping it works. And I believe it should, once I remove size. – MickG Aug 6 '15 at 13:37
  • Another thing that should be included is that TT\fi is simply to get rid of the \if, which in turn is necessary to avoid Extra \else when processing the lines of the test. – MickG Aug 6 '15 at 13:38
  • @MickG: I’m sorry, I was a bit in a rush when I wrote the answer, and I still am. I’ll polish it up when I have time. Also, support for math versions should be added. (Note: \csname sym#1\csname is just the family number corresponding to symbol font #1). – GuM Aug 6 '15 at 13:46
  • For the record, I just found out NFSS stands for New Font Selection Scheme. – MickG Aug 12 '15 at 21:49
0

For the record, here is what I ended up doing, using the idea from the older version of Gustavo's answer.

\newcommand*\GrabFontIdentifier[2]{%
  % #1 <- a control sequence, e.g. "\next"
  % #2 <- a NFSS font name, e.g. "operators"
  \sbox\z@{$%
    \expandafter\global\expandafter\let\expandafter#1%
      \the\textfont\csname sym#2\endcsname
  $}%
}
\newcommand*\TestFontIdentifier[5]{%
  % #1 <- control sequence to test, e.g. "\next"
  % #2 <- encoding, e.g. "OT1"
  % #3 <- family name, e.g. "cmr"
  % #4 <- weight, e.g. "m"
  % #5 <- shape, e.g. "r"
  TT\fi
  \expandafter\let\expandafter\@MyTemporary\csname #2/#3/#4/#5\endcsname
  \ifx\@MyTemporary #1%
}
\newcommand{\declare@ptm}{
    \@ifundefined{sympletters}
    {\DeclareSymbolFont{pletters}     {OML}{ztmcm}{m}{it}}
    {\GrabFontIdentifier{\ptm@}{pletters}
    \if\TestFontIdentifier{\ptm@}{OML}{ztmcm}{m}{it}
    \else
        \DeclareSymbolFont{pletters}     {OML}{ztmcm}{m}{it}
    \fi}
}
\newcommand{\declare@cmr}{
    \@ifundefined{symcletters}
    {\DeclareSymbolFont{cletters}{OT1}{cmm}{m}{it}}
    {\GrabFontIdentifier{\cmr@}{cletters}
    \if\TestFontIdentifier{\cmr@}{OT1}{cmm}{m}{it}
    \else
        \DeclareSymbolFont{cletters}{OT1}{cmm}{m}{it}
    \fi}
}
\newcommand{\declare@upnewtx}{
    \@ifundefined{symupletters}
    {\DeclareSymbolFont{upletters}{U}{ntxmia}{m}{it}
        \SetSymbolFont{upletters}{bold}{U}{ntxmia}{b}{it}
        \DeclareFontSubstitution{U}{ntxmia}{m}{it}}
        {\GrabFontIdentifier{\upnewtx@}{upletters}
    \if\TestFontIdentifier{\upnewtx@}{U}{ntxmia}{m}{it}
    \else
        \DeclareSymbolFont{upletters}{U}{ntxmia}{m}{it}
        \SetSymbolFont{upletters}{bold}{U}{ntxmia}{b}{it}
        \DeclareFontSubstitution{U}{ntxmia}{m}{it}
    \fi}
}
\newcommand{\declare@cop}{
    \@ifundefined{symcoperators}
    {\DeclareSymbolFont{coperators}   {OT1}{cmr} {m}{n}}
    {\GrabFontIdentifier{\cop@}{cletters}
    \if\TestFontIdentifier{\cop@}{OT1}{cmr} {m}{n}
    \else
        \DeclareSymbolFont{coperators}   {OT1}{cmr} {m}{n}
    \fi}
}

If you are perplexed about the @s without \makeatletter, remember I'm in a package. This seems to work, at least when the only declared font is upletters. It also seems to have solved the problem that got me asking this question: Too many math fonts. Right now, I can declare bbold as an alphabet without removing dutchcal, as I was forced to do before this solution was provided to me. Thx Gustavo. Now let me read the new answer, which I only just found out about.

Update: After reading the new answer, in particular the part where he says:

On the other hand, NFSS defines control sequences of the form \csname<enc>/<family>/<weight>/<shape>/<size>\endcsname as font identifiers for the font having encoding <enc>, etc.; so, in \SameFontIdentifier, we simply test whether the control sequence constructed in this way from the supplied arguments is \ifx-equal to the control sequence passed in the first argument.

I started suspecting the above wasn't doing what I wanted it to do. More precisely, I suspected it was redeclaring the fonts at every occurrence of the \declare@<blab> commands. I did some tests by adding a \message{defined} in the true branch of the \TestFontIdentifiers and a \message{undefined or differently defined} in the false branch, and I got a bunch of undefinedordifferentlydefined. So I added /\tf@size as the answer suggested, and I got a bunch of defined. So it seems one of the reasons I wanted this test, to avoid redeclaring the fonts every time, wasn't really that important, as my problem -- too many fonts -- was solved even with the redeclarations. However, I will still keep the conditionals because I do not want to delete all that code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.