diff options
Diffstat (limited to 'console/bdf.c')
-rw-r--r-- | console/bdf.c | 986 |
1 files changed, 986 insertions, 0 deletions
diff --git a/console/bdf.c b/console/bdf.c new file mode 100644 index 00000000..2e9e02bd --- /dev/null +++ b/console/bdf.c @@ -0,0 +1,986 @@ +/* Adobe Glyph Bitmap Distribution Format (BDF) parser. + 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' \ + : (((c) >= 'A' && (c) <= 'F') ? (c) - 'A' : 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; + 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); +} |