6

When using the fancyvrb environment Verbatim, you can gobble the first n characters of each line before printing it out. I'd like to be able to do something similar, but not via verbatim.

In the following MWE, I would like to read in the file:

    \textbf{This is the first line.}
%%  \textbf{This is the second line.}

and have LaTeX process it as though it'd been passed a file:

\textbf{This is the first line.}
\textbf{This is the second line.}

Here's an example of what I've tried, but it doesn't work as hoped:

\begin{filecontents*}{aetesting}
    \textbf{This is the first line.}
%%  \textbf{This is the second line.}
\end{filecontents*}
\documentclass{article}
\usepackage{catchfile}
\def\gobblefirst#1#2#3#4{}
\def\mysetup{\let\do\gobblefirst\dospecials}
\CatchFileDef{\aemyfile}{aetesting}\mysetup
\begin{document}

\aemyfile

\end{document}

UPDATE

I can almost get this to work (without catchfile)

\begin{filecontents*}{aetesting}
  The character of the First Caesar has perhaps never been worse
  appreciated than by him who in one sense described it best; that is,

  \textbf{This is the first line.}\par
%%  \textbf{This is the second line.}


%%  Great as Caesar was by the benefit of his original nature, there can be
  no doubt that he, like others, owed something to circumstances; and
\end{filecontents*}
\documentclass{article}
\makeatletter

\newread\file
\newcommand\aeomit[2]{}
\newcommand\myaccumulatedfile{}
\newcommand*\aegobbleinput[1]{%
  \IfFileExists{#1}{%
    \openin\file #1
    \begingroup
    \endlinechar\newlinechar
    \loop\unless\ifeof\file
      \obeyspaces
      \readline\file to\foo
      \edef\myaccumulatedfile{\myaccumulatedfile\expandafter\@gobbletwo\foo\relax\relax}%%
    \repeat
    \closein\file
    \expandafter\endgroup
    \scantokens\expandafter{\myaccumulatedfile}
  }{%
    \errmessage{File `#1' doesn't exist!}%
  }%
}

\makeatother
\begin{document}

Try:

\aegobbleinput{aetesting}

\end{document}

The problem is that leading spaces are ignored and I don't want them ignored. Also my line break before \textbf{This is the first line.} is no longer properly treated as a paragraph break. :(

Further update

Thinking I might try this in LaTeX3, I run into even more troubles.

\usepackage{xparse}
\ExplSyntaxOn

\ior_new:N \g_ae_fh_ior
\tl_new:N  \l_ae_fh_line_tl

\cs_new:Npn \__ae_gobble:n #1 
  {
    \file_if_exist:nTF { \__ae_open:n { #1 } }
                       { \typeout{no file!}  }
  }

\cs_new:Npn \__ae_open:n #1
  {
    \ior_open:Nn           \g_ae_fh_ior { #1 }
    \ior_str_map_inline:Nn \g_ae_fh_ior { \tl_gput_right:Nn \l_ae_fh_line_tl {##1 \par}}
    \ior_close:N           \g_ae_fh_ior
  }

\NewDocumentCommand{\aegobbleinput}{m}
    {
      \__ae_gobble:n {#1}
    }

\ExplSyntaxOff

Here I'm not even trying to truncate anything. But I can't get LaTeX to read the file. I get one of two errors with this code. When I try to use the inline map, I get the error

! Illegal parameter number in definition of \l__file_internal_name_tl.
<to be read again> 
                   1
l.6 \aegobbleinput{aetesting.tex}

? 

If I get rid of that line, even though getting rid of it should result in nothing getting parsed, I get the error message

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!
! LaTeX error: "kernel/space-in-file-name"
! 
! Space in file name '\ior_open:Nn \g_ae_fh_ior {aetesting.tex}\ior_close:N
! \g_ae_fh_ior '.
! 
! See the LaTeX3 documentation for further information.
! 
! For immediate help type H <return>.
!...............................................  

l.6 \aegobbleinput{aetesting.tex}

? 

which makes absolutely no sense to me particularly because I'm very closely following the example as posted here.

4
  • In your expl3 definition, you are missing the file name argument for \file_if_exist:nTF, hence the error.
    – Joseph Wright
    Jul 30, 2013 at 8:50
  • Your \let\do\gobblefirst\dospecials is strange as the meaning of \dospecials is macro:->\do \ \do \\\do \{\do \}\do \$\do \&\do \#\do \^\do \_\do \%\do \~. But I am not familiar with \CatchFileDef so perhaps something else happens.
    – user4686
    Jul 30, 2013 at 15:32
  • @jfbu I'm mucking around in the dark here. I apparently don't understand much of anything about these commands. They're certainly not working as I think they should. And what I'm reading in the documentation isn't really helping me. For example, in the eTeX documentation there are only 2 or 3 lines of explanation about \readline. I really feel in the dark.
    – A.Ellett
    Jul 30, 2013 at 15:37
  • Perhaps I did not explain that my proposed answer does not treat line by line: this is handed over to TeX input process, via the possibility to let the end of line act to suppress the first characters of the next line. TeX by Topic has some explanations about either reading line by line or inputting in one go a file. And eTeX has added stuff such as \everyeof. \readline seems to be for some sort of verbatim input, I am not familiar with its use, having only some limited experience with scantokens for example.
    – user4686
    Jul 30, 2013 at 15:43

2 Answers 2

1

Here is a naive attempt, certainly not foolproof. Forgot to say it does not use the catchfile package. The file is not input verbatim but each non-empty line must have at least four initial characters, which are treated verbatim and ignored.

\documentclass{article}
\usepackage{filecontents}

\begin{filecontents*}{aetesting}
    \textbf{This is the first line.}
%%  \textbf{This is the second line.}
^_^_End of lines in the input file get converted into spaces, 
    except if followed by an empty line. 

$~\\This follows an empty line in the input.



&&& This follows sucessive empty lines in the input.
\end{filecontents*}

    \makeatletter
\long\def\@gobblethree#1#2#3{}
\long\def\aeafterfi #1#2\fi{\fi #1}

\begingroup
    \catcode1=\active
    \gdef^^A{\begingroup\let\do\@makeother\dospecials\aeaux }
    \gdef\aeaux #1{\ifx #1^^A\aeafterfi{\endgroup\par^^A}%
                    \else   \aeafterfi{ \expandafter\endgroup\@gobblethree}\fi}
\endgroup
    \makeatother

\newcommand*\aeinput [1]{%
    \begingroup
     \endlinechar1
     \catcode1=\active
     \everyeof{\relax\relax\relax\relax}%
     \InputIfFileExists 
         {#1}{}%
         {File `#1' doesn't exist!}% (or using \errmessage)
    \endgroup
}

% character with ascii code 1 made invalid
% apart from its use in \aeinput 
\catcode1=15

\begin{document}

\aeinput{aetesting}

\aeinput{aetesting2} % attempt to input a non-existent file

\aeinput{aetesting} % inputting one more time

\end{document}

aeinput

2
  • Can you explain at all what this is doing? Two things in particular make no sense to me: (1) \gdef^^A. What is this? (2) How does \@gobblethree ever get ahold of a line of input? As far as I can tel you input a file, but nothing gets passed to your line processing commands.
    – A.Ellett
    Jul 30, 2013 at 15:09
  • The (non-printable) character with 8bit ascii code 1, which can be input to TeX as ^^A (A has ascii code 65, and 1=65-64) is made active, and used as end of line character when the file is input. In my initial version it gobbled the next four characters, in the posted version this is a bit more complicated as I wanted to allow empty lines in the input to serve as paragraph break. You said you didn't want verbatim input, and here the only things treated `verbatim' (and suppressed) are the first four characters of each non-empty line. Non-empty lines must have at least 4 characters.
    – user4686
    Jul 30, 2013 at 15:17
0

I'm not totally sure how you intend to use this, so you may need to tell me what to change. What I did was to print out the first line of the file, as is. For all subsequent lines, I gobbled two tokens and then output them.

Here's an approach not using catchfile.

If the input file myfile.tex is

\textbf{This is the first line.}
%%  \textbf{This is the second line.}
123456789

Then this code

\documentclass{article}
\usepackage{readarray}
\makeatletter
%GOBBLE COMMANDS, UP TO 8 BYTES
\newcommand\gobblei{\@gobble}
\newcommand\gobbleii{\@gobbletwo}
\newcommand\gobbleiii{\expandafter\@gobble\@gobbletwo}
\newcommand\gobbleiv{\expandafter\@gobbletwo\@gobbletwo}
\newcommand\gobblev{\expandafter\gobbleiii\@gobbletwo}
\newcommand\gobblevi{\expandafter\gobbleiv\@gobbletwo}
\newcommand\gobblevii{\expandafter\gobblev\@gobbletwo}
\newcommand\gobbleviii{\expandafter\gobblevi\@gobbletwo}
\newcounter{index}
\newcounter{gobbleindex}
\catcode`\%=12
\catcode`\|=14
\newcommand\gobblechars[2]{|
\catcode`\%=12
\catcode`\|=14
  \setcounter{gobbleindex}{#2}
  \readdef{#1}{\tmp}|
  \setcounter{index}{1}|
  \showrecord{1}\\|
  \whiledo{\value{index} < \nrows}{|
    \stepcounter{index}|
    \protected@edef\myrecord{\csname record\roman{index}\endcsname}|
    \def\mygobble{\csname gobble\roman{gobbleindex}\endcsname}|
    \expandafter\mygobble\myrecord|
  \\}|
\catcode`\|=12
\catcode`\%=14
}
\catcode`\|=12
\catcode`\%=14
\makeatother

\parindent 0in
\begin{document}
\gobblei    123456789\\
\gobbleii   123456789\\
\gobbleiii  123456789\\
\gobbleiv   123456789\\
\gobblev    123456789\\
\gobblevi   123456789\\
\gobblevii  123456789\\
\gobbleviii 123456789

\gobblechars{myfile.tex}{2}
\end{document}

produces this output:

enter image description here

At this point, the gobble extent is limited to eight tokens, but that could be manually extended (not quite sure how to automate that extension, if needed). Incidentally, I made | the comment character for the processing of the external file. That can be changed, obviously.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.