# Listing in a command error: Text dropped after begin of listing on input line

While I wanted to test some alignment options to ask another question regarding to listings, I have encountered a problem that I was not expecting.

Consider the following code:

% Preamble
\documentclass[letterpaper, 10pt, onecolumn]{article}

% Packages
\usepackage{listings}

% Lst options
\lstset{
language = C++,
frame = lines,
framesep = 0pt,
rulesep = 0pt,
aboveskip = 0pt,
belowskip = 0pt,
}

% Commands
\newcommand{\alphabet}{ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz}
\newcommand{\makelisting}[1]{
\newpage\noindent\alphabet
\begin{lstlisting}[basicstyle = \fontfamily{cmtt}\selectfont#1]
int main(int argc, char* argv[])
{
return 0;
}
\end{lstlisting}
\alphabet
}

% Document
\begin{document}
\makelisting{\tiny}
\makelisting{\scriptsize}
\makelisting{\footnotesize}
\makelisting{\small}
\makelisting{\normalsize}
\makelisting{\large}
\makelisting{\Large}
\makelisting{\LARGE}
\makelisting{\huge}
\makelisting{\Huge}
\end{document}


It should be pretty straightforward. However, I end up with the following error:

Package Listings Warning: Text dropped after begin of listing on input line 32.


and no file is produced. Where this is coming from, and how to make it work?

• Maybe you are interested in Why can lstlisting not be saved in a command? – leandriis Apr 22 at 16:59
• As leandriis mentions, listings like all other verbatim like constructions cannot be used inside macros. – daleif Apr 22 at 17:01
• Is there a way to pass an argument (here the size) to a savebox? How can I do the thing I want to do using savebox? (I would validate an answer that would do that) – Vincent Apr 22 at 17:03

I see no other way than to save the sample code in a file.

\begin{filecontents*}{\jobname-sample.c}
int main(int argc, char* argv[])
{
return 0;
}
\end{filecontents*}

\documentclass{article}

% Packages
\usepackage{listings}

% Lst options
\lstset{
language = C++,
frame = lines,
framesep = 0pt,
rulesep = 0pt,
aboveskip = 0pt,
belowskip = 0pt,
}

% Commands
\newcommand{\alphabet}{ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz}
\newcommand{\makelisting}[1]{%
\bigskip\noindent\alphabet
\lstinputlisting[basicstyle = \fontfamily{cmtt}\selectfont#1]{\jobname-sample.c}
\alphabet\par
}

% Document
\begin{document}
\makelisting{\tiny}
\makelisting{\scriptsize}
\makelisting{\footnotesize}
\makelisting{\small}
\makelisting{\normalsize}
\makelisting{\large}
\makelisting{\Large}
\makelisting{\LARGE}
\makelisting{\huge}
%\makelisting{\Huge}
\end{document}


What you can do is have LaTeX read and tokenize your code listing under verbatim category code régime and pass it into the definition of \makelisting wrapped into a call to \scantokens.

For having LaTeX read and tokenize things under verbatim category code régime I often use my routine \UDcollectverbarg which has the following syntax:

\UDcollectverbarg{⟨^^M-replacement⟩}{⟨Mandatory 1⟩}{⟨Mandatory 2⟩}⟨verbatimized argument⟩

This yields:

⟨Mandatory 1⟩{⟨Mandatory 2⟩{⟨verbatimized argument⟩}}

, with each character ^^M that denotes an end of a line being replaced by the token-sequence ⟨^^M-replacement⟩.

The arguments ⟨Mandatory 1⟩ and ⟨Mandatory 2⟩ are mandatory. If they consist of several tokens, they must be nested into a catcode-1/2-character-pair / into braces.
If reading and tokenizing is necessary for obtaining some of them, this will take place under unchanged category code régime.
The ⟨verbatimized argument⟩ is also mandatory. It is to be read and tokenized from the .tex-input file under verbatim category code régime. If its first character is a brace, it will be "assumed" that that argument is nested into braces. Otherwise it will be assumed, that the ending of that argument is delimited by that first character—like the argument of \verb.
Empty-lines will not be ignored.

I chose this syntax as with this syntax you can collect verbatimized arguments within the ⟨Mandatory 2⟩-argument by nesting calls to \UDcollectverbarg within \UDcollectverbarg's ⟨Mandatory 1⟩-argument.

E.g.,

\UDcollectverbarg{⟨^^M-replacement⟩}%
{\UDcollectverbarg{⟨^^M-replacement⟩}{\UDcollectverbarg{⟨^^M-replacement⟩}{⟨actionA⟩}}}%  <- Mandatory 1
{⟨actionB⟩}%                     <- Mandatory 2
⟨verbatimized argument 1⟩⟨verbatimized argument 2⟩⟨verbatimized argument 3⟩

yields:

\UDcollectverbarg{⟨^^M-replacement⟩}{\UDcollectverbarg{⟨^^M-replacement⟩}{⟨actionA⟩}}% <- Mandatory 1
{⟨actionB⟩{⟨verbatimized argument 1⟩}}%        <- Mandatory 2
⟨verbatimized argument 2⟩⟨verbatimized argument 3⟩

yields:

\UDcollectverbarg{⟨^^M-replacement⟩}{⟨actionA⟩}% <- Mandatory 1
{⟨actionB⟩{⟨verbatimized argument 1⟩}{⟨verbatimized argument 2⟩}}% <- Mandatory 2
⟨verbatimized argument 3⟩

yields:

⟨actionA⟩{⟨actionB⟩{⟨verbatimized argument 1⟩}{⟨verbatimized argument 2⟩}{⟨verbatimized argument 3⟩}}

Assume ⟨actionA⟩ = \@firstofone:

\@firstofone{⟨actionB⟩{⟨verbatimized argument 1⟩}{⟨verbatimized argument 2⟩}{⟨verbatimized argument 3⟩}}

yields:

⟨actionB⟩{⟨verbatimized argument 1⟩}{⟨verbatimized argument 2⟩}{⟨verbatimized argument 3⟩}

Here comes the example:

% Preamble
\documentclass[letterpaper, 10pt, onecolumn]{article}

% Adjust horizontal margins so that listings in \Huge fits on paper also:
\makeatletter
\setlength\evensidemargin{2.2cm}%
\setlength\marginparsep{.25\evensidemargin}%
\setlength\marginparwidth{.5\evensidemargin}%
\setlength\oddsidemargin{\if@twoside.5\fi\evensidemargin}%
\setlength\textwidth\paperwidth
\@ifundefined{pdfpagewidth}{}{\setlength\pdfpagewidth{\paperwidth}}%
\@ifundefined{pdfpageheight}{}{\setlength\pdfpageheight{\paperheight}}%
\@ifundefined{pagewidth}{}{\setlength\pagewidth{\paperwidth}}%
\@ifundefined{pageheight}{}{\setlength\pageheight{\paperheight}}%
\makeatother

% Packages
\usepackage{listings}

% Lst options
\lstset{
language = C++,
frame = lines,
framesep = 0pt,
rulesep = 0pt,
aboveskip = 0pt,
belowskip = 0pt,
}

% Commands
\newcommand{\alphabet}{ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz}

%%<..................Paraphernalia.....................................>
\makeatletter
\newcommand\UD@firstofone[1]{#1}%
\newcommand\UD@firstoftwo[2]{#1}%
\newcommand\UD@secondoftwo[2]{#2}%
%%<-------------------- Code for \UDcollectverbarg -------------------->
%% Check whether argument is empty:
%%......................................................................
%% \UD@CheckWhetherNull{<Argument which is to be checked>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is empty>}%
%%                     {<Tokens to be delivered in case that argument
%%                       which is to be checked is not empty>}%
%% The gist of this macro comes from Robert R. Schneck's \ifempty-macro:
\newcommand\UD@CheckWhetherNull[1]{%
\romannumeral0\expandafter\UD@secondoftwo\string{\expandafter
\UD@secondoftwo\expandafter{\expandafter{\string#1}\expandafter
\UD@secondoftwo\string}\expandafter\UD@firstoftwo\expandafter{\expandafter
\UD@secondoftwo\string}\expandafter\expandafter\UD@firstoftwo{ }{}%
\UD@secondoftwo}{\expandafter\expandafter\UD@firstoftwo{ }{}\UD@firstoftwo}%
}%
%%......................................................................
\begingroup
\catcode\^^M=12 %
\UD@firstofone{%
\endgroup%
\newcommand\UDEndlreplace[2]{\romannumeral0\@UDEndlreplace{#2}#1^^M\relax{}}%
\newcommand*\@UDEndlreplace{}%
\long\def\@UDEndlreplace#1#2^^M#3\relax#4#5{%
\UD@CheckWhetherNull{#3}%
{ #5{#4#2}}{\@UDEndlreplace{#1}#3\relax{#4#2#1}{#5}}%
}%
}%
\newcommand\UDcollectverbarg[3]{%
\begingroup
\let\do\@makeother % <- this and the next line switch to
\dospecials        %    verbatim-category-code-régime.
\catcode\{=1      % <- give opening curly brace the usual catcode so a
%    curly-brace-balanced argument can be gathered in
%    case of the first thing of the verbatimized-argument
%    being a curly opening brace.
\catcode\ =10     % <- give space and horizontal tab the usual catcode so \UD@collectverbarg
\catcode\^^I=10   %    cannot catch a space or a horizontal tab as its 4th undelimited argument.
%    (Its 4th undelimited argument denotes the verbatim-
%     syntax-delimiter in case of not gathering a
%     curly-brace-nested argument.)
\kernel@ifnextchar\bgroup
{% seems a curly-brace-nested argument is to be caught:
\catcode\}=2    % <- give closing curly brace the usual catcode also.
\UD@collectverbarg{#1}{#2}{#3}{}%
}{% seems an argument with verbatim-syntax-delimiter is to be caught:
\do\{% <- give opening curly brace the verbatim-catcode again.
\UD@collectverbarg{#1}{#2}{#3}%
}%
}%
\newcommand\UD@collectverbarg[4]{%
\do\ %   <- Now that \UD@collectverbarg has the delimiter or
\do\^^I%    emptiness in its 4th arg, give space and horizontal tab
%    the verbatim-catcode again.
\do\^^M% <- Give the carriage-return-character the verbatim-catcode.
\long\def\@tempb##1#4{%
%\edef\@tempb{##1}%
\def\@tempb{##1}%
\@onelevel@sanitize\@tempb % <- Turn characters into their "12/other"-pendants.
%    This may be important with things like the
%    inputenc-package which may make characters
%    active/which give them catcode 13(active).
\expandafter\UDEndlreplace\expandafter{\@tempb}{#1}{\def\@tempb}% <- this starts
%    the loop for replacing endline-characters.
\expandafter\UD@@collectverbarg\expandafter{\@tempb}{#2}{#3}% <- this "spits
%    out the result.
}%
\@tempb
}%
\newcommand\UD@@collectverbarg[3]{%
\endgroup
#2{#3{#1}}%
}%
\makeatother
%%<---------------- End of code for \UDcollectverbarg ----------------->

\makeatletter
\begingroup
\newcommand\makelisting[2]{%
\endgroup
\newcommand\makelisting[1]{%
\newpage
\noindent\alphabet
\scantokens{%
\par\noindent #1##1#2%
}%
\alphabet
}%
}%
\UDcollectverbarg{^^J}%
{%
\UDcollectverbarg{^^J}%
{\UD@firstofone}%
}%
{\makelisting}|\begin{lstlisting}[basicstyle = \fontfamily{cmtt}\selectfont||]
int main(int argc, char* argv[])
{
return 0;
}
\end{lstlisting}
%|

\makeatother

%\show\makelisting

\begin{document}
\makelisting{\tiny}
\makelisting{\scriptsize}
\makelisting{\footnotesize}
\makelisting{\small}
\makelisting{\normalsize}
\makelisting{\large}
\makelisting{\Large}
\makelisting{\LARGE}
\makelisting{\huge}
\makelisting{\Huge}
\end{document}
`