2

I want to make a macro to import all TeX input files in a directory in which the input file containing the macro exists. When reading an external file, TeX appends a blank line to the last iteration.

In the following code I use a bad algorithm because there are two loops. The first one is used to find the total file, and the other one is used to do the main job.

\documentclass{article}
\usepackage{listings}

\lstset{language={[LaTeX]TeX},breaklines=true}


\def\X
{%
    \immediate\write18{cmd /c dir /b *.tex > \jobname-temp.txt}%
    \newread\myfile
    \openin\myfile=\jobname-temp.txt
    \newcount\counter
    \counter=0
    \loop
        \unless\ifeof\myfile
        \read\myfile to\mydata
        \advance \counter by 1
    \repeat
    \closein\myfile
    \openin\myfile=\jobname-temp.txt
    \advance \counter by -1
    \loop
        \ifnum \counter > 0
        \read\myfile to\mydata
        \section\mydata
        \lstinputlisting{"\mydata"}\newpage
        \advance \counter by -1
    \repeat
    \closein\myfile
}


\begin{document}
\X
\end{document}

I want to use a single loop to increase the performance.

How to detect a blank line inserted by TeX when reading an external file line by line?

2 Answers 2

8

Simply check for EOF again after reading the line.

Minimum Working Example:

\documentclass{article}
\usepackage{filecontents}

\begin{filecontents*}{\jobname.dat}
first
second
third
fourth
\end{filecontents*}

\newread\myfile

\newcommand*\readfile{%
    \immediate\openin\myfile=\jobname.dat\relax
     \loop\unless\ifeof\myfile
        \read\myfile to\mydata
        \ifeof\myfile\else
            \section\mydata
        \fi
    \repeat
    \immediate\closein\myfile
}

\begin{document}
\readfile
\end{document}

If you want to avoid the double EOF check than use a recursive macro like the following:

\newcommand*\readfile{%
    \immediate\openin\myfile=\jobname.dat\relax
    \ifeof\myfile\else% file exists?
       \expandafter\readoneline
    \fi
    \immediate\closein\myfile
}

\def\readoneline{%
    \read\myfile to\mydata
    \ifeof\myfile\else
        \section\mydata
        % ...
        \expandafter\readoneline
    \fi
}

The added empty line adds a \par if the (original) external line ends with a line break (2x line breaks => \par, as always). Therefore \mydata will contain \par (which you would know if you would have used \show to debug it as I told you earlier). You can test for this using:

\def\lastline{\par}

%...

\ifx\mydata\lastline
  %...
\fi

Of course this test will also be true for any other implicit or explicit \par line in the input file, so testing for EOF is actually safer in general, but here you want to avoid all of such input lines anyway (not that they will appear anywhere else in you example).

1
  • why did you not think a simpler one as shown below? Commented Aug 9, 2011 at 9:41
2

I improve Martin's algorithm. I don't use a recursive approach because it might be broken due to stack overflow (without .com) if there are too many files. I also don't use double testing for EOF. :-)

\def\X
{%
    \immediate\write18{cmd /c dir /b *.txt > \jobname-temp.dat}%
    \newread\myfile
    \openin\myfile=\jobname-temp.dat\relax
    \loop   
        \read\myfile to \mydata 
        \unless\ifeof\myfile                
        \section\mydata
        \lstinputlisting{"\mydata"}\newpage
    \repeat
    \closein\myfile
}
3
  • I forgot that the condition doesn't have to follow \loop directly. However, I disagree with your statement that my recursive suffers from stack build-up (which could lead to an overflow). I'm using \expandafter\readoneline\fi to not stack up conditionals. Commented Aug 9, 2011 at 9:50
  • My answer told you to use \ifeof\myfile again and led you to your final solution. Accepting your own answer like that is not good manners. Commented Aug 10, 2011 at 11:55
  • Because of manner restriction, I return the green check mark to you. :-) Commented Aug 10, 2011 at 11:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .