#include "tok.h"



void  obj_outrecord(int recordtype,unsigned int recordlength,unsigned char *data);

void outeachPUBDEF(struct idrec *ptr);

void  obj_outLEDATA(unsigned int segm,unsigned int offset,unsigned int recordlength,

			 unsigned char *data);



#define MAXNUMEXTNAME 1024;



int *numextname;

int maxnumextname=MAXNUMEXTNAME;

unsigned int lenextstr=0;	//¤«¨­  áâப¨ á ¢­¥è­¨¬¨ ¨¬¥­ ¬¨

int numextern=0;



int postseg,stackseg;



unsigned int findextname(int extnum)

{

	for(unsigned int i=0;i<externnum;i++){

		if(numextname[i]==extnum)return i+1;

	}

	return 0;

}



int MakeObj()

{

unsigned int i;

unsigned int count,sizeblock;

	hout=CreateOutPut("obj","wb");

	i=strlen(startfileinfo->filename);

	string2[0]=(unsigned char)i;

	strcpy((char *)&string2[1],startfileinfo->filename);

	obj_outrecord(0x80,i+1,&string2[0]);// output the LNAMES

	sprintf((char *)&string2[3],"%s %s",compilerstr,__DATE__);

	i=strlen((char *)&string2[3]);

	*(short *)&string2[0]=0;

	string2[2]=(unsigned char)i;

	obj_outrecord(0x88,i+3,&string2[0]);// output the LNAMES

	for(count=0;count<totalmodule;count++){	//¨¬¥­  ¢ª«îç ¥¬ëå ä ©«®¢

		*(struct ftime *)&string2[2]=(startfileinfo+count)->time;

		strcpy((char *)&string2[7],(startfileinfo+count)->filename);

		i=strlen((startfileinfo+count)->filename);

		*(short *)&string2[0]=0xE940;

		string2[6]=(unsigned char)i;

		obj_outrecord(0x88,i+7,&string2[0]);// output the LNAMES

	}

	count=outptr-startptr;	//à §¬¥à ª®¤ 

	unsigned char *data=output+startptr;	//­ ç «® ¤ ­­ëå

	*(short *)&string2[0]=0xE940;

	obj_outrecord(0x88,2,&string2[0]);//ª®­¥æ ª®¬¥­â à¨©

	if(!am32){

		*(short *)&string2[0]=0xEA00;

		string2[2]=1;

		string2[3]=(unsigned char)(modelmem==SMALL?9:8);

		obj_outrecord(0x88,4,&string2[0]);

	}

	else{

		*(short *)&string2[0]=0xA140;

		obj_outrecord(0x88,2,&string2[0]);

	}

	obj_outrecord(0x96,39,(unsigned char *)"\000\005_TEXT\004CODE\004_BSS\003BSS\006DGROUP\005_DATA\004DATA");

// output the SEGDEF

	if(!am32){

		string2[0]=(unsigned char)0x28;

		*(short *)&string2[1]=(short)outptr;//count;// Set the length of the segment of DATA or CODE

		string2[3]=0x02;	//¨¬ï ᥣ¬¥­â  _TEXT

		*(short *)&string2[4]=0x0103;	//ª« áá CODE Overlay NONE 1

		obj_outrecord(0x98,6,string2);

		i=2;



		if(comfile==file_exe&&modelmem==SMALL){

			string2[0]=(unsigned char)0x48;

			*(short *)&string2[1]=outptrdata;// Set the length of the segment DATA

			string2[3]=0x07;	//¨¬ï ᥣ¬¥­â  _DATA

			*(short *)&string2[4]=0x0108;	//ª« áá DATA Overlay NONE

			obj_outrecord(0x98,6,string2);

			i++;

		}



		postseg=i;

		string2[0]=(unsigned char)0x48;

		*(short *)&string2[1]=(short)postsize;// Set the length of the segment BSS

		string2[3]=0x04;	//¨¬ï ᥣ¬¥­â  _BSS

		*(short *)&string2[4]=0x0105;	//ª« áá BSS Overlay NONE

		obj_outrecord(0x98,6,string2);

		i++;



		if(comfile==file_exe&&modelmem==SMALL){

			obj_outrecord(0x96,6,(unsigned char *)"\005STACK");

			string2[0]=0x74;

			*(short *)&string2[1]=(short)stacksize;// Set the length of the segment STACK

			string2[3]=0x09;	//¨¬ï ᥣ¬¥­â  STACK

			*(short *)&string2[4]=0x0109;	//ª« áá STACK Overlay NONE

			obj_outrecord(0x98,6,string2);

			stackseg=i;

		}

		string2[0]=6;	//¨¬ï DGROUP

		if(comfile==file_exe&&modelmem==SMALL){

			*(short *)&string2[1]=0x2FF;

			*(short *)&string2[3]=0x3FF;//postseg*256+255;//0x3FF;

			*(short *)&string2[5]=0x4ff;//stackseg*256+255;//0x4FF;

			i=7;

		}

		else{

			*(short *)&string2[1]=0x1FF;

//			*(short *)&string2[3]=0x2FF;

			*(short *)&string2[3]=0x2ff;//postseg*256+255;//0x3FF;

			i=5;

		}

		obj_outrecord(0x9A,i,string2);

	}

	else{

		string2[0]=(unsigned char)0xA9;

		*(long *)&string2[1]=(long)outptr;//count;// Set the length of the segment of DATA or CODE

		string2[5]=0x02;	//¨¬ï ᥣ¬¥­â  _TEXT

		*(short *)&string2[6]=0x0103;	//ª« áá CODE Overlay NONE

		obj_outrecord(0x99,8,string2);

		i=2;

/*

		string2[0]=(unsigned char)0xA9;

		*(long *)&string2[1]=0;// Set the length of the segment DATA

		string2[5]=0x07;	//¨¬ï ᥣ¬¥­â  _DATA

		*(short *)&string2[6]=0x0108;	//ª« áá DATA Overlay NONE

		obj_outrecord(0x99,8,string2);

		i++;*/



		postseg=i;

		string2[0]=(unsigned char)0xA9;

		*(long *)&string2[1]=(long)postsize;// Set the length of the segment BSS

		string2[5]=0x04;	//¨¬ï ᥣ¬¥­â  _BSS

		*(short *)&string2[6]=0x0105;	//ª« áá BSS Overlay NONE

		obj_outrecord(0x99,8,string2);

		i++;



		obj_outrecord(0x96,11,(unsigned char *)"\005STACK\004FLAT");//9,10



		if(comfile!=file_w32){

			string2[0]=0x75;

			*(long *)&string2[1]=(long)stacksize;// Set the length of the segment STACK

			string2[5]=0x09;	//¨¬ï ᥣ¬¥­â  STACK

			*(short *)&string2[6]=0x0109;	//ª« áá STACK Overlay NONE

			obj_outrecord(0x99,8,string2);

			stackseg=i;

		}

		string2[0]=10;



		obj_outrecord(0x9A,1,string2);	//GRPDEF Group: FLAT

		string2[0]=6;	//¨¬ï DGROUP

		i=1;

//		*(short *)&string2[i]=0x2FF;	//DATA

//		i+=2;

		*(short *)&string2[i]=postseg*256+255;//0x3FF;	//BSS

		i+=2;

		if(comfile!=file_w32){

			*(short *)&string2[i]=stackseg*256+255;//0x4FF

			i+=2;

		}

		obj_outrecord(0x9A,i,string2);

	}

// ¢ë¢®¤ EXTDEF

	while(externnum>maxnumextname)maxnumextname+=MAXNUMEXTNAME;

	numextname=(int *)MALLOC(maxnumextname*sizeof(int));

// output the PUBDEF records for each exteral procedures (all procedures)

	outeachPUBDEF(treestart);

	if(lenextstr!=0)obj_outrecord(0x8c,lenextstr,&string[0]);

// output the data (LEDATA) in 1K chunks as required!

	i=0;

	char *bufobj=(char *)MALLOC(512*5);

	while(i<count){

		unsigned int j;

		sizeblock=1024;

restart:

		for(j=0;j<posts;j++){

			if((postbuf+j)->type>=CALL_EXT&&(postbuf+j)->type<=FIX_CODE32&&

					(postbuf+j)->loc>=(i+startptr)&&(postbuf+j)->loc<(i+sizeblock+startptr)){

				if((postbuf+j)->loc>(i+startptr+sizeblock-(am32==FALSE?2:4))){

					sizeblock=(postbuf+j)->loc-i-startptr;//¨§¬¥­¨âì à §¬¥à ¡«®ª 

					goto restart;

				}

			}

		}

		if((i+sizeblock)>count)sizeblock=count-i;

		obj_outLEDATA(1,i+startptr,sizeblock,data+i);

		int ofsfix=0;

		for(j=0;j<posts;j++){

			if((postbuf+j)->loc>=(i+startptr)&&(postbuf+j)->loc<(i+sizeblock+startptr)){

				int hold=(postbuf+j)->loc-i-startptr;

				if((postbuf+j)->type>=CALL_32I/*POST_VAR*/&&(postbuf+j)->type<=FIX_CODE32){

					bufobj[ofsfix++]=(unsigned char)((am32==FALSE?0xC4:0xE4)|(hold/256));

					bufobj[ofsfix++]=(unsigned char)(hold%256);

					bufobj[ofsfix++]=0x14;

					bufobj[ofsfix++]=1;

					switch((postbuf+j)->type){

						case POST_VAR:

						case POST_VAR32:

							bufobj[ofsfix++]=postseg;

							break;

						case FIX_VAR:

						case FIX_VAR32:

							bufobj[ofsfix++]=(unsigned char)((comfile==file_exe&&modelmem==SMALL)?2:1);

							break;

						case FIX_CODE:

						case FIX_CODE32:

							bufobj[ofsfix++]=1;

							break;

					}

				}

				if((postbuf+j)->type>=POST_VAR32&&(postbuf+j)->type<=FIX_CODE32){



				}

				else if((postbuf+j)->type==CALL_EXT){

					int numext=findextname((postbuf+j)->num);

					if(numext!=0){

						bufobj[ofsfix++]=(unsigned char)((am32==FALSE?0x84:0xA4)|(hold/256));

						bufobj[ofsfix++]=(unsigned char)(hold%256);

						bufobj[ofsfix++]=0x56;

						bufobj[ofsfix++]=(unsigned char)numext;

					}

				}

				else if((postbuf+j)->type==EXT_VAR){

					int numext=findextname((postbuf+j)->num);

					if(numext!=0){

						bufobj[ofsfix++]=(unsigned char)((am32==FALSE?0xC4:0xE4)|(hold/256));

						bufobj[ofsfix++]=(unsigned char)(hold%256);

						bufobj[ofsfix++]=0x16;

						bufobj[ofsfix++]=1;

						bufobj[ofsfix++]=(unsigned char)numext;

					}

				}

			}

		}

		if(ofsfix!=0)obj_outrecord(0x9C+am32,ofsfix,(unsigned char *)bufobj);

		i+=sizeblock;

	}

	free(bufobj);

	if(comfile==file_exe&&modelmem==SMALL){

		i=0;

		while(i<outptrdata){

			if((i+1024)>outptrdata)obj_outLEDATA(2,i,outptrdata-i,outputdata+i);

			else obj_outLEDATA(2,i,1024,outputdata+i);

			i+=1024;

		}

	}

	if(sobj!=FALSE){

// output end of OBJ notifier

		string2[0]=0;

		i=1;

	}

	else{

		count=EntryPoint();

		*(short *)&string2[0]=0xC1;	//£« ¢­ë© ¬®¤ã«ì ¨¬¥¥â áâ àâ®¢ë©  ¤à¥á ª®â®à ­¥«ì§ï ¬¥­ïâì.

		*(short *)&string2[2]=0x101;

		if(count<65536){

			*(short *)&string2[4]=(short)count;

			i=6;

		}

		else{

			*(long *)&string2[4]=(long)count;

			i=8;

		}

	}

	obj_outrecord(i==8?0x8B:0x8A,i,string2);

	free(numextname);

	runfilesize=ftell(hout);

	fclose(hout);

	hout=NULL;

	return 0;

}



void  obj_outLEDATA(unsigned int segm,unsigned int offset,unsigned int recordlength,unsigned char *data)

{

int checksum=0;

int i;

unsigned char buf[8];

	buf[3]=(unsigned char)segm;

	if(offset>(65536-1024)){

		*(short *)&buf[1]=(short)(recordlength+6);

		buf[0]=0xA1;

		*(long *)&buf[4]=(long)offset;

		i=8;

	}

	else{

		*(short *)&buf[1]=(short)(recordlength+4);

		buf[0]=0xA0;

		*(short *)&buf[4]=(short)offset;

		i=6;

	}

	fwrite(buf,i,1,hout);

	for(i--;i>=0;i--)checksum+=buf[i];

	for(i=0;(unsigned int)i<recordlength;i++)checksum+=data[i];

	fwrite(data,recordlength,1,hout);

	checksum=-checksum;

	fwrite(&checksum,1,1,hout);

}



void  obj_outrecord(int recordtype,unsigned int recordlength,unsigned char *data)

// Outputs an OBJ record.

{

int checksum;

unsigned int i;

	recordlength++;

	checksum=recordtype;

	fwrite(&recordtype,1,1,hout);

	checksum+=(recordlength/256);

	checksum+=(recordlength&255);

	fwrite(&recordlength,2,1,hout);

	recordlength--;

	for(i=0;i<recordlength;i++)checksum+=data[i];

	fwrite(data,recordlength,1,hout);

	checksum=-checksum;

	fwrite(&checksum,1,1,hout);

}



void outeachPUBDEF(struct idrec *ptr)

{

unsigned int i;

	if(ptr!=NULL){

		outeachPUBDEF(ptr->right);

		if(ptr->rectok==tk_apiproc){

			i=0;

			for(unsigned int j=0;j<posts;j++){	//¯®¨áª ¨á¯®«ì§®¢ ­¨ï ¯à®æ¥¤ãàë

				if((postbuf+j)->num==(unsigned long)ptr->recnumber&&((postbuf+j)->type==CALL_32I||(postbuf+j)->type==CALL_32)){

					i++;

					(postbuf+j)->type=CALL_EXT;

					externnum++;

					if(externnum>=maxnumextname){

						maxnumextname+=MAXNUMEXTNAME;

						numextname=(int *)REALLOC(numextname,maxnumextname*sizeof(int));

					}

				}

			}

			if(i)goto nameext;

			goto endp;

		}

		if(externnum!=0&&ptr->rectok==tk_undefproc&&(ptr->flag&f_extern)!=0){

nameext:

			numextname[numextern++]=ptr->recnumber;

			i=strlen(ptr->recid);

			if((lenextstr+i+2)>=STRLEN){

				obj_outrecord(0x8c,lenextstr,&string[0]);

				lenextstr=0;

			}

			string[lenextstr++]=(unsigned char)i;

			strcpy((char *)&string[lenextstr],ptr->recid);

			lenextstr+=i+1;

		}

		else{

			if((ptr->rectok==tk_proc||ptr->rectok==tk_interruptproc)&&ptr->recsegm>=NOT_DYNAMIC){

				string2[0]=(unsigned char)(am32==0?0:1);

				string2[1]=0x01;

			}

			else if((ptr->rectok>=tk_bits&&ptr->rectok<=tk_doublevar)||ptr->rectok==tk_structvar){

				if((ptr->flag&f_extern))goto nameext;

				if(am32){

					string2[0]=1;

					string2[1]=(unsigned char)(ptr->recpost==0?1:postseg);

				}

				else if(comfile==file_exe&&modelmem==SMALL){

					string2[0]=1;

					string2[1]=(unsigned char)(ptr->recpost==0?2:postseg);

				}

				else{

					string2[0]=(unsigned char)(ptr->recpost==0?0:1);

					string2[1]=(unsigned char)(ptr->recpost==0?1:postseg);

				}

			}

			else goto endp;

			for(i=0;ptr->recid[i]!=0;i++)string2[i+3]=ptr->recid[i];

			string2[2]=(unsigned char)i;

			if(ptr->recnumber<65536){

				*(short *)&string2[i+3]=(short)ptr->recnumber;

				string2[i+5]=0x00;

				obj_outrecord(0x90,i+6,&string2[0]);

			}

			else{

				*(long *)&string2[i+3]=(long)ptr->recnumber;

				string2[i+7]=0x00;

				obj_outrecord(0x91,i+8,&string2[0]);

			}

		}

endp:

		outeachPUBDEF(ptr->left);

	}

}