/************************************************************************
*
* lnk7090 - Links objects from asm7090
*
* Changes:
*   05/21/03   DGP   Original.
*   12/28/04   DGP   Changed to new object tags and new memory layout.
*	
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>

#include "lnkdef.h"

FILE *lstfd = NULL;
int listmode = FALSE;
int pc; /* the linker pc */
int absolute = FALSE;
int symbolcount;
int errcount = 0;
int pgmlength = 0;
int absentry = -1;
int relentry = -1;
char errline[120];
char deckname[MAXSYMLEN+2];
char inbuf[MAXLINE];

SymNode *symbols[MAXSYMBOLS];
Memory memory[MEMSIZE];

static int linecnt = MAXLINE;
static int pagenum = 0;
static char datebuf[48];

/***********************************************************************
* printheader - Print header on listing.
***********************************************************************/

void
printheader (FILE *lstfd)
{
   if (linecnt > LINESPAGE)
   {
      linecnt = 0;
      if (pagenum) fputc ('\f', lstfd);
      fprintf (lstfd, H1FORMAT,
	       VERSION,
	       " ",
	       datebuf,
	       ++pagenum);
   }
}

/***********************************************************************
* Main procedure
***********************************************************************/

main (int argc, char **argv)
{
   FILE *infd = NULL;
   FILE *outfd = NULL;
   char *infile[MAXFILES];
   char *outfile = NULL;
   char *lstfile = NULL;
   char *bp;
   int i;
   int incnt = 0;
   int status = 0;
   time_t curtime;
   char module[32];
  
#ifdef DEBUG
   printf ("lnk7090: Entered:\n");
   printf ("args:\n");
   for (i = 1; i < argc; i++)
   {
      printf ("   arg[%2d] = %s\n", i, argv[i]);
   }
#endif

   /*
   ** Clear files.
   */

   for (i = 0; i < MAXFILES; i++)
   {
      infile[i] = NULL;
   }

   /*
   ** Clear symboltable
   */

   for (i = 0; i < MAXSYMBOLS; i++)
   {
      symbols[i] = NULL;
   }

   /*
   ** Scan off the the args.
   */

   deckname[0] = '\0';

   for (i = 1; i < argc; i++)
   {
      bp = argv[i];

      if (*bp == '-')
      {
         bp++;
         switch (*bp)
         {
	 case 'd': /* Deckname */
	    i++;
	    if (strlen (argv[i]) > MAXSYMLEN) argv[i][MAXSYMLEN] = '\0';
	    strcpy (deckname, argv[i]);
	    break;

	 case 'l': /* List link map */
	    i++;
	    lstfile = argv[i];
	    listmode = TRUE;
	    break;

         case 'o': /* Link output */
            i++;
            outfile = argv[i];
            break;

         default:
      USAGE:
	    fprintf (stderr, "lnk7090 - version %s\n", VERSION);
	    fprintf (stderr,
		  "usage: lnk7090 [-options] -o file.bin file.bin...\n");
	    fprintf (stderr, " options:\n");
	    fprintf (stderr, "    -d deck     - Deckname for output\n");
	    fprintf (stderr, "    -l listfile - Generate link map listing\n");
	    return (ABORT);
         }
      }

      else
      {
         infile[incnt++] = argv[i];
      }

   }

   if (!infile[0] && !outfile) goto USAGE;

#ifdef DEBUG
   printf (" outfile = %s\n", outfile);
   for (i = 0; i < incnt; i++)
      printf (" infile[%d] = %s\n", i, infile[i]);
   if (listmode)
      printf (" lstfile = %s\n", lstfile);
#endif

   /*
   ** Open the files.
   */

   if ((outfd = fopen (outfile, "w")) == NULL)
   {
      perror ("lnk7090: Can't open output file");
      exit (1);
   }
   if (listmode) {
      if ((lstfd = fopen (lstfile, "w")) == NULL)
      {
	 perror ("lnk7090: Can't open listing file");
	 exit (1);
      }

      /*
      ** Get current date/time.
      */

      curtime = time(NULL);
      strcpy (datebuf, ctime(&curtime));
      *strchr (datebuf, '\n') = '\0';
   }

   /*
   ** Clear memory.
   */

   for (i = 0; i < MEMSIZE; i++)
   {
      memset (&memory[i], '\0', sizeof (Memory));
   }

   /*
   ** Load the objects for pass 1.
   */

   for (i = 0; i < incnt; i++)
   {
      char temp[256];

      strcpy (temp, infile[i]);
      if ((infd = fopen (infile[i], "r")) == NULL)
      {
	 sprintf (inbuf, "lnk7090: Can't open input file %s", infile[i]);
	 perror (inbuf);
	 exit (1);
      }
      if ((bp = strrchr(temp, '.')) != NULL) *bp = '\0';
      if ((bp = strrchr(temp, '/')) == NULL) bp = temp;
      else bp++;

      strcpy (module, bp);
      for (bp = module; *bp; bp++) if (islower(*bp)) *bp = toupper(*bp);

      status = lnkloader (infd, module, pc, 1);

      fclose (infd);
   }

   /*
   ** Clear memory.
   */

   for (i = 0; i < MEMSIZE; i++)
   {
      memset (&memory[i], '\0', sizeof (Memory));
   }

   /*
   ** reLoad the objects for pass 2.
   */

   pc = 0;
   for (i = 0; i < incnt; i++)
   {
      char temp[256];

      strcpy (temp, infile[i]);
      if ((infd = fopen (infile[i], "r")) == NULL)
      {
	 sprintf (inbuf, "lnk7090: Can't open input file %s", infile[i]);
	 perror (inbuf);
	 exit (1);
      }
      if ((bp = strrchr(temp, '.')) != NULL) *bp = '\0';
      if ((bp = strrchr(temp, '/')) == NULL) bp = temp;
      else bp++;

      strcpy (module, bp);
      for (bp = module; *bp; bp++) if (islower(*bp)) *bp = toupper(*bp);

      if (listmode)
      {
	 printheader (lstfd);
         fprintf (lstfd, MODFORMAT, pc, module, infile[i]);
      }

      status = lnkloader (infd, module, pc, 2);

      fclose (infd);
   }

   if (listmode)
   {
      fprintf (lstfd, "\n%5.5o Length of program\n", pc);
      if (relentry >= 0)
	 fprintf (lstfd, "%5.5o Program entry\n", relentry);
      fprintf (lstfd, "%d errors\n", errcount);
   }

   if (errcount)
      fprintf (stderr, "lnk7090: %d errors\n", errcount);

   /*
   ** Punch out linked object
   */

   if (!errcount)
      lnkpunch (outfd);

   /*
   ** Close the files
   */

   fclose (outfd);
   if (listmode)
      fclose (lstfd);

   return (status == 0 ? NORMAL : ABORT);
}
