/* ---------------------------------------------------------------------- */
/*                   Copyright (C) 1992 by Natrlich!                     */
/*                      This file is copyrighted!                         */
/*                Refer to the documentation for details.                 */
/*           if you add to the options, remember NASM.TTP too             */
/* ---------------------------------------------------------------------- */
#include "defines.h"
#include "nasm.h"
#include OSBIND
#include "debug.h"
#include "buffer.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#if STATISTICS
#include NMALLOC_H
#endif

static char   infile[ 256],
              outfile[ 256],
#if OS == TOS
_usage[] =
"Usage: nasm65 [-{brstw}][-a xx][-e #][-o binary][-h includedir] <source>\n",
#else
_usage[] =
"Usage: nasm65 [-{brsw}][-a xx][-e #][-o binary][-h includedir] <source>\n",
# if PORTED
portnote[] =
{
# 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',' ','b','y',' ',PORTER,'\n',0

},
# endif
#endif

notice[] =
{
   'N','a','s','m','6','5',' ',' ','v',VERSION+'0','.',
   ASMREVISION/10+'0',ASMREVISION%10+'0',' ',
   'b','y',' ',AUTHOR,' ',' ','C','o','p','y','r','i','g','h','t',' ',
   '(','c',')',' ','1','9','9','2',' ',ORGANIZATION,
#if OS == TOS
   '\r','\n',
#else
   '\n',
#endif
   0
};

char          header[128];  
word          alignment;
int           runnable,
              better,
              show_open,
              show_expansion,
              show_mload,
#if OS == TOS
              tossable,
# if WITHNOISY
              noisytok,
# endif
#endif
              pssst,
              what_the_fuck,        /* cited from "Everybody wants some" */
              fdout,
              maxerrors = 30;

char          buf[ 128], *realname;

extern int  freshflag,
            errors;



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

   ENTER("main");

#if STATISTICS
   t_start = clock();
#endif
   if( x = getenv( "INC65"))
   {
      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

#if VERSION                   /* need this up here for -D defs */
   sexp_alloc();              /* reserve space for exprfast    */
   str_alloc(1);              /* reserve space for yy_txt2val  */
#endif
   while( ++i < argc)
   {
      if( *argv[i] == '-')
         switch( Xtolower( argv[i][1]))
         {
            case '_' :
               if( ++i == argc)
                  nierror("wrong arg given by CPP");
               realname = argv[ i];
               break;
               
            case 'a' :                                     
               if( ++i == argc || ! sscanf( argv[i], "%X", &foo))
                  goto usage;
               if( (alignment = (word) foo) >= 0x100)
                  nferror("Only alignment values less than $100");
               {
                  register word  i = alignment;

                  for(; i & 1; i >>= 1);
                     if( i)                          
                        nwarning("Alignment value  H I G H L Y  unusual");
               }
               break;

            case 'b' :
               better = ! better;
               break;
            
            
            case 'd' :  /* maybe we should use the env. as well */
               if( ++i < argc)              
               {
                  word  val = 0;
                  char  *x, *y;
               
                  x = argv[i];
                  upcase( x);
                  if( y = strrchr( x, '='))
                  {
                     *y = 0;
                     sscanf( y + 1, "%d", &val);
                  }
                  def_label( x, val);
               }
               else
                  goto usage;
               break;
                     
            case 'e' :
               if( ++i == argc || ! sscanf( argv[i], "%d", &maxerrors))
                  goto usage;
               break;

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

#if OS == TOS
# if WITHNOISY
            case 'n' :
               noisytok = ! noisytok;
               break;
# endif
            case 't' :
               tossable = ! tossable;
               break;
#else
            case 't' :
            case 'n' :
               break;
#endif

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

            case 'q' :
               pssst = ! pssst;
               break;

            case 'r' :
               runnable = ! runnable;
               break;

            case 's' :
               show_expansion = ! show_expansion;
               if( argv[ i][ 2])
                  show_mload = ! show_mload;
               break;

#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' ||
                   Xtolower( argv[i][3]) != 'l')
                  goto usage;
               {
                  extern char is_where[];
                  extern byte is_what[];

                  is_where[ '|'] = 1;
                  is_what[ '|']  = 0x10;
#if VERSION
                  if( (rand() & 0x100)/*Random()*/ & 0x1)
                     print_secret();
                  else
                     print2_secret();
#endif
               }
               break;

            case 'w' :
               what_the_fuck = ! what_the_fuck;
               break;

            case 'x' :
               show_open = ! show_open;
         }
      else
      {
         if( infile[0])
            goto usage;
         strcpy( infile, argv[i]);
      }
   }
   if( ! infile[0])
      goto usage;

   if( ! pssst)
   {
      Cconws( notice);
#if PORTED
      Cconws( portnote);
#endif
   }

#if OS == /* fucking */ MSDOS
   _fmode = O_BINARY;
#endif

#if ! VERSION
   Cconws("unfinished - unstable - unsupported - untested. Don't use it!\r\n");
   version0();
#endif
   MESS("Starting the INCLUDE");
   include( infile, ".s65");
   {
      extern buffer  *bp;
    
      inc_line();
   }
   if( ! outfile[0])
   {
      strcpy( outfile, infile);
      complete( outfile, runnable ? ".com" : ".o65", 1);
   }
   pro_init();                /* alloc dump space */
   if( runnable)
      def_label( "__RUN", 1);
   def_label(" __NASM65", 1);
#if YACCDEBUG
   {
      extern int   yydebug;

      yydebug = 1;
   }
#endif
   yyparse();
   MESS("we are back");
   do_local();              /* clean up and dump unrefs */
   err_undefs();
   pro_exit();
#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
#if STATISTICS
   MESS("OK JUST ABOUT DONE");
   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) / (int) CLK_TCK;
   finalstats(1);
   printf("Assembly took %ld.%lds\n", t_result,
                           (t_tmp - (t_result * (word) CLK_TCK)) >> 1 );
   stats();
#endif
   ALEAVE();
   nexit( errors ? 1 : 0);

usage:
   errors = 1;
   fputs( _usage, ESTREAM);
   fputs( "\
\t-x           : list unresolved references\n\
\t-w           : write output file anyway (W.T.F.)\n\
\t-h <path>    : \"system\" include file directory\n\
\t-o <file>    : output file specifier\n\
\t-r           : create runnable binary file\n\
\t-e <digit>   : set maximal number of errors before aborting\n\
\t-s           : show calling of macros and include files\n\
\t-d <l>[=<v>] : defines label <l>. optionally assigns <v> as value to it\n\
\t-a <value>   : alignment value (1->even 255->page)\n\
\t-q           : quiet flag\n\
\t-b           : optimize small segments\n", ESTREAM);
#if OS == TOS
   fputs( "\
\t-t           : wait for keypress before exit\n\
\t-n           : noisy tokens\n", ESTREAM);
#endif
   ALEAVE();
   nexit( 1);
}


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

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

void  yyerror()
{
}

void print_char( c)
char  c;
{
#if OS != AMIGA || defined( __hp9000s300)
   static clock_t  tick;

   Bconout( 2, (int) c);
   tick = clock() + ((int) CLK_TCK >> 2);
   while( tick > clock());
#else
   Bconout( 2, (int) c);
   sleep( 1);
#endif   
}


void print_secret()
{
   static char  vfl1[] = "Dqn~B~a-$es oRhTmW}lEe^ _az(n/w8r ",
                vfl2[] = "e  l*u4W*iCsHBHcIuM ha|zfrtn}e i9 ";

   char huge   *p = vfl1,
               *q = vfl2;
   do
   {
      print_char( *p++);
      print_char( *++q);
   }
   while( *++q && *++p);
   print_char('\r');
   print_char('\n');
}

#ifdef __hp9000s300
# define UNIT   2
# define KURZ   1
# define MITTEL 2
# define LANG   3
#else
# if OS == AMIGA
#  undef CLK_TCK
#  define CLK_TCK 50
# endif
# define UNIT   ((int) CLK_TCK >> 1)
# define KURZ   ((int) CLK_TCK / 3)
# define MITTEL ((int) CLK_TCK >> 1)
# define LANG   ((int) CLK_TCK  - 1)
#endif


void takt( s, flag, len)
char huge   *s;
{
   int   c;

   while( c = *s++)
      Bconout( 2, c ^ 0x5F);
   if( flag)
      Bconout(2, ' ');
#if ! defined( __hp9000s300) && OS != AMIGA
   {
      clock_t  tick;
      
      tick = clock() + len;
      while( tick > clock());
   }
#else
   sleep( len);
#endif   
}

static char  secret[] =
{
   0x1B, 0x3A, 0x31, 0,
   0x1D, 0x33, 0x3E, 0x2A, 0,
   0x72, 0x8,  0x3A, 0x36, 0x2C, 0x2C, 0,
   0x1D, 0x30, 0,
   0x3C, 0x37, 0x2A, 0x32, 0,
   0x8,  0x3E, 0x33, 0,
   0x25, 0x3A, 0x2D, 0,
   0x2B, 0x3E, 0x31, 0,
   0x25, 0x3A, 0x31, 0,
   0x28, 0x36, 0x2D, 0x71, 0x71, 0x71, 0
};

void print2_secret()
{
   char huge   *p = secret;

   takt( p,      1, KURZ);
   takt( p += 4, 0, LANG);
   takt( p += 5, 1, MITTEL);
   takt( p += 7, 0, LANG);
   takt( p += 3, 1, MITTEL);
   takt( p += 5, 0, MITTEL);
   takt( p += 4, 1, KURZ);
   takt( p += 4, 0, MITTEL);
   takt( p += 4, 1, KURZ);
   takt( p + 4,  0, KURZ);
   Bconout( 2, '\r');
   Bconout( 2, '\n');
}


void upcase( s)
register char  *s;
{
   register char  c;
   
   while( c = *s)
      *s++ = toupper( c);
}
