/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1991 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
#define LINKER 1
#define __BIG_GENERATOR__
#include "defines.h"
#include "nasm.h"
#include <stdio.h>
#include OSBIND
#include "debug.h"
#include NMALLOC_H
#include "object.h"
#include "process.h"
#include "ldebug.h"


byte huge         *__program, huge *__p, huge *ptohead;
byte              __c;
word              __pc, __x;
lword             __lx;
extern char       header[], *currfile, trc_loss[];
extern imm huge   *hip, huge *cip;
extern seg huge   *h_seg, huge *sp;
extern word       origin;
extern int        relocatable,
                  bootable,
                  verbose,
                  pageflag;

extern ref huge   *rhead;
extern seg huge   **pas;
extern imm huge   **pai;
extern expr huge  **pae;

word                    endpc, diff, r_end, r_start, head_off, rcode_off;

extern lword            magic;
extern byte       huge  *pb;
extern e_dropped  huge  *pe;
extern s_dropped  huge  *ps;
extern linksymbol huge  *py;
extern i_dropped  huge  *pi;
extern r_dropped  huge  *pr;
extern f_dropped  huge  *pf;
extern lword            magic, bytes, sbytes, ibytes, rbytes, ebytes,
                        ybytes, fbytes;



void pro_init()
{
   ENTER("pro_init");
   __p  = __program = nmalloc( MAXMODULE);
   __pc = origin;
   if( ! bootable)
   {
      _deposit( 255);             /* drop binary header */
      _deposit( 255);
      dpoke( __p, __pc);
      _advance( 2);              /* leave some room */
      ptohead = __p;
      _advance( 2);
      head_off = rcode_off = 6;
   }
   else
      if( bootable == 1)
      {
         _deposit( 0);
         ptohead = __p;
         _advance( 1);
         dpoke( __p, __pc);
         _advance( 4);
         head_off = 6;
      }

   if( relocatable)
   {
      _deposit( 0x4C);        /* JMP */
      head_off  += 3;
      rcode_off += 3;
      __pc      += 3;
      _advance( 2);
      def_label( "|R_START", __pc);
   }
   r_start = __pc;
   LEAVE();
}


void pro_exit()
{
   extern int  runad;

   ENTER("pro_exit");
   if( ! bootable)
   {
      if( ptohead == __p - 2)          /* kill trailing empty segment */
         __p -= 4;
      else
      {
         dpoke( ptohead, __pc - 1);
      }
      if( runad)
      {
         wdeposit( 0x2E0);
         wdeposit( 0x2E1);
         wdeposit( origin);
      }
   }
   else
      if( bootable == 1)
      {
         label       *p;

         poke( ptohead, 1 + (__pc - dpeek( ptohead + 1)) / 0x80);
         if( p = find_label( "_BOOT_INIT"))
         {
            dpoke( ptohead + 3, p->val);
         }
         else
            nwarning( "_BOOT_INIT was not defined. That might lead to \
problems, if your\nbootcode returns and the OS JSRs thru the init address");
      }
   if( __p == (__program + head_off))
      nerror("Not a single byte was generated");
   LEAVE();
}


void aload( afile, hflag)
char  *afile;                     /* 3 'V's: Van Halen, VfL und Veltins! */
{
   char  *x;
   int   fd;

   ENTER("aload");
   INTEGRITY_CHECK();
#if LOWERFILE
   downcase( afile);
#endif
   IMESS( "Trying to open \"%s\" ", (lword) afile, 4);
   if( (fd = (int) Fopen( afile, OPEN_R)) < 0)
   {
      if( hflag)
      {
         INTEGRITY_CHECK();
         x = (char *) nmalloc( strlen( afile) + strlen( header) + 2L);
         strcpy( x, header);
         strcat( x, afile);
         INTEGRITY_CHECK();
      }
      else
      {
         INTEGRITY_CHECK();
         x = (char *) nmalloc( strlen( afile) + 6L);
         strcpy( x, afile);
         complete( x, ".o65", 1);
         INTEGRITY_CHECK();
      }
      if( (fd = (int) Fopen( currfile = x, OPEN_R)) < 0)
      {
         if( fd == -35)
            nferror("Out of GEMDOS file handles (that's strange..) ?)");
         nferror( "Object file does not exist");
      }
   }
   if( verbose)
      printf( "%-16s ", afile);
   INTEGRITY_CHECK();
   do_load( fd);
   INTEGRITY_CHECK();
   Fclose( fd);
   LEAVE();
}

/* ---------------------------------------------------------- */
/*    Wrapup .. Stuff to do, when we are thru with updating   */
/* the symbol table and relocating the code. A new file might */
/* be read in after this.                                     */
/* ---------------------------------------------------------- */
void wrapup()
{
   ENTER("wrapup");
   nfree( pas);
   nfree( pai);
   MESS("pae");
   nfree( pae);
   nfree( pb);
   MESS("py");
   nfree( py);
   nfree( pe);
   MESS("pr");
   nfree( pr);
   nfree( pi);
   MESS("ps");
   nfree( ps);
   nfree( pf);  /* v--- The meek shall inherit shit [DLR] */
   rhead = (ref *)       (pae
          = (expr **)     (pas
           = (seg **)      (pai
            = (imm **)      (ps
             = (s_dropped *) (pi
              = (i_dropped *) (pr
               = (r_dropped *) (pf
                = (f_dropped *) (pe
                 = (e_dropped *) (pb
                  = (byte      *) (py = 0) )))))))));
#if ! VERSION
   check_trees();
#endif
   ALEAVE();
}


void write_results( fd)                   /* 4 'V's: Van Halen, VfL, Veltins und Vrauen! y */
{
   static char    err[] = "Write to output file failed (Disk full??)";
   long           tbytes;

   ENTER("write_results");
   tbytes = (long) (__p - __program);
   if( bootable)                          /* make it sector sized */
   {
      word  tmp;

      if( tmp = (word) tbytes & 0x7F)
         tbytes += (tmp ^ 0x7F) + 1;
   }
   if( verbose)
      printf("\t\t End  : $%04X  Size:%5ld bytes total\n",
                  __pc - 1, (lword) __pc - origin - 1);
   if( Fwrite( fd, tbytes, __program) != tbytes)
      nferror( err);
#if STATISTICS
   fprintf( ESTREAM, "%ld bytes of binary written\n", tbytes);
#endif
   Fclose( fd);
   LEAVE();
}

/* ---------------------------------------------------------- */
/*           Mallocer for identifier and other strings        */
/*                                                            */
/*  (Keeping the fingers crossed that this is faster than a)  */
/*                       (simple malloc)                      */
/* ---------------------------------------------------------- */
typedef struct _str_m
{
   long                 free;
   char huge            *space;
   struct _str_m huge   *before;
} str_m;

static str_m huge *st_h;


char   *str_alloc( size)
int   size;
{
   register str_m huge  *p;
   register char  huge  *q;
   extern   word        _a_char, _m_char;
   extern  lword        _z_char, _s_char;

   ENTER("str_alloc");
#if STATISTICS
   _a_char++;
   _z_char += size;
#endif
   if( (p = st_h) && p->free >= size)
   {
letsdoit:
      p->free  -= size;
      q         = p->space;
      p->space += size;
      IMESS("sending $%lX as address", (lword) q, 4);
      LEAVE();
      return( q);
   }
#if STATISTICS
   _m_char++;
   _s_char = sizeof(str_m) + STRMAX;
#endif
   p         = (str_m *) nmalloc( sizeof(str_m) + STRMAX);
   p->free   = STRMAX;
   p->space  = (char huge *) p + sizeof( str_m);
   p->before = st_h;
   st_h  = p;
   if( size > STRMAX)
      nierror("Unexpected internal problems force NLINK65 to crash");
   goto letsdoit;
}




/* y  Har har */









