In my library, I need to be able to append some text to a file. The problem is that that file may contain the # symbol, and it turns out that every time I append something to a file containing a #, each # is turned into two sharps: ##, so my library is lost since \# is really different from \## (issue here).
Is there a way to append something to a file containing #? For now I'm using this command:
\NewDocumentCommand\appendtofile{m+m}{%
\begingroup
\IfFileExists{#1}%
{\CatchFileDef{\filecontent}{#1}{\catcode`\\=12 \endlinechar=`^^J\catcode\endlinechar=12\relax}}% keep existing end-of-lines
{\let\filecontent\empty}%
\immediate\openout\appendwrite=#1\relax
\immediate\write\appendwrite{\detokenize\expandafter{\filecontent}#2}%
\immediate\closeout\appendwrite
\endgroup
}
MWE
\documentclass{article}
\usepackage{catchfile} % To append to a file.
\usepackage{etoolbox}
\makeatletter
\newwrite\appendwrite
%%% This command allows the user to append things to a file. But the content may contain macros that
%%% will be evaluated before writing them to the file.
% The first argument is the file name
% The second argument is the text to write
% https://tex.stackexchange.com/questions/11796/how-can-i-open-a-file-in-append-mode
\NewDocumentCommand\appendtofile{m+m}{%
\begingroup
\IfFileExists{#1}%
{\CatchFileDef{\filecontent}{#1}{\catcode\\=12 \endlinechar=^^J\catcode\endlinechar=12\relax}}% keep existing end-of-lines
{\let\filecontent\empty}%
\immediate\openout\appendwrite=#1\relax
\immediate\write\appendwrite{\detokenize\expandafter{\filecontent}#2}%
\immediate\closeout\appendwrite
\endgroup
}
%%% Add some rules and title before and after the text.
%% The first argument is the name of the file,
%% The second argument is the text to add.
\NewDocumentCommand\appendEnclosed{m+m}{
\appendtofile{#1}{% This part may contain macros, potentially expanded like \myTitle:
\string\par\string\noindent\string\rule{\string\linewidth}{2mm}\par%
\string\begin{center}\myTitle\string\end{center}
\string\par\string\noindent\string\rule{\string\linewidth}{2mm}\par%
\detokenize{#2}%%<-- this part should be printed as closely as possible to the original text, including # and if possible new lines.
\string\par\string\noindent\string\rule{\string\linewidth}{.5mm}\par%
}
}
%% Erase the file at the beginning to avoid accumulating things from previous runs.
\immediate\openout\appendwrite=mynewfile.tex%
\immediate\write\appendwrite{}%
\immediate\closeout\appendwrite%
\makeatother
\begin{document}
\def\myTitle{myTitle}
\appendEnclosed{mynewfile}{
Hello
I would love to preserve lines, but if it's not possible I can live without if latex at least adds par. I would like to be able to add macros like \textbf{a bold one}.
}
\appendEnclosed{mynewfile}{
But what I would love even more is the ability to add sharp like #. This work if I write a single sharp, but every time I append something to the file, each sharp is replaced with two sharps. Try to uncomment the next lines to see by yourself.
}
% \appendEnclosed{mynewfile}{
% The number of sharp depends on the number of time we happened something to the file. I guess when the file is read, each sharp is turned into two sharps.
% }
% \appendEnclosed{mynewfile}{
% The number of sharp depends on the number of time we happened something to the file. I guess when the file is read, each sharp is turned into two sharps.
% }
% \appendEnclosed{mynewfile}{
% The number of sharp depends on the number of time we happened something to the file. I guess when the file is read, each sharp is turned into two sharps.
% }
\section{Content of the file}
\def\myTitle{} % Just to make sure that myTitle was properly expanded when writing to the file.
\def\mymacro{MyMacro}
\input{mynewfile}
\end{document}
EDIT I just realized that the answer propose here https://tex.stackexchange.com/a/13289/116348 does not have this same issue. I managed to adapt it to my usecase. Please, let me know if I'm missing some subtle edgecases.
\documentclass{article}
\usepackage{catchfile} % To append to a file.
\usepackage{etoolbox}
\makeatletter
%% https://tex.stackexchange.com/a/13289/116348
\newwrite\appendwrite
\newcount\pratend@count@makeallother
%%% Loop to make sure all chars are normal letters, including #.
\newcommand{\makeallother}{%
\pratend@count@makeallother0\relax
\loop\ifnum\pratend@count@makeallother<255\relax
\catcode\pratend@count@makeallother12\relax
\advance\pratend@count@makeallother by 1\relax
\repeat
}
%%% This command allows the user to append things to a file. But the content may contain macros that
%%% will be evaluated before writing them to the file.
%%% TODO: Efficiency may be improved by writing to the file only before the printProof.
% The first argument is the file name
% The second argument is the text to write
\NewDocumentCommand\appendtofile{m+m}{%
\begingroup
%% Read the content
\begingroup%
\IfFileExists{#1}{%
\newlinechar\endlinechar%
\makeallother% Turn all chars into normal letters.
\everyeof{\noexpand}%
\edef\fileContent{@@input #1 }%
}{%
\let\fileContent\empty
}%
%% Open the file to write in it:
\immediate\openout\appendwrite #1\relax%
%% Write the text
\immediate\write\appendwrite{\fileContent}%
\endgroup%
\immediate\write\appendwrite{#2}%
%% Close the file
\immediate\closeout\appendwrite%
\endgroup
}
\NewDocumentCommand\appendEnclosed{m+m}{
\appendtofile{#1}{% This part may contain macros, potentially expanded like \myTitle:
\string\par\string\noindent\string\rule{\string\linewidth}{2mm}\par%
\string\begin{center}\myTitle\string\end{center}
\string\par\string\noindent\string\rule{\string\linewidth}{2mm}\par%
\detokenize{#2}%%<-- this part should be printed as closely as possible to the original text, including # and if possible new lines.
\string\par\string\noindent\string\rule{\string\linewidth}{.5mm}\par%
}
}
%% Erase the file at the beginning to avoid accumulating things from previous runs.
\immediate\openout\appendwrite=mynewfile.tex%
\immediate\write\appendwrite{}%
\immediate\closeout\appendwrite%
\makeatother
\begin{document}
\def\myTitle{myTitle}
\appendEnclosed{mynewfile.tex}{
Hello
I would love to preserve lines, but if it's not possible I can live without if latex at least adds par. I would like to be able to add macros like \textbf{a bold one}.
}
\appendEnclosed{mynewfile.tex}{
But what I would love even more is the ability to add sharp like this: #. This work if I write a single sharp, but every time I append something to the file, each sharp is replaced with two sharps. Try to uncomment the next lines to see by yourself.
}
\appendEnclosed{mynewfile.tex}{
3333
}
% \appendEnclosed{mynewfile}{
% The number of sharp depends on the number of time we happened something to the file. I guess when the file is read, each sharp is turned into two sharps.
% }
% \appendEnclosed{mynewfile}{
% The number of sharp depends on the number of time we happened something to the file. I guess when the file is read, each sharp is turned into two sharps.
% }
% \appendEnclosed{mynewfile}{
% The number of sharp depends on the number of time we happened something to the file. I guess when the file is read, each sharp is turned into two sharps.
% }
\section{Content of the file}
\def\myTitle{} % Just to make sure that myTitle was properly expanded when writing to the file.
\def\mymacro{MyMacro}
\input{mynewfile}
\end{document}
\openout, then put the file contents and then put appended data? More simple is: open the file by\openputonly once and then append repeatedly the data by\write. – wipet Oct 25 '22 at 20:12