#glulx #blorb #if

glk

Bindings for the Glk I/O interface for hosting interactive fiction interpreters

2 unstable releases

0.2.0 Nov 4, 2019
0.1.1 Oct 15, 2019
0.1.0 Oct 15, 2019

#461 in Text processing

MIT/Apache

280KB
6.5K SLoC

Rust 4K SLoC // 0.2% comments C 2K SLoC // 0.0% comments

glk-rs

This crate provides bindings to implement the Glk I/O interface for hosting interactive fiction interpreters. This standard is used by, for example, the glulxe interpreter.

It exports the C functions, rust traits and a dummy implementation. It is up to the user of this crate to provide actual implementations for the Glk functions that the interpreter will invoke.

Note

This crate currently only has the capability to provide a Glk library.

When implementing an interpreter or other Glk application it would be useful to use a Glk library, this is currently not possible with this crate, though it could likely share some of the traits, utility code, or constants at least.

How to use

Implement the trait glk::traits::Api and Glk traits (at least Base, which handles the base functionality; every Glk module is handled by a separate trait) on a structure with handlers, then call glk::init() to register the handlers.

/** Dispatch trait for all Glk APIs. Each function returns a
 * reference to a trait which will be called for functions on the associated
 * Glk module.
 */
pub trait Api {
    /** Mandatory Glk API functions. */
    fn base(&mut self) -> &mut dyn Base;
    /** GLK_MODULE_LINE_ECHO */
    fn line_echo(&mut self) -> Option<&mut dyn LineEcho>;
    /** GLK_MODULE_LINE_TERMINATORS */
    fn line_terminators(&mut self) -> Option<&mut dyn LineTerminators>;
    /** GLK_MODULE_UNICODE */
    fn unicode(&mut self) -> Option<&mut dyn Unicode>;
    /** GLK_MODULE_UNICODE_NORM */
    fn unicode_norm(&mut self) -> Option<&mut dyn UnicodeNorm>;
    /** GLK_MODULE_IMAGE */
    fn image(&mut self) -> Option<&mut dyn Image>;
    /** GLK_MODULE_SOUND */
    fn sound(&mut self) -> Option<&mut dyn Sound>;
    /** GLK_MODULE_SOUND2 */
    fn sound2(&mut self) -> Option<&mut dyn Sound2>;
    /** GLK_MODULE_HYPERLINKS */
    fn hyperlinks(&mut self) -> Option<&mut dyn Hyperlinks>;
    /** GLK_MODULE_DATETIME */
    fn date_time(&mut self) -> Option<&mut dyn Datetime>;
    /** GLK_MODULE_RESOURCE_STREAM */
    fn resource_stream(&mut self) -> Option<&mut dyn ResourceStream>;
    /** GLK_MODULE_GARGLKTEXT */
    fn garglk_text(&mut self) -> Option<&mut dyn garglk::GarGlkText>;
    /** GI blorb handler functions */
    fn giblorb(&mut self) -> Option<&mut dyn giblorb::Handlers>;
    /** GI dispatch handler functions */
    fn gidispatch(&mut self) -> Option<&mut dyn gidispatch::Handlers>;
    /** Rust Glk extension handler functions */
    fn ext(&mut self) -> Option<&mut dyn ext::Handlers>;
}

These functions could return Some(self), or delegate to a different object that implements the given trait. Or return None if the module is left unimplemented.

Then link your application to whatever needs the glk_ API.

Note that the handlers registered with glk::init are local to a thread, so make sure to call the interpreter from the same thread that registers the glk API handlers. Glk only supports single-threaded interpreters.

Example: Toyglk

A basic demo Glk implementation, using crossterm as terminal backend. It hosts the Glulxe interpreter using the glulxe crate.

  • Aims to be a complete implementation of the Glk standard, including the Unicode extension.
  • Only supports one window: the entire terminal.
  • Line and character (also special keycodes) input.
  • Saving and restoring works.
  • Supports Glk styling and GarGlkText RGB colors.

Several of my favorites stories like Blue Lacuna and Counterfeit Monkey work. e.g.

$ cargo run --release --example toyglk CounterfeitMonkey.gblorb
...
Can you hear me? >> yes

Good, you're conscious. We're conscious. I've heard urban legends about
synthesis going wrong, one half person getting lost.

Counterfeit Monkey

Glk+GarGlk styles

Glk types

glui32 is directly mapped to u32, and glsi32 to i32.

The opaque handle types (frefid_t, schanid_t, strid_t, winid_t) are represented as opaque types that can be cast from and to usize (or a pointer, if you're living dangerously).

Struct types event_t, glkdate_t, glktimeval_t, stream_result_t are provided as C-compatible structs.

Convenience types have been defined for gestalts, event types, keycodes and such. These are newtypes that wrap a u32, not enums, to leave room for extensions (or ad-hoc need) to pass new values.

License

Licensed under either of

at your option.

(note that the inner crate, glk-sys is licensed under a MIT license only, because it is based on files from glk which are licensed such)

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~0–1.9MB
~36K SLoC