% % sortlist.sty % % Implements a sorted list, with handler functions. % % \ProvidesFile{sortlist}[2005/02/12 Sorted list] \RequirePackage{strings} % % Create a new list. Requires three arguments: a name for the list, a sorting % function, and a function definition that determines what elements to sort: % % \NewSortedList{list}{\SortAlpha}{#1} % which would create a list named ``list'' which is sorted alphabetically and % uses the elements of the list as sorting keys. % % Lists are implemented as token lists. % % The key finding function should be totally expandable. The sorting function % need not be. \def\NewSortedList#1#2{% \expandafter\newtoks\csname sli@@#1\endcsname \@namedef{sli@fn@#1}{#2}% \expandafter\def\csname sli@k@#1\endcsname##1##2% } \def\IfEmptyList#1{% \@expand\@ifempty{\expandafter\the\csname sli@@#1\endcsname}{ii}% } \def\sli@namelet#1#2{\expandafter\sli@@namelet\csname #2\endcsname#1}% \def\sli@@namelet#1#2{\let#2#1}% \def\ReverseSort#1#2#3{% #1{#2}{#3}\ifCompReverse\CompReversefalse\else\CompReversetrue\fi } \def\AddToList#1#2{% \sli@namelet\sli@this{sli@@#1}% \sli@namelet\sli@sfun{sli@fn@#1}% \sli@namelet\sli@kfun{sli@k@#1}% \def\sli@elt{#2}\sli@kfun{#2}\sli@addkey \let\sli@do\relax \edef\sli@act{% \noexpand\sli@this{}% Clear the list \noexpand\sli@add{}% \the\sli@this \noexpand\sli@stop\relax }% \sli@act } \def\sli@stop{\sli@stop} \def\sli@add#1#2#3{% \ifx\sli@stop#2% % If at the end of the list, pop the element on the end of the list \edef\sli@act##1{% \sli@this{##1\sli@do{\expandafter\noexpand\sli@elt}}% }% \sli@act{#1}% \else % \sli@key ends up looking like {new-key}{key} \sli@kfun{#3}\sli@key \sli@exptwice\sli@key\sli@key\sli@addkey % So this ends up running \sli@sfun{new-key}{key} \expandafter\sli@sfun\sli@key \@test\ifCompReverse\fi {% \edef\sli@act##1##2{\sli@this{% ##1\sli@do{\expandafter\noexpand\sli@elt}\sli@do{##2}% }}\sli@act{#1}{#3}% \expandafter\sli@addend }{% \@skipafi{\sli@add{#1\sli@do{#3}}} }% \fi } \def\sli@exptwice#1#2#3{\@expand{\@expand{\sli@@exptwice{#1}}{#2}{i}}{#3}{i}} \def\sli@@exptwice#1#2#3{\def#1{{#2}{#3}}} \def\sli@addend#1\sli@stop\relax{% \edef\sli@act##1{\sli@this{\the\sli@this##1}}\sli@act{#1}% } \newif\ifCompReverse \def\SortNum#1#2{% \@tempcnta#1\relax \@tempcntb#2\relax \ifnum\@tempcnta>\@tempcntb \CompReversetrue \else \CompReversefalse \fi } \def\NoSort#1#2{\CompReversefalse} \def\SortLen#1#2{\sli@sortlen#1\sli@stop\@nil#2\sli@stop\@nil} \def\sli@sortlen#1#2\@nil#3#4\@nil{% \@test{\ifx#1\sli@stop}\fi{% \CompReversefalse }{% \@test{\ifx#3\sli@stop}\fi{% \CompReversetrue }{% \sli@sortlen#2\@nil#4\@nil }% }% }% \def\@ifbothonechar#1#2{\@ifonechar{#1}{\@ifonechar{#2}}{\@secondoftwo}} \def\SortAlpha#1#2{\sli@alpha#1\sli@stop\@nil#2\sli@stop\@nil} \def\sli@alpha#1#2\@nil#3#4\@nil{% \@ifbothonechar{#1}{#3}{% \sli@alpha@bothonechar#1{#2}#3{#4}% }{% % Group found inside argument. Expand it. \sli@alpha#1#2\@nil#3#4\@nil }% } \def\sli@alpha@bothonechar#1#2#3#4{% \ifcat\noexpand#3\relax % #3 is a control sequence, but not \sli@stop \expandafter\sli@alpha@chkthree \else \expandafter\sli@alpha@onecs \fi % Args to whichever command is chosen #1{#2}#3{#4}% } \def\sli@alpha@onecs#1{% \ifcat\noexpand#1\relax \expandafter\sli@alpha@chkone \else \expandafter\sli@alpha@chars \fi #1% Put it back onto token list } \def\sli@alpha@chkone#1#2#3#4{% \ifx#1\sli@stop \CompReversefalse \else \@skipafi{\sli@alpha#2\@nil#3#4\@nil}% \fi } \def\sli@alpha@chkthree#1#2#3#4{% \ifx#3\sli@stop \CompReversetrue \else \@skipafi{\sli@alpha#1#2\@nil#4\@nil}% \fi } \def\sli@alpha@chars#1#2#3#4{% % Both #1 and #3 are characters. \@test\ifnum`#1>`#3 \fi{% % First char is greater than second \CompReversetrue }{% \@test\ifnum`#1=`#3 \fi{% % Chars are equal. \sli@alpha#2\@nil#4\@nil }{% % Second char is greater than the first. \CompReversefalse }% }% } \def\ShowList#1{% \def\sli@act{\expandafter\the\csname sli@@#1\endcsname}% \afterassignment\sli@act\def\sli@do##1% } \endinput