2

I want to read some lines from a text file, wrap a "style" which in this case is \texttt around each line, and as such concatenate it to a macro that I can use in the document. I came up with this MWE:

\documentclass{article}

\usepackage{filecontents} % tlmgr install filecontents

\begin{filecontents*}{test-2.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\usepackage{xstring}

\def\totcontent{}
\def\mystyle#1{\texttt{#1}}

% related: http://tex.stackexchange.com/questions/116078/expand-command-read-from-file
\newread\myread
\makeatletter
\immediate\openin\myread=test-2.txt
\@whilesw\unless\ifeof\myread\fi{%
  \readline\myread t\expandafter o\csname tmpline\endcsname %
  \typeout{Got tmpline: \tmpline} %
  \StrGobbleRight{\tmpline}{1}[\tmpline] % remove the ^^M newline (last 1 char)
  \ifx\tmpline\empty\else %
    %\edef\totcontent{\totcontent, \tmpline} % works without mystyle
    %\edef\totcontent{\totcontent, \mystyle{\tmpline}} % fail, breaks
    % via http://tex.stackexchange.com/a/74709/2595:
    \g@addto@macro\totcontent{, \mystyle{\tmpline}} % compiles, but no content in output
  \fi %
}
\immediate\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

In all cases, I get this for the file reading:

Got tmpline: some more^^M
Got tmpline: words in^^M
Got tmpline: here so as^^M
Got tmpline: to eventually^^M
Got tmpline: print^^M
Got tmpline: ^^M

... which means the line ending is kept, so I remove the character at the end of the "string" with xstring's \StrGobbleRight.

The first case, \edef\totcontent{\totcontent, \tmpline} works fine, but has no style - the typeout then says:

totcontent is: , some more, words in, here so as, to eventually, print.

The second case, \edef\totcontent{\totcontent, \mystyle{\tmpline}}, breaks completely:

! Argument of \@xs@StrGobbleRight has an extra }.
<inserted text> 
                \par 
l.30 }

Here I intended on using \mystyle as a placeholder macro - expecting that in concatenation \edefs it would expand down to \texttt tokens, which I remember are \protected, and so won't expand further. Obviously, that didn't work.

The third case, \g@addto@macro\totcontent{, \mystyle{\tmpline}} actually does compile, but gives:

totcontent is: , \texttt {}, \texttt {}, \texttt {}, \texttt {}, \texttt {}.

... which is close, but still not what I wanted (I wanted the \texttt to be populated by the respective arguments from the loop).

So, how can I perform the concatenation, so in the end I end up with:

totcontent is: , \texttt {some more}, \texttt {words in}, \texttt {here so as}, \texttt {to eventually}, \texttt {print}.

... such that it would also typeset as we'd expect it to?


As per comments, example with `\read`:

\documentclass{article}

\usepackage{filecontents} % tlmgr install filecontents

\begin{filecontents*}{test-2.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\def\totcontent{}
\def\mystyle#1{\texttt{#1}}

\newread\myread
\makeatletter
\immediate\openin\myread=test-2.txt
\@whilesw\unless\ifeof\myread\fi{%
  \read\myread to \tmpline %
  \typeout{Got tmpline: \tmpline} %
%   \ifx\tmpline\empty\else %
  \ifx\tmpline\par\else %
    %\edef\totcontent{\totcontent, \tmpline} % works without mystyle
    %\edef\totcontent{\totcontent, \mystyle{\tmpline}} % fail, breaks
    \g@addto@macro\totcontent{, \mystyle{\tmpline}} % compiles, but no content in output
  \fi %
}
\immediate\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

Prints:

Got tmpline: some more 
Got tmpline: words in 
Got tmpline: here so as 
Got tmpline: to eventually 
Got tmpline: print 
Got tmpline: \par 

Then \edef\totcontent{\totcontent, \mystyle{\tmpline}} fails w:

! Use of \@pr@videpackage doesn't match its definition.

and \g@addto@macro\totcontent{, \mystyle{\tmpline}} produces:

totcontent is: , \texttt {\par }, \texttt {\par }, \texttt {\par }, \texttt {\par }, \texttt {\par }, \texttt {\par }.

... which is still not what I wanted...

  • 1
    \read\myread to \tmpline will yield the StrGobble... stuff unnecessary – user31729 Oct 14 '14 at 12:25
  • 1
    \readline is the wrong tool, use \read. – egreg Oct 14 '14 at 12:26
  • Many thanks, @ChristianHupfer and @egreg - I changed the example so it uses multi words per line; and indeed \read reads the whole line without LF (but the empty line at end is shown as \par), and does make StrGobble redundant. Still, that doesn't solve my problem: the \edef concat with \mystyle{\tmpline} then fails with ! Use of \@pr@videpackage doesn't match its definition.; and the \g@addto@macro produces \texttt {\par }, \texttt {\par }, .... – sdaau Oct 14 '14 at 12:37
  • 1
    One problem is, that \texttt is not expandable, as far as I know – user31729 Oct 14 '14 at 12:45
  • Thanks, @ChristianHupfer: that is actually what I was counting on: I didn't use \edef because I want to expand - I used it because it was the only method I know of concatenation. What I want to achieve is to get a command as if I verbatim wrote e.g. \def\tst{\texttt{something here}, \texttt{and else}}, and then use \tst in the document to be typeset - except that here it should be the result of concatenation of lines of file input as shown in MWE. Cheers! – sdaau Oct 14 '14 at 12:50
2

The usual problem are the end of lines. You don't want \readline, but the normal \read.

\begin{filecontents*}{\jobname.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\documentclass{article}

\makeatletter
\newread\myread
\makeatletter
\def\strip@final@space{\expandafter\strip@final@sp@ce\@tempa\strip@final@sp@ce}
\def\strip@final@sp@ce#1 \strip@final@sp@ce{\def\@tempa{#1}}
\def\a@par{\par}
\toks@={}
\openin\myread=\jobname.txt
\@whilesw\unless\ifeof\myread\fi{%
  \read\myread to \@tempa
  \typeout{Got tmpline: \@tempa}%
  \ifx\@tempa\a@par
  \else
    \strip@final@space
    \toks@=\expandafter{\the\expandafter\toks@\expandafter\texttt\expandafter{\@tempa}, }%
  \fi
}
\edef\totcontent{\the\toks@}
\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

This is the output in the log file

totcontent is: \texttt {some more}, \texttt {words in}, \texttt {here so as}, \
texttt {to eventually}, \texttt {print}, .

Note that \@tempa will never be empty; an empty line or the final empty line will make \@tempa to expand to \par.

A simpler approach with expl3:

\begin{filecontents*}{\jobname.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn
\seq_new:N \l_sdaau_lines_seq
\tl_new:N \l_sdaau_totcontent_tl
\ior_new:N \sdaau_read_stream
\ior_open:Nn \sdaau_read_stream { \c_job_name_tl.txt }
\ior_map_inline:Nn \sdaau_read_stream
 {
  %\msg_term:n {Got~line:~|#1|} % uncomment for debugging
  \seq_put_right:Nn \l_sdaau_lines_seq { \texttt { #1 } }
 }
\tl_set:Nx \l_sdaau_totcontent_tl { \seq_use:Nn \l_sdaau_lines_seq { ,~ } }

\tl_set_eq:NN \totcontent \l_sdaau_totcontent_tl
\ExplSyntaxOff

\begin{document}

\typeout{totcontent is: \totcontent.}

I got this: \totcontent.

\end{document}

The output is

totcontent is: \texttt {somemore}, \texttt {wordsin}, \texttt {heresoas}, \text
tt {toeventually}, \texttt {print}.

Note that there's no trailing comma.

If you plan to have blank lines in the file, then change the line

  \seq_put_right:Nn \l_sdaau_lines_seq { \texttt { #1 } }

into

  \tl_if_blank:nF { #1 }
   {
    \seq_put_right:Nn \l_sdaau_lines_seq { \texttt { #1 } }
   }
1

You can use \addto macro by the following way:

\long\def\addto#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
\def\addtolist#1{\global\addto\totcontent{, \texttt{#1}}}

\newread\infile
\openin\infile=test-2.txt
\bgroup
  \endlinechar=-1 \gdef\totcontent{}%
  \loop
    \unless\ifeof\infile
       \read\infile to\tmp
       \ifx\tmp\empty \else \expandafter\addtolist\expandafter{\tmp}\fi
       \repeat
\egroup

\message{totcontent is: \meaning\totcontent}

The terminal prints:

totcontent is: macro:->, \texttt {some more}, \texttt {words in}, \texttt {here
 so as}, \texttt {to eventually}, \texttt {print} 
0

Ok, I got at least a working version - though I cannot say I understand what is going on; so a more erudite answer would still be appreciated. But after some messing about, I got a "two-step" approach with call to \protected@edef to work. Here is the MWE:

\documentclass{article}

\usepackage{filecontents} % tlmgr install filecontents

\begin{filecontents*}{test-2.txt}
some more
words in
here so as
to eventually
print
\end{filecontents*}

\def\totcontent{}
\def\mystyle#1{\texttt{#1}}

\def\tst{\texttt{something here}, \texttt{and else}}

\newread\myread
\makeatletter
\immediate\openin\myread=test-2.txt
\@whilesw\unless\ifeof\myread\fi{%
  \read\myread to \tmpline %
  \typeout{Got tmpline: \tmpline} %
  %\ifx\tmpline\par % does NOT work if \tmpline is \par!
  \if\tmpline\par % does work if \tmpline is \par!
    \typeout{PAR} %
  \else %
    %\edef\mytmp{\par} \typeout{1: -\mytmp-}      % dbg
    %\edef\mytmp{\tmpline} \typeout{2: -\mytmp-}  % dbg
    \protected@edef\mytmp{\mystyle{\tmpline}} %
    \typeout{mytmp: \mytmp} %
    \protected@edef\totcontent{\totcontent, \mytmp}
  \fi %
}
\immediate\closein\myread
\makeatother


\begin{document}

\typeout{totcontent is: \totcontent.}

I had this: \tst;

I got this: \totcontent.

\end{document}

This produces in terminal printout:

Got tmpline: some more 
mytmp: \texttt {some more }
Got tmpline: words in 
mytmp: \texttt {words in }
Got tmpline: here so as 
mytmp: \texttt {here so as }
Got tmpline: to eventually 
mytmp: \texttt {to eventually }
Got tmpline: print 
mytmp: \texttt {print }
Got tmpline: \par 
PAR

totcontent is: , \texttt {some more }, \texttt {words in }, \texttt {here so as
 }, \texttt {to eventually }, \texttt {print }.

... and \totcontent is typeset as you'd expect, with right fonts and everything; which is what I originally wanted.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.