/* On the SGI, <a.out.h> includes a file that defines a variable named
 * auxtemp.  This causes the linker to complain about this variable
 * being multiply defined, because <a.out.h> was already included by
 * load.vanilla.c.
 */
#define _auxtemp Auxtemp

#include <a.out.h>
#include <sys/file.h>

#define READ(fd, buf, size, errmsg)\
    if (read (fd, buf, size) != size)\
        Primitive_Error (errmsg);

#define SEEK(fd, pos, errmsg)\
    if (lseek (fd, pos, L_SET) != pos)\
        Primitive_Error (errmsg);

SYMTAB *Snarf_Symbols (fp) FILE *fp; {
    int fd;			/* a file descriptor */
    long fdi;			/* a counter for the file desc table */
    pFDR file_desc;		/* pointer to the filedesc table */
    struct filehdr file_hdr;	/* pointer to the file header */
    char *strbase;
    char *strings;
    HDRR sym_hdr;		/* pointer to symbolic header */
    long symi;			/* a counter for the local symbol table */
    pSYMR symbol;		/* pointer to symbol table */

    SYMTAB *tab;
    char *p;
    SYM *sp, **nextp;

    fd = fileno(fp);

    /* rewind the object file, since who knows what it's status is... */
    SEEK(fd, 0, "unable to rewind object file");

    /* read in the file header */
    READ(fd, &file_hdr, sizeof(file_hdr), "unable to read file header");

    /* seek to the start of the symbolic header */
    SEEK(fd, file_hdr.f_symptr, "unable to seek to symbolic header");

    /* read in the symbolic header */
    READ(fd, &sym_hdr, sizeof(sym_hdr), "unable to read symbolic header");

    tab = (SYMTAB *)Safe_Malloc (sizeof (SYMTAB));
    tab->first = 0;
    tab->strings = 0;
    nextp = &tab->first;

    SEEK(fd, sym_hdr.cbSymOffset, "unable to seek to symbol table");
    symbol = (pSYMR)Safe_Malloc (sym_hdr.isymMax * sizeof (SYMR));
    READ(fd, symbol, (sym_hdr.isymMax * sizeof(SYMR)),
       "unable to read symbol table");

    SEEK(fd, sym_hdr.cbSsOffset, "unable to seek to string table");
    strings = Safe_Malloc (sym_hdr.issMax);
    READ(fd, strings, sym_hdr.issMax, "unable to read string table");

    SEEK(fd, sym_hdr.cbFdOffset, "unable to seek to file descriptor table");
    file_desc = (pFDR)Safe_Malloc (sym_hdr.ifdMax * sizeof(FDR));
    READ(fd, file_desc, (sym_hdr.ifdMax * sizeof(FDR)),
	"unable to read file descriptor table");

    /* for each file in the file descriptor table do:
    */
    for (fdi = 0; fdi < sym_hdr.ifdMax; fdi++) {
	strbase = strings + file_desc[fdi].issBase;
	for (symi = file_desc[fdi].isymBase;
		symi < file_desc[fdi].csym + file_desc[fdi].isymBase;
		symi++) {
	    if (symbol[symi].st == stProc && symbol[symi].sc == scText) {
		p = symbol[symi].iss + strbase;
	
		/* allocate another node in the symbol table list */
		sp = (SYM *)Safe_Malloc (sizeof (SYM));
		sp->name = Safe_Malloc (strlen (p) + 1);
	
		/* set the new nodes values */
		strcpy (sp->name, p);
		sp->value = symbol[symi].value;
	
		/* link the node into the linked list */
		*nextp = sp;
		nextp = &sp->next;
		*nextp = 0;
	    }
	}
    }
    return tab;
}

#ifdef INIT_OBJECTS
SYMTAB *Open_File_And_Snarf_Symbols (name) char *name; {
    FILE *fp;
    SYMTAB *tab;
  
    if ((fp = fopen (name, "r")) == NULL)
	Primitive_Error ("can't open a.out file");
    tab = Snarf_Symbols (fp);
    (void)fclose (fp);
    return tab;
}
#endif /* INIT_OBJECTS */
