/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1991 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
#define LINKER       1
#define WRITE_TABLE  0
#if WRITE_TABLE
# include <stdio.h>
#endif
#include "defines.h"
#include "nasm.h"
#include OSBIND
#include "debug.h"
#include "seg.h"
#include "labels.h"
#include "imm.h"
#include "process.h"

extern imm huge   *hip;
extern seg huge   *h_seg, huge *l_seg;
seg huge          *f_seg;
extern word       r_end, r_start, rcode_off;

#define xdeposit( x)     deposit( x)
#define xwdeposit( x)    wdeposit( x)


void def_label( s, val)
char  *s;
word  val;
{
   label huge  *q;

   if( ! (q = find_label( s)))
   {
#if ! VERSION
      extern char    *str_alloc();
      
      s = strcpy( str_alloc( strlen( s) + 1), s);
#endif   
      enter_llabel( s, val, L_PC);  /* Shouldn't really happen */
   }      
   else
      if( ! q->refs)
         nierror("Linker internal label twice defined");
      else
      {
         q->val = val;     /* Case: Label has refs, we got the value */
         entrefer( q);
      }
}

static int  countem( p, ourpage, type)
register imm huge *p;
word              ourpage;
int               type;
{
   register int   i;
   register word  tmp;
   
   for( i = 0; p; p = p->next)
      if( p->type == type && p->block != f_seg)
      {
         if( (tmp = p->offset + p->block->offset - rcode_off + r_start) 
               >= r_end || 
             (tmp & 0xFF00) > ourpage)
            break;
         i++;
      }
   return( i);
}

/* ---------------------------------------------------------- */
/*   This dumps the immediate table down into the file write  */
/*   space. The flag tells us whether we are gonna be         */
/*   page-aligned or not (then we need plenty more info)      */
/* ---------------------------------------------------------- */
#define MSB    1
#define LSB    0

void dump_imm( flag)
int  flag;
{
   register imm huge *p = hip;
   register word     i;
   word              pages, ourpage, 
                     factor = (r_start & 0xFF) - rcode_off;
#if WRITE_TABLE
   word              aux, cnt;
#endif   

   f_seg = l_seg->next;
   def_label("|IMMTAB", __pc);

   /* incorporate .DS holes into index */
/*   {
      register seg huge *p;
      register word     plus = 0;
      
      for( p = h_seg; p != f_seg; p = p->next)
      {
         p->index += plus;
         if( p->type == S_DS)
            plus += p->size;
      }
   }*/
         
   pages = ( ((r_end & 0xFF00) - (ourpage = r_start & 0xFF00)) >> 8) + 1;
#if WRITE_TABLE
   printf(  "%d pages total\n", pages);
#endif   
   xdeposit( pages);
   
   if( ! flag)
   {
      int   ipages = pages;
      
#if WRITE_TABLE
      printf( "LSB patch bytes:");
      aux = r_start & 0xFF00; 
#endif
      while( ipages--)
      {
         i = countem( p, ourpage, LSB);
         xdeposit( i);
#if WRITE_TABLE
         printf( "\n%4d bytes to patch\n", i);
         cnt = 0;
#endif
         while( i--)
         {
            while( p->type)
               p = p->next;
            xdeposit( p->offset + p->block->offset + factor);
#if WRITE_TABLE
            if( cnt++ == 8)
            {
               putchar('\n');
               cnt = 0;
            }
            printf(  "   $%04X", __p[ -1] + ourpage);
            if( i && cnt != 8)
               putchar( ',');
#endif
            p = p->next;
         }
         ourpage += 0x100;
#if WRITE_TABLE
         putchar('\n');
#endif         
      }
      p = hip;
      ourpage = r_start & 0xFF00;
   }

#if WRITE_TABLE
   printf( "\n\nMSB patch bytes:");
#endif
   while( pages--)
   {
      i = countem( p, ourpage, MSB);
      xdeposit( i);
#if WRITE_TABLE
         printf( "\n%4d bytes to patch\n", i);
         cnt = 0;
#endif
      while( i--)
      {
         while( ! p->type)
            p = p->next;
         xdeposit( p->offset + p->block->offset + factor);
#if WRITE_TABLE
         if( cnt++ == 3)
         {
            putchar('\n');
            cnt = 1;
         }
         printf( "   $%04X (LSB: $%02X)", __p[ -1] + ourpage, 
                  p->val & 0xFF);
         if( i && cnt != 3)
            putchar( ',');
#endif
         if( ! flag)
         {
            xdeposit( p->val);
         }
         p = p->next;
      }
      ourpage += 0x100;
#if WRITE_TABLE
      putchar('\n');
#endif         
   }
}


void dump_reloc()
{
   register seg huge *p = h_seg;

   def_label( "|RELTAB", __pc);
   for(;;)
   {
      if( p->type == S_DS)
      {
         xdeposit( S_SDATA); 
      }
      else
      {
         xdeposit( p->type);
         while( p != l_seg && p->next->type == p->type)
         { 
            p->next->size += p->size;
            p = p->next;
         }
      }
      xwdeposit( p->size);
      if( p == l_seg)
      {
         xdeposit( 128);    /* dump EOP */
         return;
      }
      p = p->next;
   }
}

