/*
BOIL (Brunni's Own Interpreter Language)
(c) 1998 netEstate (http://www.netestate.de/, info@netestate.de),
Michael Brunnbauer & Markus Hendel, Gesellschaft fuer Netzwerkkommunikation bR
Am Bluetenanger 8, 80995 Muenchen, Germany

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
any later version.

This program 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 General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "general.h"
#include "handles.cc"
#include "boil.h"
#include "boil.tab.h"
#include "libs.h"
#ifdef WITH_RPC
#include "rpc.h"
#endif

/* errorlib and stringlib */
unsigned long max_string_size=0xFFFFFFFF;
unsigned long string_mem=0;
int debug=0;
void panic() { perror(""); exit(1); }
unsigned long MAX_LOG_SIZE=65536;
unsigned long LOG_FLAGS_NOTICE=4;
unsigned long LOG_FLAGS_DEBUG=4;
unsigned long LOG_FLAGS_WARN=4+32+64+128+256;
unsigned long LOG_FLAGS_ERROR=4+32+64+128+256;
unsigned long LOG_FLAGS_FATAL=4+32+64+128+256;
char* LOG_STDLOG_PATH="boiler.log";
char* LOG_ERRLOG_PATH="boiler.error";
char* LOG_MAIL_ADDRESS="brunni";
char* MYNAME="boiler";
char* SENDMAIL="/usr/sbin/sendmail";

void usage()
{
  printf("%s","\
BOIL V1.0beta7 is free software and comes with ABSOLUTELY NO WARRANTY
(c) 1998 netEstate (http://www.netestate.de/, info@netestate.de),
Michael Brunnbauer & Markus Hendel, Gesellschaft fuer Netzwerkkommunikation bR
Am Bluetenanger 8, 80995 Muenchen, Germany
usage: boiler [options] file
 -h Embed code in ASCII/HTML. example: text <? printf(\"Hello World\"); ?> text
 -i Ignore first line (e.g. #!/usr/bin/boiler)
 -d Enable debugging output (not very useful yet)
 -x function. Toggle function disable (-q disables all library functions)
 -e on/off. Enable/disable eval()
 -o on/off. Enable/disable option-strings in function-definitions
 -t on/off. Enable/disable external()
 -z on/off. Enable/disable time-statistics for all enabled accounting objects
    (not only those with time-limits)
 -m size. Max. string memory (default 0xFFFFFFFF)
 -s Print accounting-statistics to stderr after termination
 -r N. Set maximum parser recursions (default 0 -> include directive disabled)
 -a X:X:X:X. Enable accounting. The following string has the format
    \"type:sum:actual:time\" and sets a limit for accumulated instances,
    actual instances and accumulated runtime of the accounting objects with
    the specified type. A limit of zero means unlimited. Possible types are:
    0 (internal recursions), 1 (variables), 2 (functions),
    3 (library-function-calls)
");
  exit(1);
};

void cldhandler(int sig)
{
  signal(sig,&cldhandler);
  return;
}

void mysig(int sig)
{
  log(LOG_DEBUG,__FILE__,__LINE__,0,
      "GOT SIGNAL %i",sig);
  printf("\nGOT SIGNAL %i\n",sig);
  exit(1);
}

int main(int argc,char** argv)
{
  flowctrl back;
  type_block* start_block;
  unsigned long longdummy;
  string stringdummy;

  stats=0;

  signal(SIGCHLD,SIG_IGN);
  signal(SIGSEGV,&mysig);

  /* reset parser */
  reset_parser();

  /* set outstream to stdout */
  outstream=stdout;

  opt options;
  if (!get_options(argc,argv,"a:x:m:r:e:t:o:z:qdhis",longdummy,
		   stringdummy,0,options,0)) { usage(); };
  if (!options.allow_eval)
    { 
      if (!(options.allow_eval=new bool()))
	{log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,NULL); };
      *options.allow_eval=1;
    };
  if (!options.allow_extern)
    {
      if (!(options.allow_extern=new bool()))
        {log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,NULL); };
      *options.allow_extern=1;
    };
  if (!options.allow_options)
    {
      if (!(options.allow_options=new bool()))
        {log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,NULL); };
      *options.allow_options=1;
    };
  if (!options.timestats)
    {
      if (!(options.timestats=new bool()))
        {log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,NULL); };
      *options.timestats=0;
    };
  if (!options.ptr_d)
    {
      if (!(options.ptr_d=new opt_d()))
        {log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,NULL); };
    };
 if (!options.ptr_h)
   {
      if (!(options.ptr_h=new opt_h()))
        {log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,NULL); };
   };
 if (!options.ptr_a)
   {
      if (!(options.ptr_a=new opt_a()))
        {log(LOG_FATAL,__FILE__,__LINE__,ERROR_OUT_OF_MEM,NULL); };
   };

 if (!defined(file)) { usage(); };

 string filedummy="?";
 filenames.insert_listelem(filedummy,filenames.length());
 filenames.insert_listelem(file,filenames.length());
 filei=1;

 prg=fopen(file,"r");
  if (!prg)
    {
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_UNSPECIFIED,
	  "cannot fopen() file: %s",(char*) file);
    };

  if (yyparse())
    {
      log(LOG_FATAL,__FILE__,__LINE__,ERROR_SYNTAX_ERROR,
	  "parsing error in file %s, line %u",
	  (char*) filenames[filei],line);
    };
  emptystack();

  fclose(prg);

  start_block=yyval.t18;

  instlibfunc();
  init_variables();
  start_block->setblock(NULL);
  start_block->perms=0;

  /*
    seed random generator with unix time (usec) modulo 65536
    we do this after parsing for security
  */
  struct timezone tz;
  timeval tv;
  gettimeofday(&tv,&tz);
  srandom((unsigned int) (tv.tv_usec%65536));

  /* let's go */
  back=start_block->execute(&options);

  /* print stats ? */
  if (stats) { print_accounting(stderr,&options); };

  freeopts(&options);
  start_block->destroy();
  delete start_block;

  if (debug)
    {
      if (back.ctrl==FLOW_OK) { printf("RETURN: FLOW_OK\n"); };
      if (back.ctrl==FLOW_CONTINUE) { printf("RETURN: FLOW_CONTINUE\n"); };
      if (back.ctrl==FLOW_BREAK) { printf("RETURN: FLOW_BREAK\n"); };
      if (back.ctrl==FLOW_RETURN) { printf("RETURN: FLOW_RETURN\n"); };
      if (back.ctrl==FLOW_EXIT) { printf("RETURN: FLOW_EXIT\n"); };
    };

  if (defined(back.error))
    {
      fprintf(stdout,"ERROR (file %s, line %u): %s\n",
	      (char*) filenames[back.file],back.line,(char*) back.error);
      exit(1);
    };
  
  exit(0);
}





