1

I'd like to know how to create a macro that can append new elements/items to a macro list (token list) BUT also adds { and } around each added item.

Example I'd like it to save each new item like this:

\appendtocslist{tokenlist}{newitem} 

yields {newitem} in the list.

Why Because I can easily parse the list with \readcslist.

I am not sure if also separating each value with a comma (or some other separator) is necessary.

Append to Command Sequence (CS) List

  • Smart enough to initiate a new macro if none exist iwth does not exist.
  • It uses csname to allow for dynamic macro names.
  • It currently uses a trailing comma character , as a separator/delimiter.

Code

\long\def\appendtocslist#1#2{% #1 = List ID (no backslash) #2=New Item to Append % I chose this complicated csname form of the list-making because it can accept dynamic csnames using counters \expandafter\ifx\csname#1\endcsname\relax\expandafter\xdef\csname#1\endcsname{#2,}\else% Macro Existence Check \expandafter\xdef\csname#1\expandafter\expandafter\expandafter\endcsname \expandafter\expandafter\expandafter {\csname #1\endcsname#2,}\fi%Append expansion of #1 with #2, delimit with ,. ^^J appears as newline in terminal or space when typeset and does not work as a delimiter }% 

Code

\documentclass{article} \usepackage{fontspec}% xelatex \makeatletter \long\def\appendtocslist#1#2{% #1 = List ID (no backslash) #2=New Item to Append % I chose this complicated csname form of the list-making because it can accept dynamic csnames using counters \expandafter\ifx\csname#1\endcsname\relax\expandafter\xdef\csname#1\endcsname{#2,}\else% Macro Existence Check \expandafter\xdef\csname#1\expandafter\expandafter\expandafter\endcsname \expandafter\expandafter\expandafter {\csname #1\endcsname#2,}\fi%Append expansion of #1 with #2, delimit with ,. ^^J appears as newline in terminal or space when typeset and does not work as a delimiter }% \long\def\readcslist#1{% \@tempcnta=1% \checknextarg% } \long\def\checknextarg{% % My job is to check for another arg and trigger a recursive cycle. % for \@ifnextchar to check, so we say \bgroup, which means literal { % I am only important if there are exactly two args. \@ifnextchar\bgroup{\recursivecycle}{\advance\@tempcnta1\finalcall}% \@ifnextchar ignores spaces } \long\def\recursivecycle#1{% % My job is to eat each argument recursively until I % cannot find any more { characters. I ignore spaces. % If I reach the end, I run whatever is in false area of \@ifnextchar \advance\@tempcnta by 1% add one for next arg \@ifnextchar\bgroup{\recursivecycle}{\finalcall}} \def\finalcall{Total n of args: \the\@tempcnta} \makeatother \begin{document} Hello. \appendtocslist{mylist}{a} \appendtocslist{mylist}{b} \appendtocslist{mylist}{c} \readcslist{d}{e}{f} % \expandafter\readargs\expandafter{\mylist} % wouldn't this be nice!% \end{document} 
10
  • Do you want also the comma? Commented Feb 1, 2018 at 15:03
  • @egreg Glad you asked first. What do you recommend from your knowledge of dealing with these things? Is it necessary if I have everything surrounded in braces for future manipulation e.g. element extraction or prepending/appending new elements? Commented Feb 1, 2018 at 15:03
  • 1
    I would avoid to reinvent the wheel and use expl3. And definitely not absorb items until no more { are found. This is very dangerous and useless: \readcslist{{a}{b}{c}} is much simpler and safer. Commented Feb 1, 2018 at 15:08
  • @egreg I was trying to avoid expl3, not to undermind the project or your efforts. Commented Feb 1, 2018 at 15:13
  • What's the connection between \appendtocslist and \readcslist? I see none. Commented Feb 1, 2018 at 15:14

2 Answers 2

1
\documentclass{article} \makeatletter % syntactic sugar \def\expandtwice{\unexpanded\expandafter\expandafter\expandafter} % append to list (or create it) \newcommand\appendtocslist[2]{% % #1 = Macro Name without \ (list name), #2=New Item to Append \ifcsname#1\endcsname \expandafter\xdef\csname#1\endcsname{% % the previous items \expandtwice{\csname#1\endcsname}% % the new item {#2}% }% \else % the list doesn't exist yet, create it \expandafter\gdef\csname#1\endcsname{{#2}} \fi } % read n-argument types (ignoring spaces) \long\def\readcslist#1{% \@tempcnta=1 \checknextarg } \long\def\checknextarg{% \@ifnextchar\bgroup{\recursivecycle}{\finalcall}% } \long\def\recursivecycle#1{% \advance\@tempcnta by 1 % add one for next arg \checknextarg } \def\finalcall{Total n of args: \the\@tempcnta} \makeatother \begin{document} Hello. \appendtocslist{mylist}{a} \appendtocslist{mylist}{b} \appendtocslist{mylist}{c} \texttt{\expandafter\meaning\csname mylist\endcsname} \readcslist{d}{e}{f} \expandafter\readcslist\mylist \end{document} 

enter image description here

2
  • I just realized that \xdef should be \protected@xdef to maintain the effect of \protect when appending things like \textit or \textbf. Obviously, you used my minimal example, but I wanted to note this here for posterity. Commented Feb 28, 2018 at 14:49
  • @JonathanKomar Yes, that would be necessary if #2 contains “dangerous” items. Commented Feb 28, 2018 at 17:31
1

In response to the question "I'd like to know how to create a macro that can append new elements/items to a macro list (token list) BUT also adds { and } around each added item."

\documentclass{article} \usepackage[T1]{fontenc} \newtoks\mylist \newcommand\addtotoklist[2]{#1\expandafter{\the#1{#2}}} \begin{document} \addtotoklist\mylist{a} \addtotoklist\mylist{b} \addtotoklist\mylist{cde} \detokenize\expandafter{\the\mylist} \end{document} 

enter image description here

1
  • Good stuff. I think it helps to know that this is shortened form of \newcommand\addtotoklist[2]{#1=\expandafter{\the#1{#2}}} . In other words, skip ahead to expand the list as it is first, then put #2 after it, then the whole line of junk (tokens) will be assigned to #1. Commented Feb 3, 2018 at 17:15

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.