poke-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] libpoke: remove global state


From: Mohammad-Reza Nabipoor
Subject: [PATCH] libpoke: remove global state
Date: Sun, 20 Aug 2023 23:22:53 +0200

2023-08-20  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>

        * libpoke/pvm-alloc.h: Fix typo s/fred/freed/.
        * common/pk-utils.h (struct pk_term_if): Forward declaration.
        (pk_print_binary): Pass `term_if' to printer.
        * common/pk-utils.c (pk_print_binary): Likewise.
        * libpoke/pkt.h (libpoke_term_if): Replace with function declaration.
        (pk_puts): Likewise.
        (pk_printf): Likewise.
        (pk_term_flush): Likewise.
        (pk_term_indent): Likewise.
        (pk_term_class): Likewise.
        (pk_term_end_class): Likewise.
        (pk_term_hyperlink): Likewise.
        (pk_term_end_hyperlink): Likewise.
        (pk_term_get_color): Likewise.
        (pk_term_set_color): Likewise.
        (pk_get_bgcolor): Likewise.
        (pk_set_bgcolor): Likewise.
        (struct pk_term_if_state): New struct to keep all the state related
        to terminal interface.
        * libpoke/pkl.h (struct pk_term_if_state): Forward declaration.
        * libpoke/pkl.c (struct pkl_compiler): Add new field (`term_if_state').
        (pkl_load_rt): Update terminal interface function calls.
        (pkl_new): Ditto and save the `term_if_state'.
        (pkl_get_term_if_state): New function.
        (pkl_get_term_if): Likewise.
        * libpoke/libpoke.h (struct pk_term_if): Add `void *data' arg to all
        function pointers.  And add a new data member (`void *data').
        Remove `printf_fn' field and add `vprintf_fn' field.
        * libpoke/libpoke.c (struct _pk_compiler): Add new fields `term_if'
        and `term_if_state'.
        (pk_compiler_new_with_flags): Add tests for presence of user-provided
        function pointers for the terminal interface.  Allocate state for
        printer (terminal interface) and pass it to the compiler.
        (pkl_compiler_free): Deallocate the state for terminal interface.
        (pk_disassemble_function_val): Update invocation of
        `pvm_disassemble_program{,_nat}' functions.
        (pk_disassemble_expression): Likewise.
        (pk_puts): New function.
        (pk_printf): Likewise.
        (pk_term_flush): Likewise.
        (pk_term_indent): Likewise.
        (pk_term_class): Likewise.
        (pk_term_end_class): Likewise.
        (pk_term_hyperlink): Likewise.
        (pk_term_end_hyperlink): Likewise.
        (pk_term_get_color): Likewise.
        (pk_term_get_bgcolor): Likewise.
        (pk_term_set_color): Likewise.
        (pk_term_set_bgcolor): Likewise.
        (_pvm_jitter_print_flush): Likewise.
        (_pvm_jitter_print_char): Likewise.
        (_pvm_jitter_begin_decoration): Likewise.
        (_pvm_jitter_end_decoration): Likewise.
        (pk_term_if_state_new): New function.
        (pk_term_if_state_free): Likewise.
        * libpoke/pkl-diag.c (pkl_print_filename): Add `term_if' arg and
        pass them to terminal interface functions.
        (pkl_detailed_location): Likewise.
        (pkl_error_internal): Update terminal interface function calls.
        (pkl_warning): Likewise.
        (pkl_ice): Likewise.
        * libpoke/pvm-program.c (include "pvm-program.h"): Add.
        (include "jitter/jitter-print.h"): Remove.
        (jitter_context_kind): Likewise.
        (jitter_context): Likewise.
        (pvm_jitter_print_flush): Move the implementation to 
`libpoke/libpoke.c'.
        (pvm_jitter_print_char): Likewise.
        (pvm_jitter_begin_decoration): Likewise.
        (pvm_jitter_end_decoration): Likewise.
        (pvm_disassemble_program_nat): Re-write.
        (pvm_disassemble_program): Likewise.
        (pvm_program_init): Likewise.
        (pvm_program_fini): Likewise.
        * libpoke/pvm-val.c (print_unit_name): Add `term_if' arg and update
        the terminal interface calls.
        (pvm_print_string): Likewise.
        (pvm_print_val_1): Update the terminal interface calls.
        * libpoke/pvm.h (struct pk_term_if_state): Forward declaration.
        (pvm_disassemble_program_nat): Add `struct pk_term_if_state *' arg.
        (pvm_disassemble_program): Likewise.
        (struct pk_term_if): Forward declaration.
        (pvm_print_string): Add `term_if' arg.
        * libpoke/pvm.c (jitter_context): Remove.
        (pvm_print_profile): Use the `term_if_state' instead of the global
        variable.
        (pvm_get_term_if_state): New function.
        (pvm_get_term_if): Likewise.
        * libpoke/pvm.jitter (wrapped-functions): Add terminal interface
        functions and accessor.
        (wrapped-globals): Remove `libpoke_term_if'.
        (PVM_PRINTI): Update the terminal interface calls.
        (PVM_PRINTL): Likewise.
        (RTRACE): Likewise.
        (printer-c): Likewise.
        (pushoc): Likewise.
        (popoc): Likewise.
        (pushobc): Likewise.
        (popobc): Likewise.
        (prints): Likewise.
        (beghl): Likewise.
        (endhl): Likewise.
        (begsc): Likewise.
        (endsc): Likewise.
        (strace): Likewise.
        (disas): Likewise.
        * poke/pk-term.h (pk_term_flush_1): Add `void *user_data' arg.
        (pk_puts_1): Likewise.
        (pk_vprintf_1): Likewise.
        (pk_term_indent_1): Likewise.
        (pk_term_class_1): Likewise.
        (pk_term_end_class_1): Likewise.
        (pk_term_hyperlink_1): Likewise.
        (pk_term_end_hyperlink_1): Likewise.
        (pk_term_get_color_1): Likewise.
        (pk_term_get_bgcolor_1): Likewise.
        (pk_term_set_color_1): Likewise.
        (pk_term_set_bgcolor_1): Likewise.
        (pk_term_flush): Re-declare as a macro.
        (pk_puts): Likewise.
        (pk_vprintf): Likewise.
        (pk_term_indent): Likewise.
        (pk_term_class): Likewise.
        (pk_term_end_class): Likewise.
        (pk_term_hyperlink): Likewise.
        (pk_term_end_hyperlink): Likewise.
        (pk_term_get_color): Likewise.
        (pk_term_get_bgcolor): Likewise.
        (pk_term_set_color): Likewise.
        (pk_term_set_bgcolor): Likewise.
        * poke/pk-term.c (pk_term_flush_1): Add `void *user_data' arg.
        (pk_puts_1): Likewise.
        (pk_vprintf_1): Likewise.
        (pk_term_indent_1): Likewise.
        (pk_term_class_1): Likewise.
        (pk_term_end_class_1): Likewise.
        (pk_term_hyperlink_1): Likewise.
        (pk_term_end_hyperlink_1): Likewise.
        (pk_term_get_color_1): Likewise.
        (pk_term_get_bgcolor_1): Likewise.
        (pk_term_set_color_1): Likewise.
        (pk_term_set_bgcolor_1): Likewise.
        * poke/poke.c (poke_term_if): Use new terminal interface functions.
        * poked/poked.c (tif_flush): Add `void *data' arg.
        (tif_puts): Likewise.
        (tif_vprintf): Likewise.
        (tif_indent): Likewise.
        (tif_class): Likewise.
        (tif_class_end): Likewise.
        (tif_hlink): Likewise.
        (tif_hlink_end): Likewise.
        (tif_color): Likewise.
        (tif_bgcolor): Likewise.
        (tif_color_set): Likewise.
        (tif_bgcolor_set): Likewise.
        (tif): Replace `printf_fn' with `vprintf_fn'.
        * testsuite/poke.libpoke/term-if.h (pk_term_flush): Add `void *data' 
arg.
        (pk_puts): Likewise.
        (pk_vprintf): Likewise.
        (pk_term_indent): Likewise.
        (pk_term_class): Likewise.
        (pk_term_end_class): Likewise.
        (pk_term_hyperlink): Likewise.
        (pk_term_end_hyperlink): Likewise.
        (pk_term_get_color): Likewise.
        (pk_term_get_bgcolor): Likewise.
        (pk_term_set_color): Likewise.
        (pk_term_set_bgcolor): Likewise.
        (poke_term_if): Replace `printf_fn' with `vprintf_fn'.
        * testsuite/poke.libpoke/api.c (test_pk_compiler_new): Ditto and
        add test cases for all color functions.
---

Hello Jose!

Finally the removal of all global states from libpoke is here!
But this breaks both the API and ABI of the libpoke :(

The main problem is `printf_fn' which is not usable in `pk_printf'
implementation; so I've replaced that with `pk_vprintf'.

That `void *data' field is also necessary for sharing the same functions
between different threads without relying on global variables.


Regards,
Mohammad-Reza


 ChangeLog                        | 173 ++++++++++++++++++
 common/pk-utils.c                |  15 +-
 common/pk-utils.h                |   8 +-
 libpoke/libpoke.c                | 301 ++++++++++++++++++++++++++-----
 libpoke/libpoke.h                |  28 +--
 libpoke/pkl-diag.c               | 125 ++++++-------
 libpoke/pkl.c                    |  37 +++-
 libpoke/pkl.h                    |  16 +-
 libpoke/pkt.h                    |  46 +++--
 libpoke/pvm-alloc.h              |   2 +-
 libpoke/pvm-program.c            |  85 ++-------
 libpoke/pvm-val.c                | 257 +++++++++++++-------------
 libpoke/pvm.c                    |  20 +-
 libpoke/pvm.h                    |  27 ++-
 libpoke/pvm.jitter               | 163 ++++++++++++-----
 poke/pk-term.c                   |  33 ++--
 poke/pk-term.h                   |  39 ++--
 poke/poke.c                      |  24 +--
 poked/poked.c                    |  40 ++--
 testsuite/poke.libpoke/api.c     |  16 +-
 testsuite/poke.libpoke/term-if.h |  36 ++--
 21 files changed, 1003 insertions(+), 488 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 25bcdefe..8575c5f4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,176 @@
+2023-08-20  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
+
+       * libpoke/pvm-alloc.h: Fix typo s/fred/freed/.
+       * common/pk-utils.h (struct pk_term_if): Forward declaration.
+       (pk_print_binary): Pass `term_if' to printer.
+       * common/pk-utils.c (pk_print_binary): Likewise.
+       * libpoke/pkt.h (libpoke_term_if): Replace with function declaration.
+       (pk_puts): Likewise.
+       (pk_printf): Likewise.
+       (pk_term_flush): Likewise.
+       (pk_term_indent): Likewise.
+       (pk_term_class): Likewise.
+       (pk_term_end_class): Likewise.
+       (pk_term_hyperlink): Likewise.
+       (pk_term_end_hyperlink): Likewise.
+       (pk_term_get_color): Likewise.
+       (pk_term_set_color): Likewise.
+       (pk_get_bgcolor): Likewise.
+       (pk_set_bgcolor): Likewise.
+       (struct pk_term_if_state): New struct to keep all the state related
+       to terminal interface.
+       * libpoke/pkl.h (struct pk_term_if_state): Forward declaration.
+       * libpoke/pkl.c (struct pkl_compiler): Add new field (`term_if_state').
+       (pkl_load_rt): Update terminal interface function calls.
+       (pkl_new): Ditto and save the `term_if_state'.
+       (pkl_get_term_if_state): New function.
+       (pkl_get_term_if): Likewise.
+       * libpoke/libpoke.h (struct pk_term_if): Add `void *data' arg to all
+       function pointers.  And add a new data member (`void *data').
+       Remove `printf_fn' field and add `vprintf_fn' field.
+       * libpoke/libpoke.c (struct _pk_compiler): Add new fields `term_if'
+       and `term_if_state'.
+       (pk_compiler_new_with_flags): Add tests for presence of user-provided
+       function pointers for the terminal interface.  Allocate state for
+       printer (terminal interface) and pass it to the compiler.
+       (pkl_compiler_free): Deallocate the state for terminal interface.
+       (pk_disassemble_function_val): Update invocation of
+       `pvm_disassemble_program{,_nat}' functions.
+       (pk_disassemble_expression): Likewise.
+       (pk_puts): New function.
+       (pk_printf): Likewise.
+       (pk_term_flush): Likewise.
+       (pk_term_indent): Likewise.
+       (pk_term_class): Likewise.
+       (pk_term_end_class): Likewise.
+       (pk_term_hyperlink): Likewise.
+       (pk_term_end_hyperlink): Likewise.
+       (pk_term_get_color): Likewise.
+       (pk_term_get_bgcolor): Likewise.
+       (pk_term_set_color): Likewise.
+       (pk_term_set_bgcolor): Likewise.
+       (_pvm_jitter_print_flush): Likewise.
+       (_pvm_jitter_print_char): Likewise.
+       (_pvm_jitter_begin_decoration): Likewise.
+       (_pvm_jitter_end_decoration): Likewise.
+       (pk_term_if_state_new): New function.
+       (pk_term_if_state_free): Likewise.
+       * libpoke/pkl-diag.c (pkl_print_filename): Add `term_if' arg and
+       pass them to terminal interface functions.
+       (pkl_detailed_location): Likewise.
+       (pkl_error_internal): Update terminal interface function calls.
+       (pkl_warning): Likewise.
+       (pkl_ice): Likewise.
+       * libpoke/pvm-program.c (include "pvm-program.h"): Add.
+       (include "jitter/jitter-print.h"): Remove.
+       (jitter_context_kind): Likewise.
+       (jitter_context): Likewise.
+       (pvm_jitter_print_flush): Move the implementation to 
`libpoke/libpoke.c'.
+       (pvm_jitter_print_char): Likewise.
+       (pvm_jitter_begin_decoration): Likewise.
+       (pvm_jitter_end_decoration): Likewise.
+       (pvm_disassemble_program_nat): Re-write.
+       (pvm_disassemble_program): Likewise.
+       (pvm_program_init): Likewise.
+       (pvm_program_fini): Likewise.
+       * libpoke/pvm-val.c (print_unit_name): Add `term_if' arg and update
+       the terminal interface calls.
+       (pvm_print_string): Likewise.
+       (pvm_print_val_1): Update the terminal interface calls.
+       * libpoke/pvm.h (struct pk_term_if_state): Forward declaration.
+       (pvm_disassemble_program_nat): Add `struct pk_term_if_state *' arg.
+       (pvm_disassemble_program): Likewise.
+       (struct pk_term_if): Forward declaration.
+       (pvm_print_string): Add `term_if' arg.
+       * libpoke/pvm.c (jitter_context): Remove.
+       (pvm_print_profile): Use the `term_if_state' instead of the global
+       variable.
+       (pvm_get_term_if_state): New function.
+       (pvm_get_term_if): Likewise.
+       * libpoke/pvm.jitter (wrapped-functions): Add terminal interface
+       functions and accessor.
+       (wrapped-globals): Remove `libpoke_term_if'.
+       (PVM_PRINTI): Update the terminal interface calls.
+       (PVM_PRINTL): Likewise.
+       (RTRACE): Likewise.
+       (printer-c): Likewise.
+       (pushoc): Likewise.
+       (popoc): Likewise.
+       (pushobc): Likewise.
+       (popobc): Likewise.
+       (prints): Likewise.
+       (beghl): Likewise.
+       (endhl): Likewise.
+       (begsc): Likewise.
+       (endsc): Likewise.
+       (strace): Likewise.
+       (disas): Likewise.
+       * poke/pk-term.h (pk_term_flush_1): Add `void *user_data' arg.
+       (pk_puts_1): Likewise.
+       (pk_vprintf_1): Likewise.
+       (pk_term_indent_1): Likewise.
+       (pk_term_class_1): Likewise.
+       (pk_term_end_class_1): Likewise.
+       (pk_term_hyperlink_1): Likewise.
+       (pk_term_end_hyperlink_1): Likewise.
+       (pk_term_get_color_1): Likewise.
+       (pk_term_get_bgcolor_1): Likewise.
+       (pk_term_set_color_1): Likewise.
+       (pk_term_set_bgcolor_1): Likewise.
+       (pk_term_flush): Re-declare as a macro.
+       (pk_puts): Likewise.
+       (pk_vprintf): Likewise.
+       (pk_term_indent): Likewise.
+       (pk_term_class): Likewise.
+       (pk_term_end_class): Likewise.
+       (pk_term_hyperlink): Likewise.
+       (pk_term_end_hyperlink): Likewise.
+       (pk_term_get_color): Likewise.
+       (pk_term_get_bgcolor): Likewise.
+       (pk_term_set_color): Likewise.
+       (pk_term_set_bgcolor): Likewise.
+       * poke/pk-term.c (pk_term_flush_1): Add `void *user_data' arg.
+       (pk_puts_1): Likewise.
+       (pk_vprintf_1): Likewise.
+       (pk_term_indent_1): Likewise.
+       (pk_term_class_1): Likewise.
+       (pk_term_end_class_1): Likewise.
+       (pk_term_hyperlink_1): Likewise.
+       (pk_term_end_hyperlink_1): Likewise.
+       (pk_term_get_color_1): Likewise.
+       (pk_term_get_bgcolor_1): Likewise.
+       (pk_term_set_color_1): Likewise.
+       (pk_term_set_bgcolor_1): Likewise.
+       * poke/poke.c (poke_term_if): Use new terminal interface functions.
+       * poked/poked.c (tif_flush): Add `void *data' arg.
+       (tif_puts): Likewise.
+       (tif_vprintf): Likewise.
+       (tif_indent): Likewise.
+       (tif_class): Likewise.
+       (tif_class_end): Likewise.
+       (tif_hlink): Likewise.
+       (tif_hlink_end): Likewise.
+       (tif_color): Likewise.
+       (tif_bgcolor): Likewise.
+       (tif_color_set): Likewise.
+       (tif_bgcolor_set): Likewise.
+       (tif): Replace `printf_fn' with `vprintf_fn'.
+       * testsuite/poke.libpoke/term-if.h (pk_term_flush): Add `void *data' 
arg.
+       (pk_puts): Likewise.
+       (pk_vprintf): Likewise.
+       (pk_term_indent): Likewise.
+       (pk_term_class): Likewise.
+       (pk_term_end_class): Likewise.
+       (pk_term_hyperlink): Likewise.
+       (pk_term_end_hyperlink): Likewise.
+       (pk_term_get_color): Likewise.
+       (pk_term_get_bgcolor): Likewise.
+       (pk_term_set_color): Likewise.
+       (pk_term_set_bgcolor): Likewise.
+       (poke_term_if): Replace `printf_fn' with `vprintf_fn'.
+       * testsuite/poke.libpoke/api.c (test_pk_compiler_new): Ditto and
+       add test cases for all color functions.
+
 2023-08-06  Mohammad-Reza Nabipoor  <mnabipoor@gnu.org>
 
        * liboke/ios.c (ios_write_int_common): Fix the function when `bits'
diff --git a/common/pk-utils.c b/common/pk-utils.c
index 1134251c..989c480f 100644
--- a/common/pk-utils.c
+++ b/common/pk-utils.c
@@ -83,8 +83,9 @@ PK_POW (pk_upow, uint64_t)
 #undef PK_POW
 
 void
-pk_print_binary (void (*puts_fn) (const char *str),
-                 uint64_t val, int size, int sign_p, int use_suffix_p)
+pk_print_binary (void (*puts_fn) (struct pk_term_if *term_if, const char *str),
+                 struct pk_term_if *term_if, uint64_t val, int size, int 
sign_p,
+                 int use_suffix_p)
 {
   char b[65];
 
@@ -92,18 +93,18 @@ pk_print_binary (void (*puts_fn) (const char *str),
     b[size-1-z] = ((val >> z) & 0x1) + '0';
   b[size] = '\0';
 
-  puts_fn (b);
+  puts_fn (term_if, b);
 
   if  (use_suffix_p)
     {
       if (size == 64)
-        puts_fn (sign_p ? "L" : "UL");
+        puts_fn (term_if, sign_p ? "L" : "UL");
       else if (size == 16)
-        puts_fn (sign_p ? "H" : "UH");
+        puts_fn (term_if, sign_p ? "H" : "UH");
       else if (size == 8)
-        puts_fn (sign_p ? "B" : "UB");
+        puts_fn (term_if, sign_p ? "B" : "UB");
       else if (size == 4)
-        puts_fn (sign_p ? "N" : "UN");
+        puts_fn (term_if, sign_p ? "N" : "UN");
     }
 }
 
diff --git a/common/pk-utils.h b/common/pk-utils.h
index 97f5dc0a..fef6a2eb 100644
--- a/common/pk-utils.h
+++ b/common/pk-utils.h
@@ -49,9 +49,13 @@ char *pk_file_readable (const char *filename);
 int64_t pk_ipow (int64_t base, uint32_t exp);
 uint64_t pk_upow (uint64_t base, uint32_t exp);
 
+struct pk_term_if;  /* Defined in `libpoke/libpoke.h'.  */
+
 /* Print the given unsigned 64-bit integer in binary. */
-void pk_print_binary (void (*puts_fn) (const char *str), uint64_t val,
-                      int size, int sign_p, int use_suffix_p);
+void pk_print_binary (void (*puts_fn) (struct pk_term_if *term_if,
+                                       const char *str),
+                      struct pk_term_if *term_if, uint64_t val, int size,
+                      int sign_p, int use_suffix_p);
 
 /* Format the given unsigned 64-bit integer in binary. */
 int pk_format_binary (char* out, size_t outlen, uint64_t val, int size,
diff --git a/libpoke/libpoke.c b/libpoke/libpoke.c
index 57559bac..690d9541 100644
--- a/libpoke/libpoke.c
+++ b/libpoke/libpoke.c
@@ -32,8 +32,12 @@
 #include "ios-dev.h" /* for struct ios_dev_if */
 #include "configmake.h"
 
+/* Poke compiler state.  */
+
 struct _pk_compiler
 {
+  struct pk_term_if term_if;
+  struct pk_term_if_state *term_if_state;
   pkl_compiler compiler;
   pvm vm;
 
@@ -46,61 +50,80 @@ struct _pk_compiler
   struct pkl_ast_node_iter completion_iter;
 };
 
-struct pk_term_if libpoke_term_if;
-
 #define PK_RETURN(code) do { return pkc->status = (code); } while (0)
 
+/* Helper function to allocate state data for terminal interface.
+   `struct pk_term_if_state' is defined in `pkt.h'.  */
+
+static struct pk_term_if_state *pk_term_if_state_new (pvm vm, void *term_if);
+
+/* Helper function to free state data for terminal interface.  */
+
+static void pk_term_if_state_free (struct pk_term_if_state *);
+
 pk_compiler
 pk_compiler_new_with_flags (struct pk_term_if *term_if, uint32_t flags)
 {
   pk_compiler pkc;
+  uint32_t pkl_flags = 0;
+  const char *libpoke_configdir;
+  const char *libpoke_datadir;
 
   if (!term_if)
     return NULL;
 
-  if (!term_if->flush_fn || !term_if->puts_fn || !term_if->printf_fn
+  if (!term_if->flush_fn || !term_if->puts_fn || !term_if->vprintf_fn
       || !term_if->indent_fn || !term_if->class_fn || !term_if->end_class_fn
-      || !term_if->hyperlink_fn || !term_if->end_hyperlink_fn)
+      || !term_if->hyperlink_fn || !term_if->end_hyperlink_fn
+      || !term_if->get_color_fn || !term_if->get_bgcolor_fn
+      || !term_if->set_color_fn || !term_if->set_bgcolor_fn)
     return NULL;
 
   pkc = calloc (1, sizeof (struct _pk_compiler));
-  if (pkc)
-    {
-      uint32_t pkl_flags = 0;
-
-      if (flags & PK_F_NOSTDTYPES)
-        pkl_flags |= PKL_F_NOSTDTYPES;
-
-      /* Determine the path to the compiler's pkl-config.pk.  */
-      const char *libpoke_configdir = getenv ("POKECONFIGDIR");
-      if (libpoke_configdir == NULL)
-        libpoke_configdir = PKGDATADIR;
-
-      /* Determine the path to the compiler's runtime files.  */
-      const char *libpoke_datadir = getenv ("POKEDATADIR");
-      if (libpoke_datadir == NULL)
-        libpoke_datadir = PKGDATADIR;
-
-      libpoke_term_if = *term_if;
-
-      pkc->vm = pvm_init ();
-      if (pkc->vm == NULL)
-        goto error;
-      pkc->compiler = pkl_new (pkc->vm,
-                               libpoke_datadir,
-                               libpoke_configdir,
-                               pkl_flags);
-      if (pkc->compiler == NULL)
-        goto error;
-      pkc->complete_type = NULL;
-      pkc->status = PK_OK;
-
-      pvm_set_compiler (pkc->vm, pkc->compiler);
-    }
+  if (!pkc)
+    return NULL;
+
+  if (flags & PK_F_NOSTDTYPES)
+    pkl_flags |= PKL_F_NOSTDTYPES;
+
+  /* Determine the path to the compiler's pkl-config.pk.  */
+  libpoke_configdir = getenv ("POKECONFIGDIR");
+  if (libpoke_configdir == NULL)
+    libpoke_configdir = PKGDATADIR;
+
+  /* Determine the path to the compiler's runtime files.  */
+  libpoke_datadir = getenv ("POKEDATADIR");
+  if (libpoke_datadir == NULL)
+    libpoke_datadir = PKGDATADIR;
+
+  pkc->term_if = *term_if;
+
+  pkc->vm = pvm_init ();
+  if (pkc->vm == NULL)
+    goto error;
 
+  pkc->term_if_state = pk_term_if_state_new (pkc->vm, &pkc->term_if);
+  if (!pkc->term_if_state)
+    goto error;
+
+  pkc->compiler = pkl_new (pkc->vm, libpoke_datadir, libpoke_configdir,
+                           pkl_flags, pkc->term_if_state);
+  if (pkc->compiler == NULL)
+    goto error;
+  pkc->complete_type = NULL;
+  pkc->status = PK_OK;
+
+  pvm_set_compiler (pkc->vm, pkc->compiler);
   return pkc;
 
- error:
+error:
+
+  if (pkc->compiler)
+    pkl_free (pkc->compiler);
+  if (pkc->term_if_state)
+    pk_term_if_state_free (pkc->term_if_state);
+  if (pkc->vm)
+    pvm_shutdown (pkc->vm);
   free (pkc);
   return NULL;
 }
@@ -118,6 +141,7 @@ pk_compiler_free (pk_compiler pkc)
   if (pkc)
     {
       pkl_free (pkc->compiler);
+      pk_term_if_state_free (pkc->term_if_state);
       pvm_shutdown (pkc->vm);
     }
 
@@ -501,9 +525,9 @@ pk_disassemble_function_val (pk_compiler pkc,
 
   program = pvm_val_cls_program (val);
   if (native_p)
-    pvm_disassemble_program_nat (program);
+    pvm_disassemble_program_nat (pkc->term_if_state, program);
   else
-    pvm_disassemble_program (program);
+    pvm_disassemble_program (pkc->term_if_state, program);
 
   PK_RETURN (PK_OK);
 }
@@ -556,9 +580,9 @@ pk_disassemble_expression (pk_compiler pkc, const char *str,
     }
 
   if (native_p)
-    pvm_disassemble_program_nat (program);
+    pvm_disassemble_program_nat (pkc->term_if_state, program);
   else
-    pvm_disassemble_program (program);
+    pvm_disassemble_program (pkc->term_if_state, program);
 
   PK_RETURN (PK_OK);
 }
@@ -1140,3 +1164,196 @@ pk_keyword_p (pk_compiler pkc, const char *str)
 
   return 0;
 }
+
+/* Terminal interface implementation.  */
+
+void
+pk_puts (struct pk_term_if *term_if, const char *str)
+{
+  term_if->puts_fn (term_if->data, str);
+}
+
+void
+pk_printf (struct pk_term_if *term_if, const char *format, ...)
+{
+  va_list ap;
+
+  va_start (ap, format);
+  term_if->vprintf_fn (term_if->data, format, ap);
+  va_end (ap);
+}
+
+void
+pk_term_flush (struct pk_term_if *term_if)
+{
+  term_if->flush_fn (term_if->data);
+}
+
+void
+pk_term_indent (struct pk_term_if *term_if, unsigned int lvl, unsigned int 
step)
+{
+  term_if->indent_fn (term_if->data, lvl, step);
+}
+
+void
+pk_term_class (struct pk_term_if *term_if, const char *aclass)
+{
+  term_if->class_fn (term_if->data, aclass);
+}
+
+int
+pk_term_end_class (struct pk_term_if *term_if, const char *aclass)
+{
+  return term_if->end_class_fn (term_if->data, aclass);
+}
+
+void
+pk_term_hyperlink (struct pk_term_if *term_if, const char *url, const char *id)
+{
+  term_if->hyperlink_fn (term_if->data, url, id);
+}
+
+int
+pk_term_end_hyperlink (struct pk_term_if *term_if)
+{
+  return term_if->end_hyperlink_fn (term_if->data);
+}
+
+struct pk_color
+pk_term_get_color (struct pk_term_if *term_if)
+{
+  return term_if->get_color_fn (term_if->data);
+}
+
+struct pk_color
+pk_term_get_bgcolor (struct pk_term_if *term_if)
+{
+  return term_if->get_bgcolor_fn (term_if->data);
+}
+
+void
+pk_term_set_color (struct pk_term_if *term_if, struct pk_color color)
+{
+  term_if->set_color_fn (term_if->data, color);
+}
+
+void
+pk_term_set_bgcolor (struct pk_term_if *term_if, struct pk_color color)
+{
+  term_if->set_bgcolor_fn (term_if->data, color);
+}
+
+/* Terminal interface for Jitter.  */
+
+static int
+_pvm_jitter_print_flush (jitter_print_context_data data)
+{
+  struct pk_term_if_state *pdata = (struct pk_term_if_state *)data;
+
+  pk_term_flush (pdata->term_if);
+  return 0;
+}
+
+static int
+_pvm_jitter_print_char (jitter_print_context_data data, char c)
+{
+  char str[2];
+  struct pk_term_if_state *pdata = (struct pk_term_if_state *)data;
+
+  str[0] = c;
+  str[1] = '\0';
+  pk_puts (pdata->term_if, (const char*) &str);
+  return 0;
+}
+
+static int
+_pvm_jitter_begin_decoration (jitter_print_context_data data,
+                             const jitter_print_decoration_name name,
+                             enum jitter_print_decoration_type type,
+                             const union jitter_print_decoration_value *value)
+{
+  struct pk_term_if_state *pdata = (struct pk_term_if_state *)data;
+  void *term_if = pdata->term_if;
+
+  if (STREQ (name, JITTER_PRINT_DECORATION_NAME_CLASS))
+    pk_term_class (term_if, value->string);
+  else
+    pk_term_hyperlink (term_if, value->string, NULL);
+
+  return 0;
+}
+
+static int
+_pvm_jitter_end_decoration (jitter_print_context_data data,
+                           const jitter_print_decoration_name name,
+                           enum jitter_print_decoration_type type,
+                           const union jitter_print_decoration_value *value)
+{
+  struct pk_term_if_state *pdata = (struct pk_term_if_state *)data;
+  void *term_if = pdata->term_if;
+
+  if (STREQ (name, JITTER_PRINT_DECORATION_NAME_CLASS))
+    pk_term_end_class (term_if, value->string);
+  else
+    pk_term_end_hyperlink (term_if);
+
+  return 0;
+}
+
+static struct pk_term_if_state *
+pk_term_if_state_new (pvm vm, void *term_if)
+{
+  jitter_print_context_kind kind = NULL;
+  struct pk_term_if_state *term_if_state = NULL;
+
+  kind = jitter_print_context_kind_make_trivial ();
+  if (!kind)
+    return NULL;
+
+  term_if_state = malloc (sizeof (struct pk_term_if_state));
+  if (!term_if_state)
+    goto error;
+
+  kind->print_char = _pvm_jitter_print_char;
+  kind->flush = _pvm_jitter_print_flush;
+  kind->begin_decoration = _pvm_jitter_begin_decoration;
+  kind->end_decoration = _pvm_jitter_end_decoration;
+
+  term_if_state->hi = 0;
+  term_if_state->vm = vm;
+  term_if_state->term_if = term_if;
+  term_if_state->jitter_print_ctx
+      = jitter_print_context_make (kind, term_if_state);
+
+  if (!term_if_state->jitter_print_ctx)
+    goto error;
+
+  return term_if_state;
+
+error:
+  if (term_if_state)
+    {
+      jitter_print_context_destroy (term_if_state->jitter_print_ctx);
+      free (term_if_state);
+    }
+  if (kind)
+    jitter_print_context_kind_destroy (kind);
+  return NULL;
+}
+
+static void
+pk_term_if_state_free (struct pk_term_if_state *term_if_state)
+{
+  jitter_print_context ctx;
+  jitter_print_context_kind kind;
+
+  if (!term_if_state)
+    return;
+
+  ctx = term_if_state->jitter_print_ctx;
+  kind = ctx->kind;
+
+  jitter_print_context_destroy (ctx);
+  jitter_print_context_kind_destroy (kind);
+  free (term_if_state);
+}
diff --git a/libpoke/libpoke.h b/libpoke/libpoke.h
index 095ef4b9..be60e8e2 100644
--- a/libpoke/libpoke.h
+++ b/libpoke/libpoke.h
@@ -76,46 +76,50 @@ struct pk_color
 struct pk_term_if
 {
   /* Flush the output in the terminal.  */
-  void (*flush_fn) (void);
+  void (*flush_fn) (void *data);
 
   /* Output a NULL-terminated C string.  */
-  void (*puts_fn) (const char *str);
+  void (*puts_fn) (void *data, const char *str);
 
   /* Output a formatted string.  */
-  void (*printf_fn) (const char *format, ...);
+  void (*vprintf_fn) (void *data, const char *format, va_list ap);
 
   /* Output LVL levels of indentation, using STEP white chars in each
      indentation level.  */
-  void (*indent_fn) (unsigned int lvl, unsigned int step);
+  void (*indent_fn) (void *data, unsigned int lvl, unsigned int step);
 
   /* Mark the beginning of a styling class with name CLASS.  */
-  void (*class_fn) (const char *aclass);
+  void (*class_fn) (void *data, const char *aclass);
 
   /* Mark the end of a styling class with name CLASS.  This function
      returns 0 if the given class is not active and therefore can't be
      ended.  1 otherwise.  */
-  int (*end_class_fn) (const char *aclass);
+  int (*end_class_fn) (void *data, const char *aclass);
 
   /* Mark the beginning of an hyperlink with url URL and identifier
      ID.  The identifier can be NULL.  */
-  void (*hyperlink_fn) (const char *url, const char *id);
+  void (*hyperlink_fn) (void *data, const char *url, const char *id);
 
   /* Mark the end of the current hyperlink.  This function returns 0
      if there is no currently an hyperlink open to close.  1
      otherwise.  */
-  int (*end_hyperlink_fn) (void);
+  int (*end_hyperlink_fn) (void *data);
 
   /* Get the current foreground color.  */
-  struct pk_color (*get_color_fn) (void);
+  struct pk_color (*get_color_fn) (void *data);
 
   /* Get the current background color.  */
-  struct pk_color (*get_bgcolor_fn) (void);
+  struct pk_color (*get_bgcolor_fn) (void *data);
 
   /* Set the foreground color.  */
-  void (*set_color_fn) (struct pk_color color);
+  void (*set_color_fn) (void *data, struct pk_color color);
 
   /* Set the background color.  */
-  void (*set_bgcolor_fn) (struct pk_color color);
+  void (*set_bgcolor_fn) (void *data, struct pk_color color);
+
+  /* User-specific data payload that will be passed to all terminal output
+     callbacks.  */
+  void *data;
 };
 
 /* Create and return a new Poke incremental compiler.
diff --git a/libpoke/pkl-diag.c b/libpoke/pkl-diag.c
index f5dbf30f..1e7ec03c 100644
--- a/libpoke/pkl-diag.c
+++ b/libpoke/pkl-diag.c
@@ -30,7 +30,7 @@
 #include "pkl-diag.h"
 
 static void
-pkl_print_filename (const char *filename)
+pkl_print_filename (void *term_if, const char *filename)
 {
   const char *fname;
 
@@ -41,11 +41,11 @@ pkl_print_filename (const char *filename)
   else
     fname = filename;
 
-  pk_printf ("%s:", fname);
+  pk_printf (term_if, "%s:", fname);
 }
 
 static void
-pkl_detailed_location (pkl_ast ast, pkl_ast_loc loc,
+pkl_detailed_location (void *term_if, pkl_ast ast, pkl_ast_loc loc,
                        const char *style_class)
 {
   size_t cur_line = 1;
@@ -93,9 +93,9 @@ pkl_detailed_location (pkl_ast ast, pkl_ast_loc loc,
               do
                 {
                   if (c == '\t')
-                    pk_puts (" ");
+                    pk_puts (term_if, " ");
                   else if (c != '\n')
-                    pk_printf ("%c", c);
+                    pk_printf (term_if, "%c", c);
                   c = fgetc (fp);
                 }
               while (c != EOF && c != '\0' && c != '\n');
@@ -130,7 +130,7 @@ pkl_detailed_location (pkl_ast ast, pkl_ast_loc loc,
               if (*p == '\n')
                 ++p;
               for (;*p != '\0' && *p != '\n'; ++p)
-                pk_printf ("%c", *p == '\t' ? ' ' : *p);
+                pk_printf (term_if, "%c", *p == '\t' ? ' ' : *p);
               break;
             }
         }
@@ -138,19 +138,19 @@ pkl_detailed_location (pkl_ast ast, pkl_ast_loc loc,
   else
     PK_UNREACHABLE ();
 
-  pk_puts ("\n");
+  pk_puts (term_if, "\n");
 
   for (i = 1; i < loc.first_column; ++i)
-    pk_puts (" ");
+    pk_puts (term_if, " ");
 
-  pk_term_class (style_class);
+  pk_term_class (term_if, style_class);
   for (; i < loc.last_column; ++i)
     if (i == loc.first_column)
-      pk_puts ("^");
+      pk_puts (term_if, "^");
     else
-      pk_puts ("~");
-  pk_term_end_class (style_class);
-  pk_puts ("\n");
+      pk_puts (term_if, "~");
+  pk_term_end_class (term_if, style_class);
+  pk_puts (term_if, "\n");
 }
 
 static void
@@ -161,6 +161,7 @@ pkl_error_internal (pkl_compiler compiler,
                     va_list valist)
 {
   char *errmsg, *p;
+  void *term_if = pkl_get_term_if (compiler);
 
   /* Write out the error message, line by line.  */
   vasprintf (&errmsg, fmt, valist);
@@ -168,41 +169,41 @@ pkl_error_internal (pkl_compiler compiler,
   p = errmsg;
   while (*p != '\0')
     {
-      pk_term_class ("error-filename");
+      pk_term_class (term_if, "error-filename");
       if (ast->filename)
-        pkl_print_filename (ast->filename);
+        pkl_print_filename (term_if, ast->filename);
       else
-        pk_puts ("<unknown>:");
-      pk_term_end_class ("error-filename");
+        pk_puts (term_if, "<unknown>:");
+      pk_term_end_class (term_if, "error-filename");
 
       if (PKL_AST_LOC_VALID (loc))
         {
-          pk_term_class ("error-location");
+          pk_term_class (term_if, "error-location");
           if (pkl_quiet_p (compiler))
-            pk_printf ("%d: ", loc.first_line);
+            pk_printf (term_if, "%d: ", loc.first_line);
           else
-            pk_printf ("%d:%d: ",
+            pk_printf (term_if, "%d:%d: ",
                        loc.first_line, loc.first_column);
-          pk_term_end_class ("error-location");
+          pk_term_end_class (term_if, "error-location");
         }
 
-      pk_term_class ("error");
-      pk_puts ("error: ");
-      pk_term_end_class ("error");
+      pk_term_class (term_if, "error");
+      pk_puts (term_if, "error: ");
+      pk_term_end_class (term_if, "error");
 
       while (*p != '\n' && *p != '\0')
         {
-          pk_printf ("%c", *p);
+          pk_printf (term_if, "%c", *p);
           p++;
         }
       if (*p == '\n')
         p++;
-      pk_puts ("\n");
+      pk_puts (term_if, "\n");
     }
   free (errmsg);
 
   if (!pkl_quiet_p (compiler))
-    pkl_detailed_location (ast, loc, "error");
+    pkl_detailed_location (term_if, ast, loc, "error");
 }
 
 void
@@ -228,38 +229,39 @@ pkl_warning (pkl_compiler compiler,
 {
   va_list valist;
   char *msg;
+  void *term_if = pkl_get_term_if (compiler);
 
   va_start (valist, fmt);
   vasprintf (&msg, fmt, valist);
   va_end (valist);
 
-  pk_term_class ("error-filename");
+  pk_term_class (term_if, "error-filename");
   if (ast->filename)
-    pkl_print_filename (ast->filename);
+    pkl_print_filename (term_if, ast->filename);
   else
-    pk_puts ("<unknown>:");
-  pk_term_end_class ("error-filename");
+    pk_puts (term_if, "<unknown>:");
+  pk_term_end_class (term_if, "error-filename");
 
   if (PKL_AST_LOC_VALID (loc))
     {
-      pk_term_class ("error-location");
+      pk_term_class (term_if, "error-location");
       if (pkl_quiet_p (compiler))
-        pk_printf ("%d: ", loc.first_line);
+        pk_printf (term_if, "%d: ", loc.first_line);
       else
-        pk_printf ("%d:%d: ",
+        pk_printf (term_if, "%d:%d: ",
                    loc.first_line, loc.first_column);
-      pk_term_end_class ("error-location");
+      pk_term_end_class (term_if, "error-location");
     }
-  pk_term_class ("warning");
-  pk_puts ("warning: ");
-  pk_term_end_class ("warning");
-  pk_puts (msg);
-  pk_puts ("\n");
+  pk_term_class (term_if, "warning");
+  pk_puts (term_if, "warning: ");
+  pk_term_end_class (term_if, "warning");
+  pk_puts (term_if, msg);
+  pk_puts (term_if, "\n");
 
   free (msg);
 
   if (!pkl_quiet_p (compiler))
-    pkl_detailed_location (ast, loc, "warning");
+    pkl_detailed_location (term_if, ast, loc, "warning");
 }
 
 void
@@ -271,6 +273,7 @@ pkl_ice (pkl_compiler compiler,
 {
   va_list valist;
   char tmpfile[1024];
+  void *term_if = pkl_get_term_if (compiler);
 
   if (!pkl_quiet_p (compiler))
   {
@@ -280,10 +283,10 @@ pkl_ice (pkl_compiler compiler,
     if (((des = path_search (tmpfile, 1024, NULL, "poke", true)) == -1)
         || ((des = mkstemp (tmpfile)) == -1))
       {
-        pk_term_class ("error");
-        pk_puts ("internal error: ");
-        pk_term_end_class ("error");
-        pk_puts ("determining a temporary file name\n");
+        pk_term_class (term_if, "error");
+        pk_puts (term_if, "internal error: ");
+        pk_term_end_class (term_if, "error");
+        pk_puts (term_if, "determining a temporary file name\n");
 
         return;
       }
@@ -291,10 +294,10 @@ pkl_ice (pkl_compiler compiler,
     out = fdopen (des, "w");
     if (out == NULL)
       {
-        pk_term_class ("error");
-        pk_puts ("internal error: ");
-        pk_term_end_class ("error");
-        pk_printf ("opening temporary file `%s'\n", tmpfile);
+        pk_term_class (term_if, "error");
+        pk_puts (term_if, "internal error: ");
+        pk_term_end_class (term_if, "error");
+        pk_printf (term_if, "opening temporary file `%s'\n", tmpfile);
         return;
       }
 
@@ -309,11 +312,11 @@ pkl_ice (pkl_compiler compiler,
 
   if (PKL_AST_LOC_VALID (loc))
     {
-      pk_term_class ("error-location");
-      pk_printf ("%d:%d: ", loc.first_line, loc.first_column);
-      pk_term_end_class ("error-location");
+      pk_term_class (term_if, "error-location");
+      pk_printf (term_if, "%d:%d: ", loc.first_line, loc.first_column);
+      pk_term_end_class (term_if, "error-location");
     }
-  pk_puts ("internal compiler error: ");
+  pk_puts (term_if, "internal compiler error: ");
   {
     char *msg;
 
@@ -321,20 +324,20 @@ pkl_ice (pkl_compiler compiler,
     vasprintf (&msg, fmt, valist);
     va_end (valist);
 
-    pk_puts (msg);
+    pk_puts (term_if, msg);
     free (msg);
   }
-  pk_puts ("\n");
+  pk_puts (term_if, "\n");
   if (!pkl_quiet_p (compiler))
     {
-      pk_printf ("Important information has been dumped in %s.\n",
+      pk_printf (term_if, "Important information has been dumped in %s.\n",
                  tmpfile);
-      pk_puts ("Please attach it to a bug report and send it to");
-      pk_term_hyperlink ("mailto:"; PACKAGE_BUGREPORT, NULL);
-      pk_puts (" " PACKAGE_BUGREPORT);
+      pk_puts (term_if, "Please attach it to a bug report and send it to");
+      pk_term_hyperlink (term_if, "mailto:"; PACKAGE_BUGREPORT, NULL);
+      pk_puts (term_if, " " PACKAGE_BUGREPORT);
     }
-  pk_term_end_hyperlink ();
-  pk_puts (".\n");
+  pk_term_end_hyperlink (term_if);
+  pk_puts (term_if, ".\n");
 }
 
 char *
diff --git a/libpoke/pkl.c b/libpoke/pkl.c
index 2b352c64..49cb1304 100644
--- a/libpoke/pkl.c
+++ b/libpoke/pkl.c
@@ -67,6 +67,7 @@ struct pkl_compiler
 {
   pkl_env env;  /* Compiler environment.  */
   pvm vm;
+  struct pk_term_if_state *term_if_state;
   int bootstrapped;
   int compiling;
   int error_on_warning;
@@ -88,10 +89,11 @@ pkl_load_rt (pkl_compiler compiler, char *poke_rt_pk)
     {
       free (poke_rt_pk);
 
-      pk_term_class ("error");
-      pk_puts ("internal error: ");
-      pk_term_end_class ("error");
-      pk_puts ("compiler failed to bootstrap itself\n");
+      pk_term_class (compiler->term_if_state->term_if, "error");
+      pk_puts (compiler->term_if_state->term_if, "internal error: ");
+      pk_term_end_class (compiler->term_if_state->term_if, "error");
+      pk_puts (compiler->term_if_state->term_if,
+               "compiler failed to bootstrap itself\n");
 
       pkl_free (compiler);
       return 0;
@@ -102,11 +104,13 @@ pkl_load_rt (pkl_compiler compiler, char *poke_rt_pk)
 
 pkl_compiler
 pkl_new (pvm vm, const char *rt_path,
-         const char *config_path, uint32_t flags)
+         const char *config_path, uint32_t flags,
+         struct pk_term_if_state *term_if_state)
 {
   pkl_compiler compiler
     = calloc (1, sizeof (struct pkl_compiler));
   pkl_env env;
+  void *term_if = term_if_state->term_if;
 
   if (!compiler)
     goto out_of_memory;
@@ -122,6 +126,9 @@ pkl_new (pvm vm, const char *rt_path,
      code for.  */
   compiler->vm = vm;
 
+  /* Set the terminal interface opaque pointer.  */
+  compiler->term_if_state = term_if_state;
+
   /* Be verbose by default :) */
   compiler->quiet_p = 0;
 
@@ -173,10 +180,10 @@ out_of_memory:
   if (compiler)
     pkl_free (compiler);
 
-  pk_term_class ("error");
-  pk_puts ("error: ");
-  pk_term_end_class ("error");
-  pk_puts ("out of memory\n");
+  pk_term_class (term_if, "error");
+  pk_puts (term_if, "error: ");
+  pk_term_end_class (term_if, "error");
+  pk_puts (term_if, "out of memory\n");
 
   return NULL;
 }
@@ -592,6 +599,18 @@ pkl_get_env (pkl_compiler compiler)
   return compiler->env;
 }
 
+struct pk_term_if_state *
+pkl_get_term_if_state (pkl_compiler compiler)
+{
+  return compiler->term_if_state;
+}
+
+struct pk_term_if *
+pkl_get_term_if (pkl_compiler compiler)
+{
+  return compiler->term_if_state->term_if;
+}
+
 int
 pkl_bootstrapped_p (pkl_compiler compiler)
 {
diff --git a/libpoke/pkl.h b/libpoke/pkl.h
index e90dedcb..a9877a76 100644
--- a/libpoke/pkl.h
+++ b/libpoke/pkl.h
@@ -80,13 +80,18 @@
 
    FLAGS is an ORed value of PKL_F_* values, or 0.
 
+   TERM_IF_STATE is a pointer to terminal interface state.
+
    If there is an error creating the compiler this function returns
    NULL.  */
 
 #define PKL_F_NOSTDTYPES 1 /* Do not define standard types.  */
 
+struct pk_term_if_state;  /* Defined in `pkt.h'.  */
+
 pkl_compiler pkl_new (pvm vm, const char *rt_path,
-                      const char *config_path, uint32_t flags);
+                      const char *config_path, uint32_t flags,
+                      struct pk_term_if_state *term_if_state);
 
 void pkl_free (pkl_compiler compiler);
 
@@ -178,6 +183,15 @@ struct pkl_env;  /* Defined in pkl-env.c */
 
 struct pkl_env *pkl_get_env (pkl_compiler compiler);
 
+/* Get pointer to terminal interface state structure.  */
+
+struct pk_term_if_state *pkl_get_term_if_state (pkl_compiler compiler);
+
+/* Get the pointer to the terminal interface.  */
+
+struct pk_term_if;  /* Defined in `libpoke.h'.  */
+struct pk_term_if *pkl_get_term_if (pkl_compiler compiler);
+
 /* Returns a boolean telling whether the compiler has been
    bootstrapped.  */
 
diff --git a/libpoke/pkt.h b/libpoke/pkt.h
index 5be77f68..39d741fc 100644
--- a/libpoke/pkt.h
+++ b/libpoke/pkt.h
@@ -21,21 +21,35 @@
 
 #include <config.h>
 
-#include "libpoke.h"  /* For struct pk_term_if */
-
-extern struct pk_term_if libpoke_term_if;
-
-#define pk_puts libpoke_term_if.puts_fn
-#define pk_printf libpoke_term_if.printf_fn
-#define pk_term_flush libpoke_term_if.flush_fn
-#define pk_term_indent libpoke_term_if.indent_fn
-#define pk_term_class libpoke_term_if.class_fn
-#define pk_term_end_class libpoke_term_if.end_class_fn
-#define pk_term_hyperlink libpoke_term_if.hyperlink_fn
-#define pk_term_end_hyperlink libpoke_term_if.end_hyperlink_fn
-#define pk_term_get_color libpoke_term_if.get_color_fn
-#define pk_term_set_color libpoke_term_if.set_color_fn
-#define pk_term_get_bgcolor libpoke_term_if.get_bgcolor_fn
-#define pk_term_set_bgcolor libpoke_term_if.set_bgcolor_fn
+#include "libpoke.h"  /* For `struct pk_color' and `struct pk_term_if *'.  */
+
+#include "jitter/jitter-print.h"
+
+void pk_puts (struct pk_term_if *term_if, const char *str);
+void pk_printf (struct pk_term_if *term_if, const char *format, ...);
+
+void pk_term_flush (struct pk_term_if *term_if);
+void pk_term_indent (struct pk_term_if *term_if, unsigned int lvl,
+                     unsigned int step);
+void pk_term_class (struct pk_term_if *term_if, const char *aclass);
+int pk_term_end_class (struct pk_term_if *term_if, const char *aclass);
+void pk_term_hyperlink (struct pk_term_if *term_if, const char *url,
+                        const char *id);
+int pk_term_end_hyperlink (struct pk_term_if *term_if);
+struct pk_color pk_term_get_color (struct pk_term_if *term_if);
+struct pk_color pk_term_get_bgcolor (struct pk_term_if *term_if);
+void pk_term_set_color (struct pk_term_if *term_if, struct pk_color color);
+void pk_term_set_bgcolor (struct pk_term_if *term_if, struct pk_color color);
+
+/* Data structure for passing data to Jitter print sub-system.  */
+
+struct pk_term_if_state
+{
+  jitter_uint hi;  /* Used as part of the hack to print literal arguments
+                      of `push32' instruction.  */
+  void *vm;  /* For PVM pretty-printers.  */
+  void *term_if;
+  jitter_print_context jitter_print_ctx;
+};
 
 #endif /* ! PKT_H */
diff --git a/libpoke/pvm-alloc.h b/libpoke/pvm-alloc.h
index 41ef049a..ee8caadd 100644
--- a/libpoke/pvm-alloc.h
+++ b/libpoke/pvm-alloc.h
@@ -25,7 +25,7 @@
 /* This file provides memory allocation services to the PVM code.  */
 
 /* Functions to initialize and finalize the allocator, respectively.
-   At finalization time all allocated memory is fred.  No pvm_alloc_*
+   At finalization time all allocated memory is freed.  No pvm_alloc_*
    services shall be used once finalized, unless pvm_alloc_init is
    invoked again.  */
 
diff --git a/libpoke/pvm-program.c b/libpoke/pvm-program.c
index 4e6ee175..a376116a 100644
--- a/libpoke/pvm-program.c
+++ b/libpoke/pvm-program.c
@@ -23,8 +23,7 @@
 #include <stdio.h> /* For stdout. */
 #include <xalloc.h> /* For xstrdup.  */
 
-#include "jitter/jitter-print.h"
-
+#include "pvm-program.h"
 #include "pk-utils.h"
 #include "pkt.h"
 
@@ -56,10 +55,6 @@ struct pvm_program
   int next_pointer;
 };
 
-/* Jitter print context to use when disassembling PVM programs.  */
-jitter_print_context_kind jitter_context_kind = NULL;
-jitter_print_context jitter_context = NULL;
-
 static void
 collect_value_pointers (pvm_program program, pvm_val val)
 {
@@ -260,59 +255,19 @@ pvm_program_routine (pvm_program program)
   return program->routine;
 }
 
-/* Jitter print context.  */
-
-static int
-pvm_jitter_print_flush (jitter_print_context_data data)
-{
-  pk_term_flush ();
-  return 0;
-}
-
-static int
-pvm_jitter_print_char (jitter_print_context_data d, char c)
-{
-  char str[2];
-
-  str[0] = c;
-  str[1] = '\0';
-  pk_puts ((const char*) &str);
-  return 0;
-}
-
-static int
-pvm_jitter_begin_decoration (jitter_print_context_data d,
-                             const jitter_print_decoration_name name,
-                             enum jitter_print_decoration_type type,
-                             const union jitter_print_decoration_value *value)
-{
-  if (STREQ (name, JITTER_PRINT_DECORATION_NAME_CLASS))
-    pk_term_class (value->string);
-  else
-    pk_term_hyperlink (value->string, NULL);
-
-  return 0;
-}
-
-static int
-pvm_jitter_end_decoration (jitter_print_context_data data,
-                           const jitter_print_decoration_name name,
-                           enum jitter_print_decoration_type type,
-                           const union jitter_print_decoration_value *value)
+void
+pvm_disassemble_program_nat (struct pk_term_if_state *term_if_state,
+                             pvm_program program)
 {
-  if (STREQ (name, JITTER_PRINT_DECORATION_NAME_CLASS))
-    pk_term_end_class (value->string);
-  else
-    pk_term_end_hyperlink ();
-
-  return 0;
+  pvm_routine_disassemble (term_if_state->jitter_print_ctx, program->routine,
+                           true, JITTER_OBJDUMP, NULL);
 }
 
 void
-pvm_disassemble_program_nat (pvm_program program)
+pvm_disassemble_program (struct pk_term_if_state *term_if_state,
+                         pvm_program program)
 {
-  pvm_routine_disassemble (jitter_context, program->routine,
-                           true, JITTER_OBJDUMP, NULL);
+  pvm_routine_print (term_if_state->jitter_print_ctx, program->routine);
 }
 
 char *
@@ -374,29 +329,11 @@ pvm_program_parse_from_string (const char *str, 
pvm_program program)
 }
 
 void
-pvm_disassemble_program (pvm_program program)
+pvm_program_init (void)
 {
-  pvm_routine_print (jitter_context, program->routine);
-}
-
-
-void
-pvm_program_init ()
-{
-  jitter_context_kind = jitter_print_context_kind_make_trivial ();
-
-  jitter_context_kind->print_char = pvm_jitter_print_char;
-  jitter_context_kind->flush = pvm_jitter_print_flush;
-  jitter_context_kind->begin_decoration = pvm_jitter_begin_decoration;
-  jitter_context_kind->end_decoration = pvm_jitter_end_decoration;
-
-  jitter_context = jitter_print_context_make (jitter_context_kind,
-                                              NULL);
 }
 
 void
-pvm_program_fini ()
+pvm_program_fini (void)
 {
-  jitter_print_context_destroy (jitter_context);
-  jitter_print_context_kind_destroy (jitter_context_kind);
 }
diff --git a/libpoke/pvm-val.c b/libpoke/pvm-val.c
index 58e33151..656e1bab 100644
--- a/libpoke/pvm-val.c
+++ b/libpoke/pvm-val.c
@@ -999,59 +999,59 @@ pvm_sizeof (pvm_val val)
 }
 
 static void
-print_unit_name (uint64_t unit)
+print_unit_name (void *term_if, uint64_t unit)
 {
   switch (unit)
     {
     case PVM_VAL_OFF_UNIT_BITS:
-      pk_puts ("b");
+      pk_puts (term_if, "b");
       break;
     case PVM_VAL_OFF_UNIT_NIBBLES:
-      pk_puts ("N");
+      pk_puts (term_if, "N");
       break;
     case PVM_VAL_OFF_UNIT_BYTES:
-      pk_puts ("B");
+      pk_puts (term_if, "B");
       break;
     case PVM_VAL_OFF_UNIT_KILOBITS:
-      pk_puts ("Kb");
+      pk_puts (term_if, "Kb");
       break;
     case PVM_VAL_OFF_UNIT_KILOBYTES:
-      pk_puts ("KB");
+      pk_puts (term_if, "KB");
       break;
     case PVM_VAL_OFF_UNIT_MEGABITS:
-      pk_puts ("Mb");
+      pk_puts (term_if, "Mb");
       break;
     case PVM_VAL_OFF_UNIT_MEGABYTES:
-      pk_puts ("MB");
+      pk_puts (term_if, "MB");
       break;
     case PVM_VAL_OFF_UNIT_GIGABITS:
-      pk_puts ("Gb");
+      pk_puts (term_if, "Gb");
       break;
     case PVM_VAL_OFF_UNIT_GIGABYTES:
-      pk_puts ("GB");
+      pk_puts (term_if, "GB");
       break;
     case PVM_VAL_OFF_UNIT_KIBIBITS:
-      pk_puts ("Kib");
+      pk_puts (term_if, "Kib");
       break;
     case PVM_VAL_OFF_UNIT_KIBIBYTES:
-      pk_puts ("KiB");
+      pk_puts (term_if, "KiB");
       break;
     case PVM_VAL_OFF_UNIT_MEBIBITS:
-      pk_puts ("Mib");
+      pk_puts (term_if, "Mib");
       break;
     case PVM_VAL_OFF_UNIT_MEBIBYTES:
-      pk_puts ("MiB");
+      pk_puts (term_if, "MiB");
       break;
     case PVM_VAL_OFF_UNIT_GIGIBITS:
-      pk_puts ("Gib");
+      pk_puts (term_if, "Gib");
       break;
     case PVM_VAL_OFF_UNIT_GIGIBYTES:
-      pk_puts ("GiB");
+      pk_puts (term_if, "GiB");
       break;
     default:
       /* XXX: print here the name of the base type of the
          offset.  */
-      pk_printf ("%" PRIu64, unit);
+      pk_printf (term_if, "%" PRIu64, unit);
     }
 }
 
@@ -1068,6 +1068,7 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
   const char *ulong64_fmt, *ulong_fmt;
   const char *int32_fmt, *int16_fmt, *int8_fmt, *int4_fmt, *int_fmt;
   const char *uint32_fmt, *uint16_fmt, *uint8_fmt, *uint4_fmt, *uint_fmt;
+  void *term_if = pvm_get_term_if (vm);
 
   /* Extract configuration settings from FLAGS.  */
   int maps = flags & PVM_PRINT_F_MAPS;
@@ -1150,14 +1151,14 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
 
   /* And print out the value in the given stream..  */
   if (val == PVM_NULL)
-    pk_puts ("null");
+    pk_puts (term_if, "null");
   else if (PVM_IS_LONG (val))
     {
       int size = PVM_VAL_LONG_SIZE (val);
       int64_t longval = PVM_VAL_LONG (val);
       uint64_t ulongval;
 
-      pk_term_class ("integer");
+      pk_term_class (term_if, "integer");
 
       if (size == 64)
         ulongval = (uint64_t) longval;
@@ -1166,20 +1167,20 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
 
       if (base == 2)
         {
-          pk_puts ("0b");
-          pk_print_binary (pk_puts, ulongval, size, /*signed_p*/ 1,
+          pk_puts (term_if, "0b");
+          pk_print_binary (pk_puts, term_if, ulongval, size, /*signed_p*/ 1,
                            /*use_suffix_p*/ 1);
         }
       else
         {
           if (size == 64)
-            pk_printf (long64_fmt, base == 10 ? longval : ulongval);
+            pk_printf (term_if, long64_fmt, base == 10 ? longval : ulongval);
           else
-            pk_printf (long_fmt, PVM_VAL_LONG_SIZE (val),
+            pk_printf (term_if, long_fmt, PVM_VAL_LONG_SIZE (val),
                        base == 10 ? longval : ulongval);
         }
 
-      pk_term_end_class ("integer");
+      pk_term_end_class (term_if, "integer");
     }
   else if (PVM_IS_INT (val))
     {
@@ -1187,7 +1188,7 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
       int32_t intval = PVM_VAL_INT (val);
       uint32_t uintval;
 
-      pk_term_class ("integer");
+      pk_term_class (term_if, "integer");
 
       if (size == 32)
         uintval = (uint32_t) intval;
@@ -1196,79 +1197,79 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
 
       if (base == 2)
         {
-          pk_puts ("0b");
-          pk_print_binary (pk_puts, (uint64_t) uintval, size, /*signed*/ 1,
-                           /*use_suffix_p*/ 1);
+          pk_puts (term_if, "0b");
+          pk_print_binary (pk_puts, term_if, (uint64_t) uintval, size,
+                           /*signed*/ 1, /*use_suffix_p*/ 1);
         }
       else
         {
           if (size == 32)
-            pk_printf (int32_fmt, base == 10 ? intval : uintval);
+            pk_printf (term_if, int32_fmt, base == 10 ? intval : uintval);
           else if (size == 16)
-            pk_printf (int16_fmt, base == 10 ? intval : uintval);
+            pk_printf (term_if, int16_fmt, base == 10 ? intval : uintval);
           else if (size == 8)
-            pk_printf (int8_fmt, base == 10 ? intval : uintval);
+            pk_printf (term_if, int8_fmt, base == 10 ? intval : uintval);
           else if (size == 4)
-            pk_printf (int4_fmt, base == 10 ? intval : uintval);
+            pk_printf (term_if, int4_fmt, base == 10 ? intval : uintval);
           else
-            pk_printf (int_fmt, PVM_VAL_INT_SIZE (val),
+            pk_printf (term_if, int_fmt, PVM_VAL_INT_SIZE (val),
                        base == 10 ? intval : uintval);
         }
 
-      pk_term_end_class ("integer");
+      pk_term_end_class (term_if, "integer");
     }
   else if (PVM_IS_ULONG (val))
     {
       int size = PVM_VAL_ULONG_SIZE (val);
       uint64_t ulongval = PVM_VAL_ULONG (val);
 
-      pk_term_class ("integer");
+      pk_term_class (term_if, "integer");
 
       if (base == 2)
         {
-          pk_puts ("0b");
-          pk_print_binary (pk_puts, ulongval, size, /*signed_p*/ 0,
+          pk_puts (term_if, "0b");
+          pk_print_binary (pk_puts, term_if, ulongval, size, /*signed_p*/ 0,
                            /*use_suffix_p*/ 1);
         }
       else
         {
           if (size == 64)
-            pk_printf (ulong64_fmt, ulongval);
+            pk_printf (term_if, ulong64_fmt, ulongval);
           else
-            pk_printf (ulong_fmt, PVM_VAL_LONG_SIZE (val), ulongval);
+            pk_printf (term_if, ulong_fmt, PVM_VAL_LONG_SIZE (val), ulongval);
         }
 
-      pk_term_end_class ("integer");
+      pk_term_end_class (term_if, "integer");
     }
   else if (PVM_IS_UINT (val))
     {
       int size = PVM_VAL_UINT_SIZE (val);
       uint32_t uintval = PVM_VAL_UINT (val);
 
-      pk_term_class ("integer");
+      pk_term_class (term_if, "integer");
 
       if (base == 2)
         {
-          pk_puts ("0b");
-          pk_print_binary (pk_puts, uintval, size, /*signed_p*/ 0,
+          pk_puts (term_if, "0b");
+          pk_print_binary (pk_puts, term_if, uintval, size, /*signed_p*/ 0,
                            /*use_suffix_p*/ 1);
         }
       else
         {
           if (size == 32)
-            pk_printf (uint32_fmt, uintval);
+            pk_printf (term_if, uint32_fmt, uintval);
           else if (size == 16)
-            pk_printf (uint16_fmt, uintval);
+            pk_printf (term_if, uint16_fmt, uintval);
           else if (size == 8)
-            pk_printf (uint8_fmt, uintval);
+            pk_printf (term_if, uint8_fmt, uintval);
           else if (size == 4)
-            pk_printf (uint4_fmt, uintval);
+            pk_printf (term_if, uint4_fmt, uintval);
           else
-            pk_printf (uint_fmt, PVM_VAL_UINT_SIZE (val),
+            pk_printf (term_if, uint_fmt, PVM_VAL_UINT_SIZE (val),
                        uintval);
         }
 
-      pk_term_end_class ("integer");
+      pk_term_end_class (term_if, "integer");
     }
   else if (PVM_IS_STR (val))
     {
@@ -1277,7 +1278,7 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
       size_t str_size = strlen (PVM_VAL_STR (val));
       size_t printable_size, i, j;
 
-      pk_term_class ("string");
+      pk_term_class (term_if, "string");
 
       /* Calculate the length (in bytes) of the printable string
          corresponding to the string value.  */
@@ -1328,10 +1329,10 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
       assert (j == printable_size);
       str_printable[j] = '\0';
 
-      pk_printf ("\"%s\"", str_printable);
+      pk_printf (term_if, "\"%s\"", str_printable);
       free (str_printable);
 
-      pk_term_end_class ("string");
+      pk_term_end_class (term_if, "string");
     }
   else if (PVM_IS_ARR (val))
     {
@@ -1339,22 +1340,22 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
       pvm_val array_offset = PVM_VAL_ARR_OFFSET (val);
 
       nelem = PVM_VAL_ULONG (PVM_VAL_ARR_NELEM (val));
-      pk_term_class ("array");
+      pk_term_class (term_if, "array");
 
-      pk_puts ("[");
+      pk_puts (term_if, "[");
       for (idx = 0; idx < nelem; idx++)
         {
           pvm_val elem_value = PVM_VAL_ARR_ELEM_VALUE (val, idx);
           pvm_val elem_offset = PVM_VAL_ARR_ELEM_OFFSET (val, idx);
 
           if (idx != 0)
-            pk_puts (",");
+            pk_puts (term_if, ",");
 
           if ((acutoff != 0) && (acutoff <= idx))
             {
-              pk_term_class ("ellipsis");
-              pk_puts ("...");
-              pk_term_end_class ("ellipsis");
+              pk_term_class (term_if, "ellipsis");
+              pk_puts (term_if, "...");
+              pk_term_end_class (term_if, "ellipsis");
               break;
             }
 
@@ -1362,27 +1363,27 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
 
           if (maps && elem_offset != PVM_NULL)
             {
-              pk_puts (" @ ");
-              pk_term_class ("offset");
+              pk_puts (term_if, " @ ");
+              pk_term_class (term_if, "offset");
               PVM_PRINT_VAL_1 (elem_offset, ndepth);
-              pk_puts ("#b");
-              pk_term_end_class ("offset");
+              pk_puts (term_if, "#b");
+              pk_term_end_class (term_if, "offset");
             }
         }
-      pk_puts ("]");
+      pk_puts (term_if, "]");
 
       if (maps && array_offset != PVM_NULL)
         {
           /* The struct offset is a bit-offset.  Do not bother to
              create a real offset here.  */
-          pk_puts (" @ ");
-          pk_term_class ("offset");
+          pk_puts (term_if, " @ ");
+          pk_term_class (term_if, "offset");
           PVM_PRINT_VAL_1 (array_offset, ndepth);
-          pk_puts ("#b");
-          pk_term_end_class ("offset");
+          pk_puts (term_if, "#b");
+          pk_term_end_class (term_if, "offset");
         }
 
-      pk_term_end_class ("array");
+      pk_term_end_class (term_if, "array");
     }
   else if (PVM_IS_SCT (val))
     {
@@ -1401,26 +1402,26 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
 
       nelem = PVM_VAL_ULONG (PVM_VAL_SCT_NFIELDS (val));
 
-      pk_term_class ("struct");
+      pk_term_class (term_if, "struct");
 
       if (struct_type_name != PVM_NULL)
         {
-          pk_term_class ("struct-type-name");
-          pk_puts ( PVM_VAL_STR (struct_type_name));
-          pk_term_end_class ("struct-type-name");
+          pk_term_class (term_if, "struct-type-name");
+          pk_puts (term_if, PVM_VAL_STR (struct_type_name));
+          pk_term_end_class (term_if, "struct-type-name");
         }
       else
-        pk_puts ("struct");
+        pk_puts (term_if, "struct");
 
       if (ndepth >= depth && depth != 0)
         {
-          pk_puts (" {...}");
-          pk_term_end_class ("struct");
+          pk_puts (term_if, " {...}");
+          pk_term_end_class (term_if, "struct");
           return;
         }
 
-      pk_puts (" ");
-      pk_printf ("{");
+      pk_puts (term_if, " ");
+      pk_printf (term_if, "{");
 
       nabsent = 0;
       for (idx = 0; idx < nelem; ++idx)
@@ -1434,88 +1435,88 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
           else
             {
               if ((idx - nabsent) != 0)
-                pk_puts (",");
+                pk_puts (term_if, ",");
 
               if (mode == PVM_PRINT_TREE)
-                pk_term_indent (ndepth + 1, indent);
+                pk_term_indent (term_if, ndepth + 1, indent);
 
               if (name != PVM_NULL)
                 {
-                  pk_term_class ("struct-field-name");
-                  pk_printf ("%s", PVM_VAL_STR (name));
-                  pk_term_end_class ("struct-field-name");
-                  pk_puts ("=");
+                  pk_term_class (term_if, "struct-field-name");
+                  pk_printf (term_if, "%s", PVM_VAL_STR (name));
+                  pk_term_end_class (term_if, "struct-field-name");
+                  pk_puts (term_if, "=");
                 }
               PVM_PRINT_VAL_1 (value, ndepth + 1);
 
               if (maps && offset != PVM_NULL)
                 {
-                  pk_puts (" @ ");
-                  pk_term_class ("offset");
+                  pk_puts (term_if, " @ ");
+                  pk_term_class (term_if, "offset");
                   PVM_PRINT_VAL_1 (offset, ndepth);
-                  pk_puts ("#b");
-                  pk_term_end_class ("offset");
+                  pk_puts (term_if, "#b");
+                  pk_term_end_class (term_if, "offset");
                 }
             }
         }
 
       if (mode == PVM_PRINT_TREE)
-        pk_term_indent (ndepth, indent);
-      pk_puts ("}");
+        pk_term_indent (term_if, ndepth, indent);
+      pk_puts (term_if, "}");
 
       if (maps && struct_offset != PVM_NULL)
         {
           /* The struct offset is a bit-offset.  Do not bother to
              create a real offset here.  */
-          pk_puts (" @ ");
-          pk_term_class ("offset");
+          pk_puts (term_if, " @ ");
+          pk_term_class (term_if, "offset");
           PVM_PRINT_VAL_1 (struct_offset, ndepth);
-          pk_puts ("#b");
-          pk_term_end_class ("offset");
+          pk_puts (term_if, "#b");
+          pk_term_end_class (term_if, "offset");
         }
 
-      pk_term_end_class ("struct");
+      pk_term_end_class (term_if, "struct");
     }
   else if (PVM_IS_TYP (val))
     {
-      pk_term_class ("type");
+      pk_term_class (term_if, "type");
 
       switch (PVM_VAL_TYP_CODE (val))
         {
         case PVM_TYPE_INTEGRAL:
           {
             if (!(PVM_VAL_INT (PVM_VAL_TYP_I_SIGNED_P (val))))
-              pk_puts ("u");
+              pk_puts (term_if, "u");
 
             switch (PVM_VAL_ULONG (PVM_VAL_TYP_I_SIZE (val)))
               {
-              case 8: pk_puts ("int8"); break;
-              case 16: pk_puts ("int16"); break;
-              case 32: pk_puts ("int32"); break;
-              case 64: pk_puts ("int64"); break;
+              case 8: pk_puts (term_if, "int8"); break;
+              case 16: pk_puts (term_if, "int16"); break;
+              case 32: pk_puts (term_if, "int32"); break;
+              case 64: pk_puts (term_if, "int64"); break;
               default: PK_UNREACHABLE (); break;
               }
           }
           break;
         case PVM_TYPE_STRING:
-          pk_puts ("string");
+          pk_puts (term_if, "string");
           break;
         case PVM_TYPE_VOID:
-          pk_puts ("void");
+          pk_puts (term_if, "void");
           break;
         case PVM_TYPE_ARRAY:
           PVM_PRINT_VAL_1 (PVM_VAL_TYP_A_ETYPE (val), ndepth);
-          pk_puts ("[");
+          pk_puts (term_if, "[");
           if (PVM_VAL_TYP_A_BOUND (val) != PVM_NULL)
             PVM_PRINT_VAL_1 (PVM_VAL_TYP_A_BOUND (val), ndepth);
-          pk_puts ("]");
+          pk_puts (term_if, "]");
           break;
         case PVM_TYPE_OFFSET:
-          pk_puts ("[");
+          pk_puts (term_if, "[");
           PVM_PRINT_VAL_1 (PVM_VAL_TYP_O_BASE_TYPE (val), ndepth);
-          pk_puts (" ");
-          print_unit_name (PVM_VAL_ULONG (PVM_VAL_TYP_O_UNIT (val)));
-          pk_puts ("]");
+          pk_puts (term_if, " ");
+          print_unit_name (term_if, PVM_VAL_ULONG (PVM_VAL_TYP_O_UNIT (val)));
+          pk_puts (term_if, "]");
           break;
         case PVM_TYPE_CLOSURE:
           {
@@ -1523,15 +1524,15 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
 
             nargs = PVM_VAL_ULONG (PVM_VAL_TYP_C_NARGS (val));
 
-            pk_puts ("(");
+            pk_puts (term_if, "(");
             for (i = 0; i < nargs; ++i)
               {
                 pvm_val atype = PVM_VAL_TYP_C_ATYPE (val, i);
                 if (i != 0)
-                  pk_puts (",");
+                  pk_puts (term_if, ",");
                 PVM_PRINT_VAL_1 (atype, ndepth);
               }
-            pk_puts (")");
+            pk_puts (term_if, ")");
 
             PVM_PRINT_VAL_1 (PVM_VAL_TYP_C_RETURN_TYPE (val), ndepth);
             break;
@@ -1544,48 +1545,48 @@ pvm_print_val_1 (pvm vm, int depth, int mode, int base, 
int indent,
             nelem = PVM_VAL_ULONG (PVM_VAL_TYP_S_NFIELDS (val));
 
             if (type_name != PVM_NULL)
-              pk_puts (PVM_VAL_STR (type_name));
+              pk_puts (term_if, PVM_VAL_STR (type_name));
             else
-              pk_puts ("struct");
+              pk_puts (term_if, "struct");
 
-            pk_puts (" {");
+            pk_puts (term_if, " {");
             for (i = 0; i < nelem; ++i)
               {
                 pvm_val ename = PVM_VAL_TYP_S_FNAME(val, i);
                 pvm_val etype = PVM_VAL_TYP_S_FTYPE(val, i);
 
                 if (i != 0)
-                  pk_puts (" ");
+                  pk_puts (term_if, " ");
 
                 PVM_PRINT_VAL_1 (etype, ndepth);
                 if (ename != PVM_NULL)
-                  pk_printf (" %s", PVM_VAL_STR (ename));
-                pk_puts (";");
+                  pk_printf (term_if, " %s", PVM_VAL_STR (ename));
+                pk_puts (term_if, ";");
               }
-            pk_puts ("}");
+            pk_puts (term_if, "}");
           break;
           }
         default:
           PK_UNREACHABLE ();
         }
 
-      pk_term_end_class ("type");
+      pk_term_end_class (term_if, "type");
     }
   else if (PVM_IS_OFF (val))
     {
       pvm_val val_type = PVM_VAL_OFF_TYPE (val);
 
-      pk_term_class ("offset");
+      pk_term_class (term_if, "offset");
       PVM_PRINT_VAL_1 (PVM_VAL_OFF_MAGNITUDE (val), ndepth);
-      pk_puts ("#");
-      print_unit_name (PVM_VAL_ULONG (PVM_VAL_TYP_O_UNIT (val_type)));
-      pk_term_end_class ("offset");
+      pk_puts (term_if, "#");
+      print_unit_name (term_if, PVM_VAL_ULONG (PVM_VAL_TYP_O_UNIT (val_type)));
+      pk_term_end_class (term_if, "offset");
     }
   else if (PVM_IS_CLS (val))
     {
-      pk_term_class ("special");
-      pk_puts ("#<closure>");
-      pk_term_end_class ("special");
+      pk_term_class (term_if, "special");
+      pk_puts (term_if, "#<closure>");
+      pk_term_end_class (term_if, "special");
     }
   else
     PK_UNREACHABLE ();
@@ -1723,9 +1724,9 @@ pvm_type_equal_p (pvm_val type1, pvm_val type2)
 }
 
 void
-pvm_print_string (pvm_val string)
+pvm_print_string (struct pk_term_if *term_if, pvm_val string)
 {
-  pk_puts (PVM_VAL_STR (string));
+  pk_puts (term_if, PVM_VAL_STR (string));
 }
 
 /* Call a struct pretty-print function in the closure CLS,
diff --git a/libpoke/pvm.c b/libpoke/pvm.c
index 0e212133..3013944c 100644
--- a/libpoke/pvm.c
+++ b/libpoke/pvm.c
@@ -147,14 +147,14 @@ pvm_init (void)
   return apvm;
 }
 
-extern jitter_print_context jitter_context; /* pvm-program.c */
-
 void
 pvm_print_profile (pvm apvm)
 {
   struct pvm_profile_runtime *p
     = pvm_state_profile_runtime (&apvm->pvm_state);
-  pvm_profile_runtime_print_unspecialized (jitter_context, p);
+  struct pk_term_if_state *term_if_state = pvm_get_term_if_state (apvm);
+
+  pvm_profile_runtime_print_unspecialized (term_if_state->jitter_print_ctx, p);
 }
 
 void
@@ -171,6 +171,20 @@ pvm_get_env (pvm apvm)
   return PVM_STATE_ENV (apvm);
 }
 
+struct pk_term_if_state *
+pvm_get_term_if_state (pvm apvm)
+{
+  assert (apvm->compiler != NULL);
+  return pkl_get_term_if_state (apvm->compiler);
+}
+
+struct pk_term_if *
+pvm_get_term_if (pvm apvm)
+{
+  assert (apvm->compiler != NULL);
+  return pkl_get_term_if (apvm->compiler);
+}
+
 enum pvm_exit_code
 pvm_run (pvm apvm, pvm_program program, pvm_val *res, pvm_val *exc)
 {
diff --git a/libpoke/pvm.h b/libpoke/pvm.h
index 26dafcfd..398781bc 100644
--- a/libpoke/pvm.h
+++ b/libpoke/pvm.h
@@ -89,15 +89,18 @@ void pvm_destroy_program (pvm_program program);
 
 int pvm_program_make_executable (pvm_program program);
 
-/* Print a native disassembly of the given program in the standard
-   output.  */
+struct pk_term_if_state;  /* Defined in `pkt.h'.  */
 
-void pvm_disassemble_program_nat (pvm_program program);
+/* Print a native disassembly of the given program using the given
+   terminal interface.  */
 
-/* Print a disassembly of the given program in the standard
-   output.  */
+void pvm_disassemble_program_nat (struct pk_term_if_state *,
+                                  pvm_program program);
 
-void pvm_disassemble_program (pvm_program program);
+/* Print a disassembly of the given program using the given terminal
+   interface.  */
+
+void pvm_disassemble_program (struct pk_term_if_state *, pvm_program program);
 
 /* **************** Assembling PVM Programs ****************  */
 
@@ -277,7 +280,8 @@ int pvm_val_equal_p (pvm_val val1, pvm_val val2);
 
 /*** PVM values.  ***/
 
-void pvm_print_string (pvm_val string);
+struct pk_term_if;  /* Defined in `libpoke.h'.  */
+void pvm_print_string (struct pk_term_if *term_if, pvm_val string);
 
 pvm_val pvm_ref_struct (pvm_val sct, pvm_val name);
 pvm_val pvm_ref_struct_cstr (pvm_val sct, const char *name);
@@ -606,6 +610,15 @@ ios_context pvm_ios_context (pvm apvm);
 
 pvm_env pvm_get_env (pvm pvm);
 
+/* Get pointer to terminal interface state structure.  */
+
+struct pk_term_if_state *pvm_get_term_if_state (pvm pvm);
+
+/* Get the pointer to the terminal interface.  */
+
+struct pk_term_if;  /* Defined in `libpoke.h'.  */
+struct pk_term_if *pvm_get_term_if (pvm pvm);
+
 /* Print a profiling summary corresponding to the current state of the
    PVM.  */
 
diff --git a/libpoke/pvm.jitter b/libpoke/pvm.jitter
index 8d44872f..e7be2552 100644
--- a/libpoke/pvm.jitter
+++ b/libpoke/pvm.jitter
@@ -90,8 +90,21 @@ wrapped-functions
   pvm_make_offset_type
   pvm_make_array_type
   pk_upow
+  pk_puts
+  pk_printf
+  pk_term_flush
+  pk_term_indent
+  pk_term_class
+  pk_term_end_class
+  pk_term_hyperlink
+  pk_term_end_hyperlink
+  pk_term_get_color
+  pk_term_get_bgcolor
+  pk_term_set_color
+  pk_term_set_bgcolor
   pk_print_binary
   pk_format_binary
+  pvm_get_term_if
   pvm_alloc
   pvm_allocate_struct_attrs
   pvm_make_struct_type
@@ -166,7 +179,6 @@ wrapped-globals
   pvm_literal_formatf_fmt
   pvm_literal_formatf_styles
   pvm_literal_dispatch_name
-  libpoke_term_if
   pvm_exception_names
 end
 
@@ -480,6 +492,8 @@ late-header-c
 #define PVM_PRINTI(TYPE,TYPEC,SIGNED_P,BASE)                                \
   do                                                                        \
   {                                                                         \
+    struct pk_term_if *term_if                                              \
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));                   \
     TYPEC val = PVM_VAL_##TYPE (JITTER_UNDER_TOP_STACK ());                 \
     char fmt[16];  /* %0NNd */                                              \
     char *iformat = pvm_literal_empty;                                      \
@@ -517,7 +531,7 @@ late-header-c
       }                                                                     \
       else if ((BASE) == 2)                                                 \
       {                                                                     \
-        pk_print_binary (pk_puts, val, JITTER_ARGN0, 1, 0);                 \
+        pk_print_binary (pk_puts, term_if, val, JITTER_ARGN0, 1, 0);        \
         JITTER_DROP_STACK ();                                               \
         JITTER_DROP_STACK ();                                               \
         break;                                                              \
@@ -531,7 +545,7 @@ late-header-c
       pvm_strcat (fmt, basefmt);                                            \
     }                                                                       \
                                                                             \
-    pk_printf (fmt, (BASE) == 10 ? val : val & mask);                       \
+    pk_printf (term_if, fmt, (BASE) == 10 ? val : val & mask);              \
     JITTER_DROP_STACK ();                                                   \
     JITTER_DROP_STACK ();                                                   \
   } while (0)
@@ -539,6 +553,8 @@ late-header-c
 #define PVM_PRINTL(TYPE,TYPEC,SIGNED_P,BASE)                                \
   do                                                                        \
   {                                                                         \
+    struct pk_term_if *term_if                                              \
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));                   \
     TYPEC val = PVM_VAL_##TYPE (JITTER_UNDER_TOP_STACK ());                 \
     char fmt[16];  /* %0NNfff */                                            \
     char *iformat = pvm_literal_empty;                                      \
@@ -571,7 +587,7 @@ late-header-c
       }                                                                     \
       else if ((BASE) == 2)                                                 \
       {                                                                     \
-        pk_print_binary (pk_puts, val, JITTER_ARGN0, 1, 0);                 \
+        pk_print_binary (pk_puts, term_if, val, JITTER_ARGN0, 1, 0);        \
         JITTER_DROP_STACK ();                                               \
         JITTER_DROP_STACK ();                                               \
         break;                                                              \
@@ -584,7 +600,7 @@ late-header-c
       pvm_strcat (fmt, basefmt);                                            \
     }                                                                       \
                                                                             \
-    pk_printf (fmt, (BASE) == 10 ? val : val & mask);                       \
+    pk_printf (term_if, fmt, (BASE) == 10 ? val : val & mask);              \
     JITTER_DROP_STACK ();                                                   \
     JITTER_DROP_STACK ();                                                   \
   } while (0)
@@ -737,6 +753,8 @@ late-header-c
 #define RTRACE(N)                                                           \
   do                                                                        \
     {                                                                       \
+      struct pk_term_if *term_if                                            \
+          = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));                 \
       int i = 0;                                                            \
       int num_elems = (N);                                                  \
       int num_elems_in_stack;                                               \
@@ -753,9 +771,9 @@ late-header-c
           pvm_val name = JITTER_AT_DEPTH_RETURNSTACK (i);                   \
                                                                             \
           if (name == PVM_NULL)                                             \
-            pk_printf ("<lambda>\n");                                       \
+            pk_printf (term_if, "<lambda>\n");                              \
           else                                                              \
-            pk_printf ("%s\n", PVM_VAL_STR (name));                         \
+            pk_printf (term_if, "%s\n", PVM_VAL_STR (name));                \
         }                                                                   \
     }                                                                       \
   while (0)
@@ -842,20 +860,24 @@ end
 
 printer-c
   code
-    static jitter_uint printer_hi;
+    #include "pkt.h"  /* For `struct pk_term_if_state'.  */
 
     static void
-    pvm_literal_printer_cast (jitter_print_context out, jitter_uint val)
+    pvm_literal_printer_cast (jitter_print_context ctx, jitter_uint val)
     {
-      pk_printf ("%" JITTER_PRIu, val);
-      pk_term_flush ();
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+      struct pk_term_if *term_if = pdata->term_if;
+
+      pk_printf (term_if, "%" JITTER_PRIu, val);
+      pk_term_flush (term_if);
     }
 
     static void
-    pvm_literal_printer (jitter_print_context out, jitter_uint val)
+    pvm_literal_printer (jitter_print_context ctx, jitter_uint val)
     {
-      pvm_print_val_with_params (NULL /* not used since no
-                                         pretty-print */,
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+
+      pvm_print_val_with_params (pdata->vm,
                                  (pvm_val) val,
                                  1 /* depth */,
                                  PVM_PRINT_FLAT,
@@ -864,25 +886,31 @@ printer-c
                                  2 /* acutoff */,
                                  0 /* flags */,
                                  NULL /* exit_exception */);
-      pk_term_flush ();
+      pk_term_flush (pdata->term_if);
     }
 
     static void
-    pvm_literal_printer_hi (jitter_print_context out, jitter_uint hi)
+    pvm_literal_printer_hi (jitter_print_context ctx, jitter_uint hi)
     {
-      pk_printf ("%%hi(0x%" JITTER_PRIx ")", hi);
-      pk_term_flush ();
-      printer_hi = hi; /* This sucks */
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+      struct pk_term_if *term_if = pdata->term_if;
+
+      pk_printf (term_if, "%%hi(0x%" JITTER_PRIx ")", hi);
+      pk_term_flush (term_if);
+      pdata->hi = hi; /* This sucks */
     }
 
     static void
-    pvm_literal_printer_lo (jitter_print_context out, jitter_uint lo)
+    pvm_literal_printer_lo (jitter_print_context ctx, jitter_uint lo)
     {
-      pk_printf ("%%lo(0x%" JITTER_PRIx") (", lo);
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+      struct pk_term_if *term_if = pdata->term_if;
+
+      pk_printf (term_if, "%%lo(0x%" JITTER_PRIx") (", lo);
 
       pvm_print_val_with_params (NULL /* not used since no
                                          pretty-print */,
-                                 ((pvm_val) printer_hi << 32) | lo,
+                                 ((pvm_val) pdata->hi << 32) | lo,
                                  1 /* depth */,
                                  PVM_PRINT_FLAT,
                                  16 /* base */,
@@ -890,37 +918,49 @@ printer-c
                                  2 /* acutoff */,
                                  0 /* flags */,
                                  NULL /* exit_exception */);
-      pk_puts (")");
-      pk_term_flush ();
-      printer_hi = 0;
+      pk_puts (term_if, ")");
+      pk_term_flush (term_if);
+      pdata->hi = 0;
     }
 
     static void
-    popf_printer (jitter_print_context out, jitter_uint nframes)
+    popf_printer (jitter_print_context ctx, jitter_uint nframes)
     {
-      pk_printf ("%" JITTER_PRIu, nframes);
-      pk_term_flush ();
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+      struct pk_term_if *term_if = pdata->term_if;
+
+      pk_printf (term_if, "%" JITTER_PRIu, nframes);
+      pk_term_flush (term_if);
     }
 
     static void
-    bits_printer (jitter_print_context out, jitter_uint val)
+    bits_printer (jitter_print_context ctx, jitter_uint val)
     {
-      pk_printf ("%" JITTER_PRIu, val);
-      pk_term_flush ();
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+      struct pk_term_if *term_if = pdata->term_if;
+
+      pk_printf (term_if, "%" JITTER_PRIu, val);
+      pk_term_flush (term_if);
     }
 
     static void
-    endian_printer (jitter_print_context out, jitter_uint val)
+    endian_printer (jitter_print_context ctx, jitter_uint val)
     {
-      pk_printf ("%s", val == IOS_ENDIAN_MSB ? "big" : "little");
-      pk_term_flush ();
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+      struct pk_term_if *term_if = pdata->term_if;
+
+      pk_printf (term_if, "%s", val == IOS_ENDIAN_MSB ? "big" : "little");
+      pk_term_flush (term_if);
     }
 
     static void
-    nenc_printer (jitter_print_context out, jitter_uint val)
+    nenc_printer (jitter_print_context ctx, jitter_uint val)
     {
-      pk_printf ("%s", val == IOS_NENC_1 ? "1c" : "2c");
-      pk_term_flush ();
+      struct pk_term_if_state *pdata = (struct pk_term_if_state *)ctx->data;
+      struct pk_term_if *term_if = pdata->term_if;
+
+      pk_printf (term_if, "%s", val == IOS_NENC_1 ? "1c" : "2c");
+      pk_term_flush (term_if);
     }
   end
 end
@@ -1374,7 +1414,9 @@ end
 
 instruction pushoc ()
   code
-    struct pk_color color = pk_term_get_color ();
+    struct pk_term_if *term_if
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
+    struct pk_color color = pk_term_get_color (term_if);
 
     JITTER_PUSH_STACK (PVM_MAKE_INT (color.red, 32));
     JITTER_PUSH_STACK (PVM_MAKE_INT (color.green, 32));
@@ -1391,6 +1433,8 @@ end
 
 instruction popoc ()
   code
+    struct pk_term_if *term_if
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
     struct pk_color color;
 
     color.blue = PVM_VAL_INT (JITTER_TOP_STACK ());
@@ -1400,7 +1444,7 @@ instruction popoc ()
     color.red = PVM_VAL_INT (JITTER_TOP_STACK ());
     JITTER_DROP_STACK ();
 
-    pk_term_set_color (color);
+    pk_term_set_color (term_if, color);
   end
 end
 
@@ -1413,7 +1457,9 @@ end
 
 instruction pushobc ()
   code
-    struct pk_color color = pk_term_get_bgcolor ();
+    struct pk_term_if *term_if
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
+    struct pk_color color = pk_term_get_bgcolor (term_if);
 
     JITTER_PUSH_STACK (PVM_MAKE_INT (color.red, 32));
     JITTER_PUSH_STACK (PVM_MAKE_INT (color.green, 32));
@@ -1431,6 +1477,8 @@ end
 instruction popobc ()
   code
     struct pk_color color;
+    struct pk_term_if *term_if =
+        pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
 
     color.blue = PVM_VAL_INT (JITTER_TOP_STACK ());
     color.green = PVM_VAL_INT (JITTER_UNDER_TOP_STACK ());
@@ -1439,7 +1487,7 @@ instruction popobc ()
     color.red = PVM_VAL_INT (JITTER_TOP_STACK ());
     JITTER_DROP_STACK ();
 
-    pk_term_set_bgcolor (color);
+    pk_term_set_bgcolor (term_if, color);
   end
 end
 
@@ -2112,7 +2160,10 @@ end
 instruction prints ()
   non-relocatable
   code
-    pvm_print_string (JITTER_TOP_STACK ());
+    struct pk_term_if *term_if
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
+
+    pvm_print_string (term_if, JITTER_TOP_STACK ());
     JITTER_DROP_STACK ();
   end
 end
@@ -2128,10 +2179,12 @@ instruction beghl ()
   code
     char *url = PVM_VAL_STR (JITTER_UNDER_TOP_STACK ());
     char *id = PVM_VAL_STR (JITTER_TOP_STACK ());
+    struct pk_term_if *term_if
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
 
     JITTER_DROP_STACK ();
     JITTER_DROP_STACK ();
-    pk_term_hyperlink (url, id);
+    pk_term_hyperlink (term_if, url, id);
   end
 end
 
@@ -2149,7 +2202,10 @@ instruction endhl ()
   non-relocatable
   branching # because of PVM_RAISE_DIRECT
   code
-    if (!pk_term_end_hyperlink ())
+    struct pk_term_if *term_if
+        = pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
+
+    if (!pk_term_end_hyperlink (term_if))
       PVM_RAISE (PVM_E_GENERIC,
                  pvm_literal_nohyperlink,
                  PVM_E_GENERIC_ESTATUS);
@@ -2167,7 +2223,10 @@ end
 instruction begsc ()
   non-relocatable
   code
-    pk_term_class (PVM_VAL_STR (JITTER_TOP_STACK ()));
+    struct pk_term_if *term_if =
+        pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
+
+    pk_term_class (term_if, PVM_VAL_STR (JITTER_TOP_STACK ()));
     JITTER_DROP_STACK ();
   end
 end
@@ -2183,7 +2242,10 @@ instruction endsc ()
   non-relocatable
   branching # because of PVM_RAISE_DIRECT
   code
-    if (!pk_term_end_class (PVM_VAL_STR (JITTER_TOP_STACK ())))
+    struct pk_term_if *term_if =
+        pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
+
+    if (!pk_term_end_class (term_if, PVM_VAL_STR (JITTER_TOP_STACK ())))
       PVM_RAISE (PVM_E_INVAL,
                  pvm_literal_invalid_class,
                  PVM_E_INVAL_ESTATUS);
@@ -7057,6 +7119,8 @@ instruction strace (?n)
     int i = 0;
     int num_elems = (int) JITTER_ARGN0;
     int num_elems_in_stack;
+    struct pk_term_if *term_if =
+        pvm_get_term_if (PVM_STATE_BACKING_FIELD (vm));
 
     PVM_ASSERT (PVM_STATE_BACKING_FIELD (canary_stack) != NULL);
 
@@ -7076,7 +7140,7 @@ instruction strace (?n)
                                    0 /* acutoff */,
                                    PVM_PRINT_F_MAPS,
                                    NULL /* exit_exception */);
-        pk_puts (pvm_literal_newline);
+        pk_puts (term_if, pvm_literal_newline);
         i++;
       }
   end
@@ -7107,8 +7171,11 @@ end
 instruction disas ()
   non-relocatable
   code
+    struct pk_term_if_state *term_if_state
+        = pvm_get_term_if_state (PVM_STATE_BACKING_FIELD (vm));
     pvm_val cls = JITTER_TOP_STACK ();
-    pvm_disassemble_program (PVM_VAL_CLS_PROGRAM (cls));
+
+    pvm_disassemble_program (term_if_state, PVM_VAL_CLS_PROGRAM (cls));
   end
 end
 
diff --git a/poke/pk-term.c b/poke/pk-term.c
index cad4ca16..874d4a1c 100644
--- a/poke/pk-term.c
+++ b/poke/pk-term.c
@@ -363,7 +363,7 @@ pk_term_shutdown ()
 }
 
 void
-pk_term_flush ()
+pk_term_flush_1 (void *user_data __attribute__ ((unused)))
 {
   ostream_flush (pk_ostream, FLUSH_THIS_STREAM);
 }
@@ -469,7 +469,7 @@ pk_puts_paged (const char *lines)
 }
 
 void
-pk_puts (const char *str)
+pk_puts_1 (void *user_data __attribute__ ((unused)), const char *str)
 {
   if (pager_active_p)
     pk_puts_paged (str);
@@ -495,7 +495,8 @@ pk_printf (const char *format, ...)
 }
 
 void
-pk_vprintf (const char *format, va_list ap)
+pk_vprintf_1 (void *user_data __attribute__ ((unused)),
+              const char *format, va_list ap)
 {
   char *str;
   int r;
@@ -509,21 +510,24 @@ pk_vprintf (const char *format, va_list ap)
 
 
 void
-pk_term_indent (unsigned int lvl,
-                unsigned int step)
+pk_term_indent_1 (void *user_data __attribute__ ((unused)),
+                  unsigned int lvl,
+                  unsigned int step)
 {
   pk_printf ("\n%*s", (step * lvl), "");
 }
 
 void
-pk_term_class (const char *class)
+pk_term_class_1 (void *user_data __attribute__ ((unused)),
+                 const char *class)
 {
   styled_ostream_begin_use_class (pk_ostream, class);
   push_active_class (class);
 }
 
 int
-pk_term_end_class (const char *class)
+pk_term_end_class_1 (void *user_data __attribute__ ((unused)),
+                     const char *class)
 {
   if (!pop_active_class (class))
     return 0;
@@ -536,7 +540,8 @@ pk_term_end_class (const char *class)
 static int hlcount = 0;
 
 void
-pk_term_hyperlink (const char *url, const char *id)
+pk_term_hyperlink_1 (void *user_data __attribute__ ((unused)),
+                     const char *url, const char *id)
 {
 #ifdef HAVE_TEXTSTYLE_HYPERLINK_SUPPORT
   styled_ostream_set_hyperlink (pk_ostream, url, id);
@@ -545,7 +550,7 @@ pk_term_hyperlink (const char *url, const char *id)
 }
 
 int
-pk_term_end_hyperlink (void)
+pk_term_end_hyperlink_1 (void *user_data __attribute__ ((unused)))
 {
 #ifdef HAVE_TEXTSTYLE_HYPERLINK_SUPPORT
   if (hlcount == 0)
@@ -567,7 +572,7 @@ pk_term_color_p (void)
 }
 
 struct pk_color
-pk_term_get_color (void)
+pk_term_get_color_1 (void *user_data __attribute__ ((unused)))
 {
 #if defined HAVE_TEXTSTYLE_ACCESSORS_SUPPORT
    if (color_mode != color_html
@@ -590,7 +595,7 @@ pk_term_get_color (void)
 }
 
 struct pk_color
-pk_term_get_bgcolor ()
+pk_term_get_bgcolor_1 (void *user_data __attribute__ ((unused)))
 {
 #if defined HAVE_TEXTSTYLE_ACCESSORS_SUPPORT
   if (color_mode != color_html
@@ -613,7 +618,8 @@ pk_term_get_bgcolor ()
 }
 
 void
-pk_term_set_color (struct pk_color color)
+pk_term_set_color_1 (void *user_data __attribute__ ((unused)),
+                     struct pk_color color)
 {
 #if defined HAVE_TEXTSTYLE_ACCESSORS_SUPPORT
   if (color_mode != color_html)
@@ -641,7 +647,8 @@ pk_term_set_color (struct pk_color color)
 }
 
 void
-pk_term_set_bgcolor (struct pk_color color)
+pk_term_set_bgcolor_1 (void *user_data __attribute__ ((unused)),
+                       struct pk_color color)
 {
 #if defined HAVE_TEXTSTYLE_ACCESSORS_SUPPORT
   if (color_mode != color_html)
diff --git a/poke/pk-term.h b/poke/pk-term.h
index 8516dc30..952ad454 100644
--- a/poke/pk-term.h
+++ b/poke/pk-term.h
@@ -32,33 +32,46 @@ void pk_term_shutdown (void);
 extern int pk_term_color_p (void);
 
 /* Flush the terminal output.  */
-extern void pk_term_flush (void);
+extern void pk_term_flush_1 (void *user_data);
+#define pk_term_flush() pk_term_flush_1 (NULL)
 
 /* Print a string to the terminal.  */
-extern void pk_puts (const char *str);
+extern void pk_puts_1 (void *user_data, const char *str);
+#define pk_puts(...) pk_puts_1 (NULL, __VA_ARGS__)
 
 /* Print a formatted string to the terminal.  */
 extern void pk_printf (const char *format, ...)
   __attribute__ ((format (printf, 1, 2)));
-extern void pk_vprintf (const char *format, va_list ap);
+extern void pk_vprintf_1 (void *user_data, const char *format, va_list ap);
+#define pk_vprintf(...) pk_vprintf_1 (NULL, __VA_ARGS__)
 
 /* Print indentation.  */
-extern void pk_term_indent (unsigned int lvl,
-                            unsigned int step);
+extern void pk_term_indent_1 (void *user_data,
+                              unsigned int lvl, unsigned int step);
+#define pk_term_indent(...) pk_term_indent_1 (NULL, __VA_ARGS__)
 
 /* Class handling.  */
-extern void pk_term_class (const char *class);
-extern int pk_term_end_class (const char *class);
+extern void pk_term_class_1 (void *user_data, const char *class);
+extern int pk_term_end_class_1 (void *user_data, const char *class);
+#define pk_term_class(...) pk_term_class_1 (NULL, __VA_ARGS__)
+#define pk_term_end_class(...) pk_term_end_class_1 (NULL, __VA_ARGS__)
 
 /* Hyperlinks.  */
-extern void pk_term_hyperlink (const char *url, const char *id);
-extern int pk_term_end_hyperlink (void);
+extern void pk_term_hyperlink_1 (void *user_data,
+                               const char *url, const char *id);
+extern int pk_term_end_hyperlink_1 (void *user_data);
+#define pk_term_hyperlink(...) pk_term_hyperlink_1 (NULL, __VA_ARGS__)
+#define pk_term_end_hyperlink() pk_term_end_hyperlink_1 (NULL);
 
 /* Color handling.  */
-extern struct pk_color pk_term_get_color (void);
-extern struct pk_color pk_term_get_bgcolor (void);
-extern void pk_term_set_color (struct pk_color color);
-extern void pk_term_set_bgcolor (struct pk_color color);
+extern struct pk_color pk_term_get_color_1 (void *user_data);
+extern struct pk_color pk_term_get_bgcolor_1 (void *user_data);
+extern void pk_term_set_color_1 (void *user_data, struct pk_color color);
+extern void pk_term_set_bgcolor_1 (void *user_data, struct pk_color color);
+#define pk_term_get_color() pk_term_get_color_1 (NULL)
+#define pk_term_get_bgcolor() pk_term_get_bgcolor_1 (NULL)
+#define pk_term_set_color(...) pk_term_set_color_1 (NULL, __VA_ARGS__)
+#define pk_term_set_bgcolor(...) pk_term_set_bgcolor_1 (NULL, __VA_ARGS__)
 
 /* Paging.  */
 extern void pk_term_start_pager (void);
diff --git a/poke/poke.c b/poke/poke.c
index d6ecf596..fe307f83 100644
--- a/poke/poke.c
+++ b/poke/poke.c
@@ -296,18 +296,18 @@ finalize (void)
 
 static struct pk_term_if poke_term_if =
   {
-    .flush_fn = pk_term_flush,
-    .puts_fn = pk_puts,
-    .printf_fn = pk_printf,
-    .indent_fn = pk_term_indent,
-    .class_fn = pk_term_class,
-    .end_class_fn = pk_term_end_class,
-    .hyperlink_fn = pk_term_hyperlink,
-    .end_hyperlink_fn = pk_term_end_hyperlink,
-    .get_color_fn = pk_term_get_color,
-    .set_color_fn = pk_term_set_color,
-    .get_bgcolor_fn = pk_term_get_bgcolor,
-    .set_bgcolor_fn = pk_term_set_bgcolor,
+    .flush_fn = pk_term_flush_1,
+    .puts_fn = pk_puts_1,
+    .vprintf_fn = pk_vprintf_1,
+    .indent_fn = pk_term_indent_1,
+    .class_fn = pk_term_class_1,
+    .end_class_fn = pk_term_end_class_1,
+    .hyperlink_fn = pk_term_hyperlink_1,
+    .end_hyperlink_fn = pk_term_end_hyperlink_1,
+    .get_color_fn = pk_term_get_color_1,
+    .set_color_fn = pk_term_set_color_1,
+    .get_bgcolor_fn = pk_term_get_bgcolor_1,
+    .set_bgcolor_fn = pk_term_set_bgcolor_1,
   };
 
 const char *
diff --git a/poked/poked.c b/poked/poked.c
index 7e087c6a..aa00363a 100644
--- a/poked/poked.c
+++ b/poked/poked.c
@@ -701,27 +701,27 @@ tifbuf_init(void)
 #endif
 
 static void
-tif_flush (void)
+tif_flush (void *data)
 {
+  (void)data;
 }
 static void
-tif_puts (const char *s)
+tif_puts (void *data, const char *s)
 {
+  (void)data;
   if (poked_options.debug_p)
     printf (">(p) '%s'\n", s);
   usock_out (srv, termout_chan, termout_cmdkind, s, strlen (s) + 1);
 }
 static void
-tif_printf (const char *fmt, ...)
+tif_vprintf (void *d, const char *fmt, va_list ap)
 {
-  va_list ap;
   char *data = NULL;
   int n;
 
-  va_start (ap, fmt);
-  n = vasprintf (&data, fmt, ap);
-  va_end (ap);
+  (void)d;
 
+  n = vasprintf (&data, fmt, ap);
   assert (n >= 0);
 
   if (poked_options.debug_p)
@@ -730,7 +730,7 @@ tif_printf (const char *fmt, ...)
   free (data);
 }
 static void
-tif_indent (unsigned int level, unsigned int step)
+tif_indent (void *d, unsigned int level, unsigned int step)
 {
   size_t len = /*newline*/ 1u + step * level;
   char *data;
@@ -743,57 +743,63 @@ tif_indent (unsigned int level, unsigned int step)
   free (data);
 }
 static void
-tif_class (const char *name)
+tif_class (void *data, const char *name)
 {
   if (termout_chan == USOCK_CHAN_OUT_OUT)
     usock_out (srv, termout_chan, OUTCMD_CLS_BEGIN, name, strlen (name) + 1);
 }
 static int
-tif_class_end (const char *name)
+tif_class_end (void *data, const char *name)
 {
   if (termout_chan == USOCK_CHAN_OUT_OUT)
     usock_out (srv, termout_chan, OUTCMD_CLS_END, name, strlen (name) + 1);
   return 1;
 }
 static void
-tif_hlink (const char *name, const char *id)
+tif_hlink (void *data, const char *name, const char *id)
 {
+  (void)data;
   (void)name;
   (void)id;
 }
 static int
-tif_hlink_end (void)
+tif_hlink_end (void *data)
 {
+  (void)data;
   return 1;
 }
 static struct pk_color
-tif_color (void)
+tif_color (void *data)
 {
   static struct pk_color c = {
     .red = 0,
     .green = 0,
     .blue = 0,
   };
+  (void)data;
   return c;
 }
 static struct pk_color
-tif_bgcolor (void)
+tif_bgcolor (void *data)
 {
   static struct pk_color c = {
     .red = 255,
     .green = 255,
     .blue = 255,
   };
+  (void)data;
   return c;
 }
 static void
-tif_color_set (struct pk_color c)
+tif_color_set (void *data, struct pk_color c)
 {
+  (void)data;
   (void)c;
 }
 static void
-tif_bgcolor_set (struct pk_color c)
+tif_bgcolor_set (void *data, struct pk_color c)
 {
+  (void)data;
   (void)c;
 }
 
@@ -904,7 +910,7 @@ poked_init (int pdap_version)
   static struct pk_term_if tif = {
     .flush_fn = tif_flush,
     .puts_fn = tif_puts,
-    .printf_fn = tif_printf,
+    .vprintf_fn = tif_vprintf,
     .indent_fn = tif_indent,
     .class_fn = tif_class,
     .end_class_fn = tif_class_end,
diff --git a/testsuite/poke.libpoke/api.c b/testsuite/poke.libpoke/api.c
index c37dfde8..64320db5 100644
--- a/testsuite/poke.libpoke/api.c
+++ b/testsuite/poke.libpoke/api.c
@@ -67,7 +67,7 @@ test_pk_compiler_new (void)
   tif.puts_fn = poke_term_if.puts_fn;
   TT (5);
 
-  tif.printf_fn = poke_term_if.printf_fn;
+  tif.vprintf_fn = poke_term_if.vprintf_fn;
   TT (6);
 
   tif.indent_fn = poke_term_if.indent_fn;
@@ -83,8 +83,20 @@ test_pk_compiler_new (void)
   TT (10);
 
   tif.end_hyperlink_fn = poke_term_if.end_hyperlink_fn;
+  TT (11);
+
+  tif.get_color_fn = poke_term_if.get_color_fn;
+  TT (12);
+
+  tif.get_bgcolor_fn = poke_term_if.get_bgcolor_fn;
+  TT (13);
+
+  tif.set_color_fn = poke_term_if.set_color_fn;
+  TT (14);
+
+  tif.set_bgcolor_fn = poke_term_if.set_bgcolor_fn;
   pkc = pk_compiler_new (&tif);
-  T ("pk_compiler_new_11", pkc != NULL);
+  T ("pk_compiler_new_15", pkc != NULL);
 
 #undef TT
 
diff --git a/testsuite/poke.libpoke/term-if.h b/testsuite/poke.libpoke/term-if.h
index dfcece14..aa11aa3b 100644
--- a/testsuite/poke.libpoke/term-if.h
+++ b/testsuite/poke.libpoke/term-if.h
@@ -20,87 +20,83 @@
 #include <stdio.h>
 
 static void
-pk_term_flush ()
+pk_term_flush (void *data __attribute__ ((unused)))
 {
 }
 
 void
-pk_puts (const char *str)
+pk_puts (void *data __attribute__ ((unused)), const char *str)
 {
   printf ("%s", str);
 }
 
-__attribute__ ((__format__ (__printf__, 1, 2)))
 void
-pk_printf (const char *format, ...)
+pk_vprintf (void *data __attribute__ ((unused)),
+            const char *format, va_list ap)
 {
-  va_list ap;
-
-  va_start (ap, format);
   vprintf (format, ap);
-  va_end (ap);
 }
 
 void
-pk_term_indent (unsigned int lvl,
+pk_term_indent (void *data __attribute__ ((unused)), unsigned int lvl,
                 unsigned int step)
 {
   printf ("\n%*s", (step * lvl), "");
 }
 
 void
-pk_term_class (const char *class)
+pk_term_class (void *data __attribute__ ((unused)), const char *class)
 {
 }
 
 int
-pk_term_end_class (const char *class)
+pk_term_end_class (void *data __attribute__ ((unused)), const char *class)
 {
   return 1;
 }
 
 void
-pk_term_hyperlink (const char *url, const char *id)
+pk_term_hyperlink (void *data __attribute__ ((unused)), const char *url,
+                   const char *id)
 {
 }
 
 int
-pk_term_end_hyperlink (void)
+pk_term_end_hyperlink (void *data __attribute__ ((unused)))
 {
   return 1;
 }
 
 struct pk_color
-pk_term_get_color (void)
+pk_term_get_color (void *data __attribute__ ((unused)))
 {
   struct pk_color inv = {-1,-1,-1};
   return inv;
 }
 
 struct pk_color
-pk_term_get_bgcolor (void)
+pk_term_get_bgcolor (void *data __attribute__ ((unused)))
 {
   struct pk_color inv = {-1,-1,-1};
   return inv;
 }
 
 void
-pk_term_set_color (struct pk_color color)
+pk_term_set_color (void *data __attribute__ ((unused)), struct pk_color color)
 {
-
 }
 
 void
-pk_term_set_bgcolor (struct pk_color color)
+pk_term_set_bgcolor (void *data __attribute__ ((unused)),
+                     struct pk_color color)
 {
-
 }
 
 static struct pk_term_if poke_term_if =
   {
     .flush_fn = pk_term_flush,
     .puts_fn = pk_puts,
-    .printf_fn = pk_printf,
+    .vprintf_fn = pk_vprintf,
     .indent_fn = pk_term_indent,
     .class_fn = pk_term_class,
     .end_class_fn = pk_term_end_class,
-- 
2.41.0




reply via email to

[Prev in Thread] Current Thread [Next in Thread]