Writing a literal TAB character in a file is, unfortunately, dependent on the TeX distribution you have and how the formats were initialized.
With a TeX Live distribution, the formats for pdftex
, pdflatex
and latex
are prepared feeding the option -translate-file=cp227.tcx
, that makes the TAB character "printable".
Compiling the input
\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out
\begingroup
\catcode`\^^I=12 %
\immediate\write\tempfile{^^I<-TAB}
\endgroup
\immediate\closeout\tempfile
\csname @@end\endcsname\end % trick for stopping with Plain TeX and LaTeX
with tex
and with pdftex
(on a TeX Live distribution) will produce two different results (I report the "hex dump"):
5e 5e 49 3c 2d 54 41 42 0a
(tex
)
09 3c 2d 54 41 42 0a
(pdftex
)
Indeed tex
is not set up with the TCX translation that makes the TAB character printable.
If one compiles the file with luatex
or lualatex
the result will be as in case 2. With xetex
it's still different.
5e 5e 49 3c 2d 54 41 42 0a
(xetex
)
09 3c 2d 54 41 42 0a
(xetex -8bit
)
Thus the ^^I
is written in this form with tex
, xetex
or xelatex
, while it is written as a literal TAB with pdftex
, pdflatex
, luatex
or lualatex
, but also with xetex
and xelatex
provided they are called with the -8bit
option.
The moral of the story is: don't use TABs and don't try writing them in files, for the result won't be predictable across systems and machines.
How to define a command that writes a line to a file respecting the TAB characters (assuming pdftex
)?
One has to remember that the category codes are fixed once a token list has been read in by TeX. So one has to use a different strategy:
\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out
\def\test{\begingroup\catcode`\^^I=12 \testaux}
\def\testaux#1{\immediate\write\tempfile{#1}\endgroup}
\test{ <-TAB}
\test{^^I<-TAB}
\immediate\closeout\tempfile
\csname @@end\endcsname\end
This will write in \jobname.out
(again showing the hex dump)
09 3c 2d 54 41 42 0a 09 3c 2d 54 41 42 0a
so two literal TABS (the space in the first argument to \test
is supposed to be a TAB, which on this system may be converted to spaces, unfortunately) are written.
If you need \test
to work also in the argument to another command, then the trick above won't work: something like \foo{x \test{^^I<-TAB}}
, where \foo
takes one argument, would defeat the delayed grabbing of the argument done in \testaux
rather than in \test
: when TeX stores the argument to \foo
it fixes the category codes.
However there's another problem: TeX normalizes ^^I
to a space token as soon as it reads it (when ^^I
has category code 10). So your problem is much more difficult to solve. If you don't need the TAB in your file other than for the purpose of writing it, you can do
\catcode`\^^I=\active
\def^^I{}
\newwrite\tempfile
\immediate\openout\tempfile=\jobname.out
\def\test#1{\begingroup
\edef^^I{\string^^I}\immediate\write\tempfile{#1}\endgroup}
\test{ <-TAB}
\test{^^I<-TAB}
\def\foo#1{#1\test{#1}}
\foo{^^I<-TAB}
\immediate\closeout\tempfile
\csname @@end\endcsname\end
This has the limitation that the TAB won't print anything and a sequence <SPACE><TAB><SPACE>
will print two spaces.
Consider very well not to proceed along this path.
If the commands where \test
is needed are limited in number, one might proceed as in the case above giving a correct definition. If you want to allow \test
as the argument to any command, you're out of luck.
If all you need is to do a write \AtEndDocument
, you can say
\begingroup
\catcode`\^^I=12
\gdef\EndTest{\test{^^I<-TAB}}
\endgroup
\AtEndDocument{\EndTest}
One could do without defining a new command:
\begingroup
\lccode`?=`\^^I
\lowercase{\endgroup\AtEndDocument{\test{?fin du document}}}
\AtEndDocument{\immediate\closeout\tempfile}
You can use a different character than ?
, what's important is that it's a category 12 character.
I assume you're missing a \newcommand
before \mycommand
and a [1]
after it.
First of all, it should be, at least,
\newwrite\file
\newcommand\mycommand[1]{
\immediate\openout\file=foobar.tex
\immediate\write\file{
foo
bar
#1
blarg
}
\immediate\closeout\file
}
or every call to \mycommand
would allocate a new output stream. Now, let's see how to cope with the newlines. As others have observed, ^^J
is set as the \newlinechar
in LaTeX, so we can use it. But, if you want that a write respects new lines also in calls such as
\mycommand{a
b
c}
you have to work harder. Here's a possibility, by changing the category code of ^^M
:
%\newlinechar`^^J % LaTeX already does this
\newwrite\file
\def\mycommand{\begingroup\obeylines\mycommandaux}
\begingroup\obeylines
\gdef\mycommandaux#1{%
\obeylines%
\def^^M{^^J}%
\immediate\openout\file=foobar.tex%
\immediate\write\file{%
foo
bar
#1
blarg% <- no new line at the end
}%
\immediate\closeout\file%
\endgroup%
}
\endgroup
\mycommand{a
b
c}
Here's the contents of foobar.tex
foo
bar
a
b
c
blarg
There is an obvious limitation: \mycommand
cannot be an argument to another command.
Best Answer