/*

  This is a part of the Project Frontier's Source code.

  Copyright (C) 1997-98 Francis Gastellu
                    aka Lone Runner/Aegis

  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 (at your option) 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.

*/
/*
                           ú+ Project Frontier +ú

þ PPE Virtual Machine Runtime

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± VIRTUAL MACHINE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

*/
     #define YYSTYPE pplvar*

     #include <ctype.h>
     #include <stdio.h>
     #include <dos.h>
	 #include <math.h>
	 #include <alloc.h>
     #include <stdlib.h>
     #include <dir.h>
     #include <time.h>
     #include <share.h>
     #include <string.h>
     #include "..\lang\ppl_type.h"
     #include "..\lang\ppl_tab.h"
     #include "..\lang\procs.h"
     #include "..\lang\funcs.h"
     #include "..\lang\exec.h"
     #include "..\lang\decrypt.h"
     #include "..\lang\vfs.h"
     #include "..\com\system.h"
     #include "..\com\tpa.h"
	 #include "..\lang\fortify.h"
     #include "..\com\sharing.h"
     #include "..\com\pcbdat.h"
     #include "..\com\ppeswap.h"

#ifdef DEBUGGER
	 #include "..\lang\debug.h"
#endif

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± PROTOTYPES ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

            void fppe_runScript(void);
	         int fppe_loadPPE(char *);
            void fppe_allocValue(pplvar *);
          double fppe_getValue(pplvar *);
	        void fppe_setValue(pplvar *, double);
         pplvar *fppe_newvar(int type, char nDim, int dim[3]);
         pplvar *fppe_copytable1var(pplvar *d1, pplvar *v);
         pplvar *fppe_copytable2var(pplvar *d1, pplvar *d2, pplvar *v);
         pplvar *fppe_copytable3var(pplvar *d1, pplvar *d2, pplvar *d3, pplvar *v);
			long fppe_table1dec(pplvar *v, int a1);
			long fppe_table2dec(pplvar *v, int a1, int a2);
			long fppe_table3dec(pplvar *v, int a1, int a2, int a3);
	        void fppe_pushvar(pplvar *);
	        void fppe_unallocvars(void);
	        void fppe_freevar(pplvar *);
	        void fppe_pushGosubStack(unsigned int);
	unsigned int fppe_popGosubStack(void);
            void fppe_unallocPPEvars(void);
      parse_type fppe_popParse(void);
            void fppe_pushParse(parse_type p);
	        void fppe_allocPPESystem(void);
	        void fppe_freePPESystem(void);
         pplvar *fppe_execFunc(pplvar *);
            void fppe_execProc(pplvar *);
	     pplvar *fppe_toStringVar(pplvar *);
			void fppe_ToString(char *buf, pplvar *v);
            void fppe_runtimeError(char *msg);
			void fppe_reloadUserVars(void);
			void fppe_assignStrVarToAny(pplvar *s, char *str);
			void fppe_allocStrTable(pplvar *s, unsigned int elems, int elemSize);
			void fppe_unallocStrTable(pplvar *s, unsigned int elems);
			void fppe_assignVar(pplvar *d, pplvar *s);
			 int fppe_isFloat(pplvar *s);
			 int fppe_isStr(pplvar *s);
			 int fppe_isSigned(pplvar *s);
			void fppe_strcpy(pplvar *dest, char*src);
			void fppe_strncpy(pplvar *dest, char*src, int size);
		   char *fppe_Cstr(char *str);
	     pplvar *fppe_intPplVar(int a);
		    void fppe_rewriteUserVars(void);
            void fppe_extendString(pplvar *s, int size);
			 int fppe_sizeofType(int type);

     char far cmnt[]="PPE Virtual Machine v1.0á9 - (c)1996 Lone Runner/AEGiS";

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± GLOBAL VARS ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/
     #define ALLOCATED_INC 64
     #define OFFSETSTACK_INC 32
     #define PARSE_INC 32
     #define ARGUMENT_INC 32

	// System Vars & Arrays - To be saved & restored for embedded PPEs !

     vfs_file *script=NULL;
     pplvar **vars;                                 // PPL Variables
     pplvar **globalVars;                           // PPL variables (never modified)
     int nVars;                                     // n of vars
     int globalNVars;                               // n of vars (never modified)
     pplvar **allocated;                            // ptr on allocated vars
     pplvar **baseallocated;                        // ptr on base of allocated vars table
     int nalloc=0;                                  // n of allocated
     int maxAlloc;                                  // current size of allocated
     int baseMaxAlloc;                              // current size of baseallocated
     pplvar **argument;                             // ptr on statement args
     int narg;                                      // n of args
     int maxArg;									// current size of argument
     unsigned int *offsetStack;                     // gosub stack
     int nStackElem;                                // n of gosub
     int maxOffset;                                 // cur size of offsetstack

     parse_type *parse;	        					// sub parsing stack (tables/functions)
     parse_type thisParse;							// this parse infos
     int nParse;                                    // n of parse in stack
     int maxParse;                                  // cur size of parse
     unsigned long argType;                         // types of args
     volatile int endPPE;                           // end PPE flag
     int doCloseUp=0;                               // closeup flag
     volatile int breakPPE;                         // break PPE flag
     int yylexPrevType;	    						// previous value returned by yylex();

     long codesize;                                 // code size
     long codestart;                                // code starting offset
     long curOffset;								// instruction pointer (ip)

#ifdef DEBUGGER
     int identHdr;                                  // index of current proc/func
#endif

     char *PPErunning;
     FILE *fileHandle[9];							   	// handles (add 1, -1 to 7)
	 int ferr[9];             						// ferr
     struct REGPACK ppeREGS;						// dointr regs
     int execStrings;								// exec !c:\ & %c:\ strings
     // Normal Vars

	 extern int far funcToken[];                    // array of functions tokens
	 extern statement far stat[];                   // array of statements infos

     char IFresult=0;								// result of an IF statement
     char zeroData[8]={0,0,0,0,0,0,0,0};
     pplvar emptyVar = {7, &emptyStr, 0, 0, 0, 0, 0};
     pplvar zeroVar = {4, &zeroData, 0, 0, 0, 0, 0};
     pplvar outRangeStr = {7, &emptyStr, 0, 0, 0, 0, 0};
     pplvar outRange = {4, &zeroData, 0, 0, 0, 0, 0};
     int userVars;
     int defaultIn, defaultOut;
	 struct ffblk ppl_ffblk;
	 char readlineLastFile[MAXPATH]="";

     int inPPE=0;

     userType ppe_user;
     int totalPPLVars;
	 extern int far RdUNetNode;

     // not to be saved

     int curProc=0;
	 char tmpS[256]="";
     int imbrication=-1;


/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± RUNPPE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

     int fppe_runPPE(char *file)
     {
     int a, rtn;
     // ----------------------- Save Critical Variables (CALL)
     pplvar **_vars = vars;
     int _nVars = nVars;
     pplvar **_allocated = allocated;
     pplvar **_baseallocated = baseallocated;
     int _nalloc = nalloc;
     int _maxAlloc = maxAlloc;
     int _baseMaxAlloc = baseMaxAlloc;
     pplvar **_argument = argument;
     int _narg = narg;
     int _maxArg = maxArg;
     unsigned int *_offsetStack = offsetStack;
     int _nStackElem = nStackElem;
     int _maxOffset = maxOffset;

     parse_type *_parse = parse;
     parse_type _thisParse = thisParse;
     int _nParse = nParse;
     int _maxParse = maxParse;
     unsigned long _argType = argType;
     int _yylexPrevType = yylexPrevType;

     long _codesize = codesize;
     long _codestart = codestart;

     char *_PPErunning = PPErunning;
   	 FILE *_fileHandle[9];
	 int _ferr[9];
     struct REGPACK _ppeREGS;
     int _execStrings = execStrings;
     int _currentUserNum = currentUserNum;
     int _userVars = userVars;
     int _defaultIn = defaultIn, _defaultOut = defaultOut;
	 struct ffblk _ppl_ffblk = ppl_ffblk;
     int _inPPE = inPPE;
     userType _ppe_user;
     int _totalPPLVars = totalPPLVars;
     int scriptSave=0;
     int _RdUNetNode;

     FILE *s;

#ifdef DEBUGGER
     int _identHdr=identHdr;
     identHdr=0;
#endif

     if (script != NULL)
     	{
        fppe_swapPPE();
        scriptSave=1;
        }

     for (a=0;a<9;a++)
     	{
        _fileHandle[a] = fileHandle[a];
        _ferr[a] = ferr[a];
        }
	 _ppeREGS.r_ax=ppeREGS.r_ax;
	 _ppeREGS.r_bx=ppeREGS.r_bx;
	 _ppeREGS.r_cx=ppeREGS.r_cx;
	 _ppeREGS.r_dx=ppeREGS.r_dx;
	 _ppeREGS.r_si=ppeREGS.r_si;
	 _ppeREGS.r_di=ppeREGS.r_di;
	 _ppeREGS.r_flags=ppeREGS.r_flags;
	 _ppeREGS.r_ds=ppeREGS.r_ds;
	 _ppeREGS.r_es=ppeREGS.r_es;
     memcpy(&_ppe_user, &ppe_user, sizeof(userType));
     inPPE = 1;
     _RdUNetNode = RdUNetNode;
     RdUNetNode = 0;

     currentUserNum = userLoggedNum;
     imbrication++;

     nalloc=0;

	 fppe_strcpy(&ppeReturnValue, "");

#ifndef DEBUGGER
#ifdef FORTIFY
     Fortify_EnterScope();
#endif
#endif
	 fppe_allocPPESystem();
     strcpy(PPErunning, file);

     rtn = fppe_loadPPE(file);							// Load PPE from disk
     switch (rtn)
     	{
        case 1:
        	sprintf(tmpStr, "Cannot execute script - not a PPE \"%s\"", file);
     		fppe_runtimeError(tmpStr);
            break;
        case 2:
        	sprintf(tmpStr, "Cannot execute script - File no found \"%s\"", file);
     		fppe_runtimeError(tmpStr);
            break;
        case 3:
        	sprintf(tmpStr, "Cannot execute script - Unsupported version \"%s\"", file);
     		fppe_runtimeError(tmpStr);
            break;
        }
     if (!rtn)
     	{
#ifdef DEBUGGER
		if (!globalQuitDebugger)
    		{
#endif
	    fppe_runScript();                              // run script
#ifdef DEBUGGER
			}
#endif
#ifdef DEBUGGER
        debuggerEndSession();
#endif
    	fppe_unallocPPEvars();                         // dealloc vars
        }

	 fppe_freePPESystem();
#ifndef DEBUGGER
#ifdef FORTIFY
     Fortify_LeaveScope();
#endif
#endif

     *tokenStr = 0;
     imbrication--;

     // ----------------------- Restore Critical Variables (CALL)
#ifdef DEBUGGER
     identHdr=_identHdr;
#endif
     vars = _vars;
     nVars = _nVars;
     allocated = _allocated;
     baseallocated = _baseallocated;
     nalloc = _nalloc;
     maxAlloc = _maxAlloc;
     baseMaxAlloc = _baseMaxAlloc;
     argument = _argument;
     narg = _narg;
     maxArg = _maxArg;
     offsetStack = _offsetStack;
     nStackElem = _nStackElem;
     maxOffset = _maxOffset;

     parse = _parse;
     thisParse = _thisParse;
     nParse = _nParse;
     maxParse = _maxParse;
     argType = _argType;
     yylexPrevType = _yylexPrevType;

     codesize = _codesize;
     codestart = _codestart;

     PPErunning = _PPErunning;
     for (a=0;a<9;a++)
     	{
        if (fileHandle[a] != NULL) fclose(fileHandle[a]);
        fileHandle[a] = _fileHandle[a];
        ferr[a] = _ferr[a];
        }
	 ppeREGS.r_ax=_ppeREGS.r_ax;
	 ppeREGS.r_bx=_ppeREGS.r_bx;
	 ppeREGS.r_cx=_ppeREGS.r_cx;
	 ppeREGS.r_dx=_ppeREGS.r_dx;
	 ppeREGS.r_si=_ppeREGS.r_si;
	 ppeREGS.r_di=_ppeREGS.r_di;
	 ppeREGS.r_flags=_ppeREGS.r_flags;
	 ppeREGS.r_ds=_ppeREGS.r_ds;
	 ppeREGS.r_es=_ppeREGS.r_es;
     if (!doCloseUp) endPPE = 0; // if closeup requested, let other PPEs quit so we deallocate everything
     breakPPE = 0;
     execStrings = _execStrings;
     if (_currentUserNum != -1) currentUserNum = _currentUserNum;
     userVars = _userVars;
     defaultIn = _defaultIn;
     defaultOut = _defaultOut;
	 ppl_ffblk = _ppl_ffblk;
     inPPE = _inPPE;
     RdUNetNode = _RdUNetNode;
     memcpy(&ppe_user, &_ppe_user, sizeof(userType));
     totalPPLVars = _totalPPLVars;

     if (scriptSave == 1)
        fppe_restorePPE();
     else
     	script = NULL;

     return rtn;
     }

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± LAUNCH THE SCRIPT ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

     void fppe_runScript(void)
     {
     int a,c,d;
     int execp;

       while (!vfs_feof(script) && !endPPE && !breakPPE)
	       {
           checkHotkeys();
           curOffset = vfs_ftell(script) - codestart;
#ifdef DEBUGGER
           if (debuggerEnabled) debuggerStep();
#endif
           execp=0;
		   vfs_fread(&c, 1, 2, script);
           if (vfs_feof(script)) break;
//           printf("%s", stat[c].name);
           if (stat[c].maxArg != stat[c].minArg)    // Fixed arg number?
			   vfs_fread(&thisParse.argNum, 1, 2, script);
           else
           	   thisParse.argNum = stat[c].maxArg;
           if (thisParse.argNum > 0)
           	    {
                thisParse.argType = 0;
		        switch(stat[c].argType)             // argType 0 = exp
			        {                               // argType 1 = var
			        case 0x075F:                    // argType 2 = table
                    case 0x08B7:
				        thisParse.argType |= 1;
				        break;

			        case 0x075B:
				        thisParse.argType |= 1;
				        thisParse.argType |= 1 << 8;
				        break;

			        case 0x07B5:
				        thisParse.argType |= 1 << 8;
				        break;

			        case 0x07E5:
				        thisParse.argType |= (long)1 << 16;
				        break;

			        case 0x078C:
				        thisParse.argType |= 1;
				        thisParse.argType |= 1 << 8;
				        break;

			        case 0x0836:
				        thisParse.argType |= 2;
				        break;

			        case 0x088C:
				        thisParse.argType |= 2;
				        thisParse.argType |= 2 << 8;
				        break;

			        case 0x2585:
				        thisParse.argType |= (long)2 << 24;
				        break;

                    case 0x756:
				        thisParse.argType |= 1;
				        thisParse.argType |= 1 << 8;
				        thisParse.argType |= (long)1 << 16;
                        break;

			        default:
				        break;
			        }
                }

           switch (c)
              	{
                case 7:                         		// Goto

				    vfs_fread(&d, 1, 2, script);
    	    	    vfs_fseek(script, codestart + d, SEEK_SET);
                    continue;

                case 0x29:								// Gosub

				    vfs_fread(&d, 1, 2, script);
                    fppe_pushGosubStack(vfs_ftell(script)-codestart);
    	    	    vfs_fseek(script, codestart + d, SEEK_SET);
                    continue;

                case 0x2A:								// Return

                	vfs_fseek(script, codestart + fppe_popGosubStack(), SEEK_SET);
                    continue;

                case 0xAB:                              // Endfunc
                case 0xA9:                              // Endproc
                    return;

                case 0xA8:								// Procedure
				    vfs_fread(&execp, 1, 2, script);
				    vfs_fread(&d, 1, 2, script);
                    thisParse.argNum = *(char *)vars[execp]->value;

                default:

                    nalloc = 0;                         // Init misc vars
   		            narg = 0;
       		        yylexPrevType=0;
                    nParse=0;
					thisParse.curarg = 0;


                	if (thisParse.argNum > 0)
       	    		    yyparse();                      // Parse arg list

                    if (execp != 0)						// Is it a user-defined procedure ?
						fppe_execProc(vars[execp]);     // yes, execute it!
                    else
                    	{
                        // Safety check - PPE speed would suffer of this!
                        //if (!(c >= MAXPROCS || c <= 0))
		                   	execProc[c]();                  // Nope, exec PPL Statement
                        //else
//                        	fppe_runtimeError("Bad token read from code");
                        }

                   	fppe_unallocvars();                 // Free vars


	                if (c == 11)                        // "IF"
                    	{
					    vfs_fread(&d, 1, 2, script);
						if (!IFresult)					// result is False ?
        	            	{
	    		    	    vfs_fseek(script, codestart + d, SEEK_SET);
    	        	        continue;
	                	    }
                        }

                    break;
                }
//           printf("\n");
           }
       if (breakPPE)
       	   {
           endPPE=1;
           breakPPE=0;
#ifndef DEBUGGER
           output("@X0C*PPE Break*", MASK_BOTH);
           delay(12);
#endif
           }
       updateStatusBar();
	 }

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± LEXICAL ANALYZER ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/
     yylex (YYSTYPE *yylval)
     {
     int c,d;

     takeNext:

     if (((thisParse.argType & 0xFF) == 1 && (yylexPrevType == VAR || yylexPrevType == TABLE1 || yylexPrevType == TABLE2 || yylexPrevType == TABLE3)) || (yylexPrevType == LONETABLE))
	 	goto separator;

     if (vfs_feof(script)) return 0;

     vfs_fread(&c, 1, 2, script);
	 if (c == 0)
        	{
            separator:
            thisParse.argType = thisParse.argType >> 8;
        	thisParse.curarg++;
     		if (thisParse.curarg >= thisParse.argNum)
	        	{
                if (nParse > 0)
                    {
					thisParse = fppe_popParse();
			        *yylval = vars[thisParse.retVar];
                    yylexPrevType = thisParse.retValue;
                    return yylexPrevType;
                    }
    	        yylexPrevType = 0;
        	   	return yylexPrevType;
            	}
            yylexPrevType = SEPAR;
            if (nParse > 0 && thisParse.type != 0xF)
            	(yylexPrevType)++;
		    return yylexPrevType;
            }
     if (c < 0)
        {
		yylexPrevType = funcToken[~c+1];
	 	return yylexPrevType;
        }
     if (c > 0)
		  	{
	    	vfs_fread(&d, 1, 2, script);
	        *yylval = vars[c];
            if (d != 0 || vars[c]->type == 0xF) // Do we have parameters for this variable ?
            	{
                if (vars[c]->type != 0xF) // is it an array ?
                	{
	                if ((thisParse.argType & 0xFF) == 2) // is it a LONEtable ?
		                {
                        vfs_fseek(script, -2, SEEK_CUR);
                        yylexPrevType = LONETABLE;
						return yylexPrevType;
                        }
                    else
		                thisParse.retValue=TABLE1+d-1;
                    }
                else
                	{
	                thisParse.retValue=FUNC; // it's a function
                    d = (*(int *)vars[c]->value) & 0xFF;
                    if (d == 0)
                    	vfs_fseek(script, -2, SEEK_CUR);
                    }
                thisParse.retVar = c;
       	        fppe_pushParse(thisParse);
           	    thisParse.argNum=d;
               	thisParse.argType=0;
                thisParse.curarg=0;
                thisParse.type = vars[c]->type;
                if (thisParse.retValue != FUNC)
					yylexPrevType = TABLE_BEGIN;
                else
					yylexPrevType = FUNC_BEGIN;
                return yylexPrevType;
                }
            yylexPrevType = VAR;
    	 	return yylexPrevType;
        	}
	 }

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± PARSER ERROR MESSAGE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

     yyerror (s)  /* Called by yyparse on error */
          char *s;
     {
       sprintf(tmpStr, "Warning: %s", s);
       fppe_runtimeError(tmpStr);
     }

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± LOAD A SCRIPT ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

int fppe_loadPPE(char *ppename)
{
char *buffer,*temp, *buffer2;
unsigned int realoctet;
unsigned int a,b,l,codeSize;
long bp;
char l1;
float pplcver;
int frtHdr=0;
FILE *debug;
char sign[6];
long symsize=0;

randomize();
nVars=0;

script = vfs_fopenread(ppename, VFS_FILE_READBIN);
if (script == NULL)
	return 2; // File not found
vfs_fread(&tmpStr, 1, 41, script);
if (strncmp("PCBoard Programming Language Executable  ", tmpStr, 41) && strncmp("Project: Frontier  -  Executable Script  ", tmpStr, 41))
	{
    vfs_fclose(script);
	return 1; // Not a PPE
    }

if (tmpStr[1] == 'r')
	frtHdr=1;

vfs_fread(&tmpStr, 1, 4, script);
tmpStr[4]=0;
pplcver = atof(tmpStr);
if (pplcver > 3.2F)
	xor17 = 1;
if (pplcver > 3.3F)
	{
    vfs_fclose(script);
    return 3; // Unsupported version
    }
vfs_fseek(script, 0x30, SEEK_SET);
vfs_fread(&a, 2, 1, script);
vars = malloc(sizeof(pplvar*)*(a+1));
nVars = 0; // Ensure we will alloc new vars at the top of the allocated[] var stack
totalPPLVars=a;
for (b=0;b<a;b++)
	{
	vfs_fread(&tmpStr, 0x0B, 1, script);
	if (pplcver > 2.0F) decrypt(tmpStr, 0x0B);
	l1 = tmpStr[9];
#pragma warn -sus
    vars[a-b] = fppe_newvar(l1, tmpStr[2], &tmpStr[3]);
#pragma warn .sus
 	if (l1 != 7)
		{
		if (pplcver > 1.0F || frtHdr)
        	{
			vfs_fread(&tmpStr, 0x0C, 1, script);
    	    if (pplcver > 2.0F) decrypt(tmpStr, 0x0C);
            }
        else
			{
			vfs_fread(&tmpStr, 8, 1, script);
	        if (pplcver > 2.0F) decrypt(tmpStr, 8);
            }
        memcpy(vars[a-b]->value, &tmpStr[4], fppe_sizeofType(l1));
		}
	else
		{
		vfs_fread(&l, 2, 1, script);
   	    temp = (char *)calloc(l+2,1); // --!
        *temp = l;
       	vfs_fread(&temp[1], l, 1, script);
		if (pplcver > 2.0F) decrypt(fppe_Cstr(temp), l);
        if (vars[a-b]->nDim == 0)
        	{
	        free(vars[a-b]->value);
   		    vars[a-b]->value = (void *)temp;
            }
        else
        	free(temp);
		}
	}

	codestart = vfs_ftell(script);
	codeSize = script->size-codestart-2;
    vfs_fread(&realoctet, 2, 1, script);
    codesize = realoctet;

    bp = vfs_ftell(script);
    vfs_fseek(script, -12, SEEK_END);
    vfs_fread(sign, 6, 1, script);
    if (!strncmp(sign, "PPSYM1", 6))
        {
        symsize = codeSize;
		vfs_fread(&codeSize, 2, 1, script);
        symsize -= codeSize;
        }
    vfs_fseek(script, bp, SEEK_SET);

    if (pplcver > 2.0F)
    	{
	    buffer = (char *)calloc(codeSize+1,1);

	    vfs_fread(buffer, codeSize, 1, script);
	    decrypt(buffer, codeSize);

	    if (realoctet != codeSize)
		    {
		    buffer2 = (char *)calloc(/*codestart +*/ realoctet+3+symsize,1);
//            memcpy(buffer2, script->data, codestart);
            *(int *)&buffer2[/*codestart*/0] = realoctet;
		    redecrypt(buffer, &buffer2[/*codestart+*/2], codeSize, realoctet);
            memcpy(buffer2/*+codestart*/+realoctet+2, script->data + codestart+codeSize+2, symsize);
            free(script->data);
            script->data = (void *)buffer2;
            script->size = /*codestart +*/ realoctet + 3 + symsize;
		    }
        else
        	{
            memcpy(script->data/*+codestart*/+2, buffer, realoctet);
            memcpy(script->data+realoctet+2, script->data + codestart+codeSize+2, symsize);
            script->data = realloc(script->data, codeSize + 2 + symsize);
	        script->size = realoctet + 2 + symsize;
	        *(unsigned int*)script->data = realoctet;
            }
	    free(buffer);
        }
    else
    	{
		memcpy(script->data, script->data+codestart, codeSize + 2 + symsize);
	    script->data = realloc(script->data, codeSize + 2 + symsize);
        script->size = codeSize + 2 + symsize;
        *(unsigned int*)script->data = realoctet;
        }

nVars = a; // ensure we will alloc following computation vars after ppe vars in allocated[]
globalNVars = nVars;
codestart/*+*/=2;
vfs_fseek(script, codestart, SEEK_SET);
globalVars = vars;

#ifdef DEBUGGER
if (debuggerEnabled) debuggerLoadSymbols(script, codestart+codesize);
#endif
if (symsize > 0)
	{
	script->data = realloc(script->data, script->size-symsize);
    script->size -= symsize;
    }

nStackElem=0;

userVars = 0;
if (pplcver < 3.0F)
	{
	if (nVars >= 17)
		if (vars[1]->type == 0 &&
			vars[2]->type == 0 &&
			vars[3]->type == 0 &&
			vars[4]->type == 0 &&
			vars[5]->type == 2 &&
			vars[6]->type == 4 &&
			vars[7]->type == 4 &&
			vars[8]->type == 4 &&
			vars[9]->type == 7 &&
			vars[10]->type == 7 &&
			vars[11]->type == 7 &&
			vars[12]->type == 7 &&
			vars[13]->type == 7 &&
			vars[14]->type == 7 &&
			vars[15]->type == 7 &&
			vars[16]->type == 0 &&
			vars[17]->type == 0 &&
			vars[18]->type == 0 &&
			vars[19]->type == 7 &&
			vars[20]->type == 7 &&
			vars[21]->type == 7 &&
			vars[22]->type == 7 &&
			vars[23]->type == 2)
            	userVars = 1;
	}
else
	if (nVars >= 18)
		if (vars[1]->type == 0 &&
			vars[2]->type == 0 &&
			vars[3]->type == 0 &&
			vars[4]->type == 0 &&
			vars[5]->type == 2 &&
			vars[6]->type == 4 &&
			vars[7]->type == 4 &&
			vars[8]->type == 4 &&
			vars[9]->type == 7 &&
			vars[10]->type == 7 &&
			vars[11]->type == 7 &&
			vars[12]->type == 7 &&
			vars[13]->type == 7 &&
			vars[14]->type == 7 &&
			vars[15]->type == 7 &&
			vars[16]->type == 0 &&
			vars[17]->type == 0 &&
			vars[18]->type == 0 &&
			vars[19]->type == 7 &&
			vars[20]->type == 7 &&
			vars[21]->type == 7 &&
			vars[22]->type == 7 &&
			vars[23]->type == 2 &&
			vars[24]->type == 4)
            	userVars = 2;

memcpy(&ppe_user, &user, sizeof(userType));

fppe_reloadUserVars();
return 0;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± DE-ALLOCATE COMPUTATION VARS ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_unallocvars(void)
{
int a;

for (a=nVars;a<nVars+nalloc;a++)
	{
	if (allocated[a]->tableElement == NULL) free(allocated[a]->value);
   	free(allocated[a]);
	}
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± CREATE A NEW VAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

pplvar *fppe_newvar(int type, char nDim, int dim[3])
{
pplvar *s;
int dec;

s = (pplvar *)calloc(sizeof(pplvar),1);
s->type=type;
s->nDim = nDim;
if (s->nDim > 0)
	{
	s->dim[0] = dim[0];
	s->dim[1] = dim[1];
	s->dim[2] = dim[2];
    }
else
	{
	s->dim[0] = 0;
	s->dim[1] = 0;
	s->dim[2] = 0;
    }
fppe_allocValue(s);

if (nVars+nalloc > maxAlloc-1) // nVars ? globalNVars ?
	{
    dec = allocated - baseallocated;
    baseMaxAlloc += ALLOCATED_INC;
    maxAlloc += ALLOCATED_INC;
	baseallocated = realloc(baseallocated, sizeof(pplvar *)*baseMaxAlloc);
    allocated = baseallocated + dec;
    }

allocated[nVars+nalloc] = s;
s->tableElement = NULL;
nalloc++;
if (type != 7 && type != 0xD)
	// fppe_setValue(s,0);
    memset(s->value, 0, fppe_sizeofType(s->type));
s->name = NULL;
s->identHdr=0;
return s;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± COPY A TABLE1 ENTRY IN A NEW VAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

long fppe_table1dec(pplvar *v, int a)
{
switch (v->type)
	{
    case 0 : // Boolean
    case 9 :  // Byte
	case 0xB : // SByte
    	return a;
    case 1 : // DWord
    case 6 : // Real
    case 8 : // Time
    case 4 : // Integer
    case 0x11 : // DDate
    case 5 : // Money
    	return 4*a;
	case 0xE : // Double
    	return 8*a;
    case 7 : // String
    case 0xD : // BigStr
    	return a;
    case 0xA : // Word
	case 0xC : // Int
    case 2 : // Date
    case 3 : // EDate
    case 0x21 : // SDate
    	return 2*a;
    default:
    	fppe_runtimeError("Invalid variable");
    	return -1;
	}
}

pplvar *fppe_copytable1var(pplvar *d1, pplvar *v)
{
pplvar *s;
unsigned int a;
long b;
char **ptr;

s = fppe_newvar(v->type, 0, v->dim);
a = fppe_getValue(d1);

if (a > v->dim[0])
	{
    fppe_runtimeError("Array index out of range");
    if (fppe_isStr(v))
    	return &outRangeStr;
    else
    	return &outRange;
    }

b = fppe_table1dec(v, a);
if (b == -1)
	return 0;

free(s->value);
if (fppe_isStr(v))
	{
    ptr = v->value;
	s->value = ptr[a];
	s->tableElement = (char**)&ptr[a];
    }
else
	{
	s->value = (char *)(v->value)+b;
    s->tableElement = (char**)-1;
    }

return s;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± COPY A TABLE2 ENTRY IN A NEW VAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

long fppe_table2dec(pplvar *v, int a1, int a2)
{
switch (v->type)
	{
    case 0 : // Boolean
    case 9 :  // Byte
	case 0xB : // SByte
    	return a1 + a2*(v->dim[0]+1);
    case 1 : // DWord
    case 6 : // Real
    case 8 : // Time
    case 4 : // Integer
    case 0x11 : // DDate
    case 5 : // Money
    	return 4 * (a1 + a2*(v->dim[0]+1));
	case 0xE : // Double
    	return 8*(a1 + a2*(v->dim[0]+1));
    case 7 : // String
    	return (a1 + a2*(v->dim[0]+1));
    case 0xD : // BigStr
    	return (a1 + a2*(v->dim[0]+1));
    case 0xA : // Word
	case 0xC : // Int
    case 2 : // Date
    case 3 : // EDate
    case 0x21 : // SDate
    	return 2*(a1 + a2*(v->dim[0]+1));
    default:
    	fppe_runtimeError("Invalid variable");
    	return -1;
	}
}

pplvar *fppe_copytable2var(pplvar *d1, pplvar *d2, pplvar *v)
{
pplvar *s;
unsigned int a1, a2;
long b;
char **ptr;

s = fppe_newvar(v->type, 0, v->dim);
a1 = fppe_getValue(d1);
a2 = fppe_getValue(d2);

if (a1 > v->dim[0] || a2 > v->dim[1])
	{
    fppe_runtimeError("Array index out of range");
    if (fppe_isStr(v))
    	return &outRangeStr;
    else
    	return &outRange;
    }

b = fppe_table2dec(v, a1, a2);
if (b == -1)
	return 0;

free(s->value);
if (fppe_isStr(v))
	{
    ptr = v->value;
	s->value = ptr[b];
	s->tableElement = (char**)&ptr[b];
    }
else
	{
	s->value = (char *)(v->value)+b;
    s->tableElement = (char**)-1;
    }
return s;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± COPY A TABLE3 ENTRY IN A NEW VAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

long fppe_table3dec(pplvar *v, int a1, int a2, int a3)
{
switch (v->type)
	{
    case 0 : // Boolean
    case 9 :  // Byte
	case 0xB : // SByte
    	return (a1 + a2*(v->dim[0]+1) + a3*(v->dim[1]+1)*(v->dim[0]+1));
    case 1 : // DWord
    case 6 : // Real
    case 8 : // Time
    case 4 : // Integer
    case 0x11 : // DDate
    case 5 : // Money
    	return 4 *(a1 + a2*(v->dim[0]+1) + a3*(v->dim[1]+1)*(v->dim[0]+1));
	case 0xE : // Double
    	return 8*(a1 + a2*(v->dim[0]+1) + a3*(v->dim[1]+1)*(v->dim[0]+1));
    case 7 : // String
    	return (a1 + a2*(v->dim[0]+1) + a3*(v->dim[1]+1)*(v->dim[0]+1));
    case 0xD : // BigStr
    	return (a1 + a2*(v->dim[0]+1) + a3*(v->dim[1]+1)*(v->dim[0]+1));
    case 0xA : // Word
	case 0xC : // Int
    case 2 : // Date
    case 3 : // EDate
    case 0x21 : // SDate
    	return 2*(a1 + a2*(v->dim[0]+1) + a3*(v->dim[1]+1)*(v->dim[0]+1));
    default:
    	fppe_runtimeError("Invalid variable");
    	return -1;
	}
}

pplvar *fppe_copytable3var(pplvar *d1, pplvar *d2, pplvar *d3, pplvar *v)
{
pplvar *s;
unsigned int a1, a2, a3;
long b;
char **ptr;

s = fppe_newvar(v->type, 0, v->dim);
a1 = fppe_getValue(d1);
a2 = fppe_getValue(d2);
a3 = fppe_getValue(d3);

if (a1 > v->dim[0] || a2 > v->dim[1] || a3 > v->dim[2] )
	{
    fppe_runtimeError("Array index out of range");
    if (fppe_isStr(v))
    	return &outRangeStr;
    else
    	return &outRange;
    }

b = fppe_table3dec(v, a1, a2, a3);

if (b == -1)
	return 0;

free(s->value);
if (fppe_isStr(v))
	{
    ptr = v->value;
	s->value = ptr[b];
	s->tableElement = (char**)&ptr[b];
    }
else
	{
	s->value = (char *)(v->value)+b;
    s->tableElement = (char**)-1;
    }
return s;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± ALLOCATE A VAR CONTENTS ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_allocValue(pplvar *s)
{
unsigned int a=1,b;

if (s->nDim > 0)
    a *= (s->dim[0]+1)*(s->dim[1]+1)*(s->dim[2]+1);

if (a >= 8192)
	fppe_runtimeError("array too big, cannot allocate");

//for (b=1;b<=s->nDim;b++)

switch (s->type)
	{
    case 0 : // Boolean
    case 9 :  // Byte
	case 0xB : // SByte
    	s->value = calloc(1*a,1);
    	break;
    case 1 : // DWord
    case 6 : // Real
    case 8 : // Time
    case 4 : // Integer
    case 0x11 : // DDate
    case 5 : // Money
		s->value = calloc(4*a,1);
        break;
	case 0xE : // Double
    case 0xF : // Function
    case 0x10 : // Proc
		s->value = calloc(8*a,1);
        break;
    case 7 : // String
        if (a > 1)
        	{
			s->value = calloc(4*a,1);
	        fppe_allocStrTable(s, a, 1); // --!
            }
        else
        	{
			s->value = calloc(2,1); // --!
            *(unsigned char*)s->value=0;
            ((char*)s->value)[1]=0;  // --!
			}
        break;
    case 0xD : // BigStr
        if (a > 1)
        	{
			s->value = calloc(4*a,1);
    	    fppe_allocStrTable(s, a, 2052);
            }
        else
        	{
			s->value = calloc(2052*a,1);
            *(char*)s->value=0;
			}
       	break;
    case 0xA : // Word
	case 0xC : // Int
    case 2 : // Date
    case 3 : // EDate
    case 0x21 : // SDate
    	s->value = calloc(2*a,1);
        break;
    default:
    	fppe_runtimeError("Invalid variable");
	}

}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± RETURN LVALUE OF A VAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

double fppe_getValue(pplvar *s)
{
switch (s->type)
	{
    case 0 :   // Boolean
    case 9 :   // Byte
    	return (double) *(unsigned char *)s->value;
	case 0xB : // SByte
    	return (double) *(signed char *)s->value;
    case 1 : // DWord
    	return (double) *(unsigned long *)s->value;
    case 6 : // Real
    	return (double) *(float *)s->value;
    case 8 : // Time
    case 4 : // Integer
    case 0x11 : // DDate
    case 5 : // Money
    	return (double) *(signed long *)s->value;
	case 0xE : // Double
    case 0xF : // Function
    case 0x10 : // Proc
    	return (double) *(double *)s->value;
    case 7 : // String
    case 0xD : // BigStr
		return (double) atoi(((char*)s->value)+1);
    case 0xA : // Word
    case 2 : // Date
    case 3 : // EDate
    case 0x21 : // SDate
    	return (double) *(unsigned int *)s->value;
	case 0xC : // Int
    	return (double) *(signed int *)s->value;
    default:
    	fppe_runtimeError("Invalid variable");
        return 0;
	}
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± SET LVALUE OF A VAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_setValue(pplvar *s, double value)
{
if (s == &outRangeStr || s == &outRange)
	return;
switch (s->type)
	{
    case 0 :   // Boolean
    	*(unsigned char *)s->value = (unsigned char)value;
        break;
    case 9 :   // Byte
    	*(unsigned char *)s->value = (unsigned char)value;
        break;
	case 0xB : // SByte
    	*(signed char *)s->value = (signed char)value;
        break;
    case 1 : // DWord
    	*(unsigned long *)s->value = (unsigned long)value;
        break;
    case 6 : // Real
    	*(float *)s->value = (float)value;
        break;
    case 8 : // Time
    	*(signed long *)s->value = (signed long)value;
        break;
    case 4 : // Integer
    	*(signed long *)s->value = (signed long)value;
        break;
    case 0x11 : // DDate
    	*(signed long *)s->value = (signed long)value;
        break;
    case 5 : // Money
    	*(signed long *)s->value = (signed long)value;
        break;
	case 0xE : // Double
    	*(double *)s->value = (double)value;
        break;
    case 7 : // String // --!
    case 0xD : // BigStr
		itoa(value, tmpS, 10);
        fppe_strcpy(s, tmpS);
        break;
    case 0xA : // Word
    case 2 : // Date
    case 3 : // EDate
    case 0x21 : // SDate
    	*(unsigned int *)s->value = (unsigned int)value;
        break;
	case 0xC : // Int
    	*(signed int *)s->value = (signed int)value;
        break;
    case 0xF :
    	*(double *)s->value = (double)value;
    case 0x10 :
    	*(double *)s->value = (double)value;
    default:
    	fppe_runtimeError("Invalid variable");
	}
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± PUSH TERMINAL ARGUMENT IN ARG STACK ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_pushvar(pplvar *v1)
{
if (narg == maxArg)
	{
    maxArg += ARGUMENT_INC;
    argument = realloc(argument, sizeof(pplvar *)*maxArg);
    }
argument[narg++] = v1;
}


/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± FREE A VAR ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_freevar(pplvar *v)
{
unsigned int b;
if (v->nDim != 0 && fppe_isStr(v))
   	{
    b = (v->dim[0]+1)*(v->dim[1]+1)*(v->dim[2]+1);
    fppe_unallocStrTable(v, b);
    }
if (v->name != NULL) free(v->name);
free(v->value);
free(v);
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± PUSH OFFSET IN OFFSET STACK (GOSUB) ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_pushGosubStack(unsigned int offset)
{
if (nStackElem == maxOffset)
	{
    maxOffset += OFFSETSTACK_INC;
    offsetStack = realloc(offsetStack, 2*maxOffset);
    }
offsetStack[nStackElem++] = offset;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± POP OFFSET FROM OFFSET STACK (GOSUB) ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

unsigned int fppe_popGosubStack(void)
{
if (nStackElem == 0)
	{
    endPPE=1; // Error!
	return vfs_ftell(script);
    }
return offsetStack[--nStackElem];
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± DE-ALLOCATE PPE VARS ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_unallocPPEvars(void)
{
int a;
unsigned int b;

for (a=0;a<nVars;a++)
	{
    if (baseallocated[a]->nDim != 0 && fppe_isStr(baseallocated[a]))
    	{
	    b = (baseallocated[a]->dim[0]+1)*(baseallocated[a]->dim[1]+1)*(baseallocated[a]->dim[2]+1);
        fppe_unallocStrTable(baseallocated[a], b);
        }
    if (baseallocated[a]->name != NULL) free(baseallocated[a]->name);
    free(baseallocated[a]->value);
    free(baseallocated[a]);
	}

free(vars);
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± PUSH PARSE STATE IN STACK ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_pushParse(parse_type p)
{
if (nParse == maxParse)
	{
    maxParse += PARSE_INC;
    parse = realloc(parse, sizeof(parse_type)*maxParse);
    }
parse[nParse++] = p;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± POP PARSE STATE FROM STACK ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

parse_type fppe_popParse(void)
{
if (nParse == 0)
	{
    fppe_runtimeError("Parse embedding fault");
	return parse[0]; // Error!
    }
return parse[--nParse];
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± ALLOCATE SYSTEME ARRAYS ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_allocPPESystem(void)
{
int a;

script = NULL;
allocated = malloc(sizeof(pplvar*)*ALLOCATED_INC);
baseallocated = allocated;
maxAlloc = ALLOCATED_INC;
baseMaxAlloc = ALLOCATED_INC;

argument = malloc(sizeof(pplvar*)*ARGUMENT_INC);
maxArg = ARGUMENT_INC;

offsetStack = malloc(2*OFFSETSTACK_INC);
maxOffset = OFFSETSTACK_INC;

parse = malloc(sizeof(parse_type)*PARSE_INC);
maxParse = PARSE_INC;

PPErunning = (char *)malloc(MAXPATH);
endPPE=0;
breakPPE=0;
nParse = 0;
yylexPrevType=0;

for (a=0;a<9;a++)
	{
	fileHandle[a]=NULL;
	ferr[a]=0;
	}
ppeREGS.r_ax=0;
ppeREGS.r_bx=0;
ppeREGS.r_cx=0;
ppeREGS.r_dx=0;
ppeREGS.r_si=0;
ppeREGS.r_di=0;
ppeREGS.r_flags=0;
ppeREGS.r_ds=0;
ppeREGS.r_es=0;
execStrings=0;
defaultIn = 0;
defaultOut = 0;
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± FREE SYSTEME ARRAYS ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_freePPESystem(void)
{
free(baseallocated);
allocated = NULL;
free(argument);
free(offsetStack);
free(parse);
free(PPErunning);
if (script != NULL)
	vfs_fclose(script);
*readlineLastFile=0;
fclose(fileHandle[0]);
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± RETURN SIZE OF A TYPE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

int fppe_sizeofType(int type)
{
switch (type)
	{
    case 0 : // Boolean
    case 9 :  // Byte
	case 0xB : // SByte
    	return 1;
    case 1 : // DWord
    case 6 : // Real
    case 8 : // Time
    case 4 : // Integer
    case 0x11 : // DDate
    case 5 : // Money
    	return 4;
	case 0xE : // Double
    case 0xF : // Function
    case 0x10 : // Proc
    	return 8;
    case 7 : // String
    case 0xD : // BigStr
    	return 0;
    case 0xA : // Word
	case 0xC : // Int
    case 2 : // Date
    case 3 : // EDate
    case 0x21 : // SDate
    	return 2;
    default:
    	fppe_runtimeError("Invalid variable");
   	    return 0;
    }
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± EXECUTE A FUNCTION ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

pplvar *fppe_execFunc(pplvar *func)
{
int offset;
int nVarsSave, nargSave, nallocSave, nParseSave;
int a,d,e;
char f;
int nargb;
parse_type _thisParse=thisParse;

#ifdef DEBUGGER
int saveIdent;
int _fullRun=0;

if (traceOver)
	{
	_fullRun = fullRun;
    fullRun=-1;
    }
saveIdent=identHdr;
identHdr = func->identHdr;
#endif

// Save critical datas
nVarsSave = nVars;
nargSave = narg;
nallocSave = nalloc;
nParseSave = nParse;

// move to beginning of function (push current offset)
offset = *(((int *)func->value)+1) ;
fppe_pushGosubStack(vfs_ftell(script)-codestart);
vfs_fseek(script, offset+codestart, SEEK_SET);

// passing arguments
f = *(char *)func->value;
e = *(((int *)func->value)+2);
e++;

for (a=narg-f,d=e;d<e+f;d++,a++)
    {
    fppe_assignVar(vars[d], argument[a]);
//	memcpy(vars[d]->value, argument[a]->value, fppe_sizeofType(vars[d]->type));
    }

d = *(((int *)func->value)+3);
nVars = nVars + f; // shift base for allocated
nargb = narg-f;
argument += nargb; // shift argument pointer so we don't overwrite current args
maxArg -= nargb;   // make sure we don't go over argument[] size
allocated += nalloc;    // idem
maxAlloc -= nalloc;     // ""
parse += nParse;
maxParse -= nParse;
nParse = 0;

// run function
fppe_runScript();

// move back to the offset we were before the function
vfs_fseek(script, codestart + fppe_popGosubStack(), SEEK_SET);

// restore critical datas
nVars = nVarsSave;
argument -= nargb; // shift back argument to its previous ptr
narg = nargSave-f; // Also, remove function arguments from arg stack
maxArg += nargb;   // and add narg saved to the size of argument[]
nalloc = nallocSave;
allocated -= nalloc;
maxAlloc += nalloc;
nParse = nParseSave;
parse -= nParse;
maxParse += nParse;

thisParse=_thisParse;

#ifdef DEBUGGER
if (traceOver)
	fullRun = _fullRun;
identHdr = saveIdent;
#endif

return vars[d];
}

/*
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± EXECUTE A PROCEDURE ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
*/

void fppe_execProc(pplvar *func)
{
int offset;
int a,d,e;
char f;
int v, cnt;
int na;
pplvar **backArgs;
#ifdef DEBUGGER
char **names;
char *p;
int saveIdent;
int _fullRun=0;

if (traceOver)
	{
	_fullRun = fullRun;
    fullRun=-1;
    }
saveIdent=identHdr;
identHdr = func->identHdr;
#endif

// move to beginning of procedure (push current offset)
offset = *(((int *)func->value)+1) ;
fppe_pushGosubStack(vfs_ftell(script)-codestart);
vfs_fseek(script, offset+codestart, SEEK_SET);

// passing arguments
f = *(char *)func->value;
e = *(((int *)func->value)+2);
e++;
v = *(((int *)func->value)+3);

backArgs = malloc(sizeof(pplvar *)*(f+1));
#ifdef DEBUGGER
names = malloc(sizeof(char *)*(f+1));
#endif
na=narg;
for (a=narg-f,d=e,cnt=1;d<e+f;d++,a++,cnt++)
    {
    backArgs[cnt-1] = vars[d];
#ifdef DEBUGGER
    names[cnt-1] = NULL;
#endif
    if (!(v & (1 << cnt-1))) // Is this parameter passed by address ?
    	{
/*        if (fppe_isStr(vars[d]))
        	strcpy(vars[d]->value, fppe_toStringVar(argument[a])->value);
        else
			memcpy(vars[d]->value, argument[a]->value, fppe_sizeofType(vars[d]->type)); // no so make a copy*/
        fppe_assignVar(vars[d], argument[a]);
        }
    else
		{
#ifdef DEBUGGER
	    names[cnt-1] = argument[a]->name;
        p = vars[d]->name;
#endif
		vars[d] = argument[a]; // yes so change address of arg
#ifdef DEBUGGER
		vars[d]->name = p;
#endif
        }
    }

fppe_unallocvars();                 // Free vars
nalloc=0;

// run function
fppe_runScript();

for (a=na-f,d=e,cnt=1;d<e+f;d++,a++,cnt++)
    {
/*for (a=0,d=e; a<f; a++,e++,d++)
    {*/
#ifdef DEBUGGER
    if (names[cnt-1] != NULL)
	    vars[d]->name = names[cnt-1];
#endif
    vars[d] = backArgs[cnt-1]; // change addresses back to parameters
    }

free(backArgs);
#ifdef DEBUGGER
free(names);
#endif

// move back to the offset we were before the function
vfs_fseek(script, codestart + fppe_popGosubStack(), SEEK_SET);

nalloc=0;

#ifdef DEBUGGER
if (traceOver)
	fullRun = _fullRun;
identHdr=saveIdent;
#endif

return;
}

pplvar *fppe_toStringVar(pplvar *v)
{
pplvar *s;

fppe_ToString(tmpS, v);

if (!fppe_isStr(v))
	s = fppe_newvar(7, 0, s->dim);

if (fppe_isStr(v))
    return v;
else
	{
	fppe_strcpy(s, tmpS);
	return s;
    }
}

void fppe_ToString(char *buf, pplvar *v)
{
time_t t;
struct tm *local;
struct time t2;
unsigned long l;
struct date dt;
struct time tm;
int pm;

    switch (v->type)
    	{
        case 0 :   // Boolean
    	    sprintf(buf, "%d", *(unsigned char *)v->value);
            break;
        case 9 :   // Byte
    	    sprintf(buf, "%d", *(unsigned char *)v->value);
            break;
	    case 0xB : // SByte
    	    sprintf(buf, "%d", *(signed char *)v->value);
            break;
        case 1 : // DWord
    	    sprintf(buf, "%lu", *(unsigned long *)v->value);
            break;
        case 6 : // Real
    	    sprintf(buf, "%g", *(float *)v->value);
            break;
        case 0x11 : // DDate
			t = (*(unsigned long *)v->value - 25568) * 86400;
			UnixToDos(t, &dt, &tm);
    	    sprintf(buf, "%04d%02d%02d", dt.da_year, dt.da_mon, dt.da_day);
            break;
        case 8 : // Time
            l = *(signed long *)v->value;
            t2.ti_hour = (long)(l / 3600);
            l -= (long)t2.ti_hour * 3600;
            t2.ti_min = (long)(l / 60);
            l -= (long)t2.ti_min * 60;
            t2.ti_sec = l;
            if (!militaryTime())
            	{
                pm=0;
                if (t2.ti_hour > 12)
                	{
                	t2.ti_hour -= 12;
                    pm=1;
                    }
				sprintf(buf, "%02d:%02d:%02d %s", t2.ti_hour, t2.ti_min, t2.ti_sec, pm ? "PM" : "AM");
            	}
            else
				sprintf(buf, "%02d:%02d:%02d", t2.ti_hour, t2.ti_min, t2.ti_sec);
	       	break;
        case 4 : // Integer
    	    sprintf(buf, "%ld", *(signed long *)v->value);
            break;
        case 5 : // Money
    	    sprintf(buf, "%ld", *(signed long *)v->value);
            break;
	    case 0xE : // Double
    	    sprintf(buf, "%g", *(double *)v->value);
            break;
        case 7 : // String
            break;
        case 0xD : // BigStr
            break;
        case 0xA : // Word
    	    sprintf(buf, "%u", *(unsigned int *)v->value);
            break;
        case 2 : // Date
			t = (*(unsigned int *)v->value - 25568) * 86400;
			UnixToDos(t, &dt, &tm);
    	    sprintf(buf, "%02d.%02d.%02d", dayPart() == 0 ? dt.da_day : dt.da_mon, dayPart() == 0 ? dt.da_mon : dt.da_day, dt.da_year <= 1999 ? dt.da_year - 1900 : dt.da_year - 2000);
            break;
        case 3 : // EDate
			t = (*(unsigned int *)v->value - 25568) * 86400;
			UnixToDos(t, &dt, &tm);
    	    sprintf(buf, "%02d%02d.%02d", dt.da_year <= 1999 ? dt.da_year - 1900 : dt.da_year - 2000, dt.da_mon, dt.da_day);
            break;
	    case 0x21 : // SDate
			t = (*(unsigned int *)v->value - 25568) * 86400;
			UnixToDos(t, &dt, &tm);
    	    sprintf(buf, "%02d.%02d.%02d", dt.da_mon, dt.da_day, dt.da_year <= 1999 ? dt.da_year - 1900 : dt.da_year - 2000);
            break;
	    case 0xC : // Int
    	    sprintf(buf, "%d", *(signed int *)v->value);
            break;
        default:
	    	fppe_runtimeError("Invalid variable");
        }
}


void fppe_runtimeError(char *msg)
{
output("\n@X0C", MASK_SYSOP|MASK_USER);
output(msg, MASK_SYSOP|MASK_USER);
output("\n", MASK_SYSOP|MASK_USER);
}

void fppe_reloadUserVars(void)
{
TPArec *tpa;
if (!userVars)
	return;

fppe_setValue(vars[1], boolean(ppe_user.Expert));
fppe_setValue(vars[2], boolean(ppe_user.FSEditor));
if (boolean(ppe_user.NoAskFSEditor))
	fppe_setValue(vars[3], 0);
else
	fppe_setValue(vars[3], 1);
fppe_setValue(vars[4], boolean(ppe_user.ClearScreen));
strncpy(tmpStr, ppe_user.RegExpDate, 6);
fppe_setValue(vars[5], sysCharDateToPPLDate(tmpStr));
fppe_setValue(vars[6], ppe_user.Security);
fppe_setValue(vars[7], ppe_user.PageLen);
fppe_setValue(vars[8], ppe_user.ExpSecurity);
fppe_strncpy(vars[9], ppe_user.City, 24);
fppe_strncpy(vars[10], ppe_user.DataPhone, 13);
fppe_strncpy(vars[11], ppe_user.VoicePhone, 13);
tmpStr[1]=0;
tmpStr[0] = ppe_user.Protocol;
fppe_strcpy(vars[12], tmpStr);
fppe_strncpy(vars[13], ppe_user.Comment1, 30);
fppe_strncpy(vars[14], ppe_user.Comment2, 30);
fppe_strncpy(vars[15], ppe_user.Password, 12);
fppe_setValue(vars[16], boolean(ppe_user.ScrollMsgBody));
if (boolean(ppe_user.ShortMsgHdr))
	fppe_setValue(vars[17], 0);
else
	fppe_setValue(vars[17], 1);
fppe_setValue(vars[18], boolean(ppe_user.WideEditor));

tpa = openTPA("UALIAS");
if (tpa != NULL)
    {
	getTPA(tpa, tmpStr, 25, curConf, 0, currentUserNum);
    reduceString(tmpStr, 25);
    closeTPA(tpa);
    fppe_strncpy(vars[19], tmpStr, 25);
    }
tpa = openTPA("UVERIF");
if (tpa != NULL)
	{
    getTPA(tpa, tmpStr, 25, curConf, 0, currentUserNum);
    reduceString(tmpStr, 25);
    closeTPA(tpa);
    fppe_strncpy(vars[20], tmpStr, 25);
    }
tpa = openTPA("UADDRESS");
if (tpa != NULL)
	{
    getTPA(tpa, tmpStr, 300, curConf, 0, currentUserNum);
    reduceString(tmpStr, 50);
    reduceString(&tmpStr[50], 50);
    reduceString(&tmpStr[100], 50);
    reduceString(&tmpStr[150], 50);
    reduceString(&tmpStr[200], 50);
    reduceString(&tmpStr[250], 50);
    fppe_strncpy(fppe_copytable1var(vars[21], fppe_intPplVar(0)), tmpStr, 50);
    fppe_strncpy(fppe_copytable1var(vars[21], fppe_intPplVar(1)), &tmpStr[50], 50);
    fppe_strncpy(fppe_copytable1var(vars[21], fppe_intPplVar(2)), &tmpStr[100], 50);
    fppe_strncpy(fppe_copytable1var(vars[21], fppe_intPplVar(3)), &tmpStr[150], 50);
    fppe_strncpy(fppe_copytable1var(vars[21], fppe_intPplVar(4)), &tmpStr[200], 50);
    fppe_strncpy(fppe_copytable1var(vars[21], fppe_intPplVar(5)), &tmpStr[250], 50);
    closeTPA(tpa);
    }
tpa = openTPA("UNOTES");
if (tpa != NULL)
	{
    getTPA(tpa, tmpStr, 250, curConf, 0, currentUserNum);
    reduceString(tmpStr, 50);
    reduceString(&tmpStr[50], 50);
    reduceString(&tmpStr[100], 50);
    reduceString(&tmpStr[150], 50);
    reduceString(&tmpStr[200], 50);
    fppe_strncpy(fppe_copytable1var(vars[22], fppe_intPplVar(0)), tmpStr, 50);
    fppe_strncpy(fppe_copytable1var(vars[22], fppe_intPplVar(1)), &tmpStr[50], 50);
    fppe_strncpy(fppe_copytable1var(vars[22], fppe_intPplVar(2)), &tmpStr[100], 50);
    fppe_strncpy(fppe_copytable1var(vars[22], fppe_intPplVar(3)), &tmpStr[150], 50);
    fppe_strncpy(fppe_copytable1var(vars[22], fppe_intPplVar(4)), &tmpStr[200], 50);
    closeTPA(tpa);
    }

tpa = openTPA("UPWDEXP");
if (tpa != NULL)
	{
    getTPA(tpa, tmpStr, 8, curConf, 0, currentUserNum);
    reduceString(tmpStr, 8);
    tmpStr[8]=0;
    fppe_setValue(vars[23], charDateToPPLDate(tmpStr, 0));
	closeTPA(tpa);
    }

//if (userVars > 1)
	//strcpy(vars[24]->value, userAccount);

}

void fppe_assignStrVarToAny(pplvar *s, char *str)
{
char *endptr;
switch (s->type)
	{
    case 2:
    	fppe_setValue(s, charDateToPPLDate(str, 0));
    	return;
    case 0x21:
    	fppe_setValue(s, charDateToPPLDate(str, 1));
    	return;
    case 8:
    	fppe_setValue(s, charTimeToPPLTime(str));
    	return;
    case 7:
    case 0xD:
        fppe_strcpy(s, str);
	    //strncpy(s->value, str, 256); // --!
	    //strncpy(s->value, str, 2048); // --!
	    return;
    case 0x11:
    	fppe_setValue(s, charDDateToPPLDate(str));
        return;
    default:
		fppe_setValue(s, strtod(str, &endptr));
	    return;
    }
}

void fppe_allocStrTable(pplvar *s, unsigned int elems, int elemSize) // --!
{
char **ptr;
int a;
ptr = (char**)s->value;

for (a = 0; a < elems; a++)
    {
	ptr[a] = calloc(elemSize+2, 1);
    *ptr[a] = elemSize;
    }

}

void fppe_unallocStrTable(pplvar *s, unsigned int elems)
{
char **ptr;
int a;
ptr = (char**)s->value;

for (a = 0; a < elems; a++)
    free(ptr[a]);
}

void fppe_redimTable(pplvar *s, int t1, int t2, int t3)
{
unsigned int b=1;

if (fppe_isStr(s))
   	{
    b *= (s->dim[0]+1)*(s->dim[1]+1)*(s->dim[2]+1);
    fppe_unallocStrTable(s, b);
    }
free(s->value);

s->dim[0] = t1;
s->dim[1] = t2;
s->dim[2] = t3;
s->nDim = 3;

if (!t3)
	s->nDim--;
if (!t2)
	s->nDim--;
if (!t1)
	s->nDim--;

fppe_allocValue(s);
}

void fppe_assignVar(pplvar *d, pplvar *s)
{
if (fppe_isStr(s))
	fppe_assignStrVarToAny(d, fppe_Cstr(s->value));
else
	{
    if (fppe_isStr(d))
    	fppe_strcpy(d, fppe_Cstr(fppe_toStringVar(s)->value));
    else
		fppe_setValue(d, fppe_getValue(s));
    }
}

int fppe_isFloat(pplvar *s)
{
return (s->type == 0xE || s->type == 6);
}

int fppe_isStr(pplvar *s)
{
return (s->type == 7 || s->type == 0xD);
}

int fppe_isSigned(pplvar *s)
{
return (s->type == 0xB || s->type == 0x8 || s->type == 0x4 || s->type == 0x5 || s->type == 0xC);
}

void fppe_strcpy(pplvar *dest, char*src)
{
int _maxAlloc;
int size;

if (dest == &outRangeStr)
	return;

size = strlen(src);
if (size > 255) size = 255; // check that we won't try to allocate more than 255 bytes for a normal string
if (dest->type == 7)
	{
	_maxAlloc = *(unsigned char*)dest->value;
    if (size > _maxAlloc)
	    {
        dest->value = realloc(dest->value, size+2);
        if (dest->tableElement)
            *dest->tableElement = dest->value;
        *(unsigned char*)dest->value = size & 0xFF;
        }
	strncpy(fppe_Cstr(dest->value), src, *(unsigned char*)dest->value);
    ((char*)dest->value)[size+1]=0;
    }
else
	strncpy(((char *)(dest->value) +1), src, 2048);
}

char *fppe_Cstr(char *str)
{
return &str[1];
}

void fppe_strncpy(pplvar *dest, char*src, int size)
{
int _maxAlloc;

if (size > 255) size = 255;
if (dest->type == 7)
	{
	_maxAlloc = *(unsigned char*)dest->value;
    if (size > _maxAlloc)
	    {
        dest->value = realloc(dest->value, size+2);
        if (dest->tableElement)
            *dest->tableElement = dest->value;
        *(unsigned char*)dest->value = size & 0xFF;
        }
	strncpy(fppe_Cstr(dest->value), src, size);
    ((char*)dest->value)[size+1]=0;
    }
else
	strncpy(((char *)(dest->value) +1), src, size);
}

pplvar *fppe_intPplVar(int a)
{
pplvar *s; // check! --!
s = fppe_newvar(0xC, 0, s->dim);
fppe_setValue(s, a);
return s;
}

void fppe_rewriteUserVars(void)
{
TPArec *tpa;
if (!userVars)
	return;

ppe_user.Expert = fppe_getValue(vars[1]) ? 'Y' : 'N';
ppe_user.FSEditor = fppe_getValue(vars[2]);
ppe_user.NoAskFSEditor = !(fppe_getValue(vars[3]));
ppe_user.ClearScreen = fppe_getValue(vars[4]);
PPLDateToSysCharDate(ppe_user.RegExpDate, fppe_getValue(vars[5]));
ppe_user.Security = fppe_getValue(vars[6]);
ppe_user.PageLen = fppe_getValue(vars[7]);
ppe_user.ExpSecurity = fppe_getValue(vars[8]);
makeSpaceString(ppe_user.City, fppe_Cstr(fppe_toStringVar(vars[9])->value), 24, 0);
makeSpaceString(ppe_user.DataPhone, fppe_Cstr(fppe_toStringVar(vars[10])->value), 13, 0);
makeSpaceString(ppe_user.VoicePhone, fppe_Cstr(fppe_toStringVar(vars[11])->value), 13, 0);
ppe_user.Protocol = *fppe_Cstr(fppe_toStringVar(vars[12])->value);
makeSpaceString(ppe_user.Comment1, fppe_Cstr(fppe_toStringVar(vars[13])->value), 30, 0);
makeSpaceString(ppe_user.Comment2, fppe_Cstr(fppe_toStringVar(vars[14])->value), 30, 0);
makeSpaceString(ppe_user.Password, fppe_Cstr(fppe_toStringVar(vars[15])->value), 12, 1);
ppe_user.ScrollMsgBody = fppe_getValue(vars[16]);
ppe_user.ShortMsgHdr = !(fppe_getValue(vars[17]));
ppe_user.WideEditor = fppe_getValue(vars[18]);

tpa = openTPA("UALIAS");
if (tpa != NULL)
    {
    strcpy(tmpStr2, fppe_Cstr(fppe_toStringVar(vars[19])->value));
	if ((*tmpStr2 != 0) ? addUserRecNr(tmpStr2, currentUserNum) : 1)
    	{
		getTPA(tpa, tmpStr2, 25, curConf, 0, currentUserNum);
    	reduceString(tmpStr2, 25);
	    strcpy(tmpStr, fppe_Cstr(fppe_toStringVar(vars[19])->value));
        if (strcmpi(tmpStr, tmpStr2))
        	{
			if (*tmpStr2 != 0) invalidUserRecNr(tmpStr2);
    		makeSpaceString(tmpStr, fppe_Cstr(fppe_toStringVar(vars[19])->value), 25, 0);
			putTPA(tpa, tmpStr, 25, curConf, 0, currentUserNum);
            }
        }
   	closeTPA(tpa);
    }
tpa = openTPA("UVERIF");
if (tpa != NULL)
	{
    makeSpaceString(tmpStr, fppe_Cstr(fppe_toStringVar(vars[20])->value), 25, 0);
	putTPA(tpa, tmpStr, 25, curConf, 0, currentUserNum);
    closeTPA(tpa);
    }
tpa = openTPA("UADDRESS");
if (tpa != NULL)
	{
    makeSpaceString(tmpStr, fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[21], fppe_intPplVar(0)))->value), 50, 0);
    makeSpaceString(&tmpStr[50], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[21], fppe_intPplVar(1)))->value), 50, 0);
    makeSpaceString(&tmpStr[100], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[21], fppe_intPplVar(2)))->value), 50, 0);
    makeSpaceString(&tmpStr[150], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[21], fppe_intPplVar(3)))->value), 50, 0);
    makeSpaceString(&tmpStr[200], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[21], fppe_intPplVar(4)))->value), 50, 0);
    makeSpaceString(&tmpStr[250], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[21], fppe_intPplVar(5)))->value), 50, 0);
    putTPA(tpa, tmpStr, 300, curConf, 0, currentUserNum);
    closeTPA(tpa);
    }
tpa = openTPA("UNOTES");
if (tpa != NULL)
	{
    makeSpaceString(tmpStr, fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[22], fppe_intPplVar(0)))->value), 50, 0);
    makeSpaceString(&tmpStr[50], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[22], fppe_intPplVar(1)))->value), 50, 0);
    makeSpaceString(&tmpStr[100], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[22], fppe_intPplVar(2)))->value), 50, 0);
    makeSpaceString(&tmpStr[150], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[22], fppe_intPplVar(3)))->value), 50, 0);
    makeSpaceString(&tmpStr[200], fppe_Cstr(fppe_toStringVar(fppe_copytable1var(vars[22], fppe_intPplVar(4)))->value), 50, 0);
    putTPA(tpa, tmpStr, 250, curConf, 0, currentUserNum);
    closeTPA(tpa);
    }

tpa = openTPA("UPWDEXP");
if (tpa != NULL)
	{
	PPLDateToCharDate(tmpStr, fppe_getValue(vars[23]), 0);
    tmpStr[8]=0;
    putTPA(tpa, tmpStr, 8, curConf, 0, currentUserNum);
	closeTPA(tpa);
    }

//if (userVars > 1)
	//strcpy(vars[24]->value, userAccount);

}

void fppe_extendString(pplvar *dest, int size)
{
int _maxAlloc;

if (!fppe_isStr(dest))
	return;

if (size > 255) size = 255; // check that we won't try to allocate more than 255b for a normal string
if (dest->type == 7)
	{
	_maxAlloc = *(unsigned char*)dest->value;
    if (size > _maxAlloc)
	    {
        dest->value = realloc(dest->value, size+2);
        if (dest->tableElement)
            *dest->tableElement = dest->value;
        *(unsigned char*)dest->value = size & 0xFF;
        }
    }
}

