/*

  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 - Debugger

ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
±±± DEBUGGER ±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ

*/

#include <stdio.h>
#include <io.h>
#include <dir.h>
#include <alloc.h>
#include <conio.h>
#include <string.h>
#include <bios.h>
#include "..\lang\ppl.h"
#include "..\lang\ppl_type.h"
#include "..\lang\debug.h"
#include "..\lang\vfs.h"
#include "..\lang\fortify.h"
#include "..\com\vio.h"
#include "..\com\system.h"
#include "..\lang\procs.h"

int swapType = 1;

typedef struct {
	unsigned long codeOffset;
    unsigned int line;
    } symType;

extern char far fullFilename[];
int far symbolPresent=0;
int far symCodeSize=0;
int far symCodePos=0;
symType far *symCode=NULL;
char far sourceFilename[MAXPATH];
char far *debugScr;
char far debugX, debugY, debugC;
char far *runScr;
char far runX, runY, runC;
int far globalQuitDebugger=0;
extern unsigned char far DEBUGSCR [];
FILE *source=NULL;
long far topOffset;
int far topLine=3;
int far botLine=17;
int far topWatch=19;
int far botWatch=24;
int far topWatchIndex=0;
int far curLine=0;
int far nextBreak=-1;
int far prevBreakLine=-1;
int far topSourceLine=0;
int far fullRun=0;
int far nLines=0;
int far topCol=0;
int far topColWatch=0;
static FILE far *readlineLast;
int far traceOver=0;
int far breakPoint[128];
char far *watch[128];
int far watchCur=0;
char far lastWatchEntry[40]="";
int far curWindow=0;
int far largest=0;
int far noMsg=0;
int far quitLoop=0;
int far running=0;
int far debuggerEnabled=0;
pplvar tableVar = {0, NULL, 0, 0, 0, 0, 0};
extern int far ppMode;
extern char prcFile[256];
extern char ppSource[256];

//---------------------------------------------------------------------------

void debuggerLoadSymbols(vfs_file *ppe, long offset)
{
long n;
int a;
unsigned char c;
long pos;

if (imbrication != 0)
	return;

pos = vfs_ftell(ppe);
vfs_fseek(ppe, offset, SEEK_SET);
vfs_fread(&n, 4, 1, ppe);

if (vfs_feof(ppe))
	{
    n = curColor;
    messagebox("PPE has no symbol table", "Warning");
    bioskey(0);
	symbolPresent=0;
    globalQuitDebugger=1;
	vfs_fseek(ppe, pos, SEEK_SET);
    color(n);
    VIOgotoxy(0, 0);
    return;
    }
else
	symbolPresent=1;

symCodeSize = n;
symCode = (symType *)calloc(symCodeSize, sizeof(symType));
symCodePos = 0;

for (a=0;a<n;a++)
	{
    vfs_fread(&symCode[a].codeOffset, 2, 1, ppe);
	vfs_fread(&symCode[a].line, 2, 1, ppe);
    }
symCodePos = a;
for (a=0;a<totalPPLVars;a++)
	{
    c = vfs_fgetc(ppe);
    if (c != 0)
    	{
	    vars[totalPPLVars-a]->name = (char *)calloc(c+1,1);
	    vfs_fread(vars[totalPPLVars-a]->name, c, 1, ppe);
	    if (vars[totalPPLVars-a]->type == 0x0F || vars[totalPPLVars-a]->type == 0x10)
    		vfs_fread(&vars[totalPPLVars-a]->identHdr, 2, 1, ppe);
        }
    else
    	vars[totalPPLVars-a]->name = NULL;
    }

c = vfs_fgetc(ppe);
vfs_fread(&sourceFilename, c, 1, ppe);
if (*ppSource != 0)
	strcpy(sourceFilename, ppSource);
vfs_fseek(ppe, pos, SEEK_SET);

if (!ppMode)
	{
	runToDebugScreen();
	debuggerMain();
	debugToRunScreen();
    }
}

//---------------------------------------------------------------------------

void debuggerInit(void)
{
int c,a;
FILE *prc;

runScr = (char *)calloc(4000, 1);
debugScr = (char *)calloc(4000, 1);
gettext(1, 1, 80, 25, runScr);
runX = VIOwherex()+1;
runY = VIOwherey()+1;
runC = curColor;
memset(&breakPoint, 0, 256);
memset(&watch, 0, 128*sizeof(char*));
debuggerEnabled=1;

if (!access(prcFile,0))
	{
    if ((prc = fopen(prcFile, "r+b")) != NULL)
    	{
        fseek(prc, 835, SEEK_SET);
        fgetc(prc);
        if (!feof(prc))
        	{
            fseek(prc, -1, SEEK_CUR);
            for (a=0;a<128;a++)
        	    fread(&breakPoint[a], 2, 1, prc);
            fgetc(prc);
            if (!feof(prc))
            	{
	            fseek(prc, -1, SEEK_CUR);
                for (a=0;a<128;a++)
        	        {
                    c = fgetc(prc);
                    if (c > 0)
            	        {
	                    watch[a] = (char *)calloc(c+1,1);
    	                fread(watch[a], c, 1, prc);
            	        }
			        }
                }
	    	fclose(prc);
        	}
        }
    else
    	ppl_S_BEEP();
    }
}

//---------------------------------------------------------------------------

void debuggerReset(void)
{
int n;
FILE *prc;
int a;

debugToRunScreen();

free(runScr);
free(debugScr);

if (!access(prcFile,0))
	{
    if ((prc = fopen(prcFile, "r+b")) != NULL)
    	{
        fseek(prc, 835, SEEK_SET);
        for (a=0;a<128;a++)
        	fwrite(&breakPoint[a], 2, 1, prc);
        for (a=0;a<128;a++)
        	{
            if (watch[a] != NULL)
            	{
	            fputc(strlen(watch[a]), prc);
    	        fwrite(watch[a], strlen(watch[a]), 1, prc);
            	}
            else
	            fputc(0, prc);
			}
    	fclose(prc);
        }
    }

for(n=0;n<128;n++)
	if (watch[n] != NULL) free(watch[n]);
}

//---------------------------------------------------------------------------

void debuggerStep(void)
{
int n;
int l;

running=1;
if (imbrication != 0 || !symbolPresent)
	return;

l = debuggerOffsetToLine(curOffset);
if (l == -2) return;
if (!debuggerIsBreakPoint(l))
	{
	if (fullRun)
		return;

	if (nextBreak != -1 && curOffset != nextBreak)
		return;
    }

curLine = l;

if (curLine == prevBreakLine && nextBreak == -1 && fullRun == 0)
	return;

prevBreakLine = curLine;

runToDebugScreen();

debuggerMain();

debugToRunScreen();
}

void runToDebugScreen(void)
{
gettext(1, 1, 80, 25, runScr);
runX = VIOwherex();
runY = VIOwherey();
runC = curColor;

puttext(1, 1, 80, 25, debugScr);
updateCursor();
color(debugC);
}

void debugToRunScreen(void)
{
gettext(1, 1, 80, 25, debugScr);
debugC = curColor;

puttext(1, 1, 80, 25, runScr);
VIOgotoxy(runX, runY);
color(runC);
}

//---------------------------------------------------------------------------

void debuggerRun(void)
{
debuggerInitScreen();
gettext(1, 1, 80, 25, debugScr);
debugToRunScreen();
noMsg=0;
kbdFlush();
if (fppe_runPPE(fullFilename) != 0)
	{
    color(0x07);
    VIOgotoxy_blind(0, 24);
    for (int a=0;a<80;a++)
        puts_blind(" ");
	exit(1);
    }

if (symCode != NULL)
	{
	free(symCode);
    symCode = NULL;
    }
}

void debuggerInitScreen(void)
{
puttext(1, 1, 80, 25, DEBUGSCR);
debugX = 1;
debugY = topLine-1;
updateCursor();
}

void updateFileViewer(int keepFocus)
{
int n,l;
char line[256];
char *p;
int quit=0;
char drive[MAXDRIVE];
char dir[MAXDIR];
char file[MAXFILE];
char ext[MAXEXT];

if (source == NULL)
	{
    source = fopen(sourceFilename, "rt");
    if (source == NULL)
    	{
		fnsplit(fullFilename, drive, dir, NULL, NULL);
		fnsplit(sourceFilename, NULL, NULL, file, ext);
		fnmerge(sourceFilename, drive, dir, file, ext);
	    source = fopen(sourceFilename, "rt");
        if (source == NULL)
    	    {
			fnsplit(fullFilename, drive, dir, file, NULL);
			fnmerge(sourceFilename, drive, dir, file, ".PPS");
		    source = fopen(sourceFilename, "rt");
            if (source == NULL)
    	        {
                messagebox("Source file not found!", "Warning");
                bioskey(0);
    	        fullRun=1;
                quitLoop=1;
                globalQuitDebugger=1;
                return;
                }
            }
    	}
    n=0;
    while (!quit)
    	{
        debugReadline(line, 255, ++n, source);
        if (feof(source))
        	quit = 1;
        }
    nLines = n;
    }

if (keepFocus)
	if (topSourceLine > curLine || topSourceLine + (botLine-topLine) < curLine || topSourceLine == 0)
		topSourceLine = curLine - (int)((botLine-topLine) / 2);

if (topSourceLine < 1)
   	topSourceLine = 1;

fseek(source, topOffset, SEEK_SET);
for (n = topLine, l=topSourceLine; n<botLine+1;n++,l++)
	{
    *line=0;
    if (l == curLine && running)
    	{ VIOsetback(3); VIOsetfore(0x0); }
    else
    	{
       	if (debuggerIsBreakPoint(l))
        	{
			VIOsetback(4);
			VIOsetfore(0xF);
            }
		else
        	{
			VIOsetback(1);
			VIOsetfore(0xE);
            }
		}
	debugReadline(line, 255, l, source);
//        p = &line[strlen(line)-1];
//        if (*p == '\n') *p = 0;
	VIOgotoxy_blind(1, n-1);
    line[topCol+78]=0;
    if (strlen(line) > topCol)
	    puts_blindn(&line[topCol], 78);
    while (!(VIOwherex() == 79))
    	puts_blind(" ");
    }

if (keepFocus && running)
	{
	debugY = curLine-topSourceLine+topLine-1;
	updateCursor();
    }

}

void printstr(int left, int top, char str[], int maxlen, int curs)
{
char str3[80];

color(0x71);
VIOgotoxy_blind(left, top);
memset(str3,'°',maxlen+1-strlen(str));
str3[maxlen+1-strlen(str)] =0;
puts_blind(str);
puts_blind(str3);
VIOgotoxy(left+curs, top);
}

int editfield(int left, int top, char str[], int maxlen)
{
char str2[80];
char str3[80];
int c,functionkey;
int len,curs,delall,codeok;

strcpy(str2,str);
curs = strlen(str);
printstr(left,top,str,maxlen,curs);

delall = 1;
len = strlen(str);

for(;;)
	{
	c = 0;
	if (bioskey(1))
		{
		c = getch();
		if (c == 0)
			{
			functionkey = 1;
			c = getch();
			}
		else functionkey = 0;
		if (c == '')
			{
			codeok = 1;
			c = getch();
			}
		else	codeok = 0;
		}
	if (c == 0) continue;

	if ((((c >=32) && !functionkey) || codeok) && (c != '\b') && (c != 13))
		{
		if (delall)
			{
			strcpy(str,"");
			len = 0;
			curs = 0;
			}
		if (len < maxlen)
			{
			if ((curs == len) && (curs > 0))
				{
				str[len] = c;
				str[len+1] = 0;
				}
			if (curs == 0)
				{
				strcpy(str3,str);
				strcpy(&str[1],str3);
				str[0] = c;
				}
			if ((curs > 0) && (curs < len))
				{
				strcpy(str3, &str[curs]);
				strcpy(&str[curs+1],str3);
				str[curs] = c;
				}
			len++;
			curs++;
			printstr(left,top,str,maxlen,curs);
			}
		}
	delall = 0;
	if ((c == 'K') && functionkey)
		{
		if (curs > 0) curs--;
		VIOgotoxy(left+curs,top);
		}

	if ((c == 'M') && functionkey)
		{
		if (curs < len) curs++;
		VIOgotoxy(left+curs,top);
		}

	if ((c == '\b') && !codeok)
		{
		if ((len > 0) && (curs > 0))

			{
			if (curs == len)
				str[len-1]=0;
			if (curs < len)
				strcpy(&str[curs-1],&str[curs]);
			len--;
			curs--;
			printstr(left,top,str,maxlen,curs);
			}
		}
	if ((c == 'S') && functionkey)
		{
		if (curs < len)
			{
			strcpy(&str[curs],&str[curs+1]);
			len--;
			printstr(left,top,str,maxlen,curs);
			}
		}

	if ((c == 'G') && functionkey)
		{
		curs = 0;
		printstr(left,top,str,maxlen,curs);
		}
	if ((c == 'O') && functionkey)
		{
		curs = len;
		printstr(left,top,str,maxlen,curs);
		}
	if ((c == 13) && !codeok)
		{
        color(0x1F);
		VIOgotoxy_blind(left,top);
		memset(str3,'Í',maxlen+1);
		str3[maxlen+1] =0;
		puts_blind(str3);
		return 0;
		}
	if ((c == 27) && !codeok)
		{
		strcpy(str,str2);
        color(0x1F);
		VIOgotoxy_blind(left,top);
		memset(str3,'Í',maxlen+1);
		str3[maxlen+1] =0;
		puts_blind(str3);
		return 1;
		}
	}
}

void debuggerMain(void)
{
int a,b;
unsigned int c;

quitLoop=0;

updateFileViewer(1);
updateWatches();

while (!quitLoop)
	{
    while (!bioskey(1));
	c = bioskey(0);

	if ((c & 0xFF) == 0)
		switch ((c & 0xFF00) >> 8)
			{
            case 'u':
        	    //CTRL END
                if (!curWindow)
                	debugY = botLine-1;
                else
                	{
                    if (watch[topWatchIndex + (botWatch-topWatch)-1] != 0)
                    	watchCur = (botWatch-topWatch)-1;
                    else
                    	while (watch[topWatchIndex + watchCur + 1] != 0)
                            watchCur++;
                 	updateWatches();
                    }
                updateCursor();
                break;
            case 'w':
        	    //CTRL HOME
                if (!curWindow)
                	debugY = topLine-1;
                else
                	{
                    watchCur=0;
                 	updateWatches();
                    }
                updateCursor();
                break;
            case 132:
        	    //CTRL PGUP
                if (!curWindow)
                	{
					debugY = topLine-1;
                    topSourceLine = 1;
					updateFileViewer(0);
                    }
                else
                	{
                    watchCur=0;
                    topWatchIndex=0;
                 	updateWatches();
                    }
                updateCursor();
                break;
            case 'v':
        	    //CTRL PGDN
                if (!curWindow)
                	{
                    if (nLines < (botLine-topLine))
                    	{
                        debugY = topLine + nLines - 1;
                        topSourceLine=1;
                        }
                    else
                    	{
				        debugY = botLine-1;
                        topSourceLine = nLines - (botLine-topLine);
                        }
			        updateFileViewer(0);
                    }
                else
                	{
                    for(a=0;a<127;a++)
                    	if (watch[a] == 0)
                        	break;
                    if (a < (botWatch-topWatch))
                       	{
                        watchCur=a-1;
                        topWatchIndex=0;
                        }
                    else
                      	{
	                    topWatchIndex = a - (botWatch-topWatch);
    	                watchCur = (botWatch-topWatch)-1;
                        }
                    updateWatches();
                    }
				updateCursor();
                break;
            case 'H':
        	    //UP
                if (!curWindow)
                    {
					if (debugY >= topLine)
					    debugY--;
                    else
			            if (topSourceLine > 1)
		    		        {
						    topSourceLine--;
						    updateFileViewer(0);
		        	        }
                    }
                else
                	{
                    forceUpWatch:
                	if (watchCur > 0)
                    	watchCur--;
                    else
                    	if (topWatchIndex > 0)
							topWatchIndex--;
                    updateWatches();
                    }
				    updateCursor();
                break;
            case 'P':
        	    //DOWN
                if (!curWindow)
                    {
					if (debugY < botLine-1)
					    debugY++;
                    else
			            if (topSourceLine +1 <= nLines - (botLine-topLine))
		    		        {
						    topSourceLine++;
						    updateFileViewer(0);
		        	        }
                    }
                else
                	{
                    if (watch[watchCur+topWatchIndex+1] != 0)
                        {
						if (watchCur < botWatch-topWatch-1)
                       	    watchCur++;
                        else
                      	    topWatchIndex++;
	                    updateWatches();
                        }
                    }
				updateCursor();
                break;
	        case 'M':
    	    	//RIGHT
                if (!curWindow)
                	{
                    if (debugX < 78)
					    debugX++;
                    else
	                    {
					    if (topCol < 255-78)
    	            	    topCol++;
					    updateFileViewer(0);
                        }
					updateCursor();
                    }
                else
                	{
                    if (topColWatch < 255-78)
                    	topColWatch++;
                    updateWatches();
                    }
        	    break;
	        case 'K':
    	    	//LEFT
                if (!curWindow)
                	{
                    if (debugX > 1)
					    debugX--;
                    else
                	    {
	                    if (topCol > 0)
    	            	    topCol--;
					    updateFileViewer(0);
                        }
					updateCursor();
                    }
                else
                	{
                    if (topColWatch > 0)
                    	topColWatch--;
                    updateWatches();
                    }
        	    break;
            case 'G':
        	    //HOME
                if (!curWindow)
                	{
	                debugX=1;
    	            topCol=0;
					updateCursor();
					updateFileViewer(0);
                    }
                else
                	{
                    topColWatch = 0;
                    updateWatches();
                    }
                break;
            case 'O':
        	    //END
                if (!curWindow)
                	{
                    *tmpStr=0;
				    debugReadline(tmpStr, 255, debugY-topLine+topSourceLine+1, source);
                    a = strlen(tmpStr);
                    if (a > 78)
                    	{
						debugX = 78;
                    	topCol = a - 77;
                        }
                    else
                    	debugX = a+1;
					updateCursor();
					updateFileViewer(0);
                    }
                else
                	{
                    updateWatches();
                    topColWatch = largest - 77;
                    if (topColWatch < 0) topColWatch = 0;
                    updateWatches();
                    }
                break;
            case 'I':
        	    //PGUP
                if (!curWindow)
                	{
		            if (topSourceLine - (botLine-topLine) > 1)
			            topSourceLine = topSourceLine - (botLine-topLine);
                    else
                    	if (topSourceLine == 1)
                        	debugY = topLine-1;
                        else
	        	            topSourceLine = 1;
		            updateFileViewer(0);
                    }
                else
                	{
                    if (topWatchIndex - (botWatch-topWatch) > 1)
			            topWatchIndex = topWatchIndex - (botWatch-topWatch)+1;
                    else
                    	if (topWatchIndex == 0)
                        	watchCur=0;
                        else
	                    	topWatchIndex = 0;
                    updateWatches();
                    }
                updateCursor();
                break;
            case 'Q':
        	    //PGDN
                if (!curWindow)
                	{
			        if (topSourceLine + (botLine-topLine) < nLines - (botLine - topLine))
						topSourceLine = topSourceLine + (botLine-topLine);
        	        else
                    	if (topSourceLine == nLines - (botLine-topLine))
                        	debugY = botLine-1;
                        else
	            	    	topSourceLine = nLines - (botLine-topLine);
					updateFileViewer(0);
                    }
                else
                	{
                    if (watch[topWatchIndex + (botWatch-topWatch)*2 - 1] != 0)
						topWatchIndex = topWatchIndex + (botWatch-topWatch-1);
                    else
                    	{
                        a=0;
                    	while (watch[topWatchIndex + (botWatch-topWatch)] != 0)
                        	{
                            a++;
                            topWatchIndex++;
                            }
                        if (a==0)
	                    	while (watch[topWatchIndex + watchCur + 1] != 0)
    	                    	watchCur++;
                        }
                    updateWatches();
                    }
                updateCursor();
                break;
            case 'A':
        	    //F7
		        nextBreak=-1;
                traceOver=0;
                fullRun=0;
		    	quitLoop = 1;
                break;
            case 'B':
        	    //F8
                traceOver=1;
                nextBreak=-1;
                fullRun=0;
                quitLoop=1;
                break;
            case 'D':
        	    //F10
                break;
            case 108:
        	    //ALT-F5
		        debugToRunScreen();
		        bioskey(0);
		        runToDebugScreen();
                break;
            case 95:
        	    //CTRL-F2
			    *(int*)((script->data)+curOffset+ codestart) = 1;
                quitLoop=1;
                noMsg=1;
                break;
            case 97:
        	    //CTRL-F4

                break;
            case 101:
        	    //CTRL-F8
                a = topSourceLine + debugY - 2;
                if (debuggerIsBreakPoint(a))
                	debuggerRemoveBreakPoint(a);
                else
                	{
                    if (debuggerLineToOffset(a) == -1)
                	    {
					    messagebox("Line does not contain any code!", "Error");
                        break;
                        }
                	debuggerAddBreakPoint(a);
                    }
                updateFileViewer(0);
                break;
            case 102:
            case 67:
        	    //CTRL-F9
				fullRun=1;
                traceOver=0;
		        quitLoop=1;
                break;
            case 82:
        	    //INS
                if (!editfield(12, topWatch-2, lastWatchEntry, 35))
                	{
				    updateCursor();
                    if (*lastWatchEntry != 0)
					    {
					    debuggerAddWatch(lastWatchEntry);
    	                updateWatches();
                        }
				    updateCursor();
                    }
                break;
            case 83:
        	    //DEL
                if (watch[topWatchIndex + watchCur] != 0)
                    {
                    debuggerRemoveWatch(topWatchIndex + watchCur);
                    for (a=topWatchIndex+ watchCur;a<126;a++)
                        watch[a] = watch[a+1];
                    if (watch[topWatchIndex + watchCur] == 0) goto forceUpWatch;
  	                updateWatches();
				    updateCursor();
                    }
                break;
            case 45:
            	globalQuitDebugger=1;
			    *(int*)((script->data)+curOffset+ codestart) = 1;
                quitLoop=1;
                noMsg=1;
                break;
            case 120:
            	curWindow = 0;
                updateCursor();
                break;
            case 121:
            	curWindow = !0;
                updateCursor();
                break;
            case 62:
            	//F4
                a = topSourceLine + debugY - 2;
                if (debuggerLineToOffset(a) == -1)
                	{
					messagebox("Line does not contain any code!", "Error");
                    break;
                    }
                nextBreak = debuggerLineToOffset(a);
                traceOver=0;
                fullRun=0;
		    	quitLoop = 1;
                break;
            }
    else
    	switch (c & 0xFF)
        	{
            case 9:
            	curWindow = !curWindow;
                updateCursor();
                break;
            case 14:
            	if (!running) break;
            	a = debuggerLineToOffset(topSourceLine+debugY-topLine+1);
                if (a != -1)
                	{
    	    	    vfs_fseek(script, codestart + a, SEEK_SET);
                    curOffset = a;
                    curLine = topSourceLine+debugY-topLine+1;
					prevBreakLine = curLine;
                    updateFileViewer(1);
                    }
                break;
            }
    }
}

void updateCursor(void)
{
if (!curWindow)
    VIOgotoxy(debugX, debugY);
else
	VIOgotoxy(2, watchCur+topWatch-1);
}

void debugReadline(char *buffer, int size, int line, FILE *file)
{
int n,l;
static long lastOff;
static int lastLine=0;
char c;
int b, exit;
char *str;

str = (char*)calloc(256,1);
if (file != readlineLast || readlineLast == NULL)
	{
    readlineLast = file;
	lastOff=0;
    }

if (lastLine >= line)
    lastLine = 0;

if (lastLine == 0)
	lastOff = 0;

fseek(file, lastOff, SEEK_SET);

/*if (lastLine >= line)
	{
	fseek(fileHandle[0], -1, SEEK_CUR);
	while (lastLine >= line)
		{
		fseek(fileHandle[0], -1, SEEK_CUR);
        fread(&c, 1, 1, fileHandle[0]);
		if (c == '\n')
			{
			lastLine--;
			fseek(fileHandle[0], -1, SEEK_CUR);
			}
		fseek(fileHandle[0], -1, SEEK_CUR);
		}
	fseek(fileHandle[0], 2, SEEK_CUR);
	}*/

l = line - lastLine;

for (n=0;n<l;n++)
	{
    if (feof(file))
    	break;
	fgets(str, size, file);
	if (str[strlen(str)-1] != '\n')
		{
	    strcpy(tmpStr, str);
    	while (tmpStr[strlen(tmpStr)-1] != '\n' && !feof(file))
			fgets(tmpStr, size, file);
		}
    }

b = strlen(str);
if (str[b-1] == '\n' && b > 0)
   	str[b-1] = 0;
if (str[b-2] == '\r' && b > 1)
   	str[b-2] = 0;

lastLine = line;
lastOff = ftell(file);
strcpy(buffer, str);
free(str);
}

void debuggerEndSession(void)
{
if (imbrication != 0 || !symbolPresent)
	return;
if (!globalQuitDebugger) runToDebugScreen();
if (!noMsg && !globalQuitDebugger && !ppMode) messagebox("PPE execution terminated.", "END");
fclose(source);
source=NULL;
fullRun=0;
readlineLast=NULL;
nextBreak=-1;
prevBreakLine=-1;
running=0;
}

int debuggerOffsetToLine(unsigned int offset)
{
int n;
for (n=0;n<symCodePos;n++)
	if (symCode[n].codeOffset == offset)
    	return symCode[n].line;
return -2;
}

int debuggerLineToOffset(unsigned int line)
{
int n;
for (n=0;n<symCodePos;n++)
	if (symCode[n].line == line)
    	return symCode[n].codeOffset;
return -1;
}

void debuggerAddBreakPoint(int line)
{
int n;
for (n=0;n<128;n++)
	if (breakPoint[n] == 0)
    	{ breakPoint[n] = line; break; }
}

void debuggerRemoveBreakPoint(int line)
{
int n;
for (n=0;n<128;n++)
	if (breakPoint[n] == line)
    	{ breakPoint[n] = 0; break; }
}

int debuggerIsBreakPoint(int line)
{
int n;
for (n=0;n<128;n++)
	if (breakPoint[n] == line)
    	return 1;
return 0;
}

void debuggerRemoveWatch(int n)
{
free(watch[n]);
watch[n]=NULL;
}

void updateWatches(void)
{
int n,o,l,d1,d2,d3;
char line[256];
int var;
char **ptr;
long b;
int first;

largest=0;
for (n=topWatch, l=topWatchIndex;n<botWatch;n++,l++)
	{
    *line=0;

	memset(&tmpStr, 0, 255);
    if (identHdr != 0) // local var ?
       	{
        *tmpStr = 1;
        tmpStr[1] = identHdr;
        strncat(&tmpStr[2], watch[l], 255);
        }

    if (watch[l] != NULL)
		{
        sprintf(line, " %s: ", watch[l]);

        var=-1;
		for (o=1;o<globalNVars;o++)
		    if (globalVars[o]->name != NULL)
            	{
				if (!strcmpi(watch[l], globalVars[o]->name) || (!strcmpi(tmpStr, globalVars[o]->name) && tmpStr[0] != 0))
					{
					var = o;
	    	    	break;
	        		}
                }

        if (var != -1)
        	{
            if (globalVars[var]->nDim != 0)
            	{
                first=1;
                tableVar.type = globalVars[var]->type;
                for (d1=0;d1<=globalVars[var]->dim[0];d1++)
                	for (d2=0;d2<=globalVars[var]->dim[1];d2++)
                    	for (d3=0;d3<=globalVars[var]->dim[2];d3++)
                            {
                            switch (globalVars[var]->nDim)
                                {
                                case 1:
                                    b = fppe_table1dec(globalVars[var], d1);
                                    break;
                                case 2:
                                    b = fppe_table2dec(globalVars[var], d1, d2);
                                    break;
                                case 3:
                                    b = fppe_table3dec(globalVars[var], d1, d2, d3);
                                    break;
                                }
                            if (fppe_isStr(globalVars[var]))
	                            {
                                ptr = (char **)globalVars[var]->value;
	                            tableVar.value = ptr[b];
	                            tableVar.tableElement = (char**)&ptr[b];
                                }
                            else
	                            {
	                            tableVar.value = (char *)(globalVars[var]->value)+b;
                                tableVar.tableElement = (char**)-1;
                                }
                            if (!first)
					    		strncat(line, ",", 254-strlen(line));
                            else
    	                        first = 0;
                            if (fppe_isStr(&tableVar))
                            	{
			        		    strncat(line, "\"", 255-strlen(line));
					    		strncat(line, fppe_Cstr((char*)tableVar.value), 254-strlen(line));
	        			    	strncat(line, "\"", 255-strlen(line));
                                }
                            else
                            	{
					        	fppe_ToString(tmpS, &tableVar);
					    		strncat(line, tmpS, 255-strlen(line));
                                }
                            }
                }
            else
		        if (fppe_isStr(globalVars[var]))
    			    {
        		    strncat(line, "\"", 255-strlen(line));
		    		strncat(line, fppe_Cstr((char*)globalVars[var]->value), 254-strlen(line));
	            	strncat(line, "\"", 255-strlen(line));
	    	        }
    	    	else
    		    	{
	        	    fppe_ToString(tmpS, globalVars[var]);
	    		    strncat(line, tmpS, 255-strlen(line));
    	    	    }
            }
        else
   		    {
			strncat(line, "Undefined symbol '", 255-strlen(line));
			strncat(line, watch[l], 255-strlen(line));
			strncat(line, "'", 255-strlen(line));
            }
         }

    if (strlen(line) > largest) largest = strlen(line);
    line[255]=0;
	VIOgotoxy_blind(1, n-1);
    if (watchCur == n-topWatch && watch[l] != 0)
    	{
		VIOsetback(7);
		VIOsetfore(1);
    	}
    else
    	{
		VIOsetback(1);
		VIOsetfore(0xE);
        }
    line[topColWatch+77]=0;
    if (strlen(line) > topColWatch)
	    puts_blind(&line[topColWatch]);
    while (!(VIOwherex() == 79))
    	puts_blind(" ");
	}
}

void debuggerAddWatch(char *name)
{
int n;

for (n=0;n<128;n++)
	if (watch[n] == NULL)
    	{
		watch[n] = (char *)(malloc(strlen(name)+1));
        strcpy(watch[n], name);
        break;
        }
}

//--------------------------------------------Message Box---------------------
void messagebox(char *msg, char *title)
{
int i;
char *buf1;
char k;

i = strlen(msg);

buf1 = (char *)malloc(((((76-i)/2)+i+4)-(76-i)/2)*2*(13-10+2));
gettext((76-i)/2,9,((76-i)/2)+i+4,12,buf1);
openbox((76-i)/2,9,((76-i)/2)+i+3,11,title);
color(0x70);
VIOgotoxy_blind((76-i)/2+2,10);
puts_blind(msg);
while(!bioskey(1));
puttext((76-i)/2,9,((76-i)/2)+i+4,12,buf1);
free(buf1);
}

//----------------------------------------------------------------------------
//

void openbox(int left, int top, int right, int bot, char titre[])
{
int a;

char str[162];
char c[2],i;

color(0x7F);
memset(str,'Í',right-left-3);
str[right-left-3] = 0;
VIOgotoxy_blind(left,top);
puts_blind("É");
puts_blind("Í");
puts_blind(str); // ÙÚ  ¿ À  Ä
puts_blind("Í");
puts_blind("»");

memset(str,' ',right-left-1);
str[right-left-1] = 0;
for(i=top+1,a=0;i<bot;i++,a++)
	{
	VIOgotoxy_blind(left,i);
	puts_blind("º");
	puts_blind(str);
	puts_blind("º");
	gettext(right+1,i,right+1,i,c);
	}
memset(str,'Í',right-left-3);
str[right-left-3]=0;
VIOgotoxy_blind(left,bot);
puts_blind("È");
puts_blind("Í");
puts_blind(str); // ÙÚ  ¿ À  Ä
puts_blind("Í");
puts_blind("¼");

color(0x70);
VIOgotoxy_blind(right-strlen(titre)-4,top);
puts_blind(" þ ");
puts_blind(titre);
puts_blind(" ");
}
