7

I am trying to modify the \label command so that it stores the chapter in .aux file in addition to page and \@currentlabel. I tried what follows and it does not work.

\documentclass{book}
\usepackage{amsthm}
\makeatletter
\def\@newl@bel#1#2#3{%
    \@ifundefined{#1@#2}%
    \relax
    {\gdef \@multiplelabels {%
            \@latex@warning@no@line{There were multiply-defined labels}}%
        \@latex@warning@no@line{Label `#2' multiply defined}}%
    \global\@namedef{#1@#2}{#3}}
\def\newlabel{\@newl@bel r}
\@onlypreamble\@newl@bel
\let \@multiplelabels \relax
\def\label#1{\@bsphack
\protected@write\@auxout{}%
{\string\newlabel{#1}{{\@currentlabel}{\thepage}{\thechapter}}}%
\@esphack}
\def\refstepcounter#1{\stepcounter{#1}%
\protected@edef\@currentlabel
{\csname p@#1\endcsname\csname the#1\endcsname}%
}

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstofthree{#1}}
\def\pageref#1{\expandafter\@setref\csname r@#1\endcsname\@secondofthree{#1}}
\def\chapref#1{\expandafter\@setref\csname r@#1\endcsname\@thirdofthree{#1}}
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
\end{document}

The new command \chapref works fine even though it is unrecognized, while \ref, and \pageref return concatenation of \@currentlabel \thepage and thechapter.

I do not really understand what do the variables in \@newl@bel stand for which makes it hard for me to see what I'm doing wrong.

As I have mentioned in the comment, I am interested in solution which does not require any reference packages. I am aware of the nice solution in this question, but I would like to know whether it can be done by modifying the \newlabel.

ajr
  • 173
  • 2
    I think you should use the zref package rather than such weird hacks. Welcome to TeX.SE ... by the way –  Jan 23 '17 at 13:47
  • I want to do it without any *ref packages. – ajr Jan 23 '17 at 13:50
  • Doing it without ref packages it is 'dangerous' -- as far as I can see your approach will break a possible use of hyperref –  Jan 23 '17 at 13:58
  • I only need it for a short document which will not require the use of '\hyperref'. It can be viewed as a school experiment. – ajr Jan 23 '17 at 14:03
  • 1
    Your example doesn't work for me. I get ? ! Undefined control sequence. \@firstofthree. Didn't you try your own example? – Ulrike Fischer Jan 23 '17 at 14:59
  • It does produce a resulting document for me, however with error - '\chapref' is unrecognized. '@firstofthree' works fine for me. – ajr Jan 23 '17 at 15:07
  • 1
    You get an error that the commands \@firstofthree (used in \ref) and \@secondofthree (used in \pageref) are undefined and then really wonder that both reference commands don't work as wanted? – Ulrike Fischer Jan 23 '17 at 15:12
  • @ajr: I've updated my solution with another version not using any *ref related package. There's no need of screwing up \new@l@bel, \refstepcounter etc. –  Jan 23 '17 at 17:19

2 Answers2

6

This is quite easy with zref and defining a new chapterprop property, storing the \thechapter then.

The price to pay is \zref and \zlabel and \zpageref, however

\documentclass{book}
\usepackage{amsthm}
\usepackage[user]{zref}


\makeatletter
\zref@newprop{chapterprop}{\thechapter}
\zref@addprops{main}{chapterprop}
\newcommand{\chapref}[1]{\zref@extract{#1}{chapterprop}}%\expandafter\@setref\csname r@#1\endcsname\@thirdofthree{#1}}
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\zlabel{theo}abc\end{theorem}
Theorem \zref{theo} in chapter \chapref{theo}, page \zpageref{theo} says that abc.
\end{document}

Update Without any *ref - related package, just hacking \label and \ref and \pageref by providing the \@...ofthree commands.

\documentclass{book}
\usepackage{amsthm}
\makeatletter

\def\label#1{\@bsphack
  \protected@write\@auxout{}%
  {\string\newlabel{#1}{{\@currentlabel}{\thepage}{\thechapter}}}%
  \@esphack}

\long\def\@firstofthree#1#2#3{#1}
\long\def\@secondofthree#1#2#3{#2}
%\long\def\@threeofthree#1#2#3{#3}% Is defined in `latex.ltx` already

\def\ref#1{\expandafter\@setref\csname r@#1\endcsname\@firstofthree{#1}}
\def\pageref#1{\expandafter\@setref\csname r@#1\endcsname
                                   \@secondofthree{#1}}
\def\chapref#1{\expandafter\@setref\csname r@#1\endcsname
                                   \@thirdofthree{#1}}
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
\end{document}

enter image description here

  • Thank you, adding definitions of "..ofthree" indeed works! For some reason my TeX did not point out that the problem was there. – ajr Jan 23 '17 at 18:43
  • @ajr: Most likely because the error was in a earlier part of your code -- TeX choked on that and did not realize \@firstof... etc. were not defined! –  Jan 23 '17 at 19:17
  • BTW, it's \@thirdofthree, not \@threeofthree. – Teepeemm Jul 07 '20 at 20:14
3

Seems your code works after commenting out a few things that are not necessary and adding definitions for \@firstofthree and \@secondofthree. (\@thirdoftree is already defined.)

Your code does break the hyperref-package and therefore does only work as long as the hyperref-package is not loaded.

\documentclass{book}
\usepackage{amsthm}
\makeatletter
\renewcommand*\@newl@bel[3]{%
  \@ifundefined{#1@#2}%
  \relax
  {%
    \gdef\@multiplelabels{%
      \@latex@warning@no@line{There were multiply-defined labels}%
    }%
    \@latex@warning@no@line{Label `#2' multiply defined}%
  }%
  \global\@namedef{#1@#2}{#3}%
}%
%\@onlypreamble\@newl@bel
%\let\@multiplelabels\relax
\renewcommand*\label[1]{%
  \@bsphack
  \protected@write\@auxout
                  {}%
                  {\string\newlabel{#1}{{\@currentlabel}{\thepage}{\thechapter}}}%
  \@esphack
}%
%\def\refstepcounter#1{%
%  \stepcounter{#1}%
%  \protected@edef\@currentlabel
%  {\csname p@#1\endcsname\csname the#1\endcsname}%
%}%
\renewcommand*\ref[1]{%
  \expandafter\@setref\csname r@#1\endcsname\@firstofthree{#1}%
}%
\renewcommand*\pageref[1]{%
  \expandafter\@setref\csname r@#1\endcsname\@secondofthree{#1}%
}%
\newcommand*\chapref[1]{%
  \expandafter\@setref\csname r@#1\endcsname\@thirdofthree{#1}%
}
\newcommand\@firstofthree[3]{#1}%
\newcommand\@secondofthree[3]{#2}%
%\newcommand\@thirdofthree[3]{#3}%
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
\end{document}

In case you really don't wish to use the zref-package I can offer another crude hack which seems not to break the hyperref-package:

Redefine/patch the \label-command in order to have the \label-command patch the \@currentlabel-macro in a way leading to \@currentlabel expand to two arguments preceeded by a robust command for selecting one of the two arguments, the first argument holding what \@currentlabel held before being patched, the second argument holding \thechapter:

\documentclass{book}
\usepackage{amsthm}
%%\usepackage{hyperref}
\makeatletter
\DeclareRobustCommand\My@GetRefArg[2]{#1}%
\DeclareRobustCommand\MyOther@GetRefArg[2]{#2}%
\newcommand\My@saved@currentlabel{}%
\AtBeginDocument{%
  \let\My@oldlabel=\label
  \renewcommand\label[1]{%
    \@bsphack
    \let\My@saved@currentlabel=\@currentlabel
    \expandafter\def
    \expandafter\@currentlabel
    \expandafter{%
    \expandafter\My@GetRefArg
    \expandafter{%
    \@currentlabel}{\thechapter}}%
    \@esphack
    \My@oldlabel{#1}%
    \@bsphack
    \let\@currentlabel=\My@saved@currentlabel
    \@esphack
  }%
  \@ifpackageloaded{hyperref}{%
    \DeclareRobustCommand\chaprefAtNoStar[1]{%
      \begingroup
      \let\My@GetRefArg\MyOther@GetRefArg
      \ref{#1}%
      \endgroup
    }%
    \DeclareRobustCommand\chaprefAtStar[1]{%
      \begingroup
      \let\My@GetRefArg\MyOther@GetRefArg
      \ref*{#1}%
      \endgroup
    }%
    \DeclareRobustCommand\chapref{%
      \@ifstar\chaprefAtStar\chaprefAtNoStar
    }%
  }{%
    \DeclareRobustCommand\chapref[1]{%
      \begingroup
      \let\My@GetRefArg\MyOther@GetRefArg
      \ref{#1}%
      \endgroup
    }%
  }%
}%
\makeatother
\theoremstyle{plain}
\newtheorem{theorem}{Theorem}
\begin{document}
\setcounter{page}{3}
\setcounter{chapter}{1}
\chapter{abc}
\begin{theorem}\label{theo}abc\end{theorem}
Theorem \ref{theo} in chapter \chapref{theo}, page \pageref{theo} says that abc.
%%
%%Theorem \ref*{theo} in chapter \chapref*{theo}, page \pageref*{theo} says that abc.
\end{document}

In case of using hyperref, hyperlinks with \chapref will not lead to the start of the chapter in question but to the anchor that was placed as the last one before placing the corresponding \label. Thus, with the example above, the hyperlink with \chapref{theo} will go to the start of the theorem in question although displaying the number of the chapter where that theorem occurs.

In case of using hyperref, you have "starred" variants of \ref and \pageref displaying the numbers in question but not producing a hyperlink. Therefore in case of hyperref being loaded there is also a "starred" variant of \chapref.

!!!I have no idea whether any of these crude hacks might break functionality of whatsoever documentclass or package.!!!

!!!Therefore I do not give any warranties. If something breaks, handling the pieces is up to you.!!!

!!!The fear of breaking functionality of whatsoever documentclass or package leads me to highly recommending using the zref-package.!!!

Ulrich Diez
  • 28,770
  • @ajr Never mind. I just provided my crude hack in order to fulfill your requirement of doing it without any ..ref-package. As I pointed out in the bottom of my answer, I'd prefer using the zref-package. Therefore accepting another answer which - unlike my answer - also provides a solution based on zref is the right thing to do. :-) – Ulrich Diez Jan 24 '17 at 08:35