
Although "Frotz" was written for MS-DOS only, it shouldn't be too
difficult to port the interpreter to other operating systems. You
are invited to write front-ends for other systems, but before you
do so you should email me at the address below to avoid double
efforts. First of all, a few warnings:


- This is an early release of Frotz, so the source code may have
  to be changed in the near future. In particular, you can expect
  a new release as soon as standard specification 1.0 is done.

- I don't know how much time I will be able to spend on "Frotz".
  If possible, I'll try to make future releases more porter-
  friendly, but I cannot promise to do so.

- If you want to add proportional width fonts or if you want to
  add "scroll-back" then you will have to change the core of the
  interpreter (in particular, "buffer.c" and "screen.c").

- "Frotz" does not use the virtual memory system of Zip or ITF. If
  you think your machine does not have sufficient memory to hold
  the entire story file in memory, you need to re-write "fastmem.c"
  as well as a few macros in "frotz.h".

- Some basic knowledge about the Z-machine and its IO behaviour
  should help you to write your front-end. You should also be
  familiar with the story file header.

- No, I am not going to write a makefile.


Here comes the good news: "Frotz" passes most OS depending tasks
to its IO interface. The core contains only a few MS-DOS specific
lines of code which are mostly workarounds for 64KB limitations.
Hopefully, these are easy to adapt to your operating system. A list
of MS-DOS specific code in the interpreter core follows.


*** frotz.h:

There are four incredibly hacky macros:

lo_word(v)  represents the lower 16 bits of a long integer
hi_word(v)  represents bits 16 to 31 of a long integer
lo(v)       represents the low byte of a 16 bit word
hi(v)       represents the high byte of a 16 bit word

Note that v as well as lo_word(v), hi_word(v), lo(v) and hi(v)
are lvalues, ie. it is legal to

hi (number) = 13;
lo_word (x1) = lo_word (x2);
hi (lo_word (value)) = fgetc (fp);

How can these macros be defined? First of all, you need to know
in which order your machine stores bytes in a word [and words in
a long integer]. For instance, Motorola 68000 CPUs store the most
significant byte [most significant word] first. In this case,
your macros should look like

#define lo_word(v) ((zword *)&v)[1]
#define hi_word(v) ((zword *)&v)[0]
#define lo(v)      ((zbyte *)&v)[1]
#define hi(v)      ((zbyte *)&v)[0]

However, if the CPU type is unknown or if your compiler simply
refuses to translate these macros then you can still define

#define lo_word(v) ((zword) (v >> 16))
#define hi_word(v) ((zword) v)
#define lo(v)      ((zbyte) (v >> 8))
#define hi(v)      ((zbyte) v)

Apparently, lo_word and lo are no longer lvalues. Therefore you
have to rewrite the code such that these two macros are never
used on the left side of an assignment. Sorry about that.

Next there are a few macros written in assembler. No, no, this is
not as horrible as it seems. All these macros perform very simple
tasks. Actually, assembler was only necessary to work around 64KB
limitations of Intel CPUs (without making use of so-called "huge"
pointers which tend to be inefficient). The following definitions
should work for your machine:

#define LOW_WORD(addr,v)  { hi(v) = zmp[addr]; lo(v) = zmp[addr+1]; }
#define CODE_WORD(v)      { hi(v) = *(pcp++); lo(v) = *(pcp++); }
#define HIGH_WORD(addr,v) { hi(v) = zmp[addr]; lo(v) = zmp[addr+1]; }
#define SET_WORD(addr,v)  { zmp[addr] = hi(v); zmp[addr+1] = lo(v); }
#define GET_PC(v)         { v = pcp - zmp; }
#define SET_PC(v)         { pcp = zmp + v; }

(Note that LOW_WORD is used to access data within the lower 64KB
of the Z-machine memory, ie. the given "addr" is always a zword.)

*** fastmem.c

On MS-DOS systems malloc cannot allocate more than 64KB of memory,
so this module uses the alternative (MS-DOS specific) functions
farmalloc, farfree and farrealloc. If your machine does not suffer
from similar limitations, you can simply replace these functions
with malloc, free and realloc. (You should also remove the line
"#include <alloc.h>".)

Another restriction is that fread can only load less than 64KB in
a single turn. This affects the load_story function which uses a
loop to load the story file in chunks of up to 60KB. This alone
is no problem, since this loop should also work on your operating
system (ugly as it may be). However, the loop contains the line

  FP_SEG (ptr) += 0xf00;

which you should replace with

  ptr += 0xf000;

(Intel CPUs being strange beasts.) Also, remove "#include <dos.h>".


About the IO interface: Take a look at the file "borland.c" which
contains an interface for MS-DOS. All functions which are prefixed
"os_..." are required to build Frotz. For a quick start you should
implement the following functions:

os_process_arguments: Store the story file name in "story_name".
os_init_screen: Prepare screen and initialise some header entries.
os_reset_screen: Shut down.
os_get_cursor: Return cursor position.
os_set_cursor: Set cursor position.
os_display_char: Print ASCII character.
os_read: Read a line of input (and return 13).
os_read_char: Read a single character.
os_erase_area: Clear rectangular area.
os_scroll_area: Scroll rectangular area.

