/***********************************************************************
*
* asm7090 - Assembler for the IBM 7090 computer.
*
* Changes:
*   05/21/03   DGP   Original.
*   08/13/03   DGP   Added XREF support.
*   12/20/04   DGP   Added MAP support and 2.0 additions.
*   02/03/05   DGP   Added JOBSYM mode.
*   02/08/05   DGP   Added FAP support and multiple assembly.
*   03/08/05   DGP   Added CPU model.
*	
***********************************************************************/

#include <stdio.h>
#ifndef WIN32
#include <unistd.h>
#endif
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <time.h>

#include "asmdef.h"
#include "asmdmem.h"

int absolute;			/* In absolute section */
int absmod;			/* In absolute module */
int genxref;			/* Generate cross reference listing */
int widemode;			/* Generate wide listing */
int monsym;			/* Include IBSYS Symbols (MONSYM) */
int jobsym;			/* Include IBJOB Symbols (JOBSYM) */
int addext;			/* Add extern for undef'd symbols (!absolute) */
int addrel;			/* ADDREL mode */
int termparn;			/* Parenthesis are terminals (NO()) */
int rboolexpr;			/* RBOOL expression */
int lboolexpr;			/* LBOOL expression */
int fapmode;			/* FAP assembly mode */
int exprtype;			/* Expression type */
int pc;				/* the assembler pc */
int symbolcount;		/* Number of symbols in symbol table */
int entsymbolcount;		/* Number of symbols in entry symbol table */
int opdefcount;			/* Number of user defined opcode in opdef */
int begincount;			/* Number of BEGINs */
int inpass;			/* Which pass are we in */
int errcount;			/* Number of errors in assembly */
int errnum;			/* Index into errline array */
int linenum;			/* Source line number */
int p1errcnt;			/* Number of pass 0/1 errors */
int p1erralloc;			/* Number of pass 0/1 errors allocated */
int pgmlength;			/* Length of program */
int radix;			/* Number scanner radix */
int qualindex;			/* QUALifier table index */
int litorigin;			/* Literal pool origin */
int litpool;			/* Literal pool size */
int headcount;			/* Number of entries in headtable */
int cpumodel;			/* CPU model (709, 7090 7094) */

char errline[10][120];		/* Pass 2 error lines for current statment */
char inbuf[MAXLINE];		/* The input buffer for the scanners */
char lbl[MAXLBLLEN+2];		/* The object label */
char deckname[MAXSYMLEN+2];	/* The assembly deckname */
char ttlbuf[TTLSIZE+2];		/* The assembly TTL buffer */
char titlebuf[TTLSIZE+2];	/* The assembly TITLE buffer */
char qualtable[MAXQUALS][MAXSYMLEN+2]; /* The QUALifier table */
char headtable[MAXHEADS];	/* HEAD table */
char datebuf[48];		/* Date/Time buffer for listing */

SymNode *addextsym;		/* Added symbol for externals */
SymNode *symbols[MAXSYMBOLS];	/* The Symbol table */
SymNode *entsymbols[MAXSYMBOLS];/* The Entry Symbol table */
SymNode *freesymbols;		/* Reusable symbols nodes */
XrefNode *freexrefs;		/* Reusable xref nodes */
OpDefCode *freeops;		/* Reusable opdef nodes */
OpDefCode *opdefcode[MAXDEFOPS];/* The user defined opcode table */
ErrTable p1error[MAXERRORS];	/* The pass 0/1 error table */
BeginTable begintable[MAXBEGINS];/* The USE/BEGIN table */
time_t curtime;			/* Assembly time */
struct tm *timeblk;		/* Assembly time */

static int verbose;		/* Verbose mode */
static int gblabsmod;		/* In absolute module */
static int gblmonsym;		/* Include IBSYS Symbols (MONSYM) */
static int gbljobsym;		/* Include IBJOB Symbols (JOBSYM) */
static int filecnt;		/* File process count */

/*
** IBSYS System nucleus defintions (MONSYM).
*/

static int mondefsset;
static SysDefs mapmondefs[] =
{
   { "SYSTRA", "S.S", 000100 },
   { "SYSDAT", "S.S", 000101 },
   { "SYSCUR", "S.S", 000102 },
   { "SYSRET", "S.S", 000103 },
   { "SYSKEY", "S.S", 000104 },
   { "SYSSWS", "S.S", 000105 },
   { "SYSPOS", "S.S", 000106 },
   { "SYSUNI", "S.S", 000107 },
   { "SYSUBC", "S.S", 000110 },
   { "SYSUAV", "S.S", 000111 },
   { "SYSUCW", "S.S", 000112 },
   { "SYSRPT", "S.S", 000113 },
   { "SYSCEM", "S.S", 000114 },
   { "SYSDMP", "S.S", 000115 },
   { "SYSIOX", "S.S", 000116 },
   { "SYSIDR", "S.S", 000117 },
   { "SYSCOR", "S.S", 000120 },
   { "SYSLDR", "S.S", 000121 },
   { "SYSACC", "S.S", 000122 },
   { "SYSPID", "S.S", 000123 },
   { "SYSCYD", "S.S", 000124 },
   { "SYSSLD", "S.S", 000126 },
   { "SYSTCH", "S.S", 000127 },
   { "SYSTWT", "S.S", 000131 },
   { "SYSGET", "S.S", 000132 },
   { "SYSJOB", "S.S", 000133 },
   { ".CHEXI", "",    000134 },
   { ".MODSW", "",    000135 },
   /* SYSUNI table */
   { "SYSLB1", "S.S", 000140 },
   { "SYSLB2", "S.S", 000141 },
   { "SYSLB3", "S.S", 000142 },
   { "SYSLB4", "S.S", 000143 },
   { "SYSCRD", "S.S", 000144 },
   { "SYSPRT", "S.S", 000145 },
   { "SYSPCH", "S.S", 000146 },
   { "SYSOU1", "S.S", 000147 },
   { "SYSOU2", "S.S", 000150 },
   { "SYSIN1", "S.S", 000151 },
   { "SYSIN2", "S.S", 000152 },
   { "SYSPP1", "S.S", 000153 },
   { "SYSPP2", "S.S", 000154 },
   { "SYSCK1", "S.S", 000155 },
   { "SYSCK2", "S.S", 000156 },
   { "SYSUT1", "S.S", 000157 },
   { "SYSUT2", "S.S", 000160 },
   { "SYSUT3", "S.S", 000161 },
   { "SYSUT4", "S.S", 000162 },
   { "SYSUT5", "S.S", 000163 },
   { "SYSUT6", "S.S", 000164 },
   { "SYSUT7", "S.S", 000165 },
   { "SYSUT8", "S.S", 000166 },
   { "SYSUT9", "S.S", 000167 },
   /* IOEX communications region */
   { ".ACTV",  "",    000702 },
   { ".NDSEL", "",    000704 },
   { ".MWR",   "",    000706 },
   { ".PUNCH", "",    000707 },
   { ".ENBSW", "",    000710 },
   { ".PAWS",  "",    000711 },
   { ".PAUSE", "",    000712 },
   { ".STOP",  "",    000713 },
   { ".SYMUN", "",    000714 },
   { ".DECVD", "",    000715 },
   { ".DECVA", "",    000716 },
   { ".CKWAT", "",    000717 },
   { ".BCD5R", "",    000720 },
   { ".BCD5X", "",    000721 },
   { ".CVPRT", "",    000722 },
   { ".STOPD", "",    000723 },
   { ".CHXAC", "",    000724 },
   { ".URRX",  "",    000725 },
   { ".RCTX",  "",    000726 },
   { ".RCHX",  "",    000727 },
   { ".TCOX",  "",    000730 },
   { ".TRCX",  "",    000731 },
   { ".ETTX",  "",    000732 },
   { ".TEFX",  "",    000733 },
   { ".TRAPX", "",    000734 },
   { ".TRAPS", "",    000735 },
   { ".COMM",  "",    000736 },
   { ".LTPOS", "",    000737 },
   { ".IOXSI", "",    000740 },
   { ".CHPSW", "",    000741 },
   { ".TRPSW", "",    000742 },
   { ".FDAMT", "",    000743 },
   { ".SDCXI", "",    000744 },
   { ".STCXI", "",    000745 },
   { ".COMMD", "",    000746 },
   { ".IBCDZ", "",    000747 },
   { ".CHXSP", "",    000750 },
   { ".BLKSW", "",    000751 },
   { "SYSORG", "S.S", 002652 },
   { "SYSEND", "S.S", 077777 },
   { "",       "",    -1     }
};

/*
** IBJOB defintions (JOBSYM), pulls in mapmondefs.
*/

static int jobdefsset;
static SysDefs jobdefs[] =
{
   { "SYSLOC", "", 021234 },
   { "SYSFAZ", "", 021235 },
   { "IBJCOR", "", 021236 },
   { "IBJDAT", "", 021237 },
   { ".JLDAT", "", 021240 },
   { ".JTYPE", "", 021242 },
   { ".JLIN",  "", 021243 },
   { ".JVER",  "", 021244 },
   { ".JKAPU", "", 021245 },
   { "SYSDSB", "", 021246 },
   { ".FDPOS", "", 021250 },
   { "SSTRA",  "", 021253 },
   { "ACTION", "", 021254 },
   { "JOBIN",  "", 021255 },
   { "JOBOU",  "", 021256 },
   { "JOBPP",  "", 021257 },
   { "IOEDIT", "", 021260 },
   { "JREEL",  "", 021261 },
   { "SUBSP",  "", 021262 },
   { "PUNCH",  "", 021263 },
   { "SYSSHD", "", 021264 },
   { "LILDMP", "", 021265 },
   { "IBSLB",  "", 021266 },
   { "PRSW",   "", 021267 },
   { "DEFINE", "", 021347 },
   { "JOIN",   "", 021351 },
   { "ATTACH", "", 021353 },
   { "CLOSE",  "", 021355 },
   { "OPEN",   "", 021357 },
   { "READ",   "", 021361 },
   { "WRITE",  "", 021363 },
   { "STASH",  "", 021365 },
   { "SUBSYS", "", 021412 },
   { "",       "", -1     }
};

/*
** FAP SST IBSYS symbols.
*/

static int ifapdefsset;
static SysDefs ifapmondefs[] =
{
   { "SYSTRA", "", 000100 },
   { "SYSDAT", "", 000101 },
   { "SYSCUR", "", 000102 },
   { "SYSRET", "", 000103 },
   { "SYSKEY", "", 000104 },
   { "SYSSWS", "", 000105 },
   { "SYSPOS", "", 000106 },
   { "SYSUNI", "", 000107 },
   { "SYSUBC", "", 000110 },
   { "SYSUAV", "", 000111 },
   { "SYSUCW", "", 000112 },
   { "SYSRPT", "", 000113 },
   { "SYSCEM", "", 000114 },
   { "SYSDMP", "", 000115 },
   { "SYSIOX", "", 000116 },
   { "SYSIDR", "", 000117 },
   { "SYSCOR", "", 000120 },
   { "SYSLDR", "", 000121 },
   { "SYSACC", "", 000122 },
   { "SYSPID", "", 000123 },
   { "SYSCYD", "", 000124 },
   { "SYSSLD", "", 000126 },
   { "SYSTCH", "", 000127 },
   { "SYSTWT", "", 000131 },
   { "SYSGET", "", 000132 },
   { "SYSJOB", "", 000133 },
   { ".CHEXI", "", 000134 },
   { ".MODSW", "", 000135 },
   /* SYSUNI table */
   { "SYSLB1", "", 000140 },
   { "SYSLB2", "", 000141 },
   { "SYSLB3", "", 000142 },
   { "SYSLB4", "", 000143 },
   { "SYSCRD", "", 000144 },
   { "SYSPRT", "", 000145 },
   { "SYSPCH", "", 000146 },
   { "SYSOU1", "", 000147 },
   { "SYSOU2", "", 000150 },
   { "SYSIN1", "", 000151 },
   { "SYSIN2", "", 000152 },
   { "SYSPP1", "", 000153 },
   { "SYSPP2", "", 000154 },
   { "SYSCK1", "", 000155 },
   { "SYSCK2", "", 000156 },
   { "SYSUT1", "", 000157 },
   { "SYSUT2", "", 000160 },
   { "SYSUT3", "", 000161 },
   { "SYSUT4", "", 000162 },
   /* IOEX communications region */
   { "(ACTIV", "", 000702 },
   { "(ACTVX", "", 000703 },
   { "(NDATA", "", 000704 },
   { "(NDSLX", "", 000705 },
   { "(PROUT", "", 000706 },
   { "(PUNCH", "", 000707 },
   { "(ENBSW", "", 000710 },
   { "(PAWSX", "", 000711 },
   { "(PAUSE", "", 000712 },
   { "(STOPX", "", 000713 },
   { "(SYMUN", "", 000714 },
   { "(DECVD", "", 000715 },
   { "(DECVA", "", 000716 },
   { "(CKWAT", "", 000717 },
   { "(BCD5R", "", 000720 },
   { "(BCD5X", "", 000721 },
   { "(CVPRT", "", 000722 },
   { "(STOPD", "", 000723 },
   { "(CHXAC", "", 000724 },
   { "(URRXI", "", 000725 },
   { "(RCTXI", "", 000726 },
   { "(RCHXI", "", 000727 },
   { "(TCOXI", "", 000730 },
   { "(TRCXI", "", 000731 },
   { "(ETTXI", "", 000732 },
   { "(TEFXI", "", 000733 },
   { "(TRAPX", "", 000734 },
   { "(TRAPS", "", 000735 },
   { "(COMMM", "", 000736 },
   { "(LTPOS", "", 000737 },
   { "(IOXSI", "", 000740 },
   { "(CHPSW", "", 000741 },
   { "(TRPSW", "", 000742 },
   { "(FDAMT", "", 000743 },
   { "(SDCXI", "", 000744 },
   { "(STCXI", "", 000745 },
   { "(COMMD", "", 000746 },
   { "(IBCDZ", "", 000747 },
   { "(CHXSP", "", 000750 },
   { "SYSORG", "", 003720 },
   { "SYSEND", "", 077777 },
   { "",       "", -1     }
};

/*
** FAP SST FORTRAN symbols, pulls in ifapmoddefs.
*/

static int ffapdefsset;
static SysDefs ffapmondefs[] =
{
   { "LIBTAP", "", 000001 },
   { "SYSTAP", "", 000001 },
   { "FINTAP", "", 000002 },
   { "SINTAP", "", 000003 },
   { "TINTAP", "", 000004 },
   { "MINTAP", "", 000005 },
   { "MLSTAP", "", 000006 },
   { "MBNTAP", "", 000007 },
   { "MCHTAP", "", 000010 },
   { "SNPTAP", "", 000011 },
   { "(SNAP)", "", 001000 },
   { "FLAGBX", "", 003730 },
   { "LINECT", "", 003731 },
   { "DATEBX", "", 003732 },
   { "(PCBK)", "", 003733 },
   { "BOTTOM", "", 003734 },
   { "(TPER)", "", 004000 },
   { "(CHKU)", "", 010000 },
   { "(SUNV)", "", 010002 },
   { "(SUAV)", "", 010003 },
   { "(SKBP)", "", 020000 },
   { "(SKDP)", "", 020002 },
   { "(SKBC)", "", 020010 },
   { "(SKDC)", "", 020012 },
   { "(RBNP)", "", 040000 },
   { "(WBNP)", "", 040001 },
   { "(RDNP)", "", 040002 },
   { "(WDNP)", "", 040003 },
   { "(RBEP)", "", 040004 },
   { "(WEFP)", "", 040005 },
   { "(RDEP)", "", 040006 },
   { "(RBNC)", "", 040010 },
   { "(WBNC)", "", 040011 },
   { "(RDNC)", "", 040012 },
   { "(WDNC)", "", 040013 },
   { "(RBEC)", "", 040014 },
   { "(WEFC)", "", 040015 },
   { "(RDEC)", "", 040016 },
   { "(WROW)", "", 040031 },
   { "BOTIOP", "", 073600 },
   { "(LOAD)", "", 073600 },
   { "(DIAG)", "", 073603 },
   { "(TAPE)", "", 073606 },
   { "(PRNT)", "", 073611 },
   { "(PNCH)", "", 073614 },
   { "(STAT)", "", 073617 },
   { "(REST)", "", 073622 },
   { "(STDN)", "", 073626 },
   { "(SECL)", "", 073643 },
   { "(MECL)", "", 073644 },
   { "(DGLD)", "", 073645 },
   { "(PGCT)", "", 073651 },
   { "(LIBT)", "", 073652 },
   { "(FGBX)", "", 073660 },
   { "(LNCT)", "", 073661 },
   { "(DATE)", "", 073662 },
   { "(SNCT)", "", 073663 },
   { "(MSLN)", "", 073664 },
   { "(ENDS)", "", 073665 },
   { "(LODR)", "", 073666 },
   { "(LBLD)", "", 073667 },
   { "(SCHU)", "", 073672 },
   { "TOPMEM", "", 077677 },
   { "",       "", -1     }
}; 

/***********************************************************************
* tabpos - Return TRUE if col is a tab stop.
***********************************************************************/

static int
tabpos (int col, int tabs[]) 
{
   if (col < BUFSIZ)
      return (tabs[col]);

    return (TRUE); 

} /* tabpos */

/***********************************************************************
* detabit - Convert tabs to equivalent number of blanks.
***********************************************************************/

static void
detabit (int tabs[], FILE *ifd, FILE *ofd)
         
{
   int c, col;
 
   col = 0;
   while ((c = fgetc (ifd)) != EOF)
   {

      switch (c)
      {

         case '\t' :
            while (TRUE)
	    { 
               fputc (' ', ofd);
               if (tabpos (++col, tabs) == TRUE) 
                  break ;
            } 
            break;

         case '\n' :
            fputc (c, ofd);
            col = 0;
            break;

         default: 
            fputc (c, ofd);
            col++;

      } /* switch */

   } /* while */

} /* detab */

/***********************************************************************
* alldig - Check if all digits.
***********************************************************************/

static int
alldig (char *digs)
{
   while (*digs)
   {
      if (!isdigit (*digs))
      {
         return (FALSE);
      }
      digs++;
   }

   return (TRUE);

} /* alldig */

/***********************************************************************
* settab - Set initial tab stops.
***********************************************************************/

static void
settab (int tabs[], int argc, char *argv[])
{
   int m, p, i, j, l;
   char *bp;
  
   p = 0;

   for (i = 0; i < BUFSIZ; i++)
       tabs[i] = FALSE;

   for (j = 1; j < argc; j++)
   {

      bp = argv[j];

      if (*bp == '+')
         bp++;

      if (alldig (bp))
      {

         l = atoi (bp) ;

         if (l < 0 || l >= BUFSIZ)
             continue;

         if (*argv[j] != '+')
         { 
            p = l;
            tabs[p] = TRUE;
         } 

         else
         { 
            if (p == 0) 
               p = l;
            for (m = p; m < BUFSIZ; m += l) 
            {
               tabs[m] = TRUE;
            }
         }

      }

   } 

   if (p == 0)
   {
      for (i = 8; i < BUFSIZ; i += 8) 
      {
         tabs[i] = TRUE;
      }
   }

} /* settab */

/***********************************************************************
* detab - Detab source.
***********************************************************************/

static int
detab (FILE *ifd, FILE *ofd) 
{
   int tabs[BUFSIZ];
   char *tabstops[] = { "as", "7", "15", "+8", "\0" };
  
#ifdef DEBUG
   printf ("detab: Entered: infile = %s, outfile = %s\n",
	    infile, outfile);
#endif

   /* set initial tab stops */

   settab (tabs, 4, tabstops);

   detabit (tabs, ifd, ofd);

   return (0);

} /* detab */

/***********************************************************************
* definemonsyms - Define MONSYM symbols
***********************************************************************/

void
definemonsyms (int fapselect)
{
   SysDefs *ss;
   int i;
   int oldline;

#ifdef DEBUGMONSYM
   printf ("definemonsyms: fapmode = %d, absmod = %d, fapselect = %d\n",
	    fapmode, absmod, fapselect);
#endif
   if (!fapmode && !absmod) return;

   if (fapmode)
   {
      if (fapselect == 1)
      {
	 if (ffapdefsset) return;
	 ss = ffapmondefs;
	 ffapdefsset = TRUE;
      }
      else
      {
	 if (ifapdefsset) return;
	 ss = ifapmondefs;
	 ifapdefsset = TRUE;
      }
   }
   else
   {
      if (mondefsset) return;
      ss = mapmondefs;
      mondefsset = TRUE;
   }

   oldline = linenum;
   linenum = 0;
   for (i = 0; ss[i].val >= 0; i++)
   {
      SymNode *s;

      s = symlookup (ss[i].name, ss[i].qual, TRUE, TRUE);

      if (s)
      {
	 s->value = ss[i].val;
	 s->relocatable = FALSE;
      }
   }
   linenum = oldline;
}

/***********************************************************************
* definejobsyms - Define JOBSYM symbols
***********************************************************************/

void
definejobsyms (void)
{
   int i;
   int oldline;

   if (!absmod) return;

   /*
   ** JOBSYM gets MONSYM, too
   */

   definemonsyms(0);

   if (!jobdefsset)
   {
      oldline = linenum;
      linenum = 0;
      jobdefsset = TRUE;
      for (i = 0; jobdefs[i].val >= 0; i++)
      {
	 SymNode *s;

	 if ((s = symlookup (jobdefs[i].name, jobdefs[i].qual, TRUE, TRUE))
	       != NULL)
	 {
	    s->value = jobdefs[i].val;
	    s->relocatable = FALSE;
	 }
      }
      linenum = oldline;
   }
}

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

int
main (int argc, char **argv)
{
   FILE *infd = NULL;
   FILE *outfd = NULL;
   FILE *lstfd = NULL;
   FILE *tmpfd0 = NULL;
   FILE *tmpfd1 = NULL;
   char *infile = NULL;
   char *outfile = NULL;
   char *lstfile = NULL;
   char *bp;
   int i;
   int done;
   int listmode;
   int status = 0;
   char mkname[32];
   char tname0[64];
   char tname1[64];
  
#ifdef DEBUG
   printf ("asm7090: Entered:\n");
   printf ("args:\n");
   for (i = 1; i < argc; i++)
   {
      printf ("   arg[%2d] = %s\n", i, argv[i]);
   }
#endif

   freesymbols = NULL;
   freexrefs = NULL;
   freeops = NULL;

   gblabsmod = FALSE;
   gbljobsym = FALSE;
   gblmonsym = FALSE;
   verbose = FALSE;

   genxref = FALSE;
   fapmode = FALSE;
   listmode = FALSE;
   termparn = TRUE;
   widemode = FALSE;

   filecnt = 0;
   p1erralloc = 0;
   cpumodel = 7090;

   deckname[0] = '\0';
   titlebuf[0] = '\0';

   /*
   ** Scan off arguments.
   */

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

      if (*bp == '-')
      {
         bp++;
         switch (*bp)
         {
	 case 'a': /* Absolute assembly */
	    gblabsmod = TRUE;
	    break;

	 case 'c': /* CPU model */
	    i++;
	    cpumodel = atoi(argv[i]);
	    if (cpumodel != 709 && cpumodel != 7090 && cpumodel != 7094)
	       goto USAGE;
	    break;

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

	 case 'f': /* FAP mode */
	    fapmode = TRUE;
	    termparn = FALSE;
	    break;

	 case 'j': /* JOBSYM */
	    gbljobsym = TRUE;
	    break;

	 case 'l': /* Listing file */
	    i++;
	    lstfile = argv[i];
	    listmode = TRUE;
	    break;

	 case 'm': /* MONSYM */
	    gblmonsym = TRUE;
	    break;

         case 'o': /* Output file */
            i++;
            outfile = argv[i];
            break;

	 case 'p': /* Parens OK == ()OK */
	    termparn = FALSE;
	    break;

	 case 'r': /* ADDREL mode */
	    gblabsmod = FALSE;
	    break;

	 case 't': /* Title */
	    i++;
	    if (strlen (argv[i]) > WIDETITLELEN) argv[i][WIDETITLELEN] = '\0';
	    strcpy (titlebuf, argv[i]);
	    break;

	 case 'V': /* Verbose mode */
	    verbose = TRUE;
	    break;

	 case 'w': /* Wide mode */
	    widemode = TRUE;
	    break;

         case 'x': /* Generate Xref */
	    genxref = TRUE;
	    break;

         default:
      USAGE:
	    fprintf (stderr, "asm7090 - version %s\n", VERSION);
	    fprintf (stderr,
		     "usage: asm7090 [-options] -o file.bin file.asm\n");
            fprintf (stderr, " options:\n");
	    fprintf (stderr, "    -a           - Absolute assembly\n");
	    fprintf (stderr,
		     "    -c model     - CPU model (709, 7090, 7094)\n");
	    fprintf (stderr, "    -d deck      - Deckname for output\n");
	    fprintf (stderr, "    -f           - FAP assembly mode\n");
	    fprintf (stderr, "    -j           - JOBSYM mode\n");
	    fprintf (stderr,
		     "    -l listfile  - Generate listing to listfile\n");
	    fprintf (stderr, "    -m           - MONSYM mode\n");
	    fprintf (stderr, "    -o outfile   - Object file name\n");
	    fprintf (stderr, "    -p           - ParensOK == ()OK\n");
	    fprintf (stderr, "    -r           - ADDREL mode\n");
	    fprintf (stderr, "    -t title     - Title for listing\n");
	    fprintf (stderr, "    -w           - Generate wide listing\n");
	    fprintf (stderr, "    -x           - Generate cross reference\n");
	    return (ABORT);
         }
      }

      else
      {
         if (infile) goto USAGE;
         infile = argv[i];
      }

   }
   if (!widemode) titlebuf[NARROWTITLELEN] = '\0';

   if (!infile && !outfile) goto USAGE;

   if (!strcmp (infile, outfile))
   {
      fprintf (stderr, "asm7090: Identical source and object file names\n");
      exit (1);
   }
   if (listmode)
   {
      if (!strcmp (outfile, lstfile))
      {
	 fprintf (stderr, "asm7090: Identical object and listing file names\n");
	 exit (1);
      }
      if (!strcmp (infile, lstfile))
      {
	 fprintf (stderr, "asm7090: Identical source and listing file names\n");
	 exit (1);
      }
   }

#ifdef DEBUG
   printf (" infile = %s\n", infile);
   printf (" outfile = %s\n", outfile);
   if (listmode)
      printf (" lstfile = %s\n", lstfile);
#endif

   /*
   ** Open the files.
   */

   if ((infd = fopen (infile, "r")) == NULL)
   {
      perror ("asm7090: Can't open input file");
      exit (1);
   }

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

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

   /*
   ** Create a temp files for intermediate use.
   */

   strcpy (mkname, TEMPSPEC);
   if ((bp = (char *)mktemp (mkname)) == NULL)
   {
      perror ("asm7090: Can't mktemp");
      return (ABORT);
   }

#ifdef WIN32
   sprintf (tname0, "%s1.s", bp);
#else
   sprintf (tname0, "/tmp/%s1.s", bp);
#endif
#ifdef DEBUGTMPFILE
   printf ("asm7090: tmp0 = %s\n", tname0);
#endif

   if ((tmpfd0 = fopen (tname0, "w+")) == NULL)
   {
      perror ("asm7090: Can't open temporary file");
      exit (1);
   }

   strcpy (mkname, TEMPSPEC);
   if ((bp = (char *)mktemp (mkname)) == NULL)
   {
      perror ("asm7090: Can't mktemp");
      return (ABORT);
   }

#ifdef WIN32
   sprintf (tname1, "%s2.s", bp);
#else
   sprintf (tname1, "/tmp/%s2.s", bp);
#endif
#ifdef DEBUGTMPFILE
   printf ("asm7090: tmp1 = %s\n", tname1);
#endif

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

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

   /*
   ** Detab the source, so we know where we are on a line.
   */

   status = detab (infd, tmpfd0);

   /*
   ** Rewind the input.
   */

   if (fseek (tmpfd0, 0, SEEK_SET) < 0)
   {
      perror ("asm7090: Can't rewind input temp file");
      exit (1);
   }

   /*
   ** Allow multiple assemblies in source
   */

   done = FALSE;
   while (!done)
   {

      /*
      ** Initalize various tables
      */

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

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

      for (i = 0; i < MAXDEFOPS; i++)
      {
	 opdefcode[i] = NULL;
      }

      addextsym = NULL;
      rboolexpr = FALSE;
      lboolexpr = FALSE;
      mondefsset = FALSE;
      jobdefsset = FALSE;
      ifapdefsset = FALSE;
      ffapdefsset = FALSE;
      exprtype = ADDREXPR;

      absmod = gblabsmod;
      monsym = gblmonsym;
      jobsym = gbljobsym;
      if (absmod)
      {
	 addext = FALSE;
	 addrel = FALSE;
	 absolute = TRUE;
      }
      else
      {
	 addext = TRUE;
	 addrel = TRUE;
	 absolute = FALSE;
      }

      pc = 0;
      symbolcount = 0;
      entsymbolcount = 0;
      opdefcount = 0;
      headcount = 0;
      errcount = 0;
      errnum = 0;
      linenum = 0;
      p1errcnt = 0;
      pgmlength = 0;
      radix = 10;
      qualindex = 0;
      litorigin = 0;
      litpool = 0;
      qualindex = 0;

      ttlbuf[0] = '\0';
      lbl[0] = '\0';
      qualtable[0][0] = '\0';

      begincount = 1;
      strcpy (begintable[0].symbol, "  ");
      begintable[0].chain = 0;
      begintable[0].bvalue = 0;
      begintable[0].value = 0;

      if (verbose)
	 fprintf (stderr, "\nasm7090: Processing file %d\n", filecnt+1);

      /*
      ** If MONSYM mode, define symbols
      */

      if (monsym)
	 definemonsyms (0);

      /*
      ** If JOBSYM mode, define symbols
      */

      if (jobsym)
	 definejobsyms ();

      /*
      ** Open the intermediate temp file
      */

      if ((tmpfd1 = fopen (tname1, "w+b")) == NULL)
      {
	 perror ("asm7090: Can't open temporary file");
	 exit (1);
      }

      /*
      ** Call pass 0 to preprocess macros, etc.
      */

      inpass = 000;
      if (verbose)
	 fprintf (stderr, "asm7090: Calling pass %03o\n", inpass);

      status = asmpass0 (tmpfd0, tmpfd1);
      if (status == 1)
      {
	 if (verbose)
	    fprintf  (stderr, "asm7090: File %d: EOF\n",
		     filecnt+1);
	 if (tmpfd1)
	    fclose (tmpfd1);
	 tmpfd1 = NULL;
	 status = 0;
         done = TRUE;
	 break;
      }
      if (filecnt++ > 0 && listmode)
         fputc ('\f', lstfd);

      /* 
      ** Call pass 1 to scan the source and get labels.
      */

      inpass = 010;
      if (verbose)
	 fprintf (stderr, "asm7090: Calling pass %03o\n", inpass);

      status = asmpass1 (tmpfd1, TRUE);

      /* 
      ** Call pass 1 again to scan the source and assign storage.
      ** We have to do this twice because MAP allows forward decls of
      ** variables that affect storage. Also, USE/BEGIN and COMMON.
      */

      if (!fapmode)
      {
	 inpass = 011;
	 if (verbose)
	    fprintf (stderr, "asm7090: Calling pass %03o\n", inpass);

	 status = asmpass1 (tmpfd1, FALSE);
	 status = asmpass1 (tmpfd1, FALSE);

	 inpass = 012;
	 if (verbose)
	    fprintf (stderr, "asm7090: Calling pass %03o\n", inpass);

	 status = asmpass1 (tmpfd1, FALSE);
      }

      /*
      ** Call pass 2 to generate object and optional listing
      */

      inpass = 020;
      if (verbose)
	 fprintf (stderr, "asm7090: Calling pass %03o\n", inpass);

      status = asmpass2 (tmpfd1, outfd, listmode, lstfd);

      /*
      ** Close the intermediate file
      */

      if (tmpfd1)
	 fclose (tmpfd1);
      tmpfd1 = NULL;

      /*
      ** Place table entries on free lists for use again.
      */

      for (i = 0; i < symbolcount; i++)
      {
	 if (symbols[i])
	 {
	    XrefNode *xr, *nxr;

	    xr = symbols[i]->xref_head;
	    while (xr)
	    {
	       nxr = xr->next;
	       freexref (xr);
	       xr = nxr;
	    }
	    freesym (symbols[i]);
	 }
      }

      for (i = 0; i < entsymbolcount; i++)
      {
	 if (entsymbols[i])
	 {
	    XrefNode *xr, *nxr;

	    xr = symbols[i]->xref_head;
	    while (xr)
	    {
	       nxr = xr->next;
	       freexref (xr);
	       xr = nxr;
	    }
	    freesym (entsymbols[i]);
	 }
      }

      for (i = 0; i < opdefcount; i++)
      {
	 if (opdefcode[i])
	    freeopd (opdefcode[i]);
      }

      /*
      ** Print assembly error count.
      */

      if (listmode)
      {
	 fprintf (lstfd, "\n%d Errors in assembly\n", errcount);
      }
      if (errcount || verbose)
      {
	 fprintf (stderr, "asm7090: File %d: %d Errors in assembly\n",
		  filecnt, errcount);
      }

      titlebuf[0] = '\0';
      deckname[0] = '\0';
      DBG_MEMCHECK();
   }

   /*
   ** Close the files
   */


   if (infd)
      fclose (infd);
   if (outfd)
      fclose (outfd);
   if (tmpfd0)
      fclose (tmpfd0);
   if (listmode && lstfd)
      fclose (lstfd);

   /*
   ** Delete tmp files
   */

   unlink (tname0);
   unlink (tname1);

   if (status != 0)
      unlink (outfile);

#ifdef DEBUGMALLOCSDUMP
   DBG_MEMDUMP();
#endif

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