From 3303a89b11161d66ec78811056b85306f696cc09 Mon Sep 17 00:00:00 2001
From: Norbert Preining <norbert@preining.info>
Date: Wed, 14 Jul 2021 03:01:33 +0000
Subject: CTAN sync 202107140301

---
 macros/latex/contrib/macrolist/macrolist.dtx | 325 +++++++++++++++++++++++++++
 1 file changed, 325 insertions(+)
 create mode 100644 macros/latex/contrib/macrolist/macrolist.dtx

(limited to 'macros/latex/contrib/macrolist/macrolist.dtx')

diff --git a/macros/latex/contrib/macrolist/macrolist.dtx b/macros/latex/contrib/macrolist/macrolist.dtx
new file mode 100644
index 0000000000..9c0ee6eb62
--- /dev/null
+++ b/macros/latex/contrib/macrolist/macrolist.dtx
@@ -0,0 +1,325 @@
+% \iffalse meta-comment
+%
+% Copyright (C) 2021 Dennis Chen <proofprogram@gmail.com>
+%
+% This file may be distributed and/or modified under
+% the conditions the LaTeX Project Public License (LPPL),
+% either version 1.3 of this license or (at your option)
+% any later version. The latest version of this license
+% can be found 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.
+% \fi
+%
+% \iffalse
+%<*package>
+
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{macrolist}[2021/07/09 v1.0.0 Create lists of macros and perform operations on them]
+
+\RequirePackage{pgffor}
+%</package>
+
+%<*driver>
+\documentclass{ltxdoc}
+\usepackage{macrolist}
+\EnableCrossrefs
+\CodelineIndex
+\RecordChanges
+\begin{document}
+    \DocInput{macrolist.dtx}
+    \PrintIndex
+\end{document}
+%</driver>
+% \fi
+% \changes{v1.0.0}{2021/07/01}{Initial version}
+%
+% \GetFileInfo{macrolist.sty}
+%
+% \title{\textsf{macrolist} -- Create lists of macros and manipulate them}
+% \author{Dennis Chen \\ proofprogram@gmail.com}
+% \date{\fileversion, v. \filedate\thanks{\url{https://github/com/chennisden/macrolist}}}
+%
+% \maketitle
+%
+% \begin{abstract}
+% The \textsf{macrolist} package allows you to create lists and manipulate them, with utilities such as |\listforeach| and an implementation of arr.join() from Javascript. Contrary to the name of the package, non-macros and groups of macros can be put into an item of the list.
+% \end{abstract}
+%
+% \section{Usage}
+%
+% \DescribeMacro{\newlist}
+% To create a list, pass in |\newlist{listname}| to create a list with the name \textsf{listname}.
+%
+% The package checks that \textsf{listname} is not the name of another list, and will throw an error if another list \textsf{listname} has already been defined.
+%
+% \iffalse
+\newcommand{\newlist}[1]{
+    \ifcsname c@macrolist@list@#1\endcsname
+        \PackageError{macrolist}{The list '#1' is already defined}{}
+    \else
+        \newcounter{macrolist@list@#1}
+        \setcounter{macrolist@list@#1}{0}
+    \fi
+}
+% \fi
+%
+% \DescribeMacro{\listelement}
+%
+% To execute the \textsf{i}th element of \textsf{listname}, write |\listelement{listname}{i}|. Note that \textit{lists are 1-indexed}, meaning the first element is numbered 1, the second element numbered 2, and so on.
+%
+% An error will be thrown if \textsf{listname} is not a defined list, if \textsf{i} is empty, or if \textsf{i} is greater than the size of the list.
+%
+% \iffalse
+\newcommand{\listelement}[2]{%
+    \macrolist@inbounds{#1}{#2}%
+    \csname macrolist@list@#1\the\numexpr #2\relax\endcsname%
+}
+% \fi
+%
+% \DescribeMacro{\listadd}
+%
+% To add something to the list \textsf{listname}, pass in |\listadd{listname}[position]{element}|, where \textsf{position} is an optional argument. If nothing is passed in for \textsf{position}, then by default \textsf{element} will be added to the end of the list.
+%
+% \iffalse
+\newcommand{\listadd}[1]{
+    \macrolist@exists{#1}
+    \def\macrolist@currlist{#1}
+    \macrolist@listadd
+}
+%% We write \listadd this way such that the optional argument will be positioned correctly
+\newcommand{\macrolist@listadd}[2][]{
+    \stepcounter{macrolist@list@\macrolist@currlist}
+
+    \if\relax\detokenize{#1}\relax
+        \expandafter\def\csname macrolist@list@\macrolist@currlist\listsize{\macrolist@currlist}\endcsname{#2}
+    \else
+        \expandafter\ifnum\csname themacrolist@list@\macrolist@currlist\endcsname=#1
+            \expandafter\def\csname macrolist@list@\macrolist@currlist\listsize{\macrolist@currlist}\endcsname{#2}
+        \else
+            \macrolist@inbounds{\macrolist@currlist}{#1}
+            \foreach \macrolist@index in {\listsize{\macrolist@currlist}, ...,\the\numexpr #1+1\relax} {
+                \global\expandafter\let\csname macrolist@list@\macrolist@currlist\macrolist@index\expandafter\endcsname\csname macrolist@list@\macrolist@currlist\the\numexpr\macrolist@index-1\relax\endcsname
+            }
+            \expandafter\def\csname macrolist@list@\macrolist@currlist#1\endcsname{#2}
+        \fi
+    \fi
+}
+% \fi
+%
+% \DescribeMacro{\listremove}
+%
+% To remove an element in a list, write |\listremove{listname}{index}|.
+%
+% \iffalse
+\newcommand{\listremove}[2]{
+    \macrolist@inbounds{#1}{#2}
+
+    \ifnum\numexpr#2\relax=\listsize{#1}
+    \else
+        \foreach \macrolist@index in {#2, ..., \the\numexpr\listsize{#1}-1\relax} {
+            \global\expandafter\let\csname macrolist@list@#1\macrolist@index\expandafter\endcsname\csname macrolist@list@#1\the\numexpr\macrolist@index+1\endcsname
+        }
+    \fi
+
+    \expandafter\let\csname macrolist@list@#1\listsize{#1}\endcsname\relax
+    \addtocounter{macrolist@list@#1}{-1}
+}
+% \fi
+%
+% \DescribeMacro{\listremovelast}
+%
+% To remove the last element in a list, write |\listremovelast{listname}|. This behaves like C++'s |pop_back|.
+%
+% \iffalse
+\newcommand{\listremovelast}[1]{
+    \macrolist@exists{#1}
+    \expandafter\let\csname macrolist@list@#1\listsize{#1}\endcsname\relax
+    \addtocounter{macrolist@list@#1}{-1}
+}
+% \fi
+%
+% \DescribeMacro{\listclear}
+%
+% To clear a list, write |\listclear{listname}|.
+%
+% \iffalse
+\newcommand{\listclear}[2]{
+    \macrolist@inbounds{#1}{#2}
+
+    \foreach \macrolist@index in {1, ..., \listsize{#1}} {
+        \expandafter\let\csname \macrolist@list@#1\macrolist@index\endcsname\relax
+    }
+
+    \setcounter{macrolist@list@#1}{0}
+}
+% \fi
+%
+% \DescribeMacro{\listsize}
+%
+% To get the size of a list, write |\listsize{listname}|.
+%
+% \iffalse
+\newcommand*{\listsize}[1]{%
+    \macrolist@exists{#1}%
+    \csname themacrolist@list@#1\endcsname
+}
+% \fi
+%
+% \DescribeMacro{\listforeach}
+%
+% To write a for each loop, write
+% \begin{verbatim}
+%\begin{listforeach}{listname}{\element}[begin][end]{action}
+% \end{verbatim}
+%
+%
+% Note that begin and end are optional arguments, and by default, they take the values \textsf{1} and |\listsize{listname}|. If you pass in \textsf{begin}, you must also pass in \textsf{end}.
+%
+% \iffalse
+\newcommand{\listforeach}[2]
+{
+    \def\macrolist@foreachstart{0} % Reset
+    % This is used to make optional arguments line up correctly
+
+    \def\macrolist@start{1}
+    \def\macrolist@end{\listsize{#1}}
+    \def\macrolist@listname{#1}
+    \def\macrolist@element{#2}
+    \macrolist@listforeachi
+}
+
+\newcommand{\macrolist@listforeachi}[1][]{
+    \if\relax\detokenize{#1}\relax
+    \else
+        \def\macrolist@start{#1}
+        \def\macrolist@foreachstart{1}
+    \fi
+    \macrolist@listforeachii
+}
+
+\newcommand{\macrolist@listforeachii}[1][]{
+    \if\relax\detokenize{#1}\relax
+        \ifnum\macrolist@foreachstart=1
+            \PackageError{macrolist}{You must either pass in both a starting and ending position or neither}{}
+        \fi
+    \else
+        \def\macrolist@end{#1}
+    \fi
+    \macrolist@listforeachaction
+}
+
+\newcommand{\macrolist@listforeachaction}[1]{
+
+    \macrolist@exists{\macrolist@listname}
+
+    \ifnum\numexpr\macrolist@start\relax>\listsize{\macrolist@listname}%
+        \PackageError{macrolist}{The starting index of the loop is out of the bounds of list '\macrolist@listname'}{}
+    \fi
+
+    \ifnum\numexpr\macrolist@end\relax>\listsize{\macrolist@listname}
+        \PackageError{macrolist}{The ending index of the loop is out of the bounds of list '\macrolist@listname'}{}
+    \fi
+
+    \foreach \macrolist@index in {\the\numexpr\macrolist@start\relax, ..., \the\numexpr\macrolist@end\relax} {%
+        \expandafter\expandafter\expandafter\let\expandafter\expandafter\macrolist@element\csname macrolist@list@\macrolist@listname\macrolist@index\endcsname
+        #1%
+    }%
+}
+% \fi
+%
+% \DescribeMacro{\listjoin}
+%
+% Executing |\listjoin{listname}{joiner}| returns all of the elements separated by \textsf{joiner}. This behaves like Javascript's \textsf{arr.join()}.
+%
+% \iffalse
+\newcommand{\listjoin}[2]{%
+    \ifnum\listsize{#1}>1
+        \listforeach{#1}{\macrolist@joinelement}[1][\listsize{#1}-1]{\macrolist@joinelement#2}%
+    \fi
+    \ifnum\listsize{#1}>0
+        \listelement{#1}{\listsize{#1}}%
+    \fi
+}
+% \fi
+%
+% \section{Example}
+% Here is the source code for a small document using \textsf{macrolist}.
+%
+% \begin{verbatim}
+%\documentclass{article}
+%\usepackage{macrolist}
+%
+%\begin{document}
+%
+%\newlist{mylist}
+%\listadd{mylist}{Some text}
+%% List: Some text
+%
+%\newcommand\macro{This is a macro}
+%
+%\listadd{mylist}{\macro}
+%% List: Some text, \macro
+%
+%\listelement{mylist}{1}
+%% Prints out "Some text"
+%
+%\listadd{mylist}[1]{Element inserted into beginning}
+%% List: Element inserted into beginning, Some text, \macro
+%
+%\listremove{mylist}{1}
+%% List: Some text, \macro
+%
+%\listforeach{mylist}{\element}{We're printing out \textbf{\element}. }
+%% We're printing out \textbf{Some text}. We're printing out \textbf{\macro}.
+%
+%\listjoin{mylist}{, }
+%% Some text, \macro
+%
+%\end{document}
+% \end{verbatim}
+%
+% \section{Implementation details}
+%
+% All internal macros are namespaced to prevent package conflicts.
+%
+% \begin{macro}{\macrolist@exists}
+% One internal macro we use is |\macrolist@exists{listname}|, which checks that \textsf{listname} exists. It throws an error otherwise.
+%
+%    \begin{macrocode}
+\newcommand*{\macrolist@exists}[1]{%
+    \ifcsname c@macrolist@list@#1\endcsname
+    \else
+        \PackageError{macrolist}
+        {The first argument is not a defined list}
+        {Make sure you have defined the list before trying to operate on it.}
+    \fi
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\macrolist@inbounds}
+% We use |\macrolist@inbounds{listname}{index}| to check that first, \textsf{listname} is a defined list using |\macrolist@exists|, and second, that \textsf{index} is within bounds. It throws an error otherwise.
+%    \begin{macrocode}
+\newcommand*{\macrolist@inbounds}[2]{%
+    \macrolist@exists{#1}%
+    %
+    \if\relax\detokenize{#2}
+        \PackageError{macrolist}
+        {No number has been passed into the second argument of your command
+        }{Pass in a number to the second argument of your command.}
+    \fi
+    %
+    \ifnum\numexpr#2 \relax>\listsize{#1}
+        \PackageError{macrolist}
+        {Index out of bounds}
+        {The number you have passed in to the second argument of your command\MessageBreak
+        is out of the bounds of list '#1'.}
+    \fi
+}
+%    \end{macrocode}
+% \end{macro}
+%
+% \Finale
+\endinput
\ No newline at end of file
-- 
cgit v1.2.3

