Write values to a file
Judging from the comments, you know this already but you can open a file with something like
\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output
I have used the tex file name \jobname
for the output file with an "output" extension. You can write to this file using
\write\myputout{stuff}
With your MWE, things go horribly wrong with expansion. To get around this in the past I have used an \unexpandedwrite
macro that I found somewhere in TeXbook. Using this I can get your MWE to compile and produce the output:
1: foo 2: bar and 3: baz 1: See 1\hbox {} 2: \begin {description} \item [whatever] Hello \end {description} and 3: Some text
Depending on what you expect for #1
, #2
, and #3
you could of course use \write
for some of them and \unexpandedwrite
for others. This is what I have done below.
EDIT
@jfbu points out in the comments that there is now an \unexpanded
macro so \unexpandedwrite
is not needed anymore, so my MWe can be shortened to:
\documentclass{article}
\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output
\newcommand\foo[3]{%
\write\myoutput{1: #1}
\write\myoutput{\unexpanded{2: #2}}
\write\myoutput{ and 3: #3}
}
\begin{document}
\foo{foo}{bar}{baz}
\foo{See \ref{sec}}{\begin{description}
\item[whatever] Hello
\end{description}}{Some text}
\section{A section}
\label{sec}
\end{document}
Here is the original code:
\documentclass{article}
%% from the TeXbook
\def\\{\let\stoken= } \\
\long\def\unexpandedwrite#1#2{\def\finwrite{\write#1}%
{\aftergroup\finwrite\aftergroup{\sanitize#2\endsanity}%
}}
\def\sanitize{\futurelet\next\sanswitch}
\def\sanswitch{\ifx\next\endsanity
\else\ifcat\noexpand\next\stoken\aftergroup\space\let\next=\eat
\else\ifcat\noexpand\next\bgroup\aftergroup{\let\next=\eat
\else\ifcat\noexpand\next\egroup\aftergroup}\let\next=\eat
\else\let\next=\copytoken\fi\fi\fi\fi \next
}
\def\eat{\afterassignment\sanitize \let\next= }
\long\def\copytoken#1{%
\ifcat\noexpand#1\relax\aftergroup\noexpand
\else\ifcat\noexpand#1\noexpand~\aftergroup\noexpand\fi\fi
\aftergroup#1\sanitize%
}
\def\endsanity\endsanity{}
\newwrite\myoutput
\immediate\openout\myoutput=\jobname.output
\newcommand\foo[3]{%
\write\myoutput{1: #1}
\unexpandedwrite\myoutput{2: #2}
\write\myoutput{ and 3: #3}
}
\begin{document}
\foo{foo}{bar}{baz}
\foo{See \ref{sec}}{\begin{description}
\item[whatever] Hello
\end{description}}{Some text}
\section{A section}
\label{sec}
\end{document}
A quick proof of concept:
\documentclass{article}
\usepackage{atbegshi}
\AtBeginShipout{\directlua{analyzebox(tex.box["AtBeginShipoutBox"])}}
\directlua{dofile("foo.lua")}
\begin{document}
\newcommand\foo[3]{1: \directlua{starttoken(1)}#1\directlua{stoptoken(1)},%
2: \directlua{starttoken(2)}#2\directlua{stoptoken(2)}%
and 3: \directlua{starttoken(3)}#3\directlua{stoptoken(3)}}
\foo{foo}{bar}{baz}
\foo{See \ref{sec}}{\begin{description}
\item[whatever] Hellö
\end{description}}{Some text}
\section{A section}
\label{sec}
\end{document}
and foo.lua
is
function starttoken(n)
local ud = node.new("whatsit","user_defined")
ud.user_id = 41564
ud.type = 100
ud.value = n * 2
node.write(ud)
end
function stoptoken(n)
local ud = node.new("whatsit","user_defined")
ud.user_id = 41564
ud.type = 100
ud.value = n * 2 + 1
node.write(ud)
end
local hlist = node.id("hlist")
local vlist = node.id("vlist")
local glyph = node.id("glyph")
local glue = node.id("glue")
local whatsit = node.id("whatsit")
local user_defined
for k,v in pairs(node.whatsits()) do
if v == "user_defined" then
user_defined = k
end
end
local inlist = false
local charlist = {}
local charlists = {}
function analyzebox( box )
while box do
if box.id == hlist or box.id == vlist then
analyzebox(box.list)
elseif box.id == glyph and inlist then
charlist[#charlist + 1] = unicode.utf8.char(box.char)
elseif inlist and box.id == glue and #charlist > 0 and charlist[#charlist] ~= " " then
charlist[#charlist + 1] = " "
elseif box.id == whatsit and box.subtype == user_defined and box.user_id == 41564 then
local curlist
local val = box.value
if val % 2 == 0 then
inlist = true
else
inlist = false
curlist = (val - 1) / 2
if charlist[#charlist] == " " then
table.remove(charlist)
end
if curlist < 3 then
charlists[curlist] = charlist
else
texio.write_nl(string.format("%q, %q, %q",table.concat(charlists[1],""),table.concat(charlists[2],""),table.concat(charlist,"")))
charlists = {}
end
charlist = {}
end
end
box = box.next
end
end
writes
"foo", "bar", "baz"
"See 1", "whatever Hellö", "Some text"
to the output...