[comp.os.minix] playing infocom adventures with minix -- zmachine part 1/2

leo@marco.UUCP (Matthias Pfaller) (03/13/90)

Do you like infocom adventures? This is an interpreter for infocom interactive
fiction games (NOT interactive fiction plus). So it should be possible to
play most of infocom's games with minix. I have tried this interpreter only
with the games I own (starcross, deadline and suspended). If the interpreter
fails with a game, please send me a bug report.

	leo@marco.uucp
# ----------------------- cut -----------------------
echo x - zmachine.doc
sed '/^X/s///' > zmachine.doc << '/'
XWith zmachine you can play Interactive Fiction games of Infocom
X(NOT Interactive Fiction Plus!!!)
X
XUsage:	zmachine [ -p protocolfile ] [ -w protocol linewith ]
X	[ -s storyfile ] [ -r restorefile ] [ <storyfile>.dat ]
X	[ <restorefile>.sav ]
X
X-p protocolfile     : send output after script command to protocolfile
X-w protocol linewith: set protocol linewith to linewith
X-s storyfile        : use storyfile (only necessary if storyfile ends
X                      not with .dat)
X-r restorefile      : restore savefile restorefile before starting game
X                      (only necessary if restorefile ends not with .sav)
X<storyfile>.dat     : use storyfile.dat
X<restorefile>.sav   : restore restorefile.dat
X
XIf you call zmachine without arguments, it trys to open the file
Xstory.dat on the current working directory. If you call zmachine with a
Xsavefile argument only, it first tries to open a file with the name
Xsavefile.dat, then a file with the name story.dat.
X
XEditing keys:
XIf the TERMCAP-Entry for your terminal is complete, you can use the
Xcorresponding special keys on your keyboard;
X
XCursor left		:	^B
XCursor right		:	^F
XUp in history		:	^P
XDown in history		:	^N
XDelete left		:	0x7f, 0x08
XDelete right 		:	^D
XStart of line		:	^A
XEnd of line		:	^E
XKill to end of line	:	^K
XKill to start of line	:	^X
XProgram function key	:	^I (TAB)
XUndo			:	^Y
XFunction key 0-9	:	^X0 - ^X9
X
X
XBug reports to leo@marco.UUCP
/
echo x - zmachine.c
sed '/^X/s///' > zmachine.c << '/'
X/*
X*	@(#)zmachine.c	2.24
X*/
X
X# include "zmachine.h"
X
Xchar *story_name;
Xstruct dev *printer;
X
Xjmp_buf restart_buf;
X
X/************************************************************************/
Xint release;
Xint status_type;
X
XBYTE *ff0;
XBYTE *fec;
Xchar *terms, *my_terms;		/* word terminators		*/
XBYTE *first_word, *last_word;
XUWORD word_len, word_num;
X
Xchar *line;			/* line buffer during status	*/
Xint use_line = 0;		/* line output			*/
XUWORD *stack, *framep, *sp;	/* stack management		*/
X
X#ifdef DEBUG
XUWORD ops_ix = 0;
Xstruct {
X	BYTE c_op;
X	struct address c_pc;
X	UWORD c_sp;
X	UWORD c_fp;
X} ops[256];
X#endif
X
XBYTE *short_cuts;
Xint save_len;
Xint status_len;			/* number of status lines	*/
X
Xint line_cnt;
X
Xint in_status = 1;
X
X/************************************************************************/
X
XWORD l116b2(d0)
Xregister WORD d0;
X{
X	WORD l116ca();
X
X	if (--d0 < 0)
X		return(fetchw_op());
X	else if (d0 == 0)
X		return(fetchb_op());
X	else if ((d0 = fetchb_op()) != 0)
X		return(l116ca(d0));
X	else 
X		return(*(sp++));
X}
X
XWORD l116c2(d0)
XWORD d0;
X{
X	WORD l116ca();
X
X	if (!d0)
X		return(*sp);
X	else
X		return(l116ca(d0));
X}
X
XWORD l116ca(d0)
XWORD d0;
X{
X	if (d0 < 0x10)
X		return(framep[- d0 + 1]);
X	else
X		return(word_get(&fec[(d0 - 0x10)*2]));
X}
X
Xvoid l116ee(d0, d1)
XWORD d0, d1;
X{
X	if (!d0)
X		*sp = d1;
X	else
X		if (d0 < 0x10)
X			framep[- d0 + 1] = d1;
X		else
X			word_put(&fec[(d0 - 0x10)*2], d1);
X}
X
Xvoid l11720(d0)
XWORD d0;
X{
X	WORD d1;
X
X	if (d1 = fetchb_op())
X		l116ee(d1, d0);
X	else
X		*(--sp) = d0;
X}
X
Xvoid l1171c(d0)
XWORD d0;
X{
X	l11720(d0 & 0xff);
X}
X
X#ifdef DEBUG
Xvoid zcore_dump()
X{
X	int i, ix;
X	FILE *fp;
X
X	fp = fopen("zcore", "w");
X	if (!fp)
X		fp = stderr;
X
X	fprintf(fp, "sp = %04x  fp = %04x\n", sp-stack, framep-stack);
X
X	fprintf(fp, "Stack:");
X	for (i = 0; i < 256; i++)
X	{
X		if (!(i % 8))
X			fprintf(fp, "\n%04x: ", i);
X
X		fprintf(fp, "%04x ", stack[i]);
X	}
X
X	fprintf(fp, "\nLast instructions(fp:sp:addr:op):\n");
X	for (i = 256; i; i--)
X	{
X		ix = (ops_ix++ & 0xff);
X		if (!(i % 4))
X			fprintf(fp, "\n");
X
X		fprintf(fp, "%02x:%02x:%05lx:%02x ", ops[ix].c_fp, ops[ix].c_sp,
X		(long)ops[ix].c_pc.offset|((long)ops[ix].c_pc.segment<<9),
X		ops[ix].c_op);
X	}
X	fprintf(fp, "\n");
X	unlink("zcore.sav");
X	save_gf("zcore.sav");
X}
X#endif
X
X/************************************************************************/
X/*				op-codes				*/
X
X/************************************************************************/
X/*			op-code utilities				*/
X
X# define dojmp()	jump(0)
X# define dontjmp()	jump(1)
X
Xvoid jump(d1)
Xregister WORD d1;
X{
X	register WORD d0;
X	void ret_0(), ret_1();
X
X	d0 = fetchb_op();
X	if(d0 & 0x80)
X		d1++;
X
X	d0 &= ~0x80;
X
X	if (!(d0 & 0x40))
X	{
X		d0 &= ~0x40;
X		d0 <<= 8;
X		d0 |= fetchb_op();
X		if (d0 & 0x2000)
X			d0 |= ~0x3fff;
X	}
X	else
X		d0 &= ~0x40;
X
X	if (--d1)
X	{
X		if (!d0)
X			ret_0();
X		else if (!(--d0))
X			ret_1();
X		else
X		{
X			pc.offset += (d0 - 1);
X			load_code();
X		}
X	}
X}
X
XBYTE *l11846(d0)
XWORD d0;
X{
X	return(ff0+9*d0+0x35);
X}
X
XBYTE *l11856(a0)
XBYTE *a0;
X{
X	register BYTE *p;
X	register WORD d;
X
X	p = main_p + word_get(a0+7);
X	d = *(p++)*2;
X	return(p + d);
X}
X
XBYTE *l11870(a0)
XBYTE *a0;
X{
X	register WORD d;
X
X	d = (*(a0++)>>5) + 1;
X	return(a0 + d);
X}
X
Xvoid illegal()
X{
X#ifdef DEBUG
X	zcore_dump();
X#endif
X	fatal("Bad operation", story_name);
X}
X
X/************************************************************************/
X/*				class 0					*/
X
Xvoid ret_1()
X{
X	void ret();
X	ret(1);
X}
X
Xvoid ret_0()
X{
X	void ret();
X	ret(0);
X}
X
Xvoid print_im()
X{
X	decode(&pc);
X	load_code();
X}
X
Xvoid printcr_im()
X{
X	void newline();
X	print_im();
X	newline();
X	ret_1();
X}
X
Xvoid nop()
X{
X}
X
Xvoid save_g()
X{
X	char *name;
X	int save_gf();
X	
X	if (!(name = read_sname()))
X		dojmp();
X	else
X		jump(save_gf(name));
X}
X
Xint save_gf(p)
Xchar *p;
X{
X	extern char *iovers;
X	UWORD *csp;
X
X	if (open_save_w(p))
X		return(0);
X
X	csp = sp;
X	*(--sp) = pc.segment;
X	*(--sp) = pc.offset;
X#ifdef GEMDOS
X	/* sorry, its awful but compatibel to infocom's interpreter */
X	*(--((long *)sp)) = (BYTE *)framep - (BYTE *)stack;
X	*(--sp) = release;
X	*(((long *)stack)) = (BYTE *)sp - (BYTE *)stack;
X	*(stack + sizeof(long)/sizeof(UWORD)) = atoi(iovers);
X#else
X	*(--sp) = framep - stack;
X	*(--sp) = release;
X	*stack = sp - stack;
X	*(stack + 1) = atoi(iovers);
X#endif
X	sp = csp;
X
X	if (write_save(0, 1, stack))
X		return(0);
X
X	if (write_save(1, save_len, main_p))
X		return(0);
X
X	if (save_keys())
X		return(0);
X
X	if (close_save())
X		return(0);
X
X	return(1);
X}
X
Xvoid restore_g()
X{
X	char *name;
X	int restore_gf();
X	
X	if (!(name = read_rname()))
X		dojmp();
X	else
X		jump(restore_gf(name));
X}
X
Xint restore_gf(p)
Xchar *p;
X{
X	extern char *iovers;
X	int sv;
X
X	if (open_save_r(p))
X		return(0);
X
X	if (read_save(0, 1, stack))
X		fatal("Save file read error", p);
X
X#ifdef GEMDOS
X	sp = (UWORD *)((BYTE *)stack + *((long *)stack));
X#else
X	sp = stack + *stack;
X#endif
X
X	if (*sp++ != release)
X		fatal("Wrong save file version", p);
X
X#ifdef GEMDOS
X	framep = (BYTE *)stack + *(((long *)sp)++);
X#else
X	framep = stack + *sp++;
X#endif
X	pc.offset = *(sp++);
X	pc.segment = *(sp++);
X
X	sv = word_get(main_h->reserved5);
X	if (read_save(1, save_len, main_p))
X		fatal("Save file read error", p);
X	word_put(main_h->reserved5, sv);
X
X#ifdef GEMDOS
X	if (*(stack + sizeof(long)/sizeof(UWORD)) == atoi(iovers))
X#else
X	if (*(stack + 1) == atoi(iovers))
X#endif
X		if (restore_keys())
X			fatal("Save file read error", p);
X
X	close_save();
X	load_code();
X
X	return(1);
X}
X	
Xvoid restart_g()
X{
X	line_cnt = 0;
X	output_chr('\n');
X	longjmp(restart_buf);
X}
X
Xvoid ret_sp()
X{
X	void ret();
X	ret(*(sp++));
X}
X
Xvoid inc_sp()
X{
X	sp++;
X}
X
Xvoid halt()
X{
X	clean_up();
X	exit(userexit(0));
X}
X
Xvoid newline()
X{
X	output_chr('\n');
X}
X
Xvoid status()
X{
X	char	room[256];
X	char	*score;
X	char	am_pm;
X	int	hour;
X
X	void	write_num();
X	void	l11e24();
X
X	use_line = 1;
X	line = room;
X
X	*line++ = ' ';
X	l11e24(l116c2(0x10));
X	*(line++) = '\0';
X	score = line;
X	if (!status_type)
X	{
X		strcpy(line, "Score: ");
X		write_num(l116c2(0x11));
X		*line++ = '/';
X		write_num(l116c2(0x12));
X	}
X	else
X	{
X		if ((hour = l116c2(0x11)) > 12)
X		{
X			hour -= 12;
X			am_pm = 'p';
X		}
X		else
X			am_pm = 'a';
X
X		if (hour == 0)
X			hour = 12;
X
X/*
X		sprintf(line, "Time: %2d:%02d %cm", hour, l116c2(0x12), am_pm);
X*/
X		strcpy(line, "Time: ");
X		line += strlen(line);
X		if (hour < 10)
X			*line++ = ' ';
X		write_num(hour);
X		*line++ = ':';
X		if (l116c2(0x12) < 10)
X			*line++ = '0';
X		write_num(l116c2(0x12));
X		*line++ = ' ';
X		*line++ = am_pm;
X		*line++ = 'm';
X	}
X	*line++ = ' ';
X	*line++ = '\0';
X	output_status(room, score);
X	use_line = 0;
X}
X
Xvoid verify()
X{
X	struct address a, end;
X	int m_len;
X	long sum;
X
X	output_str("Z-Code 3 interpreter V2.24 for ");
X	output_str(sysname);
X	output_str("\n");
X
X	m_len = main_l;
X	main_l = 0;
X
X	a.segment = 0;
X	a.offset = 0x40;
X	sum = 0;
X	waddr_to_vaddr(&end, word_get(main_h->len));
X
X	while(a.segment != end.segment || a.offset != end.offset)
X		sum += fetchb_data(&a);
X
X	main_l = m_len;
X
X	jump((UWORD)sum == word_get(main_h->checksum));
X}
X
X/************************************************************************/
X/*				class 1					*/
X
Xvoid bne(d0)
XWORD d0;
X{
X	if(d0)
X		dojmp();
X	else
X		dontjmp();
X}
X
Xvoid l1190c(d0)
XWORD d0;
X{
X	register BYTE d1;
X
X	l11720(d1 = l11846(d0)[5]);
X
X	if (d1)
X		dontjmp();
X	else
X		dojmp();
X}
X
Xvoid l118f2(d0)
XWORD d0;
X{
X	register BYTE d1;
X
X	l11720(d1 = l11846(d0)[6]);
X
X	if (d1)
X		dontjmp();
X	else
X		dojmp();
X}
X
Xvoid l118e4(d0)
XWORD d0;
X{
X	l11720(l11846(d0)[4]);
X}
X
Xvoid l11a7e(d0)
XWORD d0;
X{
X	l11720((main_p[d0-1]>>5)+1);
X}
X
Xvoid l11aac(d0)
XWORD d0;
X{
X	l116ee(d0,l116c2(d0)+1);
X}
X
Xvoid l11aba(d0)
XWORD d0;
X{
X	l116ee(d0,l116c2(d0)-1);
X}
X
Xvoid print_near(d0)
XWORD d0;
X{
X	struct address a;
X	baddr_to_vaddr(&a,d0);
X	decode(&a);
X}
X
Xvoid l118a2(d1)
XWORD d1;
X{
X	register BYTE *a0, *a1;
X	register UWORD d0;
X
X	a1 = l11846(d1);
X	if (d0 = a1[4])
X	{
X		d0 = (a0 = l11846(d0))[6];
X		if (d1 == d0)
X			a0[6] = a1[5];
X		else
X		{
X			while ((d0 = (a0 = l11846(d0))[5]) != d1)
X				;
X			a0[5] = a1[5];
X		}
X		a1[4] = a1[5] = 0;
X	}
X}
X
Xvoid l11e24(d0)
XWORD d0;
X{
X	struct address a;
X
X	baddr_to_vaddr(&a, word_get(l11846(d0)+7) + 1);
X	decode(&a);
X}
X
Xvoid ret(d0)
XWORD d0;
X{
X	sp = framep + 1;
X#ifdef GEMDOS
X	framep = (BYTE *)stack + *(((long *)sp)++);
X#else
X	framep = stack + *sp++;
X#endif
X	pc.offset = *(sp++);
X	pc.segment = *(sp++);
X	load_code();
X	l11720(d0);
X}
X
Xvoid bra(d0)
XWORD d0;
X{
X	pc.offset += (d0 - 2);
X	load_code();
X}
X
Xvoid print_far(d0)
XWORD d0;
X{
X	struct address a;
X	waddr_to_vaddr(&a, d0);
X	decode(&a);
X}
X
Xvoid l11a96(d0)
XWORD d0;
X{
X	l11720(l116c2(d0));
X}
X
Xvoid not(d0)
XWORD d0;
X{
X	l11720(~d0);
X}
X
X/************************************************************************/
X/*				class 2					*/
X
Xvoid l11824(a0)
Xregister WORD *a0;
X{
X	register WORD d0, d1;
X
X	d1 = *(a0++) - 1;
X	d0 = *(a0++);
X
X	for(;;)
X		if(*(a0++) == d0)
X		{
X			dontjmp();
X			break;
X		}
X		else if (!--d1)
X		{
X			dojmp();
X			break;
X		}
X}
X
Xvoid cbge(d0, d1)
XWORD d0, d1;
X{
X	jump(d0 < d1);
X}
X
Xvoid cble(d0, d1)
XWORD d0, d1;
X{
X	jump(d0 > d1);
X}
X
Xvoid dcbge(d0, d1)		/* decrement, compare and jump greater equal */
XWORD d0, d1;			/* dcbge */
X{
X	register WORD d2;
X
X	d2 = l116c2(d0) - 1;
X	l116ee(d0,d2);
X	if (d2 < d1)
X		dontjmp();
X	else
X		dojmp();
X}
X
Xvoid icble(d0, d1)		/* increment, compare and jump less equal */
XWORD d0, d1;			/* icble */
X{
X	register WORD d2;
X
X	d2 = l116c2(d0) + 1;
X	l116ee(d0,d2);
X	if (d2 > d1)
X		dontjmp();
X	else
X		dojmp();
X}
X
Xvoid l11926(d0, d1)
XWORD d0, d1;
X{
X	if (l11846(d0)[4] == d1)
X		dontjmp();
X	else
X		dojmp();
X}
X
Xvoid l11806(d0, d1)
XWORD d0, d1;
X{
X	jump((d1 & ~d0) == 0);
X}
X
Xvoid or(d0, d1)
XWORD d0, d1;
X{
X	l11720(d0 | d1);
X}
X
Xvoid and(d0, d1)
X{
X	l11720(d0 & d1);
X}
X
X#define tst(a0, d0)	(a0[d0 >> 3] & (1<<((~d0)&7)))
X#define clr(a0, d0)	(a0[d0 >> 3] &= ~(1<<((~d0)&7)))
X#define set(a0, d0)	(a0[d0 >> 3] |= (1<<((~d0)&7)))
X
Xvoid tstbit_jz(d0, d1)
XWORD d0, d1;
X{
X	if (tst(l11846(d0), d1))
X		dontjmp();
X	else
X		dojmp();
X}
X
Xvoid setbit(d0, d1)
XWORD d0, d1;
X{
X	set(l11846(d0), d1);
X}
X
Xvoid clrbit(d0, d1)
XWORD d0, d1;
X{
X	clr(l11846(d0), d1);
X}
X
Xvoid l11a9e(d0, d1)
XWORD d0, d1;
X{
X	l116ee(d0, d1);
X}
X
Xvoid l1187c(d0, d1)
XWORD d0, d1;
X{
X	register BYTE *a0, *a1;
X	void l118a2();
X
X	l118a2(d0);
X	a1 = l11846(d1);
X	a0 = l11846(d0);
X
X	a0[5] = a1[6];
X	a0[4] = d1;
X	a1[6] = d0;
X}
X
Xvoid l11a16(d0, d1)
XWORD d0, d1;
X{
X	struct address a;
X	baddr_to_vaddr(&a, d0 + d1 * 2);
X	l11720(fetchw_data(&a));
X}
X
Xvoid l11a28(d0, d1)
XWORD d0, d1;
X{
X	struct address a;
X	baddr_to_vaddr(&a, d0 + d1);
X	l1171c(fetchb_data(&a));
X}
X
Xvoid l11936(d0, d1)
Xregister WORD d0, d1;
X{
X	register BYTE *a0;
X
X	for (a0 = l11856(l11846(d0)); d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0))
X		;
X
X	if (d1 == d0)
X	{
X		if (!(*(a0++) & 0x20))
X			l1171c(*a0);
X		else
X			l11720(word_get(a0));
X	}
X	else
X		l11720(word_get(&ff0[(d1-1) * 2]));
X	
X}
X
Xvoid l11a54(d0, d1)
Xregister WORD d0, d1;
X{
X	register BYTE *a0;
X
X	for (a0 = l11856(l11846(d0)); d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0))
X		;
X
X	if (d1 != d0)
X		l11720(0);
X	else
X		l11720(++a0 - main_p);
X}
X
Xvoid l119a4(d0, d1)
Xregister WORD d0, d1;
X{
X	register BYTE *a0;
X
X	a0 = l11856(l11846(d0));
X
X	if (d1)
X	{
X		for(;  d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0))
X			;
X		if (d1 != d0)
X			fatal("Non-existant next property", story_name);
X		else
X			a0 = l11870(a0);
X	}
X	l11720(*a0 & 0x1f);
X}
X
Xvoid add(d0, d1)
XWORD d0, d1;
X{
X	l11720(d0 + d1);
X}
X
Xvoid sub(d0, d1)
XWORD d0, d1;
X{
X	l11720(d0 - d1);
X}
X
Xvoid mul(d0, d1)
XWORD d0, d1;
X{
X	l11720(d0 * d1);
X}
X
Xvoid div(d0, d1)
XWORD d0, d1;
X{
X	l11720(d0 / d1);
X}
X
Xvoid mod(d0, d1)
XWORD d0, d1;
X{
X	l11720(d0 % d1);
X}
X
Xvoid call(a0)
Xregister WORD *a0;
X{
X	register WORD d0, d1, d2;
X
X	d2 = *(a0++);
X	if ((d0 = *(a0++)) == 0)
X		l11720(0);
X	else
X	{
X		d2--;
X		*(--sp) = pc.segment;
X		*(--sp) = pc.offset;
X#ifdef GEMDOS
X		*(--((long *)sp)) = (BYTE *)framep - (BYTE *)stack;
X#else
X		*(--sp) = framep - stack;
X#endif
X		waddr_to_vaddr(&pc,d0);
X		load_code();
X		framep = sp - 1;
X		if (d1 = fetchb_op())
X		{
X			do
X			{
X				d0 = fetchw_op();
X				if (--d2 >= 0)
X					d0 = *(a0++);
X				*(--sp) = d0;
X			}
X			while (--d1 > 0);
X		}
X	}
X}
X
Xvoid l11a38(d0, d1, d2)
XWORD d0, d1, d2;
X{
X	word_put(&main_p[d0 + d1 * 2], d2);
X}
X
X
Xvoid l11a48(d0, d1, d2)
XWORD d0, d1; WORD d2;
X{
X	main_p[d0+d1] = (BYTE)d2;
X}
X
Xvoid l1196e(d0, d1, d2)
Xregister WORD d0, d1; WORD d2;
X{
X	register BYTE *a0;
X
X	for (a0 = l11856(l11846(d0)); d1 < (d0 = *a0 & 0x1f); a0 = l11870(a0))
X		;
X
X	if (d1 != d0)
X		fatal("Non-existant put property", story_name);
X
X	if (*(a0++) & 0x20)
X		word_put(a0, d2);
X	else
X		*a0 = d2;
X}
X
XUWORD findword(a0)
XUWORD *a0;
X{
X	register UWORD d0, step, code0, code1;
X	register BYTE *word;
X
X	d0 = word_num;
X	step = word_len;
X
X	code0 = *a0;
X	code1 = *(a0+1);
X
X	for ( d0 >>= 1, step <<= 1; d0 >>= 1; step <<= 1)
X		;
X
X	word = &first_word[step - word_len];
X	
X	do
X	{
X		step >>= 1;
X		d0 = word_get(word);
X		if (code0 <= d0)
X		{
X			if (code0 != d0)
X				word -= step;
X			else
X			{
X				d0 = word_get(word+2);
X				if (code1 <= d0)
X				{
X					if (code1 != d0)
X						word -= step;
X					else
X						return(word - main_p);
X				}
X				else
X				{
X					word += step;
X					if (last_word < word)
X						word = last_word;
X				}
X			}
X		}
X		else
X		{
X			word += step;
X			if (last_word < word)
X				word = last_word;
X		}
X	}
X	while(word_len <= step);
X	return(0);
X}
X
Xchar *wordend(c)
Xregister char c;
X{
X	register char *p;
X
X	for(p = terms; *p; p++)
X		if (*p == c)
X			return (p);
X	return(NULL);
X}
X
Xvoid input(a0)
XWORD *a0;
X{
X	char c;
X	char *inp;		/* input field				*/
X	char *end;		/* end of input line			*/
X	BYTE *out;		/* output field				*/
X	BYTE *outp;		/* pointer into output field		*/
X	char src_word[8];	/* source word				*/
X	UWORD dst_word[4];	/* word coded in z-code			*/
X	register char *lp;	/* pointer into line			*/
X	register char *cp;	/* pointer into src_word		*/
X	char *ws;		/* pointer into line (start of line)	*/
X	register int wc;	/* word count				*/
X	register char *p;	/* scratch				*/
X	static struct hist_buf history = {I_HIST_LEN, NULL, NULL};
X				/* history buffer			*/
X
X	if (!history.hb)
X	{
X		if (!(history.undo = history.hb = malloc(history.len)))
X			no_mem_error();
X		else
X			history.hb[0] = history.hb[1] = '\0';
X	}
X
X	inp = (char *)&main_p[a0[1]];
X	out = &main_p[a0[2]];
X
X	status();
X	output_chr(FLUSH);
X
X	end = read_str(inp, &history);
X
X	lp = inp + 1;
X	outp = out + 2;
X	wc = 0;
X
X	for(;;)
X	{
X		cp = src_word;
X		ws = lp;
X		while (lp < end)
X		{
X			if (p = wordend(c = *lp++))
X				break;
X			else
X				if (cp < src_word + 6)
X					*cp++ = c;
X		}
X
X		if (lp < end)
X		{
X			if (cp != src_word)
X				lp--;
X			else if (p < my_terms)
X				*cp++ = c;
X			else
X				continue;
X		}
X		else
X		{
X			if (src_word == cp)
X				break;
X		}
X
X		if (++wc >= out[0])
X		{
X			output_chr('\n');
X			output_str("too many words for internal buffer\n");
X			out[1] = 0;
X			return;
X		}
X
X		outp[2] = (char)(lp - ws);
X		outp[3] = (char)(ws - inp);
X		*cp = '\0';
X		encode(dst_word, src_word);
X		word_put(outp, findword(dst_word));
X		outp += 4;
X	}
X	out[1] = wc;
X
X	if (word_get(main_h->reserved5) & 1)
X	{
X		for (p = inp; *++p; )
X			putc_dev(*p, printer);
X		putc_dev('\n', printer);
X	}
X}
X
Xvoid l11dcc(d0)
XWORD d0;
X{
X	output_chr(d0);
X}
X
Xvoid write_num(d0)
XWORD d0;
X{
X	char buf[16];
X	register char *p;
X	int flag;
X
X	flag = 0;
X	if (d0 < 0)
X	{
X		flag = 1;
X		d0 = -d0;
X	}
X
X	p = buf + 15;
X	*p = '\0';
X	do
X		*--p = d0 % 10 + '0';
X	while(d0 /= 10);
X
X	if (flag)
X		*--p = '-';
X	
X	output_str(p);
X}
X
Xvoid rnd(d0)
XWORD d0;
X{
X	extern long zrandom();
X/*
X	static UWORD rnd0 = 0xffff, rnd1 = 0;
X	register long d1;
X
X	if (rnd0 == 0xffff)
X	{
X		d1 = Random();
X		rnd0 = d1 >> 16;
X		rnd1 = d1;
X	}
X
X	d1 = rnd0;
X	d1 |= (rnd0 = rnd1) << 16;
X	d1 >>= 1;
X	d1 = (rnd1 ^= d1);
X	d1 &= 0x7fff;
X	l11720(((UWORD)d1 % d0) + 1);
X*/
X	l11720((((UWORD)zrandom() & (UWORD)0x7fff) % d0) + 1);
X}
X
Xvoid l11aa2(d0)
XWORD d0;
X{
X	*(--sp) = d0;
X}
X
Xvoid l11aa6(d0)
XWORD d0;
X{
X	l116ee(d0, *(sp++));
X}
X
Xvoid l11e5e(d0)
XWORD d0;
X{
X	status_len = d0;
X}
X
Xvoid l11e7e(d0)
XWORD d0;
X{
X	static int x,y;
X
X	if (d0 == 0)
X	{
X		if (in_status)
X			gotoXY(x,y);
X
X		in_status = 0;
X	}
X	else if(d0 == 1)
X	{
X		if (!in_status)
X			storeXY(&x, &y);
X
X		in_status = 1;
X		gotoXY(0,1);
X	}
X}
X
X/************************************************************************/
X/*			main interpreter loop				*/
X
Xvoid (*class0[])() = {
X	ret_1,			/* op 0xb0	*/
X	ret_0,			/* op 0xb1	*/
X	print_im,			/* op 0xb2	*/
X	printcr_im,			/* op 0xb3	*/
X	nop,			/* op 0xb4	*/
X	save_g,			/* op 0xb5	*/
X	restore_g,		/* op 0xb6	*/
X	restart_g,		/* op 0xb7	*/
X	ret_sp,			/* op 0xb8	*/
X	inc_sp,			/* op 0xb9	*/
X	halt,			/* op 0xba	*/
X	newline,		/* op 0xbb	*/
X	status,			/* op 0xbc	*/
X	verify,			/* op 0xbd	*/
X	illegal,		/* op 0xbe	*/
X	illegal			/* op 0xbf	*/
X};
X
Xvoid (*class1[])() = {
X	bne,
X	l1190c,
X	l118f2,
X	l118e4,
X	l11a7e,
X	l11aac,
X	l11aba,
X	print_near,
X	illegal,
X	l118a2,
X	l11e24,
X	ret,
X	bra,
X	print_far,
X	l11a96,
X	not
X};
X
Xstruct {
X	void (*func)();
X	BYTE flag;
X	} class2[] = {
X		{ illegal,	1 },		/* 00 */
X		{ l11824,	0 },		/* 01 */
X		{ cbge,		1 },		/* 02 */
X		{ cble,		1 },		/* 03 */
X		{ dcbge,	1 },		/* 04 */
X		{ icble,	1 },		/* 05 */
X		{ l11926,	1 },		/* 06 */
X		{ l11806,	1 },		/* 07 */
X		{ or,		1 },		/* 08 */
X		{ and,		1 },		/* 09 */
X		{ tstbit_jz,	1 },		/* 0a */
X		{ setbit,	1 },		/* 0b */
X		{ clrbit,	1 },		/* 0c */
X		{ l11a9e,	1 },		/* 0d */
X		{ l1187c,	1 },		/* 0e */
X		{ l11a16,	1 },		/* 0f */
X		{ l11a28,	1 },		/* 10 */
X		{ l11936,	1 },		/* 11 */
X		{ l11a54,	1 },		/* 12 */
X		{ l119a4,	1 },		/* 13 */
X		{ add,		1 },		/* 14 */
X		{ sub,		1 },		/* 15 */
X		{ mul,		1 },		/* 16 */
X		{ div,		1 },		/* 17 */
X		{ mod,		1 },		/* 18 */
X		{ illegal,	1 },		/* 19 */
X		{ illegal,	1 },		/* 1a */
X		{ illegal,	1 },		/* 1b */
X		{ illegal,	1 },		/* 1c */
X		{ illegal,	1 },		/* 1d */
X		{ illegal,	1 },		/* 1e */
X		{ illegal,	1 },		/* 1f */
X		{ call,	0 },			/* 20 */
X		{ l11a38,	1 },		/* 21 */
X		{ l11a48,	1 },		/* 22 */
X		{ l1196e,	1 },		/* 23 */
X		{ input,	0 },		/* 24 */
X		{ l11dcc,	1 },		/* 25 */
X		{ write_num,	1 },		/* 26 */
X		{ rnd,		1 },		/* 27 */
X		{ l11aa2,	1 },		/* 28 */
X		{ l11aa6,	1 },		/* 29 */
X		{ l11e5e,	1 },		/* 2a */
X		{ l11e7e,	1 },		/* 2b */
X		{ illegal,	1 },		/* 2c */
X		{ illegal,	1 },		/* 2d */
X		{ illegal,	1 },		/* 2e */
X		{ illegal,	1 },		/* 2f */
X		{ illegal,	1 },		/* 30 */
X		{ illegal,	1 },		/* 31 */
X		{ illegal,	1 },		/* 32 */
X		{ illegal,	1 },		/* 33 */
X		{ illegal,	1 },		/* 34 */
X		{ illegal,	1 },		/* 35 */
X		{ illegal,	1 },		/* 36 */
X		{ illegal,	1 },		/* 37 */
X		{ illegal,	1 },		/* 38 */
X		{ illegal,	1 },		/* 39 */
X		{ illegal,	1 },		/* 3a */
X		{ illegal,	1 },		/* 3b */
X		{ illegal,	1 },		/* 3c */
X		{ illegal,	1 },		/* 3d */
X		{ illegal,	1 },		/* 3e */
X		{ illegal,	1 }		/* 3f */
X};
X
Xint oc;
Xint o1;
X
Xvoid run()
X{
X	register UWORD d0, d1, d2, d3, d4;
X	register UWORD *argp, *bp;
X	UWORD args[6];
X	UWORD bits[4];
X
X	argp = args;
X	for(;;)
X	{
X#ifdef DEBUG
X		ops[ops_ix].c_pc.offset = pc.offset;
X		ops[ops_ix].c_pc.segment = pc.segment;
X		ops[ops_ix].c_sp = sp - stack;
X		ops[ops_ix].c_fp = framep - stack;
X		ops[ops_ix].c_op = d0 = fetchb_op();
X		ops_ix = (ops_ix + 1) & 0xff;
X#else
X		d0 = fetchb_op();
X#endif
X		if (d0 < 0x80)
X		{
X			d1 = l116b2((d0 & 0x40)?2:1);
X			d2 = l116b2((d0 & 0x20)?2:1);
X
X			if (class2[d0 & 0x1f].flag)
X				(*class2[d0 & 0x1f].func)(d1, d2);
X			else
X			{
X				argp[0] = 2;
X				argp[1] = d1;
X				argp[2] = d2;
X				(*class2[d0 & 0x1f].func)(argp);
X			}
X		}
X		else if (d0 < 0xb0)
X			(*class1[d0 & 0x0f])(l116b2((d0 >> 4) & 0x03));
X		else if (d0 < 0xc0)
X			(*class0[d0 & 0x0f])();
X		else
X		{
X			d2 = d0;
X			bp = &bits[4];
X			d0 = fetchb_op();
X			*(--bp) = d0;
X			*(--bp) = (d0 >>= 2);
X			*(--bp) = (d0 >>= 2);
X			*(--bp) = (d0 >>= 2);
X			for (d4 = 0, d3 = 4; d3; d3--)
X			{
X				if ((d0 = *(bp++) & 3) == 3)
X					break;
X				argp[++d4] = l116b2(d0);
X			}
X			argp[0] = d4;
X
X			if (class2[d2 & 0x3f].flag)
X				(*class2[d2 & 0x3f].func)
X					(argp[1],argp[2],argp[3],argp[4]);
X			else
X				(*class2[d2 & 0x3f].func)(argp);
X		}
X	}
X}
X	
X/************************************************************************/
X/*				initializiation				*/
Xno_mem_error()
X{
X	fatal("Out of memory", NULL);
X}
X
Xmain(argc,argv)
Xint argc; char **argv;
X{
X	struct header h;
X	register BYTE *p, *q, *r;
X	register int i;
X
X	char space[128];
X	extern int optind;
X	extern char *optarg;
X	char *usage;
X
X	int c, sflag, rflag;
X	char *restore_name;
X	char *strchr(), *strrchr();
X
X# if defined(OSK)
X	usage = "\15\12Usage:\tzmachine [ -p protocolfile ] [ -w protocol linewith ]\
X\15\12\t[ -s storyfile ] [ -r restorefile ] [ <storyfile>.dat ]\
X\15\12\t[ <restorefile>.sav ]\15\12";
X# else
X	usage = "\r\nUsage:\tzmachine [ -p protocolfile ] [ -w protocol linewith ]\
X\r\n\t[ -s storyfile ] [ -r restorefile ] [ <storyfile>.dat ]\
X\r\n\t[ <restorefile>.sav ]\r\n";
X# endif
X
X	story_name = restore_name = NULL;
X
X	sflag = rflag = 0;
X	while ((c = getopt(argc, argv, "s:p:r:w:")) != EOF)
X	{
X		switch(c)
X		{
X			case 's':
X				story_name = optarg;
X				sflag++;
X				break;
X
X			case 'p':
X				print_name = optarg;
X				break;
X
X			case 'r':
X				restore_name = optarg;
X				rflag++;
X				break;
X
X			case 'w':
X				if (!(printer_width = atoi(optarg)))
X					printer_width = 80;
X				break;
X
X			default:
X				write(2, usage, strlen(usage));
X				exit(userexit(1));
X		}
X	}
X
X	while (optind < argc)
X	{
X		char *tmp;
X
X		if ((tmp = strrchr(argv[optind],'.')) &&
X			(!strcmp(tmp,".dat") || !strcmp(tmp, ".DAT")))
X			story_name = argv[optind];
X		else if (tmp && (!strcmp(tmp, ".sav") || !strcmp(tmp, ".SAV")))
X		{
X			rflag++;
X			restore_name = argv[optind];
X		}
X		else
X		{
X			fatal("Unknown filetype", argv[optind]);
X		}
X		optind++;
X	}
X
X
X	if (!story_name && restore_name && strchr(restore_name,'.'))
X	{
X		strcpy(space, restore_name);
X		strcpy(strchr(space, '.'), ".dat");
X		if (access(space,0))
X			story_name = "story.dat";
X		else
X			story_name = space;
X	}
X
X	if (!story_name)
X		story_name = "story.dat";
X
X	if (open_story())
X		fatal("Can't open", story_name);
X
X	read_header(&h);
X
X	if (h.zmachine != 3)
X		fatal("Wrong Z-machine version", story_name);
X
X	mmu_init(&h);
X
X	read_story(0, main_l, main_p);
X
X	in_status = 0;
X	
X	release = word_get(h.release);
X
X	status_type = (h.flags & 2) >> 1;
X
X	ff0 = main_p + word_get(h.reserved2);
X	fec = main_p + word_get(h.reserved3);
X	short_cuts = main_p + word_get(h.short_cuts);
X	save_len = btop((long)word_get(h.save_len));
X	if (!(stack = (UWORD *)malloc(0x100 * sizeof(WORD))))
X		no_mem_error();
X
X	printer = init_dev(prot_write, prot_crlf, printer_width, 0, 0);
X
X	if (!(terms = malloc(0x40)))
X		no_mem_error();
X
X	q = main_p + word_get(h.vocabulary);
X	for(p = (BYTE *)terms, i = *(q++); i; i--)
X		*p++ = *q++;		/* copy terminators	*/
X
X	my_terms = (char *)p;
X	for(r = (BYTE *)" \011\015.,?"; *p++ = *r++;)
X		;			/* copy my terminators	*/
X
X	word_len = *q++;		/* word-len		*/
X	word_num = word_get(q);		/* number of words	*/
X	q += 2;
X
X	first_word = q;			/* start of words	*/
X	last_word = (word_num - 1) * word_len + first_word;
X					/* end of words		*/
X
X	if (setjmp(restart_buf))
X	{
X		rflag = 0;
X		i = word_get(main_h->reserved5);
X		read_story(0, save_len, main_p);
X		word_put(main_h->reserved5, i);
X	}
X
X	printer->bp = printer->buffer;
X	printer->count = 0;
X	main_h->flags |= 32;
X
X	status_len = 1;
X	init_con();
X	if (!rflag)
X	{
X		sp = &stack[0x100];
X		framep = sp - 1;
X		baddr_to_vaddr(&pc, word_get(h.initial_pc));
X		load_code();
X	}
X	else
X	{
X		if (restore_gf(restore_name))
X			jump(1);
X		else
X			fatal("Cannot load restore file", restore_name);
X	}
X	run();
X}
/
echo x - zmachine.h
sed '/^X/s///' > zmachine.h << '/'
X/*
X*	@(#)zmachine.h	2.24
X*/
X
X# include <stdio.h>
X# include <setjmp.h>
X# include "config.h"
X
Xchar *lmalloc(), *malloc(), *realloc();
X
Xstruct dev {
X		char *buffer;
X		int width;
X		int height;
X		char *bp;
X		int count;
X		void (*out_f)();
X		int wrap;
X		void (*crlf_f)();
X	};
X
Xstruct hist_buf {
X			int len;
X			char *hb;
X			char *undo;
X		};
X
Xstruct header
X	{
X		BYTE zmachine;			/* 00		*/
X		BYTE flags;			/* 01		*/
X		ZWORD release;			/* 02		*/
X		ZWORD minmem;			/* 04		*/
X		ZWORD initial_pc;		/* 06		*/
X		ZWORD vocabulary;		/* 08		*/
X		ZWORD reserved2;		/* 0a	?	*/
X		ZWORD reserved3;		/* 0c	?	*/
X		ZWORD save_len;			/* 0e		*/
X		ZWORD reserved5;		/* 10	zero	*/
X		BYTE serial[6];			/* 12		*/
X		ZWORD short_cuts;		/* 18		*/
X		ZWORD len;			/* 1a		*/
X		ZWORD checksum;			/* 1c		*/
X		ZWORD reserved8;		/* 1e	zero	*/
X		ZWORD reserved9[16];		/* 20	zero	*/
X	};
X
X
Xstruct virt_page {
X		WORD page;
X		unsigned long lru;
X		BYTE *paddr;
X	};
X
Xstruct address
X	{
X		WORD segment;
X		WORD offset;		/* MUST be signed		*/
X	};
X
X# define FLUSH		0x7f		/* Flush output buffer		*/
X
Xextern char *story_name;		/* Name of story file		*/
Xextern char *print_name;		/* Name of protocol file	*/
Xextern int printer_width;		/* Character-width of protocol
X					   file				*/
Xextern struct dev *screen, *printer;	/* screen and protocol device
X					   structures			*/
X
Xextern int main_l;			/* len of main memory in pages	*/
Xextern BYTE *main_p;			/* start of main memory		*/
Xextern struct header *main_h;		/* pointer to header structure
X					   in main memory		*/
Xextern struct address pc;		/* programcounter		*/
Xextern struct virt_page *pc_page;	/* currently executed page	*/
X
Xextern char *sysname;			/* system name			*/
X
X/*		from io.c		*/
X
Xstruct dev *init_dev();
Xvoid	scr_write();
Xvoid	prot_write();
Xvoid	prot_crlf();
Xvoid	output_status();
Xvoid	output_chr();
Xvoid	output_str();
Xchar	*read_str();
Xint	save_keys();
Xint	restore_keys();
X
Xextern int pfile;
X
X/*		from zbios.c		*/
X
Xlong	zrandom();
Xvoid	con_flush();
Xvoid	con_chr();
Xvoid	con_str1();
Xvoid	con_str2();
Xvoid	con_crlf();
Xvoid	reverseON();		
Xvoid	reverseOFF();
Xvoid	cursorON();
Xvoid	cursorOFF();
Xvoid	gotoXY();
Xvoid	storeXY();
Xint	con_getc();
Xvoid	init_con();
X
Xint	open_story();
Xint	close_story();
Xvoid	read_story();
Xvoid	read_header();
X
Xchar	*read_sname();
Xchar	*read_rname();
Xint	open_save_w();
Xint	open_save_r();
Xint	close_save();
Xint	write_save();
Xint	read_save();
Xvoid	fatal();
Xvoid	clean_up();
Xint	userexit();
X
X/*		from mem.c		*/
X
Xvoid	load_code();
XBYTE	*load_page();
Xlong	ptob();
XUWORD	btob();
XUWORD	word_get();
Xvoid	word_put();
XBYTE	fetchb_data();
XUWORD	fetchw_data();
XBYTE	fetchb_op();
XUWORD	fetchw_op();
Xvoid	baddr_to_vaddr();
Xvoid	waddr_to_vaddr();
X
X/*		from code.c		*/
X
Xvoid	decode();
Xvoid	encode();
/
echo x - mem.c
sed '/^X/s///' > mem.c << '/'
X/*
X*	@(#)mem.c	2.24
X*/
X
X# include "zmachine.h"
X
X# define LOCK	0xffffffffL
X
XBYTE *main_p;		/* main memory pointer				*/
Xint main_l;		/* main memory len in pages			*/
Xstruct header *main_h;	/* header pointer				*/
X
Xstruct virt_page *pc_page;	/* page of current pc			*/
Xstruct virt_page main_page;	/* page control for main memory		*/
Xstruct virt_page *c_page; 	/* current active page			*/
Xstruct virt_page *virt_p;	/* the virtual memory array		*/
Xstruct address	pc;		/* program counter			*/
X
Xunsigned long lruc =  0;	/* LRU counter				*/
X
X/************************************************************************/
X
X/* find free page */
X
Xstruct virt_page *find_page()
X{
X	register struct virt_page *u, *v;
X	register long t;
X
X	for(v = virt_p, t = LOCK; v->page != -1; v++)
X		if (v->lru < t)
X		{
X			t = v->lru;
X			u = v;
X		}
X
X	return(u);
X}
X
X
X/* load a page */
X
XBYTE *load_page(page)
Xregister WORD page;
X{
X	register struct virt_page *v;
X
X	if (page != c_page->page)
X	{
X		lruc++;
X		for (v = virt_p; v->page != -1; v++)
X		{
X			if (v->page == page)
X			{
X				if (pc_page->page != page)
X					v->lru = lruc;
X
X				c_page = v;
X				return(c_page->paddr);
X			}
X		}
X		c_page = find_page();
X		c_page->page = page;
X		c_page->lru = lruc;
X		read_story(c_page->page, 1, c_page->paddr);
X	}
X	return(c_page->paddr);
X}
X
X
X/* load page for current pc */
X
Xvoid load_code()
X{
X	pc.segment += pc.offset >> 9;	/* pc.offset may be negative	*/
X	pc.offset &= 0x1ff;
X	if (pc.segment != pc_page->page)
X	{
X		pc_page->lru = lruc;
X
X		if (pc.segment >= main_l)
X		{
X			load_page(pc.segment);
X			pc_page = c_page;
X			pc_page->lru = LOCK;
X		}
X		else
X		{
X			main_page.page = pc.segment;
X			main_page.paddr = main_p+ptob(pc.segment);
X			pc_page = &main_page;
X		}
X	}
X}
X
X
X/* page to byte address */
X
Xlong ptob(page)
XUWORD page;
X{
X	return(((long)page << (long)9) & 0x1ffffL);
X}
X
X
X/* byte to page address */
X
XUWORD btop(byte)
Xlong byte;
X{
X	return((byte & 0x1ff ? (byte >> 9)+1:(byte >> 9)) & 0xff);
X}
X
X
X/* get word */
X
XUWORD word_get(p)
XBYTE *p;
X{
X	register UWORD i;
X	i = *p++ << 8;
X	return(i | *p);
X}
X
X
X/* put word */
X
Xvoid word_put(p, d)
XBYTE *p; register UWORD d;
X{
X	p[1] = d & 0xff;
X	p[0] = d >> 8;
X}
X
X
X/* fetch byte data */
X
XBYTE fetchb_data(a)
Xregister struct address *a;
X{
X	BYTE *load_page();
X	register BYTE r;
X
X	if (a->segment < main_l)
X		r = main_p[ptob(a->segment) | a->offset];
X	else
X		r = load_page(a->segment)[a->offset];
X
X	if (++(a->offset) == 0x200)
X	{
X		a->offset = 0;
X		(a->segment)++;
X	}
X	return(r);
X}
X
X
X/* fetch word data */
X
XUWORD fetchw_data(a)
Xstruct address *a;
X{
X	register UWORD r;
X	r = fetchb_data(a);
X	return((r << 8) | fetchb_data(a));
X}
X
X
X/* fetch next byte from pc */
X
XBYTE fetchb_op()
X{
X	register BYTE r;
X
X	r = pc_page->paddr[pc.offset];
X	if (++pc.offset >= 0x200)
X		load_code();
X
X	return(r);
X}
X
X
X/* fetch next word from pc */
X
XUWORD fetchw_op()
X{
X	register UWORD r;
X
X	r = fetchb_op() << 8;
X	return(r | fetchb_op());
X}
X
X
X/* byte address to virtual address */
X
Xvoid baddr_to_vaddr(vaddress, baddress)
Xregister struct address *vaddress; register UWORD baddress;
X{
X	vaddress->segment = (baddress >> 9) & 0xff;
X	vaddress->offset = baddress & 0x1ff;
X}
X
X
X/* word address to virtual address */
X
Xvoid waddr_to_vaddr(vaddress, waddress)
Xstruct address *vaddress; register UWORD waddress;
X{
X	vaddress->segment = (waddress >> 8) & 0xff;
X	vaddress->offset = (waddress & 0xff) * 2;
X}
X
X
X/* initialize mmu */
X
X#if defined(minix)
Xextern int brk();
Xextern char *sbrk();
Xstatic char *oldbrk = NULL;
Xstatic char *lmalloc(s)
Xlong s;
X{
X	char *m;
X	if (!oldbrk)
X		oldbrk = sbrk(0);
X
X	m = sbrk(0);
X	if (brk(m + s + 0x2000) != 0)
X	{
X		brk(m);
X		return(NULL);
X	}
X	else
X	{
X		brk(m + s);
X		return(m);
X	}
X}
X
Xstatic free(p)
Xchar *p;
X{
X	brk(oldbrk);
X}
X#endif
X
Xvoid mmu_init(h)
Xstruct header *h;
X{
X	long virt_l;
X	int i;
X
X	if (main_p = (BYTE *)lmalloc(btop((long)word_get(h->len) * 2L) * 512L))
X	{
X		main_l = btop((long)word_get(h->len) * 2L);
X		virt_l = 2;
X		if (!(virt_p = (struct virt_page *)lmalloc((0x200L +
X					sizeof(struct virt_page)) * 2 +
X					sizeof(struct virt_page))))
X		{
X			free(main_p);
X			goto low_mem;
X		}
X	}
X	else
X	{
Xlow_mem:
X		if ((main_p = (BYTE *)
X			lmalloc((long)btop((long)word_get(h->minmem)) * 512L))
X		   	== NULL)
X			no_mem_error();
X
X		main_l = btop((long)word_get(h->minmem));
X
X		for (virt_l = btop((long)word_get(h->len) * 2L -
X			(long)word_get(h->minmem));
X				virt_l >= 2 && virt_p == NULL; virt_l--)
X			virt_p = (struct virt_page *)lmalloc((long)
X				(virt_l * (0x200L +
X				sizeof(struct virt_page)) +
X				sizeof(struct virt_page)));
X
X		if (virt_l < 2)
X			no_mem_error();
X	}
X
X	for (i = 0; i < virt_l; i++)
X	{
X		virt_p[i].page = -2;
X		virt_p[i].lru = 0L;
X		virt_p[i].paddr = (BYTE *)virt_p +
X				(long)(sizeof(struct virt_page) *
X				(virt_l + 1L) + 0x200L * (long)i);
X	}
X	virt_p[i].page = -1;
X
X	pc_page = c_page = virt_p;
X	main_h = (struct header *)main_p;
X}
/