[net.sources] yacsfp

robert@gitpyr.UUCP (Robert Viduya) (12/13/84)

}{
The following is a program I've written to print out C source files.
The program will highlight, by boldfacing and/or underlining, reserved
words and identifiers.  It also produces a cross reference, line numbers
its output, and tracks nesting levels.  It then pipes the whole mess
through pr(1) to produce page headings.

			robert

-------------------------decapitate-here------------------------
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	Makefile
#	clst.1
#	clst.l
sed 's/^X//' << '--burp--' > Makefile
X#
X# Makefile for clst
X#
X
X#
X# The following need to be set to the proper directories:
X#	BINDIR		- binary home directory
X#	MANDIR		- manual page home directory (unformatted)
X#	CATDIR		- manual page home directory (formatted)
X# or you can just get rid of them, as well as the 'install' target.
X#
XBINDIR = $$HOME/bin
XMANDIR = $$HOME/man/src
XCATDIR = $$HOME/man
X
X#
X# option flags
X#
XCFLAGS = -O
XLFLAGS = -n
X
Xclst: clst.o
X	cc clst.o $(CFLAGS) -ll -o clst
X    
Xclst.o: clst.l
X
Xinstall: clst clst.1
X	cp clst $(BINDIR)
X	nroff -man clst.1 | col > $(CATDIR)/clst
X	cp clst.1 $(MANDIR)
X	touch install
X
Xclean:
X	rm -f *.c *.o clst
--burp--
sed 's/^X//' << '--burp--' > clst.1
X.TH CLST 1-rtv local GaTech "Georgia Institute of Technology"
X.SH NAME
Xclst \- format C source files for printing
X.SH ORIGIN
XFrom the terminal of Robert Viduya.
X.br
XGeorgia Institute of Technology
X.SH SYNOPSIS
X.br
X.BR clst
X	[
X.B \-ru
X|
X.B \-rn
X|
X.B \-rb
X]
X.br
X		[
X.B \-ub
X|
X.B \-un
X|
X.B \-uu
X]
X.br
X		[
X.B \-on
X|
X.B \-ob
X|
X.B \-ou
X]
X.br
X		[
X.B \-nx
X]
X.br
X		[
X.B \-tn
X]
X.br
X		[
X.B \-lpp
X.I n
X]
X.br
X		[
X.I files...
X]
X.SH DESCRIPTION
X.I Clst
Xformats the C source files given as arguments for printing.
XIf no files are specified,
X.I clst
Xreads standard input.
XA "\-" may be specified in the list of files to mean standard input.
XVarious options control how the files are printed.
X.I Clst
Xprocesses the files highlighting reserved symbols and user symbols by underlining
Xand boldfacing.
XIt also produces a cross reference of user symbols.
X.I Clst
Xthen pipes the result through
X.I pr(1)
Xto generate page headers for printing.
XA number of options are available to control
X.I clst.
X.PP
XThe options to
X.I clst
Xare:
X.TP 20n
X.B \-ru
Xunderline reserved symbols (default).
X.TP
X.B \-rb
Xboldface reserved symbols.
X.TP
X.B \-rn
Xprint reserved symbols normally.
X.TP
X.B \-ub
Xboldface user defined symbols (default).
X.TP
X.B \-uu
Xunderline user defined symbols.
X.TP
X.B \-un
Xprint user defined symbols normally.
X.TP
X.B \-on
Xprint other symbols normally (default).
XOther symbols are those symbols not recognized as either reserved symbols or
Xuser symbols.
X.TP
X.B \-ob
Xboldface other symbols.
X.TP
X.B \-ou
Xunderline other symbols.
X.TP
X.B \-nx
Xdo not print a cross reference (default is to print a cross reference).
X.TP
X.B \-tn
Xtrack '{' and '}' nesting level (default is to not track the nesting levels).
X.TP
X.B \-lpp \fIn\fR
Xset lines-per-page to \fIn\fR (default is 66).
X.PP
X.I Clst
Xexpects it's input to be valid C source files and will get hopelessly
Xconfused if fed anything else.
X.SH SEE ALSO
Xpr(1)
X.SH DIAGNOSTICS
X(Hopefully) self-explanatory.
X.SH BUGS
XConflicting options are not always caught.
XIn this case, the last of the conflicting options is in effect and the previous are ignored.
X.PP
XThe cross reference facility does not take into account variable scoping levels.
XIt treats all variables with the same name as one and the same irregardless of
Xthe fact that they may be actually distinct.
X.PP
--burp--
sed 's/^X//' << '--burp--' > clst.l
X%{
X/*
X * clst:	format C programs for printing
X *
X *	Robert Viduya
X *	Georgia Institute of Technology
X *	Dec 13, 1984
X *
X * Clst is a lex/c program that formats C source files for printing.
X * The program reads the source files, prefixes each line with a
X * line number (and, optionally, the current nesting level), high-
X * lights identifiers and reserved words by either boldfacing or
X * underlining and produces a cross reference of identifiers.  Clst
X * then sends the files through pr(1) to provide page headers and
X * page numbering.
X *
X */
X
X#include <strings.h>
X#define bool	char
X#define TRUE	1
X#define FALSE	0
X
X/* the following are data structures for the cross referencing */
Xstruct	NUMBERNODE {	/* linked list - identifier line number */
X    int			number;		/* line number */
X    struct NUMBERNODE	*nextnode;	/* ptr to next node */
X};
Xstruct 	IDENTNODE {	/* linked list - identifiers */
X    char		*ident;		/* ptr to identifier */
X    struct NUMBERNODE	*lnums;		/* ptr to list of line numbers */
X    struct IDENTNODE	*nextnode;	/* ptr to next node */
X};
Xstruct	IDENTNODE	*idents = NULL;	/* head of list */
Xbool	doxref		= TRUE;
X
X/* the following control how to print things */
Xenum	how_to_print {
X    NORMAL,		/* print normally */
X    BOLD,		/* print emboldened (overstrike) */
X    ULINE		/* print underlined */
X};
Xenum how_to_print usersymbol	 = BOLD;   /* how to print identifiers */
Xenum how_to_print reservedsymbol = ULINE;  /* how to print reserved symbols */
Xenum how_to_print othersymbol	 = NORMAL; /* how to print anything else */
X
X/* the following control tracking the nesting level */
Xbool	tracknest	= FALSE;	/* TRUE if we're currently tracking */
Xint	nestlevel	= 0;		/* current nesting level */
X
X/* argument processing variables */
Xint	findex;			/* index into Argv of current file */
Xint	Argc;			/* set to argc from main() */
Xchar	**Argv;			/* set to argv from main() */
X
X/* pr command for piping stuff */
Xchar		PRCMD[100];	/* psuedo constant, set to user's options */
Xchar		prcmd[100];	/* PRCMD, but heading as current filename */
Xextern FILE	*popen();
X
X/* stream i/o variables */
XFILE	*instream;	/* current file being processed */
XFILE	*outstream;	/* pr command pipe */
X
X/* lex i/o handlers */
X#undef	input()
X#undef	output(c)
X#undef	unput(c)
X#define	MAXBUF	100
Xchar	buffer[MAXBUF];		/* lex push back buffer */
Xchar	bufc;			/* next char read */
Xshort	bufp		= -1;	/* buf index, -1 = empty */
X#define input()	((bufp<0)?(((bufc=getc(instream))==EOF)?0:bufc):(buffer[bufp--]))
X#define unput(c) {buffer[++bufp]=(c);if(bufp>=MAXBUF){fputs("clst: push back buffer overflow\n",stderr);exit(1);}}
X#define output(c) {fputs("clst: invalid char, can't happen\n",stderr);exit(1);}
X
X/* miscellany */
Xint	linenumber	= 1;		/* current line number */
Xbool	incomment	= FALSE;	/* TRUE if currently in a comment */
X
X
X%}
X%%
X
X"sizeof"		|
X"auto"			|
X"static"		|
X"extern"		|
X"register"		|
X"typedef"		|
X"char"			|
X"short"			|
X"int"			|
X"long"			|
X"unsigned"		|
X"float"			|
X"double"		|
X"struct"		|
X"union"			|
X"if"			|
X"else"			|
X"while"			|
X"do"			|
X"for"			|
X"switch"		|
X"case"			|
X"default"		|
X"break"			|
X"continue"		|
X"return"		|
X"goto"			|
X"#define"		|
X"#undef"		|
X"#include"		|
X"#if"			|
X"#ifdef"		|
X"#ifndef"		|
X"#else"			|
X"#endif"		|
X"#line"			|
X"enum"			{   /* reserved words */
X			    if (incomment)
X				printsymbol(yytext,othersymbol);
X			    else
X				printsymbol(yytext,reservedsymbol);
X			}
X
X[a-zA-Z_][a-zA-Z0-9_]*	{   /* identifiers */
X			    if (incomment)
X				printsymbol(yytext,othersymbol);
X			    else {
X				printsymbol(yytext,usersymbol);
X				if (doxref)	/* add to list */
X				    addident(yytext);
X			    }
X			}
X
X[1-9][0-9]*		|
X"0"(x|X)[0-9a-fA-F]+	|
X"0"[0-9]*		{   /* numeric constants */
X			    printsymbol(yytext,othersymbol);
X			}
X
X\"(\\\"|[^\n"])*\"	{   /* string constants */
X			    if (incomment)
X				printsymbol(yytext,othersymbol);
X			    else {
X				printsymbol("\"",reservedsymbol);
X				yytext[yyleng-1] = '\0';
X				printsymbol(&yytext[1],othersymbol);
X				printsymbol("\"",reservedsymbol);
X			    }
X			}
X
X'(\\'|[^\n'])*'		{   /* character constants */
X			    if (incomment)
X				printsymbol(yytext,othersymbol);
X			    else {
X				printsymbol("'",reservedsymbol);
X				yytext[yyleng-1] = '\0';
X				printsymbol(&yytext[1],othersymbol);
X				printsymbol("'",reservedsymbol);
X			    }
X			}
X
X"{"			{   /* nesting level */
X			    if (incomment)
X				printsymbol(yytext,othersymbol);
X			    else {
X				printsymbol(yytext,reservedsymbol);
X				if (tracknest)
X				    nestlevel++;
X			    }
X			}
X
X"}"			{   /* nesting level */
X			    if (incomment)
X				printsymbol(yytext,othersymbol);
X			    else {
X				printsymbol(yytext,reservedsymbol);
X				if (tracknest)
X				    nestlevel--;
X			    }
X			}
X
X"/*"			{   /* comment */
X			    printsymbol(yytext,reservedsymbol);
X			    incomment = TRUE;
X			}
X
X"*/"			{   /* comment */
X			    printsymbol(yytext,reservedsymbol);
X			    incomment = FALSE;
X			}
X
X[ \t\f]+		{   /* white space */
X			    printsymbol(yytext,NORMAL);
X			}
X
X\n			{   /* new line */
X			    linenumber++;
X			    if (tracknest)
X				fprintf(outstream,"\n%4d  %8d: ",nestlevel,linenumber);
X			    else
X				fprintf(outstream,"\n%6d: ",linenumber);
X			}
X
X.			{   /* anything else */
X			    if (incomment)
X				printsymbol(yytext,othersymbol);
X			    else
X				printsymbol(yytext,reservedsymbol);
X			}
X%%
X
X/* print a symbol */
Xprintsymbol(symbol,type)
Xregister char		*symbol;
Xenum how_to_print	type;
X{
X    while (*symbol) {
X	pchar(*symbol,type);
X	symbol++;
X    }
X}
X
X/* print a character.  Handle boldfacing/underlining. */
Xpchar(c,type)
Xchar			c;
Xenum how_to_print	type;
X{
X    switch (type) {
X	case NORMAL:
X	    putc(c,outstream);
X	    break;
X        case BOLD:
X	    putc(c,outstream);
X	    putc('\b',outstream);
X	    putc(c,outstream);
X	    break;
X        case ULINE:
X	    putc('_',outstream);
X	    putc('\b',outstream);
X	    putc(c,outstream);
X	    break;
X	default:	/* whoops! die */
X	    fprintf(stderr,"clst: unknown symbol type: %c\n",c);
X	    exit(1);
X    }
X}
X
X/* print the cross reference */
Xprintxref()
X{
X    struct IDENTNODE	*iptr,*oiptr;
X    struct NUMBERNODE	*nptr,*onptr;
X    int			cntr;
X
X    fprintf(outstream,"\f\n");		/* force new page */
X    iptr = idents;
X    while (iptr != NULL) {	/* scan identifier list */
X	fprintf(outstream,"%-20.20s  ",iptr->ident);
X	cntr = 0;
X	nptr = iptr->lnums;
X	while (nptr != NULL) {	/* scan line number list */
X	    fprintf(outstream,"%5d  ",nptr->number);
X	    cntr = (++cntr) % 8;
X	    if ((!cntr) && (nptr->nextnode != NULL))
X		fprintf(outstream,"\n%-20.20s  "," ");
X	    onptr = nptr;
X	    nptr = nptr->nextnode;
X	    free(onptr);
X	}
X	putc('\n',outstream);
X	free(iptr->ident);
X	oiptr = iptr;
X	iptr = iptr->nextnode;
X	free(oiptr);
X    }
X    idents = NULL;
X}
X
X/* finish up processing a file, start next file */
Xyywrap()
X{
X
X    putc('\n',outstream);
X
X    if (doxref)
X	printxref();
X
X    if (fclose(instream)) {
X	fprintf(stderr,"clst: can't close input file ``%s''\n",Argv[findex]);
X	exit(1);
X    }
X    if (pclose(outstream)) {
X	fprintf(stderr,"clst: can't close pipe\n");
X	exit(1);
X    }
X
X    do {
X	findex++;
X    } while ((Argv[findex][0] == '-') && (Argv[findex][1] != '\0'));	/* arg is option - skip */
X
X    bufp = -1;	/* for some reason, lex pushes the EOF character back */
X
X    if (findex >= Argc) {
X	return(TRUE);
X    }
X    else {
X	if (strcmp(Argv[findex],"-") == 0) {	/* stdin */
X	    (void) strcat(strcpy(prcmd,PRCMD),"'STDIN'");
X	    if ((outstream = popen(prcmd,"w")) == NULL) {
X		fprintf(stderr,"clst: can't open pipe\n");
X		exit(1);
X	    }
X	    instream = stdin;
X	}
X	else {
X	    (void) strcat(strcat(strcat(strcpy(prcmd,PRCMD),"'"),Argv[findex]),"'");
X	    if ((outstream = popen(prcmd,"w")) == NULL) {
X		fprintf(stderr,"clst: can't open pipe\n");
X		exit(1);
X	    }
X	    if ((instream = fopen(Argv[findex],"r")) == NULL) {
X		fprintf(stderr,"clst: can't open file ``%s''\n",Argv[findex]);
X		exit(1);
X	    }
X	}
X	linenumber = 1;
X	if (tracknest)
X	    fprintf(outstream,"\n%4d  %8d: ",nestlevel,linenumber);
X	else
X	    fprintf(outstream,"\n%6d: ",linenumber);
X	return(FALSE);
X    }
X}
X
X/* search identifier list for id */
Xstruct IDENTNODE *findid(id,ptr)
Xchar			*id;
Xstruct IDENTNODE	*ptr;
X{
X    if (ptr == NULL)
X	return(ptr);
X    else if (strcmp(ptr->ident,id) > 0)
X	return(NULL);
X    else if (ptr->nextnode == NULL)
X	return(ptr);
X    else if (strcmp(ptr->nextnode->ident,id) > 0)
X	return(ptr);
X    else
X	return(findid(id,ptr->nextnode));
X}
X
X/* add an old identifier to the list */
Xoldident(ptr)
Xstruct IDENTNODE	*ptr;
X{
X    struct NUMBERNODE	*nptr;
X
X    nptr = ptr->lnums;
X    while (nptr->nextnode != NULL)
X	nptr = nptr->nextnode;
X    nptr->nextnode = (struct NUMBERNODE *) malloc(sizeof(struct NUMBERNODE));
X    if (nptr->nextnode == NULL) {
X	fprintf(stderr,"clst: can't allocate new number node\n");
X	exit(1);
X    }
X    nptr->nextnode->nextnode = NULL;
X    nptr->nextnode->number = linenumber;
X}
X
X/* add a new identifier to the list */
Xnewident(id,ptr)
Xchar			*id;
Xstruct IDENTNODE	*ptr;
X{
X    struct IDENTNODE	*idptr;
X
X    idptr = (struct IDENTNODE *) malloc(sizeof(struct IDENTNODE));
X    if (idptr == NULL) {
X	fprintf(stderr,"clst: can't allocate new identifier node\n");
X	exit(1);
X    }
X    idptr->lnums = (struct NUMBERNODE *) malloc(sizeof(struct NUMBERNODE));
X    if (idptr->lnums == NULL) {
X	fprintf(stderr,"clst: can't allocate new number node\n");
X	exit(1);
X    }
X    idptr->ident = (char *) malloc(strlen(id)+1);
X    if (idptr->ident == NULL) {
X	fprintf(stderr,"clst: can't allocate new string node\n");
X	exit(1);
X    }
X    strcpy(idptr->ident,id);
X    idptr->lnums->number = linenumber;
X    idptr->lnums->nextnode = NULL;
X    if (ptr == NULL) {
X	idptr->nextnode = idents;
X	idents = idptr;
X    }
X    else {
X	idptr->nextnode = ptr->nextnode;
X	ptr->nextnode = idptr;
X    }
X}
X
X/* add an identifier to the list */
Xaddident(w)
Xchar	*w;
X{
X    struct IDENTNODE	*ptr;
X
X    ptr = findid(w,idents);
X    if (ptr == NULL)
X	newident(w,ptr);
X    else if (strcmp(ptr->ident,w) == 0)
X	oldident(ptr);
X    else
X	newident(w,ptr);
X}
X
X/* handle arguments */
Xgetargs()
X{
X    int		argindx;
X
X    for (argindx = 0; argindx < Argc; argindx++)
X	if ((Argv[argindx][0] == '-') && (Argv[argindx][1] != '\0')) {
X	    if (strcmp(Argv[argindx],"-lpp") == 0) {
X		(void) strcat(strcat(PRCMD,"-l"),Argv[argindx+1]);
X		Argv[argindx+1][0] = '-';	/* don't confuse w/ stdin */
X		Argv[argindx+1][1] = '-';
X		argindx++;
X	    }
X	    else if (strcmp(Argv[argindx],"-rn") == 0)
X		reservedsymbol = NORMAL;
X	    else if (strcmp(Argv[argindx],"-ru") == 0)
X		reservedsymbol = ULINE;
X	    else if (strcmp(Argv[argindx],"-rb") == 0)
X		reservedsymbol = BOLD;
X	    else if (strcmp(Argv[argindx],"-un") == 0)
X		usersymbol = NORMAL;
X	    else if (strcmp(Argv[argindx],"-uu") == 0)
X		usersymbol = ULINE;
X	    else if (strcmp(Argv[argindx],"-ub") == 0)
X		usersymbol = BOLD;
X	    else if (strcmp(Argv[argindx],"-on") == 0)
X		othersymbol = NORMAL;
X	    else if (strcmp(Argv[argindx],"-ou") == 0)
X		othersymbol = ULINE;
X	    else if (strcmp(Argv[argindx],"-ob") == 0)
X		othersymbol = BOLD;
X	    else if (strcmp(Argv[argindx],"-nx") == 0)
X		doxref = FALSE;
X	    else if (strcmp(Argv[argindx],"-tn") == 0)
X		tracknest = TRUE;
X	    else {
X		fprintf(stderr,"usage: clst [ -lpp n ] [ -ru|b|n ] [ -ub|n|u ] [ -on|b|u ] [ -nx ] [ -tn ] files\n");
X		exit(1);
X	    }
X	}
X}
X
Xmain(argc,argv)
Xint	argc;
Xchar	**argv;
X{
X
X    Argc = argc;
X    Argv = argv;
X    findex = 1;
X
X    /* set up initial pr command */
X    (void) strcpy(PRCMD,"pr ");
X    getargs();
X    (void) strcat(PRCMD," -h ");
X
X    while ((Argv[findex][0] == '-') && (Argv[findex][1] != '\0'))	/* arg is option - skip */
X	findex++;
X
X    if (Argc == 1) {	/* no Args - must be stdin */
X	(void) strcat(strcpy(prcmd,PRCMD),"'STDIN'");
X	if ((outstream = popen(prcmd,"w")) == NULL) {
X	    fprintf(stderr,"clst: can't open pipe\n");
X	    exit(1);
X	}
X	instream  = stdin;
X    }
X    else if (strcmp(Argv[findex],"-") != 0) {	/* not stdin? */
X	(void) strcat(strcat(strcat(strcpy(prcmd,PRCMD),"'"),Argv[findex]),"'");
X	if ((outstream = popen(prcmd,"w")) == NULL) {
X	    fprintf(stderr,"clst: can't open pipe\n");
X	    exit(1);
X	}
X	if ((instream = fopen(Argv[findex],"r")) == NULL) {
X	    fprintf(stderr,"clst: can't open file ``%s''\n",Argv[findex]);
X	    exit(1);
X	}
X    }
X    else {	/* stdin */
X	(void) strcat(strcpy(prcmd,PRCMD),"'STDIN'");
X	if ((outstream = popen(prcmd,"w")) == NULL) {
X	    fprintf(stderr,"clst: can't open pipe\n");
X	    exit(1);
X	}
X	instream = stdin;
X    }
X
X    linenumber = 1;
X    if (tracknest)
X	fprintf(outstream,"\n%4d  %8d: ",nestlevel,linenumber);
X    else
X	fprintf(outstream,"\n%6d: ",linenumber);
X
X    (void) yylex();
X
X    exit(0);
X
X}
--burp--
exit
-- 
Robert Viduya
Office of Computing Services
Georgia Institute of Technology, Atlanta GA 30332
Phone:  (404) 894-4669

...!{akgua,allegra,amd,hplabs,ihnp4,masscomp,ut-ngp}!gatech!gitpyr!robert
...!{rlgvax,sb1,uf-cgrl,unmvax,ut-sally}!gatech!gitpyr!robert