mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-10-18 14:31:53 +02:00
7112 lines
273 KiB
TeX
7112 lines
273 KiB
TeX
% \iffalse
|
|
%
|
|
% NOTE: This file contains very long lines (upto approx 270 characters).
|
|
% I haven't wrapped them since I won't do that by hand and haven't
|
|
% written any program doing the work.
|
|
%
|
|
% If you want to read this .dtx file, you might get in trouble with
|
|
% such long lines!
|
|
%
|
|
%
|
|
% S O F T W A R E L I C E N S E
|
|
% =================================
|
|
%
|
|
% The files listings.dtx and listings.ins and all files generated
|
|
% from only these two files are referred as 'the listings package' or
|
|
% simply 'the package'. A driver file is any file generated mainly from
|
|
% lstdrvrs.dtx.
|
|
%
|
|
% Copyright.
|
|
% The listings package is copyright 1996--1998 Carsten Heinz.
|
|
% The driver files are copyright 1997, 1998 or 1997--1998 any
|
|
% individual author listed in these files.
|
|
%
|
|
% Distribution.
|
|
% The listings package as well as lstdrvrs.dtx and all driver files
|
|
% are distributed freely. You are not allowed to take money for the
|
|
% distribution, except for a nominal charge for copying etc..
|
|
%
|
|
% Use of the package.
|
|
% The listings package is free for any non-commercial use. Commercial
|
|
% use needs (i) explicit permission of the author of this package and
|
|
% (ii) the payment of a license fee. This fee is to be determined in
|
|
% each instance by the commercial user and the package author and is
|
|
% to be payed as donation to the LaTeX3 project.
|
|
%
|
|
% No warranty.
|
|
% The listings package as well as lstdrvrs.dtx and all driver files
|
|
% are distributed without any warranty, express or implied, as to
|
|
% merchantability or fitness for any particular purpose.
|
|
%
|
|
% Modification advice.
|
|
% Permission is granted to change the listings package as well as
|
|
% lstdrvrs.dtx. You are not allowed to distribute any changed version
|
|
% of the package or any changed version of lstdrvrs.dtx, neither under
|
|
% the same name nor under a different one. Tell the author of the
|
|
% package about your local changes: other users will welcome removed
|
|
% bugs, new features and additional programming languages.
|
|
%
|
|
% Contacts.
|
|
% Send comments and ideas on the package, error reports and additional
|
|
% programming languages to
|
|
%
|
|
% Carsten Heinz
|
|
% Tellweg 6
|
|
% 42275 Wuppertal
|
|
% Germany
|
|
%
|
|
% or preferably to
|
|
%
|
|
% cheinz@gmx.de
|
|
%
|
|
% Trademarks
|
|
% appear throughout this documentation without any trademark symbol,
|
|
% so you can't assume that a name is free. There is no intention of
|
|
% infringement; the usage is to the benefit of the trademark owner.
|
|
%
|
|
% end of software license
|
|
%
|
|
%<*driver>
|
|
\documentclass{ltxdoc}
|
|
|
|
\usepackage[doc]{listings}[1998/11/09]
|
|
\newif\iffancyvrb
|
|
\IfFileExists{fancyvrb.sty}
|
|
{\fancyvrbtrue \usepackage{fancyvrb}}
|
|
{\fancyvrbfalse}
|
|
|
|
\EnableCrossrefs
|
|
\CodelineIndex
|
|
\OldMakeindex
|
|
\OnlyDescription
|
|
|
|
\begin{document}
|
|
\DocInput{listings.dtx}
|
|
\end{document}
|
|
%</driver>
|
|
% \fi ^^A balance the \iffancyvrb! :-)
|
|
% \fi
|
|
%
|
|
%
|
|
% \makeatletter
|
|
%^^A
|
|
%^^A A modified `environment' environment
|
|
%^^A
|
|
%\def\aspect{^^A
|
|
% \def\SpecialMainEnvIndex##1{^^A
|
|
% \@bsphack ^^A
|
|
% \index{aspects:\levelchar{\protect\ttfamily##1}\encapchar main}^^A
|
|
% \@esphack}^^A
|
|
% \begingroup \catcode`\\12 \MakePrivateLetters ^^A
|
|
% \m@cro@ \iffalse}
|
|
%\let\endaspect\endmacro
|
|
%
|
|
%^^A
|
|
%^^A We define a sample environment. All material between
|
|
%^^A \begin{lstsample} and \end{lstsample} is executed
|
|
%^^A 'on the left side' and typeset verbatim on the right.
|
|
%^^A
|
|
%^^A The environment is *not* designed for purposes other than
|
|
%^^A this documentation.
|
|
% \lst@Environment{lstsample}[1]\is
|
|
% {\gdef\lst@sample{#1}^^A
|
|
% \lst@BeginWriteFile{listings.tmp}^^A
|
|
% \def\lst@BOLGobble##1{}}^^A to gobble each first %
|
|
% {\lst@EndWriteFile ^^A
|
|
%^^A We execute the code resp. typset it verbatim (= empty language
|
|
%^^A with \ttfamily).
|
|
% \begin{center}
|
|
% \small ^^A \lstCC@Let{`\^^M}\space ^^A
|
|
% \begin{minipage}{0.45\linewidth}^^A
|
|
% \MakePercentComment\lst@sample
|
|
% \input{listings.tmp}\MakePercentIgnore^^A
|
|
% \end{minipage}
|
|
% \qquad
|
|
% \begin{minipage}{0.45\linewidth}
|
|
% \lstset{language={},style={},basicstyle=\ttfamily,baseem=0.51}^^A
|
|
% \hbox to \linewidth{\lstbox\lstinputlisting{listings.tmp}\hss}
|
|
% \end{minipage}
|
|
% \end{center}}
|
|
%
|
|
%^^A
|
|
%^^A We redefine the appearance of part, section, ...
|
|
%^^A
|
|
%\def\@part[#1]#2{\addcontentsline{toc}{part}{#1}%
|
|
% {\parindent\z@ \raggedright \interlinepenalty\@M
|
|
% \normalfont \huge \bfseries #2\markboth{}{}\par}%
|
|
% \nobreak\vskip 3ex\@afterheading}
|
|
%\renewcommand*\l@section[2]{%
|
|
% \ifnum \c@tocdepth >\z@
|
|
% \addpenalty\@secpenalty
|
|
% \addvspace{.25em \@plus\p@}%
|
|
% \setlength\@tempdima{1.5em}%
|
|
% \begingroup
|
|
% \parindent \z@ \rightskip \@pnumwidth
|
|
% \parfillskip -\@pnumwidth
|
|
% \leavevmode ^^A \bfseries
|
|
% \advance\leftskip\@tempdima
|
|
% \hskip -\leftskip
|
|
% #1\nobreak\hfil \nobreak\hb@xt@\@pnumwidth{\hss #2}\par
|
|
% \endgroup
|
|
% \fi}
|
|
%\renewcommand*\l@subsection{\@dottedtocline{2}{1.5em}{2.3em}}
|
|
%\renewcommand*\l@subsubsection{\@dottedtocline{3}{3.8em}{3.2em}}
|
|
%\renewcommand\paragraph{\@startsection{paragraph}{4}{\z@}%
|
|
% {1.25ex \@plus1ex \@minus.2ex}%
|
|
% {-1em}%
|
|
% {\normalfont\normalsize\bfseries}}
|
|
%
|
|
%^^A
|
|
%^^A Suppress warning
|
|
%^^A
|
|
% \let\lstenv@DroppedWarning\relax
|
|
% \makeatother
|
|
%
|
|
%^^A
|
|
%^^A The following definitions come in handy soon.
|
|
%^^A There will be more in future.
|
|
%^^A
|
|
% \newcommand\lsthelper[4]{#1\ifx\empty#2\empty\typeout{^^JWarning: #1 has unknown email^^J}\else\space\texttt{<#2>}{}\fi}
|
|
% \newcommand\lstthanks[2]{#1\ifx\empty#2\empty\typeout{^^JWarning: #1 has unknown email^^J}\fi}
|
|
% \newcommand\lst{\texttt{lst}}
|
|
% \lstdefinelanguage[doc]{Pascal}{^^A
|
|
% keywords={alfa,and,array,begin,boolean,byte,case,char,const,div,^^A
|
|
% do,downto,else,end,false,file,for,function,get,goto,if,in,^^A
|
|
% integer,label,maxint,mod,new,not,of,or,pack,packed,page,program,^^A
|
|
% procedure,put,read,readln,real,record,repeat,reset,rewrite,set,^^A
|
|
% text,then,to,true,type,unpack,until,var,while,with,write,writeln},^^A
|
|
% sensitive=false,^^A
|
|
% doublecomment={(*}{*)}{\{}{\}},^^A
|
|
% stringizer=[d]{'}}^^A
|
|
% \lstset{defaultdialect=[doc]Pascal}
|
|
% \lstset{language=Pascal}
|
|
%
|
|
%
|
|
%^^A
|
|
%^^A The long awaited beginning of documentation
|
|
%^^A
|
|
% \newbox\abstractbox
|
|
% \setbox\abstractbox=\vbox{
|
|
% \begin{abstract}
|
|
% Listings.dtx is a source code printer for \LaTeX\ --- which always means \LaTeXe\ in this documentation.
|
|
% You can typeset stand alone files as well as enter listings using an environment similar to \texttt{verbatim} as well as you can print fragments using a command similar to |\verb|.
|
|
%^^A Since listings.dtx is a package and not a cross compiler, all listings are up to date without maintaining differences between (changed) source files and cross compiled files.
|
|
% The package supports a wide spectrum of programming languages --- some come already with \texttt{lstdrvrs.dtx}.
|
|
% Finally: Many parameters control the output.
|
|
% \end{abstract}}
|
|
%
|
|
% \title{{Listings.dtx} Version {0.19}}
|
|
% \author{Copyright 1996--1998 Carsten Heinz}
|
|
% \date{\box\abstractbox}
|
|
%
|
|
% \makeatletter\@twocolumntrue\makeatother
|
|
% \maketitle
|
|
% {\makeatletter\@starttoc{toc}}
|
|
%\iftrue
|
|
% \vfill
|
|
% \noindent \textbf{Again incompatibilities!}
|
|
% And there are certainly teething troubles since the complete kernel has been rewritten.
|
|
% So read this manual with care.
|
|
%\fi
|
|
% \onecolumn
|
|
%
|
|
%
|
|
% \part{User's guide}
|
|
%
|
|
%
|
|
% \section{Preface}
|
|
%
|
|
% The files \texttt{listings.dtx} and \texttt{listings.ins} and all files generated from only these two files are referred as 'the \textsf{listings} package' or simply 'the package'.
|
|
% A driver file is any file generated mainly from \texttt{lstdrvrs.dtx}.
|
|
%
|
|
% \paragraph{Alternatives.}
|
|
% The \textsf{listings} package is certainly not the final utility for typesetting source code listings.
|
|
% Other programs do their jobs very well if you are not satiesfied with \textsf{listings}.
|
|
% I should mention \textsf{a2ps} and the \textsf{LGrind} package.
|
|
% Let me know if you're using none of these solutions; I'd like to extend my suggestions.
|
|
%
|
|
% \paragraph{Reading this manual.}
|
|
% In any case you should read section ''\emph{\ref{uGettingStarted}. Getting started}'' step by step.
|
|
% You either start from the scratch there or you get in touch with the new user interface and other changes.
|
|
% That section is an introduction and doesn't cover all of the \textsf{listings} package, but the most common.
|
|
% After reading it you are prepared for the main reference if you need more details, more control or more features.
|
|
%
|
|
% \paragraph{Sorry!}
|
|
% On 1998/11/02 I decided to make major changes to the user interface, which were planned for version 0.2.
|
|
% But it's better to get the interface stable as soon as possible.
|
|
% In particular I must say sorry to all people I posted a pre-version of \textsf{listings} 0.19.
|
|
%
|
|
% \paragraph{Thanks.}
|
|
% There are many people I have to thank for fruitful communication, posting their ideas, giving error reports (first bug finder is listed), adding programming languages to \texttt{lstdrvrs.dtx}, etc..
|
|
% If you want to know that in detail, search for the names in the implementation part.
|
|
%^^A
|
|
%^^A Thanks for error reports (first bug finder only), new programming languages, etc.
|
|
%^^A Special thanks for communication which lead to kernel extensions.
|
|
%^^A
|
|
% Special thanks go to (alphabetical order)
|
|
% \begin{quote}
|
|
% \hyphenpenalty=10000\relax \rightskip=0pt plus \linewidth\relax
|
|
% \lstthanks{Andreas~Bartelt}{Andreas.Bartelt@Informatik.Uni-Oldenburg.DE},
|
|
% \lstthanks{Jan~Braun}{Jan.Braun@tu-bs.de},
|
|
% \lstthanks{Denis~Girou}{Denis.Girou@idris.fr},
|
|
% \lstthanks{Arne~John~Glenstrup}{panic@diku.dk},
|
|
% \lstthanks{Rolf~Niepraschk}{NIEPRASCHK@PTB.DE},
|
|
% \lstthanks{Rui~Oliveira}{rco@di.uminho.pt} and
|
|
% \lstthanks{Boris~Veytsman}{boris@plmsc.psu.edu}.
|
|
% \end{quote}
|
|
% Moreover I wish to thank
|
|
% \begin{quote}
|
|
% \hyphenpenalty=10000\relax \rightskip=0pt plus \linewidth\relax
|
|
% \lstthanks{Bj{\o}rn~{\AA}dlandsvik}{bjorn@imr.no},
|
|
% \lstthanks{Gaurav~Aggarwal}{gaurav@ics.uci.edu},
|
|
% \lstthanks{Kai~Below}{below@tu-harburg.de},
|
|
% \lstthanks{Detlev~Dr\"oge}{droege@informatik.uni-koblenz.de},
|
|
% \lstthanks{Anders~Edenbrandt}{Anders.Edenbrandt@dna.lth.se},
|
|
% \lstthanks{Harald~Harders}{h.harders@tu-bs.de},
|
|
% \lstthanks{Christian~Haul}{haul@dvs1.informatik.tu-darmstadt.de},
|
|
% \lstthanks{J\"urgen~Heim}{heim@astro.uni-tuebingen.de},
|
|
% \lstthanks{Dr.~Jobst~Hoffmann}{HOFFMANN@rz.rwth-aachen.de},
|
|
% \lstthanks{Knut~M\"uller}{knut@physik3.gwdg.de},
|
|
% \lstthanks{Zvezdan~V.~Petkovic}{zpetkovic@acm.org},
|
|
% \lstthanks{Michael~Piotrowski}{mxp@linguistik.uni-erlangen.de},
|
|
% \lstthanks{Ralf~Quast}{rquast@hs.uni-hamburg.de},
|
|
% \lstthanks{Aslak~Raanes}{araanes@ifi.ntnu.no},
|
|
% \lstthanks{Detlef~Reimers}{dreimers@aol.com},
|
|
% \lstthanks{Magne~Rudshaug}{magne@ife.no},
|
|
% \lstthanks{Andreas~Stephan}{astepha@wmpi04.math.uni-wuppertal.de},
|
|
% \lstthanks{Dominique~de~Waleffe}{ddw@miscrit.be},
|
|
% \lstthanks{Herbert~Weinhandl}{weinhand@grz08u.unileoben.ac.at},
|
|
% \lstthanks{J\"orn~Wilms}{wilms@rocinante.colorado.edu} and
|
|
% \lstthanks{Kai~Wollenweber}{kai@ece.WPI.EDU}.
|
|
% \end{quote}
|
|
%
|
|
%^^A \lsthelper{Andreas Bartelt}{Andreas.Bartelt@Informatik.Uni-Oldenburg.DE}{1997/09/11}{single line comes out using \inputlisting inside \fbox}
|
|
%^^A \lsthelper{Michael Piotrowski}{mxp@linguistik.uni-erlangen.de}{1997/11/04}{! Use of \lstdrv@perl@TestCommentCut doesn't match its definition^^J\lst@line ->I^^JRF::LangID -- Statistical identification of language for IRF/1^^J^^J(POD ist Zeile '=irgendwas' bis Zeile '=cut')}
|
|
%^^A \lsthelper{Bj{\o}rn {\AA}dlandsvik}{bjorn@imr.no}{1997/10/27}{listings.sty is incompatible to inputenc.sty}
|
|
%
|
|
%
|
|
% \section{Software license}
|
|
%
|
|
% \paragraph{Copyright.}
|
|
% The \textsf{listings} package is copyright 1996--1998 Carsten Heinz.
|
|
% The driver files are copyright 1997, 1998 or 1997--1998 any individual author listed in these files.
|
|
%
|
|
% \paragraph{Distribution.}
|
|
% The \textsf{listings} package as well as \texttt{lstdrvrs.dtx} and all driver files are distributed freely.
|
|
% You are not allowed to take money for the distribution, except for a nominal charge for copying etc..
|
|
%
|
|
% \paragraph{Use of the package.}
|
|
% The \textsf{listings} package is free for any non-commercial use.
|
|
% Commercial use needs (i) explicit permission of the author of this package and (ii) the payment of a license fee.
|
|
% This fee is to be determined in each instance by the commercial user and the package author and is to be payed as donation to the \LaTeX3 project.
|
|
%
|
|
% \paragraph{No warranty.}
|
|
% The \textsf{listings} package as well as \texttt{lstdrvrs.dtx} and all driver files are distributed without any warranty, express or implied, as to merchantability or fitness for any particular purpose.
|
|
%
|
|
% \paragraph{Modification advice.}
|
|
% Permission is granted to change the \textsf{listings} package as well as \texttt{lstdrvrs.dtx}.
|
|
% You are not allowed to distribute any changed version of the package or any changed version of \texttt{lstdrvrs.dtx}, neither under the same name nor under a different one.
|
|
% Tell the author of the package about your local changes: other users will welcome removed bugs, new features and additional programming languages.
|
|
%
|
|
% \paragraph{Contacts.}
|
|
% Send comments and ideas on the package, error reports and additional programming languages to \emph{Carsten Heinz, Tellweg 6, 42275 Wuppertal, Germany} or preferably to \texttt{cheinz@gmx.de}.
|
|
%
|
|
% \paragraph{Trademarks}
|
|
% appear throughout this documentation without any trademark symbol, so you can't assume that a name is free.
|
|
% There is no intention of infringement; the usage is to the benefit of the trademark owner.
|
|
%
|
|
%
|
|
% \section{Getting started}\label{uGettingStarted}
|
|
%
|
|
%
|
|
% \iffalse
|
|
% \subsection{Installation}
|
|
%
|
|
% \begin{enumerate}
|
|
% \item You need \texttt{listings.dtx} and \texttt{listings.ins} to install the \textsf{listings} package.
|
|
% \texttt{lstdrvrs.dtx} contains some language drivers.
|
|
% Move \texttt{.dtx} and \texttt{.ins} files into a separate folder if you want to.
|
|
% \item Remove all \texttt{lst???.sty} files if you update from an earlier version.
|
|
% \item Run \texttt{listings.ins} through \TeX.
|
|
% This creates the kernel \texttt{listings.sty} and two interface files \texttt{lst017.sty} and \texttt{lstfvrb.sty}.
|
|
% If you have \texttt{lstdrvrs.dtx}, a configuration file \texttt{listings.cfg} and a couple of driver files are also generated.
|
|
% \item Copy all created \texttt{.sty} and \texttt{.cfg} files to a directory searched by \TeX.
|
|
% \end{enumerate}
|
|
% \fi
|
|
%
|
|
%
|
|
% \subsection{Package loading}
|
|
%
|
|
% As usual in \LaTeX\ the package is loaded by |\usepackage[|\meta{options}|]{listings}|, where |[|\meta{options}|]| is optional.
|
|
% Note that \textsf{listings} 0.19 needs more save stack size than any previous version.
|
|
% The following options are available:
|
|
% \begin{description}
|
|
% \item[\texttt{0.17}]
|
|
% Use this option to compile documents created with version 0.17 of the \textsf{listings} package.
|
|
% Note that you can't use old driver files and that the option does not guarantee full compatibility.
|
|
% If you want to polish up an old document, use this option together with new commands and keys.
|
|
% There shouldn't be many problems, but I haven't made deep tests.
|
|
% \item[\normalfont\texttt{index} and \texttt{procnames}] define the 'index' respectively 'procnames' aspect, whatever that means.
|
|
% \item[\normalfont\texttt{ndkeywords} and \texttt{rdkeywords}] define second respectively third order keywords.
|
|
% \end{description}
|
|
% Note: Each option slows down the package, so it becomes quite slow if you use all options, for example.
|
|
% Note also that you can't activate any optional feature after package loading --- except you're a hacker and read the implementation part.
|
|
%
|
|
% Here is some kind of minimal file.
|
|
% \begin{verbatim}
|
|
% \documentclass{article}
|
|
%
|
|
% \usepackage{listings}
|
|
% %\usepackage[ndkeywords,index]{listings}% with some options
|
|
%
|
|
% \begin{document}
|
|
%
|
|
% \lstset{language=Pascal}
|
|
% % Any example may be inserted here.
|
|
%
|
|
% \end{document}\end{verbatim}
|
|
% \label{uMinimalFile}It loads the \textsf{listings} package without any option, but shows how the package is loaded with index option and second order keywords.
|
|
% Moreover we select Pascal as programming language.
|
|
%
|
|
% If you need more than one programming language in your document, I recommend the preamble command |\lstloadlanguages|, which loads the given programming languages only, e.g.\ |\lstloadlanguages{Pascal,Fortran,C++}|.
|
|
% You find more details in section \ref{uLanguagesAndStyles}.
|
|
%
|
|
%
|
|
% \subsection{Typesetting listings}
|
|
%
|
|
% You can print (a) stand alone files, (b) source code from \texttt{.tex} files or (c) code fragments within a paragraph.
|
|
% The difference between (b) and (c) is something like between display and text formulas (|$$| and |$|).
|
|
%
|
|
% We begin with code fragments.
|
|
% If you want '\lstinline!var i:integer;!', you can simply write '|\lstinline!var i:integer;!|'.
|
|
% The exclamation marks delimit the code fragment.
|
|
% They could be replaced by any character not in the code fragment, i.e.\ '|\lstinline$var i:integer;$|' would produce the same output.
|
|
%
|
|
% The \texttt{lstlisting} environment typesets the source code in between.
|
|
% It has one parameter, which we leave empty for the moment.
|
|
% \begin{lstsample}{}
|
|
%\begin{lstlisting}{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% Like most examples this shows the \LaTeX\ source code on the right and the result on the left.
|
|
% If you insert the \LaTeX\ code in the minimal file and run it through \TeX, the listing uses the whole text width.
|
|
%
|
|
% Finally examples for stand alone files:
|
|
% \begin{lstsample}{\lstset{baseem=0.5}}
|
|
%\lstinputlisting{listings.tmp}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% Do you wonder about the left hand side?
|
|
% Well, the file \texttt{listings.tmp} contains the current example.
|
|
% This is exactly the line you see on the right.
|
|
% If you want this line to be typeset in Pascal mode, you get what you've got.
|
|
% If you want the lines $3,4,\ldots,10$ of \texttt{testfile.pas}, write
|
|
% \begin{verbatim}
|
|
% \lstinputlisting[first=3,last=10]{testfile.pas}\end{verbatim}
|
|
% But be sure that the first line does exist, or you will get a ''runaway argument'' error.
|
|
%
|
|
% Problems could arise if you (try to) put a listing in a box, tabular environment or something similar.
|
|
% The |\lstbox| command in section \ref{uTypesettingListings} might solve this.
|
|
% If you use an extended character table in your listings, you must use the |extendedchars| key, see section \ref{uSomeSpecialKeys}.
|
|
%
|
|
%
|
|
% \subsection{The ''key=value'' interface}
|
|
%
|
|
% The \textsf{listings} package uses \textsf{keyval.sty} from the \textsf{graphics} bundle by David Carlisle.
|
|
% Each 'aspect' or 'parameter' you can control has an associated key.
|
|
% To select a programming language, for example, you need the key |language|, the sign |=| and the name of the language as value.
|
|
% The command |\lstset| gets this construction as argument.
|
|
% You have seen this in the minimal file on page \pageref{uMinimalFile}.
|
|
% You can set more than one parameter with a single |\lstset| if you separate two or more ''key=value'' constructions by commas:
|
|
% \begin{verbatim}
|
|
% \lstset{language=Pascal,keywordstyle=\bfseries}\end{verbatim}
|
|
% If the value itself contains a comma, you must enclose the value in braces:
|
|
% \begin{verbatim}
|
|
% \lstset{keywords={one,two,three}}\end{verbatim}
|
|
% |\lstset{keywords=one,two,three}| would set the one and only keyword |one| and gives an error message since the parameters |two| and |three| do not exist.
|
|
%
|
|
% Two final notes:
|
|
% (1) Some keys has default values, e.g.\ |flexiblecolumns=true| turns flexible columns on, but |flexiblecolumns| without any |=true| would do the same since the value true is default for that key.
|
|
% But you must use the value |false| if you want to turn them off.
|
|
% (2) |\lstset| sets the values local to the current group.
|
|
% Just forget it if you don't know what that means.
|
|
% The command |\lstinputlisting| (as seen above) and the environment (as you see below) both have optional arguments.
|
|
% If you use a key=value list as optional argument, these selections are valid for the particular listing only and the previous values are restored afterwards.
|
|
% For example, if the current language is Pascal, but you want \texttt{testfile.f95} from line 3 on, write
|
|
% \begin{verbatim}
|
|
% \lstinputlisting[first=3,language=Fortran]{testfile.f95}\end{verbatim}
|
|
% Afterwards Pascal is still the current language.
|
|
% Note that |\lstinline| has no optional parameter.
|
|
%
|
|
%
|
|
% \subsection{Figure out the appearance}
|
|
%
|
|
% Keywords are typeset bold, comments in italic shape and spaces in strings appear as '\textvisiblespace' (without the two quotes).
|
|
% You can change that default behaviour:
|
|
% \begin{verbatim}
|
|
%\lstset{
|
|
% basicstyle=\small, % print whole listing small
|
|
% keywordstyle=\bfseries\underbar,% 'underlined' bold keywords
|
|
% nonkeywordstyle={}, % nothing happens to other identifiers
|
|
% commentstyle=\itshape, % default
|
|
% stringstyle=\ttfamily, % typewriter font for strings
|
|
% blankstring=true} % blank spaces are blank in strings\end{verbatim}
|
|
% We typeset a previous example with these styles again.
|
|
%\lstset{basicstyle=\small,
|
|
% keywordstyle=\bfseries\underbar,nonkeywordstyle={},
|
|
% commentstyle=\itshape,stringstyle=\ttfamily,blankstring=true}
|
|
% \begin{lstsample}{}
|
|
%\begin{lstlisting}{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% The style definitions above use two kind of commands; on the one hand |\ttfamily| or |\bfseries| taking no arguments and on the other |\underline|, which gets exactly one argument.
|
|
% The \emph{very last} token of |keywordstyle|, |nonkeywordstyle| and |labelstyle| (see below) \emph{may} be a macro getting exactly one argument, namely the (non)keyword or label.
|
|
% All other tokens \emph{must not} take any arguments --- or you will get deep in trouble.
|
|
% \lstset{style={},blankstring=false}
|
|
%
|
|
% \textbf{Warning:}
|
|
% You shouldn't use striking styles too often, but 'too often' depends on how many keywords the source code contains, for example.
|
|
% Your eyes would concentrate on the framed, bold red printed keywords only, and your brain must compensate this.
|
|
% Reading such source code could be very exhausting.
|
|
% If it were longer, the last example would be quite good in this sense.
|
|
% Believe me.
|
|
%
|
|
%
|
|
% \subsection{Line numbers}
|
|
%
|
|
% You want tiny line numbers each second line?
|
|
% Here you are:
|
|
% \begin{lstsample}{}
|
|
%\lstset{labelstyle=\tiny,% <===
|
|
% labelstep=2}% <===
|
|
%\begin{lstlisting}{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% |labelstep=0| turns line numbering off.
|
|
% In the sequel we use |labelstyle=\tiny| and |labelstep=2|, even if it doesn't appear in the verbatim part.
|
|
% And now we try to interrupt (continue) a listing.
|
|
% For this purpose we use |{ }| as argument to the environment.
|
|
% \begin{lstsample}{\lstset{labelstyle=\tiny,labelstep=2}}
|
|
%\begin{lstlisting}{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%
|
|
%\end{lstlisting}
|
|
%
|
|
%And we continue the listing:
|
|
%
|
|
%\begin{lstlisting}{ }% <===
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% Note that the empty line at the end of the first part is not printed, but it is responsible for correct line numbering.
|
|
% |{ }| continued the previous '|{}|'-listing.
|
|
% In general the argument is the name of the listing.
|
|
% An empty (= |{}|) named listing always starts with line number one, no matter whether line numbers are printed or not.
|
|
% A space (= |{ }|) named listing continues the last empty or space named one.
|
|
% That's easy.
|
|
% And this mechanism becomes easier if you use real names for your listings.
|
|
% In that case all listings with the same name use a common line counter: the second (same named) listing continues automatically the first.
|
|
% Even if there are other listings in between.
|
|
% \begin{lstsample}{\lstset{labelstyle=\tiny,labelstep=2}}
|
|
%\begin{lstlisting}{Test}% <===
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%
|
|
%\end{lstlisting}
|
|
%
|
|
%And we continue the listing:
|
|
%
|
|
%\begin{lstlisting}{Test}% <===
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% The next |Test| listing goes on with line number {\makeatletter\lstno@Test}.
|
|
% Note that listing names are case sensitive.
|
|
%
|
|
%
|
|
% \subsection{Tabulators and form feeds}
|
|
%
|
|
% You might get some unexpected output if your source code contains a tabulator or form feed.
|
|
% The package assumes tabulator stops at columns 9,17,25,33,\ldots, and a form feed prints an empty line.
|
|
% This is predefined via
|
|
% \begin{verbatim}
|
|
% \lstset{tabsize=8,formfeed=\bigbreak}\end{verbatim}
|
|
% If you change the eight to the number $n$, you will get tabulator stops at columns $n+1,\allowbreak 2n+1,\allowbreak 3n+1,$ and so on.
|
|
% If you want a new page every form feed, use |formfeed=\newpage|.
|
|
% \lstset{tabsize=4}
|
|
% \begin{lstsample}{}
|
|
%\lstset{tabsize=4}
|
|
%\begin{lstlisting}{}
|
|
%123456789
|
|
% { one tabulator }
|
|
% { two tabs }
|
|
%123 { 123 and two tabs }
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \lstset{tabsize=8}\noindent
|
|
% Unfortunately both sides are typeset with |tabsize=4|.
|
|
%
|
|
%
|
|
% \subsection{Indent the listing}
|
|
%
|
|
% The examples are typeset with centered \texttt{minipage}s.
|
|
% That's the reason why you can't see that line numbers are printed in the margin (default).
|
|
% Now we separate the 'minipage margin' and the minipage by a vertical rule:
|
|
% \begin{lstsample}{\lstset{frame=l,frametextsep=0pt,labelstyle=\tiny,labelstep=2}}
|
|
%Some text before
|
|
%\begin{lstlisting}{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% The listing is lined up with the normal text.
|
|
% You can change this if you want.
|
|
% The parameter |indent| 'moves' the listing to the right (or left if the skip is negative).
|
|
% \begin{lstsample}{\lstset{frame=l,frametextsep=0pt,labelstyle=\tiny,labelstep=2}}
|
|
%Some text before
|
|
%\lstset{indent=2em}% <===
|
|
%\begin{lstlisting}{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%\end{lstlisting}
|
|
%
|
|
%\begin{lstlisting}{ }
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% Note that |\lstset{indent=2em}| also changes the indent for the second listings.
|
|
% If you want to indent a single listing only, use the argument of |\lstset| as optional argument to the listing environment:
|
|
% \begin{lstsample}{\lstset{frame=l,frametextsep=0pt,labelstyle=\tiny,labelstep=2}}
|
|
%\begin{lstlisting}[indent=2em]{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%\end{lstlisting}
|
|
%
|
|
%\begin{lstlisting}{ }
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% Such local changes apply to all supported parameters.
|
|
%
|
|
% If you use environments like \texttt{itemize} or \texttt{enumerate}, there is 'natural' indention coming from these environments.
|
|
% By default the \textsf{listings} package respects this.
|
|
% But you might use |wholeline=true| (or |false|) to make your own decision.
|
|
% \begin{lstsample}{\lstset{frame=l,frametextsep=0pt,labelstyle=\tiny,labelstep=2}}
|
|
%\begin{itemize}
|
|
%\item First item:
|
|
%
|
|
%\begin{lstlisting}{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%\end{lstlisting}
|
|
%
|
|
%\item Second item:
|
|
%\lstset{wholeline=true}% <===
|
|
%\begin{lstlisting}{ }
|
|
%Write('Keywords are case ');
|
|
%WritE('insensitive here.');
|
|
%\end{lstlisting}
|
|
%\end{itemize}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% You can use |wholeline| together with |indent|, of course.
|
|
% Refer section \ref{uListingAlignment} for a description of |spread|.
|
|
%
|
|
%
|
|
% \subsection{Fixed and flexible columns}
|
|
%
|
|
% The first thing a reader notices is --- except different styles for keywords etc. --- the column alignment of a listing.
|
|
% The problem: I don't like listings in typewriter fonts and other fonts need not to have a fixed width.
|
|
% But we don't want
|
|
% \begin{itemize}\item[]\begin{tabular}{@{}l}
|
|
% if\ x=y\ then\ write('alignment')\\
|
|
% \ \ \ \ \ \ \ else\ print('alignment');
|
|
% \end{tabular}\end{itemize}
|
|
% only because spaces are not wide enough.
|
|
% There is a simple trick to avoid such things.
|
|
% We make boxes of the same width and put one character in each box:
|
|
% \def\docharfbox#1#2{\fbox{\hbox to#1em{\hss\vphantom{fy}#2\hss}}}
|
|
% \def\docharbox#1#2{\hbox to#1em{\hss#2\hss}}
|
|
% \begin{itemize}\item[]
|
|
% \def\makeboxes#1{\docharfbox1#1\ifx#1\relax\else\expandafter\makeboxes\fi}
|
|
% \makeboxes if\ x=y\ then\ write\relax\space\ldots\\
|
|
% \makeboxes \ \ \ \ \ \ \ else \ print\relax\space\ldots
|
|
% \end{itemize}
|
|
% Going this way the alignment of columns can't be disturbed.
|
|
% \def\makeboxes#1{\docharbox{0.45}#1\ifx#1\relax\else\expandafter\makeboxes\fi}
|
|
% But if the boxes are not wide enough, we get '\makeboxes if\ x=y\ then\relax\ldots', and choosing the width so that the widest character fits in leads to
|
|
% \def\makeboxes#1{\docharbox{1}#1\ifx#1\relax\else\expandafter\makeboxes\fi}
|
|
% '\makeboxes if\ x=y\ then\ write\relax\ldots'.
|
|
% Both are not acceptable.
|
|
% Since all input will be cut up in units, we can put each unit in a box, which width is multiplied by the number of characters we put in, of course.
|
|
% The result is
|
|
% \def\makeboxes#1#2{\docharfbox{#1}{#2}\ifx#2\relax\else\expandafter\makeboxes\fi}
|
|
% \makeboxes{1.4}{i\hss f}{.7}{\ }{.7}{x}{.7}{=}{.7}{y}{.7}{\ }{2.8}{t\hss h\hss e\hss n}{.7}{\ }{3.5}{w\hss r\hss i\hss t\hss e}{.7}\relax\space.
|
|
% Since we put wide and thin characters in the same box, the width of a single character box need not to be the width of the widest character.
|
|
% The empirical value {\makeatletter\lst@baseemfixed}em (which is called 'base em' later) is a compromise between overlapping characters and the number of boxes not exceeding the text width, i.e.\ how many characters fit a line without getting an overfull |\hbox|.
|
|
%
|
|
% \begingroup
|
|
% But overlapping characters are a problem if you use many upper case letters, e.g.\ \docharbox{3}{W\hss O\hss M\hss E\hss N} --- blame me and not the women, in fact \docharbox{1.8}{M\hss E\hss N} doesn't look better.
|
|
% To go around this problem the \textsf{listings} package supports more 'flexible columns' in contrast to the fixed columns above.
|
|
% Arne John Glenstrup (whose idea the format is) pointed out that he had good experience with flexible columns and assembler listings.
|
|
% The differences can be summed up as follows: The fixed column format ruins the nice spacing intended by the font designer, and the flexible format ruins the column alignment (possibly) intended by the programmer.
|
|
% We illustrate that:
|
|
% \lstset{style={},language={}}
|
|
% \def\sample{\begin{lstlisting}{}^^J\ WOMEN\ \ are^^J \ \ \ \ \ \ \ MEN^^J WOMEN are^^J better MEN^^J \end{lstlisting}}
|
|
% \begin{center}\begin{tabular}{c@{\qquad\quad}c@{\qquad\quad}c}
|
|
% verbatim&fixed columns&flexible columns\\
|
|
% &with {\makeatletter\lst@baseemfixed}em&with {\makeatletter\lst@baseemflexible}em\\ \noalign{\medskip}
|
|
% \setkeys{lst}{basicstyle=\ttfamily,baseem=0.51}\lstbox\sample&\lstset{flexiblecolumns=false}\lstbox\sample&\lstset{flexiblecolumns=true}\lstbox\sample\lstset{flexiblecolumns=false}
|
|
% \end{tabular}\end{center}
|
|
% Hope this helps.
|
|
% Note the varying numbers of spaces between 'WOMEN' and 'are' and look at the different outputs.
|
|
% The flexible column format typesets all characters at their natural width.
|
|
% In particular characters never overlap.
|
|
% If a word needs more space than reserved ('WOMEN'), the rest of the line moves to the right.
|
|
% Sometimes a following word needs less space than reserved, or there are spaces following each other.
|
|
% Such 'surplus' space is used to fix the column alignment:
|
|
% The blank space in the third line have been printed properly, but the two blanks in the first line have been printed as one blank space.
|
|
% We can show all this more drastic if we reduce the width of a single character box:
|
|
% \begin{center}\lstset{baseem={0.3,0.0}}\begin{tabular}{c@{\qquad\quad}c@{\qquad\quad}c}
|
|
% &{\makeatletter\lst@baseemfixed}em&{\makeatletter\lst@baseemflexible}em\\ \noalign{\medskip}
|
|
% \setkeys{lst}{basicstyle=\ttfamily,baseem=0.51}\lstbox\sample&\lstset{flexiblecolumns=false}\lstbox\sample&\lstset{flexiblecolumns=true}\lstbox\sample\lstset{flexiblecolumns=false}
|
|
% \end{tabular}\end{center}
|
|
% In flexible column mode the first 'MEN' moves to the left since the blanks before are $7\cdot 0.0$em$=0$em wide.
|
|
% Even in flexible mode you shouldn't reduce 'base em' to less than 0.33333em ($\approx$ width of a single space).
|
|
% \endgroup
|
|
%
|
|
% You want to know how to select the flexible column format and how to reset to fixed columns?
|
|
% Try |flexiblecolumns=true| and |flexiblecolumns=false|.
|
|
%
|
|
%
|
|
% \subsection{Selecting other languages}\label{uSelectingOtherLanguages}
|
|
%
|
|
% You already know that |language=|\meta{language name} selects programming languages --- at least Pascal and Fortran.
|
|
% But that's not the whole truth.
|
|
% Both languages know different dialects (= version or implementation), for example Fortran 77 and Fortran 90.
|
|
% You can choose such special versions with the optional argument of |language|.
|
|
% Write
|
|
% \begin{verbatim}
|
|
% \lstset{language=[77]Fortran}% Fortran 77
|
|
% \lstset{language=[XSC]Pascal}% Pascal XSC\end{verbatim}
|
|
% to select Fortran 77 and Pascal XSC, respectively.
|
|
%
|
|
% We give a list of all languages and dialects supported by \texttt{lstdrvrs.dtx}.
|
|
% Use the given names as (optional) values to |language|.
|
|
% An 'empty' language is also defined: |\lstset{language={}}| detects no keywords, no comments, no strings, \ldots
|
|
% \begin{center}
|
|
% \begin{tabular}{ll}
|
|
% Ada & Lisp \\
|
|
% Algol (|68|,|60|) & Logo \\
|
|
% C (|ANSI|,|Objective|)& Matlab \\
|
|
% Cobol (|1985|,|1974|,|ibm|) & Mercury \\
|
|
% Comal 80 & Modula-2 \\
|
|
% C++ (|ANSI|,|Visual|) & Oberon-2 \\
|
|
% csh & Pascal (|Standard|,|XSC|,|Borland6|) \\
|
|
% Delphi & Perl \\
|
|
% Eiffel & PL/I \\
|
|
% Elan & Prolog \\
|
|
% Euphoria & Simula (|67|,|CII|,|DEC|,|IBM|) \\
|
|
% Fortran (|95|,|90|,|77|) & SQL \\
|
|
% IDL & TeX (|plain|,|primitive|,|LaTeX|,|alLaTeX|) \\
|
|
% HTML & VHDL \\
|
|
% Java
|
|
% \end{tabular}
|
|
% \end{center}
|
|
% The configuration file \texttt{listings.cfg} defines each first dialect as default dialect, i.e.\ |\lstset{language=C}| selects ANSI C.
|
|
% After
|
|
% \begin{verbatim}
|
|
% \lstset{defaultdialect=[Objective]C}\end{verbatim}
|
|
% Objective-C becomes default dialect for C, but the language is \emph{not} selected with that command.
|
|
%
|
|
% \medskip
|
|
% Remark: The driver files define the languages with |\lstdefinelanguage|.
|
|
% The languages have all 'bugs' coming from the language commands, e.g.\ in Ada and Matlab it is still possible that the package assumes a string where none exists.
|
|
% See \texttt{lstdrvrs.dtx} for more remarks on special programming languages.
|
|
%
|
|
%
|
|
% \section{Main reference}
|
|
%
|
|
% \newcommand\UTODO[1]{}
|
|
% \newenvironment{TODO}{\begin{quote}\footnotesize To do:}{\end{quote}}
|
|
% \newenvironment{macrosyntax}
|
|
% {\list{}{\itemindent-\leftmargin\labelsep=0pt\relax %
|
|
% \def\makelabel##1{\lstmklab##1,\relax}}}
|
|
% {\endlist}
|
|
% \def\lstmklab#1,#2\relax{%
|
|
% \ifx\empty#2\empty %
|
|
% \lstmklabb#1,,\relax %
|
|
% \else
|
|
% \lstmklabb#1,#2\relax %
|
|
% \fi}
|
|
% \def\lstmklabb#1,#2,\relax{%
|
|
% \llap{\scriptsize\itshape#2}%
|
|
% \rlap{\hskip-\itemindent\hskip\labelwidth\hskip\linewidth#1}}
|
|
%
|
|
% In this section we list all user environments, commands and keys together with their parameters and possible values.
|
|
% Sometimes there are examples or more detailed information at the end of the subsections.
|
|
% All user macros have the prefix \lst.
|
|
% This avoids naming conflicts with other packages or document classes.
|
|
%
|
|
% In the sequel the label \emph{changed} indicates any change in behaviour or syntax of a command, environment or key, so read these items carefully.
|
|
% Keys strongly related to special programming languages have the label \emph{lang.spec.}.
|
|
% Usually they are available only if you have loaded the corresponding programming language.
|
|
% All other labels should be clear.
|
|
% The numbers in the right margin give the version number of introduction (either as internal or as user macro/key).
|
|
%
|
|
% Note that commands, environments and keys can be distinguished easily:
|
|
% A command begins with a backslash and a key is presented in ''|key=|\meta{value}'' fashion.
|
|
% All the rest are environments, which is in fact a single one.
|
|
%
|
|
%
|
|
% \subsection{Typesetting listings}\label{uTypesettingListings}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.1,changed] |\lstinputlisting[|\meta{key=value list}|]{|\meta{file name}|}|
|
|
%
|
|
% typesets the source code file using the active language and style (locally modified by the key=value list).
|
|
% Empty lines at the end of listing are dropped.
|
|
%
|
|
% The keys |first| and |last| determines the printed line range.
|
|
% Default is \emph{always} 1--9999999, where 'always' means that you can't set |first| and |last| globally.
|
|
% If you don't want a whole file, you must specify the line range.
|
|
% The example |\lstinputlisting[first=3,last=10]{testfile.pas}| would print lines 3,4,\ldots,10 of \texttt{testfile.pas} if file and lines are present.
|
|
%
|
|
% The boolean key |print| controls whether or not |\lstinputlisting| typesets a listing:
|
|
% |print=false| speed up things for draft versions of your document and |print=true| typesets the stand alone files.
|
|
%
|
|
% Note: The keys |first|, |last| and |print| only apply to |\lstinputlisting|.
|
|
%^^A
|
|
%^^A TODO: That's not true.
|
|
%^^A The key |first| also applies to lstlisting.
|
|
%^^A It sets the line number of the first line.
|
|
%^^A
|
|
%
|
|
% \item[0.15,changed] |lstlisting[|\meta{key=value list}|]{|\meta{name}|}|
|
|
%
|
|
% typesets source code between |\begin{lstlisting}{|\meta{name}|}| (+ line break) and |\end{lstlisting}|, but empty lines at the end of listing are dropped.
|
|
% Characters on the same line as the end of environment are \emph{not} dropped, i.e.\ source code right before and \LaTeX\ code after the end of environment is typeset respectively executed.
|
|
% If \meta{name} is not empty and the listing is not continued, the name appears in the list of listings.\\
|
|
% Same named listings have common line counter, i.e.\ the second (same named) listing continues the first, the third continues the second, and so on.
|
|
% There are two exceptions: An empty named listing always starts with line number 1 and is continued with listings named |{ }| (single blank space).
|
|
%
|
|
% The key |resetlineno| (given without any value) sets the line number of the first line to 1.
|
|
% You can also specify a number, e.g.\ |resetlineno=10|.
|
|
% |advancelineno=|\meta{number} advances the number of the first line by \meta{number}.
|
|
% These two keys take also effect on |{}| and |{ }| named listings.
|
|
%
|
|
% Note: The keys |resetlineno| and |advancelineno| only apply to the environment and must be used in the optional key=value list.
|
|
%
|
|
% \item[0.18,new] |\lstinline|
|
|
%
|
|
% works like |\verb|, but uses the active language and style, of course.
|
|
% You can write '|\lstinline!var i:integer;!|' and get '\lstinline!var i:integer;!'.
|
|
% Note that these listings always use flexible columns and that |\lstinline| has no optional key=value list.
|
|
%\UTODO{implement optional key=value list}
|
|
%
|
|
% \item[0.18,new] |\lstbox[|\meta{b$\vert$c$\vert$t}|]|
|
|
%
|
|
% is used right before |\lstinputlisting| or a listing environment.
|
|
% Without |\lstbox| the listing uses a new paragraph and the complete line width, even if the listing is one character wide.
|
|
% |\lstbox| returns the listing as a |\hbox|, which has the necessary width only (line numbers possibly not included).
|
|
% Use this command within explicit |\hbox|es, |$$|\ldots|$$|, etc..
|
|
% The optional argument gives the vertical position of the listing: bottom, center (default) or top.
|
|
% \end{macrosyntax}
|
|
%
|
|
%
|
|
% \subsection{List of listings}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.16] |\listoflistings|
|
|
%
|
|
% prints a list of listings.
|
|
% The names are the file names or names of the listings.
|
|
%
|
|
% \item[0.16] |\listlistingsname|
|
|
%
|
|
% contains the header name, which is 'Listings' by default.
|
|
% You may adjust it via |\renewcommand\listlistingsname{whatever}|.
|
|
%
|
|
% \item[0.19,new] |\lstname|
|
|
%
|
|
% contains the name of the current (last) listing in \emph{printable} form.
|
|
% After |pre=\subsubsection{\lstname}| each listing begins a new subsubsection, which name is the listing name.
|
|
% The key |pre| is described in section \ref{uSomeSpecialKeys}.
|
|
% You can also use it to index all listings, but then you must expand the content first.
|
|
% Simply write |\expandafter\index\expandafter{\lstname}| (as value to |pre| if you want).
|
|
%
|
|
% \item[0.19,new] |\lstintname|
|
|
%
|
|
% contains the name of the current (last) listing possibly in nonprintable form.
|
|
% Use this macro inside |\label| and |\ref| for example.
|
|
% But be aware that a reference counter must be defined --- or the label is the current section, subsection, and so on.
|
|
% You might use it like this:
|
|
% \begin{verbatim}
|
|
% \lstset{pre=\caption{\lstname}\label{lst\lstintname}}
|
|
%
|
|
% \begin{figure}
|
|
% \begin{lstlisting}{Empty}
|
|
% \end{lstlisting}
|
|
% \end{figure}
|
|
%
|
|
% Figure \ref{lstEmpty} shows an empty listing.\end{verbatim}
|
|
% Here \emph{all} listings get a caption and a label (unless |pre| is redefined).
|
|
% \end{macrosyntax}
|
|
%
|
|
%
|
|
% \subsection{Basic style keys}\label{uBasicStyleKeys}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.18,new] |basicstyle=|\meta{basic style and size}
|
|
% \item[0.11] |keywordstyle=|\meta{style for keywords}
|
|
% \item[0.19,new,optional] |ndkeywordstyle=|\meta{style for second keywords}
|
|
% \item[0.19,new,optional] |rdkeywordstyle=|\meta{style for third keywords}
|
|
% \item[0.18,new] |nonkeywordstyle=|\meta{style}
|
|
% \item[0.11] |commentstyle=|\meta{style}
|
|
% \item[0.12] |stringstyle=|\meta{style}
|
|
% \item[0.16] |labelstyle=|\meta{style}
|
|
%
|
|
% Each value of these keys determines the font and size (or more general style) in which special parts of a listing appear.
|
|
% The \emph{last} token of the (non,nd,rd) keyword and label style might be an one-parameter command like |\textbf| or |\underline|.
|
|
%
|
|
% \item[0.16,bug] |labelstep=|\meta{step}
|
|
%
|
|
% No line numbers are printed if \meta{step} is zero.
|
|
% Otherwise all lines with ''line number $\equiv 0$ modulo \meta{step}'' get a label, which appearance is controlled by the label style.
|
|
%
|
|
% Bug: If a comment (or string) goes over several lines, the line numbers (if on) also have comment (string) style.
|
|
% The easiest work-around is possibly the use of |\normalfont| in |\lstlabelstyle|.
|
|
%
|
|
% \item[0.12] |blankstring=|\meta{true$\vert$false}
|
|
%
|
|
% let blank spaces in strings appear as blank spaces respectively as \textvisiblespace.
|
|
% The latter is predefined.
|
|
%
|
|
% \item[0.12] |tabsize=|\meta{number}
|
|
%
|
|
% sets tabulator stops at columns $n+1$, $2n+1$, $3n+1$, etc. if $n=$\meta{number}.
|
|
% Each tabulator in a listing moves the current column to the next tabulator stop.
|
|
% It is initialized with |tabsize=8|.
|
|
%
|
|
% \item[0.19,new] |formfeed=|\meta{token sequence}
|
|
%
|
|
% Whenever a listing contains a form feed \meta{token sequence} is executed.
|
|
% It is initialized with |formfeed=\bigbreak|.
|
|
% \end{macrosyntax}
|
|
%
|
|
%
|
|
% \subsection{Fixed and flexible columns}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.18,new] |flexiblecolumns=|\meta{true$\vert$false}
|
|
%
|
|
% selects the flexible respectively the fixed column format.
|
|
%
|
|
% \item[0.16,addon] |baseem=|\meta{width in units of em}\quad or\quad|baseem={|\meta{fixed}|,|\meta{flexible mode}|}|
|
|
%
|
|
% sets the width of a single character box for fixed and flexible mode (both to the same value or individually).
|
|
% It's pre-defined via |baseem={|{\makeatletter\lst@baseemfixed}|,|{\makeatletter\lst@baseemflexible}|}|.
|
|
% \end{macrosyntax}
|
|
%
|
|
%
|
|
% \subsection{Listing alignment}\label{uListingAlignment}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.19,new] |indent=|\meta{dimension}
|
|
%
|
|
% indents each listing by \meta{dimension}, which is initialized with 0pt.
|
|
% This command is the best way to move line numbers (and the listing) to the right.
|
|
%
|
|
% \item[0.19,new] |wholeline=|\meta{true$\vert$false}
|
|
%
|
|
% prevents or lets the package use indention from list environments like \texttt{enumerate} or \texttt{itemize}.
|
|
%
|
|
% \item[0.16,bug,addon] |spread=|\meta{dimension}\quad or\quad|spread={|\meta{inner}|,|\meta{outer}|}|
|
|
%
|
|
% defines \emph{additional} line width for listings, which may avoid overfull |\hbox|es if a listing has long lines.
|
|
% The inner and outer spread is given explicitly or is equally shared.
|
|
% It is initialized via |spread=0pt|.
|
|
% For one sided documents 'inner' and 'outer' have the effect of 'left' and 'right'.
|
|
% Note that |\lstbox| doesn't use this spread but |indent| (which is always 'left').
|
|
%
|
|
% Bug (two sided documents):
|
|
% At top of page it's possible that the package uses inner instead of outer spread or vice versa.
|
|
% This happens when \TeX\ finally moves one or two source code lines to the next page, but hasn't decided it when the \textsf{listings} package processes them.
|
|
% Work-around: interrupt the listing and/or use an explicit |\newpage|.
|
|
%
|
|
% \item[0.17] |lineskip=|\meta{additional space between lines}
|
|
%
|
|
% specifies the additional space between lines in listings.
|
|
% You may write |lineskip=-1pt plus 1pt minus 0.5pt| for example, but 0pt is the default.
|
|
%
|
|
% \item[0.19,new] |outputpos=|\meta{c$\vert$l$\vert$r}
|
|
%
|
|
% controls horizontal orientation of smallest output units (keywords, identifiers, etc.).
|
|
% The arguments work as follows, where vertical bars visualize the effect:
|
|
% $\vert$\hbox to 4.2em{\hss l\hss i\hss s\hss t\hss i\hss n\hss g\hss }$\vert$,
|
|
% $\vert$\hbox to 4.2em{l\hss i\hss s\hss t\hss i\hss n\hss g\hss }$\vert$ and
|
|
% $\vert$\hbox to 4.2em{\hss l\hss i\hss s\hss t\hss i\hss n\hss g}$\vert$
|
|
% in fixed column mode resp.\
|
|
% $\vert$\hbox to 3.15em{\hss listing\hss}$\vert$,
|
|
% $\vert$\hbox to 3.15em{listing\hss}$\vert$ and
|
|
% $\vert$\hbox to 3.15em{\hss listing}$\vert$
|
|
% with flexible columns (using pre-defined |baseem|).
|
|
% By default the output is centered.
|
|
% To make all things clear: You may write |outputpos=c|, |outputpos=l| or |outputpos=r|.
|
|
% \end{macrosyntax}
|
|
%
|
|
%
|
|
% \subsection{Escaping to \LaTeX}
|
|
%
|
|
% \textbf{Note:} {\itshape Any escape to \LaTeX\ may disturb the column alignment since the package can't control the spacing there.}
|
|
% \begin{macrosyntax}
|
|
% \item[0.18,new] |texcl=|\meta{true$\vert$false}
|
|
%
|
|
% activates or deactivates \LaTeX\ comment lines, see the example below.
|
|
%
|
|
% \item[0.19,new] |mathescape=|\meta{true$\vert$false}
|
|
%
|
|
% activates or deactivates special behaviour of the dollar sign.
|
|
% If activated, a dollar sign acts as \TeX's text math shift (not display style!).
|
|
%
|
|
% \item[0.19,new] |escapechar=|\meta{single character} (or empty)
|
|
%
|
|
% The given character escapes the user to \LaTeX:
|
|
% All code between two such characters is interpreted as \LaTeX\ code.
|
|
% Note that \TeX's special characters must be entered with a preceding backslash, e.g.\ |escapechar=\%|.
|
|
% \end{macrosyntax}
|
|
% Some examples clarify these commands.
|
|
% Since |texcl| only makes sense with comment lines, we will use C++ comment lines here (without saying how to define them).
|
|
% Note that only the first example runs through a C++ compiler if the source code is placed in a separate file.
|
|
% All \LaTeX\ escapes are local here, but you can also use |\lstset|.
|
|
% \lstset{commentline=//}
|
|
% \begin{lstsample}{}
|
|
%\begin{lstlisting}[texcl]{}
|
|
%// calculate $a_{ij}$
|
|
% A[i][j] = A[j][j]/A[i][j];
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
%
|
|
% \begin{lstsample}{}
|
|
%\begin{lstlisting}[mathescape]{}
|
|
%// calculate $a_{ij}$
|
|
% $a_{ij} = a_{jj}/a_{ij}$;
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
%
|
|
% \begin{lstsample}{}
|
|
%\lstset{escapechar=\%}
|
|
%\begin{lstlisting}{}
|
|
%// calc%ulate $a_{ij}$%
|
|
% %$a_{ij} = a_{jj}/a_{ij}$%;
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
% \lstset{commentline={}}
|
|
% \noindent
|
|
% In the first example the whole comment line is typset in '\LaTeX\ mode' --- except the comment line indicators |//|.
|
|
% Note that |texcl| uses comment style.
|
|
% In the second example the comment line upto $a_{ij}$ have been typeset in comment style and by the \textsf{listings} package.
|
|
% The '$a_{ij}$' itself is typeset in '\TeX\ math mode' without comment style.
|
|
% About the half comment line of the third example have been typeset by this package.
|
|
% The rest is in '\LaTeX\ mode' without comment style.
|
|
%
|
|
% To avoid problems with the current and future version of this package:
|
|
% \begin{enumerate}
|
|
% \item Don't use any command of the \textsf{listings} package when you have escaped to \LaTeX.
|
|
% \item Any environment must start and end inside the same escape.
|
|
% \item You might use |\def|, |\edef|, etc., but do not assume that the definitions are present later --- except they are |\global|.
|
|
% \item |\if \else \fi|, groups, math shifts |$| and |$$|, \ldots\ must be balanced each escape.
|
|
% \item \ldots
|
|
% \end{enumerate}
|
|
% Expand that list yourself and mail me about new items.
|
|
%
|
|
%
|
|
% \subsection{Some special keys}\label{uSomeSpecialKeys}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.18,new] |extendedchars=|\meta{true$\vert$false}
|
|
%
|
|
% allows or prohibits extended characters in listings, i.e.\ characters with codes 128--255.
|
|
% If you use extended characters, you should load the \texttt{inputenc} or \texttt{fontenc} package!
|
|
%
|
|
% \item[0.19,new,lang.spec.]|printpod=|\meta{true$\vert$false}
|
|
%
|
|
% prints or drops PODs in Perl.
|
|
%
|
|
% \item[0.12,addon] |pre=[|\meta{continue}|]{|\meta{commands to execute}|}|
|
|
% \item[0.12,addon] |post=[|\meta{continue}|]{|\meta{commands to execute}|}|
|
|
%
|
|
% The given control sequences are executed before and after typesetting resp.\ when continuing a listing, but in all cases inside a group.
|
|
% The commands are not executed if you use |\lstbox| or |\lstinline| (since the user given pre and post commands are assumed to be unsave inside |\hbox|).
|
|
% By default \meta{continue} is empty.
|
|
% The other arguments are pre-set empty.
|
|
% \end{macrosyntax}
|
|
%
|
|
% \begin{lstsample}{}
|
|
%\lstset{flexiblecolumns}
|
|
%\lstset{pre=[%
|
|
% We continue the listing.
|
|
% ]A simple prelisting example.}
|
|
%\begin{lstlisting}{}
|
|
%{ Get listings.dtx. Now! }
|
|
%\end{lstlisting}
|
|
%
|
|
%\begin{lstlisting}{ }
|
|
%{ You have it already? Good. }
|
|
%\end{lstlisting}
|
|
%
|
|
%\begin{lstlisting}{ }
|
|
%{ Tell your friends about it. }
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
%\lstset{style={}}
|
|
%
|
|
%
|
|
% \subsection{Languages and styles}\label{uLanguagesAndStyles}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.17,changed] |language=[|\meta{dialect}|]|\meta{language name}
|
|
%
|
|
% activates a (dialect of a) programming language.
|
|
% All arguments are case \emph{insensitive} here.
|
|
%
|
|
% \item[0.19,new] |\lstloadlanguages{|\meta{list of languages}|}|
|
|
%
|
|
% can only be used in the preamble.
|
|
% It loads all specified languages, where each language is given in the form |[|\meta{dialect}|]|\meta{language}.
|
|
% List of languages means a comma separated list.
|
|
%
|
|
% \item[0.18,new] |style=|\meta{style name}
|
|
%
|
|
% activates a style.
|
|
% The arguments is case \emph{insensitive}.
|
|
%
|
|
% \item[0.19,new] |\lstdefinestyle{|\meta{style name}|}{|\meta{key=value list}|}|
|
|
%
|
|
% stores the key=value list: You can select the style via |style| using te style name as argument.
|
|
% \end{macrosyntax}
|
|
% After package loading a 'standard' style and an 'empty' language are active.
|
|
% The style is defined as follows.
|
|
% \begin{verbatim}
|
|
% \lstdefinestyle{}
|
|
% {basicstyle={},
|
|
% keywordstyle=\bfseries,nonkeywordstyle={},
|
|
% commentstyle=\itshape,
|
|
% stringstyle={},
|
|
% labelstyle={},labelstep=0
|
|
% }\end{verbatim}
|
|
%
|
|
%
|
|
% \subsection{Language definitions}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.19,new] |\lstdefinelanguage[|\meta{dialect}|]{|\meta{language}|}{|\meta{key=value list}|}|
|
|
%
|
|
% defines a programming language.
|
|
% Use any 'language' key=value list and the definition is yours.
|
|
%
|
|
% \item[0.19,new] |\lstdefinedrvlanguage[|\meta{dialect}|]{|\meta{language}|}{|\meta{key=value list}|}|
|
|
%
|
|
% defines a programming language only if the user has requested the language.
|
|
% Thus this command can only be used in driver files.
|
|
%
|
|
% \item[0.19,new] |defaultdialect=[|\meta{dialect}|]|\meta{language}
|
|
%
|
|
% defines a default dialect for a language, that means a dialect which is selected whenever you leave out the optional dialect.
|
|
% If you have defined a default dialect other than empty, for example |defaultdialect=[iama]fool|, you can't select the 'empty' dialect, even not with |language=[]fool|.
|
|
%
|
|
% Note that a configuration file possibly defines some default dialects.
|
|
%
|
|
% \item[0.18,new] |\lstalias{|\meta{alias}|}{|\meta{language}|}|
|
|
%
|
|
% defines an alias for a programming language.
|
|
% Any dialect of \meta{alias} selects in fact the same dialect of \meta{language}.
|
|
% It's also possible to define an alias for one dialect: |\lstalias[|\meta{dialect alias}|]{|\meta{alias}|}[|\meta{dialect}|]{|\meta{language}|}|.
|
|
% Here all four parameters are \emph{non}optional.
|
|
% An alias with empty \meta{dialect} will select the default dialect.
|
|
% Note that aliases can't be nested: The two aliases |\lstalias{foo1}{foo2}| and |\lstalias{foo2}{foo3}| redirect |foo1| not to |foo3|.
|
|
%
|
|
% Note that a configuration file possibly defines some aliases.
|
|
%
|
|
% \item[0.18,new] |\lststorekeywords|\meta{macro}|{|\meta{keywords}|}|
|
|
%
|
|
% stores \meta{keywords} in \meta{macro} for use with keyword keys.
|
|
% This command can't be used in a language definition since it is a command and not a key.
|
|
% \end{macrosyntax}
|
|
%
|
|
% Now come all the language keys, which might be used in the key=value list of |\lstdefinelanguage|.
|
|
% Note: {\itshape If you want to enter {\upshape|\|, |{|, |}|, |%|, |#|} or {\upshape|&|} inside or as an argument here, you must do it with a preceding backslash!}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item[0.11] |keywords={|\meta{keywords}|}|
|
|
% \item[0.11] |morekeywords={|\meta{additional keywords}|}|
|
|
% \item[0.18,new] |deletekeywords={|\meta{keywords to remove}|}|
|
|
%
|
|
% \item[0.19,new,optional] |ndkeywords={|\meta{second keywords}|}|
|
|
% \item[0.19,new,optional] |morendkeywords={|\meta{additional second keywords}|}|
|
|
% \item[0.19,new,optional] |deletendkeywords={|\meta{second keywords to remove}|}|
|
|
%
|
|
% \item[0.19,new,optional] |rdkeywords={|\meta{third keywords}|}|
|
|
% \item[0.19,new,optional] |morerdkeywords={|\meta{additional third keywords}|}|
|
|
% \item[0.19,new,optional] |deleterdkeywords={|\meta{third keywords to remove}|}|
|
|
%
|
|
% Each 'keyword' argument (here and below) is a list of keywords separated by commas.
|
|
% You might use macros defined with |\lststorekeywords| as elements (i.e.\ also separated by commas).
|
|
% |keywords={save,Test,test}| defines three keywords (if keywords are case sensitive).
|
|
% If you want to remove them all, simply write |keywords={}| --- in |\lstset|'s argument, in an optional argument or in a language definition.
|
|
% The characters |\|, |{|, and |}| (entered as |\\|, |\{| and |\}|) are \emph{not} allowed within a keyword.
|
|
% You might use each of
|
|
%^^A
|
|
%^^A We need some definitions here.
|
|
%^^A
|
|
%\makeatletter ^^A
|
|
%\def\lstspec#1{^^A
|
|
% \ifx\relax#1\else ^^A
|
|
% {\lstset{keywords=#1}\setbox\@tempboxa\hbox{\lstinline a#1a}}^^A
|
|
% \lst@ifspec\lstinline a#1a\fi ^^A
|
|
% \expandafter\lstspec ^^A
|
|
% \fi}^^A
|
|
%\lst@AddToHook{Output}{\lstspectest}^^A
|
|
%\gdef\lstspecfalse{\global\let\lst@ifspec\iffalse}^^A
|
|
%\gdef\lstspectest{^^A
|
|
% \global\let\lst@ifspec=\iftrue ^^A
|
|
% \ifx\lst@thestyle\lst@keywordstyle\else ^^A
|
|
% \lstspecfalse ^^A
|
|
% \fi}^^A
|
|
%\makeatother ^^A
|
|
% {\lstset{language={}}^^A
|
|
% \lstspec !"\#$\%\&'()*+-./:;<=>?[]^`\relax.}
|
|
%^^A
|
|
%^^A a comma also works!
|
|
%^^A
|
|
%^^A End of test.
|
|
%^^A
|
|
% But note that you must enter |\#|, |\%| and |\&| instead of |#|, |%| and |&|.
|
|
%
|
|
% \item[0.14] |sensitive=|\meta{true$\vert$false}
|
|
%
|
|
% makes the keywords (first, second and third) case sensitive resp.\ insensitive.
|
|
%^^A It would be nice to have |\lst|\meta{\texttt{nd}$\vert$\texttt{rd}}|sensitive|\meta{\texttt{true}\textbar\texttt{false}}?
|
|
% This key affect the keywords only in the phase of typesetting.
|
|
% In all other situations keywords are case sensitive, i.e.\ |deletekeywords={save,Test}| removes 'save' and 'Test', but neither 'SavE' nor 'test'.
|
|
%
|
|
% \item[0.19,new] |alsoletters={|\meta{character sequence}|}|
|
|
% \item[0.19,new] |alsodigits={|\meta{character sequence}|}|
|
|
% \item[0.19,new] |alsoother={|\meta{character sequence}|}|
|
|
%
|
|
% These keys support the 'special character' auto-detection of the keyword commands.
|
|
% For our purpose here, identifiers are out of letters (|A|--|Z|,|a|--|z|,|_|,|@|,|$|) and digits (|0|--|9|), but an identifier must begin with a letter.
|
|
% If you write |keywords={one-two,\#include}|, the minus becomes necessarily a digit and the sharp a letter since the keywords can't be detected otherwise.
|
|
% The three keys overwrite such default behaviour.
|
|
% Each character of the sequence becomes a letter, digit and other, respectively.
|
|
% Note that the auto-detection might fail if you remove keywords and always fails if you use special characters not listed above.
|
|
%^^A
|
|
%^^A TODO: This is mainly due to improper \lst@ReplaceIn inside ..MakeKeywordArg..
|
|
%^^A
|
|
%
|
|
% \item[0.19,new] |stringtest=|\meta{true$\vert$false}
|
|
%
|
|
% enables or disables string tests:
|
|
% If activated, line exceeding strings issue warnings and the package exits string mode.
|
|
%
|
|
% \item[0.12,addon] |stringizer=[|\meta{b$\vert$d$\vert$m$\vert$bd}|]{|\meta{character sequence}|}|
|
|
%
|
|
% Each character might start a string or character literal.
|
|
% 'Stringizers' match each other, i.e.\ starting and ending delimiters are the same.
|
|
% The optional argument controls how the stringzier(s) itself is/are represented in a string or character literal:
|
|
% It is preceded by a |b|ackslash, |d|oubled (or both is allowed via |bd|) or it is |m|atlabed.
|
|
% The latter one is a special type for Ada and Matlab and possibly more languages, where the stringizers are also used for other purposes.
|
|
% In general the stringizer is also doubled, but a string does not start after a letter or a right parenthesis.
|
|
%
|
|
% \item[0.19,new,lang.spec.] |texcs={|\meta{list of control sequences \textup(without backslashes\textup)}|}|
|
|
%
|
|
% defines control sequences for \TeX\ and \LaTeX.
|
|
%
|
|
% \item[0.18,new,lang.spec.] |cdirectives={|\meta{list of compiler directives}|}|
|
|
%
|
|
% defines compiler directives in C, C++ and Objective-C.
|
|
% \end{macrosyntax}
|
|
% If you have already defined any of the following comments and you want to remove it, let all arguments to the comment key empty.
|
|
% \begin{macrosyntax}
|
|
% \item[0.13,changed] |commentline=|\meta{1or2 chars}
|
|
%
|
|
% The characters (\emph{in the given order}) start a comment line, which in general starts with the comment separator and ends at end of line.
|
|
% If the character sequence |//| starts a comment line (like in C++, Comal 80 or Java), |commentline=//| is the correct declaration.
|
|
% For Matlab it would be |commentline=\%| --- note the preceding backslash.
|
|
%
|
|
% \item[0.18,new] |fixedcommentline=[|\meta{n=preceding columns}|]{|\meta{character sequence}|}|
|
|
%
|
|
% Each given character becomes a 'fixed comment line' separator: It starts a comment line if and only if it is in column $n+1$.
|
|
% Fortran 77 declares its comments via |fixedcommentline={*Cc}| ($n=0$ is default).
|
|
%
|
|
% \item[0.13,changed] |singlecomment={|\meta{1or2 chars}|}{|\meta{1or2 chars}|}|
|
|
% \item[0.13,changed] |doublecomment={|\meta{1or2 chars}|}{|\meta{1or2 chars}|}{|\meta{1or2 chars}|}{|\meta{1or2 chars}|}|
|
|
%
|
|
% Here we have two or four comment separators.
|
|
% The first starts and the second ends a comment, and similarly the third and fourth separator for double comments.
|
|
% If you need three such comments use |singlecomment| and |doublecomment| at the same time.
|
|
% C, Java, PL/I, Prolog and SQL all define single comments via |singlecomment={/*}{*/}|, and Algol does it with |singlecomment={\#}{\#}|, which means that the sharp delimits both beginning and end of a single comment.
|
|
%
|
|
% \item[0.13,changed] |nestedcomment={|\meta{1or2 chars}|}{|\meta{1or2 chars}|}|
|
|
%
|
|
% is similar to |singlecomment|, but comments can be nested.
|
|
% Identical arguments are not allowed --- think a while about it!
|
|
% Modula-2 and Oberon-2 use |nestedcomment={(*}{*)}|.
|
|
%
|
|
% \item[0.17,lang.spec.] |keywordcomment={|\meta{keywords}|}|
|
|
% \item[0.17,lang.spec.] |doublekeywordcommentsemicolon={|\meta{keywords}|}{|\meta{keywords}|}{|\meta{keywords}|}|
|
|
%
|
|
% A (paired) keyword comment begins with a keyword and ends with the same keyword.
|
|
% Consider |keywordcomment={comment,co}|.
|
|
% Then '\textbf{comment}\allowbreak\ldots\textbf{comment}' and '\textbf{co}\ldots\textbf{co}' are comments.\\
|
|
%^^A
|
|
% Defining a double keyword comment (semicolon) needs three keyword lists, e.g.\ |{end}{else,end}{comment}|.
|
|
% A semicolon always ends such a comment.
|
|
% Any keyword of the first argument begins a comment and any keyword of the second argument ends it (and a semicolon also); a comment starting with any keyword of the third argument is terminated with the next semicolon only.
|
|
% In the example all possible comments are '\textbf{end}\ldots\textbf{else}', '\textbf{end}\ldots\textbf{end}' (does not start a comment again) and '\textbf{comment}\ldots;' and '\textbf{end}\ldots;'.
|
|
% Maybe a curious definition, but Algol and Simula use such comments.\\
|
|
%^^A
|
|
% Note: The keywords here need not to be a subset of the defined keywords.
|
|
% They won't appear in keyword style if they aren't.
|
|
% \end{macrosyntax}
|
|
%
|
|
%
|
|
% \section{Experimental features}
|
|
%
|
|
% This section describes the more or less unestablished parts of the \textsf{listings} package.
|
|
% It's unlikely that they are removed, but they are liable to (heavy) changes and maybe improvements.
|
|
%
|
|
%
|
|
% \subsection{Interface to \textsf{fancyvrb}}
|
|
%
|
|
% The \textsf{fancyvrb} package --- fancy verbatims --- from Timothy van Zandt provides macros for reading, writing and typesetting verbatim code.
|
|
% It has some remarkable features the \textsf{listings} package doesn't have --- some are also possible with \textsf{listings}, but you must find somebody who implements them ; -- ).
|
|
% The \textsf{fancyvrb} package is available from \texttt{CTAN: macros/latex/contrib/supported/fancyvrb}.
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item [0.19,new]|fancyvrb=|\meta{true$\vert$false}
|
|
%
|
|
% activates or deactivates the interface.
|
|
% This defines an appropiate version of |\FancyVerbFormatLine| to make the two packages work together.
|
|
% If active, the verbatim code read by the \textsf{fancyvrb} package is typeset by the \textsf{listings} package, i.e.\ with emphasized keywords, strings, comments, and so on.
|
|
% --- You should know that |\FancyVerbFormatLine| is responsible for the typesetting a single code line.
|
|
%
|
|
% If \textsf{fancyvrb} and \textsf{listings} provide similar functionality, use \textsf{fancyvrb}'s.
|
|
%
|
|
% Note that this is the first interface.
|
|
% It works only with |Verbatim|, neither with |BVerbatim| nor |LVerbatim|.
|
|
% And you shouldn't use \textsf{defineactive}. (As I can see it doesn't matter since it does nothing at all.)
|
|
% I hope to remove some restrictions in future.
|
|
% \end{macrosyntax}
|
|
%
|
|
% \iffancyvrb
|
|
% \begin{lstsample}{}
|
|
%\lstset{commentline=\ }% :-)
|
|
%
|
|
%\begin{Verbatim}[commandchars=\\\{\}]
|
|
%First verbatim line.
|
|
%\fbox{Second} verbatim line.
|
|
%\end{Verbatim}
|
|
%
|
|
%\lstset{fancyvrb}
|
|
%\begin{Verbatim}[commandchars=\\\{\}]
|
|
%First verbatim line.
|
|
%\fbox{Second} verbatim line.
|
|
%\end{Verbatim}
|
|
%\lstset{fancyvrb=false}
|
|
% \end{lstsample}
|
|
% \noindent
|
|
% The last two lines are wider than the first two since |baseem| equals not the width of a single typewriter character.
|
|
% \else
|
|
% \begin{center}
|
|
% \textsf{fancyvrb} seems to be unavailable on your platform, thus the example couldn't be printed here.
|
|
% \end{center}
|
|
% \fi
|
|
%
|
|
%
|
|
% \subsection{Listings inside arguments}\label{uListingsInsideArguments}
|
|
%
|
|
% There are some things to consider if you want to use |\lstinline| or the listing environment inside arguments.
|
|
% Since \TeX\ reads the argument before the '\lst-macro' is executed, this package can't do anything to preserve the input:
|
|
% Spaces shrink to one space, the tabulator and the end of line are converted to spaces, the comment character is not printable, and so on.
|
|
% Hence, you must work a little bit more.
|
|
% You have to put a backslash in front of each of the following four characters: |\{}%|.
|
|
% Moreover you must protect spaces in the same manner if: (i) there are two or more spaces following each other or (ii) the space is the first character in the line.
|
|
% That's not enough: Each line must be terminated with a 'line feed' |^^J|.
|
|
% Finally you can't escape to \LaTeX\ inside such listings.
|
|
%
|
|
% The easiest examples are with |\lstinline| since we need no line feed.
|
|
% \begin{verbatim}
|
|
%\footnote{\lstinline!var i:integer;! and
|
|
% \lstinline!protected\ \ spaces! and
|
|
% \fbox{\lstinline!\\\{\}\%!}}\end{verbatim}
|
|
% yields\lstset{language=Pascal}\footnote{\lstinline!var i:integer;! and \lstinline!protected\ \ spaces! and \fbox{\lstinline!\\\{\}\%!}} if the current language is Pascal.
|
|
% The environment possibly needs a preceding |\lstbox|, as the following examples show.
|
|
%
|
|
%{\let\smallbreak\relax\lstset{language={}}
|
|
% \begin{lstsample}{}
|
|
%\fbox{\lstbox
|
|
%\begin{lstlisting}{}^^J
|
|
%\ !"#$\%&'()*+,-./^^J
|
|
%0123456789:;<=>?^^J
|
|
%@ABCDEFGHIJKLMNO^^J
|
|
%PQRSTUVWXYZ[\\]^_^^J
|
|
%`abcdefghijklmno^^J
|
|
%pqrstuvwxyz\{|\}~^^J
|
|
%\end{lstlisting}}
|
|
% \end{lstsample}
|
|
%
|
|
% \lstset{language={}}
|
|
% \begin{lstsample}{}
|
|
%\fbox{\lstbox
|
|
%\begin{lstlisting}{}^^J
|
|
%We need no protection here,^^J
|
|
%\ but\ \ in\ \ this\ \ line.^^J
|
|
%\end{lstlisting}}
|
|
% \end{lstsample}
|
|
%}
|
|
%
|
|
%
|
|
% \subsection{Frames}
|
|
%
|
|
% \begin{macrosyntax}
|
|
% \item [0.19,new] |frame=|\meta{any subset of \textup{\texttt{tlrbTLRB}}}
|
|
%
|
|
% The characters |tlrbTLRB| are attached to lines at the |t|op of a listing, on the |l|eft, |r|ight and at the |b|ottom.
|
|
% There are two lines if you use upper case letters.
|
|
% If you want a single frame around a listing, write |frame=tlrb| or |frame=bltr| for example (but as optional argument or argument to |\lstset|, of course).
|
|
% If you want double lines at the top and on the left and no other lines, write |frame=TL|.
|
|
% Note that frames reside outside the listing's space.
|
|
% Use |spread| if you want to shrink frames (to |\linewidth| for example) and use |indent| if you want to move line number inside frames.
|
|
%
|
|
% \item [0.19,new] |framerulewidth=|\meta{dimension}
|
|
% \item [0.19,new] |framerulesep=|\meta{dimension}
|
|
%
|
|
% These keys control the width of the rules and the space between double rules.
|
|
% The predefined values are {\makeatletter\lst@framewidth} width and {\makeatletter\lst@framesep} separation.
|
|
%
|
|
%\iffalse
|
|
% \item [0.19,new] |frametextsep=|\meta{dimension}
|
|
%
|
|
% controls the space between frame and listing, but currently only between the listing and vertical frame lines.
|
|
% The predefined value is {\makeatletter\lst@frametextsep}.
|
|
%\fi
|
|
% \end{macrosyntax}
|
|
% |frame| does not work with |\lstbox| or |fancyvrb=true|!
|
|
% And there are certainly more problems with other commands.
|
|
% Take the time to report in.
|
|
%
|
|
% \begin{lstsample}{}
|
|
%\begin{lstlisting}[frame=tLBr]{}
|
|
%for i:=maxint to 0 do
|
|
%begin
|
|
% { do nothing }
|
|
%end;
|
|
%\end{lstlisting}
|
|
% \end{lstsample}
|
|
%
|
|
%
|
|
% \subsection{Export of identifiers}
|
|
%
|
|
%^^A \lsthelper{Aslak Raanes}{araanes@ifi.ntnu.no}{1997/11/24}{export function names}
|
|
% It would be nice to export function or procedure names, for example to index them automatically or to use them in |\listoflistings| instead of a listing name.
|
|
% In general that's a dream so far.
|
|
% The problem is that programming languages use various syntaxes for function and procedure declaration or definition.
|
|
% A general interface is completely out of the scope of this package --- that's the work of a compiler and not of a pretty printing tool.
|
|
% However, it is possible for particular languages: in Pascal each function or procedure definition and variable declaration is preceded by a particular keyword.
|
|
% \begin{macrosyntax}
|
|
% \item [0.19,new,optional] |index={|\meta{identifiers}|}|
|
|
%
|
|
% \meta{identifiers} is a comma-separated list of identifiers.
|
|
% Each appearance of such an identifier is indexed.
|
|
%
|
|
% \item [0.19,new,optional] |indexmacro=|\meta{'one parameter' macro}
|
|
%
|
|
% The specified macro gets exactly one parameter, namely the identifier, and must do the indexing.
|
|
% It is predefined as |indexmacro=\lstindexmacro|, which definition is
|
|
% \begin{verbatim}
|
|
% \newcommand\lstindexmacro[1]{\index{{\ttfamily#1}}}\end{verbatim}
|
|
% \item[0.19,new,optional] |prockeywords={|\meta{keywords}|}|
|
|
%
|
|
% \meta{keywords} is a comma-separated list of keywords, which indicate a function or procedure definition.
|
|
% Any identifier following such a keyword appears in 'procname' style.
|
|
% For Pascal you might use
|
|
% \begin{verbatim}
|
|
% prockeywords={program,procedure,function}\end{verbatim}
|
|
%
|
|
% \item[0.19,new,optional] |procnamestyle=|\meta{style for procedure names}
|
|
%
|
|
% defines the style in which procedure and function names appear.
|
|
%
|
|
% \item[0.19,new,optional] |indexprocnames=|\meta{true$\vert$false}
|
|
%
|
|
% If activated, procedure and function names are also indexed (if used with |index| option).
|
|
% \end{macrosyntax}
|
|
%
|
|
%
|
|
% \section{Troubleshooting}
|
|
%
|
|
% The known bugs have already been described.
|
|
% This section deals with problems concerning not only the \textsf{listings} package.
|
|
%
|
|
%
|
|
% \subsection{Problems with \texttt{.fd} files}
|
|
%
|
|
% You probably get the following error message with a different font definition file:
|
|
% \begin{verbatim}
|
|
%! LaTeX Error: Command textparagraph unavailable in encoding T1.
|
|
%
|
|
%See the LaTeX manual or LaTeX Companion for explanation.
|
|
%Type H <return> for immediate help.
|
|
% ...
|
|
%
|
|
%l.68 \P
|
|
% rovidesFile{omscmr.fd}
|
|
%?\end{verbatim}
|
|
% So, what happened?
|
|
% (a) The \textsf{listings} package redefines the character table to print listings.
|
|
% (b) \LaTeX\ loads the font definition files on demand.
|
|
% (a) plus (b) gives the error: \LaTeX\ loads the \texttt{.fd} files with modified character table.
|
|
% And that goes wrong.
|
|
% The work-around is quite easy: Input the \texttt{.fd} file before typesetting the listing.
|
|
%
|
|
%
|
|
% \subsection{Language definitions}
|
|
%
|
|
% Language definitions and also some style definitions tend to have long definition parts.
|
|
% This is why we tend to forget commas between the key=value elements.
|
|
% If you select a language and get a |Missing = inserted for \ifnum| error, this is surely due to a missing comma after |keywords=|value.
|
|
% If you encounter unexspected characters after selecting a language (or style), you have either forgotten a comma or you have given to many arguments to a key, for example |commentline={--}{!}|.
|
|
%
|
|
%
|
|
% \section{Forthcoming}
|
|
%
|
|
% \begin{itemize}
|
|
% \item I'd like to support more languages, for example Maple, Mathematica, PostScript, Reduce and so on.
|
|
% Fortunately my lifetime is limited, so other people may do that work.
|
|
% Write a language definition and (e-)mail it to me (with a proposal in which file to place the definition).
|
|
%
|
|
% \item There will possibly a boolean |blanklisting=|\meta{true$\vert$false} or a $*$-version of the environment.
|
|
%
|
|
% \item 'procnames' is already interesting, but marks (and indexes) only the function definitions so far.
|
|
% It would be quite easy to mark also the following function calls:
|
|
% Write another 'keyword class' which is empty at the very beginning (and can be reset with a key); each function definition appends a 'keyword' which will appear in 'procnamestyle'.
|
|
% But this would be another 'keyword test' within an inner loop.
|
|
% \item I plan to put all language definitions in a single file.
|
|
% \end{itemize}
|
|
%
|
|
%
|
|
% \StopEventually{}
|
|
%
|
|
%
|
|
% \part{Implementation}
|
|
%
|
|
% \CheckSum{5520}
|
|
% \DoNotIndex{\[,\{,\},\],\1,\2,\3,\4,\5,\6,\7,\8,\9,\0}
|
|
% \DoNotIndex{\`,\,,\!,\#,\$,\&,\',\(,\),\+,\.,\:,\;,\<,\=,\>,\?,\_}
|
|
% \DoNotIndex{\@@end,\@@par,\@currenvir,\@depth,\@dottedtocline,\@ehc}
|
|
% \DoNotIndex{\@empty,\@firstoftwo,\@gobble,\@gobbletwo,\@gobblefour,\@height}
|
|
% \DoNotIndex{\@ifnextchar,\@ifundefined,\@namedef,\@ne,\@secondoftwo}
|
|
% \DoNotIndex{\@spaces,\@starttoc,\@undefined,\@whilenum,\@width}
|
|
% \DoNotIndex{\A,\active,\addtocontents,\advance,\aftergroup,\batchmode}
|
|
% \DoNotIndex{\begin,\begingroup,\bfseries,\bgroup,\box,\bigbreak,\bullet}
|
|
% \DoNotIndex{\c@page,\catcode,\contentsname,\csname,\def,\divide,\do,\dp}
|
|
% \DoNotIndex{\edef,\egroup,\else,\end,\endcsname,\endgroup,\endinput}
|
|
% \DoNotIndex{\endlinechar,\escapechar,\everypar,\expandafter,\f@family}
|
|
% \DoNotIndex{\fi,\footnotesize,\gdef,\global,\hbox,\hss,\ht}
|
|
% \DoNotIndex{\if,\ifdim,\iffalse,\ifnum,\ifodd,\iftrue,\ifx}
|
|
% \DoNotIndex{\ignorespaces,\index,\input,\itshape,\kern}
|
|
% \DoNotIndex{\lccode,\l@ngrel@x,\leftskip,\let,\linewidth,\llap}
|
|
% \DoNotIndex{\long,\lowercase,\m@ne,\makeatletter,\mathchardef}
|
|
% \DoNotIndex{\message,\multiply,\NeedsTeXFormat,\newbox,\new@command}
|
|
% \DoNotIndex{\newcommand,\newcount,\newdimen,\newtoks,\noexpand}
|
|
% \DoNotIndex{\noindent,\normalbaselines,\normalbaselineskip}
|
|
% \DoNotIndex{\offinterlineskip,\par,\parfillskip,\parshape}
|
|
% \DoNotIndex{\parskip,\ProcessOptions,\protect,\ProvidesPackage}
|
|
% \DoNotIndex{\read,\relax,\removelastskip,\rightskip,\rlap,\setbox}
|
|
% \DoNotIndex{\smallbreak,\smash,\space,\string,\strut,\strutbox}
|
|
% \DoNotIndex{\the,\thepage,\ttdefault,\ttfamily,\tw@,\typeout,\uppercase}
|
|
% \DoNotIndex{\vbox,\vcenter,\vrule,\vtop,\wd,\xdef,\z@,\zap@space}
|
|
% \DoNotIndex{\char,\closeout,\immediate,\newwrite,\openout,\write}
|
|
% \DoNotIndex{\vskip}
|
|
%
|
|
% \DoNotIndex{\define@key,\setkeys}
|
|
%
|
|
% \DoNotIndex{\textasciicircum,\textasciitilde,\textasteriskcentered}
|
|
% \DoNotIndex{\textbackslash,\textbar,\textbraceleft,\textbraceright}
|
|
% \DoNotIndex{\textdollar,\textendash,\textgreater,\textless}
|
|
% \DoNotIndex{\textunderscore,\textvisiblespace}
|
|
%
|
|
% \DoNotIndex{\filename@area,\filename@base,\filename@ext}
|
|
% \DoNotIndex{\filename@parse,\IfFileExists,\InputIfFileExists}
|
|
% \DoNotIndex{\DeclareOption,\MessageBreak}
|
|
% \DoNotIndex{\GenericError,\GenericInfo,\GenericWarning}
|
|
%
|
|
% \DoNotIndex{\blankstringfalse,\blankstringtrue,\commentstyle}
|
|
% \DoNotIndex{\DeclareCommentLine,\DeclareDoubleComment}
|
|
% \DoNotIndex{\DeclareNestedComment,\DeclarePairedComment}
|
|
% \DoNotIndex{\DeclareSingleComment,\inputlisting,\inputlisting@,\keywords}
|
|
% \DoNotIndex{\keywordstyle,\labelstyle,\listingfalse,\listingtrue}
|
|
% \DoNotIndex{\morekeywords,\normallisting,\postlisting,\prelisting}
|
|
% \DoNotIndex{\selectlisting,\sensitivefalse,\sensitivetrue}
|
|
% \DoNotIndex{\spreadlisting,\stringizer,\stringstyle,\tablength}
|
|
%
|
|
% \DoNotIndex{\lst@AddToHook@,\lst@Aspect@,\is,\lst@AspectGobble}
|
|
% \DoNotIndex{\lst@DeleteKeysIn@,\lst@Environment@}
|
|
% \DoNotIndex{\lst@IfNextChars@,\lst@IfNextChars@@,\lst@KCOutput@}
|
|
% \DoNotIndex{\lst@MakeActive@,\lst@MSkipUptoFirst@,\lst@ReplaceIn@}
|
|
% \DoNotIndex{\lst@LocateLanguage@,\lst@SKS@,\lstalias@,\lstalias@@}
|
|
% \DoNotIndex{\lstbaseem@,\lstbox@,\lstCC@ECUse@,\lstCC@Escape@}
|
|
% \DoNotIndex{\lstCC@CBC@,\lstCC@CBC@@,\lstCC@CommentLine@}
|
|
% \DoNotIndex{\lstCC@EndKeywordComment@,\lstCC@FixedCL@}
|
|
% \DoNotIndex{\lstCC@ProcessEndPOD@,\lstCC@SpecialUseAfter@}
|
|
% \DoNotIndex{\lstCC@Stringizer@,\lstdrvlanguage@,\lstenv@AddArg@}
|
|
% \DoNotIndex{\lstenv@Process@,\lstenv@ProcessJ@,\lstinputlisting@}
|
|
% \DoNotIndex{\lstoutputpos@,\lstresetlineno@,\lstresetlineno@@}
|
|
% \DoNotIndex{\lstspread@}
|
|
% \DoNotIndex{\lstnestedcomment@,\lstpost@,\lstpre@,\lststringizer@}
|
|
%
|
|
%
|
|
% \section{Overture}
|
|
%
|
|
% The version 0.19 kernel needs 1 token register, 6 counters and 5 dimensions.
|
|
% The macros, boxes and counters |\@temp?a| and |\@temp?b| and the dimension |\@tempdima| are also used, see the index.
|
|
% And I shouldn't forget |\@gtempa|.
|
|
% Furthermore, the required \textsf{keyval} package allocates one token register.
|
|
% The \textsf{fancyvrb} interface needs one box.
|
|
%
|
|
% Before considering the implementation, here some conventions I used:
|
|
% \begin{itemize}
|
|
% \item All public macros have lower case letters and the prefix \lst.
|
|
% \item The name of all private macros and variables use the prefixes (possibly not up to date):
|
|
% \begin{itemize}
|
|
% \item |lst@| for a general macro or variable,
|
|
% \item |lstenv@| if it is defined for the listing |env|ironment,
|
|
% \item |lstCC@| for |c|haracter |c|lass macros,
|
|
% \item |lsts@| for |s|aved character meanings,
|
|
% \item |lstf@| for frame declaration,
|
|
% \item |\lsthk@|\meta{name of hook} holds hook material,
|
|
% \item a language may define (|Pre| for prepare, |SCT| for select char table)
|
|
% \begin{itemize}
|
|
% \item[] |\lstPre@|\meta{language}
|
|
% \item[] |\lstPre@|\meta{language}|@|\meta{dialect}
|
|
% \item[] |\lstSCT@|\meta{language}
|
|
% \item[] |\lstSCT@|\meta{language}|@|\meta{dialect}
|
|
% \end{itemize}
|
|
% where the first two are executed (if they exist) one time each listing (before selecting character table, but after executing the hook Before\-Select\-Char\-Table).
|
|
% The other two macros are called possibly more than once, namely whenever the package selects the character table.
|
|
% The specialized \meta{dialect} versions are called after the more general \meta{language} macros.
|
|
% \item |lstk@| is reserved for keyword tests,
|
|
%
|
|
% \item |\lstlang@|\meta{language}|@|\meta{dialect} contains a language definition,
|
|
% \item |\lststy@|\meta{the style} contains style definition,
|
|
%
|
|
% \item |\lstloc@|\meta{language} keeps location (= file name without extension) of a language definition if it's not |lst|\meta{language},
|
|
% \item |\lsta@|\meta{language}|@|\meta{dialect} contains alias,
|
|
% \item |\lstaa@|\meta{language} contains alias for all dialects of a language,
|
|
% \item |\lstdd@|\meta{language} contains default dialect of a language (if present).
|
|
% \end{itemize}
|
|
% \item If a submacro does the main work, e.g.\ |\lstinputlisting@| does it for |\lstinputlisting|, we use the suffix |@|.
|
|
% \item To distinguish procedure-like macros from macros holding data, the name of procedure macros use upper case letters with each beginning word, e.g.\ |\lst@AddTo|.
|
|
% \end{itemize}
|
|
%
|
|
% The kernel starts with identification and option declaration and processing.
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
\NeedsTeXFormat{LaTeX2e}
|
|
\ProvidesPackage{listings}[1998/11/09 v0.19 by Carsten Heinz]
|
|
\RequirePackage{keyval}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\DeclareOption{0.17}{\@namedef{lst@0.17}{}}
|
|
\DeclareOption{index}{\@namedef{lst@index}{}}
|
|
\DeclareOption{procnames}{\@namedef{lst@prockeywords}{}}
|
|
\DeclareOption{ndkeywords}{\@namedef{lst@ndkeywords}{}}
|
|
\DeclareOption{rdkeywords}{\@namedef{lst@rdkeywords}{}}
|
|
\DeclareOption{doc}{\@namedef{lst@doc}{}}
|
|
\ProcessOptions
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% Note that |doc| option is designed for this documentation only.
|
|
% \endgroup
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*info>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@InfoInfo}
|
|
% \begin{macro}{\lst@InfoWarning}
|
|
% \begin{macro}{\lst@InfoError}
|
|
% Each macro gets one argument, which is printed (\texttt{.log} and/or screen) as info, warning or error.
|
|
% \begin{macrocode}
|
|
\def\lst@InfoInfo#1{%
|
|
\GenericInfo %
|
|
{(Listings) \@spaces\@spaces\space\space}%
|
|
{Listings Info: #1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@InfoWarning#1{%
|
|
\GenericWarning %
|
|
{(Listings) \@spaces\@spaces\@spaces\space}%
|
|
{Listings Warning: #1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@InfoError#1{%
|
|
\GenericError %
|
|
{(Listings) \@spaces\@spaces\@spaces\space}%
|
|
{Listings Error: #1}%
|
|
{See the package documentation for explanation.}%
|
|
{You're using a debug version of listings.sty.^^J%
|
|
Contact your system administrator to install nondebug one.}}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</info>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{General problems and \TeX{}niques}
|
|
%
|
|
%
|
|
% \subsection{Quick 'if parameter empty'}
|
|
%
|
|
% There are many situations where you have to look whether or not a macro parameter is empty.
|
|
% Let's say, we want to test |#1|.
|
|
% The \emph{natural} way would be something like
|
|
% \begin{verbatim}
|
|
% \def\test{#1}%
|
|
% \ifx \test\empty %
|
|
% % #1 is empty
|
|
% \else %
|
|
% % #1 is not empty
|
|
% \fi %\end{verbatim}
|
|
% where |\empty| is defined by |\def\empty{}|, of course.
|
|
% And now the \emph{mad} way:
|
|
% \begin{verbatim}
|
|
% \ifx \empty#1\empty %
|
|
% % #1 is empty
|
|
% \else %
|
|
% % #1 is not empty
|
|
% \fi %\end{verbatim}
|
|
% If the parameter is empty, the |\empty| left from |#1| is compared with the |\empty| on the right.
|
|
% All is fine since they are the same.
|
|
% If the parameter is not empty, the |\empty| on the left is compared with the first token of the parameter.
|
|
% Assuming this token is not equivalent to |\empty| the |\else| section is executed, as desired.
|
|
%
|
|
% The mad way works if and only if the first token of the parameter is not equivalent to |\empty|.
|
|
% You must check if this meets your purpose.
|
|
% The two |\empty|s might be replaced by any other macro, which is not equivalent to the first token of the parameter.
|
|
% But the definition of that macro shouldn't be too complex since this would slow down the |\ifx|.
|
|
% In the examples above the mad version needs about $45\%$ of the natural's time.
|
|
% Note that this \TeX{}nique lost its importance from version 0.18 on.
|
|
%
|
|
%
|
|
% \subsection{Replacing characters}\label{iReplacingCharacters}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% In this section we define the macro
|
|
% \begin{macrosyntax}
|
|
% \item |\lst@ReplaceIn|\meta{macro}|{|\meta{replacement list $c_1m_1$\ldots$c_nm_n$}|}|
|
|
% \end{macrosyntax}
|
|
% Each character $c_i$ inside the given macro is replaced by the macro $m_i$.
|
|
% In fact, $c_i$ may be a character sequence (enclosed in braces and possibly containing macros), but $m_i$ must be a single macro which is not equivalent to |\empty| --- use |\relax| instead.
|
|
% |\lst@ReplaceIn\lst@arg{_\textunderscore {--}\textendash}| is allowed but not |\lst@ReplaceIn\lst@arg{\textunderscore_\textendash{--}}|.
|
|
% These restrictions can be dropped, see the TODO part below.
|
|
%
|
|
% We derive the main macro from \LaTeX's |\zap@space|:
|
|
% \begin{verbatim}
|
|
% \def\zap@space#1 #2{%
|
|
% #1%
|
|
% \ifx#2\@empty\else\expandafter\zap@space\fi
|
|
% #2}\end{verbatim}
|
|
% It is called like this:
|
|
% \begin{verbatim}
|
|
% \zap@space Some characters with(out) sense and \@empty
|
|
% \expandafter\zap@space\lst@arg{} \@empty
|
|
% \edef\lst@arg{\expandafter\zap@space\lst@arg{} \@empty}\end{verbatim}
|
|
% Note that |{}|\textvisiblespace\ produces a space holding up the syntax of |\zap@space|: it's defined with a space between the two parameters.
|
|
% If we want to replace a space by a visible space, we could use
|
|
% \begin{verbatim}
|
|
% \def\lst@temp#1 #2{%
|
|
% #1%
|
|
% \ifx#2\@empty\else %
|
|
% \noexpand\textvisiblespace %
|
|
% \expandafter\lst@temp %
|
|
% \fi #2}\end{verbatim}
|
|
% The additional |\noexpand\textvisiblespace| inserts visible spaces where spaces have been.
|
|
% We want to replace several characters and thus have to save our intermediate results.
|
|
% So we will follow the third '|\edef|' example.
|
|
% But there is some danger: After replacing the first character, the macro $m_1$ will expand inside the next |\edef|.
|
|
% Knowing that letters don't expand, we simply say that $m_1$ is a letter.
|
|
% Such changes must be local, so \ldots
|
|
%
|
|
% \begin{macro}{\lst@ReplaceIn}
|
|
% we open a group, store the original macro contents in |\@gtempa| and start a loop.
|
|
% Afterwards we close the group and assign the modified character string to our given macro.
|
|
% \begin{macrocode}
|
|
\def\lst@ReplaceIn#1#2{%
|
|
\bgroup \global\let\@gtempa#1%
|
|
\lst@ReplaceIn@#2\@empty\@empty %
|
|
\egroup \let#1\@gtempa}
|
|
% \end{macrocode}
|
|
% If we haven't reached the end of the list (the two |\@empty|s), we let the macro $m_i$ be a letter and define an appropiate macro to replace the character (sequence) |#2| by the macro |#3|.
|
|
% \begin{macrocode}
|
|
\def\lst@ReplaceIn@#1#2{%
|
|
\ifx\@empty#2\else %
|
|
\let#2=a%
|
|
\def\lst@temp##1#1##2{##1%
|
|
\ifx\@empty##2\else %
|
|
#2\expandafter\lst@temp %
|
|
\fi ##2}%
|
|
% \end{macrocode}
|
|
% Now we call that macro using |\xdef| (since the changes in |\@gtempa| must exist after closing a group).
|
|
% Finally we continue the loop.
|
|
% \begin{macrocode}
|
|
\xdef\@gtempa{\expandafter\lst@temp\@gtempa#1\@empty}%
|
|
\expandafter\lst@ReplaceIn@ %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% This |\lst@ReplaceIn| is currently sufficient.
|
|
% If we need to replace character sequences by character sequences (instead of single macros), we have to make some minor changes.
|
|
% The main difference is that we build the new contents inside |\lst@temp| instead of using |\edef|.
|
|
% Note that the improved version is much slower than the macros above.\vspace*{-\baselineskip}
|
|
% \begin{verbatim}
|
|
%\def\lst@ReplaceIn#1#2{\lst@ReplaceIn@#1#2\@empty\@empty}
|
|
%\def\lst@ReplaceIn@#1#2#3{%
|
|
% \ifx\@empty#3\else %
|
|
% \def\lst@temp##1#2##2{%
|
|
% \ifx\@empty##2%
|
|
% \lst@lAddTo#1{##1}%
|
|
% \else %
|
|
% \lst@lAddTo#1{##1#3}%
|
|
% \expandafter\lst@temp %
|
|
% \fi ##2}%
|
|
% \let\@tempa#1\let#1\@empty %
|
|
% \expandafter\lst@temp\@tempa#2\@empty %
|
|
% \expandafter\lst@ReplaceIn@\expandafter#1%
|
|
% \fi}\end{verbatim}
|
|
% \removelastskip
|
|
% Even here you will have a problem replacing a single brace, if it has the meaning of opening or closing a group:
|
|
% You can't enter it as an argument!
|
|
% \end{TODO}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@DeleteKeysIn}
|
|
% We define another macro, which looks quite similar to |\lst@ReplaceIn|.
|
|
% The arguments are two macros containing a comma separated keyword list.
|
|
% All keywords in the second list are removed from the first.
|
|
% \begin{macrocode}
|
|
\def\lst@DeleteKeysIn#1#2{%
|
|
\bgroup \global\let\@gtempa#1%
|
|
\let\lst@dollar=A\let\lst@minus=B\let\lst@underscore=C%
|
|
\expandafter\lst@DeleteKeysIn@#2,\relax,%
|
|
\egroup \let#1\@gtempa}
|
|
% \end{macrocode}
|
|
% To terminate the loop we remove the very last |\lst@DeleteKeysIn@| with |\@gobble|.
|
|
% \begin{macrocode}
|
|
\def\lst@DeleteKeysIn@#1,{%
|
|
\ifx\relax#1\@empty %
|
|
\expandafter\@gobble %
|
|
\else %
|
|
\ifx\@empty#1\@empty\else %
|
|
\def\lst@temp##1,#1##2{##1\ifx\@empty##2\else %
|
|
\ifx,##2\else #1\fi \expandafter\lst@temp\fi ##2}%
|
|
\xdef\@gtempa{%
|
|
\expandafter\lst@temp\expandafter,\@gtempa,#1\@empty}%
|
|
\fi %
|
|
\fi %
|
|
\lst@DeleteKeysIn@}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Looking ahead for character sequences}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@IfNextChars}
|
|
% The macro |\@ifnextchar|\meta{single character}|{|\meta{then part}|}{|\meta{else part}|}| from the \LaTeX{} kernel is well known:
|
|
% Whether or not the character behind the three arguments --- usually a character from the 'user input stream' --- equals the given single character the 'then' or 'else' part is executed.
|
|
% We define a macro which looks for an arbitrary character sequence stored in a macro:{}
|
|
% \begin{macrosyntax}
|
|
% \item |\lst@IfNextChars|\meta{macro}|{|\meta{then part}|}{|\meta{else part}|}|
|
|
% \end{macrosyntax}
|
|
% Note an important difference:
|
|
% \LaTeX's |\@ifnextchar| doesn't remove the character behind the arguments, but we remove the characters until it is possible to decide whether the 'then' or 'else' part must be executed.
|
|
% However, we save these characters in a macro called |\lst@eaten|, so they can be inserted if necessary.
|
|
%
|
|
% We save the arguments and call the macro which does the comparisons.
|
|
% \begin{macrocode}
|
|
\def\lst@IfNextChars#1#2#3{%
|
|
\let\lst@tofind#1\def\@tempa{#2}\def\@tempb{#3}%
|
|
\let\lst@eaten\@empty \lst@IfNextChars@}
|
|
% \end{macrocode}
|
|
% This macro reads the next character from the input and compares it with the next character from |\lst@tofind|.
|
|
% We append |#1| to the eaten characters and get the character we are looking for (via |\lst@IfNextChars@@|).
|
|
% \begin{macrocode}
|
|
\def\lst@IfNextChars@#1{%
|
|
\lst@lAddTo\lst@eaten{#1}%
|
|
\expandafter\lst@IfNextChars@@\lst@tofind\relax %
|
|
\ifx #1\lst@temp %
|
|
% \end{macrocode}
|
|
% If the characters are the same, we either execute |\@tempa| or continue the test.
|
|
% \begin{macrocode}
|
|
\ifx\lst@tofind\@empty %
|
|
\let\lst@next\@tempa %
|
|
\else %
|
|
\let\lst@next\lst@IfNextChars@ %
|
|
\fi %
|
|
\expandafter\lst@next %
|
|
\else %
|
|
% \end{macrocode}
|
|
% If the characters are different, we have to call |\@tempb|.
|
|
% \begin{macrocode}
|
|
\expandafter\@tempb %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% Finally comes the subsubmacro |\lst@IfNextChars@@| used above, which assigns the next character to |\lst@temp| and the rest upto |\relax| to |\lst@tofind|.
|
|
% If the implementation is not clear, read the last sentence again.
|
|
% \begin{macrocode}
|
|
\def\lst@IfNextChars@@#1#2\relax{\let\lst@temp#1\def\lst@tofind{#2}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@IfNextCharsArg}
|
|
% The difference between |\lst@IfNextChars| and the macro here is that the first parameter is a character sequence and not a macro.
|
|
% Moreover, the character sequence is made active here.
|
|
% \begin{macrocode}
|
|
\def\lst@IfNextCharsArg#1#2#3{%
|
|
\lst@MakeActive{#1}\let\lst@tofind\lst@arg %
|
|
\def\@tempa{#2}\def\@tempb{#3}%
|
|
\let\lst@eaten\@empty \lst@IfNextChars@}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Catcode changes of characters already read}\label{iCatcodeChangesOfCharactersAlreadyRead}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% Here we define two important macros:
|
|
% \begin{macrosyntax}
|
|
% \item |\lst@MakeActive{|\meta{character sequence}|}|
|
|
%
|
|
% stores the character sequence in |\lst@arg|, but all characters become active.
|
|
% The string must \emph{not} contain a begin group, end group or escape character (|{}\|); it may contain a left brace, right brace or backslash with other meaning (=catcodes).
|
|
% This command would be quite surplus if \meta{character sequence} is not already read by \TeX{} (since such catcodes can be changed easily).
|
|
% It is explicitly allowed that the charcaters have been read, e.g.\ in |\def\test{\lst@MakeActive{ABC}}| |\test|!
|
|
%
|
|
% Note that |\lst@MakeActive| changes |\lccode|s 0--9 without restoring them.
|
|
% \item |\lst@IfNextCharActive{|\meta{then part}|}{|\meta{else part}|}|
|
|
%
|
|
% executes 'then' part if next character behind the arguments is active, and the 'else' part otherwise.
|
|
% \end{macrosyntax}
|
|
% \TeX{} knows sixteen different catcodes, which say whether a character is a letter, a space, a math shift character, subscript character, and so on.
|
|
% A character gets its catcode right after reading it and \TeX{} has no primitive command to change a catcode of characters already read.
|
|
% Consider for example |\def\mathmode#1{$#1$}|.
|
|
% After that definition there is no chance to say: ''\emph{Print} the two dollar signs and the argument between instead of entering math mode''.
|
|
% And if we write |\mathmode{a_i}| and have just entered the macro |\mathmode|, the argument |a_i| is read and it's too late to change the meaning of the subscript character to a printable underbar, for example.
|
|
% But that's not the whole truth: We can change character-catcodes of an argument.
|
|
% In fact, we replace the characters by characters with same ASCII codes but different catcodes.
|
|
% It's not the same but suffices since the result is the same.
|
|
% Here we treat the very special case that all characters become active.
|
|
% A prototype macro would be
|
|
% \begin{verbatim}
|
|
% \def\MakeActive#1{\lccode`\~=`#1\lowercase{\def\lst@arg{~}}}|\end{verbatim}
|
|
% But this macro handles a single character only:
|
|
% The |\lowercase| changes the ASCII code of |~| to that of |#1| since we have said that |~| is the lower case version of |#1|.
|
|
% Fortunately the |\lowercase| doesn't change the catcode, so we have an active version of |#1|.
|
|
% Note that |~| is usually active.
|
|
%
|
|
% \begin{macro}{\lst@MakeActive}
|
|
% We won't do this character by character.
|
|
% To increase speed we change nine characters at the same time (if nine characters are left).
|
|
% We get the argument, empty |\lst@arg| and begin a loop:
|
|
% \begin{macrocode}
|
|
\def\lst@MakeActive#1{%
|
|
\let\lst@arg\@empty \lst@MakeActive@#1%
|
|
\relax\relax\relax\relax\relax\relax\relax\relax\relax}
|
|
% \end{macrocode}
|
|
% There are nine |\relax|es since |\lst@MakeActive@| has nine parameters and we don't want any problems in the case that |#1| is empty.
|
|
% We need nine active characters now instead of a single |~|.
|
|
% We make these catcode changes local and define the coming macro |\global|.
|
|
% \begin{macrocode}
|
|
\begingroup
|
|
\catcode`\^^@=\active \catcode`\^^A=\active \catcode`\^^B=\active %
|
|
\catcode`\^^C=\active \catcode`\^^D=\active \catcode`\^^E=\active %
|
|
\catcode`\^^F=\active \catcode`\^^G=\active \catcode`\^^H=\active %
|
|
% \end{macrocode}
|
|
% First we |\let| the next operation be |\relax|.
|
|
% This aborts our loop for processing all characters (default and possibly changed later).
|
|
% Then we look if we have at least one character.
|
|
% If this is not the case, the loop terminates and all is done.
|
|
% \begin{macrocode}
|
|
\gdef\lst@MakeActive@#1#2#3#4#5#6#7#8#9{\let\lst@next\relax %
|
|
\ifx#1\relax %
|
|
\else \lccode`\^^@=`#1%
|
|
% \end{macrocode}
|
|
% Otherwise we say that |^^@|=chr(0) is the lower case version of the first character.
|
|
% Then we test the second character.
|
|
% If there is none, we append the lower case |^^@| to |\lst@arg|.
|
|
% Otherwise we say that |^^A|=chr(1) is the lower case version of the second character and we test the next argument, and so on.
|
|
% \begin{macrocode}
|
|
\ifx#2\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@}}%
|
|
\else \lccode`\^^A=`#2%
|
|
\ifx#3\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A}}%
|
|
\else \lccode`\^^B=`#3%
|
|
\ifx#4\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A^^B}}%
|
|
\else \lccode`\^^C=`#4%
|
|
\ifx#5\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A^^B^^C}}%
|
|
\else \lccode`\^^D=`#5%
|
|
\ifx#6\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A^^B^^C^^D}}%
|
|
\else \lccode`\^^E=`#6%
|
|
\ifx#7\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A^^B^^C^^D^^E}}%
|
|
\else \lccode`\^^F=`#7%
|
|
\ifx#8\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A^^B^^C^^D^^E^^F}}%
|
|
\else \lccode`\^^G=`#8%
|
|
\ifx#9\relax %
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A^^B^^C^^D^^E^^F^^G}}%
|
|
% \end{macrocode}
|
|
% If nine characters are present, we append (lower case versions of) nine active characters and call this macro again via redefining |\lst@next|.
|
|
% \begin{macrocode}
|
|
\else \lccode`\^^H=`#9%
|
|
\lowercase{\lst@lAddTo\lst@arg{^^@^^A^^B^^C^^D^^E^^F^^G^^H}}%
|
|
\let\lst@next\lst@MakeActive@ %
|
|
\fi \fi \fi \fi \fi \fi \fi \fi \fi %
|
|
\lst@next}
|
|
\endgroup
|
|
% \end{macrocode}
|
|
% This |\endgroup| restores the catcodes of chr(0)--chr(8), but not the catcodes of the characters inside |\lst@MakeActive@| since they are already read.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@IfNextCharActive}
|
|
% The implementation is easy now: We compare the character |#3| with its active version |\lowercase{~}|.
|
|
% Note that the right brace between |\ifx~| and |#3| ends the |\lowercase|.
|
|
% The |\egroup| before restores the |\lccode|.
|
|
% \begin{macrocode}
|
|
\def\lst@IfNextCharActive#1#2#3{%
|
|
\bgroup \lccode`\~=`#3\lowercase{\egroup %
|
|
\ifx~}#3%
|
|
\def\lst@next{#1#3}%
|
|
\else %
|
|
\def\lst@next{#2#3}%
|
|
\fi \lst@next}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{An application to \ref{iCatcodeChangesOfCharactersAlreadyRead}}\label{iAnApplicationTo}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% We need a brief look on how the listing processing works.
|
|
% Right before processing a listing we redefine all characters, for example to preserve successive spaces or to give the tabulator a different meaning.
|
|
% More precisely, each character becomes active in the sense of \TeX, but that's not so important now.
|
|
% After the listing we switch back to the original meanings and all is fine.
|
|
% If an environment is used inside an argument the listing is already read when the environment is executed and we can do nothing to preserve the characters.
|
|
% However, (under certain circumstances) the environment can be used inside an argument --- that's at least what I've said in the user's guide.
|
|
% And now we have to work for it coming true.
|
|
% We define the macro
|
|
% \begin{macrosyntax}
|
|
% \item |\lstenv@AddArg{|\meta{\TeX{} material (already read)}|}|
|
|
% \end{macrosyntax}
|
|
% which \emph{appends} a 'verbatim' version of the argument to |\lstenv@arg|, but all appended characters are active.
|
|
% Since it's not a character to character conversion, 'verbatim' needs to be explained.
|
|
% All characters can be typed in as they are, except |\|, |{|, |}| and |%|.
|
|
% If you want one of these, you must write |\\|, |\{|, |\}| or |\%| instead.
|
|
% If two spaces should follow each other, the second (third, fourth, \ldots) space must be entered as |\|\textvisiblespace.
|
|
%
|
|
% \begin{macro}{\lstenv@AddArg}
|
|
% We call a submacro (similar to |\zap@space|) to preserve single spaces.
|
|
% \begin{macrocode}
|
|
\def\lstenv@AddArg#1{\lstenv@AddArg@#1 \@empty}
|
|
% \end{macrocode}
|
|
% We will need an active space:
|
|
% \begin{macrocode}
|
|
\begingroup \lccode`\~=`\ \relax \lowercase{%
|
|
% \end{macrocode}
|
|
% We make all characters upto the first space (with catcode 10) active and append these (plus an active space) to |\lstenv@arg|.
|
|
% If we haven't found the end |\@empty| of the input, we continue the process.
|
|
% \begin{macrocode}
|
|
\gdef\lstenv@AddArg@#1 #2{%
|
|
\lst@MakeActive{#1}%
|
|
\ifx\@empty#2\expandafter%
|
|
\lst@lAddTo\expandafter\lstenv@arg\expandafter{\lst@arg}%
|
|
\else \expandafter%
|
|
\lst@lAddTo\expandafter\lstenv@arg\expandafter{\lst@arg~}%
|
|
\expandafter\lstenv@AddArg@ %
|
|
\fi #2}
|
|
% \end{macrocode}
|
|
% Finally we end the |\lowercase| and close a group.
|
|
% \begin{macrocode}
|
|
}\endgroup
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{How to define \lst-aspects}\label{iHowToDefineLstAspects}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% This section contains commands used in defining the style and language aspects.
|
|
% There are two command classes: one extends the internal capabilities, and the other actually defines the aspects.
|
|
% \begin{macrosyntax}
|
|
% \item |\lst@Aspect{|\meta{aspect name}|}{|\meta{definition}|}|
|
|
%
|
|
% is the one and only command in the latter class.
|
|
% It defines the aspect using the \textsf{keyval} package.
|
|
%
|
|
% \item |\lst@AddToHook||{|\meta{name of hook}|}{|\meta{\TeX{} material}|}|
|
|
%
|
|
% \item |\lst@AddToHookAtTop||{|\meta{name of hook}|}{|\meta{\TeX{} material}|}|
|
|
%
|
|
% Both add \TeX{} material at predefined points.
|
|
% The first command appends the code, whereas the second places it in front of existing hook material.
|
|
% \end{macrosyntax}
|
|
% The following hooks are supported (possibly not up to date):
|
|
% \begin{center}\begin{tabular}{rp{0.6\linewidth}}
|
|
% name of hook & point/aim of execution\\ \hline
|
|
% |InitVars| & initializes variables each listing\\
|
|
% |ExitVars| & deinits variables each listing\\
|
|
% |OnExit| & executed at the very end of typesetting\\
|
|
% |EveryLine| & called at the beginning of each line\\
|
|
% |EOL| & executed after printing a source code line\\
|
|
% |InitVarsEOL| & prepares variables for the next line\\
|
|
% |EndGroup| & executed whenever the package closes a group (end of comment or string, e.g.)\\
|
|
% |Output| & called before a printing unit with letters and digits is typeset\\
|
|
% |OutputOther| & called before any other printing unit is typeset\\
|
|
% |BeforeSelectCharTable| & executed before the package changes the character table\\
|
|
% |SelectCharTable| & executed after the package has selected the standard character table\\
|
|
% &\\
|
|
% |SetStyle| & called before |\lststy@|\meta{style}\\
|
|
% |SetLanguage| & called before |\lstlang@|\meta{language}|@|\meta{dialect}\\
|
|
% \end{tabular}\end{center}
|
|
% For example, the hooks make keywords case insensitive (if necessary) before the package processes a listing and call the keyword style before a keyword is printed.
|
|
%
|
|
% \begin{macro}{\lst@Aspect}
|
|
% The command defines the aspect only if not already present.
|
|
% |\lst@ifnew| becomes true (if and) only if a new aspect is defined.
|
|
% \begin{macrocode}
|
|
\def\lst@Aspect#1{%
|
|
\@ifundefined{KV@lst@#1}%
|
|
{\let\lst@ifnew\iftrue}{\let\lst@ifnew\iffalse}%
|
|
\lst@ifnew %
|
|
%<info> \lst@InfoInfo{New aspect `#1'}%
|
|
\else %
|
|
%<info> \lst@InfoWarning{Gobble aspect `#1'}%
|
|
\expandafter\@gobblefour %
|
|
\fi %
|
|
\lstdefine@key{lst}{#1}}
|
|
% \end{macrocode}
|
|
% Now come renamed copies from two \textsf{keyval} macros, but the key definitions are made globally.
|
|
% \begin{macrocode}
|
|
\def\lstdefine@key#1#2{%
|
|
\@ifnextchar[{\lstKV@def{#1}{#2}}{\global\@namedef{KV@#1@#2}####1}}
|
|
\def\lstKV@def#1#2[#3]{%
|
|
\global\@namedef{KV@#1@#2@default\expandafter}\expandafter %
|
|
{\csname KV@#1@#2\endcsname{#3}}%
|
|
\global\@namedef{KV@#1@#2}##1}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\let\lst@ifnew\iftrue % init
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@AddToHook}
|
|
% \begin{macro}{\lst@AddToHookAtTop}
|
|
% The definitions are mainly in terms of |\lst@AddTo| and |\lst@AddToAtTop|.
|
|
% But we test whether the hook already exists.
|
|
% \begin{macrocode}
|
|
\def\lst@AddToHook#1{%
|
|
\lst@ifnew %
|
|
\@ifundefined{lsthk@#1}{%
|
|
%<info> \lst@InfoInfo{New hook `#1'}%
|
|
\expandafter\gdef\csname lsthk@#1\endcsname{}}{}%
|
|
\def\lst@next{\lst@AddToHook@\lst@AddTo{#1}}%
|
|
\expandafter\lst@next %
|
|
\else %
|
|
\expandafter\@gobble %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% The submacro makes it possible to use \texttt{if}s inside the second argument (which is the third here).
|
|
% \begin{macrocode}
|
|
\long\def\lst@AddToHook@#1#2#3{%
|
|
\expandafter#1\csname lsthk@#2\endcsname{#3}}
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% The usage of |\lst@ifnew| is still unsatisfactory:
|
|
% Defining an aspect and its hooks twice doesn't add the \TeX\ material a second time, but defining hooks and then the aspect would do so.
|
|
% \end{TODO}
|
|
% \begin{macrocode}
|
|
\def\lst@AddToHookAtTop#1{%
|
|
\lst@ifnew %
|
|
\@ifundefined{lsthk@#1}{%
|
|
%<info> \lst@InfoInfo{New hook `#1'}%
|
|
\expandafter\gdef\csname lsthk@#1\endcsname{}}{}%
|
|
\def\lst@next{\lst@AddToHook@\lst@AddToAtTop{#1}}%
|
|
\expandafter\lst@next %
|
|
\else %
|
|
\expandafter\@gobble %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@AddTo}
|
|
% \begin{macro}{\lst@AddToAtTop}
|
|
% These macros add the second argument to the macro |#1|.
|
|
% But the definition is global!
|
|
% \begin{macrocode}
|
|
\long\def\lst@AddTo#1#2{%
|
|
\expandafter\gdef\expandafter#1\expandafter{#1#2}}
|
|
% \end{macrocode}
|
|
% We need a couple of |\expandafter|s now.
|
|
% Simply note that we have\\
|
|
% {\small\hspace*{2em}
|
|
% |\expandafter\gdef\expandafter#1\expandafter{\lst@temp|$\langle$\textit{contents of }|#1|$\rangle$|}|
|
|
% }\\
|
|
% after the first phase of expansion.
|
|
% \begin{macrocode}
|
|
\def\lst@AddToAtTop#1#2{\def\lst@temp{#2}%
|
|
\expandafter\expandafter\expandafter\gdef %
|
|
\expandafter\expandafter\expandafter#1%
|
|
\expandafter\expandafter\expandafter{\expandafter\lst@temp#1}}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@lAddTo}
|
|
% A local version of |\lst@AddTo|.
|
|
% \begin{macrocode}
|
|
\def\lst@lAddTo#1#2{\expandafter\def\expandafter#1\expandafter{#1#2}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begingroup
|
|
% \noindent Since some hooks are unused and never defined by the hook macros above, we define them here:
|
|
% \begin{macrocode}
|
|
\global\let\lsthk@OutputOther\@empty
|
|
\global\let\lsthk@SetStyle\@empty
|
|
\global\let\lsthk@SetLanguage\@empty
|
|
\global\let\lsthk@PreSet\@empty
|
|
\global\let\lsthk@PostSet\@empty
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Interfacing with \textsf{keyval}}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% The \textsf{keyval} package passes the value via the one and only paramater |#1| to the definition part of the aspect macro.
|
|
% The following commands may be used to analyse the value.
|
|
% \begin{macrosyntax}
|
|
% \item |\lstKV@SetIfKey|\meta{macro}|{#1}|
|
|
%
|
|
% \meta{macro} becomes true (more precisely |\iftrue|) if the first character of |#1| equals |t| or |T|.
|
|
% It becomes false otherwise.
|
|
%
|
|
% \item |\lstKV@OptArg|\meta{submacro}|[|\meta{default arg.}|]{#1}|
|
|
%
|
|
% calls \meta{submacro} with |#1| and with inserted |[|\meta{default arg.}|]| if |#1| has no optional argument.
|
|
% \end{macrosyntax}
|
|
%
|
|
% \begin{macro}{\lstKV@SetIfKey}
|
|
% We simply test the first character of |#2|.
|
|
% \begin{macrocode}
|
|
\def\lstKV@SetIfKey#1#2{\lstKV@SetIfKey@#1#2\relax}
|
|
\def\lstKV@SetIfKey@#1#2#3\relax{\lowercase{%
|
|
\expandafter\let\expandafter#1%
|
|
\csname \ifx #2t}iftrue\else iffalse\fi\endcsname}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstKV@OptArg}
|
|
% We read the arguments and insert default if necesary, what else?
|
|
% \begin{macrocode}
|
|
\def\lstKV@OptArg#1[#2]#3{\lstKV@OptArg@{#1}{#2}#3\@}
|
|
\def\lstKV@OptArg@#1#2{%
|
|
\@ifnextchar[{\lstKV@OptArg@@{#1}}%
|
|
{\lstKV@OptArg@@{#1}[#2]}}
|
|
\def\lstKV@OptArg@@#1[#2]#3\@{#1[#2]{#3}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstset}
|
|
% Finally this main user interface macro:
|
|
% \begin{macrocode}
|
|
\def\lstset#1{\lsthk@PreSet\setkeys{lst}{#1}\lsthk@PostSet}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Internal modes}\label{iInternalModes}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@mode}
|
|
% \begin{macro}{\lst@EnterMode}
|
|
% \begin{macro}{\lst@LeaveMode}
|
|
% While typesetting a listing we will enter 'modes' to distinguish comments from strings, comment lines from single comments, \TeX\ comment lines from fixed comment lines, and so on.
|
|
% The counter |\lst@mode| keeps the current mode number.
|
|
% \begin{macrocode}
|
|
\newcount\lst@mode
|
|
% \end{macrocode}
|
|
% Each mode opens a group level, stores the mode number and execute mode specific tokens.
|
|
% Moreover we keep all these changes in mind (locally).
|
|
% \begin{macrocode}
|
|
\def\lst@EnterMode#1#2{%
|
|
\bgroup \lst@mode=#1\relax #2%
|
|
\lst@lAddTo\lst@entermodes{\lst@EnterMode{#1}{#2}}}
|
|
% \end{macrocode}
|
|
% Leaving a mode simply closes the group and calls the hook |\lsthk@EndGroup|.
|
|
% \begin{macrocode}
|
|
\def\lst@LeaveMode{\egroup\lsthk@EndGroup}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVars}{\let\lst@entermodes\@empty}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@NewMode}
|
|
% defines a new mode number.
|
|
% We simply use |\mathchardef| and advance the number in |\lst@newmode|, which is a macro --- we don't waste another counter.
|
|
% \begin{macrocode}
|
|
\def\lst@NewMode#1{%
|
|
\ifx\@undefined#1%
|
|
\global\mathchardef#1=\lst@newmode\relax %
|
|
\lst@mode=\lst@newmode\relax \advance\lst@mode\@ne %
|
|
\edef\lst@newmode{\the\lst@mode}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% We start with number 0.
|
|
% The negative range is reserved for nested comments.
|
|
% \begin{macrocode}
|
|
\def\lst@newmode{0}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@nomode}
|
|
% \begin{macro}{\lst@Pmode}
|
|
% The very first mode initializes |\lst@mode| (every listing).
|
|
% The other mode indicates active listing processing.
|
|
% \begin{macrocode}
|
|
\lst@NewMode\lst@nomode
|
|
\lst@AddToHook{InitVars}{\lst@modefalse \lst@mode\lst@nomode}
|
|
\lst@NewMode\lst@Pmode
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@modetrue}
|
|
% \begin{macro}{\lst@modefalse}
|
|
% If |\lst@ifmode| is true, no mode change is allowed --- except leaving the mode.
|
|
% \begin{macrocode}
|
|
\def\lst@modetrue{\let\lst@ifmode\iftrue}
|
|
\def\lst@modefalse{\let\lst@ifmode\iffalse}
|
|
% \end{macrocode}
|
|
% Note: |\lst@ifmode| is \emph{not} obsolete since |\lst@mode|$\neq$|\lst@nomode| does \emph{not} imply |\lst@ifmode|$=$|\iftrue|.
|
|
% And even the other implication is not true.
|
|
% It will happen that we enter a mode without setting |\lst@ifmode| true, and we'll set it true without assigning any mode!
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@InterruptModes}
|
|
% \begin{macro}{\lst@ReenterModes}
|
|
% Since we kept all mode changes in mind, it is possible two interrupt and re-enter the current mode.
|
|
% This is useful for \TeX\ comment lines, for example.
|
|
% \begin{macrocode}
|
|
\def\lst@InterruptModes{%
|
|
\ifx\lst@entermodes\@empty\else %
|
|
\global\let\lst@reenter\lst@entermodes %
|
|
\lst@LeaveAllModes %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% The last |\ifx| is not necessay since empty |\lst@entermodes| implies that we don't leave any mode.
|
|
% But we need the |\ifx| in the following macro since empty |\lst@reenter| doesn't tell us anything about the current mode.
|
|
% \begin{macrocode}
|
|
\def\lst@ReenterModes{%
|
|
\ifx\lst@reenter\@empty\else %
|
|
\lst@LeaveAllModes \lst@reenter %
|
|
\global\let\lst@reenter\@empty %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVars}{\global\let\lst@reenter\@empty}
|
|
% \end{macrocode}
|
|
% Note that these macros can't be nested:
|
|
% If you 'interrupt modes', enter some modes and say 'interrupt modes' again, then two 're-enter modes' will \emph{not} take you back in front of the first 'interrupt modes'.
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@LeaveAllModes}
|
|
% This is some kind of emergency macro.
|
|
% Since any mode is terminated by closing a group, leaving all modes means closing groups until the mode equals |\lst@nomode|.
|
|
% We'll need that macro to end a listing correctly.
|
|
% \begin{macrocode}
|
|
\def\lst@LeaveAllModes{%
|
|
\ifnum\lst@mode=\lst@nomode %
|
|
\expandafter\lsthk@EndGroup %
|
|
\else %
|
|
\expandafter\egroup\expandafter\lst@LeaveAllModes %
|
|
\fi}
|
|
\lst@AddToHook{ExitVars}{\lst@LeaveAllModes}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@egroupmode}
|
|
% We allocate a 'processing mode' and define a general purpose 'egroup' mode: close a group at end of line.
|
|
% \begin{macrocode}
|
|
\lst@NewMode\lst@egroupmode
|
|
\lst@AddToHook{EOL}
|
|
{\ifnum\lst@mode=\lst@egroupmode \lst@LeaveMode \fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Styles and languages}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@Normalize}
|
|
% normalizes the contents of the macro |#1| by making all characters lower case and stripping off spaces.
|
|
% \begin{macrocode}
|
|
\def\lst@Normalize#1{%
|
|
\lowercase\expandafter{\expandafter\edef\expandafter#1%
|
|
\expandafter{\expandafter\zap@space#1 \@empty}}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstdefinestyle}
|
|
% The internal macro name of a style is |\lststy@|\emph{the style} (normalized).
|
|
% If called, it simply sets the keys to given values.
|
|
% \begin{macrocode}
|
|
\newcommand\lstdefinestyle[2]{%
|
|
\def\lst@temp{lststy@#1}\lst@Normalize\lst@temp %
|
|
\global\@namedef\lst@temp{\setkeys{lst}{#2}}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{style}
|
|
% We give an error message if the necessary macro doesn't exist.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{style}
|
|
{\def\lst@temp{lststy@#1}\lst@Normalize\lst@temp %
|
|
\@ifundefined\lst@temp %
|
|
{\PackageError{Listings}{Style `#1' undefined}%
|
|
{You might have misspelt the name here or before.^^J%
|
|
Type <RETURN> to proceed without changing the style.}}%
|
|
% \end{macrocode}
|
|
% Otherwise we execute the hook and call the macro.
|
|
% \begin{macrocode}
|
|
{\lsthk@SetStyle \csname\lst@temp\endcsname %
|
|
%<info> \lst@InfoInfo{\expandafter\string %
|
|
%<info> \csname\lst@temp\endcsname\space called}%
|
|
}}
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% It's easy to crash the listings package with |style| (and also with |language|).
|
|
% Define |\lstdefinestyle{crash}{style=crash}| and write |\lstset{style=crash}|.
|
|
% \TeX's capacity will exceed (parameter stack size), sorry.
|
|
% Only bad girls use such recursive calls, but only good girls use this package.
|
|
% Thus this problem is of minor interest.
|
|
% \end{TODO}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstdefinelanguage}
|
|
% Nearly |\lstdefinestyle|:
|
|
% \begin{macrocode}
|
|
\newcommand\lstdefinelanguage[3][]{%
|
|
\def\@tempa{#2@#1}\lst@Normalize\@tempa %
|
|
\global\@namedef{lstlang@\@tempa}{\lstset{#3}}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstdefinedrvlanguage}
|
|
% The driver file \texttt{lstpascal.sty} contains a couple of Pascal dialects.
|
|
% It is unnecessary to hold all these dialects in memory if the user selects Standard Pascal only.
|
|
% There are different scopes:
|
|
% \begin{itemize}
|
|
% \item[--] All code outside any (style or language) definition is executed.
|
|
% Definitions should be |\global| since a driver file is input inside a group.
|
|
% Note also that |@| is a letter and |"| has catcode 12 (other).
|
|
% \item[--] All languages declared with |\lstdefinelanguage| are defined.
|
|
% \item[--] A language declared with |\lstdefinedrvlanguage| is defined if and only if the user has requested that language.
|
|
% \end{itemize}
|
|
% We either do the definition or drop it:
|
|
% \begin{macrocode}
|
|
\newcommand\lstdefinedrvlanguage[3][]{%
|
|
\def\@tempa{lstlang@#2@#1}\lst@Normalize\@tempa %
|
|
\ifx\@tempa\lst@requested %
|
|
\global\@namedef{\@tempa}{\lstset{#3}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% The command syntax is liable to changes.
|
|
% I conjecture that it will be something like the following.
|
|
% \begin{macrosyntax}
|
|
% \item[0.2] |\lstdefinedrvlanguage|[|[|\meta{dialect}|]|]|{|\meta{language}|}|\\
|
|
% \qquad[|[|\meta{base dialect}|]|]|{|\meta{base language (e.g.\ empty)}|}|\\
|
|
% \qquad|{|\meta{key=value list}|}|\\
|
|
% \qquad[|[|\meta{list of extras (keywordcomments,texcs,etc.)}|]|]
|
|
% \end{macrosyntax}
|
|
% To make 'extras' user assessible (without loading a language) a command |\lstloadextras| would be nice.
|
|
% In any case such a macro is needed to load the extras for the supported languages.
|
|
% All in all there should be the following files in future: The kernel |listings.sty|, the language definitions in |lstdrvrs.sty| (or |lstdef.sty|?) and extras in a file |lstextra.sty|.
|
|
% \end{TODO}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstloadlanguages}
|
|
% We iterate through the list and locate and load each language.
|
|
% \begin{macrocode}
|
|
\def\lstloadlanguages#1{\lstloadlanguages@#1,\relax,}
|
|
\def\lstloadlanguages@#1,{%
|
|
\ifx\relax#1\@empty \else %
|
|
\lstKV@OptArg\lstloadlanguages@@[]{#1}%
|
|
\expandafter\lstloadlanguages@ %
|
|
\fi}
|
|
\def\lstloadlanguages@@[#1]#2{%
|
|
\lst@LocateLanguage[#1]{#2}%
|
|
\@ifundefined{\lst@requested}%
|
|
{{\catcode`\^^M=9\catcode`\"=12\makeatletter %
|
|
\input{\lst@driver.sty}}}%
|
|
{}}
|
|
\@onlypreamble\lstloadlanguages
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{language}
|
|
% If the language macro |\lstlang@|\emph{language}|@|\emph{dialect} doesn't exist, we must load the driver file.
|
|
% In that case the character |@| becomes a letter and we change the catcode of the double quote for compatibility with \texttt{german.sty}.
|
|
% Moreover we make the EOL character being ignored (which removes unwanted spaces if we've forgotten |%| at end of line).
|
|
% \begin{macrocode}
|
|
\lst@Aspect{language}{\lstKV@OptArg\lstlanguage@[]{#1}}
|
|
\def\lstlanguage@[#1]#2{%
|
|
\lst@LocateLanguage[#1]{#2}%
|
|
\@ifundefined{\lst@requested}%
|
|
{{\catcode`\^^M=9\catcode`\"=12\makeatletter %
|
|
\input{\lst@driver.sty}}}{}%
|
|
% \end{macrocode}
|
|
% We give an error message, if the language/dialect is undefined now.
|
|
% \begin{macrocode}
|
|
\@ifundefined{\lst@requested}%
|
|
{\PackageError{Listings}%
|
|
{\ifx\@empty\lst@dialect@\else \lst@dialect@\space of \fi %
|
|
\lst@language@\space undefined}{The driver file is not
|
|
loadable or doesn't support the language.^^J%
|
|
Type <RETURN> to proceed without changing the language.}}%
|
|
% \end{macrocode}
|
|
% Otherwise we execute the hook and select the language.
|
|
% \begin{macrocode}
|
|
{\lsthk@SetLanguage %
|
|
%<info> \lst@InfoInfo{\expandafter\string %
|
|
%<info> \csname\lst@requested\endcsname\space called}%
|
|
\csname\lst@requested\endcsname %
|
|
\def\lst@language{#1}\lst@Normalize\lst@language %
|
|
\def\lst@dialect{#2}\lst@Normalize\lst@dialect}}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{aspect}{defaultdialect}
|
|
% We simply store the dialect.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{defaultdialect}{\lstKV@OptArg\lstdefaultdialect@[]{#1}}
|
|
\def\lstdefaultdialect@[#1]#2{%
|
|
\def\lst@temp{#2}\lst@Normalize\lst@temp %
|
|
\global\@namedef{lstdd@\lst@temp}{#1}}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% Languages might have a user name and a different internal name.
|
|
% Moreover we don't always use the standard driver file |lst|\meta{language}|.sty|.
|
|
% If the user writes |language=[fuu]foo|, this could mean that we select (internally) dialect |faa| of language |fee|, which is located in driver file |fii.sty|.
|
|
% We define the following macros:
|
|
% \begin{macrosyntax}
|
|
% \item |\lst@DriverLocation{|\meta{language}|}{|\meta{file name without extension}|}|
|
|
%
|
|
% Afterwards the package inputs the given driver file to load the language.
|
|
%
|
|
% \item |\lst@LocateLanguage[|\meta{dialect}|]{|\meta{language}|}|
|
|
%
|
|
% returns the driver file name in |\lst@driver| and |\lst@requested| contains name of driver macro (i.e.\ with prefix |lstlang@|, without backslash).
|
|
% The macro automatically chooses aliases.
|
|
% \end{macrosyntax}
|
|
% All language and dialect arguments are standardized, i.e.\ we make them free of spaces and lower case.
|
|
%
|
|
% \begin{macro}{\lstalias}
|
|
% The names are stored in |\lsta@|\emph{language}|@|\emph{dialect} and |\lstaa@|\emph{language}.
|
|
% \begin{macrocode}
|
|
\newcommand\lstalias{\@ifnextchar[{\lstalias@}{\lstalias@@}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lstalias@[#1]#2[#3]#4{%
|
|
\def\lst@temp{lsta@#2@#1}\lst@Normalize\lst@temp %
|
|
\global\@namedef{\lst@temp}{#4@#3}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lstalias@@#1#2{%
|
|
\def\lst@temp{lstaa@#1}\lst@Normalize\lst@temp %
|
|
\global\@namedef{\lst@temp}{#2}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@DriverLocation}
|
|
% We simply define a macro containing the file name.
|
|
% \begin{macrocode}
|
|
\def\lst@DriverLocation#1#2{%
|
|
\def\lst@temp{lstloc@#1}\lst@Normalize\lst@temp %
|
|
\expandafter\gdef\csname\lst@temp\endcsname{#2}%
|
|
\expandafter\lst@Normalize\csname\lst@temp\endcsname}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@LocateLanguage}
|
|
% First we test for a language alias, \ldots
|
|
% \begin{macrocode}
|
|
\def\lst@LocateLanguage[#1]#2{%
|
|
\def\lst@language@{#2}\lst@Normalize\lst@language@ %
|
|
\@ifundefined{lstaa@\lst@language@}{}%
|
|
{\edef\lst@language@{\csname lstaa@\lst@language@\endcsname}%
|
|
\lst@Normalize\lst@language@}%
|
|
% \end{macrocode}
|
|
% then we set the default dialect if necessary.
|
|
% \begin{macrocode}
|
|
\def\lst@dialect@{#1}%
|
|
\ifx\@empty\lst@dialect@ %
|
|
\@ifundefined{lstdd@\lst@language@}{}%
|
|
{\expandafter\let\expandafter\lst@dialect@ %
|
|
\csname lstdd@\lst@language@\endcsname}%
|
|
\fi %
|
|
\lst@Normalize\lst@dialect@ %
|
|
% \end{macrocode}
|
|
% Now we are ready for an alias for a language dialect.
|
|
% \begin{macrocode}
|
|
\edef\lst@requested{\lst@language@ @\lst@dialect@}%
|
|
\@ifundefined{lsta@\lst@requested}{}%
|
|
{\expandafter\let\expandafter\lst@requested %
|
|
\csname lsta@\lst@requested\endcsname %
|
|
\lst@Normalize\lst@requested}%
|
|
% \end{macrocode}
|
|
% Finally we get the driver file name and set the default dialect.
|
|
% \begin{macrocode}
|
|
\expandafter\lst@LocateLanguage@\lst@requested\relax}
|
|
\def\lst@LocateLanguage@#1@#2\relax{%
|
|
\edef\lst@driver{\@ifundefined{lstloc@#1}{lst#1}%
|
|
{\csname lstloc@#1\endcsname}}%
|
|
\ifx\@empty#2\@empty %
|
|
\@ifundefined{lstdd@#1}%
|
|
{\def\lst@dialect@{#2}}%
|
|
{\expandafter\let\expandafter\lst@dialect@ %
|
|
\csname lstdd@#1\endcsname}%
|
|
\fi %
|
|
\edef\lst@requested{lstlang@#1@\lst@dialect@}%
|
|
\lst@Normalize\lst@requested}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{Typesetting a listing}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@lineno}
|
|
% This counter keeps the current line number.
|
|
% A register is global if and only if the allocation line shows |% \global|.
|
|
% \begin{macrocode}
|
|
\newcount\lst@lineno \global\lst@lineno\@ne % \global
|
|
% \end{macrocode}
|
|
% The counter is initialized and advances every line (which means |\everypar|).
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVars}
|
|
{\global\lst@lineno\@ne %
|
|
\expandafter\everypar\expandafter{\the\everypar %
|
|
\global\advance\lst@lineno\@ne}}
|
|
% \end{macrocode}
|
|
% And we (try to) ensure correct line numbers for continued listings.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{ExitVars}
|
|
{\ifx\lst@NewLine\relax\else %
|
|
\global\advance\lst@lineno-2\relax %
|
|
\setbox\@tempboxa\vbox{\lst@NewLine}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% We only try to.
|
|
% If there is source code before |\end{lstlisting}|, it goes wrong: the line number is one too less.
|
|
% \end{TODO}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@PrintFileName}
|
|
% makes use of |\lst@ReplaceIn|:
|
|
% \begin{macrocode}
|
|
\def\lst@PrintFileName#1{%
|
|
\def\lst@arg{#1}%
|
|
\lst@ReplaceIn\lst@arg{_\textunderscore $\textdollar -\textendash}%
|
|
\lst@arg}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@SetName}
|
|
% As proposed by \lsthelper{Boris Veytsman}{boris@plmsc.psu.edu}{1998/03/22}{listing name accessible for user} the name of a listing (file name or argument to the environment) is user accessible now.
|
|
% It is set using this macro:
|
|
% \begin{macrocode}
|
|
\def\lst@SetName#1{%
|
|
\gdef\lst@intname{#1}\global\let\lstintname\lst@intname %
|
|
\let\lst@arg\lst@intname %
|
|
\lst@ReplaceIn\lst@arg{_\textunderscore $\textdollar -\textendash}%
|
|
\global\let\lstname\lst@arg}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{List of listings}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\listoflistings}
|
|
% Instead of imitating |\listoffigures| we make some local adjustments and call |\tableofcontents|.
|
|
% This has the advantage that redefinitions (e.g.\ without any |\MakeUppercase| inside) also take effect on the list of listings.
|
|
% \begin{macrocode}
|
|
\newcommand\listoflistings{\bgroup %
|
|
\let\contentsname\listlistingsname %
|
|
\let\lst@temp\@starttoc \def\@starttoc##1{\lst@temp{lol}}%
|
|
\tableofcontents \egroup}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\listlistingsname}
|
|
% Simply the header name:
|
|
% \begin{macrocode}
|
|
\newcommand\listlistingsname{Listings}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@AddToLOL}
|
|
% adds an entry to the list of listings.
|
|
% The first parameter is the name of the listing and the second is unused so far.
|
|
% \begin{macrocode}
|
|
\newcommand\lst@AddToLOL[2]{%
|
|
\ifx\@empty#1\@empty \else %
|
|
\addtocontents{lol}{\protect\lstlolline{#1}{#2}%
|
|
{\lst@language}{\thepage}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstlolline}
|
|
% prints one 'lol' line.
|
|
% Using |\lst@PrintFileFile| removes a bug first reported by \lsthelper{Magne Rudshaug}{magne@ife.no}{1998/01/09}{_ and list of listings}.
|
|
% \begin{macrocode}
|
|
\newcommand\lstlolline[4]{%
|
|
\@dottedtocline{1}{1.5em}{2.3em}{\lst@PrintFileName{#1}}{#4}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Init and EOL}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% We need some macros to initialize registers and variables before typesetting a listing and for the update every line.
|
|
%
|
|
% \begin{macro}{\lst@Init}
|
|
% The argument |#1| (assigned at the end) is either |\relax| or |\lstenv@backslash| since the backslash has a special meaning for the environment.
|
|
% The line number is used as current label (proposed by \lsthelper{Boris Veytsman}{boris@plmsc.psu.edu}{1998/03/25}{make line numbers referenced via \label and \ref}).
|
|
% The end of line character chr(13)=|^^M| controls the processing, see the definition of |\lst@MProcessListing| below.
|
|
% The vertical space in the macro code is for clarity.
|
|
% \begin{macrocode}
|
|
\def\lst@Init#1{%
|
|
\begingroup \normalbaselines \smallbreak %
|
|
\def\@currentlabel{\the\lst@lineno}%
|
|
\lst@prelisting %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lsthk@BeforeSelectCharTable %
|
|
\normalbaselines \everypar{\lsthk@EveryLine}%
|
|
\lsthk@InitVars \lsthk@InitVarsEOL %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\csname lstPre@\lst@language\endcsname %
|
|
\csname lstPre@\lst@language @\lst@dialect\endcsname %
|
|
\lstCC@Let{"000D}\lst@MProcessListing %
|
|
\let\lstCC@Backslash#1%
|
|
\lst@EnterMode{\lst@Pmode}{\lst@SelectCharTable}}
|
|
% \end{macrocode}
|
|
% Note: From version 0.19 on 'listing processing' is implemented as an internal mode, namely a mode with special character table.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVars}
|
|
{\rightskip\z@ \leftskip\z@ \parfillskip=0pt plus 1fil %
|
|
\let\par\@@par}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@DeInit}
|
|
% Here we output the remaining characters, update some variables and do some other things.
|
|
% \begin{macrocode}
|
|
\def\lst@DeInit{%
|
|
\lst@PrintToken \lst@EOLUpdate \par\removelastskip %
|
|
\lsthk@ExitVars %
|
|
\smallbreak\lst@postlisting %
|
|
\endgroup}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@EOLUpdate}
|
|
% This macro seems to be obsolete since in version 0.19 it degenerates to
|
|
% \begin{macrocode}
|
|
\def\lst@EOLUpdate{\lsthk@EOL \lsthk@InitVarsEOL}%
|
|
% \end{macrocode}
|
|
% But in future it might come in handy again.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@MProcessListing}
|
|
% This is what we have to do at EOL while processing a listing.
|
|
% We output all remaining characters and update the variables.
|
|
% We call |\endinput| if the next line number is greater than the last printing line.
|
|
% Finally we gobble characters to come to beginning of line.
|
|
% \begin{macrocode}
|
|
\def\lst@MProcessListing{%
|
|
\lst@PrintToken \lst@EOLUpdate %
|
|
\ifnum\lst@lastline<\lst@lineno \expandafter\endinput \fi %
|
|
\lst@BOLGobble}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@BOLGobble}
|
|
% But this is initially |\relax|.
|
|
% \begin{macrocode}
|
|
\let\lst@BOLGobble\relax
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{The input command}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{TODO}
|
|
% There is a conflict concerning |\lst@firstline|: It contains either the line number of the first code line or line number.
|
|
% This must be clarified before |lstlisting| can use the keys |first| and |last|.
|
|
% \end{TODO}
|
|
%
|
|
% \begin{aspect}{print}
|
|
% \begin{aspect}{first}
|
|
% \begin{aspect}{last}
|
|
% These aspects affect the input command only, not the environment.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{print}[t]{\lstKV@SetIfKey\lst@ifprint{#1}}
|
|
\lst@Aspect{first}{\def\lst@firstline{#1}}
|
|
\lst@Aspect{last}{\def\lst@lastline{#1}}
|
|
\lstset{print=true}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lstinputlisting}
|
|
% We define the main command.
|
|
% First we take care of the optional paramater and set it to $[1,9999999]$ if none is given.
|
|
% \begin{macrocode}
|
|
\newcommand\lstinputlisting[2][]{%
|
|
\begingroup %
|
|
\def\lst@firstline{1}\def\lst@lastline{9999999}\lstset{#1}%
|
|
\IfFileExists{#2}{\lst@InputListing{#2}}%
|
|
{\filename@parse{#2}%
|
|
\edef\reserved@a{\noexpand\lst@MissingFileError
|
|
{\filename@area\filename@base}%
|
|
{\ifx\filename@ext\relax tex\else\filename@ext\fi}}%
|
|
\reserved@a}%
|
|
\endgroup %
|
|
\lsthk@OnExit}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@MissingFileError}
|
|
% is a derivation of \LaTeX's |\@missingfileerror|:
|
|
% \begin{macrocode}
|
|
\def\lst@MissingFileError#1#2{%
|
|
\typeout{^^J! Package Listings Error: File `#1.#2' not found.^^J^^J%
|
|
Type X to quit or <RETURN> to proceed,^^J%
|
|
or enter new name. (Default extension: #2)^^J}%
|
|
\message{Enter file name: }%
|
|
{\endlinechar\m@ne \global\read\m@ne to\@gtempa}%
|
|
% \end{macrocode}
|
|
% Typing |x| or |X| exits.
|
|
% \begin{macrocode}
|
|
\ifx\@gtempa\@empty \else %
|
|
\def\reserved@a{x}\ifx\reserved@a\@gtempa\batchmode\@@end\fi
|
|
\def\reserved@a{X}\ifx\reserved@a\@gtempa\batchmode\@@end\fi
|
|
% \end{macrocode}
|
|
% In all other cases we try the new file name (with default extension).
|
|
% \begin{macrocode}
|
|
\filename@parse\@gtempa %
|
|
\edef\filename@ext{%
|
|
\ifx\filename@ext\relax#2\else\filename@ext\fi}%
|
|
\edef\reserved@a{\noexpand\IfFileExists %
|
|
{\filename@area\filename@base.\filename@ext}%
|
|
{\noexpand\lst@InputListing %
|
|
{\filename@area\filename@base.\filename@ext}}%
|
|
{\noexpand\lst@MissingFileError
|
|
{\filename@area\filename@base}{\filename@ext}}}%
|
|
\expandafter\reserved@a %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@InputListing}
|
|
% The one and only argument is the file name.
|
|
% We either add this name to the list of listings or the name plus a bullet to indicate that the listing has been skipped.
|
|
% Note that |\lst@Init| takes |\relax| as an argument.
|
|
% \begin{macrocode}
|
|
\def\lst@InputListing#1{%
|
|
\lst@SetName{#1}%
|
|
\lst@ifprint %
|
|
\lst@AddToLOL{#1}{}%
|
|
\lst@Init\relax \lst@SkipUptoFirst \input{#1}\lst@DeInit %
|
|
\else %
|
|
\lst@AddToLOL{#1$^\bullet$}{}%
|
|
\begin{center}%
|
|
\footnotesize --- Listing of #1 has been skipped. ---
|
|
\end{center}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@SkipUptoFirst}
|
|
% The end of line character either processes the listing or is responsible for skipping lines upto first printing line.
|
|
% \begin{macrocode}
|
|
\def\lst@SkipUptoFirst{%
|
|
\ifnum\lst@lineno=\lst@firstline\else %
|
|
% \end{macrocode}
|
|
% To skip input lines we begin a new group level (which makes our changes local) and prohibit mode changes.
|
|
% We redefine the end of line character and all output macros becomes equivalent to |\relax|, i.e.\ nothing is typeset.
|
|
% \begin{macrocode}
|
|
\bgroup \lst@modetrue %
|
|
\let\lst@Output\relax \let\lst@OutputOther\relax %
|
|
\let\lst@GotoTabStop\relax %
|
|
\lstCC@Let{"000D}\lst@MSkipUptoFirst %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@MSkipUptoFirst}
|
|
% At the moment we use a fast and not 'everything is looking good' way.
|
|
% When |\lst@MSkipUptoFirst| is executed, one input line has already been skipped.
|
|
% We end the group opened in |\lst@SkipUptoFirst|.
|
|
% This restores the definition of the end of line character chr(13).
|
|
% Then we look whether to skip more lines or not.
|
|
% \begin{macrocode}
|
|
\def\lst@MSkipUptoFirst{\egroup %
|
|
\global\advance\lst@lineno\@ne %
|
|
\ifnum\lst@lineno=\lst@firstline\else %
|
|
\expandafter\lst@MSkipUptoFirst@ %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% The argument of |\lst@MSkipUptoFirst@| ends with the next active chr(13), which means that the next input line is read.
|
|
% Again we look whether to skip more lines or not.
|
|
% \begin{macrocode}
|
|
\begingroup \lccode`\~=`\^^M%
|
|
\lowercase{\gdef\lst@MSkipUptoFirst@#1~}{%
|
|
\global\advance\lst@lineno\@ne %
|
|
\ifnum\lst@lineno=\lst@firstline\else %
|
|
\expandafter\lst@MSkipUptoFirst@ %
|
|
\fi}
|
|
\endgroup
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% This definition gives rise to a ''runaway argument'' if first line doesn't exist (no |^^M| is found).
|
|
%
|
|
% We could define |\lst@MSkipUptoFirst| exactly as |\lst@MProcessListing|, except that we start the normal line processing if we reach the first printing line.
|
|
% In that case all comments and strings are processed, but not output.
|
|
% Everything looks good, even if the first printing line is in the middle of a comment.
|
|
% We need to do the following things:
|
|
% \begin{enumerate}
|
|
% \item Install an \texttt{if} to choose between speed and good looking, which must be noticed in |\lst@SkipUptoFirst|.
|
|
% There we must (locally) switch to |\lsttexcloff|.
|
|
% \item Call |\lst@BeginDropOutput{\lst@nomode}| in |\lst@SkipUptoFirst| instead of |\bgroup\lst@modetrue| and assigning |\relax|es.
|
|
% \item Define |\lst@MSkipUptoFirstExact| by copying |\lst@MProcessListing| and renaming it.
|
|
% Replace the |\ifnum| by\vspace*{-0.5\baselineskip}
|
|
% \begin{verbatim}
|
|
%\ifnum\lst@lineno=lst@firstline %
|
|
% \lst@LeaveMode \global\lst@column\z@ \global\lst@pos\z@ %
|
|
%\fi\end{verbatim}
|
|
% \item Make the fine tuning if necessary.
|
|
% \end{enumerate}
|
|
% \end{TODO}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{The environment}\label{iTheEnvironment}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@Environment}
|
|
% This is the first attempt to provide a general macro, which defines the \lst-environments.
|
|
% The syntax comes from \LaTeX's |\newenvironment|:
|
|
% \begin{macrosyntax}
|
|
% \item |\lst@Environment{|\meta{name}|}[|\meta{number of parameters}|][|\meta{opt.~default~arg.}|]\is|\\
|
|
% |{|\meta{begin code}|}|\\
|
|
% |{|\meta{end code}|}|
|
|
% \end{macrosyntax}
|
|
% Note the additional |\is|.
|
|
% I should mention that such environments could also be used in command fashion
|
|
% \begin{verbatim}
|
|
% \lstlisting{my name}
|
|
% Here comes the listing.
|
|
% \endlstlisting\end{verbatim}
|
|
% But now the implementation.
|
|
% We define undefined environments only:
|
|
% \begin{macrocode}
|
|
\def\lst@Environment#1#2\is#3#4{%
|
|
\@ifundefined{#1}{\lst@Environment@{#1}{#2}{#3}{#4}}%
|
|
{%
|
|
%<info> \lst@InfoWarning{Multiple environment `#1'}%
|
|
}}
|
|
% \end{macrocode}
|
|
% A lonely 'end environment' produces an error:
|
|
% \begin{macrocode}
|
|
\def\lst@Environment@#1#2#3#4{%
|
|
\global\@namedef{end#1}{\lstenv@Error{#1}}%
|
|
% \end{macrocode}
|
|
% The 'main' environment macro defines the environment name (for later use) and calls a submacro (getting all arguments).
|
|
% We open a group and redefine the (active) EOL character to be |\relax|.
|
|
% This ensures |\@ifnextchar[| not to read characters of the listing --- it reads the active EOL instead.
|
|
% \begin{macrocode}
|
|
\global\@namedef{#1}{%
|
|
\def\lstenv@name{#1}%
|
|
\begingroup \lstCC@Let{"000D}\relax %
|
|
\csname#1@\endcsname}%
|
|
% \end{macrocode}
|
|
% The submacro is defined via |\new@command|.
|
|
% We misuse |\l@ngrel@x| to make the definition |\global|.
|
|
% The submacro defines the first and last line, which are possibly changed by the user's \meta{begin code} |#3|.
|
|
% \begin{macrocode}
|
|
\let\l@ngrel@x\global %
|
|
\expandafter\new@command\csname#1@\endcsname#2%
|
|
{\def\lst@firstline{1}\def\lst@lastline{9999999}%
|
|
#3%
|
|
% \end{macrocode}
|
|
% The definition of the string which terminates the environment (|end{lstlisting}| or |endlstlisting|, for example) needs some care since the braces must not have catcodes 1 and 2 (or |\lst@MakeActive| fails).
|
|
% We enter them as |\{| and |\}| (with preceding |\noexpand|s).
|
|
% \begin{macrocode}
|
|
\ifx\@currenvir\lstenv@name %
|
|
\edef\lst@temp{end\noexpand\{\lstenv@name\noexpand\}}%
|
|
\else %
|
|
\edef\lst@temp{end\lstenv@name}%
|
|
\fi %
|
|
\expandafter\lst@MakeActive\expandafter{\lst@temp}%
|
|
\let\lstenv@endstring\lst@arg %
|
|
% \end{macrocode}
|
|
% We redefine (locally) 'end environment' inside the 'begin environment' macro since ending is legal now.
|
|
% Note that the redefinition also works inside a \TeX\ comment line.
|
|
% \begin{macrocode}
|
|
\@namedef{end#1}{\lst@DeInit #4\endgroup \lsthk@OnExit}%
|
|
% \end{macrocode}
|
|
% Finally the 'begin environment' macro starts the processing.
|
|
% \begin{macrocode}
|
|
\lstenv@Process}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@Error}
|
|
% have been used above.
|
|
% \begin{macrocode}
|
|
\def\lstenv@Error#1{\PackageError{Listings}{Extra \string\end#1}%
|
|
{I'm ignoring this, since I wasn't doing a \csname#1\endcsname.}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@backslash}
|
|
% We have the problem of finding end of environment, and we've already defined the 'end environment' string.
|
|
% Coming to a backslash we either end the listing or process a backslash and insert the eaten characters again.
|
|
% (Eaten means that these characters have been read (and removed) from the input to test for |\lstenv@endstring|.)
|
|
% \begin{macrocode}
|
|
\def\lstenv@backslash{%
|
|
\lst@IfNextChars\lstenv@endstring %
|
|
{\lstenv@End}%
|
|
{\lsts@backslash \lst@eaten}}%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@End}
|
|
% This macro is called by the backslash macro and terminates a listing environment:
|
|
% We call the 'end environment' macro as a command or using |\end|.
|
|
% \begin{macrocode}
|
|
\def\lstenv@End{%
|
|
\ifx\@currenvir\lstenv@name %
|
|
\edef\lst@next{\noexpand\end{\lstenv@name}}%
|
|
\else %
|
|
\def\lst@next{\csname end\lstenv@name\endcsname}%
|
|
\fi %
|
|
\lst@next}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@Process}
|
|
% First some initialization, then call a submacro.
|
|
% \begin{macrocode}
|
|
\def\lstenv@Process{%
|
|
\lst@Init\lstenv@backslash %
|
|
\global\lst@lineno\lst@firstline\relax %
|
|
\let\lstenv@ifdropped\iffalse \lstenv@Process@}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lstenv@droppedtrue{\let\lstenv@ifdropped\iftrue}
|
|
% \end{macrocode}
|
|
% We execute either |\lstenv@ProcessM| or |\lstenv@ProcessJ| according to whether we find an active EOL or a nonactive |^^J|.
|
|
% \begin{macrocode}
|
|
\begingroup \lccode`\~=`\^^M%
|
|
\lowercase{\gdef\lstenv@Process@#1{%
|
|
\ifx~#1%
|
|
\expandafter\lstenv@ProcessM %
|
|
\else\ifx^^J#1%
|
|
\expandafter\expandafter\expandafter\lstenv@ProcessJ %
|
|
\else %
|
|
\lstenv@droppedtrue %
|
|
\expandafter\expandafter\expandafter\lstenv@Process@ %
|
|
\fi \fi}
|
|
}\endgroup
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@DroppedWarning}
|
|
% gives a warning if characters have been dropped.
|
|
% \begin{macrocode}
|
|
\def\lstenv@DroppedWarning{%
|
|
\lstenv@ifdropped %
|
|
\PackageWarning{Listings}{Text dropped after begin of listing}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@ProcessM}
|
|
% There is nothing to do if we've found an active EOL, except giving a warning if necessary.
|
|
% \begin{macrocode}
|
|
\def\lstenv@ProcessM{\lstenv@DroppedWarning \lst@BOLGobble}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@ProcessJ}
|
|
% Now comes the horrible scenario: A listing inside an argument.
|
|
% We've already worked in section \ref{iAnApplicationTo} for this.
|
|
% Here we must get the listing, i.e.\ all characters upto 'end environment'.
|
|
% We must distinguish the cases 'command fashion' and 'environment'.
|
|
% \begin{macrocode}
|
|
\def\lstenv@ProcessJ{%
|
|
\lstenv@DroppedWarning %
|
|
\lst@DontEscapeToLaTeX %
|
|
\let\lstenv@arg\@empty %
|
|
\ifx\@currenvir\lstenv@name %
|
|
\expandafter\lstenv@ProcessJEnv %
|
|
\else %
|
|
% \end{macrocode}
|
|
% The first case is pretty simple: The code is terminated by |\end|\meta{name of environment}.
|
|
% Thus we expand that control sequence before defining a temporary macro, which gets all characters upto that control sequence.
|
|
% Inside the temporary macro we assign the argument and call a submacro doing the rest.
|
|
% \begin{macrocode}
|
|
\expandafter\def\expandafter\lst@temp\expandafter##1%
|
|
\csname end\lstenv@name\endcsname{%
|
|
\lstenv@AddArg{##1}\lstenv@ProcessJ@}%
|
|
% \end{macrocode}
|
|
% Back to the definition of |\lstenv@ProcessJ| we call the temporary macro.
|
|
% \begin{macrocode}
|
|
\expandafter\lst@temp %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% We must append an active backslash and the 'end string' to |\lstenv@arg|.
|
|
% So all other processing won't notice that the code has been inside an argument.
|
|
% But the EOL character is chr(10)=|^^J| now and not chr(13).
|
|
% Finally we execute |\lstenv@arg| to typeset the listing.
|
|
% Note that we need |\lccode`\A=`\A| to preserve the argument of |\lstCC@Let| --- but obviously we could also write |\lstCC@Let{10}|\ldots
|
|
% \begin{macrocode}
|
|
\begingroup \lccode`\~=`\\ \lccode`\A=`\A
|
|
\lowercase{\gdef\lstenv@ProcessJ@{%
|
|
\expandafter\lst@lAddTo\expandafter\lstenv@arg %
|
|
\expandafter{\expandafter\ \expandafter~\lstenv@endstring}%
|
|
\lstCC@Let{"000A}\lst@MProcessListing \def\lst@BOLGobble##1{}%
|
|
\expandafter\lst@BOLGobble\lstenv@arg}
|
|
}\endgroup
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstenv@ProcessJEnv}
|
|
% Here we get all characters upto an |\end| (and the following argument).
|
|
% If the following argument equals |\lstenv@name|, we have found the end of environment and start typesetting.
|
|
% \begin{macrocode}
|
|
\def\lstenv@ProcessJEnv#1\end#2{\def\lst@temp{#2}%
|
|
\ifx\lstenv@name\lst@temp %
|
|
\lstenv@AddArg{#1}%
|
|
\expandafter\lstenv@ProcessJ@ %
|
|
\else %
|
|
% \end{macrocode}
|
|
% Otherwise we append the characters including the eaten |\end| and the eaten argument to current |\lstenv@arg|.
|
|
% And we look again for the end of environment.
|
|
% \begin{macrocode}
|
|
\lstenv@AddArg{#1\\end\{#2\}}%
|
|
\expandafter\lstenv@ProcessJEnv %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{environment}{lstlisting}
|
|
% The awkward work is done, here we deal with continued line numbering.
|
|
% \lsthelper{Boris Veytsman}{boris@plmsc.psu.edu}{1998/03/25}{continue line numbering: a.c b.c a.c} proposed to continue line numbers according to listing names.
|
|
% Thus we must save the name and either make a LOL item or define the first line number.
|
|
% Note that the macro |\lstno@| will be undefined or equivalent to |\relax|, so we always start with line number 1 in case of an empty name.
|
|
% Moreover we first test if the user has forgotten the name argument.
|
|
% \begin{macrocode}
|
|
\lst@Environment{lstlisting}[2][]\is
|
|
{\lstenv@TestEOLChar{#2}%
|
|
\expandafter\ifx\csname lstno@\lst@intname\endcsname \relax %
|
|
\ifx\lst@intname\@empty\else \lst@AddToLOL{#2}{}\fi %
|
|
\else %
|
|
\edef\lst@firstline{\csname lstno@\lst@intname\endcsname}%
|
|
\let\lst@prelisting\lst@@prelisting %
|
|
\let\lst@postlisting\lst@@postlisting %
|
|
\fi %
|
|
\lstset{#1}}
|
|
% \end{macrocode}
|
|
% At the end of environment we simply save the current line number.
|
|
% If the listing name is empty, we use a space instead of the name.
|
|
% This leaves the macro |\lstno@| undefined.
|
|
% \begin{macrocode}
|
|
{\ifx\lst@intname\@empty %
|
|
\expandafter\xdef\csname lstno@ \endcsname{\the\lst@lineno}%
|
|
\else %
|
|
\expandafter\xdef\csname lstno@\lst@intname\endcsname %
|
|
{\the\lst@lineno}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{environment}
|
|
%
|
|
% \begin{macro}{\lstenv@TestEOLChar}
|
|
% \begin{macro}{\lstenv@EOLCharError}
|
|
% Here we test for the two possible EOL characters.
|
|
% \begin{macrocode}
|
|
\begingroup \lccode`\~=`\^^M\lowercase{%
|
|
\gdef\lstenv@TestEOLChar#1{%
|
|
\lst@SetName{}%
|
|
\ifx~#1\lstenv@EOLCharError \else %
|
|
\ifx^^J#1\lstenv@EOLCharError \else %
|
|
\lst@SetName{#1}%
|
|
\fi %
|
|
\fi}
|
|
}\endgroup
|
|
% \end{macrocode}
|
|
% A simple error message.
|
|
% \begin{macrocode}
|
|
\def\lstenv@EOLCharError{%
|
|
\PackageError{Listings}
|
|
{Oops! It seems you've forgotten the argument to\MessageBreak %
|
|
a listing environment. Assuming empty argument}%
|
|
{Type <RETURN> to proceed.}}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{aspect}{advancelineno}
|
|
% \begin{aspect}{resetlineno}
|
|
% The last two aspects in this section simply advance/reset the first line.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{advancelineno}
|
|
{\global\lst@lineno\lst@firstline\relax %
|
|
\global\advance\lst@lineno#1\relax %
|
|
\edef\lst@firstline{\the\lst@lineno}}
|
|
\lst@Aspect{resetlineno}[1]{\def\lst@firstline{#1}}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Inline listings}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lstinline}
|
|
% We redefine some macros here since they are possibly not save inside |\hbox|.
|
|
% Furthermore we use flexible columns and suppress \TeX\ comment lines.
|
|
% After doing initialization we redefine |\everypar| and the new line macro.
|
|
% We don't want them.
|
|
% \begin{macrocode}
|
|
\def\lstinline{\hbox\bgroup %
|
|
\let\smallbreak\relax %
|
|
\let\lst@prelisting\relax \let\lst@postlisting\relax %
|
|
\let\lst@ifflexible\iftrue \lst@DontEscapeToLaTeX %
|
|
\def\lst@firstline{1}\def\lst@lastline{1}%
|
|
\lst@Init\relax \everypar{}\global\let\lst@NewLine\relax %
|
|
\lst@IfNextCharActive\lst@InlineM\lst@InlineJ}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@InlineM}
|
|
% \begin{macro}{\lst@InlineJ}
|
|
% treat the cases of 'normal' inlines and inline listings inside an argument.
|
|
% In the first case the given character ends the inline listing and EOL (within such a listing) immediately ends it and produces an error message.
|
|
% \begin{macrocode}
|
|
\def\lst@InlineM#1{%
|
|
\lstCC@Def{`#1}{\lst@DeInit\egroup}%
|
|
\lstCC@Def{"000D}{\lst@DeInit\egroup %
|
|
\PackageError{Listings}{lstinline ended by EOL}\@ehc}}
|
|
% \end{macrocode}
|
|
% In the other case we get all characters upto |#1| (via temporary macro), make these characters active, execute (typeset) them and end the listing.
|
|
% That's all about it.
|
|
% \begin{macrocode}
|
|
\def\lst@InlineJ#1{%
|
|
\def\lst@temp##1#1{%
|
|
\let\lstenv@arg\@empty \lstenv@AddArg{##1}%
|
|
\lstenv@arg \lst@DeInit\egroup}%
|
|
\lst@temp}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{The box command}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lstbox}
|
|
% The macro opens the |\hbox| right at the beginning and indicate its usage.
|
|
% Then we adjust some \lst-parameters:
|
|
% We switch to |\lstlistingtrue| since the command is intend to be used with small listings only;
|
|
% |\smallbreak|s preceding and following each listing are removed by redefining |\smallbreak|.
|
|
% \begin{macrocode}
|
|
\newcommand\lstbox{%
|
|
\hbox\bgroup %
|
|
\let\lst@ifbox\iftrue %
|
|
\let\smallbreak\relax %
|
|
\let\lst@prelisting\relax \let\lst@postlisting\relax %
|
|
\let\lst@@prelisting\relax\let\lst@@postlisting\relax %
|
|
\lst@outerspread\z@ \lst@innerspread\z@ %
|
|
\@ifnextchar[{\lstbox@}{\lstbox@[c]}}
|
|
% \end{macrocode}
|
|
% Here we have to choose the right box --- in fact |\vcenter| isn't a box.
|
|
% \begin{macrocode}
|
|
\def\lstbox@[#1]{%
|
|
\hbox to\z@\bgroup %
|
|
$\if#1t\vtop \else \if#1b\vbox \else \vcenter \fi\fi %
|
|
\bgroup}%
|
|
% \end{macrocode}
|
|
% We need to
|
|
% \begin{macrocode}
|
|
\let\lst@ifbox\iffalse
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@EndBox}
|
|
% And the counterpart: We have to close some groups (and use |\hss| inside the |\hbox| to $0$pt).
|
|
% The outer |\hbox| gets its correct width using a |\vrule|.
|
|
% \begin{macrocode}
|
|
\def\lst@EndBox{%
|
|
\egroup $\hss \egroup %
|
|
\vrule width\lst@maxwidth height\z@ depth\z@ %
|
|
\egroup}
|
|
% \end{macrocode}
|
|
% But that macro is called (if and) only if we've begun a |\lstbox| before.
|
|
% Note that we are possibly inside a \lst-environment here, so we have to execute |\lst@EndBox| either now or after closing the environment group.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{OnExit}
|
|
{\lst@ifbox %
|
|
\global\advance\lst@maxwidth-\lst@innerspread %
|
|
\global\advance\lst@maxwidth-\lst@outerspread %
|
|
\ifx\@currenvir\lstenv@name %
|
|
\expandafter\expandafter\expandafter\aftergroup %
|
|
\fi %
|
|
\expandafter\lst@EndBox %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@maxwidth}
|
|
% is to be allocated:
|
|
% \begin{macrocode}
|
|
\newdimen\lst@maxwidth % \global
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVars}{\global\lst@maxwidth\z@}
|
|
% \end{macrocode}
|
|
% Determine width of just printed line and update |\lst@maxwidth|.
|
|
% Here we assume that all characters of the line have been output.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVarsEOL}
|
|
{\@tempdima \lst@column\lst@width %
|
|
\advance\@tempdima -\lst@pos\lst@width %
|
|
\ifdim\lst@lostspace<\z@ \advance\@tempdima -\lst@lostspace \fi %
|
|
\ifdim\@tempdima>\lst@maxwidth \global\lst@maxwidth\@tempdima \fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{First \lst-aspects and related macros}
|
|
%
|
|
% In fact we've already defined some aspects, e.g.\ |language| and |style|.
|
|
%
|
|
%
|
|
% \subsection{Keywords}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{TODO}
|
|
% The internal keyword managing should be reorganised, so that is also handles the special characters $<,>,\vert,\sim$.
|
|
% \end{TODO}
|
|
% We have to decide whether or not a given character sequence is a reserved word.
|
|
% For example, if the character sequence is |key|, we define a macro
|
|
% \begin{verbatim}
|
|
% \def\lst@temp#1,key,#2\relax{...}\end{verbatim}
|
|
% Afterwards we call the macro with the following arguments:
|
|
% \begin{itemize}
|
|
% \item[] |,|all current keywords|,key,\relax|
|
|
% \end{itemize}
|
|
% The additional |,key,\relax| holds up the syntax of |\lst@temp|.
|
|
% When \TeX{} passes the arguments, the second is empty if and only if |key| is not a current keyword.
|
|
% So we know whether or not to select keyword style.
|
|
%
|
|
% Since \TeX{} always passes two arguments to |\lst@temp|, the whole 'input' |\lst@keywords,#1,\relax| is split in two parts.
|
|
% So there is no need to sort the keywords by probability.
|
|
% Alternatively you could do so and make a loop for the keyword tests, which terminates right after finding a keyword.
|
|
% You might think and guess that's faster than the \TeX{}nique used here.
|
|
% If your source code uses the three or four most common keywords only, you are right.
|
|
% In fact the very first versions 0.1 and 0.11 have used something like loops (even something faster), which in general is slower than this here.
|
|
% \begin{TODO}
|
|
% There exists a faster way.
|
|
% For each keyword we make |\lstk@|\emph{the keyword} equivalent to keyword style.
|
|
% |\csname lstk@|\emph{test word}|\endcsname| expands to |\relax| if the control sequence is undefined and to keyword style otherwise.
|
|
% That's the complete keyword test!
|
|
% It works very well, but needs more of \TeX{}'s memory.
|
|
% Therefore we should define also 'memory saving' and/or 'speeding up' option.
|
|
%
|
|
% Note: A keyword or character string in this state might contain |\lst@underscore| and |\lst@minus| (and possibly more macro names), which will expand inside |\csname|\ldots|\endcsname|.
|
|
% Hence the definition of |\lstk@|\emph{the keyword} needs some care.
|
|
% An easy trick: During keyword definition and keyword testing the macros should expand to |_| and |-|, respectively.
|
|
% But the reassignments of |_|, |-|, \ldots\ also need time, so the implemented way is possibly faster \ldots
|
|
% \end{TODO}
|
|
%
|
|
% \begin{macro}{\lst@SetStyleFor}
|
|
% |\relax| terminates the argument here since it is faster than enclosing it in braces.
|
|
% All the rest should be clear from the discussion above.
|
|
% \begin{macrocode}
|
|
\def\lst@SetStyleFor#1\relax{%
|
|
\def\lst@temp##1,#1,##2\relax{%
|
|
\ifx\@empty##2\@empty \let\lst@thestyle\lst@nonkeywordstyle %
|
|
\else \let\lst@thestyle\lst@keywordstyle\fi}%
|
|
\expandafter\lst@temp\expandafter,\lst@keywords,#1,\relax}%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@SetStyleForNonSensitive}
|
|
% We implement a case insensitive version.
|
|
% Use of two |\uppercase|s normalize the argument.
|
|
% \begin{macrocode}
|
|
\def\lst@SetStyleForNonSensitive#1\relax{%
|
|
\uppercase{\def\lst@temp##1,#1},##2\relax{%
|
|
\ifx\@empty##2\@empty \let\lst@thestyle\lst@nonkeywordstyle %
|
|
\else \let\lst@thestyle\lst@keywordstyle\fi}%
|
|
\uppercase{%
|
|
\expandafter\lst@temp\expandafter,\lst@keywords,#1},\relax}%
|
|
% \end{macrocode}
|
|
% Note: This macro and the coming |\lst@IfOneOfNonSensitive| both assume that the keywords in |\lst@keywords| are already upper case!
|
|
% \end{macro}
|
|
%
|
|
% The code above must be activated, of course:
|
|
% We detect keywords if and only if we haven't entered a special mode (comment, string, etc.).
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{Output}
|
|
{\lst@ifmode %
|
|
\let\lst@thestyle\relax %
|
|
\else %
|
|
\expandafter\lst@SetStyleFor\the\lst@token\relax %
|
|
\fi}
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macro}{\lst@IfOneOf}
|
|
% \begin{macro}{\lst@IfOneOfNonSensitive}
|
|
% These macros are very familiar with the keyword tests.
|
|
% Roughly speaking the fixed |\lst@keywords| is replaced by an arbitrary macro.
|
|
% The first argument has the same meaning and is terminated by |\relax|, whereas the second must be a macro name.
|
|
% If and only if that macro (= keyword list) contains the first argument, the third parameter is executed (and the fourth otherwise).
|
|
% \begin{macrocode}
|
|
\def\lst@IfOneOf#1\relax#2{%
|
|
\def\lst@temp##1,#1,##2\relax{%
|
|
\ifx \@empty##2\@empty \expandafter\@secondoftwo %
|
|
\else \expandafter\@firstoftwo \fi}%
|
|
\expandafter\lst@temp\expandafter,#2,#1,\relax}%
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@IfOneOfNonSensitive#1\relax#2{%
|
|
\uppercase{\def\lst@temp##1,#1},##2\relax{%
|
|
\ifx \@empty##2\@empty \expandafter\@secondoftwo %
|
|
\else \expandafter\@firstoftwo \fi}%
|
|
\uppercase\expandafter{%
|
|
\expandafter\lst@temp\expandafter,#2,#1},\relax}%
|
|
% \end{macrocode}
|
|
% Instead of |\lst@SetStyleFor key\relax|, we could also write
|
|
% \begin{verbatim}
|
|
% \lst@IfOneOf key\relax \lst@keywords %
|
|
% {\let\lst@thestyle\lst@keywordstyle}
|
|
% {\let\lst@thestyle\lst@nonkeywordstyle}\end{verbatim}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lststorekeywords}
|
|
% Note that this command stores the keywords globally.
|
|
% \begin{macrocode}
|
|
\newcommand\lststorekeywords[2]{\gdef#1{#2}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{sensitive}
|
|
% Announcement and init:
|
|
% \begin{macrocode}
|
|
\lst@Aspect{sensitive}[t]{\lstKV@SetIfKey\lst@ifsensitive{#1}}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@ifsentitive\iftrue}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \noindent
|
|
% Now we consider the aspects getting keywords from the user.
|
|
% They work up the keywords a little bit, namely using |\lst@Make|\ldots|KeywordArg|.
|
|
%
|
|
% \begin{aspect}{keywords}
|
|
% \lsthelper{Ralf Quast}{rquast@hs.uni-hamburg.de}{1998/01/08}{name \keywords incompatible with AMS classes} reported a naming conflict with AMS classes.
|
|
% Usage of \textsf{keyval} package removes it.
|
|
% The easy definition:
|
|
% \begin{macrocode}
|
|
\lst@Aspect{keywords}
|
|
{\lst@MakeSpecKeywordArg{#1}\let\lst@keywords\lst@arg}
|
|
% \end{macrocode}
|
|
% We have to delete all current keywords before selecting a new language --- otherwise keywords from the previous language would be present if the user specifies no keywords.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@keywords\@empty}
|
|
% \end{macrocode}
|
|
% If the user wants case insensitive keywords, she'll get it:
|
|
% We assign the correct test macros and make all keywords upper case.
|
|
% Note that these changes are local.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@ifsensitive\else %
|
|
\let\lst@SetStyleFor\lst@SetStyleForNonSensitive %
|
|
\let\lst@IfOneOf\lst@IfOneOfNonSensitive %
|
|
\lst@MakeMacroUppercase\lst@keywords %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@MakeMacroUppercase}
|
|
% This macro makes the contents of a given macro (if present) upper case.
|
|
% \begin{macrocode}
|
|
\def\lst@MakeMacroUppercase#1{%
|
|
\ifx#1\@undefined\else \uppercase\expandafter{%
|
|
\expandafter\def\expandafter#1\expandafter{#1}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{morekeywords}
|
|
% Add keywords or append control sequence with argument:
|
|
% \begin{macrocode}
|
|
\lst@Aspect{morekeywords}
|
|
{\lst@MakeMoreSpecKeywordArg{,#1}%
|
|
\expandafter\lst@lAddTo\expandafter\lst@keywords %
|
|
\expandafter{\lst@arg}}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{aspect}{deletekeywords}
|
|
% The 'submacro' |\lst@DeleteKeysIn| has been defined in section \ref{iReplacingCharacters}.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{deletekeywords}
|
|
{\lst@MakeKeywordArg{#1}%
|
|
\lst@DeleteKeysIn\lst@keywords\lst@arg}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@MakeKeywordArg}
|
|
% \begin{macro}{\lst@MakeSpecKeywordArg}
|
|
% \begin{macro}{\lst@MakeMoreSpecKeywordArg}
|
|
% The keyword commands don't save their parameters as they are.
|
|
% All spaces are removed and underscores, dollars and minuses are replaced by |\lst@underscore|, |\lst@dollar| and |\lst@minus|.
|
|
% The first thing prepares keyword tests and the second the output.
|
|
% The macro |\lst@arg| holds the parameter free of spaces, underscores and minuses.
|
|
% Use of |\zap@space| was proposed by \lsthelper{Rolf Niepraschk}{NIEPRASCHK@PTB.DE}{1997/04/24}{use \zap@space}.
|
|
% \begin{macrocode}
|
|
\def\lst@MakeKeywordArg#1{\edef\lst@arg{\zap@space#1 \@empty}%
|
|
\lst@ReplaceIn\lst@arg{_\lst@underscore $\lst@dollar -\lst@minus}}
|
|
% \end{macrocode}
|
|
% The following two macros also scan for special characters like \#, $<$ and $>$.
|
|
% \begin{macrocode}
|
|
\def\lst@MakeSpecKeywordArg{%
|
|
\let\lst@ialsodigit\@empty \let\lst@ialsoletter\@empty %
|
|
\lst@MakeMoreSpecKeywordArg}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@MakeMoreSpecKeywordArg#1{\edef\lst@arg{\zap@space#1 \@empty}%
|
|
\lstCC@lettertrue %
|
|
\expandafter\lst@SpecialKeywordScan\lst@arg\relax %
|
|
\lst@ReplaceIn\lst@arg{_\lst@underscore $\lst@dollar -\lst@minus}}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@SpecialKeywordScan}
|
|
% How does this scan work?
|
|
% Whenever we encounter a non-letter or non-digit in a keyword, we call |\lst@SKSAdd| to store that character.
|
|
% If we reach the end of keyword list, we terminate the loop by gobbling one token after the latest |\fi|.
|
|
% \begin{macrocode}
|
|
\def\lst@SpecialKeywordScan#1{%
|
|
\ifx\relax#1%
|
|
\expandafter\@gobble %
|
|
\else %
|
|
% \end{macrocode}
|
|
% If the current character is a comma, the next character must be (or become) a letter since it starts a keyword.
|
|
% This switch is turned false after reading the next character.
|
|
% \begin{macrocode}
|
|
\ifx,#1%
|
|
\lstCC@lettertrue %
|
|
\else %
|
|
\ifnum`#1<"40\relax %
|
|
\ifnum`#1<"30\relax \lst@SKSAdd#1\else %
|
|
\ifnum`#1>"39\relax \lst@SKSAdd#1\else %
|
|
% \end{macrocode}
|
|
% If we've found a digit, we do a special test to decide whether the digit becomes a letter or not.
|
|
% \begin{macrocode}
|
|
\lst@SKS@#1%
|
|
\fi \fi %
|
|
\else %
|
|
\ifnum`#1<"5B\relax \else %
|
|
\ifnum`#1="5F\relax \else %
|
|
\ifnum`#1<"61\relax \lst@SKSAdd#1\else %
|
|
\ifnum`#1<"7B\relax \else %
|
|
\ifnum`#1<"80\relax \lst@SKSAdd#1 %
|
|
\fi \fi \fi \fi \fi %
|
|
\fi %
|
|
\lstCC@letterfalse %
|
|
\fi %
|
|
\fi \lst@SpecialKeywordScan}
|
|
% \end{macrocode}
|
|
% The special test for digits: Since any digit is already a digit it needs only to become a letter if necessary.
|
|
% \begin{macrocode}
|
|
\def\lst@SKS@#1{\lstCC@ifletter \lst@SKSAdd#1\fi}
|
|
% \end{macrocode}
|
|
% The macros |\lst@ialsoletter| and |\lst@ialsodigit| contain the characters.
|
|
% If not already contained in the appropiate macro, we append the character.
|
|
% Refer |\lst@SelectStyleFor| how we scan for a substring (of length 1).
|
|
% \begin{macrocode}
|
|
\def\lst@SKSAdd#1{%
|
|
\lstCC@ifletter %
|
|
\def\lst@temp##1#1##2\relax{%
|
|
\ifx\@empty##2\@empty %
|
|
\lst@lAddTo\lst@ialsoletter{#1}%
|
|
\fi}%
|
|
\expandafter\lst@temp\lst@ialsoletter#1\relax %
|
|
\else %
|
|
\def\lst@temp##1#1##2\relax{%
|
|
\ifx\@empty##2\@empty %
|
|
\lst@lAddTo\lst@ialsodigit{#1}%
|
|
\fi}%
|
|
\expandafter\lst@temp\lst@ialsodigit#1\relax %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\let\lst@ialsoletter\@empty \let\lst@ialsodigit\@empty % init
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{alsoletter}
|
|
% \begin{aspect}{alsodigit}
|
|
% \begin{aspect}{alsoother}
|
|
% For now three easy definitions --- easy since I don't explain the last hook.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{alsoletter}{\def\lst@alsoletter{#1}}
|
|
\lst@Aspect{alsodigit}{\def\lst@alsodigit{#1}}
|
|
\lst@Aspect{alsoother}{\def\lst@alsoother{#1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SetLanguage}
|
|
{\let\lst@alsoletter\@empty %
|
|
\let\lst@alsodigit\@empty %
|
|
\let\lst@alsoother\@empty}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SelectCharTable}
|
|
{\lstCC@ChangeBasicClass\lstCC@ProcessOther\lst@alsoother %
|
|
\lstCC@ChangeBasicClass\lstCC@ProcessDigit\lst@ialsodigit %
|
|
\lstCC@ChangeBasicClass\lstCC@ProcessDigit\lst@alsodigit %
|
|
\lstCC@ChangeBasicClass\lstCC@ProcessLetter\lst@ialsoletter %
|
|
\lstCC@ChangeBasicClass\lstCC@ProcessLetter\lst@alsoletter}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@minus}
|
|
% What is the |\ifx|\ldots{} in |\lst@minus| good for?
|
|
% If you use typewriter fonts, it ensures that |----| is typeset |----| and not $-$$-$$-$$-$ as in version 0.17.
|
|
% Bug encountered by \lsthelper{Dr. Jobst Hoffmann}{HOFFMANN@rz.rwth-aachen.de}{1998/03/30}{\lst@minus\ and typewriter fonts}.
|
|
% \begin{macrocode}
|
|
\def\lst@minus{\ifx\f@family\ttdefault-{}\else$-$\fi}
|
|
\def\lst@dollar{\ifx\f@family\ttdefault\textdollar\else\textdollar\fi}
|
|
\def\lst@asterisk{\ifx\f@family\ttdefault*\else\textasteriskcentered\fi}
|
|
\def\lst@less{\ifx\f@family\ttdefault<\else\textless\fi}
|
|
\def\lst@greater{\ifx\f@family\ttdefault>\else\textgreater\fi}
|
|
\def\lst@backslash{\ifx\f@family\ttdefault\char92\else\textbackslash\fi}
|
|
\def\lst@underscore{%
|
|
\ifx\f@family\ttdefault\char95\else\textunderscore\fi}
|
|
\def\lst@lbrace{\ifx\f@family\ttdefault\char123\else\textbraceleft\fi}
|
|
\def\lst@bar{\ifx\f@family\ttdefault|\else\textbar\fi}
|
|
\def\lst@rbrace{\ifx\f@family\ttdefault\char125\else\textbraceright\fi}
|
|
% \end{macrocode}
|
|
% |\ttdefault| is defined |\long|, so the |\ifx| doesn't work since |\f@family| isn't defined |\long|!
|
|
% We go around this problem by redefining |\ttdefault| locally:
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}{\edef\ttdefault{\ttdefault}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{basicstyle}
|
|
% \begin{aspect}{keywordstyle}
|
|
% \begin{aspect}{nonkeywordstyle}
|
|
% We shouldn't forget these style aspects.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{basicstyle}{\def\lst@basicstyle{#1}}
|
|
\lst@Aspect{keywordstyle}{\def\lst@keywordstyle{#1}}
|
|
\lst@Aspect{nonkeywordstyle}{\def\lst@nonkeywordstyle{#1}}
|
|
% \end{macrocode}
|
|
% \lsthelper{Anders Edenbrandt}{Anders.Edenbrandt@dna.lth.se}{1997/04/22}{preload of .fd files} found a bug with \texttt{.fd} files.
|
|
% Here's my solution: Since we will change catcodes, these files can't be read on demand --- it would yield to obscure error messages.
|
|
% The |\setbox| sequence ensures (most times) that they are read before.
|
|
% We simply typeset distinct characters from each \texttt{.fd} file.
|
|
% Note: We never output that box.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@basicstyle %
|
|
\setbox\@tempboxa\hbox{\lst@loadfd %
|
|
{\lst@keywordstyle \lst@loadfd}%
|
|
{\lst@nonkeywordstyle \lst@loadfd}}}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@loadfd}
|
|
% These are hopefully all necessary characters.
|
|
% \begin{macrocode}
|
|
\def\lst@loadfd{a0\lst@asterisk\lst@less}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{ndkeywords}
|
|
% \begin{aspect}{ndkeywordstyle}
|
|
% \begin{aspect}{morendkeywords}
|
|
% \begin{aspect}{deletendkeywords}
|
|
% We define a second keyword class in the same manner if the user wants it.
|
|
% \begin{macrocode}
|
|
\@ifundefined{lst@ndkeywords}{}{%
|
|
\let\lst@ndkeywords\@empty \let\lst@ndkeywordstyle\@empty % init
|
|
\lst@Aspect{ndkeywords}
|
|
{\lst@MakeSpecKeywordArg{#1}\let\lst@ndkeywords\lst@arg}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@ndkeywords\@empty}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@ifsensitive\else %
|
|
\lst@MakeMacroUppercase\lst@ndkeywords %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{ndkeywordstyle}{\def\lst@ndkeywordstyle{#1}}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\setbox\@tempboxa\hbox{{\lst@ndkeywordstyle \lst@loadfd}}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{morendkeywords}
|
|
{\lst@MakeMoreSpecKeywordArg{,#1}%
|
|
\expandafter\lst@lAddTo\expandafter\lst@ndkeywords %
|
|
\expandafter{\lst@arg}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{deletendkeywords}
|
|
{\lst@MakeKeywordArg{#1}%
|
|
\lst@DeleteKeysIn\lst@ndkeywords\lst@arg}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{Output}
|
|
{\lst@ifmode\else %
|
|
\expandafter\lst@IfOneOf\the\lst@token\relax \lst@ndkeywords %
|
|
{\let\lst@thestyle\lst@ndkeywordstyle}{}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% Finally we end the argument from |\@ifundefined|.
|
|
% \begin{macrocode}
|
|
}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
% \begin{aspect}{rdkeywords}
|
|
% \begin{aspect}{rdkeywordstyle}
|
|
% \begin{aspect}{morerdkeywords}
|
|
% \begin{aspect}{deleterdkeywords}
|
|
% That's the power of \lst-aspects: An optional third keyword class.
|
|
% \begin{macrocode}
|
|
\@ifundefined{lst@rdkeywords}{}{%
|
|
\let\lst@rdkeywords\@empty \let\lst@rdkeywordstyle\@empty % init
|
|
\lst@Aspect{rdkeywords}
|
|
{\lst@MakeSpecKeywordArg{#1}\let\lst@rdkeywords\lst@arg}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@rdkeywords\@empty}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@ifsensitive\else %
|
|
\lst@MakeMacroUppercase\lst@rdkeywords %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{rdkeywordstyle}{\def\lst@rdkeywordstyle{#1}}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\setbox\@tempboxa\hbox{{\lst@rdkeywordstyle \lst@loadfd}}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{morerdkeywords}
|
|
{\lst@MakeMoreSpecKeywordArg{,#1}%
|
|
\expandafter\lst@lAddTo\expandafter\lst@rdkeywords %
|
|
\expandafter{\lst@arg}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{deleterdkeywords}
|
|
{\lst@MakeKeywordArg{#1}%
|
|
\lst@DeleteKeysIn\lst@rdkeywords\lst@arg}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{Output}
|
|
{\lst@ifmode\else %
|
|
\expandafter\lst@IfOneOf\the\lst@token\relax \lst@rdkeywords %
|
|
{\let\lst@thestyle\lst@rdkeywordstyle}{}%
|
|
\fi}
|
|
}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
%
|
|
% \subsection{Export of indentifiers}
|
|
%
|
|
% \begin{aspect}{index}
|
|
% We implement this aspect in the same manner.
|
|
% \begin{macrocode}
|
|
\@ifundefined{lst@index}{}{%
|
|
\lst@Aspect{index}{\lst@MakeSpecKeywordArg{#1}\let\lst@index\lst@arg}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@ifsensitive\else %
|
|
\lst@MakeMacroUppercase\lst@index %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{Output}
|
|
{\lst@ifmode\else %
|
|
\expandafter\lst@IfOneOf\the\lst@token\relax \lst@index %
|
|
{\expandafter\lst@indexmacro\expandafter{\the\lst@token}}{}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{indexmacro}{\let\lst@indexmacro#1}
|
|
\newcommand\lstindexmacro[1]{\index{{\ttfamily#1}}}
|
|
\let\lst@index\@empty \let\lst@indexmacro\lstindexmacro % init
|
|
}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{aspect}{procnamestyle}
|
|
% \begin{aspect}{prockeywords}
|
|
% \begin{aspect}{indexprocnames}
|
|
% The 'idea' here is the usage of a global |\lst@ifprocname| indicating a preceding 'procedure keyword'.
|
|
% All the other is known stuff.
|
|
% \begin{macrocode}
|
|
\@ifundefined{lst@prockeywords}{}{%
|
|
\lst@Aspect{prockeywords}{%
|
|
\lst@MakeSpecKeywordArg{#1}\let\lst@prockeywords\lst@arg}
|
|
\lst@Aspect{procnamestyle}{\def\lst@procnamestyle{#1}}
|
|
\lst@Aspect{indexprocnames}[t]{\lstKV@SetIfKey\lst@ifindexproc{#1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\setbox\@tempboxa\hbox{\lst@procnamestyle\lst@loadfd}%
|
|
\lst@ifsensitive\else %
|
|
\lst@MakeMacroUppercase\lst@prockeywords %
|
|
\fi %
|
|
\lst@ifindexproc \ifx\lst@indexmacro\@undefined %
|
|
\let\lst@indexmacro\@gobble %
|
|
\fi \fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{Output}
|
|
{\lst@ifmode\else %
|
|
\lst@ifprocname %
|
|
\let\lst@thestyle\lst@procnamestyle %
|
|
\expandafter\lst@indexmacro\expandafter{\the\lst@token}%
|
|
\lst@procnamefalse %
|
|
\else \expandafter%
|
|
\lst@IfOneOf\the\lst@token\relax \lst@prockeywords %
|
|
{\lst@procnametrue}{}%
|
|
\fi %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@procnametrue{\global\let\lst@ifprocname\iftrue}
|
|
\def\lst@procnamefalse{\global\let\lst@ifprocname\iffalse}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\let\lst@prockeywords\@empty % init
|
|
\lstset{procnamestyle={},indexprocnames=false}% init
|
|
\lst@procnamefalse % init
|
|
}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Labels}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \lsthelper{Rolf Niepraschk}{NIEPRASCHK@PTB.DE}{1997/04/24}{labels} asked for this feature.
|
|
%
|
|
% \begin{aspect}{labelstyle}
|
|
% \begin{aspect}{labelsep}
|
|
% \begin{aspect}{labelstep}
|
|
% The usual stuff:
|
|
% Definition with check for legal step count, \ldots
|
|
% \begin{macrocode}
|
|
\lst@Aspect{labelstyle}{\def\lst@labelstyle{#1}}
|
|
\lst@Aspect{labelsep}{\def\lst@labelsep{#1}}
|
|
\lst@Aspect{labelstep}%
|
|
{\ifnum #1>\m@ne %
|
|
\def\lst@labelstep{#1}%
|
|
\else %
|
|
\PackageError{Listings}{Nonnegative integer expected}%
|
|
{You can't use `#1' as step count for labels.^^J%
|
|
I'll forget it and proceed.}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% and load of \texttt{.fd} files (if necessary).
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\setbox\@tempboxa\hbox{\lst@stringstyle \lst@loadfd}}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@skiplabels}
|
|
% But there are more things to do.
|
|
% \begin{macrocode}
|
|
\newcount\lst@skiplabels % \global
|
|
% \end{macrocode}
|
|
% We calculate how many lines must skip their label.
|
|
% The formula is
|
|
% $$|\lst@skiplabels|=
|
|
% \textrm{\emph{first printing line}}\bmod|\lst@labelstep|.$$
|
|
% Note that we use a nonpositive representative for |\lst@skiplabels|.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\ifnum\lst@labelstep>\z@ %
|
|
\global\lst@skiplabels\lst@firstline\relax %
|
|
\global\divide\lst@skiplabels\lst@labelstep %
|
|
\global\multiply\lst@skiplabels-\lst@labelstep %
|
|
\global\advance\lst@skiplabels\lst@firstline\relax %
|
|
\ifnum\lst@skiplabels>\z@ %
|
|
\global\advance\lst@skiplabels -\lst@labelstep\relax %
|
|
\fi %
|
|
% \end{macrocode}
|
|
% If |\lst@labelstep| is nonpositive (in fact zero), no labels are printed:
|
|
% \begin{macrocode}
|
|
\else %
|
|
\let\lst@SkipOrPrintLabel\relax %
|
|
\fi}
|
|
\lst@AddToHook{EveryLine}{\lst@SkipOrPrintLabel}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@SkipOrPrintLabel}
|
|
% But default is this.
|
|
% We use the fact that |\lst@skiplabels| is nonpositive.
|
|
% The counter advances every line and if that counter is zero, we print a line number and decrement the counter by |\lst@labelstep|.
|
|
% \begin{macrocode}
|
|
\def\lst@SkipOrPrintLabel{%
|
|
\ifnum\lst@skiplabels=\z@ %
|
|
\global\advance\lst@skiplabels-\lst@labelstep\relax %
|
|
\llap{\lst@labelstyle{\the\lst@lineno}\kern\lst@labelsep}%
|
|
\fi %
|
|
\global\advance\lst@skiplabels\@ne}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Parshape and lineskip}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@innerspread}
|
|
% \begin{macro}{\lst@outerspread}
|
|
% Just allocate these dimensions.
|
|
% \begin{macrocode}
|
|
\newdimen\lst@innerspread \newdimen\lst@outerspread
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{aspect}{wholeline}
|
|
% \begin{aspect}{indent}
|
|
% \begin{aspect}{spread}
|
|
% Usual stuff.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{wholeline}[t]{\lstKV@SetIfKey\lst@ifwholeline{#1}}
|
|
\lst@Aspect{indent}{\def\lst@indent{#1}}
|
|
\lst@Aspect{spread}{\lstspread@#1,,\relax}
|
|
% \end{macrocode}
|
|
% \lsthelper{Harald Haders}{h.haders@tu-bs.de}{1998/03/30}{inner- and outerspread} had the idea of two spreads (inner and outer).
|
|
% We either divide the dimension by two or assign the two dimensions to inner- and outerspread.
|
|
% \begin{macrocode}
|
|
\def\lstspread@#1,#2,#3\relax{%
|
|
\lst@innerspread#1\relax %
|
|
\ifx\@empty#2\@empty %
|
|
\divide\lst@innerspread\tw@\relax %
|
|
\lst@outerspread\lst@innerspread %
|
|
\else %
|
|
\lst@outerspread#2\relax %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{wholeline=false,indent=\z@,spread=\z@}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@parshape}
|
|
% The definition itself is easy.
|
|
% Note that we use this parshape every line (in fact every paragraph).
|
|
% Furthermore we must repeat the parshape if we close a group level --- or the shape is forgotten.
|
|
% \begin{macrocode}
|
|
\def\lst@parshape{%
|
|
\parshape\@ne %
|
|
\ifodd\c@page -\lst@innerspread\else -\lst@outerspread\fi %
|
|
\linewidth}
|
|
\lst@AddToHookAtTop{EveryLine}{\lst@parshape}
|
|
\lst@AddToHookAtTop{EndGroup}{\lst@parshape}
|
|
% \end{macrocode}
|
|
% We calculate the line width and (inner/outer) indent for a listing.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\advance\linewidth\lst@innerspread %
|
|
\advance\linewidth\lst@outerspread %
|
|
\advance\linewidth-\lst@indent\relax %
|
|
\advance\lst@innerspread-\lst@indent\relax %
|
|
\advance\lst@outerspread-\lst@indent\relax %
|
|
\lst@ifwholeline %
|
|
\advance\linewidth\@totalleftmargin %
|
|
\else %
|
|
\advance\lst@innerspread-\@totalleftmargin %
|
|
\advance\lst@outerspread-\@totalleftmargin %
|
|
\fi %
|
|
\if@twoside\else \lst@outerspread\lst@innerspread \fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{lineskip}
|
|
% Finally we come to this attribute --- the introduction is due to communication with \lsthelper{Andreas Bartelt}{Andreas.Bartelt@Informatik.Uni-Oldenburg.DE}{1997/09/11}{problem with redefed \parskip; \lstlineskip introduced}.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{lineskip}{\def\lst@lineskip{#1}}
|
|
\lst@AddToHook{BeforeSelectCharTable}{\parskip\lst@lineskip\relax}
|
|
\lstset{lineskip=\z@}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Frames}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
% \begin{aspect}{framerulewidth}
|
|
% \begin{aspect}{framerulesep}
|
|
% \begin{aspect}{frametextsep}
|
|
% We only have to store the arguments.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{framerulewidth}{\def\lst@framewidth{#1}}
|
|
\lst@Aspect{framerulesep}{\def\lst@framesep{#1}}
|
|
\lst@Aspect{frametextsep}{\def\lst@frametextsep{#1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{framerulewidth=.4pt,framerulesep=2pt,frametextsep=3pt}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}\end{aspect}
|
|
%
|
|
% \begin{aspect}{frame}
|
|
% The main aspect saves the argument, resets all supported types |tlrbTLRB| to |\relax| and defines the user specified frame.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{frame}
|
|
{\def\lst@frame{#1}%
|
|
\lstframe@\relax tlrbTLRB\relax %
|
|
\lstframe@\@empty#1\relax}
|
|
% \end{macrocode}
|
|
% This submacro defines the macros to be equivalent to |#1| (which is |\relax| or |\@empty|).
|
|
% The second argument is the list of characters terminated by |\relax|.
|
|
% \begin{macrocode}
|
|
\def\lstframe@#1#2{%
|
|
\ifx\relax#2\else %
|
|
\expandafter\let\csname lstf@#2\endcsname#1%
|
|
\expandafter\lstframe@\expandafter#1%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{frame={}}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@framev}
|
|
% \begin{macro}{\lst@frameV}
|
|
% These macros typeset one or two vertical rules:
|
|
% \begin{macrocode}
|
|
\def\lst@framev{\hbox{\strut\vrule width\lst@framewidth}}
|
|
\def\lst@frameV{\hbox{\strut %
|
|
\vrule width\lst@framewidth\kern\lst@framesep %
|
|
\vrule width\lst@framewidth}}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@framelr}
|
|
% We typeset left and right frame rule every line (if not made |\relax|).
|
|
% Note that |\lst@framel| is possibly redefined and thus equivalent to |\lst@frameL|.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{EveryLine}{\lst@framelr}
|
|
\def\lst@framelr{%
|
|
\llap{\lst@framel\kern\lst@indent\kern\lst@frametextsep}%
|
|
\rlap{\kern\linewidth\kern\lst@frametextsep\lst@framer}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@frameh}
|
|
% This is the main macro for horizontal lines.
|
|
% The first parameter gives the size of the left and right corner.
|
|
% The other two parameters typeset these corners (and get the size parameter).
|
|
% Now: We move to the correct horizontal position, set the left corner, the horizontal line and the right corner.
|
|
% \begin{macrocode}
|
|
\def\lst@frameh#1#2#3{%
|
|
\hbox to\z@{%
|
|
\kern\ifodd\c@page -\lst@innerspread\else -\lst@outerspread\fi %
|
|
\kern-\lst@indent %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\kern-\lst@frametextsep %
|
|
\ifx\lstf@L\@empty %
|
|
\llap{#2#1}%
|
|
\else \ifx\lstf@l\@empty %
|
|
\llap{#20}%
|
|
\fi \fi %
|
|
\vrule\@width\lst@frametextsep %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\vrule\@width\lst@indent %
|
|
\vrule\@width\linewidth\@height\lst@framewidth %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\vrule\@width\lst@frametextsep %
|
|
\ifx\lstf@R\@empty %
|
|
\rlap{#3#1}%
|
|
\else \ifx\lstf@r\@empty %
|
|
\rlap{#30}%
|
|
\fi \fi %
|
|
\hss}}
|
|
% \end{macrocode}
|
|
% Note: There are no paramaters with numbers 20 and 30.
|
|
% It's |#2| respectively |#3| with size argument 0.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@framet}
|
|
% \begin{macro}{\lst@frameb}
|
|
% \begin{macro}{\lst@frameT}
|
|
% \begin{macro}{\lst@frameB}
|
|
% Now we can derive the 'top' and 'bottom' frame macros quite easily:
|
|
% \begin{macrocode}
|
|
\def\lst@framet{\lst@frameh0\lst@frameTL\lst@frameTR}%
|
|
\let\lst@frameb\lst@framet
|
|
\def\lst@frameT{%
|
|
\lst@frameh1\lst@frameTL\lst@frameTR %
|
|
\vskip\lst@framesep %
|
|
\lst@frameh0\lst@frameTL\lst@frameTR}
|
|
\def\lst@frameB{%
|
|
\lst@frameh0\lst@frameBL\lst@frameBR %
|
|
\vskip\lst@framesep %
|
|
\lst@frameh1\lst@frameBL\lst@frameBR}
|
|
% \end{macrocode}
|
|
% These macros are executed where needed.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\ifx\lstf@T\@empty %
|
|
\offinterlineskip\par\noindent\lst@frameT %
|
|
\else \ifx\lstf@t\@empty %
|
|
\offinterlineskip\par\noindent\lst@framet %
|
|
\else %
|
|
\let\lst@framet\relax %
|
|
\fi \fi %
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% Replace |\offinterlineskip| by |\nointerlineskip|?
|
|
% \end{TODO}
|
|
% We look which frame types we have on the left and on the right.
|
|
% \begin{macrocode}
|
|
\let\lst@framel\relax \let\lst@framer\relax %
|
|
\ifx\lstf@L\@empty %
|
|
\let\lst@framel\lst@frameV %
|
|
\else %
|
|
\ifx\lstf@l\relax\else \let\lst@framel\lst@framev \fi %
|
|
\fi %
|
|
\ifx\lstf@R\@empty %
|
|
\let\lst@framer\lst@frameV %
|
|
\else %
|
|
\ifx\lstf@r\relax\else \let\lst@framer\lst@framev \fi %
|
|
\fi %
|
|
% \end{macrocode}
|
|
% We can speed up things if there are no vertical frames.
|
|
% \begin{macrocode}
|
|
\ifx\lst@framel\relax \ifx\lst@framer\relax %
|
|
\let\lst@framelr\relax %
|
|
\fi \fi %
|
|
% \end{macrocode}
|
|
% Finally we close the space between the horizontal rule and the first line (the 'depth' of the current line).
|
|
% \begin{macrocode}
|
|
\ifx\lst@framelr\relax\else \ifx\lst@framet\relax\else %
|
|
{\setbox\strutbox\hbox{%
|
|
\vrule\@height0pt\@depth.3\normalbaselineskip\@width\z@}%
|
|
\kern\ifodd\c@page-\lst@innerspread\else-\lst@outerspread\fi %
|
|
\lst@framelr}%
|
|
\fi \fi}
|
|
% \end{macrocode}
|
|
% The frame at the bottom:
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{ExitVars}
|
|
{\ifx\lstf@B\@empty %
|
|
\offinterlineskip\everypar{}\par\noindent\lst@frameB %
|
|
\else \ifx\lstf@b\@empty %
|
|
\offinterlineskip\everypar{}\par\noindent\lst@framet %
|
|
\fi \fi}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@frameTL}
|
|
% \begin{macro}{\lst@frameTR}
|
|
% \begin{macro}{\lst@frameBL}
|
|
% \begin{macro}{\lst@frameBR}
|
|
% The 'corner' macros are left.
|
|
% All save the vertical rule in a temporary box to zero the depth or height of that box.
|
|
% Then we typeset the vertical and horizontal rule (in reversed order).
|
|
% \begin{macrocode}
|
|
\def\lst@frameTL#1{%
|
|
\@tempdima\lst@framesep \advance\@tempdima\lst@framewidth %
|
|
\multiply\@tempdima#1\relax %
|
|
\setbox\@tempboxa\hbox to\z@{%
|
|
\vrule\@width\lst@framewidth\@height\z@\@depth\@tempdima\hss}%
|
|
\dp\@tempboxa\z@ %
|
|
\advance\@tempdima\lst@framewidth %
|
|
\box\@tempboxa \vrule\@width\@tempdima\@height\lst@framewidth}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@frameTR#1{%
|
|
\@tempdima\lst@framesep \advance\@tempdima\lst@framewidth %
|
|
\multiply\@tempdima#1\relax %
|
|
\setbox\@tempboxa\hbox to\z@{\hss %
|
|
\vrule\@width\lst@framewidth\@height\z@\@depth\@tempdima}%
|
|
\dp\@tempboxa\z@ %
|
|
\advance\@tempdima\lst@framewidth %
|
|
\vrule\@width\@tempdima\@height\lst@framewidth \box\@tempboxa}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@frameBL#1{%
|
|
\@tempdima\lst@framesep \advance\@tempdima\lst@framewidth %
|
|
\multiply\@tempdima#1\relax %
|
|
\advance\@tempdima\lst@framewidth %
|
|
\setbox\@tempboxa\hbox to\z@{%
|
|
\vrule\@width\lst@framewidth\@height\@tempdima\hss}%
|
|
\ht\@tempboxa\z@ %
|
|
\box\@tempboxa \vrule\@width\@tempdima\@height\lst@framewidth}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@frameBR#1{%
|
|
\@tempdima\lst@framesep \advance\@tempdima\lst@framewidth %
|
|
\multiply\@tempdima#1\relax %
|
|
\advance\@tempdima\lst@framewidth %
|
|
\setbox\@tempboxa\hbox to\z@{\hss %
|
|
\vrule\@width\lst@framewidth\@height\@tempdima}%
|
|
\ht\@tempboxa\z@ %
|
|
\vrule\@width\@tempdima\@height\lst@framewidth \box\@tempboxa}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}\end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Pre and post listing}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{pre}
|
|
% \begin{aspect}{post}
|
|
% A rather trivial section.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{pre}{\lstKV@OptArg\lstpre@[]{#1}}
|
|
\lst@Aspect{post}{\lstKV@OptArg\lstpost@[]{#1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lstpre@[#1]#2{%
|
|
\def\lst@prelisting{#2}\def\lst@@prelisting{#1}}
|
|
\def\lstpost@[#1]#2{%
|
|
\def\lst@postlisting{#2}\def\lst@@postlisting{#1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{pre={},post={}}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{\TeX\ comment lines}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% Communication with \lsthelper{J\"orn Wilms}{wilms@rocinante.colorado.edu}{1997/07/07}{\TeX\ comments} is responsible for this feature.
|
|
% Some characters have a special functionality in \TeX{}, e.g.\ the underbar or the dollar sign.
|
|
% These meanings are unwanted while typesetting normal source code, i.e.\ we have to define our own character table.
|
|
% But for the comment lines we must interrupt the current processing and switch back to the original meanings.
|
|
% And at the end we must restore all previous things.
|
|
%
|
|
% \begin{aspect}{texcl}
|
|
% Announcing the aspect:
|
|
% \begin{macrocode}
|
|
\lst@Aspect{texcl}[t]{\lstKV@SetIfKey\lst@iftexcl{#1}}
|
|
\lstset{texcl=false}% init
|
|
% \end{macrocode}
|
|
% Things at EOL are easy, but we must allocate new modes for (\TeX) comment lines first.
|
|
% \begin{macrocode}
|
|
\lst@NewMode\lst@TeXCLmode
|
|
\lst@NewMode\lst@CLmode
|
|
\lst@AddToHook{EOL}
|
|
{\ifnum\lst@mode=\lst@TeXCLmode %
|
|
\lst@LeaveAllModes \lst@ReenterModes %
|
|
\fi %
|
|
\ifnum\lst@mode=\lst@CLmode \lst@LeaveMode \fi}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@BeginCommentLine}
|
|
% \begin{macro}{\lstCC@@BeginCommentLine}
|
|
% The first macro starts comment lines indicated by a single character (like |%| in \TeX), whereas the second does this for comment lines indicated by two characters (like |//| in C++).
|
|
% According to the macro naming these two macros belong more or less to section \ref{iCharacterClasses}.
|
|
% But we present them here because of \TeX\ comment lines.
|
|
%
|
|
% We print preceding characters (if any), begin the comment and output the comment separator.
|
|
% \begin{macrocode}
|
|
\def\lstCC@BeginCommentLine#1{%
|
|
\lst@NewLine \lst@PrintToken %
|
|
\lst@EnterMode{\lst@CLmode}{\lst@modetrue\lst@commentstyle}%
|
|
#1\relax %
|
|
% \end{macrocode}
|
|
% If the user don't want \TeX\ comment lines, there is nothing more to do.
|
|
% Otherwise we have to print the comment separator and interrupt the normal processing.
|
|
% \begin{macrocode}
|
|
\lst@iftexcl %
|
|
\lst@PrintToken %
|
|
\lst@LeaveMode \lst@InterruptModes %
|
|
\lst@EnterMode{\lst@TeXCLmode}{\lst@modetrue\lst@commentstyle}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% Now comes the same, but we process a 'two character'-separator.
|
|
% \begin{macrocode}
|
|
\def\lstCC@@BeginCommentLine#1#2{%
|
|
\lst@NewLine \lst@PrintToken %
|
|
\lst@EnterMode{\lst@CLmode}{\lst@modetrue\lst@commentstyle}%
|
|
#1\relax#2\relax %
|
|
\lst@iftexcl %
|
|
\lst@PrintToken %
|
|
\lst@LeaveMode \lst@InterruptModes %
|
|
\lst@EnterMode{\lst@TeXCLmode}{\lst@modetrue\lst@commentstyle}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{Doing output}
|
|
%
|
|
%
|
|
% \subsection{Output aspects and helpers}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{flexiblecolumns}
|
|
% Do you have any idea what to write here?
|
|
% \begin{macrocode}
|
|
\lst@Aspect{flexiblecolumns}[t]{\lstKV@SetIfKey\lst@ifflexible{#1}}
|
|
\lstset{flexiblecolumns=false}% init
|
|
% \end{macrocode}
|
|
% We assign the correct output macros defined below.
|
|
% As you can see there are three main macros, which handle letters, all other printing characters and tabulator stops.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@ifflexible %
|
|
\let\lst@Output\lst@OutputFlexible %
|
|
\let\lst@OutputOther\lst@OutputOtherFlexible %
|
|
\let\lst@GotoTabStop\lst@GotoTabStopFlexible %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{aspect}{baseem}
|
|
% We look whether or not the user gives two numbers, i.e.\ we test for a comma.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{baseem}{\lstbaseem@#1,,\relax}
|
|
% \end{macrocode}
|
|
% Here we check for legal arguments \ldots
|
|
% \begin{macrocode}
|
|
\def\lstbaseem@#1,#2,#3\relax{%
|
|
\def\lst@next{\PackageError{Listings}%
|
|
{Nonnegative number(s) expected}%
|
|
{Separate one or two such numbers by a comma, next time.^^J%
|
|
Now type <RETURN> to proceed.}}%
|
|
\ifdim #1em<\z@\else %
|
|
\def\lst@baseemfixed{#1}%
|
|
\let\lst@baseemflexible\lst@baseemfixed %
|
|
% \end{macrocode}
|
|
% and do the comma test.
|
|
% \begin{macrocode}
|
|
\ifx\@empty#2\@empty %
|
|
\let\lst@next\relax %
|
|
\else \ifdim #2em<\z@\else %
|
|
\def\lst@baseemflexible{#2}%
|
|
\let\lst@next\relax %
|
|
\fi \fi %
|
|
\fi \lst@next}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{baseem={0.6,0.45}}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@width}
|
|
% The dimension holds the width of a single character box while typesetting a listing.
|
|
% \begin{macrocode}
|
|
\newdimen\lst@width
|
|
\lst@AddToHook{InitVars}
|
|
{\lst@width=\lst@ifflexible\lst@baseemflexible %
|
|
\else\lst@baseemfixed\fi em\relax}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{tabsize}
|
|
% We check for a legal argument before saving it.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{tabsize}
|
|
{\ifnum#1>\z@ %
|
|
\def\lst@tabsize{#1}%
|
|
\else %
|
|
\PackageError{Listings}{Strict positive integer expected}
|
|
{You can't use `#1' as tabulator length.^^J%
|
|
Type <RETURN> to forget it and to proceed.}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% Default tabsize is 8 as proposed by \lsthelper{Rolf Niepraschk}{NIEPRASCHK@PTB.DE}{1997/04/24}{tabsize=8}.
|
|
% \begin{macrocode}
|
|
\lstset{tabsize=8}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% Before looking at the output macros, we have to introduce some registers.
|
|
%
|
|
% \begin{macro}{\lst@token}
|
|
% \begin{macro}{\lst@length}
|
|
% The token register contains the current character string, for example |char| if we have just read these characters and a whitespace before.
|
|
% The counter |\lst@length| holds the length of the string and that's 4 in the example.
|
|
% \begin{macrocode}
|
|
\newtoks\lst@token \newcount\lst@length
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVarsEOL}{\lst@token{}\lst@length\z@}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@lastother}
|
|
% This is not a \TeX{} register.
|
|
% This macro is equivalent to the last 'other' character, other in the sense of section \ref{iCharacterClasses}.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVarsEOL}{\let\lst@lastother\@empty}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@column}
|
|
% \begin{macro}{\lst@pos}
|
|
% With the two counters it is possible to determine the current column.
|
|
% It's the sum of |\lst@column| and |\lst@length| plus one minus |\lst@pos| --- |\lst@pos| will be nonpositive.
|
|
% It seems to be troublesome to decide whether a new line has just begun or not, i.e.\ if the current column number is one.
|
|
% And that's true.
|
|
% \begin{macrocode}
|
|
\newcount\lst@column \newcount\lst@pos % \global
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVarsEOL}{\global\lst@pos\z@ \global\lst@column\z@}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@lostspace}
|
|
% The output macros have to keep track of the difference between the real and desired (current) line width; the latter one given by 'current column times |\lst@width|'.
|
|
% More precisely, |\lst@lostspace| equals 'current column times |\lst@width|' minus 'width of so far printed line'.
|
|
% Whenever this dimension is positive we can insert space to fix the column alignment.
|
|
% \begin{macrocode}
|
|
\newdimen\lst@lostspace % \global
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVarsEOL}{\global\lst@lostspace\z@}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@UseLostSpace}
|
|
% This is a service macro for the fixed and flexible column output.
|
|
% We insert space and reset it (if and) only if |\lst@lostspace| is positive.
|
|
% \begin{macrocode}
|
|
\def\lst@UseLostSpace{%
|
|
\ifdim\lst@lostspace>\z@ %
|
|
\kern\lst@lostspace \global\lst@lostspace\z@ %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@InsertLostSpace}
|
|
% \begin{macro}{\lst@InsertHalfLostSpace}
|
|
% Ditto, but insert always (even if negative).
|
|
% \begin{macrocode}
|
|
\def\lst@InsertLostSpace{\kern\lst@lostspace \global\lst@lostspace\z@}
|
|
\def\lst@InsertHalfLostSpace{%
|
|
\global\lst@lostspace.5\lst@lostspace \kern\lst@lostspace}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{aspect}{outputpos}
|
|
% Note that there are two |\relax|es \ldots
|
|
% \begin{macrocode}
|
|
\lst@Aspect{outputpos}{\lstoutputpos@#1\relax\relax}
|
|
% \end{macrocode}
|
|
% or an empty argument would be bad here.
|
|
% We simply test for |l|, |c| and |r|.
|
|
% If none of them is given, we issue a warning and assume |r| --- it's default since it looks most bad to me.
|
|
% The fixed column format makes use of |\lst@lefthss| and |\lst@righthss|, whereas the flexible needs only |\lst@leftinsert|.
|
|
% \begin{macrocode}
|
|
\def\lstoutputpos@#1#2\relax{%
|
|
\ifx #1l%
|
|
\let\lst@lefthss\relax \let\lst@righthss\hss %
|
|
\let\lst@leftinsert\relax %
|
|
\else\ifx #1c%
|
|
\let\lst@lefthss\hss \let\lst@righthss\hss %
|
|
\let\lst@leftinsert\lst@InsertHalfLostSpace %
|
|
\else %
|
|
\let\lst@lefthss\hss \let\lst@righthss\relax %
|
|
\let\lst@leftinsert\lst@InsertLostSpace %
|
|
\ifx #1r\else \PackageWarning{Listings}%
|
|
{Unknown positioning for output boxes}%
|
|
\fi %
|
|
\fi\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{outputpos=c}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Dropping empty lines}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@NewLineMacro}
|
|
% This macro is assigned to |\lst@NewLine|, which is executed whenever the (next) line is not empty.
|
|
% Once called, it deactivates itself.
|
|
% \begin{macrocode}
|
|
\def\lst@NewLineMacro{%
|
|
\global\let\lst@NewLine\relax \par\noindent\hbox{}}
|
|
\lst@AddToHook{InitVars}{\global\let\lst@NewLine\lst@NewLineMacro}
|
|
% \end{macrocode}
|
|
% What we have said about |\lst@NewLine| is not the whole truth.
|
|
% Most times we'll assign |\lst@NewLineMacro|, but sometimes we append |\par\noindent\hbox{}| to prepare a new line, namely in the case that the last line has been empty.
|
|
% Then |\lst@NewLine| deactivates itself and begins two, three or more (empty) lines.
|
|
% This drops empty lines at the end of a listing.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{EOL}
|
|
{\ifx\lst@NewLine\relax %
|
|
\global\let\lst@NewLine\lst@NewLineMacro %
|
|
\else %
|
|
\lst@AddTo\lst@NewLine{\par\noindent\hbox{}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Fixed columns}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@OutputOther}
|
|
% This macro outputs a character string with nonletters.
|
|
% If there is anything to output, we possibly start a new line.
|
|
% \begin{macrocode}
|
|
\def\lst@OutputOther{%
|
|
\ifnum\lst@length=\z@\else %
|
|
\lst@NewLine \lst@UseLostSpace %
|
|
% \end{macrocode}
|
|
% The box must take |\lst@length| characters, each |\lst@width| wide.
|
|
% \begin{macrocode}
|
|
\hbox to \lst@length\lst@width{%
|
|
\lst@lefthss %
|
|
\lsthk@OutputOther %
|
|
\expandafter\lst@FillOutputBox\the\lst@token\relax %
|
|
\lst@righthss}%
|
|
% \end{macrocode}
|
|
% Finally we hold up the current column, empty the token and close the starting 'if token not empty'.
|
|
% \begin{macrocode}
|
|
\global\advance\lst@pos -\lst@length %
|
|
\lst@token{}\lst@length\z@ %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@Output}
|
|
% We reset |\lst@lastother| and use |\lst@thestyle|.
|
|
% \begin{macrocode}
|
|
\def\lst@Output{%
|
|
\let\lst@lastother\relax %
|
|
\ifnum\lst@length=\z@\else %
|
|
\lst@NewLine \lst@UseLostSpace %
|
|
\hbox to \lst@length\lst@width{%
|
|
\lst@lefthss %
|
|
\lsthk@Output \lst@thestyle{%
|
|
\expandafter\lst@FillOutputBox\the\lst@token\relax}%
|
|
\lst@righthss}%
|
|
\global\advance\lst@pos -\lst@length %
|
|
\lst@token{}\lst@length\z@ %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% Note that |\lst@lastother| becomes equivalent to |\relax| and not equivalent to |\@empty| as in all other places (e.g.\ InitVarsEOL).
|
|
% I don't know whether this will be important in future or not.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@FillOutputBox}
|
|
% Filling up a box is easy.
|
|
% If we come to the end (the |\relax| from above), we do nothing.
|
|
% Otherwise we output the argument, insert dynamic space and call the macro again.
|
|
% \begin{macrocode}
|
|
\def\lst@FillOutputBox#1{%
|
|
\ifx\relax#1\else #1\hss\expandafter\lst@FillOutputBox \fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@GotoTabStop}
|
|
% For fixed column format we only need to advance |\lst@lostspace| (which is inserted by the output macros above) and update the column.
|
|
% \begin{macrocode}
|
|
\def\lst@GotoTabStop{%
|
|
\global\advance\lst@lostspace \lst@length\lst@width %
|
|
\global\advance\lst@column\lst@length \lst@length\z@}%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Flexible columns}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@OutputOtherFlexible}
|
|
% If there is something to output, we first insert the space lost by the flexible column format.
|
|
% Then we typeset the box and update the lost space.
|
|
% Note that we don't use any |\hss| here.
|
|
% \begin{macrocode}
|
|
\def\lst@OutputOtherFlexible{%
|
|
\ifnum\lst@length=\z@\else %
|
|
\lst@NewLine \lst@UseLostSpace %
|
|
\setbox\@tempboxa\hbox{\lsthk@OutputOther\the\lst@token}%
|
|
\lst@CalcLostSpaceAndOutput %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@OutputFlexible}
|
|
% Nothing is new here.
|
|
% \begin{macrocode}
|
|
\def\lst@OutputFlexible{%
|
|
\let\lst@lastother\relax %
|
|
\ifnum\lst@length=\z@\else %
|
|
\lst@NewLine \lst@UseLostSpace %
|
|
\setbox\@tempboxa\hbox{%
|
|
\lsthk@Output \lst@thestyle{\the\lst@token}}%
|
|
\lst@CalcLostSpaceAndOutput %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@GotoTabStopFlexible}
|
|
% Here we look whether or not the line already contains printing characters.
|
|
% \begin{macrocode}
|
|
\def\lst@GotoTabStopFlexible{%
|
|
\ifx\lst@NewLine\relax %
|
|
% \end{macrocode}
|
|
% If some characters are already printed, we output a box, which has the width of a blank space.
|
|
% Possibly more space is inserted, but that's upto the current value of |\lst@lostspace|.
|
|
% \begin{macrocode}
|
|
\setbox\@tempboxa\hbox{\lst@outputblank}\@tempdima\wd\@tempboxa%
|
|
\setbox\@tempboxa\hbox{}\wd\@tempboxa\@tempdima %
|
|
\lst@CalcLostSpaceAndOutput %
|
|
\global\lst@pos\z@ %
|
|
\else %
|
|
% \end{macrocode}
|
|
% Otherwise (no printed characters) we do the same as for fixed columns.
|
|
% \begin{macrocode}
|
|
\global\advance\lst@lostspace \lst@length\lst@width %
|
|
\global\advance\lst@column\lst@length \lst@length\z@ %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@CalcLostSpaceAndOutput}
|
|
% The update of |\lst@lostspace| is simple, refer its definition above (difference between \ldots).
|
|
% \begin{macrocode}
|
|
\def\lst@CalcLostSpaceAndOutput{%
|
|
\global\advance\lst@lostspace \lst@length\lst@width %
|
|
\global\advance\lst@lostspace-\wd\@tempboxa %
|
|
% \end{macrocode}
|
|
% Moreover we keep track of |\lst@pos| and reset some variables.
|
|
% \begin{macrocode}
|
|
\global\advance\lst@pos -\lst@length %
|
|
\lst@token{}\lst@length\z@ %
|
|
% \end{macrocode}
|
|
% Before |\@tempboxa| is output, we insert appropiate space if there is enough lost space.
|
|
% \begin{macrocode}
|
|
\ifdim\lst@lostspace>\z@ \lst@leftinsert \fi %
|
|
\box\@tempboxa}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Dropping the whole output}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@BeginDropOutput}
|
|
% It's sometimes useful to process a part of a listing as usual, but to drop the output.
|
|
% This macro does the main work and gets one argument, namely the internal mode it enters.
|
|
% We save |\lst@NewLine|, restore it |\aftergroup| and redefine the output macros.
|
|
% \begin{macrocode}
|
|
\def\lst@BeginDropOutput#1{%
|
|
\let\lst@BDOsave\lst@NewLine %
|
|
\lst@EnterMode{#1}%
|
|
{\lst@modetrue %
|
|
\let\lst@Output\lst@EmptyOutput %
|
|
\let\lst@OutputOther\lst@EmptyOutputOther %
|
|
\let\lst@GotoTabStop\lst@EmptyGotoTabStop %
|
|
\aftergroup\lst@BDORestore}}
|
|
% \end{macrocode}
|
|
% Restoring |\lst@NewLine| is quite easy:
|
|
% \begin{macrocode}
|
|
\def\lst@BDORestore{\global\let\lst@NewLine\lst@BDOsave}
|
|
% \end{macrocode}
|
|
% Note that there is no |\lst@EndDropOutput| since this macro would be equivalent to |\lst@LeaveMode|.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@EmptyOutputOther}
|
|
% \begin{macro}{\lst@EmptyOutput}
|
|
% \begin{macro}{\lst@EmptyGotoTabStop}
|
|
% Here we only keep track of registers (possibly) needed by other processing macros.
|
|
% \begin{macrocode}
|
|
\def\lst@EmptyOutputOther{%
|
|
\global\advance\lst@pos -\lst@length %
|
|
\lst@token{}\lst@length\z@}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@EmptyOutput{\let\lst@lastother\relax \lst@EmptyOutputOther}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@EmptyGotoTabStop{%
|
|
\global\advance\lst@column\lst@length \lst@length\z@}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Writing to an external file}
|
|
%
|
|
% The macros are defined (if and) only if the |doc| option is used.
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
\@ifundefined{lst@doc}{}{%
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
% \begin{macro}{\lstdoc@out}
|
|
% The file we will write to.
|
|
% \begin{macrocode}
|
|
\newwrite\lstdoc@out
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@BeginWriteFile}
|
|
% redefines some macros to meet our purpose.
|
|
% The file with name |#1| is opened at the end of the macro.
|
|
% \begin{macrocode}
|
|
\def\lst@BeginWriteFile#1{%
|
|
\begingroup %
|
|
\lsthk@SetLanguage %
|
|
\let\lstCC@ifec\iffalse %
|
|
\let\lst@Output\lstdoc@Output %
|
|
\let\lst@OutputOther\lstdoc@Output %
|
|
\let\lst@GotoTabStop\lstdoc@GotoTabStop %
|
|
\let\lstCC@ProcessSpace\lstdoc@ProcessSpace %
|
|
\let\lst@MProcessListing\lstdoc@MProcessListing %
|
|
\let\smallbreak\relax %
|
|
\let\lst@prelisting\relax \let\lst@postlisting\relax %
|
|
\let\lst@@prelisting\relax \let\lst@@postlisting\relax %
|
|
\let\lstCC@Use\lstdoc@Use %
|
|
\let\lst@DeInit\lstdoc@DeInit %
|
|
\immediate\openout\lstdoc@out=#1\relax}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@EndWriteFile}
|
|
% closes the file and restores original macro meanings.
|
|
% \begin{macrocode}
|
|
\def\lst@EndWriteFile{\immediate\closeout\lstdoc@out \endgroup}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstdoc@Output}
|
|
% keeps only track of horizontal position.
|
|
% \begin{macrocode}
|
|
\def\lstdoc@Output{\global\advance\lst@pos -\lst@length \lst@length\z@}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstdoc@ProcessSpace}
|
|
% \begin{macro}{\lstdoc@GotoTabStop}
|
|
% We append the appropiate number of spaces.
|
|
% Note that |\lstCC@Append| increases |\lst@length| by 1, thus we need -2.
|
|
% \begin{macrocode}
|
|
\def\lstdoc@ProcessSpace{\lstCC@Append{ }}
|
|
\def\lstdoc@GotoTabStop{%
|
|
\@whilenum \lst@length>\z@ \do %
|
|
{\lstCC@Append{ }\advance\lst@length-2\relax}}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstdoc@MProcessListing}
|
|
% writes one line to external file.
|
|
% \begin{macrocode}
|
|
\def\lstdoc@MProcessListing{%
|
|
\immediate\write\lstdoc@out{\the\lst@token}%
|
|
\lst@token{}\lst@length\z@ %
|
|
\lst@BOLGobble}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstdoc@DeInit}
|
|
% We write the rest to file and end processing.
|
|
% \begin{macrocode}
|
|
\def\lstdoc@DeInit{%
|
|
\ifnum\lst@length=\z@\else %
|
|
\immediate\write\lstdoc@out{\the\lst@token}%
|
|
\fi %
|
|
\egroup \smallbreak\lst@postlisting \endgroup}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstdoc@Use}
|
|
% Any processed character appends the character itself to |\lst@token| (but with catcode 12 or 10).
|
|
% The original |\lstCC@Use| is defined in section \ref{iCharacterTables}.
|
|
% \begin{macrocode}
|
|
\def\lstdoc@Use#1#2#3{%
|
|
\ifnum#2=\z@ %
|
|
\expandafter\@gobbletwo %
|
|
\else %
|
|
\catcode#2=\active \lccode`\~=#2\lccode`\/=#2%
|
|
\lowercase{\def~{\lstCC@Append{/}}}%
|
|
\fi %
|
|
\lstdoc@Use#1}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
}% of \@ifundefined{lst@doc}{}{%
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Keyword comments}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*keywordcomments>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{keywordcomment}
|
|
% \begin{aspect}{doublekeywordcommentsemicolon}
|
|
% The same stuff as for the other comment commands.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{keywordcomment}
|
|
{\lst@MakeKeywordArg{#1}\let\lst@KCkeywords\lst@arg %
|
|
\let\lst@DefKC\lstCC@KeywordComment}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@Aspect{doublekeywordcommentsemicolon}{\lstDKCS@#1}
|
|
\gdef\lstDKCS@#1#2#3%
|
|
{\lst@MakeKeywordArg{#1}\let\lst@KCAkeywordsB\lst@arg %
|
|
\lst@MakeKeywordArg{#2}\let\lst@KCAkeywordsE\lst@arg %
|
|
\lst@MakeKeywordArg{#3}\let\lst@KCBkeywordsB\lst@arg %
|
|
\let\lst@DefKC\lstCC@DoubleKeywordCommentS}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SelectCharTable}{\lst@DefKC}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@ifsensitive\else %
|
|
\lst@MakeMacroUppercase\lst@KCkeywords %
|
|
\lst@MakeMacroUppercase\lst@KCAkeywordsB %
|
|
\lst@MakeMacroUppercase\lst@KCAkeywordsE %
|
|
\lst@MakeMacroUppercase\lst@KCBkeywordsB %
|
|
\fi}
|
|
\lst@AddToHook{SetLanguage}{%
|
|
\let\lst@DefKC\relax \let\lst@KCkeywords\@undefined %
|
|
\let\lst@KCAkeywordsB\@undefined \let\lst@KCAkeywordsE\@undefined %
|
|
\let\lst@KCBkeywordsB\@undefined}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@KeywordComment}
|
|
% For this type of keyword comments we save the old output macro and install a new one.
|
|
% Note that |\lstCC@KeywordComment| is executed after selecting the character table via |\lst@DefKC|.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@KeywordComment{%
|
|
\let\lst@Output@\lst@Output \let\lst@Output\lst@KCOutput}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@KCOutput}
|
|
% And now we look how the output works here.
|
|
% It starts as all the time.
|
|
% But if the current character sequence in |\lst@token| is one of the given keywords, we call a macro which starts and ends keyword comments.
|
|
% |\lst@next| is redefined there.
|
|
% After doing all this, we output the token as usual and go on.
|
|
% \begin{macrocode}
|
|
\gdef\lst@KCOutput{%
|
|
\ifnum\lst@length=\z@\else %
|
|
\let\lst@next\relax %
|
|
\expandafter\lst@IfOneOf \the\lst@token\relax \lst@KCkeywords %
|
|
{\lst@KCOutput@\lst@BeginKC}{}%
|
|
\lst@Output@ \lst@next %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@KCOutput@}
|
|
% Now we are in the situation that the current token is attached to a keyword comment.
|
|
% By default |\lst@next| becomes equivalent to the first argument, which is either |\lst@BeginKC| or |\lst@BeginDKCA| or |\lst@BeginDKCB|.
|
|
% Moreover we save the current token.
|
|
% \begin{macrocode}
|
|
\gdef\lst@KCOutput@#1{\let\lst@next#1%
|
|
\expandafter\def\expandafter\lst@save\expandafter{\the\lst@token}%
|
|
% \end{macrocode}
|
|
% If we are not in 'keyword comment mode', nothing else is done here.
|
|
% But if we are, we must end the comment.
|
|
% The problem: Closing the comment group also ruins the current character string in |\lst@token|.
|
|
% The solution: We define a global macro to restore the token and |\lst@length|.
|
|
% |\@gtempa| becomes
|
|
% \begin{itemize}\item[]
|
|
% |\lst@token{|\meta{current character string}|}\lst@length|\meta{current length}|\relax|
|
|
% \end{itemize}
|
|
% \begin{macrocode}
|
|
\lst@ifmode \ifnum\lst@mode=\lst@KCmode %
|
|
\xdef\@gtempa{%
|
|
\noexpand\lst@token{\the\lst@token}%
|
|
\noexpand\lst@length\the\lst@length\relax}%
|
|
% \end{macrocode}
|
|
% This macro is executed after closing the comment group.
|
|
% We redefine |\lst@next| just to |\relax|.
|
|
% \begin{macrocode}
|
|
\aftergroup\@gtempa \lst@LeaveMode \let\lst@next\relax %
|
|
\fi \fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@BeginKC}
|
|
% We call |\lstCC@BeginComment| and define |\lst@KCkeywords| to be the current token (possibly made upper case) since we want a matching keyword.
|
|
% Note: It's a local definition, i.e.\ after ending the comment all comment starting keywords are restored.
|
|
% \begin{macrocode}
|
|
\gdef\lst@BeginKC{%
|
|
\lstCC@BeginComment\lst@KCmode \let\lst@KCkeywords\lst@save %
|
|
\lst@ifsensitive\else \lst@MakeMacroUppercase\lst@KCkeywords \fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@DoubleKeywordCommentS}
|
|
% Let's look at the next macro collection.
|
|
% The first macro is the same as the first from above --- except that we must install a different semicolon, which is done at the very beginning.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@DoubleKeywordCommentS{%
|
|
\lstCC@EndKeywordComment{"003B}%
|
|
\let\lst@Output@\lst@Output \let\lst@Output\lst@DKCOutput}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@DKCOutput}
|
|
% The second macro is also the same as above, but if we haven't found a keyword from the |KCA| list, we try the |KCB| list.
|
|
% \begin{macrocode}
|
|
\gdef\lst@DKCOutput{%
|
|
\ifnum\lst@length=\z@\else %
|
|
\let\lst@next\relax %
|
|
\expandafter\lst@IfOneOf \the\lst@token\relax\lst@KCAkeywordsB %
|
|
{\lst@KCOutput@\lst@BeginDKCA}{%
|
|
\expandafter\lst@IfOneOf \the\lst@token\relax\lst@KCBkeywordsB %
|
|
{\lst@KCOutput@\lst@BeginDKCB}{}}%
|
|
\lst@Output@ \lst@next %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@BeginDKCA}
|
|
% \begin{macro}{\lst@BeginDKCB}
|
|
% To begin a keyword comment, we assign appropiate lists of keywords, which might end the comment.
|
|
% \begin{macrocode}
|
|
\gdef\lst@BeginDKCA{\lstCC@BeginComment\lst@KCmode %
|
|
\let\lst@KCAkeywordsB\lst@KCAkeywordsE \let\lst@KCBkeywordsB\@empty}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\gdef\lst@BeginDKCB{\lstCC@BeginComment\lst@KCmode %
|
|
\let\lst@KCAkeywordsB\@empty \let\lst@KCBkeywordsB\@empty}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@EndKeywordComment}
|
|
% Above we've installed a 'end keyword comment' semicolon.
|
|
% Before reading further you should be familiar with section \ref{iCharacterTables}.
|
|
% Roughly speaking we define commands there, which annouces the source code character $0041_{\mathrm{hex}}$='A' to be the upper case letter 'A'.
|
|
% The macro here announces a character to end keyword comments.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@EndKeywordComment#1{%
|
|
\lccode`\~=#1\lowercase{\lstCC@EndKeywordComment@~}{#1}}
|
|
% \end{macrocode}
|
|
% Looking at the submacro, |#1| is an active character with ASCII code |#2|.
|
|
% We must save a previous meaning of |#1| --- or we couldn't output the character since we've forgotten it.
|
|
% Afterwards we can redefine it: If we are in comment mode and furthermore in keyword comment mode, the 'end keyword comment' character ends the comment, as desired.
|
|
% Note that we output the old meaning of the character first.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@EndKeywordComment@#1#2{%
|
|
\expandafter\let\csname lstCC@EKC#2\endcsname#1%
|
|
\def#1{%
|
|
\ifnum\lst@mode=\lst@KCmode %
|
|
\let\lstCC@next\lstCC@EndComment %
|
|
\else %
|
|
\let\lstCC@next\relax %
|
|
\fi %
|
|
\csname lstCC@EKC#2\endcsname \lstCC@next}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</keywordcomments>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{Character classes}\label{iCharacterClasses}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \TeX{} knows sixteen category codes.
|
|
% We define our own character classes here.
|
|
% Each input character becomes active in the sense of \TeX{} and characters of different classes expand to different meanings.
|
|
% We use the following ones:
|
|
% \begin{itemize}
|
|
% \item letters --- characters identifiers are of;
|
|
% \item digits --- characters for identifiers or numerical constants;
|
|
% \item spaces --- characters treated as blank spaces;
|
|
% \item tabulators --- characters treated as tabulators;
|
|
% \item stringizers --- characters beginning and ending strings;
|
|
% \item comment indicators --- characters or character sequences beginning and ending comments;
|
|
% \item special classes support particular programming languages;
|
|
% \item others --- all other characters.
|
|
% \end{itemize}
|
|
% How these classes work together?
|
|
% The digit '3' appends the digit to the current character string, e.g.\ |ear| becomes |ear3|.
|
|
% The next nonletter causes the output of the gathered characters.
|
|
% Then we collect all coming nonletters until reaching a letter again.
|
|
% This causes the output of the nonletters, and so on.
|
|
%
|
|
% But there are more details.
|
|
% Stringizers and comment indicators change the processing mode until the string or the comment is over.
|
|
% For example, no keyword tests are done within a string or comment.
|
|
% A tabulator immediately outputs the gathered characters, without looking whether they are letters or not.
|
|
% Afterwards it is possible to determine the tabulator skip.
|
|
% And there is one thing concerning spaces:
|
|
% Many spaces following each other disturb the column alignment since they are not wide enough.
|
|
% Hence, when column alignment is on, we output the space(s) preceding a space.
|
|
%
|
|
% The above classes can be divided into three types:
|
|
% \begin{itemize}
|
|
% \item The 'letter', 'digit' and 'other' class all put characters into the 'output queue' (using |\lstCC@Append| or |\lstCC@AppendOther|, see below).
|
|
% \item Stringizer, comment indicators and special classes don't affect the output queue directly.
|
|
% For example, before a character becomes a stringizer, the 'letter', 'digit' or 'other' meaning is saved.
|
|
% Now the stringizer accesses the output queue via this saved meaning.
|
|
% \item Spaces and tabulators don't put any character into the output queue, but may affect the queue to do their job, as mentioned above.
|
|
% Instances of these classes are not overwritten (in contrast to letters, digits and others).
|
|
% \end{itemize}
|
|
% Some easy implementation before looking closer \ldots
|
|
%
|
|
% \begin{macro}{\lstCC@Append}
|
|
% This macro appends the argument to the current character string and increases the counter |\lst@length|.
|
|
% \begin{macrocode}
|
|
\def\lstCC@Append#1{\advance\lst@length\@ne %
|
|
\expandafter\lst@token\expandafter{\the\lst@token#1}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@AppendOther}
|
|
% Nearly the same, but we save the argument (a single character or a single macro) in |\lst@lastother|.
|
|
% \begin{macrocode}
|
|
\def\lstCC@AppendOther#1{\advance\lst@length\@ne \let\lst@lastother#1%
|
|
\expandafter\lst@token\expandafter{\the\lst@token#1}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ifletter}
|
|
% This \texttt{if} indicates whether the last character has been a letter or not.
|
|
% \begin{macrocode}
|
|
\def\lstCC@lettertrue{\let\lstCC@ifletter\iftrue}
|
|
\def\lstCC@letterfalse{\let\lstCC@ifletter\iffalse}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{InitVars}{\lstCC@letterfalse}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@PrintToken}
|
|
% This macro outputs the current character string in letter or nonletter mode.
|
|
% \begin{macrocode}
|
|
\def\lst@PrintToken{%
|
|
\lstCC@ifletter %
|
|
\lst@Output\lstCC@letterfalse %
|
|
\else %
|
|
\lst@OutputOther \let\lst@lastother\@empty %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Character tables}\label{iCharacterTables}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% Before looking at interesting character classes we do some rather tedious coding.
|
|
% Consider a source file of a programming language now.
|
|
% For example, the character $41_{\mathrm{hex}}=65_{\mathrm{dec}}$ usually belongs to the letter class and represents the letter 'A'.
|
|
% The listings package says |\lstCC@Use\lstCC@ProcessLetter|\ldots|{"41}{A}|\ldots\ to make this clear.
|
|
% Roughly speaking it expands to |\def A{\lstCC@ProcessLetter A}|, but the first 'A' is active and the second not.
|
|
%
|
|
% \begin{macro}{\lstCC@Def}
|
|
% \begin{macro}{\lstCC@Let}
|
|
% For speed we won't used these helpers too often.
|
|
% The letter 'A' definition from above could be achieved via |\lstCC@Def{"41}{\lstCC@ProcessLetter A}|.
|
|
% \begin{macrocode}
|
|
\def\lstCC@Def#1{\catcode#1=\active\lccode`\~=#1\lowercase{\def~}}
|
|
\def\lstCC@Let#1{\catcode#1=\active\lccode`\~=#1\lowercase{\let~}}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@SelectCharTable}
|
|
% Each input character becomes active and gets the correct meaning here.
|
|
% We change locally the catcode of the double quote for compatibility with \texttt{german.sty}.
|
|
% Note that some macros take one argument and others a series of arguments which is terminated by |{"00}{}| (or an equivalent expression).
|
|
% \begin{macrocode}
|
|
\begingroup \catcode`\"=12
|
|
\gdef\lst@SelectCharTable{%
|
|
\lstCC@Tabulator{"09}%
|
|
\lstCC@Space{"20}%
|
|
\lstCC@Use \lstCC@ProcessOther %
|
|
{"21}!{"22}"{"23}\#{"25}\%{"26}\&{"27}'{"28}({"29})%
|
|
{"2A}\lst@asterisk{"2B}+{"2C},{"2D}\lst@minus{"2E}.%
|
|
{"2F}/{"3A}:{"3B};{"3C}\lst@less{"3D}={"3E}\lst@greater{"3F}?%
|
|
{"5B}[{"5C}\lst@backslash{"5D}]{"5E}\textasciicircum{"60}{`}%
|
|
{"7B}\lst@lbrace{"7C}\lst@bar{"7D}\lst@rbrace %
|
|
{"7E}\textasciitilde{"7F}-%
|
|
\z@\@empty %
|
|
\lstCC@Use \lstCC@ProcessDigit %
|
|
{"30}0{"31}1{"32}2{"33}3{"34}4{"35}5{"36}6{"37}7{"38}8{"39}9%
|
|
\z@\@empty %
|
|
\lstCC@Use \lstCC@ProcessLetter %
|
|
{"24}\lst@dollar{"40}@%
|
|
{"41}A{"42}B{"43}C{"44}D{"45}E{"46}F{"47}G{"48}H{"49}I{"4A}J%
|
|
{"4B}K{"4C}L{"4D}M{"4E}N{"4F}O{"50}P{"51}Q{"52}R{"53}S{"54}T%
|
|
{"55}U{"56}V{"57}W{"58}X{"59}Y{"5A}Z{"5F}\lst@underscore %
|
|
{"61}a{"62}b{"63}c{"64}d{"65}e{"66}f{"67}g{"68}h{"69}i{"6A}j%
|
|
{"6B}k{"6C}l{"6D}m{"6E}n{"6F}o{"70}p{"71}q{"72}r{"73}s{"74}t%
|
|
{"75}u{"76}v{"77}w{"78}x{"79}y{"7A}z%
|
|
\z@\@empty %
|
|
% \end{macrocode}
|
|
% Define extended characters 128--255.
|
|
% \begin{macrocode}
|
|
\lstCC@ifec \lstCC@DefEC \fi %
|
|
% \end{macrocode}
|
|
% Finally we call some (hook) macros and initialize the backslash if necessary.
|
|
% \begin{macrocode}
|
|
\lsthk@SelectCharTable %
|
|
\csname lstSCT@\lst@language\endcsname %
|
|
\csname lstSCT@\lst@language @\lst@dialect\endcsname %
|
|
\ifx\lstCC@Backslash\relax\else %
|
|
\lccode`\~="5C\lowercase{\let\lsts@backslash~}%
|
|
\lstCC@Let{"5C}\lstCC@Backslash %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@DefEC}
|
|
% Currently each character in the range 128--255 is treated as a letter.
|
|
% \begin{macrocode}
|
|
\catcode`\^^@=12
|
|
\gdef\lstCC@DefEC{%
|
|
\lstCC@ECUse \lstCC@ProcessLetter %
|
|
^^80^^81^^82^^83^^84^^85^^86^^87^^88^^89^^8a^^8b^^8c^^8d^^8e^^8f%
|
|
^^90^^91^^92^^93^^94^^95^^96^^97^^98^^99^^9a^^9b^^9c^^9d^^9e^^9f%
|
|
^^a0^^a1^^a2^^a3^^a4^^a5^^a6^^a7^^a8^^a9^^aa^^ab^^ac^^ad^^ae^^af%
|
|
^^b0^^b1^^b2^^b3^^b4^^b5^^b6^^b7^^b8^^b9^^ba^^bb^^bc^^bd^^be^^bf%
|
|
^^c0^^c1^^c2^^c3^^c4^^c5^^c6^^c7^^c8^^c9^^ca^^cb^^cc^^cd^^ce^^cf%
|
|
^^d0^^d1^^d2^^d3^^d4^^d5^^d6^^d7^^d8^^d9^^da^^db^^dc^^dd^^de^^df%
|
|
^^e0^^e1^^e2^^e3^^e4^^e5^^e6^^e7^^e8^^e9^^ea^^eb^^ec^^ed^^ee^^ef%
|
|
^^f0^^f1^^f2^^f3^^f4^^f5^^f6^^f7^^f8^^f9^^fa^^fb^^fc^^fd^^fe^^ff%
|
|
^^00}
|
|
\endgroup
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{extendedchars}
|
|
% The user aspect.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{extendedchars}[t]{\lstKV@SetIfKey\lstCC@ifec{#1}}
|
|
\lstset{extendedchars=false}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@Use}
|
|
% Now we define the |\lstCC@|\ldots|Use| macros used above.
|
|
% We either define the character with code |#2| to be |#1#3| (where |#1| is |\lstCC@ProcessLetter| for example) or we gobble the two token after |\fi| to terminate the loop.
|
|
% \begin{macrocode}
|
|
\def\lstCC@Use#1#2#3{%
|
|
\ifnum#2=\z@ %
|
|
\expandafter\@gobbletwo %
|
|
\else %
|
|
\catcode#2=\active \lccode`\~=#2\lowercase{\def~}{#1#3}%
|
|
\fi %
|
|
\lstCC@Use#1}
|
|
% \end{macrocode}
|
|
% Limitation: Each second argument to |\lstCC@Use| (beginning with the third one) must be exactly one character or one control sequence.
|
|
% The reason is not the definition here.
|
|
% |\lst@AppendOther| says |\let\lst@lastother#1| and that works with the mentioned limitation only.
|
|
% I'll get over this since |\let| is faster than |\def|, and that's the motivation.
|
|
% \emph{Caution}: Don't change that |\let| to a definition with |\def|.
|
|
% All |\ifx\lst@lastother|\ldots{} in all character classes wouldn't work any more!
|
|
% And rewriting all this would slow down the package.
|
|
% Beware of that.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ECUse}
|
|
% Here we have two arguments only, namely |\lstCC@ProcessLetter|,\ldots\ and the character (and no character code).
|
|
% Reaching end of list (|^^00|) we terminate the loop.
|
|
% Otherwise we do the same as in |\lstCC@Use| if the character is not active.
|
|
% But if the character is active, we save the meaning before redefinition.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ECUse#1#2{%
|
|
\ifnum`#2=\z@ %
|
|
\expandafter\@gobbletwo %
|
|
\else %
|
|
\ifnum\catcode`#2=\active %
|
|
\lccode`\~=`#2\lccode`\/=`#2\lowercase{\lstCC@ECUse@#1~/}%
|
|
\else %
|
|
\catcode`#2=\active \lccode`\~=`#2\lowercase{\def~}{#1#2}%
|
|
\fi %
|
|
\fi %
|
|
\lstCC@ECUse#1}
|
|
% \end{macrocode}
|
|
% As mentioned, we save the meaning before redefinition.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ECUse@#1#2#3{%
|
|
\expandafter\let\csname lsts@EC#3\endcsname #2%
|
|
\edef#2{\noexpand#1\expandafter\noexpand\csname lsts@EC#3\endcsname}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@Tabulator}
|
|
% \begin{macro}{\lstCC@Space}
|
|
% The similar space and tabulator macros have one argument only (no loop and no macro or character).
|
|
% \begin{macrocode}
|
|
\def\lstCC@Tabulator#1{\lstCC@Let{#1}\lstCC@ProcessTabulator}
|
|
\def\lstCC@Space#1{\lstCC@Let{#1}\lstCC@ProcessSpace}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ChangeBasicClass}
|
|
% Finally we define a macro (collection) with the ability of moving a basic \emph{instance} of class to another class, e.g. making the digit '0' be a letter.
|
|
% The word 'basic' means any instance defined with |\lstCC@Use| or |\lstCC@ECUse|.
|
|
% The first argument of |\lstCC@ChangeBasicClass| gives the new class and the second argument is a macro containing a character sequence.
|
|
% These characters are changed.
|
|
% First we make all these characters active and call a submacro.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ChangeBasicClass#1#2{%
|
|
\ifx\@empty#2\else %
|
|
\expandafter\lst@MakeActive\expandafter{#2}%
|
|
\expandafter\lstCC@CBC@\expandafter#1\lst@arg\@empty %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% The submacro terminates (gobble two token after |\fi|) if it reaches |\@empty|.
|
|
% Otherwise another submacro redfines the character.
|
|
% Note that we expand the old meaning before calling the second submacro and that the second |\lstCC@CBC@@| is used as 'meaning' delimiter.
|
|
% \begin{macrocode}
|
|
\def\lstCC@CBC@#1#2{%
|
|
\ifx\@empty#2%
|
|
\expandafter\@gobbletwo %
|
|
\else %
|
|
\expandafter\lstCC@CBC@@#2\lstCC@CBC@@#1#2%
|
|
\fi %
|
|
\lstCC@CBC@#1}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lstCC@CBC@@#1#2\lstCC@CBC@@#3#4{\def#4{#3#2}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Letters, digits and others}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lstCC@ProcessLetter}
|
|
% To process a letter we look at the last character.
|
|
% If it hasn't been a letter, we output the preceding other characters first and switch to letter mode.
|
|
% Finally we append the current letter |#1|.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessLetter#1{%
|
|
\lstCC@ifletter\else \lst@OutputOther\lstCC@lettertrue \fi %
|
|
\lstCC@Append{#1}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessOther}
|
|
% 'Other' characters are the other way round.
|
|
% If the last character has been a letter, the preceding letters are output and we switch to nonletter mode.
|
|
% Finally we append the current other character.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessOther#1{%
|
|
\lstCC@ifletter \lst@Output\lstCC@letterfalse \fi %
|
|
\lstCC@AppendOther{#1}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessDigit}
|
|
% A digit simply appends the character to the current character string.
|
|
% But we must use the right macro.
|
|
% This allow digits to be part of an identifier or a numerical constant.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessDigit#1{%
|
|
\lstCC@ifletter \lstCC@Append{#1}\else \lstCC@AppendOther{#1}\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Tabulators and spaces}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% Here we have to take care of two things:
|
|
% First dropping empty lines at the end of a listing, and second the flexible column format.
|
|
% In both cases we use |\lst@lostspace| for the implementation.
|
|
% Whenever this dimension is positive we insert that space before |\lst@token| is output.
|
|
%
|
|
% We've defined |\lst@EOLUpdate| to drop empty lines at the end of a listing.
|
|
% |\lst@NewLine| isn't executed or reset in that case.
|
|
% Instead we append control sequences.
|
|
% But: Lines containing tabulators and spaces only should also be viewed as empty.
|
|
% In order to achieve this tabulators and spaces at the beginning of a line advance |\lst@lostspace| and don't output any characters.
|
|
% The space is inserted if there comes a letter for example.
|
|
% If there are only tabulators and spaces, the line is 'empty' since we haven't done any output.
|
|
%
|
|
% We have to do more for flexible columns.
|
|
% The whitespaces can fix the column alignment:
|
|
% If the real line is wider than it should be (|\lst@lostspace|$<$0pt), a tabulator is at least one space wide; all the other width is used to make |\lst@lostspace| more positive.
|
|
% Spaces do the same: If there are two or more spaces, at least one space is printed; the others fix the column alignment.
|
|
% If we process a string, all spaces are output, of course.
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessTabulator}
|
|
% A tabulator outputs the preceding characters.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessTabulator{%
|
|
\lst@PrintToken %
|
|
% \end{macrocode}
|
|
% Then we must calculate how many columns we need to reach the next tabulator stop.
|
|
% Each printed character decrements the counter |\lst@pos|.
|
|
% Hence we can simply add |\lst@tabsize| until |\lst@pos| is strict positive.
|
|
% That's all.
|
|
% We assign it to |\lst@length|, reset |\lst@pos| \ldots
|
|
% \begin{macrocode}
|
|
\global\advance\lst@column -\lst@pos %
|
|
\@whilenum \lst@pos<\@ne \do %
|
|
{\global\advance\lst@pos\lst@tabsize}%
|
|
\lst@length\lst@pos \global\lst@pos\z@ %}
|
|
% \end{macrocode}
|
|
% and go to the tabulator stop, e.g.\ |\lst@length| columns forward:
|
|
% \begin{macrocode}
|
|
\lst@GotoTabStop}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@AppendSpecialSpace}
|
|
% Sometimes we have special spaces:
|
|
% If there are at least two spaces, i.e.\ if the last character have been a space, we output preceding characters and advance |\lst@lostspace| to avoid alignment problems.
|
|
% Otherwise we append a space to the current character string.
|
|
% We'll need that macro soon.
|
|
% \begin{macrocode}
|
|
\def\lstCC@AppendSpecialSpace{%
|
|
\ifx\lst@lastother\lst@outputblank %
|
|
\lst@OutputOther %
|
|
\global\advance\lst@lostspace\lst@width %
|
|
\global\advance\lst@pos\m@ne %
|
|
\else %
|
|
\lstCC@AppendOther\lst@outputblank %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lst@outputblank}
|
|
% It's better not to forget this.
|
|
% \begin{macrocode}
|
|
\def\lst@outputblank{\ }
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessSpace}
|
|
% If the last character has been a letter, we output the current character string and append one space.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessSpace{%
|
|
\lstCC@ifletter %
|
|
\lst@Output\lstCC@letterfalse %
|
|
\lstCC@AppendOther\lst@outputblank %
|
|
% \end{macrocode}
|
|
% Otherwise we look whether we are in string mode or not.
|
|
% In the first case we must append a space; in the second case we must test if the hitherto line is empty.
|
|
% \begin{macrocode}
|
|
\else \ifnum\lst@mode=\lst@stringmode %
|
|
\lstCC@AppendOther\lst@outputblank %
|
|
\else \ifx\lst@NewLine\relax %
|
|
% \end{macrocode}
|
|
% If the line is not empty we either advance |\lst@lostspace| or append a space to the current character string.
|
|
% \begin{macrocode}
|
|
\lstCC@AppendSpecialSpace %
|
|
\else \ifnum\lst@length=\z@ %
|
|
% \end{macrocode}
|
|
% If the line is empty so far, we advance |\lst@lostspace|.
|
|
% Otherwise we append the space.
|
|
% \begin{macrocode}
|
|
\global\advance\lst@lostspace\lst@width %
|
|
\global\advance\lst@pos\m@ne %
|
|
\else %
|
|
\lstCC@AppendSpecialSpace %
|
|
\fi %
|
|
\fi \fi \fi}
|
|
% \end{macrocode}
|
|
% Note that this version works for fixed and flexible column output.
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Stringizer}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lst@legalstringizer}
|
|
% Currently there are three different stringizer types: 'd'oubled, 'b'ackslashed and 'm'atlabed.
|
|
% The naming of the first two is due to how the stringizer is represented in a string.
|
|
% Pascal doubles it, i.e.\ the string |'| is represented by four single quotes |''''|, where the first and last enclose the string and the two middle quotes represent the desired stringizer.
|
|
% In C++ we would write |"\""|: A backslash indicates that the next double quote belongs to the string and is not the end of string.
|
|
% The matlabed version is described below.
|
|
% I introduced it after communication with \lsthelper{Zvezdan V. Petkovic}{zpetkovic@acm.org}{1997/11/26}{'single stringizer' not a stringizer in Ada (and Matlab)}.
|
|
% \begin{macrocode}
|
|
\def\lst@legalstringizer{d,b,m,bd,db}
|
|
% \end{macrocode}
|
|
% Furthermore we have the two mixed types |bd| and |db|, which in fact equal |b|.
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{stringizer}
|
|
% Here we test whether the user type is supported or not (leading to an error message).
|
|
% In the first case we (re-) define |\lst@DefStrings|.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{stringizer}{\lstKV@OptArg\lststringizer@[d]{#1}}
|
|
\def\lststringizer@[#1]#2%
|
|
{\lst@IfOneOf#1\relax \lst@legalstringizer %
|
|
{\def\lst@DefStrings{\lstCC@Stringizer[#1]#2\@empty}}%
|
|
{\PackageError{Listings}{Illegal stringizer type `#1'}%
|
|
{Available types are \lst@legalstringizers.}}}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@DefStrings\@empty}
|
|
\lst@AddToHook{SelectCharTable}{\lst@DefStrings}
|
|
% \end{macrocode}
|
|
% The just added hook defines the strings after selecting the standard character table.
|
|
% This adjusts the character table to the user's demands.
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@Stringizer}
|
|
% This macro is similar to |\lstCC@ECUse|, but we build the 'use'd name before defining the characters \ldots
|
|
% \begin{macrocode}
|
|
\def\lstCC@Stringizer[#1]{%
|
|
\expandafter\lstCC@Stringizer@ %
|
|
\csname lstCC@ProcessStringizer@#1\endcsname}
|
|
\def\lstCC@Stringizer@#1#2{%
|
|
\ifx\@empty#2%
|
|
\expandafter\@gobbletwo %
|
|
% \end{macrocode}
|
|
% which is terminated by |\@empty|.
|
|
% Otherwise we save the old meaning in |\lsts@s|\meta{the character} (with catcode 12) and redefine it.
|
|
% \begin{macrocode}
|
|
\else %
|
|
\catcode`#2=\active \lccode`\~=`#2\lccode`\/=`#2%
|
|
\lowercase{%
|
|
\expandafter\let\csname lsts@s/\endcsname~%
|
|
\def~{#1/}}%
|
|
\fi %
|
|
\lstCC@Stringizer@#1}
|
|
% \end{macrocode}
|
|
% And now we define all 'process stringizer' macros.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessStringizer@d}
|
|
% 'd' means no extra work.
|
|
% Reaching the (first) stringizer enters string mode and coming to the next leaves it, and so on.
|
|
% Then the character sequence |''''| produces the right output:
|
|
% The second quote leaves string mode, but we enter it immediately since the stringizer is doubled.
|
|
% And now the implementation.
|
|
% First we output any preceding letters.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessStringizer@d#1{%
|
|
\lstCC@ifletter \lst@Output\lstCC@letterfalse \fi %
|
|
% \end{macrocode}
|
|
% If we already process a string, we execute the saved meaning and look whether the last other (that's the stringizer) is the matching stringizer --- a single quote must not end a string starting with a double quote.
|
|
% The macro |\lstCC@EndString| is defined at the end of this section.
|
|
% \begin{macrocode}
|
|
\ifnum\lst@mode=\lst@stringmode %
|
|
\csname lsts@s#1\endcsname %
|
|
\ifx\lst@lastother\lstCC@closestring %
|
|
\lstCC@EndString %
|
|
\fi %
|
|
\else %
|
|
\lst@OutputOther %
|
|
% \end{macrocode}
|
|
% If we don't process a string, we test whether or not a string is allowed.
|
|
% |\lstCC@BeginString| enters string mode and defines the closing stringizer.
|
|
% This 'begin string' macro gets one argument, hence we expand the control sequence name before executing the macro (if necessary).
|
|
% \begin{macrocode}
|
|
\lst@ifmode\else %
|
|
\expandafter\expandafter\expandafter\lstCC@BeginString %
|
|
\fi %
|
|
\csname lsts@s#1\endcsname %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessStringizer@b}
|
|
% 'b' means an extra if: Only if the last other is not a backslash (5-th line) the stringizer can close the string.
|
|
% The rest is the same as above.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessStringizer@b#1{%
|
|
\lstCC@ifletter \lst@Output\lstCC@letterfalse \fi %
|
|
\ifnum\lst@mode=\lst@stringmode %
|
|
\let\lst@temp\lst@lastother \csname lsts@s#1\endcsname %
|
|
\ifx\lst@temp\lst@backslash\else %!def of "005C
|
|
\ifx\lst@lastother\lstCC@closestring %
|
|
\lstCC@EndString %
|
|
\fi \fi %
|
|
\else %
|
|
\lst@OutputOther %
|
|
\lst@ifmode\else %
|
|
\expandafter\expandafter\expandafter\lstCC@BeginString %
|
|
\fi %
|
|
\csname lsts@s#1\endcsname %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessStringizer@bd}
|
|
% \begin{macro}{\lstCC@ProcessStringizer@db}
|
|
% are just the same and the same as |\lstCC@ProcessStringizer@b|:
|
|
% \begin{macrocode}
|
|
\let\lstCC@ProcessStringizer@bd\lstCC@ProcessStringizer@b
|
|
\let\lstCC@ProcessStringizer@db\lstCC@ProcessStringizer@bd
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessStringizer@m}
|
|
% 'm'atlabed is designed for programming languages where stringizers (for character or string literals) are also used for other purposes, like Matlab or Ada.
|
|
% Here we enter string mode only if the last character has not been a letter and has not been a right parenthesis.
|
|
% Hence, we have to move the |\lstCC@ifletter| and change the main |\else| part.
|
|
% By the way: The stringizer is doubled in a string.
|
|
% \begin{macrocode}
|
|
\def\lstCC@ProcessStringizer@m#1{%
|
|
\ifnum\lst@mode=\lst@stringmode %
|
|
\lstCC@ifletter \lst@Output\lstCC@letterfalse \fi %
|
|
\csname lsts@s#1\endcsname %
|
|
\ifx\lst@lastother\lstCC@closestring %
|
|
\lstCC@EndString %
|
|
\fi %
|
|
\else %
|
|
% \end{macrocode}
|
|
% And now the real 'm' changes:
|
|
% \begin{macrocode}
|
|
\lstCC@ifletter %
|
|
\lst@Output\lstCC@letterfalse %
|
|
\else %
|
|
\lst@OutputOther %
|
|
\let\lstCC@next\relax %
|
|
\ifx\lst@lastother)\else \lst@ifmode\else %
|
|
\let\lstCC@next\lstCC@BeginString %
|
|
\fi \fi %
|
|
\expandafter\expandafter\expandafter\lstCC@next %
|
|
\fi %
|
|
\csname lsts@s#1\endcsname %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{stringstyle}
|
|
% \begin{aspect}{blankstring}
|
|
% We insert some easy definitions.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{stringstyle}{\def\lst@stringstyle{#1}}
|
|
% \end{macrocode}
|
|
% Thanks to \lsthelper{Knut M\"uller}{knut@physik3.gwdg.de}{1997/04/28}{\blankstringtrue} for reporting problem with |\blankstringtrue|.
|
|
% The problem has gone.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{blankstring}[t]{\lstKV@SetIfKey\lst@ifblankstring{#1}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{blankstring=false}% init
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\setbox\@tempboxa\hbox{\lst@stringstyle \lst@loadfd}}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@stringmode}
|
|
% It's time for a new mode allocation:
|
|
% \begin{macrocode}
|
|
\lst@NewMode\lst@stringmode
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@BeginString}
|
|
% \begin{macro}{\lstCC@EndString}
|
|
% To activate string mode we do te usual things, but here we also assign the correct closing stringizer and |\lst@outputblank|.
|
|
% Note that you know that |\lst@NewLine| deactivates itself.
|
|
% \begin{macrocode}
|
|
\def\lstCC@BeginString#1{%
|
|
\lst@NewLine %
|
|
\lst@EnterMode{\lst@stringmode}{\lst@modetrue\lst@stringstyle}%
|
|
#1%
|
|
\let\lstCC@closestring\lst@lastother %
|
|
\lst@ifblankstring\else \let\lst@outputblank\textvisiblespace \fi}
|
|
% \end{macrocode}
|
|
% We terminate that mode selection after printing the collected other characters --- at least the closing stringizer.
|
|
% And we reset some registers.
|
|
% \begin{macrocode}
|
|
\def\lstCC@EndString{%
|
|
\lst@OutputOther \lst@LeaveMode \lst@token{}\lst@length\z@}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{aspect}{stringtest}
|
|
% We |\let| the test macro |\relax| if necessary.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{stringtest}[t]{\lstKV@SetIfKey\lst@ifstringtest{#1}}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@ifstringtest\iftrue}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\lst@ifstringtest\else \let\lst@TestStringMode\relax \fi}
|
|
% \end{macrocode}
|
|
% Default definition of the test macro:
|
|
% \begin{macrocode}
|
|
\def\lst@TestStringMode{%
|
|
\ifnum\lst@mode=\lst@stringmode %
|
|
\PackageWarning{Listings}{String constant exceeds line}%
|
|
\lst@LeaveMode \lst@token{}\lst@length\z@ %
|
|
\fi}
|
|
\lst@AddToHook{EOL}{\lst@TestStringMode}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Comments}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{commentstyle}
|
|
% Again we start with an easy definition.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{commentstyle}{\def\lst@commentstyle{#1}}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\setbox\@tempboxa\hbox{\lst@commentstyle \lst@loadfd}}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@BeginComment}
|
|
% \begin{macro}{\lstCC@@BeginComment}
|
|
% \begin{macro}{\lstCC@EndComment}
|
|
% These macros start and end a comment, respectively.
|
|
% The |@@| version also eat (and output) one or two characters.
|
|
% In that case the characters belong to the comment indicator.
|
|
% |\relax| ensures that the characters are really eaten, i.e.\ the characters can't end the current comment or start a new one.
|
|
% Note again that |\lst@NewLine| deactivates itself.
|
|
% \begin{macrocode}
|
|
\def\lstCC@BeginComment#1{%
|
|
\lst@NewLine \lst@PrintToken %
|
|
\lst@EnterMode{#1}{\lst@modetrue\lst@commentstyle}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lstCC@@BeginComment#1#2#3{%
|
|
\lst@NewLine \lst@PrintToken %
|
|
\lst@EnterMode{#1}{\lst@modetrue\lst@commentstyle}%
|
|
\lst@mode\lst@nomode #2\relax#3\relax \lst@mode#1\relax}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lstCC@EndComment{%
|
|
\lst@PrintToken \lst@LeaveMode \let\lst@lastother\@empty}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@TestCArg}
|
|
% Comment commands allow a single character like |!| or two characters like |//|.
|
|
% The calling syntax of this testing macro is
|
|
% \begin{macrosyntax}
|
|
% \item |\lstCC@TestCArg|\meta{characters to test}|\@empty\relax|\meta{macro}
|
|
% \end{macrosyntax}
|
|
% \meta{macro} is called after doing the test and gets three arguments:
|
|
% The given two characters as active characters (where the second equals |\@empty| if and only if a single character is given), and the third is a catcode 12 version of the first character.
|
|
% \begin{macrocode}
|
|
\begingroup \catcode`\^^@=\active
|
|
\gdef\lstCC@TestCArg#1#2#3\relax#4{%
|
|
\lccode`\~=`#1\lccode`\/=`#1%
|
|
\ifx\@empty#2%
|
|
\lowercase{\def\lst@temp{~\@empty/}}%
|
|
\else \lccode`\^^@=`#2%
|
|
\lowercase{\def\lst@temp{~^^@/}}%
|
|
\fi %
|
|
% \end{macrocode}
|
|
% If neither |#2| nor |#3| equals |\@empty|, the user has given more than two characters:
|
|
% \begin{macrocode}
|
|
\ifx\@empty#2\else \ifx\@empty#3\else \lstCC@TestCArgError \fi\fi %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\expandafter #4\lst@temp}
|
|
\endgroup
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@TestCArgError}
|
|
% \begin{macrocode}
|
|
\def\lstCC@TestCArgError{%
|
|
\PackageError{Listings}{At most 2 characters allowed}%
|
|
{The package doesn't provide more than two characters here.^^J%
|
|
I'll simply use the first two only and proceed.}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@next}
|
|
% \begin{macro}{\lstCC@bnext}
|
|
% \begin{macro}{\lstCC@enext}
|
|
% We initialize some macros used in the sequel.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{BeforeSelectCharTable}
|
|
{\let\lstCC@next\relax \let\lstCC@bnext\relax\let\lstCC@enext\relax}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lst@DefSC}
|
|
% \begin{macro}{\lst@DefNC}
|
|
% \begin{macro}{\lst@DefDC}
|
|
% \begin{macro}{\lst@DefCL}
|
|
% \begin{macro}{\lst@DefFCL}
|
|
% These macros are redefined by comment aspects.
|
|
% The comments are reset every language selection, and every listing we define the comment characters after selecting the standard character table.
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SetLanguage}
|
|
{\let\lst@DefSC\relax \let\lst@DefNC\relax \let\lst@DefDC\relax %
|
|
\let\lst@DefCL\relax \let\lst@DefFCL\relax}
|
|
\lst@AddToHook{SelectCharTable}
|
|
{\lst@DefSC \lst@DefNC \lst@DefDC \lst@DefCL \lst@DefFCL}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}\end{macro}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsubsection{Comment lines}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{commentline}
|
|
% We define the user aspect:
|
|
% \begin{macrocode}
|
|
\lst@Aspect{commentline}{\def\lst@DefCL{\lstCC@CommentLine{#1}}}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@CommentLine}
|
|
% Comment lines become undefined if the one and only argument is empty.
|
|
% \begin{macrocode}
|
|
\def\lstCC@CommentLine#1{%
|
|
\ifx\@empty#1\@empty\else %
|
|
\lstCC@TestCArg#1\@empty\relax\lstCC@CommentLine@ %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% The next submacro actually defines the comment characters.
|
|
% We save the old meaning --- or we couldn't use the original meaning any more.
|
|
% \begin{macrocode}
|
|
\def\lstCC@CommentLine@#1#2#3{%
|
|
\expandafter\let\csname lsts@CL#3\endcsname#1%
|
|
% \end{macrocode}
|
|
% The redefinitions:
|
|
% If a single character indicates a comment, the next operation is either |\relax| (since no mode change is allowed) or |\lstCC@BeginCommentLine|.
|
|
% And we execute the saved character meaning.
|
|
% \begin{macrocode}
|
|
\ifx\@empty#2%
|
|
\def#1{%
|
|
\lst@ifmode \let\lstCC@next\relax \else %
|
|
\let\lstCC@next\lstCC@BeginCommentLine %
|
|
\fi %
|
|
\expandafter\lstCC@next \csname lsts@CL#3\endcsname}%
|
|
\else %
|
|
% \end{macrocode}
|
|
% Comment lines indicated by a sequence of two characters are just the same.
|
|
% But: We enter comment mode (if and) only if the next character equals |#2|.
|
|
% And we use a different macro to enter comment mode.
|
|
% \begin{macrocode}
|
|
\def#1##1{%
|
|
\let\lstCC@next\relax %
|
|
\lst@ifmode\else \ifx##1#2%
|
|
\let\lstCC@next\lstCC@@BeginCommentLine %
|
|
\fi \fi %
|
|
\expandafter\lstCC@next \csname lsts@CL#3\endcsname##1}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{fixedcommentline}
|
|
% \begin{macro}{\lst@FCLmode}
|
|
% Another user aspect \ldots
|
|
% \begin{macrocode}
|
|
\lst@Aspect{fixedcommentline}{\lstKV@OptArg\lstfcommentline@[0]{#1}}
|
|
\def\lstfcommentline@[#1]#2%
|
|
{\def\lst@DefFCL{\lstCC@FixedCL[#1]#2\@empty}}
|
|
% \end{macrocode}
|
|
% and a mode allocation.
|
|
% \begin{macrocode}
|
|
\lst@NewMode\lst@FCLmode
|
|
% \end{macrocode}
|
|
% \end{macro}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@FixedCL}
|
|
% Note that we can't use |\lstCC@TestCArg| here since the argument might consist of more than two characters.
|
|
% We enter a loop which is terminated by |\@empty|.
|
|
% \begin{macrocode}
|
|
\def\lstCC@FixedCL[#1]#2{%
|
|
\ifx\@empty#2\else %
|
|
\lccode`\~=`#2\lccode`\/=`#2%
|
|
\lowercase{\lstCC@FixedCL@~/}{#1}%
|
|
\def\lstCC@next{\lstCC@FixedCL[#1]}%
|
|
\expandafter\lstCC@next %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% But now comes the same as above: We save the old meaning of |#1| and redefine it.
|
|
% We enter comment mode (if and) only if the character is in column |#3|+1.
|
|
% \begin{macrocode}
|
|
\def\lstCC@FixedCL@#1#2#3{%
|
|
\expandafter\let\csname lsts@FCL#2\endcsname#1%
|
|
\def#1{\let\lstCC@next\relax %
|
|
\lst@ifmode\else %
|
|
\@tempcnta\lst@column %
|
|
\advance\@tempcnta\lst@length %
|
|
\advance\@tempcnta-\lst@pos %
|
|
\ifnum\@tempcnta=#3%
|
|
\let\lstCC@next\lstCC@BeginCommentLine %
|
|
\fi %
|
|
\fi %
|
|
\expandafter\lstCC@next \csname lsts@FCL#2\endcsname}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsubsection{Single and double comments}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{singlecomment}
|
|
% \begin{aspect}{doublecomment}
|
|
% Define the user commands \ldots
|
|
% \begin{macrocode}
|
|
\lst@Aspect{singlecomment}{\def\lst@DefSC{\lstCC@SingleComment#1{}}}
|
|
\lst@Aspect{doublecomment}{\def\lst@DefDC{\lstCC@DoubleComment#1{}{}{}}}
|
|
% \end{macrocode}
|
|
% \end{aspect}\end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@SCmode}
|
|
% \begin{macro}{\lst@DCmodeA}
|
|
% \begin{macro}{\lst@DCmodeB}
|
|
% and allocate new internal modes.
|
|
% \begin{macrocode}
|
|
\lst@NewMode\lst@SCmode \lst@NewMode\lst@DCmodeA\lst@NewMode\lst@DCmodeB
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@SingleComment}
|
|
% \begin{macro}{\lstCC@DoubleComment}
|
|
% All must be done twice here, for the beginning and end of a comment.
|
|
% The use of additional arguments like |{SC}\lst@SCmode| make it possible to define single and double comments with the same macros.
|
|
% \begin{macrocode}
|
|
\def\lstCC@SingleComment#1#2{%
|
|
\ifx\@empty#1\@empty\else %
|
|
\lstCC@TestCArg#1\@empty\relax\lstCC@CommentB{SC}\lst@SCmode %
|
|
\lstCC@TestCArg#2\@empty\relax\lstCC@CommentE{SC}\lst@SCmode %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% Note the order: We define 'begin comment' and afterwards 'end comment'.
|
|
% This becomes important if |#1| equals |#2|, for example.
|
|
% Each such comment definition saves the old character meaning, which is executed after doing all comment specific.
|
|
% If we define 'end comment' first and then 'begin comment', |#1| would start a comment and then execute the old definition, which is 'end comment'.
|
|
% Since we are in comment mode now (and since |#1| equals |#2|), 'end comment' leaves comment mode immediately.
|
|
% That would be very bad!
|
|
% \begin{macrocode}
|
|
\def\lstCC@DoubleComment#1#2#3#4{%
|
|
\ifx\@empty#1\@empty\else %
|
|
\lstCC@TestCArg#1\@empty\relax\lstCC@CommentB{DCA}\lst@DCmodeA %
|
|
\lstCC@TestCArg#3\@empty\relax\lstCC@CommentB{DCB}\lst@DCmodeB %
|
|
\lstCC@TestCArg#2\@empty\relax\lstCC@CommentE{DCA}\lst@DCmodeA %
|
|
\lstCC@TestCArg#4\@empty\relax\lstCC@CommentE{DCB}\lst@DCmodeB %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@CommentB}
|
|
% is not different from |\lstCC@CommentLine@| at all:
|
|
% The save name |#3| there is replaced by |B#4#3| and instead of |\lst@CLmode| we use |#5|.
|
|
% \begin{macrocode}
|
|
\def\lstCC@CommentB#1#2#3#4#5{%
|
|
\expandafter\let\csname lsts@B#4#3\endcsname#1%
|
|
\ifx\@empty#2%
|
|
\def#1{%
|
|
\lst@ifmode \let\lstCC@bnext\relax \else %
|
|
\def\lstCC@bnext{\lstCC@BeginComment#5}%
|
|
\fi %
|
|
\lstCC@bnext \csname lsts@B#4#3\endcsname}%
|
|
\else %
|
|
\def#1##1{%
|
|
\let\lstCC@bnext\relax %
|
|
\lst@ifmode\else \ifx##1#2%
|
|
\def\lstCC@bnext{\lstCC@@BeginComment#5}%
|
|
\fi \fi %
|
|
\expandafter\lstCC@bnext \csname lsts@B#4#3\endcsname##1}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@CommentE}
|
|
% Here we insert |\ifnum\lst@mode=#5| (6-th line), where |#5| is |\lst@SCmode| for example.
|
|
% This ensures that comment delimiters match each other.
|
|
% \begin{macrocode}
|
|
\def\lstCC@CommentE#1#2#3#4#5{%
|
|
\expandafter\let\csname lsts@E#4#3\endcsname#1%
|
|
\ifx\@empty#2%
|
|
\def#1{%
|
|
\def\lstCC@enext{\csname lsts@E#4#3\endcsname}%
|
|
\lst@ifmode \ifnum\lst@mode=#5%
|
|
\def\lstCC@enext{\csname lsts@E#4#3\endcsname %
|
|
\lstCC@EndComment}%
|
|
\fi \fi %
|
|
\lstCC@enext}%
|
|
\else %
|
|
\def#1##1{%
|
|
\def\lstCC@enext{\csname lsts@E#4#3\endcsname ##1}%
|
|
\lst@ifmode \ifnum\lst@mode=#5\ifx##1#2%
|
|
\def\lstCC@enext{\csname lsts@E#4#3\endcsname ##1%
|
|
\lstCC@EndComment}%
|
|
\fi \fi \fi %
|
|
\lstCC@enext}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsubsection{Nested comments}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{nestedcomment}
|
|
% The user aspect \ldots
|
|
% \begin{macrocode}
|
|
\lst@Aspect{nestedcomment}{\lstnestedcomment@#1}
|
|
\def\lstnestedcomment@#1#2%
|
|
{\def\@tempa{#1}\def\@tempb{#2}%
|
|
\ifx\@tempa\@tempb \ifx\@tempa\@empty\else %
|
|
\PackageError{Listings}{Identical delimitors}%
|
|
{These delimitors make no sense with nested comments.}%
|
|
\fi \fi %
|
|
\def\lst@DefNC{\lstCC@NestedComment{#1}{#2}}}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@NestedComment}
|
|
% and the internal macro.
|
|
% \begin{macrocode}
|
|
\def\lstCC@NestedComment#1#2{%
|
|
\ifx\@empty#1\@empty\else %
|
|
\lstCC@TestCArg#2\@empty\relax\lstCC@NCommentE %
|
|
\lstCC@TestCArg#1\@empty\relax\lstCC@NCommentB %
|
|
\fi}
|
|
% \end{macrocode}
|
|
% Note the order: We define 'end comment' and afterwards 'begin comment'.
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@NCommentB}
|
|
% The redefinition of the character is different now.
|
|
% Since we define nested comments, we have to count the comment depth.
|
|
% If we already process a nested comment, we increase that depth by making |\lst@mode| more negative.
|
|
% \begin{macrocode}
|
|
\def\lstCC@NCommentB#1#2#3{%
|
|
\let\lsts@BNC #1%
|
|
\ifx\@empty#2%
|
|
\def#1{%
|
|
\let\lstCC@bnext\relax %
|
|
\lst@ifmode %
|
|
\ifnum\lst@mode<\z@ %
|
|
\advance\lst@mode\m@ne %
|
|
\fi %
|
|
\else %
|
|
\def\lstCC@bnext{\lstCC@BeginComment\m@ne}%
|
|
\fi %
|
|
\lstCC@bnext \lsts@BNC}%
|
|
\else %
|
|
\def#1##1{%
|
|
\let\lstCC@bnext\relax %
|
|
\lst@ifmode %
|
|
\ifnum\lst@mode<\z@ \ifx##1#2%
|
|
\advance\lst@mode\m@ne %
|
|
\fi \fi %
|
|
\else %
|
|
\ifx##1#2%
|
|
\def\lstCC@bnext{\lstCC@@BeginComment\m@ne}%
|
|
\fi %
|
|
\fi %
|
|
\lstCC@bnext \lsts@BNC ##1}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% The third argument (|\catcode| 12 version of the first) is unused so far --- also in |\lst@NCommentE|.
|
|
% If we are in need of 'double' nested comments, we will use this argument for the save name, as we've already done it for normal double comments (and comment lines).
|
|
% \end{TODO}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@NCommentE}
|
|
% If we are in nested comment mode, we either end the comment or decrease the comment depth by making |\lst@mode| less negative.
|
|
% \begin{macrocode}
|
|
\def\lstCC@NCommentE#1#2#3{%
|
|
\let\lsts@ENC #1%
|
|
\ifx\@empty#2%
|
|
\def#1{%
|
|
\let\lstCC@enext\relax %
|
|
\lst@ifmode \ifnum\lst@mode<\z@ %
|
|
\ifnum\lst@mode=\m@ne %
|
|
\let\lstCC@enext\lstCC@EndComment %
|
|
\else %
|
|
\advance\lst@mode\@ne %
|
|
\fi
|
|
\fi \fi %
|
|
\lsts@ENC \lstCC@enext}%
|
|
\else %
|
|
\def#1##1{%
|
|
\def\lstCC@enext{\lsts@ENC ##1}%
|
|
\ifx##1#2%
|
|
\lst@ifmode \ifnum\lst@mode<\z@ %
|
|
\ifnum\lst@mode=\m@ne %
|
|
\def\lstCC@enext{%
|
|
\lsts@ENC ##1\lstCC@EndComment}%
|
|
\else %
|
|
\advance\lst@mode\@ne %
|
|
\fi
|
|
\fi \fi %
|
|
\fi %
|
|
\lstCC@enext}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Escape characters}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% The introduction of this character class is due to a communication with \lsthelper{Rui Oliveira}{rco@di.uminho.pt}{1998/06/05}{escape characters}.
|
|
%
|
|
% \begin{macro}{\lstCC@Escape}
|
|
% gets three arguments all in all.
|
|
% The first is the escape character, the second is executed when the escape starts and the third right before ending it.
|
|
% We use the same grouping mechanism as for \TeX\ comment lines.
|
|
% \begin{macrocode}
|
|
\def\lstCC@Escape#1{\lccode`\~=`#1\lowercase{\lstCC@Escape@~}}
|
|
\def\lstCC@Escape@#1#2#3{%
|
|
\def#1{%
|
|
\lst@NewLine\lst@UseLostSpace \lst@PrintToken %
|
|
\lst@InterruptModes %
|
|
\lst@EnterMode{\lst@TeXmode}{\lst@modetrue}%
|
|
% \end{macrocode}
|
|
% After doing the grouping we must define the character to end the escape.
|
|
% \begin{macrocode}
|
|
\catcode`#1=\active %
|
|
\def#1{#3\lst@LeaveAllModes \lst@ReenterModes}%
|
|
#2}}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@NewMode\lst@TeXmode
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{aspect}{escapechar}
|
|
% This aspect defines |\lst@DefEsc|, which is executed after selecting the standard character table.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{escapechar}
|
|
{\ifx\@empty#1\@empty %
|
|
\let\lst@DefEsc\relax %
|
|
\else %
|
|
\def\lst@DefEsc{\lstCC@Escape{#1}\@empty\@empty}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lstset{escapechar={}}% init
|
|
\lst@AddToHook{SelectCharTable}{\lst@DefEsc}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{aspect}{mathescape}
|
|
% A switch tested after character table selection.
|
|
% We use |\lstCC@Escape| with math shifts as arguments.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{mathescape}[t]{\lstKV@SetIfKey\lst@ifmathescape{#1}}
|
|
\lstset{mathescape=false}% init
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SelectCharTable}
|
|
{\lst@ifmathescape \lstCC@Escape{\$}{$}{$}\fi}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@DontEscapeToLaTeX}
|
|
% This macro came in handy.
|
|
% \begin{macrocode}
|
|
\def\lst@DontEscapeToLaTeX{%
|
|
\let\lst@iftexcl\iffalse %
|
|
\let\lst@DefEsc\relax %
|
|
\let\lst@ifmathescape\iffalse}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{More \texttt{lst}-aspects and classes}
|
|
%
|
|
%
|
|
% \subsection{Form feeds}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{formfeed}
|
|
% We begin with the announcement --- the introduction is due to communication with \lsthelper{Jan Braun}{Jan.Braun@tu-bs.de}{1998/04/27}{\lstformfeed}.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{formfeed}{\def\lst@formfeed{#1}}
|
|
\lstset{formfeed=\bigbreak}% init
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SelectCharTable}{\lstCC@Let{`\^^L}\lstCC@FormFeed}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lstCC@FormFeed}
|
|
% Here we either execute some macros or append them to |\lst@NewLine|.
|
|
% \begin{macrocode}
|
|
\def\lstCC@FormFeed{%
|
|
\lst@PrintToken %
|
|
\ifx\lst@NewLine\relax %
|
|
\lst@EOLUpdate \lst@formfeed %
|
|
\else %
|
|
\lst@lAddTo\lst@NewLine{\lst@EOLUpdate \lst@formfeed}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{\TeX\ control sequences}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*tex>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{texcs}
|
|
% In general, it's the same as |keywords|, but control sequences are case sensitive, have a preceding backslash, \ldots
|
|
% \begin{macrocode}
|
|
\lst@Aspect{texcs}{\def\lst@texcs{#1}}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@texcs\@empty}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{Output}
|
|
{\lst@ifmode\else \ifx\lst@lastother\lst@backslash %
|
|
\expandafter\lst@IfOneOf\the\lst@token\relax \lst@texcs %
|
|
{\let\lst@thestyle\lst@keywordstyle}%
|
|
{\let\lst@thestyle\relax}%
|
|
\fi \fi}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</tex>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Compiler directives in C}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*c>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{cdirectives}
|
|
% First some usual stuff:
|
|
% \begin{macrocode}
|
|
\lst@Aspect{cdirectives}
|
|
{\lst@MakeKeywordArg{,#1}\let\lst@cdirectives\lst@arg}
|
|
\lst@AddToHook{SetLanguage}{\let\lst@cdirectives\relax}
|
|
% \end{macrocode}
|
|
% If the user has defined directives, we redefine the character |#| (but save the old meaning before):
|
|
% \begin{macrocode}
|
|
\lst@AddToHook{SelectCharTable}
|
|
{\ifx\lst@cdirectives\relax\else %
|
|
\lccode`\~=`\#\lowercase{\let\lsts@CCD~\def~}%
|
|
{\lst@ifmode\else %
|
|
% \end{macrocode}
|
|
% We enter 'directive mode' only if we are in column 1.
|
|
% Note that 'directive mode' is |\lst@egroupmode| without setting |\lst@ifmode| true.
|
|
% \begin{macrocode}
|
|
\@tempcnta\lst@column %
|
|
\advance\@tempcnta\lst@length %
|
|
\advance\@tempcnta-\lst@pos %
|
|
\ifnum\@tempcnta=\z@ %
|
|
\lst@EnterMode{\lst@egroupmode}%
|
|
{\expandafter\lst@lAddTo\expandafter\lst@keywords%
|
|
\expandafter{\lst@cdirectives}}%
|
|
\fi %
|
|
\fi %
|
|
\ifnum\lst@mode=\lst@egroupmode %
|
|
{\lst@keywordstyle\lsts@CCD\lst@PrintToken}%
|
|
\else \lsts@CCD %
|
|
\fi}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</c>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{PODs in Perl}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*perl>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{printpod}
|
|
% We begin with two user commands, which I introduced after communication with \lsthelper{Michael Piotrowski}{mxp@linguistik.uni-erlangen.de}{1997/11/11}{\lstprintpodtrue/false}.
|
|
% \begin{macrocode}
|
|
\lst@Aspect{printpod}[t]{\lstKV@SetIfKey\lst@ifprintpod{#1}}
|
|
\lstset{printpod=false}% init
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
%
|
|
% \begin{macro}{\lst@PODmode}
|
|
% Define a new mode and use |\global| since we are (possibly) in a driver file and thus inside a group.
|
|
% \begin{macrocode}
|
|
\global\lst@NewMode\lst@PODmode
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@PODcut}
|
|
% We'll need the active character string |cut|:
|
|
% \begin{macrocode}
|
|
\lst@MakeActive{cut}\global\let\lstCC@PODcut\lst@arg %
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessPOD}
|
|
% And now the POD character class; only |=| will belong to it.
|
|
% If we are in column 1 \ldots
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@ProcessPOD{%
|
|
\let\lstCC@next\relax %
|
|
\@tempcnta\lst@column %
|
|
\advance\@tempcnta\lst@length %
|
|
\advance\@tempcnta-\lst@pos %
|
|
\ifnum\@tempcnta=\z@ %
|
|
% \end{macrocode}
|
|
% and if we are already in POD mode, we either end it or proceed according to whether next characters are |cut| or not.
|
|
% \begin{macrocode}
|
|
\ifnum\lst@mode=\lst@PODmode %
|
|
\def\lstCC@next{\lst@IfNextChars\lstCC@PODcut %
|
|
{\lstCC@ProcessEndPOD}%
|
|
{\lsts@POD\lst@eaten}}%
|
|
\else %
|
|
% \end{macrocode}
|
|
% If we are in column 1 and not in POD mode, we either start a usual comment or drop the output.
|
|
% \begin{macrocode}
|
|
\lst@ifprintpod %
|
|
\lstCC@BeginComment\lst@PODmode %
|
|
\else %
|
|
\lst@BeginDropOutput\lst@PODmode %
|
|
\fi %
|
|
\let\lstCC@next\lsts@POD %
|
|
\fi %
|
|
\fi \lstCC@next}%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstCC@ProcessEndPOD}
|
|
% If the character behind |=cut| is neither |^^M| nor |^^J|, we don't end the POD.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@ProcessEndPOD#1{%
|
|
\let\lstCC@next\lstCC@ProcessEndPOD@ %
|
|
\ifnum`#1=`\^^M\else \ifnum`#1=`\^^J\else %
|
|
\def\lstCC@next{\lsts@POD\lst@eaten#1}%
|
|
\fi \fi %
|
|
\lstCC@next}
|
|
% \end{macrocode}
|
|
% The ending actions depend on |\lst@ifprintpod|: Print |=cut| (or not) and end the POD.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@ProcessEndPOD@{%
|
|
\lst@ifprintpod \lsts@POD\lst@eaten\lst@PrintToken \fi %
|
|
\lst@LeaveMode}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</perl>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{Special use of \texttt{\#} in Perl}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*perl>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lstCC@SpecialUseAfter}
|
|
% We need |#| not to begin a comment in Perl if it follows |$|.
|
|
% We'll define a special use of |#| after |$| via |\lstCC@SpecialUseAfter{\$}{\#}{\lstCC@ProcessOther\#}| where the third argument is executed coming to |$#|.
|
|
% Note that the submacro gets two of the three arguments.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@SpecialUseAfter#1{%
|
|
\lccode`\~=`#1\lccode`\/=`#1\lowercase{\lstCC@SpecialUseAfter@~/}}
|
|
% \end{macrocode}
|
|
% We save the old meaning of the first character (|$|) and redefine it to check for the character |#3|.
|
|
% \begin{macrocode}
|
|
\gdef\lstCC@SpecialUseAfter@#1#2#3#4{%
|
|
\expandafter\let\csname lsts@SUA#2\endcsname#1%
|
|
\def#1##1{%
|
|
\ifnum`##1=`#3%
|
|
\def\lstCC@next{\csname lsts@SUA#3\endcsname\relax #4}%
|
|
\else %
|
|
\def\lstCC@next{\csname lsts@SUA#3\endcsname ##1}%
|
|
\fi %
|
|
\lstCC@next}}
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</perl>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{Epilogue}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% Most initialization has already been done, see all |% init| marked lines.
|
|
% Here is more:
|
|
% \begin{macrocode}
|
|
\lstset{labelsep=5pt,sensitive=true}
|
|
\lstdefinelanguage{}{}
|
|
\lstdefinestyle{}
|
|
{basicstyle={},%
|
|
keywordstyle=\bfseries,nonkeywordstyle={},%
|
|
commentstyle=\itshape,stringstyle={},%
|
|
labelstyle={},labelstep=0}
|
|
\lst@mode=\z@
|
|
\lstset{language={},style={}}
|
|
% \end{macrocode}
|
|
% Finally we load compatibility mode, a patch file and the configuration file.
|
|
% \begin{macrocode}
|
|
\@ifundefined{lst@0.17}{}{\input{lst017.sty}}
|
|
\InputIfFileExists{lstpatch.sty}{}{}
|
|
\InputIfFileExists{listings.cfg}{}{}
|
|
% \end{macrocode}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \section{Interfaces to other packages}
|
|
%
|
|
%
|
|
% \subsection{Compatibility mode}
|
|
%
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*0.17>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% We give a warning first.
|
|
% \begin{macrocode}
|
|
\message{^^J%
|
|
*** You have requested compatibility mode `0.17'.^^J%
|
|
*** This mode is for documents created for version 0.17 only.^^J%
|
|
*** I T\@spaces I S\@spaces N O T\@spaces F U L L Y\@spaces %
|
|
C O M P A T I B L E.^^J^^J}
|
|
% \end{macrocode}
|
|
%
|
|
%
|
|
% \paragraph{Language names.}
|
|
%
|
|
% Since some programming languages changed their names, we define aliases here.
|
|
% \begin{macrocode}
|
|
\lstalias[]{blank}[]{}
|
|
\lstalias{cpp}{C++}
|
|
\lstalias[vc]{C++}[Visual]{C++}
|
|
\lstalias{comal}{Comal 80}
|
|
\lstalias{modula}{Modula-2}
|
|
\lstalias{oberon}{Oberon-2}
|
|
\lstalias[]{pxsc}[XSC]{Pascal}
|
|
\lstalias[]{tp}[Borland6]{Pascal}
|
|
\lstalias{pli}{PL/I}
|
|
% \end{macrocode}
|
|
%
|
|
%
|
|
% \paragraph{User commands.}
|
|
%
|
|
% Old commands in terms of keys:
|
|
% \begin{macrocode}
|
|
\def\inputlisting{%
|
|
\@ifnextchar[\inputlisting@{\inputlisting@[1,999999]}}
|
|
\def\inputlisting@[#1,#2]{\lstinputlisting[first=#1,last=#2]}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\newcommand\selectlisting[2][]{\lstset{language=[#1]#2}}
|
|
\def\listingtrue{\lstset{print=true}}
|
|
\def\listingfalse{\lstset{print=false}}
|
|
\def\tablength#1{\lstset{tabsize=#1}}\tablength{4}% init
|
|
\def\keywordstyle#1{\lstset{keywordstyle={#1}}}
|
|
\def\commentstyle#1{\lstset{commentstyle={#1}}}
|
|
\def\stringstyle#1{\lstset{stringstyle={#1}}}
|
|
\def\labelstyle#1{\lstset{labelstyle={#1}}}
|
|
\newcommand\stringizer[2][d]{\lstset{stringizer=[#1]#2}}
|
|
\def\blankstringtrue{\lstset{blankstring=true}}
|
|
\def\blankstringfalse{\lstset{blankstring=false}}
|
|
\def\spreadlisting#1{\lstset{spread={#1}}}
|
|
\def\prelisting#1{\def\lst@pre{#1}}
|
|
\def\postlisting#1{\def\lst@post{#1}}
|
|
\def\normallisting{%
|
|
\lstset{style={},spread=\z@,pre={},post={}}}
|
|
\def\keywords#1{\lstset{keywords={#1}}}
|
|
\def\morekeywords#1{\lstset{morekeywords={#1}}}
|
|
\def\sensitivetrue{\lstset{sensitive=true}}
|
|
\def\sensitivefalse{\lstset{sensitive=false}}
|
|
\let\lst@stringblank\textvisiblespace
|
|
% \end{macrocode}
|
|
% We define the (new) old environment.
|
|
% \begin{macrocode}
|
|
\lst@Environment{listing}[1][]\is
|
|
{\ifx\@empty#1\@empty\else \lst@AddToLOL{#1}{}\fi}
|
|
{}
|
|
% \end{macrocode}
|
|
%
|
|
%
|
|
% \paragraph{Comments.}
|
|
%
|
|
% The implementation of old comment commands in terms of the new ones is all the same:
|
|
% If the last argument is empty, we remove the comment; otherwise we execute the new key with correct syntax.
|
|
% \begin{macrocode}
|
|
\def\DeclareCommentLine#1\relax{%
|
|
\ifx\@empty#1\@empty %
|
|
\let\lst@DefCL\relax %
|
|
\else %
|
|
\lstset{commentline=#1}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\DeclareSingleComment#1 #2\relax{%
|
|
\ifx\@empty#2\@empty %
|
|
\let\lst@DefSC\relax \let\lst@DefDC\relax %
|
|
\else %
|
|
\lstset{singlecomment={#1}{#2}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\DeclarePairedComment#1\relax{
|
|
\ifx\@empty#1\@empty %
|
|
\let\lst@DefSC\relax \let\lst@DefDC\relax %
|
|
\else %
|
|
\lstset{singlecomment={#1}{#1}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\DeclareNestedComment#1 #2\relax{%
|
|
\ifx\@empty#2\@empty %
|
|
\let\lst@DefSC\relax \let\lst@DefDC\relax %
|
|
\else %
|
|
\lstset{nestedcomment={#1}{#2}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\DeclareDoubleComment#1 #2 #3 #4\relax{%
|
|
\ifx\@empty#4\@empty %
|
|
\let\lst@DefSC\relax \let\lst@DefDC\relax %
|
|
\else %
|
|
\lstset{doublecomment={#1}{#2}{#3}{#4}}%
|
|
\fi}
|
|
% \end{macrocode}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</0.17>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \subsection{\textsf{fancyvrb}}
|
|
%
|
|
% \lsthelper{Denis Girou}{Denis.Girou@idris.fr}{1998/07/26}{fancyvrb} asked whether \textsf{fancyvrb} and \textsf{listings} could work together.
|
|
% Here's the first try.
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%<*kernel>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{aspect}{fancyvrb}
|
|
% We set the boolean and input the interface file (first time only).
|
|
% \begin{macrocode}
|
|
\lst@Aspect{fancyvrb}[t]{%
|
|
\lstKV@SetIfKey\lst@iffancyvrb{#1}%
|
|
\lstfancyvrb@}
|
|
\def\lstfancyvrb@{\input{lstfvrb.sty}\lstfancyvrb@}
|
|
% \end{macrocode}
|
|
% \end{aspect}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
%</kernel>
|
|
% \end{macrocode}
|
|
%
|
|
% \begin{macrocode}
|
|
%<*fancyvrb>
|
|
% \end{macrocode}
|
|
% We will use |@|-protected names:
|
|
% \begin{macrocode}
|
|
\begingroup \makeatletter
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
% \begin{macro}{\lstFV@Def}
|
|
% \begin{macro}{\lstFV@Let}
|
|
% \begin{macro}{\lstFV@Use}
|
|
% \begin{macro}{\lstFV@ECUse}
|
|
% \begin{macro}{\lstFV@Tabulator}
|
|
% \begin{macro}{\lstFV@Space}
|
|
% \begin{macro}{\lstFV@Stringizer@}
|
|
% These are copies of the |\lstCC@|\ldots\ macros, but all catcode changes are removed.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Def#1{\lccode`\~=#1\lowercase{\def~}}%
|
|
\gdef\lstFV@Let#1{\lccode`\~=#1\lowercase{\let~}}%
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Use#1#2#3{%
|
|
\ifnum#2=\z@ %
|
|
\expandafter\@gobbletwo %
|
|
\else %
|
|
\lccode`\~=#2\lowercase{\def~}{#1#3}%
|
|
\fi %
|
|
\lstFV@Use#1}%
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@ECUse#1#2{%
|
|
\ifnum`#2=\z@ %
|
|
\expandafter\@gobbletwo %
|
|
\else %
|
|
\ifnum\catcode`#2=\active %
|
|
\lccode`\~=`#2\lccode`\/=`#2\lowercase{\lstCC@ECUse@#1~/}%
|
|
\else %
|
|
\lccode`\~=`#2\lowercase{\def~}{#1#2}%
|
|
\fi %
|
|
\fi %
|
|
\lstFV@ECUse#1}%
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Tabulator#1{\lstFV@Let{#1}\lstCC@ProcessTabulator}%
|
|
\gdef\lstFV@Space#1{\lstFV@Let{#1}\lstCC@ProcessSpace}%
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Stringizer@#1#2{%
|
|
\ifx\@empty#2%
|
|
\expandafter\@gobbletwo %
|
|
\else %
|
|
\lccode`\~=`#2\lccode`\/=`#2%
|
|
\lowercase{%
|
|
\expandafter\let\csname lsts@s/\endcsname~%
|
|
\def~{#1/}}%
|
|
\fi %
|
|
\lstFV@Stringizer@#1}%
|
|
% \end{macrocode}
|
|
% \end{macro}\end{macro}\end{macro}\end{macro}
|
|
% \end{macro}\end{macro}\end{macro}
|
|
%
|
|
% \begin{macro}{\lstFV@FancyVerbFormatLine}
|
|
% This macro will be assigned to |\FancyVerbFormatLine|: We convert the argument and typeset it.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@FancyVerbFormatLine#1{%
|
|
\let\lstenv@arg\@empty\lstenv@AddArg{#1}%
|
|
\lstenv@arg \lst@PrintToken\lst@EOLUpdate}%
|
|
% \end{macrocode}
|
|
% \begin{TODO}
|
|
% This old macro is overwritten below.
|
|
% \end{TODO}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstfancyvrb@}
|
|
% The command assigns some new macros (if it's not already done).
|
|
% \begin{macrocode}
|
|
\gdef\lstfancyvrb@{%
|
|
\ifx\FV@VerbatimBegin\lstFV@VerbatimBegin\else %
|
|
\let\lstFV@OldVB\FV@VerbatimBegin %
|
|
\let\lstFV@OldVE\FV@VerbatimEnd %
|
|
\let\FV@VerbatimBegin\lstFV@VerbatimBegin %
|
|
\let\FV@VerbatimEnd\lstFV@VerbatimEnd %
|
|
\fi %
|
|
% \end{macrocode}
|
|
% And we assign the correct |\FancyVerbFormatLine| macro.
|
|
% \begin{macrocode}
|
|
\lst@iffancyvrb %
|
|
\ifx\FancyVerbFormatLine\lstFV@FancyVerbFormatLine\else %
|
|
\let\lstFV@FVFL\FancyVerbFormatLine %
|
|
\let\FancyVerbFormatLine\lstFV@FancyVerbFormatLine %
|
|
\fi %
|
|
\else %
|
|
\ifx\lstFV@FVFL\@undefined\else %
|
|
\let\FancyVerbFormatLine\lstFV@FVFL %
|
|
\fi %
|
|
\fi}%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstFV@VerbatimBegin}
|
|
% We initialize things if necessary.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@VerbatimBegin{%
|
|
\lstFV@OldVB %
|
|
\ifx\FancyVerbFormatLine\lstFV@FancyVerbFormatLine %
|
|
\lst@DontEscapeToLaTeX %
|
|
\let\smallbreak\relax \let\normalbaselines\relax %
|
|
\let\lst@prelisting\relax \let\lst@postlisting\relax %
|
|
\def\lst@firstline{1}\def\lst@lastline{999999}%
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\let\lstCC@Use\lstFV@Use %
|
|
\let\lstCC@ECUse\lstFV@ECUse %
|
|
\let\lstCC@Tabulator\lstFV@Tabulator %
|
|
\let\lstCC@Space\lstFV@Space %
|
|
\let\lstCC@Stringizer@\lstFV@Stringizer@ %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\def\lst@next{%
|
|
\lst@Init\relax %
|
|
\everypar{}\global\let\lst@NewLine\relax}%
|
|
\expandafter\lst@next %
|
|
\fi}%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstFV@VerbatimEnd}
|
|
% A (particular) box and macro must exist after |\lst@DeInit|.
|
|
% We store them globally.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@VerbatimEnd{%
|
|
\ifx\FancyVerbFormatLine\lstFV@FancyVerbFormatLine %
|
|
\global\setbox\lstFV@gtempboxa\box\@tempboxa %
|
|
\global\let\@gtempa\FV@ProcessLine %
|
|
\lst@DeInit %
|
|
\let\FV@ProcessLine\@gtempa %
|
|
\setbox\@tempboxa\box\lstFV@gtempboxa %
|
|
\fi %
|
|
\lstFV@OldVE}%
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
\newbox\lstFV@gtempboxa %
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
%
|
|
% \begin{macro}{\lstFV@FancyVerbFormatLine}
|
|
% A slightly different definition now: |\lstenv@AddArg{#1}| has been replaced by |\lstFV@Convert#1@|.
|
|
% The '@' terminates the input |#1|.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@FancyVerbFormatLine#1{%
|
|
\let\lst@arg\@empty\lstFV@Convert#1@%
|
|
\lst@arg \lst@PrintToken\lst@EOLUpdate}%
|
|
% \end{macrocode}
|
|
% And this macro is to be defined right now.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Convert{%
|
|
\@ifnextchar\bgroup{\lstFV@Convert@Arg}{\lstFV@Convert@}}%
|
|
% \end{macrocode}
|
|
% Coming to a begin group character ('\{' with catcode 1) we convert the and add the conversion together with group delimiters to |\lst@arg|.
|
|
% We also add |\lst@PrintToken|, which prints all collected characters before we forget them.
|
|
% Finally we continue the conversion.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Convert@Arg#1{%
|
|
{\let\lst@arg\@empty \lstFV@Convert#1@\global\let\@gtempa\lst@arg}%
|
|
\expandafter\lst@lAddTo\expandafter\lst@arg\expandafter{%
|
|
\expandafter{\@gtempa\lst@PrintToken}}%
|
|
\lstFV@Convert}%
|
|
% \end{macrocode}
|
|
% If we haven't found a |\bgroup|, we look whether we've found the end of the input.
|
|
% If not, we convert one token ((non)active character or control sequence) and continue conversion.
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Convert@#1{%
|
|
\ifx @#1\else %
|
|
\expandafter\lstFV@Convert@@\string#1\@empty\@empty\relax{#1}%
|
|
\expandafter\lstFV@Convert %
|
|
\fi}%
|
|
% \end{macrocode}
|
|
% |\string#1| from above expands to 'backslash + some characters' if |#1| is a control sequence.
|
|
% In this case the argument |#2| here equals not |\@empty|.
|
|
% The other implication: If |#2| equals |\@empty|, |\string#1| necessarily expanded to a single character, which can't be a control sequence (|\escapechar>=0| granted).
|
|
% Thus, we add an active character if and only if the second argument equals |\@empty|, and we append the control sequence otherwise.
|
|
% In the latter case we must print all preceding characters (and all the lost space).
|
|
% \begin{macrocode}
|
|
\gdef\lstFV@Convert@@#1#2#3\relax#4{%
|
|
\ifx\@empty#2%
|
|
\lccode`\~=`#4\lowercase{\lst@lAddTo\lst@arg~}%
|
|
\else %
|
|
\lst@lAddTo\lst@arg{\lst@UseLostSpace\lst@PrintToken#4}%
|
|
\fi}%
|
|
% \end{macrocode}
|
|
% \end{macro}
|
|
% \begingroup
|
|
% \begin{macrocode}
|
|
\endgroup %
|
|
% \end{macrocode}
|
|
% \begin{macrocode}
|
|
%</fancyvrb>
|
|
% \end{macrocode}
|
|
% \endgroup
|
|
%
|
|
%
|
|
% \begingroup\small
|
|
% \section{History}
|
|
% Only major changes after version 0.15 are listed here.
|
|
% Previous changes are still present in the \texttt{.dtx}-file.
|
|
% Introductory version numbers of the user commands are listed in the user's guide.
|
|
% \renewcommand\labelitemi{--}
|
|
% \begin{itemize}
|
|
% \iffalse
|
|
% \item[0.1] from 1996/03/09
|
|
% \item test version to look whether package is possible or not
|
|
% \item[0.11] from 1996/08/19
|
|
% \item additional blank option (= language)
|
|
% \item alignment improved by rewriting some macros
|
|
% \item[0.12] from 1997/01/16
|
|
% \item nearly 'perfect' alignment now
|
|
% \item[0.13] from 1997/02/11
|
|
% \item additional languages: Eiffel, Fortran 90, Modula-2, Pascal XSC
|
|
% \item load on demand: language specific macros moved to driver files
|
|
% \item comments are declared now and not implemented for each language again (this makes the \TeX{} sources easier to read)
|
|
% \item[0.14] from 1997/02/18
|
|
% \item user's guide rewritten
|
|
% \item implementation guide uses macro environment from the doc package
|
|
% \item (non) case sensitivity implemented, e.g.\ Pascal is not
|
|
% \item multiple stringizer implemented, i.e.\ Modula-2 handles both string types: quotes and double quotes
|
|
% \item comment declaration is user-accessible now
|
|
% \item package compatible to \verb!german.sty! now
|
|
% \item[0.15] from 1997/04/18
|
|
% \item additional languages: Java, Turbo Pascal
|
|
% \item package renamed from listing.dtx to listings.dtx, since there is already a package named listing
|
|
% \fi
|
|
% \item[0.16] from 1997/06/01
|
|
% \iffalse
|
|
% \item changed '$<$' to '$>$' in \verb!\lst@SkipUptoFirst!
|
|
% \item bug removed: \verb!\lst@Init! must be placed before \verb!\lst@SkipUptoFirst!
|
|
% \fi
|
|
% \item listing environment rewritten
|
|
% \item[0.17] from 1997/09/29
|
|
% \item |\spreadlisting| works correct now (e.g.\ page numbers move not right any more)
|
|
% \item speed up things (quick 'if parameter empty', all |\long| except one removed, faster \verb!\lst@GotoNextTabStop!, etc.)
|
|
% \item alignment of wide other characters improved (e.g.\ $==$)
|
|
% \iffalse
|
|
% \item many new languages: Ada, Algol, Cobol, Comal 80, Elan, Fortran 77, Lisp, Logo, Matlab, Oberon, Perl, PL/I, Simula, SQL, \TeX{}
|
|
% \fi
|
|
% \item[pre-0.18] from 1998/03/24 (unpublished)
|
|
% \item bug concerning |\labelstyle| removed (now oldstylenum example works)
|
|
% \item experimental implementation of character classes
|
|
% \item[0.19] from 1998/11/09
|
|
% \item character classes and \lst-aspects (new) seem to be the ultimate, all became implemented in these terms
|
|
% \item \lst-aspects became an application (new) to \textsf{keyval} and hooks
|
|
% \item \textsf{fancyvrb} support
|
|
% \end{itemize}
|
|
%
|
|
%
|
|
% \setcounter{IndexColumns}{2}
|
|
% \PrintIndex
|
|
%
|
|
%
|
|
% \Finale
|
|
%
|
|
\endinput
|