/*
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"
 
int args_fopen[]= { TYPE_VALUE_STRING,
                    TYPE_VALUE_STRING,
                    0 };

flowctrl func_fopen(type_block* aktblock,opt* options,
                    joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back,call;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_LONG;
  back.returnval.val.longval=-1;
  FILE* fh;

  if (!defined((*args)[0].stringval) || !defined((*args)[1].stringval))
    {
      setvarulong("error",1);
      setvarstring("perror","fopen: string not defined");
      return back;
    };

  if ((*args)[0].stringval=="STDIN" && (*args)[1].stringval=="r")
    {
      fh=stdin;
    }
  else if ((*args)[0].stringval=="STDOUT" && (*args)[1].stringval=="w")
    {
      fh=stdout;
    }
  else
    {
      fh=fopen((*args)[0].stringval,(*args)[1].stringval);
    };

  if (!fh)
    {
      setvarulong("error",1);
      setvarstring("perror",(string) "fopen: "+myperror());
      return back;
    };

  back.returnval.val.longval=options->ptr_h->streams.insert(fh);
  return back;  
}

int args_popen[]= { TYPE_VALUE_STRING,
                    TYPE_VALUE_STRING,
                    0 };

flowctrl func_popen(type_block* aktblock,opt* options,
                    joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back,call;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_LONG;
  back.returnval.val.longval=-1;
  FILE* fh;

  if (!defined((*args)[0].stringval) || !defined((*args)[1].stringval))
    {
      setvarulong("error",1);
      setvarstring("perror","popen: string not defined");
      return back;
    };

  fh=popen((*args)[0].stringval,(*args)[1].stringval);
  if (!fh)
    {
      setvarulong("error",1);
      setvarstring("perror",(string) "popen: "+myperror());
      return back;
    };

  back.returnval.val.longval=options->ptr_h->streams.insert(fh);
  return back;
}

int args_exec[]= { TYPE_VALUE_STRING,
                   TYPE_VALUE_STRING,
                   TYPE_VALUE_STRING,
                   TYPE_VALUE_STRING,
                   0 };

flowctrl func_exec(type_block* aktblock,opt* options,
                   joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;

  if (!defined((*args)[0].stringval) ||
      !defined((*args)[1].stringval) ||
      !defined((*args)[2].stringval) ||
      !defined((*args)[3].stringval))
    {
      setvarulong("error",1);
      setvarstring("perror","exec: string not defined");
      return back;
    };

  unsigned long argc=0,i;
  type_value* arg;
  type_value* invar;
  type_value* outvar;
  string argvar=(*args)[1].stringval;
  flowctrl call;
  char buf[MAX_LINE_SIZE];
  FILE* instream;
  FILE* outstream;
  char** callargs;
  string dummy;

  /* get variables for streamhandles */
  call=getvar(aktblock,options,invar,(*args)[2].stringval);
  if (call.ctrl!=FLOW_OK)
    {
      setvarulong("error",1);
      setvarstring("perror","exec: cannot get variable for inhandle");
      return back;
    };
  if (invar->type!=TYPE_VALUE_LONG)
    {
      setvarulong("error",1);
      setvarstring("perror","exec: variable for inhandle has wrong type");
      return back;
    };
  call=getvar(aktblock,options,outvar,(*args)[3].stringval);
  if (call.ctrl!=FLOW_OK)
    {
      setvarulong("error",1);
      setvarstring("perror","exec: cannot get variable for outhandle");
      return back;
    };
  if (outvar->type!=TYPE_VALUE_LONG)
    {
      setvarulong("error",1);
      setvarstring("perror","exec: variable for outhandle has wrong type");
      return back;
    };

  /* count args */
  while (1)
    {
      snprintf(buf,MAX_LINE_SIZE,"%lu",argc);
      dummy=argvar+buf;
      call=getvar(aktblock,options,arg,dummy);
      if (call.ctrl!=FLOW_OK)
        {
          setvarulong("error",1);
          setvarstring("perror","exec: cannot get argument");
          return back;
        };
      if (arg->type!=TYPE_VALUE_STRING)
        {
          setvarulong("error",1);
          setvarstring("perror","exec: argument has wrong type");
          return back;
        };
      if (!defined(arg->stringval))
        {
          break;
        };
      argc++;
    };

  /* initialize args */
  callargs=new char*[argc+1];
  if (!callargs)
    {
      setvarulong("error",1);
      setvarstring("perror","exec: out of mem");
      return back;
    };
  for (i=0;i!=argc;i++)
    {
      snprintf(buf,MAX_LINE_SIZE,"%lu",i);
      dummy=argvar+buf;
      call=getvar(aktblock,options,arg,dummy);
      if (call.ctrl!=FLOW_OK)
        {
          delete[] callargs;
          setvarulong("error",1);
          setvarstring("perror","exec: cannot get argument");
          return back;
        };
      callargs[i]=arg->stringval;
    };
  callargs[argc]=0;

  /* let's go */
  if (!myexec1((*args)[0].stringval,callargs,instream,outstream))
    {
      delete[] callargs;
      setvarulong("error",1);
      setvarstring("perror","exec: failed");
      return back;
    };

  /* create/set handles for new streams */
  invar->val.longval=options->ptr_h->streams.insert(instream);
  outvar->val.longval=options->ptr_h->streams.insert(outstream);

  /* all ok */
  delete[] callargs;
  back.returnval.val.longval=1;
  return back;
}

int args_feof[]= { TYPE_VALUE_LONG,
                   0 };

flowctrl func_feof(type_block* aktblock,opt* options,
                   joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_LONG;
  back.returnval.val.longval=-1;
  FILE* fh;

  if (!options->ptr_h->streams.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","feof: illegal handle");
      return back;
    };

  fh=options->ptr_h->streams.gethandle((*args)[0].val.longval);

  back.returnval.val.longval=(long) feof(fh);
  return back;
}

int args_fgets[]= { TYPE_VALUE_LONG,
                    0 };

flowctrl func_fgets(type_block* aktblock,opt* options,
                    joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_STRING;
  FILE* fh;
  char buf[MAX_LINE_SIZE];

  if (!options->ptr_h->streams.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","fgets: illegal handle");
      return back;
    };

  fh=options->ptr_h->streams.gethandle((*args)[0].val.longval);

  back.returnval.stringval="";
  while (fgets(buf,MAX_LINE_SIZE,fh))
    {
      back.returnval.stringval+=buf;
      
      if (buf[strlen(buf)-1]=='\n') { break; };
    };

  if (back.returnval.stringval=="")
    {
      back.returnval.stringval=0;
      setvarulong("error",1);
      setvarstring("perror","fgets: EOF while no characters were read");
    };

  return back;
}

int args_fputs[]= { TYPE_VALUE_LONG,
                    TYPE_VALUE_STRING,
                    0 };

flowctrl func_fputs(type_block* aktblock,opt* options,
                    joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;
  FILE* fh;

  if (!defined((*args)[1].stringval))
    {
      setvarulong("error",1);
      setvarstring("perror","fputs: string not defined");
      return back;
    };

  if (!options->ptr_h->streams.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","fputs: illegal handle");
      return back;
    };

  fh=options->ptr_h->streams.gethandle((*args)[0].val.longval);

  if (fputs((*args)[1].stringval,fh)==EOF)
    {
      setvarulong("error",1);
      setvarstring("perror",(string) "fputs: "+myperror());
    }
  else
    {
      back.returnval.val.ulongval=1;
    };
  return back;
}

int args_fclose[]= { TYPE_VALUE_LONG,
                     0 };

flowctrl func_fclose(type_block* aktblock,opt* options,
                     joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;
  FILE* fh;

  if (!options->ptr_h->streams.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","fclose: illegal handle");
      return back;
    };

  fh=options->ptr_h->streams.gethandle((*args)[0].val.longval);

  if (fclose(fh))
    {
      setvarulong("error",1);
      setvarstring("perror",(string) "fclose: "+myperror());
      return back;
    };

  options->ptr_h->streams.del((*args)[0].val.longval);
  back.returnval.val.ulongval=1;
  return back;
}

int args_pclose[]= { TYPE_VALUE_LONG,
                     0 };

flowctrl func_pclose(type_block* aktblock,opt* options,
                     joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_LONG;
  back.returnval.val.longval=-1;
  FILE* fh;

  if (!options->ptr_h->streams.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","pclose: illegal handle");
      return back;
    };

  fh=options->ptr_h->streams.gethandle((*args)[0].val.longval);

  back.returnval.val.longval=(long) pclose(fh);
  options->ptr_h->streams.del((*args)[0].val.longval);
  return back;
}

int args_fflush[]= { TYPE_VALUE_LONG,
                     0 };

flowctrl func_fflush(type_block* aktblock,opt* options,
                     joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;
  FILE* fh;

  if (!options->ptr_h->streams.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","fclose: illegal handle");
      return back;
    };

  fh=options->ptr_h->streams.gethandle((*args)[0].val.longval);

  if (fflush(fh))
    {
      setvarulong("error",1);
      setvarstring("perror",(string) "fclose: "+myperror());
      return back;
    };

  back.returnval.val.ulongval=1;
  return back;
}

int args_setoutstream[]= { TYPE_VALUE_LONG,
                           0 };

flowctrl func_setoutstream(type_block* aktblock,opt* options,
                           joined_list<type_value>* args)
{
  aktblock=aktblock;options=options;args=args; /* to prevent warnings */
  flowctrl back;
  back.ctrl=FLOW_RETURN;
  back.returnval.type=TYPE_VALUE_ULONG;
  back.returnval.val.ulongval=0;

  if (!options->ptr_h->streams.ishandle((*args)[0].val.longval))
    {
      setvarulong("error",1);
      setvarstring("perror","setoutstream: illegal handle");
      return back;
    };

  outstream=options->ptr_h->streams.gethandle((*args)[0].val.longval);
  back.returnval.val.ulongval=1;
  return back;
}

