poke-devel
[Top][All Lists]
Advanced

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

Formatted output in poke with libtextstyle


From: Jose E. Marchesi
Subject: Formatted output in poke with libtextstyle
Date: Thu, 10 Oct 2019 19:31:15 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/26.1 (gnu/linux)

Hi people!

I will be committing something based in the work below soon.
Please take a look.  Feedback is much welcome :)

---

This patch adds support for libtextsyle[1] to poke.  This library,
written by Bruno Haible, provides a supernice styled output stream that
is portable and and allows users to style the output of programs writing
.css files.  The styled output can be colored, underlined, made bold, or
made terminal hyperlinks.
    
In a nutshell, twwo new command line options are added to GNU poke:
--color={yes,no,test} and
--style=FILE.
    
By default poke looks in PKGDATADIR/poke-default.css for the style to
use.  The user can override it by defining POKESTYLEDIR, or by using the
--style command line option.
    
There are a couple of remaining problems:
- Jitter needs to gain the capability of use user-provided printing
  abstractions, in at least two places: the instruction argument
  pretty-printers, and the disassembler.  At the moment the patch
  allows emitting libtextstyled text mixed with normal stdout by
  placing some flushes in strategic places.
- libreadline expects the prompt to be passed to readline("..."), and
  relies on the lenght of the prompt in order to calculate certain
  things, like where the cursor should stop when you press C-a, for
  example.
    
We need to document the set of classes that are supported.  At the
moment they are just sketched in etc/poke-default.css.
    
[1] 
https://www.gnu.org/software/gettext/libtextstyle/manual/html_node/index.html
    
2019-10-10  Jose E. Marchesi  <address@hidden>
    
      * etc/poke-default.css: New file.
      * src/pk-term.c: Likewise.
      * Makefile.am (SUBDIRS): Add etc/.
      * src/pvm.jitter: pk_printf is a wrapped function.
      Include pk-term.h in early-c.
      Use pk-term printing services in pretty printers and instructions.
      * src/pvm-val.h: pvm_print_string and pvm_print_val do not take a
      FILE* argument any longer.
      * src/pvm-val.c (pvm_print_binary): Likewise.
      (pvm_print_val): Likewise.
      (pvm_print_string): Likewise.
      * src/poke.c: Include pk-term.h.
      Support --color and --style long options.
      (print_help): Use print services from pk-term.
      (pk_print_version): Likewise.
      (finalize): Shutdown the pk-term subsystem.
      (repl): Likewise.
      (parse_args): Handle --color and -style.
      (initialize): Get argc and argv as arguments.
      (initialize): Initialize the pk-term subsytem.
      (main): Pass argc and argv to `initialize'.
      * src/pkl.c (pkl_new): Likewise.
      (pkl_error): Likewise.
      (pkl_warning): Likewise.
      (pkl_ice): Likewise.
      * src/pk-vm.c (pk_cmd_vm_disas_fun): Use print services from
      pk-term.
      (pk_cmd_vm_disas_map): Likewise.
      (pk_cmd_vm_disas_writ): Likewise.
      * src/pk-term.h: Include textstyle.h.
      Remove obsolete constants.
      Add prototypes for pk-term services.
      * src/pk-set.c: Include pk-term.h.
      (pk_cmd_set_obase): Use print services form pk-term.
      (pk_cmd_set_endian): Likewise.
      (pk_cmd_set_nenc): Likewise.
      * src/pk-print.c: Include pk-term.h.
      (pk_cmd_print): Use print services from pk-term.
      * src/pk-def.c: Include pk-term.h.
      (print_var_decl): Use print services from pk-term.
      (print_fun_decl): Likewise.
      * src/pk-cmd.c: Include pk-term.h.
      (pk_cmd_exec_1): Use print services from pk-term.
      (pk_cmd_exec): Likewise.
      * src/Makefile.am (poke_CPPFLAGS): Add $(top_builddir)/lib to the
      include path.
      * bootstrap.conf (gnulib_modules): Add textstyle-optional.
      * configure.ac: Use gl_LIBTEXTSTYLE_OPTIONAL.
      * src/Makefile.am (poke_LDADD): Link with libtextstyle.
      * testsuite/lib/poke-dg.exp (poke-dg-test): Pass --color=no to
      poke when running tests.
      * testsuite/lib/poke.exp (poke_start): Likewise.
      * HACKING (Appendix):List src/pk-term.c in sources.

diff --git a/HACKING b/HACKING
index 5cc9d83..61b3b36 100644
--- a/HACKING
+++ b/HACKING
@@ -1123,7 +1123,7 @@ Infrastructure for writing poke commands
   ``src/pk-cmd.h``, ``src/pk-cmd.c``
 
 Terminal stuff
-  ``src/pk-term.h``
+  ``src/pk-term.h``, ``src/pk-term.c``
 
 Commands
   ``src/pk-def.c``, ``src/pk-dump.pk``, ``src/pk-file.c``,
diff --git a/Makefile.am b/Makefile.am
index 92ca870..9af50d2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,2 +1,2 @@
 ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = lib pickles src doc testsuite po
+SUBDIRS = lib pickles src doc testsuite etc po
diff --git a/bootstrap.conf b/bootstrap.conf
index ef064eb..218df56 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -20,7 +20,7 @@
 gnulib_modules="
   progname list array-list xalloc getopt-gnu getopt-gnu printf-posix isatty 
readline
   parse-datetime mkstemp tempname tmpdir secure_getenv gcd maintainer-makefile
-  streq gendocs readline random"
+  streq gendocs readline random libtextstyle-optional"
 
 checkout_only_file=
 MSGID_BUGS_ADDRESS=address@hidden
diff --git a/configure.ac b/configure.ac
index 7aca519..4cc64b9 100644
--- a/configure.ac
+++ b/configure.ac
@@ -88,6 +88,11 @@ AC_ARG_ENABLE([debug],
 AM_CONDITIONAL([POKE_DEBUG],
                [test "x$poke_debug" = "xyes"])
 
+dnl Use libtextstyle if available.  Otherwise, use the dummy header
+dnl file provided by gnulib's libtextstyle-optional module.
+
+gl_LIBTEXTSTYLE_OPTIONAL
+
 dnl Generate output files
 AC_CONFIG_FILES(Makefile
                 lib/Makefile
@@ -95,7 +100,15 @@ AC_CONFIG_FILES(Makefile
                 pickles/Makefile
                 doc/Makefile
                 po/Makefile.in
+                etc/Makefile
                 testsuite/Makefile)
 AC_OUTPUT
 
+dnl Report warning
+
+if test "x$HAVE_LIBTEXTSTYLE" = "xno"; then
+   echo "warning: libtextstyle was not found in the system."
+   echo "warning: poke's output won't be styled."
+fi
+
 dnl End of configure.ac
diff --git a/etc/poke-default.css b/etc/poke-default.css
new file mode 100644
index 0000000..2c5f80c
--- /dev/null
+++ b/etc/poke-default.css
@@ -0,0 +1,21 @@
+/* This file is in the public domain.
+   Default styling rules for GNU poke.  */
+
+/* .logo .copyright .type .struct-type-name .array */
+
+.logo { text-decoration: blink; }
+.error { color : red; }
+.error-filename { text-decoration: underline; }
+.error-location { text-decoration: underline; }
+.warning { color : yellow; }
+.prompt { font-weight : bold; }
+.offset { color : yellow; }
+.special { color : black; }
+.string { color : brown; }
+.any { color : yellow; }
+.struct-field-name { text-decoration : underline; }
+.integer { color : green; }
+
+html {
+    font-family: Menlo, Monaco, "Courier New", monospace;   
+}
diff --git a/src/Makefile.am b/src/Makefile.am
index 910a097..69f9bf3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -23,6 +23,7 @@ bin_PROGRAMS = poke
 poke_SOURCES = poke.c poke.h \
                ios.c ios.h ios-dev.h \
                ios-dev-file.c \
+               pk-term.c pk-term.h \
                pk-cmd.c pk-cmd.h \
                pk-file.c \
                pk-info.c pk-misc.c pk-help.c pk-vm.c \
@@ -64,7 +65,7 @@ poke_CPPFLAGS = -I$(top_builddir)/lib -I$(top_srcdir)/lib \
                 -DLOCALEDIR=\"$(localedir)\"
 poke_CFLAGS = -Wall $(BDW_GC_CFLAGS)
 poke_LDADD = $(top_builddir)/lib/libpoke.la \
-             $(LTLIBREADLINE) $(BDW_GC_LIBS)
+             $(LTLIBREADLINE) $(BDW_GC_LIBS) $(LIBTEXTSTYLE)
 poke_LDFLAGS =
 
 # Integration with jitter.
diff --git a/src/pk-cmd.c b/src/pk-cmd.c
index 8c560d8..d2db4cc 100644
--- a/src/pk-cmd.c
+++ b/src/pk-cmd.c
@@ -37,6 +37,7 @@
 #include "pkl-parser.h"
 #include "ios.h"
 #include "pk-cmd.h"
+#include "pk-term.h"
 
 /* Table of supported commands.  */
 
@@ -274,8 +275,8 @@ pk_cmd_exec_1 (char *str, struct pk_trie *cmds_trie, char 
*prefix)
   if (cmd == NULL)
     {
       if (prefix != NULL)
-        printf ("%s ", prefix);
-      printf (_("%s: command not found.\n"), cmd_name);
+        pk_printf ("%s ", prefix);
+      pk_printf (_("%s: command not found.\n"), cmd_name);
       return 0;
     }
 
@@ -296,7 +297,7 @@ pk_cmd_exec_1 (char *str, struct pk_trie *cmds_trie, char 
*prefix)
 
           if (cmd->uflags[fi] == '\0')
             {
-              printf (_("%s: invalid flag `%c'\n"), cmd_name, *p);
+              pk_printf (_("%s: invalid flag `%c'\n"), cmd_name, *p);
               return 0;
             }
 
@@ -537,7 +538,7 @@ pk_cmd_exec_1 (char *str, struct pk_trie *cmds_trie, char 
*prefix)
   if (cmd->flags & PK_CMD_F_REQ_IO
       && ios_cur () == NULL)
     {
-      puts (_("This command requires an IO space.  Use the `file' command."));
+      pk_puts (_("This command requires an IO space.  Use the `file' 
command."));
       return 0;
     }
 
@@ -547,7 +548,7 @@ pk_cmd_exec_1 (char *str, struct pk_trie *cmds_trie, char 
*prefix)
       if (cur_io == NULL
           || !(ios_mode (cur_io) & IOS_M_RDWR))
         {
-          puts (_("This command requires a writable IO space."));
+          pk_puts (_("This command requires a writable IO space."));
           return 0;
         }
     }
@@ -570,7 +571,7 @@ pk_cmd_exec_1 (char *str, struct pk_trie *cmds_trie, char 
*prefix)
 
  usage:
   if (!besilent)
-    printf (_("Usage: %s\n"), cmd->usage);
+    pk_printf (_("Usage: %s\n"), cmd->usage);
   return 0;
 }
 
@@ -643,8 +644,8 @@ pk_cmd_exec (char *str)
 
           if (val != PVM_NULL)
             {
-              pvm_print_val (stdout, val, poke_obase, 0);
-              fputc ('\n', stdout);
+              pvm_print_val (val, poke_obase, 0);
+              pk_puts ("\n");
             }
         }
 
diff --git a/src/pk-def.c b/src/pk-def.c
index 9330d0a..12e234c 100644
--- a/src/pk-def.c
+++ b/src/pk-def.c
@@ -18,6 +18,7 @@
 
 #include <config.h>
 #include <assert.h>
+/* XXX to remove */
 #include <stdio.h>
 #include <string.h>
 #include <gettext.h>
@@ -27,6 +28,7 @@
 #include "pvm.h"
 #include "poke.h"
 #include "pk-cmd.h"
+#include "pk-term.h"
 
 static void
 print_var_decl (pkl_ast_node decl, void *data)
@@ -52,18 +54,18 @@ print_var_decl (pkl_ast_node decl, void *data)
   assert (val != PVM_NULL);
 
   /* Print the name and the current value of the variable.  */
-  fputs (PKL_AST_IDENTIFIER_POINTER (decl_name), stdout);
-  fputs ("\t\t", stdout);
+  pk_puts (PKL_AST_IDENTIFIER_POINTER (decl_name));
+  pk_puts ("\t\t");
   /* XXX: support different bases with a /[xbo] cmd flag.  */
-  pvm_print_val (stdout, val, 10, 0);
-  fputs ("\t\t", stdout);
+  pvm_print_val (val, 10, 0);
+  pk_puts ("\t\t");
 
   /* Print information about the site where the variable was
      declared.  */
   if (source)
-    printf ("%s:%d\n", basename (source), loc.first_line);
+    pk_printf ("%s:%d\n", basename (source), loc.first_line);
   else
-    fputs ("<stdin>\n", stdout);
+    pk_puts ("<stdin>\n");
 }
 
 static void
@@ -88,23 +90,23 @@ print_fun_decl (pkl_ast_node decl, void *data)
                           &back, &over) != NULL);
 
   /* Print the name and the type of the function.  */
-  fputs (PKL_AST_IDENTIFIER_POINTER (decl_name), stdout);
-  fputs ("  ", stdout);
+  pk_puts (PKL_AST_IDENTIFIER_POINTER (decl_name));
+  pk_puts ("  ");
   pkl_print_type (stdout, PKL_AST_TYPE (func), 1);
-  fputs ("  ", stdout);
+  pk_puts ("  ");
 
   /* Print information about the site where the function was
      declared.  */
   if (source)
-    printf ("%s:%d\n", basename (source), loc.first_line);
+    pk_printf ("%s:%d\n", basename (source), loc.first_line);
   else
-    fputs ("<stdin>\n", stdout);
+    pk_puts ("<stdin>\n");
 }
 
 static int
 pk_cmd_info_var (int argc, struct pk_cmd_arg argv[], uint64_t uflags)
 {
-  printf (_("Name\t\tValue\t\t\tDeclared at\n"));
+  pk_puts (_("Name\t\tValue\t\t\tDeclared at\n"));
   pkl_env_map_decls (pkl_get_env (poke_compiler), PKL_AST_DECL_KIND_VAR,
                      print_var_decl, NULL);
   return 1;
diff --git a/src/pk-print.c b/src/pk-print.c
index da47c34..b22e78c 100644
--- a/src/pk-print.c
+++ b/src/pk-print.c
@@ -18,12 +18,12 @@
 
 #include <config.h>
 #include <assert.h>
-#include <stdio.h> /* For stdout */
 #include <gettext.h>
 #define _(str) dgettext (PACKAGE, str)
 
 #include "poke.h"
 #include "pk-cmd.h"
+#include "pk-term.h"
 
 #define PK_PRINT_UFLAGS "xbom"
 #define PK_PRINT_F_HEX 0x1
@@ -54,7 +54,7 @@ pk_cmd_print (int argc, struct pk_cmd_arg argv[], uint64_t 
uflags)
       + !!(uflags & PK_PRINT_F_BIN)
       + !!(uflags & PK_PRINT_F_OCT) > 1)
     {
-      printf (_("print: only one of `x', `b' or `o' may be specified.\n"));
+      pk_printf (_("print: only one of `x', `b' or `o' may be specified.\n"));
       return 0;
     }
 
@@ -72,8 +72,8 @@ pk_cmd_print (int argc, struct pk_cmd_arg argv[], uint64_t 
uflags)
   if (pvm_ret != PVM_EXIT_OK)
     goto rterror;
 
-  pvm_print_val (stdout, val, base, pflags);
-  printf ("\n");
+  pvm_print_val (val, base, pflags);
+  pk_puts ("\n");
   return 1;
 
  rterror:
diff --git a/src/pk-set.c b/src/pk-set.c
index 7dbfd02..50331a7 100644
--- a/src/pk-set.c
+++ b/src/pk-set.c
@@ -25,6 +25,7 @@
 
 #include "poke.h"
 #include "pk-cmd.h"
+#include "pk-term.h"
 #include "ios.h"
 #include "pvm.h"
 
@@ -38,7 +39,10 @@ pk_cmd_set_obase (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
 
   if (base != 10 && base != 16 && base != 2 && base != 8)
     {
-      fputs ("error: obase should be one of 2, 8, 10 or 16.\n", stdout);
+      pk_term_class ("error");
+      pk_puts ("error: ");
+      pk_term_end_class ("error");
+      pk_puts ("obase should be one of 2, 8, 10 or 16.\n");
       return 0;
     }
 
@@ -114,8 +118,10 @@ pk_cmd_set_endian (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
         }
       else
         {
-          fputs ("error: endian should be one of `little', `big', `host' or 
`network'.\n",
-                 stdout);
+          pk_term_class ("error");
+          pk_puts ("error: ");
+          pk_term_end_class ("error");
+          pk_puts ("endian should be one of `little', `big', `host' or 
`network'.\n");
           return 0;
         }
 
@@ -164,8 +170,10 @@ pk_cmd_set_nenc (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
         nenc = IOS_NENC_2;
       else
         {
-          fputs ("error: nenc should be one of `1c' or `2c'.\n",
-                 stdout);
+          pk_term_class ("error");
+          pk_puts ("error: ");
+          pk_term_end_class ("error");
+          pk_puts (" nenc should be one of `1c' or `2c'.\n");
           return 0;
         }
 
diff --git a/src/pk-term.c b/src/pk-term.c
new file mode 100644
index 0000000..e160097
--- /dev/null
+++ b/src/pk-term.c
@@ -0,0 +1,131 @@
+/* pk-cmd.c - terminal related stuff.  */
+
+/* Copyright (C) 2019 Jose E. Marchesi */
+
+/* This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <unistd.h> /* For isatty */
+#include <sys/stat.h> /* For stat and stabuf */
+#include <textstyle.h>
+
+#include "poke.h" /* For poke_ostream.  */
+
+/* The following global is the libtextstyle output stream to use to
+   emit contents to the terminal.  */
+styled_ostream_t poke_ostream;
+
+void
+pk_term_init (int argc, char *argv[])
+{
+  int i;
+
+  /* Process terminal-related command-line options.  */
+  for (i = 1; i < argc; i++)
+    {
+      const char *arg = argv[i];
+
+      if (strncmp (arg, "--color=", 8) == 0)
+        {
+          if (handle_color_option (arg + 8))
+            exit (EXIT_FAILURE);
+        }
+      else if (strncmp (arg, "--style=", 8) == 0)
+        handle_style_option (arg + 8);
+    }
+
+  /* Handle the --color=test special argument.  */
+  if (color_test_mode)
+    {
+      print_color_test ();
+      exit (EXIT_SUCCESS);
+    }
+
+  /* Note that the following code needs to be compiled conditionally
+     because the textstyle.h file provided by the gnulib module
+     libtextstyle-optional defines style_file_name as an r-value.  */
+
+#ifdef HAVE_LIBTEXTSTYLE
+  /* Open the specified style.  */
+  if (color_mode == color_yes
+      || (color_mode == color_tty
+          && isatty (STDOUT_FILENO)
+          && getenv ("NO_COLOR") == NULL)
+      || color_mode == color_html)
+    {
+      /* Find the style file.  */
+      style_file_prepare ("POKE_STYLE", "POKESTYLESDIR", PKGDATADIR,
+                          "poke-default.css");
+    }
+  else
+    /* No styling.  */
+    style_file_name = NULL;
+#endif
+
+  /* Create the output styled stream.  */
+  poke_ostream =
+    (color_mode == color_html
+     ? html_styled_ostream_create (file_ostream_create (stdout),
+                                   style_file_name)
+     : styled_ostream_create (STDOUT_FILENO, "(stdout)",
+                              TTYCTL_AUTO, style_file_name));
+}
+
+void
+pk_term_shutdown ()
+{
+  styled_ostream_free (poke_ostream);
+}
+
+void
+pk_term_flush ()
+{
+  ostream_flush (poke_ostream, FLUSH_THIS_STREAM);
+}
+
+void
+pk_puts (const char *str)
+{
+  ostream_write_str (poke_ostream, str);
+}
+
+__attribute__ ((__format__ (__printf__, 1, 2)))
+void
+pk_printf (const char *format, ...)
+{
+  va_list ap;
+  char *str;
+
+  va_start (ap, format);
+  assert (vasprintf (&str, format, ap) != -1);
+  va_end (ap);
+
+  ostream_write_str (poke_ostream, str);
+  free (str);
+}
+
+void
+pk_term_class (const char *class)
+{
+  styled_ostream_begin_use_class (poke_ostream, class);
+}
+
+void
+pk_term_end_class (const char *class)
+{
+  styled_ostream_end_use_class (poke_ostream, class);
+}
diff --git a/src/pk-term.h b/src/pk-term.h
index 8eb7f1b..a8fd6fb 100644
--- a/src/pk-term.h
+++ b/src/pk-term.h
@@ -19,67 +19,26 @@
 #ifndef PK_TERM_H
 #define PK_TERM_H
 
-/* Define ANSI terminal escape sequences to print each object with
-   attributes depending on its tag. */
+#include <config.h>
 
-#if 0
+#include <textstyle.h>
 
-#define ESC        "\033"
-#define NOATTR     ESC"[0m"
-#define BOLD       ESC"[1m"
-#define FAINT      ESC"[2m"
-#define ITALIC     ESC"[3m"
-#define UNDERLINE  ESC"[4m"
-#define REVERSE    ESC"[7m"
-#define CROSSOUT   ESC"[9m"
+/* Initialize and finalize the terminal subsystem.  */
+void pk_term_init (int argc, char *argv[]);
+void pk_term_shutdown (void);
 
-#define BLACK        ESC"[0m"ESC"[30m"
-#define WHITE        ESC"[1m"ESC"[37m"
-#define BLUE         ESC"[0m"ESC"[34m"
-#define LIGHTBLUE    ESC"[1m"ESC"[34m"
-#define GREEN        ESC"[0m"ESC"[32m"
-#define LIGHTGREEN   ESC"[1m"ESC"[32m"
-#define CYAN         ESC"[0m"ESC"[36m"
-#define LIGHTCYAN    ESC"[1m"ESC"[36m"
-#define RED          ESC"[0m"ESC"[31m"
-#define LIGHTRED     ESC"[1m"ESC"[31m"
-#define MAGENTA      ESC"[0m"ESC"[35m"
-#define LIGHTMAGENTA ESC"[1m"ESC"[35m"
-#define BROWN        ESC"[0m"ESC"[33m"
-#define LIGHTGRAY    ESC"[0m"ESC"[37m"
-#define DARKGRAY     ESC"[1m"ESC"[30m"
-#define LIGHTBLUE    ESC"[1m"ESC"[34m"
-#define YELLOW       ESC"[1m"ESC"[33m"
+/* Flush the terminal output.  */
+extern void pk_term_flush (void);
 
-#else
+/* Print a string to the terminal.  */
+extern void pk_puts (const char *str);
 
-#define ESC
-#define NOATTR
-#define BOLD
-#define FAINT
-#define ITALIC
-#define UNDERLINE
-#define REVERSE
-#define CROSSOUT
+/* Print a formatted string to the terminal.  */
+extern void pk_printf (const char *format, ...);
 
-#define BLACK
-#define WHITE
-#define BLUE
-#define LIGHTBLUE
-#define GREEN
-#define LIGHTGREEN
-#define CYAN
-#define LIGHTCYAN
-#define RED
-#define LIGHTRED
-#define MAGENTA
-#define LIGHTMAGENTA
-#define BROWN
-#define LIGHTGRAY
-#define DARKGRAY
-#define LIGHTBLUE
-#define YELLOW
+/* Class handling.  */
 
-#endif
+extern void pk_term_class (const char *class);
+extern void pk_term_end_class (const char *class);
 
 #endif /* PK_TERM_H */
diff --git a/src/pk-vm.c b/src/pk-vm.c
index 11a4550..8c23d70 100644
--- a/src/pk-vm.c
+++ b/src/pk-vm.c
@@ -71,12 +71,18 @@ pk_cmd_vm_disas_fun (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
 
   if (decl == NULL)
     {
-      fprintf (stdout, "error: no such function `%s'\n", fname);
+      pk_term_class ("error");
+      pk_puts ("error: ");
+      pk_term_end_class ("error");
+      pk_printf ("no such function `%s'\n", fname);
       return 0;
     }
   else if (PKL_AST_DECL_KIND (decl) != PKL_AST_DECL_KIND_FUNC)
     {
-      fprintf (stdout, "error: `%s' is not a function\n", fname);
+      pk_term_class ("error");
+      pk_puts ("error: ");
+      pk_term_end_class ("error");
+      pk_printf ("`%s' is not a function\n", fname);
       return 0;
     }
 
@@ -113,7 +119,10 @@ pk_cmd_vm_disas_map (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
   mapper = pvm_val_mapper (exp);
   if (mapper == PVM_NULL)
     {
-      fprintf (stdout, "error: the given value is not mapped\n");
+      pk_term_class ("error");
+      pk_puts ("error: ");
+      pk_term_end_class ("error");
+      pk_printf ("the given value is not mapped\n");
       return 0;
     }
 
@@ -147,7 +156,10 @@ pk_cmd_vm_disas_writ (int argc, struct pk_cmd_arg argv[], 
uint64_t uflags)
   writer = pvm_val_writer (exp);
   if (writer == PVM_NULL)
     {
-      fprintf (stdout, "error: the given value is not mapped\n");
+      pk_term_class ("error");
+      pk_puts ("error: ");
+      pk_term_end_class ("error");
+      pk_printf ("the given value is not mapped\n");
       return 0;
     }
 
diff --git a/src/pkl.c b/src/pkl.c
index 96a2069..514d132 100644
--- a/src/pkl.c
+++ b/src/pkl.c
@@ -81,8 +81,11 @@ pkl_new ()
 
     if (!pkl_compile_file (compiler, poke_rt_pk))
       {
-        fprintf (stderr,
-                 "Internal error: compiler failed to bootstrap itself\n");
+        pk_term_class ("error");
+        pk_puts ("internal error: ");
+        pk_term_end_class ("error");
+        pk_puts ("compiler failed to bootstrap itself\n");
+
         exit (EXIT_FAILURE);
       }
     free (poke_rt_pk);
@@ -488,26 +491,35 @@ pkl_error (pkl_ast ast,
   while (*p != '\0')
     {
       if (ast->filename)
-        fprintf (stderr, "%s:", ast->filename);
+        {
+          pk_term_class ("error-filename");
+          pk_printf ("%s:", ast->filename);
+          pk_term_end_class ("error-filename");
+        }
 
       if (PKL_AST_LOC_VALID (loc))
         {
+          pk_term_class ("error-location");
           if (poke_quiet_p)
-            fprintf (stderr, "%d: ", loc.first_line);
+            pk_printf ("%d: ", loc.first_line);
           else
-            fprintf (stderr, "%d:%d: ",
-                     loc.first_line, loc.first_column);
+            pk_printf ("%d:%d: ",
+                       loc.first_line, loc.first_column);
+          pk_term_end_class ("error-location");
         }
-      fputs (RED REVERSE "error: " NOATTR, stderr);
+
+      pk_term_class ("error");
+      pk_puts ("error: ");
+      pk_term_end_class ("error");
 
       while (*p != '\n' && *p != '\0')
         {
-          fputc (*p, stderr);
+          pk_printf ("%c", *p);
           p++;
         }
       if (*p == '\n')
         p++;
-      fputc ('\n', stderr);
+      pk_puts ("\n");
     }
   free (errmsg);
 
@@ -539,7 +551,7 @@ pkl_error (pkl_ast ast,
               {
                 /* Print until newline or end of string.  */
                 for (;*p != '\0' && *p != '\n'; ++p)
-                  fputc (*p, stderr);
+                  pk_printf ("%c", *p);
                 break;
               }
           }
@@ -571,7 +583,7 @@ pkl_error (pkl_ast ast,
                 do
                   {
                     if (c != '\n')
-                      fputc (c, stderr);
+                      pk_printf ("%c", c);
                     c = fgetc (fd);
                   }
                 while (c != EOF && c != '\0' && c != '\n');
@@ -583,16 +595,19 @@ pkl_error (pkl_ast ast,
         assert (fseeko (fd, cur_pos, SEEK_SET) == 0);
       }
 
-    fputc ('\n', stderr);
+    pk_puts ("\n");
 
     for (i = 1; i < loc.first_column; ++i)
-      fputc (' ', stderr);
+      pk_puts (" ");
+
+    pk_term_class ("error");
     for (; i < loc.last_column; ++i)
       if (i == loc.first_column)
-        fputc ('^', stderr);
+        pk_puts ("^");
       else
-        fputc ('~', stderr);
-    fputc ('\n', stderr);
+        pk_puts ("~");
+    pk_term_end_class ("error");
+    pk_puts ("\n");
   }
 }
 
@@ -603,15 +618,25 @@ pkl_warning (pkl_ast_loc loc,
              ...)
 {
   va_list valist;
+  char *msg;
 
-  va_start (valist, fmt);
-  if (PKL_AST_LOC_VALID (loc))
-    fprintf (stderr, "%d:%d: ",
-             loc.first_line, loc.first_column);
-  fputs ("warning: ", stderr);
-  vfprintf (stderr, fmt, valist);
-  fputc ('\n', stderr);
+  va_start(valist, fmt);
+  vasprintf (&msg, fmt, valist);
   va_end (valist);
+  
+  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 ("warning");
+  pk_puts ("warning: ");
+  pk_term_end_class ("warning");
+  pk_puts (msg);
+  pk_puts ("\n");
+
+  free (msg);
 }
 
 void
@@ -632,17 +657,21 @@ pkl_ice (pkl_ast ast,
     if ((des = path_search (tmpfile, PATH_MAX, NULL, "poke", true) == -1)
         || ((des = mkstemp (tmpfile)) == -1))
       {
-        fputs ("internal error: determining a temporary file name\n",
-               stderr);
+        pk_term_class ("error");
+        pk_puts ("internal error: ");
+        pk_term_end_class ("error");
+        pk_puts ("determining a temporary file name\n");
+
         return;
       }
 
     out = fdopen (des, "w");
     if (out == NULL)
       {
-        fprintf (stderr,
-                 "internal error: opening temporary file `%s'\n",
-                 tmpfile);
+        pk_term_class ("error");
+        pk_puts ("internal error: ");
+        pk_term_end_class ("error");
+        pk_printf ("opening temporary file `%s'\n", tmpfile);
         return;
       }
 
@@ -656,16 +685,27 @@ pkl_ice (pkl_ast ast,
   }
 
   if (PKL_AST_LOC_VALID (loc))
-    fprintf (stderr, "%d:%d: ",
-             loc.first_line, loc.first_column);
-  fputs (RED REVERSE "internal compiler error: " NOATTR, stderr);
-  va_start (valist, fmt);
-  vfprintf (stderr, fmt, valist);
-  va_end (valist);
-  fputc ('\n', stderr);
-  fprintf (stderr, "Important information has been dumped in %s.\n",
-           tmpfile);
-  fputs ("Please attach it to a bug report and send it to address@hidden.\n", 
stderr);
+    {
+      pk_term_class ("error-location");
+      pk_printf ("%d:%d: ", loc.first_line, loc.first_column);
+      pk_term_end_class ("error-location");
+    }
+  pk_puts ("internal compiler error: ");
+  {
+    char *msg;
+
+    va_start (valist, fmt);
+    vasprintf (&msg, fmt, valist);
+    va_end (valist);
+
+    pk_puts (msg);
+    free (msg);
+  }
+  pk_puts ("\n");
+  pk_printf ("Important information has been dumped in %s.\n",
+             tmpfile);
+  /* XXX hyperlink */
+  pk_puts ("Please attach it to a bug report and send it to 
address@hidden.\n");
 }
 
 int
diff --git a/src/poke.c b/src/poke.c
index 9d1aa3b..5cd79b7 100644
--- a/src/poke.c
+++ b/src/poke.c
@@ -36,6 +36,7 @@
 #include "pk-cmd.h"
 #include "pkl.h"
 #include "pvm.h"
+#include "pk-term.h"
 #include "poke.h"
 
 /* poke can be run either interactively (from a tty) or in batch mode.
@@ -87,6 +88,8 @@ enum
   CMD_ARG,
   NO_INIT_FILE_ARG,
   SCRIPT_ARG,
+  COLOR_ARG,
+  STYLE_ARG
 };
 
 static const struct option long_options[] =
@@ -98,6 +101,8 @@ static const struct option long_options[] =
   {"command", required_argument, NULL, CMD_ARG},
   {"script", required_argument, NULL, SCRIPT_ARG},
   {"no-init-file", no_argument, NULL, NO_INIT_FILE_ARG},
+  {"color", required_argument, NULL, COLOR_ARG},
+  {"style", required_argument, NULL, STYLE_ARG},
   {NULL, 0, NULL, 0},
 };
 
@@ -106,85 +111,102 @@ print_help ()
 {
   /* TRANSLATORS: --help output, GNU poke synopsis.
      no-wrap */
-  printf (_("\
+  pk_puts (_("\
 Usage: poke [OPTION]... [FILE]\n"));
 
   /* TRANSLATORS: --help output, GNU poke summary.
      no-wrap */
-  fputs(_("\
-Interactive editor for binary files.\n"), stdout);
+  pk_puts (_("\
+Interactive editor for binary files.\n"));
 
-  puts ("");
+  pk_puts ("\n");
   /* TRANSLATORS: --help output, GNU poke arguments.
      no-wrap */
-  fputs (_("\
-  -l, --load=FILE                     load the given pickle at startup.\n"),
-         stdout);
+  pk_puts (_("\
+  -l, --load=FILE                     load the given pickle at startup.\n"));
 
-  puts ("");
+  pk_puts ("\n");
 
   /* TRANSLATORS: --help output, GNU poke arguments.
      no-wrap */
-  fputs(_("\
+  pk_puts (_("\
 Commanding poke from the command line:\n\
   -c, --command=CMD                   execute the given command.\n\
-  -s, --script=FILE                   execute commands from FILE.\n"),
-         stdout);
+  -s, --script=FILE                   execute commands from FILE.\n"));
 
-  puts ("");
+  pk_puts ("\n");
+  pk_puts (_("\
+Styling text output:\n\
+      --color=(yes|no|auto|html|test) emit styled output.\n\
+      --style=STYLE_FILE              style file to use when styling.\n"));
+
+  pk_puts ("\n");
   /* TRANSLATORS: --help output, less used GNU poke arguments.
      no-wrap */
-  fputs (_("\
+  pk_puts (_("\
   -q, --no-init-file                  do not load an init file.\n\
       --quiet                         be as terse as possible.\n\
       --help                          print a help message and exit.\n\
-      --version                       show version and exit.\n"),
-         stdout);
+      --version                       show version and exit.\n"));
 
-  puts ("");
+  pk_puts ("\n");
   /* TRANSLATORS: --help output 5+ (reports)
      TRANSLATORS: the placeholder indicates the bug-reporting address
      for this application.  Please add _another line_ with the
      address for translation bugs.
      no-wrap */
-  printf (_("\
+  pk_printf (_("\
 Report bugs to: %s\n"), PACKAGE_BUGREPORT);
 #ifdef PACKAGE_PACKAGER_BUG_REPORTS
   printf (_("Report %s bugs to: %s\n"), PACKAGE_PACKAGER,
           PACKAGE_PACKAGER_BUG_REPORTS);
 #endif
-  printf (_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
-  fputs (_("General help using GNU software: <http://www.gnu.org/gethelp/>\n"),
-         stdout);
+  pk_printf (_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
+  pk_puts (_("General help using GNU software: 
<http://www.gnu.org/gethelp/>\n"));
 }
 
 void
 pk_print_version ()
 {
-  puts ("     _____");
-  puts (" ---'   __\\_______");
-  printf ("            ______)  GNU poke %s\n", VERSION);
-  puts ("            __)");
-  puts ("           __)");
-  puts (" ---._______)");
+  pk_term_class ("logo");
+  pk_puts ("     _____\n");
+  pk_puts (" ---'   __\\_______\n");
+  pk_printf ("            ______)  GNU poke %s\n", VERSION);
+  pk_puts ("            __)\n");
+  pk_puts ("           __)\n");
+  pk_puts (" ---._______)\n");
+  pk_term_end_class ("logo");
   /* xgettesxt: no-wrap */
-  puts ("");
+  pk_puts ("\n");
 
   /* It is important to separate the year from the rest of the message,
      as done here, to avoid having to retranslate the message when a new
      year comes around.  */
-  printf (_("\
+  pk_term_class ("copyright");
+  pk_printf (_("\
 Copyright (C) %s Jose E. Marchesi.\n\
 License GPLv3+: GNU GPL version 3 or later 
<http://gnu.org/licenses/gpl.html>.\n\
 This is free software: you are free to change and redistribute it.\n\
 There is NO WARRANTY, to the extent permitted by law.\n"), "2019");
+  pk_term_end_class ("copyright");
 
-  printf (_("\
+    pk_printf (_("\
 \nPowered by Jitter %s."), JITTER_VERSION);
 
-  puts (_("\
+    pk_puts (_("\
 \n\
-Perpetrated by Jose E. Marchesi."));
+Perpetrated by Jose E. Marchesi.\n"));
+
+}
+
+static void
+finalize ()
+{
+  ios_shutdown ();
+  pk_cmd_shutdown ();
+  pkl_free (poke_compiler);
+  pvm_shutdown (poke_vm);
+  pk_term_shutdown ();
 }
 
 static void
@@ -204,11 +226,11 @@ parse_args (int argc, char *argv[])
         {
         case HELP_ARG:
           print_help ();
-          exit (EXIT_SUCCESS);
+          goto exit_success;
           break;
         case VERSION_ARG:
           pk_print_version ();
-          exit (EXIT_SUCCESS);
+          goto exit_success;
           break;
         case QUIET_ARG:
           poke_quiet_p = 1;
@@ -220,14 +242,15 @@ parse_args (int argc, char *argv[])
         case 'l':
         case LOAD_ARG:
           if (!pkl_compile_file (poke_compiler, optarg))
-            exit (EXIT_FAILURE);
+            goto exit_success;
+
           break;
         case 'c':
         case CMD_ARG:
           {
             int ret = pk_cmd_exec (optarg);
             if (!ret)
-              exit (EXIT_FAILURE);
+              goto exit_failure;
             poke_interactive_p = 0;
             break;
           }
@@ -236,19 +259,24 @@ parse_args (int argc, char *argv[])
           {
             int ret = pk_cmd_exec_script (optarg);
             if (!ret)
-              exit (EXIT_FAILURE);
+              goto exit_failure;
             poke_interactive_p = 0;
             break;
           }
+          /* libtextstyle arguments are handled in pk-term.c, not
+             here.   */
+        case COLOR_ARG:
+        case STYLE_ARG:
+          break;
         default:
-          exit (EXIT_FAILURE);
+          goto exit_failure;
         }
     }
 
   if (optind < argc)
     {
       if (!ios_open (argv[optind++]))
-        exit (EXIT_FAILURE);
+        goto exit_failure;
 
       optind++;
     }
@@ -256,8 +284,18 @@ parse_args (int argc, char *argv[])
   if (optind < argc)
     {
       print_help();
-      exit (EXIT_FAILURE);
+      goto exit_failure;
     }
+
+  return;
+
+ exit_success:
+  finalize ();
+  exit (EXIT_SUCCESS);
+  
+ exit_failure:
+  finalize ();
+  exit (EXIT_FAILURE);
 }
 
 static void
@@ -266,9 +304,9 @@ repl ()
   if (!poke_quiet_p)
     {
       pk_print_version ();
-      puts ("");
-      puts (_("For help, type \".help\"."));
-      puts (_("Type \".exit\" to leave the program."));
+      pk_puts ("\n");
+      pk_puts (_("For help, type \".help\".\n"));
+      pk_puts (_("Type \".exit\" to leave the program.\n"));
     }
 
   while (!poke_exit_p)
@@ -276,6 +314,15 @@ repl ()
       int ret;
       char *line;
 
+#if 0
+      /* This doesn't work well because readline's edition commands
+         make use of the lenght of the prompt, i.e. the prompt string
+         is expected to be passed to readline().  */
+      pk_term_class ("prompt");
+      pk_puts ("(poke) ");
+      pk_term_end_class ("prompt");
+#endif
+      pk_term_flush ();
       line = readline ("(poke) ");
       if (line == NULL)
         /* EOF in stdin (probably Ctrl-D).  */
@@ -298,7 +345,7 @@ repl ()
 }
 
 static void
-initialize ()
+initialize (int argc, char *argv[])
 {
   /* This is used by the `progname' gnulib module.  */
   set_program_name ("poke");
@@ -317,6 +364,9 @@ initialize ()
   if (poke_datadir == NULL)
     poke_datadir = PKGDATADIR;
 
+  /* Initialize the terminal output.  */
+  pk_term_init (argc, argv);
+
   /* Initialize the Poke Virtual Machine.  Note this should be done
      before initializing the compiler, since the later constructs and
      runs pvm programs internally.  */
@@ -371,20 +421,11 @@ initialize_user ()
     }
 }
 
-static void
-finalize ()
-{
-  ios_shutdown ();
-  pk_cmd_shutdown ();
-  pkl_free (poke_compiler);
-  pvm_shutdown (poke_vm);
-}
-
 int
 main (int argc, char *argv[])
 {
   /* Initialization.  */
-  initialize ();
+  initialize (argc, argv);
 
   /* Parse args, loading files, opening files for IO, etc etc */
   parse_args (argc, argv);
diff --git a/src/pvm-val.c b/src/pvm-val.c
index 48a0521..0a3adbd 100644
--- a/src/pvm-val.c
+++ b/src/pvm-val.c
@@ -435,51 +435,51 @@ pvm_sizeof (pvm_val val)
    _'s */
 
 static void
-pvm_print_binary (FILE *out, uint64_t val, int size, int sign)
+pvm_print_binary (uint64_t val, int size, int sign)
 {
   char b[65];
 
   if (size != 64 && size != 32 && size != 16 && size != 8
       && size != 4)
-    fprintf (out, "(%sint<%d>) ", sign ? "" : "u", size);
+    pk_printf ("(%sint<%d>) ", sign ? "" : "u", size);
 
   for (int z = 0; z < size; z++) {
     b[size-1-z] = ((val >> z) & 0x1) + '0';
   }
   b[size] = '\0';
 
-  fprintf (out, "0b%s", b);
+  pk_printf ("0b%s", b);
 
   if (size == 64)
     {
       if (!sign)
-        fputc ('U', out);
-      fputc ('L', out);
+        pk_puts ("U");
+      pk_puts ("L");
     }
   else if (size == 16)
     {
       if (!sign)
-        fputc ('U', out);
-      fputc ('H', out);
+        pk_puts ("U");
+      pk_puts ("H");
     }
   else if (size == 8)
     {
       if (!sign)
-        fputc ('U', out);
-      fputc ('B', out);
+        pk_puts ("U");
+      pk_puts ("B");
     }
   else if (size == 4)
     {
       {
         if (!sign)
-          fputc ('U', out);
+          pk_puts ("U");
       }
-      fputc ('N', out);
+      pk_puts ("N");
     }
 }
 
 void
-pvm_print_val (FILE *out, pvm_val val, int base, int flags)
+pvm_print_val (pvm_val val, int base, int flags)
 {
   const char *long64_fmt, *long_fmt;
   const char *ulong64_fmt, *ulong_fmt;
@@ -563,28 +563,32 @@ pvm_print_val (FILE *out, pvm_val val, int base, int 
flags)
 
   /* And print out the value in the given stream..  */
   if (val == PVM_NULL)
-    fprintf (out, "null");
+    pk_puts ("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");
+      
       if (size == 64)
         ulongval = (uint64_t) longval;
       else
         ulongval = (uint64_t) longval & ((((uint64_t) 1) << size) - 1);
 
       if (base == 2)
-        pvm_print_binary (out, ulongval, size, 1);
+        pvm_print_binary (ulongval, size, 1);
       else
         {
           if (size == 64)
-            fprintf (out, long64_fmt, base == 10 ? longval : ulongval);
+            pk_printf (long64_fmt, base == 10 ? longval : ulongval);
           else
-            fprintf (out, long_fmt,
-                     PVM_VAL_LONG_SIZE (val), base == 10 ? longval : ulongval);
+            pk_printf (long_fmt, PVM_VAL_LONG_SIZE (val),
+                       base == 10 ? longval : ulongval);
         }
+
+      pk_term_end_class ("integer");
     }
   else if (PVM_IS_INT (val))
     {
@@ -592,65 +596,76 @@ pvm_print_val (FILE *out, pvm_val val, int base, int 
flags)
       int32_t intval = PVM_VAL_INT (val);
       uint32_t uintval;
 
+      pk_term_class ("integer");
+
       if (size == 32)
         uintval = (uint32_t) intval;
       else
         uintval = (uint32_t) intval & ((((uint32_t) 1) << size) - 1);
 
       if (base == 2)
-        pvm_print_binary (out, (uint64_t) uintval, size, 1);
+        pvm_print_binary ((uint64_t) uintval, size, 1);
       else
         {
           if (size == 32)
-            fprintf (out, int32_fmt, base == 10 ? intval : uintval);
+            pk_printf (int32_fmt, base == 10 ? intval : uintval);
           else if (size == 16)
-            fprintf (out, int16_fmt, base == 10 ? intval : uintval);
+            pk_printf (int16_fmt, base == 10 ? intval : uintval);
           else if (size == 8)
-            fprintf (out, int8_fmt, base == 10 ? intval : uintval);
+            pk_printf (int8_fmt, base == 10 ? intval : uintval);
           else if (size == 4)
-            fprintf (out, int4_fmt, base == 10 ? intval : uintval);
+            pk_printf (int4_fmt, base == 10 ? intval : uintval);
           else
-            fprintf (out, int_fmt,
-                     PVM_VAL_INT_SIZE (val), base == 10 ? intval : uintval);
+            pk_printf (int_fmt, PVM_VAL_INT_SIZE (val),
+                       base == 10 ? intval : uintval);
         }
+
+      pk_term_end_class ("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");
+
       if (base == 2)
-        pvm_print_binary (out, ulongval, size, 0);
+        pvm_print_binary (ulongval, size, 0);
       else
         {
           if (size == 64)
-            fprintf (out, ulong64_fmt, ulongval);
+            pk_printf (ulong64_fmt, ulongval);
           else
-            fprintf (out, ulong_fmt,
-                     PVM_VAL_LONG_SIZE (val), ulongval);
+            pk_printf (ulong_fmt, PVM_VAL_LONG_SIZE (val), ulongval);
         }
+
+      pk_term_end_class ("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");
+
       if (base == 2)
-        pvm_print_binary (out, uintval, size, 0);
+        pvm_print_binary (uintval, size, 0);
       else
         {
           if (size == 32)
-            fprintf (out, uint32_fmt, uintval);
+            pk_printf (uint32_fmt, uintval);
           else if (size == 16)
-            fprintf (out, uint16_fmt, uintval);
+            pk_printf (uint16_fmt, uintval);
           else if (size == 8)
-            fprintf (out, uint8_fmt, uintval);
+            pk_printf (uint8_fmt, uintval);
           else if (size == 4)
-            fprintf (out, uint4_fmt, uintval);
+            pk_printf (uint4_fmt, uintval);
           else
-            fprintf (out, uint_fmt,
-                     PVM_VAL_UINT_SIZE (val), uintval);
+            pk_printf (uint_fmt, PVM_VAL_UINT_SIZE (val),
+                       uintval);
         }
+
+      pk_term_end_class ("integer");
     }
   else if (PVM_IS_STR (val))
     {
@@ -659,6 +674,8 @@ pvm_print_val (FILE *out, pvm_val val, int base, int flags)
       size_t str_size = strlen (PVM_VAL_STR (val));
       size_t printable_size, i, j;
 
+      pk_term_class ("string");
+      
       /* Calculate the length (in bytes) of the printable string
          corresponding to the string value.  */
       for (printable_size = 0, i = 0; i < str_size; i++)
@@ -702,8 +719,10 @@ pvm_print_val (FILE *out, pvm_val val, int base, int flags)
       assert (j == printable_size);
       str_printable[j] = '\0';
 
-      fprintf (out, "\"%s\"", str_printable);
+      pk_printf ("\"%s\"", str_printable);
       free (str_printable);
+
+      pk_term_end_class ("string");
     }
   else if (PVM_IS_ARR (val))
     {
@@ -712,29 +731,33 @@ pvm_print_val (FILE *out, pvm_val val, int base, int 
flags)
 
       nelem = PVM_VAL_ULONG (PVM_VAL_ARR_NELEM (val));
 
-      fprintf (out, "[");
+      pk_term_class ("array");
+      
+      pk_puts ("[");
       for (idx = 0; idx < nelem; idx++)
         {
           pvm_val elem_offset = PVM_VAL_ARR_ELEM_OFFSET (val, idx);
           pvm_val elem_value = PVM_VAL_ARR_ELEM_VALUE (val, idx);
 
           if (idx != 0)
-            fprintf (out, ",");
-          pvm_print_val (out, elem_value, base, flags);
+            pk_puts (",");
+          pvm_print_val (elem_value, base, flags);
 
           if (flags & PVM_PRINT_F_MAPS && elem_offset != PVM_NULL)
             {
-              fputc ('@', out);
-              pvm_print_val (out, elem_offset, base, flags);
+              pk_puts ("@");
+              pvm_print_val (elem_offset, base, flags);
             }
         }
-      fprintf (out, "]");
+      pk_puts ("]");
 
       if (flags & PVM_PRINT_F_MAPS && array_offset != PVM_NULL)
         {
-          fputc ('@', out);
-          pvm_print_val (out, array_offset, base, flags);
+          pk_puts ("@");
+          pvm_print_val (array_offset, base, flags);
         }
+
+      pk_term_end_class ("array");
     }
   else if (PVM_IS_SCT (val))
     {
@@ -744,13 +767,19 @@ pvm_print_val (FILE *out, pvm_val val, int base, int 
flags)
 
       nelem = PVM_VAL_ULONG (PVM_VAL_SCT_NFIELDS (val));
 
+      pk_term_class ("struct");
+      
       if (struct_type_name != PVM_NULL)
-        fputs (PVM_VAL_STR (struct_type_name), out);
+        {
+          pk_term_class ("struct-type-name");
+          pk_puts ( PVM_VAL_STR (struct_type_name));
+          pk_term_end_class ("struct-type-name");
+        }
       else
-        fputs ("struct", out);
-      fputs (" ", out);
+        pk_puts ("struct");
+      pk_puts (" ");
 
-      fprintf (out, "{");
+      pk_printf ("{");
       for (idx = 0; idx < nelem; ++idx)
         {
           pvm_val name = PVM_VAL_SCT_FIELD_NAME(val, idx);
@@ -758,82 +787,93 @@ pvm_print_val (FILE *out, pvm_val val, int base, int 
flags)
           pvm_val offset = PVM_VAL_SCT_FIELD_OFFSET(val, idx);
 
           if (idx != 0)
-            fprintf (out, ",");
+            pk_puts (",");
           if (name != PVM_NULL)
-            fprintf (out, "%s=", PVM_VAL_STR (name));
-          pvm_print_val (out, value, base, flags);
+            {
+              pk_term_class ("struct-field-name");
+              pk_printf ("%s", PVM_VAL_STR (name));
+              pk_term_end_class ("struct-field-name");
+              pk_puts ("=");
+            }
+          pvm_print_val (value, base, flags);
 
           if (flags & PVM_PRINT_F_MAPS && offset != PVM_NULL)
             {
-              fputc ('@', out);
-              pvm_print_val (out, offset, base, flags);
+              pk_puts ("@");
+              pvm_print_val (offset, base, flags);
             }
         }
-      fprintf (out, "}");
+      pk_puts ("}");
+
+      pk_term_end_class ("struct");
     }
   else if (PVM_IS_TYP (val))
     {
+      pk_term_class ("type");
+
       switch (PVM_VAL_TYP_CODE (val))
         {
         case PVM_TYPE_INTEGRAL:
           {
             if (!(PVM_VAL_UINT (PVM_VAL_TYP_I_SIGNED (val))))
-              fprintf (out, "u");
+              pk_puts ("u");
 
             switch (PVM_VAL_ULONG (PVM_VAL_TYP_I_SIZE (val)))
               {
-              case 8: fprintf (out, "int8"); break;
-              case 16: fprintf (out, "int16"); break;
-              case 32: fprintf (out, "int32"); break;
-              case 64: fprintf (out, "int64"); break;
+              case 8: pk_puts ("int8"); break;
+              case 16: pk_puts ("int16"); break;
+              case 32: pk_puts ("int32"); break;
+              case 64: pk_puts ("int64"); break;
               default: assert (0); break;
               }
           }
           break;
         case PVM_TYPE_STRING:
-          fprintf (out, "string");
+          pk_puts ("string");
           break;
         case PVM_TYPE_ANY:
-          fprintf (out, "any");
+          pk_term_class ("any");
+          pk_puts ("any");
+          pk_term_end_class ("any");
           break;
         case PVM_TYPE_ARRAY:
-          pvm_print_val (out, PVM_VAL_TYP_A_ETYPE (val), base, flags);
-          fputc ('[', out);
+          pvm_print_val (PVM_VAL_TYP_A_ETYPE (val), base, flags);
+          pk_puts ("[");
           if (PVM_VAL_TYP_A_BOUND (val) != PVM_NULL)
-            pvm_print_val (out, PVM_VAL_TYP_A_BOUND (val), base, flags);
-          fputc (']', out);
+            pvm_print_val (PVM_VAL_TYP_A_BOUND (val), base, flags);
+          pk_puts ("]");
           break;
         case PVM_TYPE_OFFSET:
-          fprintf (out, "[");
-          pvm_print_val (out, PVM_VAL_TYP_O_BASE_TYPE (val), base, flags);
-          fputc (' ', out);
+          pk_puts ("[");
+          pvm_print_val (PVM_VAL_TYP_O_BASE_TYPE (val), base, flags);
+          pk_puts (" ");
           switch (PVM_VAL_ULONG (PVM_VAL_TYP_O_UNIT (val)))
             {
             case PVM_VAL_OFF_UNIT_BITS:
-              fputc ('b', out);
+              pk_puts ("b");
               break;
             case PVM_VAL_OFF_UNIT_BYTES:
-              fputc ('B', out);
+              pk_puts ("B");
               break;
             case PVM_VAL_OFF_UNIT_KILOBITS:
-              fputs ("Kb", out);
+              pk_puts ("Kb");
               break;
             case PVM_VAL_OFF_UNIT_KILOBYTES:
-              fputs ("KB", out);
+              pk_puts ("KB");
               break;
             case PVM_VAL_OFF_UNIT_MEGABITS:
-              fputs ("Mb", out);
+              pk_puts ("Mb");
               break;
             case PVM_VAL_OFF_UNIT_MEGABYTES:
-              fputs ("MB", out);
+              pk_puts ("MB");
               break;
             case PVM_VAL_OFF_UNIT_GIGABITS:
-              fputs ("Gb", out);
+              pk_puts ("Gb");
               break;
             default:
               assert (0);
             }
-          fprintf (out, "]");
+          pk_puts ("]");
           break;
         case PVM_TYPE_CLOSURE:
           {
@@ -841,13 +881,13 @@ pvm_print_val (FILE *out, pvm_val val, int base, int 
flags)
 
             nargs = PVM_VAL_ULONG (PVM_VAL_TYP_C_NARGS (val));
 
-            fprintf (out, "(");
+            pk_puts ("(");
             for (i = 0; i < nargs; ++i)
               {
                 pvm_val atype = PVM_VAL_TYP_C_ATYPE (val, i);
-                pvm_print_val (out, atype, base, flags);
+                pvm_print_val (atype, base, flags);
               }
-            pvm_print_val (out, PVM_VAL_TYP_C_RETURN_TYPE (val), 10, flags);
+            pvm_print_val (PVM_VAL_TYP_C_RETURN_TYPE (val), 10, flags);
             break;
           }
         case PVM_TYPE_STRUCT:
@@ -856,68 +896,74 @@ pvm_print_val (FILE *out, pvm_val val, int base, int 
flags)
 
             nelem = PVM_VAL_ULONG (PVM_VAL_TYP_S_NFIELDS (val));
 
-            fprintf (out, "struct {");
+            pk_puts ("struct {");
             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)
-                  fprintf (out, " ");
+                  pk_puts (" ");
 
-                pvm_print_val (out, etype, base, flags);
+                pvm_print_val (etype, base, flags);
                 if (ename != PVM_NULL)
-                  fprintf (out, " %s", PVM_VAL_STR (ename));
-                fprintf (out, ";");
+                  pk_printf (" %s", PVM_VAL_STR (ename));
+                pk_puts (";");
               }
-            fprintf (out, "}");
+            pk_puts ("}");
           break;
           }
         default:
           assert (0);
         }
+
+      pk_term_end_class ("type");
     }
   else if (PVM_IS_OFF (val))
     {
-      pvm_print_val (out, PVM_VAL_OFF_MAGNITUDE (val), base, flags);
-      fprintf (out, CYAN "#" NOATTR);
+      pk_term_class ("offset");
+      pvm_print_val (PVM_VAL_OFF_MAGNITUDE (val), base, flags);
+      pk_puts ("#");
       switch (PVM_VAL_ULONG (PVM_VAL_OFF_UNIT (val)))
         {
         case PVM_VAL_OFF_UNIT_BITS:
-          fprintf (out, CYAN "b" NOATTR);
+          pk_puts ("b");
           break;
         case PVM_VAL_OFF_UNIT_NIBBLES:
-          fprintf (out, CYAN "N" NOATTR);
+          pk_puts ("N");
           break;
         case PVM_VAL_OFF_UNIT_BYTES:
-          fprintf (out, CYAN "B" NOATTR);
+          pk_puts ("B");
           break;
         case PVM_VAL_OFF_UNIT_KILOBITS:
-          fprintf (out, CYAN "Kb" NOATTR);
+          pk_puts ("Kb");
           break;
         case PVM_VAL_OFF_UNIT_KILOBYTES:
-          fprintf (out, CYAN "KB" NOATTR);
+          pk_puts ("KB");
           break;
         case PVM_VAL_OFF_UNIT_MEGABITS:
-          fprintf (out, CYAN "Mb" NOATTR);
+          pk_puts ("Mb");
           break;
         case PVM_VAL_OFF_UNIT_MEGABYTES:
-          fprintf (out, CYAN "MB" NOATTR);
+          pk_puts ("MB");
           break;
         case PVM_VAL_OFF_UNIT_GIGABITS:
-          fprintf (out, CYAN "Gb" NOATTR);
+          pk_puts ("Gb");
           break;
         default:
           /* XXX: print here the name of the base type of the
              offset.  */
-          fprintf (out, CYAN "%" PRIu64 NOATTR,
-                   PVM_VAL_ULONG (PVM_VAL_OFF_UNIT (val)));
+          pk_printf ("%" PRIu64, PVM_VAL_ULONG (PVM_VAL_OFF_UNIT (val)));
           break;
         }
+
+      pk_term_end_class ("offset");
     }
   else if (PVM_IS_CLS (val))
     {
-      fprintf (out, "#<closure>");
+      pk_term_class ("special");
+      pk_puts ("#<closure>");
+      pk_term_end_class ("special");
     }
   else
     assert (0);
@@ -1023,7 +1069,7 @@ pvm_type_equal (pvm_val type1, pvm_val type2)
 }
 
 void
-pvm_print_string (FILE *out, pvm_val string)
+pvm_print_string (pvm_val string)
 {
-  fputs (PVM_VAL_STR (string), out);
+  pk_puts (PVM_VAL_STR (string));
 }
diff --git a/src/pvm-val.h b/src/pvm-val.h
index 74c3547..feaf210 100644
--- a/src/pvm-val.h
+++ b/src/pvm-val.h
@@ -179,7 +179,7 @@ typedef struct pvm_val_box *pvm_val_box;
 #define PVM_VAL_STR(V) (PVM_VAL_BOX_STR (PVM_VAL_BOX ((V))))
 
 pvm_val pvm_make_string (const char *value);
-void pvm_print_string (FILE *out, pvm_val string);
+void pvm_print_string (pvm_val string);
 
 /* Arrays values are boxed, and store sequences of homogeneous values
    called array "elements".  They can be mapped in IO, or unmapped.
@@ -608,6 +608,6 @@ pvm_val pvm_val_writer (pvm_val val);
 
 #define PVM_PRINT_F_MAPS 1
 
-void pvm_print_val (FILE *out, pvm_val val, int base, int flags);
+void pvm_print_val (pvm_val val, int base, int flags);
 
 #endif /* !PVM_VAL_H */
diff --git a/src/pvm.jitter b/src/pvm.jitter
index 7251927..9af1e98 100644
--- a/src/pvm.jitter
+++ b/src/pvm.jitter
@@ -38,6 +38,7 @@ end
 ## Functions and globals to wrap.
 
 wrapped-functions
+  pk_printf
   printf
   pvm_assert
   pvm_env_lookup
@@ -80,6 +81,7 @@ early-header-c
   code
 #   include "pvm.h"
 #   include "ios.h"
+#   include "pk-term.h"
 
 #   define STREQ(a, b) (strcmp (a, b) == 0)
 #   define STRNEQ(a, b) (strcmp (a, b) != 0)
@@ -338,7 +340,7 @@ late-header-c
       fmt[5] = '\0';                                                        \
     }                                                                       \
                                                                             \
-    printf (fmt, val);                                                      \
+    pk_printf (fmt, val);                                                   \
     JITTER_DROP_STACK ();                                                   \
   } while (0)
 
@@ -380,7 +382,7 @@ late-header-c
       fmt[6] = '\0';                                                        \
     }                                                                       \
                                                                             \
-    printf (fmt, val);                                                      \
+    pk_printf (fmt, val);                                                   \
     JITTER_DROP_STACK ();                                                   \
   } while (0)
 
@@ -404,7 +406,8 @@ printer-c
     void
     pvm_literal_printer (FILE *out, jitter_uint val)
     {
-      pvm_print_val (out, (pvm_val) val, 10, 0);
+      /* XXX what about out.  */
+      pvm_print_val ((pvm_val) val, 10, 0);
     }
 
     void
@@ -418,9 +421,8 @@ printer-c
     pvm_literal_printer_lo (FILE *out, jitter_uint lo)
     {
       fprintf (out, "%%lo(0x%" JITTER_PRIx") (", lo);
-      pvm_print_val (out,
-                    ((pvm_val) printer_hi << 32) | lo,
-                    10, 0);
+      pvm_print_val (((pvm_val) printer_hi << 32) | lo,
+                      10, 0);
       fputc (')', out);
       printer_hi = 0;
     }
@@ -669,7 +671,7 @@ end
 
 instruction prints () # ( STR -- )
   code
-    pvm_print_string (stdout, JITTER_TOP_STACK ());
+    pvm_print_string (JITTER_TOP_STACK ());
     JITTER_DROP_STACK ();
   end
 end
@@ -710,8 +712,8 @@ instruction strace (?n) # ( -- )
                  jitter_original_state->pvm_state_backing.canary)))
         {
           assert (i < 1024);
-          pvm_print_val (stdout, JITTER_TOP_STACK (), 16, PVM_PRINT_F_MAPS);
-          fprintf (stdout, "\n");
+          pvm_print_val (JITTER_TOP_STACK (), 16, PVM_PRINT_F_MAPS);
+          pk_puts ("\n");
           tmp[i++] = JITTER_TOP_STACK ();
           JITTER_DROP_STACK ();
         }
diff --git a/testsuite/lib/poke-dg.exp b/testsuite/lib/poke-dg.exp
index eecc766..aebc413 100644
--- a/testsuite/lib/poke-dg.exp
+++ b/testsuite/lib/poke-dg.exp
@@ -104,7 +104,7 @@ proc poke-dg-test { prog do_what extra_tool_flags } {
 
     switch $do_what {
         "compile" {
-            catch "exec $POKE --quiet -l $prog -c .exit $extra_tool_flags" 
comp_output
+            catch "exec $POKE --quiet --color=no -l $prog -c .exit 
$extra_tool_flags" comp_output
             set output_file ""
         }
         "run" {
@@ -119,7 +119,7 @@ proc poke-dg-test { prog do_what extra_tool_flags } {
             set output_file "${objdir}/[file rootname [file tail $prog]]"
             set fd [open $output_file w]
             puts $fd "#!/bin/bash"
-            puts $fd "$VALGRIND $POKE --quiet -q -l $prog $extra_tool_flags 
$poke_commands"
+            puts $fd "$VALGRIND $POKE --quiet --color=no -q -l $prog 
$extra_tool_flags $poke_commands"
             close $fd
             file attributes $output_file -permissions a+rx
         }
diff --git a/testsuite/lib/poke.exp b/testsuite/lib/poke.exp
index 9ec33ba..cdfc80d 100644
--- a/testsuite/lib/poke.exp
+++ b/testsuite/lib/poke.exp
@@ -60,7 +60,7 @@ proc poke_start {} {
 
     #send_user "Executing $POKE --quiet\n"
 
-    spawn $POKE --quiet
+    spawn $POKE --quiet --color=no
     expect {
         -re "$poke_prompt $" { }
         timeout { perror "Failed to spawn $POKE (timeout)"; exit 1 }
         



reply via email to

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