3

Is it possible to span a lstlisting environment or lstlistinginput on multiple pages, such that the caption is repeated on each page (the listing counter stays the same), as well as being able to customize it on the following pages?

Something similar to what the longtable package provides.

Minimal example where the caption is displayed only once at the top, but should be displayed twice.

\documentclass[12pt,a4paper]{article}
\usepackage[utf8x]{inputenc}
\usepackage{listings}
\usepackage{caption}

\begin{document}

\lstset{
breaklines=true,
breakatwhitespace=false,
xleftmargin=1em,
frame=single,
numbers=left,
numbersep=5pt
}

\begin{lstlisting}[language=C, caption=Example listing of code, label=lst:c1]

struct safe_buffer {
struct list_head node;

/* original request */
void    *ptr;
size_t  size;
int direction;

/* safe buffer info */
struct dmabounce_pool *pool;
void    *safe;
dma_addr_t  safe_dma_addr;
};

struct dmabounce_pool {
unsigned long   size;
struct dma_pool *pool;
#ifdef STATS
unsigned long   allocs;
#endif
};

struct dmabounce_device_info {
struct device *dev;
struct list_head safe_buffers;
#ifdef STATS
unsigned long total_allocs;
unsigned long map_op_count;
unsigned long bounce_count;
int attr_res;
#endif
struct dmabounce_pool   small;
struct dmabounce_pool   large;

rwlock_t lock;

int (*needs_bounce)(struct device *, dma_addr_t, size_t);
};

#ifdef STATS
static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
return sprintf(buf, "%lu %lu %lu %lu %lu %lu\n",
device_info->small.allocs,
device_info->large.allocs,
device_info->total_allocs - device_info->small.allocs -
device_info->large.allocs,
device_info->total_allocs,
device_info->map_op_count,
device_info->bounce_count);
}

static DEVICE_ATTR(dmabounce_stats, 0400, dmabounce_show, NULL);
#endif

\end{lstlisting}
\end{document}

2 Answers 2

4

One idea using the mdframed package and its middleextra, secondextra keys to add a continued caption:

\documentclass[12pt,a4paper]{article}
\usepackage[a5paper]{geometry}% just for the example
\usepackage[utf8x]{inputenc}
\usepackage{listings}
\usepackage{caption}
\usepackage[framemethod=tikz]{mdframed}

\lstset{
breaklines=true,
breakatwhitespace=false,
xleftmargin=1em,
frame=single,
numbers=left,
numbersep=5pt,
}

\newcommand\mylstcaption{}

\surroundwithmdframed[
hidealllines=true,
middleextra={
  \node[anchor=west] at (O|-P)
    {\lstlistingname~\thelstlisting\  (Cont.):~\mylstcaption};},
secondextra={
  \node[anchor=west] at (O|-P)
    {\lstlistingname~\thelstlisting\  (Cont.):~\mylstcaption};},
splittopskip=2\baselineskip
]{lstlisting}

\begin{document}

\renewcommand\mylstcaption{Example listing of code}
\begin{lstlisting}[language=C, caption=\mylstcaption, label=lst:c1]

struct safe_buffer {
struct list_head node;

/* original request */
void    *ptr;
size_t  size;
int direction;

/* safe buffer info */
struct dmabounce_pool *pool;
void    *safe;
dma_addr_t  safe_dma_addr;
};

struct dmabounce_pool {
unsigned long   size;
struct dma_pool *pool;
#ifdef STATS
unsigned long   allocs;
#endif
};

struct dmabounce_device_info {
struct device *dev;
struct list_head safe_buffers;
#ifdef STATS
unsigned long total_allocs;
unsigned long map_op_count;
unsigned long bounce_count;
int attr_res;
#endif
struct dmabounce_pool   small;
struct dmabounce_pool   large;

rwlock_t lock;

int (*needs_bounce)(struct device *, dma_addr_t, size_t);
};

#ifdef STATS
static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
return sprintf(buf, "%lu %lu %lu %lu %lu %lu\n",
device_info->small.allocs,
device_info->large.allocs,
device_info->total_allocs - device_info->small.allocs -
device_info->large.allocs,
device_info->total_allocs,
device_info->map_op_count,
device_info->bounce_count);
}

static DEVICE_ATTR(dmabounce_stats, 0400, dmabounce_show, NULL);
#endif

\end{lstlisting}

\end{document}

enter image description here

Before each lstlisting environment you redefine \mylstcaption with the text of the caption.

For \lstinpulisting, the general idea is the same, but using this time a \newmdenv; to avoid unnecessary code duplication, a style was defined:

\documentclass[12pt,a4paper]{article}
\usepackage[a5paper]{geometry}% just for the example
\usepackage[utf8x]{inputenc}
\usepackage{listings}
\usepackage{caption}
\usepackage[framemethod=tikz]{mdframed}

\lstset{
breaklines=true,
breakatwhitespace=false,
xleftmargin=1em,
frame=single,
numbers=left,
numbersep=5pt,
}

\newcommand\mylstcaption{}

\mdfdefinestyle{mymdstyle}{
hidealllines=true,
middleextra={
  \node[anchor=west] at (O|-P)
    {\lstlistingname~\thelstlisting\  (Cont.):~\mylstcaption};},
secondextra={
  \node[anchor=west] at (O|-P)
    {\lstlistingname~\thelstlisting\  (Cont.):~\mylstcaption};},
splittopskip=2\baselineskip
}

\surroundwithmdframed[style=mymdstyle]{lstlisting}
\newmdenv[style=mymdstyle]{mdlisting}

\begin{document}

\renewcommand\mylstcaption{Example listing of code}
\begin{mdlisting}
\lstinputlisting[language=C, caption=\mylstcaption, label=lst:c1]{file}
\end{mdlisting}

\end{document}

Update

Here's now the same idea but using now tcolorbox:

\documentclass[12pt,a4paper]{article}
\usepackage[utf8x]{inputenc}
\usepackage[many]{tcolorbox}
\tcbuselibrary{listings}

\lstset{
  breaklines=true,
  breakatwhitespace=false,
  xleftmargin=1em,
  frame=single,
  numbers=left,
  numbersep=5pt,
}

\newtcblisting{TCBlisting}[1][]{
  breakable,
  enhanced,
  arc=0pt,
  outer arc=0pt,
  boxrule=0pt,
  colback=white,
  listing only,
  listing remove caption=false,
  listing options={#1},
  overlay middle and last={
  \node[anchor=south west,text width=\columnwidth] at (frame.north west)
    {\lstlistingname~\thelstlisting\  (Cont.):~\mylstcaption};
  }
}

\newcommand\mylstcaption{}

\begin{document}

\renewcommand\mylstcaption{Example listing of code with a long caption spanning several lines in a two-column document. this is just a test for the example.}
\begin{TCBlisting}[language=C,caption={\mylstcaption}]
struct safe_buffer {
struct list_head node;

/* original request */
void    *ptr;
size_t  size;
int direction;

/* safe buffer info */
struct dmabounce_pool *pool;
void    *safe;
dma_addr_t  safe_dma_addr;
};

struct dmabounce_pool {
unsigned long   size;
struct dma_pool *pool;
#ifdef STATS
unsigned long   allocs;
#endif
};

struct dmabounce_device_info {
struct device *dev;
struct list_head safe_buffers;
#ifdef STATS
unsigned long total_allocs;
unsigned long map_op_count;
unsigned long bounce_count;
int attr_res;
#endif
struct dmabounce_pool   small;
struct dmabounce_pool   large;

rwlock_t lock;

int (*needs_bounce)(struct device *, dma_addr_t, size_t);
};

#ifdef STATS
static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
return sprintf(buf, "%lu %lu %lu %lu %lu %lu\n",
device_info->small.allocs,
device_info->large.allocs,
device_info->total_allocs - device_info->small.allocs -
device_info->large.allocs,
device_info->total_allocs,
device_info->map_op_count,
device_info->bounce_count);
}

static DEVICE_ATTR(dmabounce_stats, 0400, dmabounce_show, NULL);
#endif

\end{TCBlisting}
\end{document}
\begin{lstlisting}[language=C, caption=\mylstcaption, label=lst:c1]

struct safe_buffer {
struct list_head node;

/* original request */
void    *ptr;
size_t  size;
int direction;

/* safe buffer info */
struct dmabounce_pool *pool;
void    *safe;
dma_addr_t  safe_dma_addr;
};

struct dmabounce_pool {
unsigned long   size;
struct dma_pool *pool;
#ifdef STATS
unsigned long   allocs;
#endif
};

struct dmabounce_device_info {
struct device *dev;
struct list_head safe_buffers;
#ifdef STATS
unsigned long total_allocs;
unsigned long map_op_count;
unsigned long bounce_count;
int attr_res;
#endif
struct dmabounce_pool   small;
struct dmabounce_pool   large;

rwlock_t lock;

int (*needs_bounce)(struct device *, dma_addr_t, size_t);
};

#ifdef STATS
static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct dmabounce_device_info *device_info = dev->archdata.dmabounce;
return sprintf(buf, "%lu %lu %lu %lu %lu %lu\n",
device_info->small.allocs,
device_info->large.allocs,
device_info->total_allocs - device_info->small.allocs -
device_info->large.allocs,
device_info->total_allocs,
device_info->map_op_count,
device_info->bounce_count);
}

static DEVICE_ATTR(dmabounce_stats, 0400, dmabounce_show, NULL);
#endif

\end{lstlisting}

\end{document}

enter image description here

4
  • Would it be possible to do the same with an \lstinputlisting command? It seems that it does not use the environment directly, so frame changes are not applied.
    – alcroito
    Commented Jun 6, 2013 at 0:34
  • @Placinta yes, it's possible with a slight variation. Please see my updated answer. Commented Jun 6, 2013 at 0:41
  • 1
    @Placinta I've made a simplification to my last code. Commented Jun 6, 2013 at 0:58
  • The method works fine except if the listing has a lot of lines, latex goes out of memory. To list a 700 line source code on multiple pages, I had to increase memory from 3MB to 200MB, and though it works, it takes a lot longer to compile. (From 2-3 seconds to about 30 seconds).
    – alcroito
    Commented Jun 6, 2013 at 1:19
-1

You could just input the file directly, i.e:

\lstinputlisting[language=C]{./Code/nameofthefile}

Of course, you can setup everything in your preamble with \lstset, as you have in your MWE.

2
  • 1
    I'm sorry, but my question was not about how to read the source code from a file, but rather how to span it on multiple pages with captions on each page.
    – alcroito
    Commented Jun 6, 2013 at 0:19
  • 1
    @Placinta my bad, I understood incorrectly Commented Jun 6, 2013 at 0:26

You must log in to answer this question.

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