Notes on porting TADS
=====================

Following are notes on changes made to the OS layer in recent
versions, starting with the most recent changes.  If you're updating
a TADS port, you should refer to the changes made since the last
working version on your system.

At the end of the file, you'll find more general information on how
the portability layer is designed and how to get TADS working on a
new operating system.  If you're porting TADS to a new system for the
first time, you should look at the general notes at the end of this
file.


Quick Start Guide
-----------------

To port TADS to a new platform, you should start by looking at
osifc.h, which specifies the entire TADS Operating System Interface.
You must provide an implementation of this interface for your
platform.

If you're porting TADS to a machine that resembles another platform
where TADS already runs, you can probably use the OS Interface
implementation for that existing platform as a starting point; if
not, you should read the documentation in osifc.h to learn what each
function must do.

You'll also need to construct a makefile or equivalent for your
platform, to compile the C files that make up TADS and link the
results into executables for the TADS Interpreter, and optionally the
TADS Compiler and other tools.  You should refer to an existing
makefile (such as the DOS or Unix makefile) as a starting point.


A Note on Newlines
------------------

Different operating systems have a tendency to disagree on the most
trivial details.  One of these pointless variations that causes a lot
of trouble is "newline" conventions: each OS has its own way of
signaling the end of a line of text in files such as C source and
header files.  In almost every case, the end of a line of text is
indicated by some combination of the special characters with ASCII
values 10 and 13, known respectively as "line feed" or "LF", and
"carriage return" or "CR".  MS-DOS uses the sequence CR-LF; Unix uses
just LF; Macintosh uses just CR; and some system somewhere probably
uses LF-CR.

In many cases, systems are tolerant of "foreign" conventions, but
sometimes the wrong conventions will confuse compilers and other
tools.  If you run into any mysterious compiler errors, or your text
editor or other tools have problems reading or displaying the TADS
source files, you might want to try converting the files to your
system's newline conventions.  One of the easiest ways to do this is
usually to use your UNZIP tool's "auto-convert text files" option
when you unpack the TADS source archive - on command-line systems,
this is usually the "unzip -a" option.


Version 2.5.8 changes
---------------------

* New OS_ATTR_xxx codes:

In the past, the single text attribute was "highlighting," specified
with OS_ATTR_HILITE.  Several new attributes have been added.  First,
there are two new attributes with specific renderings: OS_ATTR_BOLD
and OS_ATTR_ITALIC.  The former should use bold-face if available, the
latter an italic font.  On most character-mode platforms, bold-face
can be approximated with a brighter color, and italics can be ignored.
Second, there are two new abstract attributes: OS_ATTR_EM and
OS_ATTR_STRONG.  These correspond to the HTML <EM> and <STRONG>
attributes, so it's up to the platform to define the actual
appearance.

PORTS CAN IGNORE THE NEW ATTRIBUTES.  These changes have been made in
such a way that everything will continue to work as it has all along
if a port ignores the changes.  OS_ATTR_BOLD, OS_ATTR_HILITE, and
OS_ATTR_EM will all map to the same code, which is the same as the
original OS_ATTR_HILITE code.  OS_ATTR_ITALIC will map to a new code,
but since existing ports don't know this code, it will do nothing.
OS_ATTR_STRONG maps to zero by default (i.e., no change to the codes
at all), so it will also do nothing.  Thus, existing ports will work
the same as they always have with existing games.  

Any port that's capable of displaying italics might want to add
recognition of italics.  If you do this, it might be desirable to add
definitions to your OS-specific header to #define OS_ATTR_EM as
OS_ATTR_ITALIC and OS_ATTR_STRONG as OS_ATTR_BOLD, for consistency
with most HTML browser renderings.  Your #defines for these symbols
will override the defaults, since the defaults will be defined only if
your OS header doesn't otherwise define the symbols.


* MORE banner style:

A new style flag has been added: OS_BANNER_STYLE_MOREMODE.  This style
indicates that the banner should pause for a MORE prompt any time its
text overflows the vertical display area of the banner, to give the
user a chance to read a long passage and acknowledge that it's okay to
show more text.  When this flag isn't set, the default is that long
passages are allowed to scroll off the screen (assuming the
auto-vscroll style is set), even if the user might not have had a
chance to read them.  With this new style flag set, though, a banner
window should pause when text overflows the window, using the same
sort of prompt and user acknowledgment used for the MORE prompt in the
main game window.  Note that there's no sysinfo flag to opt out of
implementing this style; it's important enough that platforms
supporting the banner API at all must support this style.

Platforms based on osgen3.c won't need to do anything to support this
new style, as it's fully handled in osgen3.c.  Other platforms will
have to implement this style in their banner code.


* Parent Windows in the os_banner API:

The new concept of a "parent" window has been introduced into the
banner API.  When a banner window is created, the caller can now
optionally designate a parent banner, which is an existing banner
window from which the new banner's display area will be taken.  In
past versions, there was no explicit parent window, and each new
banner's display area was taken out of the main game window's
rectangle.  When the caller does not specify a parent banner, this
traditional behavior applies; however, when the caller specifies a
parent, the display area is taken from the parent rather than from the
main game window.

For implementations based on osgen.c or osgen3.c, no changes are
needed to any system-specific code.  All of the necessary changes are
handled entirely in osgen.c and osgen3.c.

Implementations that do not implement the banner API must merely to
change the definition of their dummy os_banner_create() function to
match the new prototype.

Systems that implement the banner API and which DO NOT use osgen.c or
osgen3.c must implement the new parent window mechanism.  This will
require several changes.  First, os_banner_create() must be changed to
use the new prototype, which includes an argument for the parent
banner handle.  Second, os_banner_create() must remember the parent
window handle with the internal data structure it uses to represent
the new window.  Third, the system-specific code that calculates the
banner layout must take the parent structure into account; see
os_banner.htm for details of the required new layout algorithm.
Fourth, if the implementation supports drawing banner window borders
(as specified through the style flags), it will have to take into
account the new rule that a border is drawn to the horizontal or
vertical extent (as appropriate) of the *union* of the banner and all
of its child windows.  Fifth, os_banner_delete() might need to hide or
set to zero size any children of the banner being deleted, since once
a parent is deleted, its children become invisible, although they
remain valid as abstract objects until explicitly deleted.

* os_nonstop_mode():

This new function lets the portable code tell the OS layer that it
wants to run in "non-stop" mode, which means that MORE prompting (or
any local equivalent) should be disabled.  By default, non-stop mode
is turned off; this function lets the portable code turn it on and
off.  Character-mode platforms based on osgen.c/osgen3.c don't have to
worry about this.  Platforms where MORE prompting doesn't exist or is
provided by the portable console layer can simply provide a dummy
implementation.  Platforms where the OS layer handles MORE prompting
should provide a real implementation of this function.


Version 2.5.7 changes
---------------------

IMPORTANT - if you're using a platform based on osgen.c, you can skip
#1 through #5, because these changes are handled by the portable osgen.c
implementation.  Skip to #6 if you're using osgen.c

1.  The function os_hilite() has been DELETED.  You should remove any
implementation of this function you provide.

2.  The new function os_set_text_attr() replaces os_hilite().  This
new function is used to set text attributes in the main window.  If
you had an implementation of os_hilite() that simply returned zero,
your os_set_text_attr() need do nothing at all.  If your os_hilite()
implementation did anything else, it can be implemented with something
like this:

  void os_set_text_attr(unsigned int attr)
  {
    os_printf("%c", (attr & OS_ATTR_HILITE) != 0 ? ON : OFF);
  }

where ON is to be replaced by the character code that os_hilite(1)
returned in your old implementation, and OFF is to be replaced by the
character code that os_hilite(2) returned.  If possible, you should
optimize this by doing nothing when the current hilite mode is not
being changed.  The purpose of this change is to generally improve the
osifc design, and to make it more extensible by providing a structured
way to add new attributes to be added in the future.

The meanings of colors in os_set_text_color() and os_set_screen_color()
have changed.  The values are now encoded RGB values; some macros are
provided in osifc.h for manipulating these color values.  Platforms
based on osgen.c will NOT have to do anything for this change, since
osgen.c defines the osifc-level color routines.

3.  The os_printf() and os_vprintf() routines have been DELETED.  These
have been replaced by os_printz() and os_print() (see #4).

4.  The new routines os_printz() and os_print() have been ADDED.  These
routines do essentially what os_printf() and os_vprintf() formerly did,
but with a greatly simplified interface.  These functions are notably
different from the former os_printf() and os_vprintf() in some important
ways:

   4a.  These routines do NOT take a printf-style format string, but
   simply take a string to display directly.  There is no need to perform
   any parameter substitutions on the string.

   4b.  os_printz() takes a NULL-TERMINATED string, while os_print() takes
   a COUNTED-LENGTH string (the byte length is given as a separate argument),
   and thus CANNOT assume that the string is null-terminated.  os_printz()
   for (PRINT-Zero-terminated) can be implemented as a simple call to
   os_print, with the string's length computed with strlen().

   4c.  These routines NO LONGER have to worry about the "highlight" escape
   code sequences.  Highlighting is handled with the new text attributes
   settings (see #2 above), so strings presented to os_print will no longer
   have any embedded escape codes.  The only special characters that these
   routines are now expected to recognize are '\n' and '\r'.

5.  Several new SYSINFO_xxx codes have been added to osifc.h.  Your
os_get_sysinfo() implementation should be updated for the new codes.


6. [Begin osgen.c changes]

All platforms based on the semi-portable osgen.c implementation must
make some small adjustments to their ossxxx routines.  THE FOLLOWING
NOTES APPLY *ONLY* TO OSGEN.C PLATFORMS - if you're not linking with
osgen.c, ignore the following.  Note that these aren't changes you
have to make to osgen.c itself - these are changes you have to make
to your system-specific code that osgen.c relies upon.

There are now two different "osgen" implementations.  First, there's
the traditional osgen.c - this is the one you'll get by default if
you do nothing, since it's the one your makefile (or equivalent)
already uses.  This version of osgen.c has been reworked a little,
but it's substantially the same as in past versions.  Second, there's
a new version called osgen3.c - if you like, you can switch to this
one.  osgen3.c is a REPLACEMENT for osgen.c - you use EITHER osgen.c
or osgen3.c, but not both.  If you switch, simply substitute osgen3.c
for osgen.c wherever it appears in your makefile.

Okay, so should you switch to osgen3.c, or stick with osgen.c?  In
the long run, the answer is that you should switch; but when you do
so is up to you.  What you get with osgen3.c is a full implementation
of the new TADS 3 "banner API," which lets TADS 3 programs control
the screen layout much more precisely than TADS 2 programs could.  If
you are building the TADS 3 interpreter, you should definitely switch
to osgen3.c, to give TADS 3 programs the full capabilities of the new
banner API.  If you're building only a TADS 2 interpreter, there's
less immediate benefit in switching, because TADS 2 programs don't
have any way to access the banner API.  The main reason not to switch
if you don't have to is that osgen3.c is a substantial rewrite that
hasn't been around nearly as long as osgen.c and thus hasn't had
nearly as much practical testing; sticking with osgen.c is less
likely to introduce new bugs.  On the other hand, it should be
practically no work to switch to osgen3.c - the only change should be
replacing osgen.c with osgen3.c in your makefile.  If you do plan to
port the TADS 3 interpreter at some point, switching to osgen3.c now
would have the advantage that you'll feel safer using osgen3.c when
the time comes for the TADS 3 port, because you will have been using
osgen3.c between now and then.

You'll have change your osxxx code as described in the sub-topics
below, regardless of whether you stick with osgen.c or switch to
osgen3.c.

6a. Several global variables have been eliminated.  You can delete
these from your osxxx.h headers and remove calcaulations from your
osxxx.c source files.  (It's not vital that you do this, but it's
encouraged in the interests of general clean-up.  If you're still
using any of these variables for your own purposes, of course, you are
free to keep them - just be aware that osgen.c no longer needs them.)
The following variables are no longer used in osgen.c:

  ldesc_color
  ldesc_column
  ldesc_curline
  ldesc_line
  max_column
  max_line
  score_column
  sdesc_column
  sdesc_line
  text_column
  text_lastcol
  text_normal_color
  text_bold_color

Note that you might not want to delete the xxx_color variables, since
you might want to use these same values in your ossgetcolor()
implementation (see "fifth..." below).  However, osgen.c no longer
uses these variables, since it now instead calls your ossgetcolor()
routine to determine what color values to use.

If you switch to osgen3.c, the following globals are also eliminated
(or, rather, can be eliminated, as osgen3.c doesn't require them):

  sdesc_color
  text_color

6b. Your osxxx.c code MUST NOT set or modify G_os_pagelength or
G_os_linewidth.  In the past, the osxxx.c code was responsible for
setting these, and was aware of the status line location and so forth.
Don't set these variables any more.  Instead, set the new global
variables G_oss_screen_width and G_oss_screen_height to the height and
width of the screen, in characters - DO NOT make any adjustments for
status lines or anything else, as osgen.c will take care of that.  Be
sure to set these variables in your os_scrini() routine, so that
they're available during osgen.c's initialization.

6c. If the screen size can ever change dynamically after
initialization, you MUST call the new function
osssb_on_resize_screen() immediately after updating the global
variables G_oss_screen_width and G_oss_screen_height.  This will
ensure that osgen.c has a chance to refigure its internal layout
parameters according to the new screen size.

6d.  You should #include "osgen.h" in your osxxx.c file(s).

6e.  You must implement the new routines oss_get_sysinfo() and
ossgetcolor().  (These actually were added just before the 2.5.6
release, so if you've sync'ed up lately, you probably have implemented
these already - they haven't changed in this version.)  Refer to
osgen.h for details on how these are supposed to work.  These new
routines provide text color support, so that games can explicitly set
the colors of the text they display; color support is optional, but if
you don't support color, you must must still provide minimal
implementations of these routines to return the same color scheme
you've used in the past.  

In the past, several global variables (text_normal_color,
sdesc_color, etc) had the "oss color codes" to use for different
types of text - these color codes were passed to ossdsp(), ossclr(),
and so on for rendering by your osxxx.c code.  osgen.c no longer uses
most of these; it only uses sdesc_color and text_color.  If you're
switching to osgen3.c, even those hold-outs are gone.  Instead, the
osgen layer calls your ossgetcolor() routine to get the color code to
use for each case.  If you don't want to support any more color than
you did in the past, you can simply implement ossgetcolor() so that
it looks for the various abstract color codes (OS_COLOR_TEXT,
OS_COLOR_STATUSLINE, etc), and returns the corresponding global
variable value.  The advantage of the new scheme is that it allows
the game code to set *specific* colors (e.g., red, blue, cyan) for
individual bits of text, as long as your osxxx.c code (and your
display hardware, of course) can support specific colors.

6f.  The macro OSGEN_ATTR_BOLD has been renamed to OS_ATTR_HILITE.  If
you ported the 2.5.6 release, you might have a reference to this
macro; the meaning is the same, so all you have to do is change the
name.  For convenience, OSGEN_ATTR_BOLD is now defined as equivalent
to OS_ATTR_HILITE, but the new name should be used as soon as
possible.

6g.  The OS_COLOR_xxx symbols have been renamed to OSGEN_COLOR_xxx.
The meanings are the same as they were; the name change reflects the
change in the osifc-level color scheme.

6h.  Eight new OSGEN_COLOR_xxx values have been introduced, to allow
for somewhat better granularity in setting colors at the system level.
With the new colors, the OSGEN_COLOR_xxx values can specify a total of
16 colors, which correspond to the eight ANSI colors at "low
intensity" and "high intensity"; the low-intensity set is essentially
the high-intensity set at half brightness.  On most systems based on
osgen.c, if this full range of colors is available, the brighter half
of the range will be used to show high-intensity text, so in fact only
eight colors will really be available; on such systems, ossgetcolor()
should simply collapse the 16 colors down to the 8 ANSI colors, by
treating the low-intensity and high-intensity version of a given color
the same, and then pick from the low- or high-intensity version
according to the boldness attribute.  Even for systems that collapse
the colors in the this manner, though, there is still value in having
the broader range, in that the full range of 16 colors can be selected
for backgrounds, which do not have a boldness attribute and thus are
free to offer the full range of 16 colors to clients.

6i.  You must implement the new routine oss_raw_key_to_cmd().  This
routine's purpose is to map "raw" keystroke codes to command-editing
CMD_xxx codes, essentially mapping results from the style that
os_getc_raw() uses to the style os_getc() uses.  This routine was
created to give the OS implementation more specific control over the
mapping of raw keystrokes to command-editing functions.  For most
systems, you can probably just copy the MS-DOS implementation, in the
source file msdos/osdos.c, making any desired changes to the control
key or other mappings.


[End osgen.c changes]


Version 2.5.6 changes
---------------------

Several new SYSINFO_xxx codes have been added - osifc.h has the full
list.  The system-specific code that provides system information
should be updated to handle the new codes.

A new file-open function, osfoprwt(), has been added.  This function
is the text-mode equivalent of osfoprwb(): it opens a text file for
both read and write access, keeping intact any existing contents.  I
have attempted to provide a suitable implementation in the source
code for each ported version of which I have a copy in my source
tree, but a platform expert on each target system might want to check
my work to make sure it's correct for their system.

A second new file-open function, osfoprwtt(), has been added.  This
function is the text-mode equivalent of osfoprwtb(): it opens a text
file for both read and write access, truncating any existing file.
I've attempted to provide a suitable definition for each platform for
this function as well.

The new function os_update_display() has been added.  This function's
purpose is to process any pending redraw events immediately, if
applicable to the system.  This function only needs to be implemented
on event-driven operating systems where the display is drawn in
response to redraw events generated by window region invalidations.
(If that doesn't mean anything to you, you're almost certainly not on
such a platform - the Windows and Macintosh GUI's both use this kind
of drawing scheme, but text-mode versions would certainly not.)  The
purpose of this routine is to update the display prior to a long
computation, to avoid the appearance that the program is frozen
during the computation delay.

The new functions os_set_text_color() and os_set_screen_color() can
optionally provide the game with control over display colors.  These
are described in osifc.h.  These functions are optional; if they're
not suitable for a given platform, simply provide empty
implementations.

The new functions os_gets_timeout() and os_gets_cancel() provides an
event-oriented interface for reading a command line from the keyboard.
This function is similar to the regular os_gets(), but has a timeout
feature that allows the keyboard read to be interrupted after a
specified interval has elapsed, and then possibly resumed later.
Timed keyboard input is optional; if it can't be implemented on a
platform, simply provide an implementation for os_gets_timeout() that
returns OS_EVT_NOTIMEOUT when a timeout is provided, and an empty
implementation for os_gets_cancel()..  Note that even if timed input
is not allowed, os_gets_timeout() should minimally call the plain
os_gets() when the caller does not specify a timeout, and only return
the OS_EVT_NOTIMEOUT error when a timeout is actually requested by the
caller.

A new interface for managing "banner" windows in the process of being
added.  This is a work in progress, and you should just ignore it for
now, providing only stub implementations.  The new interface consists
of a set of functions (about a dozen) whose names are of the form
os_banner_xxx(); I'm still in the process of working out the final
details, so the set may change in the future.  These new functions,
when they're completed, will provide functionality similar to the HTML
TADS <BANNER> tag, but without the limitations that arise from using a
single output stream to control all aspects of the display.  In the
future, this interface will allow for for implementation of
banner-like behavior in text-only platforms, allowing more flexibility
for games in their use of text-mode displays.  The banner interface
will always be entirely optional; if it is not feasible or desirable
to implement the interface, a platform will be able to provide
do-nothing implementations for these routines.


Version 2.5.2 changes
---------------------

In preparation for TADS 3, I've been tightening up the interfaces
between the OS layer and the portable code.  My goal is to ensure
that the a common OS layer can be shared by TADS 2 and TADS 3, which
will dramatically simplify the porting of TADS 3 by eliminating the
need to write a new set of OS routines.  Porting TADS 3 will simply
be a matter of compiling and linking the TADS 3 portable code with
the existing TADS 2 OS code for your platform; the only coding you
should have to do is to create the makefile.

I've been working on this OS interface improvement for some time.
This process started with the creation of osifc.h, which provides us
with a comprehensive definition of the entire interface that the
portable code uses to call the OS code.  I've also been expanding and
improving the OS interfaces slightly over the past few releases, but
I've been trying to minimize these changes to minimize the resulting
porting work created.

With this release, I've addressed a new area, which is references
from the OS code to the portable code.  In general, the OS code
should never call the portable code or use any global variables
defined in the portable code; doing so ties the OS code to a
particular portable system, which makes it difficult to re-use the OS
code in a new system (such as TADS 3).

The OS code should NOT henceforth refer to ANY function or global
variable defined in the portable code.  If your OS code refers to
anything in the portable code, your OS code will not work with TADS
3, because those portable symbols will probably not be defined at all
in TADS 3.

I've tried to remove all of the references I could find from the OS
code into the portable code.  However, until TADS 3 is ported to the
existing platforms, where the linker can root out the missing
symbols, it is difficult to know for sure that all of the references
are gone.

* OS code should no longer call runstat().  Most os_gets()
implementations started by calling runstat() to update the status
line prior to reading input.  The OS code is no longer responsible
for this.  You should simply remove any runstat() calls from your
OS code.  If you have runstat() calls that are needed in places
other than at the start of os_gets(), contact me (mjr_@hotmail.com)
if you would like advice on how to remove the dependency and I'll
try to help figure out what to do.

* The global variables "pagelength" and "linewidth" have been renamed
to G_os_pagelength and G_os_linewidth.  This formally moves these
variables into the OS layer rather than leaving them in the portable
formatter.

* The global variable "moremode" has been renamed to G_os_moremode,
moving it into the OS layer.

* OS routines should no longer call tio_is_html_mode() (or any other
tio routines).

* OS routines should no longer call qasclose().  Most of the
os_term() implementations in the OS code were calling this routine;
this should instead be handled in the portable code, so the OS code
should not use this method at all.

* OS code should no longer call outformat() or getstring().  The
text-only implementations of os_askfile() and os_input_dialog()
called these routines, because they implemented their dialogs using
formatted text.  To address this, I've moved these text
implementations to the portable layer; there is no longer a text-only
version of os_askfile() or os_input_dialog().  Refer to askf_tx.c,
askf_os.c, indlg_tx.c, and indlg_os.c for details on the new
portable-layer implementations.

MAKEFILE CHANGES: You must include one of askf_tx.c or askf_os.c in
each executable you build.  You must include one of indlg_tx.c or
indlg_os.c in each executable.  Refer to these files to determine
which one to choose.  In general, the _tx versions are text-only
implementations -- these do not invoke os_xxx routines; the _os
versions simply pass through the operation to the corresponding
os_xxx routines.  You should choose the _os version if you have a
corresponding os_xxx implementation that you want to use; you should
choose the _tx version if you want to use the plain text version.
If your os_xxx routine was calling outformat() or getstring(), you
should simply delete your os_xxx routine entirely and use the _tx
version; otherwise, keep your os_xxx routine and use the _os version.

OTHER CHANGES:

* added os_is_special_file()

* added os_uninit()

* added OS_CHARMAP_FILECONTENTS identifier



Version 2.5.1 changes
---------------------

* I added a new command code for os_getc(): CMD_EOF.  This new code
indicates that "end of file" has been reached on the console input;
this usually means that the player has terminated the application
through some means such as closing its main window, or disconnected
the terminal, or something like that.  os_getc() should return this
new code when it detects this type of condition so that code that
calls os_getc() can finish up whatever it's doing and terminate the
application gracefully.

* There's a new function called os_getc_raw().  This is conceptually
a lower-level version of os_getc().  The difference is that os_getc()
returns "translated" keystroke CMD_xxx codes, whereas os_getc_raw()
returns "raw" CMD_xxx codes.  The translated codes are higher-level
functional codes; for example, on Unix, when the user types Ctrl-E,
os_getc() would return CMD_END, because Ctrl-E is bound to the
end-of-line command.  In contrast, os_getc_raw() would simply return
ASCII 5.  Similarly, on DOS, if the user presses the Escape key,
os_getc() would return CMD_KILL, but os_getc_raw() returns ASCII 27.
Note that some keys return different CMD_xxx codes for os_getc() and
os_getc_raw(); for example, on DOS, if the user presses F1, os_getc()
returns CMD_SCR (to toggle scrollback mode), but os_getc_raw() returns
CMD_F1.

The purpose of os_getc_raw() is to allow lower-level access to keystroke
information, particularly for the inputkey() TADS function, while still
preserving the port-specific functional mapping that os_getc() affords.

Refer to osifc.h for documentation of the new function.  Note that the
CMD_xxx codes defined in osifc.h are now commented to indicate which
command codes are "translated" and which are "raw"; when a particular
key maps to one of each type, os_getc() should return the translated
CMD_xxx code and os_getc_raw() should return the raw code.

* The osfoprwb() function has traditionally been implemented
incorrectly.  On most platforms, this has been implemented as a call
to fopen() with the mode "r+b" (or simply "r+" on platforms with no
text/binary mode distinction), following the example of the DOS code.
In fact, the intended function, which was not adequately documented
in the osifc.h comments, was to open an existing file or create a new
file if it didn't already exist.  The C fopen() "r+" mode fails if the
file doesn't exist.  The intended behavior has now been correctly
documented in osifc.h, and the DOS, Windows, Unix, and Mac versions
have been changed to use the correct behavior.


Version 2.4.1 changes
---------------------

* New OS function: os_input_dialog().  A default character-mode
implementation in osgen.c should suffice for most ports, but GUI
ports should show a dialog box if possible.  The character-mode
implementation in osgen.c is selected at compile time with #define
symbol USE_STDIO_INPDLG, which osgen.c defines implicitly if
USE_STDIO is defined.

* New OS function: os_get_str_rsc().  Most platforms should be able
to use the default implementation in ostadrsc.c (in the generic
code directory).  Where possible, though, this function should be
implemented using native OS string resources; this will make it
easier for translators to localize the TADS executables.

* TADSVER.TXT has been changed to TADSVER.HTM, and DOSVER.TXT is
now DOSVER.HTM.

* The interface to the os_askfile() function has changed very
slightly, in that the result code values are now more precisely
specified.  In the past, this function simply returns zero for
success and non-zero to indicate failure of some kind.  The result
codes can now indicate the type of failure; in particular, the
function can distinguish actual errors from the case where the user
simply chooses to cancel the dialog.  Refer to osifc.h for details.
I've attempted to change all of the OS sources that I have in my
source tree; experts on the code for the individual platforms are
encouraged to double-check my changes.


Version 2.4.0 changes
---------------------

* os.h has been reorganized to make it cleaner and more consistent.
All of the DOS code has been removed from os.h and moved to new
DOS-specific headers; this leaves os.h as a very simple "switchboard"
file whose only function is to select the appropriate set of headers
to #include based on the system macro settings.  All of the non-DOS
headers already worked this way, so this change should be transparent
to other ports.

* osifc.h now has (as far as I can tell) complete documentation of
the entire TADS Operating System Interface.  In particular, all of
the file-related functions (osfoprb, osfrb, etc) are now specified
and documented in osifc.h, as are the former "library" functions
(osmalloc, osfree).  This change should not affect any existing code;
the additions are mostly comments.

* The os_find_first_file() and os_find_next_file() interfaces have
changed.  Two new parameters, outpathbuf and outpathbufsiz, have been
added; the new buffer is to receive the full path of the current
file, so that the caller doesn't have to attempt to construct the
path name from its components using possibly non-portable
assumptions.  This should have minimal impact, since the only ports
that appear to implement these functions currently are DOS, Windows,
OS/2, and Macintosh.  Refer to osifc.h for documentation.

* The os_progress() interface has changed slightly.  This function no
longer takes a (struct linfdef *) argument, which tied the function
to the particulars of an internal structure in the TADS 2 compiler;
instead, the function now takes a filename string and a line number.
This change should have minimal impact, since only the Macintosh port
currently provides a non-trivial implementation of this function.


Version 2.3.0 changes
---------------------

* ATTENTION UNIX USERS - If you run into weird display problems in
the interpreter, especially with spurious extra spaces at the
beginning of each line, try these definitions in your makefile:

  LIBS= -lncurses
  CFLAGS= -DHAVE_TPARM (plus whatever other CFLAGS you were already using)

* The existing os_term() function is now used more rigorously.  In
the past, the generic code called exit() directly in a few places,
which prevented the OS layer from doing any clean-up at termination.
The generic code should now use os_term() exclusively to terminate
execution.  This shouldn't require any new porting work, since
nothing about os_term() has changed -- the only change is that the
generic code is calling it more predictably now.  However, a few
ports may accidentally have omitted an os_term() implementation from
some executables, since it wasn't always needed before; if you get a
link error for this symbol during building, adjust your makefile to
include an os_term() implementation.

* A new file, oem.c, defines some global strings for use in identifying
the version of TADS.  You must fill in that file with a couple of
customized settings for your version.  Please refer to oem.h and
oem.c for details on how to do this.

* A few new OS interface functions have been added.  These functions
are described in comments in osifc.h.  The new functions are:

  os_get_sys_clock_ms()
  os_sleep_ms()
  os_get_event()
  os_set_title()
  osfdel_temp()

These functions should be reasonably simple to implement on most
systems.  os_get_event() in particular can simply degrade to
os_getc() with some additional argument checks and changes in the
return value if it's hard to implement fully on your system; the
USE_STDIO version in osgen.c can be used as a default implementation.

Note also that a completely portable implementation of os_sleep_ms()
is in msdos/oswin.c.  You can use this implementation if you wish,
but the function is included in the OS interface so that you can
replace it with something more suitable for your platform.  The
implementation in msdos/oswin.c discards keystrokes and other events
that occur during the delay, which may be undesirable on your system.
This implementation has the desirable effect of processing UI events,
such as window sizing, during the delay.

Most platforms can provide an empty implementation of os_set_title();
this function merely notifies the OS layer that the game has set a
title string via the HTML <title> tag.  If it's convenient, the OS
layer can use the title string as a window caption, or whatever else
makes sense.  Most character-mode display code will simply ignore
this; osgen.c has a default implementation that does nothing.

osfdel_temp() is a new function to complement os_create_tempfile().
This function deletes a temporary file previously created with
os_create_tempfile(), after the temporary file has been closed;
callers previously used osfdel(), the generic file deletion function,
to delete these temporary files.  The purpose of this new function is
to support systems that can be instructed to delete temporary files
automatically when closed; on such systems, a call to osfdel() is
redundant (and problematic), since the system will already have
automatically deleted the temporary file by the time the caller gets
around to invoking osfdel().

osnoui.c provides a simple implementation of osfdel_temp() that simply
calls osfdel(); this works with the implementation of os_create_tempfile()
in osnoui.c, so you won't need to make any changes if you're already
using this file.  If you're using a customized os_create_tempfile(),
you may want to provide a correspondingly customized osfdel_temp().
In particular, if your os_create_tempfile() opens the file in such a
way that the underlying OS will automatically delete the file when
closed, your osfdel_temp() should simply do nothing.

* The os_askfile() interface (defined in osifc.h) has been changed to
provide more information about what kind of prompt to use.  The extra
parameters indicate whether we're opening an existing file or saving
a new file, and what type of file we're interested in.  Many GUI
systems use different dialogs for opening and saving files, and
filter files displayed in a file selector dialog according to the
type of file to be chosen.  Systems that don't need the extra
information can ignore the new parameters; they're purely to make it
easier for the system code to determine what type of dialog to show.

I've updated my copies of the MSDOS, Win32, Mac, and Unix sources for
the new os_askfile interface, but I don't have a copy of every
port-specific version, so you may need to propagate this change into
your version.

* The #define's for the OSFTxxx codes (the file type codes) are now
in osifc.h.  In the past, these were scattered among the different
system-specific headers for no good reason -- these are used by
portable code, so they are necessarily part of the OS interface, and
hence belong in osifc.h.  If you encounter any errors with redundant
#define's for these symbols, you should simply remove the #define's
from your system-specific headers and use the ones in osifc.h.

* The #define's for the CMD_xxx codes (the os_getc() extended keystroke
codes) are now in osifc.h.  In the past, as with the OSFTxxx codes,
these were scattered among the system-specific headers.  It's desirable
to be able to use these key codes in the portable code, so these are
now part of the general OS interface.  As with the OSFTxxx codes, if
you run into any compilation errors with redundant #define's for CMD_xxx
symbols, you should be able to remove the #define's from your system-
specific headers and use the new osifc.h definitions.


Version 2.2.6 changes
---------------------

In past versions, the release notes for generic changes and platform-
specific changes were combined into a single file, which had to be
maintained separately on each platform.  For example, the DOS release
notes were in TADSVER.DOS.  To create a comprehensive set of release
notes for another platform, someone porting TADS had to sift through
TADSVER.DOS to pick out the generic changes, then add any changes
specific to the ported version.

In order to remove this extra work, I've broken up the release notes
into two separate files.  The new file TADSVER.TXT contains only the
generic changes.  Since these changes will automatically be included
in any port (because such changes are always in the portable portion
of the code), the distribution for a port should always be able to
include TADSVER.TXT unchanged.  The separate new file TADSVER.DOS
contains changes that apply only to the DOS version.  Since such
changes are only in the DOS osxxx code, they should not affect any
other platforms, so only DOS users should need to look at this file.

When creating a ported version, you can now simply create your own
platform-specific release notes file where you can describe any changes
that you made that apply only to your platform.

Please let me know (mjr_@hotmail.com) the name of your port-specific
release notes file, and I'll add it to the table at the top of
TADSVER.TXT, which refers users to the appropriate file for each
platform.  (You may want to add an entry to the table yourself for
your initial version, if you plan to include TADSVER.TXT with your
distribution.)


Version 2.2.4 changes
---------------------

I've changed the source distribution zip file's layout slightly to
make the TADS source tree more self-contained.  In the previous
version, several files were in a separate LIB directory, which was at
the same level in the hierarchy as the TADS2 directory.  This was an
undesirable layout for some people, since it meant that TADS had two
high-level directories.  Since keeping the files in a separate
directory doesn't serve any real purpose currently (the separation is
historical), I've merged these files into the base TADS directory
(except that a few of the files are now in TADS/MSDOS, because
they're DOS-specific).  Of course, you can still lay out your source
files however you want them, of course, but if you follow the layout
in the zip file, you'll need to adjust your makefile for the changed
location of these files.

If you change the default memory sizes in your osXXX.h file, you should
also define message strings that correspond to your new defaults for the
usage messages.  To do this, look at errmsg.c, and notice the big list
of TxD_xxxSIZ_MSG definitions.  For each value that you override in your
OS header, you should provide a corresponding TxD_xxxSIZ_MSG definition
that looks like the one in errmsg.c but uses your changed default value.


Version 2.2.3 changes
---------------------

The operating system interfaces have changed somewhat between version
2.2.2 and 2.2.3 (the HTML TADS release).  The OS interfaces have been
stable for a long time, so most systems where TADS has been ported
should have OS-dependent implementations that conform to the 2.2.2
interfaces.  Unfortunately, all of these ports will have to be reworked
slightly to accomodate the changes in 2.2.3.

The changes in 2.2.3 should be fairly minor, though, so it shouldn't
require a huge effort to upgrade port-specific code that worked with
the previous version.  The main changes are that the OS interfaces
have been rearranged slightly in the header files (note in particular
the creation of osifc.h), and some of the functions that were in
osgen.c have been moved to the new file osnoui.c.  A few functions
have had minor changes to their interfaces as well.  It will probably
be necessary to make some small changes to your makefiles because of
the rearrangements.

One of the biggest changes may be the use of ANSI-style function
prototypes throughout the code.  Depending on your compiler, you may
or may not have to change your OS function implementations to use ANSI
prototypes.


==============================================================================

General notes on porting TADS
-----------------------------


Code Organization
-----------------

The TADS code is divided into portable and system-specific sections.
In porting TADS to a new platform, only the system-specific portions
should need to be changed.  If any changes are needed to the portable
code, we consider the portable code in error and will try to correct
it so that it is the same on all platforms.  We want the portable
portion to have a single set of sources, without port-dependent
ifdefs, across all platforms.

For the most part, the system-specific sections are isolated in
files with the prefix "os", and system-specific functions and macros
all begin with "os" or "OS".

Historical note: At one point we started to group some code that High
Energy was internally sharing between multiple products into a code
library, all of whose files start with "L".  The file los.h formerly
many system-specific macros and definitions; these have been moved
into the OS files along with everything else.

oem.h
-----

This file defines information about the person who built a particular
version ("OEM" for "Original Equipment Manufacturer").  Refer to oem.h
for details about how to set up the definitions there.


osxxx.h, os.h, and osifc.h
--------------------------

The first thing to do when starting a new port is to create a new
system-specific header file for your platform.  You should choose a
name for the header based on your platform name; for example, on DOS,
the file is osdos.h, and on Unix it's osunix.h.

Next, you must define a C preprocessor macro that will identify your
platform.  This macro will be used to select the appropriate code to
include in your version of TADS, using #ifdef preprocessor directives
in the TADS code.  Many compilers automatically pre-define a symbol
for this purpose, in which case you should use this symbol;
otherwise, make up a symbol of your own and define it on the C
compiler command line or equivalent when you compile the TADS C files.

Edit the file os.h.  This is a "switchboard" file that selects an
appropriate system-specific header to include.  The TADS portable C
files #include os.h, and os.h must in turn #include your header file.
You should add a few lines to os.h to #include your header; follow
the example of DOS, Unix, and the other platforms:

#ifdef FROBNIX_OS
/* Frobnix operating system definitions are in osfrob.h */
#include "osfrob.h"
#endif

You shouldn't add anything else to os.h - the rest of your code should
go in your own "osfrob.h" file.

Now you must write the code in your OS-specific header ("osfrob.h" in
the example above).  To do this, refer to osifc.h, which defines the
TADS Operating System Interface, which is what you must implement for
your machine.

The purpose of your osxxx.h is to isolate certain platform-specific
definitions to a well-defined location in the code.  The rest of the
TADS C code is written so that it uses the definitions in osxxx.h;
this way, the other code doesn't have to be changed when moving TADS
to a new platform.

The file osifc.h contains the specification and documentation of the
TADS Operating System Interface, which contains the portable
interface definitions for functions, types, and macros that must be
tailored to each platform.  osifc.h contains a portable interface to
code that varies by platform; because the interface is portable, the
rest of the TADS code doesn't have to know anything about different
platforms, since it can expect the exact same functions to be
available on every machine.  osifc.h contains only portable code, so
you shouldn't make any changes in this file.

You can probably take one of the existing osxxx.h implementations as
a starting point, depending on your hardware and operating system.
For example, for a 68000 or 68000-like processor, you might want to
start with the Macintosh header (osmac.h), since the alignment and
byte ordering macros will be appropriate.  For an 8086-like
processor, start with the DOS headers (os.h and los.h).  Other
platforms may need additional work.

IMPORTANT NOTE: Do not make changes in osifc.h - this file should never
contain any #ifdef's for different platforms, because it defines a
portable interface that is the same everywhere, even though the
implementation of the interface varies by platform.  In particular,
the #define constants (OS_EVT_xxx, SYSINFO_xxx, and so on) MUST be the
same on all platforms, because some of these values can be used
programmatically by TADS games; a game can be compiled on one platform
and run on any other machine, so these constant values must be the same
everywhere for games to work properly.


Datatype configuration
----------------------

TADS makes relatively few assumptions about datatype sizes.  TADS
expects that shorts are at least 16 bits, ints are at least 16 bits,
and longs are at least 32 bits.


System-specific function implementation
---------------------------------------

Depending on your platform, you may be able to re-use some code that
was originally written for the DOS platform, but works with some
minor changes on other types of machines as well.

The files osdos.c, osgen.c, and osnoui.c provide an implementation of
the system routines for DOS.  osgen.c and osnoui.c should be usable
on any system with DOS-like display characteristics.  Note osgen.c
and osdos.c check to see if several USE_xxx preprocessor symbols are
defined; these macros are NOT defined anywhere in the source, but are
to be defined by the makefile.  On DOS, these os files are compiled
multiple times with different combinations of the USE_xxx symbols to
produce different object files for linking the compiler and run-time.

A stdio (C run-time library "standard input/output") implementation
of many of the routines can also be selected by defining the
preprocessor symbol USE_STDIO.

The file osnoui.c is similar in purpose to osgen.c.  The functions
implemented in osnoui.c are semi-portable implementations of functions
that have no user interface component ("no UI").


Building the system
-------------------

TADS consists of three main pieces: the compiler, the run-time, and
the debugger.  Refer to the DOS makefile to see which object files
are included in each.  Note that it may not be possible to let a
librarian/archiver resolve the links for all symbols, because a few
of the object files provide overlapping sets of symbols -- it is
necessary to manually include such object files in the links.  (The
overlapping symbol sets are generally used to provide empty
definitions for certain functions that are referenced but not
actually used by one executable, but must be fully implemented in
another.)


Debugger
--------

The debugger diverges somewhat from the convention of keeping the
os-dependent functions in a file prefixed by "os" or "los".  The
debugger's user interface is implemented in the file dbgu.c on DOS,
and dbgumac.c on Macintosh.  The DOS version also has a file, osdbg.c,
which provides lower-level functions; it should be possible to port
the debugger to a new platform by using the DOS user interface and
replacing only osdbg.c with an appropriate set of functions for the
new system.  However, for any system without DOS-like display and
input device characteristics, the entire user interface will usually
need to be replaced; for example, on the Mac, dbgu.c is not used at all,
but is replaced by dbgumac.c.  This separation of the user interface
provides maximum flexibility for the debugger's user interface while
minimizing the amount of work to port it to a new platform.


Testing
-------

The first test is to build a run-time and see if it can run games
compiled on another system.  The second is to build the compiler, use
it to compile game on your system, and see if that runs.

You can further test using the regression tests.  Compile DEEP.T,
then run tr like this:

      tr -i dsdwalk.in -l dsdwalk.new deep

Then compare dsdwalk.new (the new log generated by your version of
DEEP) with dsdwalk.log (the reference version) -- if they're
identical, your system is probably in pretty good shape.  You can
test similary with DITCH.T and DDDWALK.IN, and BUGS.T and BUGS.IN.


MS-DOS and Windows Compilation
------------------------------

Two makefiles are provided for compilation on MS-DOS and Windows
machines; both makefiles are in the msdos directory.  To avoid
confusion, these makefiles build object files into separate
directories, and name their executables differently from one
another.

makefile.bc is for compilation with the 16-bit Borland C compiler,
version 4.5.  With this makefile, you can build the real-mode and
protected-mode 16-bit DOS executables.  (You'll need the Borland
Power Pack for DOS in order to build the protected-mode versions
of the executables.)

Note that you should run makefile.bc with Borland make.

makefile.bc compiles into objs (for real-mode object files) and xobjs
(for protected-mode object files), and generates the following
executables:

    tc.exe       - real-mode TADS compiler
    tr.exe       - real-mode TADS run-time
    tdb.exe      - real-mode TADS debugger
    tcx.exe      - 16-bit protected-mode TADS compiler
    trx.exe      - 16-bit protected-mode TADS run-time
    tdbx.exe     - 16-bit protected-mode TADS debugger
    maketrx.exe  - single-file executable binder
    tadsrsc.exe  - TADS resource manager
    trcolor.exe  - run-time color picker

makefile.vc5 is for Microsoft Visual C++ version 5.0.  VC++ 5.0
can only perform 32-bit compilations, so this makefile builds only
32-bit versions of the executables.  Note that this makefile builds
the two TADS libraries that are required for building HTML TADS:
tr32h.lib (the TADS run-time 32-bit Windows library for HTML) and
tdb32h.lib (the TADS debugger 32-bit Windows library for HTML).

You should run makefile.vc5 with Microsoft nmake.

makefile.vc5 compiles into winobjs32 (for 32-bit Windows object files),
and generates the following executables:

    tc32.exe       - TADS compiler 32-bit Windows console application
    tr32.exe       - TADS run-time 32-bit Windows console application
    tdb32.exe      - TADS debugger 32-bit Windows console application
    maketrx32.exe  - executable binder 32-bit Windows console application
    tadsrsc32.exe  - TADS resource manager 32-bit Windows console application
    trcolor32.exe  - run-time color picker 32-bit Windows console application


