#define BUFSIZE	512
#define BUFEND 	256
#define SYMSIZE	12
#define BINSIZE	6
#define EXTERN	040
#define ABSLOAD	0
#define BRANCH	1
#define JUMP	2
#define LOADELC	3
#define CBITS	0666
#define EXEC	0777
#define TRUE	1
#define FALSE	0

struct {
char control,opcode;
int bval,sn;
} binbuf, *binptr;

struct csect {
int dotsave, *tbuf,*rbuf,offset,tseek,rseek;
} csect[2];

struct {
char sname[8];
int sflag,svalue;
} *symtp , *symtab;

outf 0;
fin 0;
dot 0;
dotsect 0;

main (argc,argv)
int argc;
char *argv[];
{
	char *ofile;

	int nsymbol,header[8],i,symbytes;
	int rword,word,x;
/* Interpret arguements ... must be
 * arg1	pathname of symbol table file.
 * arg2	pathname of intermediate binary file.
 * arg3 (optional) pathname of output file.
*/
	if (argc<3){
	  printf ("Input ??: symtab binary\n");
	  exit(1);
	  }
	if ((fin=open(argv[1],0))<0){
	  printf ("Can't open %s\n",argv[1]);
	  exit(1);
	  }
	symtab=sbrk(4*SYMSIZE);
	if (read(fin,symtab,4*SYMSIZE)<4*SYMSIZE){
bst:
	  printf ("Bad Symbol table %s\n",argv[1]);
	  exit(1);
	  }
	symbytes=(symtab[0].svalue-4)*SYMSIZE;
	if (symbytes > 0)
		{sbrk(symbytes);
		if (read(fin,&symtab[4].sname[0],symbytes)<symbytes) goto bst;
		 }
	close (fin);	/* Later make this unlink*/
	nsymbol=symtab[0].svalue;
/* Symbol table complete - Construct header for a.out file
*/
	header[0]=0407;
	header[1]=symtab[1].svalue;	/* Size of .text*/
	header[2]=symtab[2].svalue;	/* Size of .data */
	header[3]=symtab[3].svalue;	/* Size of .bss */
	header[4]=symtab->svalue*SYMSIZE;	/* Size of symbol table */
	header[5]=header[6]=header[7]=0;
/* Initialize the control section tables
*/
	csect[0].tseek=16;
	csect[0].rseek=header[1]+header[2]+16;
	csect[0].tbuf=sbrk(BUFSIZE);
	csect[0].rbuf=sbrk(BUFSIZE);
	csect[0].dotsave=0;
	csect[0].offset=0;
	csect[1].tseek=header[1]+16;
	csect[1].rseek=2*header[1]+header[2]+16;
	csect[1].tbuf=sbrk(BUFSIZE);
	csect[1].rbuf=sbrk(BUFSIZE);
/* ------When data starts on a segment boundary this will be valid-------
	csect[1].dotsave=(header[1]+8191)&0160000;
----------------------------------------------------------------- */
	csect[1].dotsave=header[1];
	csect[1].offset=0;

	symtab[0].svalue=0;
	symtab[1].svalue=0;
	symtab[2].svalue = header[1];
	symtab[3].svalue = header[1] + header[2];

	for (i = 4; i < nsymbol; i++)
		if (x = symtab[i].sflag & 7)
			symtab[i].svalue =+ symtab[x - 1].svalue;

	if ((fin=open(argv[2],0))<0){
	  printf ("Can't open object file %s\n",argv[2]);
	  exit(1);
	  }
	ofile="a.out";
	if(argc>=4)ofile=argv[3];
	if ((outf=creat(ofile,CBITS))<0){
	  printf("Can't create %s\n",ofile);
	  exit(1);
	  }
/* Initialization complete - begin loading
*/
	x= TRUE;
	while (read(fin,binptr,BINSIZE)>0){
	  rword=0;
	  word=binptr->bval;
	  if((i=symtab[binptr->sn].sflag&7)!=0){
	    rword= (i-1)<<1;
	    word=+ symtab[binptr->sn].svalue;
	    }
	  else if ((symtab[binptr->sn].sflag&EXTERN)!=0){
	      rword=(binptr->sn<<4)|010;
	      x= FALSE;
	      }
	  switch(binptr->control&3){

case ABSLOAD:
	  if ((binptr->control&4)!=0){
	    word=- (dot+2);
	    rword=| 1;
	    }
	  putword(word,rword);
	  break;

case BRANCH:
	  word=(binptr->opcode<<8)+ (((word-dot-2)>>1) & 0377);
	  putword(word,0); break;

case JUMP:
	  if ((i=binptr->opcode^1)!=0){
	    putword ((i<<8)+2,0);
	    }
	  putword(0167,0);
	  putword(word-dot-2,rword|1);
	  break;

case LOADELC:
	  csect[dotsect].dotsave=dot;
	  dotsect=(rword>>1)-1;
	  dot=csect[dotsect].dotsave;
	  while (dot<word){
	    putword(0,0);
	    }
	  break;
default:
	  printf("Invalid binary %o %o %o %o\n",binptr->control,
			binptr->opcode,binptr->bval,binptr->sn);
	  exit(1);
	  }
	}
	if (csect[0].offset!=0)output(0);
	if(csect[1].offset!=0)output(1);
	seek(outf,2*(header[1]+header[2])+16,0);
	write(outf,symtab,nsymbol*SYMSIZE);
	seek(outf,0,0);
	write (outf,header,16);
	close(outf);
	if (x== TRUE) chmod(ofile,EXEC);
	close(fin);
	exit(0);
}

putword (data,reloc)
int data,reloc;
{
	int j;
	j=csect[dotsect].offset;
	csect[dotsect].tbuf[j]=data;
	csect[dotsect].rbuf[j]=reloc;
	if(++csect[dotsect].offset>=BUFEND)output(dotsect);
	dot=+2;
}

output (section)
int section;
{
	seek(outf,csect[section].tseek,0);
	write(outf,csect[section].tbuf,2*csect[section].offset);
	seek(outf,csect[section].rseek,0);
	write(outf,csect[section].rbuf,2*csect[section].offset);
	csect[section].tseek=+ 2*csect[section].offset;
	csect[section].rseek=+ 2*csect[section].offset;
	csect[section].offset=0;
}
