summaryrefslogtreecommitdiff
path: root/support/lgrind/source/lgrind.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/lgrind/source/lgrind.c
Initial commit
Diffstat (limited to 'support/lgrind/source/lgrind.c')
-rw-r--r--support/lgrind/source/lgrind.c1769
1 files changed, 1769 insertions, 0 deletions
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 */
+