Using # with a double meaning is impossible with standard methods. Here's something that seems to work:
\documentclass{article}
\makeatletter
\newwrite\tofile@write
\def\tofile#1#2#3FROMHERE
{%
\begingroup
\immediate\openout\tofile@write=#1\relax
\let\do\@makeother\dospecials
\endlinechar=`\^^J
\@tofile{#2}{#3}%
}
\def\TOTHERE{TOTHERE}
\def\@tofile#1#2#3^^J{%
\def\@test{#3}%
\ifx\@test\TOTHERE
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
{\endgroup}%
{\toks@{#3}%
\begingroup\catcode`\#=6 \endlinechar=\m@ne
\everyeof{\noexpand}%
\xdef\@temp##1##2{\scantokens\expandafter{\the\toks@}}%
\endgroup
\immediate\write\tofile@write{\@temp{#1}{#2}}%
\@tofile{#1}{#2}}%
}
\makeatother
\begin{document}
\tofile{filename}{One}{Two}FROMHERE
Something \absurd{||-\for\yossi
Else #1 or #2
TOTHERE
\end{document}
The produced file is
Something \absurd{||-\for\yossi
Else One or Two
Another solution using LaTeX3 features. The opening string should be equal to the ending one and not separated from the second argument; use only printable and non (TeX) special ASCII characters. The first argument used in the example is \jobname.txt just not to clobber other files in my file system, you can use whatever name you want.
More substitutions could be accommodated, let me know.
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\tofile}{m}
{
\yossi_tofile:n { #1 }
}
\iow_new:N \g_yossi_tofile_write_stream
\cs_new_protected:Npn \yossi_tofile:n #1
{
\group_begin:
\tex_endlinechar:D `\^^J
\iow_open:Nn \g_yossi_tofile_write_stream { #1 }
\yossi_tofile_aux:nnw
}
\cs_new_protected:Npn \yossi_tofile_aux:nnw #1 #2 #3 ~%
{
\tl_set:Nn \l_yossi_eof_tl { #3 }
\tl_trim_spaces:N \l_yossi_eof_tl
\cs_set_eq:NN \do \char_set_catcode_other:N
\dospecials
\yossi_readline:nnw { #1 } { #2 }
}
\cs_new_protected:Npn \yossi_readline:nnw #1 #2 #3 ^^J
{
\str_if_eq:VnTF \l_yossi_eof_tl { #3 }
{
\iow_close:N \g_yossi_tofile_write_stream
\group_end:
}
{
\yossi_replace_write:nnn { #1 } { #2 } { #3 }
\yossi_readline:nnw { #1 } { #2 }
}
}
\cs_new_protected:Npn \yossi_replace_write:nnn #1 #2 #3
{
\tl_set:Nn \l_tmpa_tl { #3 }
\regex_replace_all:nnN { \#1 } { #1 } \l_tmpa_tl
\regex_replace_all:nnN { \#2 } { #2 } \l_tmpa_tl
\iow_now:NV \g_yossi_tofile_write_stream \l_tmpa_tl
}
\cs_generate_variant:Nn \iow_now:Nn { NV }
\cs_generate_variant:Nn \str_if_eq:nnTF { V }
\ExplSyntaxOff
\begin{document}
\tofile{\jobname.txt}{One}{Two}<<EOF
here is some nonsensical list of commands,
\unexpand\expandafter\gdef\indlude{#1}\def\expand\myOtherCrazyMacro
but who cares, I can even place my C code here
#include <stdio.h>
main() {
printf("#2",\n);
}
this }}{{is some other illegal LaTeX code, which uses % percents,
& other _^^^_ ASCII stuff.
<<EOF
\end{document}
This is the file that's written out:
here is some nonsensical list of commands,
\unexpand\expandafter\gdef\indlude{One}\def\expand\myOtherCrazyMacro
but who cares, I can even place my C code here
#include <stdio.h>
main() {
printf("Two",\n);
}
this }}{{is some other illegal LaTeX code, which uses % percents,
& other _^^^_ ASCII stuff.
Thanks to Joseph Wright for suggesting replacements via regular expressions.
A new version, allowing any number of arguments; however they have to be specified in a different way, see the example code.
\documentclass{article}
\usepackage{xparse,l3regex}
\ExplSyntaxOn
\NewDocumentCommand{\tofile}{m}
{
\manual_tofile:n { #1 }
}
\iow_new:N \g_manual_tofile_write_stream
\tl_const:Nn \c_manual_specials_tl { \ \\ \{ \} \$ \& \# \^ \_ \% \~ }
\tl_new:N \l_manual_argument_tl
\tl_new:N \l_manual_line_tl
\seq_new:N \l_manual_arguments_seq
\int_new:N \l_manual_arguments_int
\cs_new_protected:Npn \manual_dospecials:
{
\tl_map_inline:Nn \c_manual_specials_tl
{
\char_set_catcode_other:N ##1
}
}
\cs_new_protected:Npn \manual_tofile:n #1
{
\group_begin:
\tex_endlinechar:D `\^^J
\iow_open:Nn \g_manual_tofile_write_stream { #1 }
\manual_tofile_aux:nw
}
\cs_new_protected:Npn \manual_tofile_aux:nw #1 #2 ~%
{% #1 is the list of arguments, #2 is the terminator
\tl_set:Nn \l_manual_eof_tl { #2 }
\tl_trim_spaces:N \l_manual_eof_tl
\seq_set_split:Nnn \l_manual_arguments_seq { } { #1 }
\int_set:Nn \l_manual_arguments_int { \seq_count:N \l_manual_arguments_seq }
\manual_dospecials:
\manual_readline:w
}
\cs_new_protected:Npn \manual_readline:w #1 ^^J
{
\str_if_eq:VnTF \l_manual_eof_tl { #1 }
{
\iow_close:N \g_manual_tofile_write_stream
\group_end:
}
{
\manual_replace_write:n { #1 }
\manual_readline:w
}
}
\cs_new_protected:Npn \manual_replace_write:n #1
{
\tl_set:Nn \l_manual_line_tl { #1 }
\int_step_inline:nnnn { 1 } { 1 } { \l_manual_arguments_int }
{
\tl_set:Nx \l_manual_argument_tl { \seq_item:Nn \l_manual_arguments_seq { ##1 } }
\regex_replace_all:nnN { \# ##1 } { \u{l_manual_argument_tl} } \l_manual_line_tl
}
\iow_now:NV \g_manual_tofile_write_stream \l_manual_line_tl
}
\cs_generate_variant:Nn \iow_now:Nn { NV }
\cs_generate_variant:Nn \str_if_eq:nnTF { V }
\ExplSyntaxOff
\begin{document}
\tofile{test.c}{{One}{Two}{Three}}<<EOF
/* #1, #2 */
#include <stdio.h>
main() {
printf("#3",\n);
}
<<EOF
\end{document}
\tofile{\jobname.txt}{{One}{Two}{ASCII}}<<EOF
here is some nonsensical list of commands,
\unexpand\expandafter\gdef\indlude{#1}\def\expand\myOtherCrazyMacro
but who cares, I can even place my C code here
#include <stdio.h>
main() {
printf("#2",\n);
}
this }}{{is some other illegal LaTeX code, which uses % percents,
& other _^^^_ #3 stuff.
<<EOF
\end{document}
The arguments here are three, specified as braced items in the second argument to \tofile:
\tofile{\jobname.txt}{ {One} {Two} {ASCII} }<<EOF
(spaces added for clarity, they are ignored).
#also as a printable character. It's either the parameter indicator or a printable character, it can't be both. – egreg Jan 22 '14 at 15:28