2

I am writing a \bashDemo macro that will (a) execute its argument in a shell, e.g., bash, script, and (b) display the argument in a listings. So,

\bashDemo
ls -ls > myfiles
\END

will both run ls -ls >myfiles using the bash command shell, and will display using lstlistings this command within the document. The problem I have is that in consuming characters in a verbatim fashion, I have a newline both at the beginning and at the end of the argument. How do I get rid of these?

Here is my code (it is based on tobiShell.sty):

\lstdefinestyle{bash}{basicstyle={\ttfamily}}
\newwrite\ScriptFile
\edef\ScriptFileName{\jobname.sh}

% Store the argument into our script file.
\newcommand\generateScriptFile[1]{%      
    \immediate\openout\ScriptFile\ScriptFileName
    \immediate\write\ScriptFile{#1}%
    \immediate\closeout\ScriptFile
}

% Store the list of tokens in the argument into our script file
% and then list the contents of that file, prefixed by a "%".
\newcommand\listScriptFile[1]{%
   % The following does not work as expected.
  \generateScriptFile{\%\ignorespaces #1\unskip}\relax
  \lstinputlisting[style=bash]{\bashescScriptFileName}\relax
  \relax
}

\newcommand\bashDemo{\bashDemoI}

{% Define \bashDemoI
  \catcode`\^^M=13%
  \gdef\bashDemoI{%
    \bgroup
    \def\do##1{\catcode`##1 12\relax}%
    \catcode`\^^M=13%
    \def^^M{^^J}%
    \dospecials%
    \bashDemoII%         
  }%
}

{% Define \bashDemoII
  \catcode`\@=0\relax%
  @catcode`@\=12@relax%
  @gdef@bashDemoII#1\END{@relax% 
    @generateScriptFile{#1}@relax%
    @immediate@write18{bash@space@ScriptFileName@space}@relax%
    @listScriptFile{#1}@relax%
    @egroup@relax%
  }@relax%
}
6
  • 1
    You could have a look on the source code of ydoc which does something similar. I remove the trailing and leading new lines as well there. Feb 18, 2011 at 18:20
  • 1
    Just some other tips: You can replace \def\do##1{\catcode`##1 12\relax} with \let\do\@makeother and \catcode`\^^M=13 with \catcode`\^^M\active. I think you want \@percentchar instead of \%. The verbatim \END could be more easily inserted using the common \lcchar/\lowercase trick. I like \begingroup/\endgroup much more then the {, } for this kind of definitions, because they are much more readable. Feb 18, 2011 at 18:25
  • @Martin: many many thanks for the wonderful tips!!!
    – Yossi Gil
    Feb 18, 2011 at 18:39
  • 1
    @Yossi Gil: You are welcome. Removing trailing and leading new lines is a little stupid. I currently have the issue with empty content. In ydoc I have an own definition of the macrocode environment. If it is empty the leading and trailing new-lines are the same! :-) Feb 18, 2011 at 18:44
  • @Martin: Thanks again. I took a look at your code, coming up with a solution, which is not as general purpose as yours, seems to satisfy the needs of this particular domain. See below.
    – Yossi Gil
    Feb 19, 2011 at 8:58

2 Answers 2

1

Not an answer but a suggestion: you are working on so-called literate programming: code and documentation are contained in a file from which code and documentation can be extracted and processed. (Donald Knuth developed TeX as a literate program and coined the term.)

You might want to take a look at a literate programming system like NoWeb. Maybe you have heard of Sweave, which is a literate programming system for the R language. All these systems use LaTeX as part of a tool chain but use other tools as well. Literate programming probably works best on Unix systems.

1

Thanks to gentle Martin Scharrer for leading me to a satisfactory answer. The solution described below is not as general as his code in the ydoc package, but is good enough (I think) for my purposes.

The trick is to define the bashDemoII macro in such a way that it would gobble the end of line characters before and after the contents, i.e.,

 @gdef@bashDemoII^^M#1^^M\END

However, this would not work unless you do

  \catcode`\^^M\active

before hand. So, the complete definition of \bashDemoII is as follows:

\begingroup    % Define \bashDemoII
  \catcode`\@=0\relax%
  @catcode`@\=12@relax%
  @gdef@bashDemoII#1\END{@relax% 
    @generateScriptFile{#1}@relax%
    @immediate@write18{bash@space@ScriptFileName@space}@relax%
    @listScriptFile{#1}@relax%
    @egroup@relax%
  }@relax%
\endgroup
1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .