0

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.

3
  • 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
2

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}
2
  • 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

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.