#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 #include #include #include #include #include /* One of the following two (depending on your system) */ #include /* #include */ #include "lgrindef.h" #include "regexp.h" #ifndef vms # include # include #else # include # include #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 \ 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 # include 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|% 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 */