#ifndef lint
static char *RCSid = "$Id: rexx.c,v 1.13 1993/05/10 06:09:38 anders Exp anders $";
#endif

/*
 *  The Regina Rexx Interpreter
 *  Copyright (C) 1992-1994  Anders Christensen <anders@pvv.unit.no>
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Library General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library General Public
 *  License along with this library; if not, write to the Free
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

/*
    This code modified for Win32 port by Ataman Software, Inc. June 29, 1995.
*/

#include "rexx.h"
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#ifdef VMS
# include <stat.h>
#else
# include <sys/stat.h>
#endif



/*
 * Since development of Ultrix has ceased, and they never managed to 
 * fix a few things, we want to define a few things, just in order 
 * to kill a few warnings ...
 */
#if defined(FIX_PROTOS) && defined(FIX_ALL_PROTOS) && defined(ultrix)
   int fstat( int fd, struct stat *buf ) ;
   int stat( char *path, struct stat *buf ) ;
#endif




proclevel currlevel, mainlevel ;
sysinfo systeminfo ;


nodeptr parseroot=NULL ;

int nextstart=1, thischar=0, nextline=1, tstart, tline ;

char *environments[] = { "SH", "CSH", "COMMAND", "PATH", "SYSTEM" } ;

FILE *stddump=NULL ;

/* 
 * Note: must match the settings of NUM_FORM_* in flags.h
 */
char *numeric_forms[] = { "SCIENTIFIC", "ENGINEERING" } ;

char *WeekDays[] = { "Sunday", "Monday", "Tuesday", "Wednesday",
   "Thursday", "Friday", "Saturday" } ;

char *months[] = {
   "January", "February", "March", "April", "May", "June",
   "July", "August", "September", "October", "November", "December" } ;

/*
 * Note: these must match the definitions of INVO_* in defs.h
 */
char *invo_strings[] = {
   "COMMAND", "FUNCTION", "SUBROUTINE" } ;

int isclient=0 ;
int parse_error_flag ;

#ifdef TRACEMEM
void marksubtree( nodeptr ptr )
{
   int i ;
   if ( ptr ) 
   {
      markmemory(ptr,TRC_TREENODE) ;
      if (ptr->name) markmemory(ptr->name, TRC_TREENODE) ;
      for (i=0;i<5;marksubtree(ptr->p[i++])) ; 
      if (ptr->next) marksubtree( ptr->next ) ;

      if (ptr->type == X_STRING || ptr->type == X_CON_SYMBOL)
         if (ptr->u.number)
         {
            markmemory( ptr->u.number, TRC_TREENODE ) ;
            markmemory( ptr->u.number->num, TRC_TREENODE ) ;
         }

      if (ptr->type == X_CEXPRLIST)
         if (ptr->u.strng)
            markmemory( ptr->u.strng, TRC_TREENODE ) ;
   }
}
         

#endif /* TRACEMEM */



nodeptr treadit( nodeptr tree )
{
/* 
   nodeptr left, mid, right ;
 */
   return NULL ;   
/*
   if (!tree)
      return NULL ;

   left = tree->p[0] ;
   mid = tree->p[1] ;
   right = tree->p[2] ;

   switch (tree->type)
   {
      case X_OTHERWISE:
      case X_PROGRAM: 
         treadit( left ) ;
         tree = NULL ;
         break ;

      case X_STATS:
      case X_WHENS:
         left->next = treadit( mid ) ;
         treadit( left ) ;
         tree = left ;
         break ;

      case X_IF:
         treadit( mid ) ;
      case X_DO:
         treadit( right ) ;
         break ;

      case X_SELECT:
         treadit( left ) ;
      case X_WHEN:
         treadit( mid ) ;
         break ;
   }

   return tree ;
 */
}

#ifdef TRACEMEM
   int listleakedmemory=0 ;
#endif

static void Usage(void) {
	fprintf(stderr, "Regina Rexx version 0.07a\n");
	fprintf(stderr,
		"Copyright (C) 1992-1994  Anders Christensen <anders@pvv.unit.no>.\n");
#ifdef WIN32
	fprintf(stderr,
		"Copyright (C) 1995  Ataman Software, Inc. <info@ataman.com>.\n");
	fprintf(stderr,
		"Copyright 1995 Microsoft Corporation. All rights reserved.\n");
#endif
	fprintf(stderr, "\nUsage: rexx [-iCptd] [scriptfile]\n");
	exit(1);
}


#ifdef RXLIB
int dummy_main(int argc,char **argv)
#else
int main(int argc,char **argv)
#endif
{
   extern int isclient ;
   extern FILE *yyin ;
   streng *string ;
   int rccode, i, j, stdinput=1, state=0, rcode, oldi ;
#ifndef NDEBUG
   extern int yydebug ; 
#endif
   paramboxptr args ;
   char *arg ;
   int make_perl=0 ;

#ifdef FLISTS
   init_hash_table() ; /* initiate the memory system */
#endif

   stddump = stderr ;

   systeminfo = creat_sysinfo( Str_cre("SYSTEM")) ;
   systeminfo->called_as = Str_cre( argv[0] ) ;

   systeminfo->currlevel = mainlevel = currlevel = newlevel( NULL ) ; 

   initexpr() ;
   initfiletable() ;
   init_envir() ;
   init_spec_vars() ;
   init_vars() ;

   for (i=1; i<argc; i++)
   {
      arg = argv[i] ;
      if (state==0)
      {
         if (*arg=='-') 
         {
            switch (*(++arg))
            {
               case 'i':
                  starttrace() ;
                  set_trace_char('A') ;
                  intertrace() ;
                  intertrace() ;
                  break ;

               case 'C':
                  if (*(arg+1)=='p')
                     SetupClient( arg+2 ) ;
                  else if (*(arg+1)=='i')
                     SetupInternal( arg+2 ) ;
                  break ;

               case 'p':
                  make_perl = 1 ;
                  break ;   

               case 't':
                  queue_trace_char((char)(*(arg+1)? *(++arg) : 'A')) ;
                  break ;

               case 'd':
#ifdef TRACEMEM
                  if (*(arg+1)=='m')
                     listleakedmemory = 1 ;
#endif
                  break ;
		       default:
			      Usage() ;
                  break ;
            }
         }
         else
         {
            stdinput = 0 ;
            systeminfo->input_file = Str_cre(argv[i]) ;
            yyin=fopen(argv[i],"rb") ;
            if (!yyin)
               exiterror( ERR_PROG_UNREADABLE ) ;
            break ;
         }
      }
    }

   if (stdinput)
      systeminfo->input_file = Str_cre("<stdin>") ; 

   if (isclient==1) 
      RunClient() ;
   else if (isclient==2)
      return 0 ;

   oldi = ++i ;

   for (j=1;i<argc;i++)
      j += strlen(argv[i]) + 1 ;


   currlevel->args = args = Malloc(sizeof(parambox)) ;
/*   
   args->value = Str_dup(systeminfo->input_file) ;
   args = args->next = Malloc(sizeof(parambox)) ;
 */
   args->next = NULL ;
   if (oldi>=argc)
      args->value = string = NULL ;
   else
   {
      args->value = string = Str_make( j ) ;
      string->len = 0 ;
   }

   for (i=oldi;i<argc;i++) 
   {
      string = Str_catstr(string,argv[i]) ;
      string->value[string->len++] = ' ' ;
   }
   if (string && string->len)
     string->len-- ;

   signal_setup() ;

   initscanner() ;
#ifndef NDEBUG
   yydebug = 0 ;   /* 1 == yacc-debugging */
#endif

   parseroot = NULL ;
   parse_error_flag = 0 ;
   if ((rccode=yyparse())) 
/*      return rccode ;

   if (parse_error_flag) */
      exiterror( parse_error_flag ) ;

   systeminfo->firstline = first_source_line ;
   systeminfo->lastline = last_source_line ;
   systeminfo->rootnode = parseroot ;
   parseroot = NULL ;
   tline = 0 ;

#ifndef R2PERL
#ifndef MINIMAL
#ifndef VMS
#ifndef DOS
#ifndef WIN32
   if ( stdinput )
   {
      struct stat buffer ;

      /* 
       * The following line is likely to give a warning when compiled 
       * under Ultrix, this can be safely ignored, since it is just a 
       * result of Digital not defining their include files properly. 
       */
      rcode = fstat( fileno(stdin), &buffer ) ;
      if (rcode==0 && S_ISCHR(buffer.st_mode))
      { 
         printf("  \b\b") ; 
         fflush(stdout) ;
         rewind(stdin) ; 
      }
   } 
#endif /* !WIN32 */
#endif /* !DOS */
#endif /* !VMS */
#endif /* !MINIMAL */
#endif

   treadit( systeminfo->rootnode ) ;

#ifdef R2PERL
   if (make_perl)
   {
      preamble() ;
      translate( systeminfo->rootnode ) ;
      exit( 0 ) ;
   }
#endif

   flush_trace_chars() ;
   string = interpret( systeminfo->rootnode ) ;

   rcode = EXIT_SUCCESS ;
   if (string)
      rcode = myatol( string ) ;

#ifdef TRACEMEM
   if (listleakedmemory)
      listleaked( MEMTRC_LEAKED )  ;
#endif

   return(rcode) ;
   
}

#ifdef TRACEMEM
void mark_systeminfo()
{
   extern sysinfo systeminfo ;
   sysinfo sinfo ;
   labelbox *lptr ;
   lineboxptr llptr ;

   for (sinfo=systeminfo; sinfo; sinfo=sinfo->previous)
   {
      markmemory(sinfo, TRC_SYSINFO) ;
      markmemory(sinfo->called_as, TRC_SYSINFO) ;
      markmemory(sinfo->input_file, TRC_SYSINFO) ;
      markmemory(sinfo->environment, TRC_SYSINFO) ;
      markmemory(sinfo->callstack, TRC_SYSINFO) ;

      markvariables( sinfo->currlevel ) ;
      marksource( sinfo->firstline ) ;
      marksubtree( sinfo->rootnode ) ;

      for (lptr=sinfo->first; lptr; lptr=lptr->next ) 
      {
         markmemory( lptr, TRC_SYSINFO ) ;
      }

      for (llptr=sinfo->firstline; llptr; llptr=llptr->next ) 
      {
         markmemory( llptr, TRC_SYSINFO ) ;
         markmemory( llptr->line, TRC_SYSINFO ) ;
      }
   }

}
#endif


sysinfobox *creat_sysinfo( streng *envir ) 
{
   sysinfobox *sinfo ;

   sinfo = Malloc( sizeof(sysinfobox) ) ;
   sinfo->environment = envir ;
   sinfo->tracing = DEFAULT_TRACING ; 
   sinfo->interactive = DEFAULT_INT_TRACING ;
   sinfo->previous = NULL ;
   sinfo->invoked = INVO_COMMAND ;
   sinfo->called_as = NULL ;
   sinfo->input_file = NULL ;
   sinfo->panic = NULL ;
   sinfo->hooks = 0 ;
   sinfo->firstline = NULL ;
   sinfo->first = NULL ;
   sinfo->last = NULL ;
   sinfo->lastline = NULL ;
   sinfo->callstack = Malloc(sizeof(nodeptr)*10) ;
   sinfo->result = NULL ;
   sinfo->rootnode = NULL ;
   sinfo->cstackcnt = 0 ;
   sinfo->cstackmax = 10 ;

   return sinfo ;
}

#ifndef RXLIB

void SetupClient( char *Name ) 
{
   fprintf( stderr, "Warning: pipe-comm not compiled into interpreter\n" ) ;
}

void SetupInternal( char *Name ) 
{
   fprintf (stderr, "Warning: SAA API not compiled into interpreter\n" ) ;
}
 
int hookup( int type, ... ) 
{
   /* This should never happen, if we don't have support for SAA API, 
    * Then we should never get a system exit!
    */
   assert( 0 ) ;
   return 1 ;  /* to keep compiler happy */
}

void RunClient( void ) 
{
   SetupInternal( NULL ) ;
   exit( 1 ) ;
}

streng *do_an_external( streng *name, paramboxptr parms ) 
{
   SetupInternal( NULL ) ;
   exit( 1 ) ;
   return nullstringptr(); /*NOTREACHED*/
}


streng *SubCom( streng *command, streng *environment, int *rc ) 
{
   SetupInternal( NULL ) ;
   exit( 1 ) ;
   return nullstringptr(); /*NOTREACHED*/
}



#endif

