home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Dream 45
/
Amiga_Dream_45.iso
/
Amiga
/
Magazine
/
Dossier-LaTeX
/
lgrind-amiga.lha
/
lgrind
/
src
/
lgrind.c
next >
Wrap
C/C++ Source or Header
|
1996-08-04
|
48KB
|
1,641 lines
/* lgrind.c, a %%\LaTeX%% version of tgrind, which is a %%\TeX%% version
* of vgrind. Used to `grind nice program listings'.
*/
#ifndef lint
static char sccsid[] = "@(#)@(#)tfontedpr.c 1.3 (LBL) 4/12/85";
static char Version[] =
"$Id: lgrind.c,v 1.4 91/10/01 00:36:11 gvr Exp $";
#endif
/* lgrind --- general purpose "pretty printer" for use with %%\LaTeX%%.
*
* Copyright %%\copyright%% 1985 by Van Jacobson, Lawrence Berkeley Laboratory
* This program may be freely used and copied but may not be sold
* without the author's 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)
*
* 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. On VMS, we
* don't use a surrounding shell script, so the
* options are a bit different --- added %|-i|% to
* make a file to be %|\input|% in a %%\LaTeX%%
* environment. Changed some of the characters
* around --- e.g., we always take %|*|% in math
* mode (to make it centered) so we have to
* write %|*|% as %|\*|%. Etc.
* 14 Jan 88 JSL %|-e|% option for embedded code.
* 22 Jan 88 JSL Bugfix --- program could overrun @pstack@
* because of an incorrect limit test.
* Sep 91 George V Reilly Reformated and cleaned up code, including
* naughtiness with @NULL@. Added %|@|%,
* %|%%|%, %|%$|%, and %%\tt \%|%% features.
* Also the %|%<|%, %|%!|%, and %|%#|% features.
* Oct94 Matthias Eckermann (%|ud311aa@sunmail.lrz-muenchen.de|%)
* fixed a little bug, added: Internal_Help,
* command-line-param: %|-?|%
* Sep95 Michael Piefel Modified for %%\LaTeXe%%
*/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include "regexp.h"
#include "lgrindefs.h"
#include "lgrind.h"
boolean (*isproc)(unsigned char *s);
/* 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%% */
#if nospaceincomment
boolean linehead; /* at beginning of line or after whitespace */
#endif
int lastout; /* (extended) last character to outchar */
int comtype; /* type of comment */
int psptr; /* the stack index of the current procedure */
unsigned 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 */
unsigned char *fname = ""; /* File being read */
int lineno; /* Line number in that file */
unsigned char pname[BUFFERSIZE+1]; /* Current procedure name */
/* The language specific globals */
unsigned char *defsfile = DEFSFILE; /* name of language definitions file */
unsigned char language[PNAMELEN]="c"; /* the language indicator */
unsigned char the_buf[BUFFERSIZE+1]; /* general purpose buffer */
unsigned char *buf = the_buf + 1; /* @buf-1@ must be valid */
unsigned char strings[2*BUFFERSIZE]; /* store the keywords */
unsigned char defs[2 * BUFFERSIZE]; /* language definitions from lgrindefs */
unsigned char preamble[BUFFERSIZE/4]; /* first preamble */
unsigned char preambl2[BUFFERSIZE/4]; /* file preamble */
unsigned char config[BUFFERSIZE/4]; /* redefinitions within lgrind-environment */
unsigned char chartab[BUFFERSIZE/4]; /* buffer for chartab modifications */
unsigned char *l_keywds[BUFFERSIZE/2];/* keyword table address */
unsigned char *l_prcbeg; /* regular expr for procedure begin */
unsigned char *l_noproc; /* regexp for lines with NO procedure begin */
unsigned char *l_combeg; /* regexp introducing a comment */
unsigned char *l_comend; /* regexp ending a comment */
unsigned char *l_acmbeg; /* regexp introducing a comment */
unsigned char *l_acmend; /* regexp ending a comment */
unsigned char *l_blkbeg; /* regexp beginning of a block */
unsigned char *l_blkend; /* regexp ending a block */
unsigned char *l_strbeg; /* regexp starting string constant */
unsigned char *l_strend; /* regexp ending string constant */
unsigned char *l_chrbeg; /* regexp starting character constant */
unsigned char *l_chrend; /* regexp ending character constant */
unsigned char *l_cdebeg; /* regexp starting prog text within comment */
unsigned char s_cdebeg[PNAMELEN+1]; /* actual string corresponding to @l_cdebeg@ */
unsigned char *l_cdeend; /* regexp ending prog text within comment */
unsigned char *l_texbeg; /* regexp starting %%\TeX%% text in comment */
unsigned char *l_texend; /* regexp ending %%\TeX%% text in comment */
unsigned char *l_txmbeg; /* regexp starting %%\TeX%% math in comment */
unsigned char *l_txmend; /* regexp ending %%\TeX%% math in comment */
unsigned char *l_tt_beg; /* regexp starting verbatim text in comment */
unsigned char *l_tt_end; /* regexp ending typewriter text in comment */
unsigned char *l_at; /* regexp for %|@|% in %%\LaTeX%% text */
unsigned char *l_tt; /* regexp for %|||% in %%\LaTeX%% text */
unsigned char *l_pc; /* regexp for %|%|% in %%\LaTeX%% text */
unsigned char *l_id; /* string containing valid identifier chars */
unsigned char *l_record; /* start of lexical block outside functions */
unsigned 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 embed = FALSE; /* -e seen --- do embedded code */
boolean code = TRUE; /* Looking at code */
int main(int argc, char *argv[])
{
struct stat stbuf;
/* unsigned char *p;*/
boolean hseen = FALSE; /* -h seen */
unsigned char *hstring; /* header string to use */
boolean iseen = FALSE; /* -i seen */
int files_done = 0;
argc = getredirection(argc, argv);
argc--, argv++;
do {
register unsigned char *cp;
/* register int i;*/
if (argc > 0) {
/* Help-facility */
if (!strcmp(argv[0], "-?") || !strcmp(argv[0], "-help")) {
Internal_Help();
return OKEXIT;
}
if (!strcmp(argv[0], "-h")) {
hseen = TRUE;
if (argc == 1) {
hstring = "";
argc = 0;
goto rest;
}
hstring = argv[0];
argc--, argv++;
argc--, argv++;
if (argc > 0)
continue;
goto rest;
}
/* take input from the standard place */
if (!strcmp(argv[0], "-")) {
argc = 0;
goto rest;
}
/* 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")) {
use_tt = TRUE;
argc--, argv++;
continue;
}
/* specify the language */
if (!strncmp(argv[0], "-l", 2)) {
strcpy(language, argv[0]+2);
argc--, argv++;
continue;
}
/* specify the language description file */
if (!strncmp(argv[0], "-d", 2)) {
defsfile = argv[1];
argc--, argv++;
argc--, argv++;
continue;
}
/* open the file for input */
if (freopen(argv[0], "r", stdin) == NULL) {
perror(argv[0]);
exit(BADEXIT);
}
fname = argv[0];
lineno = 0;
argc--, argv++;
}
rest:
setpreambles();
/* get config data from %|lgrindefs|% */
if (tgetent(buf, "firstpreamble", defsfile)>0)
parsepreamble(preamble);
if (tgetent(buf, "filepreamble", defsfile)>0)
parsepreamble(preambl2);
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(preambl2);
if (files_done == 0) {
printf("\\begin{document}\n");
}
printf("\\begin{lgrind}\n");
}
printpreamble(config);
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");
if (hseen) {
printf("\\Head{");
putstr(hstring);
printf("}\n");
}
setlang();
/* initialize the program */
incomm = instr = inchr = _escaped = FALSE;
incode = latexcode = latex_tt = NOTCODE;
do_at = do_tt = TRUE;
blklevel = 0;
reclevel = 0;
for (psptr = 0; psptr < PSMAX; psptr++) {
pstack[psptr][0] = '\0';
plstack[psptr] = 0;
}
psptr = -1;
fstat(fileno(stdin), &stbuf);
cp = ctime(&stbuf.st_mtime);
cp[10] = cp[16] = cp[24] = '\0';
if (!embed) {
printf("\\File{");
putstr(fname);
printf("},{%s},{%s %s}\n", cp+11, cp+4, cp+20);
}
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) {
printf("\\end{document}\n");
}
return OKEXIT;
}
/*
* Internal_Help() --- show help
*/
void Internal_Help(void) {
printf("lgrind -- general purpose \"pretty printer\" for use with LaTeX.\n"
"usage: lgrind [-?] [options] <name> ...\n"
"-e process embedded text in a LaTeX file\n"
"-i format source code for inclusion in a LaTeX document.\n"
"- take input from standard input.\n"
"-n don't boldface keywords.\n"
"-h<header> specifies text in header (default: none).\n"
"-d<deffile> use another language definitions file, default:\n\t '%s'\n"
"-l<language> choose the language to us. Currently known are\n"
" C (-lc) (default), C++ (-lc++ or -lCC), Pascal (-lp),\n"
" Modula-2 (-lm2), Fortran (-lf), RATFOR (-lr),\n"
" Prolog (-lprolog), ISP (-lisp), LDL (-lldl),\n"
" Linda (-llinda), Russell (-lrussell), MODEL (-lm),\n"
" Perl (-lperl), MLisp (-lml), Icon (-lI),\n"
" PostScript (-lps), TeX (-ltex), IDL (-lidl),\n"
" Yacc (-ly), Bourne Shell(-lsh), CSH (-lcsh),\n"
" assembler (-lasm), 68000 assembler (-la68),\n"
" asm68 (-lasm68), VMS assembler (-lvmsasm).\n"
" ada (-lada), Java (-ljava).\n"
" agda (-lagda ).\n"
"If neither -e nor -i are specified, a complete LaTeX-file is produced.\n",DEFSFILE);
}
/*
* @readfile()@ --- read and process a file
*/
void
readfile(FILE *fp)
{
register unsigned char *cp;
boolean LGinline=FALSE; /* Doing %( -- %) */
unsigned char term; /* ']' or ')' */
unsigned char *atptr; /* start of %|@|% within %%\LaTeX%% text */
unsigned char *atendptr; /* end of %|@|% within %%\LaTeX%% text */
unsigned char *ttptr; /* start of %|||% within %%\LaTeX%% text */
unsigned char *ttendptr; /* end of %|||% within %%\LaTeX%% text */
unsigned char *pcptr; /* start of %|%|% within %%\LaTeX%% text */
unsigned char *pcendptr; /* end of %|%|% within %%\LaTeX%% text */
unsigned char temp[BUFFERSIZE];
unsigned char fnamebak[100];
int linenobak;
while (fgets(buf, BUFFERSIZE, fp) != NULL) {
cp = &buf[strlen(buf)-1];
if (*cp != '\n') {*(++cp) = '\n'; *(++cp) = '\0'; }
lineno++;
cp = buf;
#if nospaceincomment
linehead = TRUE;
#endif
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'@ */
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;
unsigned 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"); */
printf("\\begin{lgrind}\n");
embed = FALSE;
linenobak=lineno; strcpy(fnamebak, fname);
lineno=0; strcpy(fname, temp);
readfile(fp);
lineno=linenobak; strcpy(fname, fnamebak);
embed = TRUE;
/* printf("\\endlgrinde\\LGend\n"); */
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 */
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;
} else if (do_at &&
(atendptr = expmatch(buf, l_at, &atptr,
(unsigned char *) NULL)) != NULL) {
/* This is a gross hack. Fix it, dammit */
restart_at:
pcendptr = expmatch(cp, l_pc, &pcptr, (unsigned char *) NULL);
if (pcptr == NULL || atptr < pcptr) {
putVcp(cp, atptr-1);
printf("\\LGinlinetrue\\LGbegin\\lgrinde");
cp = atendptr;
atendptr = expmatch(cp, l_at, &atptr, (unsigned char *) NULL);
if (atptr != NULL && (pcptr == NULL || atptr < pcptr)) {
strncpy(temp, cp, atptr-cp);
temp[atptr-cp] = '\0';
cp = atendptr;
printf("\\L{\\LB{");
putScp(temp);
printf("}}\\endlgrinde\\LGend{}");
atendptr = expmatch(cp, l_at, &atptr, (unsigned char *) NULL);
if (atptr != NULL)
goto restart_at;
else {
fputs(cp, stdout); continue;
}
} else {
/* multiline */
}
} else {
fputs(buf, stdout);
continue;
}
} else if (do_tt &&
(ttendptr = expmatch(buf, l_tt, &ttptr,
(unsigned char *) NULL)) != NULL) {
pcendptr = expmatch(buf, l_pc, &pcptr, (unsigned char *) NULL);
if (pcptr == NULL || ttptr < pcptr) {
putVcp(buf, ttptr-1);
} else {
fputs(buf, stdout); continue;
}
} else {
fputs(buf, 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\n");
}
continue;
} else if (buf[1] == term) {
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;
printf("\\L{\\LB{");
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)
{
unsigned char *p, *cp;
int i;
/*
* get the language definition from the defs file
*/
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 lgrindefs file `%s'\n", defsfile);
exit(BADEXIT);
}
p = strings;
if (tgetstr("kw", &p) == NULL)
nokeyw = TRUE;
else {
unsigned 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 = (unsigned char*)malloc(strlen(cp));
strcpy(l_id, cp);
}
else l_id = "_";
l_tt = convexp("\\|");
l_at = convexp("@");
l_pc = convexp("%");
l_escape = '\\';
/* abuse of l_onecase */
l_onecase = tgetflag("cf");
isproc = l_onecase ? isprocC : isprocNorm;
l_onecase = tgetflag("oc");
if(l_onecase) re_strncmp = lc_strncmp;
else re_strncmp = strncmp;
/* re_strncmp = (l_onecase ? lc_strncmp : strncmp);*/
l_toplex = tgetflag("tl");
}
/*
extern int (*re_strncmp)();
int l_onecase;
int lc_strncmp(const char *s1, const char *s2, int len)
int strncmp(const char *s1, const char *s2, size_t n);
*/
/*
* Write out a formatted line of program text
*/
void
putScp(unsigned char *os)
{
register unsigned char *s = os; /* pointer to unmatched string */
/* register unsigned char *s1; /* temp. string */
unsigned char *comptr; /* start of a comment delimiter */
unsigned char *comendptr; /* end of a comment delimiter */
unsigned char *acmptr; /* start of an alt. comment delimiter */
unsigned char *acmendptr; /* end of an alt. comment delimiter */
unsigned char *strptr; /* start of a string delimiter */
unsigned char *strendptr; /* end of a string delimiter */
unsigned char *chrptr; /* start of a char. const delimiter */
unsigned char *chrendptr; /* end of a unsigned char. const delimiter */
unsigned char *cdeptr; /* start of prog text delim within a comment */
unsigned char *cdeendptr; /* end of prog text delim within a comment */
unsigned char *cdbptr; /* start of prog text delim within a comment */
unsigned char *cdbendptr; /* end of prog text delim within a comment */
unsigned char *texptr; /* start of %%\TeX%% text delim within a comment */
unsigned char *texendptr; /* end of %%\TeX%% text delim within a comment */
unsigned char *txmptr; /* start of %%\TeX%% math delim within a comment */
unsigned char *txmendptr; /* end of %%\TeX%% math delim within a comment */
unsigned char *tt_ptr; /* start of typewriter delim within a comment */
unsigned char *tt_endptr; /* end of typewriter delim within a comment */
unsigned char *blksptr; /* start of a lexical block start */
unsigned char *blksendptr; /* end of a lexical block start */
unsigned char *recsptr; /* start of a lexical block outside functions start */
unsigned char *recsendptr; /* end of a lexical block outside functions start */
unsigned char *blkeptr; /* start of a lexical block end */
unsigned char *blkeendptr; /* end of a lexical block end */
_sstart = os; /* remember the start for @expmatch()@ */
_escaped = FALSE;
if (nokeyw || incomm || instr)
goto skip;
if ((*isproc)(s) && reclevel == 0) {
printf("\\Proc{");
putstr(pname);
printf("}");
if (!embed && psptr < PSMAX-1) {
++psptr;
strncpy(pstack[psptr], pname, PNAMELEN);
pstack[psptr][PNAMELEN] = '\0';
plstack[psptr] = blklevel;
}
}
skip:
do {
/* check for string, comment, blockstart, etc */
if (!incomm && !instr && !inchr) {
blkeendptr = expmatch(s, l_blkend, &blkeptr, (unsigned char *) NULL);
blksendptr = expmatch(s, l_blkbeg, &blksptr, (unsigned char *) NULL);
recsendptr = expmatch(s, l_record, &recsptr, (unsigned char *) NULL);
comendptr = expmatch(s, l_combeg, &comptr, (unsigned char *) NULL);
acmendptr = expmatch(s, l_acmbeg, &acmptr, (unsigned char *) NULL);
strendptr = expmatch(s, l_strbeg, &strptr, (unsigned char *) NULL);
chrendptr = expmatch(s, l_chrbeg, &chrptr, (unsigned char *) NULL);
/* check for end of program text in comment */
if (incode != NOTCODE) {
cdeendptr = expmatch(s, l_cdeend, &cdeptr, (unsigned 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, (unsigned 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, (unsigned 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, FALSE);
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, FALSE);
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;
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;
blklevel++;
continue;
}
/* start of a lexical block outside functions */
if (recsptr != NULL) {
putKcp(s, recsendptr - 1, FALSE);
s = recsendptr;
blklevel++;
reclevel++;
continue;
}
/* check for end of comment */
} else if (incomm) {
cdeendptr = expmatch(s, l_cdebeg, &cdeptr, (unsigned char *) NULL);
texendptr = expmatch(s, l_texbeg, &texptr, (unsigned char *) NULL);
txmendptr = expmatch(s, l_txmbeg, &txmptr, (unsigned char *) NULL);
tt_endptr = expmatch(s, l_tt_beg, &tt_ptr, (unsigned 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, (unsigned 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, (unsigned char *) NULL)) != NULL) {
printf("\\texttt{");
putKcp(s, tt_ptr-1, TRUE);
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, (unsigned 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,
(unsigned char **) NULL, (unsigned 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, (unsigned char **) NULL, (unsigned 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, (unsigned char **) NULL, (unsigned 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 lgrind.doc
* 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))
/*
* Write out a portion of the line
*/
void
putKcp(unsigned char *start, unsigned char *end, boolean nix)
/*unsigned char *start; Start of string to write */
/*unsigned char *end; End of string to write */
/*boolean nix; Don't look for identifiers, numbers */
{
int i, c;
while (start <= end) {
c = *start++;
/*
* take care of nice tab stops
*/
if (c == '\t') {
while (start <= end && *start == '\t')
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 (isdigit(c) || c == '$') {
printf("\\N{");
do {
if (c == 'l')
printf("$\\ell$");
else
outchar(c);
c = *start++;
} while (isalnum(c) || c == '.');
putchar('}');
start--;
continue;
} else if (c == '#' || islidchr(c)) {
i = getid(--start);
if (i > 0)
printf("\\K{");
else {
printf("\\V{");
i = -i;
}
while (--i >= 0) {
c = *start++;
outchar(c);
}
putchar('}');
continue;
}
}
outchar(c);
}
}
/*
* Write out a portion of the line verbatim
*/
void
putVcp(unsigned char *start, unsigned char *end)
/*unsigned char *start; /* Start of string to write */
/*unsigned char *end; /* End of string to write */
{
for ( ; start <= end; start++) {
putchar(*start);
}
}
/*
* Calculate the width of a string, including tabs
*/
int
width(register unsigned char *s, register unsigned char *os)
{
register int i = 0, c;
while (s < os) {
c = *s++;
if (c == '\t') {
i = (i + 8) &~ 7;
continue;
}
if (c < ' ')
i += 2;
else
i++;
}
return i;
}
/*
* Output a string, escaping special characters
*/
void
putstr(register unsigned 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.
*/
unsigned 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", "\\#", "\\$", "\\%", "\\&",
"$\\hspace{1pt}\\acute{\\null}\\hspace{2pt}$",
/* "\\4", major update :) */
"(", ")", "\\*", "+", ",", "\\-", ".", "\\1",
"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", "\\\"A", "\\AA ", "\306", "\307",
"\310", "\311", "\312", "\313", "\314", "\315", "\316", "\317",
"\320", "\321", "\322", "\323", "\324", "\325", "\\\"O", "\327",
"\330", "\331", "\332", "\333", "\334", "\335", "\336", "\337",
"\340", "\341", "\342", "\343", "\\\"a", "\\aa ", "\346", "\347",
"\350", "\351", "\352", "\353", "\354", "\355", "\356", "\357",
"\360", "\361", "\362", "\363", "\364", "\365", "\\\"o", "\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 nospaceincomment
if ((linehead || !incomm) && c == ' ') {
putchar('_');
goto fin;
}
linehead = FALSE;
#else
if (c == ' ') {
putchar('_');
goto fin;
}
#endif
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;
}
/*
* Redefine Chartab from lgrindefs file
*/
void
parsechartab(void)
{
unsigned char *i=buf, *j=chartab, c;
int charnum=0;
while (*i++!=':') {}
while (c=*i++) {
if (c==':') continue;
charnum=(c>='0' && c<='9') ? (int)c-48 : tolower(c)-87;
charnum=charnum << 4; c=*i++;
charnum+=(c>='0' && c<='9') ? (int)c-48 : tolower(c)-87;
i++;
printtab[charnum]=j;
while (*i!=':')
if (*i=='\\') {
switch (*++i) {
case ':': *j++=':'; break;
case '\\': *j++='\\'; break;
}; i++;
} else *j++=*i++;
*j++='\0';
}
}
/*
* Look for a procedure beginning on this line
*/
boolean
isprocNorm(unsigned char *s)
{
pname[0] = '\0';
if ((!l_toplex || blklevel == 0)
&& expmatch(s, l_prcbeg, (unsigned char **) NULL, pname) != NULL
&& expmatch(s, l_noproc, (unsigned char **) NULL, (unsigned char *) NULL) == NULL)
return TRUE;
return FALSE;
}
/* Special version of the above for C functions */
boolean
isprocC(unsigned char *s)
{
unsigned char cheat[BUFFERSIZE];
unsigned 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);
}
/*
* 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(unsigned char *s)
{
unsigned char **ss = l_keywds;
int i = 1;
unsigned char *cp = s;
int firstc = *s;
while (++cp, isidchr(*cp))
i++;
if (nokeyw)
return -i;
while (cp = *ss++) {
if (!l_onecase && firstc != *cp)
continue;
if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i]))
return i;
}
return -i;
}
/*
* @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@ */
getredirection(int argc, char *argv[])
/*
* Dummy routine.
*/
{
return (argv[0], argc);
}
#endif /* @!vms@ */
/*
* Parses the %|lgrindefs|% file for a preamble
*/
void
parsepreamble(unsigned char *destination)
{
unsigned char *i=buf, *j=destination;
while (*i++!=':') {}
while (*i) {
if (*i=='\\') {
switch (*++i) {
case 'n': *j++='\n'; break;
case 't': *j++='\t'; break;
case 'f': *j++='\f'; break;
case '\\': *j++='\\'; break;
default: fprintf(stderr, "Bad preamble entry: incorrect '\\'");
}; i++;
} else *j++=*i++;
}
}
/*
* Sets the default preambles
*/
void
setpreambles(void)
{
strcpy(preamble,
"\\documentclass[10pt,a4paper]{article}\n\
\\usepackage[procnames,noindent]{lgrind}\n\
\\usepackage{fancyhead}\n\
\\pagestyle{fancy}\n");
strcpy(preambl2,
"\\lhead[\\fancyplain{}{\\bf\\thepage}]\
{\\fancyplain{}{\\bf \f}}\n\
\\rhead[\\fancyplain{}{\\bf \f}]\
{\\fancyplain{}{\\bf\\thepage}}\n\
\\cfoot{}\n");
strcpy(config,"");
}
/*
* prints a preamble, substituting %|\f|% with the current
* file's name (sorry, no more form feeds)
*/
void
printpreamble(unsigned char *string)
{
int i;
while (*string) {
if(*string=='\f') {
for(i=0;i<strlen(fname);i++) {
if(fname[i]=='_') putchar('\\');
putchar(fname[i]);
}
string++;
}
else putchar((*(string++)));
}
/*
This is the old while loop. It messed up if filenames
contained '_' characters.
while (*string) {
(*string=='\f') ?
(printf("%s", fname), string++)
: putchar(*(string++));
};
*/
}