% Package robustindex.sty, Wilberd van der Kallen 2005, 2017, 2018, 2019.
%
% Third parties often change the page numbers without rerunning makeindex.
% One would like to make the page numbers in the index entries more robust.
% We use the \pageref mechanism for that. Only after adding, deleting or
% otherwise modifying an \index{entry}, or after changing the order of the
% index entries, does one have to rerun makeindex.
% Other changes do not matter, as long as one runs LaTeX or pdflatex until 
% labels are stable.
% As usual a makeindex run has to be preceded and also followed by its
% LaTeX or pdflatex run.
%
%
% If you use hyperref, you must choose the option hyperindex=false.  
% Our package already gives hyperlinks in the index.
% Alternatively, you may go against the advice of hyperref and put our
% package later.
%
% We tested with
%
% \usepackage[plainpages=false,hyperindex=false]{hyperref}
%
% Automatic page ranges are not supported.
% Commands of the type \index{entry|editing command} are supported,
% but much more naively than in the encapsulating mechanism of makeindex.
% For instance, \index{term|(textbf} may be followed by \index{term|)textit}.
%
%
% Our package performs no miracles. But in simple situations all you need is
% adding the \usepackage{robustindex} to the preamble. Do not exclude any
% relevant files, as in \includeonly.
%
% The option multind provides support for several indexes with pagerefs.
% There is just one index file, and the usual compilation cycle 
% (latex, makeindex, latex) suffices.
% With the command \setindex in the LaTeX file one arranges which index is
% the active one at any given moment. 
% This steers the behaviour of \index and \printindex.
%
% We introduce tools to embellish an index with letter headings.
%
% That is the positive part.
% 
% While robustindex.sty broke the automatic page range feature of 
% makeindex, the multind option also broke the insertions 
% of \indexspace in the index file. And it messed up the sorting.
% We use various hacks to restore reasonable behaviour. This makes the index file
% pretty unreadable and style files of makeindex will probably fail.
%
% 
% Remark.
% The package imakeidx also synchronises the index with the manuscript,
% but it has a different method and different requirements.
%
% https://www.staff.science.uu.nl/~kalle101/stind
%
% Copyright 2019 Wilberd van der Kallen
%
% This file may be distributed under the conditions of the LaTeX Project Public
% License, either version 1.2 of this license or (at your option) any
% later version.  The latest version of this license is in
%    http://www.latex-project.org/lppl.txt
% and version 1.2 or later is part of all distributions of LaTeX
% version 1999/12/01 or later.

\ProvidesPackage{robustindex}
  [2019/01/25
  index entries with pagerefs]

\RequirePackage{makeidx}

\DeclareOption{multind}{
  \AtBeginDocument{\setindex{main}}%
  \def\robust@mult{\relax}
}%

\ProcessOptions\relax

\newcounter{indexctr}%

\newcounter{maxindctr}% Used to check if number of \index commands has changed.

\newcommand{\indstring}{ind.}%


\def\@wrindex#1{%
\@bsphack
  \stepcounter{indexctr}%
  \stepcounter{indexctr}% second time, to emulate makeindex -r.
  \protected@write \@auxout {}{%
     \string \newlabel {\indstring\theindexctr}{{\relax }{\thepage }%
     \ifx\ifHy@bookmarks\undefined\else{\relax }{page.\thepage }{}\fi%
     }%
  }%
  \@esphack
  \protected@write
    \@indexfile {}{\string \indexentry
    {\findencap#1|\relax }{\theindexctr}}% \findencap will check for the
  \endgroup                              % encap symbol | in the argument.
\@esphack
}%

\def\@multwrindex#1{%
\@bsphack 
\stepcounter{indexctr}%
\stepcounter{indexctr}% second time, to emulate makeindex -r.
\protected@write \@auxout {}{%
     \string \newlabel {\indstring\theindexctr}{{\relax }{\thepage }%
     \ifx\ifHy@bookmarks\undefined\else{\relax }{page.\thepage }{}\fi%
     }%
  }%
  \@esphack
  \protected@write
   \@indexfile {}{\string \indexentry
   {\string\indnr\robustchoice d\gr@bltr#1-\relax b{} \findencap#1|\relax}{\theindexctr}}%
  \endgroup
\@esphack
}


\ifx\robust@mult\undefined\else\let\@wrindex\@multwrindex\fi

\newcommand\sindex{\@ifnextchar[{\@sindex}{\@@sindex}}%

\def\@sindex[#1]{\setindex{#1}\index}

\def\@@sindex{\setindex{main}\index}

\newif\ifinside@range% output must be supressed inside page range.
\inside@rangefalse

\newcommand{\indpageref}[1]{%
\ifinside@range \findEndPageRange\else
   \ifnum\c@maxindctr<#1\relax\setcounter{maxindctr}{#1}\fi
   \pageref{\indstring#1}%
   \fi
}%

\newcommand{\indexpreamble}{\relax}% compare the preamble of makeindex

\newcommand{\mult@err}{\PackageWarning{robustindex}{%
 Index file is obsolete. Run makeindex. Detected}Index file is obsolete. Run makeindex. 
 \end{theindex}\endinput}%

\newcommand{\gobbletillnine}{\mult@err}
 
\newcommand{\indexincontents}{%
  \def\indexpreamble{%
     \refstepcounter{subsection}%
   % This creates a hyperlink destination.
   % Compare phantomsection in hyperref.
   % An index is not to be followed immediately by a subsection.
     \addcontentsline{toc}%
        {\ifx\c@chapter\undefined section\else chapter\fi}{\indexname}%
  }%
}%

\newcommand{\old@theindex}{}%

\let\old@theindex\theindex

\newcommand{\cndhyprndxwrng}{%
    \ifHy@hyperindex
       \PackageWarning{robustindex}{%
          Use option hyperindex=false in hyperref. Hyperlinks in the index
	  will be made through \string\pageref. Detected%
       }%
    \fi
}%

\def\theindex{%
   \old@theindex
   \indexpreamble
   \ifx\ifHy@hyperindex\undefined\else\cndhyprndxwrng\fi
}%

\ifx\ifHy@hyperindex\undefined\else\Hy@hyperindexfalse\fi
% If you put our package after the hyperref package,
% then you probably do not mind our disabling its hyperindex mechanism.

\AtEndDocument{%
   \ifnum\c@indexctr=\c@maxindctr
   \else
      \ifnum\c@indexctr=0%
         \PackageWarning{robustindex}{%
	    Package needs \string\make index in preamble,
	    and if you use hyperref, you must
	    use option hyperindex=false. Detected%
	 }%
      \else
        \ifx\robust@mult\undefined
           \PackageWarning{robustindex}{%
            Index not up to date, run makeindex. Detected%
           }\else
           \PackageWarning{robustindex}{Print each index or run makeindex. Detected}%
        \fi
      \fi
   \fi
}%

\newcommand{\wrappageref}{\protect\wrapindpageref}%

\newcommand{\wrapindpageref}{}%

\def\wrapindpageref#1, \indpageref#2{%
   \ifnum\c@maxindctr<#2\relax
      \setcounter{maxindctr}{#2}%
   \fi
   #1{\pageref{\indstring#2}}%
}%

\newcommand{\gobbleindpageref}{\wrappageref\@gobble}%

\newcommand{\gobblepageref}{% to suppress one page number.
      \protect\gobbleindpageref
}%



% Now it gets ugly, because we wish to implement a poor man's encap
% mechanism, distinguishing \index{entry}, \index{entry|(}, \index{entry|)},
% \index{entry|towrap}, \index{entry|(towrap}, \index{entry|)towrap}, where
% towrap is a sequence of letters and \towrap is to be wrapped around 
% \indpageref{countervalue}.


\newcommand{\findencap}{}%

\def\findencap#1|#2\relax{%
   \ifx\relax#2\relax
      #1|indpageref% The easy case
   \else
      #1|\wr@pencap#2% There is a | in the argument.
   \fi
}%


\newcommand{\wr@pencap}{}%

\def\wr@pencap#1|{encpageref{#1}}%

\newcommand{\encpageref}[2]{%
     \findleft@brack#1(\relax{#2}%
}%

\newcommand{\findleft@brack}{}%

\def\findleft@brack#1(#2\relax#3{%
   \ifx|#1| \dropleft@brack#2{#3}% bracket ( found.
   \else \findright@brack#1)\relax{#3}%
   \fi
}%

\newcommand{\dropleft@brack}{}%

\def\dropleft@brack#1(#2{%
   \ifx|#1|\indpageref{#2}\inside@rangetrue%
   \else
      \csname #1\endcsname{\indpageref{#2}}\inside@rangetrue%
   \fi
   % output for this key must be suppressed until end of range.
   \findEndPageRange%
}%


\newcommand{\findEndPageRange}{}% Name is helpful in error message if end not found.

\def\findEndPageRange#1,{% It actually removes a comma.
   \ignorespaces #1%
}%

\newcommand{\findright@brack}{}%

\def\findright@brack#1)#2\relax#3{%
   \ifx|#1|\unskip \dropright@brack#2{#3}% bracket ) found.
   \else
      \ifinside@range
        \findEndPageRange
      \else
        \csname#1\endcsname{\indpageref{#3}}%
      \fi
   \fi
}%

\newcommand{\dropright@brack}{}%

\def\dropright@brack#1)#2{%
   \inside@rangefalse% output no longer suppressed.
   \ifx|#1|\unskip \mbox{--}\nobreak\indpageref{#2}%
   \else
      \unskip \mbox{--}\nobreak\csname #1\endcsname{\indpageref{#2}}%
   \fi
   \ignorespaces
}%



% Now the part that supports multiple indices. We hack the sorting mechanism of
% Makeindex and put instructions for the mouth of TeX in the index file.

\newcommand{\gr@bltr}{\relax}%

\def\gr@bltr#1#2\relax{\ifcat A#10\the\uccode`#1\else 060\fi}%
% to keep "a" and "A" together.

\newcommand{\altsort}% to place some entries after the alphabet
{\def\gr@bltr##1##2\relax{\ifcat A##10\the\uccode`##1\else##1\fi}}

% But first some code for embellishing an index. Our hacking brakes the insertion of 
% \indexspace at appropriate places. We have to work hard to restore that. While we
% are at it, we may as well add the possibility to insert a letter T after the
% \indexspace that precedes the entries that start with t or T.
% First we describe the default style, that does not insert the T.
\newcommand{\indexcapstyle}[1]{\indexspace}
% To get the T one changes the style like this
% \renewcommand{\indexcapstyle}[1]{\indexspace\textbf{#1}\par}%

\newcommand{\nxtletre}{\def\item{\letr@test}}% about next letter in alphabet

\newcommand{\indexcapitalhead}[1]{% Preparing for a heading; not printed.
  \protected@write
    \@indexfile {}{\string \indexentry
    {\string\indnr \robustchoice d\gr@bltr#1\relax a #1@\protect\nxtletre
    \protect\def\protect\nwletre{#1}\string\jmptonine}{9}}%          
}%

\newcommand{\extraheaders}{\relax}

\newcommand{\capitalsinindex}[1]{% Will be called by \newindex with full alphabet.
\extraheaders\find@capitals#1\relax}%

\newcommand{\find@capitals}{\relax}%

\def\find@capitals#1#2\relax{% To deal with 26 letters.
\indexcapitalhead #1%
\ifx\relax#2\relax
\else\find@capitals#2\relax
\fi}%

\newcommand{\letr@test}{\relax}% To test if entry starts with new letter.

\long\def\letr@test#1{\ifx#1\nxtletre\else\proc@letter{\relax#1}\fi}%

\newcommand{\proc@letter}{\relax}% 

\def\proc@letter#1#2{\long\def\item{\olditem}%
\ifx#1\relax\else\indexcapstyle{\nwletre}\fi\fi#1}%

\newcommand{\olditem}{\relax}%

% All this just to embellish an index. Now the support for multiple indexes.

\newcommand{\setindex}[1]{%
\@bsphack
\expandafter\ifx\csname#1@rbstind\endcsname\relax 
  \newindex{#1}%
\else
  \edef\robustchoice{\csname#1@rbstind\endcsname}%
\fi
\@esphack}%

\ifx\robust@mult\undefined\def\setindex{\PackageWarning{robustindex}{%
 \string\setindex{}  requires option multind. Detected}}\fi

\newcounter{multindctr}%
\newcommand{\robustcutpoint}{\relax}%
\newcommand{\untilrobustcutpoint}{\relax}%
\newcommand{\newindex}{\relax}%
\newcommand{\robustchoice}{\relax}%
\newcommand{\indnr}{\relax}%

\setcounter{multindctr}{999}% Fewer than 899 indexes expected.

\long\def\untilrobustcutpoint#1\robustcutpoint{\fi}% 
% This tels the mouth of TeX not to send too much to the stomach.
% It should only forward the part that belongs to the active index.

\def\indnr#1 {}% The \indnr part is used for sorting by makeindex and needs to be ignored
               % by TeX thereafter.  

\newcommand\multindpreamble{\let\olditem\item\let\jmptonine\jmp@tnine}% 
% \multindpreamble may serve as hook for further code.

\newcommand{\jmptonine}{\mult@err}%

\newcommand{\jmp@tnine}{\relax}%

\def\jmp@tnine#1 9{\relax}

\def\newindex#1{\@bsphack
\ifx\@indexfile\undefined\PackageWarning{robustindex}{%
Package needs \string\make index in preamble. Detected}\fi
\ifnum\c@multindctr=999%
  \protected@write
    \@indexfile {}{\string \indexentry
    {\string\indnr 999b @\string\nxtletre
    \string\robustcutpoint\string\jmptonine}{9}}%                              
  \@esphack
\fi
\addtocounter{multindctr}{-1}%
\expandafter\edef\csname#1@rbstind\endcsname{\the\c@multindctr}%
\edef\robustchoice{\csname#1@rbstind\endcsname}%
\@esphack 
\protected@write
    \@indexfile {}{\string \indexentry
    {\string\indnr\the\c@multindctr d091 @\protect\relax\string\jmptonine
}{9}}% 
\protected@write
    \@indexfile {}{\string \indexentry
    {\string\indnr\the\c@multindctr a @\string\robustcutpoint 
\string\ifnum\string\robustchoice=\the\c@multindctr\string\multindpreamble
\string\else\string\untilrobustcutpoint
\string\fi\string\jmptonine
}{9}}% 
\capitalsinindex{ABCDEFGHIJKLMNOPQRSTUVWXYZ}%  
\@esphack
}%

\endinput
