LISTINGS.DTX Version 0.15

\begin{matrix}c \\ ◯ \end{matrix} 1996–1997 by Carsten Heinz

Contents

1 User’s guide 2 1.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Typesetting a listing . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.4 Output styles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.5 Selecting a language . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.6 Other languages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 1.7 It’s not all fine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2 How the package works 7 2.1 The main idea . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 Line processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.3 Tokenizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.4 Special characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3 Implementation 10 3.1 Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.2 Registers and variables . . . . . . . . . . . . . . . . . . . . . . . . . 11 3.3 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 3.4 Keywords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 3.5 Commands . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 3.6 Line processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 3.7 Tokenizing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 3.8 Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3.9 Special characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 3.10 Initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

4 Language driver files 25

5 Samples 32

6 Extensions 33

7 History 34

1 User’s guide

1.1 Introduction

You have a problem? You wanna typeset C, C++, Eiffel, Fortran 90, Java, Modula-2, Pascal, Pascal XSC or Turbo Pascal code within L^{A}TEX 2ε like

switch ( d i r e c t i o n )
{ / / choose d i r e c t i o n
case backward  : { … break ; }
case backwarddown : { … break ; }
case up  : { … break ; }
case forwardup  : { … break ; }
}
const char ∗ s t r i n g = ” S t r i n g s ␣␣ are ␣ s u p p o r t e d . ” ;

or

for i :=maxint downto 0 do

begin

{ we do
n o t h i n g }
end ;
WriteLn ( ’ P a s c a l ␣ keywords ␣ are ’ ) ;
writeln ( ’ not ␣ c a s e ␣ s e n s i t i v e . ’ ) ;

Obviously the verbatim environment doesn’t fit. You might use the tabbing environment or something like that. But you have to mark all keywords yourself and doing the indention is also a heavy work. But the most striking disadvantage is that you can’t run your L^{A}TEX 2ε-file through your C, C++, Eiffel or whatever else compiler.

Fortunately there is another possibility. You might use a cross compiler, e.g. you run a special compiler on your Pascal source code to get a TEX-file with marked keywords, etc. Then TEX produces a pretty output (usage of a well-designed cross compiler granted). If your sources change, you would have to rerun the cross compiler to get your TEX-file right and have to compile this to get your document. Again and again.

By now these days have gone. The listings package goes around this by reading the source code directly. Comments, strings and keywords can be typeset in different styles as shown by the examples above. The indention is taken from the sources. Hence, the programmer is responsible for writing ’readable’ code. The package only helps to present it.

This package is surely not the final utility for typesetting listings. May be it’s a matter of pureness whether to use a cross compiler or the listings package. Hope you join it and help to get this tool more powerful. Please report all errors and offer improvements!

1.2 Installation

The listings package consists of following files:

    listings.dtx    listings.ins     listings.dvi

    listing1.cpp    listing2.pas     listing3.cpp
    testfile.pas
    listings.sty    lstblank.sty     lstc.sty
    lstcpp.sty      lsteiffel.sty    lstfortran.sty
    lstjava.sty     lstmodula.sty    lstpascal.sty
    lstpxsc.sty     lsttp.sty

The exact names are system dependent. It doesn’t matter, if you only have the .dtx- and .ins-file. In that case run listings.ins through TEX and then listings.dtx. You will get all the other files. To install the package copy all eleven .sty-files to a directory searched by TEX. You might want to create a subdirectory. The installation is complete.

Important note: All files mentioned are distributed freely. You are not allowed to take money for the distribution or use of these files, except for a nomial charge for copying etc. The files are distributed without any warranty; without even the implied warranty of merchantability or fitness for a particular purpose. You are not allowed to change one of the files, except using a clearly different filename.

Trademarks appear throughout this documentation without any trademark symbol. So you can’t assume that a name is not trademarked. There is no intention of infringement. The usage is to the benefit of the trademark owner.

1.3 Typesetting a listing

\inputlisting The main command for this purpose is \inputlisting. The syntax is

    \inputlisting[FIRST,LAST]{WHOLE FILENAME}

where [FIRST,LAST] is optional and determines the range of lines to typeset, but at least one line will be printed. The default range is [1, 999999]. If you specify negative lines or an empty range, for example, you won’t get any warning. There is no default extension, so you must specify the whole filename. The example

    \inputlisting[3,10]{testfile.pas}

would print lines 3,4,…,10 of testfile.pas.

listing There is also a listing environment. It typesets the source code enclosed within \begin{listing} and \end{listing}. If the source code starts right after \begin{listing} you will get a bad output, since that line has not the correct position. Additionally the source preceding \end{listing} is not output and the rest of the line is not typeset by TEX. You may don’t like this, but the lines

\fortranlisting
\begin{listing}
* This is a test for the listing environment
C and not considered to be an example for
   ! Fortran!
      PROGRAM example
      ...
\end{listing}

result in

∗ T h i s i s a t e s t f o r t h e l i s t i n g e n v i r o n m e n t
C a n d n o t c o n s i d e r e d t o b e a n e x a m p l e f o r
! F o r t r a n !
PROGRAM e x a m p l e
…

\listingfalse Since typesetting listings with this package is possibly slow, you can suppress \listingtrue the output with \listingfalse. Afterwards this package only prints the name of

the source like

— Listing of testfile.pas has been skipped. —

\listingtrue reverses the effect.

\tablength If you use tabulators in your source codes, you have to tell this package the number of characters between two tabulator stops. Default value is 4. Changes are made by, e.g.,

    \tablength{8}

i.e. tabulator stops are set at the columns 1, 9, 17, 25 … Negative values are prohibited. They won’t confuse this package, since it gives an error message and proceeds with the old value of tablength.

\prelisting The commands \prelisting and \postlisting have one argument each and \postlisting can be used to add something right before a listing starts or after it ends, e.g.

\prelisting{\bigbreak} will lead to an empty line between a listing and the text above (if on the same page). A useful application of the pre-post-mechanism is the selection of fontsize and / or the change of textwidth. The C++ source line

i f ( ThereIsALongLine ) { I t E x c e e d s A S i n g l e L i n e I n T h e L i s t i n g ( ) ; }

gives rise to an overfull \hbox. You should use

    \prelisting{\footnotesize % select new fontsize
                \advance\textwidth by 1in %spread textwidth by 1 inch
                \advance\leftskip by -0.5in   % add 0.5 inch
                \advance\rightskip by -0.5in} % on each side
    \postlisting{} % nothing to do (default)

or something similar and get

i f ( T h e r e I s A L o n g L i n e ) { I t E x c e e d s A S i n g l e L i n e I n T h e L i s t i n g ( ) ; }

Note: This is a ’brute force’ example. The change of the fontsize is harmless, but there is no guarantee that the changes to textwidth and the skips work with all of L^{A}TEX 2ε. Be careful and report success and failure!

1.4 Output styles

You have some possibilities to change how the output looks like.

\keywordstyle By default keywords are typeset bold, comments in italic shape and strings

\commentstyle
\stringstyle

using no special style. You can change this with the commands \keywordstyle,

\commentstyle and \stringstyle, e.g.
    \keywordstyle{\bfseries\itshape} % bold and italic
    \commentstyle{\tt\small}         % LaTeX 2.09 typewriter, small
    \stringstyle{\ttfamily}          % typewriter

will typeset the first example of the introduction as follows

switch ( d i r e c t i o n )

     { //  choose  direction

case backward  : { … break ; }
case backwarddown : { … break ; }
case up  : { … break ; }
case forwardup  : { … break ; }
}

     const char ∗ s t r i n g = "Strings␣␣are␣supported." ;

\blankstringtrue Once again blank spaces of a string have been printed ␣. Suppress this by

\blankstringfalse using \blankstringtrue and switch to default with \blankstringfalse.

\normallisting Changes made by the commands above are reset by \normallisting (there are no arguments): Keywords are typeset bold, comments in italic shape, stringstyle and pre- and postlisting are empty and blank spaces in strings are printed ␣. The selected programming language is not affected.

1.5 Selecting a language

There are two ways to do this. When you load the package in the preamble, you can choose a language by one of the options

   blank  c  cpp  eiffel  fortran  java  modula  pascal  pxsc  tp

e.g.

    \usepackage[c,cpp,pascal]{listings}

loads all definitions for C, C++ and Pascal listings, but the last specified language is selected. Default option and language is blank: no keywords and no comments are detected (unless additional keywords are specified, see section 1.6).

In your document you can change the language with the commands

    \blanklisting    \clisting         \cpplisting
    \eiffellisting   \fortranlisting   \javalisting
    \modulalisting   \pascallisting    \pxsclisting
    \tplisting

e.g.

    \inputlisting[3,10]{testfile.pas}
    \cpplisting                 % switch to C++
    \inputlisting{testfile.cpp}

If you haven’t used the corresponding option, the languages are loaded on demand. Note: Language selection is global, i.e. the language is changed in outer blocks by selecting another language in an inner group.

1.6 Other languages

You have some possibilities to adapt this package to other languages. For our purpose here the main characteristics of a language are keywords, comments and strings.

\morekeywords With the blank option you can produce verbatim-like output. But it is also possible to add your own keywords. Use the command \morekeywords like

    \morekeywords{maxreal,minreal} % add these keywords
    \morekeywords{zero,MAXINT}     % add also

\keywords If you want the old keywords deleted, use \keywords instead. After

    \keywords{one,two,three,four,five,six,seven,eight,nine,ten,%
        eleven,twelve}

exactly these twelve keywords are present. The remark character % at the end of the first line is essential! Otherwise one keyword would be ’␣eleven’, but a keyword must begin with a letter.

\sensitivetrue Some languages are case sensitive, others are not. You can select this with

\sensitivefalse  \sensitivetrue and \sensitivefalse, respectively. This package will then use

the right keyword test.

\stringizer The command \stringizer changes the character, which begins and ends a string. If your parameter consists of several characters, each character can start a string. But the string must be terminated with the same character. Using a letter, a digit or the underbar as stringizer will not work. The Modula-2 option defines the stringizer by

    \begingroup
    \catcode`\"=12
    \stringizer{'"}
    \endgroup

The catcode is locally changed for compatibility with german.sty. The double quote is defined active there, but when we input a listing the double quote will have catcode 12 (=other).

Let’s come to comments. For our purpose a ’comment line’ is a comment, which starts with a character sequence and goes upto the end of a line. ’Comments’ start and end with given character sequences. Comment lines need not to begin at the first column and comments can start and end wherever you want.

\DeclareCommentLine      \DeclareCommentLine has one parameter, which is terminated by \relax, i.e.
    \DeclareCommentLine //\relax

is legal. The parameter is a (nearly) arbitrary character sequence, which separates a comment line. Using a letter, a digit or the underbar will not work. And: When we input a listing, the characters must have the same category codes. Refer section 2.4 and 3.9. If you don’t want any comment lines, let the parameter empty, but don’t forget the \relax!

\DeclareSingleComment Three types of comments are supported: single for languages with one kind

\DeclareDoubleComment
\DeclareNestedComment

of comment, e.g. C or C++; double for languages with two kinds of comments, e.g. Pascal comments enclosed within (* and *) and within { and }; nested for languages with one kind of comment, which can be nested, e.g. Modula-2. The declaration of such comments is similar to comment lines. The character sequences are separated by one blank space, e.g.

    \DeclareSingleComment /* */\relax
    \DeclareDoubleComment (* *) { }\relax
    \DeclareNestedComment (* *)\relax

But hold on: When we input a listing, the characters must have the same category codes. So the examples won’t work without changing them. See section 3.9. If you don’t want comments, let the second parameter of \DeclareSingleComment empty, i.e. type something like

␣␣␣␣\DeclareSingleComment␣stuff␣\relax

Note: Any language selecting command will reset keywords, comments and stringizer. You possibly need to redefine them, when you call such a command.

1.7 It’s not all fine

Please be patient of my English.

Not all languages have been tested fully, since I don’t know all languages well. Hope I haven’t forgotten any important feature of a language.

I have considered to implement more languages, e.g. Matlab. But there are so many potential keywords and I don’t want to decide, which words should be marked. Help me!

You’re not lucky about the listings package? You found errors? Damn and blast it or contact me:

    cheinz@wmpi04.math.uni-wuppertal.de

2 How the package works

What happens when a user calls \inputlisting? First we set up a bit (execute prelisting, open input file, do other initialization) and at the end we have to close the input file for example.

2.1 The main idea

The interesting part is the loop between: The source file is read, processed and typeset line by line. Before looking closer we have to deal with the alignment of columns, since this influences processing and typesetting. The problem: I don’t like listings, which are printed with typewriter fonts. But only in these fonts all characters have the same width. So we have to handle different widths. The Pascal source lines

    if x=y then write('alignment')
           else print('alignment');

shouldn’t come out as

if x=y then write(’alignment’) else print(’alignment’);  or  if x=y then write(’alignment’) else print(’alignment’);

only because blank spaces are not wide enough or because a bold letter has more width than a normal one.

There is a simple trick to avoid things like that. We make boxes of the same width and put one character in each box:

i f  x = y  t h e n  w r i t e  …
e l s e  p r i n t  …

Going this way the alignment of columns can’t be disturbed. But if the boxes are not wide enaugh, we get

i f x=y then wr i te …

And choosing the width so that the widest character fits in, leads to

i f x = y t h e n w r i t e …

Both are not acceptable. So there is more to do. Each input line will be cut up in logical units. Since we want to scan for keywords, this is no extra work. In the example the units are

if, x, =, y, then, write, …

and the blank spaces between. We put each unit in a box, which width is multiplied by the number of characters we put in, of course. The result is

i f  x = y  t h e n  w r i t e  …

Now we are ready to choose the base width of a box. Consider the ’write’. The ’w’ needs more space than base width, but the ’i’ needs less. This will compensate each other, because we put them in the same box. In general: Since wide characters use space actually reserved for thin characters, the base width need not to be the width of the widest character. This would be 1em (a \quad). But we use the empirical value 0.65em. It’s a compromise between overlapping characters and the number of boxes exceeding not the textwidth, i.e. how many characters fit a line without getting an overfull \hbox.

2.2 Line processing

Let’s discuss the line processing. The job is to classify comments, strings and other source code, where we search for keywords. We do that in several steps.

• First we pay attention on comments, which started in preceding lines, e.g.

         comment } for i:=1 to maxint do ...

In that case we look for the end of comment and output the comment. If there is other source code left, we run the line processing on that code.

• If no comment is in work, we look for one and split the input into comment and other source code. Since the other code comes first, we give it to a routine, which cuts it into the units described above (tokenizing). The output takes place there.

• Afterwards we have to output the comment. But when we look for a comment, we don’t take notice of other things. Consider

         writeln('This is a string { and not a comment }');

We cut this line at the left brace into other code and comment. After typesetting the other code we notice, that a string started, but hasn’t been finished. Our first classification was wrong. We use the comment as new input and simply run the line processing again to continue the string.

• If all strings are finished, we can output the comment, since it’s really a comment.

This is a sketch of line processing. For more detailed information see section 3.6, where the implementation is described.

One question about the third item is left: Why do we cut off a comment, even if we don’t know that it is a comment? It’s a matter of modularity and extension. Consider the alternative: The tokenize routine below (where we cut the classified input into the smallest units) would have to look for the start and end of comment. To support different languages we have to write either more than one tokenize routine or one, which handles comments of all languages. Adding another language means extending tokenizing or writing a new routine, which looks only for the particular comment. But finding a comment has nearly nothing to do with looking for delimiters (blank space, comma, plus, bracket, etc.). So we write exactly one tokenize macro and have several routines finding a comment to support different languages.

2.3 Tokenizing

The next step is breaking up the parts produced by line processing into the units mentioned above. We gather all characters, until reaching a nonletter. Then we output the collected characters using a routine, which selects the right style (comment, keyword, string). Afterwards we handle the nonletter:

If it is a stringizer, we switch a string boolean to indicate whether we are in string mode or not. This boolean is also used by the line processing.

If we found a tabulator, we typeset blank spaces to reach the next tabulator stop. The output routines are responsible for knowing the number of blanks we need.

2.4 Special characters

As you know some characters have a special meaning to TEX, e.g. the subscript _or the backslash \. TEX realizes this using so called category codes (catcodes). TEX knows sixteen different ones:

0 escape delimiter (backslash) \catcode`\\=0
1 beginning of a group ({)  \catcode`\{=1
2 ending of a group (})  \catcode`\}=2
3 mathematics shift ($)  \catcode`\$=3

            4 tabulator (&)  \catcode`\&=4

5 end of line (carriage return) \catcode`\^^M=5
6 macro parameter (#)  \catcode`\#=6

            7 superscript (^)  \catcode`\^=7
            8 subscript (_)  \catcode`\_=8
            9 ignore  \catcode`\^^@=9
           10 blank space  \catcode`\ =10

11 letter  A..Z,a..z
12 other
13 active (e.g. ~)

           14 comment  \catcode`\%=14

15 invalid characters

When TEX reads a character, it looks up the associated catcode and treats the character accordingly, e.g. an active character stands for a command without a leading backslash (like ~ or the double quote in german.sty).

We can’t change catcodes of characters, which TEX has already read. But we are able to change them before. After \catcode`\A=10 an upper ’A’ has the same effect as a blank space! Consider the TEX-source

    \def\uppera{A} % saving upper 'A'; we can't use \upperA. Why?
    \catcode`\A=10 % 'A' becomes blank space. That's the reason!
    MayAbeAaAcuriousAexample. \upperaAnd it work's.

The output is

    May be a curious example. And it work's.

First we save the ’A’. Changing the catcode has no effect on the definition in the first line, since TEX has read it before. All coming ’A’ are blank spaces.

We want to input and typeset characters ’as they are’. But the subscript or the macro parameter character are not printable. So it is necessary to change catcodes. We make these characters active. We also change catcodes of printable characters, e.g. a digit (normally other) will be treated as a letter, since indentifiers like x1, y2 are legal. Then it is possible to gather all characters upto a nonletter to cut up a unit!

We change catcodes for input and output. That’s clear. But we also do it to define some commands. One example: In Pascal we have to look for {. Let’s say, we compare it with a left brace from a source file. This only works, if both have the same meaning. And when we declare the comment, TEX must know the associated catcode, since it can’t be changed later. Hence, we have to change it also at the time of defining the macros.

There is at least one more thing to say: Catcodes aren’t easy to work with.

3 Implementation

Before considering the implementation, here some conventions I used:

• The name of all public macros (the user commands) use lowercase letters.

• The name of all private macros and variables use the prefix lst@.

• To distinguish procedure-like macros from macros holding data, the name of procedure macros use uppercase letters with each beginning word, e.g.

     \lst@ProcessLine.

3.1 Options

First we declare the options, which are executed and processed at the very end of this file. They call the language commands.

1 ⟨∗package⟩

 2 \DeclareOption{blank}  {\blanklisting}
 3 \DeclareOption{c}      {\clisting}
 4 \DeclareOption{cpp}    {\cpplisting}
 5 \DeclareOption{eiffel} {\eiffellisting}
 6 \DeclareOption{fortran}{\fortranlisting}
 7 \DeclareOption{java}   {\javalisting}
 8 \DeclareOption{modula} {\modulalisting}
 9 \DeclareOption{pascal} {\pascallisting}
10 \DeclareOption{pxsc}   {\pxsclisting}
11 \DeclareOption{tp}     {\tplisting}

The language commands call \lst@Listing to load the language driver file and to select the language.

12 \newcommand\blanklisting  {\lst@Listing{blank}}
13 \newcommand\clisting      {\lst@Listing{c}}
14 \newcommand\cpplisting    {\lst@Listing{cpp}}
15 \newcommand\eiffellisting {\lst@Listing{eiffel}}
16 \newcommand\fortranlisting{\lst@Listing{fortran}}
17 \newcommand\javalisting   {\lst@Listing{java}}
18 \newcommand\modulalisting {\lst@Listing{modula}}
19 \newcommand\pascallisting {\lst@Listing{pascal}}
20 \newcommand\pxsclisting   {\lst@Listing{pxsc}}
21 \newcommand\tplisting     {\lst@Listing{tp}}

\lst@Listing This command loads the specified driver file and selects the language. We give an error message, if the driver file doesn’t support the necessary macro.

22 \newcommand\lst@Listing[1]{%
23  \@ifundefined{lst@#1}{\input{lst#1.sty}}{}%
24  \@ifundefined{lst@#1}{%
25  \PackageError{Listings}{Driver file for `#1' corrupt}{%
26  The driver file doesn't define the macro \string\lst@#1.}}%
27  {\csname lst@#1\endcsname \def\lst@curr{#1}}}

3.2 Registers and variables

We will need some variables.

\lst@inputfile \if@lst@endinput \iflisting The logical input file is \lst@inputfile. The output of the file terminates, if and

only if the boolean \if@lst@endinput is true. \iflisting is described in the user’s guide.

28 \newread\lst@inputfile  \newif\if@lst@endinput  \newif\iflisting

\lst@last@line \lst@current@line The user specified last line and the current input line are kept in two counters:

29 \newcount\lst@last@line  \newcount\lst@current@line

\if@lst@comment \if@lst@string \lst@comment@depth Comments (not whole comment lines) and strings are indicated by following booleans. The current comment depth uses a counter.

30 \newcount\lst@comment@depth
31 \newif\if@lst@comment  \newif\if@lst@string

\lst@width \lst@length The dimension \lst@width holds the width of a single character box and is set to 0.65em, when we output a listing. The counter \lst@length holds the length of the current character string we want to output.

32 \newdimen\lst@width  \newcount\lst@length

\lst@tab@length \lst@pos The first counter saves the parameter of the \tablength command. \lst@pos holds the current column number to handle tabulators.

33 \newcount\lst@tab@length  \newcount\lst@pos

\lst@line \lst@comment \lst@commentline Some variables need no allocation here, since they are macros, e.g. most user commands save their parameter within a macro. The most important ’data’ macros

are \lst@line, \lst@comment and \lst@commentline. They hold the current

line, comment and comment line for line processing.

3.3 Comments

First we discuss comment lines (CL). Let’s say, we have a C++ source line with a comment, which is separated by ’//’. To cut the line into code and comment we

\lst@CutCL use a macro like this:

    \def\lst@CutCL#1//#2\relax{%
        \def\lst@line{#1}%
        \def\lst@commentline{//#2}%
    }

The parameter definition ensures, that the first parameter holds the code and our second paramater the comment upto a \relax, which will terminate the input. We redefine the input and comment line, where we must add the separator ’//’

\lst@CommentLine again. That’s easy. But if we call this macro using a line without any ’//’, TEX detects a syntax error, since the line doesn’t meet the definition. Hence, to look for a comment line we can’t use the cut macro, but this:

    \def\lst@CommentLine{%
        \expandafter\lst@TestCL\lst@line//\relax %
    }

Additional ’//’ and ’\relax’ hold up the syntax of the cut macro. That’s the point. We use an \expandafter, because we need the content of \lst@line and not the token itself as parameter. So the test macro is called (or expanded) after

\lst@TestCL the content is written behind.

Why we don’t use the cut macro here? Our additional ’//’ would be added to the comment! Therefore:

    \def\lst@TestCL#1//#2\relax{%
        \def\test{##2}%

        \ifx\test\empty %
            \let\lst@commentline=\empty %
        \else %
            \expandafter\lst@CutCL\lst@line\relax %
        \fi %
    }

If you compare the definition of \lst@TestCL here and the call above, you will see: The second parameter is empty, if and only if there is no comment (no double slash). So we are able to call the cut macro without additional ’//’, if we’ve found a comment.

\DeclareCommentLine \lst@CommentLine \lst@TestCL \lst@CutCL Now comes the real implementation. It’s different from the C++ example, but it only seems to. The one and only parameter of \DeclareCommentLine ist the comment line separator. First we test, if comment lines are desired. If not, we let the main macro be empty. Otherwise we define three macros similar to the example. But: To distinguish their parameters from the comment line separator #1, we have to double the ’#’: The nth parameter of a macro within a macro is ##n. If you know this, following is clear: It’s the same as the simplified example.

34 \def\DeclareCommentLine#1\relax{\def\test{#1}%
35 \ifx\test\empty \let\lst@CommentLine=\empty %
36 \else
37  \gdef\lst@CommentLine{\expandafter\lst@TestCL\lst@line#1\relax}%
38  \long\gdef\lst@TestCL##1#1##2\relax{%
39  \def\test{##2}%
40  \ifx\test\empty \let\lst@commentline=\empty %
41  \else \expandafter\lst@CutCL\lst@line\relax %
42  \fi}%
43  \gdef\lst@CutCL##1#1##2\relax{%
44  \def\lst@line{##1}\def\lst@commentline{#1##2}}%
45 \fi}

\DeclareSingleComment \lst@SOC \lst@EOC For single comments we use the same cut mechanism as above, except that we use it for the start of comment (SOC) and for the end of comment (EOC): We define six macros here. Additional the comment boolean is switch by the cut macros. The two parameters of \DeclareSingleComment are the character sequences for the beginning and ending of a single comment, of course.

46 \def\DeclareSingleComment#1 #2\relax{\def\test{#2}%
47 \ifx\test\empty %
48  \let\lst@SOC=\empty \let\lst@EOC=\empty %
49 \else %
50  \gdef\lst@SOC{\expandafter\lst@TestSOC\lst@line#1\relax}%
51  \long\gdef\lst@TestSOC##1#1##2\relax{%
52  \def\test{##2}%
53  \ifx\test\empty\else %
54  \expandafter\lst@CutSOC\lst@line\relax %
55  \fi}%
56  \gdef\lst@CutSOC##1#1##2\relax{\@lst@commenttrue %
57  \def\lst@line{##1}\def\lst@comment{#1##2}}%
58  \gdef\lst@EOC{\expandafter\lst@TestEOC\lst@line#2\relax}%
59  \long\gdef\lst@TestEOC##1#2##2\relax{%
60  \def\test{##2}%
61  \ifx\test\empty %

Here we are in the situation, that we look for the end of comment but haven’t found one. Since we are in comment mode, the whole line is the comment and the line gets empty.

62  \let\lst@comment=\lst@line \let\lst@line=\empty %
63  \else %
64  \expandafter\lst@CutEOC\lst@line\relax %
65  \fi}%
66  \gdef\lst@CutEOC##1#2##2\relax{\@lst@commentfalse %
67  \def\lst@line{##2}\def\lst@comment{##1#2}}%
68 \fi}

\DeclareDoubleComment First steps of declaring a double comment are easy: We declare a single comment and define macros for a second single comment with slightly different names (an additional @ after SOC and EOC).

69 \def\DeclareDoubleComment#1 #2 #3 #4\relax{%
70 \DeclareSingleComment#1 #2\relax %
71 \global\let\lst@SavedEOC=\lst@EOC %
72 \long\gdef\lst@TestSOC@##1#3##2\relax{%
73  \def\test{##2}%
74  \ifx\test\empty\else %
75  \expandafter\lst@CutSOC@\lst@line\relax %
76  \fi}%
77 \gdef\lst@CutSOC@##1#3##2\relax{\@lst@commenttrue %
78  \def\lst@line{##1}\def\lst@comment{#3##2}}%
79 \gdef\lst@EOC@{\expandafter\lst@TestEOC@\lst@line#4\relax}%
80 \long\gdef\lst@TestEOC@##1#4##2\relax{%
81  \def\test{##2}%
82  \ifx\test\empty %
83  \let\lst@comment=\lst@line \let\lst@line=\empty %
84  \else %
85  \expandafter\lst@CutEOC@\lst@line\relax %
86  \fi}%
87 \gdef\lst@CutEOC@##1#4##2\relax{\@lst@commentfalse %
88  \def\lst@line{##2}\def\lst@comment{##1#4}}%

Now we compose the two single comments by redefining a test macro. The job is to coincide start and end of comment: We have to look, whether the first, the second or none comment starts, and must select the right macro to find the corresponding end of comment.

89 \long\gdef\lst@TestSOC##1#1##2\relax{%

Now ##1 holds the code of the line and ##2 (possibly) the comment. But we have to look whether the other comment type starts before this here or not. So we call the test macro of the other comment first. If we’ve found one, we let \lst@EOC be the macro, which looks for the end of that comment.

90  \lst@TestSOC@##1#3\relax %
91  \if@lst@comment \let\lst@EOC=\lst@EOC@ %

Otherwise we do the test for this comment. If there is a comment, we cut up the line and let \lst@EOC be the macro, which looks for the end of this comment.

92  \else \def\test{##2}%
93  \ifx\test\empty \else %
94  \expandafter\lst@CutSOC\lst@line\relax %
95  \let\lst@EOC=\lst@SavedEOC %

96  \fi %
97  \fi}}

\DeclareNestedComment For nested comments we do it the same way: We declare a single comment and adjust some macros. Testing for an end of comment is nearly the same as for single comments.

98 \def\DeclareNestedComment#1 #2\relax{%
99 \DeclareSingleComment#1 #2\relax %
100 \long\gdef\lst@TestEOC##1#2##2\relax{%

The only difference is, that we have to count how many (new) comments start in the comment. And this is done here, the rest is the same as above.

101  \lst@CountSOC##1#1\relax %
102  \def\test{##2}%
103  \ifx\test\empty %
104  \let\lst@comment=\lst@line \let\lst@line=\empty %
105  \else %
106  \expandafter\lst@CutEOC\lst@line\relax %
107  \fi}%

An end of comment lets the comment depth decrease. If we reach 0, we set the comment boolean false. That’s not new, since this happens always with not nested comments.

108 \gdef\lst@CutEOC##1#2##2\relax{%
109  \advance\lst@comment@depth by -1\relax %
110  \ifnum 0=\lst@comment@depth \@lst@commentfalse\fi %
111  \def\lst@line{##2}\def\lst@comment{##1#2}}%

Now we have to do something for increasing the comment depth. We count how many new comments start within a comment. To move through a comment we use the same separation mechanism as all the time. The second parameter is empty, if and only if there is no (more) start of comment. While it is not empty we increase the comment depth and call this macro again with the current rest of the comment.

112 \long\gdef\lst@CountSOC##1#1##2\relax{%
113  \def\test{##2}\ifx\test\empty\else %
114  \advance\lst@comment@depth by 1%
115  \def\@tempa{\lst@CountSOC##2\relax}%

Note: \@tempa is executed after the closing \fi to call the macro again.

116  \expandafter\@tempa %
117  \fi}}

3.4 Keywords

\lst@CaseSensitiveKeywords We have to decide whether a given character sequence is a reserved word or not. Doing this test is very familiar with the cut mechanism for comments. To test, if key is a keyword, we define a macro

    \def\test#1,key,#2\relax{...}

Afterwards we call the macro with the parameters

all current keywords,key,\relax

When TEX passes the arguments, the second parameter is empty, if and only if key is not a current keyword. So we are able to decide whether to make a normal box, or a box with keywordstyle.

118 \def\lst@CaseSensitiveKeywords#1\relax{%

\relax terminates the character sequence we want to test. Now we define the test macro. It overwrites itself, but this happens after execution.

119  \def\test##1,#1,##2\relax{\def\test{##2}%
120  \ifx\test\empty \lst@MakeBox{}%
121  \else \lst@MakeBox{\lst@keywordstyle}%
122  \fi}%

We only need to call the macro defined right before. ,#1,\relax holds up the syntax of \test.

123  \expandafter\test\lst@keywords,#1,\relax}%

Since TEX always passes two arguments to the test macro, TEX splits the whole ’input’ \lst@keywords,#1,\relax into two parts. So there is no need to sort the keywords by probability.

\lst@NonCaseSensitiveKeywords Now we implement the test for keywords, which are not case sensitive. We use two uppercase to normalize the test string and the keywords. For the keywords we need some expandafters, so that the keywords are expanded before making the characters uppercase.

124 \def\lst@NonCaseSensitiveKeywords#1\relax{%
125  \uppercase{\def\test##1,#1,##2\relax{\def\test{##2}%
126  \ifx\test\empty \lst@MakeBox{}%
127  \else \lst@MakeBox{\lst@keywordstyle}%
128  \fi}}%
129  \expandafter\uppercase\expandafter{%
130  \expandafter\test\lst@keywords,#1,\relax}}%

3.5 Commands

\prelisting \postlisting \keywordstyle \commentstyle \stringstyle \keywords \morekeywords \stringizer The following user commands save the parameter in private macros.
131 \newcommand\prelisting[1]{\def\lst@prelisting{#1}}
132 \newcommand\postlisting[1]{\def\lst@postlisting{#1}}
133 \newcommand\keywordstyle[1]{\def\lst@keywordstyle{#1}}
134 \newcommand\commentstyle[1]{\def\lst@commentstyle{#1}}
135 \newcommand\stringstyle[1]{\def\lst@stringstyle{#1}}
136 \newcommand\keywords[1]{\def\lst@keywords{#1}}
137 \newcommand\morekeywords[1]{\edef\lst@keywords{\lst@keywords,#1}}
138 \newcommand\stringizer[1]{\def\lst@stringizer{#1}}
\blankstringtrue \blankstringfalse \sensitivetrue \sensitivefalse The user ’switches’ assign the right macros.
139 \newcommand\blankstringtrue{%
140  \let\lst@MakeStringBox=\lst@MakeBox}
141 \newcommand\blankstringfalse{%
142  \let\lst@MakeStringBox=\lst@MakeSpecialStringBox}
143 \newcommand\sensitivetrue{%
144  \let\lst@KeywordOrNot=\lst@CaseSensitiveKeywords}
145 \newcommand\sensitivefalse{%
146  \let\lst@KeywordOrNot=\lst@NonCaseSensitiveKeywords}

\tablength \tablength first look, if the argument is legal. If not, an error message is given.

147 \newcommand\tablength[1]{\ifnum#1>0\lst@tab@length=#1\relax \else %
148  \PackageError{Listings}{Strict positive integer expected}{%
149  You can't use `#1' as tablength.^^J I'll forget it and proceed.}\fi}

\normallisting The default style is set using commands from above:

150 \newcommand\normallisting{%
151  \keywordstyle{\bfseries}\commentstyle{\itshape}\stringstyle{}%
152  \prelisting{}\postlisting{}\blankstringfalse}

\inputlisting Now we define the main command. The first parameter is optional and set to [1, 999999], if none is given. The second parameter is the filename. If the file doesn’t exist, we give an error message. Otherwise we skip the lines upto the first printing line and output the listing, but only, if listings are desired. The inner loop terminates, if the end of file or the specified last line is reached.

153 \newcommand\inputlisting[2][1,999999]{%
154  \batchmode \openin\lst@inputfile#2 \errorstopmode %
155  \ifeof\lst@inputfile %
156  \PackageError{Listings}{File `#2' not found}{%
157  You must tell me the right name or I can't do the job.}%
158  \else %
159  \message{(#2}%
160  \iflisting %
161  \lst@SetRange[#1]\lst@current@line=1 %
162  \lst@SkipUptoFirst \@lst@endinputfalse %
163  \lst@begin %
164  \loop %
165  \read\lst@inputfile to\lst@line %
166  \advance\lst@current@line by 1%
167  \lst@AllLineProcessing %
168  \ifeof\lst@inputfile \@lst@endinputtrue \fi %
169  \ifnum\lst@last@line<\lst@current@line %
170  \@lst@endinputtrue %
171  \fi %
172  \if@lst@endinput\else %
173  \repeat %
174  \vspace*{-\baselineskip}%
175  \lst@end %

If listings aren’t desired, we typeset a message.

176  \else %
177  \begin{center}%
178  --- Listing of #2 has been skipped. ---
179  \end{center}%
180  \fi %
181  \message{)}%

The corresponding \fi from ’if file exists’ and close the input file.

182  \fi \closein\lst@inputfile}

\listing Now we define the environment for typesetting listings. The command for beginning the environment is easy. To read the TEX-file line by line we have to make the end of line character ^^M active. But this only happens, if listings are allowed. Ending the environment is very easy.

183 \def\listing{%
184  \iflisting
185  \lst@begin \catcode`\^^M=\active \vspace*{-\baselineskip}%
186  \expandafter\lst@env@ReadAndProcess %
187  \else %
188  \begin{center}%
189  --- Listing has been skipped. ---
190  \end{center}%
191  \fi}
192 \def\endlisting{}

\lst@env@ReadAndProcesss We will use a mechanism used for the new implementation of L^{A}TEX’s verbatim environments. I don’t explain it here. It is described in section 3.4 of [5].

193 \begingroup
194 \catcode`\!=\active \catcode`\[=\active \catcode`\]=\active
195 \lccode`\!=`\\ \lccode`\[=`\{ \lccode`\]=`\}
196 \catcode`\~=\active \lccode`\~=`\^^M
197 \lowercase{

The effect of lowercase is that all !, [, ] and ~ of the argument are converted to

 \, {, } and ^^M.

The macro \lst@env@ReadAndProcess gets the input upto the next end of line character. We append \end{listing}\relax to hold up the syntax of

 \lst@env@Process.
198 \gdef\lst@env@ReadAndProcess#1~{\lst@env@Process#1!end[listing]\relax}

\lst@env@Processs The second parameter of this macro is empty, if and only if the end of the environment is not reached. If the listing goes on, we define the current line, do the line processing and define the next macro. If the listing is over, we define right macro to be the next.

199 \gdef\lst@env@Process#1!end[listing]#2\relax{%
200  \def\test{#2}%
201 \ifx\test\empty %
202  \def\lst@line{#1~}%
203  \lst@AllLineProcessing %
204  \let\next\lst@env@ReadAndProcess %
205  \else %
206  \def\next{\lst@end\end{listing}}%
207  \fi\next}
208 }\endgroup

\lst@begin \lst@end Let’s look what’s to do to begin and end a listing, respectively. We insert a small skip, the user defined \lst@prelisting and \lst@postlisting and initialize some variables. Of course, we use a new group level, so that outer blocks are not affected by the changes made here.

209 \def\lst@begin{%
210  \smallbreak\bgroup\lst@prelisting %
211  \@lst@stringfalse \lst@width=0.65em \lst@comment@depth=0 %
212  \let\lst@comment=\empty \let\lst@commentline=\empty %
213  \def\lst@test{fortran}\ifx\lst@curr\lst@test \lst@width=0.8em\fi
214  \lst@ChangeCatcodes}
215 \def\lst@end{\lst@postlisting\egroup\smallbreak\ignorespaces}

\lst@SetRange \lst@SkipUptoFirst Here are two simple macros we used some time before. The counter \@tempcnta is temporary.

216 \def\lst@SetRange[#1,#2]{\@tempcnta=#1\relax \lst@last@line=#2\relax}
217 \def\lst@SkipUptoFirst{%
218  \@whilenum \@tempcnta<\lst@current@line \do %
219  {\read\lst@inputfile to\lst@line %
220  \advance\lst@current@line by 1}}

3.6 Line processing

\lst@AllLineProcessing Here comes the single line processing. First we collect the line processing in one macro: Some initialization, pre-processing and the processing.

221 \def\lst@AllLineProcessing{%
222  \let\lst@text=\empty \lst@length=0 \global\lst@pos=0 %
223  \par \noindent \lst@PreProcessLine \lst@ProcessLine}

\lst@PreProcessLineDefault Before considering the main macro we define the default for \lst@PreProcessLine. It gives a warning, if a string exceeds a line.

224 \def\lst@PreProcessLineDefault{%
225  \if@lst@string %
226  \PackageWarning{Listings}{string constant exceeds line}%
227  \@lst@stringfalse %
228  \fi}

\lst@ProcessLine Now the main macro for line processing. There is no parameter, because the data is given by \lst@line. We construct a loop by defining the macro \next to call this macro again. But this definition might changes soon to terminate line processing.

229 \def\lst@ProcessLine{\def\next{\lst@ProcessLine}%

Since a comment might exceeds a line, we have to handle this case first. We try to find the end of comment, which saves the comment in \lst@comment and might changes the boolean \if@lst@comment.

230  \if@lst@comment \lst@EOC %

To output the comment we use a little trick (concerning the naming of a macro). The tokenize macro below not only cuts up the input for scanning keywords. In comment mode it will cut the input in the same way, but always uses commentstyle for the output. Therefore we locally switch to comment mode and call the macro.

231  {\@lst@commenttrue \expandafter\lst@Tokenize\lst@comment\relax}%

We empty the comment just output. If the comment goes on, i.e. the comment was the whole line, line processing is over, i.e. there is nothing to do next: We redefine the macro \next.

232  \let\lst@comment=\empty\if@lst@comment \def\next{}\fi %
233  \else %

If no comment is in progress, the macro tries to find one and cuts off a comment line, if possible (or a part of the line as a comment line).

234  \lst@SOC \lst@CommentLine %

Now \lst@line has been cut to the noncomment rest. We have to find the keywords. \relax is used as a brake: It marks the end and will terminate tokenizing.

235  {\@lst@commentfalse\expandafter\lst@Tokenize\lst@line\relax}%

If a string has begun in \lst@Tokenize, but not finished, the potential comment above belongs to the string. What’s to do? The input line gets the comment and the next character is typeset. Then we call this macro without being in danger classifing the comment as a comment again, because the first character is missing now. But hold on: The comment might be empty and so the input line. In that case we have nothing to do next and \lst@PreProcessLine might gives a warning to the user.

236  \if@lst@string %
237  \@lst@commentfalse %
238  \ifx\lst@commentline\empty\else \@lst@commenttrue \fi %
239  \ifx\lst@comment\empty\else \@lst@commenttrue \fi %
240  \if@lst@comment %
241  \@lst@commentfalse %
242  \expandafter\expandafter\expandafter\lst@TypesetChar %
243  \expandafter\lst@commentline\lst@comment\relax %
244  \let\lst@comment=\empty \let\lst@commentline=\empty %
245  \else %
246  \def\next{}%
247  \fi %
248  \else %

If no string is in work, it’s all fine. We output the comment line, if present. In that case there is no other comment.

249  \ifx\lst@commentline\empty \else %
250  \@lst@commenttrue %
251  \expandafter\expandafter\expandafter\lst@Tokenize %
252  \expandafter\lst@commentline\lst@comment\relax %
253  \let\lst@comment=\empty \let\lst@commentline=\empty %
254  \@lst@commentfalse %
255  \fi %

For comments this macro calls itself to find the end of comment. As this is the default, we only have to assign the comment to \lst@line — the implizit parameter of this macro. If there is no comment, we redefine \next.

256  \if@lst@comment %
257  \let\lst@line=\lst@comment %
258  \else \def\next{}%
259  \fi %

We have to close some ifs and do the next thing.

260  \fi %
261  \fi\next}

\lst@TypesetChar The following macro has been used in the last macro. It typesets the next character and removes it from the input line.

262 \def\lst@TypesetChar#1#2\relax{\def\lst@line{#2}\lst@CharOutput#1}

The line processing is complete. Now we will try to scan keywords.

3.7 Tokenizing

\lst@Tokenize The tokenize macro gets code upto \relax and scans for keywords and strings. In fact it only cuts up potential keywords, which are tested right before their output.

Most time we will call the tokenize macro again, since \relax is only read at the end. So we define the next operation first:

263 \long\def\lst@Tokenize#1{%
264  \def\lst@next{\lst@Tokenize}%

An incoming letter is gathered.

265  \ifcat #1a%
266  \edef\lst@text{\lst@text#1}\advance\lst@length by 1 %

If we found a tabulator, we output the preceding text and go to the next tabulator stop.

267  \else \ifcat #1&%
268  \lst@Output \lst@GotoNextTabStop %

If we found other nonletter, we also output the preceding text. The keyword test take place there.

269  \else %
270  \lst@Output %

Getting to the terminator \relax ends tokenizing by defining next operation empty. Otherwise we look for the character, which begins and ends a string, but only if we don’t process a comment.

271  \ifx#1\relax \def\lst@next{}%
272  \else \if@lst@comment \lst@CharOutput#1%
273  \else \lst@TestStringizer#1%
274  \fi \fi %
275  \fi \fi \lst@next}

\lst@TestStringizer Here we do the stringizer tests. If a string already started, we output the current character, look for the closing stringizer and switch the string boolean, if we found it.

276 \long\def\lst@TestStringizer#1{\def\test{#1}%
277  \if@lst@string %
278  \lst@CharOutput#1%
279  \ifx \test\lst@closing@stringizer \global\@lst@stringfalse\fi %

If we are not in string mode, we compare the current character with all given stringizers, and output the character afterwards. \relax is a terminator.

280  \else %
281  \expandafter\lst@DoStringizerTest\lst@stringizer\relax %
282  \lst@CharOutput#1%
283  \fi}

\lst@DoStringizerTest Now we consider a stringizer test. Reaching \relax results in doing nothing and so terminating the tests.

284 \def\lst@DoStringizerTest#1{%
285  \ifx#1\relax \else %

Otherwise we compare the current character and the current stringizer. If they are equal, we switch the string boolean and save the stringizer as closing stringizer.

286  \expandafter\if\test#1%
287  \global\@lst@stringtrue %
288  \gdef\lst@closing@stringizer{#1}%
289  \fi %

At the end we call this macro again. The macro terminates reaching the \relax!

290  \expandafter\lst@DoStringizerTest %
291  \fi}%

3.8 Output

\lst@Output It’s time to do text output. First we look, if there is anything to output.

292 \def\lst@Output{%
293  \ifx\lst@text\empty\else %

Then we decide, whether to make a stringbox (using stringstyle) or a box for a comment (using commentstyle as explicit parameter). We distinguish a stringbox and a normal box with a given style, since this speeds up a bit. In strings we print ␣ instead of a blank space. But this needs an additional if and more time.

294  \if@lst@string \lst@MakeStringBox \else %
295  \if@lst@comment\lst@MakeBox{\lst@commentstyle}\else %

If we output neither a string nor a comment, we look for a keyword. The output takes place in the macro \lst@KeywordsOrNot (see section 4). \relax terminates the text parameter.

296  \expandafter\lst@KeywordOrNot\lst@text\relax %
297  \fi \fi %

Finally we hold up the current column, empty the text and close the starting ’if text not empty’.

298  \global\advance\lst@pos by -\lst@length %
299  \let\lst@text=\empty \lst@length=0 %
300  \fi}

\lst@MakeBox Consider the different boxes now. A box must take \lst@length characters: the width is \lst@length·\lst@width. The macro parameter possibly selects another style. We insert dynamic space at the beginning and at the ending to center the text and we fill the box. \relax is a brake.

301 \def\lst@MakeBox#1{%
302  \hbox to \lst@length\lst@width{#1\hss %
303  \expandafter\lst@FillBox\lst@text\relax \hss}}

\lst@FillBox Filling up a box is easy. If we found the end of the text, we do nothing. Otherwise we output the character and insert dynamic space. Since the underbar is not a printable character in TEX, we have to treat it special. By the way: We make the underbar having the letter catcode here; we don’t want subscripts. After all this is done, we call the fillbox macro again. Note: The macro is called after the closing \fi!

304 \begingroup
305 \catcode`\_=11
306 \gdef\lst@FillBox#1{%
307  \ifx\relax#1\else %
308  \ifx#1_\lst@underbar \else #1\fi \hss %
309  \expandafter\lst@FillBox %
310  \fi}
311 \endgroup

\lst@MakeSpecialStringBox A stringbox is nearly the same: The style parameter is replaced by stringstyle and we must fill a stringbox.

312 \def\lst@MakeSpecialStringBox{%
313  \hbox to \lst@length\lst@width{\lst@stringstyle\hss %
314  \expandafter\lst@FillStringBox\lst@text\relax \hss}}

\lst@FillStringBox Filling the stringbox is more difficult. Again the subscript character becomes a letter. \lst@active@blank is equal to a blank space, which comes from the source file. So we can use it for equality test to output a blank space as ␣.

315 \begingroup
316 \catcode`\_=11
317 \long\gdef\lst@FillStringBox#1{%
318  \ifx\relax#1\else %
319  \ifx#1_\lst@underbar \else %
320  \ifx#1\lst@active@blank \lst@string@blank \else #1%
321  \fi \fi \hss%
322  \expandafter\lst@FillStringBox%
323  \fi}%
324 \endgroup

\lst@CharOutput We define one more macro to save time. It outputs a single character. The implementation should be clear.

325 \long\def\lst@CharOutput#1{\global\advance\lst@pos by -1%
326  \hbox to \lst@width{\hss %
327  \if@lst@string \lst@stringstyle\lst@FillStringBox#1\relax %
328  \else \if@lst@comment \lst@commentstyle#1\hss %
329  \else #1\hss %
330  \fi \fi}}

\lst@GotoNextTabStop At the end of this section we consider tabulators. As seen, each typeset character decrements the counter \lst@pos. To go to the next tabulator stop, we must first determine how many blanks are needed. We simply add \lst@tab@length until \lst@pos is strict positive.

331 \def\lst@GotoNextTabStop{%
332  \@whilenum \lst@pos<1 \do %
333  {\global\advance\lst@pos by \lst@tab@length}%

Now we output \lst@pos blank spaces and we are done. Note: \lst@pos is

 decremented in \lst@CharOutput.
334  \@whilenum \lst@pos>0 \do %
335  {\lst@CharOutput\lst@active@blank}}

3.9 Special characters

\lst@underbar \lst@leftbrace \lst@rightbrace \lst@less \lst@greater \lst@vertical@bar \lst@minus \lst@multiply Some definitions of special characters:
336 \def\lst@underbar{${_-}$}
337 \def\lst@leftbrace{$\{$}
338 \def\lst@rightbrace{$\}$}
339 \def\lst@less{$<$}
340 \def\lst@greater{$>$}
341 \def\lst@vertical@bar{$|$}
342 \def\lst@minus{$-$}
343 \def\lst@multiply{$*$}

\lst@string@blank We define the macro for ␣. Temporary a blank space becomes other (catcode). Then we get the result by selecting a typewriter font.

344 \begingroup
345 \catcode`\ =12%
346 \gdef\lst@string@blank{{\ttfamily }}%
347 \endgroup

\lst@ChangeCatcodes Now begins the horrible part: It is necessary to change many catcodes. Since we need backslash and braces with other meanings, we replace them by the slash /, ( and ). Other characters like $ and & need not to be replaced, because we don’t need them for defining macros, but \, { and } are essential for doing that.

348 \begingroup
349 \catcode `/=0       \catcode `(= 1      \catcode `)=2 % new \, { and }
350 \catcode`\<=\active \catcode`\>=\active \catcode`\|=\active
351 \catcode`\-=\active \catcode`\*=\active
352 \catcode`\{=\active \catcode`\}=\active \catcode`\\=\active

From now on we must use the slash and () instead of backslash and braces. Since the blank space will also be an active character, we must terminate each line with a comment character. Otherwise TEX would think, we want to typeset something before beginning the document.

353 /catcode`/ =/active%
354 /gdef/lst@active@blank(/ )%

The following macro changes catcodes and the definition of active characters at the time we input a listing.

355 /gdef/lst@ChangeCatcodes(%
356 /catcode`/ =/active/let =/lst@active@blank%
357 /catcode`/\=/active/def\($/backslash$)%
358 /catcode`/{=/active/def{(/lst@leftbrace)%
359 /catcode`/}=/active/def}(/lst@rightbrace)%
360 /catcode`/<=/active/def<(/lst@less)%
361 /catcode`/>=/active/def>(/lst@greater)%
362 /catcode`/|=/active/def|(/lst@vertical@bar)%
363 /catcode`/-=/active/def-(/lst@minus)%
364 /catcode`/*=/active/def*(/lst@multiply)%
365 /chardef~="7E%

A tabulator (ASCII code 9=ord(I)−64) gets the catcode of a TEX-tabulator.

366 /catcode`/^^I=4%

Some characters are treated as other characters (12) or as letters (11).

367 /catcode`/$=12/catcode`/&=12/catcode`/#=/lst@sharp@catcode%
368 /catcode`/^=12/catcode`/%=12/catcode`/"=12%
369 /catcode`/1=11/catcode`/2=11/catcode`/3=11%
370 /catcode`/4=11/catcode`/5=11/catcode`/6=11%
371 /catcode`/7=11/catcode`/8=11/catcode`/9=11%
372 /catcode`/0=11/catcode`/_=11)%
373 /endgroup

All changed catcodes (time of definition) are restored by ending the group.

3.10 Initialization

Defaults are selected and the user defined options are processed.

374 \normallisting
375 \listingtrue
376 \lst@tab@length=4
377 \ExecuteOptions{blank}
378 \ProcessOptions

379 ⟨/package⟩

4 Language driver files

Each driver file contain language specific values:

• keywords;

• whether the language is case sensitive or not;

• comment lines and other comments;

• the stringizer;

• define \lst@sharp@catcode to be 11, if it is used for reserved words (compiler directives in C and C++), otherwise 12.

• \lst@PreProcessLine is intend to manipulate the input before the normal line processing takes place. Fortran 90 uses it to detect comment lines beginning with ’∗’ or ’C’ and Eiffel’s string concatenate mechanism is done there.

This package selects a language by calling a macro \lst@ with the name of the language as suffix, e.g. \lst@fortran. That macro must assign the values described above. The supported languages follow as examples.

Blank listing

\lst@blank For a blank listing we let all empty. \makeatletter lets @ be a letter here. Otherwise we can’t access, e.g. lst@blank.

380 ⟨∗blank⟩

381 \makeatletter %
382 \gdef\lst@blank{%
383  \keywords{}%
384  \sensitivetrue %
385  \DeclareCommentLine\relax %
386  \DeclareSingleComment stuff \relax %
387  \stringizer{} %
388  \chardef\lst@sharp@catcode=12 %
389  \let\lst@PreProcessLine=\lst@PreProcessLineDefault}%
390 \makeatother %

391 ⟨/blank⟩

C listing

\lst@keywords@c For C we first define the reserved words.

392 ⟨∗c⟩

393 \makeatletter %

394 \gdef\lst@keywords@c{auto,break,case,char,const,continue,default,do,%
395 double,else,enum,extern,float,for,goto,if,int,long,register,return,%
396 short,signed,sizeof,static,struct,switch,typedef,union,unsigned,%
397 void,volatile,while}%

\lst@special@c To define C (and C++) directives as keywords the catcode of # must be changed from ’parameter symbol for macros’ to ’letter’.

398 \begingroup \catcode`\#=11 %
399 \gdef\lst@special@c{#define,#elif,#else,#endif,#error,#if,#ifdef,%
400  #ifndef,#line,#include,#pragma,#undef}%
401 \endgroup %

\lst@c Since ∗ will be an active character when we input a listing, we have to change the catcode here. We also change the catcode of a double quote for compatibility with the german style file.

402 \begingroup %
403 \catcode`\*=\active \catcode`\"=12 %
404 \gdef\lst@c{\keywords{}%
405  \morekeywords{\lst@keywords@c,\lst@special@c}%
406  \sensitivetrue %
407  \DeclareCommentLine\relax %
408  \DeclareSingleComment /* */\relax %
409  \stringizer{"}%
410  \chardef\lst@sharp@catcode=11 %
411  \let\lst@PreProcessLine=\lst@PreProcessLineDefault}%
412 \endgroup %
413 \makeatother %

414 ⟨/c⟩

C++ listing

\lst@keywords@cpp Since C++ is a extension of C (from the point of view here), we load the C driver file and define the additional keywords.

415 ⟨∗cpp⟩

416 \clisting %
417 \makeatletter %
418 \begingroup \catcode`\_=11
419 \gdef\lst@keywords@cpp{asm,catch,class,const_cast,delete,dynamic_cast,%
420 friend,inline,namespace,new,operator,private,protected,public,%
421 reinterpret_cast,static_cast,template,this,throw,try,typeid,%
422 virtual,xalloc,__multiple_inheritance,__single_inheritance,%
423 __virtual_inheritance}%
424 \endgroup %

\lst@cpp Again some catcodes are changed temporary to define a comments and stringizer.

425 \begingroup %
426 \catcode`\*=\active \catcode`\"=12 %
427 \gdef\lst@cpp{\keywords{}%
428 \morekeywords{\lst@keywords@c,\lst@special@c,\lst@keywords@cpp}%
429 \sensitivetrue %
430 \stringizer{"}%
431 \DeclareCommentLine //\relax %
432 \DeclareSingleComment /* */\relax %

433 \chardef\lst@sharp@catcode=11 %
434 \let\lst@PreProcessLine=\lst@PreProcessLineDefault}%
435 \endgroup %
436 \makeatother %

437 ⟨/cpp⟩

Eiffel listing

\lst@keywords@eiffel \lst@eiffel We begin as above.

438 ⟨∗eiffel⟩

439 \makeatletter %
440 \gdef\lst@keywords@eiffel{alias,all,and,as,BIT,BOOLEAN,CHARACTER,%
441  check,class,creation,Current,debug,deferred,do,DOUBLE,else,elseif,%
442  end,ensure,expanded,export,external,false,feature,from,frozen,if,%
443  implies,indexing,infix,inherit,inspect,INTEGER,invariant,is,like,%
444  local,loop,NONE,not,obsolete,old,once,or,POINTER,prefix,REAL,%
445  redefine,rename,require,rescue,Result,retry,select,separate,%
446  STRING,strip,then,true,undefine,unique,until,variant,when,xor}%
447 \begingroup %
448 \catcode`\-=\active \catcode`\"=12%
449 \gdef\lst@eiffel{\keywords{}%
450  \morekeywords{\lst@keywords@eiffel}%
451  \sensitivetrue %
452  \DeclareCommentLine --\relax %
453  \DeclareSingleComment stuff \relax %
454  \stringizer{"}%
455  \chardef\lst@sharp@catcode=12 %
456  \let\lst@PreProcessLine=\lst@PreProcessLine@eiffel}%
457 \endgroup %

Since ’%’ continues a string, we need a different comment character and let the percent be other (catcode) to look for it.

458 \begingroup %
459 \catcode`\&=14 \catcode`\%=12 &

\lst@PreProcessLine@eiffel \lst@PreProcessLine@TestPercent If a string started on a preceding line, we test for the percent. Refer how we cut a line into a comment and other source code.

460 \gdef\lst@PreProcessLine@eiffel{&
461 \if@lst@string &
462  \expandafter\lst@PreProcessLine@TestPercent\lst@line%\relax &
463 \fi}&
464 \gdef\lst@PreProcessLine@TestPercent#1%#2\relax{&
465  \def\test{#2}&
466  \ifx\test\empty \lst@PreProcessLineDefault &
467  \else \expandafter\lst@PreProcessLine@CutPercent\lst@line\relax&
468  \fi}&

\lst@PreProcessLine@CutPercent To output the characters in front of the percent we temporary switch the string boolean. Atferwards we redefine the input line, so that the normal line processing continues the string.

469 \gdef\lst@PreProcessLine@CutPercent#1%#2\relax{&
470  \@lst@stringfalse \lst@Tokenize#1\relax &
471  \@lst@stringtrue \def\lst@line{%#2}}&

472 \endgroup %
473 \makeatother %

474 ⟨/eiffel⟩

Fortran 90 listing

\lst@keywords@fortran \lst@fortran Again the same . . .

475 ⟨∗fortran⟩

476 \makeatletter %
477 \gdef\lst@keywords@fortran{ACCESS,ACTION,ADVANCE,ALLOCATE,ALLOCATABLE,%
478  ASSIGN,ASSIGNMENT,BACKSPACE,BLANK,BLOCK,CALL,CASE,CHARACTER,CLOSE,%
479  COMMON,COMPLEX,CONTAINS,CONTINUE,CYCLE,DATA,DEALLOCATE,DEFAULT,%
480  DELIM,DIMENSION,DIRECT,DO,DOUBLE,ELSE,END,ENDFILE,ENTRY,EOR,%
481  EQUIVALENCE,ERR,EXIST,EXIT,EXTERNAL,FILE,FMT,FORM,FORMAT,%
482  FORMATTED,FUNCTION,GO,TO,IF,IMPLICIT,IN,NONE,INOUT,INQUIRE,%
483  INTEGER,INTENT,INTERFACE,INTRINSIC,IOLENGTH,IOSTAT,KIND,LEN,%
484  LOGICAL,MODULE,NAME,NAMED,NAMELIST,NEXTREC,NMT,NULLIFY,NUMBER,%
485  ONLY,OPEN,OPENED,OPERATOR,OPTIONAL,OUT,PAD,PARAMETER,PAUSE,%
486  POINTER,POSITION,PRECISION,PRINT,PRIVATE,PROGRAM,PUBLIC,READ,%
487  READWRITE,REAL,REC,RECL,RECURSIVE,RESULT,RETURN,REWIND,SELECT,%
488  SEQUENCE,SEQUENTIAL,SIZE,STAT,STATUS,STOP,SUBROUTINE,TARGET,THEN,%
489  TYPE,UNFORMATTED,UINT,USE,WHERE,WHILE,WRITE}%
490 \begingroup \catcode`\"=12%
491 \gdef\lst@fortran{\keywords{}%
492  \morekeywords{\lst@keywords@fortran}%
493  \sensitivetrue %
494  \DeclareCommentLine !\relax %
495  \DeclareSingleComment stuff \relax %
496  \stringizer{"}%
497  \chardef\lst@sharp@catcode=12 %
498  \let\lst@PreProcessLine=\lst@PreProcessLine@fortran}%
499 \endgroup %
\lst@PreProcessLine@fortran We use the \lst@PreProcessLine mechanism to handle ’∗’ and ’C’ comments.

The defined test macro tests, if the first character of the input line is a star or an uppercase c. In that case we output the line as comment and empty the input. That’s all.

500 \def\lst@PreProcessLine@fortran{%
501  \expandafter\lst@TestSpecialComment@fortran\lst@line\relax}%
502 \begingroup \catcode`\*=\active %
503 \long\gdef\lst@TestSpecialComment@fortran#1#2\relax{%
504 \ifx #1*%
505  \@lst@commenttrue \expandafter\lst@Tokenize\lst@line\relax %
506  \let\lst@line=\empty \@lst@commentfalse %
507 \else \if #1C%
508  \@lst@commenttrue \expandafter\lst@Tokenize\lst@line\relax %
509  \let\lst@line=\empty \@lst@commentfalse %
510 \fi\fi}%
511 \endgroup %
512 \makeatother %

513 ⟨/fortran⟩

Java listing

\lst@keywords@java \lst@java Nothing new . . .

514 ⟨∗java⟩

515 \makeatletter %
516 \gdef\lst@keywords@java{abstract,boolean,break,byte,case,catch,char,%
517 class,const,continue,default,do,double,else,extends,final,%
518 finally,float,for,goto,if,implements,import,instanceof,int,%
519 interface,long,native,new,null,package,private,protected,public,%
520 return,short,static,super,switch,synchronized,this,throw,throws,%
521 transient,try,void,volatile,while,true,false}%
522 \begingroup %
523 \catcode`\*=\active \catcode`\"=12 %
524 \gdef\lst@java{\keywords{}%
525 \morekeywords{\lst@keywords@java}%
526 \sensitivetrue %
527 \stringizer{"}%
528 \DeclareCommentLine //\relax %
529 \DeclareSingleComment /* */\relax %
530 \chardef\lst@sharp@catcode=11 %
531 \let\lst@PreProcessLine=\lst@PreProcessLineDefault}%
532 \endgroup %
533 \makeatother %

534 ⟨/java⟩

Modula-2 listing

\lst@keywords@modula \lst@modula Once again the keywords first, . . .

535 ⟨∗modula⟩

536 \makeatletter %
537 \gdef\lst@keywords@modula{AND,ARRAY,BEGIN,BY,CASE,CONST,DIV,DO,ELSE,%
538  ELSIF,END,EXIT,EXPORT,FOR,FROM,IF,IMPLEMENTATION,IMPORT,IN,MOD,%
539  MODULE,NOT,OF,OR,POINTER,PROCEDURE,QUALIFIED,RECORD,REPEAT,RETURN,%
540  SET,THEN,TYPE,UNTIL,VAR,WHILE,WITH,ABS,BITSET,BOOLEAN,CAP,%
541  CARDINAL,CHAR,CHR,DEC,EXCL,FALSE,FLOAT,HALT,HIGH,INC,INCL,INTEGER,%
542  LONGCARD,LONGINT,LONGREAL,MAX,MIN,NIL,ODD,ORD,PROC,REAL,SIZE,TRUE,%
543  TRUNC,VAL}%
544 \begingroup %
545 \catcode`\*=\active \catcode`\*=12 %
546 \gdef\lst@modula{\keywords{}%
547  \morekeywords{\lst@keywords@modula}%
548  \sensitivetrue %
549  \DeclareCommentLine\relax %
550  \DeclareNestedComment (* *)\relax %
551  \stringizer{'"}%
552  \chardef\lst@sharp@catcode=12 %
553  \let\lst@PreProcessLine=\lst@PreProcessLineDefault}%
554 \endgroup %
555 \makeatother %

556 ⟨/modula⟩

Pascal listing

\lst@keywords@pascal It’s all the same, the keywords:

557 ⟨∗pascal⟩

558 \makeatletter %
559 \gdef\lst@keywords@pascal{alfa,and,array,begin,boolean,byte,case,%
560  char,const,div,do,downto,else,end,false,file,for,function,get,%
561  goto,if,in,integer,label,maxint,mod,new,not,of,or,pack,packed,%
562  page,program,procedure,put,read,readln,real,record,repeat,reset,%
563  rewrite,set,text,then,to,true,type,unpack,until,var,while,with,%
564  write,writeln}%

\lst@pascal It’s not all the same. We have to change some catcodes to declare Pascal comments: The braces are temporary replaced by the brackets.

565 \begingroup %
566 \catcode`\[=1 \catcode`\]=2 %
567 \catcode`\{=\active \catcode`\}=\active %
568 \catcode`\*=\active %

Now we can define \lst@pascal.

569 \gdef\lst@pascal[\keywords[]%
570  \morekeywords[\lst@keywords@pascal]%
571  \sensitivefalse %
572  \DeclareCommentLine\relax %
573  \DeclareDoubleComment (* *) { }\relax %
574  \stringizer[']%
575  \chardef\lst@sharp@catcode=12 %
576  \let\lst@PreProcessLine=\lst@PreProcessLineDefault]%
577 \endgroup %
578 \makeatother %

579 ⟨/pascal⟩

Pascal XSC listing

\lst@keywords@pxsc \lst@pxsc Tell me, if you want more words to be keywords.

580 ⟨∗pxsc⟩

581 \pascallisting %
582 \makeatletter %
583 \gdef\lst@keywords@pxsc{dynamic,external,forward,global,module,nil,%
584  operator,priority,sum,type,use,dispose,mark,page,release,%
585  cimatrix,cinterval,civector,cmatrix,complex,cvector,dotprecision,%
586  imatrix,interval,ivector,rmatrix,rvector,string,im,inf,re,sup,%
587  chr,comp,eof,eoln,expo,image,ival,lb,lbound,length,loc,mant,%
588  maxlength,odd,ord,pos,pred,round,rval,sign,substring,succ,trunc,%
589  ub,ubound}%
590 \begingroup %
591 \catcode`\[=1 \catcode`\]=2 %
592 \catcode`\{=\active \catcode`\}=\active %
593 \catcode`\*=\active %
594 \gdef\lst@pxsc[\keywords[]%
595  \morekeywords[\lst@keywords@pascal,\lst@keywords@pxsc]%
596  \sensitivefalse %
597  \DeclareCommentLine\relax %
598  \DeclareDoubleComment (* *) { }\relax %

599  \stringizer[']%
600  \chardef\lst@sharp@catcode=12 %
601  \let\lst@PreProcessLine=\lst@PreProcessLineDefault]%
602 \endgroup %
603 \makeatother %

604 ⟨/pxsc⟩

Turbo Pascal listing

\lst@keywords@tp \lst@tp The keywords are the reserved words and predefined functions and procedures of Turbo Pascal 6.0. It’s a long list …

605 ⟨∗tp⟩

606 \makeatletter %
607 \gdef\lst@keywords@tp{and,array,asm,begin,case,const,constructor,%
608 destructor,div,do,downto,else,end,file,for,function,goto,if,%
609 implementation,in,inline,interface,label,mod,nil,not,object,of,or,%
610 packed,procedure,program,record,repeat,set,shl,shr,string,then,to,%
611 type,unit,until,uses,var,while,with,xor,%
612 Abs,Addr,ArcTan,Chr,Concat,Copy,Cos,CSeg,DiskFree,DiskSize,%
613 DosExitCode,DosVersion,DSeg,EnvCount,EnvStr,Eof,Eoln,Exp,FExpand,%
614 FilePos,FileSize,Frac,FSearch,GetBkColor,GetColor,GetDefaultPalette,%
615 GetDriverName,GetEnv,GetGraphMode,GetMaxMode,GetMaxX,GetMaxY,%
616 GetModeName,GetPaletteSize,GetPixel,GetX,GetY,GraphErrorMsg,%
617 GraphResult,Hi,ImageSize,InstallUserDriver,InstallUserFont,Int,%
618 IOResult,KeyPressed,Length,Lo,MaxAvail,MemAvail,MsDos,Odd,Ofs,Ord,%
619 OvrGetBuf,OvrGetRetry,ParamCount,ParamStr,Pi,Pos,Pred,Ptr,Random,%
620 ReadKey,Round,SeekEof,SeekEoln,Seg,SetAspectRatio,Sin,SizeOf,Sound,%
621 SPtr,Sqr,Sqrt,SSeg,Succ,Swap,TextHeight,TextWidth,Trunc,TypeOf,%
622 UpCase,WhereX,WhereY,%
623 Append,Arc,Assign,AssignCrt,Bar,Bar3D,BlockRead,BlockWrite,ChDir,%
624 Circle,ClearDevice,ClearViewPort,Close,CloseGraph,ClrEol,ClrScr,Dec,%
625 Delay,Delete,DelLine,DetectGraph,Dispose,DrawPoly,Ellipse,Erase,Exec,%
626 Exit,FillChar,FillEllipse,FillPoly,FindFirst,FindNext,FloodFill,%
627 Flush,FreeMem,FSplit,GetArcCoords,GetAspectRatio,GetDate,%
628 GetDefaultPalette,GetDir,GetCBreak,GetFAttr,GetFillSettings,GetFTime,%
629 GetImage,GetIntVec,GetLineSettings,GetMem,GetPalette,GetTextSettings,%
630 GetTime,GetVerify,GetViewSettings,GoToXY,Halt,HighVideo,Inc,%
631 InitGraph,Insert,InsLine,Intr,Keep,Line,LineRel,LineTo,LowVideo,Mark,%
632 MkDir,Move,MoveRel,MoveTo,MsDos,New,NormVideo,NoSound,OutText,%
633 OutTextXY,OvrClearBuf,OvrInit,OvrInitEMS,OvrSetBuf,PackTime,PieSlice,%
634 PutImage,PutPixel,Randomize,Read,ReadLn,Rectangle,Release,Rename,%
635 Reset,RestoreCrtMode,Rewrite,RmDir,RunError,Sector,Seek,%
636 SetActivePage,SetAllPalette,SetBkColor,SetCBreak,SetColor,SetDate,%
637 SetFAttr,SetFillPattern,SetFillStyle,SetFTime,SetGraphBufSize,%
638 SetGraphMode,SetIntVec,SetLineStyle,SetPalette,SetRGBPalette,%
639 SetTextBuf,SetTextJustify,SetTextStyle,SetTime,SetUserCharSize,%
640 SetVerify,SetViewPort,SetVisualPage,SetWriteMode,Sound,Str,%
641 SwapVectors,TextBackground,TextColor,TextMode,Truncate,UnpackTime,%
642 Val,Window,Write,WriteLn}%
643 \begingroup %
644 \catcode`\[=1 \catcode`\]=2 %
645 \catcode`\{=\active \catcode`\}=\active %
646 \catcode`\*=\active %
647 \gdef\lst@pxsc[\keywords[]%

648  \morekeywords[\lst@keywords@tp]%
649  \sensitivefalse %
650  \DeclareCommentLine\relax %
651  \DeclareDoubleComment (* *) { }\relax %
652  \stringizer[']%
653  \chardef\lst@sharp@catcode=12 %
654  \let\lst@PreProcessLine=\lst@PreProcessLineDefault]%
655 \endgroup %
656 \makeatother %

657 ⟨/tp⟩

5 Samples

This documentation uses some files to illustrate the listings package. Here they are:

658 ⟨∗listing1⟩

659  switch (direction)
660  {// choose direction
661  case backward     : { ... break; }
662  case backwarddown : { ... break; }
663  case up           : { ... break; }
664  case forwardup    : { ... break; }

665 }

666

667  const char* string = "Strings  are supported.";

668 ⟨/listing1⟩

669 ⟨∗listing2⟩

670  for i:=maxint downto 0 do
671  begin
672  { we do
673  nothing }
674  end;

675

676  WriteLn('Pascal keywords are');
677  writeln('not case sensitive.');

678 ⟨/listing2⟩

679 ⟨∗listing3⟩

680  if (ThereIsALongLine) { ItExceedsASingleLineInTheListing(); }

681 ⟨/listing3⟩

682 ⟨∗listing4⟩

683  (* ------------------------------ *)
684  (* A short test for Pascal option *)
685  (*  (not for a Pascal compiler)   *)
686  (* ------------------------------ *)

687

688 (* Since comments can't be nested,
689  (* this comment ends right after this *)
690  and not here *)

691

692 (* But using the braces like { these here } will work *)
693 { And doing it (* the other way round also }

694

695 'A String without any context'
696 'This is a string (* and not a comment'
697 'This is a String (* and not a comment' *)
698 'This is a String { and not a comment'

699

700 { This is a comment '''and not a string'' }

701 ⟨/listing4⟩

6 Extensions

For an additional language first declare a new option and define a language command. Refer the supported languages for examples. Then add a driver file. Refer the last section how this is done.

\lst@CommentLine If you want comment lines or comments, which are not supported by the dec-

\lst@SOC
\lst@EOC

laration commands of this package, you have a problem. Contact me or follow these steps:

1. Define the macro, which cuts up the input line into a comment line and the noncomment rest: The macro gets the input via the macro \lst@line. After the call \lst@line must hold the noncomment rest and \lst@commentline the comment line. The C++ line

    if (comments!=appear) // comment stuff
must be cut into ’if (comments!=appear) ’ and ’// comment stuff’.

2. Define the macro, which finds the start of a comment: The macro gets the input via the macro \lst@line. After the call \lst@line must contain the source line upto the first appearance of a comment (exclusive). The comment and might the rest of the line must be in the macro \lst@comment. If a comment is separated (not if and only if), you have to call \@lst@commenttrue. The Pascal line

    if { comment } appears then
is cut into ’if ’ and ’{ comment } appears then’.

3. Define the macro, which finds the end of a comment: The macro gets the input via the macro \lst@line. After the call \lst@comment must hold the comment and \lst@line the noncomment rest of the line (which might be empty, of course). If the end of comment is found, you have to call

\@lst@commentfalse. The Pascal line
    { comment } appears then

must be cut into ’{ comment }’ and ’ appears then’.

Assign these macros to \lst@CommentLine, \lst@SOC and \lst@EOC within your language command.

7 History

0.1 from 1996/03/09

– test version to look whether package is possible or not 0.11 from 1996/08/19

– additional blank option

– \keywords, \morekeywords, \keywordstyle and \commentstyle are

new commands

– implementation guide improved and user’s guide updated

– alignment improved by rewriting some macros 0.12 from 1997/01/16

– nearly perfect alignment now

– \stringizer, \stringstyle, \prelisting and \postlisting are new
– user selection \listingtrue and \listingfalse possible
– \blankstringtrue and \blankstringfalse handle output of blanks

in strings

– package supports tabulators now; new command \tablength 0.13 from 1997/02/11

– additional languages: Eiffel, Fortran 90, Modula-2, Pascal XSC

– load on demand: language specific macros have been moved to driver files

– comments are declared now and not implemented for each language again (this makes these TEX sources easier to read)

– ’string exceeds line’ test moved to \lst@PreProcessLineDefault – sample files moved to .dtx-file

0.14 from 1997/02/18 – user’s guide rewritten

– implementation guide uses macro environment from the doc package – (non) case sensitivity implemented, e.g. Pascal is not

– multiple stringizer implemented, i.e. Modula-2 handles both string types: quotes and double qoutes

– comment declaration is user-accessible now

– package compatible to german.sty now

– changed some identifiers 0.15 from 1997/04/18

– listing environment is new

– additional languages: Java, Turbo Pascal

– \lst@width changes from 0.65em to 0.8em for Fortran 90

– corrected some mistakes in the documentation

– package renamed from listing.dtx to listings.dtx, since there is already a listing package

References

[1] Bertrand Meyer: Eiffel: the language Prentice Hall International (UK) Ldt, 1992; ISBN 0-13-247925-7

[2] Thomas Michel: Fortran 90: Lehr– und Handbuch Mannheim; Leipzig; Wien; Zürich: BI-Wiss.-Verlag, 1994; ISBN 3-411-16861-7

[3] Niklaus Wirth: Programmieren in Modula-2, Übers. Guido Pfeiffer 2. Auflage – Berlin; Heidelberg; New York; London; Paris; Tokyo; Hong Kong: Springer, 1991; ISBN 3-540-51689-1

[4] http://java.sun.com

[5] Rainer Schöpf, Bernd Raichle, Chris Rowley: A New Implementation of L^{A}TEX’s verbatim and verbatim* Environments.

Index

Numbers written in italic refer to the page where the corresponding entry is described, the ones underlined to the code line of the definition, the rest to the code lines where the entry is used.

Symbols

\@lst@commentfalse . . . . . . . . . 66,

87, 110, 235, 237, 241, 254, 506, 509

\@lst@commenttrue . . . . . . . . . 56,

77, 231, 238, 239, 250, 505, 508

\@lst@endinputfalse . . . . . . . . . . . 162
\@lst@endinputtrue . . . . . . . . 168, 170
\@lst@stringfalse . 211, 227, 279, 470
\@lst@stringtrue . . . . . . . . . 287, 471

\@tempcnta . . . . . . . . . . . . . . 216, 218 \@whilenum . . . . . . . . . . 218, 332, 334

B

\batchmode . . . . . . . . . . . . . . . . . . 154 \blanklisting . . . . . . . . . . . . . . . 2, 12

\blankstringfalse . . . . . . 5, \underline{139}, 152
\blankstringtrue . . . . . . . . . . . 5, \underline{139}

C

\clisting . . . . . . . . . . . . . . 3, 13, 416 \commentstyle . . . . . . . . . . 4, \underline{131}, 151 \cpplisting . . . . . . . . . . . . . . . . . 4, 14

D

\DeclareCommentLine . . . . . . . . . . .

. . . . . . . 6, \underline{34}, 385, 407, 431, 452, 494, 528, 549, 572, 597, 650

\DeclareDoubleComment . . . . . . . . .

. . . . . . . . . . . 6, \underline{69}, 573, 598, 651

\DeclareNestedComment . . . . 6, \underline{98}, 550

\DeclareOption . . . . . . . . . . . . . . 2–11

                                       \DeclareSingleComment . . . . 6, \underline{46},

70, 99, 386, 408, 432, 453, 495, 529

E \eiffellisting . . . . . . . . . . . . . . 5, 15 \endlisting . . . . . . . . . . . . . . . . . . 192 environments:

listing . . . . . . . . . . . . . . . . . . . 3 \errorstopmode . . . . . . . . . . . . . . . 154 \ExecuteOptions . . . . . . . . . . . . . . 377

F \fortranlisting . . . . . . . . . . . . . 6, 16

I

                                       \if@lst@comment . . . . . . . . . . . \underline{30},

91, 230, 232, 240, 256, 272, 295, 328

                                       \if@lst@endinput . . . . . . . . . . \underline{28}, 172

\if@lst@string . . . . . . . . . . . . . . .

. . \underline{30}, 225, 236, 277, 294, 327, 461 \iflisting . . . . . . . . . . . \underline{28}, 160, 184 \inputlisting . . . . . . . . . . . . . . 3, \underline{153}

J \javalisting . . . . . . . . . . . . . . . . 7, 17

K \keywords … 6, \underline{131}, 383, 404, 427,

449, 491, 524, 546, 569, 594, 647 \keywordstyle . . . . . . . . . . 4, \underline{131}, 151 \lccode . . . . . . . . . . . . . . . . . 195, 196 \listing . . . . . . . . . . . . . . . . . . . . \underline{183} listing (environment) . . . . . . . . . . . 3 \listingfalse . . . . . . . . . . . . . . . . . 4 \listingtrue . . . . . . . . . . . . . . . 4, 375 \lowercase . . . . . . . . . . . . . . . . . . 197

\lst@active@blank . 320, 335, 354, 356
\lst@AllLineProcessing 167, 203, \underline{221}

\lst@begin . . . . . . . . . . 163, 185, \underline{209} \lst@blank . . . . . . . . . . . . . . . . . . \underline{380} \lst@c . . . . . . . . . . . . . . . . . . . . . . \underline{402}

\lst@CaseSensitiveKeywords . \underline{118}, 144
\lst@ChangeCatcodes . . . . . . . 214, \underline{348}
\lst@CharOutput . . . . . . . . . . . . . .

. . . . . 262, 272, 278, 282, \underline{325}, 335

\lst@closing@stringizer . . . 279, 288

\lst@comment . . . . . . \underline{34}, 57, 62, 67, 78, 83, 88, 104, 111, 212, 231, 232, 239, 243, 244, 252, 253, 257

\lst@comment@depth . . . . . . . . . . . .

. . . . . . . . . \underline{30}, 109, 110, 114, 211

\lst@CommentLine . . . . 12, 33, \underline{34}, 234
\lst@commentline . . . . . . . . \underline{34}, 40,

44, 212, 238, 243, 244, 249, 252, 253

\lst@commentstyle . . . . 134, 295, 328

\lst@CountSOC . . . . . . . . 101, 112, 115 \lst@cpp . . . . . . . . . . . . . . . . . . . . \underline{425} \lst@curr . . . . . . . . . . . . . . . . 27, 213

\lst@current@line . . . . . . . . . . . .

. . . . . \underline{29}, 161, 166, 169, 218, 220 \lst@CutCL . . . . . . . . . . . . . . . . 12, \underline{34} \lst@CutEOC . . . . . . . . . 64, 66, 106, 108 \lst@CutEOC@ . . . . . . . . . . . . . . . 85, 87 \lst@CutSOC . . . . . . . . . . . . . 54, 56, 94 \lst@CutSOC@ . . . . . . . . . . . . . . . 75, 77

\lst@DoStringizerTest . . . . . 281, \underline{284}

\lst@eiffel . . . . . . . . . . . . . . . . . . \underline{438} \lst@end . . . . . . . . . . . . 175, 206, \underline{209}

\lst@env@Process . . . . . . . . . 198, 199
\lst@env@Processs . . . . . . . . . . . . \underline{199}
\lst@env@ReadAndProcess 186, 198, 204
\lst@env@ReadAndProcesss . . . . . . . \underline{193}

\lst@EOC . . . . . . 33, \underline{46}, 71, 91, 95, 230 \lst@EOC@ . . . . . . . . . . . . . . . . . 79, 91 \lst@FillBox . . . . . . . . . . . . . 303, \underline{304}

\lst@FillStringBox . . . . 314, \underline{315}, 327

\lst@fortran . . . . . . . . . . . . . . . . . \underline{475}

\lst@GotoNextTabStop . . . . . . 268, \underline{331}

\lst@greater . . . . . . . . . . . . . \underline{336}, 361 \lst@inputfile . . . . . . . . . . . . . . .

. . \underline{28}, 154, 155, 165, 168, 182, 219 \lst@java . . . . . . . . . . . . . . . . . . . \underline{514}

\lst@KeywordOrNot . . . . 144, 146, 296

\lst@keywords . . . . . 123, 130, 136, 137 \lst@keywords@c . . . . . . \underline{392}, 405, 428

                                       \lst@keywords@cpp . . . . . . . . \underline{415}, 428
                                       \lst@keywords@eiffel . . . . . . . . . . \underline{438}
                                       \lst@keywords@fortran . . . . . . . . . \underline{475}
                                       \lst@keywords@java . . . . . . . . . . . . \underline{514}
                                       \lst@keywords@modula . . . . . . . . . . \underline{535}
                                       \lst@keywords@pascal . . \underline{557}, 570, 595
                                       \lst@keywords@pxsc . . . . . . . . . . . . \underline{580}
                                       \lst@keywords@tp . . . . . . . . . . . . . \underline{605}
                                       \lst@keywordstyle . . . . 121, 127, 133

\lst@last@line . . . . . . . . \underline{29}, 169, 216 \lst@leftbrace . . . . . . . . . . . \underline{336}, 358 \lst@length . . . . . . . . . . . . . . . . . .

. . \underline{32}, 222, 266, 298, 299, 302, 313 \lst@less . . . . . . . . . . . . . . . \underline{336}, 360 \lst@line \underline{34}, 37, 41, 44, 50, 54, 57,

58, 62, 64, 67, 75, 78, 79, 83, 85, 88, 94, 104, 106, 111, 165, 202, 219, 235, 257, 262, 462, 467, 471, 501, 505, 506, 508, 509

\lst@Listing . . . . . . . . . . . . 12–21, \underline{22} \lst@MakeBox . . . . . . . . . . . . . . . . .

. 120, 121, 126, 127, 140, 295, \underline{301}

                                       \lst@MakeSpecialStringBox . . 142, \underline{312}
                                       \lst@MakeStringBox . . . . 140, 142, 294

\lst@minus . . . . . . . . . . . . . . \underline{336}, 363 \lst@modula . . . . . . . . . . . . . . . . . . \underline{535} \lst@multiply . . . . . . . . . . . . \underline{336}, 364 \lst@next . . . . . . . . . . . 264, 271, 275

                                       \lst@NonCaseSensitiveKeywords . .

. . . . . . . . . . . . . . . . . . . \underline{124}, 146 \lst@Output . . . . . . . . . . 268, 270, \underline{292} \lst@pascal . . . . . . . . . . . . . . . . . . \underline{565} \lst@pos … \underline{33}, 222, 298, 325, 332–334

                                       \lst@postlisting . . . . . . . . . 132, 215

\lst@prelisting . . . . . . . . . . 131, 210

                                       \lst@PreProcessLine . . . . . . . . . . .

. . . . . . . . 223, 389, 411, 434, 456, 498, 531, 553, 576, 601, 654

                                       \lst@PreProcessLine@CutPercent .

. . . . . . . . . . . . . . . . . . . 467, \underline{469}

                                       \lst@PreProcessLine@eiffel . 456, \underline{460}
                                       \lst@PreProcessLine@fortran 498, \underline{500}
                                       \lst@PreProcessLine@TestPercent . \underline{460}
                                       \lst@PreProcessLineDefault . . . . .

. . . . . . . . . . . . \underline{224}, 389, 411, 434, 466, 531, 553, 576, 601, 654

                                       \lst@ProcessLine . . . . . . . . . 223, \underline{229}

\lst@pxsc . . . . . . . . . . . . . . . \underline{580}, 647 \lst@rightbrace . . . . . . . . . . \underline{336}, 359 \lst@SavedEOC . . . . . . . . . . . . . . 71, 95 \lst@SetRange . . . . . . . . . . . . 161, \underline{216}

\lst@sharp@catcode . . . . . . . . . . . .

. . . . . . . . 367, 388, 410, 433, 455, 497, 530, 552, 575, 600, 653

\lst@SkipUptoFirst . . . . . . . . 162, \underline{216}

\lst@SOC . . . . . . . . . . . . . . 33, \underline{46}, 234 \lst@special@c . . . . . . . \underline{398}, 405, 428

\lst@string@blank . . . . . . . . 320, \underline{344}

\lst@stringizer . . . . . . . . . . 138, 281

\lst@stringstyle . . . . . 135, 313, 327

\lst@tab@length …. \underline{33}, 147, 333, 376 \lst@test . . . . . . . . . . . . . . . . . . . 213 \lst@TestCL . . . . . . . . . . . . . . . . 12, \underline{34} \lst@TestEOC . . . . . . . . . . . 58, 59, 100 \lst@TestEOC@ . . . . . . . . . . . . . . 79, 80 \lst@TestSOC . . . . . . . . . . . . 50, 51, 89 \lst@TestSOC@ . . . . . . . . . . . . . . 72, 90

\lst@TestSpecialComment@fortran .

. . . . . . . . . . . . . . . . . . . 501, 503

\lst@TestStringizer . . . . . . . 273, \underline{276}

\lst@text . . . . . . . . . . . . . . . . . . .

. 222, 266, 293, 296, 299, 303, 314 \lst@Tokenize . . . . . . . . . . . . . . . .

. 231, 235, 251, \underline{263}, 470, 505, 508 \lst@tp . . . . . . . . . . . . . . . . . . . . . \underline{605}

\lst@TypesetChar . . . . . . . . . 242, \underline{262}

\lst@underbar . . . . . . . . 308, 319, \underline{336}

\lst@vertical@bar . . . . . . . . \underline{336}, 362

\lst@width . \underline{32}, 211, 213, 302, 313, 326

M

\modulalisting . . . . . . . . . . . . . . 8, 18

\morekeywords … 6, \underline{131}, 405, 428,

450, 492, 525, 547, 570, 595, 648

N \normallisting . . . . . . . . . 5, \underline{150}, 374

P \PackageError . . . . . . . . . 25, 148, 156 \PackageWarning . . . . . . . . . . . . . . 226 \pascallisting . . . . . . . . . . 9, 19, 581 \postlisting . . . . . . . . . . . 4, \underline{131}, 152 \prelisting . . . . . . . . . . . . 4, \underline{131}, 152 \ProcessOptions . . . . . . . . . . . . . . 378 \pxsclisting . . . . . . . . . . . . . . . 10, 20

S \sensitivefalse . 6, \underline{139}, 571, 596, 649

\sensitivetrue . . . . . . . . . 6, \underline{139},

384, 406, 429, 451, 493, 526, 548 \stringizer . . 6, \underline{131}, 387, 409, 430,

454, 496, 527, 551, 574, 599, 652 \stringstyle . . . . . . . . . . . 4, \underline{131}, 151

T \tablength . . . . . . . . . . . . . . . . 4, \underline{147} \tplisting . . . . . . . . . . . . . . . . 11, 21

U \uppercase . . . . . . . . . . . . . . 125, 129