/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1992 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/* ---------------------------------------------------------------------- */
#define LINKER 1
#include "defines.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include OSBIND
#include "nasm.h"
#include "debug.h"
#include NMALLOC_H
#include "code.h"
#if STATISTICS
# include <time.h>
#endif


#define STDORIGIN    0x2000
#define MAXFILES     256         /* max files to link together */
#define MAXLIBS      16

char          *currfile;
static char   *infile[MAXFILES],
              *libraries[ MAXLIBS],
              linkfile[ 256],
              outfile[ 256],
#if OS == TOS
_usage[] =
"Usage:\nnlink65 [-{tiwv}][-m [xxxx]][-s *][-b batch][-d ldir][-l lib]\
[-o com] <files>\n",
#else
_usage[] =
"Usage:\nnlink65 [-{wiv}][-m [xxxx]][-s *][-b batch][-d ldir][-l lib]\
[-o com] <files>\n",
#if PORTED
portnoy[] =
{
#  if INCOMPATIBLE
   'W','a','r','n','i','n','g',':',' ','O','b','j','e','c','t',' ',
   'f','i','l','e',' ',
   'i','n','c','o','m','p','a','t','i','b','i','l','t','y','.',' ',
#  endif
   'P','o','r','t','e','d',' ','b','y',' ',PORTER,'\n',
   0
},
# endif
#endif
notice[] =
{
   'N','l','i','n','k','6','5',' ','v',VERSION+'0','.',
   LINKREVISION/10+'0',LINKREVISION%10+'0',' ',
   'b','y',' ',AUTHOR,' ',' ','C','o','p','y','r','i','g','h','t',' ',
   '(','c',')',' ','1','9','9','2',' ',ORGANIZATION,'\r','\n',0
};

extern seg  *sp;
seg         *l_seg;
char        header[128];
int         relocatable, 
            moveable,
            dumpvalues,
            verbose,
            runad,
            pageflag = 1,
#if OS == TOS
            tossable,
#endif
            what_the_fuck,        /* cited from "Everybody wants some" */
            bootable,
            fdout,
            files,
#if STATISTICS
            tok_remain,
#endif            
            libs,
            maxerrors = 20;

word        relative = 743,
            mv_offset,
            origin = STDORIGIN;

extern int  freshflag,
            errors;


void  main( argc, argv)
int   argc;
char  **argv;
{
#if STATISTICS
   clock_t        t_start, t_finish, t_result, t_tmp;
#endif
   char           *x;
   int            i = 0,
                  foo;

   ENTER("main");
#if STATISTICS
   t_start = clock();
#endif
   if( x = getenv( "LIB65"))
   {
      strcpy( header, x);
      fixheader();
   }
#if OS == TOS
   else
      tossable = 1;
#endif

#if DEBUG
   if( argc > 1)
      printf("Argc=%d  argv[1]=\"%s\"\n", argc, argv[1]);
#endif

   while( ++i < argc)
      if( *argv[i] == '-')
         switch( Xtolower( argv[i][1]))
         {
            case 'b' :
            {
               register char  c;
               FILE           *fp, *fopen();
               static char    x[256];

               if( ++i >= argc)
                  goto usage;
               strcpy( linkfile, argv[i]);
               complete( linkfile, ".lnk", 0);
               if( ! (fp = fopen( linkfile, "r")))
                  nferror("Opening the linkfile failed");
               do
                  switch( c = getc( fp))
                  {
                     case '#'  :
                        while( (c = getc( fp)) != '\n' && c != EOF);
                        break;

                     default   :
                     {
                        register int   i = 0;

                        do
                           x[i++] = c;
                        while( (c = getc( fp)) != ' '  && c != '\t' &&
                               c != '\r' && c != '\n' && c != EOF && i < 255);
                        x[i++] = 0;
                        infile[ files++] = strcpy( (char *) nmalloc( (long) i), x);
                     }
                     case ' '  :
                     case '\t' :
                     case '\r' :
                     case '\n' :
                     case EOF  : ;
                  }
               while( c != EOF);
               fclose( fp);
            }
            break;

            case 'd' :
               if( ++i == argc)
                  goto usage;
               strcpy( header, argv[i]);
               fixheader();
               break;

            case 'i' :
               runad = ! runad;
               break;

            case 'l' :
               if( ++i >= argc)
                  goto usage;
               libraries[ libs++] = argv[i];
               break;

            case 'm' :
               switch( argv[i][2])
               {
                  case 'm' :
                     relocatable = -9;
                     moveable    = 1;
                  case '3' :
                     relocatable += 2;
                  case '2' :
                     if( ++i == argc || ! sscanf( argv[i],"%X", &foo))
                  default  :
                        goto usage;
                     relative = foo;
                     relocatable += 2;
                  case '1' :
                     relocatable++;
                  case '0' :
                  case 0   :
                     if( pageflag)
                        pageflag = ++relocatable & 2;   /* **-Port #7-** */
               }
               break;

            case 'o' :
               if( ++i == argc)
            default  :
                  goto usage;
               strcpy( outfile, argv[i]);
               break;

            case 's' :
               if( ++i >= argc || ! sscanf( argv[i], "%X", &foo))
                  goto usage;
               if( (origin = foo) < 0x100)
                  nwarning("Zeropage destination");
               else
                  if( origin < 0x200)
                     nwarning("Stack destination");
               if( pageflag)
                  pageflag = ! (origin & 0xFF);
               break;

#if OS == TOS
            case 't' :
               tossable = ! tossable;
               break;
#endif
#ifdef __DATE__
            case ':' :
               fputs( __DATE__, stderr);
# ifdef __TIME__
               fprintf( stderr, " %s", __TIME__);
# endif                              
               putc( '\n', stderr);
               break;
#endif               
            case 'v' :
               if( Xtolower( argv[ i][2]) == 'f')
               {
                  dumpvalues = ! dumpvalues;
                  if( Xtolower( argv[ i][3]) != 'l')
                     break;
               }
               verbose = ! verbose;
               break;
               
            case 'w' :
               what_the_fuck = ! what_the_fuck;
               break;
               
            case 'x' :
            {
               char  *p = &argv[i][2];
               
               bootable = ! bootable;
               if( *p)
               {
                  if( *p == ':')
                     bootable++;
                  if( ! sscanf( p, "%X", &foo))
                     goto usage;
                  define( "_BOOT_INIT", (word) foo);
               }
            }
         }
      else
         infile[files++] = argv[i];

   if( ! infile[0])
      goto usage;

#if OS == MSDOS
   _fmode = O_BINARY;
#endif
   Cconws( notice);
#if ! VERSION
   Cconws("unfinished - unstable - unsupported -- untested. Don't use it!\r\n");
   version0();
#endif
#if PORTED
   Cconws( portnoy);
#endif
   if( relocatable && pageflag)
      origin = (origin & 0xFF00) - 3;
   if( moveable)
      mv_offset = relative - origin;
   pro_init();
#if VERSION
   sexp_alloc();
#endif
   for( i = 0; i != files; i++)
      if( (x = strrchr( currfile = infile[ i], '.')) && x[ 1] == 'l')
         lload( currfile);
      else
         aload( currfile, 0);

   if( lerr_undefs( 1))
      for( i = 0; i != libs; i++)
         lload( currfile = libraries[ i]);
   if( lerr_undefs( 1))
      lload( currfile = "std.l65");
   currfile = 0;
   /* YOU CAN'T DO ANYTHING BELOW THIS POINT IN TERMS OF LIST */
   /* MANAGEMENT LOADING OF FILES ET.C.                       */
   lerr_undefs( 0);
#if ! VERSION
   if( ! errors)
      lerr_imms();
#endif
   if( relocatable)
   {
      extern word  __pc, r_end, head_off;

      r_end = __pc;
      dpoke( __program + head_off - 2, r_end);  /* Fix JSR to RELOC.O65 */
      def_label( "|MEMLO", relative);
      def_label( "|R_END", __pc);
      l_seg = sp;
      if( ! moveable)
      {
         aload( currfile = (pageflag ? "preloc.o65" : "breloc.o65"), 1);
         dump_reloc();
         dump_imm( pageflag); 
      }
      else
         aload( currfile = "mover.o65", 1);
#if ! VERSION
      if( ! errors)
         lerr_undefs( 0);
#endif
   }
   if( dumpvalues)
      show_values();
   pro_exit();
   if( ! outfile[0])
   {
      strcpy( outfile, infile[0]);
      complete( outfile, bootable ? ".boo" : ".com", 1);
   }
#if ! DEBUG
   if( ! errors || what_the_fuck)
   {
#endif
      if( (fdout = (int) Fkreate( outfile, 0x775)) < 0)
         nferror("Can't create output file");
      write_results( fdout);
#if ! DEBUG
   }
#endif
   MESS("OK JUST ABOUT DONE");
#if STATISTICS
   t_finish = clock();
   if( t_start > t_finish)
      t_tmp = t_start - t_finish;
   else
      t_tmp = t_finish - t_start;
   t_result = (t_finish - t_start) / (word) CLK_TCK;
   finalstats(1);
   printf("Link took %ld.%lds\n", t_result,
                           (t_tmp - (t_result * (word) CLK_TCK)) >> 1 );
   stats();
#endif
   LEAVE();
   nexit( errors ? 1 : 0);

usage:
   fputs( _usage, ESTREAM);
   fputs( "\
\t-v         : verbose\n\
\t-i         : append RUNAD for DOS 2.X\n\
\t-x[binit]  : create boot sectors (restrictions may apply)\n\
\t-w         : write output file anyway (W.T.F.)\n\
\t-m[0]      : mover to (LOMEM) [Default]\n\
\t-m1        : mover to (LOMEM) page aligned\n\
\t-m2 <xxxx> : mover to (xxxx)\n\
\t-m3 <xxxx> : mover to (xxxx)  page aligned\n\
\t-mm <xxxx> : mover to xxxx\n\
\t-s  <xxxx> : origin to load/run binary at\n\
\t-d  <path> : default directory\n\
\t-o  <file> : output file\n\
\t-b  <batch>: take input files from batchfile\n\
\t-l  <libs> : libraries to use\n", ESTREAM);
#if OS == TOS
   fputs( "\
\t-t         : wait for keypress before exit\n", ESTREAM);
#endif
   LEAVE();
   nexit( 1);
}

void  fixheader()
{
   static char foo[] = { DIRSLASH, 0 };

   ENTER("fixheader");
   if( header[ strlen( header)] != DIRSLASH)
      strcat( header, foo);
#if DEBUG
   printf("Current include-path : \"%s\" \n", header);
#endif
   LEAVE();
}


