3

Consider the following style file goat.sty:

\NeedsTeXFormat{LaTeX2e}[2014/05/01]
\ProvidesPackage{goat}[2014/10/16 goat]

\DeclareOption{mammalbirdfish}{
\makeatletter
 \begingroup
  \catcode`\_=\active
  \protected\gdef_{\@ifnextchar|\subtextup\sb}
 \endgroup
\def\subtextup|#1|{\sb{\textup{#1}}}
\AtBeginDocument{\catcode`\_=12 \mathcode`\_=32768}
\makeatother}

\ExecuteOptions{mammalbirdfish}
\ProcessOptions

When I try to load the package in my LaTeX document be executing \usepackage{goat}, I get the following error:

! Missing control sequence inserted.
<inserted text> 
                \inaccessible 
l.13 \ExecuteOptions{mammalbirdfish}

How do I get the above chunk of code into my style file?

P.S. I've never written a style file before so please forgive me if my question has a trivial answer.

Update

I also can't put

\ExplSyntaxOn
  \cs_new_eq:NN \calc \fp_eval:n
\ExplSyntaxOff

into my style file

\NeedsTeXFormat{LaTeX2e}[2014/05/01]
\ProvidesPackage{goat}[2014/10/16 goat]

\RequirePackage{expl3}

\DeclareOption{macros}{
\ExplSyntaxOn
  \cs_new_eq:NN \calc \fp_eval:n
\ExplSyntaxOff
}

\ExecuteOptions{macros}
\ProcessOptions

When I compile the doucment

\documentclass{article}

\usepackage{goat}

\begin{document}

test

\end{document}

it gives the error

! Undefined control sequence.
\ds@makroer ...scriptfalse \par \ExplSyntaxOn \cs 
                                                  _new_eq:NN \calc \fp _eval...

How do I fix this?

(Let my know if I should ask the update question as a new one; it was put here because I think it might be a similar problem.)

  • I don't know if this has a trivial answer, but in my (yet small) experience, the trick for run a local *.sty file is storing it in the same directory where is the *.texfile where you load that file. I know there is a way to store it in a local directory and there invokes it whenever you need but I don't do it yet. – Aradnix Oct 16 '14 at 00:07
  • 1
    @Aradnix I don't see how that has got anything to do with my question. I know where to put the file but not how to execute the code mentioned. – Svend Tveskæg Oct 16 '14 at 00:11
  • 1
    Don't use \makeatletter... \makeatother in .sty, .cls etc. files. @ is already a letter in this context. You only need these in documents (preferably in the preamble). [I don't suppose this is the problem. Just 'by the way...'.] – cfr Oct 16 '14 at 00:12
  • @cfr Thanks for the pointer! (No, that's not the problem.) – Svend Tveskæg Oct 16 '14 at 00:15
  • If you create a new \if and use the option to toggle the \if, then you can execute the code after \ProcessOptions conditionally. E.g. \newif\ifmammalbirdfish \mammalbirdfishfalse and then put \mammalbirdfishtrue in the option declaration and the code which is currently there in an \ifmammalbirdfish ... \fi after \ProcessOptions. – cfr Oct 16 '14 at 00:35
  • I don't get an error if I just add that code to the package file. Can you post an MWE? EDIT: Obviously, you need \RequirePackage{expl3} first... – cfr Oct 16 '14 at 02:50
  • 1
    Oh. Yes. That doesn't surprise me. Don't put it into the \DeclareOption. Use the Option to toggle a switch and put the code after \ProcessOptions. You might want to look at one of the packages for handling keys if you are doing a lot of this. – cfr Oct 16 '14 at 03:13

2 Answers2

4

Let's see what happens with

\DeclareOption{mammalbirdfish}{
\makeatletter
 \begingroup
  \catcode`\_=\active
  \protected\gdef_{\@ifnextchar|\subtextup\sb}
 \endgroup
\def\subtextup|#1|{\sb{\textup{#1}}}
\AtBeginDocument{\catcode`\_=12 \mathcode`\_=32768}
\makeatother}

\ExecuteOptions{mammalbirdfish}
\ProcessOptions

The code from \makeatletter to \makeatother is given as argument to \DeclareOption, so it has already been tokenized and, in particular, the _ after \gdef has category code 8, so it's illegal after \gdef when the code is executed (storing it is not a problem, as TeX doesn't interpret commands at that moment).

It's (almost) never needed to issue \makeatletter and \makeatother in a class or package file, because they are read with implicit \makeatletter and \makeatother at the end. To be more precise, these commands in a class or package file usually are wrong, unless they appear as part of a macro definition. In this case they are wrong, because when \ProcessOptions expands the code for the mammalbirdfish option, \makeatother will ruin all subsequent reading of the code in the class or package.

Note that setting that code as an option which is executed no matter what is nonsense: such an option should never be passed to \ExecuteOptions.

However, the most important problem is the category code of _. I'll show a different strategy than setting a conditional and doing the code after \ProcessOptions if the conditional is true.

\begingroup\lccode`\~=`\_
\lowercase{\endgroup
  \DeclareOption{mammalbirdfish}{%
    \protected\gdef~{\@ifnextchar|\subtextup\sb}%
    \def\subtextup|#1|{\sb{\textup{#1}}}%
    \AtBeginDocument{\catcode`\_=12 \mathcode`\_=\string"8000 }%
  }%
}

which works because there's no uppercase character token in the code and so only ~ (which is already active) will be converted to (active) _.

Similar problems are with

\DeclareOption{macros}{
\ExplSyntaxOn
  \cs_new_eq:NN \calc \fp_eval:n
\ExplSyntaxOff
}

which should be

\ExplSyntaxOn
\DeclareOption{macros}{
  \cs_new_eq:NN \calc \fp_eval:n
}
\ExplSyntaxOff

otherwise the characters : and _ would have be tokenized as “other characters”.

egreg
  • 1,121,712
2

I'm not sure my comment isn't less clear than mud, but this is too much code for a comment - sorry. Happy to delete it later if best.

\NeedsTeXFormat{LaTeX2e}[2014/05/01]
\ProvidesPackage{goat}[2014/10/16 goat]

\newif\ifmammalbirdfish
\mammalbirdfishfalse
\DeclareOption{mammalbirdfish}{%
  \mammalbirdfishtrue}

\ExecuteOptions{mammalbirdfish}
\ProcessOptions
\ifmammalbirdfish
  \begingroup
    \catcode`\_=\active
    \protected\gdef_{\@ifnextchar|\subtextup\sb}%
  \endgroup
  \def\subtextup|#1|{\sb{\textup{#1}}}%
  \AtBeginDocument{%
    \catcode`\_=12 \mathcode`\_=32768}%
\fi
cfr
  • 198,882
  • @SvendTveskæg Well, I don't know why. I just know things are different when you are declaring options than later. – cfr Oct 16 '14 at 00:46
  • Sorry for 'un-accepting' your answer; I really like egreg's explanations and what I believe to be improvements to the answer. – Svend Tveskæg Oct 16 '14 at 12:16
  • @SvendTveskæg His answer is much better than mine although I don't completely understand it. You should *definitely* accept that answer! – cfr Oct 16 '14 at 21:34