/*---------------------------------------------------------------------*/
/*    serrano/prgm/project/bigloo/runtime/Clib/cmain.c                 */
/*                                                                     */
/*    Author      :  Manuel Serrano                                    */
/*    Creation    :  Fri Jul 17 09:40:49 1992                          */
/*    Last change :  Sun Nov 16 15:06:35 2003 (serrano)                */
/*                                                                     */
/*    Le fichier de main de toute application. Comme je m'y prends     */
/*    plus intelligement que dans la version 0.8 (si, si :-), je       */
/*    peux compiler une fois pour toute ce fichier. Je ne suis plus    */
/*    oblige de le construire et le compiler pour chaque application.  */
/*---------------------------------------------------------------------*/
#include <bigloo.h>
#include <time.h>
#if( (defined( sun ) && !defined( __svr4__) && !defined( __SVR4 )) \
     || defined( sony_news ) )
#   include <machine/vmparam.h>
#else
#   if( defined( sun ) && (defined( __svr4__ ) || defined( __SVR4 )) )
#      include <sys/vmparam.h>
#   endif
#endif

/*---------------------------------------------------------------------*/
/*    Heap handling                                                    */
/*---------------------------------------------------------------------*/
#define MegToByte(x) ((x) * (1024 * 1024))
#define MegToKilo(x) ((x) * 1024)
#define MegTo4K(x)   ((x) * (1024 >> 2))

#define DEFAULT_HEAP_SIZE 4

/* The initial heap size (in mega byte) */
BGL_RUNTIME_DEF long heap_size = DEFAULT_HEAP_SIZE;

/*---------------------------------------------------------------------*/
/*    Des recuperations externes                                       */
/*---------------------------------------------------------------------*/
extern void cref();
extern void memshow();
extern void bgl_init_eval_cnst();
extern obj_t c_constant_string_to_string();
extern obj_t c_error();
extern void bgl_init_objects();
extern obj_t bigloo_exit_apply();
#if BGL_GC_CUSTOM   
extern void bgl_gc_profile_init();
#endif
#ifndef _MSC_VER
extern char *getenv();
#endif

/*---------------------------------------------------------------------*/
/*    Une variable pour memoriser le bas de la pile                    */
/*---------------------------------------------------------------------*/
long glob_dummy;

BGL_RUNTIME_DEF obj_t command_line = 0L;
char *executable_name = 0L;
char **bgl_envp;
int bgl_envp_len;

/*---------------------------------------------------------------------*/
/*    get_top_of_stack ...                                             */
/*    -------------------------------------------------------------    */
/*    On ne peut pas chercher le top de la pile dans la fonction       */
/*    `call_cc' car on ne sait pas si les arguments d'une fonction     */
/*    sont ranges apres les variables locales ou le contraire. Il me   */
/*    semble que la solution est donc d'appeller une autre fonction,   */
/*    prendre une variable locale et retourner cette adresse car on    */
/*    est sur qu'elle sera plus grande (ou plus petite si la pile      */
/*    decroit) que la valeur du frame pointer de `call_cc'.            */
/*    -------------------------------------------------------------    */
/*    This function can't be included inside callcc.c otherwise it may */
/*    be incorrectly inlined by optimizing C compilers.                */
/*---------------------------------------------------------------------*/
char *
get_top_of_stack()
{
   long *dummy; /* dummy est un long et pas un char car je veux */
                /* etre sur de ne pas avoir de pbm d'alignement*/

#ifdef _MSC_VER
#  pragma warning( push )
   // returning address of local variable or temporary
#  pragma warning( disable: 4172 )    
#endif

   return (char *)(&(dummy));

#ifdef _MSC_VER
#   pragma warning( pop )
#endif
}

/*---------------------------------------------------------------------*/
/*    bigloo_exit ...                                                  */
/*---------------------------------------------------------------------*/
BGL_RUNTIME_DEF
obj_t
bigloo_exit( obj_t val )
{
   val = bigloo_exit_apply( val );
   FREE_ALLOCATION();
   exit( (long)INTEGERP( val ) ? (long)CINT( val ) : 0 );
   return BUNSPEC;
}

/*---------------------------------------------------------------------*/
/*    bigloo_main ...                                                  */
/*    -------------------------------------------------------------    */
/*    Le vrai point d'entree d'une application `bigloo'. La fonction   */
/*    `main' qui est cree par le compilo ne sert a rien. Elle existe   */
/*    uniquement car je ne suis pas sur que tous les compilos supporte */
/*    que la fonction C `main' soit mise en librairie. Comme ca, je    */
/*    suis tranquile.                                                  */
/*---------------------------------------------------------------------*/
BGL_EXPORTED_DEF
int
_bigloo_main( int argc, char *argv[], char *envp[], obj_t (*bigloo_main)() )
{
   long  mega_size;
   char *env_size;
   obj_t cons;
   long  i;

   /* we store the global environment */
   bgl_envp = envp;
   bgl_envp_len = 0;

   if( envp ) {
      char **runner = envp;
      while( *runner ) bgl_envp_len++, runner++;
   }

   /* on initialise le tas */
   if( !(env_size = getenv( "BIGLOOHEAP" )) )
      mega_size = heap_size;
   else
      mega_size = atoi( env_size );

#if( (THE_GC == BOEHM_GC) &&                                     \
     ( (!defined( BOEHM_GC_VERSION)) ||                          \
       (BOEHM_GC_VERSION == 2)       ||                          \
       (BOEHM_GC_VERSION == 3) ) )
   heap_size = MegTo4K( mega_size );
#else
   heap_size = MegToByte( mega_size );
#endif

#if BGL_GC_CUSTOM   
   bgl_gc_profile_init();
#endif
   
   if( !INIT_ALLOCATION( heap_size ) )
   {
      char mes[ 600 ];

      sprintf( mes, "%ld Meg wanted", heap_size / (1024 * 1024) );
      c_error( "Can't allocate heap", mes, -10 );
      return 1;
   }
   else
   {
      /* on sauve le nom de l'executable */
      executable_name = argv[ 0 ];
      
      /* on initialise les objects pre-alloues (les chars, bool, ...) */
      bgl_init_objects();

      /* on memorise l'adresse du bas de la pile */
      BGL_STACK_BOTTOM_SET( (char *)&argc );
   
      /* on initialise les constantes du fichier `Clib/eval.c' */
      bgl_init_eval_cnst();
	 
      /* on construit la liste des argv */
      for( i = argc - 1, cons = BNIL; i >= 0; i-- )
         cons = MAKE_PAIR( c_constant_string_to_string( argv[ i ] ), cons );

      /* on met a jour la variable `command-line' */
      command_line = cons;

      /* initialize the random seed */
      {
	 time_t taux;
	 struct tm *tm;
	 time( &taux );
	 tm = gmtime( &taux );
	    
	 srand( (24 * (60 * tm->tm_sec + tm->tm_min)) + tm->tm_hour );
      }
      
      /* on appelle le main de l'utilisateur */
      bigloo_main( cons );
      return 0;
   }
}
