
To port SCARE to a new input/output scheme, you need to create a set of
input/output functions, specific to your platform for the core interpreter.
Something like

    os_<platform>.c

file is sufficient for simple cases.  More complex cases probably call for
a platform-specific subdirectory.

There are two example interface modules in the SCARE source, os_ansi.c and
os_glk.c.  The first of these is pretty much the simplest interface that is
possible for SCARE (though it could be slightly simpler if it gave up with
splitting output lines on spaces).  The second is a Glk interface for Linux.

Together, these modules should provide a model for porting SCARE to other
platforms.  Note that the interpreter core is not thread-safe.


Your port must implement the following functions

  void os_print_string (const sc_char *string);
  void os_print_tag (sc_int tag, const sc_char *arg);
  void os_print_string_debug (const sc_char *string);

    These functions print output to the display.  The first provides a single
    text string to print; though often largely ASCII, this string may contain
    any Microsoft codepage 1252 character.  New lines in output strings are
    always represented by the single ASCII character '\n'.

    The second indicates that the game output a text formatting tag.  Adrift
    games have HTML-like markup in their text, and use it to create display
    effects.  The following tag values, defined in scare.h, are ones that
    the interpreter could send:

      SC_TAG_ITALICS,         SC_TAG_ENDITALICS
      SC_TAG_BOLD,            SC_TAG_ENDBOLD,
      SC_TAG_UNDERLINE,       SC_TAG_ENDUNDERLINE,
      SC_TAG_COLOR,           SC_TAG_ENDCOLOR,

        These request italics, bold, underlined, and secondary color output,
        and cancel the output style.  For all of these, expect arg to be "".

      SC_TAG_FONT,            SC_TAG_ENDFONT,

        This requests text coloring and font control.  The value of arg
        indicates what color or font size or face is being set.

      SC_TAG_BGCOLOR,

        This requests a given display background color.  The value of arg
        indicates the color.

      SC_TAG_CENTER,          SC_TAG_ENDCENTER,
      SC_TAG_RIGHT,           SC_TAG_ENDRIGHT,

        These set and clear centering and right text justification.

      SC_TAG_WAIT,

        This requests a short delay.  The delay time is given in the value of
        arg, in seconds with one decimal place (for example, "7.3").

      SC_TAG_WAITKEY,

        This requests that the interpreter wait until the player presses a
        key.

      SC_TAG_CLS,

        Request to clear the screen.

      SC_TAG_UNKNOWN

        SCARE will output this if it has run into an HTML-like tag in an
        Adrift game that it doesn't recognize.  In this case, the raw tag text
        will appear in arg, stripped of its <...>.

        Unknown tags are sometimes used deliberately by games; one example is
        differentiating rooms with otherwise identical names, "Forest<1>" and
        "Forest<2>".  Here, the game relies on the Adrift Runner ignoring the
        "invalid" tag.  Because of this, your interpreter should probably also
        just ignore unknown tags.

    The third output function, os_print_string_debug(), is called by the
    interpreter core when its game debugger is active.  Your interpreter
    might want to use a separate window, or a distinctive text output style,
    for output from the game debugger.  Otherwise, this function should just
    call, or behave as, os_print_string().  As with os_print_string(), new
    lines are represented by the single ASCII character '\n'.


  sc_bool os_read_line (sc_char *buffer, sc_int length);
  sc_bool os_read_line_debug (sc_char *buffer, sc_int length);

    Read a line of input from the user into buffer.  The maximum allowable
    length to read is in length.

    There is no need to terminate buffer with any \n or \r.  It does, of
    course, need to terminate with a NUL (\0).

    The function should return TRUE when data has been placed in the buffer,
    telling the interpreter core to use this data as player input.  Returning
    FALSE will cause the interpreter core to discard any buffer contents, and
    reprompt for input.

    The debug version of os_read_line() is used by the interpreter core when
    the game debugger is active.  This lets your interpreter use a separate
    window for debugging a game, if you wish.  Otherwise, the function should
    call, or behave as, os_read_line(), with the possible exception that it's
    usually a good idea to change the input prompt to indicate that debug
    input is being requested.


  sc_bool os_confirm (sc_int type);

    Called by the interpreter core when it is about to do something which
    probably needs some form of confirmation.  Confirmation types are

      SC_CONF_QUIT            User entered "quit"
      SC_CONF_RESTART         User entered "restart"
      SC_CONF_SAVE            User entered "save"
      SC_CONF_RESTORE         User entered "restore" or "load"
      SC_CONF_VIEW_HINTS      User entered "hints"

    In practice, confirming save isn't useful since it doesn't destroy the
    state of the current running game.  For the others, however, it's probably
    useful to get some form of "Are you sure?" confirmation from the user,
    though if your interpreter can successfully obscure hint strings until
    selected by the user, you might want to also unconditionally confirm hint
    display at this point.  Return TRUE if confirmed, FALSE if not.

    In a GUI interpreter, this function would probably pop up a confirm
    dialog box.


  void *os_open_file (sc_bool is_save);

    Called by the core interpreter when it wants to open a file or other
    data stream for a saved game.  The value of is_save is TRUE when opening
    for write, FALSE when opening for read.

    Return the data stream from the call; in the case of stdio, this would
    be the FILE*, for Glk, it's the strid_t.  For other input/output schemes,
    return something that uniquely identifies the channel, so that you know
    what to read from or write to, and close, later on.  If you cannot open
    the file successfully, or want to cancel the operation, return NULL.

  void os_write_file (void *opaque, const sc_byte *buffer, sc_int length);
  sc_int os_read_file (void *opaque, sc_byte *buffer, sc_int length);

    Write or read saved game data.  The value of opaque is whatever your
    os_open_file() function returned.  So for stdio, you could cast opaque
    to a FILE*, and use it directly with fread()/fwrite(), for example.

    Buffer is a pointer to data to write or read, and length is the count of
    bytes to write, or maximum number of bytes to read.  os_read_file() should
    return the number of bytes actually placed into buffer, and zero on end of
    file.

  void os_close_file (void *opaque);

    Close the data stream or channel associated with opaque.  The interpreter
    core calls this when it has finished writing or reading a game save file.


  void os_play_sound (sc_char *filepath,
                      sc_int offset, sc_int length, sc_bool is_looping);
  void os_stop_sound (void);
  void os_show_graphic (sc_char *filepath, sc_int offset, sc_int length);

    Calls to these functions indicate that the game has requested either a
    sound to be played or a picture displayed.

    The values of the filename, offset, and length arguments indicate how
    to retrieve the resource.  There are two ways a game can request a
    resource -- either as an external file, or from an offset and length in
    the main TAF game file.  The clue to which of these it is using is in the
    values of the offset and length arguments.

    If the values of the offset and length arguments are both zero, the game
    has not built resources into the TAF file, and expects the interpreter to
    retrieve external file data.  In this case, the path to the file is in
    the filename argument.  It's often not terribly useful, relying on files
    being in the same absolute path on the system playing the game as they
    occupied on the game's development system, perhaps "C:\\BOB\BUBBLES.MID".
    Moreover, the file path is highly Windows-specific.  In this case, SCARE
    can supply only the file's path, and your platform-specific interpreter
    needs to figure out how best to handle it.  Sorry, that's Adrift for you.

    If the values of the offset and length arguments are not zero, the
    resource is built in to the TAF game file, and so can be fairly easily
    extracted and used.  The offsets are file offsets, in bytes, into the TAF
    game file, and the lengths are the number of bytes to extract from that
    TAF game file to produce the resource file.  The filepath argument still
    contains the path to the resource file on the game's development system,
    but it can (and almost definitely should) be ignored where the offset and
    length are passed to your interpreter.

    For sound resources, is_looping shows whether the sound loops, or is
    played only once.  Stop looping sounds on a call to os_stop_sound().

    For graphics, the SCARE core makes a special os_show_graphic() call on
    quitting or restarting a game.  This call has a zero-length filepath
    string (that is, ""), and is an indication that your interface should
    clear graphics display if it can do so.  If it cannot, this call may be
    ignored.
 
    The core interpreter tracks the currently playing sound or displayed
    graphic, and attempts to send game requests to the interface only when a
    resource changes; that is, on a change of sound or when sound is turned
    off, or on a changed of graphic.

    If you do not intend your interface to handle these calls, the functions
    should be stub do-nothing functions in the interpreter interface.

    For Linux users, a simple way to get graphics displayed is to use 'xv'
    to display it, once extracted.  The os_ansi.c and os_glk.c interfaces
    contain a small and inelegant piece of code to do this; they use 'dd' to
    extract the graphic data from the TAF file into the file /tmp/scare.jpg,
    then create a background 'xv' job to display the image.  A second
    background job cleans away the temporary file after a few seconds.  To
    compile this into Linux builds of SCARE, define a value for the C pre-
    processor macro LINUX_GRAPHICS.


  void os_display_hints (sc_game game)

    Display the hints relevant to the current state of the game.  See below
    for information on how to retrieve a list of game hints to display.  A
    GUI interpreter might display these as a list widget; other interfaces
    will have their own methods of doing this.

    An interface might also not display hints at all, in which case this
    function can be a stub.
    

The interpreter core offers these functions, which you call from your
platform-specific module to run a game:

  void sc_set_trace_flags (sc_uint trace_flags);

    Set tracing in SCARE modules that support it.  The argument is bit mask;
    see scare.h for a list of flag bits and their meanings.

  sc_game sc_game_from_filename (const sc_char *filename);
  sc_game sc_game_from_stream (FILE *stream);
  sc_game sc_game_from_callback (sc_int (*callback)
                                (void *, sc_byte *, sc_int),
                                void *opaque);

    These functions create a game object from various sources.  The simplest
    to use is sc_game_from_filename(), where filename is the path to an
    Adrift .taf file.

    As an alternative, you can call sc_game_from_stream() to create a game
    from a stdio FILE* already open to the .taf file.

    Finally, there is sc_game_from_callback(), which is a stdio-less game
    creation function.  You hand this function the name of a callback
    function, and an opaque pointer.  When the interpreter core needs data
    from the .taf file to construct the game, it will call callback() with the
    opaque value passed in, and a pointer to a buffer and a maximum length.
    callback() should read in data using whatever input/output scheme it wants
    to use, and return the count of bytes buffered, or zero on end of file.

    Callbacks behave just like os_read_file() above.  For an example, see
    os_glk.c, which steadfastly avoids using stdio for input/output, and relies
    purely on Glk.

  void sc_interpret_game (sc_game game);

    Call this function with a game created using one of the above functions
    to start running an Adrift game, or to resume one stopped with "quit".

  void sc_restart_game (sc_game game);

    Restart the game.  The game may be either running or stopped.

    For cases where the game is running, this function would be called from
    the event handler for a GUI interpreter's "Restart" button or menu option.
    It is implemented as a longjump when used on running games, so the function
    does not return to the caller, in this case, if successful.

    For cases where the game is stopped, the function resets the game state to
    its initial conditions, then returns as normal.

    Use sc_is_game_running() to determine whether the game is running, and
    sc_has_game_completed() to determine if the game was lost or won, or if
    the user left the game using "quit".

  sc_bool sc_save_game (sc_game game);
  sc_bool sc_save_game_to_filename (sc_game game,
                                    const sc_char *filename);
  void sc_save_game_to_stream (sc_game game, FILE *stream);
  void sc_save_game_to_callback (sc_game game,
                                 void (*callback)
                                 (void *, const sc_byte *, sc_int),
                                 void *opaque);

    Save the state of the current running game.  The game may be running
    or stopped.  Functions returning a status return TRUE if the save was
    successful (the user indicated a valid save file), FALSE otherwise.

    These functions are designed to be called from the event handler of a GUI
    interpreter's "Save" button or menu option.  The first function results
    in calls to os_open_file(), os_write_file(), and os_close_file() functions,
    acting exactly as the game "save" command.  The others save the game state
    to either a named file, a file stream, or via callbacks.

    SCARE uses the same file save format as the official Adrift Runner (at
    least, as version 4.0.36 of the Runner), so games saved with SCARE should
    be restoreable by the Adrift Runner itself.

  sc_bool sc_load_game (sc_game game);
  sc_bool sc_load_game_from_filename (sc_game game,
                                      const sc_char *filename);
  sc_bool sc_load_game_from_stream (sc_game game, FILE *stream);
  sc_bool sc_load_game_from_callback (sc_game game,
                                      sc_int (*callback)
                                      (void *, sc_byte *, sc_int),
                                      void *opaque);

    Restore the state of a previously saved game.  The game may be running
    or stopped.  If successful, and the game is running, these functions do
    not return, since they are implemented as a longjump.  If successful and
    the game is not running, they return TRUE.  If restore fails, these
    functions return FALSE.

    These functions are designed to be called from the event handler of a GUI
    interpreter's "Restore" or "Load" button or menu option.  The first
    function results in calls to os_open_file(), os_read_file(), and
    os_close_file() functions, acting exactly as the game "restore" command.
    The others load the game state from either a named file, a file stream,
    or via callbacks.

    Because the format is the same, SCARE can restore games saved by the
    Adrift Runner version 4.0.36.

  sc_bool sc_undo_game_turn (sc_game game);

    Undo one turn of a running game.  The game may be running or stopped.
    If successful, the function returns TRUE.  If undo fails, the function
    returns FALSE.

    This function is designed to be called from the event handler for a GUI
    interpreter's "Undo" button or menu option.

    SCARE maintains a limited number of undo buffers.  The function returns
    FALSE when no undo buffer is available; that is, at the start of the game,
    or when repeated undo has used up all buffers.

  void sc_quit_game (sc_game game);

    Stop the currently running game.  This function is implemented as a
    longjump, making it appear as if the call made to sc_interpret_game()
    returned.  The game must be running.

    Because it contains a longjump, this function never returns to its caller.

    A game stopped this way, or one stopped by the player typing the "quit"
    command, can be restarted by calling sc_interpret_game() again, with the
    same game argument.

  void sc_free_game (sc_game game);

    After sc_interpret_game() has returned, call this function to free all
    memory resources in use by the game, and destroy the game object.  The
    game must not be running.

    If the program is going to exit after running a game (that it, if it
    returns from main() or glk_main(), or calls exit() or glk_exit()), you
    may save some time by simply omitting the call to this function.  While
    sc_free_game() will carefully tidy up heap and malloc'ed memory allocated
    to the game, the time spent doing this could be saved if the next action
    is to exit the program.

  sc_bool sc_is_game_running (sc_game game);

    Selected functions above require that the game is running, or stopped,
    before they can be called.  This function tells you whether the game is
    being run, or not.

    A game starts running when sc_interpret_game() is called.  It stops when
    sc_interpret_game() returns, either normally (game end, user entered
    "quit"), or when a platform-specific module calls sc_quit_game().

  sc_bool sc_has_game_completed (sc_game game);

    If the game has been won or lost, it can't be restarted by another call to
    os_interpret_game().  The function sc_has_game_completed() can be used to
    find out if a game is runnable at all.  It returns TRUE if the game has
    ended, FALSE otherwise.

  sc_bool sc_is_game_undo_available (sc_game game);

    The function sc_undo_game_turn() requires an undo buffer to be available.
    This function tells you whether undo is available, or not.

    It returns TRUE if the game can undo a turn, otherwise FALSE.  The
    function can be called prior to calling sc_undo_game_turn(), and if it
    returns TRUE, then sc_undo_game_turn() will succeed.

  const sc_char *sc_get_game_name (sc_game game);
  const sc_char *sc_get_game_author (sc_game game);
  sc_int sc_get_game_turns (sc_game game);
  sc_int sc_get_game_score (sc_game game);
  sc_int sc_get_game_max_score (sc_game game);

    These functions return the name, author, turns count, current score, and
    maximum score for the game.  The game doesn't need to be running to get
    this information.

  const sc_char *sc_get_game_room (sc_game game);
  const sc_char *sc_get_game_status_line (sc_game game);

    These functions return the current room name, and any status line that the
    game outputs.  If a game outputs no status line, the return value from
    sc_get_game_status_line() is always NULL.  The return value of the function
    sc_get_game_room() may also be NULL if the game hasn't yet run any turns.

    These two values can be used, together with the score, to build an Adrift
    Runner-like status line.

    The Adrift Runner displays the current room name in a box in the bottom
    left of the display.  If the game implements a status line, it displays
    this alongside it, otherwise it displays the score instead.

  const sc_char *sc_get_game_preferred_font (sc_game game);

    A game may request that it be displayed in the Adrift Runner using a
    particular default font.  If your interface has fine grained control over
    font display, and you want to implement this feature, this function
    returns the preferred default font set by the game's author, and built
    into the game.

    The values of the string are the font name and size, separated by a comma,
    for example "Comic Sans MS, 14", or "Verdana, 12".  If the game has no
    default font preference, this function returns NULL.

  void sc_set_game_bold_room_names (sc_game game, sc_bool flag);
  sc_bool sc_get_game_bold_room_names (sc_game game);
  void sc_set_game_verbose (sc_game game, sc_bool flag);
  sc_bool sc_get_game_verbose (sc_game game);
  void sc_set_game_notify_score_change (sc_game game, sc_bool flag);
  sc_bool sc_get_game_notify_score_change (sc_game game);

    These functions control a couple of facets of the way the interpreter core
    behaves.  The Adrift Runner allows the user to select bold or normal text
    for printing room names.  Call the appropriate function, from an event
    handler in the case of a GUI interpreter, to set the option.

    Verbose mode means that the interpreter prints out full room descriptions
    on each visit, Brief mode only prints those descriptions when asked for,
    or when a room is visited for the first time.  The mode can be set either
    by sc_set_game_verbose() or by the player entering the "verbose" or "brief"
    commands.

    The Adrift Runner can be set to indicate whether the game score changed
    during a turn.  A particular game will set this according to preference,
    and it can be change either by sc_set_game_notify_score_change() or by the
    player entering the "notification on" or "notification off" commands.

  sc_does_game_use_sounds (sc_game game);
  sc_does_game_use_graphics (sc_game game);

    These functions return TRUE if the game contains any resources of the
    type indicated -- sounds or graphics.  There are no restrictions on
    when these functions may be called.

  sc_game_hint sc_iterate_game_hints (sc_game game, sc_game_hint hint);

    This function provides serial access to a game's hints.  If hint is NULL,
    it returns the first valid hint found, otherwise it returns the next one
    after the hint passed in.  It returns NULL when there are no more game
    hints available.  See below for how to use returned hints.

    If you need a less insistently sequential form of access to hints, you'll
    need to allocate a hints array, and fill it using this function.  Also,
    note that the valid hints for a game vary as the game is run, so any hints
    array that you do build like this you should consider to be invalid once
    control has been passed to, or returns into, run_interpret().

    This function, and its cousins below, is intended to be called from
    os_display_hints(), but it is also valid, though perhaps pointless, to
    call it while the game is not running.

  const sc_char *sc_get_game_hint_question (sc_game game, sc_game_hint hint);
  const sc_char *sc_get_game_subtle_hint (sc_game game, sc_game_hint hint);
  const sc_char *sc_get_game_unsubtle_hint (sc_game game, sc_game_hint hint);

    These functions return the hint question, and the subtle and unsubtle
    ("sledgehammer") game hints.  The question is akin to a topic in other IF
    systems, for example "How do I get the bull's attention?".  A hint has a
    maximum of two strings to display, the first is intended to be subtle
    ("Look carefully at what you're wearing"), and the second much less so
    ("Wave your red underpants at the bull!").

    The second hint may be absent, but the first (usually) won't be.  If
    either is absent, the function that gets it for you will return NULL.

    A note about these functions; they share the same data area for their
    return strings, so it's probably not a good idea to keep the addresses
    they return across other game hint calls.  For that case, you need to
    take copies of the strings, and use those.

  void sc_set_game_debugger_enabled (sc_game game, sc_bool flag);
  sc_bool sc_get_game_debugger_enabled (sc_game game);
  sc_bool sc_run_game_debugger_command (sc_game game, const sc_char *command);

    The first of these functions enables or disables SCARE's game debugger.
    When enabled, entering "debug" at the game prompt will bring up the game
    debugger.  SCARE's debugger lets you inspect the current game state,
    and also set watchpoints that will trigger, and drop into the debugger
    when one of the game's items (objects, tasks, events, and so on) changes
    state.

    The second function queries SCARE's game debugger availability.  SCARE's
    game debugger is disabled by default; this helps to prevent major
    accidental "spoilers".

    The third function takes a command string and treats it as if typed in
    at a game debugging prompt.  This function is intended for interpreters
    that might want to use a GUI to debug the game in a separate window, or
    otherwise outside the main flow of game play.  The debugger needs to be
    enabled for this function to succeed.  It returns FALSE if the debugger
    is disabled, or if the command was not understood.

    Please see DEBUGGER for more on how to use SCARE's game debugger.

  void sc_set_predictable_random (sc_bool flag);
  void sc_reseed_random_sequence (sc_uint new_seed);

    By default, SCARE uses the platform's own rand() function, seeded from
    the system time shown when SCARE starts running.  This will normally
    provide good random numbers, but is not predictable (unless reseeded),
    and will probably give different number sequences on different platforms.
    This makes games with randomized sections hard to test predictably.

    To address this, SCARE contains its own alternative random number
    generator, seeded with the constant value 1 when SCARE starts running.
    Although relatively good, this generator produces random numbers that
    are not as well distributed as those produced by the platform's own
    generator.  It is however portable across all platforms, and so makes
    randomized game sections predictable; useful for testing purposes.  Call
    sc_set_predictable_random() with flag TRUE to select this alternative
    random number generator, or FALSE to reinstate the platform's generator.

    Call sc_reseed_random_sequence() to seed the currently set random number
    generator with the given seed value.  Use this to provide repeatable
    random number sequences.  The new seed value may not be zero.

  sc_int sc_strncasecmp (const sc_char *s1, const sc_char *s2, sc_int n);
  sc_int sc_strcasecmp (const sc_char *s1, const sc_char *s2);

    ANSI/ISO C doesn't offer case-insensitive string comparison functions.
    Most platforms offer either str[n]casecmp() or str[n]icmp(), but neither
    is ANSI/ISO standard so SCARE implements its own.  If you want to use
    them, here they are.

  const sc_char *sc_scare_version (void);
  sc_int sc_scare_emulation (void);

    The first function returns a string giving SCARE's version information.
    The second returns an integer indicating SCARE's Adrift emulation level,
    for example 4046, representing 4.0.46.

