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


#if VERSION
# define the_10seek( x, y)
#endif

extern label huge *h_global[SEP];
extern char huge  *space, huge *old_p_space, huge *p_space;
extern char       trc_loss[], header[];
extern int        version;
extern word       diff, head_off, endpc;
extern lword      magic, __lx;
extern obj_h      l;
extern lword      bytes;

#if ! VERSION
static int        revision;
#endif
extern void       fix_lversion(), fix_lsizes();
#if BIGENDIAN
extern void       flip_libstructs();
#endif

static g_table huge  *globals;
static f_table huge  *files;
word                 gindex, findex;
static lword         gbytes, fbytes, cbytes;
static lword         gsize, fsize;

#if ! VERSION
extern char       x1[], x2[], x3[], x4[], x5[], x6[];
static char       y1[] = " _GLOBALS ",
                  y2[] = " _F_INDEX ",
                  y3[] = " _OBJFILE ";
#endif


check_name( name)
register char  *name;
{
   register char  *s;
   register int   i = gindex, j;

   while( i--)
   {
      s = globals[i].name;
      j = 0;
      while( name[j] && *s++ == name[j] && ++j < SIGNIFICANT);
      if( ! (name[j] || *s) || j == SIGNIFICANT)
         return( globals[i].index );
   }
   return( -1);
}


void  find_undef()
{
   register int         i, r;
   register label huge  *p;

   ENTER("find_undef");
restart:
   for( i = 0; i != SEP; i++)
      if( p = h_global[ i])
         do
            if( p->refs)
               if( (r = check_name( p->name)) != -1)
               {
                  xload( files[ r].seek, (long) files[ r].bytes);
                  goto restart;
               }
         while( p = p->next);
   LEAVE();
}


static int  fd;
static char *bfile;

lload( afile)
char  *afile;                     /* 3 'V's: Van Halen, VfL und Veltins! */
{
   static lib_h   l;
   register char  *x;
   register long  foo;

   ENTER("lload");
#if LOWERFILE
   downcase( afile);
#endif
   IMESS( "Trying to open \"%s\" ", (lword) afile, 4);
   if( (fd = (int) Fopen( afile, OPEN_R)) < 0)
   {
      MESS("Open failed");
      x = (char *) nmalloc( strlen( afile) + strlen( header) + 5L);
      strcpy( x, header);
      strcat( x, afile);
      complete( x, ".l65", 1);
      afile = x;
      if( (fd = (int) Fopen( afile, OPEN_R)) < 0)
      {
         if( fd == -35)
            nferror("Out of GEMDOS file handles (that's strange..) ?)");
         nferror("Library file not found");
      }
   }
   bfile = afile;
   INTEGRITY_CHECK();
   if( Fread( fd, sizeof( lib_h), &l) != sizeof( lib_h))
      nferror("File is too short to be a library");
   IMESS("Sizeof( lib_h) = %ld", sizeof( lib_h), 4);

   magic    = lbeek( &l.magic);
   version  = dbeek( &l.version);
#if ! VERSION
   revision = dbeek( &l.revision);
#endif
   gbytes   = gsize = lbeek( &l.gbytes);
   fbytes   = fsize = lbeek( &l.xbytes);
   cbytes   = lbeek( &l.cbytes);

   if( magic != LIBMAGIC)
      nferror("This is not a library");
#if BIGENDIAN
   if( version < DVERSION)
#else
   if( version < LIB_READ_COMP)
#endif
      nferror("Library was created with an obsolete version");
   if( version > DVERSION)
      nferror("Linker is too oldfashioned for these fancy new libraries");
#if ! VERSION
   if( revision != LIBREVISION)
      nferror("Library was created by a different revision");
#endif
   if( version != DVERSION)
      fix_lsizes( version, &gsize, &fsize);

   INTEGRITY_CHECK();
   the_10seek( fd, y1);
   globals = (g_table *) nmalloc( gsize);
   if( (foo = Fread( fd, gbytes, globals)) != gbytes)
      ngferror( foo, trc_loss);

   INTEGRITY_CHECK();
   the_10seek( fd, y2);
   files = (f_table *) nmalloc( fsize);
   if( fbytes)
      if( (foo = Fread( fd, fbytes, files)) != fbytes)
         ngferror( foo, trc_loss);

   INTEGRITY_CHECK();
   the_10seek( fd, y3);

   if( version != DVERSION)
      fix_lversion( version, &gbytes, globals, &fbytes, files);

   gindex = (word) (gbytes / sizeof( g_table));
   findex = (word) (fbytes / sizeof( f_table));

#if BIGENDIAN
   flip_libstructs( gindex, findex, globals, files);
#endif
   INTEGRITY_CHECK();
   find_undef();
   Fclose( fd);
   nfree( globals);
   nfree( files);
   LEAVE();
}

#if VERSION
void xload( seek, bckbytes)
long  seek, bckbytes;
{
   extern int  verbose;

   ENTER("xload");

   if( Fseek( seek, fd, 1) < 0)
      nferror("Library file corrupted");
   if( verbose)
      printf( "%-16s ", bfile);
   do_load( fd);
   if( Fseek( - (bckbytes + seek), fd, 1) < 0)
      nierror("Seek failure");
   LEAVE();
}

#else

void xload( seek, bckbytes)
long  seek, bckbytes;
{
   extern int  verbose;
   long        pos;

   ENTER("xload");
   pos = Fseek( 0, fd, 1);
   if( Fseek( seek, fd, 1) < 0)
      nferror("Library file corrupted");
   if( verbose)
      printf( "%-16s ", bfile);
   do_load( fd);
   if( Fseek( - (bckbytes + seek), fd, 1) < 0)
      nierror("Seek failure");
   if( Fseek( 0, fd, 1) != pos)
      nferror("The seek just didn't work");
   LEAVE();
}

#endif
