# Prompted \read input when there should be none

I can't understand how \read# to \sth or \ifeof are supposed to work. If an stream not in [0,15] is used, or the stream is closed, or doesn't exist, it will prompt you to manually input the num if you're running the .tex in a console. Otherwise, you get error and it breaks the documents on the spot, in my case- doesn't print out the rest of the longtable.

The MWE kind of simulates the case. Data gets read from a file, 2 rows at a time, a beginning and ending date. In the original these get compared to the current date row's date and if there's a match it begins to \immediate\write to a data file until the 2. date is match, then it stops, closes output stream, and this happens for each pair of dates- here it should be a simple overwriting of \aaaaa and \bbbbb since that's enough to reproduce the error.

A few places in the original code contain \ifeof, it's like I can never get it to go to the true branch. In the MWE the T-branch doesn't execute either.

MWE:

\documentclass[a4paper]{article}
\usepackage{
etoolbox,
xstring,
}
\newcounter{foo}
\newbool{hasReadPeriod}

\begin{document}

\newwrite\periods
\immediate\openout\periods=1.dat
\def\mynum{6}
\def\testi{%
\stepcounter{foo}%
\immediate\write\periods{0000-00-\thefoo}%
\ifnum\thefoo=\mynum
\else
\testi{}%
\fi
}

\testi{} Test 1: write \mynum{} rows + 1 empty.\par \vspace*{0.25cm}\hrule\vspace*{0.25cm}
\immediate\closeout\periods

\newread\periods
\openin\periods=1.dat
\setcounter{foo}{0}

Test 2: step counter foo, read 2 rows from file on odd numbers
\def\testii{%
\stepcounter{foo}%
\thefoo%
\ifeof\periods
this never shows up, why?
\closein\periods% does nothing
\else
\ifbool{hasReadPeriod}%
{%
. F\quad%
\global\boolfalse{hasReadPeriod}%
b5 = \bbbbb%
}%
{%
\global\read\periods to \aaaaa%
\global\read\periods to \bbbbb%
\global\booltrue{hasReadPeriod}%
. T\quad%
a5 = \aaaaa%
}%
\fi
%
\ifnum\thefoo=\mynum
\quad LAST ROW%
\fi
%
\par
}

\testii{}\testii{}\testii{}
\testii{}\testii{}\testii{}
% \testii{}% COMMENT ME OUT OR WON'T BUILD (WO/ MAN. INPUT)
\end{document}


edit: \globals are because the respective things in the main don't get read or written, or T/F'd, it's in a longtable. Don't know how much that matters in the example, but given that it's inside a command, I'd rather make sure.

• you could remove geometry and fontspec which are irrelevant to this but force xetex to be used. – David Carlisle Oct 4 '18 at 15:32
• note however that \ifnum\thefoo=\mynum is a very unsafe test as \mynum is defined by \def\mynum{6} which does not terminate the number so the \else branch will be expanded early. – David Carlisle Oct 4 '18 at 15:34
• In the main, the read line is a string which gets compared via \ifx to an \xdef'd date made of \the<counters>. Should be beside the point, getting the same error/prompt. Please elaborate what a terminated number is. – vlg Oct 4 '18 at 15:42

## 1 Answer

If you use

                \global\read\periods to \aaaaa%
\show\aaaaa


then you will see on the terminal

> \aaaaa=macro:
->0000-00-3 .
<argument> ...ead \periods to \aaaaa \show \aaaaa
\global \read \periods to ...
l.65 \testii{}\testii{}\testii
{}
?
> \aaaaa=macro:
->0000-00-5 .
<argument> ...ead \periods to \aaaaa \show \aaaaa
\global \read \periods to ...
l.66 \testii{}\testii
{}\testii{}
?
> \aaaaa=macro:
->\par .


So on the last line \aaaaa is \par but you do two \read so step off the end.

so you could test for that:

\documentclass[a4paper]{article}

\usepackage{
etoolbox,
xstring,
}

\newcounter{foo}
\newbool{hasReadPeriod}

\begin{document}

\newwrite\periods
\immediate\openout\periods=1.dat
\def\mynum{6}
\def\testi{%
\stepcounter{foo}%
\immediate\write\periods{0000-00-\thefoo}%
\ifnum\thefoo=\mynum
\else
\testi{}%
\fi
}

\testi{} Test 1: write \mynum{} rows + 1 empty.\par \vspace*{0.25cm}\hrule\vspace*{0.25cm}
\immediate\closeout\periods

\newread\periods
\openin\periods=1.dat
\setcounter{foo}{0}

\def\endpar{\par}
Test 2: step counter foo, read 2 rows from file on odd numbers
\def\testii{%
\stepcounter{foo}%
\thefoo%
\ifeof\periods
this never shows up, why?
\closein\periods% does nothing
\else
\ifbool{hasReadPeriod}%
{%
. F\quad%
\global\boolfalse{hasReadPeriod}%  why all the \global????
b5 = \bbbbb%
}%
{%
\global\read\periods to \aaaaa%
\ifx\aaaaa\endpar\else
\global\read\periods to \bbbbb%
\global\booltrue{hasReadPeriod}%
. T\quad%
a5 = \aaaaa%
\fi
}%
\fi
%
\ifnum\thefoo=\mynum
\quad LAST ROW%
\fi
%
\par
}

\testii{}\testii{}\testii{}
\testii{}\testii{}\testii{}
\testii{}% COMMENT ME OUT OR WON'T BUILD (WO/ MAN. INPUT)
\end{document}

• So, basically, a check after the first \read if it's a \par to see if any more should be read. Why doesn't the \ifeof every go true? I want to see when the {\HUGE EOF} appears, I don't understand why it doesn't. – vlg Oct 4 '18 at 16:06
• @vlg \ifeof isn't true until you get to the end of the file but since you read two lines at a time you need to check after the final aaa before reading bbb, add another \testii and you'll see it is now end of file – David Carlisle Oct 4 '18 at 17:44