
/*
 *  AUTOREFS  refsfile docfile docfile docfile
 *
 *  Given one or more autodoc or .H files (e.g. intuition.doc) or include
 *  files (e.g. exec/types.h), this program appends to a dme.refs file
 *  <refsfile> appropriate lines.
 *
 *  AUTOREFS determines the file type from the extension (.h for header
 *  files, otherwise assumed to be a doc file).
 */

#include <stdio.h>

main(ac,av)
char *av[];
{
    short i;
    FILE *fi;
    FILE *fo;

    if (ac == 1) {
	puts("autorefs outfile docfile docfile ...");
	exit(1);
    }
    fo = fopen(av[1], "a");
    if (!fo) {
	printf("unable to open %s for append\n", av[1]);
	exit(1);
    }
    for (i = 2; i < ac; ++i) {
	register char *file = av[i];
	register short len = strlen(file);
	short doth = 0;

	if (len >= 2 && (file[len-1] == 'h' || file[len-1] == 'H') && file[len-2] == '.')
	    doth = 1;

	fi = fopen(file, "r");
	if (fi) {
	    if (doth) {
		printf("Scanning .H  file: %s\n", file);
		scanhfile(fi, fo, file);
	    } else {
		printf("Scanning DOC file: %s\n", file);
		scandocfile(fi, fo, file);
	    }
	    fclose(fi);
	} else {
	    printf("Unable to read %s\n", file);
	}
    }
}

/*
 *  Find the headers for each function entry and generate a DME.REFS
 *  entry for it.  The @@<N> is a short form seek position (this field
 *  normally holds a search string).
 */

scandocfile(fi, fo, filename)
FILE *fi;
FILE *fo;
char *filename;
{
    char buf[256];
    long pos = 0;

    while (fgets(buf, 256, fi)) {
	register short len = strlen(buf) - 1;
	register char *ptr = buf + len;
	char *header, *tail;

	buf[len] = 0;
	while (ptr != buf && ptr[-1] != ' ' && ptr[-1] != 9)
	    --ptr;
	if (ptr != buf && *ptr && strncmp(buf, ptr, strlen(ptr)) == 0) {
	    header = ptr;
	    for (ptr = buf + len; ptr != buf && IsAlphaNum(ptr[-1]); --ptr);
	    tail = ptr;
	    fprintf(fo, "%-20s (^l) %s @@%ld\n", tail, filename, pos);
	}
	pos = ftell(fi);
    }
}

/*
 *  Find each structure definition (stupid search, assume struct on left
 *  hand side) then generate dme.refs entry from the end point of the
 *  previous structure to the beginning of the next structure.	That is,
 *  the reference refers to the structure and all fields before and after
 *  it until the next structure (before and after).
 */

scanhfile(fi, fo, filename)
FILE *fi;
FILE *fo;
char *filename;
{
    char buf[256];
    char sname[128];
    long lin  = 1;
    long lin1;
    long lin2 = 1;
    long pos  = 0;
    long pos1;
    long pos2 = 0;
    short snameisvalid = 0;
    short newsname = 0;

    while (fgets(buf, 256, fi)) {
	register char *ptr = buf;
	if (ptr[0] == ' ')  /*  allow one space before struct */
	    ++ptr;
			    /*	ok if "union" 1 less than "struct"  */
	if (strncmp(ptr, "struct", 6) == 0 || strncmp(ptr, "union", 5) == 0) {
	    if (snameisvalid)
		fprintf(fo, "%-20s %3ld %s @@%ld\n", sname, lin-lin1, filename, pos1);
	    SetSName(sname, ptr+6);
	    snameisvalid = 0;
	    newsname = 1;
	    pos1 = pos2;
	    lin1 = lin2;
	}
	pos = ftell(fi);
	++lin;
	if (strncmp(ptr, "};", 2) == 0) {
	    pos2 = pos;
	    lin2 = lin;
	    snameisvalid = newsname;
	}
    }
    if (snameisvalid)
	fprintf(fo, "%-20s %3ld %s @@%ld\n", sname, lin-lin1, filename, pos1);
}

SetSName(buf, ptr)
register char *buf, *ptr;
{
    while (*ptr == ' ' || *ptr == 9)
	++ptr;
    while (*ptr && *ptr != '\n' && *ptr != ' ' && *ptr != 9)
	*buf++ = *ptr++;
    *buf = 0;
}

IsAlphaNum(c)
char c;
{
    if ((c >= 'a' && c <= 'z') ||
	(c >= 'A' && c <= 'Z') ||
	(c >= '0' && c <= '9') ||
	(c == '_') || (c == '(') || (c == ')')
    )
	return(1);
    return(0);
}

