0

By the following codes, I expect to typeset a pdf file of two pages. In the frist page, I want to print (1)(2).

But it does not work. I guess this is because of the wrong use of the LaTeX macro \@abspage@last, or wrong use of compiler option argument. Anyone has ideas to make it work?

Codes:

\documentclass{article}
\usepackage{pgffor}
\makeatletter
\newcommand{\lastpagenumber}{\@abspage@last}
\makeatother
%\newcommand{\lastpagenumberA}{\PreviousTotalPages}

\begin{document} \foreach \i in {1,...,\lastpagenumber}{(\i)} %\rule{\numexpr 4/\lastpagenumberA\relax in}{5pt} \clearpage\mbox{} \end{document}

lyl
  • 2,727

2 Answers2

2

When the .aux file doesn't exist, \@abspage@last is set to 1073741823 and of course you don't want to produce that many pages.

So, let's try and “fix” by telling LaTeX that if \@abspage@last equals \maxdimen we set \lastpagenumber to, say, zero.

\documentclass{article}
\usepackage{pgffor}

\makeatletter \newcommand{\lastpagenumber}{% \ifnum@abspage@last=\maxdimen \expandafter 0% \else \expandafter@abspage@last \fi } \makeatother

\begin{document}

\foreach \i in {1,...,\lastpagenumber}{(\i)}

\clearpage

\mbox{LAST}

\end{document}

Now, if the .aux file doesn't exist (or, for some reason, it doesn't set a value for \@abspage@last), you get two pages. The first page has “(1)(0)” (because of how \foreach works) and the second one has “LAST”.

OK, now the .aux file exists and contains

\gdef \@abspage@last{2}

We run again LaTeX to get “(1)(2)” in the first page and “LAST” in the second one.

Perhaps even better, as it avoids one expansion step when using \lastpagenumber:

\documentclass{article}
\usepackage{pgffor}

\makeatletter \newcommand{\lastpagenumber}{} \AtBeginDocument{% \ifnum@abspage@last=\maxdimen \def\lastpagenumber{0}% \else \let\lastpagenumber@abspage@last \fi } \makeatother

\begin{document}

\foreach \i in {1,...,\lastpagenumber}{(\i)}

\clearpage

\mbox{LAST}

\end{document}

I do \newcommand{\lastpagenumber}{} for safety: if some package you load defines \lastpagenumber, you get an error and you know you cannot use this command.

Next, after the .aux file is read in (provided it exists), we check whether \@abspage@last is \maxdimen; in this case we define \lastpagenumber to expand to 0, otherwise we make it equal to \@abspage@last.

egreg
  • 1,121,712
  • I don't understand what \expandafter does here, can you explain it to me, thanks! – ljguo Sep 26 '22 at 09:17
  • 1
    @ljguo I want to remove \else or \fi. That's a common trick in TeX, see https://tex.stackexchange.com/q/107753/4427 – egreg Sep 26 '22 at 09:20
  • Absolutely excellent answer - even I understand it. +1. – ljguo Sep 26 '22 at 09:24
  • @egreg This is the most detail, wonderful explanation I have ever seen! Thank you so much! And, (1) \def\lastpagenumber{0}, So the value 0 is not important, it can be any integer number? (2) Should it be \global\def\lastpagenumber{0}, as it is in the scope of AtBeginDocument? (3) Does avoids one expansion refer to \let\lastpagenumber\@abspage@last? (4) Is it possible to `\expandafter\let\lastpage@abspage@last \fi', if so, is this a good idea? – lyl Sep 26 '22 at 10:10
  • @lyl (1) Yes, you can set it to whatever integer value you like. (2) When the code in \AtBeginDocument is executed it's not in any scope. (3) Yes. (4) That's completely wrong code. – egreg Sep 26 '22 at 10:13
  • @egreg (2) If I put the above\AtBeginDocument{...} into a macro(named \getlastpagenumber, for exmple, should \global\def be used? (4) I mean similar like `\expandafter (\let\lastpage@abspage@last) \fi' (I know this is wrong syntax), I use it to express my idea. Is it possible? – lyl Sep 26 '22 at 10:20
  • @lyl Sorry, but I cannot understand what you mean. – egreg Sep 26 '22 at 10:43
  • @egreg if only aux was the problem, I tried \IfFileExists{\jobname .aux}{\makeatletter\let\lastpagenumber\@abspage@last\makeatother}{} and expected it to work, but it doesn't. Why? – Niranjan Sep 26 '22 at 11:22
  • I think this is related to https://tex.stackexchange.com/a/576082/174620 – Niranjan Sep 26 '22 at 11:40
  • @Niranjan The existence of the .aux file doesn't guarantee that \@abspage@last has a sensible value. – egreg Sep 26 '22 at 11:55
  • @egreg Oh, okay. So the .aux approach would be bad in any case. The problem that I was facing was because of the strange working of \IfFileExists which I have reported: https://github.com/latex3/latex3/issues/1132 – Niranjan Sep 26 '22 at 11:59
  • @egreg (4) I mean how to expand \fi first, then expand \let\lastpage\@abspage@last? – lyl Sep 27 '22 at 00:24
1

you can say:

\documentclass{article}
\ExplSyntaxOn
\iow_new:N \l_lastpage_file 
\file_if_exist:nTF{\c_sys_jobname_str.page}
{
  \file_input:n{\c_sys_jobname_str.page}
}
{
  % \cs_set_eq:NN \lastpage \relax
  \cs_set:Npn \lastpage {1}
}
\AtEndDocument{
\iow_open:Nn \l_lastpage_file{\c_sys_jobname_str.page}
\iow_now:Nx \l_lastpage_file 
{
  \cs_set:Npn \exp_not:N \lastpage 
  {
    \thepage
  }
}
\iow_close:N \l_lastpage_file 
}
\ExplSyntaxOff

\usepackage{pgffor} \begin{document}

\foreach \i in {1,...,\lastpage}{(\i)} \rule{\numexpr 4/\lastpage\relax in}{5pt}

\newpage test

\foreach \i in {1,...,\lastpage}{(\i)} \rule{\numexpr 4/\lastpage\relax in}{5pt} \newpage test

\foreach \i in {1,...,\lastpage}{(\i)} \rule{\numexpr 4/\lastpage\relax in}{5pt} \end{document}


This also works, but it still needs to be compiled twice!

\documentclass{article}
\usepackage{pgffor}
\begin{document}
\makeatletter
\ifnum\@abspage@last > 1000
\newcommand{\lastpagenumber}{1}
\else
\newcommand{\lastpagenumber}{\@abspage@last}
\fi
\makeatother
\foreach \i in {1,...,\lastpagenumber}{(\i)}
AA
%\rule{\numexpr 4/\lastpagenumberA\relax in}{5pt}
\clearpage\mbox{}
\end{document}

enter image description here

ljguo
  • 1,213
  • 1
  • 4
  • 12
  • Thank you @ljguo. This solution also needs run twice -- the first run gives unexpected typeset(from \cs_set:Npn \lastpage {1} ?), and the second gives the expect typeset. during the first run in which calculation of the number of total pages is performed, if the value of \lastpage(now is an uncorrect value) influences the ultimate number of physical pages, then the second run of the codes may lead to a wrong typeset. – lyl Sep 26 '22 at 08:13
  • Yes, it needs to be run twice, the first one generates \jobname.page, the second time reads the file, since the first \lastpage has not been imported, you can only use \cs_set:Npn \lastpage { 1 } to avoid Undefined control sequence. – ljguo Sep 26 '22 at 08:21