LaTeX: Lstlisting automatically recognizing code passage
I am writing a program (in C, but I suppose that's not so relevant) in connection with a little documentary material in LaTeX. I want the documentary material to contain code snippets from my original code.开发者_高级运维
In order to include source code and keep it up to date, I do the following in my document:
\lstinputlisting[firstline=200, lastline=210]{../src/source.c)
This loads automatically the lines 200 to 210 (which contain e.g. a function) from ../src/source.c
into my document.
However, if I add some lines before line 200, this means that line 200 "wanders down some lines", so I have to adjust this in order to get my original function.
So here's my question: Does anybody know about a possibility how to dynamically tell lstinputlisting
(or any adequate substitute) to tell which lines to take?
I imagine something like the following: I add special comments to my C source code that will be recognized by lstinputlisting
, e.g.
/// lstinputlisting "myfunc" BEGIN
int myFunction(int x){
return x+2;
}
/// lstinputlisting "myfunc" END
Then, lstlisting
scans the file and just includes the lines between the BEGIN
and the END
things.
I am answering a few months after your post, but the feature of lstlistings I describe below has been in that package for several years.
The keyword to look for is the option linerange
, as well as, for convenience, rangeprefix
and rangesuffix
.
Here is a complete example.
\documentclass{article}
\usepackage{fullpage,times,listings}
\lstloadlanguages{C++}
\lstset{language=C++,keywordstyle=\bfseries,commentstyle=\itshape,
rangeprefix=//----------------,rangesuffix=----------------,
includerangemarker=false,columns=spaceflexible}
\begin{document}
We first show the main function.
\lstinputlisting[linerange=main0-main1]{code.cpp}
Then we show the implementation.
\lstinputlisting[linerange=fact0-fact1]{code.cpp}
\end{document}
then save the following in code.cpp:
#include <cassert>
//----------------fact0----------------
// A recursive implementation of factorial
int factorial(int i)
{
if(i)
return i * factorial(i-1);
else
return 1;
}
//----------------fact1----------------
//----------------main0----------------
// Test the implementation.
int main()
{
assert(factorial(5) == 120);
}
//----------------main1----------------
This is a good solution because one inevitably edits the code, and then it becomes tedious to update the line numbers throughout one's TeX files. Using symbols solves this problem, but it also leaves a trace in the code itself that if the number of lines changes, or if the width changes too much, one needs to confirm that the typeset output still looks reasonable.
Finally, after editing the code, you need to typeset the latex files again only if you inserted/deleted within the marked blocks.
The only reasonable way of making this happen that I can think of off the top of my head, is to create a makefile and have that be responsible for producing the correct output.
Assuming sourcefile.c is in ./src and LaTeX files are in ./tex then ./tex/Makefile could look something like this:
doc.tex: sourcefile.grep
<command to compile doc.tex>
sourcefile.grep:
<command to grep/whatever to dump from
../src/sourcefile.c to ./tex/sourcefile.grep>
And the lstlistings in doc.tex would then point to ./src/sourcefile.grep
Would not be easier to use #include
in C?
It is not perfect, but good enough, solution.
Here is an example (could not compile, I'd written last time something in C
5 years ago):
Main C
program:
#include <stdio.h>
//function included from separate file -- will be included in LaTeX too
#include "fun_x.c"
int main()
{
int d = 0;
printf("%d", fun_x(d));
//code included from separate file -- will be included in LaTeX too
#include "calc.c"
return 0;
}
fun_x.c
file:
int fun_x(int c)
{
c++;
return c;
}
calc.c
file:
d = 99;
d = fun_x(d);
LaTeX source:
\begin{document}
...
\lstinputlisting{../src/fun_x.c)
...
\lstinputlisting{../src/calc.c)
...
\end{document}
Something like this was discussed on the TeX SE a while back and one answer used a package catchfilebetweentags
. This doesn't solve your problem directly, but perhaps you can use that to feed the fragment you want to \lstlistings
, perhaps again with a temporary file.
精彩评论