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/tgrind |
Initial commit
Diffstat (limited to 'support/tgrind')
-rw-r--r-- | support/tgrind/README | 36 | ||||
-rw-r--r-- | support/tgrind/makefile | 30 | ||||
-rw-r--r-- | support/tgrind/regexp.c | 595 | ||||
-rw-r--r-- | support/tgrind/retest.c | 66 | ||||
-rw-r--r-- | support/tgrind/sysv/makefile | 30 | ||||
-rw-r--r-- | support/tgrind/sysv/regexp.c | 595 | ||||
-rw-r--r-- | support/tgrind/sysv/retest.c | 69 | ||||
-rw-r--r-- | support/tgrind/sysv/tfontedpr.c | 620 | ||||
-rw-r--r-- | support/tgrind/sysv/tgrind.sh | 99 | ||||
-rw-r--r-- | support/tgrind/sysv/tgrindmac.tex | 139 | ||||
-rw-r--r-- | support/tgrind/tfontedpr.c | 620 | ||||
-rw-r--r-- | support/tgrind/tgrind.1 | 103 | ||||
-rw-r--r-- | support/tgrind/tgrind.sh | 101 | ||||
-rw-r--r-- | support/tgrind/tgrindmac.tex | 139 | ||||
-rw-r--r-- | support/tgrind/vgrindefs.c | 297 | ||||
-rw-r--r-- | support/tgrind/vgrindefs.src | 128 |
16 files changed, 3667 insertions, 0 deletions
diff --git a/support/tgrind/README b/support/tgrind/README new file mode 100644 index 0000000000..14672b05f2 --- /dev/null +++ b/support/tgrind/README @@ -0,0 +1,36 @@ +This is a pretty printer similar to 4bsd's "vgrind" except it uses +TeX instead of troff. It was written by Van Jacobson of Lawrence +Berkeley Laboratory (van@lbl-rtsg.arpa). + +To install it: + + (1) Decide where you want to put the program (I suggest /usr/local). + + (2) Move the entire contents of either ./BSD or ./SYS_V into this + working directory, or wherever you want to work on the + compilation. + + (3) Edit "Makefile": + set DESTDIR to the program destination directory. + (the tgrind shell script, tgrind.sh, will go here. Also + the formatting program, tfontedpr, will go into the "lib" + subdirectory of DESTDIR, e.g., /usr/local/lib). + set TEXINPUTS to the pathname of your TeX "\input" directory + (the TeX macro file "tgrindmac.tex" will get put here). + set DEFSFILE to the pathname of your vgrind language definitions + file. If you're running 4.2bsd, this is "/usr/lib/vgrindefs". + Both vgrind & tgrind can use the same file. A vgrindefs file + that has been updated considerably since the 4.2 distribution + is included in this directory ("vgrindefs.src"). + + (4) Edit "tgrind.sh": + Put the pathname for tfontedpr in the "set b=" statement. + Put the pathname for TeX in the "set tex=" statement. + Look at the comments about output routing & do whatever you + think is appropriate. + + (5) Type "make install". + +Good luck. Please let me know of any problems, enhancements, suggestions, etc. + + -Van diff --git a/support/tgrind/makefile b/support/tgrind/makefile new file mode 100644 index 0000000000..cff6b98697 --- /dev/null +++ b/support/tgrind/makefile @@ -0,0 +1,30 @@ +# @(#)Makefile 4.1 (Berkeley) 10/19/82 +# +DESTDIR=/usr/local +DEFSFILE=/usr/local/lib/vgrindefs +TEXINPUTS=/usr/lib/tex/macros + +CFLAGS=-O -g -DDEBUG +SOURCES=tfontedpr.c vgrindefs.c regexp.c retest.c +CMDS=tfontedpr retest +OBJS=retest.o regexp.o tfontedpr.o vgrindefs.o + +all: $(CMDS) + +tfontedpr: tfontedpr.o vgrindefs.o regexp.o + cc ${CFLAGS} -o tfontedpr tfontedpr.o vgrindefs.o regexp.o + +tfontedpr.o: tfontedpr.c + cc ${CFLAGS} -DDEFSFILE=\"${DEFSFILE}\" -c tfontedpr.c + +retest: retest.o regexp.o + cc ${CFLAGS} -o retest retest.o regexp.o + +install: all + install -s tfontedpr ${DESTDIR}/lib/tfontedpr + install -c tgrind.sh ${DESTDIR}/bin/tgrind + install -c tgrindmac.tex ${TEXINPUTS}/tgrindmac.tex + install -c vgrindefs.src ${DEFSFILE} + +clean: + rm -f ${CMDS} ${OBJS} diff --git a/support/tgrind/regexp.c b/support/tgrind/regexp.c new file mode 100644 index 0000000000..8738273f38 --- /dev/null +++ b/support/tgrind/regexp.c @@ -0,0 +1,595 @@ +#ifndef lint +static char *sccsid="@(#)regexp.c 1.2 (LBL) 4/12/85"; +#endif +/* + * regular expression matching routines for tgrind/tfontedpr. + * + * These routines were written by Dave Presotto (I think) for vgrind. + * Minor mods & attempts to improve performance by Van Jacobson (van@lbl-rtsg) + * and Chris Torek (chris@maryland). + * + * Modifications. + * -------------- + * 30Mar85 Van & Chris Changed expmatch to return pointer to start of what + * was matched in addition to pointer to match end. + * Several changes to improve performance (too numerous + * to mention). + * 11Dec84 Dave Presotto Written. + */ + +#include <ctype.h> + +typedef int boolean; +#define TRUE 1 +#define FALSE 0 +#define NIL 0 + +#define makelower(c) (isupper((c)) ? tolower((c)) : (c)) + +int (*re_strncmp)(); /* function used by expmatch to compare + * strings. The caller should make it point to + * strncmp if case is significant & + * lc_strncmp otherwise. + */ + +/* lc_strncmp - like strncmp except that we convert the + * first string to lower case before comparing. + */ + +lc_strncmp(s1, s2, len) + register char *s1,*s2; + register int len; +{ + while (len-- > 0) + if (*s2 - makelower(*s1)) + return(1); + else + s2++, s1++; + + return(0); +} + +/* The following routine converts an irregular expression to + * internal format. + * + * Either meta symbols (\a \d or \p) or character strings or + * operations ( alternation or perenthesizing ) can be + * specified. Each starts with a descriptor byte. The descriptor + * byte has STR set for strings, META set for meta symbols + * and OPER set for operations. + * The descriptor byte can also have the OPT bit set if the object + * defined is optional. Also ALT can be set to indicate an alternation. + * + * For metasymbols the byte following the descriptor byte identities + * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For + * strings the byte after the descriptor is a character count for + * the string: + * + * meta symbols := descriptor + * symbol + * + * strings := descriptor + * character count + * the string + * + * operatins := descriptor + * symbol + * character count + */ + +/* + * handy macros for accessing parts of match blocks + */ +#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ +#define MNEXT(A) (A+2) /* character following a metasymbol block */ + +#define OSYM(A) (*(A+1)) /* symbol in an operation block */ +#define OCNT(A) (*(A+2)) /* character count */ +#define ONEXT(A) (A+3) /* next character after the operation */ +#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ + +#define SCNT(A) (*(A+1)) /* byte count of a string */ +#define SSTR(A) (A+2) /* address of the string */ +#define SNEXT(A) (A+2+*(A+1)) /* character following the string */ + +/* + * bit flags in the descriptor + */ +#define OPT 1 +#define STR 2 +#define META 4 +#define ALT 8 +#define OPER 16 + +char *ure; /* pointer current position in unconverted exp */ +char *ccre; /* pointer to current position in converted exp*/ +char *malloc(); + +char * +convexp(re) + char *re; /* unconverted irregular expression */ +{ + register char *cre; /* pointer to converted regular expression */ + + /* allocate room for the converted expression */ + if (re == NIL) + return (NIL); + if (*re == '\0') + return (NIL); + cre = malloc (4 * strlen(re) + 3); + ccre = cre; + ure = re; + + /* start the conversion with a \a */ + *cre = META | OPT; + MSYM(cre) = 'a'; + ccre = MNEXT(cre); + + /* start the conversion (its recursive) */ + expconv (); + *ccre = 0; + return (cre); +} + +expconv() +{ + register char *cs; /* pointer to current symbol in converted exp */ + register char c; /* character being processed */ + register char *acs; /* pinter to last alternate */ + register int temp; + + /* let the conversion begin */ + acs = NIL; + cs = NIL; + while (*ure != NIL) { + switch (c = *ure++) { + + case '\\': + switch (c = *ure++) { + + /* escaped characters are just characters */ + default: + if (cs == NIL || (*cs & STR) == 0) { + cs = ccre; + *cs = STR; + SCNT(cs) = 1; + ccre += 2; + } else + SCNT(cs)++; + *ccre++ = c; + break; + + /* normal(?) metacharacters */ + case 'a': + case 'd': + case 'e': + case 'p': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + break; + } + break; + + /* just put the symbol in */ + case '^': + case '$': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + break; + + /* mark the last match sequence as optional */ + case '?': + if (cs) + *cs = *cs | OPT; + break; + + /* recurse and define a subexpression */ + case '(': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = OPER; + OSYM(cs) = '('; + ccre = ONEXT(cs); + expconv (); + OCNT(cs) = ccre - cs; /* offset to next symbol */ + break; + + /* return from a recursion */ + case ')': + if (acs != NIL) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + return; + + /* mark the last match sequence as having an alternate */ + /* the third byte will contain an offset to jump over the */ + /* alternate match in case the first did not fail */ + case '|': + if (acs != NIL && acs != cs) + OCNT(ccre) = ccre - acs; /* make a back pointer */ + else + OCNT(ccre) = 0; + *cs |= ALT; + cs = ccre; + *cs = OPER; + OSYM(cs) = '|'; + ccre = ONEXT(cs); + acs = cs; /* remember that the pointer is to be filles */ + break; + + /* if its not a metasymbol just build a scharacter string */ + default: + if (cs == NIL || (*cs & STR) == 0) { + cs = ccre; + *cs = STR; + SCNT(cs) = 1; + ccre = SSTR(cs); + } else + SCNT(cs)++; + *ccre++ = c; + break; + } + } + if (acs != NIL) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + return; +} +/* end of convertre */ + + +/* + * The following routine recognises an irregular expresion + * with the following special characters: + * + * \? - means last match was optional + * \a - matches any number of characters + * \d - matches any number of spaces and tabs + * \p - matches any number of alphanumeric + * characters. The + * characters matched will be copied into + * the area pointed to by 'name'. + * \| - alternation + * \( \) - grouping used mostly for alternation and + * optionality + * + * The irregular expression must be translated to internal form + * prior to calling this routine + * + * The value returned is the pointer to the last character matched. + * If strtptr is non-null, a pointer to the start of the string matched + * (excluding \a matches) will be returned at *strtptr. + * If mstring is non-null, the string matched by a \p will be copied + * into mstring. + */ + +boolean _escaped; /* true if we are currently _escaped */ +char *_start; /* start of string */ + +char * +expmatch (s, re, strtptr, mstring) + register char *s; /* string to check for a match in */ + register char *re; /* a converted irregular expression */ + char **strtptr; /* where to put ptr to start of match */ + char *mstring; /* where to put whatever matches a \p */ +{ + register char *cs; /* the current symbol */ + register char *ptr, *s1; /* temporary pointer */ + register char c; /* temporary */ + boolean matched; /* a temporary boolean */ + + /* initial conditions */ + if ( strtptr ) + *strtptr = NIL; + if (re == NIL) + return (NIL); + cs = re; + matched = FALSE; + + /* loop till expression string is exhausted (or at least pretty tired) */ + while (*cs) { + switch (*cs & (OPER | STR | META)) { + + /* try to match a string */ + case STR: + matched = !((*re_strncmp)(s, SSTR(cs), SCNT(cs))); + if (matched) { + + /* hoorah it matches */ + s += SCNT(cs); + cs = SNEXT(cs); + } else if (*cs & ALT) { + + /* alternation, skip to next expression */ + cs = SNEXT(cs); + } else if (*cs & OPT) { + + /* the match is optional */ + cs = SNEXT(cs); + matched = 1; /* indicate a successful match */ + } else { + + /* no match, error return */ + return (NIL); + } + break; + + /* an operator, do something fancy */ + case OPER: + switch (OSYM(cs)) { + + /* this is an alternation */ + case '|': + if (matched) + + /* last thing in the alternation was a match, skip ahead */ + cs = OPTR(cs); + else + + /* no match, keep trying */ + cs = ONEXT(cs); + break; + + /* this is a grouping, recurse */ + case '(': + ptr = expmatch (s, ONEXT(cs), strtptr, mstring); + if (ptr != NIL) { + + /* the subexpression matched */ + matched = 1; + s = ptr; + } else if (*cs & ALT) { + + /* alternation, skip to next expression */ + matched = 0; + } else if (*cs & OPT) { + + /* the match is optional */ + matched = 1; /* indicate a successful match */ + } else { + + /* no match, error return */ + return (NIL); + } + cs = OPTR(cs); + break; + } + break; + + /* try to match a metasymbol */ + case META: + switch (MSYM(cs)) { + + /* try to match anything and remember what was matched */ + case 'p': + /* + * This is really the same as trying the match the + * remaining parts of the expression to any subset + * of the string. + */ + s1 = s; + do { + ptr = expmatch (s1, MNEXT(cs), strtptr, mstring); + if (ptr != NIL && s1 != s) { + + /* we have a match, remember the match */ + if ( mstring ) { + strncpy (mstring, s, s1 - s); + mstring[s1 - s] = '\0'; + } + return (ptr); + + } else if (ptr != NIL && (*cs & OPT)) { + + /* \p was optional so no match is ok */ + return (ptr); + + } else if (ptr != NIL) { + + /* not optional and we still matched */ + return (NIL); + } + if (!isalnum(*s1) && *s1 != '_') + return (NIL); + if (*s1 == '\\') + _escaped = _escaped ? FALSE : TRUE; + else + _escaped = FALSE; + } while (*s1++); + return (NIL); + + /* try to match anything */ + case 'a': + /* + * This is really the same as trying the match the + * remaining parts of the expression to any subset + * of the string. + */ + s1 = s; + do { + /* + * Hack for an important special case: if the next thing + * in the pattern is a string, just gobble characters until + * we find something that matches that string (this saves + * the cost of a recursive call on expmatch while scanning + * for the start of comments or strings). Since many + * patterns end with a string, we also treat that as a + * special case. + */ + if( *(ptr=MNEXT(cs)) == STR ) { + c = *SSTR(ptr); + while( *s1 && *s1 != c ) + s1++; + + if ( *s1 == 0 ) + return(NIL); + + if ( SNEXT(ptr) == 0 && (s1 != s || *cs & OPT)) { + /* next item is a string, it's the last item and + * the \a match is ok - just loop to try & match + * the string. + */ + if ( strtptr ) + *strtptr = s1; + + cs = ptr; + s = s1; + break; + } + } + ptr = expmatch (s1, MNEXT(cs), strtptr, mstring); + if (ptr != NIL && (s1 != s || *cs & OPT)) { + + /* we have a match */ + if ( strtptr ) + *strtptr = s1; + + return(ptr); + + } else if (ptr != NIL) { + + /* not optional and we still matched */ + return (NIL); + } + if (*s1 == '\\') + _escaped = _escaped ? FALSE : TRUE; + else + _escaped = FALSE; + } while (*s1++); + return (NIL); + + /* fail if we are currently _escaped */ + case 'e': + if (_escaped) + return(NIL); + cs = MNEXT(cs); + break; + + /* match any number of tabs and spaces */ + case 'd': + ptr = s; + while (*s == ' ' || *s == '\t') + s++; + if (s != ptr || s == _start) { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*s == '\n' || *s == '\0') { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* check for end of line */ + case '$': + if (*s == '\0' || *s == '\n') { + + /* match, be happy */ + s++; + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* check for start of line */ + case '^': + if (s == _start) { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* end of a subexpression, return success */ + case ')': + return (s); + } + break; + } + } + return (s); +} diff --git a/support/tgrind/retest.c b/support/tgrind/retest.c new file mode 100644 index 0000000000..67f4a525a7 --- /dev/null +++ b/support/tgrind/retest.c @@ -0,0 +1,66 @@ +#ifndef lint +static char *sccsid="@(#)retest.c 1.1 (LBL) 3/29/85"; +#endif + +#include <ctype.h> + +int l_onecase = 0; +char * _start; +char * _escaped; +char * convexp(); +char * expmatch(); +main() +{ + char reg[132]; + char *ireg; + char str[132]; + char *match; + char matstr[132]; + char c; + + while (1) { + printf ("\nexpr: "); + scanf ("%s", reg); + ireg = convexp(reg); + match = ireg; + while(*match) { + switch (*match) { + + case '\\': + case '(': + case ')': + case '|': + printf ("%c", *match); + break; + + default: + if (isalnum(*match)) + printf("%c", *match); + else + printf ("<%03o>", *match); + break; + } + match++; + } + printf("\n"); + getchar(); + while(1) { + printf ("string: "); + match = str; + while ((c = getchar()) != '\n') + *match++ = c; + *match = 0; + if (str[0] == '#') + break; + matstr[0] = 0; + _start = str; + _escaped = 0; + match = expmatch (str, ireg, matstr); + if (match == 0) + printf ("FAILED\n"); + else + printf ("match\nmatstr = %s\n", matstr); + } + + } +} diff --git a/support/tgrind/sysv/makefile b/support/tgrind/sysv/makefile new file mode 100644 index 0000000000..84fa4f0165 --- /dev/null +++ b/support/tgrind/sysv/makefile @@ -0,0 +1,30 @@ +# @(#)Makefile 4.1 (Berkeley) 10/19/82 +# +DESTDIR=/usr/local +DEFSFILE=/usr/local/lib/vgrindefs +TEXINPUTS=/usr/lib/tex/macros + +CFLAGS=-g +SOURCES=tfontedpr.c vgrindefs.c regexp.c retest.c +CMDS=tfontedpr retest +OBJS=retest.o regexp.o tfontedpr.o vgrindefs.o + +all: $(CMDS) + +tfontedpr: tfontedpr.o vgrindefs.o regexp.o + cc ${CFLAGS} -o tfontedpr tfontedpr.o vgrindefs.o regexp.o + +tfontedpr.o: tfontedpr.c + cc ${CFLAGS} -DDEFSFILE=\"${DEFSFILE}\" -c tfontedpr.c + +retest: retest.o regexp.o + cc ${CFLAGS} -o retest retest.o regexp.o + +install: all + install -s tfontedpr ${DESTDIR}/lib/tfontedpr + install -c tgrind.sh ${DESTDIR}/bin/tgrind + install -c tgrindmac.tex ${TEXINPUTS}/tgrindmac.tex + install -c vgrindefs.src ${DEFSFILE} + +clean: + rm -f ${CMDS} ${OBJS} diff --git a/support/tgrind/sysv/regexp.c b/support/tgrind/sysv/regexp.c new file mode 100644 index 0000000000..ba7ab74eeb --- /dev/null +++ b/support/tgrind/sysv/regexp.c @@ -0,0 +1,595 @@ +#ifndef lint +static char *sccsid="@(#)regexp.c 1.2 (LBL) 4/12/85"; +#endif +/* + * regular expression matching routines for tgrind/tfontedpr. + * + * These routines were written by Dave Presotto (I think) for vgrind. + * Minor mods & attempts to improve performance by Van Jacobson (van@lbl-rtsg) + * and Chris Torek (chris@maryland). + * + * Modifications. + * -------------- + * 30Mar85 Van & Chris Changed expmatch to return pointer to start of what + * was matched in addition to pointer to match end. + * Several changes to improve performance (too numerous + * to mention). + * 11Dec84 Dave Presotto Written. + */ + +#include <ctype.h> + +typedef int boolean; +#define TRUE 1 +#define FALSE 0 +#define NIL 0 + +#define makelower(c) (isupper((c)) ? tolower((c)) : (c)) + +int (*re_strncmp)(); /* function used by expmatch to compare + * strings. The caller should make it point to + * strncmp if case is significant & + * lc_strncmp otherwise. + */ + +/* lc_strncmp - like strncmp except that we convert the + * first string to lower case before comparing. + */ + +lc_strncmp(s1, s2, len) + register char *s1,*s2; + register int len; +{ + while (len-- > 0) + if (*s2 - makelower(*s1)) + return(1); + else + s2++, s1++; + + return(0); +} + +/* The following routine converts an irregular expression to + * internal format. + * + * Either meta symbols (\a \d or \p) or character strings or + * operations ( alternation or perenthesizing ) can be + * specified. Each starts with a descriptor byte. The descriptor + * byte has STR set for strings, META set for meta symbols + * and OPER set for operations. + * The descriptor byte can also have the OPT bit set if the object + * defined is optional. Also ALT can be set to indicate an alternation. + * + * For metasymbols the byte following the descriptor byte identities + * the meta symbol (containing an ascii 'a', 'd', 'p', '|', or '('). For + * strings the byte after the descriptor is a character count for + * the string: + * + * meta symbols := descriptor + * symbol + * + * strings := descriptor + * character count + * the string + * + * operatins := descriptor + * symbol + * character count + */ + +/* + * handy macros for accessing parts of match blocks + */ +#define MSYM(A) (*(A+1)) /* symbol in a meta symbol block */ +#define MNEXT(A) (A+2) /* character following a metasymbol block */ + +#define OSYM(A) (*(A+1)) /* symbol in an operation block */ +#define OCNT(A) (*(A+2)) /* character count */ +#define ONEXT(A) (A+3) /* next character after the operation */ +#define OPTR(A) (A+*(A+2)) /* place pointed to by the operator */ + +#define SCNT(A) (*(A+1)) /* byte count of a string */ +#define SSTR(A) (A+2) /* address of the string */ +#define SNEXT(A) (A+2+*(A+1)) /* character following the string */ + +/* + * bit flags in the descriptor + */ +#define OPT 1 +#define STR 2 +#define META 4 +#define ALT 8 +#define OPER 16 + +char *ure; /* pointer current position in unconverted exp */ +char *ccre; /* pointer to current position in converted exp*/ +char *malloc(); + +char * +convexp(re) + char *re; /* unconverted irregular expression */ +{ + register char *cre; /* pointer to converted regular expression */ + + /* allocate room for the converted expression */ + if (re == NIL) + return (NIL); + if (*re == '\0') + return (NIL); + cre = malloc (4 * strlen(re) + 3); + ccre = cre; + ure = re; + + /* start the conversion with a \a */ + *cre = META | OPT; + MSYM(cre) = 'a'; + ccre = MNEXT(cre); + + /* start the conversion (its recursive) */ + expconv (); + *ccre = 0; + return (cre); +} + +expconv() +{ + register char *cs; /* pointer to current symbol in converted exp */ + register char c; /* character being processed */ + register char *acs; /* pinter to last alternate */ + register int temp; + + /* let the conversion begin */ + acs = NIL; + cs = NIL; + while (*ure != NIL) { + switch (c = *ure++) { + + case '\\': + switch (c = *ure++) { + + /* escaped characters are just characters */ + default: + if (cs == NIL || (*cs & STR) == 0) { + cs = ccre; + *cs = STR; + SCNT(cs) = 1; + ccre += 2; + } else + SCNT(cs)++; + *ccre++ = c; + break; + + /* normal(?) metacharacters */ + case 'a': + case 'd': + case 'e': + case 'p': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + break; + } + break; + + /* just put the symbol in */ + case '^': + case '$': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + break; + + /* mark the last match sequence as optional */ + case '?': + if (cs) + *cs = *cs | OPT; + break; + + /* recurse and define a subexpression */ + case '(': + if (acs != NIL && acs != cs) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = OPER; + OSYM(cs) = '('; + ccre = ONEXT(cs); + expconv (); + OCNT(cs) = ccre - cs; /* offset to next symbol */ + break; + + /* return from a recursion */ + case ')': + if (acs != NIL) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + cs = ccre; + *cs = META; + MSYM(cs) = c; + ccre = MNEXT(cs); + return; + + /* mark the last match sequence as having an alternate */ + /* the third byte will contain an offset to jump over the */ + /* alternate match in case the first did not fail */ + case '|': + if (acs != NIL && acs != cs) + OCNT(ccre) = ccre - acs; /* make a back pointer */ + else + OCNT(ccre) = 0; + *cs |= ALT; + cs = ccre; + *cs = OPER; + OSYM(cs) = '|'; + ccre = ONEXT(cs); + acs = cs; /* remember that the pointer is to be filles */ + break; + + /* if its not a metasymbol just build a scharacter string */ + default: + if (cs == NIL || (*cs & STR) == 0) { + cs = ccre; + *cs = STR; + SCNT(cs) = 1; + ccre = SSTR(cs); + } else + SCNT(cs)++; + *ccre++ = c; + break; + } + } + if (acs != NIL) { + do { + temp = OCNT(acs); + OCNT(acs) = ccre - acs; + acs -= temp; + } while (temp != 0); + acs = NIL; + } + return; +} +/* end of convertre */ + + +/* + * The following routine recognises an irregular expresion + * with the following special characters: + * + * \? - means last match was optional + * \a - matches any number of characters + * \d - matches any number of spaces and tabs + * \p - matches any number of alphanumeric + * characters. The + * characters matched will be copied into + * the area pointed to by 'name'. + * \| - alternation + * \( \) - grouping used mostly for alternation and + * optionality + * + * The irregular expression must be translated to internal form + * prior to calling this routine + * + * The value returned is the pointer to the last character matched. + * If strtptr is non-null, a pointer to the start of the string matched + * (excluding \a matches) will be returned at *strtptr. + * If mstring is non-null, the string matched by a \p will be copied + * into mstring. + */ + +boolean _escaped; /* true if we are currently _escaped */ +char *_regstart; /* start of string */ + +char * +expmatch (s, re, strtptr, mstring) + register char *s; /* string to check for a match in */ + register char *re; /* a converted irregular expression */ + char **strtptr; /* where to put ptr to start of match */ + char *mstring; /* where to put whatever matches a \p */ +{ + register char *cs; /* the current symbol */ + register char *ptr, *s1; /* temporary pointer */ + register char c; /* temporary */ + boolean matched; /* a temporary boolean */ + + /* initial conditions */ + if ( strtptr ) + *strtptr = NIL; + if (re == NIL) + return (NIL); + cs = re; + matched = FALSE; + + /* loop till expression string is exhausted (or at least pretty tired) */ + while (*cs) { + switch (*cs & (OPER | STR | META)) { + + /* try to match a string */ + case STR: + matched = !((*re_strncmp)(s, SSTR(cs), SCNT(cs))); + if (matched) { + + /* hoorah it matches */ + s += SCNT(cs); + cs = SNEXT(cs); + } else if (*cs & ALT) { + + /* alternation, skip to next expression */ + cs = SNEXT(cs); + } else if (*cs & OPT) { + + /* the match is optional */ + cs = SNEXT(cs); + matched = 1; /* indicate a successful match */ + } else { + + /* no match, error return */ + return (NIL); + } + break; + + /* an operator, do something fancy */ + case OPER: + switch (OSYM(cs)) { + + /* this is an alternation */ + case '|': + if (matched) + + /* last thing in the alternation was a match, skip ahead */ + cs = OPTR(cs); + else + + /* no match, keep trying */ + cs = ONEXT(cs); + break; + + /* this is a grouping, recurse */ + case '(': + ptr = expmatch (s, ONEXT(cs), strtptr, mstring); + if (ptr != NIL) { + + /* the subexpression matched */ + matched = 1; + s = ptr; + } else if (*cs & ALT) { + + /* alternation, skip to next expression */ + matched = 0; + } else if (*cs & OPT) { + + /* the match is optional */ + matched = 1; /* indicate a successful match */ + } else { + + /* no match, error return */ + return (NIL); + } + cs = OPTR(cs); + break; + } + break; + + /* try to match a metasymbol */ + case META: + switch (MSYM(cs)) { + + /* try to match anything and remember what was matched */ + case 'p': + /* + * This is really the same as trying the match the + * remaining parts of the expression to any subset + * of the string. + */ + s1 = s; + do { + ptr = expmatch (s1, MNEXT(cs), strtptr, mstring); + if (ptr != NIL && s1 != s) { + + /* we have a match, remember the match */ + if ( mstring ) { + strncpy (mstring, s, s1 - s); + mstring[s1 - s] = '\0'; + } + return (ptr); + + } else if (ptr != NIL && (*cs & OPT)) { + + /* \p was optional so no match is ok */ + return (ptr); + + } else if (ptr != NIL) { + + /* not optional and we still matched */ + return (NIL); + } + if (!isalnum(*s1) && *s1 != '_') + return (NIL); + if (*s1 == '\\') + _escaped = _escaped ? FALSE : TRUE; + else + _escaped = FALSE; + } while (*s1++); + return (NIL); + + /* try to match anything */ + case 'a': + /* + * This is really the same as trying the match the + * remaining parts of the expression to any subset + * of the string. + */ + s1 = s; + do { + /* + * Hack for an important special case: if the next thing + * in the pattern is a string, just gobble characters until + * we find something that matches that string (this saves + * the cost of a recursive call on expmatch while scanning + * for the start of comments or strings). Since many + * patterns end with a string, we also treat that as a + * special case. + */ + if( *(ptr=MNEXT(cs)) == STR ) { + c = *SSTR(ptr); + while( *s1 && *s1 != c ) + s1++; + + if ( *s1 == 0 ) + return(NIL); + + if ( SNEXT(ptr) == 0 && (s1 != s || *cs & OPT)) { + /* next item is a string, it's the last item and + * the \a match is ok - just loop to try & match + * the string. + */ + if ( strtptr ) + *strtptr = s1; + + cs = ptr; + s = s1; + break; + } + } + ptr = expmatch (s1, MNEXT(cs), strtptr, mstring); + if (ptr != NIL && (s1 != s || *cs & OPT)) { + + /* we have a match */ + if ( strtptr ) + *strtptr = s1; + + return(ptr); + + } else if (ptr != NIL) { + + /* not optional and we still matched */ + return (NIL); + } + if (*s1 == '\\') + _escaped = _escaped ? FALSE : TRUE; + else + _escaped = FALSE; + } while (*s1++); + return (NIL); + + /* fail if we are currently _escaped */ + case 'e': + if (_escaped) + return(NIL); + cs = MNEXT(cs); + break; + + /* match any number of tabs and spaces */ + case 'd': + ptr = s; + while (*s == ' ' || *s == '\t') + s++; + if (s != ptr || s == _regstart) { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*s == '\n' || *s == '\0') { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* check for end of line */ + case '$': + if (*s == '\0' || *s == '\n') { + + /* match, be happy */ + s++; + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* check for start of line */ + case '^': + if (s == _regstart) { + + /* match, be happy */ + matched = 1; + cs = MNEXT(cs); + } else if (*cs & ALT) { + + /* try the next part */ + matched = 0; + cs = MNEXT(cs); + } else if (*cs & OPT) { + + /* doesn't matter */ + matched = 1; + cs = MNEXT(cs); + } else + + /* no match, error return */ + return (NIL); + break; + + /* end of a subexpression, return success */ + case ')': + return (s); + } + break; + } + } + return (s); +} diff --git a/support/tgrind/sysv/retest.c b/support/tgrind/sysv/retest.c new file mode 100644 index 0000000000..098d06eae8 --- /dev/null +++ b/support/tgrind/sysv/retest.c @@ -0,0 +1,69 @@ +#ifndef lint +static char *sccsid="@(#)retest.c 1.1 (LBL) 3/29/85"; +#endif + +#include <ctype.h> + +int l_onecase = 0; +char * _regstart; +char * _escaped; +char * convexp(); +char * expmatch(); +int (*re_strncmp)(); +main() +{ + char reg[132]; + char *ireg; + char str[132]; + char *match; + char matstr[132]; + char c; + int strncmp(); + + re_strncmp = strncmp; + while (1) { + printf ("\nexpr: "); + scanf ("%s", reg); + ireg = convexp(reg); + match = ireg; + while(*match) { + switch (*match) { + + case '\\': + case '(': + case ')': + case '|': + printf ("%c", *match); + break; + + default: + if (isalnum(*match)) + printf("%c", *match); + else + printf ("<%03o>", *match); + break; + } + match++; + } + printf("\n"); + getchar(); + while(1) { + printf ("string: "); + match = str; + while ((c = getchar()) != '\n') + *match++ = c; + *match = 0; + if (str[0] == '#') + break; + matstr[0] = 0; + _regstart = str; + _escaped = 0; + match = expmatch (str, ireg, matstr); + if (match == 0) + printf ("FAILED\n"); + else + printf ("match\nmatstr = %s\n", matstr); + } + + } +} diff --git a/support/tgrind/sysv/tfontedpr.c b/support/tgrind/sysv/tfontedpr.c new file mode 100644 index 0000000000..9ed861e3fd --- /dev/null +++ b/support/tgrind/sysv/tfontedpr.c @@ -0,0 +1,620 @@ +#ifndef lint +static char sccsid[] = "@(#)@(#)tfontedpr.c 1.3 (LBL) 4/12/85"; +#endif + +/* tfontedpr - general purpose "pretty printer" for use with TeX. + * + * Copyright (C) 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 used as part of the "tgrind" shell script. It + * converts program source file(s) to TeX input files. + * + * 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. + * -------------- + * 30Mar85 Chris & Van: Fixed "\C" & "\S" (comment & string start indicators) + * to really appear at the start of comments & strings. + * Changes for speeded-up expmatch. + * 29Mar85 Chris Torek (chris@maryland): Bug fixes for '~' and '^L' + * output. Most cpu-time eaters recoded to improve + * efficiency. + * 10Feb85 Van Written. + */ + +#include <ctype.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#define boolean int +#define TRUE 1 +#define FALSE 0 +#define NIL 0 +#define STANDARD 0 +#define ALTERNATE 1 + +#define STRLEN 10 /* length of strings introducing things */ +#define PNAMELEN 80 /* length of a function/procedure name */ +#define PSMAX 20 /* size of procedure name stacking */ + +/* regular expression routines */ + +char *expmatch(); /* match a string to an expression */ +char *convexp(); /* convert expression to internal form */ +char *tgetstr(); + +boolean isproc(); + + +char *ctime(); + +/* + * The state variables + */ + +boolean incomm; /* in a comment of the primary type */ +boolean instr; /* in a string constant */ +boolean inchr; /* in a string constant */ +boolean nokeyw = FALSE; /* no keywords being flagged */ +boolean prccont; /* continue last procedure */ +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 */ +char *defsfile = DEFSFILE; /* name of language definitions file */ +char pname[BUFSIZ+1]; + +/* + * The language specific globals + */ + +char *language = "c"; /* the language indicator */ +char *l_keywds[BUFSIZ/2]; /* keyword table address */ +char *l_prcbeg; /* regular expr for procedure begin */ +char *l_combeg; /* string introducing a comment */ +char *l_comend; /* string ending a comment */ +char *l_acmbeg; /* string introducing a comment */ +char *l_acmend; /* string ending a comment */ +char *l_blkbeg; /* string begining of a block */ +char *l_blkend; /* string ending a block */ +char *l_strbeg; /* delimiter for string constant */ +char *l_strend; /* delimiter for string constant */ +char *l_chrbeg; /* delimiter for character constant */ +char *l_chrend; /* delimiter for character constant */ +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 */ + +/* + * global variables also used by expmatch + */ +extern boolean _escaped; /* if last character was an escape */ +extern char *_regstart; /* start of the current string */ + +int (*re_strncmp)(); /* function to do string compares */ +extern int strncmp(); +extern int lc_strncmp(); + +/* + * The following table converts ASCII characters to a printed + * representation, taking care of all the TeX 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.) + */ +char *printtab[128] = { + "\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", "\\^[", "\\^\\!","\\^]", "\\^\\^","\\^_", + " ", "!", "\\\"", "\\#", "\\$", "\\%", "\\&", "\\'", + "(", ")", "*", "+", ",", "\\-", ".", "\\/", + "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", "[", "\\!", "]", "\\^", "\\_", + "`", "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", "\\{", "\\|", "\\}", "\\~", "\\^?", +}; + +/* Output a character, with translation. Avoid side effects with this + macro! */ +#define outchar(c) (printtab[c][1] ? printf("%s", printtab[c]) : putchar(c)) + +/* + * Output a TeX command to tab to column "col" (see tgrindmac.tex for a + * partial explanation of the bizarre brace arrangement). + */ +#define tabto(col) printf("}\\Tab{%d}{", col); + +main(argc, argv) + int argc; + register char *argv[]; +{ + char *fname = "", *p; + struct stat stbuf; + char buf[BUFSIZ]; + char strings[2 * BUFSIZ]; + char defs[2 * BUFSIZ]; + + printf("\\input tgrindmac\n"); + argc--, argv++; + do { + register char *cp; + register int i; + + if (argc > 0) { + if (!strcmp(argv[0], "-h")) { + if (argc == 1) { + printf("\\Head{}\n"); + argc = 0; + goto rest; + } + printf("\\Head{"); + putstr( argv[1] ); + printf( "}\n" ); + argc--, argv++; + argc--, argv++; + if (argc > 0) + continue; + goto rest; + } + + /* take input from the standard place */ + if (!strcmp(argv[0], "-")) { + argc = 0; + goto rest; + } + + /* indicate no keywords */ + if (!strcmp(argv[0], "-n")) { + nokeyw++; + argc--, argv++; + continue; + } + + /* specify the language */ + if (!strncmp(argv[0], "-l", 2)) { + 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(1); + } + + fname = argv[0]; + argc--, argv++; + } + rest: + + /* + * 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 (0); + } else if (i < 0) { + fprintf (stderr, "cannot find vgrindefs file %s\n", defsfile); + exit (0); + } + p = strings; + if (tgetstr ("kw", &p) == NIL) + nokeyw = TRUE; + else { + char **cpp; + + cpp = l_keywds; + cp = strings; + while (*cp) { + while (*cp == ' ' || *cp =='\t') + *cp++ = NULL; + if (*cp) + *cpp++ = cp; + while (*cp != ' ' && *cp != '\t' && *cp) + cp++; + } + *cpp = NIL; + } + p = buf; + l_prcbeg = convexp (tgetstr ("pb", &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)); + l_escape = '\\'; + l_onecase = tgetflag ("oc"); + if ( l_onecase ) + re_strncmp = lc_strncmp; + else + re_strncmp = strncmp; + l_toplex = tgetflag ("tl"); + + /* initialize the program */ + + incomm = FALSE; + instr = FALSE; + inchr = FALSE; + _escaped = FALSE; + blklevel = 0; + for (psptr=0; psptr<PSMAX; psptr++) { + pstack[psptr][0] = NULL; + plstack[psptr] = 0; + } + psptr = -1; + fstat(fileno(stdin), &stbuf); + cp = ctime(&stbuf.st_mtime); + cp[10] = '\0'; + cp[16] = '\0'; + cp[24] = '\0'; + printf("\\File{"); + putstr( fname ); + printf("},{%s},{%s %s}\n", cp+11, cp+4, cp+20); + + /* + * MAIN LOOP!!! + */ + while (fgets(buf, sizeof buf, stdin) != NULL) { + cp = buf; + 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 (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 (argc > 0); + printf("\\vfill\\eject\\end\n"); + exit(0); +} + +#define isidchr(c) (isalnum(c) || (c) == '_') + +putScp(os) + 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 *blksptr; /* start of a lexical block start */ + char *blksendptr; /* end of a lexical block start */ + char *blkeptr; /* start of a lexical block end */ + char *blkeendptr; /* end of a lexical block end */ + + _regstart = os; /* remember the start for expmatch */ + _escaped = FALSE; + if (nokeyw || incomm || instr) + goto skip; + if (isproc(s)) { + printf("\\Proc{"); + putstr(pname); + printf("}"); + if (psptr < PSMAX) { + ++psptr; + strncpy (pstack[psptr], pname, PNAMELEN); + pstack[psptr][PNAMELEN] = NULL; + plstack[psptr] = blklevel; + } + } +skip: + do { + /* check for string, comment, blockstart, etc */ + if (!incomm && !instr && !inchr) { + + blkeendptr = expmatch (s, l_blkend, &blkeptr, NIL); + blksendptr = expmatch (s, l_blkbeg, &blksptr, NIL); + comendptr = expmatch (s, l_combeg, &comptr, NIL); + acmendptr = expmatch (s, l_acmbeg, &acmptr, NIL); + strendptr = expmatch (s, l_strbeg, &strptr, NIL); + chrendptr = expmatch (s, l_chrbeg, &chrptr, NIL); + + /* start of a comment? */ + if (comptr != NIL + && (strptr == NIL || comptr < strptr) + && (acmptr == NIL || comptr < acmptr) + && (chrptr == NIL || comptr < chrptr) + && (blksptr == NIL || comptr < blksptr) + && (blkeptr == NIL || 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 != NIL + && (strptr == NIL || acmptr < strptr) + && (chrptr == NIL || acmptr < chrptr) + && (blksptr == NIL || acmptr < blksptr) + && (blkeptr == NIL || acmptr < blkeptr)) { + putKcp (s, acmptr-1, FALSE); + printf("\\C{}"); + s = acmendptr; + putKcp (acmptr, acmendptr, FALSE); + incomm = TRUE; + comtype = ALTERNATE; + continue; + } + + /* start of a string? */ + if (strptr != NIL + && (chrptr == NIL || strptr < chrptr) + && (blksptr == NIL || strptr < blksptr) + && (blkeptr == NIL || 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 != NIL + && (blksptr == NIL || chrptr < blksptr) + && (blkeptr == NIL || 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 != NIL) { + if (blksptr == NIL || blkeptr < blksptr) { + putKcp (s, blkeendptr - 1, FALSE); + s = blkeendptr; + blklevel--; + 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 != NIL) { + putKcp (s, blksendptr - 1, FALSE); + s = blksendptr; + blklevel++; + continue; + } + + /* check for end of comment */ + } else if (incomm) { + if ((comendptr = expmatch( s, + comtype==STANDARD? l_comend : l_acmend, + NIL, NIL)) != NIL) { + 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, NIL, NIL)) != NIL) { + 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, NIL, NIL)) != NIL) { + 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); +} + +putKcp(start, end, nix) + register char *start; /* start of string to write */ + register char *end; /* end of string to write */ + register boolean nix; /* true if we should force nokeyw */ +{ + register int i, c; + + if (nokeyw) + nix = TRUE; + + while (start <= end) { + c = *start++; + /* take care of nice tab stops */ + if (c == '\t') { + while (start <= end && *start == '\t') + start++; + tabto(width(_regstart, start)); + continue; + } + if (!nix && (isidchr(c) || + c == '#' || c == '%' || c == '!' || c == '$')) { + /* potential keyword */ + start--; + if (start == _regstart || !isidchr(start[-1])) { + i = iskw(start); + if (i > 0) { + printf("\\K{"); + while (--i >= 0) { + c = *start++; + outchar(c); + } + putchar('}'); + continue; + } + } + start++; + } + outchar(c); + } +} + + +width(s, os) + register char *s, *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 */ +putstr(cp) + register char *cp; +{ + register int c; + + if (cp == NULL) + return; + while ((c = *cp++) != 0) + outchar(c); +} + +/* + * look for a process beginning on this line + */ +boolean +isproc(s) + char *s; +{ + pname[0] = NULL; + if ((!l_toplex || blklevel == 0) + && expmatch(s, l_prcbeg, NIL, pname) != NIL) + return (TRUE); + return (FALSE); +} + + +/* iskw - check to see if the next word is a keyword + */ + +iskw(s) + register char *s; +{ + register char **ss = l_keywds; + register int i = 1; + register char *cp = s; + register int firstc = *s; + + while (++cp, isidchr(*cp)) + i++; + while (cp = *ss++) { + if (!l_onecase && firstc != *cp) + continue; + if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i])) + return (i); + } + return (0); +} diff --git a/support/tgrind/sysv/tgrind.sh b/support/tgrind/sysv/tgrind.sh new file mode 100644 index 0000000000..a5cf61097f --- /dev/null +++ b/support/tgrind/sysv/tgrind.sh @@ -0,0 +1,99 @@ +#! /bin/sh +# Script to grind nice program listings using TeX. +# +# written Feb, 1985 by Van Jacobson, Lawrence Berkeley Laboratory (adapted +# from the 4.2bsd "vgrind" script). +# +# Translated to Bourne Shell, March 1987, Lou Salkind, New York University +# +# Since TeX output handling is site dependent, you'll have to edit this +# file to get output to your local typesetting device(s). Our site uses +# the flags "-v" (versatec output), "-q" (qms output) and "-o" (keep dvi file) +# to route output. Put something appropriate to your site at the "PUT OUTPUT +# HANDLING..." comment at the end of this script. If you've already dealt +# with this in your local tex command, just change the -v/q/k (or whatever) +# cases in the first "switch" to set variable "texoptions" appropriately. +# +b=/usr/local/lib/tfontedpr +tex=/usr/local/bin/tex +options= +texoptions= +files= +head="" +format="" +output="dvi" +outputfile=tgrind.dvi +expecting=filename + +for A do + case $A in + + -d) + expecting=doptions ;; + + -f) + format="Y" ;; + + -h) + expecting=head ;; + + -o) + output=dvi + expecting=outputfile ;; + +# some sample devices... + -v) + output="ver" ;; + + -q) + output="qms" ;; + + -*) + options="$options $A" ;; + + *) + case $expecting in + outputfile) + outputfile="$A" ;; + head) + head="$A" ;; + doptions) + options="$options -d $A" ;; + filename) + files="$files $A" ;; + esac + expecting=filename ;; + esac +done + +if [ "$format" = "Y" ]; then + if [ "$head" != "" ]; then + $b $options -h "$head" $files + else + $b $options $files + fi + exit 0 +fi + +trap 'rm -f tgrnd$$.tex tgrnd$$.dvi tgrnd$$.log' 0 2 3 15 + +if [ "$head" != "" ]; then + $b $options -h "$head" $files >tgrnd$$.tex +else + $b $options $files >tgrnd$$.tex +fi +$tex $texoptions tgrnd$$.tex + +# PUT OUTPUT HANDLING COMMANDS HERE. +case $output in +ver) + ;; +qms) + ;; +dvi) +# if [ `expr $outputfile : '/*'` -eq 0 ]; then +# outputfile=$mydir/$outputfile +# fi + mv tgrnd$$.dvi $outputfile + ;; +esac diff --git a/support/tgrind/sysv/tgrindmac.tex b/support/tgrind/sysv/tgrindmac.tex new file mode 100644 index 0000000000..c09b7c83cd --- /dev/null +++ b/support/tgrind/sysv/tgrindmac.tex @@ -0,0 +1,139 @@ +% @(#)tgrindmac.tex 1.4 (LBL) 3/30/85 +% Macros for TeX "tgrind" (a TeX equivalent of 4bsd "vgrind"). +% +% Copyright (C) 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. +% +% Please send improvements, bug fixes, comments, etc., to +% van@lbl-rtsg.arpa +% ...ucbvax!lbl-csam!van +% +% Modifications. +% -------------- +% 10Feb85, vj Written. +% 23Mar85, rf Substitute ambx10 for amb10 +% 29Mar85, Chris Torek: Use tt font for all characters in strings. +% Print decent quotes in comments rather than use tt +% font quotes. Show filename (to terminal & log file) +% at start of each new file. +% 30Mar85, vj Fixed bug in tabbing. + +\font\sevenrm=cmr7 % font for right margin line numbers +\font\twelvebf=cmbx10 scaled \magstep1 % font for page headers +\font\forteenrm=cmr10 scaled \magstep2 % font for right margin proc names + +% tfontedpr outputs a "\Head{Hdr text}" if you give it the "-h" flag. +% We remember the text in "\Header" so it can be included in the +% head line. +\def\Head#1{\def\Header{#1}} +\def\Header{\null} + +% We get a "\File{Filename},{Last Mod Time},{Last Mod Date}" at the start of +% each new file. We remember this stuff for inclusion in the page head & foot. +% We reset the page number & current line number to 0 and output a null +% mark to let the output routine know we're starting a new file. +% We set up the \headline & \footline token lists inside the File macro to +% save remembering the filename & mod time with yet other macros. +\def\File#1,#2,#3{\vfill\eject\mark{\empty} +\global\linecount=0\linenext=9\pageno=1\message{#1} +\headline={\twelvebf\Header\hfil +\edef\a{\topmark}\edef\b{\botmark}\edef\c{\firstmark} +\ifx\c\empty\botmark\else +\ifx\a\empty\botmark\else +\ifx\b\empty\topmark\else +\ifx\a\b\topmark\else\topmark--\botmark\fi +\fi\fi\fi(#1)} +\footline={\it{}#2 #3\hfil{}Page \folio{} of #1}} + +% There's a "\Proc{Proc Name}" at the start of each procedure. If +% the language definition allows nested procedures (e.g., pascal), there +% will be a "\ProcCont{Proc Name}" at the end of each inner procedure. +% (In this case, "proc name" is the name of the outer procedure. I.e., +% ProcCont marks the continuation of "proc name"). +\def\Proc#1{\global\def\Procname{#1}\global\setbox\procbox=\hbox{\forteenrm #1}} +\def\ProcCont#1{\global\def\Procname{#1} +\global\setbox\procbox=\hbox{\forteenrm$\ldots$#1}} +\newbox\procbox +\def\Procname{\null} + +% Each formfeed in the input is replaced by a "\NewPage" macro. If +% you really want a page break here, define this as "\vfill\eject". +\def\NewPage{\filbreak\bigskip} + +% Each line of the program text is enclosed by a "\L{...}". We turn +% each line into an hbox of size hsize. If we saw a procedure name somewhere +% in the line (i.e., "procbox" is not null), we right justify "procbox" +% on the line. Every 10 lines we output a small, right justified line number. +\def\L#1{\filbreak\hbox to \hsize{\CF\strut\global\advance\linecount by1 +#1\hss\ifvoid\procbox\linebox\else\box\procbox\mark{\Procname}\fi}} + +\newcount\linecount \linecount=0 +\newcount\linenext \linenext=9 +\def\linebox{\ifnum\linecount>\linenext\global\advance\linenext by10 +\hbox{\sevenrm\the\linecount}\fi} + + +% The following weirdness is to deal with tabs. "Pieces" of a line +% between tabs are output as "\LB{...}". E.g., a line with a tab at +% column 16 would be output as "\LB{xxx}\Tab{16}\LB{yyy}". (Actually, to +% reduce the number of characters in the .tex file the \Tab macro +% supplies the 2nd & subsequent \LB's.) We accumulate the LB stuff in an +% hbox. When we see a Tab, we grab this hbox (using "\lastbox") and turn +% it into a box that extends to the tab position. We stash this box in +% "\linesofar" & use "\everyhbox" to get \linesofar concatenated onto the +% front of the next piece of the line. (There must be a better way of +% doing tabs [cf., the Plain.tex tab macros] but I'm not not enough of a +% TeX wizard to come up with it. Suggestions would be appreciated.) + +\def\LB{\CF\hbox} +\newbox\linesofar\setbox\linesofar=\null +\everyhbox={\box\linesofar} +\newdimen\TBwid +\def\Tab#1{\setbox\tbox=\lastbox\TBwid=1\wd\tbox\advance\TBwid by 1\ts +\ifdim\TBwid>#1\ts +\setbox\linesofar=\hbox{\box\tbox\space}\else +\setbox\linesofar=\hbox to #1\ts{\box\tbox\hfil}\fi\LB} + +% A normal space is too thin for code listings. We make spaces & tabs +% be in "\ts" units (which are the width of a "0" in the current font). +\newdimen\ts +\newbox\tbox +\setbox\tbox=\hbox{0} \ts=1\wd\tbox \setbox\tbox=\hbox{\hskip 1\ts} +\def\space{\hskip 1\ts\relax} + +% Font changing stuff for keywords, comments & strings. We put keywords +% in boldface, comments in text-italic & strings in typewriter. Since +% we're usually changing the font inside of a \LB macro, we remember the +% current font in \CF & stick a \CF at the start of each new box. +% Also, the characters " and ' behave differently in comments than in +% code, and others behave differently in strings than in code. +\newif\ifcomment\newif\ifstring +\let\CF=\rm +\def\K#1{{\bf #1}} % Keyword +\def\C{\it\global\let\CF=\it\global\commenttrue\relax} % Comment Start +\def\CE{\rm\global\let\CF=\rm\global\commentfalse\relax}% Comment End +\def\S{\tt\global\let\CF=\tt\global\stringtrue\relax} % String Start +\def\SE{\rm\global\let\CF=\rm\global\stringfalse\relax} % String End + +% Special characters. +\def\{{\ifmmode\lbrace\else\ifstring{\char'173}\else$\lbrace$\fi\fi} +\def\}{\ifmmode\rbrace\else\ifstring{\char'175}\else$\rbrace$\fi\fi} +\def\!{\ifmmode\backslash\else\ifstring{\char'134}\else$\backslash$\fi\fi} +\def\|{\ifmmode|\else\ifstring{\char'174}\else$|$\fi\fi} +\def\<{\ifmmode<\else\ifstring<\else$<$\fi\fi} +\def\>{\ifmmode>\else\ifstring>\else$>$\fi\fi} +\def\/{\ifmmode/\else\ifstring/\else$/$\fi\fi} +\def\-{\ifmmode-\else\ifstring-\else$-$\fi\fi} +\def\_{\ifstring{\char'137}\else\underbar{\ }\fi} +\def\&{{\char'046}} +\def\#{{\char'043}} +\def\%{{\char'045}} +\def\~{{\char'176}} +\def\"{\ifcomment''\else{\tt\char'042}\fi} +\def\'{\ifcomment'\else{\tt\char'047}\fi} +\def\^{{\char'136}} +\def\${{\rm\char'044}} + +\raggedright\obeyspaces\let =\space% diff --git a/support/tgrind/tfontedpr.c b/support/tgrind/tfontedpr.c new file mode 100644 index 0000000000..786cc6d2bf --- /dev/null +++ b/support/tgrind/tfontedpr.c @@ -0,0 +1,620 @@ +#ifndef lint +static char sccsid[] = "@(#)@(#)tfontedpr.c 1.3 (LBL) 4/12/85"; +#endif + +/* tfontedpr - general purpose "pretty printer" for use with TeX. + * + * Copyright (C) 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 used as part of the "tgrind" shell script. It + * converts program source file(s) to TeX input files. + * + * 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. + * -------------- + * 30Mar85 Chris & Van: Fixed "\C" & "\S" (comment & string start indicators) + * to really appear at the start of comments & strings. + * Changes for speeded-up expmatch. + * 29Mar85 Chris Torek (chris@maryland): Bug fixes for '~' and '^L' + * output. Most cpu-time eaters recoded to improve + * efficiency. + * 10Feb85 Van Written. + */ + +#include <ctype.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> + +#define boolean int +#define TRUE 1 +#define FALSE 0 +#define NIL 0 +#define STANDARD 0 +#define ALTERNATE 1 + +#define STRLEN 10 /* length of strings introducing things */ +#define PNAMELEN 80 /* length of a function/procedure name */ +#define PSMAX 20 /* size of procedure name stacking */ + +/* regular expression routines */ + +char *expmatch(); /* match a string to an expression */ +char *convexp(); /* convert expression to internal form */ +char *tgetstr(); + +boolean isproc(); + + +char *ctime(); + +/* + * The state variables + */ + +boolean incomm; /* in a comment of the primary type */ +boolean instr; /* in a string constant */ +boolean inchr; /* in a string constant */ +boolean nokeyw = FALSE; /* no keywords being flagged */ +boolean prccont; /* continue last procedure */ +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 */ +char *defsfile = DEFSFILE; /* name of language definitions file */ +char pname[BUFSIZ+1]; + +/* + * The language specific globals + */ + +char *language = "c"; /* the language indicator */ +char *l_keywds[BUFSIZ/2]; /* keyword table address */ +char *l_prcbeg; /* regular expr for procedure begin */ +char *l_combeg; /* string introducing a comment */ +char *l_comend; /* string ending a comment */ +char *l_acmbeg; /* string introducing a comment */ +char *l_acmend; /* string ending a comment */ +char *l_blkbeg; /* string begining of a block */ +char *l_blkend; /* string ending a block */ +char *l_strbeg; /* delimiter for string constant */ +char *l_strend; /* delimiter for string constant */ +char *l_chrbeg; /* delimiter for character constant */ +char *l_chrend; /* delimiter for character constant */ +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 */ + +/* + * global variables also used by expmatch + */ +extern boolean _escaped; /* if last character was an escape */ +extern char *_start; /* start of the current string */ + +int (*re_strncmp)(); /* function to do string compares */ +extern int strncmp(); +extern int lc_strncmp(); + +/* + * The following table converts ASCII characters to a printed + * representation, taking care of all the TeX 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.) + */ +char *printtab[128] = { + "\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", "\\^[", "\\^\\!","\\^]", "\\^\\^","\\^_", + " ", "!", "\\\"", "\\#", "\\$", "\\%", "\\&", "\\'", + "(", ")", "*", "+", ",", "\\-", ".", "\\/", + "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", "[", "\\!", "]", "\\^", "\\_", + "`", "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", "\\{", "\\|", "\\}", "\\~", "\\^?", +}; + +/* Output a character, with translation. Avoid side effects with this + macro! */ +#define outchar(c) (printtab[c][1] ? printf("%s", printtab[c]) : putchar(c)) + +/* + * Output a TeX command to tab to column "col" (see tgrindmac.tex for a + * partial explanation of the bizarre brace arrangement). + */ +#define tabto(col) printf("}\\Tab{%d}{", col); + +main(argc, argv) + int argc; + register char *argv[]; +{ + char *fname = "", *p; + struct stat stbuf; + char buf[BUFSIZ]; + char strings[2 * BUFSIZ]; + char defs[2 * BUFSIZ]; + + printf("\\input tgrindmac\n"); + argc--, argv++; + do { + register char *cp; + register int i; + + if (argc > 0) { + if (!strcmp(argv[0], "-h")) { + if (argc == 1) { + printf("\\Head{}\n"); + argc = 0; + goto rest; + } + printf("\\Head{"); + putstr( argv[1] ); + printf( "}\n" ); + argc--, argv++; + argc--, argv++; + if (argc > 0) + continue; + goto rest; + } + + /* take input from the standard place */ + if (!strcmp(argv[0], "-")) { + argc = 0; + goto rest; + } + + /* indicate no keywords */ + if (!strcmp(argv[0], "-n")) { + nokeyw++; + argc--, argv++; + continue; + } + + /* specify the language */ + if (!strncmp(argv[0], "-l", 2)) { + 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(1); + } + + fname = argv[0]; + argc--, argv++; + } + rest: + + /* + * 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 (0); + } else if (i < 0) { + fprintf (stderr, "cannot find vgrindefs file %s\n", defsfile); + exit (0); + } + p = strings; + if (tgetstr ("kw", &p) == NIL) + nokeyw = TRUE; + else { + char **cpp; + + cpp = l_keywds; + cp = strings; + while (*cp) { + while (*cp == ' ' || *cp =='\t') + *cp++ = NULL; + if (*cp) + *cpp++ = cp; + while (*cp != ' ' && *cp != '\t' && *cp) + cp++; + } + *cpp = NIL; + } + p = buf; + l_prcbeg = convexp (tgetstr ("pb", &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)); + l_escape = '\\'; + l_onecase = tgetflag ("oc"); + if ( l_onecase ) + re_strncmp = lc_strncmp; + else + re_strncmp = strncmp; + l_toplex = tgetflag ("tl"); + + /* initialize the program */ + + incomm = FALSE; + instr = FALSE; + inchr = FALSE; + _escaped = FALSE; + blklevel = 0; + for (psptr=0; psptr<PSMAX; psptr++) { + pstack[psptr][0] = NULL; + plstack[psptr] = 0; + } + psptr = -1; + fstat(fileno(stdin), &stbuf); + cp = ctime(&stbuf.st_mtime); + cp[10] = '\0'; + cp[16] = '\0'; + cp[24] = '\0'; + printf("\\File{"); + putstr( fname ); + printf("},{%s},{%s %s}\n", cp+11, cp+4, cp+20); + + /* + * MAIN LOOP!!! + */ + while (fgets(buf, sizeof buf, stdin) != NULL) { + cp = buf; + 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 (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 (argc > 0); + printf("\\vfill\\eject\\end\n"); + exit(0); +} + +#define isidchr(c) (isalnum(c) || (c) == '_') + +putScp(os) + 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 *blksptr; /* start of a lexical block start */ + char *blksendptr; /* end of a lexical block start */ + char *blkeptr; /* start of a lexical block end */ + char *blkeendptr; /* end of a lexical block end */ + + _start = os; /* remember the start for expmatch */ + _escaped = FALSE; + if (nokeyw || incomm || instr) + goto skip; + if (isproc(s)) { + printf("\\Proc{"); + putstr(pname); + printf("}"); + if (psptr < PSMAX) { + ++psptr; + strncpy (pstack[psptr], pname, PNAMELEN); + pstack[psptr][PNAMELEN] = NULL; + plstack[psptr] = blklevel; + } + } +skip: + do { + /* check for string, comment, blockstart, etc */ + if (!incomm && !instr && !inchr) { + + blkeendptr = expmatch (s, l_blkend, &blkeptr, NIL); + blksendptr = expmatch (s, l_blkbeg, &blksptr, NIL); + comendptr = expmatch (s, l_combeg, &comptr, NIL); + acmendptr = expmatch (s, l_acmbeg, &acmptr, NIL); + strendptr = expmatch (s, l_strbeg, &strptr, NIL); + chrendptr = expmatch (s, l_chrbeg, &chrptr, NIL); + + /* start of a comment? */ + if (comptr != NIL + && (strptr == NIL || comptr < strptr) + && (acmptr == NIL || comptr < acmptr) + && (chrptr == NIL || comptr < chrptr) + && (blksptr == NIL || comptr < blksptr) + && (blkeptr == NIL || 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 != NIL + && (strptr == NIL || acmptr < strptr) + && (chrptr == NIL || acmptr < chrptr) + && (blksptr == NIL || acmptr < blksptr) + && (blkeptr == NIL || acmptr < blkeptr)) { + putKcp (s, acmptr-1, FALSE); + printf("\\C{}"); + s = acmendptr; + putKcp (acmptr, acmendptr, FALSE); + incomm = TRUE; + comtype = ALTERNATE; + continue; + } + + /* start of a string? */ + if (strptr != NIL + && (chrptr == NIL || strptr < chrptr) + && (blksptr == NIL || strptr < blksptr) + && (blkeptr == NIL || 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 != NIL + && (blksptr == NIL || chrptr < blksptr) + && (blkeptr == NIL || 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 != NIL) { + if (blksptr == NIL || blkeptr < blksptr) { + putKcp (s, blkeendptr - 1, FALSE); + s = blkeendptr; + blklevel--; + 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 != NIL) { + putKcp (s, blksendptr - 1, FALSE); + s = blksendptr; + blklevel++; + continue; + } + + /* check for end of comment */ + } else if (incomm) { + if ((comendptr = expmatch( s, + comtype==STANDARD? l_comend : l_acmend, + NIL, NIL)) != NIL) { + 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, NIL, NIL)) != NIL) { + 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, NIL, NIL)) != NIL) { + 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); +} + +putKcp(start, end, nix) + register char *start; /* start of string to write */ + register char *end; /* end of string to write */ + register boolean nix; /* true if we should force nokeyw */ +{ + register int i, c; + + if (nokeyw) + nix = TRUE; + + while (start <= end) { + c = *start++; + /* take care of nice tab stops */ + if (c == '\t') { + while (start <= end && *start == '\t') + start++; + tabto(width(_start, start)); + continue; + } + if (!nix && (isidchr(c) || + c == '#' || c == '%' || c == '!' || c == '$')) { + /* potential keyword */ + start--; + if (start == _start || !isidchr(start[-1])) { + i = iskw(start); + if (i > 0) { + printf("\\K{"); + while (--i >= 0) { + c = *start++; + outchar(c); + } + putchar('}'); + continue; + } + } + start++; + } + outchar(c); + } +} + + +width(s, os) + register char *s, *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 */ +putstr(cp) + register char *cp; +{ + register int c; + + if (cp == NULL) + return; + while ((c = *cp++) != 0) + outchar(c); +} + +/* + * look for a process beginning on this line + */ +boolean +isproc(s) + char *s; +{ + pname[0] = NULL; + if ((!l_toplex || blklevel == 0) + && expmatch(s, l_prcbeg, NIL, pname) != NIL) + return (TRUE); + return (FALSE); +} + + +/* iskw - check to see if the next word is a keyword + */ + +iskw(s) + register char *s; +{ + register char **ss = l_keywds; + register int i = 1; + register char *cp = s; + register int firstc = *s; + + while (++cp, isidchr(*cp)) + i++; + while (cp = *ss++) { + if (!l_onecase && firstc != *cp) + continue; + if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i])) + return (i); + } + return (0); +} diff --git a/support/tgrind/tgrind.1 b/support/tgrind/tgrind.1 new file mode 100644 index 0000000000..357d2fea6e --- /dev/null +++ b/support/tgrind/tgrind.1 @@ -0,0 +1,103 @@ +.TH TGRIND 1 +.UC 4 +.SH NAME +tgrind \- grind nice program listings using TeX +.SH SYNOPSIS +.B tgrind +[ +.B \-f +] [ +.B \- +] [ +.B \-n +] [ +.B \-h +header +] [ +.B \-d +<description file> +] [ +.B \-l<language> +] +name ... +.SH DESCRIPTION +.I Tgrind +formats program sources in a nice style using +.IR TeX(1) . +Comments are placed in italics, keywords in bold face and strings in +typewriter font. +Source file line numbers appear in the right margin (every 10 lines). +The start of a function is indicated by the function name in large +type in the right margin. +.PP +In regular mode +.I tgrind +processes its input file(s) and passes them to +.I TeX(1) +for formating and output. +.PP +In format mode (i.e., when the +.B -f +flag is used), +.I tgrind +processes its input file(s) and writes the result to standard output. +This output can be saved for later editting, inclusion in a larger +document, etc. +.PP +The options are: +.IP \-f +forces format mode +.IP \- +take input from standard input +.IP \-n +don't boldface keywords +.IP \-h +specifies text to go on the left side of every output page (default is none) +.IP \-d +specifies the language definitions file (default is /usr/local/lib/vgrindefs) +.IP \-l +specifies the language to use. Currently known are PASCAL (-lp), RATFOR (-lr), +Modula-2 (-lm2), MODEL (-lm), C (-lc or the default), ISP (-li), +Yacc (-ly), Prolog (-lprolog), Icon (-lI), TeX (-ltex), CSH (-lcsh), and +Bourne Shell (-lsh). +.SH FILES +.ta 2i +tgrindmac.tex macro package +.br +/usr/local/lib/tfontedpr preprocessor +.br +/usr/local/lib/vgrindefs language descriptions +.SH AUTHOR +Van Jacobson, Lawrence Berkeley Laboratory (based on "vgrind" +by Dave Presotto & William Joy of UC Berkeley). +.SH SEE ALSO +tex(1), vgrind(1), vgrindefs(5) +.SH BUGS +.PP +The marginal\-function\-name mechanism depends on the quality +of the language description in +.IR vgrindefs . +The distributed +.I vgrindefs +fails to recognize many legal C function declarations. +.PP +Arbitrary formatting styles for programs mostly look bad. +The use of spaces to align source code often fails miserably (because +of the variable width output font). If you plan to +.I tgrind +your program, try to use tabs. +.PP +The indexing option of +.I vgrind +is missing. However, nice indices can be generated using the +.B -v +option of +.I ctags +together with appropriate TeX macros. +.PP +The +.B -f +flag means different things to +.I tgrind +and +.IR vgrind . diff --git a/support/tgrind/tgrind.sh b/support/tgrind/tgrind.sh new file mode 100644 index 0000000000..ed66ec561c --- /dev/null +++ b/support/tgrind/tgrind.sh @@ -0,0 +1,101 @@ +#! /bin/csh +# Script to grind nice program listings using TeX. +# +# written Feb, 1985 by Van Jacobson, Lawrence Berkeley Laboratory (adapted +# from the 4.2bsd "vgrind" script). +# +# Since TeX output handling is site dependent, you'll have to edit this +# file to get output to your local typesetting device(s). Our site uses +# the flags "-v" (versatec output), "-q" (qms output) and "-k" (keep dvi file) +# to route output. Put something appropriate to your site at the "PUT OUTPUT +# HANDLING..." comment at the end of this script. If you've already dealt +# with this in your local tex command, just change the -v/q/k (or whatever) +# cases in the first "switch" to set variable "texoptions" appropriately. +# +set b=/usr/local/lib/tfontedpr +set tex=/usr/local/bin/tex +set options= +set texoptions= +set files= +set head="" +set format="" +set output="ver" +top: +if ($#argv > 0) then + switch ($1:q) + + case -d: + if ($#argv < 2) then + echo "tgrind: $1:q option must have argument" + goto done + else + set options = ($options $1:q $2) + shift + shift + goto top + endif + + case -f: + set format="Y" + shift + goto top + + case -h: + if ($#argv < 2) then + echo "tgrind: $1:q option must have argument" + goto done + else + set head="$2" + shift + shift + goto top + endif + + case -v: + set output="ver" + shift + goto top + + case -q: + set output="qms" + shift + goto top + + case -k: + set output="" + shift + goto top + + case -*: + set options = "$options $1:q" + shift + goto top + + default: + set files = "$files $1:q" + shift + goto top + endsw +endif + +if ("$format" == "Y") then + if ("$head" != "") then + $b $options -h "$head" $files + else + $b $options $files + endif + goto done +endif + +if ("$head" != "") then + $b $options -h "$head" $files >/tmp/$$.tex +else + $b $options $files >/tmp/$$.tex +endif +cd /tmp +$tex $texoptions $$.tex + +# PUT OUTPUT HANDLING COMMANDS HERE. +/usr/local/bin/iptex $$ +rm -f $$.tex $$.dvi $$.log +done: diff --git a/support/tgrind/tgrindmac.tex b/support/tgrind/tgrindmac.tex new file mode 100644 index 0000000000..32d904dcba --- /dev/null +++ b/support/tgrind/tgrindmac.tex @@ -0,0 +1,139 @@ +% @(#)tgrindmac.tex 1.4 (LBL) 3/30/85 +% Macros for TeX "tgrind" (a TeX equivalent of 4bsd "vgrind"). +% +% Copyright (C) 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. +% +% Please send improvements, bug fixes, comments, etc., to +% van@lbl-rtsg.arpa +% ...ucbvax!lbl-csam!van +% +% Modifications. +% -------------- +% 10Feb85, vj Written. +% 23Mar85, rf Substitute ambx10 for amb10 +% 29Mar85, Chris Torek: Use tt font for all characters in strings. +% Print decent quotes in comments rather than use tt +% font quotes. Show filename (to terminal & log file) +% at start of each new file. +% 30Mar85, vj Fixed bug in tabbing. + +\font\sevenrm=amr7 % font for right margin line numbers +\font\twelvebf=ambx10 scaled \magstep1 % font for page headers +\font\forteenrm=amr10 scaled \magstep2 % font for right margin proc names + +% tfontedpr outputs a "\Head{Hdr text}" if you give it the "-h" flag. +% We remember the text in "\Header" so it can be included in the +% head line. +\def\Head#1{\def\Header{#1}} +\def\Header{\null} + +% We get a "\File{Filename},{Last Mod Time},{Last Mod Date}" at the start of +% each new file. We remember this stuff for inclusion in the page head & foot. +% We reset the page number & current line number to 0 and output a null +% mark to let the output routine know we're starting a new file. +% We set up the \headline & \footline token lists inside the File macro to +% save remembering the filename & mod time with yet other macros. +\def\File#1,#2,#3{\vfill\eject\mark{\empty} +\global\linecount=0\linenext=9\pageno=1\message{#1} +\headline={\twelvebf\Header\hfil +\edef\a{\topmark}\edef\b{\botmark}\edef\c{\firstmark} +\ifx\c\empty\botmark\else +\ifx\a\empty\botmark\else +\ifx\b\empty\topmark\else +\ifx\a\b\topmark\else\topmark--\botmark\fi +\fi\fi\fi(#1)} +\footline={\it{}#2 #3\hfil{}Page \folio{} of #1}} + +% There's a "\Proc{Proc Name}" at the start of each procedure. If +% the language definition allows nested procedures (e.g., pascal), there +% will be a "\ProcCont{Proc Name}" at the end of each inner procedure. +% (In this case, "proc name" is the name of the outer procedure. I.e., +% ProcCont marks the continuation of "proc name"). +\def\Proc#1{\global\def\Procname{#1}\global\setbox\procbox=\hbox{\forteenrm #1}} +\def\ProcCont#1{\global\def\Procname{#1} +\global\setbox\procbox=\hbox{\forteenrm$\ldots$#1}} +\newbox\procbox +\def\Procname{\null} + +% Each formfeed in the input is replaced by a "\NewPage" macro. If +% you really want a page break here, define this as "\vfill\eject". +\def\NewPage{\filbreak\bigskip} + +% Each line of the program text is enclosed by a "\L{...}". We turn +% each line into an hbox of size hsize. If we saw a procedure name somewhere +% in the line (i.e., "procbox" is not null), we right justify "procbox" +% on the line. Every 10 lines we output a small, right justified line number. +\def\L#1{\filbreak\hbox to \hsize{\CF\strut\global\advance\linecount by1 +#1\hss\ifvoid\procbox\linebox\else\box\procbox\mark{\Procname}\fi}} + +\newcount\linecount \linecount=0 +\newcount\linenext \linenext=9 +\def\linebox{\ifnum\linecount>\linenext\global\advance\linenext by10 +\hbox{\sevenrm\the\linecount}\fi} + + +% The following weirdness is to deal with tabs. "Pieces" of a line +% between tabs are output as "\LB{...}". E.g., a line with a tab at +% column 16 would be output as "\LB{xxx}\Tab{16}\LB{yyy}". (Actually, to +% reduce the number of characters in the .tex file the \Tab macro +% supplies the 2nd & subsequent \LB's.) We accumulate the LB stuff in an +% hbox. When we see a Tab, we grab this hbox (using "\lastbox") and turn +% it into a box that extends to the tab position. We stash this box in +% "\linesofar" & use "\everyhbox" to get \linesofar concatenated onto the +% front of the next piece of the line. (There must be a better way of +% doing tabs [cf., the Plain.tex tab macros] but I'm not not enough of a +% TeX wizard to come up with it. Suggestions would be appreciated.) + +\def\LB{\CF\hbox} +\newbox\linesofar\setbox\linesofar=\null +\everyhbox={\box\linesofar} +\newdimen\TBwid +\def\Tab#1{\setbox\tbox=\lastbox\TBwid=1\wd\tbox\advance\TBwid by 1\ts +\ifdim\TBwid>#1\ts +\setbox\linesofar=\hbox{\box\tbox\space}\else +\setbox\linesofar=\hbox to #1\ts{\box\tbox\hfil}\fi\LB} + +% A normal space is too thin for code listings. We make spaces & tabs +% be in "\ts" units (which are the width of a "0" in the current font). +\newdimen\ts +\newbox\tbox +\setbox\tbox=\hbox{0} \ts=1\wd\tbox \setbox\tbox=\hbox{\hskip 1\ts} +\def\space{\hskip 1\ts\relax} + +% Font changing stuff for keywords, comments & strings. We put keywords +% in boldface, comments in text-italic & strings in typewriter. Since +% we're usually changing the font inside of a \LB macro, we remember the +% current font in \CF & stick a \CF at the start of each new box. +% Also, the characters " and ' behave differently in comments than in +% code, and others behave differently in strings than in code. +\newif\ifcomment\newif\ifstring +\let\CF=\rm +\def\K#1{{\bf #1}} % Keyword +\def\C{\it\global\let\CF=\it\global\commenttrue\relax} % Comment Start +\def\CE{\rm\global\let\CF=\rm\global\commentfalse\relax}% Comment End +\def\S{\tt\global\let\CF=\tt\global\stringtrue\relax} % String Start +\def\SE{\rm\global\let\CF=\rm\global\stringfalse\relax} % String End + +% Special characters. +\def\{{\ifmmode\lbrace\else\ifstring{\char'173}\else$\lbrace$\fi\fi} +\def\}{\ifmmode\rbrace\else\ifstring{\char'175}\else$\rbrace$\fi\fi} +\def\!{\ifmmode\backslash\else\ifstring{\char'134}\else$\backslash$\fi\fi} +\def\|{\ifmmode|\else\ifstring{\char'174}\else$|$\fi\fi} +\def\<{\ifmmode<\else\ifstring<\else$<$\fi\fi} +\def\>{\ifmmode>\else\ifstring>\else$>$\fi\fi} +\def\/{\ifmmode/\else\ifstring/\else$/$\fi\fi} +\def\-{\ifmmode-\else\ifstring-\else$-$\fi\fi} +\def\_{\ifstring{\char'137}\else\underbar{\ }\fi} +\def\&{{\char'046}} +\def\#{{\char'043}} +\def\%{{\char'045}} +\def\~{{\char'176}} +\def\"{\ifcomment''\else{\tt\char'042}\fi} +\def\'{\ifcomment'\else{\tt\char'047}\fi} +\def\^{{\char'136}} +\def\${{\rm\char'044}} + +\raggedright\obeyspaces\let =\space% diff --git a/support/tgrind/vgrindefs.c b/support/tgrind/vgrindefs.c new file mode 100644 index 0000000000..bc969a3507 --- /dev/null +++ b/support/tgrind/vgrindefs.c @@ -0,0 +1,297 @@ +#ifndef lint +static char sccsid[] = "@(#)vgrindefs.c 4.3 (Berkeley) 12/11/84"; +#endif + +/* Copyright (c) 1979 Regents of the University of California */ + +#define BUFSIZ 1024 +#define MAXHOP 32 /* max number of tc= indirections */ + +#include <ctype.h> +/* + * grindcap - routines for dealing with the language definitions data base + * (code stolen almost totally from termcap) + * + * BUG: Should use a "last" pointer in tbuf, so that searching + * for capabilities alphabetically would not be a n**2/2 + * process when large numbers of capabilities are given. + * Note: If we add a last pointer now we will screw up the + * tc capability. We really should compile termcap. + * + * Essentially all the work here is scanning and decoding escapes + * in string capabilities. We don't use stdio because the editor + * doesn't, and because living w/o it is not hard. + */ + +static char *tbuf; +static char *filename; +static int hopcount; /* detect infinite loops in termcap, init 0 */ +char *tskip(); +char *tgetstr(); +char *tdecode(); +char *getenv(); + +/* + * Get an entry for terminal name in buffer bp, + * from the termcap file. Parse is very rudimentary; + * we just notice escaped newlines. + */ +tgetent(bp, name, file) + char *bp, *name, *file; +{ + register char *cp; + register int c; + register int i = 0, cnt = 0; + char ibuf[BUFSIZ]; + char *cp2; + int tf; + + tbuf = bp; + tf = 0; + filename = file; + tf = open(filename, 0); + if (tf < 0) + return (-1); + for (;;) { + cp = bp; + for (;;) { + if (i == cnt) { + cnt = read(tf, ibuf, BUFSIZ); + if (cnt <= 0) { + close(tf); + return (0); + } + i = 0; + } + c = ibuf[i++]; + if (c == '\n') { + if (cp > bp && cp[-1] == '\\'){ + cp--; + continue; + } + break; + } + if (cp >= bp+BUFSIZ) { + write(2,"Vgrind entry too long\n", 23); + break; + } else + *cp++ = c; + } + *cp = 0; + + /* + * The real work for the match. + */ + if (tnamatch(name)) { + close(tf); + return(tnchktc()); + } + } +} + +/* + * tnchktc: check the last entry, see if it's tc=xxx. If so, + * recursively find xxx and append that entry (minus the names) + * to take the place of the tc=xxx entry. This allows termcap + * entries to say "like an HP2621 but doesn't turn on the labels". + * Note that this works because of the left to right scan. + */ +tnchktc() +{ + register char *p, *q; + char tcname[16]; /* name of similar terminal */ + char tcbuf[BUFSIZ]; + char *holdtbuf = tbuf; + int l; + + p = tbuf + strlen(tbuf) - 2; /* before the last colon */ + while (*--p != ':') + if (p<tbuf) { + write(2, "Bad vgrind entry\n", 18); + return (0); + } + p++; + /* p now points to beginning of last field */ + if (p[0] != 't' || p[1] != 'c') + return(1); + strcpy(tcname,p+3); + q = tcname; + while (q && *q != ':') + q++; + *q = 0; + if (++hopcount > MAXHOP) { + write(2, "Infinite tc= loop\n", 18); + return (0); + } + if (tgetent(tcbuf, tcname, filename) != 1) + return(0); + for (q=tcbuf; *q != ':'; q++) + ; + l = p - holdtbuf + strlen(q); + if (l > BUFSIZ) { + write(2, "Vgrind entry too long\n", 23); + q[BUFSIZ - (p-tbuf)] = 0; + } + strcpy(p, q+1); + tbuf = holdtbuf; + return(1); +} + +/* + * Tnamatch deals with name matching. The first field of the termcap + * entry is a sequence of names separated by |'s, so we compare + * against each such name. The normal : terminator after the last + * name (before the first field) stops us. + */ +tnamatch(np) + char *np; +{ + register char *Np, *Bp; + + Bp = tbuf; + if (*Bp == '#') + return(0); + for (;;) { + for (Np = np; *Np && *Bp == *Np; Bp++, Np++) + continue; + if (*Np == 0 && (*Bp == '|' || *Bp == ':' || *Bp == 0)) + return (1); + while (*Bp && *Bp != ':' && *Bp != '|') + Bp++; + if (*Bp == 0 || *Bp == ':') + return (0); + Bp++; + } +} + +/* + * Skip to the next field. + */ +static char * +tskip(bp) + register char *bp; +{ + + register char c; + + while (c = *bp++) { + if (c == ':' && *(bp-1) != '\\') + break; + } + + if (*bp == ':') + bp++; + return (bp); +} + +/* + * Return the (numeric) option id. + * Numeric options look like + * li#80 + * i.e. the option string is separated from the numeric value by + * a # character. If the option is not found we return -1. + * Note that we handle octal numbers beginning with 0. + */ +tgetnum(id) + char *id; +{ + register int i, base; + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (*bp == 0) + return (-1); + if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) + continue; + if (*bp == '@') + return(-1); + if (*bp != '#') + continue; + bp++; + base = 10; + if (*bp == '0') + base = 8; + i = 0; + while (isdigit(*bp)) + i *= base, i += *bp++ - '0'; + return (i); + } +} + +/* + * Handle a flag option. + * Flag options are given "naked", i.e. followed by a : or the end + * of the buffer. Return 1 if we find the option, or 0 if it is + * not given. + */ +tgetflag(id) + char *id; +{ + register char *bp = tbuf; + + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (*bp++ == id[0] && *bp != 0 && *bp++ == id[1]) { + if (!*bp || *bp == ':') + return (1); + else if (*bp == '@') + return(0); + } + } +} + +/* + * Get a string valued option. + * These are given as + * cl=^Z + * Much decoding is done on the strings, and the strings are + * placed in area, which is a ref parameter which is updated. + * No checking on area overflow. + */ +char * +tgetstr(id, area) + char *id, **area; +{ + register char *bp = tbuf; + for (;;) { + bp = tskip(bp); + if (!*bp) + return (0); + if (*bp++ != id[0] || *bp == 0 || *bp++ != id[1]) + continue; + if (*bp == '@') + return(0); + if (*bp != '=') + continue; + bp++; + return (tdecode(bp, area)); + } +} + +/* + * Tdecode does the grung work to decode the + * string capability escapes. + */ +static char * +tdecode(str, area) + register char *str; + char **area; +{ + register char *cp; + register int c; + int i; + + cp = *area; + while (c = *str++) { + if (c == ':' && *(cp-1) != '\\') + break; + *cp++ = c; + } + *cp++ = 0; + str = *area; + *area = cp; + return (str); +} diff --git a/support/tgrind/vgrindefs.src b/support/tgrind/vgrindefs.src new file mode 100644 index 0000000000..d04d94c6b1 --- /dev/null +++ b/support/tgrind/vgrindefs.src @@ -0,0 +1,128 @@ +model|mod|m:\ + :pb=^\d(space\d\p\drep)|(\p\dis|inline|public\dbeginproc):\ + :bb=\dbeginproc|space|case\d:be=\dendproc|end\d|;:\ + :cb=\$:ce=\$|$:sb=":se=":lb=':le=\a|$:\ + :kw=abs and array beginproc boolean by case cdnl char copied dispose\ + div do dynamic else elsif end endproc entry external FALSE false\ + fi file for formal fortran global if iff ift\ + in integer include inline is lbnd\ + max min mod new NIL nil noresult not notin od of or procedure public\ + read readln readonly record recursive rem rep repeat res\ + result return set\ + space string subscript such then TRUE true type ubnd union until\ + varies while width: +pascal|pasc|p:\ + :pb=(^\d?procedure|function|program\d\p\d|\(|;|\:)|(=\d?record\d):\ + :bb=\dcase|begin\d:be=\dend|forward\d|;:\ + :oc:\ + :cb={:ce=}:ab=\(*:ae=*\):\ + :sb=':se=':lb=":le=":\ + :kw=and array assert begin case const div do downto else end file for\ + forward function goto if in label mod nil not of or packed procedure\ + program record repeat set then to type until var while with oct hex\ + external: +Icon|icon|I:\ + :pb=^\d?procedure\d\p\d?\(\a?\):\ + :bb=(^\d?procedure\d\p\d?\(\a?\))|{:be=}|(^\d?end\d?$):\ + :cb=#:ce=$:\ + :sb=":se=\e":lb=':le=\e':tl:\ + :kw=break by case create default do dynamic else end every external\ + fail global if initial local next not of procedure record\ + repeat return static suspend then to until using while\ + &ascii &clock &cset &date &dateline &errout &fail &host &input\ + &lcase &level &main &null &output &pos &random &source &subject\ + &time &trace &ucase &version: +C|c:\ + :pb=^\d?*?\d?\p\d?\(\a?\)(\d|{):bb={:be=}:cb=/*:ce=*/:sb=":se=\e":lb=':\ + :le=\e':tl:\ + :kw=asm auto break case char continue default do double else enum\ + extern float for fortran goto if int long register return short\ + sizeof static struct switch typedef union unsigned void while #define\ + #else #endif #if #ifdef #ifndef #include #undef # define else endif\ + if ifdef ifndef include undef: +ISP|isp|i:\ + :cb=!:ce=!|$:oc:\ + :kw=and begin decode define end eql eqv geq gtr if leave leq lss mod\ + neq next not or otherwise repeat restart resume sr0 sr1 srd srr sl0 sl1\ + sld slr tst xor: +SH|sh:\ + :bb={:be=}:cb=#:ce=$:sb=":se=\e":lb=':\ + :le=\e':tl:\ + :kw=break case cd continue do done \ + elif else esac eval exec exit export \ + fi for if in then while until \ + read readonly set shift test trap umask wait: +CSH|csh:\ + :bb={:be=}:cb=#:ce=$:sb=":se=\e":lb=':\ + :le=\e':tl:\ + :kw=alias alloc break breaksw case cd chdir continue default\ + echo else end endif endsw exec exit foreach \ + glob goto history if logout nice nohup onintr repeat set\ + setenv shift source switch then time \ + while umask unalias unset wait while @ env \ + argv child home ignoreeof noclobber noglob \ + nomatch path prompt shell status verbose : +ldl|LDL:\ + :pb=^\p\::bb=\::be=;:cb=/*:ce=*/:sb=":se=\e":\ + :kw=constant functions grammar reswords tokens add1 addste\ + car cdr check colno cond cons copy defun divide empty enter\ + eq equal findattr firstchild ge getattr getfield gt hash label\ + lambda lastchild le leftsibling lookone lookup lt minus name ne\ + newnode nextcom nil null parent plus precnl prevcom prog progn\ + quote reglob return rightsibling self set setattr setfield setq\ + stjoin sub1 t times tnull tokno ttype: +TEX|tex:\ + :bb={:be=}:cb=%:ce=$:kw=: +SOURCE|source|src:\ + :kw=: +Miranda|mira:\ + :pb=^\d?\p\d?\:\::be==:cb=\|\|:ce=$:sb=":se=\e":lb=':le=\e':\ + :kw=abstype div rem type where with %export %free %include %insert %list %nolist: +prolog|PROLOG:\ + :bb=\:-:be=.:cb=%:ce=$:ab=/*:ae=*/:\ + :sb=":se=\e":lb=':le=\e':oc:\ + :kw=op mod abort ancestors arg ascii ask assert asserta assertz\ + atom atomic char clause close concat consult ed ef em eof fail\ + file findall write functor getc integer is length listing load name\ + nl nonvar not numbervars op or pp prin print private prompt putc\ + ratom read read_from_this_file rename repeat retract retractall\ + save see seeing seen sh skip statistics subgoal_of system tab\ + tell telling time told trace true unload untrace var write: +r|R|ratfor:\ + :pb=^\d?program|subroutine|function|(integer|real|complex|character\dfunction)\d\p\d|\(:\ + :bb={:be=}:cb=#:ce=$:sb=":se=":lb=':le=':oc:\ + :kw= break call case character common complex data default define\ + dimension do else end equivalence external false for function go\ + goto if implicit include integer logical next pause program read\ + real repeat return rewind stop string subroutine switch true until\ + while write: +modula2|mod2|m2:\ + :pb=(^\d?(procedure|function|module)\d\p\d|\(|;|\:):\ + :bb=\d(begin|case|for|if|loop|record|repeat|while|with)\d:\ + :be=\dend|;:\ + :cb={:ce=}:\ + :ab=\(*:ae=*\):\ + :sb=":se=":\ + :oc:\ + :kw=and array begin by case const\ + definition div do else elsif end exit export\ + for from if implementation import in\ + loop mod module not of or pointer procedure qualified\ + record repeat return set then to type\ + until var while with: +yacc|Yacc|y:\ + :cb=/*:ce=*/:sb=":se=\e":lb=':le=\e':tl:\ + :kw=%{ %} %% %union %token %type\ + #else #endif #if #ifdef #ifndef #include #undef # define else endif\ + if ifdef ifndef include undef: +asm68:\ + :pb=(^\d?.proc\d\p\d:\ + :oc:\ + :cb=;:ce=$:\ + :sb=':se=':lb=":le=":\ + :kw=ascii block byte end equ include long proc word: +a68:\ + :oc:\ + :cb=\|:ce=$:\ + :sb=':se=':lb=":le=":\ + :kw=ascii block byte end equ globl insrt long proc text word: |