home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d1xx
/
d166
/
cref.lha
/
Cref
/
cref.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-11-22
|
18KB
|
914 lines
/*
** cref - C cross referencer VERSION 2.
** This program reads its standard input or one or more files
** and prints the file plus an alphabetic list of word references
** by line number.
**
** To run:
** cref [-q] [-lnnn] [-wnnn] [-hheading] [-tnnn] [-?] [file ...]
**
** Options:
** q - don't print normal input file listing.
** lnnn - set page length to n instead of the default 66.
** wnnn - set page width to n instead of the default 132.
** hccc - set page heading to 'ccc' rather than file names.
** tnnn - set tab spaces to n instead if the default 8.
** ? - display this list.
**
** Mike Edmonds - 5/81
**--------------------------------------------------------------------
**
** VERSION 2 with comment bug fixed. May 1988
**
** Amiga port by Joel Swank 9/87
**
** Compiled under Manx:
** cc cref.c
** ln cref.o -lc
**
** Changes besides porting:
**
** + Deleted temporary file option because the Amiga sort command
** cannot sort files larger than memory.
** + Added -t option
** + Added -? option
** + Added Usage message and error msgs.
** + Rewrote case statments that overflowed compiler table
** + Fixed BUG that caused end of comment to be missed. star-star-slash
** was missed.
*/
#include <stdio.h>
#include <ctype.h>
#include <signal.h>
#include <exec/types.h>
#include <stat.h>
#define MAXWORD 15 /* maximum chars in word */
#define MAXPAGLINES 9999 /* maximum posible lines in page */
#define MINPAGLINES 4 /* minimum posible lines in page */
#define MAXLINWIDTH 132 /* maximum posible chars in line */
#define MINLINWIDTH MAXWORD+12 /* minimum posible chars in line */
#define MAXTABSIZE 132 /* maximum posible chars in tab */
#define MINTABSIZE 1 /* minimum posible chars in tab */
#define igncase(c) (isupper(c)? tolower(c) : (c))
#undef FALSE
#undef TRUE
#define FALSE 0
#define TRUE 1
#ifdef DEBUG
#define debug(a,b) fprintf(stderr,(a),(b))
#else
#define debug(a,b)
#endif
/*
* global structures
*/
#define LINLIST struct _linlist
#define WRDLIST struct _wrdlist
struct _linlist { /* line number list node */
long ln_no ; /* line number */
LINLIST *ln_next ; /* next element pointer (or NULL) */
} ;
struct _wrdlist { /* word list node */
char *wd_wd ; /* pointer to word */
char *wd_lwd ; /* pointer to word (lower case) */
LINLIST wd_ln ; /* first element of line list */
WRDLIST *wd_low ; /* lower child */
WRDLIST *wd_hi ; /* higher child */
} ;
/*
* options
*/
char *Progname ;
int Quiet = FALSE ; /* don't print input file listing? (-q) */
int Maxpaglines = 66 ; /* maximum lines in page (-l) */
int Maxlinwidth = 132 ; /* maximum chars in print line (-w) */
int Tabsize = 8 ; /* default length of tab */
/*
* global variables
*/
char Crefhdr[MAXLINWIDTH+1] ;/* report header */
char *Filename ; /* name of current input file */
char Date[30] ; /* current or last file modify date */
long Hiline = 1L ; /* current (and max.) input file line number */
int files=0 ; /* count of source files */
WRDLIST *Wdtree = NULL ; /* ptr to root node of binary word list */
/*
* C language reserved keywords (in pseudo random order)
*/
char *Ckeywords[] = {
"char",
"static",
"break",
"#define",
"#if",
"default",
"#ifdef",
"#ifndef",
"register",
"void",
"if",
"while",
"#line",
"union",
"switch",
"#else",
"asm",
"do",
"#include",
"#undef",
"#endif",
"long",
"continue",
"float",
"short",
"typedef",
"for",
"struct",
"case",
"else",
"unsigned",
"int",
"extern",
"auto",
"goto",
"entry",
"return",
"double",
"sizeof",
0
} ;
/*
* main - Store C keywords.
* Get program options and format heading lines.
* Get words from input file (or files) and store in tree.
* Retrieve and print in word sequence.
*/
main(argc, argv)
int argc ;
char *argv[] ;
{
char wordfilebuf[BUFSIZ] ;
register FILE *filep ;
char *getword(), *word ;
struct stat stbuf ;
long time() ;
register cnt ;
Progname = *argv ; /* get options */
getcmd(argc, argv) ;
/* store C keywords */
for (cnt=0 ; Ckeywords[cnt] ; cnt++)
storword(Ckeywords[cnt], 0L) ;
listchr(-2); /* clear output line */
/* read and store files */
for (cnt=1 ; cnt < argc ; cnt++)
if (*argv[cnt] != '-')
{ files++ ;
Filename = argv[cnt] ;
if ((filep = fopen(Filename, "r")) == NULL)
fatal("can't open %s", Filename) ;
stat(Filename, &stbuf) ;
mkdate((long)stbuf.st_mtime) ;
while (word = getword(filep))
storword(word, Hiline);
fclose(filep) ;
}
if (!files) /* no files - read stdin */
{ if (*Crefhdr)
Filename = Crefhdr ;
else
Filename = "stdin" ;
mkdate(time( (long *)0)) ;
while (word = getword(stdin))
storword(word, Hiline) ;
}
/* print cross reference report */
cref(Wdtree) ;
exit(0) ;
}
/*
* getcmd - get arguments from command line & build page headings
*/
getcmd(argc, argv)
register argc ;
register char *argv[] ;
{
register cnt ;
debug("GETCMD(%d", argc) ;
debug(", %s)\n", argv[0]) ;
*Crefhdr = '\0' ;
/* get command options */
for (cnt=1; cnt < argc; cnt++)
{ if (*argv[cnt] == '-')
{ switch(argv[cnt][1])
{ case 'q':
Quiet = TRUE ;
break ;
case 'l':
Maxpaglines = atoi(&argv[cnt][2]) ;
if (Maxpaglines < MINPAGLINES
|| Maxpaglines > MAXPAGLINES)
fatal("Bad -l value: %s", argv[cnt]) ;
break ;
case 'w':
Maxlinwidth = atoi(&argv[cnt][2]) ;
if (Maxlinwidth < MINLINWIDTH
|| Maxlinwidth > MAXLINWIDTH)
fatal("Bad -w value: %s", argv[cnt]) ;
break ;
case 't':
Tabsize = atoi(&argv[cnt][2]) ;
if (Tabsize < MINTABSIZE
|| Tabsize > MAXTABSIZE)
fatal("Bad -t value: %s", argv[cnt]) ;
break ;
case 'h':
strncpy(Crefhdr, &argv[cnt][2], MAXLINWIDTH) ;
Crefhdr[MAXLINWIDTH] = '\0' ;
break ;
case '?': /* help option */
usage();
printf(" Options:\n");
printf(" q - don't print normal input file listing\n");
printf(" lnnn - set page length to n instead of the default 66.\n");
printf(" wnnn - set page width to n instead of the default 132.\n");
printf(" hccc - set page heading to 'ccc' rather than file names\n");
printf(" tnnn - set tab spacing to n instead of the default 8\n");
printf(" ? - display this list.\n");
exit(0);
default:
usage();
exit(0);
}
}
}
/* insert file names in hdr */
if (!*Crefhdr)
for (cnt=1; cnt < argc; cnt++)
if (*argv[cnt] != '-')
strjoin(Crefhdr, ' ', argv[cnt], MAXLINWIDTH) ;
}
usage()
{
printf("usage:cref [-q] [-lnnn] [-wnnn] [-hheading] [-tnnn] [-?] [file ...]\n");
}
/*
* getword - read, print and return next word from file
*/
char *
getword(filep)
FILE *filep ;
{
static char wordbuf[MAXWORD+1] ;
register char *wp = wordbuf ;
register maxw = sizeof(wordbuf) ;
register chr ;
int inword=0, lastchr=0 ;
long slineno ;
#define _listchr(chr) if (!Quiet) listchr(chr)
#define _rtrnwrd(wp) \
{ ungetc(chr, filep) ; \
*(wp) = '\0' ; \
return wordbuf ; \
}
while ((chr = getc(filep)) != EOF)
{
/* normal char - add to current word */
if ((chr <= 'z' && chr >= 'a') ||
(chr <= 'Z' && chr >= 'A') ||
chr == '_' )
{
if (maxw-- <= 1)
_rtrnwrd(wp) ;
*wp++ = chr ;
inword++ ;
_listchr(chr) ;
}
else switch (chr)
{
/* digit - can't be 1st char in word */
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
if (inword)
{ if (maxw-- <= 1)
_rtrnwrd(wp) ;
*wp++ = chr ;
}
_listchr(chr) ;
break ;
/* '#' - must be 1st char in word */
case '#':
if (inword)
_rtrnwrd(wp) ;
*wp++ = chr ;
inword++ ;
_listchr(chr) ;
break ;
/* newline - end current word */
case '\n':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
Hiline++ ;
break ;
/* comments - print & bypass */
case '/':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
slineno = Hiline ;
if ((chr = getc(filep)) == '*')
{ _listchr(chr) ;
while (chr != EOF)
{ chr = getc(filep) ;
_listchr(chr) ;
if (chr == '\n')
Hiline++ ;
else if (chr == '*')
{
restar: /* Fix for missing end of comment bug */
chr = getc(filep) ; /* star-star-slash was missed */
_listchr(chr) ;
if (chr == '\n')
Hiline++ ;
else if (chr == '/')
break ; ;
if (chr == '*') goto restar; /* JHS 5/24/88 */
}
}
if (chr == EOF)
fatal("unterminated comment at %ld in %s", slineno, Filename) ;
}
else
ungetc(chr, filep) ;
break ;
/* words in quotes - print & bypass */
case '"':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
slineno = Hiline ;
if (lastchr != '\\')
{ do
{ if (chr == '\\' && lastchr == '\\')
lastchr = '\0' ;
else
lastchr = chr ;
if ((chr = getc(filep)) == EOF)
fatal("unterminated quote at %ld in %s", slineno, Filename) ;
_listchr(chr) ;
if (chr == '\n')
Hiline++ ;
} while (chr != '"' || lastchr == '\\') ;
}
break ;
/* letters in quotes - print & bypass */
case '\'':
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
if (isprint(chr = getc(filep)))
{ _listchr(chr) ;
if (chr == '\\')
{ if (!isprint(chr = getc(filep)))
goto toofar ;
_listchr(chr) ;
}
if ((chr = getc(filep)) != '\'')
goto toofar ;
_listchr(chr) ;
}
else
toofar:
ungetc(chr, filep) ;
break ;
default:
if (inword)
_rtrnwrd(wp) ;
_listchr(chr) ;
break ;
}
lastchr = chr ;
}
if (inword)
_rtrnwrd(wp) ;
_listchr(EOF) ;
return NULL ;
}
/*
* listchr - list the input files one character at a time
*/
static Listpage = 0 ;
static Listpline = MAXPAGLINES ;
listchr(chr)
register chr ;
{
static char linebuf[MAXLINWIDTH*2], *lineptr=linebuf ;
static lastchr=0, linecnt=0 ;
int remain;
if (chr == -2) /* clear line buffer */
{
setmem(linebuf,Maxlinwidth,' ');
return;
}
if (chr == EOF) /* EOF - print final line */
{ *lineptr = '\0' ;
listline(linebuf) ;
Listpage = 0 ;
Listpline = MAXPAGLINES ;
lineptr = linebuf ;
linecnt = 0 ;
return ;
}
if (lineptr == linebuf) /* new line - format line number */
{ ltoc(linebuf, Hiline, 6) ;
lineptr = linebuf+6 ;
*lineptr++ = ' ' ;
*lineptr++ = ' ' ;
linecnt = 8 ;
}
#define _lineoflo(ctr, newctr) \
if ((ctr) >= Maxlinwidth) \
{ *lineptr = '\0' ; \
listline(linebuf) ; \
lineptr = &linebuf[8] ; \
linecnt = (newctr) ; \
}
switch (chr)
{ /* newline - print last line */
case '\n':
if (lastchr != '\f')
{ *lineptr = '\0' ;
listline(linebuf) ;
}
lineptr = linebuf ;
linecnt = 0 ;
break ;
/* formfeed - print line and end page */
case '\f':
if (linecnt != 8)
{ *lineptr = '\0' ;
listline(linebuf) ;
}
Listpline = MAXPAGLINES ;
lineptr = linebuf ;
linecnt = 0 ;
break ;
/* tab - skip to next tab stop */
case '\t':
linecnt += Tabsize ;
remain = linecnt % Tabsize ;
linecnt -= remain;
_lineoflo(linecnt, 8) ;
lineptr += Tabsize ;
lineptr -= remain;
break ;
/* backspace - print, but don't count */
case '\b':
*lineptr++ = chr ;
break ;
/* ctl-char - print as "^x" */
case 001: case 002: case 003:
case 004: case 005: case 006: case 007:
case 013:
case 015: case 016: case 017:
case 020: case 021: case 022: case 023:
case 024: case 025: case 026: case 027:
case 030: case 031: case 032: case 033:
case 034: case 035: case 036: case 037:
_lineoflo(linecnt+=2, 10) ;
*lineptr++ = '^' ;
*lineptr++ = ('A'-1) + chr ;
break ;
default:
if (isprint(chr))
{ _lineoflo(++linecnt, 9) ;
*lineptr++ = chr ;
}
else /* non-ascii chars - print as "\nnn" */
{ _lineoflo(linecnt+=4, 12) ;
*lineptr++ = '\\' ;
*lineptr++ = '0' + ((chr & 0300) >> 6) ;
*lineptr++ = '0' + ((chr & 070) >> 3) ;
*lineptr++ = '0' + (chr & 07) ;
}
break ;
}
lastchr = chr ;
}
/* print a completed line from the input file */
listline(line)
register char *line ;
{
if (*line)
{ if (++Listpline >= (Maxpaglines-8))
{ if (files >1 || Listpage) putchar('\f') ;
printf("\n%s %s Page %d\n\n",
Date, Filename, ++Listpage) ;
Listpline = 0 ;
}
puts(line) ;
listchr(-2); /* clear line buffer */
}
}
/*
* storword - store word and line # in binary word tree or word file
*/
storword(word, lineno)
register char *word ;
long lineno ;
{
char lword[MAXWORD+1] ;
register char *cp1, *cp2 ;
WRDLIST *addword() ;
/* convert word to lower case */
for (cp1=word, cp2=lword ; *cp2++ = igncase(*cp1) ; cp1++)
;
/* store words and lineno */
Wdtree = addword(Wdtree, word, lword, lineno) ;
}
/*
* addword - add word and line# to in-core word list
*/
WRDLIST *
addword(wdp, word, lword, lineno)
register WRDLIST *wdp ;
char *word, *lword ;
long lineno ;
{
char *malloc() ;
int comp ;
/* insert new word into list */
if (wdp == NULL)
{ register wordlen = strlen(word) + 1 ;
wdp = (WRDLIST *)malloc((wordlen * 2) + sizeof(WRDLIST)) ;
if (wdp == NULL)
goto nomemory ;
wdp->wd_wd = (char *)wdp + sizeof(WRDLIST) ;
wdp->wd_lwd = wdp->wd_wd + wordlen ;
strcpy(wdp->wd_wd, word) ;
strcpy(wdp->wd_lwd, lword) ;
wdp->wd_hi = wdp->wd_low = NULL ;
wdp->wd_ln.ln_no = lineno ;
wdp->wd_ln.ln_next = NULL ;
}
/* word matched in list? */
else if (((comp = strcmp(lword, wdp->wd_lwd)) == 0)
&& ((comp = strcmp(word, wdp->wd_wd)) == 0))
{ register LINLIST *lnp, **lnpp ;
if (wdp->wd_ln.ln_no)
{ /* add line# to linked list */
lnp = &wdp->wd_ln ;
do
{ if (lineno == lnp->ln_no)
return wdp ;
lnpp = &lnp->ln_next ;
} while ((lnp = *lnpp) != NULL) ;
*lnpp = (LINLIST *)malloc(sizeof(LINLIST)) ;
if ((lnp = *lnpp) == NULL)
goto nomemory ;
lnp->ln_no = lineno ;
lnp->ln_next = NULL ;
}
}
else if (comp < 0) /* search for word in children */
wdp->wd_low = addword(wdp->wd_low, word, lword, lineno) ;
else
wdp->wd_hi = addword(wdp->wd_hi, word, lword, lineno) ;
return wdp ;
/* not enough memory - convert to -b */
nomemory:
fatal("not enough memory for in-core word list") ;
}
/*
* cref - print cross reference report from internal word list
*/
#define MAXLNOS 2000 /* maximum line nos. for a word */
long Linenos[MAXLNOS] ; /* list of line numbers for a word */
cref(wdtree)
register WRDLIST *wdtree ;
{
creftree(wdtree) ;
}
creftree(wdp) /* recursively print word tree nodes */
register WRDLIST *wdp ;
{
register LINLIST *lnp ;
register nos ;
if (wdp != NULL)
{ creftree(wdp->wd_low) ; /* print lower children */
nos = 0 ;
if (Linenos[0] = wdp->wd_ln.ln_no)
{ lnp = &wdp->wd_ln ;
while ((lnp = lnp->ln_next) != NULL)
if (nos < (MAXLNOS-2))
Linenos[++nos] = lnp->ln_no ;
printword(wdp->wd_wd, nos) ;
}
creftree(wdp->wd_hi) ; /* print higher children */
}
}
/*
* printword - print a word and all its line number references
*/
printword(word, nos)
char *word ;
register nos ;
{
static firstime=TRUE, linecnt, maxlnos, lnosize ;
register cnt ;
if (firstime)
{ firstime = FALSE ;
linecnt = Maxpaglines ;
for (lnosize=1 ; Hiline ; lnosize++)
Hiline /= 10L ;
maxlnos = (Maxlinwidth - (MAXWORD+7)) / lnosize ;
}
if (linecnt >= (Maxpaglines - 8))
{ printheads() ;
linecnt = 5 ;
}
printf("%-15s%5d ", word, ++nos) ;
Linenos[nos] = 0 ;
for (nos=0, cnt=0 ; Linenos[nos] ; nos++)
{ if (++cnt > maxlnos)
{ cnt = 1 ;
if (linecnt++ >= (Maxpaglines - 2))
{ printheads() ;
linecnt = 5 ;
printf("%-15s(cont) ", word);
}
else
printf("\n%22s", " ") ;
}
printf("%*ld", lnosize, Linenos[nos]) ;
}
putchar('\n') ;
linecnt++ ;
}
/*
* printheads - print page headings
*/
printheads()
{
static page=0 ;
long time() ;
if (!page)
mkdate(time( (long *)0)) ;
putchar('\f') ;
printf("\nCREF %s %.*s Page %d\n\n",
Date, (Maxlinwidth-36), Crefhdr, ++page) ;
printf("word refs line numbers\n\n") ;
}
/*
* ltoc - store ASCII equivalent of long value in given field
*/
ltoc(fld, lval, len)
register char *fld ;
register long lval ;
register len ;
{
fld += len ;
while (len-->0)
if (lval)
{ *--fld = '0' + (lval%10L) ;
lval /= 10L ;
}
else
*--fld = ' ' ;
}
/*
* mkdate - build time/date for use in heading lines
*/
mkdate(atime)
long atime ;
{
long mtime ;
char *cp, *ctime() ;
debug("MKDATE(%ld)\n", atime) ;
mtime = atime ;
cp = ctime(&mtime) ;
*(cp+24) = ' ' ; /* clear newline */
strcpy(cp+16, cp+19) ; /* shift over seconds */
strcpy(Date, cp+4) ;
}
/*
* strjoin - join "str1" to "str2" (separated by "sep")
* Truncate if necessary to "max" chars.
*/
strjoin(str1, sep, str2, max)
register char *str1, *str2;
char sep ;
register max ;
{
if (*str2)
{ if (*str1)
{ while (*str1++)
if (--max <= 0)
goto oflo ;
max--, str1-- ;
*str1++ = sep ;
}
while (*str1++ = *str2++)
if (--max <= 0)
goto oflo ;
}
return ;
oflo:
*--str1 = '\0' ;
return ;
}
/*
* error - print standard error msg
*/
error(ptrn, data1, data2)
register char *ptrn, *data1, *data2 ;
{
fprintf(stderr, "%s: ", Progname) ;
fprintf(stderr, ptrn, data1, data2) ;
putc('\n', stderr) ;
}
/*
* fatal - print standard error msg and halt process
*/
fatal(ptrn, data1, data2)
register char *ptrn, *data1, *data2 ;
{
error(ptrn, data1, data2) ;
exit(1);
}