/*
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
*/

#define TYPE_BLOCK 10
#define TYPE_REFERENCE 11
#define TYPE_EXPR_LIST 12
#define TYPE_FUNCTION_CALL 13
#define TYPE_EXPR 14
#define TYPE_ARG_LIST_ENTRY 15
#define TYPE_ARG_LIST 16
#define TYPE_FUNCTION_DEKL 17
#define TYPE_DEKL_LIST_ENTRY 18
#define TYPE_DEKL_LIST 19
#define TYPE_VARIABLE_DEKL 20
#define TYPE_EXPR_STMT 21
#define TYPE_CHOICE_STMT 22
#define TYPE_LOOP_STMT 23
#define TYPE_JUMP_STMT 24
#define TYPE_STMT 25
#define TYPE_STMT_LIST 26
#define TYPE_EVAL_STMT 27
#define TYPE_EXTERNAL_STMT 28

#define T_CONST_STRING 1
#define T_CONST_STRING_HEX 2
#define T_CONST_STRING_OCT 3
#define T_CONST_DEZ 4
#define T_CONST_OCT 5
#define T_CONST_HEX 6
#define T_CONST_DOUBLE 7
#define T_WORD 8
#define T_COMMENT 9
#define T_COMMENT_LINE 10
#define T_PRINT 11
#define T_UNDEF 12
#define T_EOF 13
#define T_DIRECTIVE 14
#define T_DIRECTIVE_ARG 15

#define ACC_TYPE_RECURSION 0
#define ACC_TYPE_VAR 1
#define ACC_TYPE_FUNC 2
#define ACC_TYPE_LIBRARY 3

#define FLOW_OK 1
#define FLOW_CONTINUE 2
#define FLOW_BREAK 3
#define FLOW_RETURN 4
#define FLOW_EXIT 5

#define TYPE_VALUE_LONG 1
#define TYPE_VALUE_DOUBLE 2
#define TYPE_VALUE_STRING 3
#define TYPE_VALUE_VOID 4
#define TYPE_VALUE_ULONG 5

#define TYPE_STMT_VARIABLE_DEKL 1
#define TYPE_STMT_FUNCTION_DEKL 2
#define TYPE_STMT_EXPR_STMT 3
#define TYPE_STMT_BLOCK 4
#define TYPE_STMT_CHOICE_STMT 5
#define TYPE_STMT_LOOP_STMT 6
#define TYPE_STMT_JUMP_STMT 7
#define TYPE_STMT_PRINT_STMT 8

#define TYPE_DEKL_LIST_ENTRY_REF 1
#define TYPE_DEKL_LIST_ENTRY_REFINIT 2

#define TYPE_EXPR_STMT_EMPTY 1
#define TYPE_EXPR_STMT_DEFINED 2

#define TYPE_CHOICE_STMT_IF 1
#define TYPE_CHOICE_STMT_ELSE 2

#define TYPE_LOOP_STMT_WHILE 1
#define TYPE_LOOP_STMT_DO 2
#define TYPE_LOOP_STMT_FOR 3

#define TYPE_JUMP_STMT_BREAK 1
#define TYPE_JUMP_STMT_CONTINUE 2
#define TYPE_JUMP_STMT_RETURN 3
#define TYPE_JUMP_STMT_RETURNVAL 4

#define FLAG_PERMS_FUNC 1
#define FLAG_PERMS_VAR 2
#define FLAG_PERMS_DECLARE_VAR 4
#define FLAG_PERMS_DECLARE_FUNC 8

#define TYPE_FUNC_DEKL_NORMAL 1
#define TYPE_FUNC_DEKL_EVAL 2
#define TYPE_FUNC_DEKL_EXTERNAL 3

#define TYPE_FUNCTION_NORMAL 1
#define TYPE_FUNCTION_EVAL 2
#define TYPE_FUNCTION_EXTERNAL 3
#define TYPE_FUNCTION_LIBRARY 4

#define TYPE_EXPR_CONST 1
#define TYPE_EXPR_REFERENCE 2
#define TYPE_EXPR_FUNCTION_CALL 3
#define TYPE_EXPR_ASSIGNMENT 4
#define TYPE_EXPR_POSTINKREMENT 5
#define TYPE_EXPR_POSTDEKREMENT 6
#define TYPE_EXPR_PREINCREMENT 7
#define TYPE_EXPR_PREDECREMENT 8
#define TYPE_EXPR_EXPR 9
#define TYPE_EXPR_OPERATOR_ONE 10
#define TYPE_EXPR_OPERATOR_TWO 11
#define TYPE_EXPR_CAST 12

#define TYPE_REFERENCE_SIMPLE 1
#define TYPE_REFERENCE_COMPLEX 2

#define TYPE_OPERATOR_ONE_NEG_AR 1
#define TYPE_OPERATOR_ONE_NEG_BOOL 2
#define TYPE_OPERATOR_ONE_NEG_BIT 3

#define TYPE_OPERATOR_TWO_MULT 1
#define TYPE_OPERATOR_TWO_DIV 2
#define TYPE_OPERATOR_TWO_MODULO 3
#define TYPE_OPERATOR_TWO_PLUS 4
#define TYPE_OPERATOR_TWO_MINUS 5
#define TYPE_OPERATOR_TWO_SHIFTLEFT 6
#define TYPE_OPERATOR_TWO_SHIFTRIGHT 7
#define TYPE_OPERATOR_TWO_LOWER 8
#define TYPE_OPERATOR_TWO_GREATER 9
#define TYPE_OPERATOR_TWO_LE 10
#define TYPE_OPERATOR_TWO_GE 11
#define TYPE_OPERATOR_TWO_EQUAL 12
#define TYPE_OPERATOR_TWO_NOTEQUAL 13
#define TYPE_OPERATOR_TWO_AND_BIT 14
#define TYPE_OPERATOR_TWO_EOR_BIT 15
#define TYPE_OPERATOR_TWO_OR_BIT 16
#define TYPE_OPERATOR_TWO_AND_BOOL 17
#define TYPE_OPERATOR_TWO_OR_BOOL 18

#define TYPE_HANDLE_STREAM 1
#define TYPE_HANDLE_PGCONN 2
#define TYPE_HANDLE_PGRESULT 3
#define TYPE_HANDLE_RPCTRANS 4
#define TYPE_HANDLE_RPCCLIENT 5
#define TYPE_HANDLE_SOCKET 6
#define TYPE_HANDLE_DIR 7
#define TYPE_HANDLE_MSQLCONN 8
#define TYPE_HANDLE_MSQLRESULT 9
#define TYPE_HANDLE_MYSQLCONN 10
#define TYPE_HANDLE_MYSQLRESULT 11

#define CGIWRAP_BUF 65535

#ifndef LINETRACK
#undef YYLSP_NEEDED
#endif

/* for pointers to work before class is declared */
struct type_value;
struct flowctrl;
struct type_function;
struct type_reference;
struct type_function_call;
struct type_expr;
struct type_arg_list_entry;
struct type_function_dekl;
struct type_dekl_list_entry;
struct type_variable_dekl;
struct type_expr_stmt;
struct type_choice_stmt;
struct type_loop_stmt;
struct type_jump_stmt;
struct type_stmt;
struct type_eval_stmt;
struct type_block;
struct type_arg_list;
struct type_dekl_list;
struct type_stmt_list;
struct type_expr_list;
struct type_external_stmt;

/* some basic types and funcs */

void set_error(type_block*,long);
void set_perror(type_block*,string);
int pgetchar();
extern int yyparse();
void reset_parser();

#ifdef WITH_RPC
extern boilrpc_1(struct svc_req *, register SVCXPRT *);
extern boilrpc_1_fork(struct svc_req *, register SVCXPRT *);
#endif

struct type_value
{
  unsigned char type;
  union {
    long longval;
    unsigned long ulongval;
    double doubleval;
  } val;
  string stringval;

  type_value();
  ~type_value();
  type_value(type_value&);
  type_value& operator=(type_value);
};

type_value operator-(type_value&);
type_value operator!(type_value&);
type_value operator~(type_value&);
type_value operator*(type_value&,type_value&);
type_value operator/(type_value&,type_value&);
type_value operator%(type_value&,type_value&);
type_value operator+(type_value&,type_value&);
type_value operator-(type_value&,type_value&);
type_value operator<<(type_value&,type_value&);
type_value operator>>(type_value&,type_value&);
type_value operator<(type_value&,type_value&);
type_value operator>(type_value&,type_value&);
type_value operator<=(type_value&,type_value&);
type_value operator>=(type_value&,type_value&);
type_value operator==(type_value&,type_value&);
type_value operator!=(type_value&,type_value&);
type_value operator&(type_value&,type_value&);
type_value operator^(type_value&,type_value&);
type_value operator|(type_value&,type_value&);
type_value operator&&(type_value&,type_value&);
type_value operator||(type_value&,type_value&);

struct token
{
  int type;
  void* ptr;
};

void freetoken(int,void*);
void freetokenstack();
void deltoken(void*);
void instoken(int,void*);
void emptystack();

struct flowctrl
{
  unsigned char  ctrl;
  type_value returnval;
  string error;
  unsigned int line,file;

  flowctrl();
  flowctrl& operator=(flowctrl);
};

struct type_acc
{
  unsigned long acc;

  unsigned long count;
  unsigned long max;

  unsigned long count_akt;
  unsigned long max_akt;

  mytimer start_time;
  mytimer count_time;
  mytimer max_time;

  unsigned long recursion;

  type_acc();
};

#ifdef WITH_RPC
struct rpc_transport
{
  SVCXPRT* transport;
  unsigned long program;
  unsigned long version;
};
#endif

struct opt_h
{
  hlist<FILE*> streams;
#ifdef WITH_POSTGRES
  hlist<PGconn*> pg_connections;
  hlist<PGresult*> pg_querys;
#endif
#ifdef WITH_MSQL
  hlist<int> msql_connections;
  hlist<m_result*> msql_querys;
#endif
#ifdef WITH_MYSQL
  hlist<MYSQL*> mysql_connections;
  hlist<MYSQL_RES*> mysql_querys;
#endif
#ifdef WITH_RPC
  hlist<rpc_transport> rpc_transports;
  hlist<CLIENT*> rpc_clients;
#endif
  hlist<int> sockets;
  hlist<DIR*> dirs;
};

struct opt_a
{
  type_acc accounting[ACCOUNTING_ANZ];
};

struct opt_d
{
  hashdir<char,string,256,1> disabled;
};

struct opt
{
  bool* allow_eval;
  bool* allow_extern;
  bool* allow_options;
  bool* timestats;
  opt_d* ptr_d; /* disabled functions */
  opt_h* ptr_h; /* handles */
  opt_a* ptr_a; /* accounting */
  opt();
};

flowctrl acc_add(opt*,int);
void acc_del(opt*,int);
void print_accounting(FILE*,opt*);
int get_options(int,char**,char*,unsigned long&,string&,opt*,opt&,
		unsigned long);
void freeopts(opt*);
void setvarulong(string,long);
void setvarstring(string,string);
void init_variables();
int autocast(type_value&,int,bool);

#ifdef WITH_RPC
void code_rpc_value(rpc_value*,type_value*);
int decode_rpc_value(rpc_value*,type_value*);
void code_rpc_accounting(rpc_accounting*,opt_a*);
int decode_rpc_accounting(rpc_accounting*,opt_a*);
void code_rpc_flowctrl(rpc_flowctrl*,flowctrl*,opt_a*);
int decode_rpc_flowctrl(rpc_flowctrl*,flowctrl*,opt_a*);
void code_rpc_function_args(rpc_function_args*,joined_list<type_value>*);
int decode_rpc_function_args(rpc_function_args*,joined_list<type_value>*);
rpc_flowctrl* boilrpc_call_1_svc(rpc_callargs*, struct svc_req*);

extern type_block* svc_run_block;
extern opt* svc_run_options;
#endif

flowctrl makevar(type_block*,opt*,type_value*,string&);
void ctrldump(flowctrl,opt_a*,int);
opt optchanges(opt*,opt*);

void cldhandler(int);

struct type_function
{
  unsigned char type;
  bool called;
  string name;
  string passwd;
  unsigned char returntype;
  type_block* block;
  type_block* myblock;
  type_arg_list* args;
  unsigned long external_handle;
  string external_function;
  string external_pw;
  flowctrl (*library_ptr)(type_block*,opt*,joined_list<type_value>*);

  flowctrl call(type_block*,opt*,bool,bool,joined_list<type_value>*);
};

/* normal global objects */

extern bool embed,first_line,stats;
extern FILE* prg;
extern char* prgstr;
extern unsigned long max_parse_recursions,max_string_size;
extern unsigned int line,filei;
extern joined_list<string> filenames;
extern string file;
extern string w,w1;
extern bool first,last;
extern char lastchar;
extern int wtype;
extern joined_list<token> tokenstack;
extern hashdir<type_function,string,256,0> libfunctions;
extern hashdir<type_value,string,256,0> variables;
extern FILE* outstream;

struct cachefield
{
  string name;
  string value;
};

extern hashdir<hashdir<joined_list<cachefield>,string,256,0>,string,256,0>
tcache;
extern unsigned long tcache_size;
extern unsigned char tcache_hash;

/* these are used for parsing */

/* library-function must get and declare variables and functions too */

flowctrl declarevar(type_block*,opt*,type_value*,string&);
flowctrl declarefunc(type_block*,opt*,type_function*);
flowctrl getvar(type_block*,opt*,type_value*&,string&);
flowctrl getfunc(type_block*,opt*,type_function*&,string&);
struct type_reference
{
  unsigned int line,file;
  unsigned char type;
  type_block* block;
  type_block* aktblock;
  string name;
  type_expr* expr;
  type_expr* counter;
  unsigned long perms;

  void destroy();
  flowctrl handlecomplex(opt* options);
  flowctrl getvariable(opt*,type_value*&);
  flowctrl getfunction(opt*,type_function*&);
  flowctrl declarevariable(opt*,type_value*);
  flowctrl declarefunction(opt*,type_function*);
  void setblock(type_block*);
};


struct type_function_call
{
  unsigned int line,file;
  type_block* block;
  type_reference* reference;
  type_expr_list* expr_list;
  bool nofatal;

  void destroy();
  flowctrl call(opt*);
  void setblock(type_block*);
};

struct type_expr
{
  unsigned int line,file;
  unsigned char type,cast,optype;
  union {
    type_value* constant;
    type_reference* reference;
    type_function_call* function_call;
  } uptr;
  type_expr* expr1;
  type_expr* expr2;
  type_block* block;

  void destroy();
  flowctrl eval(opt*);
  void setblock(type_block*);
};

struct type_arg_list_entry
{
  unsigned int line,file;
  unsigned char argtype;
  string argname;

  void destroy();
};

struct type_function_dekl
{
  unsigned int line,file;
  unsigned char type;
  unsigned char returntype;
  type_reference* reference;
  type_block* myblock;
  type_eval_stmt* eval_stmt;
  type_external_stmt* external_stmt;
  type_expr* opt_expr;

  type_arg_list* args;

  void destroy();
  flowctrl declare(opt*);
  void setblock(type_block*);
  /* FIXME: we had push() and pop() declared here, why ? */
};

struct type_dekl_list_entry
{
  unsigned int line,file;
  unsigned char type;
  type_reference* reference;
  type_expr* expr;

  void destroy();
  flowctrl declare(opt*,int);
  void setblock(type_block*);
};

struct type_variable_dekl
{
  unsigned int line,file;
  unsigned char vartype;
  type_dekl_list* dekl_list;

  void destroy();
  flowctrl declare(opt*);
  void setblock(type_block*);
};

struct type_expr_stmt
{
  unsigned int line,file;
  unsigned char type;
  type_expr* expr;

  void destroy();
  flowctrl execute(opt*);
  void setblock(type_block*);
};

struct type_choice_stmt
{
  unsigned int line,file;
  unsigned char type;
  type_expr* expr;
  type_stmt* stmt1;
  type_stmt* stmt2;

  void destroy();
  flowctrl execute(opt*);
  void setblock(type_block*);
  void push();
  void pop();
};

struct type_loop_stmt
{
  unsigned int line,file;
  unsigned char type;
  type_expr* expr;
  type_expr* expr_for; /* expr for the end of a for-loop */
  type_stmt* stmt;
  type_stmt* stmt_for; /* expr before for-loop */

  void destroy();
  flowctrl execute(opt*);
  void setblock(type_block*);
  void push();
  void pop();
};

struct type_jump_stmt
{
  unsigned int line,file;
  unsigned char type;
  type_expr* expr;

  void destroy();
  flowctrl execute(opt*);
  void setblock(type_block*);
};

struct type_eval_stmt
{
  unsigned int line,file;
  type_expr* expr_code;

  void destroy();
  flowctrl makeblock(opt*,type_block*&);
  void setblock(type_block*);
};

struct type_external_stmt
{
  unsigned int line,file;
  type_expr* expr_handle;
  type_expr* expr_function;
  type_expr* expr_pw;

  void destroy();
  flowctrl getdata(opt*,unsigned long&,string&,string&);
  void setblock(type_block*);
};

struct type_stmt
{
  unsigned int line,file;
  unsigned char type;
  string print_stmt;
  union {
    type_variable_dekl* variable_dekl;
    type_function_dekl* function_dekl;
    type_expr_stmt* expr_stmt;
    type_choice_stmt* choice_stmt;
    type_loop_stmt* loop_stmt;
    type_jump_stmt* jump_stmt;
    type_block* block; 
  } uptr;

  void destroy();
  flowctrl execute(opt*);
  void setblock(type_block*);
  void push();
  void pop();
};

struct type_stack_entry
{
  hashdir<type_value,string,256,1> variables;
  hashdir<type_function,string,256,1> functions;
};

struct type_block
{
  unsigned int line,file;
  type_block* block;
  unsigned long perms;
  opt new_options;

  joined_list<type_stack_entry> stack;
  type_stmt_list* stmt_list;

  void destroy();
  flowctrl execute(opt*);
  void setblock(type_block*);
  void push();
  void pop();
};

/* for lists the type must be declared so they come at least */

struct type_arg_list
{
  void destroy();
  joined_list<type_arg_list_entry> args;
};

struct type_dekl_list
{
  void destroy();
  joined_list<type_dekl_list_entry> entrys;
};

struct type_stmt_list
{
  void destroy();
  joined_list<type_stmt> stmts;
};

struct type_expr_list
{
  void destroy();
  joined_list<type_expr> exprs;
};

