Read a file and store its contents in a variable

I am trying to implement single sourcing such that same document can be conditionally typeset for number of purposes. This is what I would like to do.

\IfFileExists{../DecMaker.txt}{
var x = DecMaker.txt %the file will contain a single digit number
if x = 0{
\newcommand{\product}{Windows}
}
if x = 1{
\newcommand{\product}{Linux}
}
if x = 2{
\newcommand{\product}{Mac}
}
\product\ computer bought from ThisRandomBrand is amazing!
}
{
Go and buy a \product\ computer from ThisRandomBrand!!
}


I read up a bit about etoolbox and tried to use the \iftoggle command. Its complicating the matters with multiple ifs.

Please let me know if you need more details.

EDIT: I intend to use the above variable in numerous other places in my document. E.g.

if x = 0{
Press the power button and pray that you don't get a blue screen
}
if x = 1{
Congratulations for forwarding the evolution!!
}


You can use catchfile. It's also better to separate the reading of the auxiliary file from the definition part, so you can easily reuse the code for the OS. The macro \newOScommand has five arguments: the name of the command to define and the four branches as shown in the example.

\usepackage{catchfile}

\IfFileExists{../DecMaker.txt}
{\CatchFileEdef{\OSnumber}{../DecMaker.txt}{\endlinechar=-1 }}
{\def\OSnumber{-1}}

\newcommand{\newOScommand}[5]{%
\ifcase\OSnumber\relax
\newcommand{#1}{#2}\or
\newcommand{#1}{#3}\or
\newcommand{#1}{#4}\else
\newcommand{#1}{#5}%
\fi

\newOScommand{\product}{Windows}{Linux}{Mac}{No computer}

• Wow!! Thanks! Just the thing I needed! Sadly, I already accepted TH's answer. – abyshukla Jun 28 '17 at 8:41
• @manucpp You can change your mind and accept this one if it's the best for you. I told you to accept the answer but I forgot to tell you to wait a little for better ones. – CarLaTeX Jun 28 '17 at 8:44

I'm not sure what the right way to do this with the LaTeX macros like \IfFileExists, but using the low-level TeX primitives this is easy to do.

\documentclass{article}
\begin{document}
\openin\makerfile=../DecMaker.txt
\ifeof\makerfile
Go and buy a computer from ThisRandomBrand!!
\else
\closein\makerfile
\edef\product{%
\ifcase\makerline
Windows%
\or Linux%
\or Mac%
\fi
}
\product\ computer bought from ThisRandomBrand is amazing!
\fi
\end{document}


It tries to open ../DecMaker.txt and if that fails, it outputs the "Go and buy..." line. Otherwise, it defines \product to Windows, Linux, or Mac and outputs the "Linux computer..." line (for example).

I don't know (and cannot easily test) what happens if this file is actually run on a Windows machine. In particular, I don't know if ../DecMaker.txt is treated as the path you want.

If DecMaker.txt were moved to the same directory, then this should work correctly everywhere.

• It works!! Thank you! However, I'd greatly appreciate if you could elaborate on the happenings. What is \makerfile and \makerline, for instance. – abyshukla Jun 28 '17 at 4:56
• @manucpp, the question asks about reading a file and storing its contents. My answer really only takes the first line of the file, but since you said the file would only have only a single digit, this should work. – TH. Jun 28 '17 at 5:00
• I intend to use the above variable in numerous other places in my document. Where is it being stored? Also, how do I begin learning more about TeX primitives? They seem to have answers on most of my problems. – abyshukla Jun 28 '17 at 5:14
• Oh, the input from the file got written to \makerline. You can change the name to something more appropriate for your use case. Note that it contains both the digit and a trailing space token. Any place TeX expects a number (e.g., \ifnum, \ifcase, and \count0=) allows an optional space token to follow the number. The space is used to mark the end of the number. If you don't want the space, you can use {\endlinechar=-1 \global\read\makerfile to\makerline}. – TH. Jun 28 '17 at 5:44
• @manucpp sorry, I missed your initial comment. \makerfile is a small integer that represents one of TeX's 16 input streams. \openin\makerfile=file.ext tries to open the given file and associates it with the integer assigned to \makerfile. \makerline is just a macro that gets set to the contents of the next line to be read from the input stream. So \read\makerfile to\makerline reads the first line from the file and assigns it to \makerline. You could read the second line by using another \read\makerfile to\foo. – TH. Jun 29 '17 at 5:39

Run with lualatex

\documentclass{article}
\usepackage{luacode}
\begin{luacode}
local x = {"Windows","Linux","Darwin"}

function FileTest(filename)
local f=assert(io.open(filename, "r"))
f:close()
if t then
return x[tonumber(t)].." computer bought from ThisRandomBrand is amazing!"
else
return "Go and buy a computer from ThisRandomBrand!!"
end
end
\end{luacode}

\newcommand\Test[1]{\directlua{tex.print(FileTest("#1"))}}

\begin{document}
\Test{../DecMaker.txt}
\end{document}

• I am currently using xelatex. How separated is lualatex from xelatex? – abyshukla Jun 28 '17 at 6:10
• lualatex has the same font handling as xelatex but more flexibility in using the script language Lua – user2478 Jun 28 '17 at 6:35