% \iffalse meta-comment
%
% Copyright (C) 2012 by Sigitas Tolu\v{s}is <sigitas@vtex.lt>
% ---------------------------------------------------------------------------
% This work may be distributed and/or modified under the
% conditions of the LaTeX Project Public License, either version 1.3
% 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.3 or later is part of all distributions of LaTeX
% version 2005/12/01 or later.
%
% This work has the LPPL maintenance status `maintained'.
%
% The Current Maintainer of this work is Sigitas Tolu\v{s}is.
%
% This work consists of the files texsort.dtx and texsort.ins
% and the derived filebase texsort.sty.
%
% Also available from:
%  http://www.vtex.lt/tex/download/macros/
%
% \fi
%
% \iffalse
%<*driver>
\ProvidesFile{texsort.dtx}
%</driver>
%<*package>
%% Copyright (C) 2000-2012 by Sigitas Tolu\v{s}is <sigitas@vtex.lt>
%% VTeX Ltd., Akademijos 4, Vilnius, Lithuania
%% http://www.vtex.lt/tex/download/macros/
%% --------------------------------------------------------------------------
%% This work may be distributed and/or modified under the
%% conditions of the LaTeX Project Public License, either version 1.3
%% 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.3 or later is part of all distributions of LaTeX
%% version 2005/12/01 or later.
%%
%% PURPOSE:   Sort/compress numerical lists
%%
%</package>
%<package>\NeedsTeXFormat{LaTeX2e}[1999/12/01]
%<package>\ProvidesPackage{texsort}
%<*package>
    [2012/05/29 v1.1 Sort/compress alphanumerical list]
%</package>
%
%<*driver>
\documentclass{ltxdoc}
\usepackage{texsort}[2012/05/29]
%%\EnableCrossrefs
%%\CodelineIndex
%%\RecordChanges
\begin{document}
  \DocInput{texsort.dtx}
  %%\PrintChanges
  %%\PrintIndex
\end{document}
%</driver>
% \fi
%
% \CheckSum{629}
%
% \CharacterTable
%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%   Digits        \0\1\2\3\4\5\6\7\8\9
%   Exclamation   \!     Double quote  \"     Hash (number) \#
%   Dollar        \$     Percent       \%     Ampersand     \&
%   Acute accent  \'     Left paren    \(     Right paren   \)
%   Asterisk      \*     Plus          \+     Comma         \,
%   Minus         \-     Point         \.     Solidus       \/
%   Colon         \:     Semicolon     \;     Less than     \<
%   Equals        \=     Greater than  \>     Question mark \?
%   Commercial at \@     Left bracket  \[     Backslash     \\
%   Right bracket \]     Circumflex    \^     Underscore    \_
%   Grave accent  \`     Left brace    \{     Vertical bar  \|
%   Right brace   \}     Tilde         \~}
%
%
% \changes{v0.1a}{2000/06/06}{Created alfa version}
% \changes{v1.0}{2000/06/08}{Added compression}
% \changes{v1.1}{2012/05/29}{Converted to DTX file}
%
% \DoNotIndex{\newcommand,\newenvironment}
%
% \providecommand*{\url}{\texttt}
% \GetFileInfo{texsort.dtx}
% \title{The \textsf{texsort} package}
% \author{Sigitas Tolu\v{s}is \\ \url{sigitas@vtex.lt}}
% \date{\fileversion~from \filedate}
%
% \maketitle
%
% \section{Introduction}
%
% Purpose: sort/compress numerical lists.
%
% \section{Usage}
%
% \DescribeMacro{\sortlist}
% 
% \leftline{Sort list:}
%
% \verb|\sortlist{1,5,20,6,23,2,1,4000,4}\to{mylist}\sep{,}|
%
% \medskip
% \leftline{Result:}
%
% \sortlist{1,5,20,6,23,2,1,4000,4}\to{mylist}\sep{,}
% \verb|\mylist->|\mylist
%
% \bigskip
% \DescribeMacro{\compresslist}
%
% \leftline{Compress list:}
%
% \verb|\compresslist{\mylist}\to{clist}\sep{,}{-}|
%
% \medskip
% \leftline{Result:}
% \compresslist{\mylist}\to{clist}\sep{,}{-}%
% \verb|\clist->|\clist
%
% \StopEventually{}
%
% \section{Implementation}
%
% \iffalse
%<*package>
% \fi
%
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{texsort}[2012/05/29]
%    \end{macrocode}
%
%    \begin{macrocode}
\newcount\t@mp@r@a
\newcount\t@mp@r@b
\newcount\t@mp@r@c
%    \end{macrocode}
%
% \begin{macro}{\initarray}
% \marg{list}\marg{array}
%
% \medskip
% Converts \meta{list} to \meta{array}.
% \medskip
%    \begin{macrocode}
\def\initarray#1#2{%
  \bgroup
    \@tempcnta=\z@
    \@for\@@refb:=#2\do{%
      \advance\@tempcnta by\@ne
      \bgroup
        \setbox\z@\hbox{%
          \expandafter\global\expandafter\t@mp@r@a\expandafter\add@zero\@@refb\relax
          }%
        \ifdim\wd0>\z@\relax
           \@latex@warning{Not number \@@refb!}%
        \fi
        \expandafter\edef\csname @a@\endcsname{\expandafter\xdef\expandafter
          \noexpand\csname#1@\the\@tempcnta\endcsname{\the\t@mp@r@a}}\@a@
      \egroup
    }%
    \expandafter\xdef\csname #1@lenght\endcsname{\the\@tempcnta}%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\outarray}
% \marg{array}\marg{sep}
%
% \medskip
% Outputs \meta{array} elements separated by \meta{sep}.
% \medskip
%    \begin{macrocode}
\def\outarray#1\sep#2{%
  \bgroup
    \@tempcnta=\z@\relax
    \@tempcntb=\getarraylenght{#1}%
    \loop
    \ifnum\@tempcnta<\@tempcntb 
      \advance\@tempcnta by\@ne\relax
      \ifnum\@tempcnta>\@ne\relax#2\fi
      \csname#1@\the\@tempcnta\endcsname
    \repeat
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\add@zero}
% \marg{arg}
%
% \medskip
% Adds 0 before \meta{arg}.
% \medskip
%    \begin{macrocode}
\def\add@zero#1{0#1}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\getarrayitem}
% \marg{array}\marg{index}\verb|\to|\marg{command}
%
% \medskip
% Gets \meta{array} element by \meta{index} to \verb|\|\meta{command}.
% \medskip
%    \begin{macrocode}
\def\getarrayitem#1#2\to#3{\expandafter\xdef\csname#3\endcsname{\csname#1@#2\endcsname}}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\setarrayitem}
% \marg{array}\marg{index}\marg{value}
%
% \medskip
% Sets \meta{array} element by \meta{index} to \meta{value}.
% \medskip
%    \begin{macrocode}
\def\setarrayitem#1#2#3{%
  \bgroup
    \setbox0\hbox{%
      \expandafter\global\expandafter\t@mp@r@a\expandafter\add@zero#3\relax
      }%
    \ifdim\wd0>\z@\relax
      \@latex@warning{Not number #3!}%
    \fi
    \expandafter\xdef\csname#1@#2\endcsname{\the\t@mp@r@a}%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\getarraylenght}
% \marg{array}
%
% \medskip
% Gets \meta{array} elements count.
% \medskip
%    \begin{macrocode}
\def\getarraylenght#1{\@ifundefined{#1@lenght}{0}{\csname #1@lenght\endcsname}}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\setarraylenght}
% \marg{array}\marg{value}
%
% \medskip
% Sets \meta{array} elements count to \meta{value}.
% \medskip
%    \begin{macrocode}
\def\setarraylenght#1#2{\expandafter\xdef\csname #1@lenght\endcsname{#2}}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\upheap}
% \marg{array}\marg{index}
%
% \medskip
% Internal macro of sort algorithm.
% \medskip
%    \begin{macrocode}
\def\upheap#1#2{%
  \bgroup
    \getarrayitem{#1}{#2}\to{vara}%
    \@namedef{#1@0}{\maxdimen}%
    \@tempcntb=#2\relax
    \loop
    \@tempcnta=\@tempcntb
    \divide\@tempcnta by2\getarrayitem{#1}{\the\@tempcnta}\to{varb}%
    \ifnum\varb>\vara\relax
    \else
      \getarrayitem{#1}{\the\@tempcnta}\to{varb}%
      \setarrayitem{#1}{\the\@tempcntb}{\varb}%
      \divide\@tempcntb by2\relax
    \repeat
    \setarrayitem{#1}{\the\@tempcntb}{\vara}%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\insertheapelem}
% \marg{array}\marg{value}
%
% \medskip
% Internal macro of sort algorithm.
% \medskip
%    \begin{macrocode}
\def\insertheapelem#1#2{%
  \bgroup 
    \@tempcnta=\getarraylenght{#1}\relax
    \advance\@tempcnta by1\relax
    \setarraylenght{#1}{\the\@tempcnta}\relax
    \setarrayitem{#1}{\the\@tempcnta}{#2}%
    \upheap{#1}{\the\@tempcnta}%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
\newcount\@tempcntd
%    \end{macrocode}
%
% \begin{macro}{\downheap}
% \marg{array}\marg{index}
%
% \medskip
% Internal macro of sort algorithm.
% \medskip
%    \begin{macrocode}
\def\downheap#1#2{%
  \bgroup
    \getarrayitem{#1}{#2}\to{vara}%
    \@tempcntb=\getarraylenght{#1}%
    \t@mp@r@c=\@tempcntb\relax
    \divide\@tempcntb by2\relax
    \t@mp@r@b=\@tempcntb\relax
    \@tempcntb=#2\relax
    \ifnum\@tempcntb>\t@mp@r@b\relax
    \else 
      \loop
      \@tempcnta=\@tempcntb \advance\@tempcnta by\@tempcntb\relax
      \@tempcntd=\@tempcnta \advance\@tempcntd by1\relax
      \ifnum\@tempcnta<\t@mp@r@c\relax
        \getarrayitem{#1}{\the\@tempcnta}\to{temp@@a}%
        \getarrayitem{#1}{\the\@tempcntd}\to{temp@@b}%
        \ifnum\temp@@a<\temp@@b\relax
          \@tempcnta=\@tempcntd
        \fi
      \fi
      \getarrayitem{#1}{\the\@tempcnta}\to{temp@@a}%
      \ifnum\vara>\temp@@a\relax
        \t@mp@r@b=-1\relax
      \else
        \getarrayitem{#1}{\the\@tempcnta}\to{temp@@a}%
        \setarrayitem{#1}{\the\@tempcntb}{\temp@@a}%
        \@tempcntb=\@tempcnta
      \fi
      \ifnum\@tempcntb>\t@mp@r@b\relax
      \else
      \repeat
    \fi
    \setarrayitem{#1}{\the\@tempcntb}{\vara}%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}

%    \end{macrocode}
%
% \begin{macro}{\removetop}
% \marg{array}\verb|\to|\marg{command}
%
% \medskip
% Internal macro of sort algorithm.
% \medskip
%    \begin{macrocode}
\def\removetop#1\to#2{%
  \bgroup
    \getarrayitem{#1}{1}\to{temp@@c}%
    \expandafter\xdef\csname #2\endcsname{\temp@@c}%
    \@tempcnta=\getarraylenght{#1}%
    \getarrayitem{#1}{\the\@tempcnta}\to{temp@@a}%
    \setarrayitem{#1}{1}{\temp@@a}%
    \setarrayitem{#1}{\the\@tempcnta}{}%
    \advance\@tempcnta by-1\relax
    \setarraylenght{#1}{\the\@tempcnta}%
    \downheap{#1}{1}%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\g@addto@macrobeg}
% \marg{macro}\marg{definition}
%
% \medskip
% Adds some more \meta{definition} to \meta{macro} begining.
% \medskip
%    \begin{macrocode}
\long\def\g@addto@macrobeg#1#2{%
  \begingroup
    \def\@a@{#2}%
    \toks@\expandafter\expandafter\expandafter{\expandafter\@a@#1}%
    \xdef#1{\the\toks@}%
  \endgroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\sortlistarray}
% \marg{array}\marg{sorted array}
%
% \medskip
% Sorts \meta{array} and puts result to \meta{sorted array}.
%    \begin{macrocode}
\def\sortlistarray#1\to#2{%
  \bgroup
    \@for\@@refb:=#1\do{%
      \insertheapelem{@tempa@}{\@@refb}%
      }%
    \@tempcntb=\getarraylenght{@tempa@}%
    \setarraylenght{#2}{\the\@tempcntb}%
    \@for\@@refb:=#1\do{%
      \removetop{@tempa@}\to{aka}%
      \setarrayitem{#2}{\the\@tempcntb}{\aka}%
      \advance\@tempcntb by-1\relax
      }%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\sortlist}
% \marg{list}\verb|\to|\marg{macro}\verb|\sep|\marg{sep}
%
% \medskip
% Sorts \meta{list} and puts elements separated by \meta{sep} to \meta{macro}.
% \medskip
%    \begin{macrocode}
\def\sortlist#1\to#2\sep#3{%
  \bgroup
    \@for\@@refb:=#1\do{%
      \insertheapelem{@tempa@}{\@@refb}%
      }%
    \@tempcntb=\getarraylenght{@tempa@}%
    \expandafter\def\csname#2\endcsname{}%
    \expandafter\def\expandafter\@a@\expandafter{\csname#2\endcsname}%
    \@for\@@refb:=#1\do{%
      \removetop{@tempa@}\to{aka}%
      \advance\@tempcntb by-1\relax
      \expandafter\expandafter\expandafter
        \g@addto@macrobeg\expandafter\@a@\expandafter{\aka}%
      \ifnum\@tempcntb>0\relax
        \expandafter\expandafter\expandafter
          \g@addto@macrobeg\expandafter\@a@\expandafter{#3}%
      \fi
      }%
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\compresslist}
% \marg{list}\verb|\to|\marg{macro}\verb|\sep|\marg{single}\marg{multi}
%
% \medskip
% Compress \meta{list} and puts result to \marg{macro};
% single elements separated by \meta{single}, multi by \meta{multi}.
% \medskip
%    \begin{macrocode}
\def\compresslist#1\to#2\sep#3#4{%
  \bgroup
    \expandafter\def\csname#2\endcsname{}%
    \expandafter\def\expandafter\@a@\expandafter{\csname#2\endcsname}%
    \t@mp@r@a=-1\relax
    \@tempcnta=-2\relax
    \expandafter\@for\expandafter\@@refb\expandafter:\expandafter=#1\do{%
       \ifnum\t@mp@r@a=-1\relax
         \t@mp@r@a=\@@refb\relax
         \t@mp@r@b=\@@refb\relax
         \t@mp@r@c=\@@refb\relax
         \expandafter\expandafter\expandafter
           \g@addto@macro\expandafter\@a@\expandafter{\the\t@mp@r@a}%
       \else
         \t@mp@r@c=\@@refb\relax
         \ifnum\t@mp@r@c=\t@mp@r@a\relax
           \expandafter\expandafter\expandafter
             \g@addto@macro\expandafter\@a@\expandafter{#3}%
           \expandafter\expandafter\expandafter
             \g@addto@macro\expandafter\@a@\expandafter{\the\t@mp@r@c}%
           \t@mp@r@b=\t@mp@r@c\relax
         \else
           \@tempcnta=\t@mp@r@b\relax
           \advance\@tempcnta by1\relax
           \ifnum\@tempcnta=\t@mp@r@c\relax
             \t@mp@r@b=\t@mp@r@c\relax
           \else
             \@tempcnta=\t@mp@r@a\relax
             \advance\@tempcnta by-\t@mp@r@b\relax
             \ifnum\@tempcnta<-1\relax
               \expandafter\expandafter\expandafter
                 \g@addto@macro\expandafter\@a@\expandafter{#4}%
               \expandafter\expandafter\expandafter
                 \g@addto@macro\expandafter\@a@\expandafter{\the\t@mp@r@b}%
               \expandafter\expandafter\expandafter
                 \g@addto@macro\expandafter\@a@\expandafter{#3}%
               \expandafter\expandafter\expandafter
                 \g@addto@macro\expandafter\@a@\expandafter{\the\t@mp@r@c}%
             \else
               \ifnum\t@mp@r@a<\t@mp@r@b
                 \expandafter\expandafter\expandafter
                   \g@addto@macro\expandafter\@a@\expandafter{#3}%
                 \expandafter\expandafter\expandafter
                   \g@addto@macro\expandafter\@a@\expandafter{\the\t@mp@r@b}%
               \fi
               \expandafter\expandafter\expandafter
                 \g@addto@macro\expandafter\@a@\expandafter{#3}%
               \expandafter\expandafter\expandafter
                 \g@addto@macro\expandafter\@a@\expandafter{\the\t@mp@r@c}%
             \fi
             \t@mp@r@a=\t@mp@r@c\relax
             \t@mp@r@b=\t@mp@r@c\relax
           \fi
         \fi
       \fi
       }%
    \ifnum\t@mp@r@a<\t@mp@r@c\relax
      \advance\t@mp@r@a by-\t@mp@r@c\relax
      \ifnum\t@mp@r@a<-1\relax
        \expandafter\expandafter\expandafter
          \g@addto@macro\expandafter\@a@\expandafter{#4}%
      \else
        \expandafter\expandafter\expandafter
          \g@addto@macro\expandafter\@a@\expandafter{#3}%
      \fi
      \expandafter\expandafter\expandafter
        \g@addto@macro\expandafter\@a@\expandafter{\the\t@mp@r@c}%
    \fi
  \egroup
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%\endinput
%    \end{macrocode}
%
% \iffalse
%</package>
% \fi
%
% \Finale