#include "pm.h"
#include <sys/stat.h>

/*
 * pm - initialization routines
 */

char *stab;
struct	nlist	nl[6] ;		/* symbols pulled out of the text image	 */
extern	struct	pentry	*proctb;
extern	struct	sentry	*semtab;
extern	struct	tty	*tptr;
extern	struct	qent	*Q;

setup(argc, argv)
int	argc;
char	*argv[];
{
	char		*malloc();
	FILE		*txtfd, *corefd;
	struct stat	stat;
	register struct nlist	*sp1, *sp2;
	register 	i;
	int		n;
	int		svalcomp();
	int		symsize;	/* size of symbol table */
	int		isymbol;	/* index to symbol table */
	int		csymbol;	/* number of symbol table entries */
	int		iExt;		/* index of externals */
	int		cExt;		/* count of externals */
	FILE		*ldptr;
	struct nlist *space;
	nl[0].n_un.n_name = "_currpid";
#define	CURRPID		0
	nl[1].n_un.n_name = "_proctab";
#define	PROC		1
	nl[2].n_un.n_name = "_q";
#define	XQ		2
	nl[3].n_un.n_name = "_semaph";
#define	SEMS		3
	nl[4].n_un.n_name = "_tty";
#define	TTYS		4
	nl[5].n_un.n_name = 0;

	procargs(argc, argv);

	if (verbose)
		printf("Opening core file...\n");
	corefd = fopen(corefile, "r");
	if(corefd == (FILE *)NULL){
		fprintf(stderr, "Can't open %s\n", corefile);
		exit(-1);
	}
	
	if (verbose)
		printf("Opening text file...\n");
	txtfd = fopen(txtfile, "r");
	if(txtfd == (FILE *)NULL){
		fprintf(stderr, "Can't open %s\n", txtfile);
		exit(-2);
	}

	if (verbose)
		printf("Reading core header of %d bytes\n",
			sizeof(struct core86) );
	fread(&c_header, sizeof(struct core86), 1, corefd);/* read the header */
	
	fstat(fileno(corefd), &stat);
	if ( stat.st_size <= sizeof(struct core86) ) {
		fprintf(stderr,"Malformed core file header (size=%d)\n",
			stat.st_size);
		exit(-2);
	}
	stat.st_size -= sizeof(struct core86);
	if (verbose)
		printf("Allocating %d bytes for core image\n",stat.st_size);
	core = (short *)malloc(stat.st_size);
	if(core == (short *)NULL){
		fprintf(stderr, "Can't allocate memory for core image\n");
		exit(-3);
	}

	if (verbose)
		printf("Reading core image...\n");
	fread(core, sizeof(char), stat.st_size, corefd);/* read the rest */

	if (verbose)
		printf("Reading a86.out header...\n");
	fread(&a_out, sizeof (struct exec), 1, txtfd);
	text = (short *)malloc(a_out.a_text + a_out.a_data + a_out.a_bss);
	if(text == (short *)NULL){
		fprintf(stderr, "Can't allocate space for system image\n");
		exit(-4);
	}

	fread(text, sizeof(char), a_out.a_text + a_out.a_data, txtfd);

	symtab = (struct nlist *)malloc(a_out.a_syms);
	esymtab = &symtab[a_out.a_syms / sizeof (struct nlist)];
	if(a_out.a_syms == 0)
	       	printf("No symbol table\n");
	if(symtab == (struct nlist *)NULL){
		fprintf(stderr, "Can't allocate space for symbol table\n");
		exit(-5);
	}

	
	fread(symtab, a_out.a_syms, sizeof(char), txtfd);
/* 
 * read in the string table.
 */
	
	fseek(txtfd, N_STROFF(a_out), 0);
	fread(&n, sizeof( long), 1, txtfd);
	if(verbose)
	    printf("Allocating string table of %d bytes.\n", n);
	if ( (stab=malloc(n)) == NULL) {
	    fprintf(stderr, "nlist86: can't malloc.\n");
	    exit(-1);
	}
	fread(stab,1,n,txtfd);
	stab -= 4;
	for (sp1 = symtab; sp1<esymtab; sp1++) {
	    sp1->n_un.n_name = sp1->n_un.n_strx + stab;
/*	    printf("symbol %s's value is 0x%04x\n", sp1->n_un.n_name,
	    sp1->n_value);
*/
	}

	/*
	 * produce list of externals sorted by address 
	 */

	ssymtab = (struct nlist *)malloc(a_out.a_syms);
	i = 0;
	for(sp1 = symtab, sp2 = ssymtab; sp1 < esymtab; sp1++){
		if((sp1->n_type & N_EXT) == 0)
			continue;
		i++;
		*sp2++ = *sp1;
	}

	essymtab = ssymtab + i;


	/* 
	 * look up addresses of interesting tables 
	 */

	nlist86(nl);
	qsort(ssymtab, i, sizeof(struct nlist), svalcomp);
	if (verbose) { 	
	    printf("\n\n Externals sorted by address\n");
	    for (sp1 = ssymtab; sp1 <= essymtab; sp1++) {
		printf("0x%04x:\t%s\n",sp1->n_value,sp1->n_un.n_name);
	    }
	}
	currpid = core[nl[CURRPID].n_value >> 1];
	proctb = (struct pentry *)(&core[nl[PROC].n_value >> 1]);
	semtab = (struct sentry *)(&core[nl[SEMS].n_value >> 1]);
	Q = (struct qent *)(&core[nl[XQ].n_value >> 1]);
        tptr = (struct tty *)(&core[nl[TTYS].n_value >> 1]);

}


svalcomp(sp1, sp2)
register struct nlist *sp1, *sp2;
{
	if(sp1->n_value == sp2->n_value)
		return(0);
	if(sp1->n_value < sp2->n_value)
		return(-1);
	return(1);
}
nlist86(list)
struct nlist *list;
{
	register struct nlist *p, *q;
	int f, m, n, i;

	for(p = list; p->n_un.n_name[0]; p++) {
		p->n_type = 0;
		p->n_value = 0;
	}

	for(q = ssymtab; q < essymtab; q++) {

/*printf("nlist86:looking at symbol: %s, its offset = %d.\n", q->n_un.n_name,
    q->n_un.n_strx);*/
	    for(p = list; p->n_un.n_name[0]; p++) {
		for(i=0;q->n_un.n_name[i];i++)
		    if(p->n_un.n_name[i] != q->n_un.n_name[i]) goto cont;
		p->n_value = q->n_value;
		p->n_type = q->n_type;
		break;
		cont:		;
	    }
	}
	return(0);
}

/*
 *===================================================
 * procargs - unified argument processing procedure
 *===================================================
 *
 * This procedure continas the logic for converting the UNIX argument
 * list into global variables
 */

procargs(argc, argv)
int argc;
char *argv[];
{
        int arg, unswitched, more;
        char *swptr;

	corefile = "core86";
	txtfile = "a86.out";
	allopts = 1;
	popt = sopt = topt = 1;
	verbose = 0;

        unswitched = 0;
        for ( arg=1 ; arg<argc ; arg++ ) {
                if ( argv[arg][0] == '-' ) {
                        more = 1;
                        swptr = &argv[arg][1];
                        while ( more && *swptr!='\0' ) {
                                switch ( *swptr++ ) {
				case 'v':
					verbose=1;

				case 'p':
					allopts = 0;
					popt = 1;
					break;

				case 's':
					allopts = 0;
					sopt = 1;
					break;

				case 't':
					allopts = 0;
					topt = 1;
					break;

                                default:
                                        usagexit(argv[0]);
                                }
                        }
                } else { /* there's no dash in front */
                        switch ( unswitched++ ) {
			case 0:
				txtfile = argv[arg];
				break;
			
			case 1:
				corefile = argv[arg];
				break;

                        default:
                                usagexit(argv[0]);
                        }
                }
        }
}
usagexit(pgm)
char *pgm;
{
        fprintf(stderr,"usage: %s [program [core]]\n",pgm);
        exit(1);
}
