Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I have a problem. I would like :

  • to construct an etoolbox list
  • to save this list in a temp file
  • to read this list from this file at the next run
  • to use this file.

For any reason, I can't see the solution. That is my actual code.

\documentclass{article}
\usepackage{etoolbox}
\begin{document}
% The list
\def\a{}
\listadd{\a}{a}
\listadd{\a}{b}
% Print the list from the tex code
\begin{itemize}
              \renewcommand*{\do}[1]{\item #1}
              \dolistloop{\a}
              \end{itemize}

\a
% Write the list in an outfile
\newwrite\outf
\openout\outf=list.txt
\write\outf{\a}
\closeout\outf
% Read the list from this file
\newread\inf
\openin\inf=list.txt
\read\inf to \b
\closein\inf
\b
% Print the list from the file
\begin{itemize}
              \renewcommand*{\do}[1]{\item #1}
              \dolistloop{\b}
              \end{itemize}

\end{document}

In the documentation of etoolbox, it's said that an internal list is just a macro with | as separator. In my outfile, I have a|b. So what is the problem ?

share|improve this question
1  
Note that expanding \a in the wild is explicitly discouraged by etoolbox and that \show or \meaning should be used to inspect its value. –  egreg Jan 5 '13 at 20:29
add comment

1 Answer

up vote 10 down vote accepted

You need to close the file with \immediate or the operation would be delayed at the next shipout. Similarly, write with \immediate.

But this is not the only precautions to be taken. In the footnote at page 24 in the documentation of etoolbox you find that the list delimiter is | with category code 3. So

\documentclass{article}
\newwrite\outf
\newread\inf

\usepackage{etoolbox}
\begin{document}
% The list
\def\a{}
\listadd{\a}{a}
\listadd{\a}{b}
% Print the list from the tex code
\begin{itemize}
\renewcommand*{\do}[1]{\item #1}
\dolistloop{\a}
\end{itemize}

% Write the list in an outfile
\immediate\openout\outf=list.txt
\immediate\write\outf{\unexpanded\expandafter{\a}}
\immediate\closeout\outf

% Read the list from this file
\openin\inf=list.txt
{\catcode`|=3 \endlinechar=-1
 \global\read\inf to \b}
\closein\inf
% Print the list from the file
\begin{itemize}
\renewcommand*{\do}[1]{\item #1}
\dolistloop{\b}
\end{itemize}

\end{document}

The unusual combination of character code and category code is meant for having a delimiter that shouldn't appear in normal documents, so that the macros cannot be fooled by (almost) any kind of input.

Notice that I've added \unexpanded as suggested by Joseph Wright. This will protect against unwanted expansion of commands that don't survive \edef or \write (all font changing commands, for instance).


A safer version is to deconstruct the list when writing and rebuild it when reading it back. This won't depend on any particularity of the delimiter. We simply add an additional pair of braces around the list items, that will be stripped off during the rebuilding of the list.

\documentclass{article}
\usepackage{etoolbox}

\newwrite\outf
\newread\inf
\newcommand\readlistadd[1]{\listadd\templist{#1}}

\begin{document}
% The list
\def\a{}
\listadd{\a}{a}
\listadd{\a}{b}
% Print the list from the tex code
\begin{itemize}
\renewcommand*{\do}[1]{\item #1}
\dolistloop{\a}
\end{itemize}

% Write the list in an outfile
\immediate\openout\outf=list.txt
\renewcommand\do[1]{\immediate\write\outf{{\unexpanded{#1}}}}
\dolistloop{\a}
\immediate\closeout\outf

% Read the list from this file
\openin\inf=list.txt
{\endlinechar=-1
 \def\templist{}
 \everyeof{}
 \loop\unless\ifeof\inf
  \read\inf to \temp
  \ifx\temp\empty\else
   \expandafter\readlistadd\temp
  \fi
 \repeat
 \global\let\b\templist
}
\closein\inf
% Print the list from the file
\begin{itemize}
\renewcommand*{\do}[1]{\item #1}
\dolistloop{\b}
\end{itemize}

\end{document}
share|improve this answer
    
Thanks, the solution is, indeed, in the catcode problem –  Maïeul Jan 5 '13 at 20:24
2  
I'd convert to a comma or brace list myself: I don't think relying on the internals of another package is a good plan. –  Joseph Wright Jan 5 '13 at 20:25
    
@JosephWright I would use a different approach myself. In any case all category code settings used during write must be restored during read. –  egreg Jan 5 '13 at 20:26
    
@egreg I'd also strongly encourage writing with appropriate control of expansion (here most easily \unexpanded\expandafter{\a}), as unexpected expansion on writing files can be a real pain. –  Joseph Wright Jan 5 '13 at 20:33
    
@JosephWright Yes, you are very right. –  egreg Jan 5 '13 at 20:46
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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