summaryrefslogtreecommitdiff
path: root/support/lgrind
diff options
context:
space:
mode:
Diffstat (limited to 'support/lgrind')
-rw-r--r--support/lgrind/FAQ37
-rw-r--r--support/lgrind/Makefile63
-rw-r--r--support/lgrind/README87
-rwxr-xr-xsupport/lgrind/example/asm2tex17
-rw-r--r--support/lgrind/example/asm2tex.bat14
-rwxr-xr-xsupport/lgrind/example/c2tex17
-rw-r--r--support/lgrind/example/c2tex.bat14
-rw-r--r--support/lgrind/example/egcprog.c34
-rw-r--r--support/lgrind/example/egmasm.asm145
-rw-r--r--support/lgrind/example/lgrindeg.tex51
-rw-r--r--support/lgrind/example/subst5
-rw-r--r--support/lgrind/lgrind.dtx1174
-rw-r--r--support/lgrind/lgrind.gls37
-rw-r--r--support/lgrind/lgrind.ind156
-rw-r--r--support/lgrind/lgrind.ins27
-rw-r--r--support/lgrind/lgrind.pdfbin0 -> 193067 bytes
-rw-r--r--support/lgrind/lgrindef850
-rw-r--r--support/lgrind/source/.cvsignore2
-rw-r--r--support/lgrind/source/Makefile39
-rw-r--r--support/lgrind/source/README10
-rw-r--r--support/lgrind/source/lgrind.1228
-rw-r--r--support/lgrind/source/lgrind.c1769
-rw-r--r--support/lgrind/source/lgrindef.5248
-rw-r--r--support/lgrind/source/lgrindef.c330
-rw-r--r--support/lgrind/source/lgrindef.h12
-rw-r--r--support/lgrind/source/lgutil.c323
-rw-r--r--support/lgrind/source/makefile.dos34
-rw-r--r--support/lgrind/source/makefile.emx55
-rw-r--r--support/lgrind/source/regexp.c648
-rw-r--r--support/lgrind/source/regexp.h13
-rw-r--r--support/lgrind/source/retest.c75
-rw-r--r--support/lgrind/source/v2lg.c78
32 files changed, 6592 insertions, 0 deletions
diff --git a/support/lgrind/FAQ b/support/lgrind/FAQ
new file mode 100644
index 0000000000..1c5dee867d
--- /dev/null
+++ b/support/lgrind/FAQ
@@ -0,0 +1,37 @@
+How do I produce `@' in LGrinded texts?
+
+ Please RTFM. But since it comes up so often: use @@ in program text. To
+ produce @ in LaTeX text in embedded listings mode you have to turn usage
+ of @ off using a '%@-' comment. You can turn it on again using '%@+'.
+
+
+
+How can I use filenames containing a `$'? This is rather important since
+the `$' denotes the root directory under RISC OS.
+
+ I really cannot figure out what exactly goes wrong. But at least I can
+ offer a workaround. When using T1 or LY1 encoding there are no problems.
+ Put \usepackage[x]{fontenc} (with x=T1 or x=LY1 and possibly others, but
+ not OT1) in the preamble. (For standalone listings use firstpreamble in
+ the lgrindef file.)
+
+
+
+My source code doesn't seem to align properly. What am I doing wrong?
+
+ LGrind uses by default a proportional font for its output. That's part
+ of the beauty. However, aligning with spaces doesn't work, since they
+ are relative horizontal motions. When using tabs, everything is fine. If
+ the standard tab width of 8 is too big for you, fiddle around with your
+ editor to save the file with tabwidth 4, say, and then use '-t 4' as an
+ option to LGrind.
+
+
+
+How do I activate line wrap?
+
+ There is no line-wrap. LGrind has no way of knowing where a line break
+ should be. It depends on the surrounding LaTeX, after all. Make your lines
+ short enough to be pretty; or make your margins and font small.
+
+
diff --git a/support/lgrind/Makefile b/support/lgrind/Makefile
new file mode 100644
index 0000000000..01f4c7e5f7
--- /dev/null
+++ b/support/lgrind/Makefile
@@ -0,0 +1,63 @@
+# Makefile for LGrind, a LaTeX prettyprinter
+
+# $Id: Makefile,v 1.10 2000/12/27 21:42:37 mike Exp $
+
+BASEDIR=/usr
+#DEFSFILE=${HOME}/Work/lgrind/lgrindef
+DEFSFILE=$(BASEDIR)/share/texmf/tex/latex/lgrind/lgrindef
+TEXFILEDIR=$(BASEDIR)/share/texmf/tex/latex/lgrind
+DOCDIR=$(BASEDIR)/doc/lgrind
+
+INSTALL=install
+SOURCES=lgrind.c lgutil.c regexp.c regexp.h lgrindef.c lgrindef.h retest.c v2lg.c
+TEXFILES=lgrind.dtx lgrind.sty lgrind.ins
+
+VERSION=3.66
+DISTVERSION=lgrind-$(VERSION)
+
+.PHONY: all install clean distribution lgrind
+
+all: lgrind.sty lgrind.dvi lgrind
+
+lgrind.sty: lgrind.dtx
+ latex lgrind.ins
+
+lgrind.dvi: lgrind.dtx
+ latex lgrind.dtx
+ latex lgrind.dtx
+
+lgrind:
+ cd source; \
+ make DEFSFILE=$(DEFSFILE) BASEDIR=$(BASEDIR) INSTALL=$(INSTALL) VERSION=$(VERSION)
+
+clean:
+ rm -f lgrind.log
+ rm -f lgrind.aux
+ rm -f lgrind.dvi
+ rm -f lgrind.sty
+ rm -f lgrind.idx
+ rm -f lgrind.glo
+ rm -f doc-lgrind.lg
+ cd source; \
+ make clean
+
+distribution: clean
+ mkdir $(DISTVERSION)
+ cp -r example $(DISTVERSION)
+ rm -rf $(DISTVERSION)/example/CVS
+ cp -r source $(DISTVERSION)
+ rm -rf $(DISTVERSION)/source/CVS
+ cp README FAQ lgrind.* lgrindef $(DISTVERSION)
+ sed -e "s/^#DEFSFILE/=DEFSFILE/;s/^DEFSFILE/#DEFSFILE/;s/^=DEFSFILE/DEFSFILE/"\
+ < Makefile >$(DISTVERSION)/Makefile
+ tar czf $(DISTVERSION).tar.gz $(DISTVERSION)
+ rm -r $(DISTVERSION)
+
+install: all
+ $(INSTALL) -m 755 -d $(TEXFILEDIR)
+ $(INSTALL) -m 644 lgrind.sty $(TEXFILEDIR)
+ $(INSTALL) -m 755 -d $(DOCDIR)
+ $(INSTALL) -m 644 lgrind.dvi $(DOCDIR)
+ $(INSTALL) -m 644 lgrindef $(DEFSFILE)
+ cd source; \
+ make install BASEDIR=$(BASEDIR) INSTALL=$(INSTALL)
diff --git a/support/lgrind/README b/support/lgrind/README
new file mode 100644
index 0000000000..5db42af138
--- /dev/null
+++ b/support/lgrind/README
@@ -0,0 +1,87 @@
+=-----
+LGrind - a source pretty printer for LaTeX
+=-----
+Version 3.67
+
+Welcome to LGrind. LGrind is a descendant of the Unix utility vgrind. It is
+used to produce a beautified version of your source code using LaTeX. Unlike
+other packages this is not pure TeX but an external preprocessor. You run e.g.
+ lgrind example.c > example.tex
+ latex example.tex
+to get a complete listing. Options for producing includable files and pro-
+cessing embedded listings in LaTeX texts are provided.
+
+
+What you need: (Installation part 2)
+^^^^^^^^^^^^^^
+- lgrind (or lgrind.exe) just where you like it
+- lgrind.sty somewhere in LaTeXs reach
+- lgrindef anywhere; (position is semi-fixed in the executable)
+- LaTeX2e the obsolete LaTeX 2.09 is not supported
+- LGrind utilizes by default the fancyhdr package by Piet van Oostrum. You
+ can change this behaviour by modifying the lgrindef file.
+
+
+How to get these files: (Installation part 1)
+^^^^^^^^^^^^^^^^^^^^^^^
+- If your executable is not provided, all the source files are in the source
+ directory, a makefile provided.
+- Run LaTeX or TeX on lgrind.ins. You will obtain lgrind.sty.
+- Or simply run make in the top directory. This also gives lgrind.sty
+
+
+Documentation
+^^^^^^^^^^^^^
+Main documentation is in lgrind.dtx. Run LaTeX on lgrind.dtx and the result is
+lgrind.dvi. There are also manpages lgrind.1 and lgrindef.5 for people who
+prefer those, but notice that I am not always able to keep them up to date.
+To right the wrong impression: parts of the documentation have been written
+by my predecessors, my thanks to them.
+
+
+
+Files in the directories:
+^^^^^^^^^^^^^^^^^^^^^^^^^
+lgrind.ins DocStrip driver
+lgrind.dtx Documented package
+lgrind.gls Glossary and index for the documentation (for the ones with-
+lgrind.ind out MakeIndex, and because it had to be modified by hand)
+lgrindef The language definition file
+
+
+In the directory 'source':
+lgrind.c The source code for the LGrind executable
+lgutil.c
+lgrindef.c
+lgrindef.h
+regexp.c
+regexp.h
+v2lg.c Source code for verbatim to embedded source converter
+retest.c Test program for the regular expression routines
+lgrind.1 Man-pages for the LGrind program
+lgrindef.5 and the language definition file
+Makefile Makefile for Unices
+makefile.dos Makefile for MS-DOS (not tested anymore)
+makefile.emx Makefile for use with DMAKE
+
+
+In the directory 'example':
+c2tex.bat Example batch files for facilitating calls to LGrind
+asm2tex.bat
+c2tex ditto as Bourne shell scripts
+asm2tex
+egmasm.asm Example sources
+egcprog.c
+subst Example substitution file
+lgrindeg.tex Example making use of the above
+
+
+
+Comments, contributions, questions and cheques
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LGrind contains non-free code written by Van Jacobson, who does not answer
+to any request for changing his licence. This software is therefore not
+maintained. I also do not accept any cheques anymore.
+
+Have Fun!
+
diff --git a/support/lgrind/example/asm2tex b/support/lgrind/example/asm2tex
new file mode 100755
index 0000000000..dcb2fc5a6f
--- /dev/null
+++ b/support/lgrind/example/asm2tex
@@ -0,0 +1,17 @@
+#!/bin/sh
+# convert .asm (Microsoft [or whatever] assembler) to .lg
+
+if [ -n "$1" ] && [ -f $1 -o -f $1.asm ]
+then
+ if [ `basename $1` = `basename $1 .asm` ]
+ then
+ lgrind -i -lmasm $1.asm > $1.lg
+ echo Created $1.lg
+ else
+ lgrind -i -lmasm $1 > `basename $1 .asm`.lg
+ echo Created `basename $1 .asm`.lg
+ fi
+else
+ echo Usage: $0 "<file>[.asm]"
+ echo $1.asm does not exist.
+fi
diff --git a/support/lgrind/example/asm2tex.bat b/support/lgrind/example/asm2tex.bat
new file mode 100644
index 0000000000..b89f223bab
--- /dev/null
+++ b/support/lgrind/example/asm2tex.bat
@@ -0,0 +1,14 @@
+@echo off
+rem convert .asm (Microsoft assembler) to .lg
+if not exist %1.asm goto Complain
+
+lgrind -i -lmasm %1.asm > %1.lg
+echo Created %1.lg
+goto Done
+
+:Complain
+echo '%1.asm' does not exist.
+
+:Done
+
+
diff --git a/support/lgrind/example/c2tex b/support/lgrind/example/c2tex
new file mode 100755
index 0000000000..48a301a726
--- /dev/null
+++ b/support/lgrind/example/c2tex
@@ -0,0 +1,17 @@
+#!/bin/sh
+# convert .c to .lg
+
+if [ -n "$1" ] && [ -f $1 -o -f $1.c ]
+then
+ if [ `basename $1` = `basename $1 .c` ]
+ then
+ lgrind -i -v subst $1.c > $1.lg
+ echo Created $1.lg
+ else
+ lgrind -i -v subst $1 > `basename $1 .c`.lg
+ echo Created `basename $1 .c`.lg
+ fi
+else
+ echo Usage: $0 "<file>[.c]"
+ echo $1.c does not exist.
+fi
diff --git a/support/lgrind/example/c2tex.bat b/support/lgrind/example/c2tex.bat
new file mode 100644
index 0000000000..f4b4a2fbc2
--- /dev/null
+++ b/support/lgrind/example/c2tex.bat
@@ -0,0 +1,14 @@
+@echo off
+rem convert .c to .lg
+if not exist %1.c goto Complain
+
+lgrind -i -v subst %1.c > %1.lg
+echo Created %1.lg
+goto Done
+
+:Complain
+echo '%1.c' does not exist.
+
+:Done
+
+
diff --git a/support/lgrind/example/egcprog.c b/support/lgrind/example/egcprog.c
new file mode 100644
index 0000000000..b79f448051
--- /dev/null
+++ b/support/lgrind/example/egcprog.c
@@ -0,0 +1,34 @@
+/* endian.c
+ * Demonstrates endian ordering
+ */
+
+#include <stdio.h>
+
+void main( void )
+{
+ short Data_16;
+ long Data_32;
+ char far *p;
+
+ Data_16 = 0x1234;
+ Data_32 = 0x56789abc;
+
+ p = (char far *)&Data_16;
+ printf("16-bit quantity, data=%04x\n", Data_16);
+ printf("address %Fp = %02x\n", p, (int)(*p) & 0xff);
+ p++ ;
+ printf("address %Fp = %02x\n", p, (int)(*p) & 0xff);
+ p++ ;
+
+
+ p = (char far *)&Data_32;
+ printf("32-bit quantity, data=%08lx\n", Data_32);
+ printf("address %Fp = %02x\n", p, (int)(*p) & 0xff);
+ p++ ;
+ printf("address %Fp = %02x\n", p, (int)(*p) & 0xff);
+ p++ ;
+ printf("address %Fp = %02x\n", p, (int)(*p) & 0xff);
+ p++ ;
+ printf("address %Fp = %02x\n", p, (int)(*p) & 0xff);
+
+}
diff --git a/support/lgrind/example/egmasm.asm b/support/lgrind/example/egmasm.asm
new file mode 100644
index 0000000000..b4baa5962c
--- /dev/null
+++ b/support/lgrind/example/egmasm.asm
@@ -0,0 +1,145 @@
+;************************************************
+; vgac.asm
+; PC VGA graphics control in assembly language
+; uses BIOS for keyboard read and setting graphics
+; modes, and procedure for setting a VGA pixel
+; version for C calling convention :-
+; LARGE model
+; no MAIN entry point
+; assemble only (no link)
+; underscore for C-callable functions
+; don't pop arguments off stack (caller does this)
+;
+; J Leis
+; 24 May 1994
+;************************************************
+
+TITLE vgac.asm - vga assembler program, callable from C
+.MODEL LARGE
+.286
+.DOSSEG
+
+; stack segment directive
+.STACK
+
+; data segment directive
+.DATA
+
+; code segment directive
+.CODE
+
+
+_VgaMode PROC
+
+ pusha
+ mov ah, 0 ; function 0 = set video mode
+ mov al, 12h ; mode 12 = vga graphics
+ int 10h
+ popa
+ ret
+
+_VgaMode ENDP
+
+
+_TextMode PROC
+
+ pusha
+ mov ah, 0 ; function 0 = set video
+ mov al, 03h ; mode 3 = text
+ int 10h
+ popa
+ ret
+
+_TextMode ENDP
+
+
+_ShowMessage PROC
+
+ pusha ; save registers if necessary
+
+ ; call DOS interrupt to display a message
+ mov bx, 01h
+ lea dx, mesg ; equivalent to mov dx, OFFSET mesg
+ mov cx, l_mesg
+ mov ah, 040h
+ int 021h
+
+ popa
+ ret
+
+_ShowMessage ENDP
+
+
+_ReadKey PROC
+
+ pusha ; save registers if necessary
+
+ mov ah, 00h ; function 0 - wait for key & read it
+ int 16h ; int 16h = keyboard services
+ ; al now equals ascii code of key
+
+ popa
+ ret
+
+_ReadKey ENDP
+
+
+; setpixel( xc, yc, color )
+; stacking order:
+; memory near call far call
+; color highest [bp+8] [bp+10]
+; y-coord [bp+6] [bp+8]
+; x-coord lowest [bp+4] [bp+6]
+;
+_SetPixel PROC
+
+ push bp
+ mov bp, sp
+
+ pusha ; save registers if necessary
+
+ mov dx, 03CEh ; graphics controller register
+
+ mov ax, 0205h ; write mode 2
+ out dx, ax
+
+ mov ax, 0003h ; function
+ out dx, ax
+
+ mov ax, 0A000h ; graphics screen segment
+ mov es, ax
+
+ mov ax, [bp+8] ; get y co-ord
+ mov bx, 640/8 ; 80 bytes/line
+ mul bx
+ mov bx, [bp+6] ; get x-coord
+ mov cl, 3 ; divide by 8 bits/byte
+ shr bx, cl
+ add bx, ax
+
+ mov al, es:[bx] ; dummy write to latch data in screen RAM
+ mov cx, [bp+6] ; get x-coord
+ and cx, 0007h ; get bit mask
+ mov al, 07h
+ sub al, cl
+ mov ah, 80h
+ shr ah, cl ; shift to bit position
+ mov al, 08h ; set mask register
+
+ mov dx, 03CEh ; dx destroyed by mul
+ out dx, ax ; write bit mask
+
+ mov cx, [bp+10]; color ; write the color value
+ mov es:[bx], cl
+
+ popa
+
+ pop bp
+ ret ; don't pop args off stack - C does this
+
+_SetPixel ENDP
+
+;no main procedure (main in C)
+
+; end of file
+END
diff --git a/support/lgrind/example/lgrindeg.tex b/support/lgrind/example/lgrindeg.tex
new file mode 100644
index 0000000000..5de9f4592f
--- /dev/null
+++ b/support/lgrind/example/lgrindeg.tex
@@ -0,0 +1,51 @@
+% lgrindeg.tex
+% Simple example program for testing `lgrind' additions
+% MATLAB/QBASIC/C/MASM/LaTeX
+% Note: Matlab,qbasic, masm are registered trademarks.
+%
+% John Leis, 18 June 1996
+% University of Southern Queensland
+% leis@usq.edu.au
+
+\documentclass[a4paper]{article}
+
+\usepackage{lgrind}
+
+\begin{document}
+
+\title{ Example of the `LGrind' Package }
+\author{ John Leis }
+\date{ 15 June 1996 }
+\maketitle
+
+\clearpage
+
+\begin{figure}
+ \begin{center}
+ \begin{tabular}{ll}
+ \hline\hline
+ Language & Command in DOS batch file \\
+ \hline
+ C & \verb+ lgrind -i -v subst %1.c > %1.lg + \\
+ MASM & \verb+ lgrind -i -lmasm %1.asm > %1.lg + \\
+ \hline \\
+ \end{tabular}
+ \end{center}
+ \caption{Commands for lgrind'ing source file into \LaTeXe\ format}
+ \label{fig:commands}
+\end{figure}
+
+
+\lagrind{egcprog.lg}{Example `C' language program.}{fig:egcprog}
+
+\clearpage
+\begin{center}
+ \textbf{\large This is a multi-page listing} \\
+ It has no caption. \\
+ Used for Appendices etc. \\
+\end{center}
+
+\lgrindfile{egmasm.lg}
+
+\end{document}
+
diff --git a/support/lgrind/example/subst b/support/lgrind/example/subst
new file mode 100644
index 0000000000..062741373c
--- /dev/null
+++ b/support/lgrind/example/subst
@@ -0,0 +1,5 @@
+x_gamma=x$\sb\gamma$
+f_1=f$_1$
+delta=$\delta$
+Data_16=Data$\sb{16}$
+Data_32=Data$\sb{32}$
diff --git a/support/lgrind/lgrind.dtx b/support/lgrind/lgrind.dtx
new file mode 100644
index 0000000000..999bd0e408
--- /dev/null
+++ b/support/lgrind/lgrind.dtx
@@ -0,0 +1,1174 @@
+% \iffalse
+%
+% This is LGrind.DTX. This was written by:
+%
+% - Van Jacobson, Lawrence Berkeley Laboratory (based on
+% vgrind by Dave Presotto & William Joy of UC Berkeley),
+% the original written for \TeX.
+% - Jerry Leichter of Yale University, modifications for \LaTeX.
+% - George V. Reilly of Brown University, renamed to lgrind
+% - Michael Piefel, Humboldt-University Berlin, for \LaTeXe
+% and a thousand little changes
+%
+% \fi
+% \iffalse
+%% Based on Van Jacobson's ``tgrindmac'', a macro package for TeX.
+%% Modified, 1987 by Jerry Leichter. Put '@' in all internal names.
+%% Modified, 1991 by George Reilly. Changed name from tgrind to lgrind.
+%% Modified, 1995 by Michael Piefel. Made it work with \LaTeXe.
+%% -1999 Hundreds of bells and whistles. No changelog here.
+%
+%<*dtx>
+\ProvidesFile{lgrind.dtx}
+ [2002/01/28 v3.67 LGrind environment and supporting stuff]
+%</dtx>
+%<package>\NeedsTeXFormat{LaTeX2e}[1996/06/01]
+%<package>\ProvidesPackage{lgrind}
+%<package> [2002/01/28 v3.67 LGrind environment and supporting stuff]
+%<*driver>
+\NeedsTeXFormat{LaTeX2e}[1996/06/01]
+\documentclass{ltxdoc}
+\CodelineIndex
+\RecordChanges
+\DocInput{lgrind.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \newcommand{\LG}{\textsf{LGrind}}
+% \newcommand{\NFSS}{\textsf{NFSS}}
+% \frenchspacing
+%
+% \GetFileInfo{lgrind.dtx}
+% \begin{document}
+% \title{The \LG{} package\thanks{This file
+% has version number \fileversion, last
+% revised \filedate.}}
+% \author{Various Artists}
+% \date{\filedate}
+% \maketitle
+%
+% \CheckSum{679}
+%
+% \begin{abstract}
+% The \LG{} package is a pretty printer for source
+% code. It evolved from vgrind, supported \TeX{} (tgrind) and
+% \LaTeX{} and now finally \LaTeXe, in particular \NFSS.
+% \end{abstract}
+%
+% \changes{v1.0}{1985/02/10}{Written}
+% \changes{v2.0}{1991/09/06}{Upgrade to \LaTeX2.09}
+% \changes{v3.0}{1995/09/24}{Upgrade to \LaTeXe}
+%
+% \section{Introduction}
+% \subsection{What is it?}
+% The \LG{} package consists of three files:
+% \begin{itemize}
+% \item \texttt{lgrind} or \texttt{lgrind.exe} is the executable. It will
+% convert an \LaTeX-File with embedded listings or a source code file
+% into a lot of macro-calls.
+% \item \texttt{lgrind.sty} provides the environments and macros to make
+% the produced mess readable.
+% \item \texttt{lgrindef} contains the information
+% needed to tell keywords from comments, comments from strings \dots
+% \end{itemize}
+%
+% \subsection{Who is to blame?}
+% \LG{} is not the work of a single one. The program is based on
+% \textsf{vgrind} by Dave Presotto \& William Joy of UC Berkeley.
+%
+% Van Jacobson wrote \textsf{tgrind} for \TeX. Jerry Leichter
+% of Yale University modified it for \LaTeX. George V. Reilly of
+% Brown University changed the name to lgrind and added the
+% program-text-within-comments and @-within-\LaTeX{} features,
+% and finally
+% Michael Piefel of the Humboldt-University Berlin converted it to
+% work under \LaTeXe, i.\,e. with \NFSS, and improved the documentation.
+%
+% However, there have been many contributors who supported the development; in
+% particular the range of supported languages is mainly due to them.
+% Unfortunately I do not know all of them, but my thanks go to everybody.
+% A special Thank You to
+% Torsten Sch\"utze for his OS/2 support and many and various hints.
+%
+% \section{\LG{} -- grind nice program listings}
+%
+% \begin{tabbing}
+% \texttt{lgrind} \= \texttt{[-s] [-e] [-i] [-o \meta{file}] [-n] [-c] [-t }\meta{width}
+% \texttt{] [-h }\meta{header}\texttt{]} \\
+% \>\texttt{[-v }\meta{varfile}\texttt{] [-d[!] }\meta{description file}\texttt{]}
+% \texttt{[-l}\meta{language}\texttt{] [}\meta{name}\texttt{\textbar-]}
+% \end{tabbing}
+%
+% \LG{} processes its input file(s) and writes the result to standard
+% output. This output can be saved for later editing, inclusion in a
+% larger document, etc.
+%
+% The options are:
+%
+% \makebox[2em][l]{-e} process a \LaTeX-file for embedded text.
+%
+% \makebox[2em][l]{-i} process for inclusion in a \LaTeX-document.
+%
+% \makebox[2em][l]{-} take input from standard input.
+%
+% \changes{v3.5}{1998/05/23}{Output redirection (-o) implemented.}
+% \makebox[2em][l]{-o} redirect output.
+%
+% \makebox[2em][l]{-n} don't boldface keywords.
+%
+% \makebox[2em][l]{-a} don't treat @, etc. specially in \LaTeX.
+%
+% \makebox[2em][l]{-c} don't treat @, etc. specially in comments.
+%
+% \makebox[2em][l]{-t} change tab width (default 8).
+%
+% \makebox[2em][l]{-h} specifies text to go on the left side of every output
+% page (default is none).
+%
+% \makebox[2em][l]{-v} take variable substitution strings from file.
+%
+% \makebox[2em][l]{-d} specifies the language definitions file.
+%
+% \changes{v3.3}{1996/08/23}{"lgrindef" position can be changed permanently}
+% \makebox[2em][l]{-d!} same as -d, except the change is permanent (modifies
+% executable)
+%
+% \makebox[2em][l]{-l} specifies the language to use.
+%
+% \makebox[2em][l]{-s} shows a list of currently known languages.
+%
+% The standard for \LG{} is to take its input from the file given on the
+% command line and write on standard output. You can change this behaviour with
+% the options - and -o, respectively. Please note that as soon as a file is
+% detected on the command line (either its name or a -) it is processed with the
+% options then in effect, thus
+% allowing to give multiple files on one line with possibly multiple targets.
+%
+% If neither -e nor -i are specified, a complete \LaTeX-file is produced. When
+% no language is given on the command line, \LG{} tries to figure out the
+% language via the extension of the file. A table of extensions and their
+% languages is in the definition file. If the extension is unknown, C is chosen
+% as a default.
+%
+% When \LG{} is started without any parameters, it will show a short help screen.
+% The same happens when the appropriate option is given, but this is
+% implementation dependent (usually what is common for the operation system, the
+% default for DOS is |-?| and for Unix |--help|).
+%
+% The position of the \texttt{lgrindef}-file is determined by giving it on the
+% command line (highest priority), by defining an environment variable
+% \texttt{LGRINDEF}, and by the position fixed in \LG{}s executable. The latter
+% can be changed by using -d! and then using the newly created file as the new
+% \LG{}.
+% \changes{v3.5}{1998/05/30}{Now testing for \texttt{LGRINDEF} environment variable.}
+%
+% The languages which are currently known are stored in the language definition
+% file; their number increases more or less rapidly. At the time of writing the
+% languages in the table below are part of the distribution.
+%
+% \begin{table}\begin{minipage}{0.8\linewidth}
+% \let\thefootnote\thempfootnote
+% \newcommand{\fnm}[1]{\textsuperscript{\itshape#1}}
+% \begin{tabbing}
+% \hspace*{2em} \= \hspace{9em} \= \hspace{9em} \= \\
+% \> Ada \> \LaTeX\footnote{John Leis, University of Southern Queensland, leis@usq.edu.au.}
+% \> RATFOR \\
+% \> Asm \> LDL \> RLaB\footnote{Jim Green, National Physical Laboratory, jjg1@cise.npl.co.uk} \\
+% \> Asm68 \> Lex \> Russell \\
+% \> BASIC\fnm{a} \> Linda \> SAS\footnote{Michael Friendly, friendly@hotspur.psych.yorku.ca} \\
+% \> Batch\fnm{b} \> Lisp (Emacs) \> Scheme\footnote{Neale Pickett, npickett@watchguard.com} \\
+% \> C \> MASM\fnm{a} \> sh \\
+% \> C++ \> MATLAB\fnm{a} \> SICStus\fnm{b} \\
+% \> csh \> ML\fnm{d} \> src \\
+% \> FORTRAN \> Mercury \> SQL \\
+% \> Gnuplot\footnote{Denis Petrovic, Denis.Petrovic@public.srce.hr}
+% \> model \> Tcl/Tk\footnote{Alexander Bednarz, Forsch.-zentrum J\"ulich, A.Bednarz@kfa-juelich.de} \\
+% \> Icon \> Modula2 \> VisualBasic\fnm{a} \\
+% \> IDL\footnote{Diego Berrueta, diego@berrueta.net}
+% \> Pascal \> VMSasm \\
+% \> ISP \> PERL \> yacc \\
+% \> Java \> PostScript \> \\
+% \> Kimwitu++ \> PROLOG \>
+% \end{tabbing}\par
+% \let\footnoterule\relax
+% \end{minipage}\end{table}
+% \changes{v3.67}{2002/01/28}{Added Scheme and ML language definitions}
+% \subsection{Operation modes}
+% There are three modes of operation: stand-alone, include and embedded.
+%
+% Use |lgrind -ly bary.y > bary.tex| (or |lgrind -o bary.tex bary.y|) to
+% produce a stand-alone \LaTeX-file from, say, a Yacc file. This results in a
+% document which is formatted using Piet van Oostrum's \textsf{fancyhdr.sty} to
+% make the headers and footers. BTW: You really should have this package. It's
+% marvellous. But of course you can change the layout to your likings by
+% editing the \texttt{lgrindef}-file.
+%
+% To include a C-file named \texttt{foo.c} into your \LaTeX-document, first
+% give the command: |lgrind -i -lc foo.c > foo.tex| This will generate
+% \texttt{foo.tex}, which will have the pretty-printed version of
+% \texttt{foo.c}. Then include \texttt{lgrind.sty} as you include any other
+% package, namely with |\usepackage{lgrind}| at the beginning of your
+% \LaTeX-document. Having done this, within the document you can include
+% \texttt{foo.tex} using |\lagrind| and |\lgrindfile| described in the next section.
+%
+% Finally, for the embedded (and probably most powerful) mode, when you have a
+% \LaTeX-file with embedded program listings, you can preprocess it with a command like:
+% |lgrind -e pretty-sources.lg > even-prettier-sources.tex|
+% and get a new \LaTeX-file which you then feed into \LaTeX. Commands you can
+% use within embedded texts are described below.
+%
+% \section{Preparing documents}
+%
+% \subsection{Using the \LG.sty-file}
+% The \LG{} package is included via the |\usepackage| command. You have to include it
+% in your document preamble when you want to include listings and when using embedded
+% mode. It is done automatically for stand-alone listings.
+% Currently the following options are supported:
+% \begin{description}
+% \changes{v3.5}{1998/05/23}{Procedure names added to index in addition to
+% printing them in the margin.}
+% \item[procnames] prints the names of starting and, if nested
+% procedures are allowed, continued procedures in the margin. Don't make the
+% margin too small, or don't make the names too long \dots
+% \item[noprocindex] do not put found procedure beginnings in the index
+% \item[noindent] cancels the indentation. Useful for long listings or listings
+% within their own sections.
+% \item[fussy] lets \LaTeX\ print all overfull hboxes. The default is to suppress
+% this for about a tenth of an inch.
+% \item[norules] lets \LG{} suppress the surrounding rules for included material
+% (using |\lagrind| and |\lgrindfile|).
+% \item[nolineno] doesn't print line numbers.\footnote{To be exact, prints line
+% numbers every 50,000 lines. But source code should never get so long in a
+% single file~-- that's over 3 MByte! If you really want no numbers,
+% set $\backslash$\texttt{LGnuminterval} to zero; then you won't get procedure
+% names, either.}
+% \item[lineno5] prints line numbers every 5 lines. The default is 10.
+% \item[leftno] print line numbers in the left margin. Default is the right.
+% \end{description}
+%
+% \subsection{Stand-alone and included listings}
+% After processing a source code file with \LG{} without the -e or -i
+% options you get a \LaTeX-file which can be directly compiled.
+%
+% When using -i \LG{} will produce a file which can be included with the
+% following macros:
+%
+% \DescribeMacro{\lgrindfile}
+% The first is |\lgrindfile{|\meta{file}|}|, which will simply include
+% the file \meta{file} at that point of text, and will draw horizontal
+% lines before and after the listing.
+%
+% \DescribeMacro{\lagrind}
+% The macro
+% |\lagrind[|\meta{float}|]{|\meta{file}|}{|\meta{caption}|}{|\meta{label}|}|
+% will put the listing also within a figure environment, using the \meta{float}
+% options (h, t, b or p), \meta{caption} and \meta{label} you gave. The starred
+% form of |\lagrind| will also use the starred |figure*|.
+%
+% Note that floats cannot be longer than one page, so you should only use
+% |\lagrind| for short fragments, longer pieces should use |\lgrindfile| (which
+% is non-floating).
+%
+% \DeleteShortVerb{\|}\MakeShortVerb{\"}\MakePercentIgnore
+% \subsection{Embedded programs within a \LaTeX-file}
+% You don't have to process every single source file with \LG{}, only to
+% include it in your document. Within the text of your \LaTeX-file, you can
+% mark groups of lines as program code, either text- or display-style to
+% be specific. You can use several commands for controlling the inclusion
+% of source code into your \LaTeX-file.
+%
+% Write your text, don't forget to include \LG.sty. Use the following
+% commands. You can `debug' your text without including the lengthy
+% listings. As a last step (but one), you process your file with \LG{}
+% and its option -e, which will provide you with your final \LaTeX{}
+% source file.
+%
+% The commands are similar to the math environments. \DescribeEnv{\%( \%)}
+% With "%(" and "%)" you obtain code in text style, i.\,e. in the same line.
+% \DescribeEnv{@ @}Surrounding the text with "@" is a shorthand.
+% \begin{verbatim}
+% The expression
+% %(
+% a + 3
+% %)
+% produces 10.\end{verbatim}
+% produces the same as "The expression @a + 3@ produces 10." The output
+% will have `a + 3' set as a program.
+%
+% \DescribeEnv{\%[ \%]}As with math, the square bracket equivalent produces
+% display style listings, i.\,e. indented text on an own line.
+%
+% \DescribeEnv{\%*} As long listings tend not to fit on one page, there will
+% be page breaks inserted. Since page breaks can considerably affect readability
+% there will be none at all unless you insert lines consisting of just "%*".
+% Pages will end here and only here, but not necessarily here. (That is, you
+% allow (or recommend) a page break. It will be taken if needed.)
+% \changes{v3.3}{1996/09/02}{Allow page breaks in embedded listings}
+%
+% \DescribeEnv{\%=} You can insert your own code by using a line starting with
+% "%=" in the program text. Whatever you enter after that is left in the output,
+% exactly as you typed it. It will be executed in a strange environment, so
+% doing anything fancy is very tricky. \DescribeMacro{\Line} A macro, "\Line",
+% is provided to help you do simple things. For example,
+% \begin{verbatim}
+% %[
+% %=\Line{________\vdots}
+% a = 1;
+% %]\end{verbatim}
+% produces:
+%
+% \hspace*{4em}\vdots
+%
+% \hspace*{4em}\textit{a}\textsf{ = 1;}
+%
+% (Within the program text, \_ is active and expands to a
+% fixed-width space. A whole bunch of macros are also defined. If you
+% understand how \LG{} sets lines up, you can replace the 8 \_'s
+% with a call to "\Tab"---but I'll let you hang yourself on that one.)
+%
+% \DescribeEnv{\%<}The "%<"\meta{file} command includes \meta{file} as a
+% program listing in your document. Before inclusion it will be pretty
+% printed. This is the almost the same as \LG ing the \meta{file}
+% separately and with -i and including it via "\lgrindfile", only that
+% it's simpler for you. \DescribeEnv{\%!} With "%!"\meta{command} the
+% input is taken from a shell command.
+%
+% While you can specify the language used on the command line, this does
+% not suffice for mixed-language programs (or projects). The command
+% \DescribeEnv{\%\#}"%#"\meta{language} provides you a means to change
+% the language on the fly wherever you want.
+%
+% \DescribeEnv{\%@}The shorthand "@" is very useful, and since "@" is not usable
+% in normal \LaTeX{} text there is no conflict. If, however, you use "@" in your
+% text (after "\makeatletter") the result produced by \LG{} is not satisfactory.
+% To disable the shorthand you can use a command line option, or locally "%@-".
+% Using "%@+" will switch it on again.
+%
+% Important rules:
+% \begin{itemize}
+% \item "%" and the following character must be the first two characters on
+% the line to be recognized.
+% \item
+% Put \emph{nothing} on the line after the "%" and the key character.
+% If you do that, \LG{} will provide a default environment that will
+% produce an "\hbox" for "%( )%", and a "\vbox" for "%[ %]".
+% If you put stuff on the line, \LG{} assumes you want to control
+% the format completely. Doing this requires understanding \emph{exactly}
+% what the code \LG{} produces is doing. (Sometimes I'm not sure I do!)
+% \item
+% "%)" and "%]" are simply ignored outside
+% of a code group, but any extra "%(" or "%[" produces a
+% warning, so a missing "%)" or "%]" is usually caught.
+% \item
+% Remember that the code between "%("/"%[" and "%)"/"%]" is put into a
+% single box. Expect the usual problems with long boxes! Use "%*" if needed.
+% \end{itemize}
+%
+% \subsection{Formatting your source code}
+% Well, \LG{} uses a different font for comments. This has as a consequence
+% that functions you refer to are typeset differently in the program and
+% in the comments, which is unsatisfactory. And, wouldn't it be great to
+% use \LaTeX{} commands to produce e.\,g. `\copyright'?
+%
+% The \texttt{lgrindef}-file defines environments for exactly these
+% purposes. They are usually defined as follows, but of course it is possible
+% to use other strings if the standard collides with the syntax of the
+% language in question.
+%
+% \DescribeEnv{\%\% \%\%}Text which is surrounded by "%%" is directly
+% passed to \LaTeX, a pair of curled braces around it. So the copyright
+% symbol would be produced with "%%\copyright%%".
+% \DescribeEnv{\%\$ \$\%}The "%$"\meta{text}"$%" works much the same,
+% except that \meta{text} is set in math mode.
+%
+% When \LG{} discovers a line that contains \emph{only} a comment beginning
+% right at the start of the line and ending at the very end (no spaces), containing
+% \emph{only} \LaTeX{} text as in the environment described above, the line
+% will be copied verbatim into the resulting \LaTeX{} document, with a newline
+% appended. This allows (e.\,g., in C):
+% \begin{verbatim}
+% /*%%\section{Main program}%%*/
+% int main()
+% {
+% //%%\subsection{Variables}%%
+% int a;\end{verbatim}
+% \changes{v3.6}{1999/05/28}{Complete \LaTeX{} lines allowed}
+%
+% The underscore which is normally the subscripting operator in math mode is
+% used internally in \LG{}. You can still use the command "\sb" instead (and
+% "\sp" for superscripts).\label{underscore}
+%
+% \DescribeEnv{\%| |\%}In "%|"\meta{text}"|%" a kind of verbatim
+% environment is provided. \meta{Text} is typeset in typewriter.
+%
+% \DescribeEnv{@ @}Program text within a comment is surrounded by "@". The text
+% is processed exactly as if it wasn't a comment. To produce an at-sign
+% you have to use "@@".
+%
+% \subsection{Greater control\dots}
+% Many things are controllable by re-defining various macros. You can
+% change what fonts \LG{} will use for various kinds of things, how
+% much it indents the output, whether it adds line numbers, and if so at
+% what interval it prints them and whether it sticks them on the left or
+% right, and so on. This stuff is all described below in the code section,
+% though probably not very well. The default settings produce output
+% that looks reasonable to me, though I can't say I'm ecstatic about it.
+% Doing a \emph{really} good job would require defining some special fonts.
+%
+% Nonetheless as an example my own private font setup. After having defined a
+% font family called ttp (for typewriter proportional), using Boton (a
+% commercial font which has a nice `code look' to it), I define:
+%
+% \begin{verbatim}
+% \def\CMfont{\ttpfamily\itshape}
+% \def\KWfont{\ttpfamily\bfseries}
+% \def\VRfont{\ttpfamily}
+% \def\BGfont{\ttpfamily}
+% \end{verbatim}
+%
+% You can put these redefinitions in the preamble of your \LaTeX-file when
+% using embedded and included mode; for stand-alone listings you have to put
+% them into the \texttt{lgrindef}-file. This will change fonts for all modes.
+%
+% \subsection{Error messages}
+% The output of \LG{} always contains exactly one output line for each input
+% line. Hence, you can look up line numbers in \TeX{} error messages in your
+% original file, rather than in the \LG ed (LGround?) file. (Of course, if
+% the problem is in the \LG{} output\dots)
+%
+% \subsection{Variable substitution}
+% \LG{} usually prints variables exactly the way they appear in the source
+% code. However, very often one uses names for variables which really denote
+% symbols and have special formatting, only that the input alphabet of the
+% target language does of course not allow anything fancier than plain ASCII.
+%
+% I find myself using greek variables very often, because they are used in the
+% problem domain. So there is a `delta' which really should be `$\delta$',
+% there is a `gamma\_1' for `$\gamma\sb1$' and so forth. LG{} allows you to
+% change those names back to what you desire by use of a variable substution
+% file (using option -v).
+%
+% This file is very simple, and so is its parser. There is one substitution per
+% line, giving the original name, an equality sign, and the text replacing the
+% original:
+% \begin{verbatim}
+% delta=$\delta$
+% gamma_1=$\gamma\sb1$
+% \end{verbatim}
+% You can do everything you want to here. Remember that \emph{usually} variable
+% names are set upright and not in math mode. Therefore don't forget the
+% dollar-sign, and use "\sb" instead of "_" (see section \ref{underscore}).
+%
+% \section{The \texttt{lgrindef}-file}
+% The \texttt{lgrindef}-file is \LG's language definition data base.
+% It is here where \LG{} learns what are keywords, what comments, where
+% are functions, how to distinguish plain comments from \LaTeX-commands etc.
+%
+% The first field is just the language name (and any variants
+% of it). Thus the C language could be specified to \LG{} as `c' or `C'.
+%
+% \subsection{Capabilities}
+% Capabilities are of two types: Boolean capabilities which indicate that
+% the language has some particular feature and string capabilities which
+% give a regular expression or keyword list.
+%
+% Entries may continue onto multiple lines by giving a "\" as the last
+% character of a line. Lines starting with "#" are comments.
+%
+% The following table names and describes each capability.
+% \bgroup\renewcommand{\descriptionlabel}[1]{\hspace{\labelsep}\makebox[1.5em][l]{\textsf{#1}}}
+% \begin{description}
+% \item[ab] Regular expression for the start of an alternate form comment
+% \item[ae] Regular expression for the end of an alternate form comment
+% \item[bb] Regular expression for the start of a block
+% \item[be] Regular expression for the end of a lexical block
+% \item[cb] Regular expression for the start of a comment
+% \item[ce] Regular expression for the end of a comment
+% \item[cf] (Boolean) Use specialized routine for detecting C functions
+% \changes{v3.1}{1995/11/12}{C functions are now detected much more reliably}
+% \item[id] String giving characters other than letters and digits
+% that may legally occur in identifiers (default `\_')
+% \item[kw] A list of keywords separated by spaces
+% \item[lb] Regular expression for the start of a character constant
+% \item[le] Regular expression for the end of a character constant
+% \item[mb] Regular expression for the start of \TeX{} math within a comment
+% \item[me] Regular expression for the end of \TeX{} math within a comment
+% \item[np] Regular expression for a line that does \emph{not} contain
+% the start of a procedure (e.\,g. prototypes)
+% \item[oc] (Boolean) Present means upper and lower case are equivalent
+% \item[pb] Regular expression for start of a procedure
+% \item[pl] (Boolean) Procedure definitions are constrained to the lexical
+% level matched by the `px' capability
+% \item[px] A match for this regular expression indicates that procedure
+% definitions may occur at the next lexical level. Useful for lisp-like
+% languages in which procedure definitions occur as subexpressions of defuns.
+% \item[rb] Regular expression for the start of block outside the actual
+% code.\footnote{I included this especially for the \texttt{objects} and
+% \texttt{records} in Pascal and Modula-2. They \emph{end} (with the "<"be">"
+% expression), but shouldn't have any influence on the surrounding procedure.
+% When defining \texttt{record} as normal block start, its \texttt{end} ends
+% the procedure. Workaround: Make \texttt{record} itself a procedure start.
+% But that prints a continuation mark when \textsf{procnames} is on.}
+% \changes{v3.1}{1995/11/12}{Pascal objects now treated properly}
+% \item[sb] Regular expression for the start of a string
+% \item[se] Regular expression for the end of a string
+% \item[tb] Regular expression for the start of \TeX{} text within a comment
+% \item[tc] (String) Use the named language entry as a continuation of the
+% current one
+% \item[te] Regular expression for the end of \TeX{} text within a comment
+% \item[tl] (Boolean) Present means procedures are only defined at the top
+% lexical level
+% \item[vb] Regular expression for the start of typewriter text within a
+% comment
+% \item[ve] Regular expression for the end of typewriter text within a comment
+% \item[zb] Regular expression for the start of program text within a comment
+% \item[ze] Regular expression for the end of program text within a comment
+% \end{description}
+% \egroup
+%
+% \subsection{Regular Expressions}
+% \texttt{lgrindef} uses regular expressions similar to those of
+% \textsf{ex} and \textsf{lex}. The characters `"^"', `"$"', `"|"', `:',
+%%stopzone % VIM syncing
+% and `"\"' are reserved characters and must be `quoted' with a preceding
+% "\" if they are to be included as normal characters.
+%
+% The meta-symbols and their meanings are:
+% \begin{description}
+% \item[\$] The end of a line
+% \item[\^] The beginning of a line
+% \item[$\backslash$d] A delimiter (space, tab, newline, start of line)
+% \item[$\backslash$a] Matches any string of symbols (like `.*' in lex)
+% \item[$\backslash$p] Matches any identifier. In a procedure definition
+% (the `pb' capability) the string that matches this symbol is used
+% as the procedure name.
+% \item[( )] Grouping
+% \item[$|$] Alternation
+% \item[?] Last item is optional
+% \item[$\backslash$e] Preceding any string means that the string will not
+% match an input string if the input string is preceded by an escape character
+% ("\"). This is typically used for languages (like C) that can include the
+% string delimiter in a string by escaping it.
+% \end{description}
+%
+% Unlike other regular expressions in the system, these match words and
+% not characters. Hence something like `(tramp"|"steamer)flies?'
+% would match `tramp', `steamer', `trampflies', or `steamerflies'.
+% Contrary to some forms of regular expressions, \texttt{lgrindef}
+% alternation binds very tightly. Grouping parentheses are likely to
+% be necessary in expressions involving alternation.
+%
+% \subsection{Keyword List}
+% The keyword list is just a list of keywords in the language separated
+% by spaces. If the `oc' boolean is specified, indicating that upper
+% and lower case are equivalent, then all the keywords should be specified
+% in lower case.
+%
+% \subsection{Configuration options}
+% \changes{v3.1}{1995/11/07}{The \LaTeX-text put into the files
+% can be configured}
+% In addition to the language definitions the \texttt{lgrindef}-file
+% contains various configuration data. When the entries do not exist,
+% default values are used:
+% \begin{description}
+% \item[firstpreamble] is the (\LaTeX-)text that comes at the beginning of
+% an stand-alone file created by \LG{} from source code (it must contain
+% "\begin{document}" somewhere).
+% \item[postamble] is the (\LaTeX-)text that comes at the end of
+% an stand-alone file (and must contain "\end{document}"). This is the place to
+% put a "\printindex" if you wish so (don't forget "\usepackage{makeidx}" and
+% "\makeindex" in the preamble).
+% \item[filepreamble] is inserted before every processed source file in a
+% stand-alone \LaTeX-file. In these two preambles you can use "\f", which
+% will be substituted by the current input file (e.\,g. to put it into the
+% header).
+% \item[configuration] follows the opening of the \texttt{lgrind}-environment.
+% This is used for redefining the macros used within it, e.\,g. the fonts
+% or the width of a space (the "\@ts" unit).
+% \item[chartab] is a list of characters that will be substituted by a
+% \LaTeX-string. This is useful when you do (or can) not use any of the fancy
+% methods to persuade \LaTeX{} into using your extended ASCII-characters.
+% The format is a two digit hex number (the ASCII- (or whatever) value of the
+% character), an equal sign, and the according \LaTeX{}-string, ended with a
+% colon. You have to escape certain characters (like the backslash). So if
+% you, e.\,g., have IBM ASCII code page 437 input and use the
+% \textsf{german}-package, you can have your \"a using \verb+84="a+. Note
+% that the substituting string must contain more than one character;
+% otherwise it will be ignored. To print a `b' instead of an `a' you can
+% use \verb+61={b}+.
+% \end{description}
+%
+% \StopEventually{\PrintChanges\PrintIndex}
+%
+% \section{The Implementation of \LG.sty}
+% \begin{macrocode}
+%<*package>
+% \end{macrocode}
+% \setlength{\parindent}{0pt}
+%
+% \begin{macro}{\LGnuminterval}\begin{macro}{\lc@unt}\begin{macro}{\ln@xt}
+% The counter "\LGnuminterval" represents the line numbering interval.
+% Its default is 10, it is set by two options and can be changed everywhere
+% you want to. "\lc@unt" counts the current line, "\ln@xt" contains the next
+% line to get numbered.
+% \begin{macrocode}
+\newcount\lc@unt
+\newcount\ln@xt
+\newcount\LGnuminterval
+\LGnuminterval=10
+\DeclareOption{nolineno}{\LGnuminterval=50000}
+\DeclareOption{lineno5}{\LGnuminterval=5}
+% \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\LGleftnum}
+% Line numbers are usually on the right. By setting "LGleftnum" to true
+% or false this behaviour can be altered.
+% \begin{macrocode}
+\newif\ifLGleftnum
+\DeclareOption{leftno}{\LGleftnumtrue}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\LGindent}
+% "\LGindent" is the indentation for all display style listing lines.
+% \begin{macrocode}
+\newskip\LGindent
+\LGindent=1.6667\parindent
+\DeclareOption{noindent}{\LGindent=0pt}
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4}{1997/02/05}{Rules around included material can be suppressed.
+% New option norules.}
+% \begin{macro}{\LGnorules}
+% Normally \LG{} puts rules around everything that is included (via "\lagrind"
+% and "\lgrindfile"), this can be changed with an option.
+% \begin{macrocode}
+\newif\ifLGnorules
+\DeclareOption{norules}{\LGnorulestrue}
+% \end{macrocode}
+% \end{macro}
+%
+% \changes{v3.4}{1997/01/30}{Prevent slightly overfull hboxes. New option fussy.}
+% \begin{macro}{\LGsloppy}
+% "\LGsloppy" is the amount that a horizontal box may be overfull without getting
+% a warning from \LaTeX. This is useful since there are often many boxes which are
+% overfull by only a few points, and this does not really show since listings are
+% very ragged.
+% \begin{macrocode}
+\newlength{\LGsloppy}
+\setlength{\LGsloppy}{7.2pt}
+\DeclareOption{fussy}{\LGsloppy=0pt}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\Proc}\begin{macro}{\ProcCont}
+% There's a "\Proc{"\meta{ProcName}"}" at the start of each procedure. If
+% the language allows nested procedures (e.\,g. Pascal), there
+% will be a "\ProcCont{"\meta{ProcName}"}" at the end of each inner procedure.
+% (In this case, \meta{ProcName} is the name of the outer procedure. I.\,e.,
+% "\ProcCont" marks the continuation of \meta{ProcName}).
+%
+% \begin{macro}{\DefaultProc}
+% \changes{v3.0}{1995/09/24}{Reintroduced procedure names in the margins}
+% \begin{macro}{\DefaultProcCont}
+% Default is not to do anything with the name. Optionally the names are
+% printed in the same margin as the line numbers. The name is put into a
+% box which will be output whenever it is not empty.
+%
+% \begin{macrocode}
+\newcommand{\DefaultProc}{\@gobble}
+\newcommand{\DefaultProcCont}{\@gobble}
+\DeclareOption{procnames}{
+\renewcommand{\DefaultProc}[1]{\renewcommand{\Procname}{#1}%
+\global\setbox\procbox=\hbox{\PNsize #1}}
+\renewcommand{\DefaultProcCont}[1]{\renewcommand\Procname{#1}
+\global\setbox\procbox=\hbox{\PNsize\dots #1}}}
+\newbox\procbox
+\newcommand{\Procname}{}
+% \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\ifLGnoprocindex}
+% \changes{v3.6}{1999/05/27}{Added option to suppress indexing of functions}
+% \begin{macrocode}
+\newif\ifLGnoprocindex
+\DeclareOption{noprocindex}{\LGnoprocindextrue}
+% \end{macrocode}
+% \end{macro}
+%
+% End of initialization, execute any options.
+% \begin{macrocode}
+\ProcessOptions
+% \end{macrocode}
+% \changes{v3.0}{1995/09/28}{Added package options}
+%
+% \begin{macro}{\BGfont}\begin{macro}{\CMfont}\begin{macro}{\NOfont}
+% \changes{v3.1}{1995/11/12}{Numbers can now have an own style (i.\,e. font)}
+% \begin{macro}{\KWfont}\begin{macro}{\STfont}\begin{macro}{\TTfont}
+% \begin{macro}{\VRfont}\begin{macro}{\PNsize}\begin{macro}{\LGsize}
+% \begin{macro}{\LGfsize}
+% These are the fonts and sizes for background (everything that doesn't fit
+% elsewhere), comments, numbers, keywords, strings, verbatim text, variables,
+% the procedure names
+% in the margins, displayed code ("%[ ]%"), and included code ("\lgrindfile"
+% and "\lagrind"), respectively. Note that the suffixes `font' and `size'
+% have been chosen solely for the author's intention; you can do anything
+% you want, e.\,g. "\tiny" comments. You have to use, however, font changes
+% which don't require an argument.
+% \begin{macrocode}
+\def\BGfont{\sffamily}
+\def\CMfont{\rmfamily\itshape}
+\def\NOfont{\sffamily}
+\def\KWfont{\rmfamily\bfseries}
+\def\STfont{\ttfamily}
+\def\TTfont{\ttfamily\upshape}
+\def\VRfont{\rmfamily}
+\def\PNsize{\BGfont\small}
+\def\LGsize{\small}
+\def\LGfsize{\footnotesize}
+% \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+% \end{macro}\end{macro}\end{macro}
+% \end{macro}\end{macro}\end{macro}
+% \end{macro}
+%
+% \begin{macro}{\ifLGinline}\begin{macro}{\ifLGd@fault}
+% \begin{macro}{\LGbegin}\begin{macro}{\LGend}
+% The flag "LGinline" is true for in-line code. "\LGbegin" and "\LGend" are
+% default commands to open and close a code example and use it to perform
+% certain ops depending whether we're in-line or display style."\LGend" is
+% a no-op unless "\LGbegin" (where "LGd@fault" is set true) was executed,
+% so you can provide explicit open
+% code on the "%[" or "%(" line without providing any special code on the
+% matching "%]" or "%)" line.
+% \begin{macrocode}
+\newif\ifLGinline
+\newif\ifLGd@fault
+\def\LGbegin{\ifLGinline$\hbox\else$$\vbox\fi\bgroup\LGd@faulttrue}
+\def\LGend{\ifLGd@fault\egroup\ifLGinline$\else$$\fi\LGd@faultfalse\fi}
+% \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%%stopzone % VIM syncing
+%
+% \begin{macro}{\ifc@omment}\begin{macro}{\ifstr@ng}
+% These two conditions indicate if we are setting a comment or maybe
+% a string constant, respectively.
+% \begin{macrocode}
+\newif\ifc@mment
+\newif\ifstr@ng
+% \end{macrocode}
+% \end{macro}\end{macro}
+%
+% \begin{macro}{\ifright@}
+% To get decent quotes (opening and closing) within comments, we remember
+% whether the next one is going to be `{}``'{} or, if true, `{}'''{}.
+% \begin{macrocode}
+\newif\ifright@
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\ls@far}\begin{macro}{\tb@x}\begin{macro}{\TBw@d}
+% These three are all for the sake of tabbing. "\ls@far" stores the
+% ``line so far''. The tabwidth goes in "\TBw@d", whilst "\tb@x" is
+% merely a temporary variable for "\Tab" and setting "\@ts".
+% \begin{macrocode}
+\newbox\ls@far
+\newbox\tb@x
+\newdimen\TBw@d
+% \end{macrocode}
+% \end{macro}\end{macro}\end{macro}
+%
+% The underscore marks a point where the pre-processor wants a fixed-width
+% space (of width "\@ts").
+% \begin{macrocode}
+\newdimen\@ts
+{\catcode`\_=\active \gdef\@setunder{\let_=\sp@ce}}
+% \end{macrocode}
+%
+% \begin{macro}{\lgrindhead}
+% \begin{macro}{\lgrindfilename}\begin{macro}{\lgrindfilesize}
+% \begin{macro}{\lgrindmodyear}\begin{macro}{\lgrindmodmonth}
+% \begin{macro}{\lgrindmodday}\begin{macro}{\lgrindmodtime}
+% We pollute the global namspace once more with these macros, for when they
+% are used in the headers or footers, their values must still be known.
+% Therefore they cannot be local to the "lgrind" environment.
+% \begin{macrocode}
+\newcommand{\lgrindhead}{}
+\newcommand{\lgrindfilename}{}\newcommand{\lgrindfilesize}{}
+\newcommand{\lgrindmodyear}{}\newcommand{\lgrindmodmonth}{}
+\newcommand{\lgrindmodday}{}\newcommand{\lgrindmodtime}{}
+% \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+% \end{macro}\end{macro}\end{macro}
+%
+% \begin{environment}{lgrind}
+% This is the environment that eventually defines all necessary macros for
+% formatting. All \LG ed text goes into such an environment, no matter if
+% directly so or from within another one. It takes one optional argument,
+% the line number.
+% \begin{macrocode}
+\newenvironment{lgrind}[1][1]{%
+% \end{macrocode}
+%
+% \begin{macro}{\Line}
+% The "\Line" macro is provided for use with "%=" in embedded listings.
+% It's just there to hide the actual structure of this, for nobody
+% \emph{really} wants to know anyway.
+% \begin{macrocode}
+\def\Line##1{\L{\LB{##1}}}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\Head}\begin{macro}{\File}
+% \changes{v3.3}{1996/09/11}{given a meaningful definition}
+% The next are primarily meant for stand-alone listings. "\Head" and
+% "\File" are inserted by \LG, they define macros that contain
+% a user-specified string (the header option -h), the name, size
+% and modification time of the processed file. These can then be
+% used e.\,g. in the headers and footers.
+% \begin{macrocode}
+\newcommand{\Head}[1]{\gdef\lgrindhead{##1}}%
+\newcommand{\File}[6]{\gdef\lgrindfilename{##1}\message{(LGround: ##1)}%
+ \gdef\lgrindmodyear{##2}\gdef\lgrindmodmonth{##3}%
+ \gdef\lgrindmodday{##4}\gdef\lgrindmodtime{##5}%
+ \gdef\lgrindfilesize{##6}}%
+% \end{macrocode}
+% \end{macro}\end{macro}
+% The "\Proc"s now get what
+% was specified for them in the options section.
+% \begin{macrocode}
+\let\Proc=\DefaultProc%
+\let\ProcCont=\DefaultProcCont%
+\ifLGnoprocindex%
+ \let\index\@gobble%
+\fi%
+% \end{macrocode}
+%
+% We set a "\hfuzz" to prevent some of the lesser overfull hbox warnings.
+% \begin{macrocode}
+\hfuzz=\LGsloppy%
+% \end{macrocode}
+%
+% \begin{macro}{\NewPage}
+% Each formfeed in the input is replaced by a "\NewPage" macro. If
+% you really want a page break here, define this as "\vfill\eject".
+% \begin{macrocode}
+\def\NewPage{\filbreak\bigskip}%
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\L}
+% Each line of displayed program text is enclosed by a "\L{"\dots"}". We
+% turn each line into an hbox. Firstly we look whether we are in-line.
+% Every "\LGnuminterval" lines we output a
+% small line number in past the margin.
+% \begin{macrocode}
+\ifLGinline%
+ \def\L##1{\setbox\ls@far\null{\CF\strut##1}\ignorespaces}%
+% \end{macrocode}
+% \begin{macro}{\r@ghtlno}\begin{macro}{\l@ftlno}
+% Things get more difficult for display style listings. Here we set
+% "\r@ghtlno" and "\l@ftlno" to no-ops, only to redefine them shortly
+% after.
+% \begin{macrocode}
+\else%
+ \let\r@ghtlno\relax\let\l@ftlno\relax%
+ \ifnum\LGnuminterval>\z@%
+ \ifLGleftnum%
+% \end{macrocode}
+% If there was a procedure name somewhere, "\procbox" is not empty and
+% thus ready to be printed. Otherwise we test "\lc@unt" against "\ln@ext"
+% to determine whether or not to print a line number.
+% \begin{macrocode}
+ \def\l@ftlno{\ifnum\lc@unt>\ln@xt%
+ \global\advance\ln@xt by\LGnuminterval%
+ \llap{{\normalfont\scriptsize\the\lc@unt\quad}}\fi}%
+ \def\r@ghtlno{\rlap{\enspace\box\procbox}}%
+% \end{macrocode}
+% And once again when the line number is meant to be on the right.
+% \begin{macrocode}
+ \else%
+ \def\r@ghtlno{\ifnum\lc@unt>\ln@xt%
+ \global\advance\ln@xt by\LGnuminterval%
+ \rlap{{\normalfont\scriptsize\enspace\the\lc@unt%
+ \enspace\box\procbox}}%
+ \else\rlap{\enspace\box\procbox}\fi}%
+ \fi%
+ \fi%
+% \end{macrocode}
+% \end{macro}\end{macro}
+% "\lc@unt" is incremented and everything is squeezed into a "\hbox".
+% \begin{macrocode}
+ \def\L##1{\@@par\setbox\ls@far=\null\strut%
+ \global\advance\lc@unt by1%
+ \hbox to \linewidth{\hskip\LGindent\l@ftlno ##1\egroup%
+ \hfil\r@ghtlno}%
+ \ignorespaces}%
+\fi%
+% \end{macrocode}
+% \end{macro}
+%
+% The initialization of "\lc@unt" and "\ln@xt". Every "lgrind"-environment
+% starts over unless given a line number as argument.
+% \begin{macrocode}
+\lc@unt=#1\advance\lc@unt by-1%
+\ln@xt=\LGnuminterval\advance\ln@xt by-1%
+\loop\ifnum\lc@unt>\ln@xt\advance\ln@xt by\LGnuminterval\repeat%
+% \end{macrocode}
+%
+% \begin{macro}{\LB}\begin{macro}{\Tab}
+% The following weirdness is to deal with tabs. ``Pieces'' of a line
+% between tabs are output as "\LB{"\dots"}". E.\,g., a line with a tab at
+% column 16 would be output as "\LB{xxx}\Tab{16}\LB{yyy}". (Actually, to
+% reduce the number of characters in the ".tex" file the "\Tab" macro
+% supplies the 2nd \& subsequent "\LB"s.) We accumulate the "\LB" stuff in
+% an "\hbox". When we see a "\Tab", we grab this hbox (using "\lastbox")
+% and turn it into a box that extends to the tab position. We stash this
+% box in "\ls@far" \& stick it on in front of the next piece of the line.
+% (There must be a better way of doing tabs but I'm not enough of a \TeX
+% wizard to come up with it. Suggestions would be appreciated. Oh, well,
+% this comment's been in here for a decade. I don't believe in Santa Claus.)
+% \begin{macrocode}
+\def\LB{\hbox\bgroup\bgroup\box\ls@far\CF\let\next=}%
+\def\Tab##1{\egroup\setbox\tb@x=\lastbox\TBw@d=\wd\tb@x%
+ \advance\TBw@d by 1\@ts\ifdim\TBw@d>##1\@ts%
+ \setbox\ls@far=\hbox{\box\ls@far \box\tb@x \sp@ce}\else%
+ \setbox\ls@far=\hbox to ##1\@ts{\box\ls@far \box\tb@x \hfil}\fi\LB}%
+% \end{macrocode}
+% \end{macro}\end{macro}
+%
+% A normal space is too thin for code listings. We make spaces \& tabs
+% be in "\@ts" units, which for displays are 80 \% the width of a ``0'' in the
+% typewriter font. For inline stuff, on the other hand, we prefer a
+% somewhat smaller space -- actually, the same size as normal inter-word
+% spaces -- to help make the included stuff look like a unit.
+% \begin{macrocode}
+\ifLGinline\def\sp@ce{{\hskip .3333em}}%
+\else \setbox\tb@x=\hbox{\texttt{0}}%
+ \@ts=0.8\wd\tb@x \def\sp@ce{{\hskip 1\@ts}}\fi%
+\catcode`\_=\active \@setunder%
+% \end{macrocode}
+%
+% \begin{macro}{\CF}\begin{macro}{\N}\begin{macro}{\K}\begin{macro}{\V}
+% \begin{macro}{\ic@r}
+% \begin{macro}{\C}\begin{macro}{\CE}\begin{macro}{\S}\begin{macro}{\SE}
+% Font changing. Since we are usually changing the font inside of a "\LB"
+% macro, we remember the current font in "\CF" \& stick a "\CF" at the
+% start of each new box. Also, the characters ``\texttt{\char'042}'' and
+% ``"'"'' behave differently in comments than in code, and others behave
+% differently in strings than in code.
+%
+% "\N" is for numbers, "\K" marks keywords, "\V" variables, "\C" and "\CE"
+% surround comments, "\S" and "\SE" strings.
+% "\ic@r" inserts an optional "\/".
+% \begin{macrocode}
+\def\CF{\ifc@mment\CMfont\else\ifstr@ng\STfont\fi\fi}%
+\def\N##1{{\NOfont ##1}\global\futurelet\next\ic@r}%
+\def\K##1{{\KWfont ##1}\global\futurelet\next\ic@r}%
+\def\V##1{{\VRfont ##1}\global\futurelet\next\ic@r}%
+\def\ic@r{\let\@tempa\/\ifx.\next\let\@tempa\relax%
+ \else\ifx,\next\let\@tempa\relax\fi\fi\@tempa}%
+\def\C{\egroup\bgroup\CMfont \global\c@mmenttrue \global\right@false}%
+\def\CE{\egroup\bgroup \global\c@mmentfalse}%
+\def\S{\egroup\bgroup\STfont \global\str@ngtrue}%
+\def\SE{\egroup\bgroup \global\str@ngfalse}%
+% \end{macrocode}
+% \end{macro}\end{macro}\end{macro}\end{macro}\end{macro}
+% \end{macro}\end{macro}\end{macro}\end{macro}
+%
+% \begin{macro}{\,}\begin{macro}{\!}
+% We need positive and negative thinspaces in both text and math modes, so
+% we re-define "\," and "\!" here. The definition for "\," isn't really
+% needed for \LaTeX, but we try to be more complete. Note that in \LaTeX{}
+% terms, the new definition isn't robust, like the old~-- but nothing we
+% produce here is likely to be robust --~or \emph{needs} to be!~-- anyway!
+% \begin{macrocode}
+\def\,{\relax \ifmmode\mskip\thinmuskip \else\thinspace \fi}%
+\def\!{\relax \ifmmode\mskip-\thinmuskip \else\negthinspace \fi}%
+% \end{macrocode}
+% \end{macro}\end{macro}
+%
+% Special characters. "\CH" chooses its first option alone in math mode;
+% its second option in a string; and its third option, enclosed in "$"s,
+%%stopzone % VIM syncing
+% otherwise. (At the moment, nothing is ever set in math mode, but you
+% never know \dots)
+% \begin{macrocode}
+\def\CH##1##2##3{\relax\ifmmode ##1\relax%
+\else\ifstr@ng ##2\relax\else$##3$\fi\fi }%
+\def\|{\CH|||}% not necessary for T1
+\def\<{\CH<<<}% dto.
+\def\>{\CH>>>}% dto.
+\def\-{\CH---}% minus sign nicer than hyphen
+\def\_{\ifstr@ng {\char'137}\else%
+ \leavevmode \kern.06em \vbox{\hrule width.35em}%
+ \ifdim\fontdimen\@ne\font=\z@ \kern.06em \fi\fi }%
+\def\#{{\STfont\char'043}}%
+\def\2{\CH\backslash {\char'134}\backslash }% % \
+\def\3{\ifc@mment\ifright@ ''\global\right@false%
+ \else``\global\right@true \fi%
+ \else{\texttt{\char'042}}\fi}% % "
+\def\5{{\texttt{\char'136}}}% % ^
+% \end{macrocode}
+%
+% Finally we don't want any indentation other than our own. We allow \LaTeX{}
+% to stretch our listings a bit. Then we open a group, select the background
+% font and (fanfare!) are ready to begin.
+% \begin{macrocode}
+\parindent\z@\parskip\z@ plus 1pt%
+\bgroup\BGfont%
+}
+% \end{macrocode}
+%
+% This is the end of the "lgrind" environment. Rather short (in comparison!)
+% \begin{macrocode}
+{\egroup\@@par} % end of environment lgrind
+% \end{macrocode}
+% \end{environment}
+%
+% The following are generated as part of opening and closing included
+% code sequences.
+% \begin{macrocode}
+\def\lgrinde{\ifLGinline\else\LGsize\fi\begin{lgrind}}
+\def\endlgrinde{\end{lgrind}}
+% \end{macrocode}
+%
+% \begin{macro}{\lagrind}
+% The "lagrind" environment is one of two for including files. It puts
+% its argument inside a "figure" environment. It can be used without or
+% with a star (first line), and with or without the usual floating
+% arguments (second and third).
+% \begin{macrocode}
+\def\lagrind{\@ifstar{\@slagrind}{\@lagrind}}
+
+\def\@lagrind{\@ifnextchar[{\@@lagrind}{\@@lagrind[t]}}
+\def\@slagrind{\@ifnextchar[{\@@slagrind}{\@@slagrind[t]}}
+% \end{macrocode}
+%
+% \begin{macro}{\@@lagrind}
+% The unstarred version. Everything is pretty obvious, we open a "figure",
+% put in a "minipage", input the file in question, make caption and label
+% and that's it.
+% \begin{macrocode}
+\def\@@lagrind[#1]#2#3#4{%
+ \begin{figure}[#1]
+\ifLGnorules\else\hrule\fi
+\vskip .5\baselineskip
+\begin{minipage}\columnwidth\LGsize\LGindent\z@
+ \begin{lgrind}
+\input #2\relax
+ \end{lgrind}
+\end{minipage}
+\vskip .5\baselineskip plus .5\baselineskip
+\ifLGnorules\else\hrule\fi\vskip .5\baselineskip
+\begingroup
+ \setbox\z@=\hbox{#4}%
+ \ifdim\wd\z@>\z@
+\caption{#3}%
+\label{#4}%
+ \else
+\captcont{#3}%
+ \fi
+\endgroup
+\vskip 2pt
+ \end{figure}
+}
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@slagrind}
+% D\'ej\`a vu? The starred version got an asterisk attached to "figure".
+% \begin{macrocode}
+\def\@@slagrind[#1]#2#3#4{%
+ \begin{figure*}[#1]
+\ifLGnorules\else\hrule\fi
+\vskip .5\baselineskip
+\begin{minipage}\linewidth\LGsize\LGindent\z@
+ \begin{lgrind}
+\input #2\relax
+ \end{lgrind}
+\end{minipage}
+\vskip .5\baselineskip plus .5\baselineskip
+\ifLGnorules\else\hrule\fi\vskip .5\baselineskip
+\begingroup
+ \setbox\z@=\hbox{#4}%
+ \ifdim\wd\z@>\z@
+\caption{#3}%
+\label{#4}%
+ \else
+\captcont{#3}%
+ \fi
+\endgroup
+\vskip 2pt
+ \end{figure*}
+}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\lgrindfile}
+% This is similar. We draw lines above and below, no "figure". But it can
+% get longer than one page.
+% \begin{macrocode}
+\def\lgrindfile#1{%
+ \par\addvspace{0.1in}
+ \ifLGnorules\else\hrule\fi
+ \vskip .5\baselineskip
+ \begingroup\LGfsize\LGindent\z@
+\begin{lgrind}
+ \input #1\relax
+\end{lgrind}
+ \endgroup
+ \vskip .5\baselineskip
+ \ifLGnorules\else\hrule\vspace{0.1in}\fi
+}
+% \end{macrocode}
+% \end{macro}
+%
+% And now \dots
+% \begin{macrocode}
+%</package>
+% \end{macrocode}
+% That's it. Thank you for reading up to here.
+%
+% Michael Piefel
+%
+% \vspace{2ex}
+% \hrule
+%
+% \Finale
+%
+% \iffalse
+%<*example>
+\documentclass{report}
+\usepackage{lgrind}
+
+\begin{document}
+
+\chapter{Introduction}
+This is a \LaTeX file with embedded code. Process it with \textsf{LGrind}
+and its option -e.
+
+\appendix
+\chapter{lgrind.c}
+%<example>%< lgrind.c
+
+\chapter{regexp.c}
+\section{Header}
+%<example>%< regexp.h
+\section{Code}
+%<example>%< regexp.c
+
+\chapter{lgrindef.c}
+\section{Header}
+%<example>%< lgrindef.h
+\section{Code}
+%<example>%< lgrindef.c
+
+\end{document}
+%</example>
+% \fi
+\endinput
diff --git a/support/lgrind/lgrind.gls b/support/lgrind/lgrind.gls
new file mode 100644
index 0000000000..ab7dc39e93
--- /dev/null
+++ b/support/lgrind/lgrind.gls
@@ -0,0 +1,37 @@
+
+ \begin{theglossary}
+
+ \makeatletter\scan@allowedfalse
+
+ \item v1.0\efill
+ \subitem General:\ Written\pfill 1
+ \item v2.0\efill
+ \subitem General:\ Upgrade to \LaTeX 2.09\pfill 1
+ \item v3.0\efill
+ \subitem General:\ Added package options\pfill 11
+ \subsubitem Upgrade to \LaTeXe \pfill 1
+ \subitem \verb*+\DefaultProc+:\ Reintroduced procedure names in the margins\pfill 11
+ \item v3.1\efill
+ \subitem General:\ C functions are now detected much more reliably\pfill 8
+ \subsubitem Pascal objects now treated properly\pfill 8
+ \subsubitem The \LaTeX -text put into the files can be configured\pfill
+ 10
+ \subitem \verb*+\NOfont+:\ Numbers can now have an own style (i.\,e. font)\pfill 11
+ \item v3.3\efill
+ \subitem General:\ "lgrindef" position can be changed permanently\pfill 2
+ \subsubitem Allow page breaks in embedded listings\pfill 5
+ \subitem \verb*+\File+:\ given a meaningful definition\pfill 13
+ \item v3.4\efill
+ \subitem General:\ Prevent slightly overfull hboxes. New option fussy.\pfill 11
+ \subsubitem Rules around included material can be suppressed. New option norules.\pfill
+ 11
+ \item v3.5\efill
+ \subitem General:\ Now testing for \texttt {LGRINDEF} environment variable.\pfill 2
+ \subsubitem Output redirection (-o) implemented.\pfill 2
+ \subsubitem Procedure names added to index in addition to printing them in the margin.\pfill
+ 3
+ \item v3.6\efill
+ \subitem General:\ Complete \LaTeX {} lines allowed\pfill 6
+ \subitem \verb*+\ifLGnoprocindex+:\ Added option to suppress indexing of functions\pfill 11
+
+ \end{theglossary}
diff --git a/support/lgrind/lgrind.ind b/support/lgrind/lgrind.ind
new file mode 100644
index 0000000000..2b31491fd3
--- /dev/null
+++ b/support/lgrind/lgrind.ind
@@ -0,0 +1,156 @@
+
+ \begin{theindex}
+ \makeatletter\scan@allowedfalse
+{\bfseries\hfil Symbols\hfil}\nopagebreak
+
+ \item \verb*+\,+\pfill \main{116}
+ \item =\verb*+\!+\pfill \main{116}
+ \item {\ttfamily @ @} (environment)\pfill \usage{4}, \usage{6}
+ \item \verb*+\@@lagrind+\pfill \main{143}
+ \item \verb*+\@@slagrind+\pfill \main{166}
+ \item {\ttfamily \%!} (environment)\pfill \usage{5}
+ \item {\ttfamily \%( \%)} (environment)\pfill \usage{4}
+ \item {\ttfamily \%*} (environment)\pfill \usage{5}
+ \item {\ttfamily \%<} (environment)\pfill \usage{5}
+ \item {\ttfamily \%=} (environment)\pfill \usage{5}
+ \item {\ttfamily \%@} (environment)\pfill \usage{5}
+ \item {\ttfamily \%[ \%]} (environment)\pfill \usage{5}
+ \item {\ttfamily \%\#} (environment)\pfill \usage{5}
+ \item {\ttfamily \%\$ \$\%} (environment)\pfill \usage{6}
+ \item {\ttfamily \%\% \%\%} (environment)\pfill \usage{6}
+ \item {\ttfamily \%| |\%} (environment)\pfill \usage{6}
+
+ \indexspace
+{\bfseries\hfil B\hfil}\nopagebreak
+
+ \item \verb*+\BGfont+\pfill \main{30}
+
+ \indexspace
+{\bfseries\hfil C\hfil}\nopagebreak
+
+ \item \verb*+\C+\pfill \main{106}
+ \item \verb*+\CE+\pfill \main{106}
+ \item \verb*+\CF+\pfill \main{106}
+ \item \verb*+\CMfont+\pfill \main{30}
+
+ \indexspace
+{\bfseries\hfil D\hfil}\nopagebreak
+
+ \item \verb*+\DefaultProc+\pfill \main{18}
+ \item \verb*+\DefaultProcCont+\pfill \main{18}
+
+ \indexspace
+{\bfseries\hfil E\hfil}\nopagebreak
+
+ \item environments:\efill
+ \subitem {\ttfamily @ @}\pfill \usage{4}, \usage{6}
+ \subitem {\ttfamily \%!}\pfill \usage{5}
+ \subitem {\ttfamily \%( \%)}\pfill \usage{4}
+ \subitem {\ttfamily \%*}\pfill \usage{5}
+ \subitem {\ttfamily \%<}\pfill \usage{5}
+ \subitem {\ttfamily \%=}\pfill \usage{5}
+ \subitem {\ttfamily \%@}\pfill \usage{5}
+ \subitem {\ttfamily \%[ \%]}\pfill \usage{5}
+ \subitem {\ttfamily \%\#}\pfill \usage{5}
+ \subitem {\ttfamily \%\$ \$\%}\pfill \usage{6}
+ \subitem {\ttfamily \%\% \%\%}\pfill \usage{6}
+ \subitem {\ttfamily lgrind}\pfill \main{13}
+
+ \indexspace
+{\bfseries\hfil F\hfil}\nopagebreak
+
+ \item \verb*+\File+\pfill \main{58}
+
+ \indexspace
+{\bfseries\hfil H\hfil}\nopagebreak
+
+ \item \verb*+\Head+\pfill \main{58}
+
+ \indexspace
+{\bfseries\hfil I\hfil}\nopagebreak
+
+ \item \verb*+\ic@r+\pfill \main{106}
+ \item \verb*+\ifc@omment+\pfill \main{44}
+ \item \verb*+\ifLGd@fault+\pfill \main{40}
+ \item \verb*+\ifLGinline+\pfill \main{40}
+ \item \verb*+\ifLGnoprocindex+\pfill \main{27}
+ \item \verb*+\ifright@+\pfill \main{46}
+ \item \verb*+\ifstr@ng+\pfill \main{44}
+
+ \indexspace
+{\bfseries\hfil K\hfil}\nopagebreak
+
+ \item \verb*+\K+\pfill \main{106}
+ \item \verb*+\KWfont+\pfill \main{30}
+
+ \indexspace
+{\bfseries\hfil L\hfil}\nopagebreak
+
+ \item \verb*+\L+\pfill \main{70}
+ \item \verb*+\l@ftlno+\pfill \main{72}
+ \item \verb*+\lagrind+\pfill \usage{4}, \main{139}
+ \item \verb*+\LB+\pfill \main{97}
+ \item \verb*+\lc@unt+\pfill \main{2}
+ \item \verb*+\LGbegin+\pfill \main{40}
+ \item \verb*+\LGend+\pfill \main{40}
+ \item \verb*+\LGfsize+\pfill \main{30}
+ \item \verb*+\LGindent+\pfill \main{10}
+ \item \verb*+\LGleftnum+\pfill \main{8}
+ \item \verb*+\LGnorules+\pfill \main{13}
+ \item \verb*+\LGnuminterval+\pfill \main{2}
+ \item {\ttfamily lgrind} (environment)\pfill \main{56}
+ \item \verb*+\lgrindfile+\pfill \usage{4}, \main{189}
+ \item \verb*+\lgrindfilename+\pfill \main{52}
+ \item \verb*+\lgrindfilesize+\pfill \main{52}
+ \item \verb*+\lgrindhead+\pfill \main{52}
+ \item \verb*+\lgrindmodday+\pfill \main{52}
+ \item \verb*+\lgrindmodmonth+\pfill \main{52}
+ \item \verb*+\lgrindmodtime+\pfill \main{52}
+ \item \verb*+\lgrindmodyear+\pfill \main{52}
+ \item \verb*+\LGsize+\pfill \main{30}
+ \item \verb*+\LGsloppy+\pfill \main{15}
+ \item \verb*+\Line+\pfill \usage{5}, \main{57}
+ \item \verb*+\ln@xt+\pfill \main{2}
+ \item \verb*+\ls@far+\pfill \main{47}
+
+ \indexspace
+{\bfseries\hfil N\hfil}\nopagebreak
+
+ \item \verb*+\N+\pfill \main{106}
+ \item \verb*+\NewPage+\pfill \main{69}
+ \item \verb*+\NOfont+\pfill \main{30}
+
+ \indexspace
+{\bfseries\hfil P\hfil}\nopagebreak
+
+ \item \verb*+\PNsize+\pfill \main{30}
+ \item \verb*+\Proc+\pfill \main{18}
+ \item \verb*+\ProcCont+\pfill \main{18}
+
+ \indexspace
+{\bfseries\hfil R\hfil}\nopagebreak
+
+ \item \verb*+\r@ghtlno+\pfill \main{72}
+
+ \indexspace
+{\bfseries\hfil S\hfil}\nopagebreak
+
+ \item \verb*+\S+\pfill \main{106}
+ \item \verb*+\SE+\pfill \main{106}
+ \item \verb*+\STfont+\pfill \main{30}
+
+ \indexspace
+{\bfseries\hfil T\hfil}\nopagebreak
+
+ \item \verb*+\Tab+\pfill \main{97}
+ \item \verb*+\tb@x+\pfill \main{47}
+ \item \verb*+\TBw@d+\pfill \main{47}
+ \item \verb*+\TTfont+\pfill \main{30}
+
+ \indexspace
+{\bfseries\hfil V\hfil}\nopagebreak
+
+ \item \verb*+\V+\pfill \main{106}
+ \item \verb*+\VRfont+\pfill \main{30}
+
+ \end{theindex}
diff --git a/support/lgrind/lgrind.ins b/support/lgrind/lgrind.ins
new file mode 100644
index 0000000000..fb78e75beb
--- /dev/null
+++ b/support/lgrind/lgrind.ins
@@ -0,0 +1,27 @@
+%%
+%% This file will generate fast loadable files and documentation
+%% driver files from the doc files in this package when run through
+%% LaTeX or TeX.
+%%
+\def\batchfile{lgrind.ins}
+\input docstrip.tex
+\preamble
+
+LGrind is used to format source code of different programming
+languages for LaTeX.
+
+LGrind is a major adaptation of Jerry Leichter's tgrind for LaTeX,
+which was a notable improvement upon Van Jacobsen's tgrind for
+plain TeX, which was adapted from vgrind, a troff prettyprinter.
+
+LGrind contains non-free code written by Van Jacobson, who does not answer
+to any request for changing his licence. This software is therefore not
+maintained. I also do not accept any cheques anymore.
+\endpreamble
+\keepsilent
+
+\generateFile{lgrind.sty}{t}{%
+ \from{lgrind.dtx}{package}}
+
+\generateFile{doc-lgrind.lg}{t}{%
+ \from{lgrind.dtx}{example}}
diff --git a/support/lgrind/lgrind.pdf b/support/lgrind/lgrind.pdf
new file mode 100644
index 0000000000..4ad643093e
--- /dev/null
+++ b/support/lgrind/lgrind.pdf
Binary files differ
diff --git a/support/lgrind/lgrindef b/support/lgrind/lgrindef
new file mode 100644
index 0000000000..c2311f8688
--- /dev/null
+++ b/support/lgrind/lgrindef
@@ -0,0 +1,850 @@
+# Database of program templates for lgrind
+# $Id: lgrindef,v 1.7 2000/12/27 21:42:37 mike Exp $
+
+Ada:\
+ :pb=(^\d?procedure|function\d\p\d|\():\
+ :np=;\d?$:id=_.:\
+ :bb=\d(begin|case|do|if|loop|select)\d:be=\dend\d|;:\
+ :rb=(\=|\:|\d|^)(protected|record):\
+ :oc:\
+ :cb=--:ce=$:ab=--:ae=$:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=":se=":lb=':le=':\
+ :kw=abort abs accept access aliased all and array at begin body case\
+ constant declare delay delta digits do else elsif end entry exception exit\
+ for function generic goto if in is limited loop mod new not null of or\
+ others out package pragma private procedure protected raise range record\
+ rem renames requeue return reverse select separate subtype tagged task\
+ terminate then type until use when while with xor:
+
+Asm:\
+ :oc:\
+ :cb=#:ce=$:ab=/*:ae=*/:\
+ :sb=':se=':lb=":le=":\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=ascii block byte end equ globl text data word even long\
+ #else #endif #if #ifdef #ifndef #include #undef #define else endif\
+ if ifdef ifndef include undef define:
+
+Asm68:\
+ :pb=(^\d?.proc\d\p\d:\
+ :oc:\
+ :cb=;:ce=$:\
+ :sb=':se=':lb=":le=":\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=ascii block byte end equ include long proc word:
+
+# JL - Added QBASIC Aug 95
+BASIC:\
+ :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:\
+ :cb=':ce=$:sb=":se=":\
+ :le=\e':tl:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw= ABS APPEND ABSOLUTE AS ACCESS ASC AND ATN ANY \
+ BASE BLOAD BEEP BSAVE BINARY \
+ CALL COLOR CALL ABSOLUTE COM CASE COMMON CDBL CONST\
+ CHAIN COS CHDIR CSNG CHR$ CSRLIN CINT CVD CIRCLE CVDMBF\
+ CLEAR CVI CLNG CVL CLOSE CVS CLS CVSMBF \
+ DATA DEFLNG DEFSNG DATE$ DEFSTR DATE$ DIM DECLARE DO LOOP\
+ DEF FNDOUBLE DEF SEG DRAW DEFDBL $DYNAMIC DEFINT \
+ ELSE ERDEV ELSEIF ERDEV$ END ERL ENVIRON ERR ENVIRON$ \
+ ERROR EOF EXIT EQV EXP ERASE \
+ FIELD FOR NEXT FILEATTR FRE FILES FREEFILE FIX FUNCTION\
+ GET GOSUB GET GOTO \
+ HEX$ IF THEN ELSE INSTR IMP INT INKEY$ INTEGER \
+ INP IOCTL INPUT IOCTL$ INPUT$ IS \
+ KEY KILL KEY \
+ LBOUND LOCK UNLOCK LCASE$ LOF LEFT$ LOG LEN LONG LET LOOP\
+ LINE LPOS LINE INPUT LPRINT LIST LPRINT USING LOC LSET LOCATE LTRIM$\
+ MID$ MKI$ MID$ MKL$ MKD$ MKS$ MKDIR MKSMBF$ MKDMBF$ MOD \
+ NAME NOT NEXT \
+ OCT$ ON TIMER OFF ON GOSUB ON COM ON GOTO ON ERROR OPEN \
+ ON OPEN COM ON KEY OPTION BASE ON PEN OR ON PLAY OUT ON STRIG OUTPUT \
+ PAINT POINT PALETTE POKE PCOPY POS PEEK PRESET PEN PRINT \
+ PEN PRINT USING PLAY PSET PLAY PUT PLAY PUT PMAP \
+ RANDOM RETURN RANDOMIZE RIGHT$ READ RMDIR REDIM RND REM RSET RESET \
+ RTRIM$ RESTORE RUN RESUME \
+ SCREEN SQR STATIC SEEK $STATIC SEEK STEP SELECT CASE STICK SGN STOP \
+ SHARED STR$ SHELL STRIG SIN STRIG SINGLE STRING SLEEP STRING$ \
+ SOUND SUB SPACE$ SWAP SPC SYSTEM \
+ TAB TIMER TAN TO THEN TROFF TIME$ TRON TIME$ TYPE TIMER \
+ UBOUND UNTIL UCASE$ USING UNLOCK \
+ VAL VARSEG VARPTR VIEW VARPTR$ VIEW \
+ WAIT WIDTH WEND WINDOW WHILE WEND WRITE \
+ XOR :
+
+# DOS Batch file language description for the LGrind pretty-printer
+# Jim Green <j.j.green@shef.ac.uk> 11/15/96 Notice that the tex block
+# is a triple-precent rather than a double, and that `program text
+# within a comment' also has an added percent (to avoid conflicts with
+# environmental variables and `@echo off' statements respectively).
+# This assumes that it is possible to write a batch file sufficiently
+# complex to need such explanation.
+Batch|bat:\
+ :pb=^\d?\:\p\d?$:\
+ :cb=rem :ce=$:\
+ :sb=echo:se=$:\
+ :zb=%@:ze=%@:tb=%%%:te=%%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=call do echo @echo exist for goto if in not pause rem shift:
+
+C:\
+ :pb=\p\d?\(:cf:np=\)\d?;:bb={:be=}:\
+ :cb=/*:ce=*/:sb=":se=\e":lb=':le=\e':\
+ :tl:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=asm auto break case cdecl char continue default do double else\
+ enum extern far float for fortran goto huge if int interrupt long\
+ near pascal register return short signed sizeof static struct\
+ switch typedef union unsigned void while\
+ #define #else #endif #if #ifdef #ifndef #include #undef # define\
+ else endif if ifdef ifndef include undef #pragma #elif pragma elif\
+ #module #dictionary module dictionary\
+ variant_struct variant_union\
+ noshare readonly globaldef globalref globalvalue main_program:
+#Last couple of lines are partial ANSI, plus VAX-C specific
+
+C++|CC:\
+ :pb=\p\d?\(:cf:np=\)\d?;:bb={:be=}:\
+ :cb=/*:ce=*/:ab=//:ae=$:sb=":se=\e":lb=':le=\e':\
+ :tl:id=_~\::\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=and and_eq asm auto bitand bitor bool break case catch char class\
+ compl const const_cast continue default delete do double dynamic_cast\
+ else enum explicit export extern false float for friend goto if inline\
+ int long mutable namespace new not not_eq operator or or_eq private\
+ private\: protected protected\: public public\: register\
+ reinterpret_cast return short signed sizeof static static_cast struct\
+ switch template this throw true try typedef typeid typename union\
+ unsigned using virtual void volatile wchar_t while xor xor_eq\
+ static_cast const_cast dynamic_cast reinterpret_cast\
+ #define #else #endif #if #ifdef #ifndef #include #undef #pragma #\
+ define else endif if ifdef ifndef include undef defined:
+
+csh:\
+ :bb={:be=}:cb=#:ce=$:sb=":se=\e":lb=':\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :le=\e':tl:\
+ :kw=alias alloc break breaksw case cd chdir continue default\
+ echo else end endif endsw exec exit foreach \
+ glob goto history if logout nice nohup onintr repeat set\
+ setenv shift source switch then time \
+ while umask unalias unset wait while @ env \
+ argv child home ignoreeof noclobber noglob \
+ nomatch path prompt shell status verbose :
+
+FORTRAN|f77|f:\
+ :pb=(function|subroutine|program)\d\p\d?\(\a?\):\
+ :bb=(function|subroutine|program)\d\p\d?\(\a?\):be=^\dend\d:\
+ :cb=^(c|C|*):ce=$:\
+ :sb=':se=':\
+ :oc:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=call character close common complex continue data dimension do\
+ double else elseif end enddo endif entry equivalence format function\
+ goto if implicit include integer logical open pause parameter print\
+ precision program read real return stop subroutine then write\
+ gt ge lt le eq ne and or not false true:
+# The last should contain a lot more periods. But LGrind's parser doesn't like
+# them. So you can't use 'gt' as identifier. (Who would want to, anyway?)
+
+Gnuplot:\
+ :pb=\d?\p\(\a\)=:\
+ :cb=#:ce=$:\
+ :sb=("|'):se=("|'):\
+ :zb=@:ze=@:\
+ :tb=%%:te=%%::mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=cd clear exit load pause plot pwd quit replot save set showsplot\
+ title using with:
+
+Icon:\
+ :pb=^\d?procedure\d\p\d?\(\a?\):\
+ :bb=(^\d?procedure\d\p\d?\(\a?\))|{:be=}|(^\d?end\d?$):\
+ :cb=#:ce=$:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=":se=\e":lb=':le=\e':tl:\
+ :kw=break by case create default do dynamic else end every external\
+ fail global if initial local next not of procedure record\
+ repeat return static suspend then to until using while\
+ &ascii &clock &cset &date &dateline &errout &fail &host &input\
+ &lcase &level &main &null &output &pos &random &source &subject\
+ &time &trace &ucase &version:
+
+# Written by Diego Berrueta <diego@berrueta.net>
+IDL:\
+ :pb=\p\d?\(:cf:np=\)\d?;:bb={:be=}:\
+ :cb=/*:ce=*/:ab=//:ae=$:sb=":se=\e":lb=':le=\e':\
+ :tl:id=_~\::\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=abstract any attribute boolean case char const context \
+ custom default double exception enum factory FALSE fixed float \
+ in inout interface local long module native Object\
+ octet oneway out private public raises readonly sequence short \
+ string struct supports switch TRUE truncatable typedef unsigned \
+ union ValueBase valuetype void wchar wstring\
+ #define #else #endif #if #ifdef #ifndef #include #undef #pragma #\
+ define else endif if ifdef ifndef include undef defined:
+
+ISP:\
+ :cb=!:ce=!|$:oc:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=and begin decode define end eql eqv geq gtr if leave leq lss mod\
+ neq next not or otherwise repeat restart resume sr0 sr1 srd\
+ srr sl0 sl1 sld slr tst xor:
+
+Java:\
+ :pb=\p\d?\(:cf:np=\)\d?;:bb={:be=}:\
+ :cb=/*:ce=*/:ab=//:ae=$:sb=":se=\e":lb=':\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :le=\e':tl:id=_~\:\
+ :kw=abstract boolean break byte byvalue case catch char class const\
+ continue default do double else extends false final finally float for goto\
+ if implements import instanceof int interface long native new null package\
+ private protected public return short static super switch synchronized this\
+ throw throws true try void volatile while:
+# Somewhere these come from, but they are not in my Java book.
+# :kw=cast future generic inner rest transient var:
+
+
+Kimwitu++|kimw:\
+ :pb=\p\d?\(:cf:np=\)\d?;:bb={:be=}:\
+ :cb=/*:ce=*/:ab=//:ae=$:sb=":se=\e":lb=':le=\e':\
+ :tl:id=_~\::\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=and and_eq asm auto bitand bitor bool break case catch char class\
+ compl const const_cast continue default delete do double dynamic_cast\
+ else enum explicit export extern false float for foreach friend goto\
+ if inline int long mutable namespace new not not_eq operator or or_eq\
+ private private\: protected protected\: provided public public\:\
+ register reinterpret_cast return rview short signed sizeof static\
+ static_cast struct switch template this throw true try typedef typeid\
+ typename union unsigned using uview virtual void volatile wchar_t\
+ while with xor xor_eq\
+ static_cast const_cast dynamic_cast reinterpret_cast\
+ #define #else #endif #if #ifdef #ifndef #include #undef #pragma #\
+ define else endif if ifdef ifndef include undef defined:
+
+# JL - Jan 96 Added LaTeX
+# JL - May 96 LaTeX-2e additions
+LaTeX:\
+ :tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :cb=%:ce=$:kw=\
+ abstract addcontentsline addtocontents addtocounter address addtolength \
+ addvspace alph appendix arabic array article author begin bf bfseries \
+ bibitem bigskip book \
+ cdots center centering circle cite cleardoublepage clearpage \
+ cline closing color colorbox dashbox date ddots definecolor description \
+ displaymath document documentclass documentstyle dotfill em emph end \
+ enumerate eqnarray equation fbox fcolorbox figure flushbottom flushleft \
+ flushright fnsymbol footnote footnotemark footnotesize footnotetext frac \
+ frame framebox hfill hline hhline hrulefill hspace huge Huge hyphenation \
+ include includeonly indent input it itemize itshape kill label large \
+ Large LARGE ldots letter line linebreak linethickness list location \
+ makebox maketitle mark mbox mdseries medskip minipage multicols \
+ multicolumn multiput newcommand newcounter newenvironment newfont \
+ newlength newline newpage newsavebox newtheorem nocite noindent \
+ nolinebreak normalfont normalsize nopagebreak onecolumn opening oval \
+ overbrace overline pagebreak pagecolor pagenumbering pageref pagestyle \
+ par parbox picture put quotation quote raggedbottom raggedleft \
+ raggedright raisebox ref report resizebox rm rmfamily roman rotatebox \
+ rule savebox sc scriptsize setcounter setlength settowidth scalebox \
+ sf sffamily shortstack signature sl slshape small smallskip sqrt \
+ tabbing table tabular telephone \
+ textbf textit textmd textrm textsc textsf textsl texttt textup \
+ thanks thebibliography theorem thispagestyle tiny title titlepage \
+ tt ttfamily twocolumn typeout typein \
+ underbrace underline upshape usebox usecounter usepackage \
+ value vdots vector verb \
+ verbatim verse vfill vline vspace :
+
+LDL:\
+ :pb=^\p\::bb=\::be=;:cb=/*:ce=*/:sb=":se=\e":\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=constant functions grammar reswords tokens add1 addste\
+ car cdr check colno cond cons copy defun divide empty enter\
+ eq equal findattr firstchild ge getattr getfield gt hash label\
+ lambda lastchild le leftsibling lookone lookup lt minus name ne\
+ newnode nextcom nil null parent plus precnl prevcom prog progn\
+ quote reglob return rightsibling self set setattr setfield setq\
+ stjoin sub1 t times tnull tokno ttype:
+
+Lex:\
+ :lb=[|':le=]|\e':tc=C++:
+
+#Linda is just like C, with a couple of extra keywords. Note: The non-
+#blocking operations are included, as are the pre-defined VAX Linda-C macros.
+Linda:\
+ :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:\
+ :cb=/*:ce=*/:sb=":se=\e":lb=':\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :le=\e':tl:\
+ :kw=asm auto break case char continue default do double else enum\
+ extern float for fortran goto if int long register return short\
+ sizeof static struct switch typedef union unsigned void while #define\
+ #else #endif #if #ifdef #ifndef #include #undef # define else endif\
+ if ifdef ifndef include undef\
+ #pragma #elif pragma elif #line\
+ #module #dictionary module dictionary\
+ variant_struct variant_union\
+ noshare readonly globaldef globalref globalvalue main_program\
+ in inp rd rdp out eval newtype varying nchar\
+ $ARR $ARRAY $ARRAY_TYPE $MAKE_ARRAY\
+ $STR $STRING $STRING_TYPE $SET_DIM $MAKE_STRING\
+ #ttcontext ttcontext:
+
+make:\
+ :cb=#:ce=$:\
+ :sb=':se=':lb=":le=":\
+ :id=-_:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=define endef ifeq ifneq else endif include override export unexport vpath\
+ subst patsubst strip findstring filter filter-out sort dir notdir suffix basename\
+ addsuffix addprefix join word words firstword wildcard shell origin foreach:
+
+# JL - 'masm' (Microsoft Assembler) by way of
+# modification of 'asm' style provided above.
+# The instructions are *not* defined as keywords here.
+MASM:\
+ :oc:\
+ :cb=;:ce=$:ab=/*:ae=*/:\
+ :sb=':se=':lb=":le=":\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=ascii block globl even long\
+ 286 386 486 \
+ code data dosseg end endp equ \
+ huge large medium model proc small stack tiny title :
+
+# JL - Added MATLAB Jan 96
+# Note: the string delimiter ' is also used as a transpose operator
+# causing the rest of the line to be interpreted as a string.
+MATLAB:\
+ :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:\
+ :cb=%:ce=$:sb=':se='|$|;:\
+ :le=\e':tl:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw= \
+ abs acos acosh acot acoth acsc acsch \
+ airfoil all andrew angle angle ans any arith \
+ asec asech asin asinh atan atan2 atanh auread \
+ auwrite axes axis balance bar bartlett bench bessel \
+ bessela besselap besself besseli besselj besselk bessely beta \
+ betacore betainc betaln bilinear blackman blanks blt bone \
+ boxcar break brighten bucky buttap butter buttonv buttord \
+ cart2pol cart2sph caxis cceps cd cdf2rdf cedit ceil \
+ census censusex cheb1ap cheb1ord cheb2ap cheb2ord chebwin cheby1 \
+ cheby2 choices choicex chol cinvert cla clabel clc \
+ clear clf clg clock close cohere colmmd colon \
+ colormap colormenu colperm colstyle comet comet3 compan compass \
+ computer cond condest conj contour contour3 contourc contrast \
+ conv conv conv2 conv2 convmtx cool copper corrcoef \
+ corrcoef cos cosh cot coth cov cov cplxdemo \
+ cplxgrid cplxmap cplxpair cplxpair cplxroot cputime cross csc \
+ csch csd cumprod cumsum cylinder czt cztdemo d \
+ datalist date dbclear dbcont dbdown dbquit dbstack dbstatus \
+ dbstep dbstop dbtype dbup dc2sc dct deblank debug \
+ dec2hex decimate deconv deconv del2 delete delsq delsqdemo \
+ delsqshow demo demod det detrend dftmtx diag diary \
+ diff dir diric disp dmperm dos drawnow earthex \
+ earthmap echo eig eigmovie ellip ellipap ellipj ellipk \
+ ellipke ellipord else elseif end eps erf erfc \
+ erfcore erfcx erfinv error errorbar etime etree etreeplot \
+ eval exist exp expm expm1 expm2 expm3 eye \
+ fclose feather feof ferror feval fft fft fft2 \
+ fft2 fftdemo fftfilt fftshift fftshift fftshift fgetl fgets \
+ figtext figure fill fill3 filtdemo filter filter filter2 \
+ filtfilt filtic find findstr finite fir1 fir2 firls \
+ fitdemo fitfun fix flag fliplr flipud floor flops \
+ fmin fmins fopen foptions for format fourier fplot \
+ fplotdemo fprintf fread freqs freqspace freqz frewind fscanf \
+ fseek ftell full function funm fwrite fzero gallery \
+ gamma gammainc gammaln gca gcd gcf get getenv \
+ getframe ginput global gplot gradient gray graymon grid \
+ griddata grpdelay gtext hadamard hamming hankel hanning hardcopy \
+ help hess hex2dec hex2num hidden highlight hilb hilbert \
+ hint hist hold home hostid hot hsv hsv2rgb \
+ humps i icubic idct ident if ifft ifft \
+ ifft2 ifft2 iffuse imag image imagedemo imageext imagesc \
+ impinvar impz imread imtext imwrite inf info input \
+ inquire int2str interp interp1 interp1 interp2 interp3 interp4 \
+ interp5 interpft intfilt intro inv inverf invfreqs invfreqz \
+ invhilb isempty isglobal ishold isieee isinf isletter isnan \
+ issparse isstr isunix j jet kaiser keyboard knot \
+ kron lalala lasterr lcm legend length levinson life lifeloop \
+ lin2mu line linspace load loadwave log log10 log2 \
+ loglog logm logspace lookfor lorenz lorenzeq lotka lower \
+ lp2bp lp2bs lp2hp lp2lp lpc ls lscov lu \
+ magic man mathlist matlabro max mean medfilt1 median \
+ membrane memory menu mesh meshc meshdom meshgrid meshz \
+ meta min mkpp mmove2 moddemo modulate more movie \
+ moviein mu2lin nalist nan nargchk nargin nargout nestdiss \
+ nested newplot nextpow2 nnls nnz nonzeros norm normest \
+ null num2str numgrid nzmax ode23 ode23p ode45 odedemo \
+ ones orient orth pack paren pascal patch path \
+ pause pcolor peaks penny pi pink pinv planerot \
+ plot plot3 pol2cart polar poly poly2rc polyder polyfit \
+ polyline polymark polystab polyval polyvalm pow2 ppval print \
+ printopt prism prod prony psd punct puzzle pwd \
+ qr qrdelete qrinsert quad quad8 quad8stp quaddemo quadstp \
+ quake quit quiver qz rand randn randperm rank \
+ rat rats rbbox rc2poly rceps rcond readme real \
+ realmax realmin relop rem remez remezord resample reset \
+ reshape resi2 residue residuez return rgb2hsv rgbplot rjr \
+ roots rose rosser rot90 round rref rrefmovie rsf2csf \
+ save savewave sawtooth saxis sc2dc schur script sec \
+ sech semilogx semilogy sepdemo sepplot set setstr shading \
+ shg showwind sig1help sig2help sigdemo1 sigdemo2 sign sin \
+ sinc sinh size slash slice sort sos2ss sos2tf \
+ sos2zp sound sounddemo soundext spalloc sparlist sparse sparsfun \
+ sparsity spaugment spconvert spdiags specgram specials spectrum specular \
+ speye spfun sph2cart sphere spinmap spiral spline spline \
+ spline2d spones spparms sprandn sprandsym sprank sprintf spy \
+ spypart sqdemo sqrt sqrtm square ss2sos ss2tf ss2zp \
+ sscanf stairs std stem stem stmcb str2mat str2num \
+ strcmp strings strips subplot subscribe subspace sum sunspots \
+ superquad surf surface surfc surfl surfnorm svd swapprev \
+ symbfact symmmd symrcm table1 table2 tan tanh tempdir \
+ tempname terminal text tf2ss tf2zp tfe tffunc tic \
+ title toc toeplitz trace trapz treelayout treeplot triang \
+ tril triu type uicontrol uigetfile uimenu uiputfile uisetcolor \
+ uisetfont unix unmesh unmkpp unwrap unwrap upper vander \
+ vco ver version vibes view viewmtx waterfall what \
+ whatsnew which while white whitebg who whos why \
+ wilkinson xcorr xcorr2 xcov xlabel xor xyzchk ylabel \
+ yulewalk zerodemo zeros zlabel zp2sos zp2ss zp2tf zplane :
+
+# Courtesy of Dominique de Waleffe (ddw@miscrit.be)
+Mercury:\
+ :bb=\:-:be=.:cb=%:ce=$:ab=/*:ae=*/:\
+ :zb=@:ze=@:tb=%*%:te=%*%:mb=%*\$:me=\*$%:vb=%*\|:ve=\|*%:\
+ :sb=":se=\e":lb=':le=\e':oc:\
+ :kw=pred type module import_module mode \:\: -> --> ---> \:-\
+ pragma func lambda det semidet multi cc_multi failure nondet\
+ true fail is in out di uo ui interface implementation:
+
+# This entry makes use of new capabilities added to support the description
+# of lisp-like languages (id, pl, and px). The set of keywords given is a
+# matter of taste. It would be reasonable to add all the wired functions to
+# the list.
+MLisp|Emacs Mock Lisp:\
+ :cb=;:ce=$:lb=':le=\e':sb=":se=\e":bb=\(:be=\):\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :id=_-$#@./,%&?!^*+~`|;<>'\::\
+ :kw=defun if progn while:pl:px=\d\(defun:pb=^\d\(\p($|(\d\a$)):
+
+SML/NJ:ML:\
+ :cb=\(\*:ce=\*\):\
+ :pb=fun:\
+ :id=_':\
+ :lb=(#)":le=":sb=":se=\e":\
+ :kw=fun let in end if then else andalso orelse and val fun structure\
+ exception infix infixr nonfix type abstype datatype withtype with\
+ local rec open use sig eqtype functor signature handle raise fn while\
+ do case of as \:\: ... => -> |:
+
+# Scheme has a funky character quoting mechanism, 'a' in C is #\a in
+# Scheme. Lgrind doesn't deal with this well. I tried a few different
+# things, and decided the best option was to punt.
+Scheme|scm:\
+ :cb=;:ce=$:\
+ :lb=(#):le=(\\):\
+ :sb=":se=\e":\
+ :id=_-$#@./,%&?!^*+~`|;<>'\::\
+ :pb=\(define\d\(:\
+ :kw=define lambda let:
+
+model:\
+ :pb=^\d(space\d\p\drep)|(\p\dis|inline|public\dbeginproc):\
+ :bb=\dbeginproc|space|case\d:be=\dendproc|end\d|;:\
+ :cb=\$:ce=\$|$:sb=":se=":lb=':le=\a|$:\
+ :kw=abs and array beginproc boolean by case cdnl char copied dispose\
+ div do dynamic else elsif end endproc entry external FALSE false\
+ fi file for formal fortran global if iff ift\
+ in integer include inline is lbnd\
+ max min mod new NIL nil noresult not notin od of or procedure public\
+ read readln readonly record recursive rem rep repeat res\
+ result return set\
+ space string subscript such then TRUE true type ubnd union until\
+ varies while width:
+
+Modula2|mod2|m2:\
+ :pb=(^\d?(PROCEDURE|MODULE)\d\p\d|\(|;|\:)|(=|\:\d?RECORD\d):\
+ :np=FORWARD:id=_.:\
+ :bb=\d(BEGIN|CASE|FOR|IF|LOOP|WHILE|WITH|CLASS)\d:\
+ :be=\dEND\d|;:\
+ :cb=\(*:ce=*\):\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=":se=":lb=':le=':\
+ :kw=AND ARRAY BEGIN BY CASE CONST\
+ DEFINITION DIV DO ELSE ELSIF END EXIT EXPORT\
+ FOR FROM IF IMPLEMENTATION IMPORT IN\
+ LOOP MOD MODULE NOT OF OR POINTER PROCEDURE QUALIFIED\
+ RECORD REPEAT RETURN SET THEN TO TYPE\
+ UNTIL VAR WHILE WITH:
+
+# Of course this is not simple Pascal anymore. Borland set THE standard
+# for a modern Pascal. Available as Delphi or Free Pascal.
+Pascal|pas|p|bp:\
+ :pb=(^\d?procedure|function|constructor|destructor\d\p\d|\(|;|\:):\
+ :np=forward:id=_.:\
+ :bb=\d(case|begin|asm)\d:be=\dend\d|;:\
+ :rb=(\=|\:|\d|^)(record|object(\(\a\))?)(\d|$):\
+ :oc:\
+ :cb={:ce=}:ab=\(*:ae=*\):\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=':se=':\
+ :kw=and asm array begin case const constructor destructor div do\
+ downto else end end. exports file for function goto if implementation\
+ in inherited inline interface label library mod nil not object of or\
+ packed procedure program record repeat set shl shr then to type unit\
+ until uses var while with xor\
+ $ifdef $ifndef $ifopt $else $endif\
+ absolute assembler export external far forward index interrupt\
+ name near private public resident virtual\
+ break continue exit halt:
+# The last four are not keywords, but procedures, but they are far more than
+# normal and deserve to be treated as if (at least by a pretty printer).
+# The 14 modifiers in the last two lines but one also should be treated
+# specially though they are not keywords. "string", on the other hand, IS
+# a keyword, but since "integer", "boolean" etc. are not, along with any
+# self defined type whatsoever, it is not in this list.
+
+#Perl definition; snarfed from the net
+PERL|pl:\
+ :pb=^\d?sub\d\p(\d|{):\
+ :bb={:be=}:cb=\d#:ce=$:sb=":se=\e":lb=':le=\e':\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :tl:\
+ :kw=if until while elsif else unless for foreach continue sub\
+ accept and atan2 bind chdir chmod chop chown chroot close\
+ closedir cmp connect cos crypt dbmclose dbmopen defined delete die\
+ do dump each eof eq eval exec exit exp fcntl fileno flock fork\
+ getc getlogin getpeername getpgrp getppid getpriority getpwnam\
+ getgrnam gethostbyname getnetbyname getprotobyname getpwuid getgrgid\
+ getservbyname gethostbyaddr getnetbyaddr getprotobynumber\
+ getservbyport getpwent getgrent gethostent getnetent getprotoent\
+ getservent gt setpwent setgrent sethostent setnetent setprotoent\
+ setservent endpwent endgrent endhostent endnetent endprotoent\
+ endservent ge getsockname getsockopt gmtime goto grep hex ioctl\
+ index int join keys kill last le length link listen local localtime\
+ log lstat lt m mkdir ne next not oct open opendir or ord pack pop print printf\
+ push q qq rand read readdir readlink recv redo rename reset return\
+ reverse rewinddir rindex rmdir s seek seekdir select setpgrp send\
+ setpriority setsockopt shift shutdown sin sleep socket socketpair\
+ sort split sprintf sqrt srand stat study substr syscall system\
+ symlink tell telldir time times tr y umask undef unlink unpack\
+ unshift utime values vec wait wantarray warn write x xor:
+
+PostScript|ps:\
+ :oc:\
+ :cb=%:ce=$:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=\(:se=\e\):\
+ :kw=forall array null dict begin end def store string \
+ exec if ifelse repeat for loop exit stop stopped quit \
+ start save restore gsave grestore grestoreall definefont \
+ newpath initgraphics erasepage showpage copypage initclip \
+ clip eoclip fill eofill stroke image imagemask:
+
+PROLOG:\
+ :bb=\:-:be=.$:cb=%:ce=$:ab=/*:ae=*/:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=":se=\e":lb=':le=\e':oc:\
+ :kw=op mod abort ancestors arg ascii ask assert asserta assertz\
+ atom atomic char clause close concat consult ed ef em eof fail\
+ file findall write functor getc integer is length listing load name\
+ nl nonvar not numbervars op or pp prin print private prompt putc\
+ ratom read read_from_this_file rename repeat retract retractall\
+ save see seeing seen sh skip statistics subgoal_of system tab\
+ tell telling time told trace true unload untrace var write:
+
+Python|py:\
+ :pb=^\d?(def|class)\d\p(\d|\\|\(|\:):\
+ :cb=#:ce=$:sb=":se=\e":lb=':le=\e':\
+ :kw=accept and break class continue def del elif else except\
+ exec finally for from global if import in is lambda not or\
+ pass print raise return try while:
+
+RATFOR:\
+ :pb=^\d?program|subroutine|function|(integer|real|complex|character\dfunction)\d\p\d|\(:\
+ :bb={:be=}:cb=#:ce=$:sb=":se=":lb=':le=':oc:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw= break call case character common complex data default define\
+ dimension do else end equivalence external false for function go\
+ goto if implicit include integer logical next pause program read\
+ real repeat return rewind stop string subroutine switch true until\
+ while write:
+
+# RLaB language description for the LGrind pretty-printer
+# Jim Green <j.j.green@shef.ac.uk> 10/15/96
+RLaB:\
+ :pb=^\d?\p\d?=\d?function\d?\(:\
+ :bb={:be=}:\
+ :cb=//:ce=$:\
+ :sb=":se=":\
+ :tl:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw= \
+ abs acos all any asin asinh atan atan2 atanh autospec \
+ avsmooth backsub balance bandred banner besselj bessely \
+ bodetf break cd ceil center chol choose chop class clear \
+ clearall close command command_ compan compleme complex \
+ conditio conj continua continue corr cos cosh cross cumprod \
+ cumsum czt det detrend diag diary diff disp division dlopen \
+ dot eig epsilon erf error errors eval examples exist exp \
+ expm eye factor faxis fft fftplot files filter find finite \
+ fix fliplr flipud floor fmin for format fprintf fread frexp \
+ fseek function funm fvscope gamma getb getenv getline \
+ getplot global hankel help hess hex hilb hilbert house if \
+ ifft imag in inf input int int2str intersec intro inv isempty \
+ isinf isnan isreal issymm join jordan keywords lagrange \
+ lcheck length lininsrt linspace lintrp list lmsale load \
+ loaddir local log log10 log2 logb logm logspace lu lyap max \
+ max2 maxi mdsmax mdsmooth mean median members min min2 mini \
+ mod mret nan nextpow2 nmsmax norm num2str ode ode4 ode78 \
+ ones open operator pascal pause pclose pend pinv plalt \
+ plaspect plaxis plaz plclose plcont plegend plend plerry \
+ plfont plgrid plgrid3 plhist plhistx plhold plhold_o plimits \
+ plline plmesh plot plot3 plplot plpoint plprint plptex \
+ plscol0 plsfile plstart plstyle pltitle plwid plwin poly \
+ printf printmat prod pstart ptitle putenv pwin qq_norma qr \
+ quadr rand rank rcond read readb readm real redit \
+ relation rem replot require reshape return rfile rk4 rlab roots \
+ rot90 round save scalars schord schur section set set3d show \
+ show_pro showpwin sign sin sinh size sizeof solve sort \
+ spectrog sprintf sqrt srand static std steng stmag string \
+ strsplt strtod stzcr subplot sum surspl svd sylv symm system \
+ tan tanh temp tempacosh tempangle tic tmpnam toc toeplitz \
+ trace transpos trapz trig tril triu type union variable \
+ vector while window write writeb writem xlabel \
+ ylabel zeros zlabel:
+
+# It's not obvious what constitutes a "procedure definition" in Russell.
+# This entry doesn't even try...
+Russell:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :cb=\(*:ce=*\):kw=cand cor do od if fi else enum record prod union\
+ extend export hide with constants let use in ni val var func type\
+ field characters readonly:sb=":se=":lb=':le=':
+
+SAS:\
+ :pb=(^\d?(data|start|%macro)\d\p\d|\(|;):\
+ :cb=/*:ce=*/:\
+ :ab=^\d?*:ae=;:\
+ :sb=":se=":lb=':le=':\
+ :oc:\
+ :bb=\d(do|select)\d:\
+ :be=\dend;:\
+ :kw=proc data by cards do drop else end file filename format go if \
+ input infile keep label length libname merge options output put \
+ retain rename run then title to select set stop until update \
+ when where while %include %macro %mend %do %end %if %then %let:
+
+SDL:\
+ :cb=/*:ce=*/:\
+ :ab=comment:ae=;:\
+ :sb=":se=":lb=':le=':\
+ :oc:\
+ :kw=task else nextstate in out with from interface to via env and use fpar \
+ process procedure block system service type endprocess endprocedure endblock \
+ endsystem endservice package endpackage channel endchannel signalroute connect \
+ synonym dcl signal gate timer signallist create output set reset call operators \
+ literals all state endstate input start stop return none decision enddecision \
+ join virtual redefined finalized adding inherits remote exported imported:
+
+sh:\
+ :bb={:be=}:cb=#:ce=$:sb=":se=\e":lb=':\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :le=\e':tl:\
+ :kw=break case cd continue do done \
+ elif else esac eval exec exit export \
+ fi for if in then while until \
+ read readonly set shift test trap umask wait:
+
+SICStus:\
+ :bb=\:-:be=.$:cb=%:ce=$:ab=/*:ae=*/:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=":se=\e":lb=':le=\e':\
+ :kw=abolish abort absolute_file_name ancestors arg assert\
+ asserta assertz at_end_of_stream at_end_of_line atom\
+ atom_chars atomic bagof block break call callable call_residue\
+ character_count clause close compare compile compound consult\
+ copy_term current_atom current_host current_input current_input\
+ current_key current_module current_op current_output\
+ current_predicate current_stream debug debugging depth dif\
+ display dynamic ensure_loaded erase error_exception expand_term\
+ fail false fcompile fileerrors findall float flush_output\
+ foreign foreign_file format freeze frozen functor\
+ garbage_collect gc get get0 ground halt help if\
+ incore initialization instance integer is keysort leash\
+ length library_directory line_count line_position listing\
+ load load_foreign_files maxdepth meta_predicate mod\
+ module mode multifile name nl nodebug nofileerrors nogc nonvar\
+ nospy nospyall notrace number number_chars numbervars\
+ on_exception op open open_null_stream otherwise peek_char\
+ phrase plsys portray portray_clause portray_message\
+ predicate_property prepare_foreign_files print print_message\
+ profile_data profile_reset prolog_flag prompt put public\
+ raise_exception read read_term reconsult recorda recorded\
+ recordz reinitialize repeat require restore retract retractall\
+ save save_program see seeing seek seen set_input set_output\
+ set_stream_position setarg setof simple skip skip_line socket\
+ socket_accept socket_bind socket_connect socket_interrupt\
+ socket_listen socket_select sort source_file spy spypoint\
+ statistics stream_code stream_position subgoal_of subsumes_chk\
+ tab tell telling term_expansion term_hash term_subsume time_out\
+ told trace true ttyflush ttyget ttyget0 ttynl ttyput ttyskip\
+ ttytab undo unix unknown unknown_predicate_handler use_module\
+ user_help var version when write write_canonical write_term\
+ writeq:
+
+src:\
+ :kw=:
+
+# Very incomplete...
+SQL:\
+ :oc:ab=/*:ae=*/:\
+ :sb=':se=':lb=":le=":\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw=select where from as group by order asc desc union insert values\
+ delete into create table integer varchar primary key not null float\
+ default:
+
+# A.Bednarz@kfa-juelich.de
+# Received Jan 97
+Tcl/Tk|tcl|tk:\
+ :bb={:be=}:cb=\d#:ce=$:sb=":se=\e":lb=':\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :le=\e':tl:pb=\d?proc\d\p\d{:id=-$_.,:\
+ :kw=after append array auto_execok auto_load auto_mkindex \
+auto_reset bell bind bindtags break button canvas case catch cd \
+checkbutton clipboard close concat continue destroy entry eof error \
+eval exec exit expr file fileevent flush focus for foreach format \
+frame gets glob global grab history if image incr info join label \
+lappend lindex linsert list listbox llength lower lrange lreplace \
+lsearch lsort menu menubutton message open option pack pid place \
+proc puts pwd radiobutton raise read regexp regsub rename return \
+scale scan scrollbar seek selection send set source split string \
+subst switch tell text time tk tkButtonDown tkButtonEnter tkButtonInvoke \
+tkButtonLeave tkButtonUp tkCancelRepeat tkCheckRadioInvoke tkEntryAutoScan \
+tkEntryBackspace tkEntryButton1 tkEntryClipboardKeysyms tkEntryInsert \
+tkEntryKeySelect tkEntryMouseSelect tkEntrySeeInsert tkEntrySetCursor \
+tkEntryTranspose tkFirstMenu tkListboxAutoScan tkListboxBeginExtend \
+tkListboxBeginSelect tkListboxBeginToggle tkListboxCancel tkListboxDataExtend \
+tkListboxExtendUpDown tkListboxMotion tkListboxSelectAll tkListboxUpDown \
+tkMbButtonUp tkMbEnter tkMbLeave tkMbMotion tkMbPost tkMenuButtonDown \
+tkMenuEscape tkMenuFind tkMenuFindName tkMenuFirstEntry tkMenuInvoke \
+tkMenuLeave tkMenuLeftRight tkMenuMotion tkMenuNextEntry tkMenuUnpost \
+tkPostOverPoint tkSaveGrabInfo tkScaleActivate tkScaleButton2Down \
+tkScaleButtonDown tkScaleControlPress tkScaleDrag tkScaleEndDrag \
+tkScaleIncrement tkScreenChanged tkScrollButton2Down tkScrollButtonDown \
+tkScrollButtonUp tkScrollByPages tkScrollByUnits tkScrollDrag \
+tkScrollEndDrag tkScrollSelect tkScrollStartDrag tkScrollToPos \
+tkScrollTopBottom tkTextAutoScan tkTextButton1 tkTextClipboardKeysyms \
+tkTextInsert tkTextKeyExtend tkTextKeySelect tkTextNextPara tkTextPrevPara \
+tkTextResetAnchor tkTextScrollPages tkTextSelectTo tkTextSetCursor \
+tkTextTranspose tkTextUpDownLine tkTraverseToMenu tkTraverseWithinMenu \
+tk_popup tkwait toplevel trace unknown unset update uplevel upvar while winfo wm:
+
+
+# JL - Added visbasic 6 Aug 1996. Note: this is not complete!
+VisualBasic|vbasic:\
+ :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:\
+ :cb=':ce=$:sb=":se=":\
+ :le=\e':tl:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :kw= Access And As Asc Boolean Byte Call Case Chr Close Currency Debug \
+ Declare Dim Do Double Else ElseIf End Exit False For Format Function \
+ Get If Input Integer Left Len Line Long Loop Lset Ltrim Mid Mod Next \
+ Not Object On Open Or Output Print Private Pset Public Put Read Right \
+ Rset Rtrim Select Single Static Str String Sub Then To Trim True Type \
+ Until Val Variant Wend While :
+
+VMSasm:\
+ :pb=^\d?.entry\d\p(\d|,|$|;):\
+ :oc:\
+ :cb=;:ce=$:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :sb=(.ident|.asci(x|c|d|i|z))\d:se=$:\
+ :kw=.address .align .ascix .ascic .ascid .ascii .asciz \
+ .blkx .byte .cross .debug .default .d_floating .double \
+ .disable .enable .end .endc .endm .endr .entry .error \
+ .even .external .f_floating .float .g_floating .ident .if \
+ .if_x .iff .irp .irpc .library .link .list .long .macro \
+ .mask .mcall .mdelete .mexit .narg .nchr .nlist .nocross \
+ .noshow .ntype .octa .odd .opdef .packed .page .print \
+ .psect .quad .refn .repeat .restore_psect .save_psect \
+ .show .signed_byte .signed_word .subtitle .title .transfer \
+ .warn .weak .word:
+
+yacc|y:\
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\$:me=\$%:vb=%\|:ve=\|%:\
+ :cb=/*:ce=*/:sb=":se=\e":lb=':le=\e':tl:\
+ :kw=%{ %} %% %union %token %type\
+ #else #endif #if #ifdef #ifndef #include #undef #define else endif\
+ if ifdef ifndef include undef:
+
+
+EndOfLanguageDefinitions:
+#
+# The following entries are NOT language definitions,
+# but configuration specifications for the LGrind program
+#
+BeginOfConfigurationItems:
+
+# a list of extensions and the language that belongs to them
+# these can be wrong or too system specific
+# recommendations appreciated
+extensions:\
+ :c=c:\
+ :C=c++:cpp=c++:cc=c++:h=c++:\
+ :pas=pascal:\
+ :ads=ada:adb=ada:\
+ :tcl=tcl/tk:\
+ :y=yacc:\
+ :tex=latex:\
+ :java=java:\
+ :mod=modula2:\
+ :bas=visualbasic:\
+ :ps=postscript:eps=postscript:pfa=postscript:\
+ :pro=prolog:\
+ :scm=scheme:\
+ :m=matlab:\
+ :ml=sml/nj:\
+ :f=f77:F=f77:for=f77:\
+ :l=lex:\
+ :k=kimwitu++:\
+ :py=python:
+
+# character substitution table
+chartab:\
+:84="a:94="o:81="u:e1="s:8e="A:99="O:9a="U:e0=$\\alpha$:
+
+# preamble to put at the beginning of a stand-alone listing
+firstpreamble:\
+\\documentclass[a4paper,twoside]{article}\n\
+\\usepackage[procnames,noindent]{lgrind}\n\
+\\usepackage{fancyhdr,a4wide}\n\
+\\usepackage{german}\n\
+\\usepackage{makeidx}\n\
+\\pagestyle{fancy}\n\n\
+\\makeindex\n\n\
+\\begin{document}\n
+
+# postamble to put at the very end of a stand-alone listing
+postamble:\
+\\printindex\n\
+\\end{document}
+
+# preamble to put before each file in a stand-alone listing
+filepreamble:\
+\\renewcommand{\\footrulewidth}{0.4pt}\n\
+\\fancyhead[C]{\\lgrindhead}\n\
+\\fancyhead[LO,RE]{\\lgrindfilesize~Bytes\\\\\\lgrindmodtime}\n\
+\\fancyhead[RO,LE]{\\bfseries \\lgrindfilename\\\\\
+\\lgrindmodday.\\lgrindmodmonth.\\lgrindmodyear}\n\
+\\fancyfoot[C]{\\bfseries\\thepage}\n\
+\\setlength{\\headheight}{24pt}\n
+
+# preferences for line numbering, changing fonts etc.
+# (comes after "\begin{lgrind}")
+configuration:
+
diff --git a/support/lgrind/source/.cvsignore b/support/lgrind/source/.cvsignore
new file mode 100644
index 0000000000..7726bfbebb
--- /dev/null
+++ b/support/lgrind/source/.cvsignore
@@ -0,0 +1,2 @@
+lgrind
+
diff --git a/support/lgrind/source/Makefile b/support/lgrind/source/Makefile
new file mode 100644
index 0000000000..b785122aae
--- /dev/null
+++ b/support/lgrind/source/Makefile
@@ -0,0 +1,39 @@
+# Makefile for lgrind, a LaTeX prettyprinter
+# make binaries
+# $Id: Makefile,v 1.4 1999/12/18 21:54:29 mike Exp $
+
+BINDIR=$(BASEDIR)/bin
+MANDIR=$(BASEDIR)/man
+
+CC=gcc
+MANPAGES1=lgrind.1
+MANPAGES5=lgrindef.5
+OBJS=lgrind.o regexp.o retest.o lgrindef.o v2lg.o
+
+CFLAGS=-O2
+# CFLAGS=-Dpopen=fopen -Dpclose=fclose
+# There are operating systems and compilers without these...
+
+.PHONY: all install clean distribution
+
+all: lgrind
+
+lgrind: lgrind.o lgrindef.o regexp.o
+ $(CC) $(CFLAGS) -o lgrind lgrind.o lgrindef.o regexp.o
+
+lgrind.o: lgrind.c lgutil.c
+ $(CC) $(CFLAGS) -DDEFSFILE=\"$(DEFSFILE)\" -DVERSION=\"$(VERSION)\" -c lgrind.c
+
+v2lg: v2lg.o
+ $(CC) $(CFLAGS) -o v2lg v2lg.o
+
+retest: retest.o regexp.o
+ $(CC) $(CFLAGS) -o retest retest.o regexp.o
+
+install: all
+ $(INSTALL) -s lgrind $(BINDIR)/lgrind
+ $(INSTALL) -m 644 $(MANPAGES1) $(MANDIR)/man1
+ $(INSTALL) -m 644 $(MANPAGES5) $(MANDIR)/man5
+
+clean:
+ rm -f $(OBJS) lgrind retest v2lg
diff --git a/support/lgrind/source/README b/support/lgrind/source/README
new file mode 100644
index 0000000000..6762cd342e
--- /dev/null
+++ b/support/lgrind/source/README
@@ -0,0 +1,10 @@
+These sources should compile without any problems.
+
+The "access" function is declared in "io.h" or "unistd.h", depending on your
+system. Replace "unistd" in "lgrind.c" with "io" if necessary. If your
+compiler issues only a warning for missing prototypes you can delete the
+#include completely.
+
+
+The -d! option is tested and works well. It writes a patched version of the
+executable, run it at your own risk.
diff --git a/support/lgrind/source/lgrind.1 b/support/lgrind/source/lgrind.1
new file mode 100644
index 0000000000..8963aad647
--- /dev/null
+++ b/support/lgrind/source/lgrind.1
@@ -0,0 +1,228 @@
+'\" t
+.\" @(#)lgrind.1 3.62 25/05/99 MPi; from UCB 4.3
+.\" $Id: lgrind.1,v 1.5 2000/12/27 21:42:42 mike Exp $
+.\" This man page was reverse engineered by George V. Reilly from the
+.\" preformatted man page written by Tuna Ertemalp for Jerry Leichter's
+.\" version of tgrind. gvr remains wilfully ignorant of troff.
+.dS C C\" \" Fixed-width font
+.TH lgrind 1 "25 May 1999" "TeX/LaTeX"
+.SH NAME
+lgrind \- grind nice program listings using LaTeX
+.SH NOTE
+This man page is not yet much outdated, but might be soon except somebody
+asks me to work on it. Consider the LaTeX docs the real docs.
+.SH SYNOPSIS
+\fBlgrind\fR [ \fB-e\fP ] [ \fB-i\fP ] [ \fB-\fP ] [ \fB-n\fP ] [ \fB-c\fP ]
+[ \fB-t\fP \fI<width>\fP ]
+[ \fB-h\fP \fI<header>\fP ] [ \fB-d\fP \fI<description file>\fP ]
+[ \fB-l\fP\fI<language>\fP ] [ \fB-s\fP ] \fI<name>\fP ...
+.PP
+.SH DESCRIPTION
+LGrind formats program sources in a nice style using LaTeX(1).
+Comments are placed in roman, keywords in bold face, variables in
+italics, and strings in typewriter font. Source file line numbers
+appear in the right margin (every 10 lines).
+.PP
+LGrind processes its input file(s) and writes the result to standard
+output. This output can be saved for later editting, inclusion in a
+larger document, etc.
+.PP
+The options are:
+.IP "\fB\-e\fP"
+process a LaTeX file for embedded code.
+.IP "\fB\-i\fP"
+process source code file for inclusion in a LaTeX document.
+.IP "\fB\-\fP"
+take input from standard input.
+.IP "\fB\-n\fP"
+don't boldface keywords.
+.IP "\fB\-c\fP"
+don't treat @, etc. specially in comments.
+.IP "\fB\-t\fP"
+change tab width (default 8).
+.IP "\fB\-h\fP"
+specifies text to go into the header.
+.IP "\fB\-d\fP"
+specifies the language definitions file (default is
+\fB/usr/lib/texmf/tex/latex/lgrind/lgrindef\fP).
+.IP "\fB\-d!\fP"
+same as above, but write patched executable.
+.IP "\fB\-l\fP"
+specifies the language to use.
+.IP "\fB\-s\fP"
+shows a list of currently known languages.
+.PP
+If LGrind is called without parameters, a help screen will be shown.
+If neither \fB\-e\fP nor \fB\-i\fP are specified, a complete LaTeX
+file is produced. When no language is specified, LGrind tries to find
+out the language used itself; C is used when this fails.
+.SH USAGE
+For example, to include a C file named \fBfoo.c\fP
+into your LaTeX document, first give the command:
+.IP "\fC lgrind -i -lc foo.c > foo.tex\fP"
+.PP
+This will generate \fCfoo.tex\fP, which will have the
+pretty-printed version of \fCfoo.c\fP with a lot of LaTeX commands.
+.PP
+Then include \fClgrind.sty\fP as you include any other style,
+namely with the \fC\eusepackage{lgrind}\fP line at
+the beginning of your LaTeX document. Having done this,
+within the document you can include \fCfoo.tex\fP using one of the
+following commands:
+.PP
+.IP "\fC\elgrindfile{foo.tex}\fP"
+which will simply include the file at that point
+of text, and will draw horizontal lines before and
+after the listing.
+.PP
+.IP "\fC\elagrind[htbp]{foo.tex}{caption}{label}\fP"
+which will put the listing also within a figure
+environment, using the float options, caption and
+label you gave.
+.PP
+To produce a standalone LaTeX file from, say, a Yacc file:
+.IP "\fC lgrind -ly bary.y > bary.tex\fP"
+This uses Piet van Oostrum's \fCfancyhdr.sty\fP to make the
+headers and footers.
+.PP
+For a more detailed explanation of these commands, refer to
+\fC/usr/TeX/texmf/doc/latex/lgrind.dvi\fP.
+.PP
+.SH "EMBEDDED PROGRAMS WITHIN A LaTeX FILE"
+(From Jerry Leichter's notes.)
+.PP
+Within the text of your LaTeX file, you mark groups of lines as
+either text- or display-style program code:
+.PP
+Text style:
+.TS
+l l.
+.fT \*C
+ The expression
+ %(
+ a + 3
+ %)
+ produces 10.
+.fT
+.TE
+prints something like: "The expression \fIa\fP + 3 produces 10."
+(with "a + 3" set as a program.)
+.PP
+The same effect can be achieved with inline @'s.
+.TS
+l l.
+.fT \*C
+ The expression @a + 3@ produces 10.
+.TE
+.PP
+Display style:
+.TS
+l l.
+.fT \*C
+ The statement
+ %[
+ a += 3;
+ %]
+ is an example of an incrementing operator.
+.fT
+.TE
+prints something like:
+.TS
+l l.
+ The statement
+ a += 3;
+ is an example of an incrementing operator.
+.TE
+.PP
+Important rules:
+.IP
+\fC%\fP and the following character must be the first two characters on
+the line to be recognized.
+.IP
+Put \fInothing\fR on the line after the \fC%\fR and the key character.
+If you do that, LGrind will provide a default environment that will
+produce an \fC\ehbox\fP for \fC%(\fP \fC)%\fP, and a \fC\evbox\fP for
+\fC%[\fP \fC-\fP \fC%]\fP. If you put stuff on the line, LGrind
+assumes you want to control the format completely. Doing this
+requires understanding \fIexactly\fP what the code LGrind produces is
+doing. (Sometimes I'm not sure I do!)
+.IP
+\fC%)\fP and \fC%]\fP are, if I remember right, simply ignored outside
+of a code group, but any extra \fC%(\fP or \fC%[\fP produces a
+warning, so a missing \fC%)\fP or \fC%]\fP is usually caught.
+.PP
+You can insert your own code by using a line starting with \fC%=\fP in
+the program text. Whatever you enter after that is left in the
+output, exactly as you typed it. It will be executed in a strange
+environment, so doing anything fancy is very tricky. A macro, \fC\eLine\fP,
+is provided to help you do simple things. For example,
+.TS
+tab (/);
+l.
+.fT \*C
+%[
+%=\eLine{________\evdots}
+ a = 1;
+%]
+.fT
+.TE
+produces:
+.TS
+tab (/);
+l.
+.fT \*C
+ \.
+ \.
+ \.
+ a = 1;
+.fT
+.TE
+.PP
+(Within the program text, \fC_\fP is active and expands to a
+fixed-width space. A whole bunch of macros are also defined. If you
+understand how LGrind sets lines up, you can replace the 8 \fC_\fP's
+with a call to \fC\eTab\fP \(em but I'll let you hang yourself on that one.)
+.PP
+The output of LGrind always contains exactly one output line for each input
+line. Hence, you can look up line numbers in TeX error messages in your
+original file, rather than in the lgrind'ed (lground?) file. (Of course, if
+the problem is in the LGrind output....)
+.PP
+Many things are controllable by re-defining various macros. You can
+change what fonts LGrind will use for various kinds of things, how
+much it indents the output, whether it adds line numbers, and if so at
+what interval it prints them and whether it sticks them on the left or
+right, and so on. This stuff is all described in \fClgrind.dvi\fP,
+though probably not very well. The default settings produce output
+that looks reasonable to me, though I can't say I'm ecstatic about it.
+Doing a \fIreally\fP good job would require defining some special fonts.
+.PP
+.SH FILES
+.IP "\fC/usr/bin/lgrind\fP"
+Executable
+.PP
+.IP "\fC/usr/doc/lgrind/lgrind.dvi\fP"
+Documentation
+.PP
+.IP "\fC/usr/lib/texmf/tex/latex/lgrind/lgrind.sty\fP"
+LaTeX style file
+.PP
+.IP "\fC/usr/lib/texmf/tex/latex/lgrind/lgrindef\fP"
+Language descriptions
+.PP
+.SH AUTHORS
+Van Jacobson, Lawrence Berkeley Laboratory (based on
+"vgrind" by Dave Presotto & William Joy of UC Berkeley),
+wrote it for TeX.
+.PP
+Jerry Leichter of Yale University modified it for LaTeX.
+.PP
+George V. Reilly of Brown University changed the name to lgrind,
+fixed up the man page, and added the program-text-within-comments
+and @-within-LaTeX features.
+.PP
+Michael Piefel of Humboldt-University Berlin adapted it to
+LaTeX2e and wrote decent documentation.
+.PP
+.SH "SEE ALSO"
+\fBlatex\fR(1), \fBtex\fR(1), \fBvgrind\fR(1), \fBlgrindef\fR(5)
diff --git a/support/lgrind/source/lgrind.c b/support/lgrind/source/lgrind.c
new file mode 100644
index 0000000000..272bc164e0
--- /dev/null
+++ b/support/lgrind/source/lgrind.c
@@ -0,0 +1,1769 @@
+#ifndef lint
+static char sccsid[] = "@(#)lgrind.c 3.66 (MPi) 5/10/99";
+static char rcsid[] =
+ "$Id: lgrind.c,v 1.14 2000/12/27 21:42:42 mike Exp $";
+#endif
+
+/*
+ * Copyright %%\copyright%% 1980 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+/* lgrind --- general purpose "pretty printer" for use with %%\LaTeX%%.
+ * A %%\LaTeX%% version of tgrind, which is a %%\TeX%% version
+ * of vgrind. Used to "grind nice program listings."
+ *
+ * Copyright %%\copyright%% 1985 by Van Jacobson, Lawrence Berkeley Laboratory
+ * This program may be freely used and copied but %%{\bf may not be sold}%%
+ * without the author's %%{\bf written permission}%%. This notice must remain
+ * in any copy or derivative.
+ *
+ * This program is an adaptation of "vfontedpr" v4.2 (12/11/84) from
+ * the 4.2bsd Unix distribution. Vfontedpr was written by Dave
+ * Presotto (based on an earlier program of the same name written by
+ * Bill Joy).
+ *
+ * I would welcome comments, enhancements, bug fixes, etc. Please
+ * mail them to:
+ * van@@lbl-rtsg.arpa (from arpanet, milnet, csnet, etc.)
+ * ..!ucbvax!lbl-csam!van (from Usenet/UUCP)
+ */
+
+/*%%\par{\bf Thank you very much, Van. Due to the ``may not be sold'' clause%%*/
+/*%%this program has become non-free. And since the author of this licence%%*/
+/*%%cannot be contacted (address too old, apparently newer ones exist, but%%*/
+/*%%no answers from them), this cannot be changed.}\par%%*/
+
+/* Copyright %%\copyright%% 1995-99 by Michael Piefel
+ *
+ * Modifications.
+ * --------------
+ * 10 Feb 85 Van Written.
+ * 29 Mar 85 Chris Torek (chris@@maryland): Bug fixes for %|~|% and
+ * %|^L|% output. Most cpu-time eaters recoded
+ * to improve efficiency.
+ * 30 Mar 85 Chris & Van Fixed %|\C|% & %|\S|% (comment & string start
+ * indicators to really appear at the start of
+ * comments & strings. Changes for speeded-up
+ * @expmatch()@.
+ * 8 Oct 87 JSL Modified so as to compile on VMS. %|-i|% option
+ * Jan 88 JSL %|-e|% option for embedded code.
+ * Sep 91 George V Reilly Reformated and cleaned up code, including
+ * naughtiness with @NULL@. Added %|@|%,
+ * %|%%|%, %|%$|%, and %%\tt \%|%% features.
+ * Also the %|%<|%, %|%!|%, and %|%#|% features.
+ * Oct 94 Matthias Eckermann (%|ud311aa@@sunmail.lrz-muenchen.de|%)
+ * fixed a little bug, added: Internal_Help,
+ * Sep 95 Michael Piefel Modified for %%\LaTeXe%%
+ * Feb 96 Michael Piefel Restructured into ANSI C
+ * May 99 Michael Piefel Made it Y2K compliant
+ * Oct 99 Michael Piefel Space runs make tabstops
+ * Dec 99 Michael Piefel Version option, space allowed after '-l'
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <malloc.h>
+#include <time.h>
+/* One of the following two (depending on your system) */
+#include <unistd.h>
+/* #include <io.h> */
+#include "lgrindef.h"
+#include "regexp.h"
+
+#ifndef vms
+# include <sys/types.h>
+# include <sys/stat.h>
+#else
+# include <types.h>
+# include <stat.h>
+#endif
+
+#define STANDARD 0
+#define ALTERNATE 1
+
+#define NOTCODE 0 /* the three states of @incode@ */
+#define INITCODE 1
+#define OTHERCODE 2
+
+#define PNAMELEN 80 /* length of a function/procedure name */
+#define PSMAX 20 /* size of procedure name stacking */
+
+#ifndef vms
+# define OKEXIT 0
+# define BADEXIT 1
+# ifndef DEFSFILE
+# define DEFSFILE "/usr/lib/texmf/tex/latex/lgrind/lgrindef"
+# endif
+#else
+# define OKEXIT 1
+# define BADEXIT 0
+# define DEFSFILE "TEX$INPUTS:lgrindef.src"
+#endif
+
+#ifndef unix
+# define HELPOPTION "-?"
+#else
+# define HELPOPTION "--help"
+#endif
+
+typedef struct varsubst {
+ char *var;
+ char *subst;
+ struct varsubst *next;
+} varsubst;
+
+varsubst *varsubstlist;
+
+/* forward declarations */
+
+int getredirection(int argc, char **argv);
+void setlang();
+void Internal_Help();
+void Internal_Help_Language_List();
+void readfile(FILE *);
+void putScp(char *);
+boolean putKcp(char *, char *, boolean);
+void putVcp(char *, char *);
+void putstr(char *);
+boolean (*isproc)(char *);
+boolean isprocNorm(char *);
+boolean isprocC(char *);
+void outchar(int);
+void parsechartab(void);
+varsubst *parsevartab(char *);
+void parsepreamble(char *);
+void setpreambles(void);
+void printpreamble(char *);
+void writeDefsfileInExe(char *, char *);
+int substvarname(char **, int);
+
+/*
+ * The state variables
+ */
+
+boolean incomm; /* in a comment of the primary type */
+boolean instr; /* in a string constant */
+boolean inchr; /* in a character constant */
+int incode; /* in program text within a comment */
+int latexcode; /* in program text within %%\LaTeX%% */
+int latex_tt; /* in %|\texttt|% text within %%\LaTeX%% */
+boolean use_tt; /* use %|\texttt|% everywhere */
+boolean do_at; /* pay attention to %|@|%s in %%\LaTeX%% */
+boolean do_tt; /* pay attention to %|||%s in %%\LaTeX%% */
+boolean nokeyw = FALSE; /* no keywords being flagged */
+boolean prccont; /* continue last procedure */
+boolean code_cmnts = TRUE; /* Treat %|@|%, etc specially in comments */
+boolean code_latex = TRUE; /* Treat %|@|%, etc specially in %%\LaTeX%% */
+int lastout; /* (extended) last character to outchar */
+int comtype; /* type of comment */
+int psptr; /* the stack index of the current procedure */
+char pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */
+int plstack[PSMAX]; /* the procedure nesting level stack */
+int blklevel; /* current nesting level */
+int reclevel; /* current @record@ nesting level */
+int procedures_pending; /* proc starts w/o block starts */
+char fname[200]=""; /* File being read */
+int lineno; /* Line number in that file */
+int linenocode; /* Line number of the source code worked on */
+char pname[BUFFERSIZE+1]; /* Current procedure name */
+
+/*
+ * The language specific globals
+ */
+char defsbuf[200]="DeFsBuF"DEFSFILE;
+char *defsfile=&defsbuf[7]; /* name of language definitions file */
+char language[PNAMELEN]="mPi"; /* the language indicator */
+char the_buf[BUFFERSIZE+1]; /* general purpose buffer */
+char *buf = the_buf + 1; /* @buf-1@ must be valid */
+char *strings; /* store the keywords */
+char *defs; /* language definitions from lgrindef */
+char preamble[BUFFERSIZE/4]; /* first preamble */
+char postamble[BUFFERSIZE/4]; /* first preamble */
+char preamble2[BUFFERSIZE/4]; /* file preamble */
+char config[BUFFERSIZE/4]; /* redefinitions within lgrind-environment */
+char chartab[BUFFERSIZE/4]; /* buffer for chartab modifications */
+char *l_keywds[BUFFERSIZE/2]; /* keyword table address */
+char *l_prcbeg; /* regular expr for procedure begin */
+char *l_noproc; /* regexp for lines with NO procedure begin */
+char *l_combeg; /* regexp introducing a comment */
+char *l_comend; /* regexp ending a comment */
+char *l_acmbeg; /* regexp introducing a comment */
+char *l_acmend; /* regexp ending a comment */
+char *l_blkbeg; /* regexp beginning of a block */
+char *l_blkend; /* regexp ending a block */
+char *l_strbeg; /* regexp starting string constant */
+char *l_strend; /* regexp ending string constant */
+char *l_chrbeg; /* regexp starting character constant */
+char *l_chrend; /* regexp ending character constant */
+char *l_cdebeg; /* regexp starting prog text within comment */
+char s_cdebeg[BUFFERSIZE/8]; /* actual string corresponding to @l_cdebeg@ */
+char *l_cdeend; /* regexp ending prog text within comment */
+char *l_texbeg; /* regexp starting %%\TeX%% text in comment */
+char *l_texend; /* regexp ending %%\TeX%% text in comment */
+char *l_txmbeg; /* regexp starting %%\TeX%% math in comment */
+char *l_txmend; /* regexp ending %%\TeX%% math in comment */
+char *l_tt_beg; /* regexp starting verbatim text in comment */
+char *l_tt_end; /* regexp ending typewriter text in comment */
+char *l_at; /* regexp for %|@|% in %%\LaTeX%% text */
+char *l_tt; /* regexp for %|||% in %%\LaTeX%% text */
+char *l_pc; /* regexp for %|%|% in %%\LaTeX%% text */
+char *l_id; /* string containing valid identifier chars */
+char *l_record; /* start of lexical block outside functions */
+char l_escape; /* character used to escape characters */
+boolean l_toplex; /* procedures only defined at top lex level */
+boolean l_onecase; /* upper & lower case equivalent */
+boolean l_cfunctions; /* special for C function search */
+boolean embed = FALSE; /* -e seen --- do embedded code */
+boolean code = TRUE; /* Looking at code */
+int TabWidth = 8; /* Default width of a tab */
+
+/*
+ * global variables also used by expmatch
+ */
+
+extern boolean _escaped; /* if last character was an escape */
+extern char *_sstart; /* start of the current string */
+
+extern int (*re_strncmp)(const char*, const char*, size_t);
+ /* function to do string compares */
+
+int main(int argc, char **argv)
+{
+ struct stat stbuf;
+ boolean hseen = FALSE; /* -h seen */
+ char *hstring=""; /* header string to use */
+ char *programname; /* the zeroeth argument */
+ boolean iseen = FALSE; /* -i seen */
+ int files_done = 0;
+
+ defs=(char*)malloc(2*BUFFERSIZE);
+ strings=(char*)malloc(2*BUFFERSIZE);
+ argc = getredirection(argc, argv);
+
+ /* abuse of programname */
+ programname=getenv("LGRINDEF");
+ if (programname) strcpy(defsfile, programname);
+
+ programname=argv[0];
+ argc--, argv++;
+
+ if (argc==0) {
+ Internal_Help();
+ return OKEXIT;
+ }
+
+ do {
+ struct tm modtime = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ if (argc > 0) {
+ /* Help-facility */
+ if (!strcmp(argv[0], HELPOPTION)) {
+ Internal_Help();
+ return OKEXIT;
+ }
+
+ if (!strcmp(argv[0], "-s")) {
+ Internal_Help_Language_List();
+ return OKEXIT;
+ }
+
+ if (!strcmp(argv[0], "--version")) {
+ printf("LGrind %s\n", VERSION);
+ return OKEXIT;
+ }
+
+
+ /* Header */
+ if (!strcmp(argv[0], "-h")) {
+ hseen = TRUE;
+ if (argc == 1) {
+ argc--;
+ goto rest;
+ }
+ hstring = argv[1];
+ argc--, argv++;
+ argc--, argv++;
+ if (argc > 0)
+ continue;
+ goto rest;
+ }
+
+ /* take input from the standard place */
+ if (!strcmp(argv[0], "-")) {
+ argc = 0;
+ goto rest;
+ }
+
+ /* put output to non-standard place */
+ if (!strcmp(argv[0], "-o")) {
+ if (freopen(argv[1], "w", stdout) == NULL) {
+ perror(argv[1]);
+ return BADEXIT;
+ }
+ argc--, argv++;
+ argc--, argv++;
+ continue;
+ }
+
+ /* Process embedded text */
+ if (!strcmp(argv[0], "-e")) {
+ embed = TRUE;
+ argc--, argv++;
+ continue;
+ }
+
+ /* format for inclusion */
+ if (!strcmp(argv[0], "-i")) {
+ iseen = TRUE;
+ argc--, argv++;
+ continue;
+ }
+
+ /* indicate no keywords */
+ if (!strcmp(argv[0], "-n")) {
+ nokeyw++;
+ argc--, argv++;
+ continue;
+ }
+
+ /* Don't treat %|@|%, etc. specially in comments */
+ if (!strcmp(argv[0], "-c")) {
+ code_cmnts = FALSE;
+ argc--, argv++;
+ continue;
+ }
+
+ /* Do treat %|@|%, etc. specially in comments */
+ if (!strcmp(argv[0], "+c")) {
+ code_cmnts = TRUE;
+ argc--, argv++;
+ continue;
+ }
+
+ /* Don't treat %|@|%, etc. specially in
+ * %%\LaTeX%% text (@embed@ only) */
+ if (!strcmp(argv[0], "-a")) {
+ code_latex = FALSE;
+ argc--, argv++;
+ continue;
+ }
+
+ /* Do treat %|@|%, etc. specially in
+ * %%\LaTeX%% text (@embed@ only) */
+ if (!strcmp(argv[0], "+a")) {
+ code_latex = TRUE;
+ argc--, argv++;
+ continue;
+ }
+
+ /* Use %|\texttt|% for all fonts */
+ if (!strcmp(argv[0], "-t")) {
+ sscanf(argv[1], "%d", &TabWidth);
+ argc--, argv++;
+ argc--, argv++;
+ continue;
+ }
+
+ /* specify the language */
+ if (!strncmp(argv[0], "-l", 2)) {
+ if (strlen(argv[0])==2) {
+ strcpy(language, argv[1]);
+ argc--, argv++;
+ argc--, argv++;
+ } else {
+ strcpy(language, argv[0]+2);
+ argc--, argv++;
+ continue;
+ }
+ }
+
+ /* specify the language description file for permanent use */
+ if (!strcmp(argv[0], "-d!")) {
+ writeDefsfileInExe(programname, argv[1]);
+ return OKEXIT;
+ }
+
+ /* specify the language description file */
+ if (!strncmp(argv[0], "-d", 2)) { /* TODO strncmp? */
+ strcpy(defsfile, argv[1]);
+ argc--, argv++;
+ argc--, argv++;
+ continue;
+ }
+
+ /* specify the file containing variable substitutions */
+ if (!strcmp(argv[0], "-v")) {
+ varsubstlist=parsevartab(argv[1]);
+ argc--, argv++;
+ argc--, argv++;
+ continue;
+ }
+
+ /* open the file for input */
+ if (freopen(argv[0], "r", stdin) == NULL) {
+ perror(argv[0]);
+ return BADEXIT;
+ }
+
+ strcpy(fname, argv[0]);
+ argc--, argv++;
+ }
+ rest:
+
+ lineno = 0;
+ setpreambles();
+
+ /* get config data from %|lgrindef|% */
+ if (tgetent(buf, "firstpreamble", defsfile)>0)
+ parsepreamble(preamble);
+
+ if (tgetent(buf, "postamble", defsfile)>0)
+ parsepreamble(postamble);
+
+ if (tgetent(buf, "filepreamble", defsfile)>0)
+ parsepreamble(preamble2);
+
+ if (tgetent(buf, "configuration", defsfile)>0)
+ parsepreamble(config);
+
+ if (tgetent(buf, "chartab", defsfile)>0)
+ parsechartab();
+
+ if (iseen && embed) {
+ fprintf(stderr, "-i makes no sense with -e; -e ignored\n");
+ embed = FALSE;
+ }
+
+ if (!iseen && !embed) {
+ if (files_done == 0) printpreamble(preamble);
+ printpreamble(preamble2);
+ printf("\\begin{lgrind}\n");
+ printpreamble(config);
+ /* In case \BGfont was modified in config */
+ printf("\\BGfont\n");
+ }
+
+
+ if (embed)
+ printf("%% This document was generated automagically by lgrind. DO NOT EDIT.\n\n");
+ if (iseen)
+ {
+ printf("%% Remember to use the lgrind style\n\n");
+ printf("\\Head{");
+ if (hseen) putstr(hstring);
+ printf("}\n");
+ }
+
+ setlang();
+
+ /* initialize the program */
+
+ incomm = instr = inchr = _escaped = FALSE;
+ incode = latexcode = latex_tt = NOTCODE;
+ do_at = do_tt = code_latex;
+ blklevel = 0;
+ reclevel = 0;
+ for (psptr = 0; psptr < PSMAX; psptr++) {
+ pstack[psptr][0] = '\0';
+ plstack[psptr] = 0;
+ }
+ psptr = -1;
+ if (*fname=='\0') {
+ time_t tm;
+ strcpy(fname, "stdin");
+ stbuf.st_size=0;
+ tm=time(NULL);
+ modtime = *localtime(&tm);
+ }
+ else {
+ stat(fname, &stbuf);
+ modtime = *localtime(&stbuf.st_mtime);
+ }
+
+ if (!embed) {
+ printf("\\File{");
+ putstr(fname);
+ printf("}{%d}{%d}{%d}{%d:%02d}{%ld}\n", modtime.tm_year+1900, modtime.tm_mon+1,
+ modtime.tm_mday, modtime.tm_hour, modtime.tm_min, stbuf.st_size);
+ }
+
+ code = FALSE;
+ readfile(stdin);
+ files_done++;
+
+ if (!iseen && !embed) {
+ printf("\\end{lgrind}\n");
+ }
+
+ if (code)
+ fprintf(stderr, "Reached EOF within code in file %s\n", fname);
+ } while (argc > 0);
+
+ if (!iseen && !embed) {
+ printpreamble(postamble);
+ }
+ return OKEXIT;
+}
+
+
+/*
+ * @readfile()@ --- read and process a file
+ */
+void readfile(FILE *fp)
+{
+ register char *cp;
+ boolean LGinline=FALSE; /* Doing %( -- %) */
+ char term; /* ']' or ')' */
+ char *atptr; /* start of %|@|% within %%\LaTeX%% text */
+ char *atendptr; /* end of %|@|% within %%\LaTeX%% text */
+ char *pcptr; /* start of %|%|% within %%\LaTeX%% text */
+ char *pcendptr; /* end of %|%|% within %%\LaTeX%% text */
+ char temp[BUFFERSIZE];
+ char fnamebak[200];
+ int linenobak;
+
+ while (fgets(buf, BUFFERSIZE, fp) != NULL) {
+ cp = &buf[strlen(buf)-1];
+ if (*cp != '\n') {*(++cp) = '\n'; *(++cp) = '\0'; }
+ lineno++;
+ cp = buf;
+ lastout = '\0';
+ if (embed) {
+ if (!code) {
+ if (buf[0] == '%' &&
+ (buf[1] == '[' || buf[1] == '('
+ || buf[1] == '#' || buf[1] == '<' || buf[1] == '!'
+ || buf[1] == '@' || buf[1] == '|')) {
+
+ for (cp = buf + 2; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+
+ /* Change the language */
+ if (buf[1] == '#') {
+ if (*cp == '\n')
+ fprintf(stderr, "no language seen after %%# in file\
+ %s at line %d\n", fname, lineno);
+ else {
+ cp[strlen(cp) - 1] = '\0'; /* nuke the @'\n'@ */
+ while ((*cp==' ') || (*cp=='\t')) cp++;
+ strcpy(language, cp);
+ printf("%% switching to %s\n", language);
+ setlang();
+ }
+ continue;
+ }
+
+ /* Turn %|@|% or %|||% processing within %%\LaTeX%%
+ * text on or off. */
+
+ if (buf[1] == '@' || buf[1] == '|') {
+ if (*cp == '\n')
+ fprintf(stderr, "no setting seen after %%%c in file\
+ %s at line %d\n", buf[1], fname, lineno);
+ else {
+ int flag = (*cp == '1' || *cp == '+');
+ if (buf[1] == '@')
+ do_at = flag;
+ else
+ do_tt = flag;
+ }
+ continue;
+ }
+
+ code = TRUE;
+
+ /* take input from another file or from a shell command */
+ if (buf[1] == '<' || buf[1] == '!') {
+ FILE *fp;
+ char source = buf[1];
+
+ cp[strlen(cp) - 1] = '\0'; /* nuke the @'\n'@ */
+ if (source == '<')
+ fp = fopen(cp, "r");
+ else /* @source == '!'@ */
+ fp = popen(cp, "r");
+
+ if (fp == NULL) {
+ sprintf(temp, "%%%c on `%s' failed", source, cp);
+ perror(temp);
+ } else {
+ strcpy(temp, cp);
+ printf("%% start of `%s'\n", temp);
+ /* printf("\\LGinlinefalse\\LGbegin\\lgrinde\n"); */
+ /* the above was not %%all%% incorrect ... */
+ printf("\\LGinlinefalse");
+ printf("\\begin{lgrind}\n");
+ printpreamble(config);
+ /* In case \BGfont was modified in config */
+ printf("\\BGfont\n");
+ embed = FALSE;
+ linenobak=lineno; strcpy(fnamebak, fname);
+ lineno=0; strcpy(fname, temp);
+ linenocode=0;
+ readfile(fp);
+ lineno=linenobak; strcpy(fname, fnamebak);
+ embed = TRUE;
+ printf("\\end{lgrind}\n");
+ printf("%% end of `%s'\n", temp);
+ if (source == '<')
+ fclose(fp);
+ else
+ pclose(fp);
+ }
+ code = FALSE;
+ continue;
+ }
+
+ /* embedded inline or displayed code */
+ linenocode=0;
+ if (buf[1] == '(') {
+ LGinline = TRUE;
+ term = ')';
+ printf("\\LGinlinetrue");
+ } else { /* @buf[1] == '['@ */
+ LGinline = FALSE;
+ term = ']';
+ printf("\\LGinlinefalse");
+ }
+ if (buf[2] == '\n') {
+ printf("\\LGbegin\\lgrinde\n");
+ } else {
+ buf[strlen(buf)-1] = '\0';
+ printf("%s\\lgrinde\n", &buf[2]);
+ }
+ continue;
+
+ } /* @if (buf[0] == '%'@%%\dots%% (special comment) */
+ else
+ {
+ while (do_at && (atendptr = expmatch(cp, l_at, &atptr, (char *) NULL)) != NULL
+ && ( (pcendptr = expmatch(cp, l_pc, &pcptr, (char *) NULL)) == NULL
+ || atptr < pcptr ) )
+ {
+ putVcp(cp, atptr-1);
+ printf("\\LGinlinetrue\\LGbegin\\lgrinde");
+ cp = atendptr;
+ atendptr = expmatch(cp, l_at, &atptr, (char *) NULL);
+ /* No %|@|%: implicit %|@|% just before NL */
+ if (atptr == NULL)
+ atptr = atendptr = cp + strlen(cp) - 1;
+ strncpy(temp, cp, (size_t)(atptr-cp));
+ temp[(int)(atptr-cp)] = '\0';
+ cp = atendptr;
+ linenocode++;
+ putScp(temp);
+ printf("}}\\egroup\\endlgrinde\\LGend{}");
+ }
+ fputs(cp, stdout);
+ continue;
+ }
+ } /* @if (!code)@ */
+
+ /*
+ * We're in embedded code.
+ */
+ if (buf[0] == '%') {
+ if (buf[1] == '*') {
+ if (term != ']')
+ fprintf(stderr, "%%* only makes sense in display mode\
+ in file %s at line %d\n", fname, lineno);
+ else {
+ printf("\\endlgrinde\\LGend\n");
+ printf("\\LGinlinefalse\\LGbegin\\lgrinde[%d]\n", linenocode+1);
+ }
+ continue;
+ } else if (buf[1] == term) {
+ if (term == ')') printf("\\egroup");
+ if (buf[2] == '\n')
+ printf("\\endlgrinde\\LGend\n");
+ else
+ printf("\\endlgrinde%s", &buf[2]);
+ code = FALSE;
+ continue;
+ } else if (buf[1] == '=') { /* Send literal */
+ fputs(&buf[2], stdout);
+ continue;
+ } else if (buf[1] == '[' || buf[1] == '('
+ || buf[1] == ']' || buf[1] == ')') {
+ fprintf(stderr,
+ "Possible nested embedded code in file %s at line %d\n",
+ fname, lineno);
+ }
+ }
+
+ /*
+ * Inline code --- suppress leading whitespace
+ */
+ if (LGinline) {
+ while (isspace(*cp))
+ cp++;
+ }
+ } /* @if (embed)@ */
+
+ if (*cp == '\f') {
+ printf("\\NewPage\n");
+ cp++;
+ if (*cp == '\n') /* some people like ^Ls on their own line */
+ continue;
+ }
+ prccont = FALSE;
+ linenocode++;
+ putScp(cp);
+ if (!embed && prccont && (psptr >= 0)) {
+ printf("\\ProcCont{");
+ putstr(pstack[psptr]);
+ printf("}");
+ }
+#ifdef DEBUG
+ printf("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr);
+#endif
+ } /* @while fgets()@ */
+}
+
+
+
+/*
+ * Set all of the language-dependent variables
+ */
+void setlang(void)
+{
+ char *p, *cp;
+ int i;
+
+ /*
+ * get the language definition from the defs file
+ */
+ if (strcmp(language, "mPi") == 0) /* none yet defined */
+ {
+ i = tgetent(defs, "extensions", defsfile);
+ if (i == 0) strcpy(language, "c");
+ else
+ {
+ cp = strrchr(fname, '.');
+ if (cp !=NULL)
+ {
+ p=buf; cp = tgetstr(cp+1, &p);
+ }
+ if (cp != NULL) strcpy(language, cp);
+ else strcpy(language, "c");
+ }
+ }
+ i = tgetent(defs, language, defsfile);
+ if (i == 0) {
+ fprintf(stderr, "no entry for language %s\n", language);
+ exit(BADEXIT);
+ } else if (i < 0) {
+ fprintf(stderr, "cannot find lgrindef file `%s'\n", defsfile);
+ exit(BADEXIT);
+ }
+
+ p = strings;
+ if (tgetstr("kw", &p) == NULL)
+ nokeyw = TRUE;
+ else {
+ char **cpp;
+
+ cpp = l_keywds;
+ cp = strings;
+ while (*cp) {
+ while (*cp == ' ' || *cp =='\t')
+ *cp++ = '\0';
+ if (*cp)
+ *cpp++ = cp;
+ while (*cp != ' ' && *cp != '\t' && *cp)
+ cp++;
+ }
+ *cpp = NULL;
+ }
+
+ p = buf; l_prcbeg = convexp(tgetstr("pb", &p));
+ p = buf; l_noproc = convexp(tgetstr("np", &p));
+ p = buf; l_combeg = convexp(tgetstr("cb", &p));
+ p = buf; l_comend = convexp(tgetstr("ce", &p));
+ p = buf; l_acmbeg = convexp(tgetstr("ab", &p));
+ p = buf; l_acmend = convexp(tgetstr("ae", &p));
+ p = buf; l_strbeg = convexp(tgetstr("sb", &p));
+ p = buf; l_strend = convexp(tgetstr("se", &p));
+ p = buf; l_blkbeg = convexp(tgetstr("bb", &p));
+ p = buf; l_blkend = convexp(tgetstr("be", &p));
+ p = buf; l_chrbeg = convexp(tgetstr("lb", &p));
+ p = buf; l_chrend = convexp(tgetstr("le", &p));
+ p = s_cdebeg; l_cdebeg = convexp(tgetstr("zb", &p));
+ p = buf; l_cdeend = convexp(tgetstr("ze", &p));
+ p = buf; l_texbeg = convexp(tgetstr("tb", &p));
+ p = buf; l_texend = convexp(tgetstr("te", &p));
+ p = buf; l_txmbeg = convexp(tgetstr("mb", &p));
+ p = buf; l_txmend = convexp(tgetstr("me", &p));
+ p = buf; l_tt_beg = convexp(tgetstr("vb", &p));
+ p = buf; l_tt_end = convexp(tgetstr("ve", &p));
+ p = buf; l_record = convexp(tgetstr("rb", &p));
+ p = buf; cp = tgetstr("id", &p) ;
+ if (cp)
+ {
+ l_id = (char*)malloc(strlen(cp));
+ strcpy(l_id, cp);
+ }
+ else l_id = "_";
+
+ l_tt = convexp("\\|");
+ l_at = convexp("@");
+ l_pc = convexp("%");
+
+ l_escape = '\\';
+ l_cfunctions = tgetflag("cf");
+ isproc = l_cfunctions ? isprocC : isprocNorm;
+
+ l_onecase = tgetflag("oc");
+ re_strncmp = l_onecase ? lc_strncmp : strncmp;
+ l_toplex = tgetflag("tl");
+}
+
+
+/*
+ * Write out a line of TeX in comment verbatim
+ */
+void putVtc(char *stringstart, char *comacmptr)
+{
+ char *texptr, *texendptr;
+ char texline[BUFFERSIZE/8];
+ texendptr = expmatch(stringstart, l_texend, &texptr, (char *) NULL);
+ if (texendptr == comacmptr)
+ {
+ strncpy(texline, stringstart, texptr-stringstart);
+ texline[texptr-stringstart]='\0';
+ printf("%s\n", texline);
+ }
+}
+
+
+/*
+ * Write out a formatted line of program text
+ */
+void putScp(char *os)
+{
+ register char *s = os; /* pointer to unmatched string */
+ register char *s1; /* temp. string */
+ char *comptr; /* start of a comment delimiter */
+ char *comendptr; /* end of a comment delimiter */
+ char *acmptr; /* start of an alt. comment delimiter */
+ char *acmendptr; /* end of an alt. comment delimiter */
+ char *strptr; /* start of a string delimiter */
+ char *strendptr; /* end of a string delimiter */
+ char *chrptr; /* start of a char. const delimiter */
+ char *chrendptr; /* end of a char. const delimiter */
+ char *cdeptr; /* start of prog text delim within a comment */
+ char *cdeendptr; /* end of prog text delim within a comment */
+ char *cdbptr; /* start of prog text delim within a comment */
+ char *cdbendptr; /* end of prog text delim within a comment */
+ char *texptr; /* start of %%\TeX%% text delim within a comment */
+ char *texendptr; /* end of %%\TeX%% text delim within a comment */
+ char *txmptr; /* start of %%\TeX%% math delim within a comment */
+ char *txmendptr; /* end of %%\TeX%% math delim within a comment */
+ char *tt_ptr; /* start of typewriter delim within a comment */
+ char *tt_endptr; /* end of typewriter delim within a comment */
+ char *blksptr; /* start of a lexical block start */
+ char *blksendptr; /* end of a lexical block start */
+ char *recsptr; /* start of a lexical block outside functions start */
+ char *recsendptr; /* end of a lexical block outside functions start */
+ char *blkeptr; /* start of a lexical block end */
+ char *blkeendptr; /* end of a lexical block end */
+
+ _sstart = os; /* remember the start for @expmatch()@ */
+ _escaped = FALSE;
+ if (nokeyw || incomm || instr)
+ goto skip;
+
+ /* check for complete comment TeX line */
+ comendptr = expmatch(s, l_combeg, &comptr, (char *) NULL);
+ acmendptr = expmatch(s, l_acmbeg, &acmptr, (char *) NULL);
+ texendptr = expmatch(s, l_texbeg, &texptr, (char *) NULL);
+ if (texptr && comptr == s)
+ if (texptr == comendptr)
+ {
+ comendptr = expmatch(comendptr, l_comend, &comptr, (char *) NULL);
+ if (*comendptr=='\n')
+ {
+ putVtc(texendptr, comptr);
+ return;
+ }
+ } else if (texptr == acmendptr)
+ {
+ acmendptr = expmatch(acmendptr, l_acmend, &acmptr, (char *) NULL);
+ if (*acmendptr=='\n')
+ {
+ putVtc(texendptr, acmptr);
+ return;
+ }
+ }
+
+ if ((*isproc)(s) && reclevel == 0) {
+ printf("\\index{"); putstr(pname); printf("}");
+ printf("\\Proc{");
+ if (strlen(pname)>30)
+ {
+ s1=pname+strlen(pname)-1;
+ while (s1>pname && (isalnum(*s1) || *s1=='_')) s1--;
+ if (s1!=pname) strcpy(pname, s1+1);
+ }
+ if (strlen(pname)>32) {
+ strcpy(pname, pname+strlen(pname)-28);
+ printf("\\dots "); }
+ putstr(pname);
+ printf("}");
+ if (!embed && psptr < PSMAX-1) {
+ ++psptr;
+ strncpy(pstack[psptr], pname, PNAMELEN);
+ pstack[psptr][PNAMELEN] = '\0';
+ plstack[psptr] = blklevel-1;
+ }
+ }
+
+ skip:
+ printf("\\L{\\LB{");
+
+ do {
+ /* check for string, comment, blockstart, etc */
+ if (!incomm && !instr && !inchr) {
+
+ blkeendptr = expmatch(s, l_blkend, &blkeptr, (char *) NULL);
+ blksendptr = expmatch(s, l_blkbeg, &blksptr, (char *) NULL);
+ recsendptr = expmatch(s, l_record, &recsptr, (char *) NULL);
+ comendptr = expmatch(s, l_combeg, &comptr, (char *) NULL);
+ acmendptr = expmatch(s, l_acmbeg, &acmptr, (char *) NULL);
+ strendptr = expmatch(s, l_strbeg, &strptr, (char *) NULL);
+ chrendptr = expmatch(s, l_chrbeg, &chrptr, (char *) NULL);
+
+ /* check for end of program text in comment */
+ if (incode != NOTCODE) {
+ cdeendptr = expmatch(s, l_cdeend, &cdeptr, (char *) NULL);
+
+ if ((cdeptr == NULL && (comptr != NULL || acmptr != NULL))
+ || (cdeptr != NULL
+ && ((comptr != NULL && comptr < cdeptr)
+ || ((acmptr != NULL && acmptr < cdeptr))))) {
+ fprintf(stderr, "Comments may not be nested within\
+ program text within comments in file %s at\
+ line %d\n", fname, lineno);
+ s = (comptr != NULL) ? comptr : acmptr;
+ incode = NOTCODE;
+ continue;
+ }
+
+ /* look to see if there's a \<zb> in the program text */
+ cdbendptr = expmatch(s, l_cdebeg, &cdbptr, (char *) NULL);
+ if (cdeptr != NULL
+ && (strptr == NULL || cdbptr < strptr)
+ && (chrptr == NULL || cdbptr < chrptr)
+ && (blksptr == NULL || cdbptr < blksptr)
+ && (recsptr == NULL || cdbptr < recsptr)
+ && (blkeptr == NULL || cdbptr < blkeptr)) {
+ if (cdbptr > s && cdbptr[-1] == l_escape) {
+ putKcp(s, cdbptr-2, FALSE);
+ printf("\\C{}");
+ putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
+ printf("\\CE{}");
+ s = cdbendptr;
+ incode = OTHERCODE;
+ continue;
+ }
+ }
+
+ comendptr =
+ expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
+ &comptr, (char *) NULL);
+
+ if ((cdeptr == NULL && comptr != NULL)
+ || (cdeptr != NULL && (comptr != NULL && comptr < cdeptr))) {
+ fprintf(stderr, "Unterminated program text within comment\
+ in file %s at line %d\n", fname, lineno);
+ printf("\\C{}");
+ s = comptr;
+ incode = NOTCODE; incomm = TRUE;
+ continue;
+ }
+
+
+ if (cdeendptr != NULL) {
+ if ((strptr == NULL || cdeptr < strptr)
+ && (chrptr == NULL || cdeptr < chrptr)
+ && (blksptr == NULL || cdeptr < blksptr)
+ && (recsptr == NULL || cdeptr < recsptr)
+ && (blkeptr == NULL || cdeptr < blkeptr)) {
+ if (incode == INITCODE && cdeptr == s) {
+ printf("\\C{}");
+ putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
+ } else {
+ putKcp(s, cdeptr-1, FALSE);
+ printf("\\C{}");
+ }
+ s = cdeendptr;
+ incode = NOTCODE; incomm = TRUE;
+ continue;
+ }
+ } else if (strptr == NULL && chrptr == NULL
+ && blksptr == NULL && recsptr == NULL
+ && blkeptr == NULL) {
+ cdeptr = s;
+ s += strlen(s);
+ putKcp(cdeptr, s-1, FALSE);
+ incode = OTHERCODE;
+ continue;
+ } /* else there is a string/char/block on this line */
+
+ incode = OTHERCODE;
+ } /* @if (incode)@ */
+
+
+ /* start of a comment? */
+ if (comptr != NULL
+ && (strptr == NULL || comptr < strptr)
+ && (acmptr == NULL || comptr < acmptr)
+ && (chrptr == NULL || comptr < chrptr)
+ && (blksptr == NULL || comptr < blksptr)
+ && (recsptr == NULL || comptr < recsptr)
+ && (blkeptr == NULL || comptr < blkeptr)) {
+ putKcp(s, comptr-1, FALSE);
+ printf("\\C{}");
+ s = comendptr;
+ putKcp(comptr, comendptr-1, TRUE);
+ incomm = TRUE;
+ comtype = STANDARD;
+ continue;
+ }
+
+ /* start of an alternate-form comment? */
+ if (acmptr != NULL
+ && (strptr == NULL || acmptr < strptr)
+ && (chrptr == NULL || acmptr < chrptr)
+ && (blksptr == NULL || acmptr < blksptr)
+ && (recsptr == NULL || acmptr < recsptr)
+ && (blkeptr == NULL || acmptr < blkeptr)) {
+ putKcp(s, acmptr-1, FALSE);
+ printf("\\C{}");
+ s = acmendptr;
+ putKcp(acmptr, acmendptr-1, TRUE);
+ incomm = TRUE;
+ comtype = ALTERNATE;
+ continue;
+ }
+
+ /* start of a string? */
+ if (strptr != NULL
+ && (chrptr == NULL || strptr < chrptr)
+ && (blksptr == NULL || strptr < blksptr)
+ && (recsptr == NULL || strptr < recsptr)
+ && (blkeptr == NULL || strptr < blkeptr)) {
+ putKcp(s, strptr-1, FALSE);
+ printf("\\S{}");
+ s = strendptr;
+ putKcp(strptr, strendptr-1, FALSE);
+ instr = TRUE;
+ continue;
+ }
+
+ /* start of a character string? */
+ if (chrptr != NULL
+ && (blksptr == NULL || chrptr < blksptr)
+ && (recsptr == NULL || chrptr < recsptr)
+ && (blkeptr == NULL || chrptr < blkeptr)) {
+ putKcp(s, chrptr-1, FALSE);
+ printf("\\S{}");
+ s = chrendptr;
+ putKcp(chrptr, chrendptr-1, FALSE);
+ inchr = TRUE;
+ continue;
+ }
+
+ /* end of a lexical block */
+ if (blkeptr != NULL) {
+ if ((blksptr == NULL || blkeptr < blksptr) &&
+ (recsptr == NULL || blkeptr < recsptr)) {
+ putKcp(s, blkeendptr - 1, FALSE);
+ s = blkeendptr;
+ if (blklevel) blklevel--;
+ if (reclevel) reclevel--;
+ else if (psptr >= 0 && plstack[psptr] >= blklevel) {
+
+ /* end of current procedure */
+ blklevel = plstack[psptr];
+
+ /* see if we should print the last proc name */
+ if (--psptr >= 0)
+ prccont = TRUE;
+ else
+ psptr = -1;
+ }
+ continue;
+ }
+ }
+
+ /* start of a lexical block */
+ if (blksptr != NULL) {
+ putKcp(s, blksendptr - 1, FALSE);
+ s = blksendptr;
+ if (procedures_pending)
+ procedures_pending--;
+ else
+ /* when C functions then not on top level */
+ if (!l_cfunctions || blklevel)
+ blklevel++;
+ continue;
+ }
+
+ /* start of a lexical block outside functions */
+ if (recsptr != NULL) {
+ putKcp(s, recsendptr - 1, FALSE);
+ s = recsendptr;
+ if (procedures_pending)
+ procedures_pending--;
+ else
+ blklevel++;
+ reclevel++;
+ continue;
+ }
+
+ /* check for end of comment */
+ } else if (incomm) {
+
+ cdeendptr = expmatch(s, l_cdebeg, &cdeptr, (char *) NULL);
+ texendptr = expmatch(s, l_texbeg, &texptr, (char *) NULL);
+ txmendptr = expmatch(s, l_txmbeg, &txmptr, (char *) NULL);
+ tt_endptr = expmatch(s, l_tt_beg, &tt_ptr, (char *) NULL);
+
+ if (code_cmnts) {
+
+ /* Check for program text within comment */
+ if (cdeptr != NULL
+ && (texptr == NULL || cdeptr < texptr)
+ && (tt_ptr == NULL || cdeptr < tt_ptr)
+ && (txmptr == NULL || cdeptr < txmptr)) {
+ putKcp(s, cdeptr-1, TRUE);
+ printf("\\CE{}");
+ s = cdeendptr;
+ incode = INITCODE; incomm = FALSE;
+ continue;
+ }
+
+ /* Check for %%\TeX%% text within comment */
+ if (texptr != NULL
+ && (tt_ptr == NULL || texptr < tt_ptr)
+ && (txmptr == NULL || texptr < txmptr)) {
+ putKcp(s, texptr-1, TRUE);
+ s = texendptr;
+ if ((texendptr =
+ expmatch(s, l_texend, &texptr, (char *) NULL)) != NULL) {
+ putchar('{'); putVcp(s, texptr-1); putchar('}');
+ s = texendptr;
+ } else {
+ fprintf(stderr, "LaTeX text within a comment must all be\
+ on one line (file %s at line %d)\n", fname, lineno);
+ s += strlen(s);
+ }
+ continue;
+ }
+
+ /* Check for typewriter text within comment */
+ if (tt_ptr != NULL
+ && (txmptr == NULL || tt_ptr < txmptr)) {
+ putKcp(s, tt_ptr-1, TRUE);
+ s = tt_endptr;
+ if ((tt_endptr =
+ expmatch(s, l_tt_end, &tt_ptr, (char *) NULL)) != NULL) {
+ printf("{\\TTfont ");
+ latex_tt=TRUE;
+ putKcp(s, tt_ptr-1, TRUE);
+ latex_tt=FALSE;
+ printf("}");
+ s = tt_endptr;
+ } else {
+ fprintf(stderr, "typewriter text within a comment must all\
+ be on one line (file %s at line %d)\n\t%s",
+ fname, lineno, s);
+ s += strlen(s);
+ }
+ continue;
+ }
+
+ /* Check for %%\TeX%% math within comment */
+ if (txmptr != NULL) {
+ putKcp(s, txmptr-1, TRUE);
+ s = txmendptr;
+ if ((txmendptr =
+ expmatch(s, l_txmend, &txmptr, (char *) NULL)) != NULL) {
+ putchar('$'); putVcp(s, txmptr-1); putchar('$');
+ s = txmendptr;
+ } else {
+ fprintf(stderr, "TeX math within a comment must all be\
+ on one line (file %s at line %d)\n", fname, lineno);
+ s += strlen(s);
+ }
+ continue;
+ }
+ } /* @if (code_cmnts)@ */
+
+ if ((comendptr =
+ expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
+ (char **) NULL, (char *) NULL)) != NULL) {
+ putKcp(s, comendptr-1, TRUE);
+ s = comendptr;
+ incomm = FALSE;
+ printf("\\CE{}");
+ } else {
+ comptr = s;
+ s += strlen(s);
+ putKcp(comptr, s-1, TRUE);
+ }
+ continue;
+
+ /* check for end of string */
+ } else if (instr) {
+ if ((strendptr =
+ expmatch(s, l_strend, (char **) NULL, (char *) NULL)) != NULL) {
+ putKcp(s, strendptr-1, TRUE);
+ s = strendptr;
+ instr = FALSE;
+ printf("\\SE{}");
+ } else {
+ strptr = s;
+ s += strlen(s);
+ putKcp(strptr, s-1, TRUE);
+ }
+ continue;
+
+ /* check for end of character string */
+ } else if (inchr) {
+ if ((chrendptr =
+ expmatch(s, l_chrend, (char **) NULL, (char *) NULL)) != NULL) {
+ putKcp(s, chrendptr-1, TRUE);
+ s = chrendptr;
+ inchr = FALSE;
+ printf("\\SE{}");
+ } else {
+ chrptr = s;
+ s += strlen(s);
+ putKcp(chrptr, s-1, TRUE);
+ }
+ continue;
+ }
+
+ /* print out the line */
+ chrptr = s;
+ s += strlen(s);
+ putKcp(chrptr, s-1, FALSE);
+
+ } while (*s);
+}
+
+
+/*
+ * Output a %%\LaTeX%% command to tab to column "col" (see the documentation
+ * for a partial explanation of the bizarre brace arrangement).
+ */
+#define tabto(col) printf("}\\Tab{%d}{", col);
+
+
+/*
+ * @islidchr()@ is @TRUE@ for things that can begin identifiers;
+ * @isidchr@ is @TRUE@ of identifier constituents.
+ */
+#define islidchr(c)(((isalpha(c) || (strchr(l_id, c))) && c!=0))
+#define isidchr(c)(((isalnum(c) || (strchr(l_id, c))) && c!=0))
+
+
+/*
+ * Get the identifier starting at @s@. It is assumed that @s@ may indeed
+ * start an identifier. Value is %$>0$% for a keyword --- the count of
+ * characters in the keyword --- and %$<0$% if not a keyword, in which
+ * case the value returned is the negative of the number of bytes in
+ * the matched identifier.
+ *
+ * This function checks @nokeyw@ and won't check to see if the
+ * identifier found is a keyword if it is @TRUE@.
+ */
+int getid(char *s)
+{
+ char **ss = l_keywds;
+ int i = 1;
+ char *cp = s;
+ int firstc = *s;
+
+ while (++cp, isidchr(*cp))
+ i++;
+ if (nokeyw)
+ return -i;
+ while ((cp = *ss++) != '\0') {
+ if (!l_onecase && firstc != *cp)
+ continue;
+ if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i]))
+ return i;
+ }
+ return -i;
+}
+
+
+/*
+ * Calculate the width of a string, including tabs
+ */
+int width(register char *s, register char *os)
+{
+ register int i = 0, c;
+
+ while (s < os) {
+ c = *s++;
+ if (c == '\t') {
+ /* i = (i + 8) &~ 7; */
+ i = ((i + TabWidth) / TabWidth) * TabWidth;
+ continue;
+ }
+ if (c < ' ')
+ i += 2;
+ else
+ i++;
+ }
+ return i;
+}
+
+
+/*
+ * Write out a portion of the line
+ */
+boolean putKcp(char *start, char *end, boolean nix)
+/* start Start of string to write
+ end End of string to write
+ nix Don't look for identifiers, numbers
+ returns whether we ate only as much as we ought to */
+{
+ int i, c;
+
+ while (start <= end) {
+ c = *start++;
+ /*
+ * take care of nice tab stops ...
+ * ... and of space runs
+ */
+ if (c == '\t' || (c == ' ' && *start == ' ')) {
+ while (start <= end && ( *start == '\t' || *start == ' ' ))
+ start++;
+ tabto(width(_sstart, start));
+ continue;
+ }
+
+ /*
+ * First split off numbers. We have a rather ad hoc
+ * definition: A number is a digit followed by any number
+ * of digits or letters, and periods.
+ * (Additionally a number can start with %|$|% (e.g. hex numbers).)
+ * This produces meaningless parses --- %$.2$% is parsed as %|.|%
+ * followed by the number %|2|% --- but should produce decent
+ * results for most languages (outside of maybe FORTRAN and DCL).
+ */
+ if (!nix) {
+ if (c == '#' || islidchr(c)) {
+ i = getid(--start);
+ if (i > 0)
+ printf("\\K{");
+ else {
+ printf("\\V{");
+ i = substvarname(&start, -i);
+ }
+ while (--i >= 0) {
+ c = *start++;
+ outchar(c);
+ }
+ putchar('}');
+ continue;
+ }
+ else if (isdigit(c) || c == '$') {
+ printf("\\N{");
+ do {
+ if (c == 'l')
+ printf("$\\ell$");
+ else
+ outchar(c);
+ c = *start++;
+ } while (isalnum(c) || (c == '.' && *start != '.'));
+ putchar('}');
+ start--;
+ continue;
+ }
+ }
+ outchar(c);
+ }
+ return (start-1)==end;
+}
+
+
+
+/*
+ * Write out a portion of the line verbatim
+ */
+void putVcp(char *start, char *end)
+/* start Start of string to write
+ end End of string to write */
+{
+ for ( ; start <= end; start++) {
+ putchar(*start);
+ }
+}
+
+
+/*
+ * Output a string, escaping special characters
+ */
+void putstr(register char *cp)
+{
+ register int c;
+
+ if (cp == NULL)
+ return;
+ while ((c = *cp++) != '\0')
+ outchar(c);
+}
+
+
+/*
+ * The following table converts ASCII characters to a printed
+ * representation, taking care of all the %%\LaTeX%% quoting. N.B.: all
+ * single-character strings are assumed to be equivalent to the
+ * character for that index (i.e., @printtab['c']@ can't be @"f"@).
+ * (This is purely for efficiency hacking.)
+ *
+ * Notes:
+ * Some pairs of characters are handled specially within @outchar()@;
+ * this table contains no indication when that happens.
+ * %|`|% is output as %|{`}|% to avoid various ligatures, such as %|!`|%.
+ * The %|''|% and %|--|% (and %|---|%) ligatures are not a problem
+ * because those characters are output as macros anyway. Using %|{`}|%
+ * is sufficient since nothing we put out will ever be given to the
+ * hyphenation algorithms anyway.
+ *
+ * @ttprinttab@ is the same for the emulated verbatim mode
+ */
+
+char *printtab[256] = {
+ "\0x", "\\^A", "\\^B", "\\^C", "\\^D", "\\^E", "\\^F", "\\^G",
+ "\\^H", "\t", "}}\n", "\\^K", "\0x", "\\^M", "\\^N", "\\^O",
+ "\\^P", "\\^Q", "\\^R", "\\^S", "\\^T", "\\^U", "\\^V", "\\^W",
+ "\\^X", "\\^Y", "\\^Z", "\\^[", "\\^\\!","\\^]", "\\^\\^","\\^\\_",
+ " ", "!", "\\3", "\\#", "\\$", "\\%", "\\&", "{'}",
+ "(", ")", "*", "+", ",", "\\-", ".", "/",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", ":", ";", "\\<", "=", "\\>", "?",
+ "@", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "[", "\\2", "]", "\\5", "\\_",
+ "{`}", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "\\{", "\\|", "\\}", "\\~{}", "\\^?",
+ "\200", "\201", "\202", "\203", "\204", "\205", "\206", "\207",
+ "\210", "\211", "\212", "\213", "\214", "\215", "\216", "\217",
+ "\220", "\221", "\222", "\223", "\224", "\225", "\226", "\227",
+ "\230", "\231", "\232", "\233", "\234", "\235", "\236", "\237",
+ "\240", "\241", "\242", "\243", "\244", "\245", "\246", "\247",
+ "\250", "\251", "\252", "\253", "\254", "\255", "\256", "\257",
+ "\260", "\261", "\262", "\263", "\264", "\265", "\266", "\267",
+ "\270", "\271", "\272", "\273", "\274", "\275", "\276", "\277",
+ "\300", "\301", "\302", "\303", "\304", "\305", "\306", "\307",
+ "\310", "\311", "\312", "\313", "\314", "\315", "\316", "\317",
+ "\320", "\321", "\322", "\323", "\324", "\325", "\326", "\327",
+ "\330", "\331", "\332", "\333", "\334", "\335", "\336", "\337",
+ "\340", "\341", "\342", "\343", "\344", "\345", "\346", "\347",
+ "\350", "\351", "\352", "\353", "\354", "\355", "\356", "\357",
+ "\360", "\361", "\362", "\363", "\364", "\365", "\366", "\367",
+ "\370", "\371", "\372", "\373", "\374", "\375", "\376", "\377",
+};
+
+char *ttprinttab[256] = {
+ "\0x", "\\^A", "\\^B", "\\^C", "\\^D", "\\^E", "\\^F", "\\^G",
+ "\\^H", "\t", "}}\n", "\\^K", "\0x", "\\^M", "\\^N", "\\^O",
+ "\\^P", "\\^Q", "\\^R", "\\^S", "\\^T", "\\^U", "\\^V", "\\^W",
+ "\\^X", "\\^Y", "\\^Z", "\\^[", "\\^\\!","\\^]", "\\^\\^","\\^\\_",
+ " ", "!", "{34}", "{35}", "{36}", "{37}", "{38}", "{39}",
+ "(", ")", "*", "+", ",", "{45}", ".", "/",
+ "0", "1", "2", "3", "4", "5", "6", "7",
+ "8", "9", ":", ";", "{60}", "=", "{62}", "?",
+ "@", "A", "B", "C", "D", "E", "F", "G",
+ "H", "I", "J", "K", "L", "M", "N", "O",
+ "P", "Q", "R", "S", "T", "U", "V", "W",
+ "X", "Y", "Z", "[", "{92}", "]", "{94}", "{95}",
+ "{96}", "a", "b", "c", "d", "e", "f", "g",
+ "h", "i", "j", "k", "l", "m", "n", "o",
+ "p", "q", "r", "s", "t", "u", "v", "w",
+ "x", "y", "z", "{123}", "{124}", "{125}", "{126}", "\\^?",
+ "\200", "\201", "\202", "\203", "\204", "\205", "\206", "\207",
+ "\210", "\211", "\212", "\213", "\214", "\215", "\216", "\217",
+ "\220", "\221", "\222", "\223", "\224", "\225", "\226", "\227",
+ "\230", "\231", "\232", "\233", "\234", "\235", "\236", "\237",
+ "\240", "\241", "\242", "\243", "\244", "\245", "\246", "\247",
+ "\250", "\251", "\252", "\253", "\254", "\255", "\256", "\257",
+ "\260", "\261", "\262", "\263", "\264", "\265", "\266", "\267",
+ "\270", "\271", "\272", "\273", "\274", "\275", "\276", "\277",
+ "\300", "\301", "\302", "\303", "\304", "\305", "\306", "\307",
+ "\310", "\311", "\312", "\313", "\314", "\315", "\316", "\317",
+ "\320", "\321", "\322", "\323", "\324", "\325", "\326", "\327",
+ "\330", "\331", "\332", "\333", "\334", "\335", "\336", "\337",
+ "\340", "\341", "\342", "\343", "\344", "\345", "\346", "\347",
+ "\350", "\351", "\352", "\353", "\354", "\355", "\356", "\357",
+ "\360", "\361", "\362", "\363", "\364", "\365", "\366", "\367",
+ "\370", "\371", "\372", "\373", "\374", "\375", "\376", "\377",
+};
+
+
+
+#define EMDASH (-1)
+/*
+ * Output one character, fixed up as required. Since there is no call-back
+ * to tell @outchar()@ to flush what it has stored, it must always produce
+ * some output --- it can't simply retain state. This makes certain
+ * translations impossible, but we can live without them for now....
+ */
+void outchar(int c)
+{
+ if (!latex_tt)
+ {
+ if (c == ' ') {
+ putchar('_');
+ goto fin;
+ }
+ switch (lastout) {
+ case '.':
+ case '|':
+ if (c == lastout)
+ printf("\\,");
+ break;
+ case ' ':
+#if 0 /* gvr hates this trick */
+ if (incomm && c == '-') {
+ printf("---");
+ c = EMDASH; /* For future cleverness... */
+ goto fin;
+ }
+#endif
+ break;
+ case '[':
+ if (c == ']')
+ printf("\\,");
+ break;
+ case '-':
+ if (c == '>')
+ printf("\\!");
+ break;
+ case '<':
+ if (c == '-')
+ printf("\\!");
+ break;
+ }
+ if (incomm && c == '-') {
+ putchar('-');
+ goto fin;
+ }
+ printtab[(unsigned char)c][1] ?
+ printf("%s", printtab[(unsigned char)c]) : putchar(c);
+ fin:
+ lastout = c;
+ }
+ else
+ c==32 ? putchar('~') :
+ ttprinttab[(unsigned char)c][1] ?
+ printf("\\symbol%s", ttprinttab[(unsigned char)c]) : putchar(c);
+}
+
+
+/*
+ * Look for a procedure beginning on this line
+ */
+boolean isprocNorm(char *s)
+{
+ pname[0] = '\0';
+ if ((!l_toplex || blklevel == 0)
+ && expmatch(s, l_prcbeg, (char **) NULL, pname) != NULL
+ && expmatch(s, l_noproc, (char **) NULL, (char *) NULL) == NULL)
+ {
+ procedures_pending++;
+ blklevel++;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Special version of the above for C functions */
+boolean isprocC(char *s)
+{
+ char cheat[BUFFERSIZE];
+ char *j=s, *i=cheat;
+ boolean comm=FALSE, string=FALSE, schar=FALSE;
+ int brack=0;
+
+ if (blklevel!=0) return FALSE;
+ while (*j)
+ {
+ if (*j=='"' && !comm && !schar) string=(string+1)%2;
+ else if (*j=='\'' && !comm && !string) schar=(schar+1)%2;
+ else if (*j=='\\' && !comm) j++;
+ else if (!comm && !string && !schar && *j=='{') brack++;
+ else if (!comm && !string && !schar && *j=='}') brack--;
+ else if (!comm && !string && !schar && *j=='#') break;
+ else if (!comm && !string && !schar && *j=='/' && *(j+1)=='/') break;
+ else if (!comm && !string && !schar && *j=='/' && *(j+1)=='*') comm=TRUE;
+ else if ( !string && !schar && *j=='*' && *(j+1)=='/')
+ {comm=FALSE; j++;}
+ else if (!brack && !comm && !string && !schar)
+ *i++=*j;
+ j++;
+ }
+ *i = '\0';
+
+ return isprocNorm(cheat);
+}
+
+
+/* The VMS code below has been absolutely untested for the last few years.
+ * Don't ask me about it. Please. MPi
+ */
+
+/*
+ * @getredirection()@ is intended to aid in porting C programs
+ * to VMS (Vax-11 C) which does not support %|>|% and %|<|%
+ * I/O redirection. With suitable modification, it may
+ * useful for other portability problems as well.
+ *
+ * Modified, 24-Jan-86 by Jerry Leichter
+ * When creating a new output file, force the maximum record size to
+ * 512; otherwise, it ends up as 0 (though the C I/O system won't write
+ * a record longer than 512 bytes anyway) which will cause problems if
+ * the file is later opened for @APPEND@ --- if the maximum record size
+ * is 0, C will use the length of the longest record written to the file
+ * for its buffer!
+ */
+
+#ifdef vms
+# include <stdio.h>
+# include <errno.h>
+
+ int
+getredirection(argc, argv)
+ int argc;
+ char **argv;
+/*
+ * Process VMS redirection args. Exit if any error is seen.
+ * If @getredirection()@ processes an argument, it is erased
+ * from the vector. @getredirection()@ returns a new @argc@ value.
+ *
+ * Warning: do not try to simplify the code for VMS. The code
+ * presupposes that @getredirection()@ is called before any data is
+ * read from @stdin@ or written to @stdout@.
+ *
+ * Normal usage is as follows:
+ *
+ *@ main(argc, argv)
+ * int argc;
+ * char *argv[];
+ * {
+ * argc = getredirection(argc, argv);
+ * }@
+ */
+{
+ register char *ap; /* Argument pointer */
+ int i; /* @argv[]@ index */
+ int j; /* Output index */
+ int file; /* File_descriptor */
+
+ for (j = i = 1; i < argc; i++) { /* Do all arguments */
+ switch (*(ap = argv[i])) {
+ case '<': /* %|<file|% */
+ if (freopen(++ap, "r", stdin) == NULL) {
+ perror(ap); /* Can't find file */
+ exit(errno); /* Is a fatal error */
+ }
+ break;
+
+ case '>': /* %|>file|% or %|>>file|% */
+ if (*++ap == '>') { /* %|>>file|% */
+ /*
+ * If the file exists, and is writable by us,
+ * call @freopen()@ to append to the file (using the
+ * file's current attributes). Otherwise, create
+ * a new file with "vanilla" attributes as if
+ * the argument was given as %|>filename|%.
+ * @access(name, 2)@ is @TRUE@ if we can write on
+ * the specified file.
+ */
+ if (access(++ap, 2) == 0) {
+ if (freopen(ap, "a", stdout) != NULL)
+ break; /* Exit @case@ statement */
+ perror(ap); /* Error, can't append */
+ exit(errno); /* After @access@ test */
+ } /* If file accessable */
+ }
+ /*
+ * On VMS, we want to create the file using "standard"
+ * record attributes. @create(...)@ creates the file
+ * using the caller's default protection mask and
+ * "variable length, implied carriage return"
+ * attributes. @dup2()@ associates the file with @stdout@.
+ */
+ if ((file = creat(ap, 0, "rat=cr", "rfm=var", "mrs=512")) == -1
+ || dup2(file, fileno(stdout)) == -1) {
+ perror(ap); /* Can't create file */
+ exit(errno); /* is a fatal error */
+ } /* If %|>|% creation */
+ break; /* Exit @case@ test */
+
+ default:
+ argv[j++] = ap; /* Not a redirector */
+ break; /* Exit @case@ test */
+ }
+ } /* For all arguments */
+ argv[j] = NULL; /* Terminate @argv[]@ */
+ return j; /* Return new @argc@ */
+}
+
+#else /* @!vms@ */
+
+int getredirection(int argc, char **argv)
+ /*
+ * Dummy routine.
+ */
+{
+ return argc;
+}
+
+#endif /* @!vms@ */
+
+#include "lgutil.c"
+/* Helper functions */
+
diff --git a/support/lgrind/source/lgrindef.5 b/support/lgrind/source/lgrindef.5
new file mode 100644
index 0000000000..3606fd3666
--- /dev/null
+++ b/support/lgrind/source/lgrindef.5
@@ -0,0 +1,248 @@
+.\" @(#)lgrindef.5 3.62 11/2/97 MPi; from UCB 4.3
+.\" Copyright (c) 1983 Regents of the University of California.
+.\" All rights reserved. The Berkeley software License Agreement
+.\" specifies the terms and conditions for redistribution.
+.\"
+.\" $Id: lgrindef.5,v 1.4 1999/10/05 17:41:35 mike Exp $
+.\"
+.\" This is the standard SunOS vgrindefs(5) manpage, with a few
+.\" additions to describe the extra capabilities needed by lgrind,
+.\" viz.: zb, ze, tb, te, mb, me, vb, ve, cf, rb.
+.\"
+.tr ||
+.TH LGRINDEF 5 "11 February 1997" "TeX/LaTeX"
+.SH NAME
+lgrindef \- LGrind's language definition data base
+.SH NOTE
+This man page is not yet much outdated, but might be soon except somebody
+asks me to work on it. Consider the LaTeX docs the real docs.
+.SH SYNOPSIS
+.B /usr/TeX/texmf/tex/latex/lgrind/lgrindef
+.SH DESCRIPTION
+.IX "lgrindef file" "" "\fLlgrindef\fP \(em LGrind language definitions"
+.B lgrindef
+contains all language definitions for
+.BR lgrind (1).
+The data base is very similar to
+.BR vgrind (5)
+and
+.BR termcap (5),
+and it is upward-compatible with that of
+.BR vgrind (5).
+Capabilities in
+.B lgrindef
+are of two types:
+Boolean capabilities which indicate that the language has
+some particular feature
+and string
+capabilities which give a regular expression or
+keyword list.
+Entries may continue onto multiple lines by giving a \e as the last
+character of a line.
+Lines starting with # are comments.
+.SS Capabilities
+The following table names and describes each capability.
+.PP
+.PD 0
+.ta \w'\fBName\fP 'u
+.nr Xx \w'\fBName\fP \fBType\fP 'u
+.TP \n(Xxu
+.B
+Name Type
+.B Description
+.TP
+.B ab \fRstr
+Regular expression for the start of an alternate form comment
+.TP
+.B ae \fRstr
+Regular expression for the end of an alternate form comment
+.TP
+.B bb \fRstr
+Regular expression for the start of a block
+.TP
+.B be \fRstr
+Regular expression for the end of a lexical block
+.TP
+.B cb \fRstr
+Regular expression for the start of a comment
+.TP
+.B ce \fRstr
+Regular expression for the end of a comment
+.TP
+.B cf \fRbool
+(Boolean) Use specialized C function detection
+.TP
+.B id \fRstr
+String giving characters other than letters and digits
+that may legally occur in identifiers (default `_')
+.TP
+.B kw \fRstr
+A list of keywords separated by spaces
+.TP
+.B lb \fRstr
+Regular expression for the start of a character constant
+.TP
+.B le \fRstr
+Regular expression for the end of a character constant
+.TP
+.B mb \fRstr
+Regular expression for the start of TeX math within a comment
+.TP
+.B me \fRstr
+Regular expression for the end of TeX math within a comment
+.TP
+.B np \fRstr
+Regular expression for a line
+.B not
+containing the start of a procedure
+.TP
+.B oc \fRbool
+Present means upper and lower case are equivalent
+.TP
+.B pb \fRstr
+Regular expression for start of a procedure
+.TP
+.B pl \fRbool
+Procedure definitions are constrained to the lexical level
+matched by the `px' capability
+.TP
+.B px \fRstr
+A match for this regular expression indicates
+that procedure definitions may occur at the next lexical level.
+Useful for lisp-like languages in which procedure definitions
+occur as subexpressions of defuns.
+.TP
+.B rb \fRstr
+Regular expression for the start of a block outside the actual code
+.TP
+.B sb \fRstr
+Regular expression for the start of a string
+.TP
+.B se \fRstr
+Regular expression for the end of a string
+.TP
+.B rb \fRstr
+Regular expression for the end of a block outside a funtion
+(e. g. records in Pascal and Modula-2)
+.TP
+.B tb \fRstr
+Regular expression for the start of TeX text within a comment
+.TP
+.B tc \fRstr
+Use the named entry as a continuation of this one
+.TP
+.B te \fRstr
+Regular expression for the end of TeX text within a comment
+.TP
+.B tl \fRbool
+Present means procedures are only defined at the top lexical level
+.TP
+.B vb \fRstr
+Regular expression for the start of typewriter text within a comment
+.TP
+.B ve \fRstr
+Regular expression for the end of typewriter text within a comment
+.TP
+.B zb \fRstr
+Regular expression for the start of program text within a comment
+.TP
+.B ze \fRstr
+Regular expression for the end of program text within a comment
+.PD
+.DT
+.SS "Regular Expressions"
+.B lgrindef
+uses regular expressions similar to those of
+.BR ex (1)
+and
+.BR lex (1).
+The characters `^',
+`$',
+`\^|',
+`:',
+and `\e'
+are reserved characters and must be
+`quoted' with a preceding \e if they
+are to be included as normal characters.
+The metasymbols and their meanings are:
+.IP $
+The end of a line
+.PD 0.2v
+.IP ^
+The beginning of a line
+.IP \ed
+A delimiter (space, tab, newline, start of line)
+.IP \ea
+Matches any string of symbols
+(like `.*' in lex)
+.IP \ep
+Matches any identifier.
+In a procedure definition
+(the `pb' capability)
+the string that matches this symbol is used as the procedure name.
+.IP (\^)
+Grouping
+.IP |
+Alternation
+.IP ?
+Last item is optional
+.IP \ee
+Preceding any string means that the string will not match an
+input string if the input string is preceded by an escape character (\e).
+This is typically used for languages (like C) that can include the
+string delimiter in a string by escaping it.
+.PD
+.PP
+Unlike other regular expressions in the system,
+these match words and not characters.
+Hence something like `(tramp\^|\^steamer)flies?'
+would match `tramp',
+`steamer',
+`trampflies',
+or `steamerflies'.
+Contrary to some forms of regular expressions,
+.B lgrindef
+alternation binds very tightly.
+Grouping parentheses are likely to be necessary in expressions
+involving alternation.
+.SS "Keyword List"
+The keyword list is just a list of keywords in the language separated
+by spaces.
+If the `oc' boolean is specified,
+indicating that upper and lower case are equivalent,
+then all the keywords should be specified in lower case.
+.SH EXAMPLE
+The following entry,
+which describes the C language,
+is typical of a language entry.
+.IP
+.ft B
+.nf
+C\^|\^the C programming language:\e
+ :pb=^\ed?*?\ed?\ep\ed?\(\ea?\):bb={:be=}:cb=/*:ce=*/:\e
+ :sb=":se=\ee":lb=':le=\ee':tl:\e
+ :zb=@:ze=@:tb=%%:te=%%:mb=%\e$:me=\e$%:vb=%\e\^|:ve=\e\^|%:\e
+ :kw=asm auto break case char continue default do double\e
+ else enum extern float for fortran goto if int long\e
+ register return short sizeof static struct switch typedef\e
+ union unsigned while #define #else #endif #if #ifdef\e
+ #ifndef #include #undef # define else endif if ifdef\e
+ ifndef include undef:
+.fi
+.ft
+.PP
+Note that the first field is just the language name
+(and any variants of it).
+Thus the C language could be specified to
+.BR lgrind (1)
+as `c' or `C', since case is not significant here.
+.SH FILES
+.ta \w'/usr/TeX/texmf/tex/latex/lgrind/lgrindef 'u
+\fB/usr/TeX/texmf/tex/latex/lgrind/lgrindef\fR file containing terminal descriptions
+.SH "SEE ALSO"
+.BR latex (1),
+.BR lgrind (1),
+.BR vgrindefs (5),
+For full documentation, refer to the package itself; it comes as a .dtx
+containing both the documentation and the LaTeX-files.
+
diff --git a/support/lgrind/source/lgrindef.c b/support/lgrind/source/lgrindef.c
new file mode 100644
index 0000000000..c096010a97
--- /dev/null
+++ b/support/lgrind/source/lgrindef.c
@@ -0,0 +1,330 @@
+#ifndef lint
+static char sccsid[] = "@(#)lgrindef.c 4.3 (Berkeley) 11/12/84";
+static char rcsid[] =
+ "$Id: lgrindef.c,v 1.3 1999/05/28 11:00:16 mike Exp $";
+#endif
+
+/* Copyright %%\copyright%% 1979 Regents of the University of California
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define MAXHOP 32 /* max number of %|tc=|% indirections */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "lgrindef.h"
+
+/*
+ * grindcap --- routines for dealing with the language definitions data base
+ * (code stolen almost totally from termcap)
+ *
+ * BUG: Should use a "last" pointer in @tbuf@, so that searching
+ * for capabilities alphabetically would not be a %$n^2/2$%
+ * process when large numbers of capabilities are given.
+ * Note: If we add a last pointer now we will screw up the
+ * %|tc|% capability. We really should compile termcap.
+ *
+ * Essentially all the work here is scanning and decoding escapes
+ * in string capabilities. We don't use stdio because the editor
+ * doesn't, and because living w/o it is not hard.
+ */
+
+static char *tbuf;
+static char *filename;
+static int hopcount = 0; /* detect infinite loops in termcap */
+
+static char *tskip(char *);
+static char *tdecode(char *, char **);
+
+/*
+ * @tnchktc@: check the last entry, see if it's %|tc=xxx|%. If so,
+ * recursively find %|xxx|% and append that entry (minus the names)
+ * to take the place of the %|tc=xxx|% entry. This allows termcap
+ * entries to say "like an HP2621 but doesn't turn on the labels".
+ * Note that this works because of the left to right scan.
+ */
+static int tnchktc(void)
+{
+ register char *p, *q;
+ char tcname[16]; /* name of similar terminal */
+ char tcbuf[BUFFERSIZE];
+ char *holdtbuf = tbuf;
+ int l;
+
+ p = tbuf + strlen(tbuf) - 2; /* before the last colon */
+ while (*--p != ':')
+ if (p < tbuf) {
+ /* Not very informative. Wrong BTW (for the configs). Shut up. */
+ /* write(2, "Bad lgrind entry\n", 18); */
+ return 0;
+ }
+ p++;
+ /* @p@ now points to beginning of last field */
+ if (p[0] != 't' || p[1] != 'c')
+ return 1;
+ strcpy(tcname,p+3);
+ q = tcname;
+ while (q && *q != ':')
+ q++;
+ *q = '\0';
+ if (++hopcount > MAXHOP) {
+ fprintf(stderr, "Infinite tc= loop\n");
+ return 0;
+ }
+ if (tgetent(tcbuf, tcname, filename) != 1)
+ return 0;
+ for (q = tcbuf; *q != ':'; q++)
+ ;
+ l = (int)(p - holdtbuf + strlen(q));
+ if (l > BUFFERSIZE) {
+ fprintf(stderr, "LGrind entry too long\n");
+ q[(int)(BUFFERSIZE - (p-tbuf))] = '\0';
+ }
+ strcpy(p, q+1);
+ tbuf = holdtbuf;
+ return 1;
+}
+
+
+/*
+ * @tnamatch@ deals with name matching. The first field of the termcap
+ * entry is a sequence of names separated by %|||%'s, so we compare
+ * against each such name. The normal %|:|% terminator after the last
+ * name (before the first field) stops us.
+ */
+static int tnamatch(char *np)
+{
+ register char *Np, *Bp;
+
+ Bp = tbuf;
+ if (*Bp == '#')
+ return 0;
+ for (;;) {
+ for (Np = np; *Np && toupper(*Bp) == toupper(*Np); Bp++, Np++)
+ continue;
+ if (*Np == '\0' && (*Bp == '|' || *Bp == ':' || *Bp == '\0'))
+ return 1;
+ while (*Bp != '\0' && *Bp != ':' && *Bp != '|')
+ Bp++;
+ if (*Bp == '\0' || *Bp == ':')
+ return 0;
+ Bp++;
+ }
+}
+
+
+/*
+ * Skip to the next field. Notice that this is very dumb, not
+ * knowing about %|\:|% escapes or any such. If necessary, %|:|%'s can
+ * be put into the termcap file in octal.
+ */
+static char *tskip(register char *bp)
+{
+ while (*bp && *bp != ':')
+ bp++;
+ if (*bp == ':')
+ bp++;
+ return bp;
+}
+
+
+/*
+ * Return the (numeric) option id.
+ * Numeric options look like
+ * %|li#80|%
+ * i.e. the option string is separated from the numeric value by
+ * a %|#|% character. If the option is not found we return %$-1$%.
+ * Note that we handle octal numbers beginning with %$0$%.
+ */
+int tgetnum(char *id)
+{
+ register int i, base;
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (*bp == '\0')
+ return -1;
+ if (*bp++ != id[0] || *bp == '\0' || *bp++ != id[1])
+ continue;
+ if (*bp == '@')
+ return -1;
+ if (*bp != '#')
+ continue;
+ bp++;
+ base = 10;
+ if (*bp == '0')
+ base = 8;
+ i = 0;
+ while (isdigit(*bp))
+ i *= base, i += *bp++ - '0';
+ return i;
+ }
+}
+
+
+
+/*
+ * Handle a flag option.
+ * Flag options are given "naked", i.e. followed by a %|:|% or the end
+ * of the buffer. Return 1 if we find the option, or 0 if it is
+ * not given.
+ */
+int tgetflag(char *id)
+{
+ register char *bp = tbuf;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return 0;
+ if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) {
+ if (!*bp || *bp == ':')
+ return 1;
+ else if (*bp == '@')
+ return 0;
+ }
+ }
+}
+
+
+/*
+ * Get a string valued option.
+ * These are given as
+ * %|cl=^Z|%
+ * Much decoding is done on the strings, and the strings are
+ * placed in area, which is a ref parameter which is updated.
+ * No checking on area overflow.
+ */
+char *tgetstr(char *id, char **area)
+{
+ register char *bp = tbuf, *i;
+ register int eq;
+
+ for (;;) {
+ bp = tskip(bp);
+ if (!*bp)
+ return 0;
+ eq=1;
+ for (i=id; *i;)
+ if (*i++!=*bp++) { eq=0; break; }
+ if (!eq)
+ continue;
+ if (*bp == '@')
+ return 0;
+ if (*bp != '=')
+ continue;
+ bp++;
+ return tdecode(bp, area);
+ }
+}
+
+
+/*
+ * @tdecode@ does the grunge work to decode the
+ * string capability escapes.
+ */
+static char *tdecode(register char *str, char **area)
+{
+ char *cp = *area, c;
+
+ while ((c = *str++) != 0) {
+ if (c == ':') {
+ if (*(cp-1) == '\\')
+ cp--;
+ else
+ break;
+ }
+ *cp++ = c;
+ }
+ *cp++ = '\0';
+ str = *area;
+ *area = cp;
+ return str;
+}
+
+/*
+ * Get an entry for terminal name in buffer @bp@,
+ * from the termcap file. Parse is very rudimentary;
+ * we just notice escaped newlines.
+ */
+int tgetent(char *bp, char *name, char *file)
+{
+ register char *cp;
+ register char c; /* 30.7.96 -- tryal [sic] */
+ register int i = 0, cnt = 0;
+ char ibuf[BUFFERSIZE];
+ FILE *tf;
+
+ tbuf = bp;
+ tf = 0;
+ filename = file;
+ tf = fopen(filename, "rt");
+ if (tf == NULL)
+ return -1;
+ for (;;) {
+ cp = bp;
+ for (;;) {
+ if (i == cnt) {
+ cnt = fread(ibuf, 1, BUFFERSIZE, tf);
+ if (cnt <= 0) {
+ fclose(tf);
+ return 0;
+ }
+ i = 0;
+ }
+ c = ibuf[i++];
+ if (c == '\n') {
+ if (cp > bp && cp[-1] == '\\'){
+ cp--;
+ continue;
+ }
+ break;
+ }
+ if (cp >= bp+BUFFERSIZE) {
+ fprintf(stderr, "LGrind entry too long\n");
+ break;
+ } else
+ *cp++ = c;
+ }
+ *cp = '\0';
+
+ /*
+ * The real work for the match.
+ */
+ if (tnamatch(name)) {
+ fclose(tf);
+ return tnchktc();
+ }
+ }
+}
diff --git a/support/lgrind/source/lgrindef.h b/support/lgrind/source/lgrindef.h
new file mode 100644
index 0000000000..f213d9b948
--- /dev/null
+++ b/support/lgrind/source/lgrindef.h
@@ -0,0 +1,12 @@
+/* sccsid[] = "@(#)lgrindef.h 3.6 (MPi) 3/8/98";
+ * rcsid[] =
+ * "$Id: lgrindef.h,v 1.3 1999/05/26 07:30:03 mike Exp $";
+ *
+ * Created 19 February 1996
+ */
+
+#define BUFFERSIZE 8192
+int tgetent(char *bp, char *name, char *file);
+int tgetnum(char *id);
+int tgetflag(char *id);
+char *tgetstr(char *id, char **area);
diff --git a/support/lgrind/source/lgutil.c b/support/lgrind/source/lgutil.c
new file mode 100644
index 0000000000..121ba366a0
--- /dev/null
+++ b/support/lgrind/source/lgutil.c
@@ -0,0 +1,323 @@
+#ifndef lint
+#ifdef standalone_lgutil
+static char sccsid[] = "@(#)lgutil.c 3.6 (MPi) 24/3/98";
+static char rcsid[] =
+ "$Id: lgutil.c,v 1.7 1999/12/18 21:54:29 mike Exp $";
+#endif /* standalone_lgutil */
+#endif
+
+/* lgutil.c
+ * Utility Functions for LGrind
+ * This file is @#include@d from lgrind.c (likely to change)
+ */
+
+/* Copyright %%\copyright%% 1998,1999 Michael Piefel
+ *
+ * This file is something like GPL, though LGrind is BSD.
+ * I don't want to become a lawyer.
+ */
+
+/*
+ * Internal_Help() --- show help
+ */
+
+void Internal_Help()
+{
+ printf("lgrind -- general purpose \"pretty printer\" for use with LaTeX.\n");
+ printf("usage: lgrind [options] <name> ...\n");
+ printf("-e process embedded text in a LaTeX file\n");
+ printf("-i format source code for inclusion in a LaTeX document.\n");
+ printf("-n don't boldface keywords.\n");
+ printf("-a don't treat @, etc. specially in LaTeX.\n");
+ printf("-c don't treat @, etc. specially in comments.\n");
+ printf("- take input from standard input.\n");
+ printf("-o <file> write to file (instead of standard output).\n");
+ printf("-t <width> change tab width (default 8).\n");
+ printf("-h <header> specifies text in header (default: none).\n");
+ printf("-v <varfile> take variable substitutions from file.\n");
+ printf("-d <deffile> use a different language definitions file, default:\
+\n \"%s\"\n", defsfile);
+ printf("-l<language> choose the language to use.\n");
+ printf("-s show a list of currently known languages.\n\n");
+ printf("If neither -e nor -i are specified, a complete LaTeX-file is produced.\n\n");
+ printf("Direct comments and questions to lgrind@gmx.net\n");
+}
+
+
+typedef struct langRec {
+ char *name;
+ char *alternatives;
+ struct langRec *next; } langRec;
+
+void AddToLList(char *line, langRec **into, int *chainLength)
+{
+ char *token, *item, *alts;
+
+ if (*line!='#' && *line!='\n')
+ {
+ item=strdup(line);
+ if ((token=strtok(item, "|:\\\n")) == NULL) return;
+ (**into).next=(langRec*)malloc(sizeof(langRec));
+ *into=(**into).next;
+ (**into).name=strdup(token);
+ (*chainLength)++;
+ if ((token=strtok(NULL, "|:\\\n")) == NULL)
+ {
+ (**into).alternatives="\0";
+ return;
+ }
+ (**into).alternatives=strdup(token);
+ while ((token=strtok(NULL, "|:\\\n")) != NULL)
+ {
+ alts=(**into).alternatives;
+ (**into).alternatives=(char*)malloc(
+ strlen((**into).alternatives)+strlen(token)+1);
+ /* This is extremely poor style and dangerous. I leave memory
+ * allocated here because after invocation of this help facility
+ * the program will stop anyway. In this context it is safe. */
+ strcpy((**into).alternatives, alts);
+ strcat((**into).alternatives, ", ");
+ strcat((**into).alternatives, token);
+ }
+ }
+}
+
+void Internal_Help_Language_List()
+{
+ FILE *tf;
+ int check, i, llch;
+ langRec *lch, *rch, *currlch;
+ /* @lch2@ was originally "language chain", but I guess
+ it's "left" as well */
+
+ printf("When specifying a language case is insignificant. You can use the\n");
+ printf("name of the language, or, where available, one of the synonyms in\n");
+ printf("parantheses. Thus the following are legal and mark Tcl/Tk, Pascal\n");
+ printf("and Fortran input, respectively:\n");
+ printf(" lgrind -ltcl/tk ...\n");
+ printf(" lgrind -lpaSCAL ...\n");
+ printf(" lgrind -lf ...\n");
+ printf("The list of languages currently available in your lgrindef file:\n");
+ tf = fopen(defsfile, "rt");
+ if (tf == NULL)
+ {
+ fprintf(stderr, "cannot find lgrindef file `%s'\n", defsfile);
+ return;
+ }
+
+ llch=0;
+ currlch=lch=(langRec*)malloc(sizeof(langRec));
+ (*currlch).name="";
+ *config='\n';
+ do {
+ check=0;
+ if (*config=='\n' || config[strlen(config)-2]!='\\')
+ check=1;
+ if (fgets(config, BUFFERSIZE, tf)==NULL) break;
+ if (check!=0) AddToLList(config, &currlch, &llch);
+ } while (strcmp((*currlch).name, "EndOfLanguageDefinitions")!=0);
+ rch=lch;
+ for (check=0; check<llch/2; check++)
+ rch=(*rch).next;
+ for (check=0; check<llch/2; check++)
+ {
+ lch=(*lch).next;
+ rch=(*rch).next;
+ printf(" %s", (*lch).name);
+ if (*((*lch).alternatives)) printf(" (%s)", (*lch).alternatives);
+ else printf(" ");
+ for (i=strlen((*lch).name)+strlen((*lch).alternatives);
+ i<30; i++) putchar(' ');
+ if (rch!=currlch)
+ {
+ printf("%s", (*rch).name);
+ if (*((*rch).alternatives)) printf(" (%s)", (*rch).alternatives);
+ }
+ printf("\n");
+ }
+}
+
+
+/*
+ * Redefine Chartab from lgrindef file
+ */
+void parsechartab(void)
+{
+ char *i=buf, *j=chartab, c;
+ int charnum=0;
+
+ while (*i++!=':') {}
+ while ((c=*i++)!='\0') {
+ if (c==':') continue;
+ charnum=(c>='0' && c<='9') ? (int)c-48 : tolower(c)-87;
+ charnum=charnum << 4; c=*i++;
+ charnum+=(c>='0' && c<='9') ? (int)c-48 : tolower(c)-87;
+ i++;
+
+ printtab[charnum]=j;
+ while (*i!=':')
+ if (*i=='\\') {
+ switch (*++i) {
+ case ':': *j++=':'; break;
+ case '\\': *j++='\\'; break;
+ }; i++;
+ } else *j++=*i++;
+ *j++='\0';
+ }
+
+}
+
+/*
+ * Parses the %|lgrindef|% file for a preamble
+ */
+void parsepreamble(char *destination)
+{
+ char *i=buf, *j=destination;
+
+ while (*i++!=':') ;
+ while (*i) {
+ if (*i=='\\') {
+ switch (*++i) {
+ case 'n': *j++='\n'; break;
+ case 't': *j++='\t'; break;
+ case 'f': *j++='\f'; break;
+ case '\\': *j++='\\'; break;
+ default: fprintf(stderr, "Bad preamble entry: incorrect '\\'\n");
+ }; i++;
+ } else *j++=*i++;
+ *j='\0';
+ }
+}
+
+/*
+ * Sets the default preambles
+ */
+void setpreambles(void)
+{
+ strcpy(preamble,
+"\\documentclass[a4paper]{article}\n\
+\\usepackage[procnames,noindent]{lgrind}\n\
+\\usepackage{fancyhdr}\n\
+\\pagestyle{fancy}\n\
+\\begin{document}\n");
+ strcpy(postamble, "\\end{document}\n");
+ strcpy(preamble2,
+"\\lhead[\\fancyplain{}{\\bf\\thepage}]\
+{\\fancyplain{}{\\bf \f}}\n\
+\\rhead[\\fancyplain{}{\\bf \f}]\
+{\\fancyplain{}{\\bf\\thepage}}\n\
+\\cfoot{}\n");
+ strcpy(config, "");
+}
+
+/*
+ * prints a preamble, substituting %|\f|% with the current
+ * file's name (sorry, no more form feeds)
+ */
+void printpreamble(char *string)
+{
+ char *i;
+ while (*string)
+ if (*string=='\f')
+ { i=fname-1;
+ while (*(++i)) outchar(*i);
+ string++;
+ }
+ else putchar(*string++);
+}
+
+/*
+ * try to create an executable file to store the new lgrindef-file
+ */
+void writeDefsfileInExe(char *progname, char *newdefsfile)
+{
+ char *buffer, *i;
+ FILE *progfile, *newfile;
+ long pos=0;
+ int ret;
+
+ buffer = (char*) malloc(30000);
+ /* So small? Why in chunks? Well, it's gotta run on machines with
+ only limited access to their resources (you know, the IBM PC) */
+ progfile=fopen(progname, "rb");
+ newfile=fopen("lgrind.new", "wb");
+
+ if (buffer && progfile && newfile)
+ {
+ fread(buffer, 1, 200, progfile);
+ do {
+ ret=fread(buffer+200, 1, 29500, progfile);
+ for(i=buffer; i<buffer+ret; i++)
+ if (*i=='D' &&
+ *(i+1)=='e' &&
+ *(i+2)=='F' &&
+ *(i+3)=='s' &&
+ *(i+4)=='B' &&
+ *(i+5)=='u' &&
+ *(i+6)=='F' &&
+ strcmp(defsfile, i+7)==0) {
+ memcpy(i+7, newdefsfile, strlen(newdefsfile)+1);
+ }
+ fwrite(buffer, 1, ret==29500 ? ret : ret+200, newfile);
+ memcpy(buffer, buffer+29500, 200);
+ pos+=29500;
+ } while (ret==29500);
+ fclose(progfile);
+ fclose(newfile);
+ }
+ free(buffer);
+}
+
+/*
+ * Reads a variable substitution table from a file
+ */
+varsubst *parsevartab(char* fname)
+{
+ FILE *f = fopen(fname, "rt");
+ char linebuf[201], *cp;
+ varsubst *varsubsts=NULL, *substitem, *substlistpos;
+
+ if (f==NULL) return;
+ while (!feof(f))
+ {
+ fscanf(f, "%200[^\n]", linebuf);
+ fscanf(f, "\n");
+ cp=strchr(linebuf, '=');
+ if (cp==NULL) continue;
+ *cp++='\0';
+ substitem=(varsubst*)malloc(sizeof(varsubst));
+ substitem->var=strdup(linebuf);
+ substitem->subst=strdup(cp);
+ substitem->next=NULL;
+ if (varsubsts==NULL)
+ {
+ varsubsts=substitem;
+ substlistpos=substitem;
+ } else {
+ substlistpos->next=substitem;
+ substlistpos=substitem;
+ }
+ }
+ fclose(f);
+ return varsubsts;
+}
+
+/*
+ * Replaces a variable by alternate representation
+ */
+int substvarname(char **ident, int i)
+{
+ varsubst *substlistpos = varsubstlist;
+
+ while (substlistpos!=NULL)
+ {
+ if (re_strncmp(*ident, substlistpos->var, i)==0)
+ {
+ *ident+=i; /* skip i characters in input */
+ printf("%s", substlistpos->subst);
+ return 0;
+ }
+ substlistpos=substlistpos->next;
+ }
+ return i;
+}
diff --git a/support/lgrind/source/makefile.dos b/support/lgrind/source/makefile.dos
new file mode 100644
index 0000000000..540e1337e7
--- /dev/null
+++ b/support/lgrind/source/makefile.dos
@@ -0,0 +1,34 @@
+# Makefile for lgrind, a LaTeX prettyprinter
+
+# $Id: makefile.dos,v 1.1.1.1 1999/05/13 13:02:55 mike Exp $
+
+# You will possibly want to change this
+DEFSFILE=$(EMTEXDIR:\\=\\\\)\\\\texinput\\\\lgrind\\\\lgrindef
+# if you encounter problems with the last line, enter the path
+# directly; if all else fails, modify lgrind.c
+
+CC=bcc
+SOURCES=lgrind.c regexp.c regexp.h lgrindef.c lgrindef.h retest.c v2lg.c
+TEXFILES=lgrind.dtx lgrind.sty lgrind.ins
+CMDS=lgrind.exe
+OBJS=lgrind.obj regexp.obj retest.obj lgrindef.obj v2lg.obj
+
+HELPOPTION=-?
+# popen? pclose? This is DOS!
+#CFLAGS=-v -mc -Dpopen=fopen -Dpclose=fclose
+CFLAGS=-O2 -mc -Dpopen=fopen -Dpclose=fclose
+# Well, the DEFSFILE is still (semi-)fixed in the EXE...
+
+.c.obj:
+ $(CC) $(CFLAGS) -DDEFSFILE="$(DEFSFILE)" -DHELPOPTION="$(HELPOPTION)" -c $<
+
+all: $(CMDS)
+
+lgrind.exe: lgrind.obj lgrindef.obj regexp.obj
+ $(CC) $(CFLAGS) lgrind.obj lgrindef.obj regexp.obj
+
+v2lg: v2lg.c
+ $(CC) $(CFLAGS) v2lg
+
+retest: retest.c regexp.c
+ $(CC) $(CFLAGS) retest regexp
diff --git a/support/lgrind/source/makefile.emx b/support/lgrind/source/makefile.emx
new file mode 100644
index 0000000000..3cbdbbb381
--- /dev/null
+++ b/support/lgrind/source/makefile.emx
@@ -0,0 +1,55 @@
+# Makefile for lgrind, a LaTeX prettyprinter
+# for EMX+GCC with DMAKE, bound DOS-extender
+
+# $Id: makefile.emx,v 1.1.1.1 1999/05/13 13:02:55 mike Exp $
+
+# You will almost certainly want to change these
+DESTDIR=c:\\emtex\\bin
+DEFSFILE=c:\\emtex\\texinput\\lgrind\\lgrindef
+TEXINPUTS=c:\\emtex\\texinput\\lgrind
+
+SOURCES=lgrind.c regexp.c regexp.h lgrindef.c lgrindef.h retest.c v2lg.c
+TEXFILES=lgrind.doc lgrind.sty lgrind.ins
+MANPAGES=lgrind.1 lgrindef.5
+EXAMPLES=doc-lgrind.lg
+CMDS=lgrind.exe
+OBJS=lgrind.o regexp.o retest.o lgrindef.o v2lg.o
+
+CC=gcc
+HELPOPTION=-?
+CFLAGS=-O2 -DOS2
+# CFLAGS=-g
+# CFLAGS=-O2 -Dpopen=fopen -Dpclose=fclose
+# There are operating systems and compilers without these...
+
+.SUFFIXES: .o .c
+
+.c.o:
+ $(CC) -c $(CFLAGS) $<
+
+all: $(CMDS)
+
+lgrind.exe: lgrind.o lgrindef.o regexp.o
+ $(CC) $(CFLAGS) -o lgrind.exe lgrind.o lgrindef.o regexp.o -s
+# alternatively you can bind the DOS-extender permanently:
+# $(CC) $(CFLAGS) -o lgrind lgrind.o lgrindef.o regexp.o -s
+# emxbind c:\emx\bin\emx.exe lgrind lgrind.exe -p
+
+lgrind.o: lgrind.c
+ $(CC) $(CFLAGS) -DDEFSFILE=\"${DEFSFILE}\" -DHELPOPTION=\"${HELPOPTION}\"\
+ -c lgrind.c
+
+v2lg.exe: v2lg.o
+ $(CC) $(CFLAGS) -o v2lg.exe v2lg.o
+
+retest.exe: retest.o regexp.o
+ $(CC) $(CFLAGS) -o retest.exe retest.o regexp.o
+
+install: all
+ -copy lgrind.exe $(DESTDIR)\\lgrind.exe
+ -copy lgrindef $(DEFSFILE)
+ -copy lgrind.dtx $(TEXINPUTS)\\lgrind.dtx
+ -copy lgrind.sty $(TEXINPUTS)\\lgrind.sty
+
+clean:
+ -del $(CMDS) $(OBJS) retest.exe v2lg.exe
diff --git a/support/lgrind/source/regexp.c b/support/lgrind/source/regexp.c
new file mode 100644
index 0000000000..87b19433ce
--- /dev/null
+++ b/support/lgrind/source/regexp.c
@@ -0,0 +1,648 @@
+#ifndef lint
+static char sccsid[] = "@(#)regexp.c 1.2 (LBL) 12/4/85";
+static char rcsid[] =
+ "$Id: regexp.c,v 1.3 1999/05/27 16:17:43 mike Exp $";
+#endif
+
+/*
+ * Copyright %%\copyright%% 1980 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Regular expression matching routines for lgrind/tgrind/tfontedpr.
+ *
+ * These routines were written by Dave Presotto (I think) for vgrind.
+ * Minor mods & attempts to improve performance by Van Jacobson
+ * (van@@lbl-rtsg) and Chris Torek (chris@@maryland).
+ *
+ * Modifications.
+ * --------------
+ * Sep 91 George V Reilly Fixed up some bogus uses of @NIL@ and @NULL@.
+ * 30 Mar 85 Van & Chris Changed @expmatch()@ to return pointer to
+ * start of what was matched in addition to
+ * pointer to match end. Several changes to
+ * improve performance (too numerous to mention).
+ * 11 Dec 84 Dave Presotto Written.
+ */
+
+
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <string.h>
+#include "regexp.h"
+
+#define makelower(c) (isupper((c)) ? tolower((c)) : (c))
+
+extern char *l_id;
+static void expconv(void); /* forward declaration */
+
+int (*re_strncmp)(const char *, const char *, size_t);
+ /* function used by @expmatch()@ to compare
+ * strings. The caller should make it point to
+ * @strncmp()@ if case is significant &
+ * @lc_strncmp()@ otherwise.
+ */
+
+
+/* @lc_strncmp()@ --- like @strncmp()@ except that we convert the
+ * first string to lower case before comparing.
+ */
+int lc_strncmp(register const char *s1, register const char *s2, register size_t len)
+{
+ while (len-- > 0)
+ if (*s2 - makelower(*s1))
+ return 1;
+ else
+ s2++, s1++;
+
+ return 0;
+}
+
+
+/* The following routine converts an irregular expression to
+ * internal format.
+ *
+ * Either meta symbols (%|\a|%, %|\d|%, or %|\p|%) or character strings
+ * or operations (alternation or parenthesizing) can be specified.
+ * Each starts with a descriptor byte. The descriptor byte
+ * has @STR@ set for strings, @META@ set for meta symbols,
+ * and @OPER@ set for operations. The descriptor byte can also have
+ * the @OPT@ bit set if the object defined is optional. Also @ALT@
+ * can be set to indicate an alternation.
+ *
+ * For metasymbols, the byte following the descriptor byte identities
+ * the meta symbol (containing an ASCII @'a'@, @'d'@, @'p'@, @'|'@,
+ * or @'('@). For strings, the byte after the descriptor is a
+ * character count for the string:
+ *@
+ * meta symbols := descriptor
+ * symbol
+ *
+ * strings := descriptor
+ * character count
+ * the string
+ *
+ * operations := descriptor
+ * symbol
+ * character count@
+ */
+
+
+/*
+ * handy macros for accessing parts of match blocks
+ */
+#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */
+#define MNEXT(A) (A+2) /* character following a metasymbol block */
+
+#define OSYM(A) (*(A+1)) /* symbol in an operation block */
+#define OCNT(A) (*(A+2)) /* character count */
+#define ONEXT(A) (A+3) /* next character after the operation */
+#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */
+
+#define SCNT(A) (*(A+1)) /* byte count of a string */
+#define SSTR(A) (A+2) /* address of the string */
+#define SNEXT(A) (A+2+*(A+1)) /* character following the string */
+
+
+/*
+ * bit flags in the descriptor
+ */
+#define OPT 1
+#define STR 2
+#define META 4
+#define ALT 8
+#define OPER 16
+
+char *ure; /* pointer current position in unconverted exp */
+char *ccre; /* pointer to current position in converted exp */
+
+
+
+/*
+ * Convert an irregular expression to the internal form
+ */
+char *convexp(char *re)
+/* re unconverted irregular expression */
+{
+ register char *cre; /* pointer to converted regular expression */
+
+ /* allocate room for the converted expression */
+ if (re == NULL)
+ return NULL;
+ if (*re == '\0')
+ return NULL;
+ cre = (char*)malloc(4 * strlen(re) + 3);
+ ccre = cre;
+ ure = re;
+
+ /* start the conversion with a %|\a|% */
+ *cre = META | OPT;
+ MSYM(cre) = 'a';
+ ccre = MNEXT(cre);
+
+ /* start the conversion (it's recursive) */
+ expconv();
+ *ccre = 0;
+ return cre;
+}
+
+
+/*
+ * Actually do the conversion
+ */
+static void expconv(void)
+{
+ register char *cs; /* pointer to current symbol in converted exp */
+ register char c; /* character being processed */
+ register char *acs; /* pointer to last alternate */
+ register int temp;
+
+ /* let the conversion begin */
+ acs = NULL;
+ cs = NULL;
+ while (*ure != '\0') {
+ switch (c = *ure++) {
+
+ case '\\':
+ switch (c = *ure++) {
+
+ /* escaped characters are just characters */
+ default:
+ if (cs == NULL || (*cs & STR) == 0) {
+ cs = ccre;
+ *cs = STR;
+ SCNT(cs) = 1;
+ ccre += 2;
+ } else
+ SCNT(cs)++;
+ *ccre++ = c;
+ break;
+
+ /* normal(?) metacharacters */
+ case 'a':
+ case 'd':
+ case 'e':
+ case 'p':
+ if (acs != NULL && acs != cs) {
+ do {
+ temp = OCNT(acs);
+ OCNT(acs) = ccre - acs;
+ acs -= temp;
+ } while (temp != 0);
+ acs = NULL;
+ }
+ cs = ccre;
+ *cs = META;
+ MSYM(cs) = c;
+ ccre = MNEXT(cs);
+ break;
+ }
+ break;
+
+ /* just put the symbol in */
+ case '^':
+ case '$':
+ if (acs != NULL && acs != cs) {
+ do {
+ temp = OCNT(acs);
+ OCNT(acs) = ccre - acs;
+ acs -= temp;
+ } while (temp != 0);
+ acs = NULL;
+ }
+ cs = ccre;
+ *cs = META;
+ MSYM(cs) = c;
+ ccre = MNEXT(cs);
+ break;
+
+ /* mark the last match sequence as optional */
+ case '?':
+ if (cs)
+ *cs = *cs | OPT;
+ break;
+
+ /* recurse and define a subexpression */
+ case '(':
+ if (acs != NULL && acs != cs) {
+ do {
+ temp = OCNT(acs);
+ OCNT(acs) = ccre - acs;
+ acs -= temp;
+ } while (temp != 0);
+ acs = NULL;
+ }
+ cs = ccre;
+ *cs = OPER;
+ OSYM(cs) = '(';
+ ccre = ONEXT(cs);
+ expconv();
+ OCNT(cs) = ccre - cs; /* offset to next symbol */
+ break;
+
+ /* return from a recursion */
+ case ')':
+ if (acs != NULL) {
+ do {
+ temp = OCNT(acs);
+ OCNT(acs) = ccre - acs;
+ acs -= temp;
+ } while (temp != 0);
+ acs = NULL;
+ }
+ cs = ccre;
+ *cs = META;
+ MSYM(cs) = c;
+ ccre = MNEXT(cs);
+ return;
+
+ /* Mark the last match sequence as having an alternate. */
+ /* The third byte will contain an offset to jump over the */
+ /* alternate match in case the first did not fail */
+ case '|':
+ if (acs != NULL && acs != cs)
+ OCNT(ccre) = ccre - acs; /* make a back pointer */
+ else
+ OCNT(ccre) = 0;
+ *cs |= ALT;
+ cs = ccre;
+ *cs = OPER;
+ OSYM(cs) = '|';
+ ccre = ONEXT(cs);
+ acs = cs; /* remember that the pointer is to be filled */
+ break;
+
+ /* if it's not a metasymbol, just build a character string */
+ default:
+ if (cs == NULL || (*cs & STR) == 0) {
+ cs = ccre;
+ *cs = STR;
+ SCNT(cs) = 1;
+ ccre = SSTR(cs);
+ } else
+ SCNT(cs)++;
+ *ccre++ = c;
+ break;
+ }
+ }
+ if (acs != NULL) {
+ do {
+ temp = OCNT(acs);
+ OCNT(acs) = ccre - acs;
+ acs -= temp;
+ } while (temp != 0);
+ acs = NULL;
+ }
+ return;
+} /* end of @expconv()@ */
+
+
+/*
+ * The following routine recognises an irregular expression
+ * with the following special characters:
+ *
+ * %|\?|% means last match was optional
+ * %|\a|% matches any number of characters
+ * %|\d|% matches any number of spaces and tabs
+ * %|\p|% matches any number of alphanumeric characters.
+ * The characters matched will be copied into
+ * the area pointed to by @mstring@.
+ * %|\||% alternation
+ * %|\( \)|% grouping used mostly for alternation and
+ * optionality
+ *
+ * The irregular expression must be translated to internal form
+ * prior to calling this routine
+ *
+ * The value returned is the pointer to the last character matched.
+ * If @strtptr@ is non-@NULL@, a pointer to the start of the string matched
+ * (excluding %|\a|% matches) will be returned at @*strtptr@.
+ * If @mstring@ is non-@NULL@, the string matched by a %|\p|% will be copied
+ * into @mstring@.
+ */
+
+boolean _escaped; /* true if we are currently @_escaped@ */
+char *_sstart; /* start of string. Set in @putScp()@. */
+
+
+char *expmatch(
+ register char *s, /* string to check for a match in */
+ register char *re, /* a converted irregular expression */
+ char **strtptr, /* where to put ptr to start of match */
+ char *mstring) /* where to put whatever matches a %|\p|% */
+{
+ register char *cs; /* the current symbol */
+ register char *ptr, *s1; /* temporary pointer */
+ register char c; /* temporary */
+ boolean matched; /* a temporary @boolean@ */
+
+ /* initial conditions */
+ if (strtptr)
+ *strtptr = '\0';
+ if (re == NULL)
+ return NULL;
+ cs = re;
+ matched = FALSE;
+
+ /* loop till expression string is exhausted (or at least pretty tired) */
+ while (*cs) {
+ switch (*cs & (OPER | STR | META)) {
+
+ /* try to match a string */
+ case STR:
+ matched = !((*re_strncmp)(s, SSTR(cs), SCNT(cs)));
+ if (matched) {
+
+ /* hoorah: it matches */
+ s += SCNT(cs);
+ cs = SNEXT(cs);
+ } else if (*cs & ALT) {
+
+ /* alternation: skip to next expression */
+ cs = SNEXT(cs);
+ } else if (*cs & OPT) {
+
+ /* the match is optional */
+ cs = SNEXT(cs);
+ matched = 1; /* indicate a successful match */
+ } else {
+
+ /* no match: error return */
+ return NULL;
+ }
+ break;
+
+ /* an operator: do something fancy */
+ case OPER:
+ switch (OSYM(cs)) {
+
+ /* this is an alternation */
+ case '|':
+ if (matched)
+
+ /* last thing in the alternation was a match: skip ahead */
+ cs = OPTR(cs);
+ else
+
+ /* no match: keep trying */
+ cs = ONEXT(cs);
+ break;
+
+ /* this is a grouping: recurse */
+ case '(':
+ ptr = expmatch(s, ONEXT(cs), strtptr, mstring);
+ if (ptr != NULL) {
+
+ /* the subexpression matched */
+ matched = 1;
+ s = ptr;
+ } else if (*cs & ALT) {
+
+ /* alternation: skip to next expression */
+ matched = 0;
+ } else if (*cs & OPT) {
+
+ /* the match is optional */
+ matched = 1; /* indicate a successful match */
+ } else {
+
+ /* no match: error return */
+ return NULL;
+ }
+ cs = OPTR(cs);
+ break;
+ }
+ break;
+
+ /* try to match a metasymbol */
+ case META:
+ switch (MSYM(cs)) {
+
+ /* try to match anything and remember what was matched */
+ case 'p':
+ /*
+ * This is really the same as trying the match the
+ * remaining parts of the expression to any subset
+ * of the string.
+ */
+ s1 = s;
+ do {
+ ptr = expmatch(s1, MNEXT(cs), strtptr, mstring);
+ if (ptr != NULL && s1 != s) {
+
+ /* we have a match: remember the match */
+ if (mstring) {
+ strncpy(mstring, s, (size_t)(s1 - s));
+ mstring[(int)(s1 - s)] = '\0';
+ }
+ return ptr;
+
+ } else if (ptr != NULL && (*cs & OPT)) {
+
+ /* %|\p|% was optional, so no match is ok */
+ return ptr;
+
+ } else if (ptr != NULL) {
+
+ /* not optional and we still matched */
+ return NULL;
+ }
+ if (!isalnum(*s1) && !strchr(l_id, *s1))
+ return NULL;
+ if (*s1 == '\\')
+ _escaped = _escaped ? FALSE : TRUE;
+ else
+ _escaped = FALSE;
+ } while (*s1++);
+ return NULL;
+
+ /* try to match anything */
+ case 'a':
+ /*
+ * This is really the same as trying the match the
+ * remaining parts of the expression to any subset
+ * of the string.
+ */
+ s1 = s;
+ do {
+ /*
+ * Hack for an important special case: if the next thing
+ * in the pattern is a string, just gobble characters until
+ * we find something that matches that string (this saves
+ * the cost of a recursive call on @expmatch()@ while scanning
+ * for the start of comments or strings). Since many
+ * patterns end with a string, we also treat that as a
+ * special case.
+ */
+ if(*(ptr = MNEXT(cs)) == STR) {
+ c = *SSTR(ptr);
+ while(*s1 && *s1 != c)
+ s1++;
+
+ if (*s1 == 0)
+ return NULL;
+
+ if (SNEXT(ptr) == 0 && (s1 != s || *cs & OPT)) {
+ /* next item is a string, it's the last item and
+ * the %|\a|% match is ok --- just loop to try & match
+ * the string.
+ */
+ if (strtptr)
+ *strtptr = s1;
+
+ cs = ptr;
+ s = s1;
+ break;
+ }
+ }
+ ptr = expmatch(s1, MNEXT(cs), strtptr, mstring);
+ if (ptr != NULL && (s1 != s || *cs & OPT)) {
+
+ /* we have a match */
+ if (strtptr)
+ *strtptr = s1;
+
+ return ptr;
+
+ } else if (ptr != NULL) {
+
+ /* not optional and we still matched */
+ return NULL;
+ }
+ if (*s1 == '\\')
+ _escaped = _escaped ? FALSE : TRUE;
+ else
+ _escaped = FALSE;
+ } while (*s1++);
+ return NULL;
+
+ /* fail if we are currently @_escaped@ */
+ case 'e':
+ if (_escaped)
+ return NULL;
+ cs = MNEXT(cs);
+ break;
+
+ /* match any number of tabs and spaces */
+ case 'd':
+ ptr = s;
+ while (*s == ' ' || *s == '\t')
+ s++;
+
+ if (s != ptr || s == _sstart) {
+
+ /* match: be happy */
+ matched = 1;
+ cs = MNEXT(cs);
+ } else if (*s == '\n' || *s == '\0') {
+
+ /* match: be happy */
+ matched = 1;
+ cs = MNEXT(cs);
+ } else if (*cs & ALT) {
+
+ /* try the next part */
+ matched = 0;
+ cs = MNEXT(cs);
+ } else if (*cs & OPT) {
+
+ /* doesn't matter */
+ matched = 1;
+ cs = MNEXT(cs);
+ } else
+
+ /* no match: error return */
+ return NULL;
+
+ break;
+
+ /* check for end of line */
+ case '$':
+ if (*s == '\0' || *s == '\n') {
+
+ /* match: be happy */
+ /* s++; was here
+ * removed; now $ is left in stream to be matched again, which
+ * is not bad (EOL can end several things at once. Also it
+ * leaves things like CE on the same line.
+ */
+ matched = 1;
+ cs = MNEXT(cs);
+ } else if (*cs & ALT) {
+
+ /* try the next part */
+ matched = 0;
+ cs = MNEXT(cs);
+ } else if (*cs & OPT) {
+
+ /* doesn't matter */
+ matched = 1;
+ cs = MNEXT(cs);
+ } else
+
+ /* no match: error return */
+ return NULL;
+ break;
+
+ /* check for start of line */
+ case '^':
+ if (s == _sstart) {
+
+ /* match: be happy */
+ matched = 1;
+ cs = MNEXT(cs);
+ } else if (*cs & ALT) {
+
+ /* try the next part */
+ matched = 0;
+ cs = MNEXT(cs);
+ } else if (*cs & OPT) {
+
+ /* doesn't matter */
+ matched = 1;
+ cs = MNEXT(cs);
+ } else
+
+ /* no match: error return */
+ return NULL;
+ break;
+
+ /* end of a subexpression: return success */
+ case ')':
+ return s;
+ }
+ break;
+ }
+ }
+ return s;
+}
diff --git a/support/lgrind/source/regexp.h b/support/lgrind/source/regexp.h
new file mode 100644
index 0000000000..048a2840e5
--- /dev/null
+++ b/support/lgrind/source/regexp.h
@@ -0,0 +1,13 @@
+/* sccsid[] = "@(#)regexp.h 3.6 (MPi) 3/8/98";
+ * rcsid[] =
+ * "$Id: regexp.h,v 1.3 1999/05/26 07:30:03 mike Exp $";
+ *
+ * Created 19 February 1996
+ */
+
+typedef int boolean;
+#define TRUE 1
+#define FALSE 0
+int lc_strncmp(const char *s1, const char *s2, size_t len);
+char *convexp(char *re);
+char *expmatch(register char *s, register char *re, char **strtptr, char *mstring);
diff --git a/support/lgrind/source/retest.c b/support/lgrind/source/retest.c
new file mode 100644
index 0000000000..9ff3572532
--- /dev/null
+++ b/support/lgrind/source/retest.c
@@ -0,0 +1,75 @@
+/* Test program for the regular expression routines */
+
+#ifndef lint
+static char sccsid[] = "@(#)retest.c 1.1 (LBL) 29/3/85";
+static char rcsid[] =
+ "$Id: retest.c,v 1.3 1999/05/26 07:30:03 mike Exp $";
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+
+int l_onecase = 0;
+char *_start;
+char *_escaped;
+char *convexp();
+char *expmatch();
+char *l_id="_";
+
+
+
+main()
+{
+ char reg[132];
+ char *ireg;
+ char str[132];
+ char *match;
+ char matstr[132];
+ char c;
+
+ for (;;) {
+ printf ("\nexpr: ");
+ scanf ("%s", reg);
+ ireg = convexp(reg);
+ match = ireg;
+ while(*match) {
+ switch (*match) {
+
+ case '\\':
+ case '(':
+ case ')':
+ case '|':
+ printf ("%c", *match);
+ break;
+
+ default:
+ if (isalnum(*match))
+ printf("%c", *match);
+ else
+ printf ("<%03o>", *match);
+ break;
+ }
+ match++;
+ }
+ printf("\n");
+ getchar();
+ for (;;) {
+ printf ("string: ");
+ match = str;
+ while ((c = getchar()) != '\n')
+ *match++ = c;
+ *match = 0;
+ if (str[0] == '#')
+ break;
+ matstr[0] = 0;
+ _start = str;
+ _escaped = 0;
+ match = expmatch (str, ireg, matstr);
+ if (match == 0)
+ printf ("FAILED\n");
+ else
+ printf ("match\nmatstr = %s\n", matstr);
+ }
+
+ }
+}
diff --git a/support/lgrind/source/v2lg.c b/support/lgrind/source/v2lg.c
new file mode 100644
index 0000000000..5aa5df206f
--- /dev/null
+++ b/support/lgrind/source/v2lg.c
@@ -0,0 +1,78 @@
+/*
+ * Filter a LaTeX file into an lgrind file. Convert
+ * \begin{verbatim}-\end{verbatim} pairs into %[ - %] pairs. Tabify
+ * the former verbatim environments. Convert \verb|stuff| into @stuff@.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)v2lg.c 1.1 20/3/85";
+static char rcsid[] =
+ "$Id: v2lg.c,v 1.2 1999/05/25 17:01:36 mike Exp $";
+#endif
+
+
+#include <stdio.h>
+#include <string.h>
+
+#define FALSE 0
+#define TRUE 1
+
+#define STREQ(s,t) ((*(s) == *(t)) && (!*(s) || !strcmp((s),(t))))
+
+
+int main(int argc, char **argv)
+{
+ int in_verbatim = FALSE, col, start_col;
+ char in[256], out[256], *ic, *oc, *verb, delim;
+
+ while (fgets(in, sizeof(in), stdin) != NULL) {
+ if (in_verbatim) {
+ if (STREQ(in, "\\end{verbatim}\n")) {
+ fputs("%]\n", stdout);
+ in_verbatim = FALSE;
+ continue;
+ }
+ for (col = 0, ic = in, oc = out; *ic != '\n'; ) {
+ if (*ic != ' ' && *ic != '\t') {
+ *oc++ = *ic++; col++;
+ } else { /* \t == ' ' in a verbatim environment */
+ start_col = col;
+ while (*ic == ' ' || *ic == '\t') {
+ if (((++col) & 7) == 0) {
+ *oc++ = '\t'; start_col = col;
+ }
+ ic++;
+ }
+ if ((col & 7) != 0)
+ for ( ; start_col < col; start_col++)
+ *oc++ = ' ';
+ }
+ }
+ *oc++ = '\n'; *oc++ = '\0';
+ fputs(out, stdout);
+ continue;
+ }
+ if (STREQ(in, "\\begin{verbatim}\n")) {
+ fputs("%[\n", stdout);
+ in_verbatim = TRUE;
+ continue;
+ }
+ for (ic = in; (verb = strstr(ic, "\\verb")) != NULL; ) {
+ for ( ; ic < verb; ic++)
+ putchar(*ic);
+ ic += 5; /* Skip over \verb */
+ if (*ic == '*') /* \verb* => funny-looking spaces */
+ ic++;
+ delim = *ic++; /* the delimiter char */
+ putchar('@');
+ while (*ic != delim) {
+ putchar(*ic); ic++;
+ }
+ ic++; /* Skip the other delimiter */
+ putchar('@');
+ }
+ fputs(ic, stdout);
+ }
+ return 0;
+}
+