/*
 * This subroutine generates the appropriate machine code format to be
 * output to the selected file. Format options are:
 *    'I' (Intel) format.
 *    'S' (SYM) format.
 * If 'objcode' is NULL then close up shop and finish things off.
 *
 * $Log: genobj.c,v $
 * Revision 1.2  1997/06/04 01:09:51  david
 * ANSI-fied the program.
 *
 */

#include <stdio.h>
#include "xasm.h"

static char *RcsId = "$Id: genobj.c,v 1.2 1997/06/04 01:09:51 david Exp $";

#define RECSIZE 16

static FILE *fd = NULL;
static char buffer[RECSIZE*2+1];
static int bufptr = 0;
static int tbytes = 0; /* Pointer into buffer & count */
static WORD addr = 0;
static int checksum = 0;

/* objcode = Object code string to be output */
void genobj( char *objcode )
{
if ( pass == 1 || objfile == NULL )
   return;

if ( fd == NULL )
   if ( (fd = fopen( objfile, "w" )) == NULL )
      {
      fprintf( stderr, "genobj: Error on open of file %s.\n", objfile );
      exit( 1 );
      }
      
switch( out_form )
   {
   case 'I' : /* Intel format */
      genintel( objcode );
      break;
   case 'S' : /* SYM format */
      gensym( objcode );
      break;
   default :
      fprintf( stderr, "genobj: Invalid Switch (%c).\n", out_form );
   }
   
if ( objcode == NULL )
   {
   if ( fd != NULL )
      if ( fclose( fd ) == EOF )
	 {
	 fprintf(stderr,"genobj: Error on close of file %s.\n", objfile );
	 exit( 1 );
	 }
   fd = NULL;
   return;
   }
}

/* Generate INTEL format */
void genintel( char *objcode )
{
static int first = 1;
int i, n;

if ( objcode == NULL ) /* End of file signal? */
   {
   if ( tbytes > 0 )
      outintel( addr, "" ); /* Anything but NULL */
   outintel( start, NULL ); /* EOF signal */
   return;
   }

if ( *objcode == '\0' )
   return;

if ( first )
   {
   first = 0;
   addr = loc;
   }
 else
   if ( (addr + tbytes) != loc )
      {
      outintel( addr, "" ); /* Address Discontinuity...Flush buffer */
      addr = loc; /* Set new addr for output record. */
      }
   
/* Loop for number of bytes */
for ( i = (strlen( objcode ) >> 1), n = 0; i > 0; i--, n +=2 )
   {
   buffer[bufptr++] = objcode[n];   /* Put into buffer */
   buffer[bufptr++] = objcode[n+1];
   buffer[bufptr] = '\0';
   tbytes++;
   chk( &objcode[n] ); /* Form checksum */
   
   if ( tbytes == RECSIZE )
      {
      outintel( addr, "" ); /* Record full...Flush buffer */
      addr += RECSIZE; /* Set new output address */
      }
   }
}

/* Output buffer ( at address 'addr' ) and reset variables */
/* objcode == NULL if end-of-file record */
void outintel( WORD addr, char *objcode )
{
char tbuf[80], *tptr;
int type = 0;
	
/* Now get rest of checksum which includes # bytes, address and type */
ichk( addr >> 8 ); ichk( addr & 0xff ); ichk( tbytes );
if ( objcode == NULL )
   type	= 0;
ichk( type );
sprintf( tbuf, ":%02x%04x%02x%s%02x\n", tbytes, addr, type, buffer,
   ( 0 - checksum ) & 0xff );
/* Convert to UPPER CASE */
for ( tptr = tbuf; *tptr != '\0'; tptr++ )
    *tptr = ( *tptr >= 'a' && *tptr <= 'z' ) ? *tptr - 0x20 : *tptr;
fprintf( fd, "%s", tbuf );
checksum = 0;
tbytes = 0;
bufptr = 0;
buffer[bufptr] = '\0'; /* Reset buffer */
}

/* Form checksum from string */
/* byteptr =  Pointer to 2 parts of the byte */
void chk( char *byteptr )
{
char temp;
	
temp = byteptr[2];
byteptr[2] = '\0';
ichk( atoh( byteptr ) );
byteptr[2] = temp;
}

void ichk( BYTE byte )
{
checksum += byte;
}

void gensym( char *objcode )
{
static int first = 1;
int i, n;

if ( objcode == NULL ) /* End of file signal? */
   {
   if ( tbytes > 0 )
      outsym( addr, "" ); /* Anything but NULL */
   outsym( start, NULL ); /* EOF signal */
   return;
   }

if ( *objcode == '\0' )
   return;

if ( first )
   {
   first = 0;
   addr = loc;
   }
 else
   if ( (addr + tbytes) != loc )
      {
      outsym( addr, "" ); /* Address Discontinuity...Flush buffer */
      addr = loc; /* Set new addr for output record. */
      }
   
/* Loop for number of bytes */
for ( i = (strlen( objcode ) >> 1), n = 0; i > 0; i--, n +=2 )
   {
   buffer[bufptr++] = objcode[n];   /* Put into buffer */
   buffer[bufptr++] = objcode[n+1];
   buffer[bufptr] = '\0';
   tbytes++;
   chk( &objcode[n] ); /* Form checksum */
   
   if ( tbytes == RECSIZE )
      {
      outsym( addr, "" ); /* Record full...Flush buffer */
      addr += RECSIZE; /* Set new output address */
      }
   }
}

/* objcode == NULL if end-of-file record */
void outsym( WORD addr, char *objcode )
{
char tbuf[80], *tptr;
	
/* Now get rest of checksum which includes # bytes, address and type */
ichk( addr >> 8 ); ichk( addr & 0xff ); ichk( tbytes );
if ( objcode == NULL )
   {
   fprintf( fd, ";00\n" );
   checksum = 0;
   tbytes = 0;
   bufptr = 0;
   return;
   }
sprintf( tbuf, ";%02x%04x%s%04x\n", tbytes, addr, buffer, checksum );
/* Convert to UPPER CASE */
for ( tptr = tbuf; *tptr != '\0'; tptr++ )
    *tptr = ( *tptr >= 'a' && *tptr <= 'z' ) ? *tptr - 0x20 : *tptr;
fprintf( fd, "%s", tbuf );
checksum = 0;
tbytes = 0;
bufptr = 0;
buffer[bufptr] = '\0'; /* Reset buffer */
}
