summaryrefslogtreecommitdiff
path: root/console-client
diff options
context:
space:
mode:
authorMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
committerMarcus Brinkmann <marcus@gnu.org>2002-09-17 12:26:10 +0000
commit09e69605b16070de8ce317d86ad736d665a58906 (patch)
tree7c0dc29f4fc660a44d2f7d6ec9d099cc4f8301a6 /console-client
parentdbe4c7712b652b7ad3126e94c47b00fa2bbb0a05 (diff)
2002-09-17 Marcus Brinkmann <marcus@gnu.org>
* Makefile (prog-subdirs): Add console-client. sutils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * MAKEDEV.sh (mkdev: vcs): New console device. (mkdev: tty[0-9a-f]|tty[0-9][0-9a-f]): Replaced with new rules for tty[1-9][0-9]. utils/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * console-ncurses.c: File removed (the ncursesw console client is now a driver in the console-client). * Makefile: Revert 2002-08-22 change: Do not include`../config.make'. (targets) [LIBNCURSES]: Removed. (SRCS) [LIBNCURSES]: Likewise. (HURDLIBS) [LIBNCURSES]: Likewise. (console-ncurses): Target removed. (console-ncurses-CPPFLAGS): Removed. (console-ncurses-LDLIBS): Likewise. console-client/ 2002-09-17 Marcus Brinkmann <marcus@gnu.org> * Makefile, bdf.c, bdf.h, bell.h, console.c, display.h, driver.c, driver.h, generic-speaker.c, input.h, pc-kbd.c, timer.c, timer.h, unicode.h, vga.c, vga-dynacolor.c, vga-dynacolor.h, vga-dynafont.c, vga-dynafont.h, vga-hw.h, vga-support.c, vga-support.h: New file.
Diffstat (limited to 'console-client')
-rw-r--r--console-client/ChangeLog6
-rw-r--r--console-client/Makefile75
-rw-r--r--console-client/bdf.c990
-rw-r--r--console-client/bdf.h272
-rw-r--r--console-client/bell.h56
-rw-r--r--console-client/console.c468
-rw-r--r--console-client/display.h138
-rw-r--r--console-client/driver.c353
-rw-r--r--console-client/driver.h282
-rw-r--r--console-client/generic-speaker.c488
-rw-r--r--console-client/input.h83
-rw-r--r--console-client/ncursesw.c611
-rw-r--r--console-client/pc-kbd.c824
-rw-r--r--console-client/timer.c210
-rw-r--r--console-client/timer.h72
-rw-r--r--console-client/unicode.h350
-rw-r--r--console-client/vga-dynacolor.c322
-rw-r--r--console-client/vga-dynacolor.h108
-rw-r--r--console-client/vga-dynafont.c1047
-rw-r--r--console-client/vga-dynafont.h83
-rw-r--r--console-client/vga-hw.h139
-rw-r--r--console-client/vga-support.c480
-rw-r--r--console-client/vga-support.h86
-rw-r--r--console-client/vga.c573
24 files changed, 8116 insertions, 0 deletions
diff --git a/console-client/ChangeLog b/console-client/ChangeLog
new file mode 100644
index 00000000..c43a5dfa
--- /dev/null
+++ b/console-client/ChangeLog
@@ -0,0 +1,6 @@
+2002-09-17 Marcus Brinkmann <marcus@gnu.org>
+
+ * Makefile, bdf.c, bdf.h, bell.h, console.c, display.h, driver.c,
+ driver.h, generic-speaker.c, input.h, pc-kbd.c, timer.c, timer.h,
+ unicode.h, vga.c, vga-dynacolor.c, vga-dynacolor.h, vga-dynafont.c,
+ vga-dynafont.h, vga-hw.h, vga-support.c, vga-support.h: New file.
diff --git a/console-client/Makefile b/console-client/Makefile
new file mode 100644
index 00000000..836ec514
--- /dev/null
+++ b/console-client/Makefile
@@ -0,0 +1,75 @@
+#
+# Copyright (C) 1994,95,96,97,98,99,2000,01,02 Free Software Foundation, Inc.
+#
+# 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 2, 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, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+dir := console-client
+makemode := utility
+
+target = console
+SRCS = console.c timer.c driver.c
+LCLHDRS = timer.h driver.h display.h input.h bell.h \
+ unicode.h bdf.h \
+ vga-dynafont.h vga-dynacolor.h vga-hw.h vga.h
+
+OBJS = $(filter-out %.sh,$(SRCS:.c=.o))
+HURDLIBS = cons threads ports
+LDLIBS = -ldl
+module-dir = $(libdir)/hurd/console
+console-LDFLAGS = -Wl,-E
+
+# In seeking, thou shalt find it!
+CPPFLAGS += -DQUAERENDO_INVENIETIS
+
+include ../Makeconf
+
+driver-CPPFLAGS = -D'CONSOLE_DEFPATH="$(module-dir)\0"' \
+ -D'CONSOLE_SONAME_SUFFIX=".so.$(hurd-version)"'
+
+console: ../libcons/libcons.a ../libports/libports.a \
+ ../libthreads/libthreads.a ../libshouldbeinlibc/libshouldbeinlibc.a
+
+modules = vga pc_kbd generic_speaker
+
+vga.so.$(hurd-version): $(patsubst %.c,%_pic.o,bdf.c vga-dynafont.c \
+ vga-dynacolor.c vga-support.c vga.c)
+pc_kbd.so.$(hurd-version): $(patsubst %.c,%_pic.o,pc-kbd.c)
+generic_speaker.so.$(hurd-version): $(patsubst %.c,%_pic.o,generic-speaker.c)
+
+ifneq ($(LIBNCURSESW),)
+modules += ncursesw
+ncursesw.so.$(hurd-version): $(patsubst %.c,%_pic.o,ncursesw.c)
+ncursesw-CPPFLAGS = $(NCURSESW_INCLUDE)
+ncursesw-LDLIBS = $(LIBNCURSESW)
+endif
+
+all: $(addsuffix .so.$(hurd-version), $(modules))
+
+cleantarg += $(addsuffix .so.$(hurd-version), $(modules))
+
+install: $(module-dir) $(addprefix $(module-dir)/,$(addsuffix .so.$(hurd-version),$(modules)))
+
+$(module-dir):
+ @$(MKINSTALLDIRS) $@
+
+$(module-dir)/%: %
+ $(INSTALL_DATA) $< $@
+
+# You can use this rule to make a dynamically-loadable version of any
+# of the modules.
+%.so.$(hurd-version):
+ $(CC) -shared -Wl,-soname=$@ -o $@ $(rpath) \
+ $(CFLAGS) $($*-CFLAGS) $(LDFLAGS) \
+ '-Wl,-(' $($*-LDLIBS) '-Wl,-)' $^
diff --git a/console-client/bdf.c b/console-client/bdf.c
new file mode 100644
index 00000000..6c67c409
--- /dev/null
+++ b/console-client/bdf.c
@@ -0,0 +1,990 @@
+/* bdf.c - Parser for the Adobe Glyph Bitmap Distribution Format (BDF).
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann <marcus@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <malloc.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <search.h>
+
+#include "bdf.h"
+
+
+/* Return a statically allocated string describing the BDF error value
+ ERR. */
+const char *
+bdf_strerror (bdf_error_t err)
+{
+ switch (err)
+ {
+ case BDF_NO_ERROR:
+ return "Success";
+ case BDF_SYSTEM_ERROR:
+ return "System error";
+ case BDF_SYNTAX_ERROR:
+ return "Syntax error";
+ case BDF_INVALID_ARGUMENT:
+ return "Invalid Argument";
+ case BDF_COUNT_MISMATCH:
+ return "Count mismatch";
+ default:
+ return "Unknown error";
+ }
+}
+
+
+/* Copy the string starting from ARG and return the pointer to it in
+ STRING. If QUOTED is true, outer double quotes are stripped, and
+ two consecutive double quotes within the string are replaced by one
+ douple quotes. */
+static bdf_error_t
+parse_string (char *arg, char **string, int quoted)
+{
+ if (quoted)
+ {
+ char *value = ++arg;
+ do
+ {
+ value = strchr (value, '"');
+ if (!value)
+ return BDF_INVALID_ARGUMENT;
+ else if (*(value + 1) == '"')
+ {
+ char *copyp = value++;
+ while (*(++copyp))
+ *(copyp - 1) = *copyp;
+ *(copyp - 1) = 0;
+ }
+ }
+ while (*value != '"' || *(value + 1) == '"');
+ *value = 0;
+ }
+
+ *string = strdup (arg);
+ if (!*string)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+
+/* Parse the string STR for format TEMPLATE, and require an exact
+ match. Set err if a parsing error occurs. TEMPLATE must be a
+ string constant. */
+#define parse_template(str, template, rest...) \
+ do \
+ { \
+ int parse_template_count = -1; \
+ sscanf (str, template " %n", rest, &parse_template_count); \
+ if (parse_template_count == -1 || *(str + parse_template_count)) \
+ err = BDF_SYNTAX_ERROR; \
+ } \
+ while (0)
+
+
+#define hex2nr(c) (((c) >= '0' && (c) <= '9') ? (c) - '0' \
+ : (((c) >= 'a' && (c) <= 'f') ? (c) - 'a' + 10 \
+ : (((c) >= 'A' && (c) <= 'F') ? (c) - 'A' + 10 : 0)))
+
+/* Convert a two-digit hex number starting from LINE to a char and
+ return the result in BYTE. */
+static bdf_error_t
+parse_hexbyte (char *line, unsigned char *byte)
+{
+ if (!isxdigit (*line) || !isxdigit(*(line + 1)))
+ return BDF_SYNTAX_ERROR;
+ else
+ *byte = (hex2nr (*line) << 4) + hex2nr (*(line + 1));
+ return 0;
+}
+
+
+/* Like getline(), but keeps track of line count in COUNT, skips
+ COMMENT lines, and removes whitespace at the beginning and end of a
+ line. */
+static int
+next_line (char **line, int *size, FILE *file, int *count)
+{
+ int len;
+
+ do
+ {
+ len = getline (line, size, file);
+ if (len >= 0)
+ {
+ char *cline = *line;
+ if (count)
+ (*count)++;
+ if (!strncmp (cline, "COMMENT", 7))
+ len = 0;
+ else
+ while (len > 0 && (cline[len - 1] == '\n' || cline[len - 1] == '\r'
+ || cline[len - 1] == ' '
+ || cline[len - 1] == '\t'))
+ cline[--len] = 0;
+ }
+ }
+ while (len <= 0 && !feof (file) && !ferror (file));
+ return len;
+}
+
+
+/* Isolate the next white-space seperated argument from the current
+ line, and set ARGP to the beginning of the next argument. It is an
+ error if there is no further argument. */
+static bdf_error_t
+find_arg (char **argp)
+{
+ char *arg = *argp;
+
+ arg = strchr (arg, ' ');
+ if (arg)
+ {
+ *(arg++) = 0;
+ while (*arg == ' ' || *arg == '\t')
+ arg++;
+ }
+ if (!arg || !*arg)
+ return BDF_SYNTAX_ERROR;
+ *argp = arg;
+ return 0;
+}
+
+
+/* Read the font from stream FILE, and return it in FONT. If
+ LINECOUNT is not zero, it will contain the number of lines in the
+ file at success, and the line an error occured at failure. */
+bdf_error_t
+bdf_read (FILE *filep, bdf_font_t *font, int *linecount)
+{
+ bdf_error_t err = 0;
+ char *line = 0;
+ int line_size = 0;
+ int len;
+ int done = 0;
+ bdf_font_t bdf;
+ struct
+ {
+ /* Current line. */
+ enum { START, FONT, PROPERTIES, GLYPHS, GLYPH, BITMAP } location;
+ /* The number of properties parsed so far. */
+ int properties;
+ /* The number of glyphs parsed so far. */
+ int glyphs;
+
+ /* True if we have seen a SIZE keyword so far. */
+ int has_size : 1;
+ /* True if we have seen a FONTBOUNDINGBOX keyword so far. */
+ int has_fbbx : 1;
+ /* True if we have seen a METRICSSET keyword so far. */
+ int has_metricsset : 1;
+
+ /* Current glyph. */
+ struct bdf_glyph *glyph;
+ /* True if we have seen an ENCODING keyword for the glyph. */
+ int glyph_has_encoding : 1;
+ /* True if we have seen an BBX keyword for the glyph. */
+ int glyph_has_bbx : 1;
+ /* Width of the glyph in bytes. */
+ int glyph_bwidth;
+ /* Height of the glyph in pixel. */
+ int glyph_bheight;
+ /* How many bitmap lines have been parsed already. */
+ int glyph_blines;
+ } parser = { location: START, properties: 0, glyphs: 0,
+ has_size: 0, has_fbbx: 0 };
+
+ bdf = calloc (1, sizeof *bdf);
+ if (!bdf)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ if (linecount)
+ *linecount = 0;
+
+ while (!err && (len = next_line (&line, &line_size, filep, linecount)) >= 0)
+ {
+ switch (parser.location)
+ {
+ case START:
+ {
+ /* This is the start of the file, only comments are allowed
+ until STARTFONT is encountered. */
+ char *arg = line;
+ err = find_arg (&arg);
+
+ if (err)
+ continue;
+ if (!strcmp (line, "STARTFONT"))
+ {
+ char *minor = strchr (arg, '.');
+ if (minor)
+ *(minor++) = '\0';
+ parser.location = FONT;
+ parse_template (arg, "%i", &bdf->version_maj);
+ if (minor)
+ parse_template (minor, "%i", &bdf->version_min);
+ else
+ bdf->version_min = 0;
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case FONT:
+ {
+ /* This is the global header before the CHARS. */
+ char *arg = line;
+ err = find_arg (&arg);
+
+ if (err)
+ continue;
+ else if (!bdf->has_content_version
+ && !strcmp (line, "CONTENTVERSION"))
+ {
+ bdf->has_content_version = 1;
+ parse_template (arg, "%i", &bdf->content_version);
+ }
+ else if (!bdf->name && !strcmp (line, "FONT"))
+ err = parse_string (arg, &bdf->name, 0);
+ else if (!parser.has_size
+ && !strcmp (line, "SIZE"))
+ {
+ parser.has_size = 1;
+ parse_template (arg, "%i%i%i", &bdf->point_size,
+ &bdf->res_x, &bdf->res_y);
+ }
+ else if (!parser.has_fbbx && !strcmp (line, "FONTBOUNDINGBOX"))
+ {
+ parser.has_fbbx = 1;
+ parse_template (arg, "%i%i%i%i", &bdf->bbox.width,
+ &bdf->bbox.height, &bdf->bbox.offx,
+ &bdf->bbox.offy);
+ }
+ else if (!parser.has_metricsset && !strcmp (line, "METRICSSET"))
+ {
+ parser.has_metricsset = 1;
+ parse_template (arg, "%i", &bdf->metricsset);
+ if (!err && (bdf->metricsset < 0
+ || bdf->metricsset > 2))
+ err = BDF_INVALID_ARGUMENT;
+ }
+ else if (!bdf->properties && !strcmp (line, "STARTPROPERTIES"))
+ {
+ parser.location = PROPERTIES;
+ parse_template (arg, "%i", &bdf->properties_count);
+ if (!err && (bdf->properties_count <= 0))
+ err = BDF_INVALID_ARGUMENT;
+ if (err)
+ goto leave;
+ bdf->__properties_allocated = bdf->properties_count;
+ bdf->properties = calloc (bdf->properties_count,
+ sizeof (struct bdf_property));
+ if (!bdf->properties)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ else if (!strcmp (line, "CHARS"))
+ {
+ /* This marks the end of the first section, so check
+ for mandatory global options. */
+ if (!bdf->name || !parser.has_size || !parser.has_fbbx)
+ err = BDF_SYNTAX_ERROR;
+ else
+ {
+ parser.location = GLYPHS;
+ parse_template (arg, "%i", &bdf->glyphs_count);
+ if (!err && (bdf->glyphs_count < 0))
+ err = BDF_INVALID_ARGUMENT;
+ if (!err)
+ {
+ bdf->__glyphs_allocated = bdf->glyphs_count;
+ bdf->glyphs = calloc (bdf->glyphs_count,
+ sizeof (struct bdf_glyph));
+ if (!bdf->glyphs)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ }
+ }
+ else if (!bdf->has_swidth && !strcmp (line, "SWIDTH"))
+ {
+ bdf->has_swidth = 1;
+ parse_template (arg, "%i%i", &bdf->swidth.x, &bdf->swidth.y);
+ }
+ else if (!bdf->has_dwidth && !strcmp (line, "DWIDTH"))
+ {
+ bdf->has_dwidth = 1;
+ parse_template (arg, "%i%i", &bdf->dwidth.x, &bdf->dwidth.y);
+ }
+ else if (!bdf->has_swidth1 && !strcmp (line, "SWIDTH1"))
+ {
+ bdf->has_swidth1 = 1;
+ parse_template (arg, "%i%i", &bdf->swidth1.x, &bdf->swidth1.y);
+ }
+ else if (!bdf->has_dwidth1 && !strcmp (line, "DWIDTH1"))
+ {
+ bdf->has_dwidth1 = 1;
+ parse_template (arg, "%i%i", &bdf->dwidth1.x, &bdf->dwidth1.y);
+ }
+ else if (!bdf->has_vvector && !strcmp (line, "VVECTOR"))
+ {
+ bdf->has_vvector = 1;
+ parse_template (arg, "%i%i", &bdf->vvector.x, &bdf->vvector.y);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case PROPERTIES:
+ /* This is the property list in the global header, between
+ STARTPROPERTIES and ENDPROPERTIES. */
+ if (!strcmp (line, "ENDPROPERTIES"))
+ {
+ parser.location = FONT;
+ if (parser.properties != bdf->properties_count)
+ err = BDF_COUNT_MISMATCH;
+ }
+ else
+ {
+ if (parser.properties == bdf->properties_count)
+ err = BDF_COUNT_MISMATCH;
+ else
+ {
+ struct bdf_property *prop
+ = &bdf->properties[parser.properties++];
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+
+ err = parse_string (line, &prop->name, 0);
+ if (!err)
+ {
+ if (*arg == '"')
+ {
+ prop->type = BDF_PROPERTY_STRING;
+ err = parse_string (arg, &prop->value.string, 1);
+ }
+ else
+ {
+ prop->type = BDF_PROPERTY_NUMBER;
+ parse_template (arg, "%i", &prop->value.number);
+ }
+ }
+ }
+ }
+ break;
+
+ case GLYPHS:
+ /* This is the second section of the file, containing the
+ glyphs. */
+ if (!strcmp (line, "ENDFONT"))
+ {
+ if (parser.glyphs != bdf->glyphs_count)
+ err = BDF_COUNT_MISMATCH;
+ done = 1;
+ }
+ else
+ {
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+ else if (!strcmp (line, "STARTCHAR"))
+ {
+ if (parser.glyphs == bdf->glyphs_count)
+ err = BDF_COUNT_MISMATCH;
+
+ parser.location = GLYPH;
+ parser.glyph = &bdf->glyphs[parser.glyphs++];
+ parser.glyph_has_encoding = 0;
+ parser.glyph_has_bbx = 0;
+ parser.glyph_blines = 0;
+ err = parse_string (arg, &(parser.glyph->name), 0);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case GLYPH:
+ /* This is a glyph, but not its bitmap yet. */
+ if (!strcmp (line, "BITMAP"))
+ {
+ if (!parser.glyph_has_encoding
+ || !parser.glyph_has_bbx
+
+ /* In writing mode 0, SWIDTH and DWIDTH are mandatory. */
+ || (bdf->metricsset != 1
+ && (!(parser.glyph->has_swidth || bdf->has_swidth)
+ || !(parser.glyph->has_dwidth || bdf->has_dwidth)))
+
+ /* In writing mode 1, SWIDTH1, DWIDTH1 and VVECTOR
+ are mandatory. */
+ || (bdf->metricsset != 0
+ && (!(parser.glyph->has_swidth1 || bdf->has_swidth1)
+ || !(parser.glyph->has_dwidth1 || bdf->has_dwidth1)
+ || !(parser.glyph->has_vvector
+ || bdf->has_vvector))))
+ err = BDF_SYNTAX_ERROR;
+
+ parser.location = BITMAP;
+ parser.glyph->bitmap = malloc (parser.glyph_bwidth
+ * parser.glyph_bheight);
+ if (!parser.glyph->bitmap)
+ {
+ errno = ENOMEM;
+ err = BDF_SYSTEM_ERROR;
+ }
+ }
+ else
+ {
+ char *arg = line;
+
+ err = find_arg (&arg);
+ if (err)
+ continue;
+ else if (!parser.glyph_has_encoding
+ && !strcmp (line, "ENCODING"))
+ {
+ parser.glyph_has_encoding = 1;
+ parse_template (arg, "%i", &parser.glyph->encoding);
+ if (err == BDF_SYNTAX_ERROR)
+ {
+ err = 0;
+ parse_template (arg, "%i%i", &parser.glyph->encoding,
+ &parser.glyph->internal_encoding);
+ if (!err && parser.glyph->encoding != -1)
+ err = BDF_SYNTAX_ERROR;
+ }
+ }
+ else if (!parser.glyph_has_bbx && !strcmp (line, "BBX"))
+ {
+ parser.glyph_has_bbx = 1;
+ parse_template (arg, "%i%i%i%i", &parser.glyph->bbox.width,
+ &parser.glyph->bbox.height,
+ &parser.glyph->bbox.offx,
+ &parser.glyph->bbox.offy);
+ if (!err)
+ {
+ parser.glyph_bwidth = (parser.glyph->bbox.width + 7) / 8;
+ parser.glyph_bheight = parser.glyph->bbox.height;
+ }
+ }
+ else if (!parser.glyph->has_swidth && !strcmp (line, "SWIDTH"))
+ {
+ parser.glyph->has_swidth = 1;
+ parse_template (arg, "%i%i", &parser.glyph->swidth.x,
+ &parser.glyph->swidth.y);
+ }
+ else if (!parser.glyph->has_dwidth && !strcmp (line, "DWIDTH"))
+ {
+ parser.glyph->has_dwidth = 1;
+ parse_template (arg, "%i%i", &parser.glyph->dwidth.x,
+ &parser.glyph->dwidth.y);
+ }
+ else if (!parser.glyph->has_swidth1 && !strcmp (line, "SWIDTH1"))
+ {
+ parser.glyph->has_swidth1 = 1;
+ parse_template (arg, "%i%i", &parser.glyph->swidth1.x,
+ &parser.glyph->swidth1.y);
+ }
+ else if (!parser.glyph->has_dwidth1 && !strcmp (line, "DWIDTH1"))
+ {
+ parser.glyph->has_dwidth1 = 1;
+ parse_template (arg, "%i%i", &parser.glyph->dwidth1.x,
+ &parser.glyph->dwidth1.y);
+ }
+ else if (!parser.glyph->has_vvector && !strcmp (line, "VVECTOR"))
+ {
+ parser.glyph->has_vvector = 1;
+ parse_template (arg, "%i%i", &parser.glyph->vvector.x,
+ &parser.glyph->vvector.y);
+ }
+ else
+ err = BDF_SYNTAX_ERROR;
+ }
+ break;
+
+ case BITMAP:
+ /* This is the bitmap of a glyph. */
+ if (!strcmp (line, "ENDCHAR"))
+ {
+ if (parser.glyph_blines != parser.glyph_bheight)
+ err = BDF_COUNT_MISMATCH;
+ parser.location = GLYPHS;
+ parser.glyph = 0;
+ }
+ else
+ {
+ if (strlen (line) != 2 * parser.glyph_bwidth)
+ err = BDF_SYNTAX_ERROR;
+ else if (parser.glyph_blines == parser.glyph_bheight)
+ err = BDF_COUNT_MISMATCH;
+ else
+ {
+ char *number = line;
+ unsigned char *bline = parser.glyph->bitmap
+ + parser.glyph_bwidth * parser.glyph_blines++;
+
+ do
+ {
+ err = parse_hexbyte (number, bline);
+ number += 2;
+ bline++;
+ }
+ while (!err && *number);
+ }
+ }
+ break;
+ }
+ }
+ while (!err && !done && !feof (filep) && !ferror (filep));
+
+ leave:
+ if (ferror (filep))
+ err = ferror (filep);
+ if (err)
+ free (bdf);
+ else
+ *font = bdf;
+ return err;
+}
+
+
+/* Destroy the BDF font object and release all associated
+ resources. */
+void
+bdf_destroy (bdf_font_t font)
+{
+ int i;
+ for (i = 0; i < font->glyphs_count; i++)
+ free (font->glyphs[i].name);
+ free (font->glyphs);
+ for (i = 0; i < font->properties_count; i++)
+ {
+ free (font->properties[i].name);
+ if (font->properties[i].type == BDF_PROPERTY_STRING)
+ free (font->properties[i].value.string);
+ }
+ free (font->properties);
+ free (font->name);
+}
+
+
+bdf_error_t
+bdf_new (bdf_font_t *font, int version_maj, int version_min,
+ const char *name, int point_size, int res_x, int res_y,
+ int bbox_width, int bbox_height, int bbox_offx, int bbox_offy,
+ int metricsset)
+{
+ bdf_font_t bdf;
+
+ if (!font
+ || (version_maj != 2)
+ || (version_min != 1 && version_min != 2)
+ || !name)
+ return BDF_INVALID_ARGUMENT;
+
+ bdf = calloc (1, sizeof *bdf);
+ if (!bdf)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ bdf->version_maj = version_maj;
+ bdf->version_min = version_min;
+ bdf->name = strdup (name);
+ if (!name)
+ {
+ free (bdf);
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+
+ bdf->point_size = point_size;
+ bdf->res_x = res_x;
+ bdf->res_y = res_y;
+ bdf->bbox.width = bbox_width;
+ bdf->bbox.height = bbox_height;
+ bdf->bbox.offx = bbox_offx;
+ bdf->bbox.offy = bbox_offy;
+ bdf->metricsset = metricsset;
+ *font = bdf;
+ return 0;
+}
+
+
+#define bdf_set_something(what) \
+bdf_error_t \
+bdf_set_##what (bdf_font_t font, int glyph, int x, int y) \
+{ \
+ if (x < 0 || y < 0 || glyph > font->glyphs_count - 1) \
+ return BDF_INVALID_ARGUMENT; \
+ if (glyph < 0) \
+ { \
+ font->has_##what = 1; \
+ font->what.x = x; \
+ font->what.y = y; \
+ } \
+ else \
+ { \
+ font->glyphs[glyph].has_##what = 1; \
+ font->glyphs[glyph].what.x = x; \
+ font->glyphs[glyph].what.y = y; \
+ } \
+ return 0; \
+}
+
+bdf_set_something (swidth)
+bdf_set_something (dwidth)
+bdf_set_something (swidth1)
+bdf_set_something (dwidth1)
+bdf_set_something (vvector)
+
+
+static bdf_error_t
+expand_properties (bdf_font_t font, int count)
+{
+ if (font->__properties_allocated == font->properties_count)
+ {
+ struct bdf_property *new;
+ new = realloc (font->properties,
+ (font->__properties_allocated + count)
+ * sizeof (struct bdf_property));
+ if (!new)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->__properties_allocated += count;
+ font->properties = new;
+ }
+ return 0;
+}
+
+
+/* Add a new string property to the font FONT. */
+bdf_error_t
+bdf_add_string_property (bdf_font_t font, const char *name, const char *value)
+{
+ bdf_error_t err;
+ struct bdf_property *prop;
+
+ err = expand_properties (font, 16);
+ if (err)
+ {
+ err = expand_properties (font, 1);
+ if (err)
+ return err;
+ }
+
+ prop = &font->properties[font->properties_count];
+ prop->type = BDF_PROPERTY_STRING;
+ prop->name = strdup (name);
+ if (prop->name)
+ prop->value.string = strdup (value);
+ if (!prop->name || !prop->value.string)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->properties_count++;
+ return 0;
+}
+
+
+/* Add a new number property to the font FONT. */
+bdf_error_t
+bdf_add_number_property (bdf_font_t font, const char *name, int value)
+{
+ bdf_error_t err;
+ struct bdf_property *prop;
+
+ err = expand_properties (font, 16);
+ if (err)
+ {
+ err = expand_properties (font, 1);
+ if (err)
+ return err;
+ }
+
+ prop = &font->properties[font->properties_count];
+ prop->type = BDF_PROPERTY_NUMBER;
+ prop->name = strdup (name);
+ if (!prop->name)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ prop->value.number = value;
+ font->properties_count++;
+ return 0;
+}
+
+
+static bdf_error_t
+expand_glyphs (bdf_font_t font, int count)
+{
+ if (font->__glyphs_allocated == font->glyphs_count)
+ {
+ struct bdf_glyph *new;
+ new = realloc (font->glyphs,
+ (font->__glyphs_allocated + count)
+ * sizeof (struct bdf_glyph));
+ if (!new)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ font->__glyphs_allocated += count;
+ font->glyphs = new;
+ }
+ return 0;
+}
+
+
+/* Add a new glyph with the specified paramters to the font FONT. If
+ encoding is -1, internal_encoding specifies the internal
+ encoding. All other parameters are mandatory. */
+bdf_error_t
+bdf_add_glyph (bdf_font_t font, const char *name, int encoding,
+ int internal_encoding, int bbox_width, int bbox_height,
+ int bbox_offx, int bbox_offy, const unsigned char *bitmap)
+{
+ bdf_error_t err;
+ struct bdf_glyph *glyph;
+ int bsize;
+
+ err = expand_glyphs (font, 64);
+ if (err)
+ {
+ err = expand_glyphs (font, 1);
+ if (err)
+ return err;
+ }
+
+ glyph = &font->glyphs[font->glyphs_count];
+ memset (glyph, 0, sizeof (*glyph));
+
+ glyph->name = strdup (name);
+ if (!glyph->name)
+ {
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ glyph->encoding = encoding;
+ if (encoding == -1)
+ glyph->internal_encoding = internal_encoding;
+ glyph->bbox.width = bbox_width;
+ glyph->bbox.height = bbox_height;
+ glyph->bbox.offx = bbox_offx;
+ glyph->bbox.offy = bbox_offy;
+ bsize = ((bbox_width + 7) / 8) * bbox_height;
+ glyph->bitmap = malloc (bsize);
+ if (!glyph->bitmap)
+ {
+ free (glyph->name);
+ errno = ENOMEM;
+ return BDF_SYSTEM_ERROR;
+ }
+ memcpy (glyph->bitmap, bitmap, bsize);
+ font->glyphs_count++;
+ return 0;
+}
+
+
+/* Write the font FONT in BDF format to stream FILEP. */
+bdf_error_t
+bdf_write (FILE *filep, bdf_font_t font)
+{
+ int index;
+
+ if (font->version_maj != 2
+ || (font->version_min != 1 && font->version_min != 2))
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "STARTFONT %i.%i\n", font->version_maj, font->version_min);
+
+ if (!font->name)
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "FONT %s\n", font->name);
+ fprintf (filep, "SIZE %i %i %i\n", font->point_size,
+ font->res_x, font->res_y);
+ fprintf (filep, "FONTBOUNDINGBOX %i %i %i %i\n",
+ font->bbox.width, font->bbox.height,
+ font->bbox.offx, font->bbox.offy);
+ if (font->has_swidth)
+ fprintf (filep, "SWIDTH %i %i\n", font->swidth.x, font->swidth.y);
+ if (font->has_dwidth)
+ fprintf (filep, "DWIDTH %i %i\n", font->dwidth.x, font->dwidth.y);
+ if (font->has_swidth1)
+ fprintf (filep, "SWIDTH1 %i %i\n", font->swidth1.x, font->swidth1.y);
+ if (font->has_dwidth1)
+ fprintf (filep, "DWIDTH1 %i %i\n", font->dwidth1.x, font->dwidth1.y);
+ if (font->has_vvector)
+ fprintf (filep, "VVECTOR %i %i\n", font->vvector.x, font->vvector.y);
+ if (font->properties_count < 0)
+ return BDF_INVALID_ARGUMENT;
+ /* XXX We always print out a properties block for xmbdfed's sake. */
+ fprintf (filep, "STARTPROPERTIES %i\n", font->properties_count);
+ if (font->properties_count > 0)
+ {
+ fprintf (filep, "STARTPROPERTIES %i\n", font->properties_count);
+ for (index = 0; index < font->properties_count; index++)
+ {
+ struct bdf_property *prop = &font->properties[index];
+
+ if (prop->type == BDF_PROPERTY_NUMBER)
+ fprintf (filep, "%s %i\n", prop->name, prop->value.number);
+ else
+ {
+ char *val = prop->value.string;
+
+ fprintf (filep, "%s \"", prop->name);
+ while (*val)
+ {
+ fputc (*val, filep);
+ if (*(val++) == '"')
+ fputc ('"', filep);
+ }
+ fprintf (filep, "\"\n");
+ }
+ }
+ }
+ fprintf (filep, "ENDPROPERTIES\n");
+ if (font->glyphs_count <= 0)
+ return BDF_INVALID_ARGUMENT;
+ fprintf (filep, "CHARS %i\n", font->glyphs_count);
+
+ for (index = 0; index < font->glyphs_count; index++)
+ {
+ struct bdf_glyph *glyph = &font->glyphs[index];
+ unsigned char *bitmap;
+ int row, col;
+
+ fprintf (filep, "STARTCHAR %s\n", glyph->name);
+ if (glyph->encoding != -1)
+ fprintf (filep, "ENCODING %i\n", glyph->encoding);
+ else
+ fprintf (filep, "ENCODING %i %i\n", glyph->encoding,
+ glyph->internal_encoding);
+ if (glyph->has_swidth)
+ fprintf (filep, "SWIDTH %i %i\n", glyph->swidth.x, glyph->swidth.y);
+ if (glyph->has_dwidth)
+ fprintf (filep, "DWIDTH %i %i\n", glyph->dwidth.x, glyph->dwidth.y);
+ if (glyph->has_swidth1)
+ fprintf (filep, "SWIDTH1 %i %i\n", glyph->swidth1.x, glyph->swidth1.y);
+ if (glyph->has_dwidth1)
+ fprintf (filep, "DWIDTH1 %i %i\n", glyph->dwidth1.x, glyph->dwidth1.y);
+ if (glyph->has_vvector)
+ fprintf (filep, "VVECTOR %i %i\n", glyph->vvector.x, glyph->vvector.y);
+ fprintf (filep, "BBX %i %i %i %i\n", glyph->bbox.width,
+ glyph->bbox.height, glyph->bbox.offx, glyph->bbox.offy);
+ fprintf (filep, "BITMAP\n");
+ bitmap = glyph->bitmap;
+ for (row = 0; row < glyph->bbox.height; row++)
+ {
+ for (col = 0; col < (glyph->bbox.width + 7) / 8; col++)
+ fprintf (filep, "%02X", *(bitmap++));
+ fputc ('\n', filep);
+ }
+ fprintf (filep, "ENDCHAR\n");
+ }
+ fprintf (filep, "ENDFONT\n");
+ if (ferror (filep))
+ {
+ errno = ferror (filep);
+ return BDF_SYSTEM_ERROR;
+ }
+ return 0;
+}
+
+
+/* The function returns -1 if the encoding of glyph A is lower than
+ the encoding of glyph B, 1 if it is the other way round, and 0 if
+ the encoding of both glyphs is the same. */
+int
+bdf_compare_glyphs (const void *a, const void *b)
+{
+ struct bdf_glyph *first = (struct bdf_glyph *) a;
+ struct bdf_glyph *second = (struct bdf_glyph *) b;
+
+ if (first->encoding < second->encoding)
+ return -1;
+ else if (first->encoding > second->encoding)
+ return 1;
+ else
+ {
+ if (first->encoding == -1)
+ {
+ if (first->internal_encoding < second->internal_encoding)
+ return -1;
+ else if (first->internal_encoding > second->internal_encoding)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ }
+}
+
+
+/* Sort the glyphs in the font FONT. This must be called before using
+ bdf_find_glyphs, after the font has been created or after new
+ glyphs have been added to the font. */
+void
+bdf_sort_glyphs (bdf_font_t font)
+{
+ qsort (font->glyphs, font->glyphs_count, sizeof (struct bdf_glyph),
+ bdf_compare_glyphs);
+}
+
+
+/* Find the glyph with the encoding ENC (and INTERNAL_ENC, if ENC is
+ -1) in the font FONT. Requires that the glyphs in the font are
+ sorted. */
+struct bdf_glyph *
+bdf_find_glyph (bdf_font_t font, int enc, int internal_enc)
+{
+ struct bdf_glyph key = { encoding: enc, internal_encoding: internal_enc };
+ return bsearch (&key, font->glyphs, font->glyphs_count,
+ sizeof (struct bdf_glyph), bdf_compare_glyphs);
+}
diff --git a/console-client/bdf.h b/console-client/bdf.h
new file mode 100644
index 00000000..1f0bce41
--- /dev/null
+++ b/console-client/bdf.h
@@ -0,0 +1,272 @@
+/* bdf.h - Parser for the Adobe Glyph Bitmap Distribution Format (BDF).
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann <marcus@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _BDF_H_
+#define _BDF_H_
+
+#include <stdio.h>
+
+/* Version 2.2 of the Glyph Bitmap Distribution Format Specification
+ was released by Adobe 22 March 1993 and is a superset of version 2.1.
+
+ The format of a BDF file is a human-readable ASCII text file.
+ Every line consists of a keyword, which may be followed by one or
+ more arguments. The specification is vague about the exact data
+ types of the arguments, so we treat a string as an 8-bit string
+ which must not contain a binary null, and a number like an integer
+ as an int. Leading and trailing white space are removed, multiple
+ spaces that seperate arguments are replaced by a single white
+ space, and empty lines are ignored. */
+
+
+/* Possible error values returned by the BDF functions. */
+typedef enum
+{
+ /* No error occured. This is guaranteed to be zero. */
+ BDF_NO_ERROR = 0,
+
+ /* A system error occured. The caller should consult errno. */
+ BDF_SYSTEM_ERROR,
+
+ /* All following errors indicate that the file is not a valid BDF
+ file. */
+ BDF_SYNTAX_ERROR,
+
+ /* An argument is out of range or of an invalid type. */
+ BDF_INVALID_ARGUMENT,
+
+ /* The number of properties, glyphs or bitmap lines is
+ incorrect. */
+ BDF_COUNT_MISMATCH
+} bdf_error_t;
+
+/* Return a statically allocated string describing the error value ERR. */
+const char *bdf_strerror (bdf_error_t err);
+
+
+/* A property in the BDF font file is an unspecified KEYWORD VALUE
+ pair in a line after STARTPROPERTIES and before ENDPROPERTIES.
+ VALUE can be an integer or a string in double quotes (two
+ consecutives double quotes can be used to include a double quote in
+ the string. */
+struct bdf_property
+{
+ /* The property name. */
+ char *name;
+
+ /* The type indicates which member of the union is valid. */
+ enum { BDF_PROPERTY_NUMBER, BDF_PROPERTY_STRING } type;
+ union
+ {
+ int number;
+ char *string;
+ } value;
+};
+typedef struct bdf_property *bdf_property_t;
+
+/* The bounding box of a font or a glyph within. */
+struct bdf_bbox
+{
+ int width;
+ int height;
+ int offx;
+ int offy;
+};
+
+/* A vector, used for displacement and resolution. */
+struct bdf_vector
+{
+ int x;
+ int y;
+};
+
+/* A single glyph in the font. */
+struct bdf_glyph
+{
+ /* The name of the glyph. */
+ char *name;
+
+ /* The Adode Standard Encoding of the glyph, or -1 if not
+ available. */
+ int encoding;
+
+ /* If encoding is -1, internal_encoding contains the internal
+ encoding of the glyph. The internal encoding is private to the
+ font and the application. */
+ int internal_encoding;
+
+ /* The bounding box of the glyph. The width of the bounding box,
+ divided by 8 (rounding up), specifies how many bytes are used in
+ the bitmap for each row of the glyph. The height specifies the
+ number of rows. */
+ struct bdf_bbox bbox;
+
+ /* The bitmap of the glyph, row-by-row from top to bottom, and
+ byte-by-byte within a row from left to right. Within a byte, the
+ most significant bit is left in the glyph. */
+ unsigned char *bitmap;
+
+ /* If the writing direction is horizontal, SWIDTH and DWIDTH are
+ relevant. If the writing direction is vertical, SWIDTH1, DWIDTH1
+ and VVECTOR are relevant. Relevant values have to be specified
+ here, or font-wide in the global section. A global value can be
+ overridden for individual glyphs. */
+ int has_swidth : 1;
+ int has_dwidth : 1;
+ int has_swidth1 : 1;
+ int has_dwidth1 : 1;
+ int has_vvector : 1;
+ struct bdf_vector swidth;
+ struct bdf_vector dwidth;
+ struct bdf_vector swidth1;
+ struct bdf_vector dwidth1;
+ struct bdf_vector vvector;
+};
+
+/* A font is a set of glyphs with some font-wide attributes. */
+struct bdf_font
+{
+ /* The version of the font format. Should be 2.1 or 2.2. It is
+ split up into major and minor component to make precise
+ comparison possible. */
+ int version_maj;
+ int version_min;
+
+ /* The font name. */
+ char *name;
+
+ /* The content version, if available. The content version indicates
+ the revision of the appearance of the glyphs within the font. */
+ int has_content_version : 1;
+ int content_version;
+
+ /* The point size of the font in device pixels. */
+ int point_size;
+
+ /* The resolution of the display the font is intended for (dpi).
+ This is needed if you want to scale the glyphs for a different
+ device than they were intended for. */
+ int res_x;
+ int res_y;
+
+ /* The global bounding box parameters. */
+ struct bdf_bbox bbox;
+
+ int __properties_allocated;
+ int properties_count;
+ struct bdf_property *properties;
+ int __glyphs_allocated;
+ int glyphs_count;
+ struct bdf_glyph *glyphs;
+
+ /* The metricsset. If 0, the font has a horizontal writing
+ direction. If 1, the font has a vertical writing direction. If
+ 2, the font has a mixed writing direction. */
+ int metricsset;
+
+ /* The following have the same meaning as the corresponding members
+ in the glyph structure and specify a font wide default which must
+ be used if the glyph does not provide its own values. */
+ int has_swidth : 1;
+ int has_dwidth : 1;
+ int has_swidth1 : 1;
+ int has_dwidth1 : 1;
+ int has_vvector : 1;
+ struct bdf_vector swidth;
+ struct bdf_vector dwidth;
+ struct bdf_vector swidth1;
+ struct bdf_vector dwidth1;
+ struct bdf_vector vvector;
+};
+typedef struct bdf_font *bdf_font_t;
+
+
+/* Read the font from stream FILE, and return it in FONT. If
+ LINECOUNT is not zero, it will contain the number of lines in the
+ file at success, and the current line an error occured at
+ failure. */
+bdf_error_t bdf_read (FILE *file, bdf_font_t *font, int *linecount);
+
+/* Destroy the BDF font object and release all associated
+ resources. */
+void bdf_destroy (bdf_font_t font);
+
+/* Create a new font object with the specified mandatory
+ parameters. */
+bdf_error_t bdf_new (bdf_font_t *font, int version_maj, int version_min,
+ const char *name, int point_size, int res_x, int res_y,
+ int bbox_width, int bbox_height, int bbox_offx,
+ int bbox_offy, int metricsset);
+
+/* Set the SWIDTH of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_swidth (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the DWIDTH of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_dwidth (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the SWIDTH1 of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_swidth1 (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the DWIDTH1 of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_dwidth1 (bdf_font_t font, int glyph, int x, int y);
+
+/* Set the VVECTOR of the glyph GLYPH in font FONT to X and Y. If
+ glyph is negativ, the default for the font will be set. */
+bdf_error_t bdf_set_vvector (bdf_font_t font, int glyph, int x, int y);
+
+/* Add a new string property to the font FONT. */
+bdf_error_t bdf_add_string_property (bdf_font_t font, const char *name,
+ const char *value);
+
+/* Add a new number property to the font FONT. */
+bdf_error_t bdf_add_number_property (bdf_font_t font, const char *name,
+ int value);
+
+/* Add a new glyph with the specified paramters to the font FONT. If
+ encoding is -1, internal_encoding specifies the internal
+ encoding. All other parameters are mandatory. */
+bdf_error_t bdf_add_glyph (bdf_font_t font, const char *name, int encoding,
+ int internal_encoding, int bbox_width,
+ int bbox_height, int bbox_offx, int bbox_offy,
+ const unsigned char *bitmap);
+
+/* Write the font FONT in BDF format to stream FILEP. */
+bdf_error_t bdf_write (FILE *filep, bdf_font_t font);
+
+/* The function returns -1 if the encoding of glyph A is lower than
+ the encoding of glyph B, 1 if it is the other way round, and 0 if
+ the encoding of both glyphs is the same. */
+int bdf_compare_glyphs (const void *a, const void *b);
+
+/* Sort the glyphs in the font FONT. This must be called before using
+ bdf_find_glyphs, after the font has been created or after new
+ glyphs have been added to the font. */
+void bdf_sort_glyphs (bdf_font_t font);
+
+/* Find the glyph with the encoding ENC (and INTERNAL_ENC, if ENC is
+ -1) in the font FONT. Requires that the glyphs in the font are
+ sorted. */
+struct bdf_glyph *bdf_find_glyph (bdf_font_t font, int enc, int internal_enc);
+
+#endif /* _BDF_H_ */
diff --git a/console-client/bell.h b/console-client/bell.h
new file mode 100644
index 00000000..3ff40bde
--- /dev/null
+++ b/console-client/bell.h
@@ -0,0 +1,56 @@
+/* bell.h - The interface to and for a bell driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _BELL_H_
+#define _BELL_H_ 1
+
+#include <errno.h>
+
+
+/* The bell drivers are set up by the driver's initialization routine
+ and added to the console client with driver_add_bell. All
+ subsequent operations on the display are fully synchronized by the
+ caller. The driver deinitialization routine should call
+ driver_remove_bell. */
+
+/* Forward declaration. */
+struct bell_ops;
+typedef struct bell_ops *bell_ops_t;
+
+/* Add the bell HANDLE with the operations OPS to the console client.
+ As soon as this is called, operations on this bell may be
+ performed, even before the function returns. */
+error_t driver_add_bell (bell_ops_t ops, void *handle);
+
+/* Remove the bell HANDLE with the operations OPS from the console
+ client. As soon as this function returns, no operations will be
+ performed on the bell anymore. */
+error_t driver_remove_bell (bell_ops_t ops, void *handle);
+
+struct bell_ops
+{
+ /* Beep! the bell HANDLE. */
+ error_t (*beep) (void *handle);
+
+ /* Do not use, do not remove. */
+ void (*deprecated) (void *handle, int key);
+};
+
+#endif /* _BELL_H_ */
diff --git a/console-client/console.c b/console-client/console.c
new file mode 100644
index 00000000..32c7fc1e
--- /dev/null
+++ b/console-client/console.c
@@ -0,0 +1,468 @@
+/* console.c -- A pluggable console client.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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 2, 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <argp.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <wchar.h>
+#include <error.h>
+#include <assert.h>
+
+#include <cthreads.h>
+
+#include <hurd/console.h>
+#include <hurd/cons.h>
+
+#include <version.h>
+
+#include "driver.h"
+#include "timer.h"
+
+const char *cons_client_name = "console";
+const char *cons_client_version = HURD_VERSION;
+
+
+/* The global lock protects the active_vcons variable, and thus all
+ operations on the virtual console that is currently active. */
+static struct mutex global_lock;
+
+/* The active virtual console. This is the one currently
+ displayed. */
+static vcons_t active_vcons = NULL;
+
+
+/* Callbacks for input source drivers. */
+
+/* Switch the active console to console ID or DELTA (relative to the
+ active console). */
+error_t
+console_switch (int id, int delta)
+{
+ error_t err = 0;
+ vcons_t vcons;
+ vcons_t new_vcons;
+
+ /* We must give up our global lock before we can call back into
+ libcons. This is because cons_switch will lock CONS, and as
+ other functions in libcons lock CONS while calling back into our
+ functions which take the global lock (like cons_vcons_add), we
+ would deadlock. So we acquire a reference for VCONS to make sure
+ it isn't deallocated while we are outside of the global lock. We
+ also know that */
+
+ mutex_lock (&global_lock);
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return EINVAL;
+ }
+ ports_port_ref (vcons);
+ mutex_unlock (&global_lock);
+
+ err = cons_switch (vcons, id, delta, &new_vcons);
+ if (!err)
+ {
+ mutex_lock (&global_lock);
+ if (active_vcons != new_vcons)
+ {
+ cons_vcons_close (active_vcons);
+ active_vcons = new_vcons;
+ }
+ mutex_unlock (&new_vcons->lock);
+ ports_port_deref (vcons);
+ mutex_unlock (&global_lock);
+ }
+ return err;
+}
+
+
+/* Enter SIZE bytes from the buffer BUF into the currently active
+ console. This can be called by the input driver at any time. */
+error_t
+console_input (char *buf, size_t size)
+{
+ error_t err = 0;
+ vcons_t vcons;
+
+ mutex_lock (&global_lock);
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return EINVAL;
+ }
+ ports_port_ref (vcons);
+ mutex_unlock (&global_lock);
+
+ if (vcons)
+ {
+ err = cons_vcons_input (vcons, buf, size);
+ ports_port_deref (vcons);
+ }
+ return err;
+}
+
+
+/* Scroll the active console by TYPE and VALUE as specified by
+ cons_vcons_scrollback. */
+int
+console_scrollback (cons_scroll_t type, float value)
+{
+ int nr = 0;
+ vcons_t vcons;
+
+ mutex_lock (&global_lock);
+ vcons = active_vcons;
+ if (!vcons)
+ {
+ mutex_unlock (&global_lock);
+ return EINVAL;
+ }
+ ports_port_ref (vcons);
+ mutex_unlock (&global_lock);
+
+ if (vcons)
+ {
+ nr = cons_vcons_scrollback (vcons, type, value);
+ ports_port_deref (vcons);
+ }
+ return nr;
+}
+
+
+/* Exit the console client. Does not return. */
+void
+console_exit (void)
+{
+ driver_fini ();
+ exit (0);
+}
+
+/* Signal an error to the user. */
+void console_error (const wchar_t *const err_msg)
+{
+ mutex_lock (&global_lock);
+ bell_iterate
+ if (bell->ops->beep)
+ bell->ops->beep (bell->handle);
+ mutex_unlock (&global_lock);
+}
+
+#if QUAERENDO_INVENIETIS
+void
+console_deprecated (int key)
+{
+ mutex_lock (&global_lock);
+ input_iterate
+ if (input->ops->deprecated)
+ (*input->ops->deprecated) (input->handle, key);
+ display_iterate
+ if (display->ops->deprecated)
+ (*display->ops->deprecated) (display->handle, key);
+ bell_iterate
+ if (bell->ops->deprecated)
+ (*bell->ops->deprecated) (bell->handle, key);
+ mutex_unlock (&global_lock);
+}
+#endif /* QUAERENDO_INVENIETIS */
+
+
+/* Callbacks for libcons. */
+
+/* The user may define this function. It is called after a
+ virtual console entry was added. CONS is locked. */
+void
+cons_vcons_add (cons_t cons, vcons_list_t vcons_entry)
+{
+ error_t err = 0;
+ mutex_lock (&global_lock);
+ if (!active_vcons)
+ {
+ vcons_t vcons;
+
+ /* The first virtual console added to the list is automatically
+ opened after startup. */
+ err = cons_vcons_open (cons, vcons_entry, &vcons);
+ if (!err)
+ {
+ vcons_entry->vcons = vcons;
+ active_vcons = vcons;
+ mutex_unlock (&vcons->lock);
+ }
+ }
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user may define this function. Make the changes from
+ cons_vcons_write, cons_vcons_set_cursor_pos,
+ cons_vcons_set_cursor_status and cons_vcons_scroll active. VCONS
+ is locked and will have been continuously locked from the first
+ change since the last update on. This is the latest possible point
+ the user must make the changes visible from. The user can always
+ make the changes visible at a more convenient, earlier time. */
+void
+cons_vcons_update (vcons_t vcons)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->update)
+ display->ops->update (display->handle);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Set the cursor on virtual
+ console VCONS, which is locked, to position COL and ROW. */
+void
+cons_vcons_set_cursor_pos (vcons_t vcons, uint32_t col, uint32_t row)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->set_cursor_pos)
+ display->ops->set_cursor_pos (display->handle, col, row);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Set the cursor status of
+ virtual console VCONS, which is locked, to STATUS. */
+void
+cons_vcons_set_cursor_status (vcons_t vcons, uint32_t status)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->set_cursor_status)
+ display->ops->set_cursor_status (display->handle, status);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Scroll the content of virtual
+ console VCONS, which is locked, up by DELTA if DELTA is positive or
+ down by -DELTA if DELTA is negative. DELTA will never be zero, and
+ the absolute value if DELTA will be smaller than or equal to the
+ height of the screen matrix.
+
+ See <hurd/cons.h> for more information about this function. */
+void
+cons_vcons_scroll (vcons_t vcons, int delta)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->scroll)
+ display->ops->scroll (display->handle, delta);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Deallocate the scarce
+ resources (like font glyph slots, colors etc) in the LENGTH entries
+ of the screen matrix starting from position COL and ROW. This call
+ is immediately followed by a subsequent cons_vcons_write call with
+ the same LENGTH, COL and ROW arguments, and should help to make the
+ write successful. If there are no scarce resources, the caller
+ might do nothing. */
+void cons_vcons_clear (vcons_t vcons, size_t length,
+ uint32_t col, uint32_t row)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->clear)
+ display->ops->clear (display->handle, length, col, row);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Write LENGTH characters
+ starting from STR on the virtual console VCONS, which is locked,
+ starting from position COL and ROW. */
+void
+cons_vcons_write (vcons_t vcons, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->write)
+ display->ops->write (display->handle, str, length, col, row);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Make the virtual console
+ VCONS, which is locked, beep audibly. */
+void
+cons_vcons_beep (vcons_t vcons)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ bell_iterate
+ if (bell->ops->beep)
+ bell->ops->beep (bell->handle);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Make the virtual console
+ VCONS, which is locked, flash visibly. */
+void
+cons_vcons_flash (vcons_t vcons)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ display_iterate
+ if (display->ops->flash)
+ display->ops->flash (display->handle);
+ mutex_unlock (&global_lock);
+}
+
+
+/* The user must define this function. Notice the current status of
+ the scroll lock flag. */
+void
+cons_vcons_set_scroll_lock (vcons_t vcons, int onoff)
+{
+ mutex_lock (&global_lock);
+ if (vcons == active_vcons)
+ input_iterate
+ if (input->ops->set_scroll_lock_status)
+ input->ops->set_scroll_lock_status (input->handle, onoff);
+ mutex_unlock (&global_lock);
+}
+
+
+/* Console-specific options. */
+static const struct argp_option
+options[] =
+ {
+ {"driver-path", 'D', "PATH", 0, "Specify search path for driver modules" },
+ {"driver", 'd', "NAME", 0, "Add driver NAME to the console" },
+ {0}
+ };
+
+/* Parse a command line option. */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ static int devcount = 0;
+ error_t err;
+
+ switch (key)
+ {
+ case 'D':
+ {
+ char *s;
+ char *d;
+
+ if (driver_path)
+ free (driver_path);
+ driver_path = malloc (strlen (arg) + 2);
+ if (!driver_path)
+ {
+ argp_failure (state, 1, ENOMEM, "adding driver path failed");
+ return EINVAL;
+ }
+ s = arg;
+ d = driver_path;
+ while (*s)
+ {
+ *(d++) = (*s == ':') ? '\0' : *s;
+ s++;
+ }
+ *(d++) = '\0';
+ *d = '\0';
+ }
+ break;
+
+ case 'd':
+ err = driver_add (arg /* XXX */, arg,
+ state->argc, state->argv, &state->next, 0);
+ if (err)
+ {
+ argp_failure (state, 1, err, "loading driver `%s' failed", arg);
+ return EINVAL;
+ }
+ devcount++;
+ break;
+
+ case ARGP_KEY_SUCCESS:
+ if (!devcount)
+ {
+ argp_error (state, "at least one --driver argument required");
+ return EINVAL;
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+/* Add our startup arguments to the standard cons set. */
+static const struct argp_child startup_children[] =
+ { { &cons_startup_argp }, { 0 } };
+static struct argp startup_argp = {options, parse_opt, 0,
+ 0, startup_children};
+
+int
+main (int argc, char *argv[])
+{
+ error_t err;
+ char *errname;
+
+ driver_init ();
+
+ /* Parse our command line. This shouldn't ever return an error. */
+ argp_parse (&startup_argp, argc, argv, 0, 0, 0);
+
+ err = driver_start (&errname);
+ if (err)
+ error (1, 0, "Starting driver %s failed", errname);
+
+ mutex_init (&global_lock);
+
+ err = cons_init ();
+ if (err)
+ {
+ driver_fini ();
+ error (1, err, "Console library initialization failed");
+ }
+
+ err = timer_init ();
+ if (err)
+ {
+ driver_fini ();
+ error (1, err, "Timer thread initialization failed");
+ }
+
+ cons_server_loop ();
+
+ /* Never reached. */
+ driver_fini ();
+ return 0;
+}
diff --git a/console-client/display.h b/console-client/display.h
new file mode 100644
index 00000000..44e62773
--- /dev/null
+++ b/console-client/display.h
@@ -0,0 +1,138 @@
+/* display.h - The interface to and for a display driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _DISPLAY_H_
+#define _DISPLAY_H_ 1
+
+#include <errno.h>
+#include <stdint.h>
+
+#include <hurd/console.h>
+
+
+/* The display drivers are set up by the driver's initialization
+ routine and added to the console client with driver_add_display.
+ All subsequent operations on the display are fully synchronized by
+ the caller. The driver deinitialization routine should call
+ driver_remove_display. */
+
+/* Forward declaration. */
+struct display_ops;
+typedef struct display_ops *display_ops_t;
+
+/* Add the display HANDLE with the operations OPS to the console
+ client. As soon as this is called, operations on this display may
+ be performed, even before the function returns. */
+error_t driver_add_display (display_ops_t ops, void *handle);
+
+/* Remove the display HANDLE with the operations OPS from the console
+ client. As soon as this function returns, no operations will be
+ performed on the display anymore. */
+error_t driver_remove_display (display_ops_t ops, void *handle);
+
+
+struct display_ops
+{
+ /* Set the cursor's position on display HANDLE to column COL and row
+ ROW. The home position (COL and ROW both being 0) is the upper
+ left corner of the screen matrix. COL will be smaller than the
+ width and ROW will be smaller than the height of the display.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*set_cursor_pos) (void *handle, uint32_t col, uint32_t row);
+
+
+ /* Set the cursor's state to STATE on display HANDLE. The possible
+ values for STATE are defined by the CONS_CURSOR_* symbols in
+ <hurd/console.h>.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*set_cursor_status) (void *handle, uint32_t state);
+
+
+ /* Scroll the display by DELTA lines up if DELTA is positive, and by
+ -DELTA lines down if DELTA is negative. DELTA will never be
+ zero, and the absolute value if DELTA will be smaller than or
+ equal to the height of the screen matrix.
+
+ The area that becomes free will be filled in a subsequent write
+ call. The purpose of the function is two-fold: It is called with
+ an absolute value of DELTA smaller than the screen height to
+ perform scrolling. It is called with an absolute value of DELTA
+ equal to the screen height to prepare a full refresh of the
+ screen. In the latter case the driver should not really perform
+ any scrolling. Instead it might deallocate limited resources
+ (like display glyph slots and palette colors) if that helps to
+ perform the subsequent write. It goes without saying that the
+ same deallocation, if any, should be performed on the area that
+ will be filled with the scrolled in content.
+
+ XXX Possibly need a function to invalidate scrollback buffer, or
+ in general to signal a switch of the console so state can be
+ reset. Only do this if we make guarantees about validity of
+ scrollback buffer, of course.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*scroll) (void *handle, int delta);
+
+ /* Deallocate the scarce resources (like font glyph slots, colors
+ etc) in the LENGTH entries of the screen matrix starting from
+ position COL and ROW. This call is immediately followed by calls
+ to write which cover the same area. If there are no scarce
+ resources, the caller might do nothing. */
+ error_t (*clear) (void *handle, size_t length, uint32_t col, uint32_t row);
+
+ /* Write the text STR with LENGTH characters to column COL and row
+ ROW on display HANDLE. LENGTH can be longer than the width of
+ the screen matrix minus COL. In this case the driver should
+ automatically wrap around the edge. However, LENGTH will never
+ be so huge that the whole text starting from COL and ROW will go
+ beyond the lower right corner of the screen matrix.
+
+ The driver is allowed to delay the effect of this operation until
+ the UPDATE function is called. */
+ error_t (*write) (void *handle, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row);
+
+ /* Flush all the past changes on display HANDLE that have not been
+ flushed yet. This should make all past changes visible to the
+ user. The driver is free to make them visible earlier, but it
+ must happen before returning from this call.
+
+ The purpose of this function is to group several related change
+ operations together, but also several change operations which
+ occur in rapid succession. The first grouping is essential to
+ make it possible for a driver to implement double buffering. The
+ second grouping is important to keep up performance if there is a
+ lot of activity on the screen matrix. */
+ error_t (*update) (void *handle);
+
+ /* Flash the display HANDLE once. This should be done
+ immediately. */
+ error_t (*flash) (void *handle);
+
+ /* Do not use, do not remove. */
+ void (*deprecated) (void *handle, int key);
+};
+
+#endif /* _DISPLAY_H_ */
diff --git a/console-client/driver.c b/console-client/driver.c
new file mode 100644
index 00000000..74df1907
--- /dev/null
+++ b/console-client/driver.c
@@ -0,0 +1,353 @@
+/* driver.c - The console client driver code.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include <dlfcn.h>
+
+#include <cthreads.h>
+
+#include "driver.h"
+
+
+/* The number of entries by which we grow a driver or component list
+ if we need more space. */
+#define LIST_GROW 4
+
+/* The path where we search for drivers, in addition to the default
+ path. The directories are separated by '\0' and terminated with an
+ empty string. XXX Should use argz or something. XXX Should get a
+ protective lock. */
+char *driver_path;
+
+/* The driver list lock, the list itself, its current length and the
+ total number of entries in the list. */
+struct mutex driver_list_lock;
+driver_t driver_list;
+size_t driver_list_len;
+size_t driver_list_alloc;
+
+
+/* Initialize the driver framework. */
+error_t
+driver_init (void)
+{
+ mutex_init (&driver_list_lock);
+ mutex_init (&display_list_lock);
+ mutex_init (&input_list_lock);
+ mutex_init (&bell_list_lock);
+ return 0;
+}
+
+
+/* Deinitialize and unload all loaded drivers and deinitialize the
+ driver framework. */
+error_t
+driver_fini (void)
+{
+ int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ {
+ driver_list[i].ops->fini (driver_list[i].handle, 1);
+ dlclose (driver_list[i].module);
+ free (driver_list[i].name);
+ free (driver_list[i].driver);
+ }
+ driver_list_len = 0;
+ mutex_unlock (&driver_list_lock);
+ return 0;
+}
+
+
+/* Load, intialize and (if START is non-zero) start the driver DRIVER
+ under the given NAME (which must be unique among all loaded
+ drivers) with arguments ARGZ with length ARGZ_LEN. This funtion
+ will grab the driver list lock. The driver itself might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_add (const char *const name, const char *const driver,
+ int argc, char *argv[], int *next, int start)
+{
+ error_t err;
+ static char cons_defpath[] = CONSOLE_DEFPATH;
+ driver_ops_t ops;
+ char *filename = NULL;
+ char *modname;
+ void *shobj = NULL;
+ driver_t drv;
+ int i;
+ char *dir = driver_path;
+ int defpath = 0;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ if (driver_list[i].name && !strcmp (driver_list[i].name, name))
+ {
+ mutex_unlock (&driver_list_lock);
+ return EEXIST;
+ }
+
+ if (!dir || !*dir)
+ {
+ dir = cons_defpath;
+ defpath = 1;
+ }
+
+ while (dir)
+ {
+ if (filename)
+ free (filename);
+ if (asprintf (&filename,
+ "%s/%s%s", dir, driver, CONSOLE_SONAME_SUFFIX) < 0)
+ {
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ errno = 0;
+ shobj = dlopen (filename, RTLD_LAZY);
+ if (!shobj)
+ {
+ const char *errstring = dlerror (); /* Must always call or it leaks! */
+ if (errno != ENOENT)
+ {
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return errno ?: EGRATUITOUS;
+ }
+ }
+ else
+ break;
+
+ dir += strlen (dir) + 1;
+ if (!*dir)
+ {
+ if (defpath)
+ break;
+ else
+ {
+ dir = cons_defpath;
+ defpath = 1;
+ }
+ }
+ }
+
+ if (!shobj)
+ {
+ if (filename)
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOENT;
+ }
+
+ if (asprintf (&modname, "driver_%s_ops", driver) < 0)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ ops = dlsym (shobj, modname);
+ free (modname);
+ if (!ops || !ops->init)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return EGRATUITOUS;
+ }
+
+ if (driver_list_len == driver_list_alloc)
+ {
+ size_t new_alloc = driver_list_alloc + LIST_GROW;
+ driver_t new_list = realloc (driver_list,
+ new_alloc * sizeof (*driver_list));
+ if (!new_list)
+ {
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return errno;
+ }
+ driver_list = new_list;
+ driver_list_alloc = new_alloc;
+ }
+ drv = &driver_list[driver_list_len];
+
+ drv->name = strdup (name);
+ drv->driver = strdup (driver);
+ drv->filename = filename;
+ drv->ops = ops;
+ drv->module = shobj;
+ if (!drv->name || !drv->driver)
+ {
+ if (drv->name)
+ free (drv->name);
+ if (drv->driver)
+ free (drv->driver);
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return ENOMEM;
+ }
+
+ /* If we will start the driver, the init function must not exit. */
+ err = (*drv->ops->init) (&drv->handle, start, argc, argv, next);
+ if (!err && start && drv->ops->start)
+ err = (*drv->ops->start) (drv->handle);
+ if (err)
+ {
+ free (drv->name);
+ free (drv->driver);
+ dlclose (shobj);
+ free (filename);
+ mutex_unlock (&driver_list_lock);
+ return err;
+ }
+
+ driver_list_len++;
+ mutex_unlock (&driver_list_lock);
+ return 0;
+}
+
+
+/* Start all drivers. Only used once at start up, after all the
+ option parsing and driver initialization.
+
+ Returns 0 on success, and the name of a driver if it initializing
+ that driver fails. */
+error_t
+driver_start (char **name)
+{
+ error_t err = 0;
+ int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ {
+ if (driver_list[i].ops->start)
+ err = (*driver_list[i].ops->start) (driver_list[i].handle);
+ if (err)
+ {
+ *name = driver_list[i].name;
+ while (--i >= 0)
+ (*driver_list[i].ops->fini) (driver_list[i].handle, 1);
+ break;
+ }
+ }
+ mutex_unlock (&driver_list_lock);
+ return err;
+}
+
+
+/* Deinitialize and unload the driver with the name NAME. This
+ function will grab the driver list lock. The driver might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_remove (const char *const name)
+{
+ error_t err;
+ int i;
+
+ mutex_lock (&driver_list_lock);
+ for (i = 0; i < driver_list_len; i++)
+ if (driver_list[i].name && !strcmp (driver_list[i].name, name))
+ {
+ err = driver_list[i].ops->fini (driver_list[i].handle, 0);
+ if (!err)
+ {
+ dlclose (driver_list[i].module);
+ free (driver_list[i].name);
+ free (driver_list[i].driver);
+ free (driver_list[i].filename);
+ while (i + 1 < driver_list_len)
+ {
+ driver_list[i] = driver_list[i + 1];
+ i++;
+ }
+ driver_list_len--;
+ }
+ mutex_unlock (&driver_list_lock);
+ return err;
+ }
+ mutex_unlock (&driver_list_lock);
+ return ESRCH;
+}
+
+
+#define ADD_REMOVE_COMPONENT(component) \
+struct mutex component##_list_lock; \
+component##_t component##_list; \
+size_t component##_list_len; \
+size_t component##_list_alloc; \
+ \
+error_t \
+driver_add_##component (component##_ops_t ops, void *handle) \
+{ \
+ mutex_lock (&component##_list_lock); \
+ if (component##_list_len == component##_list_alloc) \
+ { \
+ size_t new_alloc = component##_list_alloc + LIST_GROW; \
+ component##_t new_list = realloc (component##_list, \
+ new_alloc \
+ * sizeof (*component##_list)); \
+ if (!new_list) \
+ { \
+ mutex_unlock (&component##_list_lock); \
+ return errno; \
+ } \
+ component##_list = new_list; \
+ component##_list_alloc = new_alloc; \
+ } \
+ component##_list[component##_list_len].ops = ops; \
+ component##_list[component##_list_len].handle = handle; \
+ component##_list_len++; \
+ mutex_unlock (&component##_list_lock); \
+ return 0; \
+} \
+ \
+error_t \
+driver_remove_##component (component##_ops_t ops, void *handle) \
+{ \
+ int i; \
+ \
+ mutex_lock (&component##_list_lock); \
+ for (i = 0; i < component##_list_len; i++) \
+ if (component##_list[i].ops == ops \
+ && component##_list[i].handle == handle) \
+ { \
+ while (i + 1 < component##_list_len) \
+ { \
+ component##_list[i] = component##_list[i + 1]; \
+ i++; \
+ } \
+ component##_list_len--; \
+ } \
+ mutex_unlock (&component##_list_lock); \
+ return 0; \
+}
+
+ADD_REMOVE_COMPONENT (display)
+ADD_REMOVE_COMPONENT (input)
+ADD_REMOVE_COMPONENT (bell)
diff --git a/console-client/driver.h b/console-client/driver.h
new file mode 100644
index 00000000..ac8f5c98
--- /dev/null
+++ b/console-client/driver.h
@@ -0,0 +1,282 @@
+/* driver.h - The interface to and for a console client driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _CONSOLE_DRIVER_H_
+#define _CONSOLE_DRIVER_H_ 1
+
+#include <errno.h>
+#include <stddef.h>
+
+#include "display.h"
+#include "input.h"
+#include "bell.h"
+
+
+/* The path where we search for drivers, in addition to the default
+ path. The directories are separated by '\0' and terminated with an
+ empty string. XXX Should use argz or something. XXX Should get a
+ protective lock. */
+extern char *driver_path;
+
+
+/* The driver framework allows loading and unloading of new drivers.
+ It also provides some operations on the loaded drivers. The device
+ framework module does its own locking, so all operations can be run
+ at any time by any thread. */
+
+/* Initialize the driver framework. */
+error_t driver_init (void);
+
+/* Deinitialize and unload all loaded drivers and deinitialize the
+ driver framework. */
+error_t driver_fini (void);
+
+/* Forward declaration. */
+struct driver_ops;
+typedef struct driver_ops *driver_ops_t;
+
+/* Load, initialize and (if START is non-zero) start the driver DRIVER
+ under the given NAME (which must be unique among all loaded
+ drivers) with arguments ARGC, ARGV and NEXT (see
+ parse_startup_args). This function will grab the driver list lock.
+ The driver itself might try to grab the display, input source and
+ bell list locks as well. */
+error_t driver_add (const char *const name, const char *const driver,
+ int argc, char *argv[], int *next, int start);
+
+/* Start all drivers. Only used once at start up, after all the
+ option parsing and driver initialization.
+
+ Returns 0 on success, and the error if it initializing that driver
+ fails (NAME points to the driver name then). */
+error_t driver_start (char **name);
+
+/* Deinitialize and unload the driver with the name NAME. This
+ function will grab the driver list lock. The driver might try to
+ grab the display, input source and bell list locks as well. */
+error_t driver_remove (const char *const name);
+
+/* Iterate over all loaded drivers. This macro will grab the driver
+ list lock. You use it with a block:
+
+ driver_iterate
+ {
+ printf ("%s\n", driver->ops->name);
+ }
+
+ Or even just:
+
+ driver_iterate printf ("%s\n", driver->ops->name);
+
+ The variable DRIVER is provided by the macro. */
+#define driver_iterate \
+ for (driver_t driver = (mutex_lock (&driver_list_lock), \
+ &driver_list[0]); \
+ driver < &driver_list[driver_list_len] \
+ || (mutex_unlock (&driver_list_lock), 0); \
+ driver++)
+
+
+struct driver_ops
+{
+ /* Initialize an instance of the driver and return a handle for it
+ in HANDLE. The options in ARGC, ARGV and NEXT should be
+ processed and validated.
+
+ If NO_EXIT is zero, the function might exit on fatal errors or
+ invalid arguments. The drawback is that it must NOT allocate any
+ resources that need to be freed or deallocated explicitely before
+ exiting the program either, because other driver instances are
+ also allowed to exit without prior notice at some later time.
+ Allocation and initialization of such resources (like the video
+ card) must be delayed until the start() function is called (see
+ below).
+
+ If NO_EXIT is non-zero, the function must not exit, but report
+ all errors back to the caller. In this case, it is guaranteed
+ that the START function is called immediately after this function
+ returns, and that the driver is properly unloaded with fini() at
+ some later time.
+
+ The above behaviour, and the split into an init() and a start()
+ function, was carefully designed to allow the init() function the
+ optimal use of argp at startup and at run time to parse options.
+
+ ARGV[*NEXT] is the next argument to be parsed. ARGC is the
+ number of total arguments in ARGV. The function should increment
+ *NEXT for each argument parsed. The function should not reorder
+ arguments, nor should it parse non-option arguments. It should
+ also not parse over any single "--" argument.
+
+ Every driver must implement this function.
+
+ If NO_EXIT is zero, the function should return zero on success
+ and otherwise either terminate or return an appropriate error
+ value. If it returns, either the program terminates because of
+ other errors, or the function start() is called.
+
+ If NO_EXIT is non-zero, the function should return zero on
+ success and an appropriate error value otherwise. If it returns
+ success, the function start() will be called next, otherwise
+ nothing happens. */
+ error_t (*init) (void **handle, int no_exit,
+ int argc, char *argv[], int *next);
+
+ /* Activate the driver instance. This function should load all the
+ display, input and bell river components for this driver
+ instance.
+
+ If successful, the function should return zero. In this case it
+ is guaranteed that fini() will be called before the program
+ terminates. If not successful, the function should free all
+ resources associated with HANDLE and return non-zero. */
+ error_t (*start) (void *handle);
+
+ /* Deinitialize the driver. This should remove all the individual
+ drivers installed by init() and release all resources. It should
+ also reset all hardware devices into the state they had before
+ calling init(), as far as applicable. HANDLE is provided as
+ returned by init().
+
+ The function is allowed to fail if FORCE is 0. If FORCE is not
+ 0, the driver should remove itself no matter what. */
+ error_t (*fini) (void *handle, int force);
+};
+
+
+/* The driver structure. */
+struct driver
+{
+ /* The unique name of the driver. */
+ char *name;
+
+ /* The plugin name. */
+ char *driver;
+
+ /* The filename that was identified as providing the plugin. */
+ char *filename;
+
+ driver_ops_t ops;
+ void *handle;
+
+ /* The following members are private to the driver support code. Do
+ not use. */
+
+ /* The shared object handle as returned by dlopen(). */
+ void *module;
+};
+typedef struct driver *driver_t;
+
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex driver_list_lock;
+extern driver_t driver_list;
+extern size_t driver_list_len;
+
+
+/* Iterate over all loaded displays. This macro will grab the display
+ list lock. You use it with a block, just like driver_iterate.
+
+ display_iterate display->ops->flash (display->handle);
+
+ The variable DISPLAY is provided by the macro. */
+#define display_iterate \
+ for (display_t display = (mutex_lock (&display_list_lock), \
+ &display_list[0]); \
+ display < &display_list[display_list_len] \
+ || (mutex_unlock (&display_list_lock), 0); \
+ display++)
+
+
+/* The display structure. */
+struct display
+{
+ display_ops_t ops;
+ void *handle;
+};
+typedef struct display *display_t;
+
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex display_list_lock;
+extern display_t display_list;
+extern size_t display_list_len;
+
+
+/* Iterate over all loaded inputs. This macro will grab the input
+ list lock. You use it with a block, just like driver_iterate.
+
+ input_iterate input->ops->set_scroll_lock_status (input->handle, 0);
+
+ The variable INPUT is provided by the macro. */
+#define input_iterate \
+ for (input_t input = (mutex_lock (&input_list_lock), &input_list[0]); \
+ input < &input_list[input_list_len] \
+ || (mutex_unlock (&input_list_lock), 0); \
+ input++)
+
+
+/* The input structure. */
+struct input
+{
+ input_ops_t ops;
+ void *handle;
+};
+typedef struct input *input_t;
+
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex input_list_lock;
+extern input_t input_list;
+extern size_t input_list_len;
+
+
+/* Iterate over all loaded bells. This macro will grab the bell list
+ lock. You use it with a block, just like driver_iterate.
+
+ bell_iterate bell->ops->beep (bell->handle);
+
+ The variable BELL is provided by the macro. */
+#define bell_iterate \
+ for (bell_t bell = (mutex_lock (&bell_list_lock), &bell_list[0]); \
+ bell < &bell_list[bell_list_len] \
+ || (mutex_unlock (&bell_list_lock), 0); \
+ bell++)
+
+
+/* The bell structure, needed by the macro above. Don't use it
+ directly. */
+struct bell
+{
+ bell_ops_t ops;
+ void *handle;
+};
+typedef struct bell *bell_t;
+
+/* Forward declarations needed by the macro above. Don't use these
+ variables directly. */
+extern struct mutex bell_list_lock;
+extern bell_t bell_list;
+extern size_t bell_list_len;
+
+#endif /* _CONSOLE_DRIVER_H_ */
diff --git a/console-client/generic-speaker.c b/console-client/generic-speaker.c
new file mode 100644
index 00000000..9288cd24
--- /dev/null
+++ b/console-client/generic-speaker.c
@@ -0,0 +1,488 @@
+/* generic-speaker.c - The simple speaker bell driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <sys/io.h>
+
+#include <cthreads.h>
+
+#include "driver.h"
+#include "timer.h"
+
+/* This driver should work on IA32, IA64, Alpha, PowerPC, MIPS and ARM
+ architectures. It requires a Programmable Interrupt Timer (PIT) at
+ I/O ports 0x40 - 0x43 and a speaker that can be connected to timer
+ 2 at I/O port 0x61. */
+
+/* The beep timer. */
+static struct timer_list generic_speaker_timer;
+
+/* Forward declaration. */
+static struct bell_ops generic_speaker_ops;
+
+
+/* The speaker port. */
+#define SPEAKER 0x61
+
+/* If 0, follow state of SPEAKER_DATA bit, otherwise enable output
+ from timer 2. */
+#define SPEAKER_TMR2 0x01
+
+/* If SPEAKER_TMR2 is not set, this provides direct input into the
+ speaker. Otherwise, this enables or disables the output from the
+ timer. */
+#define SPEAKER_DATA 0x02
+
+
+/* The PIT channel value ports. You can write to and read from them.
+ Do not mess with timer 0 or 1. */
+#define PIT_COUNTER_0 0x40
+#define PIT_COUNTER_1 0x41
+#define PIT_COUNTER_2 0x42
+
+/* The frequency of the PIT clock. */
+#define PIT_FREQUENCY 0x1234dd
+
+/* The PIT control port. You can only write to it. Do not mess with
+ timer 0 or 1. */
+#define PIT_CTRL 0x43
+#define PIT_CTRL_SELECT_MASK 0xc0
+#define PIT_CTRL_SELECT_0 0x00
+#define PIT_CTRL_SELECT_1 0x40
+#define PIT_CTRL_SELECT_2 0x80
+
+/* Read and load control. */
+#define PIT_CTRL_READLOAD_MASK 0x30
+#define PIT_CTRL_COUNTER_LATCH 0x00 /* Hold timer value until read. */
+#define PIT_CTRL_READLOAD_LSB 0x10 /* Read/load the LSB. */
+#define PIT_CTRL_READLOAD_MSB 0x20 /* Read/load the MSB. */
+#define PIT_CTRL_READLOAD_WORD 0x30 /* Read/load the LSB then the MSB. */
+
+/* Mode control. */
+#define PIT_CTRL_MODE_MASK 0x0e
+
+/* Interrupt on terminal count. Setting the mode sets output to low.
+ When counter is set and terminated, output is set to high. */
+#define PIT_CTRL_INTR_ON_TERM 0x00
+
+/* Programmable one-shot. When loading counter, output is set to
+ high. When counter terminated, output is set to low. Can be
+ triggered again from that point on by setting the gate pin to
+ high. */
+#define PIT_CTRL_PROGR_ONE_SHOT 0x02
+
+/* Rate generator. Output is low for one period of the counter, and
+ high for the other. */
+#define PIT_CTRL_RATE_GEN 0x04
+
+/* Square wave generator. Output is low for one half of the period,
+ and high for the other half. */
+#define PIT_CTRL_SQUAREWAVE_GEN 0x06
+
+/* Software triggered strobe. Setting the mode sets output to high.
+ When counter is set and terminated, output is set to low. */
+#define PIT_CTRL_SOFTSTROBE 0x08
+
+/* Hardware triggered strobe. Like software triggered strobe, but
+ only starts the counter when the gate pin is set to high. */
+#define PIT_CTRL_HARDSTROBE 0x0a
+
+
+/* Count mode. */
+#define PIT_CTRL_COUNT_MASK 0x01
+#define PIT_CTRL_COUNT_BINARY 0x00 /* 16-bit binary counter. */
+#define PIT_CTRL_COUNT_BCD 0x01 /* 4-decade BCD counter. */
+
+
+/* Let's be loud! */
+
+/* The 12th root of 2. Sort of. */
+#define T_TEMP_SCALE 1.0594630943592952645
+#define T_DOWN_ONE_HALF(x) ((short) (x / T_TEMP_SCALE))
+#define T_UP_ONE_HALF(x) ((short) (x * T_TEMP_SCALE))
+#define T_DOWN_ONE_OCTAVE(x) ((short) (x / 2))
+#define T_UP_ONE_OCTAVE(x) ((short) (x * 2))
+#define T_REST ((short) 0)
+#define T_FINE ((short) (-1))
+
+#define T_b_3 T_UP_ONE_OCTAVE (T_b_2)
+#define T_b_F_3 T_UP_ONE_OCTAVE (T_b_F_2)
+#define T_a_S_3 T_b_F_3
+#define T_a_3 T_UP_ONE_OCTAVE (T_a_2)
+#define T_a_F_3 T_UP_ONE_OCTAVE (T_a_F_2)
+#define T_g_S_3 T_a_F_3
+#define T_g_3 T_UP_ONE_OCTAVE (T_g_2)
+#define T_g_F_3 T_f_S_3
+#define T_f_S_3 T_UP_ONE_OCTAVE (T_f_S_2)
+#define T_f_3 T_UP_ONE_OCTAVE (T_f_2)
+#define T_e_3 T_UP_ONE_OCTAVE (T_e_2)
+#define T_e_F_3 T_UP_ONE_OCTAVE (T_e_F_2)
+#define T_d_S_3 T_e_F_3
+#define T_d_3 T_UP_ONE_OCTAVE (T_d_2)
+#define T_d_F_3 T_c_S_3
+#define T_c_S_3 T_UP_ONE_OCTAVE (T_c_S_2)
+#define T_c_3 T_UP_ONE_OCTAVE (T_c_2)
+
+#define T_b_2 T_UP_ONE_OCTAVE (T_b_1)
+#define T_b_F_2 T_UP_ONE_OCTAVE (T_b_F_1)
+#define T_a_S_2 T_b_F_2
+#define T_a_2 T_UP_ONE_OCTAVE (T_a_1)
+#define T_a_F_2 T_UP_ONE_OCTAVE (T_a_F_1)
+#define T_g_S_2 T_a_F_2
+#define T_g_2 T_UP_ONE_OCTAVE (T_g_1)
+#define T_g_F_2 T_f_S_2
+#define T_f_S_2 T_UP_ONE_OCTAVE (T_f_S_1)
+#define T_f_2 T_UP_ONE_OCTAVE (T_f_1)
+#define T_e_2 T_UP_ONE_OCTAVE (T_e_1)
+#define T_e_F_2 T_UP_ONE_OCTAVE (T_e_F_1)
+#define T_d_S_2 T_e_F_2
+#define T_d_2 T_UP_ONE_OCTAVE (T_d_1)
+#define T_d_F_2 T_c_S_2
+#define T_c_S_2 T_UP_ONE_OCTAVE (T_c_S_1)
+#define T_c_2 T_UP_ONE_OCTAVE (T_c_1)
+
+#define T_b_1 T_UP_ONE_HALF (T_b_F_1)
+#define T_b_F_1 T_UP_ONE_HALF (T_a_1)
+#define T_a_S_1 T_b_F_1
+#define T_a_1 ((short) (440))
+#define T_a_F_1 T_DOWN_ONE_HALF (T_a_1)
+#define T_g_S_1 T_a_F_1
+#define T_g_1 T_DOWN_ONE_HALF (T_a_F_1)
+#define T_g_F_1 T_f_S_1
+#define T_f_S_1 T_DOWN_ONE_HALF (T_g_1)
+#define T_f_1 T_DOWN_ONE_HALF (T_f_S_1)
+#define T_e_1 T_DOWN_ONE_HALF (T_f_1)
+#define T_e_F_1 T_DOWN_ONE_HALF (T_e_1)
+#define T_d_S_1 T_e_F_1
+#define T_d_1 T_DOWN_ONE_HALF (T_e_F_1)
+#define T_d_F_1 T_c_S_1
+#define T_c_S_1 T_DOWN_ONE_HALF (T_d_1)
+#define T_c_1 T_DOWN_ONE_HALF (T_c_S_1)
+
+#define T_b T_DOWN_ONE_OCTAVE (T_b_1)
+#define T_b_F T_DOWN_ONE_OCTAVE (T_b_F_1)
+#define T_a_S T_b_F
+#define T_a T_DOWN_ONE_OCTAVE (T_a_1)
+#define T_a_F T_DOWN_ONE_OCTAVE (T_a_F_1)
+#define T_g_S T_a_F
+#define T_g T_DOWN_ONE_OCTAVE (T_g_1)
+#define T_g_F T_f_S
+#define T_f_S T_DOWN_ONE_OCTAVE (T_f_S_1)
+#define T_f T_DOWN_ONE_OCTAVE (T_f_1)
+#define T_e T_DOWN_ONE_OCTAVE (T_e_1)
+#define T_e_F T_DOWN_ONE_OCTAVE (T_e_F_1)
+#define T_d_S T_e_F
+#define T_d T_DOWN_ONE_OCTAVE (T_d_1)
+#define T_d_F T_c_S
+#define T_c_S T_DOWN_ONE_OCTAVE (T_c_S_1)
+#define T_c T_DOWN_ONE_OCTAVE (T_c_1)
+
+struct note
+{
+ short pitch;
+ short duration;
+};
+
+struct melody
+{
+ int measure;
+ struct note *next;
+ struct note note[];
+};
+
+static struct melody beep1 =
+ { 160, NULL, {
+ /* The classical bell. */
+ { T_a_1, 4 }, { T_FINE, 0 }
+ } };
+
+static struct melody beep2 =
+ { 60, NULL, {
+ /* The Linux bell. */
+ { 750, 1 }, { T_FINE, 0 }
+ } };
+
+static struct melody beep3 =
+ { 160, NULL, {
+ /* The tritonus. Quite alarming. */
+ { T_f_2, 2 }, { T_b_1, 4 }, { T_FINE, 0 }
+ } };
+
+static struct melody beep4 =
+ { 160, NULL, {
+ /* C-Major chord. A bit playful. */
+ { T_c_2, 2 }, { T_e_2, 2 }, { T_g_2, 2 },
+ { T_FINE, 0 }
+ } };
+
+static struct melody *beep[] = { &beep1, &beep2, &beep3, &beep4 };
+static int active_beep;
+
+#if QUAERENDO_INVENIETIS
+struct melody tune1 =
+ { 160, NULL, {
+ /* The Free Software Song. Measure: 7/4. */
+ { T_d_2, 16 }, { T_c_2, 8 }, { T_b_1, 16 }, { T_a_1, 16 },
+ { T_b_1, 16 }, { T_c_2, 8 }, { T_b_1, 8 }, { T_a_1, 8 }, { T_g_1, 16 },
+ { T_g_1, 24 }, { T_a_1, 24 }, { T_b_1, 8 },
+ { T_c_2, 24 }, { T_b_1, 14 }, { T_REST, 2 }, { T_b_1, 8 }, { T_d_2, 8 },
+ { T_a_1, 22 }, { T_REST, 2 }, { T_a_1, 32 },
+ { T_c_2, 16 }, { T_d_2, 8 }, { T_c_2, 16 }, { T_b_1, 24 },
+ { T_d_2, 16 }, { T_c_2, 8 }, { T_b_1, 16 }, { T_a_1, 16 },
+ { T_b_1, 16 }, { T_c_2, 8 }, { T_b_1, 8 }, { T_a_1, 8 }, { T_g_1, 16 },
+ { T_g_1, 24 }, { T_a_1, 24 }, { T_b_1, 8 },
+ { T_c_2, 24 }, { T_b_1, 14 }, { T_REST, 2 }, { T_b_1, 8 }, { T_d_2, 8 },
+ { T_a_1, 22 }, { T_REST, 2 }, { T_a_1, 30 }, { T_REST, 2 },
+ { T_a_1, 56 }, { T_FINE, 0 }
+ } };
+
+struct melody tune2 =
+ { 160, NULL, {
+ /* I feel pretty. Measure: 3/4. By Leonard Bernstein. */
+ { T_c_1, 8 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 20 },
+ { T_REST, 8 }, { T_c_1, 8 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 20 },
+ { T_REST, 8 }, { T_c_1, 8 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 12 }, { T_e_1, 8 },
+ { T_f_1, 4 }, { T_a_1, 12 }, { T_f_1, 8 },
+ { T_c_2, 32 },
+ { T_b_F_1,8 }, { T_a_1, 8 },
+ { T_g_1, 4 }, { T_f_1, 20 },
+ { T_REST, 8 }, { T_g_1, 8 }, { T_a_1, 8 },
+ { T_b_F_1,12}, { T_a_1, 4 }, { T_g_1, 4 }, { T_f_1, 4 },
+ { T_e_1, 16 }, { T_d_1, 3 }, { T_e_1, 2 }, { T_d_1, 3 },
+ { T_c_1, 56 }, { T_FINE, 0 }
+ } };
+
+struct melody tune3 =
+ { 120, NULL, {
+ /* Summertime. Measure: 4/4. By George & Ira Gershwin. */
+ { T_b_1, 8 }, { T_g_1, 8 },
+ { T_b_1, 36 }, { T_REST, 4 }, { T_a_1, 6 }, { T_g_1, 2 },
+ { T_a_1, 6 }, { T_b_1, 2 }, { T_g_1, 8 },
+ { T_e_1, 16 }, { T_b, 24 }, { T_REST, 8 },
+ { T_b_1, 8 }, { T_g_1, 8 },
+ { T_a_1, 3 }, { T_REST, 1 }, { T_a_1, 28 },
+ { T_REST, 8 }, { T_g_1, 6 }, { T_e_1, 2 },
+ { T_g_1, 6 }, { T_e_1, 2 }, { T_g_1, 8 },
+ { T_f_S_1,48}, { T_REST, 4 }, { T_b_1, 8 }, { T_g_1, 4 },
+ { T_b_1, 3 }, { T_REST, 1 }, { T_b_1, 7 }, { T_REST, 1 }, { T_b_1, 20 },
+ { T_REST, 8 }, { T_a_1, 6 }, { T_g_1, 2 },
+ { T_a_1, 6 }, { T_b_1, 2 }, { T_g_1, 8 },
+ { T_e_1, 16 }, { T_b, 32 }, { T_REST, 8 },
+ { T_b, 8 }, { T_d_1, 8 }, { T_b, 4 },
+ { T_d_1, 4 }, { T_e_1, 8 }, { T_g_1, 8 },
+ /* Keen attempt at a glissando. */
+ { T_b_1, 2 }, { T_b_1 + (T_b_1 - T_a_1) / 3, 1 },
+ { T_b_1 + 2 * (T_b_1 - T_a_1) / 3, 1 },
+ { T_a_1, 12 }, { T_g_1, 15 }, { T_REST, 1 },
+ { T_g_1, 4 }, { T_e_1, 68 },
+ { T_FINE, 0 }
+ } };
+
+struct melody tune4 =
+ { 250, NULL, {
+ /* Indiana Jones Theme. Measure: 4/4. By John Williams. */
+ { T_e_1, 4 }, { T_REST, 8 }, { T_f_1, 4 },
+ { T_g_1, 4 }, { T_REST, 4 }, { T_c_2, 24 },
+ { T_REST, 16 }, { T_d_1, 4 }, { T_REST, 8 }, { T_e_1, 4 },
+ { T_f_1, 32 },
+ { T_REST, 16 }, { T_g_1, 4 }, { T_REST, 8 }, { T_a_1, 4 },
+ { T_b_1, 4 }, { T_REST, 4 }, { T_f_2, 24 },
+ { T_REST, 16 }, { T_a_1, 4 }, { T_REST, 8 }, { T_b_1, 4 },
+ { T_c_2, 8 }, { T_REST, 8 }, { T_d_2, 12 }, { T_REST, 4 },
+ { T_e_2, 8 }, { T_REST, 8 },
+ { T_e_1, 4 }, { T_REST, 8 }, { T_f_1, 4 },
+ { T_g_1, 4 }, { T_REST, 4 }, { T_c_2, 24 },
+ { T_REST, 16 }, { T_d_2, 4 }, { T_REST, 8 }, { T_e_2, 4 },
+ { T_f_2, 32 },
+ { T_REST, 16 }, { T_g_1, 4 }, { T_REST, 8 }, { T_g_1, 4 },
+ { T_e_2, 16 }, { T_d_2, 4 }, { T_REST, 8 }, { T_g_1, 4 },
+ { T_e_2, 16 }, { T_d_2, 4 }, { T_REST, 8 }, { T_g_1, 4 },
+ { T_f_2, 16 }, { T_e_2, 4 }, { T_REST, 8 }, { T_d_2, 4 },
+ { T_c_2, 32 }, { T_FINE, 0 }
+ } };
+
+struct melody *tune[] = { &tune1, &tune2, &tune3, &tune4 };
+#endif /* QUAERENDO_INVENIETIS */
+
+
+static void
+beep_off (void)
+{
+ unsigned char status;
+
+ status = inb (SPEAKER) & ~(SPEAKER_TMR2 | SPEAKER_DATA);
+ outb (status, SPEAKER);
+}
+
+static void
+beep_on (short pitch)
+{
+ unsigned char status;
+ unsigned int counter;
+
+ if (pitch < 20)
+ pitch = 20;
+ else if (pitch > 32767)
+ pitch = 32767;
+
+ counter = PIT_FREQUENCY / pitch;
+
+ /* Program timer 2. */
+ outb (PIT_CTRL_SELECT_2 | PIT_CTRL_READLOAD_WORD
+ | PIT_CTRL_SQUAREWAVE_GEN | PIT_CTRL_COUNT_BINARY, PIT_CTRL);
+ outb (counter & 0xff, PIT_COUNTER_2); /* LSB */
+ outb ((counter >> 8) & 0xff, PIT_COUNTER_2); /* MSB */
+
+ /* Start speaker. */
+ status = inb (SPEAKER) | SPEAKER_TMR2 | SPEAKER_DATA;
+ outb (status, SPEAKER);
+}
+
+
+static int
+next_note (void *handle)
+{
+ struct melody *melody = handle;
+
+ switch (melody->next->pitch)
+ {
+ case T_FINE:
+ beep_off ();
+ return 0;
+
+ case T_REST:
+ beep_off ();
+ break;
+
+ default:
+ beep_on (melody->next->pitch);
+ break;
+ }
+
+ generic_speaker_timer.expires
+ += (60 * HZ * melody->next->duration / (8 * melody->measure));
+ melody->next++;
+ return 1;
+}
+
+
+/* Initialization of the generic speaker driver. */
+static error_t
+generic_speaker_init (void **handle, int no_exit,
+ int argc, char *argv[], int *next)
+{
+ timer_clear (&generic_speaker_timer);
+ generic_speaker_timer.fnc = &next_note;
+
+ return 0;
+}
+
+
+/* Start the driver. */
+static error_t
+generic_speaker_start (void *handle)
+{
+ error_t err;
+
+#if OSKIT_MACH
+ if (ioperm (SPEAKER, 1, 1) < 0)
+ return errno;
+ if (ioperm (PIT_COUNTER_2, PIT_CTRL - PIT_COUNTER_2 + 1, 1) < 0)
+ return errno;
+#endif
+
+ beep_off ();
+
+ err = driver_add_bell (&generic_speaker_ops, NULL);
+ /* XXX We can not disable the I/O ports on error as there might be
+ concurrent users of it. */
+ return err;
+}
+
+
+/* Deinitialization of the generic speaker driver. */
+static error_t
+generic_speaker_fini (void *handle, int force)
+{
+ driver_remove_bell (&generic_speaker_ops, NULL);
+
+ /* XXX We can not disable the I/O ports as there might be concurrent
+ users of it. */
+ if (timer_remove (&generic_speaker_timer))
+ beep_off ();
+ return 0;
+}
+
+
+/* Beep! */
+static error_t
+generic_speaker_beep (void *handle)
+{
+ if (timer_remove (&generic_speaker_timer))
+ beep_off ();
+ generic_speaker_timer.fnc_data = beep[active_beep];
+ beep[0]->next = &beep[active_beep]->note[1];
+ beep_on (beep[active_beep]->note[0].pitch);
+ generic_speaker_timer.expires = fetch_jiffies ()
+ + (60 * HZ * beep[active_beep]->note[0].duration
+ / (8 * beep[active_beep]->measure));
+ timer_add (&generic_speaker_timer);
+ return 0;
+}
+
+#if QUAERENDO_INVENIETIS
+static void
+generic_speaker_play_melody (void *handle, int key)
+{
+ if (key < 0 || key >= sizeof (tune) / sizeof (tune[0]))
+ return;
+
+ if (timer_remove (&generic_speaker_timer))
+ beep_off ();
+ generic_speaker_timer.fnc_data = tune[key];
+ tune[key]->next = &tune[key]->note[1];
+ beep_on (tune[key]->note[0].pitch);
+ generic_speaker_timer.expires = fetch_jiffies ()
+ + (60 * HZ * tune[key]->note[0].duration / (8 * tune[key]->measure));
+ timer_add (&generic_speaker_timer);
+ return;
+}
+#endif /* QUAERENDO_INVENIETIS */
+
+
+struct driver_ops driver_generic_speaker_ops =
+ {
+ generic_speaker_init,
+ generic_speaker_start,
+ generic_speaker_fini
+ };
+
+static struct bell_ops generic_speaker_ops =
+ {
+ generic_speaker_beep,
+#if QUAERENDO_INVENIETIS
+ generic_speaker_play_melody
+#else
+ NULL
+#endif
+ };
diff --git a/console-client/input.h b/console-client/input.h
new file mode 100644
index 00000000..38c2a64f
--- /dev/null
+++ b/console-client/input.h
@@ -0,0 +1,83 @@
+/* input.h - The interface to and for an input driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _INPUT_H_
+#define _INPUT_H_ 1
+
+#include <errno.h>
+#include <stddef.h>
+
+#include <hurd/cons.h>
+
+
+/* The input drivers are set up by the driver's initialization routine
+ and added to the console client with driver_add_input. All
+ subsequent operations on the display are fully synchronized by the
+ caller. The driver deinitialization routine should call
+ driver_remove_input. */
+
+/* Forward declaration. */
+struct input_ops;
+typedef struct input_ops *input_ops_t;
+
+/* Add the input source HANDLE with the operations OPS to the console
+ client. As soon as this is called, operations on this input source
+ may be performed, even before the function returns. */
+error_t driver_add_input (input_ops_t ops, void *handle);
+
+/* Remove the input HANDLE with the operations OPS from the console
+ client. As soon as this function returns, no operations will be
+ performed on the input source anymore. */
+error_t driver_remove_input (input_ops_t ops, void *handle);
+
+/* Enter SIZE bytes from the buffer BUF into the currently active
+ console. This can be called by the input driver at any time. */
+error_t console_input (char *buf, size_t size);
+
+/* Scroll the active console by TYPE and VALUE as specified by
+ cons_vcons_scrollback. */
+int console_scrollback (cons_scroll_t type, float value);
+
+/* Switch the active console to console ID or DELTA (relative to the
+ active console). */
+error_t console_switch (int id, int delta);
+
+/* Signal an error to the user. */
+void console_error (const wchar_t *const err_msg);
+
+/* Exit the console client. Does not return. */
+void console_exit (void);
+
+#if QUAERENDO_INVENIETIS
+/* Do not use, do not remove. */
+void console_deprecated (int key);
+#endif
+
+
+struct input_ops
+{
+ /* Set the status of the scroll lock indication. */
+ error_t (*set_scroll_lock_status) (void *handle, int onoff);
+
+ /* Do not use, do not remove. */
+ void (*deprecated) (void *handle, int key);
+};
+
+#endif /* _INPUT_H_ */
diff --git a/console-client/ncursesw.c b/console-client/ncursesw.c
new file mode 100644
index 00000000..b47d6513
--- /dev/null
+++ b/console-client/ncursesw.c
@@ -0,0 +1,611 @@
+/* ncursesw.c - The ncursesw console driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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 2, 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <assert.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <wchar.h>
+
+/* The makefiles make sure that this program is compiled with
+ -I${prefix}/ncursesw. */
+#include <curses.h>
+
+#include <cthreads.h>
+#include <hurd/console.h>
+
+#include "driver.h"
+
+
+/* ncurses is not thread-safe. This lock protects all calls into the
+ ncurses library. */
+struct mutex ncurses_lock;
+
+/* Forward declaration. */
+static struct display_ops ncursesw_display_ops;
+static struct input_ops ncursesw_input_ops;
+static struct bell_ops ncursesw_bell_ops;
+
+struct curses_kc_to_cons_kc
+{
+ int curses;
+ char *cons;
+};
+
+static struct curses_kc_to_cons_kc keycodes[] =
+ {
+ { KEY_BREAK, NULL }, /* XXX */
+ { KEY_DOWN, CONS_KEY_DOWN },
+ { KEY_UP, CONS_KEY_UP },
+ { KEY_RIGHT, CONS_KEY_RIGHT },
+ { KEY_LEFT, CONS_KEY_LEFT },
+ { KEY_HOME, CONS_KEY_HOME },
+ { KEY_BACKSPACE, CONS_KEY_BACKSPACE },
+ { KEY_F(1), CONS_KEY_F1 },
+ { KEY_F(2), CONS_KEY_F2 },
+ { KEY_F(3), CONS_KEY_F3 },
+ { KEY_F(4), CONS_KEY_F4 },
+ { KEY_F(5), CONS_KEY_F5 },
+ { KEY_F(6), CONS_KEY_F6 },
+ { KEY_F(7), CONS_KEY_F7 },
+ { KEY_F(8), CONS_KEY_F8 },
+ { KEY_F(9), CONS_KEY_F9 },
+ { KEY_F(10), CONS_KEY_F10 },
+ { KEY_DL, NULL }, /* XXX Delete line. */
+ { KEY_IL, NULL }, /* XXX Insert line. */
+ { KEY_DC, CONS_KEY_DC },
+ { KEY_IC, CONS_KEY_IC },
+ { KEY_EIC, NULL }, /* XXX Exit insert mode. */
+ { KEY_CLEAR, NULL }, /* XXX Clear screen. */
+ { KEY_EOS, NULL }, /* XXX Clear to end of screen. */
+ { KEY_EOL, NULL }, /* XXX Clear to end of line. */
+ { KEY_SF, NULL }, /* XXX Scroll one line forward. */
+ { KEY_SR, NULL }, /* XXX Scroll one line backward. */
+ { KEY_NPAGE, CONS_KEY_NPAGE },
+ { KEY_PPAGE, CONS_KEY_PPAGE },
+ { KEY_STAB, NULL }, /* XXX Set tab. */
+ { KEY_CTAB, NULL }, /* XXX Clear tab. */
+ { KEY_CATAB, NULL }, /* XXX Clear all tabs. */
+ { KEY_ENTER, NULL }, /* XXX Enter or send. */
+ { KEY_SRESET, NULL }, /* XXX Soft (partial) reset. */
+ { KEY_RESET, NULL }, /* XXX Reset or hard reset. */
+ { KEY_PRINT, NULL }, /* XXX Print or copy. */
+ { KEY_LL, NULL }, /* XXX Home down or bottom (lower left). */
+ { KEY_A1, NULL }, /* XXX Upper left of keypad. */
+ { KEY_A3, NULL }, /* XXX Upper right of keypad. */
+ { KEY_B2, NULL }, /* XXX Center of keypad. */
+ { KEY_C1, NULL }, /* XXX Lower left of keypad. */
+ { KEY_C3, NULL }, /* XXX Lower right of keypad. */
+ { KEY_BTAB, CONS_KEY_BTAB },
+ { KEY_BEG, NULL }, /* XXX Beg(inning) key. */
+ { KEY_CANCEL, NULL }, /* XXX Cancel key. */
+ { KEY_CLOSE, NULL }, /* XXX Close key. */
+ { KEY_COMMAND, NULL }, /* XXX Cmd (command) key. */
+ { KEY_COPY, NULL }, /* XXX Copy key. */
+ { KEY_CREATE, NULL }, /* XXX Create key. */
+ { KEY_END, CONS_KEY_END },
+ { KEY_EXIT, NULL }, /* XXX Exit key. */
+ { KEY_FIND, NULL }, /* XXX Find key. */
+ { KEY_HELP, NULL }, /* XXX Help key. */
+ { KEY_MARK, NULL }, /* XXX Mark key. */
+ { KEY_MESSAGE, NULL }, /* XXX Message key. */
+ { KEY_MOUSE, NULL }, /* XXX Mouse event read. */
+ { KEY_MOVE, NULL }, /* XXX Move key. */
+ { KEY_NEXT, NULL }, /* XXX Next object key. */
+ { KEY_OPEN, NULL }, /* XXX Open key. */
+ { KEY_OPTIONS, NULL }, /* XXX Options key. */
+ { KEY_PREVIOUS, NULL }, /* XXX Previous object key. */
+ { KEY_REDO, NULL }, /* XXX Redo key. */
+ { KEY_REFERENCE, NULL }, /* XXX Ref(erence) key. */
+ { KEY_REFRESH, NULL }, /* XXX Refresh key. */
+ { KEY_REPLACE, NULL }, /* XXX Replace key. */
+ { KEY_RESIZE, NULL }, /* XXX Screen resized. */
+ { KEY_RESTART, NULL }, /* XXX Restart key. */
+ { KEY_RESUME, NULL }, /* XXX Resume key. */
+ { KEY_SAVE, NULL }, /* XXX Save key. */
+ { KEY_SBEG, NULL }, /* XXX Shifted beginning key. */
+ { KEY_SCANCEL, NULL }, /* XXX Shifted cancel key. */
+ { KEY_SCOMMAND, NULL }, /* XXX Shifted command key. */
+ { KEY_SCOPY, NULL }, /* XXX Shifted copy key. */
+ { KEY_SCREATE, NULL }, /* XXX Shifted create key. */
+ { KEY_SDC, NULL }, /* XXX Shifted delete char key. */
+ { KEY_SDL, NULL }, /* XXX Shifted delete line key. */
+ { KEY_SELECT, NULL }, /* XXX Select key. */
+ { KEY_SEND, NULL }, /* XXX Shifted end key. */
+ { KEY_SEOL, NULL }, /* XXX Shifted clear line key. */
+ { KEY_SEXIT, NULL }, /* XXX Shifted exit key. */
+ { KEY_SFIND, NULL }, /* XXX Shifted find key. */
+ { KEY_SHELP, NULL }, /* XXX Shifted help key. */
+ { KEY_SHOME, NULL }, /* XXX Shifted home key. */
+ { KEY_SIC, NULL }, /* XXX Shifted input key. */
+ { KEY_SLEFT, NULL }, /* XXX Shifted left arrow key. */
+ { KEY_SMESSAGE, NULL }, /* XXX Shifted message key. */
+ { KEY_SMOVE, NULL }, /* XXX Shifted move key. */
+ { KEY_SNEXT, NULL }, /* XXX Shifted next key. */
+ { KEY_SOPTIONS, NULL }, /* XXX Shifted options key. */
+ { KEY_SPREVIOUS, NULL }, /* XXX Shifted prev key. */
+ { KEY_SPRINT, NULL }, /* XXX Shifted print key. */
+ { KEY_SREDO, NULL }, /* XXX Shifted redo key. */
+ { KEY_SREPLACE, NULL }, /* XXX Shifted replace key. */
+ { KEY_SRIGHT, NULL }, /* XXX Shifted right arrow. */
+ { KEY_SRSUME, NULL }, /* XXX Shifted resume key. */
+ { KEY_SSAVE, NULL }, /* XXX Shifted save key. */
+ { KEY_SSUSPEND, NULL }, /* XXX Shifted suspend key. */
+ { KEY_SUNDO, NULL }, /* XXX Shifted undo key. */
+ { KEY_SUSPEND, NULL }, /* XXX Suspend key. */
+ { KEY_UNDO, NULL } /* XXX Undo key. */
+ };
+
+static int
+ucs4_to_altchar (wchar_t chr, chtype *achr)
+{
+ switch (chr)
+ {
+ case CONS_CHAR_RARROW:
+ *achr = ACS_RARROW;
+ break;
+ case CONS_CHAR_LARROW:
+ *achr = ACS_LARROW;
+ break;
+ case CONS_CHAR_UARROW:
+ *achr = ACS_UARROW;
+ break;
+ case CONS_CHAR_DARROW:
+ *achr = ACS_DARROW;
+ break;
+ case CONS_CHAR_BLOCK:
+ *achr = ACS_BLOCK;
+ break;
+ case CONS_CHAR_LANTERN:
+ *achr = ACS_LANTERN;
+ break;
+ case CONS_CHAR_DIAMOND:
+ *achr = ACS_DIAMOND;
+ break;
+ case CONS_CHAR_CKBOARD:
+ *achr = ACS_CKBOARD;
+ break;
+ case CONS_CHAR_DEGREE:
+ *achr = ACS_DEGREE;
+ break;
+ case CONS_CHAR_PLMINUS:
+ *achr = ACS_PLMINUS;
+ break;
+ case CONS_CHAR_BOARD:
+ *achr = ACS_BOARD;
+ break;
+ case CONS_CHAR_LRCORNER:
+ *achr = ACS_LRCORNER;
+ break;
+ case CONS_CHAR_URCORNER:
+ *achr = ACS_URCORNER;
+ break;
+ case CONS_CHAR_ULCORNER:
+ *achr = ACS_ULCORNER;
+ break;
+ case CONS_CHAR_LLCORNER:
+ *achr = ACS_LLCORNER;
+ break;
+ case CONS_CHAR_PLUS:
+ *achr = ACS_PLUS;
+ break;
+ case CONS_CHAR_S1:
+ *achr = ACS_S1;
+ break;
+ case CONS_CHAR_S3:
+ *achr = ACS_S3;
+ break;
+ case CONS_CHAR_HLINE:
+ *achr = ACS_HLINE;
+ break;
+ case CONS_CHAR_S7:
+ *achr = ACS_S7;
+ break;
+ case CONS_CHAR_S9:
+ *achr = ACS_S9;
+ break;
+ case CONS_CHAR_LTEE:
+ *achr = ACS_LTEE;
+ break;
+ case CONS_CHAR_RTEE:
+ *achr = ACS_RTEE;
+ break;
+ case CONS_CHAR_BTEE:
+ *achr = ACS_BTEE;
+ break;
+ case CONS_CHAR_TTEE:
+ *achr = ACS_TTEE;
+ break;
+ case CONS_CHAR_VLINE:
+ *achr = ACS_VLINE;
+ break;
+ case CONS_CHAR_LEQUAL:
+ *achr = ACS_LEQUAL;
+ break;
+ case CONS_CHAR_GEQUAL:
+ *achr = ACS_GEQUAL;
+ break;
+ case CONS_CHAR_PI:
+ *achr = ACS_PI;
+ break;
+ case CONS_CHAR_NEQUAL:
+ *achr = ACS_NEQUAL;
+ break;
+ case CONS_CHAR_STERLING:
+ *achr = ACS_STERLING;
+ break;
+ case CONS_CHAR_BULLET:
+ *achr = ACS_BULLET;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static any_t
+input_loop (any_t unused)
+{
+ int fd = 0;
+ fd_set rfds;
+ int w_escaped = 0;
+
+ FD_ZERO (&rfds);
+ FD_SET (fd, &rfds);
+
+ while (1)
+ {
+ int ret;
+
+ FD_SET (fd, &rfds);
+
+ ret = select (fd + 1, &rfds, 0, 0, 0);
+ if (ret == 1)
+ {
+ char buffer[100];
+ char *buf = buffer;
+ size_t size = 0;
+
+ mutex_lock (&ncurses_lock);
+ while ((ret = getch ()) != ERR)
+ {
+ int i;
+ int found;
+
+ if (w_escaped)
+ {
+ switch (ret)
+ {
+ case 'x':
+ endwin ();
+ exit (0);
+ break;
+ case 23: /* ^W */
+ assert (size < 100);
+ buf[size++] = ret;
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ /* Avoid a dead lock. */
+ mutex_unlock (&ncurses_lock);
+ console_switch (1 + (ret - '1'), 0);
+ mutex_lock (&ncurses_lock);
+ break;
+ default:
+ break;
+ }
+ w_escaped = 0;
+ }
+ else
+ switch (ret)
+ {
+ case 23: /* ^W */
+ w_escaped = 1;
+ break;
+ default:
+ found = 0;
+ for (i =0; i < sizeof(keycodes) / sizeof(keycodes[0]); i++)
+ {
+ if (keycodes[i].curses == ret)
+ {
+ if (keycodes[i].cons)
+ {
+ assert (size < 101 - strlen(keycodes[i].cons));
+ strcpy (&buf[size], keycodes[i].cons);
+ size += strlen (keycodes[i].cons);
+ }
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ {
+ assert (size < 100);
+ buf[size++] = ret;
+ }
+ break;
+ }
+ }
+ mutex_unlock (&ncurses_lock);
+ if (size)
+ console_input (buf, size);
+ }
+ }
+}
+
+static inline attr_t
+conchar_attr_to_attr (conchar_attr_t attr)
+{
+ return ((attr.intensity == CONS_ATTR_INTENSITY_BOLD
+ ? A_BOLD : (attr.intensity == CONS_ATTR_INTENSITY_DIM
+ ? A_DIM : A_NORMAL))
+ | (attr.underlined ? A_UNDERLINE : 0)
+ | (attr.reversed ? A_REVERSE : 0)
+ | (attr.blinking ? A_BLINK: 0)
+ | (attr.concealed ? A_INVIS : 0));
+}
+
+static inline short
+conchar_attr_to_color_pair (conchar_attr_t attr)
+{
+ return COLOR_PAIR (attr.bgcol << 3 | attr.fgcol);
+}
+
+static void
+mvwputsn (conchar_t *str, size_t len, off_t x, off_t y)
+{
+ cchar_t chr;
+ wchar_t wch[2] = { L'\0', L'\0' };
+ uint32_t last_attr = * (uint32_t *) &str->attr;
+ attr_t attr = conchar_attr_to_attr (str->attr);
+ short color_pair = conchar_attr_to_color_pair (str->attr);
+
+ move (y, x);
+ while (len)
+ {
+ int ret;
+ chtype ac;
+
+ if (last_attr != *(uint32_t *) &str->attr)
+ {
+ last_attr = * (uint32_t *) &str->attr;
+ attr = conchar_attr_to_attr (str->attr);
+ color_pair = conchar_attr_to_color_pair (str->attr);
+ }
+
+ if (ucs4_to_altchar (str->chr, &ac))
+ addch (ac | attr | color_pair);
+ else
+ {
+ wch[0] = str->chr;
+ ret = setcchar (&chr, wch, attr, color_pair, NULL);
+#if 0
+ if (ret == ERR)
+ {
+ printf ("setcchar failed: %s\n", strerror (errno));
+ printf ("[%lc]\n", wch[0]);
+ assert (!"Do something if setcchar fails.");
+ }
+#endif
+ ret = add_wch (&chr);
+#if 0
+ if (ret == ERR)
+ {
+ printf ("add_wch failed: %i, %s\n", ret, strerror (errno));
+ printf ("[%lc]\n", wch[0]);
+ assert (!"Do something if add_wchr fails.");
+ }
+#endif
+ }
+ len--;
+ str++;
+ }
+}
+
+
+static error_t
+ncursesw_update (void *handle)
+{
+ mutex_lock (&ncurses_lock);
+ refresh ();
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_set_cursor_pos (void *handle, uint32_t col, uint32_t row)
+{
+ mutex_lock (&ncurses_lock);
+ move (row, col);
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_set_cursor_status (void *handle, uint32_t status)
+{
+ mutex_lock (&ncurses_lock);
+ curs_set (status ? (status == 1 ? 1 : 2) : 0);
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_scroll (void *handle, int delta)
+{
+ /* XXX We don't support scrollback for now. */
+ assert (delta >= 0);
+
+ mutex_lock (&ncurses_lock);
+ idlok (stdscr, TRUE);
+ scrollok (stdscr, TRUE);
+ scrl (delta);
+ idlok (stdscr, FALSE);
+ scrollok (stdscr, FALSE);
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_write (void *handle, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row)
+{
+ int x;
+ int y;
+
+ mutex_lock (&ncurses_lock);
+ getyx (stdscr, y, x);
+ mvwputsn (str, length, col, row);
+ wmove (stdscr, y, x);
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+static error_t
+ncursesw_flash (void *handle)
+{
+ mutex_lock (&ncurses_lock);
+ flash ();
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+/* Bell driver operations. */
+error_t
+ncursesw_beep (void *handle)
+{
+ mutex_lock (&ncurses_lock);
+ beep ();
+ mutex_unlock (&ncurses_lock);
+ return 0;
+}
+
+
+
+static error_t
+ncursesw_driver_init (void **handle, int no_exit,
+ int argc, char *argv[], int *next)
+{
+ mutex_init (&ncurses_lock);
+ return 0;
+}
+
+static error_t
+ncursesw_driver_start (void *handle)
+{
+ error_t err;
+ int i;
+
+ initscr ();
+ start_color ();
+ for (i = 0; i < 64; i++)
+ init_pair (i, i & 7, i >> 3);
+ raw ();
+ noecho ();
+ nonl ();
+ intrflush (stdscr, FALSE);
+ nodelay (stdscr, TRUE);
+ timeout (1);
+ keypad (stdscr, TRUE);
+
+ err = driver_add_display (&ncursesw_display_ops, NULL);
+ if (err)
+ {
+ endwin ();
+ return err;
+ }
+ err = driver_add_input (&ncursesw_input_ops, NULL);
+ if (err)
+ {
+ err = driver_remove_display (&ncursesw_display_ops, NULL);
+ endwin ();
+ return err;
+ }
+ err = driver_add_bell (&ncursesw_bell_ops, NULL);
+ if (err)
+ {
+ err = driver_remove_input (&ncursesw_input_ops, NULL);
+ err = driver_remove_display (&ncursesw_display_ops, NULL);
+ endwin ();
+ return err;
+ }
+
+ cthread_detach (cthread_fork (input_loop, NULL));
+ endwin ();
+
+ return err;
+}
+
+/* Destroy the display HANDLE. */
+static error_t
+ncursesw_driver_fini (void *handle, int force)
+{
+ /* XXX Cancel the input thread. */
+ mutex_lock (&ncurses_lock);
+ driver_remove_display (&ncursesw_display_ops, NULL);
+ driver_remove_input (&ncursesw_input_ops, NULL);
+ driver_remove_bell (&ncursesw_bell_ops, NULL);
+ mutex_unlock (&ncurses_lock);
+
+ endwin ();
+ return 0;
+}
+
+
+struct driver_ops driver_ncursesw_ops =
+ {
+ ncursesw_driver_init,
+ ncursesw_driver_start,
+ ncursesw_driver_fini,
+ };
+
+static struct display_ops ncursesw_display_ops =
+ {
+ ncursesw_set_cursor_pos,
+ ncursesw_set_cursor_status,
+ ncursesw_scroll,
+ ncursesw_write,
+ ncursesw_update,
+ ncursesw_flash,
+ NULL
+ };
+
+static struct input_ops ncursesw_input_ops =
+ {
+ NULL,
+ NULL
+ };
+
+static struct bell_ops ncursesw_bell_ops =
+ {
+ ncursesw_beep,
+ NULL
+ };
diff --git a/console-client/pc-kbd.c b/console-client/pc-kbd.c
new file mode 100644
index 00000000..3ec6404e
--- /dev/null
+++ b/console-client/pc-kbd.c
@@ -0,0 +1,824 @@
+/* pc-kbd.c - The PC Keyboard input driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <iconv.h>
+#include <sys/mman.h>
+
+#include <device/device.h>
+#include <cthreads.h>
+
+#include <hurd/console.h>
+#include <hurd/cons.h>
+
+#include "driver.h"
+
+
+/* The keyboard device in the kernel. */
+static device_t kbd_dev;
+
+/* The converter. */
+static iconv_t cd;
+
+/* Forward declaration. */
+static struct input_ops pc_kbd_ops;
+
+
+/* A list of scan codes generated by the keyboard. */
+enum scancode
+ {
+ SC_ESC = 0x01,
+ SC_1 = 0x02,
+ SC_2 = 0x03,
+ SC_3 = 0x04,
+ SC_4 = 0x05,
+ SC_5 = 0x06,
+ SC_6 = 0x07,
+ SC_7 = 0x08,
+ SC_8 = 0x09,
+ SC_9 = 0x0A,
+ SC_0 = 0x0B,
+ SC_MINUS = 0x0C, /* - */
+ SC_EQUAL = 0x0D, /* = */
+ SC_BACKSPACE = 0x0E,
+ SC_TAB = 0x0F,
+ SC_Q = 0x10,
+ SC_W = 0x11,
+ SC_E = 0x12,
+ SC_R = 0x13,
+ SC_T = 0x14,
+ SC_Y = 0x15,
+ SC_U = 0x16,
+ SC_I = 0x17,
+ SC_O = 0x18,
+ SC_P = 0x19,
+ SC_LEFT_BRACKET = 0x1A, /* [ */
+ SC_RIGHT_BRACKET = 0x1B, /* ] */
+ SC_ENTER = 0x1C,
+ SC_LEFT_CTRL = 0x1D,
+ SC_A = 0x1E,
+ SC_S = 0x1F,
+ SC_D = 0x20,
+ SC_F = 0x21,
+ SC_G = 0x22,
+ SC_H = 0x23,
+ SC_J = 0x24,
+ SC_K = 0x25,
+ SC_L = 0x26,
+ SC_SEMICOLON = 0x27, /* ; */
+ SC_APOSTROPHE = 0x28, /* ' */
+ SC_BACKQUOTE = 0x29, /* ` */
+ SC_LEFT_SHIFT = 0x2A,
+ SC_BACKSLASH = 0x2B, /* \ */
+ SC_Z = 0x2C,
+ SC_X = 0x2D,
+ SC_C = 0x2E,
+ SC_V = 0x2F,
+ SC_B = 0x30,
+ SC_N = 0x31,
+ SC_M = 0x32,
+ SC_COMMA = 0x33, /* , */
+ SC_PERIOD = 0x34, /* . */
+ SC_SLASH = 0x35, /* / */
+ SC_RIGHT_SHIFT = 0x36,
+ SC_PAD_ASTERISK = 0x37,
+ SC_LEFT_ALT = 0x38,
+ SC_SPACE = 0x39,
+ SC_CAPSLOCK = 0x3A,
+ SC_F1 = 0x3B,
+ SC_F2 = 0x3C,
+ SC_F3 = 0x3D,
+ SC_F4 = 0x3E,
+ SC_F5 = 0x3F,
+ SC_F6 = 0x40,
+ SC_F7 = 0x41,
+ SC_F8 = 0x42,
+ SC_F9 = 0x43,
+ SC_F10 = 0x44,
+ SC_NUMLOCK = 0x45,
+ SC_SCROLLLOCK = 0x46,
+ SC_PAD_7 = 0x47,
+ SC_PAD_8 = 0x48,
+ SC_PAD_9 = 0x49,
+ SC_PAD_MINUS = 0x4A,
+ SC_PAD_4 = 0x4B,
+ SC_PAD_5 = 0x4C,
+ SC_PAD_6 = 0x4D,
+ SC_PAD_PLUS = 0x4E,
+ SC_PAD_1 = 0x4F,
+ SC_PAD_2 = 0x50,
+ SC_PAD_3 = 0x51,
+ SC_PAD_0 = 0x52,
+ SC_PAD_DECIMAL = 0x53,
+ SC_SYSREQ = 0x54,
+ SC_F11 = 0x57,
+ SC_F12 = 0x58,
+ SC_FLAG_UP = 0x80, /* ORed to basic scancode. */
+ SC_EXTENDED1 = 0xE0, /* One code follows. */
+ SC_EXTENDED2 = 0xE1, /* Two codes follow (only used for Pause). */
+ SC_ERROR = 0xFF /* Too many keys held down. */
+ };
+
+/* Codes which can follow SC_EXTENDED1. */
+enum scancode_x1
+ {
+ SC_X1_PAD_ENTER = 0x1C,
+ SC_X1_RIGHT_CTRL = 0x1D,
+ SC_X1_PAD_SLASH = 0x35,
+ SC_X1_PRTSC = 0x37,
+ SC_X1_RIGHT_ALT = 0x38,
+ SC_X1_BREAK = 0x46,
+ SC_X1_HOME = 0x47,
+ SC_X1_UP = 0x48,
+ SC_X1_PGUP = 0x49,
+ SC_X1_LEFT = 0x4B,
+ SC_X1_RIGHT = 0x4D,
+ SC_X1_END = 0x4F,
+ SC_X1_DOWN = 0x50,
+ SC_X1_PGDN = 0x51,
+ SC_X1_INS = 0x52,
+ SC_X1_DEL = 0x53
+ };
+
+
+/* Scancode to Unicode mapping. The empty string stands for the NULL
+ character. */
+char *sc_to_kc[][7] =
+ {
+ /*None, Shift, Ctrl, LAlt, S+LAlt, C+LAlt, RAlt */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "\e", "\e", "\e", "\e\e", "\e\e", "\e\e", "\e" }, /* SC_ESC. */
+ { "1", "!", 0, "\e1", "\e!", 0, "1" }, /* SC_1. */
+ { "2", "@", "", "\e2", "\e@", 0, "2" }, /* SC_2. */
+ { "3", "#", "\e", "\e3", "\e#", 0, "3" }, /* SC_3. */
+ { "4", "$", "\x1c", "\e4", "\e$", "\e\x1c", "4" }, /* SC_4. */
+ { "5", "%", "\x1d", "\e5", "\e%", 0, "5" }, /* SC_5. */
+ { "6", "^", "\x1e", "\e6", "\e^", 0, "6" }, /* SC_6. */
+ { "7", "&", "\x1f", "\e7", "\e&", "\e\x1f", "7" }, /* SC_7. */
+ { "8", "*", "\x7f", "\e8", "\e*", 0, "8" }, /* SC_8. */
+ { "9", "(", 0, "\e9", "\e(", 0, "9" }, /* SC_9. */
+ { "0", ")", 0, "\e0", "\e)", 0, "0" }, /* SC_0. */
+ { "-", "_", "\x1f", "\e-", "\e_", "\e\x1f", "-" }, /* SC_MINUS. */
+ { "=", "+", 0, "\e=", "\e+", 0, "=" }, /* SC_EQUAL. */
+ { CONS_KEY_BACKSPACE, CONS_KEY_BACKSPACE, CONS_KEY_BACKSPACE, /* XXX */ 0,
+ CONS_KEY_BACKSPACE, /*XXX*/ 0, CONS_KEY_BACKSPACE }, /* SC_BACKSPACE. */
+ /* XXX back tab? */
+ { "\t", "\t", "\t", "\e\t", "\e\t", "\e\t", "\t" }, /* SC_TAB. */
+ { "q", "Q", "\x11", "\eq", "\eQ", "\e\x11", "q" }, /* SC_Q. */
+ { "w", "W", "\x17", "\ew", "\eW", "\e\x17", "w" }, /* SC_W. */
+ { "e", "E", "\x05", "\ee", "\eE", "\e\x05","\xe2\x82\xac" }, /* SC_E. */
+ { "r", "R", "\x12", "\er", "\eR", "\e\x12", "r" }, /* SC_R. */
+ { "t", "T", "\x14", "\et", "\eT", "\e\x14", "t" }, /* SC_T. */
+ { "y", "Y", "\x19", "\ey", "\eY", "\e\x19", "y" }, /* SC_Y. */
+ { "u", "U", "\x15", "\eu", "\eU", "\e\x15", "u" }, /* SC_U. */
+ { "i", "I", "\x09", "\ei", "\eI", "\e\x09", "i" }, /* SC_I. */
+ { "o", "O", "\x0f", "\eo", "\eO", "\e\x0f", "o" }, /* SC_O. */
+ { "p", "P", "\x10", "\ep", "\eP", "\e\x10", "p" }, /* SC_P. */
+ { "[", "{", "\e", "\e[", "\e{", 0, 0 }, /* SC_LEFT_BRACKET. */
+ { "]", "}", "\x1d", "\e]", "\e}", "\e\x1d", "~" }, /* SC_RIGHT_BRACKET. */
+ {"\x0d","\x0d", "\x0d","\e\x0d","\e\x0d","\e\x0d","\x0d" }, /* SC_ENTER. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_CTRL. XXX */
+ { "a", "A", "\x01", "\ea", "\eA", "\e\x01", "a" }, /* SC_A. */
+ { "s", "S", "\x13", "\es", "\eS", "\e\x13", "s" }, /* SC_S. */
+ { "d", "D", "\x04", "\ed", "\eD", "\e\x04", "d" }, /* SC_D. */
+ { "f", "F", "\x06", "\ef", "\eF", "\e\x06", "f" }, /* SC_F. */
+ { "g", "G", "\x07", "\eg", "\eG", "\e\x07", "g" }, /* SC_G. */
+ { "h", "H", "\x08", "\eh", "\eH", "\e\x08", "h" }, /* SC_H. */
+ { "j", "J", "\x0a", "\ej", "\eJ", "\e\x0a", "j" }, /* SC_J. */
+ { "k", "K", "\x0b", "\ek", "\eK", "\e\x0b", "k" }, /* SC_K. */
+ { "l", "L", "\x0c", "\el", "\eL", "\e\x0c", "l" }, /* SC_L. */
+ { ";", ":", 0, "\e;", "\e:", 0, 0 }, /* SC_SEMICOLON. */
+ { "'", "\"", "\x07", "\e'", "\e\"", 0, 0 }, /* SC_APOSTROPHE. */
+ { "`", "~", 0, "\e`", "\e~", 0, 0 }, /* SC_BACKQUOTE. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_SHIFT. */
+ { "\\", "|", "\x1c", "\e\\", "\e|", 0, 0 }, /* SC_BACKSLASH. */
+ { "z", "Z", "\x1a", "\ez", "\eZ", "\e\x1a", "z" }, /* SC_Z. */
+ { "x", "X", "\x18", "\ex", "\eX", "\e\x18", "x" }, /* SC_X. */
+ { "c", "C", "\x03", "\ec", "\eC", "\e\x03", "\xc2\xa2" }, /* SC_C. */
+ { "v", "V", "\x16", "\ev", "\eV", "\e\x16", "v" }, /* SC_V. */
+ { "b", "B", "\x02", "\eb", "\eB", "\e\x02", "b" }, /* SC_B. */
+ { "n", "N", "\x0e", "\en", "\eN", "\e\x0e", "n" }, /* SC_N. */
+ { "m", "M", "\x0d", "\em", "\eM", "\e\x0d", "m" }, /* SC_M. */
+ { ",", "<", 0, "\e,", "\e<", 0, 0 }, /* SC_COMMA. */
+ { ".", ">", 0, "\e.", "\e>", 0, 0 }, /* SC_PERIOD. */
+ { "/", "?", "\x7f", "\e/", "\e?", 0, 0 }, /* SC_SLASH. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_RIGHT_SHIFT. */
+ { "*", "*", "*", "*", "*", "*", "*" }, /* SC_PAD_ASTERISK. XXX */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_LEFT_ALT. XXX */
+ { " ", " ", "", "\e ", "\e ", /*XXX*/0, " " }, /* SC_SPACE. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_CAPSLOCK. */
+ { CONS_KEY_F1, CONS_KEY_F13, 0, 0, 0, 0, 0 }, /* SC_F1. */
+ { CONS_KEY_F2, CONS_KEY_F14, 0, 0, 0, 0, 0 }, /* SC_F2. */
+ { CONS_KEY_F3, CONS_KEY_F15, 0, 0, 0, 0, 0 }, /* SC_F3. */
+ { CONS_KEY_F4, CONS_KEY_F16, 0, 0, 0, 0, 0 }, /* SC_F4. */
+ { CONS_KEY_F5, CONS_KEY_F17, 0, 0, 0, 0, 0 }, /* SC_F5. */
+ { CONS_KEY_F6, CONS_KEY_F18, 0, 0, 0, 0, 0 }, /* SC_F6. */
+ { CONS_KEY_F7, CONS_KEY_F19, 0, 0, 0, 0, 0 }, /* SC_F7. */
+ { CONS_KEY_F8, CONS_KEY_F20, 0, 0, 0, 0, 0 }, /* SC_F8. */
+ { CONS_KEY_F9, 0, 0, 0, 0, 0, 0 }, /* SC_F9. */
+ { CONS_KEY_F10, 0, 0, 0, 0, 0, 0 }, /* SC_F10. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_NUMLOCK. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_SCROLLLOCK. */
+ { CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME, 0, 0, 0, 0 }, /* SC_PAD_7. */
+ { CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP, 0, 0, 0, 0 }, /* SC_PAD_8. */
+ { CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE,0, 0, 0, 0 }, /* SC_PAD_9. */
+ { "-", "-", "-", "-", "-", "-", "-" }, /* SC_PAD_MINUS. */
+ { CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT, 0, 0, 0, 0 }, /* SC_PAD_4. */
+ {/* XXX */ "\e[G", "\e[G", "\e[G", 0, 0, 0, 0 }, /* SC_PAD_5. */
+ { CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT,0, 0, 0, 0 }, /* SC_PAD_6. */
+ { "+", "+", "+", "+", "+", "+", "+" }, /* SC_PAD_MINUS. */
+ { CONS_KEY_END, CONS_KEY_END, CONS_KEY_END, 0, 0, 0, 0 }, /* SC_PAD_1. */
+ { CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN, 0, 0, 0, 0 }, /* SC_PAD_2. */
+ { CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE,0, 0, 0, 0 }, /* SC_PAD_3. */
+ { CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC, 0, 0, 0, 0 }, /* SC_PAD_0. */
+ { CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC, 0, 0, 0, 0 }, /* SC_PAD_DECIMAL. */
+ { 0, 0, /*XX*/0, 0, 0, 0, 0 }, /* SC_SYSREQ. */
+ { CONS_KEY_F11, 0, 0, 0, 0, 0, 0 }, /* SC_F11. */
+ { CONS_KEY_F12, 0, 0, 0, 0, 0, 0 } /* SC_F12. */
+ };
+
+char *sc_x1_to_kc[][7] =
+ {
+ /* None, Shift, Ctrl, LAlt, S+LAlt, C+LAlt, RAlt */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { "\n", "\n", "\n", "\n", "\n", "\n", 0 }, /* SC_X1_PAD_ENTER. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_RIGHT_CTRL. */
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { "/", "/", "/", "/", "/", "/", 0 }, /* SC_X1_PAD_SLASH. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_PRTSC. */
+ { 0, 0, 0, 0, 0, 0, 0 }, /* SC_X1_RIGHT_ALT. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 },
+ { "\e[P", "\e[P", "\e[P", "\e[P", "\e[P", "\e[P","\e[P" }, /* SC_X1_BREAK. */
+ { CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME,
+ CONS_KEY_HOME, CONS_KEY_HOME, CONS_KEY_HOME }, /* SC_X1_HOME. */
+ { CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP,
+ CONS_KEY_UP, CONS_KEY_UP, CONS_KEY_UP }, /* SC_X1_UP. */
+ { CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE,
+ CONS_KEY_PPAGE, CONS_KEY_PPAGE, CONS_KEY_PPAGE }, /* SC_X1_PGUP. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT,
+ CONS_KEY_LEFT, CONS_KEY_LEFT, CONS_KEY_LEFT }, /* SC_X1_LEFT. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT,
+ CONS_KEY_RIGHT, CONS_KEY_RIGHT, CONS_KEY_RIGHT }, /* SC_X1_RIGHT. */
+ { 0, 0, 0, 0, 0, 0, 0 },
+ { CONS_KEY_END, CONS_KEY_END, CONS_KEY_END, CONS_KEY_END,
+ CONS_KEY_END, CONS_KEY_END, CONS_KEY_END }, /* SC_X1_END. */
+ { CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN,
+ CONS_KEY_DOWN, CONS_KEY_DOWN, CONS_KEY_DOWN }, /* SC_X1_DOWN. */
+ { CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE,
+ CONS_KEY_NPAGE, CONS_KEY_NPAGE, CONS_KEY_NPAGE }, /* SC_X1_PGDN. */
+ { CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC,
+ CONS_KEY_IC, CONS_KEY_IC, CONS_KEY_IC }, /* SC_X1_INS. */
+ { CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC,
+ CONS_KEY_DC, CONS_KEY_DC, CONS_KEY_DC } /* SC_X1_DEL. */
+ };
+
+
+/* This gross stuff is cut & pasted from Mach sources, as Mach doesn't
+ export the interface we are using here. */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+
+typedef u_short kev_type; /* kd event type */
+
+/* (used for event records) */
+struct mouse_motion {
+ short mm_deltaX; /* units? */
+ short mm_deltaY;
+};
+typedef u_char Scancode;
+
+typedef struct {
+ kev_type type; /* see below */
+ struct timeval time; /* timestamp */
+ union { /* value associated with event */
+ boolean_t up; /* MOUSE_LEFT .. MOUSE_RIGHT */
+ Scancode sc; /* KEYBD_EVENT */
+ struct mouse_motion mmotion; /* MOUSE_MOTION */
+ } value;
+} kd_event;
+#define m_deltaX mmotion.mm_deltaX
+#define m_deltaY mmotion.mm_deltaY
+
+/*
+ * kd_event ID's.
+ */
+#define MOUSE_LEFT 1 /* mouse left button up/down */
+#define MOUSE_MIDDLE 2
+#define MOUSE_RIGHT 3
+#define MOUSE_MOTION 4 /* mouse motion */
+#define KEYBD_EVENT 5 /* key up/down */
+
+
+#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */
+#define IOC_OUT 0x40000000 /* copy out parameters */
+#define IOC_IN 0x80000000U /* copy in parameters */
+#define _IOC(inout,group,num,len) \
+ (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))
+#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
+#define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t))
+
+#define KDSKBDMODE _IOW('K', 1, int) /* set keyboard mode */
+#define KB_EVENT 1
+#define KB_ASCII 2
+
+#define KDGKBDTYPE _IOR('K', 2, int) /* get keyboard type */
+#define KB_VANILLAKB 0
+
+/* End of Mach code. */
+
+
+/* The input loop. */
+static any_t
+input_loop (any_t unused)
+{
+ while (1)
+ {
+ kd_event data_buf;
+
+ /* io_buf_ptr_t is (char *), not (void *). So I have a few
+ casts to quiet warnings. */
+ io_buf_ptr_t data_ptr = (void *) &data_buf;
+ mach_msg_type_number_t data_cnt = sizeof data_buf;
+
+ /* I suppose this could be sped up by reading multiple events
+ per call. But that isn't important since this is called just
+ a couple of times per keystroke. Things might be different
+ if we supported a mouse. */
+ error_t err = device_read (kbd_dev, /* device */
+ 0, /* mode: could be D_NOWAIT */
+ -1, /* recnum: not used by kbdread */
+ sizeof (kd_event), /* bytes_wanted */
+ &data_ptr, &data_cnt);
+ if (err)
+ /* XXX The error occured likely because KBD_DEV was closed, so
+ terminate. */
+ return 0;
+
+ if ((void *) data_ptr != &data_buf)
+ {
+ /* Copy the structure to the expected place. */
+ data_buf = *(kd_event *) data_ptr;
+ munmap (data_ptr, data_cnt);
+ }
+
+ if (data_buf.type == KEYBD_EVENT)
+ {
+ enum scancode fsc = data_buf.value.sc;
+ enum scancode sc = fsc & 0x7f;
+ int down = !(fsc & SC_FLAG_UP);
+ char buf[100];
+ size_t size = 0;
+ int modifier = -1;
+
+ static struct {
+ wchar_t direct;
+ unsigned int extended : 2;
+ unsigned int left_shift : 1;
+ unsigned int right_shift : 1;
+ unsigned int caps_lock : 1;
+ unsigned int caps_lock_pressed : 1;
+ unsigned int left_ctrl : 1;
+ unsigned int right_ctrl : 1;
+ unsigned int left_alt : 1;
+ unsigned int right_alt : 1;
+ unsigned int num_lock : 1;
+ unsigned int num_lock_pressed : 1;
+ } state;
+
+ if (!state.left_alt && !state.right_alt)
+ {
+ if (state.left_ctrl || state.right_ctrl)
+ modifier = 2;
+ else if (state.left_shift || state.right_shift)
+ modifier = 1;
+ else
+ modifier = 0;
+ }
+ else if (state.left_alt)
+ {
+ if (state.left_ctrl || state.right_ctrl)
+ modifier = 5;
+ if (state.left_shift || state.right_shift)
+ modifier = 4;
+ else
+ modifier = 3;
+ }
+ else if (state.right_alt)
+ {
+ if (!state.left_ctrl && !state.right_ctrl
+ && !state.left_shift && !state.right_shift)
+ modifier = 6;
+ }
+
+ if (!state.extended)
+ {
+ if (fsc == SC_EXTENDED1)
+ state.extended = 1;
+ else if (fsc == SC_EXTENDED2)
+ state.extended = 2;
+ else if (sc == SC_LEFT_SHIFT)
+ state.left_shift = down;
+ else if (sc == SC_RIGHT_SHIFT)
+ state.right_shift = down;
+ else if (sc == SC_CAPSLOCK)
+ {
+ if (down && !state.caps_lock_pressed)
+ {
+ state.caps_lock = !state.caps_lock;
+ state.caps_lock_pressed = 1;
+ }
+ else if (!down)
+ state.caps_lock_pressed = 0;
+ }
+ else if (sc == SC_NUMLOCK)
+ {
+ if (down && !state.num_lock_pressed)
+ {
+ state.num_lock = !state.num_lock;
+ state.num_lock_pressed = 1;
+ }
+ else if (!down)
+ state.num_lock_pressed = 0;
+ }
+ else if (sc == SC_LEFT_CTRL)
+ state.left_ctrl = down;
+ else if (sc == SC_LEFT_ALT)
+ state.left_alt = down;
+ else if (state.left_alt && down && sc >= SC_F1 && sc <= SC_F10) /* XXX */
+ console_switch (1 + (sc - SC_F1), 0);
+ else if (state.left_alt && state.left_ctrl && down && sc == SC_BACKSPACE)
+ console_exit ();
+ else if (state.right_alt && down && sc == SC_PAD_0) /* XXX */
+ state.direct = (state.direct << 4) | 0x0;
+ else if (state.right_alt && down && sc == SC_PAD_1) /* XXX */
+ state.direct = (state.direct << 4) | 0x1;
+ else if (state.right_alt && down && sc == SC_PAD_2) /* XXX */
+ state.direct = (state.direct << 4) | 0x2;
+ else if (state.right_alt && down && sc == SC_PAD_3) /* XXX */
+ state.direct = (state.direct << 4) | 0x3;
+ else if (state.right_alt && down && sc == SC_PAD_4) /* XXX */
+ state.direct = (state.direct << 4) | 0x4;
+ else if (state.right_alt && down && sc == SC_PAD_5) /* XXX */
+ state.direct = (state.direct << 4) | 0x5;
+ else if (state.right_alt && down && sc == SC_PAD_6) /* XXX */
+ state.direct = (state.direct << 4) | 0x6;
+ else if (state.right_alt && down && sc == SC_PAD_7) /* XXX */
+ state.direct = (state.direct << 4) | 0x7;
+ else if (state.right_alt && down && sc == SC_PAD_8) /* XXX */
+ state.direct = (state.direct << 4) | 0x8;
+ else if (state.right_alt && down && sc == SC_PAD_9) /* XXX */
+ state.direct = (state.direct << 4) | 0x9;
+ else if (state.right_alt && down && sc == SC_NUMLOCK) /* XXX */
+ state.direct = (state.direct << 4) | 0xa;
+ else if (state.right_alt && down && sc == SC_PAD_ASTERISK) /* XXX */
+ state.direct = (state.direct << 4) | 0xc;
+ else if (state.right_alt && down && sc == SC_PAD_MINUS) /* XXX */
+ state.direct = (state.direct << 4) | 0xd;
+ else if (state.right_alt && down && sc == SC_PAD_PLUS) /* XXX */
+ state.direct = (state.direct << 4) | 0xe;
+ else if (down && sc < sizeof (sc_to_kc)/sizeof (sc_to_kc[0]))
+ {
+#if QUAERENDO_INVENIETIS
+ if (state.left_alt && state.right_alt
+ && sc_to_kc[sc][0][0] >= '0' && sc_to_kc[sc][0][0] <= '9'
+ && sc_to_kc[sc][0][1] == '\0')
+ console_deprecated (sc_to_kc[sc][0][0] - '0');
+ else
+#endif
+ {
+ /* Special rule for caps lock. */
+ if (modifier == 0 && state.caps_lock
+ && sc_to_kc[sc][modifier]
+ && sc_to_kc[sc][modifier][0] >= 'a'
+ && sc_to_kc[sc][modifier][0] <= 'z'
+ && sc_to_kc[sc][modifier][1] == '\0')
+ modifier = 1;
+ else if (state.num_lock && sc == SC_PAD_0)
+ {
+ modifier = 0;
+ sc = SC_0;
+ }
+ else if (state.num_lock && sc == SC_PAD_1)
+ {
+ modifier = 0;
+ sc = SC_1;
+ }
+ else if (state.num_lock && sc == SC_PAD_2)
+ {
+ modifier = 0;
+ sc = SC_2;
+ }
+ else if (state.num_lock && sc == SC_PAD_3)
+ {
+ modifier = 0;
+ sc = SC_3;
+ }
+ else if (state.num_lock && sc == SC_PAD_4)
+ {
+ modifier = 0;
+ sc = SC_4;
+ }
+ else if (state.num_lock && sc == SC_PAD_5)
+ {
+ modifier = 0;
+ sc = SC_5;
+ }
+ else if (state.num_lock && sc == SC_PAD_6)
+ {
+ modifier = 0;
+ sc = SC_6;
+ }
+ else if (state.num_lock && sc == SC_PAD_7)
+ {
+ modifier = 0;
+ sc = SC_7;
+ }
+ else if (state.num_lock && sc == SC_PAD_8)
+ {
+ modifier = 0;
+ sc = SC_8;
+ }
+ else if (state.num_lock && sc == SC_PAD_9)
+ {
+ modifier = 0;
+ sc = SC_9;
+ }
+ else if (state.num_lock && sc == SC_PAD_DECIMAL)
+ {
+ modifier = 0;
+ sc = SC_PERIOD;
+ }
+
+ if (modifier >= 0 && sc_to_kc[sc][modifier])
+ {
+ if (!sc_to_kc[sc][modifier][0])
+ {
+ /* Special meaning, emit NUL. */
+ assert (size < 100);
+ buf[size++] = '\0';
+ }
+ else
+ {
+ assert (size
+ < 101 - strlen(sc_to_kc[sc][modifier]));
+ strcpy (&buf[size], sc_to_kc[sc][modifier]);
+ size += strlen (sc_to_kc[sc][modifier]);
+ }
+ }
+ }
+ }
+ }
+ else if (state.extended == 1)
+ {
+ state.extended = 0;
+ if (sc == SC_X1_RIGHT_CTRL)
+ state.right_ctrl = down;
+ else if (sc == SC_X1_RIGHT_ALT)
+ {
+ state.right_alt = down;
+
+ /* Handle the AltGR+Keypad direct input. */
+ if (down)
+ state.direct = (wchar_t) 0;
+ else
+ {
+ if (state.direct != (wchar_t) 0)
+ {
+ char *buffer = &buf[size];
+ size_t left = sizeof (buf) - size;
+ char *inbuf = (char *) &state.direct;
+ size_t inbufsize = sizeof (wchar_t);
+ int nr;
+
+ nr = iconv (cd, &inbuf, &inbufsize, &buffer, &left);
+ if (nr == (size_t) -1)
+ {
+ if (errno == E2BIG)
+ console_error (L"Input buffer overflow");
+ else if (errno == EILSEQ)
+ console_error
+ (L"Input contained invalid byte sequence");
+ else if (errno == EINVAL)
+ console_error
+ (L"Input contained incomplete byte sequence");
+ else
+ console_error
+ (L"Input caused unexpected error");
+ }
+ size = sizeof (buf) - left;
+ }
+ }
+ }
+ else if (state.right_alt && down && sc == SC_X1_PAD_SLASH) /* XXX */
+ state.direct = (state.direct << 4) | 0xb;
+ else if (state.right_alt && down && sc == SC_X1_PAD_ENTER) /* XXX */
+ state.direct = (state.direct << 4) | 0xf;
+ else if (state.left_alt && down && sc == SC_X1_RIGHT) /* XXX */
+ console_switch (0, 1);
+ else if (state.left_alt && down && sc == SC_X1_LEFT) /* XXX */
+ console_switch (0, -1);
+ else if (state.left_alt && down && sc == SC_X1_UP) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_LINES, 1);
+ else if (state.left_alt && down && sc == SC_X1_DOWN) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_LINES, -1);
+ else if (state.right_shift && down && sc == SC_X1_PGUP) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_SCREENS, 0.5);
+ else if (state.right_shift && down && sc == SC_X1_PGDN) /* XXX */
+ console_scrollback (CONS_SCROLL_DELTA_SCREENS, -0.5);
+ else if (down && sc < sizeof (sc_x1_to_kc)/sizeof (sc_x1_to_kc[0]))
+ {
+ if (modifier >= 0 && sc_x1_to_kc[sc][modifier])
+ {
+ assert (size < 101 - strlen(sc_x1_to_kc[sc][modifier]));
+ strcpy (&buf[size], sc_x1_to_kc[sc][modifier]);
+ size += strlen (sc_x1_to_kc[sc][modifier]);
+ }
+ }
+ }
+ else if (state.extended == 2)
+ state.extended = 3;
+ else if (state.extended == 3)
+ state.extended = 0;
+
+ if (size)
+ console_input (buf, size);
+ }
+ }
+ return 0;
+}
+
+
+
+/* Initialize the PC keyboard driver. */
+static error_t
+pc_kbd_init (void **handle, int no_exit, int argc, char *argv[], int *next)
+{
+ return 0;
+}
+
+
+/* Start the PC keyboard driver. */
+static error_t
+pc_kbd_start (void *handle)
+{
+ error_t err;
+ device_t device_master;
+ int data[1];
+
+ cd = iconv_open ("UTF-8", "WCHAR_T");
+ if (cd == (iconv_t) -1)
+ return errno;
+
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ {
+ iconv_close (cd);
+ return err;
+ }
+
+ err = device_open (device_master, D_READ, "kbd", &kbd_dev);
+ mach_port_deallocate (mach_task_self (), device_master);
+ if (err)
+ {
+ iconv_close (cd);
+ return err;
+ }
+
+ data[0] = KB_EVENT;
+ err = device_set_status (kbd_dev, KDSKBDMODE, data, 1);
+ if (err)
+ {
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+ return err;
+ }
+
+ err = driver_add_input (&pc_kbd_ops, NULL);
+ if (err)
+ {
+ device_set_status (kbd_dev, KDSKBDMODE, data, 1);
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+ return err;
+ }
+ cthread_detach (cthread_fork (input_loop, NULL));
+
+ return 0;
+}
+
+/* Deinitialize the PC keyboard driver. */
+static error_t
+pc_kbd_fini (void *handle, int force)
+{
+ int data[1];
+
+ driver_remove_input (&pc_kbd_ops, NULL);
+ data[0] = KB_ASCII;
+ device_set_status (kbd_dev, KDSKBDMODE, data, 1);
+ device_close (kbd_dev);
+ mach_port_deallocate (mach_task_self (), kbd_dev);
+ iconv_close (cd);
+
+ return 0;
+}
+
+
+/* Set the scroll lock status indication (Scroll LED) to ONOFF. */
+static error_t
+pc_kbd_set_scroll_lock_status (void *handle, int onoff)
+{
+ /* XXX */
+ return 0;
+}
+
+
+struct driver_ops driver_pc_kbd_ops =
+ {
+ pc_kbd_init,
+ pc_kbd_start,
+ pc_kbd_fini
+ };
+
+static struct input_ops pc_kbd_ops =
+ {
+ pc_kbd_set_scroll_lock_status,
+ NULL
+ };
diff --git a/console-client/timer.c b/console-client/timer.c
new file mode 100644
index 00000000..7bcdeab0
--- /dev/null
+++ b/console-client/timer.c
@@ -0,0 +1,210 @@
+/* timer.c - A timer module for Mach.
+ Copyright (C) 1995,96,2000,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <string.h>
+#include <maptime.h>
+
+#include <cthreads.h>
+
+#include "timer.h"
+
+/* The value of fetch_jiffies() at startup. */
+long long timer_root_jiffies;
+
+/* The mapped time. */
+volatile struct mapped_time_value *timer_mapped_time;
+
+
+/* The timer thread. */
+static thread_t timer_thread;
+
+/* The lock protects the timer list TIMERS. */
+static struct mutex timer_lock;
+
+/* A list of all active timers. */
+static struct timer_list *timers;
+
+
+static inline void
+timer_add_internal (struct timer_list *timer)
+{
+ struct timer_list **tp;
+
+ for (tp = &timers; *tp; tp = &(*tp)->next)
+ if ((*tp)->expires > timer->expires)
+ {
+ timer->next = *tp;
+ timer->next->prev = &timer->next;
+ timer->prev = tp;
+ *tp = timer;
+ break;
+ }
+ if (!*tp)
+ {
+ timer->next = 0;
+ timer->prev = tp;
+ *tp = timer;
+ }
+}
+
+
+/* Make the timer thread aware of new timers at the beginning of the
+ list. */
+static inline void
+kick_timer_thread (void)
+{
+ /* XXX This is a whacky notion. */
+ while (!timer_thread)
+ swtch_pri (0);
+
+ if (timer_thread != mach_thread_self ())
+ {
+ thread_suspend (timer_thread);
+ thread_abort (timer_thread);
+ thread_resume (timer_thread);
+ }
+}
+
+/* The timer thread. */
+static int
+timer_function (int this_is_a_pointless_variable_with_a_rather_long_name)
+{
+ mach_port_t recv = mach_reply_port ();
+ int wait = 0;
+
+ timer_thread = mach_thread_self ();
+
+ mutex_lock (&timer_lock);
+ while (1)
+ {
+ int jiff = fetch_jiffies ();
+
+ if (!timers)
+ wait = -1;
+ else if (timers->expires < jiff)
+ wait = 0;
+ else
+ wait = ((timers->expires - jiff) * 1000) / HZ;
+
+ mutex_unlock (&timer_lock);
+ mach_msg (NULL, (MACH_RCV_MSG | MACH_RCV_INTERRUPT
+ | (wait == -1 ? 0 : MACH_RCV_TIMEOUT)),
+ 0, 0, recv, wait, MACH_PORT_NULL);
+ mutex_lock (&timer_lock);
+
+ while (timers && timers->expires < fetch_jiffies ())
+ {
+ struct timer_list *tp;
+
+ tp = timers;
+
+ timers = timers->next;
+ if (timers)
+ timers->prev = &timers;
+
+ tp->next = 0;
+ tp->prev = 0;
+
+ if ((*tp->fnc) (tp->fnc_data))
+ timer_add_internal (tp);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Initialize the timer component. Must be called once at startup. */
+error_t
+timer_init (void)
+{
+ error_t err;
+ struct timeval tp;
+
+ mutex_init (&timer_lock);
+
+ err = maptime_map (0, 0, &timer_mapped_time);
+ if (err)
+ return err;
+
+ maptime_read (timer_mapped_time, &tp);
+
+ timer_root_jiffies = (long long) tp.tv_sec * HZ
+ + ((long long) tp.tv_usec * HZ) / 1000000;
+
+ cthread_detach (cthread_fork ((cthread_fn_t) timer_function, 0));
+ return 0;
+}
+
+
+/* Initialize the timer TIMER. */
+void
+timer_clear (struct timer_list *timer)
+{
+ memset (timer, 0, sizeof (struct timer_list));
+}
+
+/* Add the timer TIMER to the list. */
+void
+timer_add (struct timer_list *timer)
+{
+ mutex_lock (&timer_lock);
+ timer_add_internal (timer);
+
+ if (timers == timer)
+ kick_timer_thread ();
+
+ mutex_unlock (&timer_lock);
+}
+
+/* Remove the timer TIMER from the list. */
+int
+timer_remove (struct timer_list *timer)
+{
+ mutex_lock (&timer_lock);
+ if (timer->prev)
+ {
+ *timer->prev = timer->next;
+ if (timer->next)
+ timer->next->prev = timer->prev;
+
+ timer->next = 0;
+ timer->prev = 0;
+ mutex_unlock (&timer_lock);
+ return 1;
+ }
+ else
+ {
+ mutex_unlock (&timer_lock);
+ return 0;
+ }
+}
+
+/* Change the expiration time of the timer TIMER to EXPIRES. */
+void
+timer_change (struct timer_list *timer, long long expires)
+{
+ /* XXX Should optimize this. */
+ timer_remove (timer);
+ timer->expires = expires;
+ timer_add (timer);
+}
+
diff --git a/console-client/timer.h b/console-client/timer.h
new file mode 100644
index 00000000..4204192e
--- /dev/null
+++ b/console-client/timer.h
@@ -0,0 +1,72 @@
+/* timer.h - Interface to a timer module for Mach.
+ Copyright (C) 1995,96,2000,02 Free Software Foundation, Inc.
+ Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _TIMER_H_
+#define _TIMER_H_
+
+#include <errno.h>
+#include <maptime.h>
+
+
+/* Initialize the timer component. Must be called once at startup. */
+error_t timer_init (void);
+
+/* The data structure of a timer. A user can set the values EXPIRES,
+ DATA and FUNCTION, and should leave the other fields alone. */
+struct timer_list
+{
+ struct timer_list *next, **prev; /* things like to test "T->prev != NULL" */
+ long long expires;
+
+ /* The function to be called when the timer expires. If the
+ function returns a non-zero value, the timer is put back on the
+ list. */
+ int (*fnc) (void *);
+ void *fnc_data;
+};
+
+/* Initialize the timer TIMER. */
+void timer_clear (struct timer_list *timer);
+
+/* Add the timer TIMER to the list. */
+void timer_add (struct timer_list *timer);
+
+/* Remove the timer TIMER from the list. */
+int timer_remove (struct timer_list *timer);
+
+/* Change the expiration time of the timer TIMER to EXPIRES. */
+void timer_change (struct timer_list *timer, long long expires);
+
+extern inline long long
+fetch_jiffies ()
+{
+ extern volatile struct mapped_time_value *timer_mapped_time;
+ extern long long timer_root_jiffies;
+ struct timeval tv;
+ long long j;
+
+ maptime_read (timer_mapped_time, &tv);
+
+#define HZ 100
+ j = (long long) tv.tv_sec * HZ + ((long long) tv.tv_usec * HZ) / 1000000;
+ return j - timer_root_jiffies;
+}
+
+#endif /* _TIMER_H_ */
diff --git a/console-client/unicode.h b/console-client/unicode.h
new file mode 100644
index 00000000..386628c9
--- /dev/null
+++ b/console-client/unicode.h
@@ -0,0 +1,350 @@
+/* unicode.h - A list of useful Unicode characters.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _UNICODE_H_
+#define _UNICODE_H_
+
+#define UNICODE_NO_BREAK_SPACE ((wchar_t) 0x00a0)
+#define UNICODE_INVERTED_EXCLAMATION_MARK ((wchar_t) 0x00a1)
+#define UNICODE_CENT_SIGN ((wchar_t) 0x00a2)
+#define UNICODE_POUND_SIGN ((wchar_t) 0x00a3)
+#define UNICODE_CURRENCY_SIGN ((wchar_t) 0x00a4)
+#define UNICODE_YEN_SIGN ((wchar_t) 0x00a5)
+#define UNICODE_BROKEN_BAR ((wchar_t) 0x00a6)
+#define UNICODE_BROKEN_VERTICAL_BAR UNICODE_BROKEN_BAR
+#define UNICODE_SECTION_SIGN ((wchar_t) 0x00a7)
+#define UNICODE_DIARESIS ((wchar_t) 0x00a8)
+#define UNICODE_COPYRIGHT_SIGN ((wchar_t) 0x00a9)
+#define UNICODE_FEMININE_ORDINAL_INDICATOR ((wchar_t) 0x00aa)
+#define UNICODE_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK ((wchar_t) 0x00ab)
+#define UNICODE_LEFT_POINTING_GUILLEMET \
+ UNICODE_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK
+#define UNICODE_NOT_SIGN ((wchar_t) 0x00ac)
+#define UNICODE_SOFT_HYPHEN ((wchar_t) 0x00ad)
+#define UNICODE_REGISTERED_SIGN ((wchar_t) 0x00ae)
+#define UNICODE_REGISTERED_TRADE_MARK_SIGN UNICODE_REGISTERED_SIGN
+#define UNICODE_MACRON ((wchar_t) 0x00af)
+#define UNICODE_DEGREE_SIGN ((wchar_t) 0x00b0)
+#define UNICODE_PLUS_MINUS_SIGN ((wchar_t) 0x00b1)
+#define UNICODE_SUPERSCRIPT_TWO ((wchar_t) 0x00b2)
+#define UNICODE_SUPERSCRIPT_THREE ((wchar_t) 0x00b3)
+#define UNICODE_ACUTE_ACCENT ((wchar_t) 0x00b4)
+#define UNICODE_MICRO_SIGN ((wchar_t) 0x00b5)
+#define UNICODE_PILCROW_SIGN ((wchar_t) 0x00b6)
+#define UNICODE_PARAGRAPH_SIGN UNICODE_PILCROW_SIGN
+#define UNICODE_MIDDLE_DOT ((wchar_t) 0x00b7)
+#define UNICODE_CEDILLA ((wchar_t) 0x00b8)
+#define UNICODE_SUPERSCRIPT_ONE ((wchar_t) 0x00b9)
+#define UNICODE_MASCULINE_ORDINAL_INDICATOR ((wchar_t) 0x00ba)
+#define UNICODE_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK ((wchar_t) 0x00bb)
+#define UNICODE_RIGHT_POINTING_GUILLEMET \
+ UNICODE_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK
+#define UNICODE_VULGAR_FRACTION_ONE_QUARTER ((wchar_t) 0x00bc)
+#define UNICODE_VULGAR_FRACTION_ONE_HALF ((wchar_t) 0x00bd)
+#define UNICODE_VULGAR_FRACTION_THREE_QUARTERS ((wchar_t) 0x00be)
+#define UNICODE_INVERTED_QUESTION_MARK ((wchar_t) 0x00bf)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_GRAVE ((wchar_t) 0x00c0)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_ACUTE ((wchar_t) 0x00c1)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_CIRCUMFLEX ((wchar_t) 0x00c2)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_TILDE ((wchar_t) 0x00c3)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_DIARESIS ((wchar_t) 0x00c4)
+#define UNICODE_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE ((wchar_t) 0x00c5)
+#define UNICODE_LATIN_CAPITAL_LETTER_AE ((wchar_t) 0x00c6)
+#define UNICODE_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA ((wchar_t) 0x00c7)
+#define UNICODE_LATIN_CAPITAL_LIGATURE_AE UNICODE_LATIN_CAPITAL_LETTER_AE
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_GRAVE ((wchar_t) 0x00c8)
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_ACUTE ((wchar_t) 0x00c9)
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_CIRCUMFLEX ((wchar_t) 0x00ca)
+#define UNICODE_LATIN_CAPITAL_LETTER_E_WITH_DIARESIS ((wchar_t) 0x00cb)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_GRAVE ((wchar_t) 0x00cc)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_ACUTE ((wchar_t) 0x00cd)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_CIRCUMFLEX ((wchar_t) 0x00ce)
+#define UNICODE_LATIN_CAPITAL_LETTER_I_WITH_DIARESIS ((wchar_t) 0x00cf)
+#define UNICODE_LATIN_CAPITAL_LETTER_ETH ((wchar_t) 0x00d0)
+#define UNICODE_LATIN_CAPITAL_LETTER_N_WITH_TILDE ((wchar_t) 0x00d1)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_GRAVE ((wchar_t) 0x00d2)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_ACUTE ((wchar_t) 0x00d3)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_CIRCUMFLEX ((wchar_t) 0x00d4)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_TILDE ((wchar_t) 0x00d5)
+#define UNICODE_LATIN_CAPITAL_LETTER_O_WITH_DIARESIS ((wchar_t) 0x00d6)
+#define UNICODE_MULTIPLICATION_SIGN ((wchar_t) 0x00d7)
+#define UNICODE_CAPITAL_LETTER_O_WITH_STROKE ((wchar_t) 0x00d8)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_GRAVE ((wchar_t) 0x00d9)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_ACUTE ((wchar_t) 0x00da)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_CIRCUMFLEX ((wchar_t) 0x00db)
+#define UNICODE_LATIN_CAPITAL_LETTER_U_WITH_DIARESIS ((wchar_t) 0x00dc)
+#define UNICODE_LATIN_CAPITAL_LETTER_Y_WITH_ACUTE ((wchar_t) 0x00dd)
+#define UNICODE_LATIN_CAPITAL_LETTER_THORN ((wchar_t) 0x00de)
+#define UNICODE_LATIN_SMALL_LETTER_SHARP_S ((wchar_t) 0x00df)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_GRAVE ((wchar_t) 0x00e0)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_ACUTE ((wchar_t) 0x00e1)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX ((wchar_t) 0x00e2)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_DIARESIS ((wchar_t) 0x00e4)
+#define UNICODE_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE ((wchar_t) 0x00e5)
+#define UNICODE_LATIN_SMALL_LETTER_AE ((wchar_t) 0x00e6)
+#define UNICODE_LATIN_SMALL_LIGATURE_AE UNICODE_LATIN_SMALL_LETTER_AE
+#define UNICODE_LATIN_SMALL_LETTER_C_WITH_CEDILLA ((wchar_t) 0x00e7)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_GRAVE ((wchar_t) 0x00e8)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_ACUTE ((wchar_t) 0x00e9)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX ((wchar_t) 0x00ea)
+#define UNICODE_LATIN_SMALL_LETTER_E_WITH_DIARESIS ((wchar_t) 0x00eb)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_GRAVE ((wchar_t) 0x00ec)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_ACUTE ((wchar_t) 0x00ed)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX ((wchar_t) 0x00ee)
+#define UNICODE_LATIN_SMALL_LETTER_I_WITH_DIARESIS ((wchar_t) 0x00ef)
+#define UNICODE_LATIN_SMALL_LETTER_ETH ((wchar_t) 0x00f0)
+#define UNICODE_LATIN_SMALL_LETTER_N_WITH_TILDE ((wchar_t) 0x00f1)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_GRAVE ((wchar_t) 0x00f2)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_ACUTE ((wchar_t) 0x00f3)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX ((wchar_t) 0x00f4)
+#define UNICODE_LATIN_SMALL_LETTER_O_WITH_DIARESIS ((wchar_t) 0x00f6)
+#define UNICODE_DIVISION_SIGN ((wchar_t) 0x00f7)
+#define UNICODE_SMALL_LETTER_O_WITH_STROKE ((wchar_t) 0x00f8)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_GRAVE ((wchar_t) 0x00f9)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_ACUTE ((wchar_t) 0x00fa)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX ((wchar_t) 0x00fb)
+#define UNICODE_LATIN_SMALL_LETTER_U_WITH_DIARESIS ((wchar_t) 0x00fc)
+#define UNICODE_LATIN_SMALL_LETTER_Y_WITH_ACUTE ((wchar_t) 0x00fd)
+#define UNICODE_LATIN_SMALL_LETTER_THORN ((wchar_t) 0x00fe)
+#define UNICODE_LATIN_SMALL_LETTER_Y_WITH_DIARESIS ((wchar_t) 0x00ff)
+
+#define UNICODE_LATIN_SMALL_LETTER_F_WITH_HOOK ((wchar_t) 0x0192)
+#define UNICODE_LATIN_SMALL_LETTER_SCRIPT_F \
+ UNICODE_LATIN_SMALL_LETTER_F_WITH_HOOK
+#define UNICODE_GREEK_CAPITAL_LETTER_GAMMA ((wchar_t) 0x0393)
+#define UNICODE_GREEK_CAPITAL_LETTER_OMICRON ((wchar_t) 0x039f)
+#define UNICODE_GREEK_CAPITAL_LETTER_SIGMA ((wchar_t) 0x03a3)
+#define UNICODE_GREEK_CAPITAL_LETTER_PHI ((wchar_t) 0x03a6)
+#define UNICODE_GREEK_CAPITAL_LETTER_OMEGA ((wchar_t) 0x03a9)
+#define UNICODE_GREEK_SMALL_LETTER_ALPHA ((wchar_t) 0x03b1)
+#define UNICODE_GREEK_SMALL_LETTER_BETA ((wchar_t) 0x03b2)
+#define UNICODE_GREEK_SMALL_LETTER_DELTA ((wchar_t) 0x03b4)
+#define UNICODE_GREEK_SMALL_LETTER_EPSILON ((wchar_t) 0x03b5)
+#define UNICODE_GREEK_SMALL_LETTER_MU ((wchar_t) 0x03bc)
+#define UNICODE_GREEK_SMALL_LETTER_PI ((wchar_t) 0x03c0)
+#define UNICODE_GREEK_SMALL_LETTER_SIGMA ((wchar_t) 0x03c3)
+#define UNICODE_GREEK_SMALL_LETTER_TAU ((wchar_t) 0x03c4)
+#define UNICODE_GREEK_SMALL_LETTER_PHI ((wchar_t) 0x03c6)
+
+#define UNICODE_BULLET ((wchar_t) 0x2022)
+#define UNICODE_DOUBLE_EXCLAMATION_MARK ((wchar_t) 0x203c)
+#define UNICODE_SUPERSCRIPT_LATIN_SMALL_LETTER ((wchar_t) 0x207f)
+#define UNICODE_PESETA_SIGN ((wchar_t) 0x20a7)
+
+#define UNICODE_LEFTWARDS_ARROW ((wchar_t) 0x2190)
+#define UNICODE_UPWARDS_ARROW ((wchar_t) 0x2191)
+#define UNICODE_RIGHTWARDS_ARROW ((wchar_t) 0x2192)
+#define UNICODE_DOWNWARDS_ARROW ((wchar_t) 0x2193)
+#define UNICODE_LEFT_RIGHT_ARROW ((wchar_t) 0x2194)
+#define UNICODE_UP_DOWN_ARROW ((wchar_t) 0x2195)
+#define UNICODE_UP_DOWN_ARROW_WITH_BASE ((wchar_t) 0x21a8)
+
+#define UNICODE_BULLET_OPERATOR ((wchar_t) 0x2219)
+#define UNICODE_SQUARE_ROOT ((wchar_t) 0x221a)
+#define UNICODE_INFINITY ((wchar_t) 0x221e)
+#define UNICODE_RIGHT_ANGLE ((wchar_t) 0x221f)
+#define UNICODE_INTERSECTION ((wchar_t) 0x2229)
+#define UNICODE_ALMOST_EQUAL_TO ((wchar_t) 0x2248)
+#define UNICODE_NOT_EQUAL_TO ((wchar_t) 0x2260)
+#define UNICODE_IDENTICAL_TO ((wchar_t) 0x2261)
+#define UNICODE_LESS_THAN_OR_EQUAL_TO ((wchar_t) 0x2264)
+#define UNICODE_GREATER_THAN_OR_EQUAL_TO ((wchar_t) 0x2265)
+
+#define UNICODE_HOUSE ((wchar_t) 0x2302)
+#define UNICODE_REVERSED_NOT_SIGN ((wchar_t) 0x2310)
+#define UNICODE_TOP_HALF_INTEGRAL ((wchar_t) 0x2320)
+#define UNICODE_BOTTOM_HALF_INTEGRAL ((wchar_t) 0x2321)
+
+#define UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL ((wchar_t) 0x2500)
+#define UNICODE_BOX_DRAWINGS_HEAVY_HORIZONTAL ((wchar_t) 0x2501)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL ((wchar_t) 0x2502)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT ((wchar_t) 0x250c)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_HEAVY ((wchar_t) 0x250d)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_LIGHT ((wchar_t) 0x250e)
+#define UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_RIGHT ((wchar_t) 0x250f)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT ((wchar_t) 0x2510)
+#define UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT ((wchar_t) 0x2514)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_HEAVY ((wchar_t) 0x2515)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_LIGHT ((wchar_t) 0x2516)
+#define UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_RIGHT ((wchar_t) 0x2517)
+#define UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_LEFT ((wchar_t) 0x2518)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT ((wchar_t) 0x251c)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_RIGHT_HEAVY ((wchar_t) 0x251d)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_UP_LIGHT ((wchar_t) 0x251e)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_UP_LIGHT ((wchar_t) 0x251f)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_RIGHT_LIGHT ((wchar_t) 0x2520)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_UP_HEAVY ((wchar_t) 0x2521)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_DOWN_HEAVY ((wchar_t) 0x2522)
+#define UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_RIGHT ((wchar_t) 0x2523)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT ((wchar_t) 0x2524)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL ((wchar_t) 0x252c)
+#define UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_DOWN_LIGHT ((wchar_t) 0x252d)
+#define UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_DOWN_LIGHT ((wchar_t) 0x252e)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_HORIZONTAL_HEAVY ((wchar_t) 0x252f)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_HORIZONTAL_LIGHT ((wchar_t) 0x2530)
+#define UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_DOWN_HEAVY ((wchar_t) 0x2531)
+#define UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_DOWN_HEAVY ((wchar_t) 0x2532)
+#define UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_HORIZONTAL ((wchar_t) 0x2533)
+#define UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL ((wchar_t) 0x2534)
+#define UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_UP_LIGHT ((wchar_t) 0x2535)
+#define UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_UP_LIGHT ((wchar_t) 0x2536)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_HORIZONTAL_HEAVY ((wchar_t) 0x2537)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_HORIZONTAL_LIGHT ((wchar_t) 0x2538)
+#define UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_UP_HEAVY ((wchar_t) 0x2539)
+#define UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_UP_HEAVY ((wchar_t) 0x253a)
+#define UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_HORIZONTAL ((wchar_t) 0x253b)
+#define UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL ((wchar_t) 0x253c)
+#define UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_VERTICAL_LIGHT \
+ ((wchar_t) 0x253d)
+#define UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_VERTICAL_LIGHT \
+ ((wchar_t) 0x253e)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_HORIZONTAL_HEAVY \
+ ((wchar_t) 0x253f)
+#define UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_DOWN_HORIZONTAL_LIGHT \
+ ((wchar_t) 0x2540)
+#define UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_UP_HORIZONTAL_LIGHT \
+ ((wchar_t) 0x2541)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_HORIZONTAL_LIGHT \
+ ((wchar_t) 0x2542)
+#define UNICODE_BOX_DRAWINGS_LEFT_UP_HEAVY_AND_RIGHT_DOWN_LIGHT \
+ ((wchar_t) 0x2543)
+#define UNICODE_BOX_DRAWINGS_RIGHT_UP_HEAVY_AND_LEFT_DOWN_LIGHT \
+ ((wchar_t) 0x2544)
+#define UNICODE_BOX_DRAWINGS_LEFT_DOWN_HEAVY_AND_RIGHT_UP_LIGHT \
+ ((wchar_t) 0x2545)
+#define UNICODE_BOX_DRAWINGS_RIGHT_DOWN_HEAVY_AND_LEFT_UP_LIGHT \
+ ((wchar_t) 0x2546)
+#define UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_UP_HORIZONTAL_HEAVY \
+ ((wchar_t) 0x2547)
+#define UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_DOWN_HORIZONTAL_HEAVY \
+ ((wchar_t) 0x2548)
+#define UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_VERTICAL_HEAVY \
+ ((wchar_t) 0x2549)
+#define UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_VERTICAL_HEAVY \
+ ((wchar_t) 0x254a)
+#define UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_HORIZONTAL \
+ ((wchar_t) 0x254b)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL ((wchar_t) 0x2550)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL ((wchar_t) 0x2551)
+#define UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE ((wchar_t) 0x2552)
+#define UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE ((wchar_t) 0x2553)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT ((wchar_t) 0x2554)
+#define UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE ((wchar_t) 0x2555)
+#define UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE ((wchar_t) 0x2556)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT ((wchar_t) 0x2557)
+#define UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE ((wchar_t) 0x2558)
+#define UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE ((wchar_t) 0x2559)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT ((wchar_t) 0x255a)
+#define UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE ((wchar_t) 0x255b)
+#define UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE ((wchar_t) 0x255c)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_LEFT ((wchar_t) 0x255d)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE \
+ ((wchar_t) 0x255e)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE \
+ ((wchar_t) 0x255f)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT ((wchar_t) 0x2560)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE ((wchar_t) 0x2561)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE ((wchar_t) 0x2562)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT ((wchar_t) 0x2563)
+#define UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE \
+ ((wchar_t) 0x2564)
+#define UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE \
+ ((wchar_t) 0x2565)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL ((wchar_t) 0x2566)
+#define UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE ((wchar_t) 0x2567)
+#define UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE ((wchar_t) 0x2568)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL ((wchar_t) 0x2569)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE \
+ ((wchar_t) 0x256a)
+#define UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE \
+ ((wchar_t) 0x256b)
+#define UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL ((wchar_t) 0x256c)
+#define UNICODE_BOX_DRAWINGS_LIGHT_ARC_DOWN_AND_RIGHT ((wchar_t) 0x256d)
+#define UNICODE_BOX_DRAWINGS_LIGHT_ARC_UP_AND_RIGHT ((wchar_t) 0x2570)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_RIGHT_TO_LOWER_LEFT \
+ ((wchar_t) 0x2571)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_LEFT_TO_LOWER_RIGHT \
+ ((wchar_t) 0x2572)
+#define UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_CROSS ((wchar_t) 0x2573)
+#define UNICODE_BOX_DRAWINGS_LIGHT_RIGHT ((wchar_t) 0x2576)
+#define UNICODE_BOX_DRAWINGS_HEAVY_RIGHT ((wchar_t) 0x257a)
+#define UNICODE_BOX_DRAWINGS_LIGHT_LEFT_AND_HEAVY_RIGHT ((wchar_t) 0x257c)
+#define UNICODE_BOX_DRAWINGS_HEAVY_LEFT_AND_LIGHT_RIGHT ((wchar_t) 0x257e)
+
+#define UNICODE_UPPER_HALF_BLOCK ((wchar_t) 0x2580)
+#define UNICODE_LOWER_ONE_EIGHTH_BLOCK ((wchar_t) 0x2581)
+#define UNICODE_LOWER_ONE_QUARTER_BLOCK ((wchar_t) 0x2582)
+#define UNICODE_LOWER_THREE_EIGHTHS_BLOCK ((wchar_t) 0x2583)
+#define UNICODE_LOWER_HALF_BLOCK ((wchar_t) 0x2584)
+#define UNICODE_LOWER_FIVE_EIGHTHS_BLOCK ((wchar_t) 0x2585)
+#define UNICODE_LOWER_THREE_QUARTERS_BLOCK ((wchar_t) 0x2586)
+#define UNICODE_LOWER_SEVEN_EIGHTHS_BLOCK ((wchar_t) 0x2587)
+#define UNICODE_FULL_BLOCK ((wchar_t) 0x2588)
+#define UNICODE_LEFT_HALF_BLOCK ((wchar_t) 0x258c)
+#define UNICODE_RIGHT_HALF_BLOCK ((wchar_t) 0x2590)
+#define UNICODE_LIGHT_SHADE ((wchar_t) 0x2591)
+#define UNICODE_MEDIUM_SHADE ((wchar_t) 0x2592)
+#define UNICODE_DARK_SHADE ((wchar_t) 0x2593)
+#define UNICODE_UPPER_ONE_EIGHTH_BLOCK ((wchar_t) 0x2594)
+#define UNICODE_RIGHT_ONE_EIGHTH_BLOCK ((wchar_t) 0x2595)
+#define UNICODE_QUADRANT_LOWER_LEFT ((wchar_t) 0x2596)
+#define UNICODE_QUADRANT_LOWER_RIGHT ((wchar_t) 0x2597)
+#define UNICODE_QUADRANT_UPPER_LEFT ((wchar_t) 0x2598)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_LEFT_AND_LOWER_RIGHT \
+ ((wchar_t) 0x2599)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_RIGHT ((wchar_t) 0x259a)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_LEFT \
+ ((wchar_t) 0x259b)
+#define UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_RIGHT \
+ ((wchar_t) 0x259c)
+#define UNICODE_QUADRANT_UPPER_RIGHT ((wchar_t) 0x259d)
+#define UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT ((wchar_t) 0x259e)
+#define UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT_AND_LOWER_RIGHT \
+ ((wchar_t) 0x259f)
+
+#define UNICODE_BLACK_SQUARE ((wchar_t) 0x25a0)
+#define UNICODE_BLACK_RECTANGLE ((wchar_t) 0x25ac)
+#define UNICODE_BLACK_UP_POINTING_TRIANGLE ((wchar_t) 0x25b2)
+#define UNICODE_BLACK_RIGHT_POINTING_TRIANGLE ((wchar_t) 0x25b6)
+#define UNICODE_BLACK_DOWN_POINTING_TRIANGLE ((wchar_t) 0x25bc)
+#define UNICODE_BLACK_LEFT_POINTING_TRIANGLE ((wchar_t) 0x25c0)
+#define UNICODE_WHITE_CIRCLE ((wchar_t) 0x25cb)
+#define UNICODE_INVERSE_BULLET ((wchar_t) 0x25d8)
+#define UNICODE_INVERSE_WHITE_CIRCLE ((wchar_t) 0x25d9)
+
+#define UNICODE_WHITE_SMILING_FACE ((wchar_t) 0x263a)
+#define UNICODE_BLACK_SMILING_FACE ((wchar_t) 0x263b)
+#define UNICODE_WHITE_SUN_WITH_RAYS ((wchar_t) 0x263c)
+#define UNICODE_FEMALE_SIGN ((wchar_t) 0x2640)
+#define UNICODE_MALE_SIGN ((wchar_t) 0x2642)
+#define UNICODE_BLACK_SPADE_SUIT ((wchar_t) 0x2660)
+#define UNICODE_BLACK_CLUB_SUIT ((wchar_t) 0x2663)
+#define UNICODE_BLACK_HEART_SUIT ((wchar_t) 0x2665)
+#define UNICODE_BLACK_DIAMOND_SUIT ((wchar_t) 0x2666)
+#define UNICODE_EIGHTH_NOTE ((wchar_t) 0x266a)
+#define UNICODE_BEAMED_EIGHTH_NOTES ((wchar_t) 0x266b)
+
+#define UNICODE_PRIVATE_USE_AREA ((wchar_t) 0xe000)
+#define UNICODE_PRIVATE_USE_AREA_LAST ((wchar_t) 0xf8ff)
+
+#define UNICODE_REPLACEMENT_CHARACTER ((wchar_t) 0xfffd)
+
+#endif /* _UNICODE_H_ */
+
diff --git a/console-client/vga-dynacolor.c b/console-client/vga-dynacolor.c
new file mode 100644
index 00000000..7b81e2f9
--- /dev/null
+++ b/console-client/vga-dynacolor.c
@@ -0,0 +1,322 @@
+/* vga-dynacolor.c - Dynamic color handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+
+#include <hurd/console.h>
+
+#include "vga-hw.h"
+#include "vga-support.h"
+#include "vga-dynacolor.h"
+
+
+dynacolor_t dynacolor_init_8 = DYNACOLOR_INIT_8;
+dynacolor_t dynacolor_init_16 = DYNACOLOR_INIT_16;
+
+static const unsigned char std_palette[16][DYNACOLOR_COMPONENTS] =
+ {
+ { 0, 0, 0 }, /* Black. */
+ { 42, 0, 0 }, /* Red. */
+ { 0, 42, 0 }, /* Green. */
+ { 42, 21, 0 }, /* Brown. */
+ { 0, 0, 42 }, /* Blue. */
+ { 42, 0, 42 }, /* Magenta. */
+ { 0, 42, 42 }, /* Cyan. */
+ { 42, 42, 42 }, /* White. */
+ { 21, 21, 21 }, /* Bright Black. */
+ { 63, 21, 21 }, /* Bright Red. */
+ { 21, 63, 21 }, /* Bright Green. */
+ { 63, 63, 21 }, /* Bright Yellow. */
+ { 21, 21, 63 }, /* Bright Blue. */
+ { 63, 21, 63 }, /* Bright Magenta. */
+ { 21, 63, 63 }, /* Bright Cyan. */
+ { 63, 63, 63 } /* Bright White. */
+ };
+
+/* The currently active (visible) dynafont. */
+static dynacolor_t *active_dynacolor;
+
+static unsigned char saved_palette[16][DYNACOLOR_COMPONENTS];
+
+/* We initialize this to the desired mapping for
+ vga_exchange_palette_attributes. */
+/* Palette index 0 is left as it is, for the border color. */
+static unsigned char saved_palette_attr[16] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
+
+
+/* Initialize the dynacolor subsystem. */
+void
+dynacolor_init (void)
+{
+ /* Palette index 0 is left as it is, as it is also used for the
+ border color by default. */
+ vga_exchange_palette_attributes (0, saved_palette_attr, 16);
+ vga_read_palette (0, saved_palette[0], 16);
+
+ vga_write_palette (0, std_palette[0], 16);
+}
+
+
+/* Restore the original palette. */
+void
+dynacolor_fini (void)
+{
+ vga_write_palette (0, saved_palette[0], 16);
+ vga_exchange_palette_attributes (0, saved_palette_attr, 16);
+}
+
+
+/* Activate the dynamic color palette DC. */
+void
+dynacolor_activate (dynacolor_t *dc)
+{
+ if (dc == active_dynacolor)
+ return;
+
+ if (dc->ref[0] < 0 && (!active_dynacolor || active_dynacolor->ref[0] >= 0))
+ {
+ /* Switching from dynamic to static palette. */
+ vga_write_palette (0, std_palette[0], 16);
+ }
+ else if (dc->ref[0] >= 0
+ && (!active_dynacolor || active_dynacolor->ref[0] < 0))
+ {
+ /* Switching from static to dynamic palette. */
+ int i;
+ for (i = 0; i < 16; i++)
+ if (dc->col[i] >= 0)
+ {
+ vga_write_palette (dc->col[i], std_palette[i], 1);
+ vga_write_palette (8 + dc->col[i], std_palette[i], 1);
+ }
+ }
+ active_dynacolor = dc;
+}
+
+
+/* Try to allocate a slot for the color COL in the dynamic color
+ palette DC. Return the allocated slot number or -1 if no slot is
+ available. */
+signed char
+dynacolor_allocate (dynacolor_t *dc, unsigned char col)
+{
+ int i;
+
+ for (i = 0; i < 8; i++)
+ if (dc->ref[i] == 0)
+ {
+ /* We want to reuse slot i. Clear the old user. */
+ int j;
+
+ for (j = 0; j < 16; j++)
+ if (dc->col[j] == i)
+ {
+ dc->col[j] = -1;
+ break;
+ }
+
+ dc->ref[i] = 1;
+ dc->col[col] = i;
+ if (active_dynacolor == dc)
+ {
+ vga_write_palette (0 + i, std_palette[col], 1);
+ vga_write_palette (8 + i, std_palette[col], 1);
+ }
+ return i;
+ }
+ return -1;
+}
+
+
+/* This is a convenience function that looks up a replacement color
+ pair if the original colors are not available. The function always
+ succeeds. DC is the dynacolor to use for allocation, FGCOL and
+ BGCOL are the desired colors, and R_FGCOL and R_BGCOL are the
+ resulting colors. The function assumes that the caller already
+ tried to look up the desired colors before trying to replace them,
+ and that the result of the lookup is contained in R_FGCOL and
+ R_BGCOL.
+
+ Example:
+
+ res_bgcol = dynacolor_lookup (&dc, bgcol);
+ res_fgcol = dynacolor_lookup (&dc, fgcol);
+ if (res_bgcol == -1 || res_fgcol == -1)
+ dynacolor_replace_colors (&dc, fgcol, bgcol, &res_fgcol, &res_bgcol);
+
+ After the above code, res_fgcol and res_bgcol contain valid color
+ values. */
+void
+dynacolor_replace_colors (dynacolor_t *dc,
+ signed char fgcol, signed char bgcol,
+ signed char *r_fgcol, signed char *r_bgcol)
+{
+ /* Replacement colors. As we have 8 colors in our palette, and
+ one was already tried, we only need to try out 8 possible
+ replacements. Only the first seven can fail. But one is
+ possibly taken by the fore-/background color, so we actually
+ have to try up to nine. XXX Maybe we should have a table
+ based on pairs, but that increases the number of cases a
+ lot. */
+ /* Note that no color must occur twice in one replacement list,
+ and that the color to be replaced must not occure either. */
+ static signed char pref[16][9] =
+ {
+ /* Replacements for CONS_COLOR_BLACK. */
+ { CONS_COLOR_BLACK | (1 << 3), CONS_COLOR_BLUE,
+ CONS_COLOR_YELLOW, CONS_COLOR_RED, CONS_COLOR_MAGENTA,
+ CONS_COLOR_GREEN, CONS_COLOR_CYAN, CONS_COLOR_WHITE,
+ CONS_COLOR_BLUE | (1 << 3) },
+ /* Replacements for CONS_COLOR_RED. */
+ { CONS_COLOR_RED | (1 << 3), CONS_COLOR_YELLOW,
+ CONS_COLOR_MAGENTA, CONS_COLOR_BLUE, CONS_COLOR_CYAN,
+ CONS_COLOR_GREEN, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_GREEN. */
+ { CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_YELLOW, CONS_COLOR_BLUE, CONS_COLOR_RED,
+ CONS_COLOR_MAGENTA, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_YELLOW. */
+ { CONS_COLOR_YELLOW | (1 << 3), CONS_COLOR_RED,
+ CONS_COLOR_GREEN, CONS_COLOR_MAGENTA, CONS_COLOR_BLUE,
+ CONS_COLOR_CYAN, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_BLUE. */
+ { CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_MAGENTA, CONS_COLOR_RED, CONS_COLOR_GREEN,
+ CONS_COLOR_YELLOW, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_MAGENTA. */
+ { CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_RED,
+ CONS_COLOR_BLUE, CONS_COLOR_YELLOW, CONS_COLOR_CYAN,
+ CONS_COLOR_BLUE, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_CYAN. */
+ { CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_BLUE,
+ CONS_COLOR_MAGENTA, CONS_COLOR_GREEN, CONS_COLOR_RED,
+ CONS_COLOR_YELLOW, CONS_COLOR_WHITE, CONS_COLOR_BLACK,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_WHITE. */
+ { CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_GREEN, CONS_COLOR_YELLOW, CONS_COLOR_MAGENTA,
+ CONS_COLOR_RED, CONS_COLOR_BLUE, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_BLACK | (1 << 3). */
+ { CONS_COLOR_BLACK, CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_YELLOW | (1 << 3), CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_WHITE | (1 << 3),
+ CONS_COLOR_WHITE },
+ /* Replacements for CONS_COLOR_RED | (1 << 3). */
+ { CONS_COLOR_RED, CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_GREEN | (1 << 3). */
+ { CONS_COLOR_GREEN, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_YELLOW | (1 << 3), CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_RED | (1 << 3), CONS_COLOR_MAGENTA | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_YELLOW | (1 << 3). */
+ { CONS_COLOR_YELLOW, CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_MAGENTA | (1 << 3),
+ CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_BLUE | (1 << 3). */
+ { CONS_COLOR_BLUE, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_MAGENTA | (1 << 3). */
+ { CONS_COLOR_MAGENTA, CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_CYAN | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_CYAN | (1 << 3). */
+ { CONS_COLOR_CYAN, CONS_COLOR_BLUE | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_GREEN | (1 << 3),
+ CONS_COLOR_RED | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_WHITE | (1 << 3), CONS_COLOR_WHITE,
+ CONS_COLOR_BLACK | (1 << 3) },
+ /* Replacements for CONS_COLOR_WHITE | (1 << 3). */
+ { CONS_COLOR_WHITE, CONS_COLOR_CYAN | (1 << 3),
+ CONS_COLOR_GREEN | (1 << 3), CONS_COLOR_YELLOW | (1 << 3),
+ CONS_COLOR_MAGENTA | (1 << 3), CONS_COLOR_RED | (1 << 3),
+ CONS_COLOR_BLUE | (1 << 3), CONS_COLOR_CYAN,
+ CONS_COLOR_BLACK | (1 << 3) },
+ };
+
+ signed char res_fgcol = *r_fgcol;
+ signed char res_bgcol = *r_bgcol;
+ signed char new_bgcol = bgcol;
+ int i;
+
+ /* First get a background color. */
+ if (res_bgcol == -1)
+ {
+ for (i = 0; i < 9; i++)
+ {
+ /* If the foreground color is found, make sure to not
+ set the background to it. */
+ if (res_fgcol == -1 || pref[bgcol][i] != fgcol)
+ {
+ res_bgcol = dynacolor_lookup (*dc, pref[bgcol][i]);
+ if (res_bgcol >= 0)
+ break;
+ }
+ }
+
+ assert (res_bgcol >= 0);
+ new_bgcol = pref[bgcol][i];
+ }
+
+ if (fgcol == bgcol)
+ {
+ assert (res_fgcol == -1);
+ /* Acquire another reference. */
+ res_fgcol = dynacolor_lookup (*dc, new_bgcol);
+ }
+ else
+ assert (res_fgcol != res_bgcol);
+
+ if (res_fgcol == -1)
+ {
+ /* Now find a foreground color. */
+ for (i = 0; i < 9; i++)
+ {
+ if (pref[fgcol][i] != new_bgcol)
+ {
+ res_fgcol = dynacolor_lookup (*dc, pref[fgcol][i]);
+ if (res_fgcol >= 0)
+ break;
+ }
+ }
+ assert (res_fgcol >= 0);
+ }
+ *r_fgcol = res_fgcol;
+ *r_bgcol = res_bgcol;
+}
diff --git a/console-client/vga-dynacolor.h b/console-client/vga-dynacolor.h
new file mode 100644
index 00000000..304bcc1b
--- /dev/null
+++ b/console-client/vga-dynacolor.h
@@ -0,0 +1,108 @@
+/* vga-dynacolor.h - Interface to dynamic color handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_DYNACOLOR_H_
+#define _VGA_DYNACOLOR_H_ 1
+
+/* Every component can have up to 6 bits. */
+#define DYNACOLOR_COMPONENT_MAX 0x63
+
+/* The components are, in that order, red, green, blue. */
+#define DYNACOLOR_COMPONENTS 3
+
+/* The maximum number of colors. */
+#define DYNACOLOR_COLORS 8
+
+struct dynacolor
+{
+ int ref[8];
+ /* Reverse lookup, -1 denotes an unmapped color. */
+ signed char col[16];
+};
+
+typedef struct dynacolor dynacolor_t;
+
+/* We start with one reference for the black color so that it is
+ always available. It is also put in front so that it can be shared
+ as the border color. The importance of this is that for
+ non-standard font heights, we have some black-filled normal text
+ rows below the screen matrix, for which we must allocate a real
+ color slot :( */
+#define DYNACOLOR_INIT_8 { { 1, 0, 0, 0, 0, 0, 0, 0 }, \
+ { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } }
+#define DYNACOLOR_INIT_16 { { -1 } }
+
+extern dynacolor_t dynacolor_init_8;
+extern dynacolor_t dynacolor_init_16;
+
+
+/* Initialize the dynacolor subsystem. */
+void dynacolor_init (void);
+
+/* Restore the original palette. */
+void dynacolor_fini (void);
+
+/* Activate the dynamic color palette DC. */
+void dynacolor_activate (dynacolor_t *dc);
+
+/* Try to allocate a slot for the color COL in the dynamic color
+ palette DC. Return the allocated slot number (with one reference)
+ or -1 if no slot is available. */
+signed char dynacolor_allocate (dynacolor_t *dc, unsigned char col);
+
+/* Get the slot number for color C in the dynamic color palette DC, or
+ -1 if we ran out of color slots. If successful, this allocates a
+ reference for the color. */
+#define dynacolor_lookup(dc,c) \
+ ((dc).ref[0] < 0 ? (c) : \
+ ((dc).col[(c)] >= 0 ? (dc).ref[(dc).col[(c)]]++, (dc).col[(c)] : \
+ dynacolor_allocate (&(dc), (c))))
+
+/* Add a reference to palette entry P in the dynamic font DC. */
+#define dynacolor_add_ref(dc,p) \
+ ((dc).ref[0] >= 0 && (dc).ref[p]++)
+
+/* Deallocate a reference for palette entry P in the dynamic font DC. */
+#define dynacolor_release(dc,p) \
+ ((dc).ref[0] >= 0 && (dc).ref[p]--)
+
+/* This is a convenience function that looks up a replacement color
+ pair if the original colors are not available. The function always
+ succeeds. DC is the dynacolor to use for allocation, FGCOL and
+ BGCOL are the desired colors, and R_FGCOL and R_BGCOL are the
+ resulting colors. The function assumes that the caller already
+ tried to look up the desired colors before trying to replace them,
+ and that the result of the lookup is contained in R_FGCOL and
+ R_BGCOL.
+
+ Example:
+
+ res_bgcol = dynacolor_lookup (&dc, bgcol);
+ res_fgcol = dynacolor_lookup (&dc, fgcol);
+ if (res_bgcol == -1 || res_fgcol == -1)
+ dynacolor_replace_colors (&dc, fgcol, bgcol, &res_fgcol, &res_bgcol);
+
+ After the above code, res_fgcol and res_bgcol contain valid color
+ values. */
+void dynacolor_replace_colors (dynacolor_t *dc,
+ signed char fgcol, signed char bgcol,
+ signed char *r_fgcol, signed char *r_bgcol);
+
+#endif /* _VGA_DYNACOLOR_H_ */
diff --git a/console-client/vga-dynafont.c b/console-client/vga-dynafont.c
new file mode 100644
index 00000000..0df28df1
--- /dev/null
+++ b/console-client/vga-dynafont.c
@@ -0,0 +1,1047 @@
+/* vga-dynafont.c - Dynamic font handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <malloc.h>
+#include <wchar.h>
+#include <stdlib.h>
+#include <hurd/ihash.h>
+#include <string.h>
+
+#include <hurd/console.h>
+#include "vga-hw.h"
+#include "vga-support.h"
+#include "bdf.h"
+#include "vga-dynafont.h"
+#include "unicode.h"
+
+
+/* The currently active (visible) dynafont. The original idea was to
+ use some sort of caching for multiple dynafonts using the 8 font
+ buffers on the graphic card, but the new idea is to share a common
+ state among all virtual consoles and do a full refresh on
+ switching. However, bits and pieces of the old idea are still
+ present, in case they become useful. */
+static dynafont_t active_dynafont;
+
+
+/* One glyph in a VGA font is 8 pixels wide and 32 pixels high. Only
+ the first N lines are visible, and N depends on the VGA register
+ settings. */
+typedef char vga_font_glyph[VGA_FONT_HEIGHT];
+
+
+/* For each glyph in the VGA font, one instance of this structure is
+ held in the dynafont. */
+struct mapped_character
+{
+ /* Reference count of the mapped character. If this drops zero, we
+ can remove the mapping at any time. */
+ int refs;
+
+ /* Remember the character this glyph belongs to, so the glyph can be
+ reloaded when the font is changed. This is actually a wchar_t
+ with some text attributes mixed into the high bits. */
+#define WCHAR_BOLD ((wchar_t) 0x40000000)
+#define WCHAR_ITALIC ((wchar_t) 0x20000000)
+#define WCHAR_MASK ((wchar_t) 0x001fffff)
+ wchar_t character;
+
+ /* Used by libihash for fast removal of elements. */
+ void **locp;
+};
+
+
+struct dynafont
+{
+ /* The sorted font to take the glyphs from. */
+ bdf_font_t font;
+
+ /* The sorted font to take the italic glyphs from. */
+ bdf_font_t font_italic;
+
+ /* The sorted font to take the bold glyphs from. */
+ bdf_font_t font_bold;
+
+ /* The sorted font to take the bold and italic glyphs from. */
+ bdf_font_t font_bold_italic;
+
+ /* The size of the VGA font (256 or 512). Must be a power of 2! */
+ int size;
+
+ /* A hash containing a pointer to a struct mapped_character for each
+ UCS-4 character we map to a VGA font index. */
+ ihash_t charmap;
+
+ /* The struct mapped_characters are preallocated for all vga font
+ index values. This points to an array of SIZE such elements. */
+ struct mapped_character *charmap_data;
+
+ /* The last vga font index that had been free (or could be
+ reused). */
+ int vga_font_last_free_index;
+
+ /* The number of free slots in the VGA font. */
+ int vga_font_free_indices;
+
+ int use_lgc;
+
+ /* The last vga font index that had been free (or could be reused)
+ for horizontal line graphic characters. */
+ int vga_font_last_free_index_lgc;
+
+ /* The number of free slots in the VGA font for horizontal line
+ graphic charactes. */
+ int vga_font_free_indices_lgc;
+
+ /* The font memory as stored on the card. */
+ vga_font_glyph *vga_font;
+
+ /* The cursor size, standout or normal. */
+ int cursor_standout;
+};
+
+
+/* The VGA standard font follows IBM code page 437. The following
+ table maps this to unicode. For simplicity, a 1:1 mapping is
+ assumed. Ambiguities are special cased in create_system_font. */
+static
+wchar_t ibm437_to_unicode[VGA_FONT_SIZE] = {
+ 0, /* 0x00 */
+ UNICODE_WHITE_SMILING_FACE, /* 0x01 */
+ UNICODE_BLACK_SMILING_FACE, /* 0x02 */
+ UNICODE_BLACK_HEART_SUIT, /* 0x03 */
+ UNICODE_BLACK_DIAMOND_SUIT, /* 0x04 */
+ UNICODE_BLACK_CLUB_SUIT, /* 0x05 */
+ UNICODE_BLACK_SPADE_SUIT, /* 0x06 */
+ UNICODE_BULLET, /* 0x07 */
+ UNICODE_INVERSE_BULLET, /* 0x08 */
+ UNICODE_WHITE_CIRCLE, /* 0x09 */
+ UNICODE_INVERSE_WHITE_CIRCLE, /* 0x0a */
+ UNICODE_MALE_SIGN, /* 0x0b */
+ UNICODE_FEMALE_SIGN, /* 0x0c */
+ UNICODE_EIGHTH_NOTE, /* 0x0d */
+ UNICODE_BEAMED_EIGHTH_NOTES, /* 0x0e */
+ UNICODE_WHITE_SUN_WITH_RAYS, /* 0x0f */
+ UNICODE_BLACK_RIGHT_POINTING_TRIANGLE, /* 0x10 */
+ UNICODE_BLACK_LEFT_POINTING_TRIANGLE, /* 0x11 */
+ UNICODE_UP_DOWN_ARROW, /* 0x12 */
+ UNICODE_DOUBLE_EXCLAMATION_MARK, /* 0x13 */
+ UNICODE_PILCROW_SIGN, /* 0x14 */
+ UNICODE_SECTION_SIGN, /* 0x15 */
+ UNICODE_BLACK_RECTANGLE, /* 0x16 */
+ UNICODE_UP_DOWN_ARROW_WITH_BASE, /* 0x17 */
+ UNICODE_UPWARDS_ARROW, /* 0x18 */
+ UNICODE_DOWNWARDS_ARROW, /* 0x19 */
+ UNICODE_RIGHTWARDS_ARROW, /* 0x1a */
+ UNICODE_LEFTWARDS_ARROW, /* 0x1b */
+ UNICODE_RIGHT_ANGLE, /* 0x1c */
+ UNICODE_LEFT_RIGHT_ARROW, /* 0x1d */
+ UNICODE_BLACK_UP_POINTING_TRIANGLE, /* 0x1e */
+ UNICODE_BLACK_DOWN_POINTING_TRIANGLE, /* 0x1f */
+ ' ', '!', '"', '#', '$', '%', '&', '\'', /* 0x20 - 0x27 */
+ '(', ')', '*', '+', ',', '-', '.', '/', /* 0x28 - 0x2f */
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', /* 0x30 - 0x37 */
+ ':', ';', '<', '=', '>', '?', /* 0x38 - 0x3f */
+ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 0x40 - 0x47 */
+ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', /* 0x48 - 0x4f */
+ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', /* 0x50 - 0x57 */
+ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', /* 0x58 - 0x5f */
+ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', /* 0x60 - 0x67 */
+ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', /* 0x68 - 0x6f */
+ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', /* 0x70 - 0x77 */
+ 'x', 'y', 'z', '{', '|', '}', '~', UNICODE_HOUSE, /* 0x78 - 0x7f */
+ UNICODE_LATIN_CAPITAL_LETTER_C_WITH_CEDILLA, /* 0x80 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_DIARESIS, /* 0x81 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_ACUTE, /* 0x82 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_CIRCUMFLEX, /* 0x83 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_DIARESIS, /* 0x84 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_GRAVE, /* 0x85 */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_RING_ABOVE, /* 0x86 */
+ UNICODE_LATIN_SMALL_LETTER_C_WITH_CEDILLA, /* 0x87 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_CIRCUMFLEX, /* 0x88 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_DIARESIS, /* 0x89 */
+ UNICODE_LATIN_SMALL_LETTER_E_WITH_GRAVE, /* 0x8a */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_DIARESIS, /* 0x8b */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_CIRCUMFLEX, /* 0x8c */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_GRAVE, /* 0x8d */
+ UNICODE_LATIN_CAPITAL_LETTER_A_WITH_DIARESIS, /* 0x8e */
+ UNICODE_LATIN_CAPITAL_LETTER_A_WITH_RING_ABOVE, /* 0x8f */
+ UNICODE_LATIN_CAPITAL_LETTER_E_WITH_ACUTE, /* 0x90 */
+ UNICODE_LATIN_SMALL_LETTER_AE, /* 0x91 */
+ UNICODE_LATIN_CAPITAL_LETTER_AE, /* 0x92 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_CIRCUMFLEX, /* 0x93 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_DIARESIS, /* 0x94 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_GRAVE, /* 0x95 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_CIRCUMFLEX, /* 0x96 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_GRAVE, /* 0x97 */
+ UNICODE_LATIN_SMALL_LETTER_Y_WITH_DIARESIS, /* 0x98 */
+ UNICODE_LATIN_CAPITAL_LETTER_O_WITH_DIARESIS, /* 0x99 */
+ UNICODE_LATIN_CAPITAL_LETTER_U_WITH_DIARESIS, /* 0x9a */
+ UNICODE_CENT_SIGN, /* 0x9b */
+ UNICODE_POUND_SIGN, /* 0x9c */
+ UNICODE_YEN_SIGN, /* 0x9d */
+ UNICODE_PESETA_SIGN, /* 0x9e */
+ UNICODE_LATIN_SMALL_LETTER_F_WITH_HOOK, /* 0x9f */
+ UNICODE_LATIN_SMALL_LETTER_A_WITH_ACUTE, /* 0xa0 */
+ UNICODE_LATIN_SMALL_LETTER_I_WITH_ACUTE, /* 0xa1 */
+ UNICODE_LATIN_SMALL_LETTER_O_WITH_ACUTE, /* 0xa2 */
+ UNICODE_LATIN_SMALL_LETTER_U_WITH_ACUTE, /* 0xa3 */
+ UNICODE_LATIN_SMALL_LETTER_N_WITH_TILDE, /* 0xa4 */
+ UNICODE_LATIN_CAPITAL_LETTER_N_WITH_TILDE, /* 0xa5 */
+ UNICODE_FEMININE_ORDINAL_INDICATOR, /* 0xa6 */
+ UNICODE_MASCULINE_ORDINAL_INDICATOR, /* 0xa7 */
+ UNICODE_INVERTED_QUESTION_MARK, /* 0xa8 */
+ UNICODE_REVERSED_NOT_SIGN, /* 0xa9 */
+ UNICODE_NOT_SIGN, /* 0xaa */
+ UNICODE_VULGAR_FRACTION_ONE_HALF, /* 0xab */
+ UNICODE_VULGAR_FRACTION_ONE_QUARTER, /* 0xac */
+ UNICODE_INVERTED_EXCLAMATION_MARK, /* 0xad */
+ UNICODE_LEFT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, /* 0xae */
+ UNICODE_RIGHT_POINTING_DOUBLE_ANGLE_QUOTATION_MARK, /* 0xaf */
+ UNICODE_LIGHT_SHADE, /* 0xb0 */
+ UNICODE_MEDIUM_SHADE, /* 0xb1 */
+ UNICODE_DARK_SHADE, /* 0xb2 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL, /* 0xb3 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_LEFT, /* 0xb4 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_LEFT_DOUBLE, /* 0xb5 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_LEFT_SINGLE, /* 0xb6 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_LEFT_SINGLE, /* 0xb7 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_LEFT_DOUBLE, /* 0xb8 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_LEFT, /* 0xb9 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL, /* 0xba */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_LEFT, /* 0xbb */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_LEFT, /* 0xbc */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_LEFT_SINGLE, /* 0xbd */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_LEFT_DOUBLE, /* 0xbe */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_LEFT, /* 0xbf */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, /* 0xc0 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL, /* 0xc1 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL, /* 0xc2 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT, /* 0xc3 */
+ UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL, /* 0xc4 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL, /* 0xc5 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE, /* 0xc6 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE, /* 0xc7 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT, /* 0xc8 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT, /* 0xc9 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL, /* 0xca */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL, /* 0xcb */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT, /* 0xcc */
+ UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL, /* 0xcd */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL,/* 0xce */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xcf */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd0 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xd1 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd2 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE, /* 0xd3 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE, /* 0xd4 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE, /* 0xd5 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE, /* 0xd6 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0xd7 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0xd8 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_LEFT, /* 0xd9 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, /* 0xda */
+ UNICODE_FULL_BLOCK, /* 0xdb */
+ UNICODE_LOWER_HALF_BLOCK, /* 0xdc */
+ UNICODE_LEFT_HALF_BLOCK, /* 0xdd */
+ UNICODE_RIGHT_HALF_BLOCK, /* 0xde */
+ UNICODE_UPPER_HALF_BLOCK, /* 0xdf */
+ UNICODE_GREEK_SMALL_LETTER_ALPHA, /* 0xe0 */
+ /* The next one: Also sz-ligature. */
+ UNICODE_GREEK_SMALL_LETTER_BETA, /* 0xe1 */
+ UNICODE_GREEK_CAPITAL_LETTER_GAMMA, /* 0xe2 */
+ UNICODE_GREEK_SMALL_LETTER_PI, /* 0xe3 */
+ UNICODE_GREEK_CAPITAL_LETTER_SIGMA, /* 0xe4 */
+ UNICODE_GREEK_SMALL_LETTER_SIGMA, /* 0xe5 */
+ /* The next one: Also micro. */
+ UNICODE_GREEK_SMALL_LETTER_MU, /* 0xe6 */
+ UNICODE_GREEK_SMALL_LETTER_TAU, /* 0xe7 */
+ UNICODE_GREEK_CAPITAL_LETTER_PHI, /* 0xe8 */
+ UNICODE_GREEK_CAPITAL_LETTER_OMICRON, /* 0xe9 */
+ UNICODE_GREEK_CAPITAL_LETTER_OMEGA, /* 0xea */
+ UNICODE_GREEK_SMALL_LETTER_DELTA, /* 0xeb */
+ UNICODE_INFINITY, /* 0xec */
+ UNICODE_GREEK_SMALL_LETTER_PHI, /* 0xed */
+ UNICODE_GREEK_SMALL_LETTER_EPSILON, /* 0xee */
+ UNICODE_INTERSECTION, /* 0xef */
+ UNICODE_IDENTICAL_TO, /* 0xf0 */
+ UNICODE_PLUS_MINUS_SIGN, /* 0xf1 */
+ UNICODE_GREATER_THAN_OR_EQUAL_TO, /* 0xf2 */
+ UNICODE_LESS_THAN_OR_EQUAL_TO, /* 0xf3 */
+ UNICODE_TOP_HALF_INTEGRAL, /* 0xf4 */
+ UNICODE_BOTTOM_HALF_INTEGRAL, /* 0xf5 */
+ UNICODE_DIVISION_SIGN, /* 0xf6 */
+ UNICODE_ALMOST_EQUAL_TO, /* 0xf7 */
+ UNICODE_DEGREE_SIGN, /* 0xf8 */
+ UNICODE_BULLET_OPERATOR, /* 0xf9 */
+ UNICODE_MIDDLE_DOT, /* 0xfa */
+ UNICODE_SQUARE_ROOT, /* 0xfb */
+ UNICODE_SUPERSCRIPT_LATIN_SMALL_LETTER, /* 0xfc */
+ UNICODE_SUPERSCRIPT_TWO, /* 0xfd */
+ UNICODE_BLACK_SQUARE, /* 0xfe */
+ UNICODE_NO_BREAK_SPACE /* 0xff */
+ };
+
+/* Read the VGA card's memory as IBM 437 font and create a Unicode BDF
+ font from it. If an error occurs, errno is set and NULL is
+ returned. */
+static bdf_font_t
+create_system_font (void)
+{
+ bdf_error_t bdferr;
+ bdf_font_t font;
+ unsigned char bitmap[VGA_FONT_SIZE][VGA_FONT_HEIGHT]; /* 8kB on stack. */
+ int width = 9; /* XXX Find out if we are in 8 or 9 pixel mode. */
+ int i;
+
+ /* Add the glyph at position POS to the font for character
+ ENCODING. */
+ void vga_add_glyph (int pos, int encoding)
+ {
+ char name[16];
+ snprintf (name, sizeof (name), "VGA %i", pos);
+
+ if (width == 8)
+ bdferr = bdf_add_glyph (font, name, encoding,
+ 0, 8, 16, 0, 0, bitmap[pos]);
+ else
+ {
+ int i;
+ char glyph_bitmap[32];
+
+ for (i = 0; i < 16; i++)
+ {
+ glyph_bitmap[i * 2] = bitmap[pos][i];
+ if (pos >= VGA_FONT_LGC_BEGIN
+ && pos < VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ glyph_bitmap[i * 2 + 1]
+ = (bitmap[pos][i] & 1) ? 0x80 : 0;
+ else
+ glyph_bitmap[i * 2 + 1] = 0;
+ }
+ bdferr = bdf_add_glyph (font, name, encoding,
+ 0, 9, 16, 0, 0, glyph_bitmap);
+ }
+ }
+
+ /* The point size and resolution is arbitrary. */
+ bdferr = bdf_new (&font, 2, 2, "vga-system", 10, 100, 100,
+ width, 16, 0, 0, 0);
+ if (bdferr)
+ {
+ if (bdferr != BDF_SYSTEM_ERROR)
+ errno = EGRATUITOUS;
+ return NULL;
+ }
+
+ vga_read_font_buffer (0, 0, (unsigned char *) bitmap,
+ VGA_FONT_SIZE * VGA_FONT_HEIGHT);
+
+ for (i = 0; i < VGA_FONT_SIZE; i++)
+ if (ibm437_to_unicode[i])
+ {
+ vga_add_glyph (i, ibm437_to_unicode[i]);
+ if (bdferr)
+ break;
+
+ /* Some glyphs are ambivalent. */
+ if (ibm437_to_unicode[i] == UNICODE_GREEK_SMALL_LETTER_BETA)
+ vga_add_glyph (i, UNICODE_LATIN_SMALL_LETTER_SHARP_S);
+ else if (ibm437_to_unicode[i] == UNICODE_GREEK_SMALL_LETTER_MU)
+ vga_add_glyph (i, UNICODE_MICRO_SIGN);
+ if (bdferr)
+ break;
+ }
+
+ if (bdferr)
+ {
+ bdf_destroy (font);
+ if (bdferr != BDF_SYSTEM_ERROR)
+ errno = EGRATUITOUS;
+ return NULL;
+ }
+
+ return font;
+}
+
+
+#if QUAERENDO_INVENIETIS
+#define GNU_HEAD_BEGIN (UNICODE_PRIVATE_USE_AREA + 0x0f00)
+
+static void
+add_gnu_head (bdf_font_t font)
+{
+#define GNU_HEAD_WIDTH 6
+ static unsigned char gnu_head[][GNU_HEAD_WIDTH] =
+ {
+ { 255, 255, 255, 255, 255, 255 }, { 255, 0, 127, 255, 252, 31 },
+ { 252, 0, 31, 255, 224, 7 }, { 248, 0, 7, 255, 0, 3 },
+ { 240, 0, 15, 255, 128, 3 }, { 240, 31, 255, 255, 252, 1 },
+ { 224, 63, 241, 255, 255, 1 }, { 192, 127, 128, 96, 255, 129 },
+ { 192, 255, 0, 0, 63, 193 }, { 192, 254, 0, 0, 31, 193 },
+ { 192, 252, 0, 0, 15, 193 }, { 192, 248, 0, 0, 15, 193 },
+ { 192, 248, 0, 0, 7, 129 }, { 192, 96, 63, 131, 192, 1 },
+ { 192, 1, 227, 98, 112, 1 }, { 192, 3, 195, 244, 176, 3 },
+ { 224, 7, 221, 125, 248, 3 }, { 240, 15, 184, 124, 120, 7 },
+ { 240, 15, 248, 124, 60, 15 }, { 248, 15, 220, 254, 124, 127 },
+ { 252, 31, 223, 255, 254, 127 }, { 255, 159, 159, 255, 31, 191 },
+ { 255, 223, 159, 255, 35, 63 }, { 255, 191, 127, 195, 152, 127 },
+ { 255, 188, 255, 156, 199, 255 }, { 255, 96, 253, 134, 115, 255 },
+ { 254, 134, 251, 227, 251, 255 }, { 254, 46, 254, 249, 251, 255 },
+ { 255, 238, 126, 127, 231, 255 }, { 255, 239, 127, 127, 207, 255 },
+ { 255, 239, 63, 63, 231, 255 }, { 255, 247, 159, 158, 15, 255 },
+ { 255, 247, 207, 193, 159, 255 }, { 255, 247, 223, 255, 223, 255 },
+ { 255, 243, 199, 252, 31, 255 }, { 255, 251, 227, 224, 63, 255 },
+ { 255, 253, 241, 240, 255, 255 }, { 255, 252, 244, 126, 255, 255 },
+ { 255, 254, 121, 122, 255, 255 }, { 255, 255, 252, 48, 255, 255 },
+ { 255, 255, 252, 35, 255, 255 }, { 255, 255, 249, 1, 127, 255 },
+ { 255, 255, 251, 0, 127, 255 }, { 255, 255, 255, 128, 255, 255 },
+ { 255, 255, 255, 255, 255, 255 }
+ };
+ /* Height of a single glyph, truncated to fit VGA glyph slot. */
+ int height = (font->bbox.height > 32) ? 32 : font->bbox.height;
+ /* Width of a single glyph in byte. */
+ int width = (font->bbox.width + 7) / 8;
+ /* Number of rows in bitmap. */
+ int rows = sizeof (gnu_head) / sizeof (gnu_head[0]);
+ /* Number of rows of glyphs necessary. */
+ int nr = (rows + height - 1) / height;
+ int row, col;
+
+ /* Check that all those glyphs are free in the private area. */
+ if (nr * GNU_HEAD_WIDTH > GNU_HEAD_BEGIN - UNICODE_PRIVATE_USE_AREA + 1)
+ return;
+ for (int i = 0; i < nr * GNU_HEAD_WIDTH; i++)
+ if (bdf_find_glyph (font, (int) GNU_HEAD_BEGIN + i, 0)
+ || bdf_find_glyph (font, -1, (int) GNU_HEAD_BEGIN + i))
+ return;
+
+ for (row = 0; row < nr; row++)
+ for (col = 0; col < GNU_HEAD_WIDTH; col++)
+ {
+ char bitmap[font->bbox.height][width];
+ char name[] = "GNU Head ..........";
+
+ /* strlen ("GNU Head ") == 9. */
+ sprintf (&name[9], "%i", row * GNU_HEAD_WIDTH + col);
+
+ memset (bitmap, 0, sizeof (bitmap));
+ for (int j = 0; j < height && row * height + j < rows; j++)
+ bitmap[j][0] = gnu_head[row * height + j][col];
+
+ if (bdf_add_glyph (font, name,
+ GNU_HEAD_BEGIN + row * GNU_HEAD_WIDTH + col,
+ 0, font->bbox.width, font->bbox.height,
+ 0, 0, (unsigned char *) bitmap))
+ return;
+ }
+}
+#endif
+
+/* Create a new dynafont object, which uses glyphs from the font FONT
+ (which should be 8 or 9 pixels wide and 13 to 16 pixels high).
+ SIZE is either 256 or 512, and specifies the number of available
+ glyphs in the font cache. The object is returned in DYNAFONT.
+
+ The font is consumed. If FONT is the null pointer, the VGA card's
+ memory is converted to a font according to the VGA default map (IBM
+ Code Page 437). */
+error_t
+dynafont_new (bdf_font_t font, bdf_font_t font_italic, bdf_font_t font_bold,
+ bdf_font_t font_bold_italic, int size, dynafont_t *dynafont)
+{
+ error_t err = 0;
+ dynafont_t df;
+ struct bdf_glyph *glyph = NULL;
+
+ if (!font)
+ font = create_system_font ();
+ if (!font || !font->bbox.height)
+ return errno;
+
+ df = malloc (sizeof *df);
+ if (!df)
+ return ENOMEM;
+
+#if QUAERENDO_INVENIETIS
+ add_gnu_head (font);
+#endif
+ bdf_sort_glyphs (font);
+ df->font = font;
+ df->font_italic = font_italic;
+ df->font_bold = font_bold;
+ df->font_bold_italic = font_bold_italic;
+ df->size = size;
+ df->cursor_standout = 0;
+ err = ihash_create (&df->charmap);
+ if (err)
+ {
+ free (df);
+ return err;
+ }
+
+ df->charmap_data = calloc (size, sizeof (struct mapped_character));
+ if (!df->charmap_data)
+ {
+ ihash_free (df->charmap);
+ free (df);
+ return ENOMEM;
+ }
+
+ df->vga_font = malloc (sizeof (vga_font_glyph) * size);
+ if (!df->vga_font)
+ {
+ ihash_free (df->charmap);
+ free (df->charmap_data);
+ free (df);
+ return ENOMEM;
+ }
+ if (df->font->bbox.width == 9)
+ {
+ /* 32 from 256 font slots are for horizontal line graphic
+ characters. */
+ df->use_lgc = 1;
+ df->vga_font_free_indices = df->size
+ - (df->size / 256) * VGA_FONT_LGC_COUNT;
+ df->vga_font_last_free_index = 0;
+ df->vga_font_free_indices_lgc = (df->size / 256) * VGA_FONT_LGC_COUNT;
+ df->vga_font_last_free_index_lgc = VGA_FONT_LGC_BEGIN;
+ }
+ else
+ {
+ df->use_lgc = 0;
+ df->vga_font_free_indices = df->size;
+ df->vga_font_last_free_index = 0;
+ df->vga_font_free_indices_lgc = 0;
+ df->vga_font_last_free_index_lgc = 0;
+ }
+
+ /* Ensure that we always have the replacement character
+ available. */
+ {
+ struct mapped_character *chr = &df->charmap_data[FONT_INDEX_UNKNOWN];
+ df->vga_font_free_indices--;
+ chr->refs = 1;
+
+ glyph = bdf_find_glyph (df->font, UNICODE_REPLACEMENT_CHARACTER, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1, UNICODE_REPLACEMENT_CHARACTER);
+ if (glyph)
+ {
+ /* XXX Take glyph size into account. */
+ for (int i = 0; i < ((df->font->bbox.height > 32)
+ ? 32 : df->font->bbox.height); i++)
+ df->vga_font[FONT_INDEX_UNKNOWN][i]
+ = glyph->bitmap[i * ((df->font->bbox.width + 7) / 8)];
+ if (df->font->bbox.height < 32)
+ memset (((char *) df->vga_font[FONT_INDEX_UNKNOWN])
+ + df->font->bbox.height, 0, 32 - df->font->bbox.height);
+
+ /* Update the hash table. */
+ ihash_add (df->charmap, UNICODE_REPLACEMENT_CHARACTER,
+ chr, &chr->locp);
+ }
+ else
+ {
+ int i;
+ char *gl = df->vga_font[FONT_INDEX_UNKNOWN];
+ /* XXX Take font height into account. */
+ gl[0] = 0x7E; /* ****** */
+ gl[1] = 0xC3; /* ** ** */
+ gl[2] = 0x99; /* * ** * */
+ gl[3] = 0x99; /* * ** * */
+ gl[4] = 0xF9; /* ***** * */
+ gl[5] = 0xF3; /* **** ** */
+ gl[6] = 0xF3; /* *** *** */
+ gl[7] = 0xE7; /* *** *** */
+ gl[8] = 0xFF; /* ******** */
+ gl[9] = 0xE7; /* *** *** */
+ gl[10] = 0xE7; /* *** *** */
+ gl[11] = 0x7E; /* ****** */
+ for (i = 12; i < 32; i++)
+ gl[i] = 0;
+ }
+ }
+
+ *dynafont = df;
+ return err;
+}
+
+
+/* Release a dynafont object and its associated resources. */
+void
+dynafont_free (dynafont_t df)
+{
+ if (active_dynafont == df)
+ active_dynafont = NULL;
+
+ bdf_destroy (df->font);
+ if (df->font_italic)
+ bdf_destroy (df->font_italic);
+ if (df->font_bold)
+ bdf_destroy (df->font_bold);
+ if (df->font_bold_italic)
+ bdf_destroy (df->font_bold_italic);
+ ihash_free (df->charmap);
+ free (df->charmap_data);
+ free (df->vga_font);
+ free (df);
+}
+
+
+/* Determine if CHR is a character that needs to be continuous in the
+ horizontal direction by repeating the last (eighth) column in
+ 9-pixel-width mode. */
+static inline int
+is_lgc (wchar_t chr)
+{
+ /* This list must be sorted for bsearch! */
+ static wchar_t horiz_glyphs[] =
+ {
+ UNICODE_BOX_DRAWINGS_LIGHT_HORIZONTAL, /* 0x2500 */
+ UNICODE_BOX_DRAWINGS_HEAVY_HORIZONTAL, /* 0x2501 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_RIGHT, /* 0x250c */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_HEAVY, /* 0x250d */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_LIGHT, /* 0x250e */
+ UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_RIGHT, /* 0x250f */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_RIGHT, /* 0x2514 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_HEAVY, /* 0x2515 */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_LIGHT, /* 0x2516 */
+ UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_RIGHT, /* 0x2517 */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_RIGHT, /* 0x251c */
+ UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_RIGHT_HEAVY, /* 0x251d */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x251e */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x251f */
+ UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_RIGHT_LIGHT, /* 0x2520 */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_RIGHT_UP_HEAVY, /* 0x2521 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_RIGHT_DOWN_HEAVY, /* 0x2522 */
+ UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_RIGHT, /* 0x2523 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DOWN_AND_HORIZONTAL, /* 0x252c */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_DOWN_LIGHT, /* 0x252d */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_DOWN_LIGHT, /* 0x252e */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x252f */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2530 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_DOWN_HEAVY, /* 0x2531 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_DOWN_HEAVY, /* 0x2532 */
+ UNICODE_BOX_DRAWINGS_HEAVY_DOWN_AND_HORIZONTAL, /* 0x2533 */
+ UNICODE_BOX_DRAWINGS_LIGHT_UP_AND_HORIZONTAL, /* 0x2534 */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x2535 */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_UP_LIGHT, /* 0x2536 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x2537 */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2538 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_UP_HEAVY, /* 0x2539 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_UP_HEAVY, /* 0x253a */
+ UNICODE_BOX_DRAWINGS_HEAVY_UP_AND_HORIZONTAL, /* 0x253b */
+ UNICODE_BOX_DRAWINGS_LIGHT_VERTICAL_AND_HORIZONTAL, /* 0x253c */
+ UNICODE_BOX_DRAWINGS_LEFT_HEAVY_AND_RIGHT_VERTICAL_LIGHT, /* 0x253d */
+ UNICODE_BOX_DRAWINGS_RIGHT_HEAVY_AND_LEFT_VERTICAL_LIGHT, /* 0x253e */
+ UNICODE_BOX_DRAWINGS_VERTICAL_LIGHT_AND_HORIZONTAL_HEAVY, /* 0x253f */
+ UNICODE_BOX_DRAWINGS_UP_HEAVY_AND_DOWN_HORIZONTAL_LIGHT, /* 0x2540 */
+ UNICODE_BOX_DRAWINGS_DOWN_HEAVY_AND_UP_HORIZONTAL_LIGHT, /* 0x2541 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_HEAVY_AND_HORIZONTAL_LIGHT, /* 0x2542 */
+ UNICODE_BOX_DRAWINGS_LEFT_UP_HEAVY_AND_RIGHT_DOWN_LIGHT, /* 0x2543 */
+ UNICODE_BOX_DRAWINGS_RIGHT_UP_HEAVY_AND_LEFT_DOWN_LIGHT, /* 0x2544 */
+ UNICODE_BOX_DRAWINGS_LEFT_DOWN_HEAVY_AND_RIGHT_UP_LIGHT, /* 0x2545 */
+ UNICODE_BOX_DRAWINGS_RIGHT_DOWN_HEAVY_AND_LEFT_UP_LIGHT, /* 0x2546 */
+ UNICODE_BOX_DRAWINGS_DOWN_LIGHT_AND_UP_HORIZONTAL_HEAVY, /* 0x2547 */
+ UNICODE_BOX_DRAWINGS_UP_LIGHT_AND_DOWN_HORIZONTAL_HEAVY, /* 0x2548 */
+ UNICODE_BOX_DRAWINGS_RIGHT_LIGHT_AND_LEFT_VERTICAL_HEAVY, /* 0x2549 */
+ UNICODE_BOX_DRAWINGS_LEFT_LIGHT_AND_RIGHT_VERTICAL_HEAVY, /* 0x254a */
+ UNICODE_BOX_DRAWINGS_HEAVY_VERTICAL_AND_HORIZONTAL, /* 0x254b */
+ UNICODE_BOX_DRAWINGS_DOUBLE_HORIZONTAL, /* 0x2550 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_RIGHT_DOUBLE, /* 0x2552 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_RIGHT_SINGLE, /* 0x2553 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_RIGHT, /* 0x2554 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_RIGHT_DOUBLE, /* 0x2558 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_RIGHT_SINGLE, /* 0x2559 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_RIGHT, /* 0x255a */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_RIGHT_DOUBLE, /* 0x255e */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_RIGHT_SINGLE, /* 0x255f */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_RIGHT, /* 0x2560 */
+ UNICODE_BOX_DRAWINGS_DOWN_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x2564 */
+ UNICODE_BOX_DRAWINGS_DOWN_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x2565 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_DOWN_AND_HORIZONTAL, /* 0x2566 */
+ UNICODE_BOX_DRAWINGS_UP_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x2567 */
+ UNICODE_BOX_DRAWINGS_UP_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x2568 */
+ UNICODE_BOX_DRAWINGS_DOUBLE_UP_AND_HORIZONTAL, /* 0x2569 */
+ UNICODE_BOX_DRAWINGS_VERTICAL_SINGLE_AND_HORIZONTAL_DOUBLE, /* 0x256a */
+ UNICODE_BOX_DRAWINGS_VERTICAL_DOUBLE_AND_HORIZONTAL_SINGLE, /* 0x256b */
+ UNICODE_BOX_DRAWINGS_DOUBLE_VERTICAL_AND_HORIZONTAL, /* 0x256c */
+ UNICODE_BOX_DRAWINGS_LIGHT_ARC_DOWN_AND_RIGHT, /* 0x256d */
+ UNICODE_BOX_DRAWINGS_LIGHT_ARC_UP_AND_RIGHT, /* 0x2570 */
+#if 0
+ /* The diagonal lines don't look much better with or without the
+ ninth column. */
+ /* 0x2571 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_RIGHT_TO_LOWER_LEFT,
+ /* 0x2572 */
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_UPPER_LEFT_TO_LOWER_RIGHT,
+ UNICODE_BOX_DRAWINGS_LIGHT_DIAGONAL_CROSS, /* 0x2573 */
+#endif
+ UNICODE_BOX_DRAWINGS_LIGHT_RIGHT, /* 0x2576 */
+ UNICODE_BOX_DRAWINGS_HEAVY_RIGHT, /* 0x257a */
+ UNICODE_BOX_DRAWINGS_LIGHT_LEFT_AND_HEAVY_RIGHT, /* 0x257c */
+ UNICODE_BOX_DRAWINGS_HEAVY_LEFT_AND_LIGHT_RIGHT, /* 0x257e */
+ UNICODE_UPPER_HALF_BLOCK, /* 0x2580 */
+ UNICODE_LOWER_ONE_EIGHTH_BLOCK, /* 0x2581 */
+ UNICODE_LOWER_ONE_QUARTER_BLOCK, /* 0x2582 */
+ UNICODE_LOWER_THREE_EIGHTHS_BLOCK, /* 0x2583 */
+ UNICODE_LOWER_HALF_BLOCK, /* 0x2584 */
+ UNICODE_LOWER_FIVE_EIGHTHS_BLOCK, /* 0x2585 */
+ UNICODE_LOWER_THREE_QUARTERS_BLOCK, /* 0x2586 */
+ UNICODE_LOWER_SEVEN_EIGHTHS_BLOCK, /* 0x2587 */
+ UNICODE_FULL_BLOCK, /* 0x2588 */
+ UNICODE_RIGHT_HALF_BLOCK, /* 0x2590 */
+#if 0
+ /* The shades don't look much better with or without the ninth
+ column. */
+ UNICODE_LIGHT_SHADE, /* 0x2591 */
+ UNICODE_MEDIUM_SHADE, /* 0x2592 */
+ UNICODE_DARK_SHADE, /* 0x2593 */
+#endif
+ UNICODE_BLACK_SQUARE, /* 0x25a0 */
+ UNICODE_UPPER_ONE_EIGHTH_BLOCK, /* 0x2594 */
+ UNICODE_RIGHT_ONE_EIGHTH_BLOCK, /* 0x2595 */
+ UNICODE_QUADRANT_LOWER_RIGHT, /* 0x2597 */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_LEFT_AND_LOWER_RIGHT, /* 0x2599 */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_LOWER_RIGHT, /* 0x259a */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_LEFT, /* 0x259b */
+ UNICODE_QUADRANT_UPPER_LEFT_AND_UPPER_RIGHT_AND_LOWER_RIGHT, /* 0x259c */
+ UNICODE_QUADRANT_UPPER_RIGHT, /* 0x259d */
+ UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT, /* 0x259e */
+ UNICODE_QUADRANT_UPPER_RIGHT_AND_LOWER_LEFT_AND_LOWER_RIGHT, /* 0x259f */
+ };
+
+ int cmp_wchar (const void *a, const void *b)
+ {
+ const wchar_t *wa = (const wchar_t *) a;
+ const wchar_t *wb = (const wchar_t *) b;
+ return (*wa > *wb) - (*wa < *wb);
+ }
+
+#if QUAERENDO_INVENIETIS
+ /* XXX The (maximum) size is hard coded. */
+ if (chr >= GNU_HEAD_BEGIN && chr <= GNU_HEAD_BEGIN + 50)
+ return 1;
+#endif
+
+ return bsearch (&chr, horiz_glyphs,
+ sizeof (horiz_glyphs) / sizeof (horiz_glyphs[0]),
+ sizeof (horiz_glyphs[0]), cmp_wchar) ? 1 : 0;
+}
+
+
+/* Try to look up glyph CHR in font FONT of dynafont DF with attribute
+ ATTR. This is a helper function for dynafont_lookup. Returns 1 on
+ success, 0 otherwise. */
+static int
+dynafont_lookup_internal (dynafont_t df, bdf_font_t font,
+ wchar_t wide_chr, wchar_t attr, int *rpos)
+{
+ /* When hashing the character, we mix in the font attribute. */
+ struct mapped_character *chr = ihash_find (df->charmap,
+ (int) (wide_chr | attr));
+ int lgc;
+ struct bdf_glyph *glyph;
+ int pos;
+ int found = 0;
+
+ lgc = df->use_lgc ? is_lgc (wide_chr) : 0;
+
+ if (chr)
+ {
+ if (!chr->refs++)
+ {
+ if (lgc)
+ df->vga_font_free_indices_lgc--;
+ else
+ df->vga_font_free_indices--;
+ }
+ /* Return the index of CHR. */
+ *rpos = chr - df->charmap_data;
+ return 1;
+ }
+
+ /* The character is not currently mapped. Look for an empty slot
+ and add it. */
+ if ((lgc && !df->vga_font_free_indices_lgc)
+ || (!lgc && !df->vga_font_free_indices))
+ return 0;
+
+ glyph = bdf_find_glyph (font, (int) wide_chr, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (font, -1, (int) wide_chr);
+ if (!glyph)
+ return 0;
+
+ if (lgc)
+ {
+ int start_pos = df->vga_font_last_free_index_lgc + 1;
+ if ((start_pos % VGA_FONT_SIZE)
+ == VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ {
+ start_pos += VGA_FONT_SIZE - VGA_FONT_LGC_COUNT;
+ start_pos %= df->size;
+ }
+ pos = start_pos;
+
+ do
+ {
+ if (df->charmap_data[pos].refs == 0)
+ {
+ found = 1;
+ break;
+ }
+ pos++;
+ if ((pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN + VGA_FONT_LGC_COUNT)
+ {
+ pos += VGA_FONT_SIZE - VGA_FONT_LGC_COUNT;
+ pos %= df->size;
+ }
+ }
+ while (pos != start_pos);
+
+ assert (found);
+ df->vga_font_free_indices_lgc--;
+ df->vga_font_last_free_index_lgc = pos;
+ }
+ else
+ {
+ int start_pos = (df->vga_font_last_free_index + 1) % df->size;
+ if (df->use_lgc && (start_pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN)
+ start_pos += VGA_FONT_LGC_COUNT;
+ pos = start_pos;
+
+ do
+ {
+ if (df->charmap_data[pos].refs == 0)
+ {
+ found = 1;
+ break;
+ }
+ pos = (pos + 1) % df->size;
+ if (df->use_lgc && (pos % VGA_FONT_SIZE) == VGA_FONT_LGC_BEGIN)
+ pos += VGA_FONT_LGC_COUNT;
+ }
+ while (pos != start_pos);
+
+ assert (found);
+ df->vga_font_free_indices--;
+ df->vga_font_last_free_index = pos;
+ }
+
+ /* Ok, we found a new entry, use it. */
+ chr = &df->charmap_data[pos];
+ chr->refs = 1;
+ chr->character = (wide_chr | attr);
+
+ /* XXX Should look at glyph bbox. */
+ for (int i = 0; i < ((font->bbox.height > 32)
+ ? 32 : font->bbox.height); i++)
+ df->vga_font[pos][i]
+ = glyph->bitmap[i * ((font->bbox.width + 7) / 8)];
+ if (font->bbox.height < 32)
+ memset (((char *) df->vga_font[pos])
+ + font->bbox.height, 0, 32 - font->bbox.height);
+
+ if (active_dynafont == df)
+ vga_write_font_buffer (0, pos, df->vga_font[pos],
+ VGA_FONT_HEIGHT);
+ /* Update the hash table. */
+ if (chr->locp)
+ ihash_locp_remove (df->charmap, chr->locp);
+ ihash_add (df->charmap, (int) (wide_chr | attr), chr, &chr->locp);
+ *rpos = pos;
+ return 1;
+}
+
+/* Look up the vga font index for an UCS-4 character. If not already
+ mapped, try to find space for a new entry and add the mapping.
+ Acquires an additional reference to the character. Might return
+ the glyph for the unrepresentable character if the glyph is ot
+ available for this character or no free slot is available right
+ now. In the former case, some information gets lost (to do
+ otherwise, one would have to either assign one of the scarce font
+ indices to each undisplayable character value on screen, or to
+ store the whole scrollback buffer as wide chars as well to recover
+ the lost info from that copy of the original text. */
+int
+dynafont_lookup (dynafont_t df, conchar_t *conchr)
+{
+ wchar_t attr = (conchr->attr.italic ? WCHAR_ITALIC : 0)
+ | (conchr->attr.bold ? WCHAR_BOLD : 0);
+ int found = 0;
+ int pos = FONT_INDEX_UNKNOWN;
+
+ if (attr == (WCHAR_BOLD | WCHAR_ITALIC) && df->font_bold_italic)
+ found = dynafont_lookup_internal (df, df->font_bold_italic,
+ conchr->chr, WCHAR_BOLD | WCHAR_ITALIC,
+ &pos);
+ /* This order will prefer bold over italic if both are requested but
+ are not available at the same time. The other order is just as
+ good. XXX. */
+ if (!found && (attr & WCHAR_BOLD) && df->font_bold)
+ found = dynafont_lookup_internal (df, df->font_bold,
+ conchr->chr, WCHAR_BOLD, &pos);
+ if (!found && (attr & WCHAR_ITALIC) && df->font_italic)
+ found = dynafont_lookup_internal (df, df->font_italic,
+ conchr->chr, WCHAR_ITALIC, &pos);
+ if (!found)
+ found = dynafont_lookup_internal (df, df->font, conchr->chr, 0, &pos);
+ if (!found)
+ {
+ df->charmap_data[FONT_INDEX_UNKNOWN].refs++;
+ pos = FONT_INDEX_UNKNOWN;
+ }
+ return pos;
+}
+
+
+/* Release a reference to the glyph VGA_FONT_INDEX in dynafont DF. */
+void
+dynafont_release (dynafont_t df, int vga_font_index)
+{
+ if (! --df->charmap_data[vga_font_index].refs)
+ {
+ if (df->use_lgc
+ && is_lgc (df->charmap_data[vga_font_index].character & WCHAR_MASK))
+ df->vga_font_free_indices_lgc++;
+ else
+ df->vga_font_free_indices++;
+ }
+}
+
+
+
+/* Set the cursor to normal if STANDOUT is zero, or to a block cursor
+ otherwise. */
+void
+dynafont_set_cursor (dynafont_t df, int standout)
+{
+ int height = (df->font->bbox.height > 32) ? 32 : df->font->bbox.height;
+
+ df->cursor_standout = standout;
+
+ if (df == active_dynafont)
+ {
+ if (standout)
+ vga_set_cursor_size (1, -1);
+ else
+ vga_set_cursor_size ((height >= 2) ? height - 2 : 0, -1);
+ }
+}
+
+
+/* Load the VGA font to the card and make it active. */
+void
+dynafont_activate (dynafont_t df)
+{
+ int height = (df->font->bbox.height > 32) ? 32 : df->font->bbox.height;
+
+ vga_write_font_buffer (0, 0, (char *) df->vga_font,
+ df->size * VGA_FONT_HEIGHT);
+ vga_select_font_buffer (0, (df->size == 512) ? 1 : 0);
+
+ /* XXX Changing the font height below 13 or above 16 will cause
+ display problems for the user if we don't also program the video
+ mode timings. The standard font height for 80x25 is 16. */
+ vga_set_font_height (height);
+ vga_set_font_width (df->font->bbox.width <= 8 ? 8 : 9);
+
+ active_dynafont = df;
+ dynafont_set_cursor (df, df->cursor_standout);
+}
+
+
+#if 0
+/* XXX This code is deactivated because it needs to be changed to
+ allow the italic and bold code, too. */
+
+/* Change the font used by dynafont DF to FONT. This transformation
+ is initially loss-less, if the new font can't display some
+ characters on the screen, you can always go back to a font that
+ does and get the glyphs for those characters back. (However, the
+ comments in dynafont_lookup hold for glyphs looked up after the font
+ change.) */
+void
+dynafont_change_font (dynafont_t df, bdf_font_t font)
+{
+ int i;
+
+ df->font = font;
+ for (i = 0; i < df->size; i++)
+ {
+ /* If we don't derive the unknown or space glyph from the font,
+ we don't update it. */
+#ifndef ENCODING_UNKNOWN
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+ if (! df->charmap_data[i].refs)
+ {
+ /* The glyph is not used. If it is mapped, we need to
+ remove the mapping to invalidate the glyph. */
+ if (df->charmap_data[i].locp)
+ ihash_locp_remove (df->charmap, df->charmap_data[i].locp);
+ }
+
+ else
+ {
+ /* The glyph is mapped and in use. We will not destroy the
+ mapping, but just override the glyph in the VGA font.
+ This way the user can recover from loading a bad font by
+ going back to a better one. */
+ struct bdf_glyph *glyph;
+ glyph = bdf_find_glyph (df->font,
+ (int) df->charmap_data[i].character, 0);
+ if (!glyph)
+ glyph = bdf_find_glyph (df->font, -1,
+ (int) df->charmap_data[i].character);
+ if (!glyph)
+ {
+#ifdef ENCODING_UNKNOWN
+ /* The new font doesn't have a representation for the
+ unknown glyph at the desired place, so keep the old
+ one. XXX Should load the built-in one here. */
+ if (i == FONT_INDEX_UNKNOWN)
+ continue;
+#endif
+ memcpy (df->vga_font[i], df->vga_font[FONT_INDEX_UNKNOWN], 32);
+ }
+ else
+ {
+ /* XXX Take font size and glyph size into account. */
+ for (int j = 0; j < ((df->font->bbox.height > 32)
+ ? 32 : df->font->bbox.height); j++)
+ df->vga_font[i][j]
+ = glyph->bitmap[j * ((df->font->bbox.width + 7) / 8)];
+ if (df->font->bbox.height < 32)
+ memset (((char *) df->vga_font[i]) + df->font->bbox.height,
+ 0, 32 - df->font->bbox.height);
+ }
+ }
+ }
+
+ if (active_dynafont == df)
+ /* Refresh the card info. */
+ dynafont_activate (df);
+}
+#endif
diff --git a/console-client/vga-dynafont.h b/console-client/vga-dynafont.h
new file mode 100644
index 00000000..c2bab700
--- /dev/null
+++ b/console-client/vga-dynafont.h
@@ -0,0 +1,83 @@
+/* vga-dynafont.h - Interface to the dynamic font handling for VGA cards.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_DYNAFONT_H_
+#define _VGA_DYNAFONT_H_ 1
+
+#include <wchar.h>
+
+#include "bdf.h"
+
+
+/* The dynafont interface does not do locking on its own, for maximum
+ efficiency it relies on locking by the caller (because usually the
+ caller has some other data structures to lock along with the
+ dynafont. However, it is safe to call two functions on different
+ dynafonts asynchronously. */
+typedef struct dynafont *dynafont_t;
+
+/* The representation for the unknown glyph is always at the same
+ location. */
+#define FONT_INDEX_UNKNOWN 0
+
+/* Create a new dynafont object, which uses glyphs from the font FONT
+ (which must be 8 pixels wide and up to 32 pixels heigh). SIZE is
+ either 256 or 512, and specifies the number of available glyphs in
+ the font cache. The object is returned in DYNAFONT. The caller
+ must ensure the integrity of FONT until the object is destroyed or
+ the font is changed with dynafont_change_font. */
+error_t dynafont_new (bdf_font_t font, bdf_font_t font_italic,
+ bdf_font_t font_bold, bdf_font_t font_bold_italic,
+ int size, dynafont_t *dynafont);
+
+/* Release a dynafont object and its associated resources. */
+void dynafont_free (dynafont_t df);
+
+/* Look up the vga font index for an UCS-4 character. If not already
+ mapped, try to find space for a new entry and add the mapping.
+ Acquires an additional reference to the character. Might return
+ the glyph for the unrepresentable character if the glyph is ot
+ available for this character or no free slot is available right
+ now. In the former case, some information gets lost (to do
+ otherwise, one would have to either assign one of the scarce font
+ indices to each undisplayable character value on screen, or to
+ store the whole scrollback buffer as wide chars as well to recover
+ the lost info from that copy of the original text. */
+int dynafont_lookup (dynafont_t df, conchar_t *chr);
+
+/* Release a reference to the glyph VGA_FONT_INDEX in dynafont DF. */
+void dynafont_release (dynafont_t df, int vga_font_index);
+
+/* Load the VGA font to the card and make it active. */
+void dynafont_activate (dynafont_t df);
+
+/* Set the cursor to normal if STANDOUT is zero, or to a block cursor
+ otherwise. */
+void dynafont_set_cursor (dynafont_t df, int standout);
+
+/* Change the font used by dynafont DF to FONT. This transformation
+ is initially loss-less, if the new font can't display some
+ characters on the screen, you can always go back to a font that
+ does and get the glyphs for those characters back. (However, the
+ comments in dynafont_lookup hold for glyphs looked up after the font
+ change.) */
+void dynafont_change_font (dynafont_t df, bdf_font_t font);
+
+#endif /* _VGA_DYNAFONT_H_ */
diff --git a/console-client/vga-hw.h b/console-client/vga-hw.h
new file mode 100644
index 00000000..6be87d31
--- /dev/null
+++ b/console-client/vga-hw.h
@@ -0,0 +1,139 @@
+/* vga-hw.h - Definitions for the VGA hardware.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_HW_H_
+#define _VGA_HW_H_ 1
+
+#define VGA_VIDEO_MEM_BASE_ADDR 0x0a0000
+#define VGA_VIDEO_MEM_LENGTH 0x004000
+
+#define VGA_FONT_BUFFER 8
+#define VGA_FONT_SIZE 256
+#define VGA_FONT_HEIGHT 32
+#define VGA_FONT_LGC_BEGIN 0xc0
+#define VGA_FONT_LGC_COUNT 32
+
+#define VGA_MIN_REG 0x3c0
+#define VGA_MAX_REG 0x3df
+
+/* The sequencer address register selects the sub-register of the
+ sequencer that is accessed through the sequencer data register. */
+#define VGA_SEQ_ADDR_REG 0x3c4
+#define VGA_SEQ_DATA_REG 0x3c5
+
+/* The reset subregister can be used to asynchronously or
+ synchronously halt or clear the sequencer. */
+#define VGA_SEQ_RESET_ADDR 0x00
+#define VGA_SEQ_RESET_ASYNC 0x10 /* Can cause loss of video data. */
+#define VGA_SEQ_RESET_SYNC 0x01
+#define VGA_SEQ_RESET_CLEAR 0x11 /* Sequencer can operate. */
+
+/* The clocking mode subregister. */
+#define VGA_SEQ_CLOCK_MODE_ADDR 0x01
+#define VGA_SEQ_CLOCK_MODE_8 0x01 /* 8-pixel width for fonts. */
+
+/* The map subregister specifies which planes are written to. */
+#define VGA_SEQ_MAP_ADDR 0x02
+#define VGA_SEQ_MAP_PLANE0 0x01
+#define VGA_SEQ_MAP_PLANE1 0x02
+#define VGA_SEQ_MAP_PLANE2 0x04
+#define VGA_SEQ_MAP_PLANE3 0x08
+
+/* The font subregister. */
+#define VGA_SEQ_FONT_ADDR 0x03
+
+/* The memory mode subregister specifies the way that memory is
+ accessed. */
+#define VGA_SEQ_MODE_ADDR 0x04
+#define VGA_SEQ_MODE_EXT 0x02 /* Access 265kB rather than 64kB. */
+#define VGA_SEQ_MODE_SEQUENTIAL 0x04 /* Sequential, not odd/even addr. */
+#define VGA_SEQ_MODE_CHAIN4 0x08 /* Chain 4 addressing. */
+
+
+/* The graphics address register selects the sub-register that is
+ accessed through the graphics data register. */
+#define VGA_GFX_ADDR_REG 0x3ce
+#define VGA_GFX_DATA_REG 0x3cf
+
+/* The map subregister selects the plane to read from. */
+#define VGA_GFX_MAP_ADDR 0x04
+#define VGA_GFX_MAP_PLANE0 0x00
+#define VGA_GFX_MAP_PLANE1 0x01
+#define VGA_GFX_MAP_PLANE2 0x02
+#define VGA_GFX_MAP_PLANE3 0x03
+
+/* The mode subregister selects the memory access mode. */
+#define VGA_GFX_MODE_ADDR 0x05
+#define VGA_GFX_MODE_SHIFT256 0x40
+#define VGA_GFX_MODE_SHIFT 0x20
+#define VGA_GFX_MODE_HOSTOE 0x10
+#define VGA_GFX_MODE_READ0 0x00
+#define VGA_GFX_MODE_READ1 0x08
+#define VGA_GFX_MODE_WRITE0 0x00
+#define VGA_GFX_MODE_WRITE1 0x01
+#define VGA_GFX_MODE_WRITE2 0x02
+#define VGA_GFX_MODE_WRITE3 0x03
+
+/* The miscellaneous subregister. */
+#define VGA_GFX_MISC_ADDR 0x06
+#define VGA_GFX_MISC_GFX 0x01 /* Switch on graphics mode. */
+#define VGA_GFX_MISC_CHAINOE 0x02
+#define VGA_GFX_MISC_A0TOBF 0x00
+#define VGA_GFX_MISC_A0TOAF 0x04
+#define VGA_GFX_MISC_B0TOB7 0x08
+#define VGA_GFX_MISC_B8TOBF 0x0c
+
+
+/* The CRTC Registers. XXX Depends on the I/O Address Select field.
+ However, the only need to use the other values is for compatibility
+ with monochrome adapters. */
+#define VGA_CRT_ADDR_REG 0x3d4
+#define VGA_CRT_DATA_REG 0x3d5
+
+/* The maximum scan line subregister. */
+#define VGA_CRT_MAX_SCAN_LINE 0x09
+
+/* The cursor start subregister. */
+#define VGA_CRT_CURSOR_START 0x0a
+#define VGA_CRT_CURSOR_DISABLE 0x20
+
+/* The cursor end subregister. */
+#define VGA_CRT_CURSOR_END 0x0b
+
+/* The cursor position subregisters. */
+#define VGA_CRT_CURSOR_HIGH 0x0e
+#define VGA_CRT_CURSOR_LOW 0x0f
+
+
+/* The DAC Registers. */
+#define VGA_DAC_WRITE_ADDR_REG 0x3c8
+#define VGA_DAC_READ_ADDR_REG 0x3c7
+#define VGA_DAC_DATA_REG 0x3c9
+
+
+/* The Attribute Registers. */
+#define VGA_ATTR_ADDR_DATA_REG 0x3c0
+#define VGA_ATTR_DATA_READ_REG 0x3c1
+
+
+/* Other junk. */
+#define VGA_INPUT_STATUS_1_REG 0x3da
+
+#endif /* _VGA_HW_H_ */
diff --git a/console-client/vga-support.c b/console-client/vga-support.c
new file mode 100644
index 00000000..babdfa46
--- /dev/null
+++ b/console-client/vga-support.c
@@ -0,0 +1,480 @@
+/* vga-support.c - VGA hardware access.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <errno.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/io.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <string.h>
+
+#include "vga-hw.h"
+#include "vga-support.h"
+
+
+/* The base of the video memory mapping. */
+char *vga_videomem;
+
+/* The saved state of the VGA card. */
+struct vga_state
+{
+ unsigned char seq_clock_mode;
+ unsigned char seq_map;
+ unsigned char seq_font;
+ unsigned char seq_mode;
+
+ unsigned char gfx_map;
+ unsigned char gfx_mode;
+ unsigned char gfx_misc;
+
+ unsigned char crt_max_scan_line;
+ unsigned char crt_cursor_start;
+ unsigned char crt_cursor_end;
+ unsigned char crt_cursor_high;
+ unsigned char crt_cursor_low;
+
+ char videomem[2 * 80 * 25];
+ unsigned char fontmem[2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT];
+};
+
+static struct vga_state *vga_state;
+
+
+#if OSKIT_MACH
+#else
+
+#include <device/device.h>
+#include <hurd.h>
+
+/* Constants from Mach. */
+#define VIDMMAP_BEGIN 0xA0000
+#define VIDMMAP_SIZE (0xC0000 - 0xA0000)
+#define VIDMMAP_KDOFS 0xA0000 /* == kd_bitmap_start in mach/i386/i386at/kd.c */
+
+#endif
+
+error_t
+vga_init (void)
+{
+ error_t err;
+#if OSKIT_MACH
+ int fd;
+#else
+ device_t device_master = MACH_PORT_NULL;
+ memory_object_t kd_mem = MACH_PORT_NULL;
+ static device_t kd_device = MACH_PORT_NULL;
+ vm_address_t mapped;
+#endif
+
+#if OSKIT_MACH
+ if (ioperm (VGA_MIN_REG, VGA_MAX_REG - VGA_MIN_REG + 1, 1) < 0)
+ {
+ free (vga_state);
+ return errno;
+ }
+
+ fd = open ("/dev/mem", O_RDWR);
+ if (fd < 0)
+ return errno;
+ vga_videomem = mmap (0, VGA_VIDEO_MEM_LENGTH, PROT_READ | PROT_WRITE,
+ MAP_SHARED, fd, VGA_VIDEO_MEM_BASE_ADDR);
+ err = errno;
+ close (fd);
+ if (vga_videomem == (void *) -1)
+ return err;
+#else
+ err = get_privileged_ports (0, &device_master);
+ if (err)
+ return err;
+
+ err = device_open (device_master, D_WRITE, "kd", &kd_device);
+ if (err)
+ return err;
+
+ err = device_map (kd_device, VM_PROT_READ | VM_PROT_WRITE,
+ VIDMMAP_BEGIN - VIDMMAP_KDOFS, VIDMMAP_SIZE,
+ &kd_mem, 0);
+ if (err)
+ return err;
+
+ err = vm_map (mach_task_self (), &mapped, VIDMMAP_SIZE,
+ 0, 1, kd_mem, VIDMMAP_BEGIN - VIDMMAP_KDOFS, 0,
+ VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE,
+ VM_INHERIT_NONE);
+ if (err)
+ return err;
+
+ vga_videomem = (char *) mapped;
+ assert (vga_videomem != NULL);
+
+ mach_port_deallocate (mach_task_self (), device_master);
+ mach_port_deallocate (mach_task_self (), kd_mem);
+#endif
+
+ /* Save the current state. */
+ vga_state = malloc (sizeof (*vga_state));
+ if (!vga_state)
+ return errno;
+
+ outb (VGA_SEQ_CLOCK_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_clock_mode = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_map = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_FONT_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_font = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ vga_state->seq_mode = inb (VGA_SEQ_DATA_REG);
+
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ vga_state->gfx_map = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ vga_state->gfx_mode = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ vga_state->gfx_misc = inb (VGA_GFX_DATA_REG);
+
+ outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG);
+ vga_state->crt_max_scan_line = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_start = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_end = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_high = inb (VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG);
+ vga_state->crt_cursor_low = inb (VGA_CRT_DATA_REG);
+
+ /* Read/write in interleaved mode. */
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (VGA_GFX_MISC_CHAINOE | VGA_GFX_MISC_A0TOAF, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb (VGA_GFX_MODE_HOSTOE, VGA_GFX_DATA_REG);
+
+ memcpy (vga_state->videomem, vga_videomem, 2 * 80 * 25);
+ vga_read_font_buffer (0, 0, vga_state->fontmem,
+ 2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT);
+
+ /* 80 cols, 25 rows, two bytes per cell and twice because with lower
+ max scan line we get more lines on the screen. */
+ memset (vga_videomem, 0, 80 * 25 * 2 * 2);
+
+ return 0;
+}
+
+
+/* Release the resources and privileges associated with the VGA
+ hardware access. */
+void
+vga_fini (void)
+{
+ /* Recover the saved state. */
+ vga_write_font_buffer (0, 0, vga_state->fontmem,
+ 2 * VGA_FONT_SIZE * VGA_FONT_HEIGHT);
+ memcpy (vga_videomem, vga_state->videomem, 2 * 80 * 25);
+
+ /* Restore the registers. */
+ outb (VGA_SEQ_CLOCK_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_clock_mode, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_map, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_FONT_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_font, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ outb (vga_state->seq_mode, VGA_SEQ_DATA_REG);
+
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ outb (vga_state->gfx_map, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb (vga_state->gfx_mode, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (vga_state->gfx_misc, VGA_GFX_DATA_REG);
+
+ outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_max_scan_line, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_start, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_end, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_high, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG);
+ outb (vga_state->crt_cursor_low, VGA_CRT_DATA_REG);
+
+ ioperm (VGA_MIN_REG, VGA_MAX_REG, 0);
+ munmap (vga_videomem, VGA_VIDEO_MEM_LENGTH);
+}
+
+
+/* Write DATALEN bytes from DATA to the font buffer BUFFER, starting
+ from glyph INDEX. */
+void
+vga_write_font_buffer (int buffer, int index, char *data, size_t datalen)
+{
+ char saved_seq_map;
+ char saved_seq_mode;
+ char saved_gfx_mode;
+ char saved_gfx_misc;
+
+ int offset = buffer * VGA_FONT_SIZE + index * VGA_FONT_HEIGHT;
+ assert (offset >= 0 && offset + datalen <= VGA_VIDEO_MEM_LENGTH);
+
+ /* Select plane 2 for sequential writing. */
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ saved_seq_map = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MAP_PLANE2, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ saved_seq_mode = inb (VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_SEQUENTIAL | VGA_SEQ_MODE_EXT | 0x1 /* XXX Why? */,
+ VGA_SEQ_DATA_REG);
+
+ /* Set write mode 0, but assume that rotate count, enable set/reset,
+ logical operation and bit mask fields are set to their
+ `do-not-modify-host-value' default. The misc register is set to
+ select sequential addressing in text mode. */
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_mode = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_WRITE0, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_misc = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_A0TOAF, VGA_GFX_DATA_REG);
+
+ memcpy (vga_videomem + offset, data, datalen);
+
+ /* Restore sequencer and graphic register values. */
+ outb (VGA_SEQ_MAP_ADDR, VGA_SEQ_ADDR_REG);
+ outb (saved_seq_map, VGA_SEQ_DATA_REG);
+ outb (VGA_SEQ_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ outb (saved_seq_mode, VGA_SEQ_DATA_REG);
+
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_mode, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_misc, VGA_GFX_DATA_REG);
+}
+
+
+/* Read DATALEN bytes into DATA from the font buffer BUFFER, starting
+ from glyph INDEX. */
+void
+vga_read_font_buffer (int buffer, int index, char *data, size_t datalen)
+{
+ char saved_gfx_map;
+ char saved_gfx_mode;
+ char saved_gfx_misc;
+
+ int offset = buffer * VGA_FONT_SIZE + index * VGA_FONT_HEIGHT;
+ assert (offset >= 0 && offset + datalen <= VGA_VIDEO_MEM_LENGTH);
+
+ /* Read sequentially from plane 2. */
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_map = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MAP_PLANE2, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_mode = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_READ0, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ saved_gfx_misc = inb (VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_A0TOBF, VGA_GFX_DATA_REG);
+
+ memcpy (data, vga_videomem + offset, datalen);
+
+ outb (VGA_GFX_MAP_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_map, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MODE_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_mode, VGA_GFX_DATA_REG);
+ outb (VGA_GFX_MISC_ADDR, VGA_GFX_ADDR_REG);
+ outb (saved_gfx_misc, VGA_GFX_DATA_REG);
+}
+
+
+/* Set FONT_BUFFER_SUPP to FONT_BUFFER if the font is small. */
+void
+vga_select_font_buffer (int font_buffer, int font_buffer_supp)
+{
+ char font = ((font_buffer & 6) >> 1) | ((font_buffer & 1) << 4)
+ | ((font_buffer_supp & 6) << 1) | ((font_buffer_supp & 1) << 5);
+
+ outb (VGA_SEQ_FONT_ADDR, VGA_SEQ_ADDR_REG);
+ outb (font, VGA_SEQ_DATA_REG);
+}
+
+/* Set the font height in pixel. */
+void
+vga_set_font_height (int height)
+{
+ char saved;
+
+ outb (VGA_CRT_MAX_SCAN_LINE, VGA_CRT_ADDR_REG);
+ saved = inb (VGA_CRT_DATA_REG);
+ saved &= ~31;
+ saved |= (height - 1) & 31;
+ outb (saved, VGA_CRT_DATA_REG);
+}
+
+
+/* Set the font height in pixel. WIDTH can be 8 or 9. */
+void
+vga_set_font_width (int width)
+{
+ char saved;
+
+ if (width != 8 && width != 9)
+ return;
+
+ outb (VGA_SEQ_CLOCK_MODE_ADDR, VGA_SEQ_ADDR_REG);
+ saved = inb (VGA_SEQ_DATA_REG);
+ if (width == 8)
+ saved |= VGA_SEQ_CLOCK_MODE_8;
+ else
+ saved &= ~VGA_SEQ_CLOCK_MODE_8;
+ outb (saved, VGA_SEQ_DATA_REG);
+}
+
+
+/* Enable (if ON is true) or disable (otherwise) the cursor. Expects
+ the VGA hardware to be locked. */
+void
+vga_display_cursor (int on)
+{
+ char crs_start;
+
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ crs_start = inb (VGA_CRT_DATA_REG);
+ if (on)
+ crs_start &= ~VGA_CRT_CURSOR_DISABLE;
+ else
+ crs_start |= VGA_CRT_CURSOR_DISABLE;
+ outb (crs_start, VGA_CRT_DATA_REG);
+}
+
+
+/* Set cursor size from START to END (set to -1 to not set one of the
+ values). */
+void
+vga_set_cursor_size (int start, int end)
+{
+ char saved;
+
+ if (start >= 0)
+ {
+ outb (VGA_CRT_CURSOR_START, VGA_CRT_ADDR_REG);
+ saved = inb (VGA_CRT_DATA_REG);
+ saved &= ~31;
+ saved |= start & 31;
+ outb (saved, VGA_CRT_DATA_REG);
+ }
+ if (end >= 0)
+ {
+ outb (VGA_CRT_CURSOR_END, VGA_CRT_ADDR_REG);
+ saved = inb (VGA_CRT_DATA_REG);
+ saved &= ~31;
+ saved |= end & 31;
+ outb (saved, VGA_CRT_DATA_REG);
+ }
+}
+
+
+/* Set the cursor position to POS, which is (x_pos + y_pos * width). */
+void
+vga_set_cursor_pos (unsigned int pos)
+{
+ outb (VGA_CRT_CURSOR_HIGH, VGA_CRT_ADDR_REG);
+ outb (pos >> 8, VGA_CRT_DATA_REG);
+ outb (VGA_CRT_CURSOR_LOW, VGA_CRT_ADDR_REG);
+ outb (pos & 0xff, VGA_CRT_DATA_REG);
+}
+
+
+/* Read NR entries from the color palette, starting from INDEX. DATA
+ must be able to hold at least 3 * NR bytes and will contain the
+ desired colors in RGB form. Only the lower six bits of each
+ component are significant. */
+void
+vga_read_palette (unsigned char index, unsigned char *data, int nr)
+{
+ /* Every color has three components. */
+ nr *= 3;
+
+ outb (index, VGA_DAC_READ_ADDR_REG);
+ while (nr--)
+ *(data++) = inb (VGA_DAC_DATA_REG);
+}
+
+
+/* Write NR entries to the color palette, starting from INDEX. DATA
+ must be at least 3 * NR of bytes long and contains the desired
+ colors in RGB form. Only the lower six bits for each component are
+ significant. */
+void
+vga_write_palette (unsigned char index, const unsigned char *data, int nr)
+{
+ /* Every color has three components. */
+ nr *= 3;
+
+ outb (index, VGA_DAC_WRITE_ADDR_REG);
+ while (nr--)
+ outb (*(data++), VGA_DAC_DATA_REG);
+}
+
+
+/* Exchange NR entries in the internal palette with the values in
+ PALETTE_ATTR, starting from the internal palette entry INDEX (which
+ can be betweern 0 and 15). Only the lower six bits of each entry
+ in PALETTE_ATTR is significant.
+
+ The internal palette entry is used to look up a color in the
+ palette for the color attribute in text mode with the corresponding
+ value.
+
+ Example: The attribute byte specifies 3 as the foreground color.
+ This means that the character with this attribute gets the color of
+ the palette entry specified by the internal palette entry 3 (the
+ fourth one). */
+void
+vga_exchange_palette_attributes (unsigned char index,
+ unsigned char *palette_attr,
+ int nr)
+{
+ if (!nr)
+ return;
+
+ /* We want to read and change the palette attribute register. */
+ while (nr--)
+ {
+ unsigned char attr;
+
+ /* Side effect of reading the input status #1 register is to
+ reset the attribute mixed address/data register so that the
+ next write it expects is the address, not the data. */
+ inb (VGA_INPUT_STATUS_1_REG);
+
+ /* Set the address. */
+ outb (index++, VGA_ATTR_ADDR_DATA_REG);
+ attr = inb (VGA_ATTR_DATA_READ_REG);
+ outb ((attr & ~077) | (*palette_attr & 077), VGA_ATTR_ADDR_DATA_REG);
+ *(palette_attr++) = attr & 077;
+ }
+
+ /* Re-enable the screen, which was blanked during the palette
+ operation. */
+ inb (VGA_INPUT_STATUS_1_REG);
+ outb (0x20, VGA_ATTR_ADDR_DATA_REG);
+}
diff --git a/console-client/vga-support.h b/console-client/vga-support.h
new file mode 100644
index 00000000..51dec782
--- /dev/null
+++ b/console-client/vga-support.h
@@ -0,0 +1,86 @@
+/* vga-support.h - Interface for VGA hardware access.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _VGA_SUPPORT_H_
+#define _VGA_SUPPORT_H_ 1
+
+#include <errno.h>
+#include <sys/types.h>
+
+
+/* The VGA interface does not do locking on its own, for maximum
+ efficiency it relies on locking by the caller (because usually the
+ caller has some other data structures to lock along with the
+ VGA hardware. */
+
+/* The mapped video memory. */
+extern char *vga_videomem;
+
+/* Initialize the VGA hardware and set up the permissions and memory
+ mappings. */
+error_t vga_init (void);
+
+/* Release the resources and privileges associated with the VGA
+ hardware access. */
+void vga_fini (void);
+
+/* Write DATALEN bytes from DATA to the font buffer BUFFER, starting
+ from glyph index. */
+void vga_write_font_buffer (int buffer, int index,
+ char *data, size_t datalen);
+
+/* Read DATALEN bytes into DATA from the font buffer BUFFER, starting
+ from glyph INDEX. */
+void vga_read_font_buffer (int buffer, int index,
+ char *data, size_t datalen);
+
+/* Set FONT_BUFFER_SUPP to FONT_BUFFER if the font is small. */
+void vga_select_font_buffer (int font_buffer, int font_buffer_supp);
+
+/* Set the font height in pixel. */
+void vga_set_font_height (int height);
+
+/* Set the font height in pixel. WIDTH can be 8 or 9. */
+void vga_set_font_width (int width);
+
+/* Enable (if ON is true) or disable (otherwise) the cursor. Expects
+ the VGA hardware to be locked. */
+void vga_display_cursor (int on);
+
+/* Set cursor size from START to END (set to -1 to not set one of the
+ values). */
+void vga_set_cursor_size (int start, int end);
+
+/* Set the cursor position to POS, which is (x_pos + y_pos *
+ width). */
+void vga_set_cursor_pos (unsigned int pos);
+
+/* Read NR entries from the color palette, starting from INDEX. */
+void vga_read_palette (unsigned char index, unsigned char *data, int nr);
+
+/* Write NR entries to the color palette, starting from INDEX. */
+void vga_write_palette (unsigned char index,
+ const unsigned char *data, int nr);
+
+void vga_exchange_palette_attributes (unsigned char index,
+ unsigned char *saved_palette_attr,
+ int nr);
+
+#endif /* _VGA_SUPPORT_H_ */
diff --git a/console-client/vga.c b/console-client/vga.c
new file mode 100644
index 00000000..304adbc1
--- /dev/null
+++ b/console-client/vga.c
@@ -0,0 +1,573 @@
+/* vga.c - The VGA device display driver.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ This file is part of the GNU Hurd.
+
+ The GNU Hurd 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 2, or (at
+ your option) any later version.
+
+ The GNU Hurd 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <iconv.h>
+#include <argp.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <sys/io.h>
+#include <sys/mman.h>
+#include <sys/fcntl.h>
+#include <cthreads.h>
+#include <hurd/console.h>
+
+#include "driver.h"
+#include "timer.h"
+
+#include "vga-hw.h"
+#include "vga-support.h"
+#include "bdf.h"
+#include "vga-dynafont.h"
+#include "vga-dynacolor.h"
+#include "unicode.h"
+
+
+#define VGA_DISP_WIDTH 80
+#define VGA_DISP_HEIGHT 25
+
+/* The font file. */
+#define DEFAULT_VGA_FONT "/lib/hurd/fonts/vga-system.bdf"
+static char *vga_display_font;
+
+#define DEFAULT_VGA_FONT_ITALIC "/lib/hurd/fonts/vga-system-italic.bdf"
+static char *vga_display_font_italic;
+
+#define DEFAULT_VGA_FONT_BOLD "/lib/hurd/fonts/vga-system-bold.bdf"
+static char *vga_display_font_bold;
+
+#define DEFAULT_VGA_FONT_BOLD_ITALIC \
+ "/lib/hurd/fonts/vga-system-bold-italic.bdf"
+static char *vga_display_font_bold_italic;
+
+/* The timer used for flashing the screen. */
+static struct timer_list vga_display_timer;
+
+/* The lock that protects the color palette manipulation. */
+static struct mutex vga_display_lock;
+
+/* Forward declaration. */
+static struct display_ops vga_display_ops;
+
+
+struct refchr
+{
+ unsigned int used : 1;
+ unsigned int chr : 9;
+ unsigned int attr : 8;
+};
+
+
+struct vga_display
+{
+ /* The VGA font for this display. */
+ dynafont_t df;
+ int df_size;
+
+ /* The color palette. */
+ dynacolor_t dc;
+
+ int width;
+ int height;
+
+ /* Current attribute. */
+ int cur_conchar_attr_init;
+ conchar_attr_t cur_conchar_attr;
+ char cur_attr;
+
+ /* Remember for each cell on the display the glyph written to it and
+ the colors (in the upper byte) assigned. 0 means unassigned. */
+
+ struct refchr refmatrix[VGA_DISP_HEIGHT][VGA_DISP_WIDTH];
+};
+
+
+static void
+vga_display_invert_border (void)
+{
+ unsigned char col[3];
+
+ mutex_lock (&vga_display_lock);
+ vga_read_palette (0, col, 1);
+ col[0] = 0xff - col[0];
+ col[1] = 0xff - col[1];
+ col[2] = 0xff - col[2];
+ vga_write_palette (0, col, 1);
+ mutex_unlock (&vga_display_lock);
+}
+
+
+static int
+vga_display_flash_off (void *dummy)
+{
+ vga_display_invert_border ();
+ return 0;
+}
+
+
+static error_t
+vga_display_flash (void *handle)
+{
+ if (timer_remove (&vga_display_timer))
+ vga_display_invert_border ();
+ vga_display_invert_border ();
+ vga_display_timer.expires = fetch_jiffies () + 10;
+ timer_add (&vga_display_timer);
+ return 0;
+}
+
+
+/* Parse arguments at startup. */
+static error_t
+parse_startup_args (int no_exit, int argc, char *argv[], int *next)
+{
+#define PARSE_FONT_OPT(x,y) \
+ do { \
+ if (!strcmp (argv[*next], x)) \
+ { \
+ (*next)++; \
+ if (*next == argc) \
+ { \
+ if (no_exit) \
+ return EINVAL; \
+ else \
+ error (1, 0, "option " x \
+ " requires an argument"); \
+ } \
+ if (vga_display_##y) \
+ free (vga_display_##y); \
+ vga_display_##y = strdup (argv[*next]); \
+ if (!vga_display_##y) \
+ { \
+ if (no_exit) \
+ return errno; \
+ else \
+ error (1, errno, "malloc failed"); \
+ } \
+ (*next)++; \
+ continue; \
+ } \
+ } while (0)
+
+ while (*next < argc)
+ {
+ PARSE_FONT_OPT ("--font", font);
+ PARSE_FONT_OPT ("--font-italic", font_italic);
+ PARSE_FONT_OPT ("--font-bold", font_bold);
+ PARSE_FONT_OPT ("--font-bold-italic", font_bold_italic);
+
+ break;
+ }
+ return 0;
+}
+
+/* Initialize the subsystem. */
+static error_t
+vga_display_init (void **handle, int no_exit, int argc, char *argv[], int *next)
+{
+ error_t err;
+ struct vga_display *disp;
+
+ /* XXX Assert that we are called only once. */
+ mutex_init (&vga_display_lock);
+ timer_clear (&vga_display_timer);
+ vga_display_timer.fnc = &vga_display_flash_off;
+
+ /* Parse the arguments. */
+ err = parse_startup_args (no_exit, argc, argv, next);
+ if (err)
+ return err;
+
+ /* Create and initialize the display srtucture as much as
+ possible. */
+ disp = calloc (1, sizeof *disp);
+ if (!disp)
+ return ENOMEM;
+
+ /* Set this to 256 for full color support. */
+ disp->df_size = 512;
+ disp->width = VGA_DISP_WIDTH;
+ disp->height = VGA_DISP_HEIGHT;
+
+ *handle = disp;
+ return 0;
+}
+
+
+/* Start the driver. */
+static error_t
+vga_display_start (void *handle)
+{
+ error_t err;
+ struct vga_display *disp = handle;
+ bdf_font_t font = NULL;
+ bdf_font_t font_italic = NULL;
+ bdf_font_t font_bold = NULL;
+ bdf_font_t font_bold_italic = NULL;
+ FILE *font_file;
+
+ err = vga_init ();
+ if (err)
+ return err;
+
+ dynacolor_init ();
+
+#define LOAD_FONT(x,y) \
+ do { \
+ font_file = fopen (vga_display_##x ?: DEFAULT_VGA_##y, "r"); \
+ if (font_file) \
+ { \
+ bdf_error_t bdferr = bdf_read (font_file, &x, NULL); \
+ if (bdferr) \
+ x = NULL; \
+ else \
+ bdf_sort_glyphs (x); \
+ fclose (font_file); \
+ } \
+ } while (0)
+
+ LOAD_FONT (font, FONT);
+ LOAD_FONT (font_italic, FONT_ITALIC);
+ LOAD_FONT (font_bold, FONT_BOLD);
+ LOAD_FONT (font_bold_italic, FONT_BOLD_ITALIC);
+
+ err = dynafont_new (font, font_italic, font_bold, font_bold_italic,
+ disp->df_size, &disp->df);
+ if (err)
+ {
+ free (disp);
+ vga_fini ();
+ return err;
+ }
+ dynafont_activate (disp->df);
+
+ disp->dc = (disp->df_size == 512) ? dynacolor_init_8 : dynacolor_init_16;
+ dynacolor_activate (&disp->dc);
+
+ err = driver_add_display (&vga_display_ops, disp);
+ if (err)
+ {
+ dynafont_free (disp->df);
+ dynacolor_fini ();
+ vga_fini ();
+ free (disp);
+ }
+ return err;
+}
+
+
+/* Destroy the display HANDLE. */
+static error_t
+vga_display_fini (void *handle, int force)
+{
+ struct vga_display *disp = handle;
+ driver_remove_display (&vga_display_ops, disp);
+ if (timer_remove (&vga_display_timer))
+ vga_display_flash_off (0);
+
+ dynafont_free (disp->df);
+ free (disp);
+ dynacolor_fini ();
+ vga_fini ();
+ if (vga_display_font)
+ free (vga_display_font);
+ if (vga_display_font_italic)
+ free (vga_display_font_italic);
+ if (vga_display_font_bold)
+ free (vga_display_font_bold);
+ if (vga_display_font_bold_italic)
+ free (vga_display_font_bold_italic);
+
+ return 0;
+}
+
+
+/* Set the cursor's position on display HANDLE to column COL and row
+ ROW. */
+static error_t
+vga_display_set_cursor_pos (void *handle, uint32_t col, uint32_t row)
+{
+ struct vga_display *disp = handle;
+ unsigned int pos = row * disp->width + col;
+
+ vga_set_cursor_pos (pos);
+
+ return 0;
+}
+
+
+/* Set the cursor's state to STATE on display HANDLE. */
+static error_t
+vga_display_set_cursor_status (void *handle, uint32_t state)
+{
+ struct vga_display *disp = handle;
+
+ if (state != CONS_CURSOR_INVISIBLE)
+ dynafont_set_cursor (disp->df, state == CONS_CURSOR_VERY_VISIBLE ? 1 : 0);
+ vga_display_cursor (state == CONS_CURSOR_INVISIBLE ? 0 : 1);
+
+ return 0;
+}
+
+
+/* Scroll the display by the desired amount. The area that becomes
+ free will be filled in a subsequent write call. */
+static error_t
+vga_display_scroll (void *handle, int delta)
+{
+ struct vga_display *disp = handle;
+ int count = abs(delta) * disp->width;
+ int i;
+ struct refchr *refpos;
+
+ if (delta > 0)
+ {
+ memmove (vga_videomem, vga_videomem + 2 * count,
+ 2 * disp->width * (disp->height - delta));
+ refpos = &disp->refmatrix[0][0];
+ }
+ else
+ {
+ memmove (vga_videomem + 2 * count, vga_videomem,
+ 2 * disp->width * (disp->height + delta));
+ refpos = &disp->refmatrix[disp->height + delta][0];
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (refpos->used)
+ {
+ dynafont_release (disp->df, refpos->chr);
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_release (disp->dc, refpos->attr & 7);
+ dynacolor_release (disp->dc, (refpos->attr >> 4) & 7);
+ }
+ refpos++;
+ }
+
+ if (delta > 0)
+ {
+ memmove (&disp->refmatrix[0][0], &disp->refmatrix[0][0] + count,
+ sizeof (struct refchr) * disp->width * (disp->height - delta));
+ refpos = &disp->refmatrix[disp->height - delta][0];
+ }
+ else
+ {
+ memmove (&disp->refmatrix[0][0] + count, &disp->refmatrix[0][0],
+ sizeof (struct refchr) * disp->width * (disp->height + delta));
+ refpos = &disp->refmatrix[0][0];
+ }
+
+ for (i = 0; i < count; i++)
+ (refpos++)->used = 0;
+
+ return 0;
+}
+
+
+/* Change the font on the console CONSOLE to font. The old font will
+ not be accessed by the vga console subsystem anymore after this
+ call completed. */
+static void
+vga_display_change_font (void *handle, bdf_font_t font)
+{
+ struct vga_display *disp = handle;
+
+ dynafont_change_font (disp->df, font);
+}
+
+
+static inline char
+vga_display_recalculate_attr (dynacolor_t *dc, conchar_attr_t attr)
+{
+ char vga_attr;
+ signed char res_fgcol;
+ signed char res_bgcol;
+ signed char fgcol;
+ signed char bgcol;
+
+ /* VGA has way too few bits for this stuff. The highest background
+ color bit is also the blinking bit if blinking is enabled. The
+ highest foreground color bit is the font selector bit,
+ unfortunately. Underlining is enabled if foreground is ?001 and
+ background ?000. */
+
+ /* Reversed means colors are reversed. Note that this does not
+ reverse the intensity. */
+ if (attr.reversed)
+ {
+ fgcol = attr.bgcol;
+ bgcol = attr.fgcol;
+ }
+ else
+ {
+ fgcol = attr.fgcol;
+ bgcol = attr.bgcol;
+ }
+
+ /* Set the foreground color. */
+ if (attr.concealed)
+ fgcol = bgcol;
+ else
+ {
+ /* Intensity bold and dim also affect the font selection bit. */
+ switch (attr.intensity)
+ {
+ case CONS_ATTR_INTENSITY_BOLD:
+ fgcol |= 1 << 3;
+ break;
+ case CONS_ATTR_INTENSITY_DIM:
+ fgcol = CONS_COLOR_BLACK | 1 << 3;
+ break;
+ case CONS_ATTR_INTENSITY_NORMAL:
+ break;
+ }
+ }
+
+ /* Try to get the colors as desired. This might change the palette,
+ so we need to take the lock (in case a flash operation times
+ out). */
+ mutex_lock (&vga_display_lock);
+ res_bgcol = dynacolor_lookup (*dc, bgcol);
+ res_fgcol = dynacolor_lookup (*dc, fgcol);
+ mutex_unlock (&vga_display_lock);
+ if (res_bgcol == -1 || res_fgcol == -1)
+ dynacolor_replace_colors (dc, fgcol, bgcol, &res_fgcol, &res_bgcol);
+ vga_attr = res_bgcol << 4 | res_fgcol;
+
+ vga_attr |= attr.blinking << 7;
+
+ /* XXX We can support underlined in a monochrome mode. */
+ return vga_attr;
+}
+
+
+/* Deallocate any scarce resources occupied by the LENGTH characters
+ from column COL and row ROW. */
+static error_t
+vga_display_clear (void *handle, size_t length, uint32_t col, uint32_t row)
+{
+ struct vga_display *disp = handle;
+ struct refchr *refpos = &disp->refmatrix[row][col];
+
+ while (length > 0)
+ {
+ if (refpos->used)
+ {
+ dynafont_release (disp->df, refpos->chr);
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_release (disp->dc, refpos->attr & 7);
+ dynacolor_release (disp->dc, (refpos->attr >> 4) & 7);
+ refpos->used = 0;
+ }
+ refpos++;
+ length--;
+ }
+ return 0;
+}
+
+/* Write the text STR with LENGTH characters to column COL and row
+ ROW. */
+static error_t
+vga_display_write (void *handle, conchar_t *str, size_t length,
+ uint32_t col, uint32_t row)
+{
+ struct vga_display *disp = handle;
+ char *pos = vga_videomem + 2 * (row * disp->width + col);
+ struct refchr *refpos = &disp->refmatrix[row][col];
+
+ /* Although all references to the current fgcol or bgcol could have
+ been released here, for example due to a scroll operation, we
+ know that the color slots have not been reused yet, as no routine
+ but ours does color allocation. This ensures that cur_attr is
+ still valid. XXX consider recalculating the attribute for more
+ authentic (but less homogenous) colors anyway. */
+
+ while (length--)
+ {
+ int charval = dynafont_lookup (disp->df, str);
+ if (!disp->cur_conchar_attr_init
+ || *(uint32_t *) &disp->cur_conchar_attr != *(uint32_t *) &str->attr)
+ {
+ if (!disp->cur_conchar_attr_init)
+ disp->cur_conchar_attr_init = 1;
+ disp->cur_conchar_attr = str->attr;
+ disp->cur_attr = vga_display_recalculate_attr (&disp->dc, str->attr);
+ }
+ else
+ {
+ /* Add two references to the colors. See comment above for
+ why we can assume that this will succeed. */
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_add_ref (disp->dc, disp->cur_attr & 7);
+ dynacolor_add_ref (disp->dc, (disp->cur_attr >> 4) & 7);
+ }
+
+ *(pos++) = charval & 0xff;
+ *(pos++) = disp->cur_attr
+ | (disp->df_size == 512 ? (charval >> 5) & 0x8 : 0);
+
+ /* Perform reference counting. */
+ if (refpos->used)
+ {
+ dynafont_release (disp->df, refpos->chr);
+ /* We intimately know that reference counting is only done
+ for the up to 8 colors mode. */
+ dynacolor_release (disp->dc, refpos->attr & 7);
+ dynacolor_release (disp->dc, (refpos->attr >> 4) & 7);
+ }
+ refpos->used = 1;
+ refpos->chr = charval;
+ refpos->attr = disp->cur_attr;
+ refpos++;
+
+ /* Wrap around displayed area. */
+ str++;
+ }
+ return 0;
+}
+
+
+struct driver_ops driver_vga_ops =
+ {
+ vga_display_init,
+ vga_display_start,
+ vga_display_fini,
+ };
+
+static struct display_ops vga_display_ops =
+ {
+ vga_display_set_cursor_pos,
+ vga_display_set_cursor_status,
+ vga_display_scroll,
+ vga_display_clear,
+ vga_display_write,
+ NULL,
+ vga_display_flash,
+ NULL
+ };