% \iffalse meta-comment
%%
%% autoaffil.dtx  --  Documented source for the autoaffil LaTeX package
%%
%% Copyright (C) 2026 Philip Bittihn <philip@bittihn.de>
%%
%% This work may be distributed and/or modified under the conditions of
%% the LaTeX Project Public License, either version 1.3c of this license
%% or (at your option) any later version.
%% The latest version of this license is in
%%     https://www.latex-project.org/lppl.txt
%%
%% This work has the LPPL maintenance status `maintained'.
%% The Current Maintainer of this work is Philip Bittihn.
%%
%% This work consists of the files autoaffil.dtx and autoaffil.ins
%% and the derived file autoaffil.sty.
%%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{autoaffil.dtx}[2026/06/06 v1.0 autoaffil documented source]
\documentclass{ltxdoc}
\usepackage[T1]{fontenc}
\usepackage{lmodern}
\usepackage[colorlinks=true,allcolors=black,
  pdfauthor={Philip Bittihn},
  pdftitle={The autoaffil package}]{hyperref}
\CodelineIndex
\EnableCrossrefs
\RecordChanges
\begin{document}
  \DocInput{autoaffil.dtx}
  \PrintChanges
  \PrintIndex
\end{document}
%</driver>
% \fi
%
% \changes{v1.0}{2026/06/06}{Initial public release}
%
% \GetFileInfo{autoaffil.dtx}
%
% \DoNotIndex{\newcommand,\renewcommand,\def,\edef,\gdef,\xdef,\let,\global}
% \DoNotIndex{\ifx,\fi,\ifnum,\else,\newif}
% \DoNotIndex{\begingroup,\endgroup,\par,\relax,\expandafter}
% \DoNotIndex{\csname,\endcsname,\arabic,\stepcounter,\setcounter,\value}
% \DoNotIndex{\the,\toks,\numexpr,\noexpand,\mbox,\hspace,\textbf}
% \DoNotIndex{\newcounter,\DeclareOption,\ProcessOptions}
% \DoNotIndex{\NeedsTeXFormat,\ProvidesPackage,\RequirePackage}
% \DoNotIndex{\AtBeginDocument,\makeatletter,\makeatother}
% \DoNotIndex{\noindent,\vskip,\centering,\normalfont,\normalsize}
% \DoNotIndex{\@empty,\@for,\@whilenum,\@author,\author,\parbox,\textwidth}
%
% \title{The \textsf{autoaffil} package\thanks{This file has version
%   \fileversion, last revised \filedate.}}
% \author{Philip Bittihn\\\texttt{philip@bittihn.de}}
% \date{\filedate}
% \maketitle
%
% \begin{abstract}
% \textsf{autoaffil} provides the author/affiliation layout style
% common in physics and related fields: all authors in a single block
% with superscript numbers linking each name to a list of affiliations
% printed below---the style native to \textsf{revtex4-2} with the
% \texttt{superscriptaddress} option, and familiar from journals such as
% \emph{Physical Review Letters}.  The package brings this style to the
% standard \textsf{article} class and compatible classes, with automatic
% deduplication: authors and affiliations are declared individually in
% the preamble; identical affiliation strings are assigned the same
% number; numbers are assigned in order of first appearance; and
% \cs{maketitle} outputs the complete block without further intervention.
% \end{abstract}
%
% \tableofcontents
%
% \section{Introduction}
%
% The author/affiliation layout style used in physics and related fields
% places all author names in a single block with superscript numbers
% linking each name to a list of affiliations printed below.  This is the style native to \textsf{revtex4-2} with the
% \texttt{superscriptaddress} option, and familiar from journals such as
% \emph{Physical Review Letters}.
%
% Reproducing this style in the standard \textsf{article} class has
% traditionally required either hand-numbering (tedious and error-prone)
% or the \textsf{authblk} package (which still requires manual
% deduplication and can interact badly with some journal styles).
%
% \textsf{autoaffil} takes a different approach: authors and
% affiliations are declared separately and identically-worded
% affiliations are \emph{automatically} assigned the same number.
% The output block is injected into \cs{maketitle} in a way that is
% robust across document classes. The only external dependency is
% \textsf{etoolbox}, which is standard in any modern \TeX\ distribution.
%
% \section{Installation}
%
% \subsection{From a \TeX\ distribution}
%
% If \textsf{autoaffil} is included in your \TeX\ distribution
% (TeX~Live, MiK\TeX), no manual installation is needed:
% \begin{quote}
% |tlmgr install autoaffil| \quad (TeX Live)
% \end{quote}
%
% \subsection{Manual installation}
%
% \begin{enumerate}
% \item Run |latex autoaffil.ins| to extract |autoaffil.sty|.
% \item Place |autoaffil.sty| in a directory searched by \LaTeX.
%   For a single project, the same directory as your |.tex| file
%   suffices. For a system-wide installation, place it under your
%   local |texmf| tree at |tex/latex/autoaffil/autoaffil.sty| and
%   run |texhash| (or |mktexlsr|).
% \end{enumerate}
%
% \section{Usage}
%
% \subsection{Quick start}
%
% \begin{verbatim}
%   \documentclass{article}
%   \usepackage[ranges,superaftercomma]{autoaffil}
%
%   \autoauthor{Alice Anderson}
%     \autoaffil{MIT, Cambridge MA}
%     \autoaffil{Princeton University}
%   \autoauthor[*]{Bob Brown}
%     \autoaffil{MIT, Cambridge MA}   % same text -> same number (1)
%     \autoaffil{CERN, Geneva}
%   \autoauthor[*,\dagger]{Carol Chen}
%     \autoaffil{CERN, Geneva}        % deduplicated: same number as Bob's
%   \autoremark{*}{Equal contribution.}
%   \autoremark{\dagger}{Corresponding: carol@example.com}
%
%   \title{My Paper}
%   \begin{document}
%   \maketitle
%   ...
%   \end{document}
% \end{verbatim}
%
% \noindent With |[superaftercomma]|, the comma precedes the
% superscript; with |[ranges]|, runs of three or more consecutive
% numbers compress to a range (none occur here). The output looks like:
% \begin{quote}
% \textbf{Alice Anderson},$^{1,2}$~\textbf{Bob Brown},$^{1,3,*}$~\textbf{Carol Chen}$^{3,*,\dagger}$\\[0.4em]
% $^1$ MIT, Cambridge MA\\
% $^2$ Princeton University\\
% $^3$ CERN, Geneva\\[0.2em]
% $^*$ Equal contribution.\\
% $^\dagger$ Corresponding: carol@example.com
% \end{quote}
%
% \noindent (Affiliation numbers appear before extra symbols like $*$
% and $\dagger$. Bob's affiliations 1 and 3 are non-consecutive so they
% stay as |1,3|; with |[ranges]| an author whose affiliations are 1, 2,
% and 3 would instead show |1--3|.)
%
% \subsection{Declaring authors and affiliations}
% \label{sec:decl}
%
% \DescribeMacro{\autoauthor}
% \cs{autoauthor}\oarg{extra}\marg{name} declares one author.  Authors
% are output in the order they are declared.  The optional argument
% \meta{extra} is a comma-separated list of math-mode symbols that are
% appended as extra superscripts \emph{after} the affiliation numbers
% (e.g.\ |*|, |\dagger|, |\ddagger|).
%
% \DescribeMacro{\autoaffil}
% \cs{autoaffil}\marg{text} attaches one affiliation to the most recently
% declared author.  Repeat for each affiliation of that author.  If
% \meta{text} is identical---exact string match---to a previously
% registered affiliation, no new number is allocated; the existing
% number is reused.  Deduplication is therefore automatic and does not
% require any manual numbering or cross-referencing.
%
% \textbf{Tip for multi-author documents.}
% To guarantee string identity and keep affiliation text in one place,
% predefine each affiliation as a command in the preamble:
% \begin{verbatim}
%   \newcommand{\MIT}{\autoaffil{MIT, Cambridge MA}}
%   \newcommand{\CERN}{\autoaffil{CERN, Geneva}}
% \end{verbatim}
% Then declare authors as:
% \begin{verbatim}
%   \autoauthor{Alice Anderson} \MIT \Princeton
%   \autoauthor{Bob Brown}      \MIT \CERN
% \end{verbatim}
% Any future change to an affiliation string needs to be made in exactly
% one place and cannot accidentally break deduplication.
%
% \DescribeMacro{\autoremark}
% \cs{autoremark}\marg{symbol}\marg{text} defines a special remark entry,
% typically for equal contribution, corresponding author information, or
% similar annotations. \meta{symbol} is math-mode content (|*|,
% |\dagger|, |\ddagger|, \ldots). Remarks are output in definition order
% by \cs{printremarks}.
%
% \subsection{Package options}
% \label{sec:options}
%
% Options may be freely combined:
% \begin{verbatim}
%   \usepackage[ranges,superaftercomma,nobreak]{autoaffil}
% \end{verbatim}
%
% \begin{description}
%
% \item[\texttt{ranges}]
%   Compress runs of three or more consecutive affiliation numbers in a
%   superscript into an en-dash range. For example, an author with
%   affiliations 1, 2, 3 gets the superscript $^{1\textrm{--}3}$ instead
%   of $^{1,2,3}$. Pairs and isolated singles are not compressed.
%   Multiple disjoint ranges in a single superscript are supported
%   (e.g.\ $^{1\textrm{--}3,5\textrm{--}7}$).
%
% \item[\texttt{superaftercomma}]
%   Place the affiliation superscript \emph{after} the inter-author
%   comma rather than before it (the default). This matches the style
%   used by the \emph{Physical Review} family of journals (revtex4-2
%   style).
%
% \item[\texttt{nobreak}]
%   Wrap each author-name\,+\,superscript unit in \cs{mbox} so that
%   \TeX\ cannot break a line in the middle of one author's entry. The
%   spaces between author entries remain valid break points. This option
%   is most useful for short author lists or narrow typeblocks.
%
% \item[\texttt{manual}]
%   Suppress automatic insertion of the author block into \cs{maketitle}.
%   The three output commands (see \S\,\ref{sec:output}) must then be
%   called explicitly by the user. This is useful for documents that need
%   unusual placement of author information.
%
% \end{description}
%
% \subsection{Output commands}
% \label{sec:output}
%
% In the default (auto) mode, \cs{maketitle} outputs the full block
% automatically. In |[manual]| mode---or for unusual placement
% requirements---the three components can be placed individually:
%
% \DescribeMacro{\printauthors}
% \cs{printauthors} typesets the author list as a single paragraph:
% \cs{aafauthorfont}-formatted names separated by \cs{aafauthorsep} and
% \cs{aafauthorspace}, with superscripted affiliation numbers.
%
% \DescribeMacro{\printaffils}
% \cs{printaffils} typesets the numbered affiliation list, one entry per
% line, each preceded by its number in a superscript.
%
% \DescribeMacro{\printremarks}
% \cs{printremarks} typesets the special remarks declared with
% \cs{autoremark}, one per line, each preceded by its symbol in a
% superscript. If no remarks were declared, this command produces no output.
%
% \subsection{Customisation hooks}
% \label{sec:hooks}
%
% The following hooks can be redefined after |\usepackage{autoaffil}|:
%
% \DescribeMacro{\aafauthorfont}
% \cs{aafauthorfont}\marg{name}: formatting applied to each author name.
% Default: |\textbf|\marg{name} (bold).\\
% Example: |\renewcommand\aafauthorfont[1]{\textit{#1}}|
%
% \DescribeMacro{\aafauthorsep}
% \cs{aafauthorsep}: separator token(s) emitted between consecutive
% author entries. Default: |,| (comma).\\
% Example: |\renewcommand\aafauthorsep{;}|
%
% \DescribeMacro{\aafauthorspace}
% \cs{aafauthorspace}: breakable space emitted between consecutive
% author entries (after the separator in default mode, or after the
% superscript in |superaftercomma| mode). \emph{Must} be a breakable
% space so that long author lists wrap correctly.
% Default: |\hspace{0.5em plus 0.2em minus 0.1em}|\\
% Example: |\renewcommand\aafauthorspace{\ }|
%
% \subsection{Compatibility notes}
% \label{sec:compat}
%
% \begin{itemize}
%
% \item \textbf{Deduplication is exact string comparison.} |\ifx| is
%   applied to |\edef|-expanded strings. |MIT| and |MIT | (trailing
%   space) are treated as different affiliations. The recommended way to
%   ensure consistency is to predefine each affiliation as a command:
%   |\newcommand{\MIT}{\autoaffil{MIT, Cambridge MA}}| --- there is then
%   one authoritative spelling and the string identity is guaranteed
%   automatically (see Section~\ref{sec:decl}).
%
% \item \textbf{Auto mode compatibility.} Auto mode works with any
%   document class whose |\@maketitle| typesets |\@author|---this
%   includes the standard \textsf{article} class, essentially all
%   standard \LaTeX\ classes, and the large majority of journal and
%   preprint style files. The output block is injected via
%   |\author{...}| in |\AtBeginDocument|, wrapped in a
%   |\parbox[t]{\textwidth}| to allow paragraph-mode commands inside
%   the LR-mode tabular cells that many classes use around |\@author|.
%   Manual mode (|\printauthors|, |\printaffils|, |\printremarks|) works
%   with any class whatsoever.
%
% \item \textbf{\textsf{hyperref} PDF metadata.} |\@author| is used by
%   \textsf{hyperref} to set the PDF |Author| metadata field. With the
%   parbox approach this field will contain \LaTeX\ markup. Users who
%   need clean metadata should call |\hypersetup{pdfauthor={...}}|
%   explicitly.
%
% \item \textbf{\texttt{[manual]} mode.} In auto mode, |\@author| is set
%   to empty (via |\author{}|); classes that insert a non-zero-height
%   strut in the author tabular cell may show a small blank space at the
%   title position. This is harmless since the user controls placement
%   manually.
%
% \end{itemize}
%
% \StopEventually{\PrintChanges\PrintIndex}
%
% \section{Implementation}
%
% Open the \textsf{package} docstrip guard. Everything between this
% and the closing guard is extracted to |autoaffil.sty|.
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
% \subsection{Package identification and dependencies}
%
% We require \LaTeXe{} and load \textsf{etoolbox} (used indirectly via
% |\AtBeginDocument| and |\apptocmd|; its presence also ensures
% availability of |\newrobustcmd| for potential future use).
%
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{autoaffil}[2026/06/06 v1.0 Automatic affiliation footnotes (PB)]
\RequirePackage{etoolbox}
%    \end{macrocode}
%
% \subsection{Package options}
%
% Four boolean flags. All default to \textit{false}; the corresponding
% option sets the flag to \textit{true}.
%
%    \begin{macrocode}
% ---- package options ----

% ranges: compress runs of 3 or more consecutive affiliation numbers in
% a superscript list into a range n--m; pairs and singles are unchanged.
\newif\ifaaf@ranges
\aaf@rangesfalse
\DeclareOption{ranges}{\aaf@rangestrue}

% superaftercomma: place superscripts after the inter-author comma
% (revtex4-2 style) rather than before it.
\newif\ifaaf@superaftercomma
\aaf@superaftercommafalse
\DeclareOption{superaftercomma}{\aaf@superaftercommatrue}

% nobreak: prevent line breaks within a single author's name+superscript unit.
\newif\ifaaf@nobreak
\aaf@nobreakfalse
\DeclareOption{nobreak}{\aaf@nobreaktrue}

% manual: suppress automatic insertion of the author/affiliation/remarks block
% into \maketitle.  Use \printauthors, \printaffils, and \printremarks to place
% the blocks manually.  Without this option the blocks are inserted
% automatically by \maketitle.
\newif\ifaaf@manual
\aaf@manualfalse
\DeclareOption{manual}{\aaf@manualtrue}

\ProcessOptions\relax
%    \end{macrocode}
%
% \subsection{Customisation hooks}
%
% \begin{macro}{\aafauthorfont}
% \begin{macro}{\aafauthorsep}
% \begin{macro}{\aafauthorspace}
% The three public customisation hooks, all defined with |\newcommand|
% so users can redefine them with |\renewcommand|.
%    \begin{macrocode}
% ===========================================================
%  User-customisable hooks for \printauthors.
%  Redefine any of these after \usepackage{autoaffil}.
%
%  \aafauthorfont   -- applied to each author name as \aafauthorfont{Name}.
%                      Default: \textbf (bold).
%
%  \aafauthorsep    -- separator emitted between consecutive author entries.
%                      Default: , (comma).
%                      Example: \renewcommand\aafauthorsep{;}
%
%  \aafauthorspace  -- space emitted between consecutive author entries,
%                      after the separator (default mode) or after the
%                      superscript (superaftercomma mode).
%                      Must be a breakable space so long author lists wrap
%                      correctly.  Default: a half-em stretchable glue
%                      (\hspace{0.5em plus 0.2em minus 0.1em}), which is
%                      slightly wider than a normal inter-word space but
%                      allows line breaks just like one.
%                      Example: \renewcommand\aafauthorspace{\ } % plain space
%                               \renewcommand\aafauthorspace{\quad}
% ===========================================================
\newcommand\aafauthorfont[1]{\textbf{#1}}
\newcommand\aafauthorsep{,}
\newcommand\aafauthorspace{\hspace{0.5em plus 0.2em minus 0.1em}}
%    \end{macrocode}
% \end{macro}\end{macro}\end{macro}
%
%    \begin{macrocode}
\makeatletter
%    \end{macrocode}
%
% \subsection{Counters and data storage}
%
% All data are stored in dynamically-named control sequences following
% the convention |aaf@|\meta{type}|@|\meta{N}.  Four counters track the
% list sizes; |aaf@i| is a reusable scratch counter used in loops.
%
% \begin{center}
% \begin{tabular}{ll}
% \hline
% Control sequence & Content \\
% \hline
% |aaf@authorname@N|  & name of author $N$ \\
% |aaf@authorextra@N| & extra superscript marks for author $N$ \\
% |aaf@authormarks@N| & comma-separated affiliation numbers for author $N$ \\
% |aaf@affiltext@N|   & text of affiliation $N$ \\
% |aaf@remarksym@N|     & math-mode symbol for remark $N$ \\
% |aaf@remarktext@N|    & text of remark $N$ \\
% \hline
% \end{tabular}
% \end{center}
%
%    \begin{macrocode}
\newcounter{aaf@naffils}
\newcounter{aaf@nauthors}
\newcounter{aaf@nremarks}
\newcounter{aaf@i}
%    \end{macrocode}
%
% \subsection{Affiliation lookup and registration}
%
% \begin{macro}{\aaf@findaffil}
% |\aaf@findaffil|\marg{text} performs a linear search over the
% registered affiliations for an exact string match via |\ifx| on
% |\edef|-expanded strings. Sets |\aaf@found| to the matching index, or
% |0| if not found. The loop terminates early on a match by advancing
% |aaf@i| to |aaf@naffils|.
%    \begin{macrocode}
% ---- \aaf@findaffil{text} ----
\newcommand\aaf@findaffil[1]{%
  \def\aaf@found{0}%
  \setcounter{aaf@i}{0}%
  \@whilenum\value{aaf@i}<\value{aaf@naffils}\do{%
    \stepcounter{aaf@i}%
    \def\aaf@tmp{#1}%
    \expandafter\ifx\csname aaf@affiltext@\arabic{aaf@i}\endcsname\aaf@tmp
      \xdef\aaf@found{\arabic{aaf@i}}%
      \setcounter{aaf@i}{\value{aaf@naffils}}%
    \fi
  }%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\aaf@registeraffil}
% |\aaf@registeraffil|\marg{text} registers an affiliation string,
% allocating a new sequential number if it has not been seen before.
% Sets the global |\aaf@curnum| to the (possibly pre-existing) index.
%    \begin{macrocode}
% ---- \aaf@registeraffil{text} ----
\newcommand\aaf@registeraffil[1]{%
  \aaf@findaffil{#1}%
  \ifnum\aaf@found=0\relax
    \stepcounter{aaf@naffils}%
    \expandafter\gdef\csname aaf@affiltext@\arabic{aaf@naffils}\endcsname{#1}%
    \xdef\aaf@curnum{\arabic{aaf@naffils}}%
  \else
    \xdef\aaf@curnum{\aaf@found}%
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{User-level declaration commands}
%
% \begin{macro}{\autoauthor}
% Increments |aaf@nauthors|, stores the name and optional extra
% superscript marks, and initialises the marks list to empty.
%    \begin{macrocode}
% ---- \autoauthor[extra]{Name} ----
\newcommand\autoauthor[2][]{%
  \stepcounter{aaf@nauthors}%
  \edef\aaf@aid{\arabic{aaf@nauthors}}%
  \expandafter\gdef\csname aaf@authorname@\aaf@aid\endcsname{#2}%
  \expandafter\gdef\csname aaf@authorextra@\aaf@aid\endcsname{#1}%
  \expandafter\gdef\csname aaf@authormarks@\aaf@aid\endcsname{}%
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\autoaffil}
% Registers the affiliation (deduplicating if necessary) and appends its
% index to the current author's comma-separated marks list.
%    \begin{macrocode}
% ---- \autoaffil{text} ----
\newcommand\autoaffil[1]{%
  \edef\aaf@aid{\arabic{aaf@nauthors}}%
  \aaf@registeraffil{#1}%
  \expandafter\let\expandafter\aaf@curmarks\csname aaf@authormarks@\aaf@aid\endcsname
  \ifx\aaf@curmarks\@empty
    \expandafter\xdef\csname aaf@authormarks@\aaf@aid\endcsname{\aaf@curnum}%
  \else
    \expandafter\xdef\csname aaf@authormarks@\aaf@aid\endcsname{\aaf@curmarks,\aaf@curnum}%
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\autoremark}
% Appends a remark symbol and text to the remarks list.
%    \begin{macrocode}
% ---- \autoremark{symbol}{text} ----
% Defines a special remark entry (e.g.\ equal contribution, corresponding
% author) identified by a math-mode symbol such as * or \dagger.
% Remarks are printed in definition order by \printremarks.
\newcommand\autoremark[2]{%
  \stepcounter{aaf@nremarks}%
  \expandafter\gdef\csname aaf@remarksym@\arabic{aaf@nremarks}\endcsname{#1}%
  \expandafter\gdef\csname aaf@remarktext@\arabic{aaf@nremarks}\endcsname{#2}%
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Range compression}
%
% \begin{macro}{\aaf@compress}
% |\aaf@compress|\marg{comma-list} processes a sorted comma-separated
% list of integers left-to-right, compressing consecutive runs of
% three or more into en-dash ranges, and stores the result in
% |\aaf@result|.
%
% The algorithm maintains a \emph{current run} described by three
% variables: |\aaf@rc@start| (first number), |\aaf@rc@end| (last
% number), and |\aaf@rc@len| (run length). On each new number: if it
% is the successor of |\aaf@rc@end| the run is extended; otherwise the
% run is flushed and a new run is started.
%    \begin{macrocode}
% ===========================================================
%  Range compression.
%  \aaf@compress{comma-list-of-integers}  ->  sets \aaf@result
% ===========================================================

\def\aaf@dash{\mbox{--}}

\newcommand\aaf@compress[1]{%
  \def\aaf@rc@out{}%
  \def\aaf@rc@start{}%
  \def\aaf@rc@end{}%
  \def\aaf@rc@len{0}%
  \@for\aaf@rc@n:=#1\do{%
    \expandafter\aaf@rc@process\expandafter{\aaf@rc@n}%
  }%
  \ifx\aaf@rc@start\@empty\else\aaf@rc@flush\fi
  \let\aaf@result\aaf@rc@out
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\aaf@rc@process}
% Process one entry from the |\@for| loop. The double |\expandafter|
% pattern forces expansion of the loop variable |\aaf@rc@n| before
% passing it as an argument, which prevents |\@nil| sentinels (appended
% internally by |\@for|) from reaching the arithmetic in |\numexpr|.
%    \begin{macrocode}
\newcommand\aaf@rc@process[1]{%
  \ifx\aaf@rc@start\@empty
    \def\aaf@rc@start{#1}%
    \def\aaf@rc@end{#1}%
    \def\aaf@rc@len{1}%
  \else
    \edef\aaf@rc@succ{\the\numexpr\aaf@rc@end+1\relax}%
    \edef\aaf@rc@cur{#1}%
    \ifx\aaf@rc@cur\aaf@rc@succ
      \def\aaf@rc@end{#1}%
      \edef\aaf@rc@len{\the\numexpr\aaf@rc@len+1\relax}%
    \else
      \aaf@rc@flush
      \def\aaf@rc@start{#1}%
      \def\aaf@rc@end{#1}%
      \def\aaf@rc@len{1}%
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\aaf@rc@flush}
% Flush the current run to |\aaf@rc@out|. The flush rules are:
% length~1 $\to$ emit the start number; length~2 $\to$ emit
% |start,end|; length~$\geq3$ $\to$ emit |start\aaf@dash end|.
%
% Output is accumulated in |\aaf@rc@out| using |\toks| register
% concatenation to avoid prematurely expanding |\aaf@dash|
% (which expands to |\mbox{--}| and must remain unexpanded until
% typesetting time).
%    \begin{macrocode}
\newcommand\aaf@rc@flush{%
  \ifnum\aaf@rc@len=1\relax
    \edef\aaf@rc@piece{\aaf@rc@start}%
  \else\ifnum\aaf@rc@len=2\relax
    \edef\aaf@rc@piece{\aaf@rc@start,\aaf@rc@end}%
  \else
    \edef\aaf@rc@piece{\aaf@rc@start\noexpand\aaf@dash\aaf@rc@end}%
  \fi\fi
  \ifx\aaf@rc@out\@empty
    \let\aaf@rc@out\aaf@rc@piece
  \else
    \toks0=\expandafter{\aaf@rc@out}%
    \toks2=\expandafter{\aaf@rc@piece}%
    \edef\aaf@rc@out{\the\toks0,\the\toks2}%
  \fi
  \def\aaf@rc@start{}%
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Superscript materialisation}
%
% \begin{macro}{\aaf@prepare@marks}
% Sets |\aaf@allmarks| and |\aaf@extramarks| to fully materialised
% literal-token strings for author \meta{aid}.  When the |ranges|
% option is active, |\aaf@allmarks| is passed through |\aaf@compress|
% and the result is re-materialised via |\toks| (severing any alias
% chain before the final |\edef|).
%
% \textbf{Implementation note (the trailing-comma trap):}
% |\edef| must be used (not |\let|) for the initial materialisation.
% A |\let| alias to a csname whose content was itself built by |\@for|
% can retain an alias chain that introduces a spurious trailing comma
% inside a subsequent |$^{...}$| argument. The |\edef| collapses the
% chain into literal character tokens, preventing this.
%    \begin{macrocode}
% ===========================================================
%  \aaf@prepare@marks{aid}
%  Sets \aaf@allmarks and \aaf@extramarks to fully materialised
%  literal-token strings.
% ===========================================================
\newcommand\aaf@prepare@marks[1]{%
  \edef\aaf@allmarks{\csname aaf@authormarks@#1\endcsname}%
  \edef\aaf@extramarks{\csname aaf@authorextra@#1\endcsname}%
  \ifaaf@ranges
    \ifx\aaf@allmarks\@empty\else
      \aaf@compress{\aaf@allmarks}%
      \toks0=\expandafter{\aaf@result}%
      \edef\aaf@allmarks{\the\toks0}%
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\aaf@emit@super}
% Typesets the superscript using the already-materialised
% |\aaf@allmarks| and |\aaf@extramarks|. These \emph{must} be set by
% |\edef| before calling this macro. Argument passing is deliberately
% avoided because passing a macro as |#1| and then using it in
% |$^{#1}$| reintroduces the alias-chain problem described above.
%    \begin{macrocode}
% ===========================================================
%  \aaf@emit@super
%  Typesets the superscript using the already-set \aaf@allmarks
%  and \aaf@extramarks.  These MUST already be fully materialised
%  literal-token strings (set by \edef) before calling this.
% ===========================================================
\newcommand\aaf@emit@super{%
  \ifx\aaf@allmarks\@empty
    \ifx\aaf@extramarks\@empty\else$^{\aaf@extramarks}$\fi
  \else
    \ifx\aaf@extramarks\@empty
      $^{\aaf@allmarks}$%
    \else
      $^{\aaf@allmarks,\aaf@extramarks}$%
    \fi
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Author list typesetting}
%
% \begin{macro}{\printauthors}
% Typesets the full author list. Two layout strategies are used
% depending on the |superaftercomma| option. The |nobreak| option is
% orthogonal and is handled by the locally-defined |\aaf@unit| wrapper.
%
% \textbf{\texttt{superaftercomma} layout:}
% Between authors: |\aafauthorspace|. Each non-last author's unit is
% |name + separator + superscript|; the last author's unit is
% |name + superscript|. The comma belongs to the current author but
% the superscript belongs to the \emph{current} author (not deferred).
%
% \textbf{Default layout:}
% Each unit is |name + superscript|. Between units:
% |\aafauthorsep| followed by |\aafauthorspace|.
%    \begin{macrocode}
% ---- \printauthors ----
%
% Default layout:
%   \aafauthorfont{Name1}^{m1}\aafauthorsep\aafauthorspace\aafauthorfont{Name2}^{m2}...
%
% superaftercomma layout:
%   \aafauthorfont{Name1}\aafauthorsep^{m1}\aafauthorspace\aafauthorfont{Name2}...
%
% nobreak: each name+superscript unit (including the trailing separator in
%   superaftercomma mode) is wrapped in \mbox{} so it cannot be broken.
%   The inter-author space remains a valid break point.
%
% Implementation note: \aaf@unit{content} wraps content in \mbox{} when
%   nobreak is active, and is transparent otherwise.
%
\newcommand\printauthors{%
  \begingroup
  \setcounter{aaf@i}{0}%
  % Set up the unit wrapper: \aaf@unit{tokens} either outputs tokens
  % directly (no nobreak) or wraps them in \mbox{tokens} (nobreak).
  \ifaaf@nobreak
    \def\aaf@unit##1{\mbox{##1}}%
  \else
    \def\aaf@unit##1{##1}%
  \fi
  \ifaaf@superaftercomma
    %
    % ---- superaftercomma layout ----
    %
    % Each unit is: \aafauthorfont{name}\aafauthorsep^{marks}, wrapped by \aaf@unit.
    % The last unit is: \aafauthorfont{name}^{marks} (no trailing sep).
    % Between units: \aafauthorspace (breakable unless nobreak).
    %
    \def\aaf@prev@marks{}%
    \def\aaf@prev@extra{}%
    \def\aaf@isfirst{1}%
    \@whilenum\value{aaf@i}<\value{aaf@nauthors}\do{%
      \stepcounter{aaf@i}%
      \edef\aaf@aid{\arabic{aaf@i}}%
      % Emit inter-author space before all but the first author.
      \ifx\aaf@isfirst\@empty
        \aafauthorspace
      \fi
      \def\aaf@isfirst{}%
      % Prepare this author's marks now (needed to build the unit).
      \aaf@prepare@marks{\aaf@aid}%
      \let\aaf@prev@marks\aaf@allmarks
      \let\aaf@prev@extra\aaf@extramarks
      % Emit unit: name+sep+super for non-last authors, name+super for the last.
      \ifnum\aaf@aid<\value{aaf@nauthors}%
        % Not last: unit = name + separator + super.
        \aaf@unit{%
          \aafauthorfont{\csname aaf@authorname@\aaf@aid\endcsname}\aafauthorsep%
          \let\aaf@allmarks\aaf@prev@marks
          \let\aaf@extramarks\aaf@prev@extra
          \aaf@emit@super
        }%
      \else
        % Last author: unit = name + super (no trailing separator).
        \aaf@unit{%
          \aafauthorfont{\csname aaf@authorname@\aaf@aid\endcsname}%
          \let\aaf@allmarks\aaf@prev@marks
          \let\aaf@extramarks\aaf@prev@extra
          \aaf@emit@super
        }%
      \fi
    }%
    %
  \else
    %
    % ---- default layout ----
    %
    % Each unit is: \aafauthorfont{name}^{marks}, wrapped by \aaf@unit.
    % Between units: \aafauthorsep\aafauthorspace.
    %
    \def\aaf@sep{}%
    \@whilenum\value{aaf@i}<\value{aaf@nauthors}\do{%
      \stepcounter{aaf@i}%
      \edef\aaf@aid{\arabic{aaf@i}}%
      \aaf@sep
      \aaf@prepare@marks{\aaf@aid}%
      \aaf@unit{%
        \aafauthorfont{\csname aaf@authorname@\aaf@aid\endcsname}%
        \aaf@emit@super
      }%
      \def\aaf@sep{\aafauthorsep\aafauthorspace}%
    }%
  \fi
  \endgroup
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\printaffils}
% Typesets the numbered affiliation list, one entry per line.
%    \begin{macrocode}
% ---- \printaffils ----
\newcommand\printaffils{%
  \begingroup
  \setcounter{aaf@i}{0}%
  \@whilenum\value{aaf@i}<\value{aaf@naffils}\do{%
    \stepcounter{aaf@i}%
    \noindent$^{\arabic{aaf@i}}$\csname aaf@affiltext@\arabic{aaf@i}\endcsname\par
  }%
  \endgroup
}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\printremarks}
% Typesets the special remarks. Produces no output if no remarks were
% declared.
%    \begin{macrocode}
% ---- \printremarks ----
% Typesets the special remarks defined with \autoremark, one per line,
% each preceded by its symbol in a superscript.
\newcommand\printremarks{%
  \begingroup
  \setcounter{aaf@i}{0}%
  \@whilenum\value{aaf@i}<\value{aaf@nremarks}\do{%
    \stepcounter{aaf@i}%
    \noindent$^{\csname aaf@remarksym@\arabic{aaf@i}\endcsname}$%
    \csname aaf@remarktext@\arabic{aaf@i}\endcsname\par
  }%
  \endgroup
}
%    \end{macrocode}
% \end{macro}
%
% \subsection{Automatic insertion into \cs{maketitle}}
%
% \begin{macro}{\aaf@block}
% |\aaf@block| typesets the complete author/affiliation/remarks block.
% |\normalfont| and |\normalsize| at the top reset any font or size
% inherited from the surrounding |\@maketitle| context (some classes
% wrap |\@author| in bold or a larger size). The vertical skip before
% remarks section is only inserted when remarks exist.
%    \begin{macrocode}
% ===========================================================
%  Automatic insertion into \maketitle (disabled by [manual]).
%
%  \aaf@block typesets the complete author/affiliation/remarks block.
%  \normalfont and \normalsize at the top reset any font inherited
%  from the surrounding context in \@maketitle.
%
%  Strategy: set \@author to \aaf@block inside a full-width parbox
%  via \author{...} in \AtBeginDocument.  Every \@maketitle typesets
%  \@author, so the block appears at the correct location in any
%  document class without needing to know its internal structure.
%  The \parbox allows paragraph-mode content (incl. \par, \noindent)
%  inside tabular cells (LR mode) used by many classes.
% ===========================================================

\newcommand\aaf@block{%
  \normalfont  % reset font family/series/shape (some classes apply \bf
               % or other font commands around \@author in \@maketitle)
  \normalsize  % reset font size
  \printauthors\par
  \vskip 0.6em\relax
  \printaffils
  \ifnum\value{aaf@nremarks}>0\relax
    \vskip 0.4em\relax
    \printremarks
  \fi
}
%    \end{macrocode}
% \end{macro}
%
% The |\AtBeginDocument| hook either calls |\author{}| (manual mode, to
% suppress the ``No |\author| given'' warning) or sets |\@author| to
% |\aaf@block| inside a full-width top-aligned |\parbox|.
%
% \textbf{Why \texttt{\textbackslash parbox}:} many classes typeset |\@author| inside a
% tabular |c|-column (LR mode). Paragraph-mode commands such as |\par|
% and |\noindent| (used by |\printauthors|, |\printaffils|,
% |\printremarks|) require paragraph mode. A |\parbox[t]{\textwidth}|
% provides this sub-environment; |\centering| inside it centres each
% output line.
%
% \textbf{Why not \texttt{\textbackslash patchcmd}:} an earlier implementation patched
% |\@maketitle| directly. This requires exact token-level matching of
% the surrounding context, which varies across classes. Setting
% |\@author| instead is class-agnostic: every |\@maketitle|
% implementation typesets |\@author| somewhere, so the block always
% appears at the correct location.
%    \begin{macrocode}
\AtBeginDocument{%
  \ifaaf@manual
    % Manual mode: call \author{} to suppress the "No \author given"
    % warning (autoaffil manages author display itself).
    \author{}%
  \else
    % Auto mode: set \@author to our block inside a \parbox[t]{\textwidth}.
    %
    % This is the general injection strategy: rather than patching
    % \@maketitle (which would require exact token-level matching of
    % the surrounding context, varying across classes), we place our
    % content directly into \@author.  Since every \@maketitle typesets
    % \@author somewhere, the block always appears at the correct location
    % regardless of the surrounding structure.
    %
    % \parbox[t]{\textwidth} creates a top-aligned paragraph box spanning
    % the full text width.  This lets \printauthors, \printaffils, and
    % \printremarks use paragraph-mode commands (such as \par and \noindent)
    % even when \@author is typeset inside a tabular cell (LR mode).
    % \centering centres each line within the parbox.
    \author{%
      \parbox[t]{\textwidth}{%
        \centering
        \aaf@block
      }%
    }%
  \fi
}

\makeatother
%    \end{macrocode}
%
% Close the \textsf{package} docstrip guard.
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \Finale
