diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/lgrind/source/lgrind.c |
Initial commit
Diffstat (limited to 'support/lgrind/source/lgrind.c')
-rw-r--r-- | support/lgrind/source/lgrind.c | 1769 |
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 */ + |