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