summaryrefslogtreecommitdiff
path: root/console-client/bdf.c
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/bdf.c
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/bdf.c')
-rw-r--r--console-client/bdf.c990
1 files changed, 990 insertions, 0 deletions
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);
+}