Saving arguments of commands to be used later

I have made it so that \@name[<index>] \@work[<index>], and \@email[<index>] are arrays, where the index is stepped with every call to \information{}{}{}.

\listcontact{<index>} will provide the contact info for the one specified index. In the MWE, I loop through all indices.

\documentclass{article}
\usepackage{pgffor}
\makeatletter
\newcounter{infocnt}
\newcommand{\name}[1]{%
  \expandafter\def\csname @name[\theinfocnt]\endcsname{#1}}
\newcommand{\work}[1]{%
  \expandafter\def\csname @work[\theinfocnt]\endcsname{#1}}
\newcommand{\email}[1]{%
  \expandafter\def\csname @email[\theinfocnt]\endcsname{#1}}
\newcommand{\information}[3]{%
  \stepcounter{infocnt}%
  \name{#1}%
  \work{#2}%
  \email{#3}%
}
\newcommand\listcontact[1]{\noindent%
  NAME: \textbf{\csname @name[#1]\endcsname}\\
  WORK: \textbf{\csname @work[#1]\endcsname}\\
  EMAIL: \textbf{\csname @email[#1]\endcsname}\par
  \vskip 1in
}
\makeatother
\information{Faa Foo}{Univ.\ Blah}{[email protected]}
\information{XXX}{YYY}{[email protected]}
\begin{document}
\foreach\x in {1,2,...,\theinfocnt}{\listcontact{\x}}
\end{document}

enter image description here

If I had my 'druthers, though, I would input the list all at once, quite simply, with the same output. The listofitems package immediately stores the list as an accessible array:

\documentclass{article}
\usepackage{listofitems}
\newcommand\listcontact[1]{\noindent%
  NAME: \textbf{\contacts[#1,1]}\\
  WORK: \textbf{\contacts[#1,2]}\\
  EMAIL: \textbf{\contacts[#1,3]}\par
  \vskip 1in
}
\setsepchar{\\/&}
\begin{document}
\readlist*\contacts{
 Faa Foo & Univ.\ Blah & [email protected]\\
 XXX & YYY & [email protected]}
\foreachitem\x\in\contacts[]{\listcontact{\xcnt}}

Here is the email of contact 2: \contacts[2,3].
\end{document}

enter image description here

With a small supplement from the readarray package, the list of contacts could even be stored in an external file.


This is “property lists” playground. Here I define \newcontact for defining a contact with a key-value interface.

With \newcontactscheme one defines different ways to print the data; default is used by \listcontact if no optional argument is supplied. In the definition, use \getcontact{<key>}{#1} to print the value corresponding to <key> for the current contact, represented by #1.

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newcontact}{mm}
 {% #1 = contact label, #2 = data
  \prop_new:c { g_sigur_contact_#1_prop }
  \prop_gset_from_keyval:cn { g_sigur_contact_#1_prop } { #2 }
 }
\NewDocumentCommand{\listcontact}{O{default}m}
 {
  \cs_set_eq:Nc \__sigur_contact_list:n { sigur_contact_list_#1:n }
  \__sigur_contact_list:n { #2 }
 }
\NewDocumentCommand{\getcontact}{mm}
 {
  \sigur_contact_print:nn { #1 } { #2 }
 }
\NewDocumentCommand{\newcontactscheme}{m+m}
 {% #1 = scheme name, #2 = definition
  \cs_new_protected:cn { sigur_contact_list_#1:n } { #2 }
 }
\cs_new_protected:Nn \sigur_contact_print:nn
 {
  \prop_item:cn { g_sigur_contact_#2_prop } { #1 }
 }
\ExplSyntaxOff

\newcontactscheme{default}{%
  \par\noindent
  \getcontact{name}{#1}\\
  \getcontact{work}{#1}\\
  \getcontact{email}{#1}\par
}
\newcontactscheme{short}{%
  \getcontact{name}{#1}, \getcontact{email}{#1}%
}
\newcontactscheme{alternate}{%
  \begin{tabular}[t]{@{}l@{ }l@{}}
  Name:  & \getcontact{name}{#1} \\
  Work:  & \getcontact{work}{#1} \\
  Email: & \texttt{\getcontact{email}{#1}}
  \end{tabular}%
}

\newcontact{foo}{
  name=Faa Foo,
  work=Univ.\ Blah,
  [email protected]
}
\newcontact{xxx}{
  name=XXX,
  work=YYY,
  [email protected]
}

\begin{document}

\listcontact{foo}

\medskip

\listcontact{xxx}

\medskip

Short: \listcontact[short]{xxx}

\medskip

Alternate: \listcontact[alternate]{foo}

\end{document}

enter image description here

A version that also defines \listallcontacts (the optional argument is one of the defined schemes).

\documentclass{article}
\usepackage{xparse}

\ExplSyntaxOn

\NewDocumentCommand{\newcontact}{mm}
 {% #1 = contact label, #2 = data
  \prop_new:c { g_sigur_contact_#1_prop }
  \prop_gset_from_keyval:cn { g_sigur_contact_#1_prop } { #2 }
  \seq_gput_right:Nn \g_sigur_contact_seq { #1 }
 }
\NewDocumentCommand{\listcontact}{O{default}m}
 {
  \cs_set_eq:Nc \__sigur_contact_list:n { sigur_contact_list_#1:n }
  \__sigur_contact_list:n { #2 }
 }
\NewDocumentCommand{\listallcontacts}{O{default}}
 {
  \cs_set_eq:Nc \__sigur_contact_list:n { sigur_contact_list_#1:n }
  \seq_map_inline:Nn \g_sigur_contact_seq
   {
    \__sigur_contact_list:n { ##1 } \par
   }
 }
\NewDocumentCommand{\getcontact}{mm}
 {
  \sigur_contact_print:nn { #1 } { #2 }
 }
\NewDocumentCommand{\newcontactscheme}{m+m}
 {% #1 = scheme name, #2 = definition
  \cs_new_protected:cn { sigur_contact_list_#1:n } { #2 }
 }

\seq_new:N \g_sigur_contact_seq

\cs_new_protected:Nn \sigur_contact_print:nn
 {
  \prop_item:cn { g_sigur_contact_#2_prop } { #1 }
 }
\ExplSyntaxOff

\newcontactscheme{default}{%
  \par\noindent
  \getcontact{name}{#1}\\
  \getcontact{work}{#1}\\
  \getcontact{email}{#1}\par
}
\newcontactscheme{short}{%
  \getcontact{name}{#1}, \getcontact{email}{#1}%
}
\newcontactscheme{alternate}{%
  \begin{tabular}[t]{@{}l@{ }l@{}}
  Name:  & \getcontact{name}{#1} \\
  Work:  & \getcontact{work}{#1} \\
  Email: & \texttt{\getcontact{email}{#1}}
  \end{tabular}%
}

\newcontact{foo}{
  name=Faa Foo,
  work=Univ.\ Blah,
  [email protected]
}
\newcontact{xxx}{
  name=XXX,
  work=YYY,
  [email protected]
}

\begin{document}

\listcontact{foo}

\medskip

\listcontact{xxx}

\medskip

Short: \listcontact[short]{xxx}

\medskip

Alternate: \listcontact[alternate]{foo}

\medskip

\listallcontacts

\medskip

\listallcontacts[short]

\end{document}

This is similar to Steven Seglets solution with slightly different packaging. You can show a single contact with \ShowContact{} or list all the contact with \listcontacts

enter image description here

Notes:

  • The values are stored based on #1 which is used as the key to access the contacts. An attempt to reuse the same key is now flagged as an error.
  • This has now been updated to add a \medskip between entries when the entire list is printed. The \medskip is not added before the first entry, nor after the last as shown in the figure.

Code:

\documentclass{article}
\usepackage{etoolbox}

\makeatletter

\newtoggle{@IsFirstEntryInList}

\newcommand*{\@ShowContact}[1]{%
    \iftoggle{@IsFirstEntryInList}{%
        \global\togglefalse{@IsFirstEntryInList}%
    }{%
        \medskip% <-- separator between entries
    }%
    \ShowContact{#1}%
}
\newcommand*{\ShowContact}[1]{%
    \par\noindent\textbf{\csuse{name #1}}%
    \par\noindent\textit{\csuse{work #1}}%
    \par\noindent\texttt{\csuse{email #1}}%
}%

%% https://tex.stackexchange.com/a/14394/4301
\newcommand*{\listcontacts}{% Initialize
    \global\toggletrue{@IsFirstEntryInList}%
}
\newcommand{\AddToListOfContacts}[1]{%
    \g@addto@macro\listcontacts{{#1}}%
}


\newcommand{\information}[3]{%
    \ifcsdef{name #1}{%
        \PackageError{\jobname}{Multiple uses of the key: '#1'}{}%
    }{%
        \csdef{name #1}{#1}%
        \csdef{work #1}{#2}%
        \csdef{email #1}{#3}%
        \AddToListOfContacts{\unexpanded{\@ShowContact{#1}}}%
    }%
}
\makeatother

\information{Faa Foo}{Univ.\ Blah}{[email protected]}
\information{Harvard}{Harvard University}{[email protected]}
%\information{Harvard}{xxx University}{[email protected]}% <-- Triggers an error

\begin{document}
\noindent
To show one contact:

\ShowContact{Harvard}

\medskip\noindent
To show all contacts:

\listcontacts
\par\noindent
Text following to check that there is no extra space at end...
\end{document}

Tags:

Macros