/*
 *   rpl.c
 *
 *   This file is part of Emu48
 *
 *   Copyright (C) 1995 Sebastien Carlier
 *
 */
#include "pch.h"
#include "Emu48.h"


//|  SX  |  GX  | Name
//#7056A #806E9 =TEMPOB
//#7056F #806EE =TEMPTOP
//#70574 #806F3 =RSKTOP   (B)
//#70579 #806F8 =DSKTOP   (D1)
//#7066E #807ED =AVMEM    (D)
//#705B0 #8072F =INTRPPTR (D0)

#define TEMPOB   ((cCurrentRomType=='S')?0x7056A:0x806E9)
#define TEMPTOP  ((cCurrentRomType=='S')?0x7056F:0x806EE)
#define RSKTOP   ((cCurrentRomType=='S')?0x70574:0x806F3)
#define DSKTOP   ((cCurrentRomType=='S')?0x70579:0x806F8)
#define AVMEM    ((cCurrentRomType=='S')?0x7066E:0x807ED)
#define INTRPPTR ((cCurrentRomType=='S')?0x705B0:0x8072F)

DWORD RPL_SkipOb(DWORD d)
{
	BYTE X[8];
	DWORD n, l;
	
	Npeek(X,d,5);
	n = Npack(X, 5); // read prolog
	switch (n)
	{
	case 0x02911: l= 10; break; // System Binary
	case 0x02933: l= 21; break; // Real
	case 0x02955: l= 26; break; // Long Real
	case 0x02977: l= 37; break; // Complex
	case 0x0299D: l= 47; break; // Long Complex
	case 0x029BF: l=  7; break; // Character
	case 0x02BAA: l= 15; break; // Extended Pointer
	case 0x02E92: l= 11; break; // XLIB Name
	case 0x02A74: // List
	case 0x02AB8: // Algebraic
	case 0x02ADA: // Unit
	case 0x02D9D: // Program
		n=d+5;
		do
		{
			d=n; n=RPL_SkipOb(d);
		} while (d!=n);
		return n+5;
	case 0x0312B: return d; // SEMI
	case 0x02E48: // Global Name
	case 0x02E6D: // Local Name
	case 0x02AFC: // Tagged
		Npeek(X,d+5,2); n = 7 + Npack(X,2)*2;
		return RPL_SkipOb(d+n);
	case 0x02A96: // Directory
		d+=8;
		n = Read5(d);
		if (n==0)
		{
			return d+5;
		}
		else
		{
			d+=n;
			Npeek(X,d,2);
			n = Npack(X,2)*2 + 4;
			return RPL_SkipOb(d+n);
		}
	case 0x029E8: // Array
	case 0x02A0A: // Linked Array
	case 0x02A2C: // String
	case 0x02A4E: // Binary Integer
	case 0x02B1E: // Graphic
	case 0x02B40: // Library
	case 0x02B62: // Backup
	case 0x02B88: // Library Data
	case 0x02BCC: // Reserved 1
	case 0x02BEE: // Reserved 2
	case 0x02C10: // Reserved 3
	case 0x02DCC: // Code
		l = 5+Read5(d+5);
		break;
	default: return d+5;
	}
	return d+l;
}

DWORD RPL_ObjectSize(BYTE *o)
{
	DWORD n, l = 0;
	
	n = Npack(o, 5); // read prolog
	switch (n)
	{
	case 0x02911: l= 10; break; // System Binary
	case 0x02933: l= 21; break; // Real
	case 0x02955: l= 26; break; // Long Real
	case 0x02977: l= 37; break; // Complex
	case 0x0299D: l= 47; break; // Long Complex
	case 0x029BF: l=  7; break; // Character
	case 0x02BAA: l= 15; break; // Extended Pointer
	case 0x02E92: l= 11; break; // XLIB Name
	case 0x02A74: // List
	case 0x02AB8: // Algebraic
	case 0x02ADA: // Unit
	case 0x02D9D: // Program
		n=5;
		do { l+=n; o+=n; n=RPL_ObjectSize(o); } while (n);
		l += 5;
		break;
	case 0x0312B: l=  0; break; // SEMI
	case 0x02E48: // Global Name
	case 0x02E6D: // Local Name
	case 0x02AFC: // Tagged
		n = 7 + Npack(o+5,2)*2;
		l = n + RPL_ObjectSize(o+n);
		break;
	case 0x02A96: // Directory
		n = Npack(o+8,5);
		if (n==0) // empty dir
		{
			l=13;
		}
		else
		{
			l = 8+n;
			n = Npack(o+l,2)*2 + 4;
			l += n;
			l += RPL_ObjectSize(o+l);
		}
		break;
	case 0x029E8: // Array
	case 0x02A0A: // Linked Array
	case 0x02A2C: // String
	case 0x02A4E: // Binary Integer
	case 0x02B1E: // Graphic
	case 0x02B40: // Library
	case 0x02B62: // Backup
	case 0x02B88: // Library Data
	case 0x02BCC: // Reserved 1
	case 0x02BEE: // Reserved 2
	case 0x02C10: // Reserved 3
	case 0x02DCC: // Code
		l = 5 + Npack(o+5,5);
		break;
	default: l=5;
	}
	return l;
}

DWORD RPL_CreateTemp(DWORD l)
{
	DWORD a, b, c;
	BYTE *p;
	
	l += 6;
	a = Read5(TEMPTOP);
	b = Read5(RSKTOP);     // start of available mem
	c = Read5(DSKTOP);     // end of available mem
	if ((b+l)>c) return 0; // check if there is enough memory
	Write5(TEMPTOP, a+l);  // adjust end of temporary objects
	Write5(RSKTOP,  b+l);  // adjust start of available mem
	Write5(AVMEM, (c-(b+l))/5); // free memory (*5 nibbles)
	p = (BYTE*)LocalAlloc(0,b-a);
	Npeek(p,a,b-a);
	Nwrite(p,a+l,b-a);
	LocalFree(p);
	Write5(a+l-5,l); // set temporary object length field
	return (a+1);    // return temporary object address
}

DWORD RPL_Pick(UINT l)
{
	DWORD stkp;
	
	if (l==0) return 0;
	stkp = Read5(DSKTOP) + (l-1)*5;
	return Read5(stkp);
}

VOID RPL_Replace(DWORD n)
{
	DWORD stkp;
	
	stkp = Read5(DSKTOP);
	Write5(stkp,n);
	return;
}

VOID RPL_Push(DWORD n)
{
	DWORD stkp, avmem;
	
	avmem = Read5(AVMEM);
	if (avmem==0) return;
	avmem--;
	Write5(AVMEM,avmem);
	stkp = Read5(DSKTOP);
	stkp-=5;
	Write5(stkp,n);
	Write5(DSKTOP,stkp);
	return;
}
