Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!gem.mps.ohio-state.edu!uwm.edu!cs.utexas.edu!uunet!mcsun!hp4nl!star.cs.vu.nl!ast@cs.vu.nl
From: ast@cs.vu.nl (Andy Tanenbaum)
Newsgroups: comp.os.minix
Subject: MINIX cross reference program
Message-ID: <3412@ast.cs.vu.nl>
Date: 28 Sep 89 13:58:11 GMT
Sender: ast@cs.vu.nl
Reply-To: ast@cs.vu.nl (Andy Tanenbaum)
Organization: VU Informatica, Amsterdam
Lines: 1083
/* mref - MINIX cross referencer Author: Andy Tanenbaum */
/* Mref is intended for producing listings and cross reference maps of
* MINIX. The default is to produce three outputs:
*
* on stdout: numbered listing of all the files given as args
* on symbol.out: list of all "global" symbols and their definition line
* on xref.out: cross reference map of all references to global symbols
*
* For this program, a global symbol is one that is defined as PUBLIC, PRIVATE,
* EXTERN, #define, or SYMBOL. The latter is provided to allow users to force
* symbols x, y, and z to "global" status but simply making up a file with
*
* SYMBOL x
* SYMBOL y
* SYMBOL z
*
* The numbering is consecutive across files, i.e., the second file begins
* where the first one left off, except that each file begins at the top of
* a new page, and the line number is rounded upward to the next page.
* The three types of output can each be suppressed, using the -l, -d, and -x
* flags, respectively. Line numbering between procedures may be optionally
* suppressed with -s, as in the MINIX book. Page length and numbering can be
* user controlled with flags.
*
* Normally output is designed for a dumb line printer, but the -t flag causes
* the output to be enhanced with macros and font control so it can be fed to
* troff (or nroff). If troff form, the symbol table is printed in three
* columns, the first page being shorter to allow for the chapter opening.
*
* Flags:
* -# Number of lines to print per page, default = 50
* -d Don't produce definition file (symbol table)
* -l Don't produce listing
* -m Multiple reference on one line only are cited once
* -p n Set initial page number to n
* -t Generate troff macro call before each page
* -s Suppress line numbering between procedures
* -x Don't produce the cross reference map
*
* Examples:
* mref -60 *.c # print 60 lines per page (default is 50)
* mref -t -p 50 *.c # first page is 50; generate .Ep and .Op macros
* mref -l -d *.h *.c # no listing or symbols, just cross ref map
*/
#include
#include
#define LINE_SIZE 512
#define PHYS_PAGE 66 /* physical page length */
#define DEF_LEN 50 /* default # lines/page */
#define SYM_SIZE 13 /* symbols are truncated to this size */
#define HDR_SIZE 5 /* number of lines in the default header */
#define NSYMS 2000 /* size of the symbol table */
#define NTOKENS 100 /* maximum number of tokens per line */
#define MAX_VALUES 100 /* maximum times a name can be declared */
#define MAX_PER_LINE 9 /* number of cross refs to print per line */
#define NCOLS 3 /* number of columns for troffed symbol.out */
#define SYM_FILE "symbol.out" /* place to write the symbol table */
#define XREF_FILE "xref.out" /* place to write cross ref map */
#define TMP_FILE "xref.tmp" /* temporary xref file for gathering refs */
#define SORTED_FILE "xref.sort" /* temporary xref file for sorting */
#define DEF 1 /* this line contains #define */
#define EXT 2 /* this line contains EXTERN */
#define PRIV 3 /* this line contains PRIVATE */
#define PUB 4 /* this line contains PUBLIC */
#define SYM 5 /* this line contains SYMBOL */
int listing = 1; /* 1 = output listing; 0: don't */
int xref = 1; /* 1 = output cross ref map; 0: don't */
int definitions = 1; /* 1 = output definitions; 0: don't */
int sflag = 0; /* 1 = number all lines; 0: most */
int tflag = 0; /* 1 = troff output; 0: flat */
int mflag = 0; /* 1 = max one ref/line 0: many */
int page_len = DEF_LEN; /* # lines to print per page */
int phys_page = PHYS_PAGE; /* total page size: top hdr+text+bottom hdr */
int cur_line; /* current line number */
int cur_page = 1; /* current page number */
int ntokens; /* number of tokens in the token[] array */
int suppressing; /* don't print numbers between procedures */
int hunting; /* set when hunting for end of declaration */
int comment; /* set when scanning a comment */
int xcount; /* number of references so far to this sym */
int prev_ref; /* previous reference printed */
int stride; /* length of first symbol table page */
int stride2; /* length of second symbol table page */
char *prog_name; /* argv[0] */
char line_buf[LINE_SIZE]; /* buffer for 1 line */
char b[LINE_SIZE]; /* processed line goes here */
char *token[NTOKENS]; /* array of pointers to tokens */
/* Symbol table. If a symbol is defined multiple times, it will get as many
* entries in the symbol table as there are definitions.
*/
struct symtab {
char sym_name[SYM_SIZE+1]; /* symbol, followed by at least one '\0' */
char sym_type; /* PUB, PRIV, EXT, SYM, or DEF */
int sym_val; /* line number on which symbol occurs */
} symtab[NSYMS];
char *ppmap[] = {"", "#define", "EXTERN ", "PRIVATE", "PUBLIC ", "SYMBOL "};
char *ppmap2[] = {"", "#def", "EXTN", "PRIV", "PUBL", "SYMB"};
char spaces[] = " ";
char *xref_text[] = {
".nf\n" ,
".tr _\\(ru\n",
".ta 1.25i 2iR 2.45iR 2.9iR 3.35iR 3.8iR 4.25iR 4.7iR 5.15iR 5.6iR 6.05iR\n",
(char *) 0
};
char *list_text[] = {
".po .5i\n",
".nf\n",
".ec `\n",
".vs 12.01p\n",
"`f(CW\n",
".nr T `w'0'\n",
".ta 8u*`nTu 16u*`nTu 24u*`nTu 32u*`nTu 40u*`nTu 48u*`nTu 56u*`nTu 64u*`nTu 72u*`nTu 80u*`nTu\n",
".de Op \n",
".bp ``$1\n",
".sp 1.25i\n",
".tl '``fR``s10MINIX SOURCE CODE``s0'``s11File: ``$2``s0``fP'``fB``s12``n%%``s0``fP'\n",
".sp 1\n",
"``f(CW\n",
"..\n",
".de Ep \n",
".bp ``$1\n",
".sp 1.25i\n",
".tl '``fB``s12``n%%``s0``fP``fR'``s11File: ``$2'``s0``s10MINIX SOURCE CODE``s0``fP'\n",
".sp 1\n",
"``f(CW\n",
"..\n",
(char *) 0
};
char *sym_text[] = {
".nf\n" ,
".tr _\\(ru\n",
".ta 1.6iR 2.0i 3.6iR 4.0i 5.6iR\n",
(char *) 0
};
FILE *sym; /* for symbol table file */
FILE *xr; /* for cross reference file */
FILE *tmp; /* for collecting cross references */
FILE *sortf; /* for sorting cross refernces */
main(argc, argv)
int argc;
char *argv[];
{
int i, j;
char *p;
/* Process the command line. */
if (argc < 2) usage();
prog_name = argv[0];
for(i = 1; i < argc; i++) {
p = argv[i];
if (*p != '-') break;
p++;
i += eat_flag(argv, i);
}
stride = page_len/2; /* allow for chapter opening */
stride2 = page_len;
/* Create the output files. */
make_files();
/* Read all the files. Make the listing and extract the symbols. */
for (j = i; j < argc; j++) process(argv[j]);
/* Read all the files again and generate the cross refererence data. */
cur_line = 0;
for (j = i; j < argc; j++) gen_xref(argv[j]);
/* Go get the cross reference data and print it. */
collect_xref();
/* Print the symbol table. */
if (definitions) print_sym();
exit(0);
}
int eat_flag(argv, i)
char *argv[]; /* argument array */
int i; /* process argv[i] */
{
char *p;
int r = 0;
p = argv[i];
p++;
if (*p >= '0' && *p <= '9') {
page_len = atoi(p); /* e.g. numb -60 file */
return;
}
while (1) {
/* Flag may be something like -dls. */
switch(*p) {
case 'd':
definitions = 0;
break;
case 'l':
listing = 0;
break;
case 'x':
xref = 0;
break;
case 'm':
mflag = 1;
break;
case 's':
sflag = 1;
break;
case 't':
tflag = 1;
break;
case 'p':
cur_page = atoi(argv[i+1]);
i++;
r = 1;
break;
default:
usage();
}
p++;
if (*p == 0) return(r);
}
}
make_files()
{
/* Create output files. */
int fd;
if (tflag && listing) output_macros(stdout, list_text);
if (definitions) {
if ( (fd = creat(SYM_FILE, 0666)) < 0) {
fprintf(stderr, "numb: cannot create %s\n", SYM_FILE);
exit(2);
}
close(fd);
sym = fopen(SYM_FILE, "w");
if (sym == NULL) {
fprintf(stderr, "numb: cannot open %s for output\n", SYM_FILE);
exit(2);
}
if (tflag) output_macros(sym, sym_text);
}
if (xref) {
if ( (fd = creat(XREF_FILE, 0666)) < 0) {
fprintf(stderr, "numb: cannot create %s\n", XREF_FILE);
exit(2);
}
close(fd);
xr = fopen(XREF_FILE, "w");
if (xr == NULL) {
fprintf(stderr, "numb: cannot open %s for output\n",XREF_FILE);
exit(2);
}
if (tflag) output_macros(xr, xref_text);
if ( (fd = creat(TMP_FILE, 0666)) < 0) {
fprintf(stderr, "numb: cannot create %s\n", TMP_FILE);
exit(2);
}
close(fd);
tmp = fopen(TMP_FILE, "w");
if (xr == NULL) {
fprintf(stderr, "numb: cannot open %s for output\n", TMP_FILE);
exit(2);
}
}
}
process(file)
char *file;
{
/* Process one file. */
int k;
FILE *f;
if ( (f = fopen(file, "r")) == NULL) {
fprintf(stderr, "numb: cannot open %s\n", file);
exit(1);
}
while (1) {
if (fgets(line_buf, LINE_SIZE, f) == NULL) {
/* End of file hit. */
fclose(f);
if (listing && cur_line % page_len != 0) {
fill_page(); /* fill out the e.g. 50 lines */
eject(); /* space to top of next sheet */
}
return;
}
if (listing)
list(file);
else
cur_line++;
if (definitions || xref) get_sym();
}
}
list(file)
char *file;
{
/* We are printing a listing. */
if (cur_line % page_len == 0) new_page(file);
if (suppressing == 1 && strlen(line_buf) == 1)
printf("\n");
else
printf("%5d %s", cur_line, line_buf);
cur_line++;
if (cur_line % page_len == 0) eject();
if (strlen(line_buf) > 1) suppressing = 0;
if (strcmp(line_buf, "}\n") == 0 && sflag) suppressing = 1;
}
get_sym()
{
/* Look for lines starting with PRIVATE, PUBLIC, EXTERN, SYMBOL or #define and
* make a symbol table entry for them. Life is slightly complicated by
* constructions like:
*
* 1000 PRIVATE struct foobar {
* 1001 int i;
* 1002 char c;
* 1003 } name[MAX];
*
* in which the symbol 'name' is triggered on line 1000, but its value is 1003.
*/
int n, type;
register char c;
char *p, *q, *backup();
/* If we are hunting for the end of a declaration, the rules are different.*/
if (hunting) {
q = line_buf;
while (*q == ' ' || *q == '\t') q++;
if (*q != '}') return;
q++;
while (*q == ' ' || *q == '\t') q++;
p = q;
while (isalnum(*p) || *p == '_') p++;
*p = 0;
enter_sym(q, cur_line - 1, hunting);
hunting = 0;
return;
}
/* For efficiency, make a quick check to see if this line is interesting. */
c = line_buf[0];
if (c != 'P' && c != 'E' && c != 'S' && c != '#') return;
squash(); /* squeeze out white space */
/* Real check to see if this line is interesting. */
type = 0;
if (strncmp(b, "#define", 7) == 0) type = DEF;
if (strncmp(b, "PRIVATE", 7) == 0) type = PRIV;
if (strncmp(b, "PUBLIC", 6) == 0) type = PUB;
if (strncmp(b, "EXTERN", 6) == 0) type = EXT;
if (strncmp(b, "SYMBOL", 6) == 0) type = SYM;
if (type == 0) return;
/* Process #define */
if (type == DEF) {
q = &b[8];
while (*q != ' ') q++;
*q = 0;
enter_sym(&b[8], cur_line - 1, type);
return;
}
q = b + strlen(b) - 1; /* q points to last character */
if (*q == '!' || *q == '+') {
*q = ' ';
while (*q == ' ') q--;
}
/* If last char is paren, }, or comma, this is a function call. */
if (*q == ')' || *q == ',' || *q == '}') {
/* It is a paren. */
q = b;
while (*q != '(') q++;
if (*(q+1) == '*') *q = ' '; /* worry about: int (*foo[N])() */
strip(b, "(", 1);
strip(b, "[", 1);
q = b + strlen(b) - 1;
q = backup(q);
enter_sym(q, cur_line - 1, type);
return;
}
/* If last char is semicolon, '[', or letter, this is a declaration. */
if (*q == ';' || *q == ']' || *q == '_' || isalnum(*q)) {
/* It is a declaration. */
if (*q == ';') q--;
if (*q == ' ') q--;
*(q+1) = 0;
if (*q == ']') strip(b, "[", 1); /* e.g. PRIVATE int foo[N]; */
q = b + strlen(b) - 1;
q = backup(q);
enter_sym(q, cur_line - 1, type);
return;
}
/* If last char is curly bracket, this is the start of a struct array. */
if (*q == '{') {
hunting = type; /* Start hunting for the '}' */
return;
}
panic("getsym got unknown line type");
}
fill_page()
{
/* Fill out current page with line feeds. This routine is only called when
* an end of file is encountered. It fills out the current page to 50
* lines (or whatever). For -t it does nothing.
*/
int k;
k = cur_line % page_len;
if (k > 0) k = page_len - k;
cur_line += k;
if (tflag == 0) while (k--) printf("\n");
}
eject()
{
/* Finish off the last 11 or so blank lines on a page (not for -t. */
int i;
if (tflag) return;
i = phys_page - page_len - HDR_SIZE;
while(i--) printf("\n");
}
new_page(file)
char *file;
{
/* Top of page processing. */
int i;
if (tflag) {
/* Generate a troff macro that does the heading (odd/even). */
if (cur_page & 1)
printf(".Op %d %s\n", cur_page, file); /* odd page */
else
printf(".Ep %d %s\n", cur_page, file); /* even page */
} else {
/* Standard header */
printf("\n\n\nPage: %d ", cur_page);
printf("File: %s\n\n", file);
}
cur_page++;
}
squash()
{
/* Copy line_buf to b, squeezing out white space, comments, and initializers. */
register char *p, *q;
char c;
p = line_buf;
q = b;
c = *p;
*q++ = *p++; /* copy first character */
if (c == '#') {
while (*p == ' ' || *p == '\t') p++; /* skip spaces after '#' */
}
while (*p != '\0') {
if (*p == '\n' || *p == '=') break;
if (*p == '/' && *(p+1) == '*') break;
if (*p == ' ' || *p == '\t') {
while (*p == ' ' || *p == '\t') p++;
*q++ = ' '; /* copy one space */
} else {
*q++ = *p++;
}
}
if (*(q-1) == ' ') q--;
*q = 0;
}
strip(string, s, n)
char *string;
char *s;
int n;
{
/* Scan b for the string s and truncate it there if found. */
char *p;
p = string;
while (*p != '\0') {
if (strncmp(p, s, n) == 0) {
*p = 0;
if (*(p-1) == ' ') *(p-1) = 0;
return;
} else {
p++;
}
}
}
char *backup(q)
char *q;
{
/* Back the pointer q up to the start of the word it points to. */
while (*q != ' ' && *q != '*') q--;
return(q+1);
}
enter_sym(p, value, type)
char *p; /* pointer to name of symbol */
int value; /* line number on which symbol occurs */
int type; /* PUB, PRIV, EXT, DEF, SYM */
{
/* Enter a symbol in the hash table. A symbol may be define in FS and again
* in MM, etc. Up to 3 definitions are stored.
*/
int h, len;
struct symtab *hp;
/* Watch out for the #define PUBLIC line, etc. */
if (strlen(p) == 0) return;
if (strcmp(p, "PUBLIC") == 0) return;
if (strcmp(p, "PRIVATE") == 0) return;
if (strcmp(p, "EXTERN") == 0) return;
if (strcmp(p, "int") == 0) return;
if (strcmp(p, "char") == 0) return;
if (strcmp(p, "void") == 0) return;
strip(p, "(", 1);
h = find_slot(p);
hp = &symtab[h];
len = strlen(p);
if (len > SYM_SIZE) len = SYM_SIZE;
/* Enter the symbol. Multiple definitions are allowed. */
strncpy(hp->sym_name, p, len); /* entry is SYM_SIZE+1 for \'0' */
hp->sym_type = type;
hp->sym_val = value;
}
int find_slot(p)
char *p;
{
/* Hash the string and return an index into the hash table. If a collision
* occurs, the first consecutive free slot is used.
*/
unsigned int h, hash();
/* Search all entries starting at h for a free slot. */
h = hash(p);
while (1) {
if (symtab[h].sym_type == 0) return((int)h); /* empty slot */
h = (h + 1) % NSYMS; /* try next entry */
}
}
int lookup(p)
char *p;
{
/* Is p is in the symbol table? Return slot if it is present, -1 if absent. */
unsigned int h, hash();
int n;
n = strlen(p);
if (n > SYM_SIZE) n = SYM_SIZE;
h = hash(p);
while (1) {
if (symtab[h].sym_type == 0) return(-1); /* not present */
if (strncmp(p, symtab[h].sym_name, n) == 0) return( (int) h);
h = (h + 1) % NSYMS;
}
}
unsigned int hash(p)
char *p;
{
/* Compute and return the hash code of p. */
int i, n;
unsigned h;
n = strlen(p);
if (n > SYM_SIZE) n = SYM_SIZE;
h = 0;
for (i=0; i < n; i++) {
h += 23 * i * (int) *p;
p++;
}
h = h % NSYMS;
return(h);
}
print_sym()
{
/* Print all the definitions. */
int n, k, count, s, i, limit;
struct symtab *ap, *bp, *cp;
n = compact(); /* compact the symbol table */
if (n < 0 || n > NSYMS) panic("compact returned invalid value");
sort(n); /* sort the symbol table */
/* Print the symbol table. */
if (tflag) {
/* Produce the symbol.out file for troff. */
i = 0;
limit = stride;
while (1) {
while (i < limit) {
ap = &symtab[i];
bp = &symtab[i+stride];
cp = &symtab[i+2*stride];
if (ap < &symtab[n])
fprintf(sym,"%s\t%d",ap->sym_name,ap->sym_val);
if (bp < &symtab[n])
fprintf(sym,"\t%s\t%d",bp->sym_name,bp->sym_val);
if (cp < &symtab[n])
fprintf(sym,"\t%s\t%d",cp->sym_name,cp->sym_val);
fprintf(sym, "\n");
i++;
}
fprintf(sym, ".bp\n");
if (cp >= &symtab[n-1]) return;
i += 2 * stride;
stride = stride2; /* 1st page may be different */
limit = i + stride;
}
} else {
/* Produce the flat version of symbol.out. */
for (ap = &symtab[0]; ap < &symtab[n]; ap++) {
k = strlen(ap->sym_name);
fprintf(sym, "%s%s %5d %s\n", ap->sym_name, &spaces[k],
ap->sym_val, ppmap[ap->sym_type]);
}
}
}
compact()
{
/* Compact the symbol table to make sorting more efficient. */
unsigned int d;
struct symtab *ap, *bp;
bp = &symtab[NSYMS-1]; /* bp points to last entry */
for (ap = &symtab[0]; ap < bp; ap++) {
if (ap->sym_type != 0) continue; /* skip used slots. */
/* ap points to an empty slot. Find a full one and swap them. */
while (bp->sym_type == 0 && bp > symtab) bp--; /* skip empty slots */
if (bp <= ap) {
d = ap - symtab;
return(d);
}
swap(ap, bp);
}
return(ap - symtab);
}
swap(ap, bp)
struct symtab *ap, *bp;
{
/* Swap two symbol table entries. */
struct symtab xp;
xp = *ap;
*ap = *bp;
*bp = xp;
}
sort(n)
int n; /* number of nonnull entries in symtab */
{
/* Sort the symbol table. Use bubble sort. */
int s;
struct symtab *ap, *bp;
for (ap = &symtab[0]; ap < &symtab[n-1]; ap++) {
for (bp = ap + 1; bp < &symtab[n]; bp++) {
s = strcmp(ap->sym_name, bp->sym_name);
if (s < 0) continue;
if (s == 0 && ap->sym_type < bp->sym_type) continue;
swap(ap, bp);
}
}
}
gen_xref(file)
char *file;
{
/* Build the cross reference listing. Reread file, looking up all
* symbols in the hash table. On every hit, an entry written to the temporary
* file. Later they will be sorted and printed.
*/
int i, k;
register char *p;
char c, *skip_comment();
FILE *f;
if ( (f = fopen(file, "r")) == NULL) {
fprintf(stderr, "numb: cannot open %s\n", file);
exit(1);
}
while (1) {
/* Each iteration of this outer loop reads one line of the file. */
if (fgets(line_buf, LINE_SIZE, f) == NULL) {
/* End of file hit. */
fclose(f);
if (cur_line % page_len != 0) {
k = cur_line % page_len;
if (k > 0) k = page_len - k;
cur_line += k;
}
return;
}
ntokens = 0;
p = line_buf;
if (comment) {
p = skip_comment(p);
if (*p == '\n') {
cur_line++;
continue; /* we haven't seen end yet */
}
}
c = *p;
while (c != '\n') {
/* This loop scans the line looking for tokens. */
if (isalpha(c) || c == '_') {
/* This is the start of a token. */
token[ntokens++] = p; /* store start of token */
while (isalnum(*p) || *p == '_') p++;
c = *p; /* save character after token */
*p = 0; /* terminate the token */
continue;
}
/* Check to see if it is a comment. */
if (c == '/' && *(p+1) == '*') {
p = skip_comment(p+2); /* it's a comment */
c = *p;
continue;
}
/* Check to see if it is a string. */
if (c == '"') {
p++;
while (*p != '"') p++;
p++;
c = *p;
continue;
}
/* It is not a token or a comment, just ignore it. */
p++;
c = *p;
}
/* Process the token array just constructed. This is where the
* cross references are written to TMP_FILE. Put out leading
* zeros so that sort will get them right.
*/
for (i = 0; i < ntokens; i++) {
p = token[i];
if (strlen(p) > SYM_SIZE) *(p + SYM_SIZE) = 0;
k = lookup(p);
if (k > 0) {
fprintf(tmp, "%s ", p);
if (cur_line < 10) fprintf(tmp, "0000%d\n", cur_line);
else if (cur_line < 100) fprintf(tmp, "000%d\n", cur_line);
else if (cur_line < 1000) fprintf(tmp, "00%d\n", cur_line);
else if (cur_line < 10000 )fprintf(tmp, "0%d\n", cur_line);
else fprintf(tmp, "%d\n", cur_line);
}
}
cur_line++;
}
}
char *skip_comment(p)
char *p;
{
/* Skip a comment. */
while (1) {
if (*p == '*' && *(p+1) == '/') {
comment = 0;
return(p+2);
}
if (*p == '\n') {
comment = 1; /* next line is still comment. */
return(p);
}
p++;
}
}
collect_xref()
{
/* Sort the cross references and format them. */
int i, n, values[MAX_VALUES], used, nval, s, flag;
register char *p;
char *pname, *pnum;
char cur[SYM_SIZE+1]; /* name currently being processed. */
/* Use the sort program to sort the file where the cross references have been
* accumulating.
*/
fclose(tmp); /* close temporary file to flush the buffer */
sort_xref(); /* sort the cross references */
unlink(TMP_FILE); /* temporary file is not needed any more */
/* Open the sorted file to read it back. */
sortf = fopen(SORTED_FILE, "r");
if (sortf == NULL) {
fprintf(stderr, "numb: cannot read back %s \n", SORTED_FILE);
exit(2);
}
/* Read back each line in turn. */
used = 0;
while (1) {
if (fgets(line_buf, LINE_SIZE, sortf) == NULL) {
/* EOF seen. Flush current line and return. */
fprintf(xr, "\n");
fclose(xr);
unlink(SORTED_FILE);
return;
}
/* Terminate both of the tokens contained on each line with 0s. */
p = line_buf;
pname = p;
while (*p != ' ') p++;
*p = 0;
p++;
pnum = p;
while (*p != '\n') p++;
*p = 0;
/* Is this name the one we are currently working on? */
if (used == 0 || strcmp(pname, cur) != 0) {
nval = new_name(cur, used, pname, values);
xcount = nval; /* # refs on this line so far */
}
used = 1;
/* For every reference, see if it is a definition. If so, do not
* print it, since the definitions are printed when the symbol is
* encountered for the first time.
*/
s = atoi(pnum);
flag = 0;
for (i = 0; i < nval; i++) if (s == values[i]) flag = 1;
if (flag) continue;
if (mflag && s == prev_ref) continue; /* max 1 citation/line */
if (xcount > 0 && xcount % MAX_PER_LINE == 0) {
if (tflag)
fprintf(xr, "\t");
else
fprintf(xr, " ");
}
/* The next line prints a reference on the cross reference listing. */
if (tflag)
fprintf(xr, "\t%d", s);
else
fprintf(xr, " %5d", s);
prev_ref = s; /* remember it for subsequent use */
xcount++; /* number of symbols printed on this line */
if (xcount % MAX_PER_LINE == 0) fprintf(xr, "\n");
}
}
int new_name(cur, used, pname, values)
char *cur[SYM_SIZE+1]; /* storage for current name */
int used; /* 0 only on first call. */
char *pname; /* pointer to the new name */
int values[MAX_VALUES]; /* all the definitions of the new name */
{
/* A new name has been read. Finish off the old one and prepare new one. */
int slot, nval, i,j, type, temp;
/* If a name is currently in use (all except first time), finish it. */
if (used && xcount % MAX_PER_LINE > 0) fprintf(xr, "\n");
xcount = 0;
/* Copy the new name in place and fetch its definitions. Multiple definitions
* are allowed, e.g., do_fork may appear in FS and also in MM, but if they
* are different types (e.g., one PUBLIC and one PRIVATE) only one of them
* will be included in the listing, to avoid messing up the layout.
*/
strcpy(cur, pname);
cur[SYM_SIZE] = 0;
slot = lookup(pname);
nval = 0;
while (symtab[slot].sym_type > 0) {
if (strcmp(pname, symtab[slot].sym_name) == 0) {
values[nval++] = symtab[slot].sym_val;
type = symtab[slot].sym_type;
if (nval == MAX_VALUES) break;
}
slot = (slot + 1) % NSYMS;
}
/* Sort the values. */
for (i = 0; i < nval-1; i++) {
for (j = i+1; j < nval; j++) {
if (values[i] > values[j]) {
temp = values[i];
values[i] = values[j];
values[j] = temp;
}
}
}
/* Print the line in the cross reference map that contains the symbol. */
fprintf(xr, "%s", pname);
if (tflag) {
fprintf(xr, "\t%s\\fB", ppmap2[type]);
for (i = 0; i < nval; i++) fprintf(xr, "\t%d",values[i]);
fprintf(xr, "\\fR");
} else {
i = strlen(pname);
fprintf(xr,"%s %s ", &spaces[i], ppmap2[type]);
for (i = 0; i < nval; i++) fprintf(xr, "%5d ",values[i]);
}
return(nval);
}
sort_xref()
{
/* Sort the cross reference file by forking off a copy of 'sort'. */
int status, pid;
pid = fork();
if (pid > 0) {
/* Parent just waits. */
wait(&status);
if (status != 0) panic("couldn't sort cross references");
} else {
/* Child execs sort. */
close(0);
close(1);
if (open(TMP_FILE, 0) < 0) exit(1);
if (creat(SORTED_FILE, 0644) < 0) exit(2);
execl("/bin/sort", "sort", 0);
execl("/usr/bin/sort", "sort", 0);
exit(3);
}
}
output_macros(f, text)
FILE *f;
char *text[];
{
/* Output troff commands. */
int i;
i = 0;
while (text[i] != (char *) 0) {
fprintf(f, text[i]);
i++;
}
}
sym_macros()
{
}
xref_macros()
{
}
panic(s)
char *s;
{
fprintf(stderr, "%s: %s\n", prog_name, s);
exit(2);
}
usage()
{
fprintf(stderr,"Usage: %s [-] [-dlmtsx] [-p pagenr] file ... \n",
prog_name);
}