[net.sources] C Function Cross-Referencer

olson@fortune.UUCP (12/22/83)

#N:fortune:10100008:000:10539
fortune!olson    Dec 22 12:03:00 1983

Since I have received several requests (from an article in net.unix-wizards)
I am posting my C function Crossreference program.  It is called
crossref (Unfortunately I just noticed today that someone is posting
an OBJECT code cross-referencer also called crossref...)
There is no makefile, the program is a lex program and compiling 
instructions are in the long comment at the beginning of the code.

The man page is in the source between #ifdef DOCUMENTATION and #endif
DOCUMENTATION.  Format it using nroff -man.

To extract the sources, save this file in a directory where there
is no file called crossref.l, edit it to remove the news headers
(and trailer for us notes folks), then run it as 'sh FILE'.


----------  Remove up to and including this line ---------
sed 's/^XX//' > crossref.l << 'ENDofFILE'
XX%k 150
XX%a 5000
XX%o 10000
XX%n 200
XX%e 200
XX%p 1500
XX
XX
XX%{
XX/****** the LEX definitions are at the very end of the file ***********/
XX
XX#include <ctype.h>
XX#include <stdio.h>
XX#define yywrap() 1
XX
XX#define yywrap() 1
XXchar *filename = "-";
XX
XXextern int yylineno;
XXextern char yytext[], yysbuf[], *yysptr;
XX
XX/*	C cross referencer, based on a program from S. Bourne's book.
XX	Expanded and generally rewritten by Dave Olson.  Handles macro
XX	functions, types on separate line, etc.  DOES NOT handle
XX	variables.  (For large programs, there is just too much output,
XX	and the result is meaningless.  Could add an option(s) to do both,
XX	just variables, or just functions.
XX	
XX	This program was written by me on my own time, and is in the
XX	public domain.  It may be copied and modified, but not sold
XX	nor included in another product which is sold.
XX
XX	If you make modifications, please send me mail (preferably with a
XX	diff listing), so I can incorporate them if I like them.
XX	I make no claims as to how robust and thorough this code is.
XX
XX	I have used it on code amounting to 8000 lines of C code with
XX	no problems.
XX
XX	The man page immediately follows this comment, and is enclose in
XX	#ifdef DOCUMENTATION.
XX	format the documentation by using writing it to a file, then
XX	running 'nroff -man' on it.
XX
XX	Compile this program by:
XX		lex thisfile.l
XX		cc -O -n -o thisfile lex.yy.c
XX
XX	Dave Olson, Fortune Systems {ihnp4,harpo,ucbvax!amd70}!fortune!olson
XX*/
XX#ifdef DOCUMENTATION
XX.TH crossref local Fortune
XX.SH NAME
XXcrossref - make a function cross reference listing for C programs
XX.SH SYNOPSIS
XXcrossref [-o file] [file ...]
XX.SH DESCRIPTION
XXcrossref produces a function cross reference for C programs.  The -o
XXoption specifies output to the given file, otherwise output goes to
XXstdout.  0 or more filenames may be given, files that can't be read
XXare skipped, and processing continues with the next file. If no files
XXare given crossref reads the standard input.
XX.PP
XXcrossref requires that function declarations start in column 1.  Macro
XXfunctions are also handled.  Functions declared as
XX.RS
XXtype function_name(params)
XX.br
XX 		or
XX.br
XXtype
XX.br
XXfunction_name(params)
XX.RE
XX.sp
XXare both recognized (where 'type' may be null).
XXWhite space is allowed between the name and the '('.
XX.SH "SAMPLE OUTPUT"
XX.nf
XXASSERT()
XX        /lpr/malloc.c, 140, 211, 212, 217, 226, 228, 260, 269,
XX		  289, 290, 293, 317, 404
XX		/lpr/lprint.c, 110, 115
XXASSERT(p):#define  /lpr/malloc.c, 125, 136
XXcreat()
XX        /lpr/malloc.c, 57
XXfree()
XX        /lpr/malloc.c, 320
XXfree(ap):[int]  /lpr/malloc.c, 283
XXmalloc()
XX        /lpr/malloc.c, 322
XXmalloc(nbytes):unsigned char *   /lpr/malloc.c, 195
XX        /lpr/malloc.c, 120
XX.fi
XX.PP
XXNote that the line showing the declaration of a function follows the
XXlist of files where it is referenced.  The function name on the
XXdeclaration line is followed by a ':', and it's declared type.  If no
XXtype is declared, it is implicitly declared as 'int', and marked
XXwith ':[int]'.
XX.PP
XXFunctions referenced many times have the line # listing split at column
XX80, and indented 2 spaces (shown shorter here so it fits on the man
XXpage).  If the function is referenced in more than one file, each file
XXstarts on a new line.  Functions that have no declaration are
XXpresumably declared in another file, or are library routines.
XX.SH AUTHOR
XXDave Olson, loosely based on an example in the book ' The Unix System'
XXby S. Bourne.
XX#endif DOCUMENTATION
XX
XXchar *progname;
XX
XXFILE *out, *fromsort, *pop(), *fdopen();
XXmain(argc,argv)
XXchar **argv;
XX{
XX	short rc=0;
XX	int pip[2];
XX	char *rindex();
XX	char **args, *argbase[12];
XX
XX	if(progname=rindex(*argv,'/'))
XX		progname++;
XX	else 
XX		progname = *argv;
XX
XX	if(*(argv+1) && !strcmp(*(1+argv),"-o"))  {
XX		argv += 2;
XX		out = fopen(*argv,"w");
XX		if(out == NULL) {
XX			fprintf(stderr,"%s: unable to open %s, bye\n",progname,*argv);
XX			exit(1);
XX		}
XX	}
XX	else {
XX		out = fdopen(dup(1),"w");
XX		if(out == NULL) {
XX			fprintf(stderr,"%s: unable to dup stdout,bye\n",progname);
XX			exit(1);
XX		}
XX	}
XX
XX	if(pipe(pip) < 0 || dup2(pip[0],0) < 0 ) {
XX		fprintf(stderr,"%s: unable to set up input pipe, bye\n",progname);
XX		exit(2);
XX	}
XX
XX	if(dup2(pip[1],1) < 0) {
XX		fprintf(stderr,"%s: unable to set up output pipe, bye\n",progname);
XX		exit(2);
XX	}
XX	close(pip[1]);
XX	close(pip[0]);
XX
XX	/*	no problem with stdout in child, because pop() does a dup2() to
XX		redirect the i/o */
XX	args = argbase;
XX	*args++ = "sort";
XX	*args++ = "-ut;";
XX	*args++ = "+0";
XX	*args++ = "-1";
XX	*args++ = "+1";
XX	*args++ = "-2";
XX	*args++ = "+2n";
XX	*args++ = "-3";
XX	*args = 0;
XX
XX	fromsort = pop(argbase,"r");
XX
XX	if(fromsort == NULL) {
XX		fprintf(stderr,"%s: unable run 'sort', bye\n",progname);
XX		exit(1);
XX	}
XX
XX	if(!*(argv+1))
XX		yylex();
XX	else while(*++argv) {
XX		if(freopen(*argv,"r",stdin) == NULL) {
XX			fprintf(stderr,"%s: Can't open input file %s\n", progname,*argv);
XX			rc++;
XX		}
XX		else {
XX			filename = *argv;
XX			yylineno = 1;
XX			yylex();
XX		}
XX	}
XX	fclose(stdout);
XX	pass2();
XX	pclose(fromsort);
XX	return rc;	/* number of files that couldn't be opened */
XX}
XX
XX#define MAXLEN	79 /* max output line length */
XX#define MAXW 128
XXchar lastw[MAXW];
XXchar lastc;
XX
XXshort wlen;
XX
XXpass2()
XX{
XX	char f1[MAXW], f2[MAXW], *strcpy(), *rindex(), *k;
XX	short len, didnl=0;
XX
XX	*f1 = *f2 = '0';
XX	while(word() != EOF) {
XX		if(!strcmp(lastw,f1)) {
XX			word();
XX			if(strcmp(lastw,f2)) { /* same function, different file */
XX				fprintf(out,"\n%*s%s", 8,"",strcpy(f2,lastw));
XX				len = wlen + 8;
XX			}
XX		}
XX		else {
XX			strcpy(f1,lastw);
XX			word();
XX			if((k=rindex(f1,')')) && *++k == ':')	/* func definition */
XX				fprintf(out,"\n%s  %s",f1,strcpy(f2,lastw));
XX			else 	/* func reference */
XX				fprintf(out,"\n%s\n%*s%s",f1,8,"",strcpy(f2,lastw));
XX			len = wlen + 8;
XX		}
XX		if(lastc != '\n')  {
XX			word();
XX			/* 2 for the ', ', and 1 for the final ',' on a line */
XX			if((len + wlen + 3) > MAXLEN) {
XX				fprintf(out,",\n%*s",10,"",lastw);
XX				len = wlen + 10;
XX				didnl++;
XX			}
XX			else {
XX				if(!didnl)
XX					fprintf(out,", %s",lastw);
XX				else
XX					fputs(lastw,out);
XX				len += wlen + 2;
XX				didnl = 0;
XX			}
XX		}
XX		lastc = '\0';
XX	}
XX	putc('\n',out);
XX	return 0;
XX}
XX
XX
XXword()	/* read a word from the input stream */
XX{
XX	register char *p = lastw;
XX	register int c;
XX
XX	if(lastc != '\n') {
XX		while((c = getc(fromsort)) != ';' && c != '\n' && c != EOF)
XX			if(p < &lastw[MAXW])
XX				*p++ = c;
XX		lastc = c;
XX	}
XX	wlen = p - lastw;
XX	*p++ = '\0';
XX	return lastc;
XX}
XX
XX
XX/* based on @(#)popen.c	4.1 (Berkeley) 12/21/80 */
XX#ifndef FILE
XX#	include <stdio.h>
XX#endif
XX#include <signal.h>
XX#define	tst(a,b)	(*mode == 'r'? (b) : (a))
XX#define	RDR	0
XX#define	WTR	1
XXstatic	int	popen_pid[20];
XXFILE *
XXpop(cmd,mode)
XXchar	**cmd;
XXchar	*mode;
XX{
XX	int p[2];
XX	register myside, hisside, pid;
XX
XX	if(pipe(p) < 0)
XX		return NULL;
XX	myside = tst(p[WTR], p[RDR]);
XX	hisside = tst(p[RDR], p[WTR]);
XX	if((pid = fork()) == 0) {
XX		/* myside and hisside reverse roles in child */
XX		close(myside);
XX		dup2(hisside, tst(0, 1));
XX		close(hisside);
XX		execvp(*cmd,cmd);
XX		_exit(1);
XX	}
XX	if(pid == -1)
XX		return NULL;
XX	popen_pid[myside] = pid;
XX	close(hisside);
XX	return(fdopen(myside, mode));
XX}
XX
XXint
XXpclose(ptr)
XXFILE *ptr;
XX{
XX	register f, r, (*hstat)(), (*istat)(), (*qstat)();
XX	int status;
XX
XX	f = fileno(ptr);
XX	fclose(ptr);
XX	istat = signal(SIGINT, SIG_IGN);
XX	qstat = signal(SIGQUIT, SIG_IGN);
XX	hstat = signal(SIGHUP, SIG_IGN);
XX	while((r = wait(&status)) != popen_pid[f] && r != -1)
XX		;
XX	if(r == -1)
XX		status = -1;
XX	signal(SIGINT, istat);
XX	signal(SIGQUIT, qstat);
XX	signal(SIGHUP, hstat);
XX	return(status);
XX}
XX
XXint gotnl;
XXchar type[128];
XX
XX/* skip over comments */
XXcomment()
XX{
XX	register char c;
XX
XX	while(c = input())
XX		if(c == '*' && input() == '/')
XX			return;
XX}
XX
XX/* skip over strings */
XXstrings()
XX{
XX	register char c;
XX
XX	while(c = input()) {
XX		if(c == '"')
XX			return;
XX		else if(c == '\\')
XX			input();
XX	}
XX}
XX
XXfndef()
XX{
XX	register char *p;
XX
XX	p = yytext + yyleng -1;
XX	/* skip trailing white space */
XX	while(isspace(*p) && p > yytext)
XX		p--;
XX	*(p+1) = '\0';
XX
XX	while(*p != '(' && p > yytext)
XX		p--;
XX	/* skip any white space between func name and '(' */
XX	while(isspace(*p) && p > yytext)
XX		p--;
XX	/* find beginning of func name */
XX	while(!isspace(*p) && p > yytext)
XX		p--;
XX	if(p > yytext) {	/* function type was given */
XX		printf("%s",++p);
XX		*p = '\0';
XX		printf(":%s;%s;%d\n",yytext,filename,yylineno-1);
XX	}
XX	else if(!gotnl)	/* type probably declared on prev line */
XX		printf("%s:%s;%s;%d\n",p,type,filename,yylineno-1);
XX	else	/* no type given */
XX		printf("%s:[int];%s;%d\n",p,filename,yylineno-1);
XX}
XX%}
XX
XX%%
XX"/*"	comment();
XX"\""	strings();
XX^[a-zA-Z0-9_]+[ \t*]*"("[a-zA-Z0-9, \t]*")"[ \t\n]	fndef();
XX^#[ \t]*define[ \t][a-zA-Z_]+"("[a-zA-Z0-9, \t]*")"[; \t\n]+	fndef();
XXif[ \t]*"("	;
XXreturn[ \t]*"("	;
XXwhile[ \t]*"("	;
XXfor[ \t]*"("	;
XXswitch[ \t]*"("	;
XXauto[ \t{\n]	;
XXbreak[ \t{\n;]	;
XXelse[ \t{\n;]	;
XX^[^;+-/(){}\n]+\n	{gotnl=0;
XX				strncpy(type,yytext,yyleng);
XX				type[yyleng] = 0;
XX				type[yyleng-1] = ' ';
XX				}
XX[a-zA-Z0-9_]+[\t ]*"("	printf("%s);%s;%d\n",yytext,filename,yylineno);
XX.	;
XX\n	gotnl=1;
XX%%
ENDofFILE
echo 'Extraction of crossref.l completed'

olson@fortune.UUCP (01/03/84)

#R:fortune:10100008:fortune:10100010:000:578
fortune!olson    Jan  3 09:08:00 1984

I have received several pieces of mail from people saying they are
having problems compiling my 'crossref' program

I should have mentioned that this program uses one library
function, and one system call which are found only on V7 and Berkeley
Unix's.  The library routine is rindex(), which is identical to 
strrchar() on Sys 3 and 5.

The system call is dup2(fd1,fd2).  This is functionally the same
as: close(fd2);fcntl(fd1,F_DUPFD,fd2);  on Sys 3 and 5.

Hope this helps those who were having problems.
	Dave Olson, Fortune Systems {ihnp4,harpo,ucbvax!amd70}!fortune!olson

olson@fortune.UUCP (01/06/84)

#R:fortune:10100008:fortune:10100011:000:578
fortune!olson    Jan  5 16:08:00 1984

I have received several pieces of mail from people saying they are
having problems compiling my 'crossref' program

I should have mentioned that this program uses one library
function, and one system call which are found only on V7 and Berkeley
Unix's.  The library routine is rindex(), which is identical to 
strrchar() on Sys 3 and 5.

The system call is dup2(fd1,fd2).  This is functionally the same
as: close(fd2);fcntl(fd1,F_DUPFD,fd2);  on Sys 3 and 5.

Hope this helps those who were having problems.
	Dave Olson, Fortune Systems {ihnp4,harpo,ucbvax!amd70}!fortune!olson