[mod.sources] a cross reference program

sources-request@genrad.UUCP (05/26/85)

From: harvard!seismo!uwvax!uwmacc!jiml (Jim Leinweber)

In the last few months a couple of requests for f77 or C cross
reference map generators have appeared on the net.  This submission
is a quick and dirty implementation of a general purpose (i.e. stupid)
cross reference utility.  It was done using lex, awk, and sh as an
example for a UNIX tutorial.  I have mailed copies to the original
requestors.  Possibly some of the rest of the net isn't satisfied by
egrep, ctags, ptx, etc., and might like it too.

-- Jim Leinweber  (jiml@uwmacc.UUCP, leinwebe@wisc-ai.arpa)

----------------- cut here --------------------
#! /bin/sh
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by uwmacc!jiml on Fri May 24 12:42:06 CDT 1985
# Contents:  Makefile READ_ME mergelines.awk xref.man xref.man.sh xref.sh
#	xrefhead.sh xreflex.l
 
echo x - Makefile
sed 's/^x//' > "Makefile" <<'x//E*O*F Makefile//'
xCFLAGS = -O
xLINT = lint -ph
xDESTDIR = /usr/local
xMANLOC = /usr/man/manl/xref.l
x
xall : xref xreflex xref.1 ; @echo 1>&2 "[Made xref xreflex xref.1]"
x
xxref : xrefhead.sh mergelines.awk ; sh xref.sh $(DESTDIR) >/dev/null
x
xxreflex : lex.yy.c ; cc -o xreflex $(CFLAGS) lex.yy.c -ll
xlex.yy.c : xreflex.l ; lex -v xreflex.l
x
xxref.1 : xref.man ; sh xref.man.sh $(DESTDIR) >/dev/null
x
x
xpiecetest :
x	xreflex xreflex.l xref.man >xreflex_out
x	sort -u +0f -1 +0 -1 +1 -2 +2n <xreflex_out >sort_out
x	awk -f mergelines.awk <sort_out >awk_out
x
xlint : lex.yy.c ; $(LINT) lex.yy.c > xreflex.lint
x
xinstall : all
x	install -c xref $(DESTDIR)
x	install -c -s xreflex $(DESTDIR)
x	install -c -m 644 xref.1 $(MANLOC)
x
xclean : ; -rm *_out *.lint *.yy.c xref xreflex xref.1
x//E*O*F Makefile//
chmod  u=rw,g=r,o=r  Makefile
 
echo x - READ_ME
sed 's/^x//' > "READ_ME" <<'x//E*O*F READ_ME//'
xIn the last few months there have been requests on USENET for a cross
xreferencing program.  Standard UNIX usage is, one supposes, to use
xegrep on a case by case basis for this purpose.  However, I cobbled up
xsuch a program as an example using of using make, lex and awk for a
xshort UNIX tutorial.  It has had only minimal testing and is not
xespecially efficient;  caveat emptor!
x
xThis package makes three files:
x    xref - a shell script which cross references files
x    xreflex - a lex(1) program used by xref
x    xref.1 - a manual entry for xref
x
xIt was developed on a 4.2BSD system, and assumes that make, lex, cc, 
xsh, ed, fgrep, sort, and awk are available under /bin or
x/usr/{bin,ucb,local}.  It should run with at worst minimal changes
xunder any other flavor of UNIX.  If fgrep, sort, and awk are somewhere
xelse be sure to change the PATH in xrefhead.sh.
x
xThe idea is to cross reference files by "xref file1 ... >listing".
xA pipeline of the form "lex program | fgrep | sort | awk" extracts
xwords and their locations, discards extraneous ones, sorts the rest,
xand merges the resulting name,file,line triples into a fairly standard
xcross reference map.
x
xVarious make targets are available:
x    make all		# makes xref & xreflex for /usr/local
x    make DESTDIR=somewhere all	# ... for somewhere instead.
x    make piecetest	# produce intermediate *_out files.
x    make DESTDIR=somewhere MANLOC=elsewhere install
x			# install xref, xreflex, xref.1
x    make clean		# remove computed files
x
xxref is produced by minor editing from xrefhead.sh and mergelines.awk.
xxref.1 is produced by minor editing from xref.man.
xxreflex is produced by lex and cc from xref.l.
x
x-- Jim Leinweber  (jiml@uwmacc.UUCP, leinwebe@wisc-ai.ARPA)
xMadison Academic Computing Center, 1210 W. Dayton ST., Madison Wi 53706
x//E*O*F READ_ME//
chmod  u=rw,g=r,o=r  READ_ME
 
echo x - mergelines.awk
sed 's/^x//' > "mergelines.awk" <<'x//E*O*F mergelines.awk//'
x# Input: lines of the form "name \t file \t line number"
x# Output: merged lines of the form "name \t file \t n1 n2 n3 ..."
x#   Starts a new line for new names or files, and when line gets long.
x#   Suppresses name and previous file on continuation lines.
x
xBEGIN { # Print header and compute usable width
x	fmt = "%-14s\t%-14s\t%s\n"
x	printf fmt, "NAME", "FILE", "LINE NUMBERS"
x	###uwidth = '$width'-16-16-5;  # sizes of name, file, number
x	if (uwidth<3) uwidth=80-16-16-5;  }
x
x$1 != name { printf fmt, pname, pfile, line;  
x	name = pname = $1;  file = pfile = $2;  line = "" }
x
x$2 != file { printf fmt, pname, pfile, line;  
x	pname = "";  file = pfile = $2;  line = "" }
x
xlength(line) > uwidth { printf fmt, pname, pfile, line;  
x	pname = "";  pfile = "";  line = "" }
x
x{ line = line " " sprintf("%4s",$3) }
x
xEND { printf fmt, pname, pfile, line }
x//E*O*F mergelines.awk//
chmod  u=rw,g=r,o=r  mergelines.awk
 
echo x - xref.man
sed 's/^x//' > "xref.man" <<'x//E*O*F xref.man//'
x.TH XREF LOCAL U-WISC
x.ad b
x.SH NAME
xxref \- cross reference files
x.SH SYNOPSIS
x\fBxref\fR [\fB-k\fR keyfile] [\fB-w\fR n] file ...
x.SH DESCRIPTION
x.I Xref
xcross references to standard output
xall the "names" in its (text) input files
xtogether with the files and line numbers they occur on.
xIf no files are supplied, it reads standard input.
xNames consist of letters, underscores, and (non-initial) digits.
x.PP
xAvailable options are:
x.TP
x.B \-k " keyfile"
xUse keyfile as a list of words which should be
xsuppressed from the cross reference.
xAs the removal is done via "fgrep -v", the words should occur one
xper line.
xTo prevent internal matches from discarding valid longer words,
xeach word can be preceded by a space and followed by a tab.
xBy default all words are included.
x.TP
x.B \-w " n"
xFormat the output with a width of n columns, by default 80.
xN is primarily intended for raising the line length;
xa lower limit of 40 is silently enforced.
x.ne 5
x.SH FILES
x.br
x???usrlocal/xreflex	first stage of xref (lexical analyzer)
x.SH DIAGNOSTICS
xComplains about unreadable files, and exits with status 2 if no
xfiles can be read.
xUnhappy subprocesses (fgrep, sort, awk) may also bleat.
x.SH "SEE ALSO"
xctags(1),
xegrep(1),
xptx(1)
x.SH BUGS
xFilenames containing shell meta-characters may be misprocessed.
xThe four stage pipeline is relatively inefficient.
xA general purpose program cannot take advantage of semantic
xknowledge of its input in order to produce prettier, better classified
xoutput.
x.SH AUTHOR
xJim Leinweber
x//E*O*F xref.man//
chmod  u=rw,g=r,o=r  xref.man
 
echo x - xref.man.sh
sed 's/^x//' > "xref.man.sh" <<'x//E*O*F xref.man.sh//'
x>xref.1
xed xref.1 <<EOF
xr xref.man
x/???usrlocal/p
xs;;$1;p
xw
xq
xEOF
x//E*O*F xref.man.sh//
chmod  u=rw,g=r,o=r  xref.man.sh
 
echo x - xref.sh
sed 's/^x//' > "xref.sh" <<'x//E*O*F xref.sh//'
x>xref
xed xref <<EOF
xr xrefhead.sh
x/???usrlocal/p
xs;;$1;p
x\$r mergelines.awk
xg/###/s///p
x\$s/.*/&'/p
xw
xq
xEOF
x//E*O*F xref.sh//
chmod  u=rw,g=r,o=r  xref.sh
 
echo x - xrefhead.sh
sed 's/^x//' > "xrefhead.sh" <<'x//E*O*F xrefhead.sh//'
x#! /bin/sh
x# quick and dirty cross reference generator
x
xDESTDIR=???usrlocal			# revised by Makefile
xPATH=/bin:/usr/bin:/usr/ucb:$DESTDIR	# revise these if necessary
x
xwidth=80				# defaults
xfarg="-e '~'"				# a dummy character
x
xfiles=""
xwhile true
xdo
x    case "$1" in
x	"")	break;;
x	-k)	keywords=$2; shift
x		farg="-f $keywords";;
x	-w)	width=$2; shift;;
x	-*)	echo 1>&2 "Usage:  xref [-k keyfile] [-w n] [file ...]"
x		exit 2;;
x	 *)	files="$files $1";;
x    esac
x    shift
xdone
x
xxreflex $files |
x    fgrep -v $farg |
x	sort -u +0f -1 +0 -1 +1 -2 +2n |
x	    awk '\
x//E*O*F xrefhead.sh//
chmod  u=rw,g=r,o=r  xrefhead.sh
 
echo x - xreflex.l
sed 's/^x//' > "xreflex.l" <<'x//E*O*F xreflex.l//'
x%{
x#define INFINITE_LOOP  while (1)
xint gargc;		/* global argc duplicate */
xchar **gargv;		/* global argv duplicate */
xint n = 1;		/* line counter */
xchar *fname = "-";	/* current file name */
x
x%}
xstartid [A-Za-z_]
xmoreid [A-Za-z_0-9]
x%%
x{startid}{moreid}*	printf(" %s\t%s\t%d\n", yytext, fname, n);
x\n			n++;
x.			;
x%%
x
xyywrap()
x{
x    /* reset line count & proceed to next file, or quit */
x    n = 1;
x    if (next_open())   return(0);
x    else   exit(0);
x}
x
xnext_open()
x{
x    (void) fclose(stdin);
x    while (--gargc > 0) {
x	fname = *++gargv;
x	if (fopen(fname,"r") != NULL)
x	    return(1);
x	fprintf(stderr, "xref: can't open %s\n", fname);
x    }
x    return(0);
x}
x
xmain(argc,argv,env)
xint argc;   char **argv;   char *env[];
x{
x    gargc = argc;   gargv=argv;
x    if (gargc==1 || next_open())
x	INFINITE_LOOP (void) yylex();
x    exit(2);
x}
x//E*O*F xreflex.l//
chmod  u=rw,g=r,o=r  xreflex.l
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$   dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
      28     117     746 Makefile
      38     289    1792 READ_ME
      23     161     847 mergelines.awk
      49     251    1509 xref.man
       8      11      66 xref.man.sh
      11      15     108 xref.sh
      28      84     557 xrefhead.sh
      44     123     837 xreflex.l
     229    1051    6462 total
!!!
wc  Makefile READ_ME mergelines.awk xref.man xref.man.sh xref.sh\
xrefhead.sh xreflex.l | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0