shithub: freetype+ttf2subf

Download patch

ref: 993a8d044538e59ebaffe27d4d04f8efb979fd7c
parent: b89a42c6c554ff13f65b3161c5754de4f6a04628
author: David Turner <[email protected]>
date: Sat May 18 08:03:43 EDT 2002

adding BDF driver

git/fs: mount .git/fs: mount/attach disallowed
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -92,6 +92,9 @@
 FT_TRACE_DEF( pcfdriver )
 FT_TRACE_DEF( pcfread )
 
+/* BDF fonts component */
+FT_TRACE_DEF( bdf )
+
 /* PFR fonts component */
 FT_TRACE_DEF( pfr )
 
--- a/src/Jamfile
+++ b/src/Jamfile
@@ -17,6 +17,7 @@
 SubInclude  FT2_TOP src pshinter ;
 SubInclude  FT2_TOP src autohint ;
 SubInclude  FT2_TOP src base ;
+SubInclude  FT2_TOP src bdf ;
 SubInclude  FT2_TOP src cache ;
 SubInclude  FT2_TOP src cff ;
 SubInclude  FT2_TOP src cid ;
--- /dev/null
+++ b/src/bdf/bdf.c
@@ -1,0 +1,33 @@
+/*  bdf.c
+
+    FreeType font driver for bdf files
+
+    Copyright (C) 2001 by
+    Francesco Zappa Nardelli 
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#define FT_MAKE_OPTION_SINGLE_OBJECT
+
+#include <ft2build.h>
+#include "bdflib.c"
+#include "bdfdriver.c"
+
+/* END */
--- /dev/null
+++ b/src/bdf/bdf.h
@@ -1,0 +1,367 @@
+/*
+ * Copyright 2000 Computing Research Labs, New Mexico State University
+ * Copyright 2001 Francesco Zappa Nardelli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#ifndef __BDF_H__
+#define __BDF_H__
+
+/*
+ * $Id$
+ */
+
+#include <string.h>
+
+#include <ft2build.h>
+#include FT_INTERNAL_OBJECTS_H
+#include FT_INTERNAL_STREAM_H
+
+
+FT_BEGIN_HEADER
+/* Imported from bdfP.h */
+
+#ifndef MYABS
+#define MYABS(xx) ((xx) < 0 ? -(xx) : (xx))
+#endif
+
+#define _bdf_glyph_modified(map, e) ((map)[(e) >> 5] & (1 << ((e) & 31)))
+#define _bdf_set_glyph_modified(map, e) (map)[(e) >> 5] |= (1 << ((e) & 31))
+#define _bdf_clear_glyph_modified(map, e) (map)[(e) >> 5] &= ~(1 << ((e) & 31))
+
+/* end of bdfP.h */
+
+/**************************************************************************
+ *
+ * BDF font options macros and types.
+ *
+ **************************************************************************/
+
+#define BDF_UNIX_EOL 1           /* Save fonts with Unix LF.              */
+#define BDF_DOS_EOL  2           /* Save fonts with DOS CRLF.             */
+#define BDF_MAC_EOL  3           /* Save fonts with Mac CR.               */
+
+#define BDF_CORRECT_METRICS 0x01 /* Correct invalid metrics when loading. */
+#define BDF_KEEP_COMMENTS   0x02 /* Preserve the font comments.           */
+#define BDF_KEEP_UNENCODED  0x04 /* Keep the unencoded glyphs.            */
+#define BDF_PROPORTIONAL    0x08 /* Font has proportional spacing.        */
+#define BDF_MONOWIDTH       0x10 /* Font has mono width.                  */
+#define BDF_CHARCELL        0x20 /* Font has charcell spacing.            */
+
+#define BDF_ALL_SPACING (BDF_PROPORTIONAL|BDF_MONOWIDTH|BDF_CHARCELL)
+
+#define BDF_DEFAULT_LOAD_OPTIONS \
+    (BDF_CORRECT_METRICS|BDF_KEEP_COMMENTS|BDF_KEEP_UNENCODED|BDF_PROPORTIONAL)
+
+typedef struct {
+    int ttf_hint;
+    int correct_metrics;
+    int keep_unencoded;
+    int keep_comments;
+    int pad_cells;
+    int font_spacing;
+    long point_size;
+    unsigned long resolution_x;
+    unsigned long resolution_y;
+    int bits_per_pixel;
+    int eol;
+} bdf_options_t;
+
+/*
+ * Callback function type for unknown configuration options.
+ */
+typedef int (*bdf_options_callback_t) (bdf_options_t *opts,
+                                          char **params,
+                                          unsigned long nparams,
+                                          void *client_data);
+
+/**************************************************************************
+ *
+ * BDF font property macros and types.
+ *
+ **************************************************************************/
+
+#define BDF_ATOM     1
+#define BDF_INTEGER  2
+#define BDF_CARDINAL 3
+
+/*
+ * This structure represents a particular property of a font.
+ * There are a set of defaults and each font has their own.
+ */
+typedef struct {
+    char *name;         /* Name of the property.                        */
+    int format;         /* Format of the property.                      */
+    int builtin;        /* A builtin property.                          */
+    union {
+        char *atom;
+        long int32;
+        unsigned long card32;
+    } value;            /* Value of the property.                       */
+} bdf_property_t;
+
+/**************************************************************************
+ *
+ * BDF font metric and glyph types.
+ *
+ **************************************************************************/
+
+/*
+ * A general bitmap type, mostly used when the glyph bitmap is being edited.
+ */
+typedef struct {
+    short x;
+    short y;
+    unsigned short width;
+    unsigned short height;
+    unsigned short bpp;
+    unsigned short pad;
+    unsigned char *bitmap;
+    unsigned long bytes;
+} bdf_bitmap_t;
+
+typedef struct {
+    int font_spacing;
+    unsigned short swidth;
+    unsigned short dwidth;
+    unsigned short width;
+    unsigned short height;
+    short x_offset;
+    short y_offset;
+    short ascent;
+    short descent;
+} bdf_metrics_t;
+
+typedef struct {
+    unsigned short width;
+    unsigned short height;
+    short x_offset;
+    short y_offset;
+    short ascent;
+    short descent;
+} bdf_bbx_t;
+
+typedef struct {
+    char *name;                 /* Glyph name.                          */
+    long encoding;              /* Glyph encoding.                      */
+    unsigned short swidth;      /* Scalable width.                      */
+    unsigned short dwidth;      /* Device width.                        */
+    bdf_bbx_t bbx;              /* Glyph bounding box.                  */
+    unsigned char *bitmap;      /* Glyph bitmap.                        */
+    unsigned short bytes;       /* Number of bytes used for the bitmap. */
+} bdf_glyph_t;
+
+typedef struct {
+    char *key;
+    void *data;
+} _hashnode, *hashnode;
+
+typedef struct {
+    int limit;
+    int size;
+    int used;
+    hashnode *table;
+} hashtable;
+
+typedef struct {
+    unsigned short pad;         /* Pad to 4-byte boundary.              */
+    unsigned short bpp;         /* Bits per pixel.                      */
+    long start;                 /* Beginning encoding value of glyphs.  */
+    long end;                   /* Ending encoding value of glyphs.     */
+    bdf_glyph_t *glyphs;        /* Glyphs themselves.                   */
+    unsigned long glyphs_size;  /* Glyph structures allocated.          */
+    unsigned long glyphs_used;  /* Glyph structures used.               */
+    bdf_bbx_t bbx;              /* Overall bounding box of glyphs.      */
+} bdf_glyphlist_t;
+
+typedef struct {
+    char *name;                 /* Name of the font.                     */
+    bdf_bbx_t bbx;              /* Font bounding box.                    */
+
+    long point_size;            /* Point size of the font.               */
+    unsigned long resolution_x; /* Font horizontal resolution.           */
+    unsigned long resolution_y; /* Font vertical resolution.             */
+
+    int hbf;                    /* Font came from an HBF font.           */
+
+    int spacing;                /* Font spacing value.                   */
+
+    unsigned short monowidth;   /* Logical width for monowidth font.     */
+
+    long default_glyph;         /* Encoding of the default glyph.        */
+
+    long font_ascent;           /* Font ascent.                          */
+    long font_descent;          /* Font descent.                         */
+
+    long glyphs_size;           /* Glyph structures allocated.           */
+    long glyphs_used;           /* Glyph structures used.                */
+    bdf_glyph_t *glyphs;        /* Glyphs themselves.                    */
+
+    long unencoded_size;        /* Unencoded glyph structures allocated. */
+    long unencoded_used;        /* Unencoded glyph structures used.      */
+    bdf_glyph_t *unencoded;     /* Unencoded glyphs themselves.          */
+
+    unsigned long props_size;   /* Font properties allocated.            */
+    unsigned long props_used;   /* Font properties used.                 */
+    bdf_property_t *props;      /* Font properties themselves.           */
+
+    char *comments;             /* Font comments.                        */
+    unsigned long comments_len; /* Length of comment string.             */
+
+    char *acmsgs;               /* Auto-correction messages.             */
+    unsigned long acmsgs_len;   /* Length of auto-correction messages.   */
+
+    bdf_glyphlist_t overflow;   /* Storage used for glyph insertion.     */
+
+    void *internal;             /* Internal data for the font.           */
+
+    unsigned long nmod[2048];   /* Bitmap indicating modified glyphs.    */
+    unsigned long umod[2048];   /* Bitmap indicating modified unencoded. */
+
+    unsigned short modified;    /* Boolean indicating font modified.     */
+    unsigned short bpp;         /* Bits per pixel.                       */
+
+  FT_Memory memory;
+  bdf_property_t *user_props;
+  unsigned long nuser_props;
+  hashtable proptbl;
+
+} bdf_font_t;
+
+
+/**************************************************************************
+ *
+ * Types for load/save callbacks.
+ *
+ **************************************************************************/
+
+/*
+ * Callback reasons.
+ */
+#define BDF_LOAD_START       1
+#define BDF_LOADING          2
+#define BDF_SAVE_START       3
+#define BDF_SAVING           4
+#define BDF_TRANSLATE_START  5
+#define BDF_TRANSLATING      6
+#define BDF_ROTATE_START     7
+#define BDF_ROTATING         8
+#define BDF_SHEAR_START      9
+#define BDF_SHEARING         10
+#define BDF_GLYPH_NAME_START 11
+#define BDF_GLYPH_NAME       12
+#define BDF_EXPORT_START     13
+#define BDF_EXPORTING        14
+#define BDF_EMBOLDEN_START   15
+#define BDF_EMBOLDENING      16
+#define BDF_WARNING          20
+#define BDF_ERROR            21
+
+/*
+ * Error codes.
+ */
+#define BDF_OK                 0
+#define BDF_MISSING_START     -1
+#define BDF_MISSING_FONTNAME  -2
+#define BDF_MISSING_SIZE      -3
+#define BDF_MISSING_FONTBBX   -4
+#define BDF_MISSING_CHARS     -5
+#define BDF_MISSING_STARTCHAR -6
+#define BDF_MISSING_ENCODING  -7
+#define BDF_MISSING_BBX       -8
+
+#define BDF_NOT_CONSOLE_FONT  -10
+#define BDF_NOT_MF_FONT       -11
+#define BDF_NOT_PSF_FONT      -12
+
+#define BDF_OUT_OF_MEMORY     -20
+
+#define BDF_EMPTY_FONT        -99
+#define BDF_INVALID_LINE      -100
+
+typedef struct {
+    unsigned long reason;
+    unsigned long current;
+    unsigned long total;
+    unsigned long errlineno;
+} bdf_callback_struct_t;
+
+typedef void (*bdf_callback_t) (bdf_callback_struct_t *call_data,
+                                   void *client_data);
+
+/**************************************************************************
+ *
+ * BDF font API.
+ *
+ **************************************************************************/
+
+/*
+ * Startup and shutdown functions are no more needed
+ */
+
+/*
+ * Font options functions.
+ */
+/*extern void bdf_default_options (bdf_options_t *opts);*/
+
+/*
+ * Font load, create, save and free functions.
+ */
+
+FT_LOCAL( bdf_font_t* )  bdf_load_font (FT_Stream stream, FT_Memory memory,
+                                        bdf_options_t *opts,
+                                        bdf_callback_t callback, void *data);
+
+
+FT_LOCAL( void )         bdf_free_font (bdf_font_t *font);
+
+/*
+ * Font property functions.
+ */
+/* extern void bdf_create_property (char *name, int type, bdf_font_t *font); */
+FT_LOCAL( bdf_property_t* )  bdf_get_property (char *name, bdf_font_t *font);
+FT_LOCAL( unsigned long )    bdf_property_list (bdf_property_t **props);
+
+FT_LOCAL( void )             bdf_add_font_property (bdf_font_t *font,
+                                                    bdf_property_t *property);
+                                                    
+FT_LOCAL( void )             bdf_delete_font_property (bdf_font_t *font, char *name);
+
+FT_LOCAL( bdf_property_t* )  bdf_get_font_property (bdf_font_t *font,
+                                                    char *name);
+                                                    
+FT_LOCAL( unsigned long )    bdf_font_property_list (bdf_font_t *font,
+                                                      bdf_property_t **props);
+
+/*
+ * Font comment functions.
+ */
+FT_LOCAL( int )              bdf_replace_comments (bdf_font_t *font, char *comments,
+                                                   unsigned long comments_len);
+
+/*
+ * Other miscellaneous functions.
+ */
+FT_LOCAL( void )             bdf_set_default_metrics (bdf_font_t *font);
+
+/* */
+
+FT_END_HEADER
+
+#endif /* _h_bdf */
--- /dev/null
+++ b/src/bdf/bdfdriver.c
@@ -1,0 +1,463 @@
+/*  bdfdriver.c
+
+    FreeType font driver for bdf files
+
+    Copyright (C) 2001-2002 by
+    Francesco Zappa Nardelli 
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "bdf.h"
+#include "bdfdriver.h"
+
+#include "bdferror.h"
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* The macro FT_COMPONENT is used in trace mode.  It is an implicit      */
+  /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log  */
+  /* messages during execution.                                            */
+  /*                                                                       */
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_bdf
+
+
+FT_CALLBACK_DEF( FT_Error )
+BDF_Face_Done( BDF_Face  face )
+{
+  FT_Memory  memory = FT_FACE_MEMORY( face );
+
+  bdf_free_font(face->bdffont); 
+  
+  FT_FREE( face->en_table ); 
+
+  FT_FREE( face->charset_encoding);
+  FT_FREE( face->charset_registry);
+  FT_FREE( face->root.family_name );
+  
+  FT_FREE( face->root.available_sizes );
+  FT_FREE( face->bdffont );
+
+  FT_TRACE4(("bdf: done face\n"));
+  
+  return FT_Err_Ok;
+}
+
+
+FT_CALLBACK_DEF( FT_Error )
+BDF_Face_Init( FT_Stream      stream,
+               BDF_Face       face,
+               FT_Int         face_index,
+               FT_Int         num_params,
+               FT_Parameter*  params )
+{
+  FT_Error       error  = FT_Err_Ok;
+  FT_Memory      memory = FT_FACE_MEMORY( face );
+  bdf_font_t*    font;
+  bdf_options_t  options;
+
+  FT_UNUSED( num_params );
+  FT_UNUSED( params );
+  FT_UNUSED( face_index );
+
+  (void) FT_STREAM_SEEK( 0 );
+
+  options.correct_metrics = 1;   /* FZ XXX : options semantics */
+  options.keep_unencoded  = 1;
+  options.pad_cells       = 1;
+
+  font = bdf_load_font( stream, memory, &options, 0, 0 );
+  if ( font == NULL )
+  {
+    FT_TRACE2(("[not a valid BDF file]\n"));
+    goto Fail;
+  }
+
+  /* we have a bdf font: let's construct the face object */
+  face->bdffont = font;
+  {
+    FT_Face          root = FT_FACE( face );
+    bdf_property_t*  prop = NULL;
+
+    FT_TRACE4(("glyph %d - %d, unencoded %d %d\n",font->glyphs_size,
+               font->glyphs_used, font->unencoded_size, font->unencoded_used));
+
+
+    root->num_faces  = 1;
+    root->face_index = 0;
+    root->face_flags =  FT_FACE_FLAG_FIXED_SIZES |
+                        FT_FACE_FLAG_HORIZONTAL  |
+                        FT_FACE_FLAG_FAST_GLYPHS ;
+
+    prop = bdf_get_font_property (font,"SPACING");
+    
+    if ( prop && prop->format == BDF_ATOM )
+    { 
+      if ( (*(prop->value.atom) == 'M') ||
+           (*(prop->value.atom) == 'C') )
+        {
+          root->face_flags |= FT_FACE_FLAG_FIXED_WIDTH;
+        }
+      }
+    }
+
+    /* FZ XXX : TO DO : FT_FACE_FLAGS_VERTICAL  */
+    /* FZ XXX : I need a font to implement this */
+
+    root->style_flags = 0;
+    
+    prop = bdf_get_font_property (font,"SLANT");
+    
+    if ( prop && prop->format == BDF_ATOM )
+    { 
+      if ( (*(prop->value.atom) == 'O' ) ||
+           (*(prop->value.atom) == 'I' ) )
+      {
+        root->style_flags |= FT_STYLE_FLAG_ITALIC;
+      }
+    }
+
+    prop = bdf_get_font_property (font,"WEIGHT_NAME");
+    
+    if ( prop && prop->format == BDF_ATOM )
+    {
+      if ( *(prop->value.atom) == 'B' )
+        root->style_flags |= FT_STYLE_FLAG_BOLD;
+    }
+
+
+    prop = bdf_get_font_property (font,"FAMILY_NAME");
+    if (prop != NULL) {
+      int l = strlen(prop->value.atom) + 1;
+      if ( FT_ALLOC( root->family_name, l * sizeof(char)) )
+        goto Fail;
+      strcpy(root->family_name, prop->value.atom);
+    } else root->family_name = 0;
+
+    root->style_name = (char *)"Regular";
+    if ( root->style_flags & FT_STYLE_FLAG_BOLD )
+      {
+        if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+          root->style_name = (char *)"Bold Italic";
+        else
+          root->style_name = (char *)"Bold";
+      }
+    else if ( root->style_flags & FT_STYLE_FLAG_ITALIC )
+      root->style_name = (char *)"Italic";
+
+    root->num_glyphs = font->glyphs_size ; /* unencoded included */
+    
+    root->num_fixed_sizes = 1;
+    if ( FT_ALLOC_ARRAY( root->available_sizes, 1,
+                      FT_Bitmap_Size ) )
+      goto Fail;
+    
+    prop = bdf_get_font_property(font,"PIXEL_SIZE");
+    if (prop != NULL) {
+      bdf_property_t *xres = 0, *yres = 0;
+
+      xres = bdf_get_font_property(font,"RESOLUTION_X");
+      yres = bdf_get_font_property(font,"RESOLUTION_Y");
+      if ((xres != NULL) && (yres != NULL)) {
+        FT_TRACE4(("prop %d %d %d\n",prop->value.int32, xres->value.int32, 
+                   yres->value.int32));
+        root->available_sizes->width = 
+          prop->value.int32 * 75 / xres->value.int32;
+        root->available_sizes->height = 
+          prop->value.int32 * 75 / yres->value.int32;
+      }
+    } else { 
+      /* some fonts have broken SIZE declaration (jiskan24.bdf) */
+      FT_ERROR(("BDF Warning: reading size\n"));
+      root->available_sizes->width = font->point_size ;
+      root->available_sizes->height = font->point_size ;
+    }      
+ 
+    /* encoding table */
+    {
+      bdf_glyph_t *cur = font->glyphs;
+      int n;
+
+      if ( FT_ALLOC ( face->en_table , 
+                   font->glyphs_size * sizeof(BDF_encoding_el ) ) )
+        goto Fail;
+
+      for (n = 0; n<font->glyphs_size ; n++) {
+        (face->en_table[n]).enc = cur[n].encoding ;
+        FT_TRACE4(("enc n: %d, val %ld\n",n,cur[n].encoding));
+        (face->en_table[n]).glyph = n;
+      }
+    }
+    
+    /* charmaps */
+    {
+      bdf_property_t *charset_registry = 0, *charset_encoding = 0;
+      
+      charset_registry = bdf_get_font_property(font,"CHARSET_REGISTRY");
+      charset_encoding = bdf_get_font_property(font,"CHARSET_ENCODING");
+      if ((charset_registry != NULL) && (charset_encoding != NULL)) {
+        if ((charset_registry->format == BDF_ATOM) && 
+            (charset_encoding->format == BDF_ATOM)) {
+          if (FT_ALLOC(face->charset_encoding, 
+                    (strlen(charset_encoding->value.atom)+1) * sizeof(char))) 
+            goto Exit;
+          if (FT_ALLOC(face->charset_registry, 
+                    (strlen(charset_registry->value.atom)+1) * sizeof(char))) 
+            goto Exit;
+          strcpy(face->charset_registry,charset_registry->value.atom);
+          strcpy(face->charset_encoding,charset_encoding->value.atom);
+            
+          face->charmap.encoding = ft_encoding_none;
+          face->charmap.platform_id = 0;
+          face->charmap.encoding_id = 0;
+          face->charmap.face = root; 
+          face->charmap_handle = &face->charmap;
+          root->charmap = face->charmap_handle;
+          goto Exit;
+        }  
+      }
+
+      /* otherwise assume adobe standard encoding */
+      face->charmap.encoding = ft_encoding_adobe_standard;
+      face->charmap.platform_id = 7; /* taken from t1objs.c */
+      face->charmap.encoding_id = 0;
+      face->charmap.face = root; 
+      face->charmap_handle = &face->charmap;
+      root->charmap = face->charmap_handle;
+    }
+  }
+ 
+ Exit:
+  return FT_Err_Ok;
+  
+ Fail:
+  BDF_Face_Done( face );
+  return FT_Err_Unknown_File_Format;
+}
+
+static
+FT_Error  BDF_Set_Pixel_Size( FT_Size  size )
+{
+  BDF_Face face = (BDF_Face)FT_SIZE_FACE( size );
+  FT_Face  root = FT_FACE( face );
+
+  FT_TRACE4(("rec %d - pres %d\n",size->metrics.y_ppem,
+      root->available_sizes->height));
+  if (size->metrics.y_ppem == root->available_sizes->height) {
+   
+    size->metrics.ascender = face->bdffont->bbx.ascent << 6; 
+    size->metrics.descender = face->bdffont->bbx.descent * (-64);
+    size->metrics.height = face->bdffont->bbx.height <<6;
+      
+    return FT_Err_Ok;
+  }
+  else {
+    return FT_Err_Invalid_Pixel_Size;
+  }
+}
+
+static
+FT_Error  BDF_Glyph_Load( FT_GlyphSlot  slot,
+                          FT_Size       size,
+                          FT_UInt       glyph_index,
+                          FT_Int        load_flags )
+{
+  BDF_Face face = (BDF_Face)FT_SIZE_FACE( size );
+  FT_Error error = FT_Err_Ok;
+  FT_Bitmap *bitmap = &slot->bitmap;
+  bdf_glyph_t glyph;
+  int i;
+  FT_Memory memory = face->bdffont->memory;
+  
+  if (!face) {
+    error = FT_Err_Invalid_Argument;
+    goto Exit;
+  }
+  
+  /* slot, bitmap => freetype, glyph => bdflib */
+  glyph = face->bdffont->glyphs[glyph_index];
+  
+  bitmap->pitch = (glyph.bbx.width + 7) >> 3;
+  bitmap->rows = glyph.bbx.height;
+  bitmap->width = glyph.bbx.width;
+  bitmap->num_grays = 1;              /* unused */
+  bitmap->pixel_mode = ft_pixel_mode_mono;
+  
+  if ( FT_ALLOC ( bitmap->buffer , glyph.bytes) )
+    return FT_Err_Out_Of_Memory;
+  FT_MEM_SET( bitmap->buffer , 0 , glyph.bytes );
+  for (i=0 ; i<glyph.bytes ; i++) {
+    bitmap->buffer[i] = glyph.bitmap[i];
+  }
+
+  slot->bitmap_left = 0;
+  slot->bitmap_top = glyph.bbx.ascent ; 
+
+  /*  FZ TO DO : vertical metrics  */
+  slot->metrics.horiAdvance = glyph.dwidth << 6;
+  slot->metrics.horiBearingX = glyph.bbx.x_offset << 6 ;
+  slot->metrics.horiBearingY = glyph.bbx.y_offset << 6 ;
+  slot->metrics.width = bitmap->width << 6 ;
+  slot->metrics.height = bitmap->rows << 6;
+  
+  slot->linearHoriAdvance = (FT_Fixed)glyph.dwidth << 16;
+  slot->format = ft_glyph_format_bitmap;
+  slot->flags = FT_GLYPH_OWN_BITMAP;
+    
+ Exit:
+  return error; 
+}
+
+static
+FT_UInt  BDF_Get_Char_Index( FT_CharMap  charmap,
+                             FT_ULong    char_code )
+{
+  BDF_Face face = ((BDF_Face)charmap->face);
+  BDF_encoding_el *en_table = face->en_table;
+  int low, high, mid;
+
+  FT_TRACE4(("get_char_index %ld\n", char_code));
+  
+  low = 0;
+  high = face->bdffont->glyphs_used - 1;   
+  while (low <= high) {
+    mid = (low+high) / 2;
+    if (char_code < en_table[mid].enc)
+      high = mid - 1;
+    else if (char_code > en_table[mid].enc)
+      low = mid + 1;
+    else return en_table[mid].glyph;
+  }
+  
+  return face->bdffont->default_glyph;
+}
+
+FT_CALLBACK_TABLE_DEF
+const FT_Driver_ClassRec  bdf_driver_class =
+{
+  {
+    ft_module_font_driver,
+    sizeof ( FT_DriverRec ),
+    
+    "bdf",
+    0x10000L,
+    0x20000L,
+      
+    0,
+    
+    (FT_Module_Constructor)0,
+    (FT_Module_Destructor) 0,
+    (FT_Module_Requester)  0
+  },
+  
+  sizeof( BDF_FaceRec ),
+  sizeof( FT_SizeRec ),
+  sizeof( FT_GlyphSlotRec ),
+ 
+    (FT_Face_InitFunc)        BDF_Face_Init,
+    (FT_Face_DoneFunc)        BDF_Face_Done,
+    (FT_Size_InitFunc)        0,
+    (FT_Size_DoneFunc)        0,
+    (FT_Slot_InitFunc)        0,
+    (FT_Slot_DoneFunc)        0,
+
+    (FT_Size_ResetPointsFunc) BDF_Set_Pixel_Size,
+    (FT_Size_ResetPixelsFunc) BDF_Set_Pixel_Size,
+
+    (FT_Slot_LoadFunc)        BDF_Glyph_Load,
+
+#ifndef FT_CONFIG_OPTION_USE_CMAPS    
+   (FT_CharMap_CharIndexFunc)0,
+#else
+    (FT_CharMap_CharIndexFunc)0,
+#endif
+
+    (FT_Face_GetKerningFunc)  0,
+    (FT_Face_AttachFunc)      0,
+    (FT_Face_GetAdvancesFunc) 0,
+
+#ifndef FT_CONFIG_OPTION_USE_CMAPS
+    (FT_CharMap_CharNextFunc) 0, /*PCF_Char_Get_Next,*/
+#else
+    (FT_CharMap_CharNextFunc) 0
+#endif    
+  };
+
+ /*  
+  (FTDriver_initFace)     BDF_Init_Face,
+  (FTDriver_doneFace)     BDF_Done_Face,
+  (FTDriver_initSize)     0,
+  (FTDriver_doneSize)     0,
+  (FTDriver_initGlyphSlot)0,
+  (FTDriver_doneGlyphSlot)0,
+  
+  (FTDriver_setCharSizes) BDF_Set_Pixel_Size,
+  (FTDriver_setPixelSizes)BDF_Set_Pixel_Size,
+
+  (FTDriver_loadGlyph)    BDF_Load_Glyph,
+  (FTDriver_getCharIndex) BDF_Get_Char_Index,
+  
+  (FTDriver_getKerning)   0,
+  (FTDriver_attachFile)   0,
+  (FTDriver_getAdvances)  0
+  */
+
+
+
+#ifdef FT_CONFIG_OPTION_DYNAMIC_DRIVERS
+
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* <Function>                                                            */
+  /*    getDriverClass                                                     */
+  /*                                                                       */
+  /* <Description>                                                         */
+  /*    This function is used when compiling the TrueType driver as a      */
+  /*    shared library (`.DLL' or `.so').  It will be used by the          */
+  /*    high-level library of FreeType to retrieve the address of the      */
+  /*    driver's generic interface.                                        */
+  /*                                                                       */
+  /*    It shouldn't be implemented in a static build, as each driver must */
+  /*    have the same function as an exported entry point.                 */
+  /*                                                                       */
+  /* <Return>                                                              */
+  /*    The address of the TrueType's driver generic interface.  The       */
+  /*    format-specific interface can then be retrieved through the method */
+  /*    interface->get_format_interface.                                   */
+  /*                                                                       */
+  FT_EXPORT_DEF( const FT_Driver_Class* )  
+  getDriverClass( void )
+  {
+    return &bdf_driver_class;
+  }
+
+
+#endif /* FT_CONFIG_OPTION_DYNAMIC_DRIVERS */
+
+
+/* END */
--- /dev/null
+++ b/src/bdf/bdfdriver.h
@@ -1,0 +1,68 @@
+/*  bdfdriver.h  
+
+    FreeType font driver for bdf fonts
+
+  Copyright (C) 2001 by            
+  Francesco Zappa Nardelli     
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+
+#ifndef __BDF_DRIVER_H__
+#define __BDF_DRIVER_H__
+
+#include <ft2build.h>
+#include FT_INTERNAL_DRIVER_H
+
+#include "bdf.h"
+
+FT_BEGIN_HEADER
+
+    typedef struct {
+      FT_Long   enc;
+      FT_Short  glyph;
+    } BDF_encoding_el;
+
+    typedef struct  BDF_FaceRec_
+    {
+      FT_FaceRec       root;
+
+      char            *charset_encoding;
+      char            *charset_registry;
+
+      bdf_font_t      *bdffont;  
+
+      BDF_encoding_el *en_table;
+      
+      FT_CharMap       charmap_handle;
+      FT_CharMapRec    charmap;  /* a single charmap per face */
+    } BDF_FaceRec, *BDF_Face;
+
+
+    FT_EXPORT_VAR( const FT_Driver_ClassRec )  bdf_driver_class;
+
+FT_END_HEADER
+
+
+#endif /* __BDF_DRIVER_H__ */
+
+
+/* END */
+
--- /dev/null
+++ b/src/bdf/bdferror.h
@@ -1,0 +1,44 @@
+/*
+ * Copyright 2001 Francesco Zappa Nardelli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+  /*************************************************************************/
+  /*                                                                       */
+  /* This file is used to define the PCF error enumeration constants.      */
+  /*                                                                       */
+  /*************************************************************************/
+
+#ifndef __BDFERROR_H__
+#define __BDFERROR_H__
+
+#include FT_MODULE_ERRORS_H
+
+#undef __FTERRORS_H__
+
+#define FT_ERR_PREFIX  BDF_Err_
+#define FT_ERR_BASE    FT_Mod_Err_BDF
+
+#include FT_ERRORS_H
+
+#endif /* __PCFERROR_H__ */
+
+
+/* END */
--- /dev/null
+++ b/src/bdf/bdflib.c
@@ -1,0 +1,2465 @@
+/*
+ * Copyright 2000 Computing Research Labs, New Mexico State University
+ * Copyright 2001 Francesco Zappa Nardelli
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COMPUTING RESEARCH LAB OR NEW MEXICO STATE UNIVERSITY BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
+ * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+static char rcsid[] = "$Id$";
+*/
+
+#include <ft2build.h>
+
+#include FT_INTERNAL_DEBUG_H
+#include FT_INTERNAL_STREAM_H
+#include FT_INTERNAL_OBJECTS_H
+
+#include "bdf.h"
+
+#include "bdferror.h"
+
+#undef MAX
+#define MAX(h, i) ((h) > (i) ? (h) : (i))
+
+#undef MIN
+#define MIN(l, o) ((l) < (o) ? (l) : (o))
+
+/**************************************************************************
+ *
+ * Masks used for checking different bits per pixel cases.
+ *
+ **************************************************************************/
+
+static const unsigned char onebpp[]   = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+static const unsigned char twobpp[]   = { 0xc0, 0x30, 0x0c, 0x03 };
+static const unsigned char fourbpp[]  = { 0xf0, 0x0f };
+static const unsigned char eightbpp[] = { 0xff };
+
+/**************************************************************************
+ *
+ * Default BDF font options.
+ *
+ **************************************************************************/
+
+static const bdf_options_t _bdf_opts =
+{
+    1,                /* Hint TTF glyphs.               */
+    1,                /* Correct metrics.               */
+    1,                /* Preserve unencoded glyphs.     */
+    1,                /* Preserve comments.             */
+    1,                /* Pad character-cells.           */
+    BDF_PROPORTIONAL, /* Default spacing.               */
+    12,               /* Default point size.            */
+    0,                /* Default horizontal resolution. */
+    0,                /* Default vertical resolution.   */
+    1,                /* Bits per pixel.                */
+    BDF_UNIX_EOL,     /* Line separator.                */
+};
+
+/**************************************************************************
+ *
+ * Builtin BDF font properties.
+ *
+ **************************************************************************/
+
+/*
+ * List of most properties that might appear in a font.  Doesn't include the
+ * RAW_* and AXIS_* properties in X11R6 polymorphic fonts.
+ */
+static const bdf_property_t _bdf_properties[] =
+{
+    {"ADD_STYLE_NAME",          BDF_ATOM,     1},
+    {"AVERAGE_WIDTH",           BDF_INTEGER,  1},
+    {"AVG_CAPITAL_WIDTH",       BDF_INTEGER,  1},
+    {"AVG_LOWERCASE_WIDTH",     BDF_INTEGER,  1},
+    {"CAP_HEIGHT",              BDF_INTEGER,  1},
+    {"CHARSET_COLLECTIONS",     BDF_ATOM,     1},
+    {"CHARSET_ENCODING",        BDF_ATOM,     1},
+    {"CHARSET_REGISTRY",        BDF_ATOM,     1},
+    {"COMMENT",                 BDF_ATOM,     1},
+    {"COPYRIGHT",               BDF_ATOM,     1},
+    {"DEFAULT_CHAR",            BDF_CARDINAL, 1},
+    {"DESTINATION",             BDF_CARDINAL, 1},
+    {"DEVICE_FONT_NAME",        BDF_ATOM,     1},
+    {"END_SPACE",               BDF_INTEGER,  1},
+    {"FACE_NAME",               BDF_ATOM,     1},
+    {"FAMILY_NAME",             BDF_ATOM,     1},
+    {"FIGURE_WIDTH",            BDF_INTEGER,  1},
+    {"FONT",                    BDF_ATOM,     1},
+    {"FONTNAME_REGISTRY",       BDF_ATOM,     1},
+    {"FONT_ASCENT",             BDF_INTEGER,  1},
+    {"FONT_DESCENT",            BDF_INTEGER,  1},
+    {"FOUNDRY",                 BDF_ATOM,     1},
+    {"FULL_NAME",               BDF_ATOM,     1},
+    {"ITALIC_ANGLE",            BDF_INTEGER,  1},
+    {"MAX_SPACE",               BDF_INTEGER,  1},
+    {"MIN_SPACE",               BDF_INTEGER,  1},
+    {"NORM_SPACE",              BDF_INTEGER,  1},
+    {"NOTICE",                  BDF_ATOM,     1},
+    {"PIXEL_SIZE",              BDF_INTEGER,  1},
+    {"POINT_SIZE",              BDF_INTEGER,  1},
+    {"QUAD_WIDTH",              BDF_INTEGER,  1},
+    {"RAW_ASCENT",              BDF_INTEGER,  1},
+    {"RAW_AVERAGE_WIDTH",       BDF_INTEGER,  1},
+    {"RAW_AVG_CAPITAL_WIDTH",   BDF_INTEGER,  1},
+    {"RAW_AVG_LOWERCASE_WIDTH", BDF_INTEGER,  1},
+    {"RAW_CAP_HEIGHT",          BDF_INTEGER,  1},
+    {"RAW_DESCENT",             BDF_INTEGER,  1},
+    {"RAW_END_SPACE",           BDF_INTEGER,  1},
+    {"RAW_FIGURE_WIDTH",        BDF_INTEGER,  1},
+    {"RAW_MAX_SPACE",           BDF_INTEGER,  1},
+    {"RAW_MIN_SPACE",           BDF_INTEGER,  1},
+    {"RAW_NORM_SPACE",          BDF_INTEGER,  1},
+    {"RAW_PIXEL_SIZE",          BDF_INTEGER,  1},
+    {"RAW_POINT_SIZE",          BDF_INTEGER,  1},
+    {"RAW_PIXELSIZE",           BDF_INTEGER,  1},
+    {"RAW_POINTSIZE",           BDF_INTEGER,  1},
+    {"RAW_QUAD_WIDTH",          BDF_INTEGER,  1},
+    {"RAW_SMALL_CAP_SIZE",      BDF_INTEGER,  1},
+    {"RAW_STRIKEOUT_ASCENT",    BDF_INTEGER,  1},
+    {"RAW_STRIKEOUT_DESCENT",   BDF_INTEGER,  1},
+    {"RAW_SUBSCRIPT_SIZE",      BDF_INTEGER,  1},
+    {"RAW_SUBSCRIPT_X",         BDF_INTEGER,  1},
+    {"RAW_SUBSCRIPT_Y",         BDF_INTEGER,  1},
+    {"RAW_SUPERSCRIPT_SIZE",    BDF_INTEGER,  1},
+    {"RAW_SUPERSCRIPT_X",       BDF_INTEGER,  1},
+    {"RAW_SUPERSCRIPT_Y",       BDF_INTEGER,  1},
+    {"RAW_UNDERLINE_POSITION",  BDF_INTEGER,  1},
+    {"RAW_UNDERLINE_THICKNESS", BDF_INTEGER,  1},
+    {"RAW_X_HEIGHT",            BDF_INTEGER,  1},
+    {"RELATIVE_SETWIDTH",       BDF_CARDINAL, 1},
+    {"RELATIVE_WEIGHT",         BDF_CARDINAL, 1},
+    {"RESOLUTION",              BDF_INTEGER,  1},
+    {"RESOLUTION_X",            BDF_CARDINAL, 1},
+    {"RESOLUTION_Y",            BDF_CARDINAL, 1},
+    {"SETWIDTH_NAME",           BDF_ATOM,     1},
+    {"SLANT",                   BDF_ATOM,     1},
+    {"SMALL_CAP_SIZE",          BDF_INTEGER,  1},
+    {"SPACING",                 BDF_ATOM,     1},
+    {"STRIKEOUT_ASCENT",        BDF_INTEGER,  1},
+    {"STRIKEOUT_DESCENT",       BDF_INTEGER,  1},
+    {"SUBSCRIPT_SIZE",          BDF_INTEGER,  1},
+    {"SUBSCRIPT_X",             BDF_INTEGER,  1},
+    {"SUBSCRIPT_Y",             BDF_INTEGER,  1},
+    {"SUPERSCRIPT_SIZE",        BDF_INTEGER,  1},
+    {"SUPERSCRIPT_X",           BDF_INTEGER,  1},
+    {"SUPERSCRIPT_Y",           BDF_INTEGER,  1},
+    {"UNDERLINE_POSITION",      BDF_INTEGER,  1},
+    {"UNDERLINE_THICKNESS",     BDF_INTEGER,  1},
+    {"WEIGHT",                  BDF_CARDINAL, 1},
+    {"WEIGHT_NAME",             BDF_ATOM,     1},
+    {"X_HEIGHT",                BDF_INTEGER,  1},
+    {"_MULE_BASELINE_OFFSET",   BDF_INTEGER,  1},
+    {"_MULE_RELATIVE_COMPOSE",  BDF_INTEGER,  1},
+};
+
+static const FT_ULong _num_bdf_properties = FT_NUM_ELEMENT(_bdf_properties);
+
+/*
+ * User defined properties.
+ */
+/*static bdf_property_t *user_props;
+  static unsigned long nuser_props = 0;*/
+
+/**************************************************************************
+ *
+ * Hash table utilities for the properties.
+ *
+ **************************************************************************/
+
+#define INITIAL_HT_SIZE 241
+
+typedef void (*hash_free_func)(hashnode node);
+
+static hashnode*
+hash_bucket(char *key, hashtable *ht)
+{
+  char*         kp  = key;
+  unsigned long res = 0;
+  hashnode*     bp  = ht->table, *ndp;
+
+  /*
+   * Mocklisp hash function.
+   */
+  while (*kp)
+    res = (res << 5) - res + *kp++;
+
+  ndp = bp + (res % ht->size);
+  while (*ndp)
+  {
+    kp = (*ndp)->key;
+
+    if (kp[0] == key[0] && ft_strcmp(kp, key) == 0)
+      break;
+
+    ndp--;
+    if (ndp < bp)
+      ndp = bp + (ht->size - 1);
+  }
+  return ndp;
+}
+
+
+static  FT_Error
+hash_rehash ( hashtable*  ht,
+              FT_Memory   memory )
+{
+  hashnode *obp = ht->table, *bp, *nbp;
+  int i, sz = ht->size;
+  FT_Error error;
+
+  ht->size <<= 1;
+  ht->limit  = ht->size / 3;
+
+  if ( FT_NEW_ARRAY( ht->table , ht->size ) )
+    return error;
+
+  for (i = 0, bp = obp; i < sz; i++, bp++)
+  {
+    if (*bp)
+    {
+      nbp = hash_bucket((*bp)->key, ht);
+      *nbp = *bp;
+    }
+  }
+  FT_FREE(obp);
+
+  return FT_Err_Ok;
+}
+
+
+static FT_Error
+hash_init ( hashtable*  ht,
+            FT_Memory   memory )
+{
+  int      sz = INITIAL_HT_SIZE;
+  FT_Error error;
+
+  ht->size  = sz;
+  ht->limit = sz / 3;
+  ht->used  = 0;
+
+  if ( FT_NEW_ARRAY( ht->table, size ) )
+    return error;
+
+  return FT_Err_Ok;
+}
+
+
+static void
+hash_free( hashtable*  ht,
+           FT_Memory   memory )
+{
+  /* FT_Error error; */
+
+  if ( ht != 0 )
+  {
+    int        i, sz = ht->size;
+    hashnode*  bp    = ht->table;
+
+    for (i = 0; i < sz; i++, bp++)
+    {
+      if (*bp)
+        FT_FREE(*bp);
+    }
+    if (sz > 0)
+      FT_FREE(ht->table);
+  }
+}
+
+
+static FT_Error
+hash_insert ( char*       key,
+              void*       data,
+              hashtable*  ht,
+              FT_Memory   memory )
+{
+  FT_Error  error   = FT_Err_Ok;
+  hashnode  nn, *bp = hash_bucket(key, ht);
+
+  nn = *bp;
+  if (!nn)
+  {
+    if ( FT_NEW( nn ) )
+      return error;
+
+    *bp      = nn;
+    nn->key  = key;
+    nn->data = data;
+
+    if (ht->used >= ht->limit)
+      error = hash_rehash(ht, memory);
+
+    ht->used++;
+  }
+  else
+    nn->data = data;
+
+  return error;
+}
+
+
+static hashnode
+hash_lookup(char *key, hashtable *ht)
+{
+  hashnode *np = hash_bucket(key, ht);
+  return   *np;
+}
+
+#ifdef 0
+static void
+hash_delete(char *name, hashtable *ht , FT_Memory memory)
+{
+  hashnode *hp;
+  /* FT_Error error; */
+
+  hp = hash_bucket(name, ht);
+  FT_FREE( *hp );
+}
+#endif
+
+/*
+ * The builtin property table.
+ */
+/*static hashtable proptbl; */ /* XXX eliminate this */
+
+
+
+/**************************************************************************
+ *
+ * Utility types and functions.
+ *
+ **************************************************************************/
+
+/*
+ * Function type for parsing lines of a BDF font.
+ */
+typedef int (*_bdf_line_func_t)( char*         line,
+                                 unsigned long linelen,
+                                 unsigned long lineno,
+                                 void*         call_data,
+                                 void*         client_data );
+
+/*
+ * List structure for splitting lines into fields.
+ */
+typedef struct
+{
+  char**         field;
+  unsigned long  size;
+  unsigned long  used;
+  char*          bfield;
+  unsigned long  bsize;
+  unsigned long  bused;
+
+} _bdf_list_t;
+
+
+/*
+ * Structure used while loading BDF fonts.
+ */
+typedef struct
+{
+  unsigned long          flags;
+  unsigned long          cnt;
+  unsigned long          row;
+  unsigned long          bpr;
+  short                  minlb;
+  short                  maxlb;
+  short                  maxrb;
+  short                  maxas;
+  short                  maxds;
+  short                  rbearing;
+  char*                  glyph_name;
+  long                   glyph_enc;
+  bdf_font_t*            font;
+  bdf_options_t*         opts;
+  void*                  client_data;
+  bdf_callback_t         callback;
+  bdf_callback_struct_t  cb;
+  unsigned long          have[2048];
+  _bdf_list_t            list;
+
+  FT_Memory              memory;
+
+} _bdf_parse_t;
+
+#define setsbit(m, cc) (m[(cc) >> 3] |= (1 << ((cc) & 7)))
+#define sbitset(m, cc) (m[(cc) >> 3] & (1 << ((cc) & 7)))
+
+/*
+ * An empty string for empty fields.
+ */
+static const char empty[1] = { 0 };   /* XXX eliminate this */
+
+/*
+ * Assume the line is NULL terminated and that the `list' parameter was
+ * initialized the first time it was used.
+ */
+static FT_Error
+_bdf_split ( char*          separators,
+             char*          line,
+             unsigned long  linelen,
+             _bdf_list_t*   list,
+             FT_Memory      memory )
+{
+  int mult, final_empty;
+  char *sp, *ep, *end;
+  unsigned char seps[32];
+  FT_Error error;
+
+  /*
+   * Initialize the list.
+   */
+  list->used = list->bused = 0;
+
+  /*
+   * If the line is empty, then simply return.
+   */
+  if ( linelen == 0 || line[0] == 0 )
+    return FT_Err_Ok;
+
+  /*
+   * If the `separators' parameter is NULL or empty, split the list into
+   * individual bytes.
+   */
+  if ( separators == 0 || *separators == 0 )
+  {
+    if ( linelen > list->bsize )
+    {
+      if ( list->bsize )
+      {
+        if ( FT_ALLOC ( list->bfield , linelen) )
+          return error;
+      }
+      else
+      {
+        if ( FT_REALLOC ( list->bfield , list->bsize, linelen) )
+          return error;
+      }
+      list->bsize = linelen;
+    }
+    list->bused = linelen;
+
+    FT_MEM_COPY (list->bfield, line, linelen);
+    return FT_Err_Ok;
+  }
+
+  /*
+   * Prepare the separator bitmap.
+   */
+  FT_MEM_ZERO( seps, 32 );
+
+  /*
+   * If the very last character of the separator string is a plus, then set
+   * the `mult' flag to indicate that multiple separators should be
+   * collapsed into one.
+   */
+  for ( mult = 0, sp = separators; sp && *sp; sp++ )
+  {
+    if ( sp[0] == '+' && sp[1] == 0)
+      mult = 1;
+    else
+      setsbit( seps, sp[0] );
+  }
+
+  /*
+   * Break the line up into fields.
+   */
+  final_empty = 0;
+  sp          = ep = line;
+  end         = sp + linelen;
+  for ( ; sp < end && *sp;)
+  {
+    /*
+     * Collect everything that is not a separator.
+     */
+    for ( ; *ep && !sbitset( seps, *ep ); ep++ ) ;
+
+    /*
+     * Resize the list if necessary.
+     */
+    if ( list->used == list->size )
+    {
+      if ( list->size == 0 )
+      {
+        if ( FT_NEW_ARRAY( list->field , 5) )
+          return error;
+      }
+      else
+      {
+        if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 )
+          return error;
+      }
+      list->size += 5;
+    }
+
+    /*
+     * Assign the field appropriately.
+     */
+    list->field[ list->used++ ] = (ep > sp) ? sp : empty;
+
+    sp = ep;
+    if (mult)
+    {
+      /*
+       * If multiple separators should be collapsed, do it now by
+       * setting all the separator characters to 0.
+       */
+      for ( ; *ep && sbitset(seps, *ep); ep++ )
+        *ep = 0;
+
+    }
+    else if (*ep != 0)
+    {
+      /*
+       * Don't collapse multiple separators by making them 0, so just
+       * make the one encountered 0.
+       */
+      *ep++ = 0;
+    }
+
+    final_empty = ( ep > sp && *ep == 0 );
+    sp          = ep;
+  }
+
+  /*
+   * Finally, NULL terminate the list.
+   */
+  if ( list->used + final_empty + 1 >= list->size )
+  {
+    if ( list->used == list->size )
+    {
+      if ( list->size == 0 )
+      {
+        if ( FT_NEW_ARRAY( list->field, 5 ) )
+          return error;
+      }
+      else
+      {
+        if ( FT_RENEW_ARRAY( list->field , list->size, list->size+5 ) )
+          return error;
+      }
+      list->size += 5;
+    }
+  }
+
+  if (final_empty)
+    list->field[ list->used++ ] = empty;
+
+  if ( list->used == list->size )
+  {
+    if ( list->size == 0 )
+    {
+      if ( FT_NEW_ARRAY( list->field , 5 ) )
+        return error;
+    }
+    else
+    {
+      if ( FT_NEW_ARRAY( list->field, list->size, list->size + 5 ) )
+        return error;
+    }
+    list->size += 5;
+  }
+  list->field[ list->used ] = 0;
+
+  return FT_Err_Ok;
+}
+
+
+static void
+_bdf_shift( unsigned long  n,
+            _bdf_list_t*   list)
+{
+  unsigned long i, u;
+
+  if ( list == 0 || list->used == 0 || n == 0 )
+    return;
+
+  if ( n >= list->used )
+  {
+    list->used = 0;
+    return;
+  }
+  for ( u = n, i = 0; u < list->used; i++, u++ )
+    list->field[i] = list->field[u];
+
+  list->used -= n;
+}
+
+
+static char*
+_bdf_join( int             c,
+           unsigned long*  len,
+           _bdf_list_t*    list)
+{
+  unsigned long i, j;
+  char *fp, *dp;
+
+  if ( list == 0 || list->used == 0 )
+    return 0;
+
+  *len = 0;
+
+  dp = list->field[0];
+
+  for ( i = j = 0; i < list->used; i++ )
+  {
+    fp = list->field[i];
+    while (*fp)
+      dp[j++] = *fp++;
+      
+    if (i + 1 < list->used)
+      dp[j++] = c;
+  }
+  dp[j] = 0;
+
+  *len = j;
+  return dp;
+}
+
+/*
+ * High speed file reader that passes each line to a callback.
+ */
+int ftreadstream( FT_Stream  stream,
+                  char*      buffer,
+                  int        count )
+{
+  int read_bytes;
+  int pos = stream->pos;
+
+  if ( pos >= stream->size )
+  {
+    FT_ERROR(( "FT_Read_Stream_At:" ));
+    FT_ERROR(( " invalid i/o; pos = 0x%lx, size = 0x%lx\n",
+               pos, stream->size ));
+    return 0;
+  }
+
+  if ( stream->read )
+    read_bytes = stream->read( stream, pos, buffer, count );
+  else
+  {
+    read_bytes = stream->size - pos;
+    if ( read_bytes > count )
+      read_bytes = count;
+
+    ft_memcpy( buffer, stream->base + pos, read_bytes );
+  }
+
+  stream->pos = pos + read_bytes;
+
+  return read_bytes;
+}
+
+static int
+_bdf_readstream( FT_Stream         stream,
+                 _bdf_line_func_t  callback,
+                 void*             client_data,
+                 unsigned long*    lno)
+{
+  _bdf_line_func_t cb;
+  unsigned long lineno;
+  int n, res, done, refill, bytes, hold;
+  char *ls, *le, *pp, *pe, *hp;
+  char buf[65536];
+
+  if (callback == 0)
+    return -1;
+
+  cb     = callback;
+  lineno = 1;
+  buf[0] = 0;
+  res    = done = 0;
+  pp     = ls = le = buf;
+  bytes  = 65536;
+
+  while ( !done && (n = ftreadstream(stream, pp, bytes)) > 0 )
+  {
+    /*
+     * Determine the new end of the buffer pages.
+     */
+    pe = pp + n;
+
+    for (refill = 0; done == 0 && refill == 0; )
+    {
+      while (le < pe && *le != '\n' && *le != '\r')
+        le++;
+
+      if (le == pe)
+      {
+        /*
+         * Hit the end of the last page in the buffer.  Need to find
+         * out how many pages to shift and how many pages need to be
+         * read in.  Adjust the line start and end pointers down to
+         * point to the right places in the pages.
+         */
+        pp = buf + (((ls - buf) >> 13) << 13);
+        n = pp - buf;
+        ls -= n;
+        le -= n;
+        n   = pe - pp;
+        (void) ft_memcpy(buf, pp, n);
+        pp = buf + n;
+        bytes = 65536 - n;
+        refill = 1;
+      }
+      else
+      {
+        /*
+         * Temporarily NULL terminate the line.
+         */
+        hp   = le;
+        hold = *le;
+        *le  = 0;
+
+        if (callback && *ls != '#' && *ls != 0x1a && le > ls &&
+            (res = (*cb)(ls, le - ls, lineno, (void *) &cb,
+                         client_data)) != 0)
+          done = 1;
+        else {
+            ls = ++le;
+            /*
+             * Handle the case of DOS crlf sequences.
+             */
+            if (le < pe && hold == '\n' && *le =='\r')
+              ls = ++le;
+        }
+
+        /*
+         * Increment the line number.
+         */
+        lineno++;
+
+        /*
+         * Restore the character at the end of the line.
+         */
+        *hp = hold;
+      }
+    }
+  }
+  *lno = lineno;
+  return res;
+}
+
+
+FT_LOCAL_DEF( void )
+_bdf_memmove(char *dest, char *src, unsigned long bytes)
+{
+    long i, j;
+
+    i = (long) bytes;
+    j = i & 7;
+    i = (i + 7) >> 3;
+
+    /*
+     * Do a memmove using Ye Olde Duff's Device for efficiency.
+     */
+    if (src < dest) {
+        src += bytes;
+        dest += bytes;
+
+        switch (j) {
+          case 0: do {
+              *--dest = *--src;
+            case 7: *--dest = *--src;
+            case 6: *--dest = *--src;
+            case 5: *--dest = *--src;
+            case 4: *--dest = *--src;
+            case 3: *--dest = *--src;
+            case 2: *--dest = *--src;
+            case 1: *--dest = *--src;
+          } while (--i > 0);
+        }
+    } else if (src > dest) {
+        switch (j) {
+          case 0: do {
+              *dest++ = *src++;
+            case 7: *dest++ = *src++;
+            case 6: *dest++ = *src++;
+            case 5: *dest++ = *src++;
+            case 4: *dest++ = *src++;
+            case 3: *dest++ = *src++;
+            case 2: *dest++ = *src++;
+            case 1: *dest++ = *src++;
+          } while (--i > 0);
+        }
+    }
+}
+
+static const unsigned char a2i[128] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char odigits[32] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char ddigits[32] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char hdigits[32] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x03,
+    0x7e, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+#define isdigok(m, d) (m[(d) >> 3] & (1 << ((d) & 7)))
+
+/*
+ * Routine to convert an ASCII string into an unsigned long integer.
+ */
+static unsigned long
+_bdf_atoul(char *s, char **end, int base)
+{
+  unsigned long v;
+  unsigned char *dmap;
+
+  if (s == 0 || *s == 0)
+    return 0;
+
+  /*
+   * Make sure the radix is something recognizable.  Default to 10.
+   */
+  switch (base)
+  {
+    case 8: dmap = odigits; break;
+    case 16: dmap = hdigits; break;
+    default: base = 10; dmap = ddigits; break;
+  }
+
+  /*
+   * Check for the special hex prefix.
+   */
+  if ( s[0] == '0' && ( s[1] == 'x' || s[1] == 'X'))
+  {
+    base = 16;
+    dmap = hdigits;
+    s   += 2;
+  }
+
+  for ( v = 0; isdigok(dmap, *s); s++ )
+    v = (v * base) + a2i[(int) *s];
+
+  if (end != 0)
+    *end = s;
+
+  return v;
+}
+
+
+/*
+ * Routine to convert an ASCII string into an signed long integer.
+ */
+static long
+_bdf_atol(char *s, char **end, int base)
+{
+  long v, neg;
+  unsigned char *dmap;
+
+  if (s == 0 || *s == 0)
+    return 0;
+
+  /*
+   * Make sure the radix is something recognizable.  Default to 10.
+   */
+  switch (base) {
+    case 8: dmap = odigits; break;
+    case 16: dmap = hdigits; break;
+    default: base = 10; dmap = ddigits; break;
+  }
+
+  /*
+   * Check for a minus sign.
+   */
+  neg = 0;
+  if (*s == '-') {
+      s++;
+      neg = 1;
+  }
+
+  /*
+   * Check for the special hex prefix.
+   */
+  if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
+      base = 16;
+      dmap = hdigits;
+      s += 2;
+  }
+
+  for (v = 0; isdigok(dmap, *s); s++)
+    v = (v * base) + a2i[(int) *s];
+
+  if (end != 0)
+    *end = s;
+
+  return (!neg) ? v : -v;
+}
+
+
+/*
+ * Routine to convert an ASCII string into an signed short integer.
+ */
+static short
+_bdf_atos(char *s, char **end, int base)
+{
+    short v, neg;
+    unsigned char *dmap;
+
+    if (s == 0 || *s == 0)
+      return 0;
+
+    /*
+     * Make sure the radix is something recognizable.  Default to 10.
+     */
+    switch (base) {
+      case 8: dmap = odigits; break;
+      case 16: dmap = hdigits; break;
+      default: base = 10; dmap = ddigits; break;
+    }
+
+    /*
+     * Check for a minus.
+     */
+    neg = 0;
+    if (*s == '-') {
+        s++;
+        neg = 1;
+    }
+
+    /*
+     * Check for the special hex prefix.
+     */
+    if (*s == '0' && (*(s + 1) == 'x' || *(s + 1) == 'X')) {
+        base = 16;
+        dmap = hdigits;
+        s += 2;
+    }
+
+    for (v = 0; isdigok(dmap, *s); s++)
+      v = (v * base) + a2i[(int) *s];
+
+    if (end != 0)
+      *end = s;
+
+    return (!neg) ? v : -v;
+}
+
+/*
+ * Routine to compare two glyphs by encoding so they can be sorted.
+ */
+static int
+by_encoding(const void *a, const void *b)
+{
+    bdf_glyph_t *c1, *c2;
+
+    c1 = (bdf_glyph_t *) a;
+    c2 = (bdf_glyph_t *) b;
+    if (c1->encoding < c2->encoding)
+      return -1;
+    else if (c1->encoding > c2->encoding)
+      return 1;
+    return 0;
+}
+
+
+
+static FT_Error
+bdf_create_property( char*        name,
+                     int          format,
+                     bdf_font_t*  font )
+{
+  unsigned long    n;
+  bdf_property_t*  p;
+  FT_Memory        memory = font->memory;
+  FT_Error         error;
+
+  /*
+   * First check to see if the property has
+   * already been added or not.  If it has, then
+   * simply ignore it.
+   */
+  if ( hash_lookup( name, &(font->proptbl)) )
+    return FT_Err_Ok;
+
+  if (font->nuser_props == 0)
+  {
+    if ( FT_NEW( font->user_props ) )
+      return error;
+  }
+  else
+  {
+    if ( FT_RENEW_ARRAY( font->user_props, font->nuser_props,
+                                          (font->nuser_props + 1) ) )
+      return error;
+  }
+
+  p = font->user_props + font->nuser_props;
+  
+  FT_ZERO( p );
+  
+  n = (unsigned long) (ft_strlen(name) + 1);
+  
+  if ( FT_ALLOC ( p->name , n) )
+    return error;
+    
+  FT_MEM_COPY(p->name, name, n);
+  p->format  = format;
+  p->builtin = 0;
+
+  n = _num_bdf_properties + font->nuser_props;
+
+  error = hash_insert(p->name, (void *) n, &(font->proptbl) , memory);
+  if (error) return error;
+
+  font->nuser_props++;
+  return FT_Err_Ok;
+}
+
+
+FT_LOCAL_DEF( bdf_property_t* )
+bdf_get_property(char *name, bdf_font_t *font)
+{
+  hashnode hn;
+  unsigned long propid;
+
+  if (name == 0 || *name == 0)
+    return 0;
+
+  if ((hn = hash_lookup(name, &(font->proptbl))) == 0)
+    return 0;
+
+  propid = (unsigned long) hn->data;
+  if (propid >= _num_bdf_properties)
+    return font->user_props + (propid - _num_bdf_properties);
+
+  return _bdf_properties + propid;
+}
+
+
+/**************************************************************************
+ *
+ * BDF font file parsing flags and functions.
+ *
+ **************************************************************************/
+
+/*
+ * Parse flags.
+ */
+#define _BDF_START     0x0001
+#define _BDF_FONT_NAME 0x0002
+#define _BDF_SIZE      0x0004
+#define _BDF_FONT_BBX  0x0008
+#define _BDF_PROPS     0x0010
+#define _BDF_GLYPHS    0x0020
+#define _BDF_GLYPH     0x0040
+#define _BDF_ENCODING  0x0080
+#define _BDF_SWIDTH    0x0100
+#define _BDF_DWIDTH    0x0200
+#define _BDF_BBX       0x0400
+#define _BDF_BITMAP    0x0800
+
+#define _BDF_SWIDTH_ADJ 0x1000
+
+#define _BDF_GLYPH_BITS (_BDF_GLYPH|_BDF_ENCODING|_BDF_SWIDTH|\
+                         _BDF_DWIDTH|_BDF_BBX|_BDF_BITMAP)
+
+#define _BDF_GLYPH_WIDTH_CHECK 0x40000000
+#define _BDF_GLYPH_HEIGHT_CHECK 0x80000000
+
+/*
+ * Auto correction messages.
+ */
+#define ACMSG1 "FONT_ASCENT property missing.  Added \"FONT_ASCENT %hd\"."
+#define ACMSG2 "FONT_DESCENT property missing.  Added \"FONT_DESCENT %hd\"."
+#define ACMSG3 "Font width != actual width.  Old: %hd New: %hd."
+#define ACMSG4 "Font left bearing != actual left bearing.  Old: %hd New: %hd."
+#define ACMSG5 "Font ascent != actual ascent.  Old: %hd New: %hd."
+#define ACMSG6 "Font descent != actual descent.  Old: %hd New: %hd."
+#define ACMSG7 "Font height != actual height. Old: %hd New: %hd."
+#define ACMSG8 "Glyph scalable width (SWIDTH) adjustments made."
+#define ACMSG9 "SWIDTH field missing at line %ld.  Set automatically."
+#define ACMSG10 "DWIDTH field missing at line %ld.  Set to glyph width."
+#define ACMSG11 "SIZE bits per pixel field adjusted to %hd."
+#define ACMSG12 "Duplicate encoding %ld (%s) changed to unencoded."
+#define ACMSG13 "Glyph %ld extra rows removed."
+#define ACMSG14 "Glyph %ld extra columns removed."
+#define ACMSG15 "Incorrect glyph count: %ld indicated but %ld found."
+
+/*
+ * Error messages.
+ */
+#define ERRMSG1 "[line %ld] Missing \"%s\" line."
+#define ERRMSG2 "[line %ld] Font header corrupted or missing fields."
+#define ERRMSG3 "[line %ld] Font glyphs corrupted or missing fields."
+
+static FT_Error
+_bdf_add_acmsg ( bdf_font_t*    font,
+                 char*          msg,
+                 unsigned long  len )
+{
+  char*      cp;
+  FT_Memory  memory = font->memory;
+  FT_Error   error;
+
+  if ( font->acmsgs_len == 0 )
+  {
+    if ( FT_ALLOC ( font->acmsgs , len + 1 ) )
+      return error;
+  }
+  else
+  {
+    if ( FT_REALLOC ( font->acmsgs , font->acmsgs_len ,
+                      font->acmsgs_len + len + 1 ) )
+      return error;
+  }
+
+  cp = font->acmsgs + font->acmsgs_len;
+  FT_MEM_COPY(cp, msg, len);
+  cp   += len;
+  *cp++ = '\n';
+  font->acmsgs_len += len + 1;
+
+  return FT_Err_Ok;
+}
+
+
+static FT_Error
+_bdf_add_comment ( bdf_font_t*    font,
+                   char*          comment,
+                   unsigned long  len )
+{
+  char *cp;
+  FT_Memory memory = font->memory;
+  FT_Error error;
+
+  if (font->comments_len == 0) {
+    if ( FT_ALLOC ( font->comments , len + 1 ) )
+      return error;
+  }
+  else
+  {
+    if ( FT_REALLOC ( font->comments , font->comments_len,
+                      font->comments_len + len + 1) )
+      return error;
+  }
+
+  cp = font->comments + font->comments_len;
+  FT_MEM_COPY(cp, comment, len);
+  cp += len;
+  *cp++ = '\n';
+  font->comments_len += len + 1;
+
+  return FT_Err_Ok;
+}
+
+/*
+ * Set the spacing from the font name if it exists, or set it to the default
+ * specified in the options.
+ */
+static void
+_bdf_set_default_spacing( bdf_font_t*     font,
+                          bdf_options_t*  opts)
+{
+  unsigned long  len;
+  char            name[128];
+  _bdf_list_t     list;
+  FT_Memory       memory;
+  /*    FT_Error error; */
+
+  if ( font == 0 || font->name == 0 || font->name[0] == 0 )
+    return;
+
+  memory = font->memory;
+
+  font->spacing = opts->font_spacing;
+
+  len = (unsigned long) ( ft_strlen(font->name) + 1 );
+  (void) ft_memcpy(name, font->name, len);
+  
+  list.size = list.used = 0;
+  _bdf_split("-", name, len, &list, memory);
+  
+  if (list.used == 15) {
+      switch (list.field[11][0]) {
+        case 'C': case 'c': font->spacing = BDF_CHARCELL; break;
+        case 'M': case 'm': font->spacing = BDF_MONOWIDTH; break;
+        case 'P': case 'p': font->spacing = BDF_PROPORTIONAL; break;
+      }
+  }
+  if (list.size > 0)
+    FT_FREE(list.field);
+}
+
+
+/*
+ * Determine if the property is an atom or not.  If it is, then clean it up so
+ * the double quotes are removed if they exist.
+ */
+static int
+_bdf_is_atom( char*          line,
+              unsigned long  linelen,
+              char*         *name,
+              char*         *value,
+	      bdf_font_t*    font)
+{
+    int hold;
+    char *sp, *ep;
+    bdf_property_t *p;
+
+    *name = sp = ep = line;
+    while (*ep && *ep != ' ' && *ep != '\t')
+      ep++;
+
+    hold = -1;
+    if (*ep)
+    {
+      hold = *ep;
+      *ep  = 0;
+    }
+
+    p = bdf_get_property(sp, font);
+
+    /*
+     * Restore the character that was saved before any return can happen.
+     */
+    if (hold != -1)
+      *ep = hold;
+
+    /*
+     * If the propert exists and is not an atom, just return here.
+     */
+    if (p && p->format != BDF_ATOM)
+      return 0;
+
+    /*
+     * The property is an atom.  Trim all leading and trailing whitespace and
+     * double quotes for the atom value.
+     */
+    sp = ep;
+    ep = line + linelen;
+
+    /*
+     * Trim the leading whitespace if it exists.
+     */
+    *sp++ = 0;
+    while (*sp && (*sp == ' ' || *sp == '\t'))
+      sp++;
+
+    /*
+     * Trim the leading double quote if it exists.
+     */
+    if (*sp == '"')
+      sp++;
+    *value = sp;
+
+    /*
+     * Trim the trailing whitespace if it exists.
+     */
+    while (ep > sp && (*(ep - 1) == ' ' || *(ep - 1) == '\t'))
+      *--ep = 0;
+
+    /*
+     * Trim the trailing double quote if it exists.
+     */
+    if (ep > sp && *(ep - 1) == '"')
+      *--ep = 0;
+
+    return 1;
+}
+
+
+static FT_Error
+_bdf_add_property ( bdf_font_t*  font,
+                    char*        name,
+                    char*        value)
+{
+    unsigned long propid;
+    hashnode hn;
+    int len;
+    bdf_property_t *prop, *fp;
+    FT_Memory memory = font->memory;
+    FT_Error error;
+    /*    hashtable proptbl = font->proptbl;
+    bdf_property_t *user_props = font->user_props;
+    unsigned long nuser_props = font->nuser_props;
+    */
+
+     /*
+     * First, check to see if the property already exists in the font.
+     */
+    if ((hn = hash_lookup(name, (hashtable *) font->internal)) != 0) {
+        /*
+         * The property already exists in the font, so simply replace
+         * the value of the property with the current value.
+         */
+        fp = font->props + (unsigned long) hn->data;
+
+        switch (prop->format)
+        {
+          case BDF_ATOM:
+            {
+              /*
+               * Delete the current atom if it exists.
+               */
+              FT_FREE ( fp->value.atom );
+  
+              if (value == 0)
+                len = 1;
+              else
+                len = ft_strlen(value) + 1;
+              if (len > 1)
+              {
+  	      if ( FT_ALLOC ( fp->value.atom , len ) )
+                  return error;
+                  
+                FT_MEM_COPY(fp->value.atom, value, len);
+              }
+              else
+                fp->value.atom = 0;
+            }
+            break;
+            
+          case BDF_INTEGER:
+            fp->value.int32 = _bdf_atol(value, 0, 10);
+            break;
+            
+          case BDF_CARDINAL:
+            fp->value.card32 = _bdf_atoul(value, 0, 10);
+            break;
+          
+          default:
+            ;
+        }
+        return FT_Err_Ok;
+    }
+
+    /*
+     * See if this property type exists yet or not.  If not, create it.
+     */
+    hn = hash_lookup(name, &(font->proptbl));
+    if (hn == 0) {
+        bdf_create_property(name, BDF_ATOM, font);
+        hn = hash_lookup(name, &(font->proptbl));
+    }
+
+    /*
+     * Allocate another property if this is overflow.
+     */
+    if (font->props_used == font->props_size)
+    {
+      if (font->props_size == 0)
+      {
+        if ( FT_NEW( font->props ) )
+          return error;
+      }
+      else
+      {
+        if ( FT_RENEW_ARRAY( font->props, font->props_size,
+                                         (font->props_size + 1) ) )
+          return error;
+      }
+      fp = font->props + font->props_size;
+      FT_ZERO( fp );
+      font->props_size++;
+    }
+
+    propid = (unsigned long) hn->data;
+    if (propid >= _num_bdf_properties)
+      prop = font->user_props + (propid - _num_bdf_properties);
+    else
+      prop = _bdf_properties + propid;
+
+    fp = font->props + font->props_used;
+
+    fp->name    = prop->name;
+    fp->format  = prop->format;
+    fp->builtin = prop->builtin;
+
+    switch (prop->format)
+    {
+      case BDF_ATOM:
+        {
+          fp->value.atom = NULL;
+          
+          if ( value && value[0] != 0 )
+          {
+            len = ft_strlen(value) + 1;
+
+  	    if ( FT_ALLOC ( fp->value.atom , len ) )
+                return error;
+                
+             FT_MEM_COPY (fp->value.atom, value, len);
+          }
+        }
+        break;
+
+    case BDF_INTEGER:
+      fp->value.int32 = _bdf_atol(value, 0, 10);
+      break;
+
+    case BDF_CARDINAL:
+      fp->value.card32 = _bdf_atoul(value, 0, 10);
+      break;
+    
+    default:
+      ;
+    }
+
+    /*
+     * If the property happens to be a comment, then it doesn't need
+     * to be added to the internal hash table.
+     */
+    if ( ft_memcmp(name, "COMMENT", 7) != 0 )
+      /*
+       * Add the property to the font property table.
+       */
+      hash_insert( fp->name, (void *) font->props_used,
+                   (hashtable *) font->internal, memory);
+
+    font->props_used++;
+
+    /*
+     * Some special cases need to be handled here.  The DEFAULT_CHAR property
+     * needs to be located if it exists in the property list, the FONT_ASCENT
+     * and FONT_DESCENT need to be assigned if they are present, and the
+     * SPACING property should override the default spacing.
+     */
+    if ( ft_memcmp(name, "DEFAULT_CHAR", 12) == 0 )
+      font->default_glyph = fp->value.int32;
+      
+    else if ( ft_memcmp(name, "FONT_ASCENT", 11) == 0 )
+      font->font_ascent = fp->value.int32;
+      
+    else if ( ft_memcmp(name, "FONT_DESCENT", 12) == 0 )
+      font->font_descent = fp->value.int32;
+      
+    else if ( ft_memcmp(name, "SPACING", 7) == 0 )
+    {
+      if (fp->value.atom[0] == 'p' || fp->value.atom[0] == 'P')
+        font->spacing = BDF_PROPORTIONAL;
+        
+      else if (fp->value.atom[0] == 'm' || fp->value.atom[0] == 'M')
+        font->spacing = BDF_MONOWIDTH;
+        
+      else if (fp->value.atom[0] == 'c' || fp->value.atom[0] == 'C')
+        font->spacing = BDF_CHARCELL;
+    }
+
+    return FT_Err_Ok;
+}
+
+/*
+ * Actually parse the glyph info and bitmaps.
+ */
+static int
+_bdf_parse_glyphs( char*          line,
+                   unsigned long  linelen,
+                   unsigned long  lineno,
+                   void*          call_data,
+                   void*          client_data)
+{
+  int c;
+  char *s;
+  unsigned char *bp;
+  unsigned long i, slen, nibbles;
+  double ps, rx, dw, sw;
+  _bdf_line_func_t *next;
+  _bdf_parse_t *p;
+  bdf_glyph_t *glyph;
+  bdf_font_t *font;
+  char nbuf[128];
+  FT_Memory memory;
+  FT_Error error;
+
+  next = (_bdf_line_func_t *) call_data;
+  p = (_bdf_parse_t *) client_data;
+
+  font = p->font;
+  memory = font->memory;
+
+  /*
+   * Check for a comment.
+   */
+  if (ft_memcmp(line, "COMMENT", 7) == 0) {
+      linelen -= 7;
+      s = line + 7;
+      if (*s != 0) {
+          s++;
+          linelen--;
+      }
+      _bdf_add_comment(p->font, s, linelen);
+      return 0;
+  }
+
+  /*
+   * The very first thing expected is the number of glyphs.
+   */
+  if (!(p->flags & _BDF_GLYPHS)) {
+      if (ft_memcmp(line, "CHARS", 5) != 0) {
+          sprintf(nbuf, ERRMSG1, lineno, "CHARS");
+          _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
+          return BDF_MISSING_CHARS;
+      }
+      _bdf_split(" +", line, linelen, &p->list, memory);
+      p->cnt = font->glyphs_size = _bdf_atoul(p->list.field[1], 0, 10);
+
+      /*
+       * Make sure the number of glyphs is non-zero.
+       */
+      if (p->cnt == 0)
+        font->glyphs_size = 64;
+
+if ( FT_ALLOC ( font->glyphs , sizeof(bdf_glyph_t) *
+                      font->glyphs_size ) )
+        return FT_Err_Out_Of_Memory;
+
+      /*
+       * Set up the callback to indicate the glyph loading is about to
+       * begin.
+       */
+      if (p->callback != 0) {
+          p->cb.reason = BDF_LOAD_START;
+          p->cb.total = p->cnt;
+          p->cb.current = 0;
+          (*p->callback)(&p->cb, p->client_data);
+      }
+      p->flags |= _BDF_GLYPHS;
+      return 0;
+  }
+
+  /*
+   * Check for the ENDFONT field.
+   */
+  if (ft_memcmp(line, "ENDFONT", 7) == 0) {
+      /*
+       * Sort the glyphs by encoding.
+       */
+    qsort((char *) font->glyphs, font->glyphs_used, sizeof(bdf_glyph_t),
+          by_encoding);
+
+      p->flags &= ~_BDF_START;
+      return 0;
+  }
+
+  /*
+   * Check for the ENDCHAR field.
+   */
+  if (ft_memcmp(line, "ENDCHAR", 7) == 0) {
+      /*
+       * Set up and call the callback if it was passed.
+       */
+    if (p->callback != 0) {
+      p->cb.reason = BDF_LOADING;
+      p->cb.total = font->glyphs_size;
+      p->cb.current = font->glyphs_used;
+      (*p->callback)(&p->cb, p->client_data);
+    }
+    p->glyph_enc = 0;
+    p->flags &= ~_BDF_GLYPH_BITS;
+    return 0;
+  }
+
+  /*
+   * Check to see if a glyph is being scanned but should be ignored
+   * because it is an unencoded glyph.
+   */
+  if ((p->flags & _BDF_GLYPH) &&
+      p->glyph_enc == -1 && p->opts->keep_unencoded == 0)
+    return 0;
+
+  /*
+   * Check for the STARTCHAR field.
+   */
+  if (ft_memcmp(line, "STARTCHAR", 9) == 0) {
+      /*
+       * Set the character name in the parse info first until the
+       * encoding can be checked for an unencoded character.
+       */
+    if (p->glyph_name != 0)
+      FT_FREE(p->glyph_name);
+    _bdf_split(" +", line, linelen, &p->list,memory);
+    _bdf_shift(1, &p->list);
+    s = _bdf_join(' ', &slen, &p->list);
+    if ( FT_ALLOC ( p->glyph_name , (slen + 1) ) )
+      return BDF_OUT_OF_MEMORY;
+    FT_MEM_COPY(p->glyph_name, s, slen + 1);
+    p->flags |= _BDF_GLYPH;
+    return 0;
+  }
+
+  /*
+   * Check for the ENCODING field.
+   */
+  if (ft_memcmp(line, "ENCODING", 8) == 0) {
+    if (!(p->flags & _BDF_GLYPH)) {
+      /*
+       * Missing STARTCHAR field.
+       */
+      sprintf(nbuf, ERRMSG1, lineno, "STARTCHAR");
+      _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+      return BDF_MISSING_STARTCHAR;
+    }
+    _bdf_split(" +", line, linelen, &p->list, memory);
+    p->glyph_enc = _bdf_atol(p->list.field[1], 0, 10);
+
+    /*
+     * Check to see if this encoding has already been encountered.  If it
+     * has then change it to unencoded so it gets added if indicated.
+     */
+    if (p->glyph_enc >= 0) {
+      if (_bdf_glyph_modified(p->have, p->glyph_enc)) {
+        /*
+         * Add a message saying a glyph has been moved to the
+         * unencoded area.
+         */
+        sprintf(nbuf, ACMSG12, p->glyph_enc, p->glyph_name);
+        _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+        p->glyph_enc = -1;
+        font->modified = 1;
+      } else
+        _bdf_set_glyph_modified(p->have, p->glyph_enc);
+    }
+
+    if (p->glyph_enc >= 0) {
+      /*
+       * Make sure there are enough glyphs allocated in case the
+       * number of characters happen to be wrong.
+       */
+      if (font->glyphs_used == font->glyphs_size) {
+        if ( FT_REALLOC ( font->glyphs,
+                          sizeof(bdf_glyph_t) * font->glyphs_size,
+                          sizeof(bdf_glyph_t) * (font->glyphs_size + 64) ) )
+          return BDF_OUT_OF_MEMORY;
+        FT_MEM_SET ((char *) (font->glyphs + font->glyphs_size),
+                    0, sizeof(bdf_glyph_t) << 6); /* FZ inutile */
+        font->glyphs_size += 64;
+      }
+
+      glyph = font->glyphs + font->glyphs_used++;
+      glyph->name = p->glyph_name;
+      glyph->encoding = p->glyph_enc;
+
+      /*
+       * Reset the initial glyph info.
+       */
+      p->glyph_name = 0;
+    } else {
+      /*
+       * Unencoded glyph.  Check to see if it should be added or not.
+       */
+      if (p->opts->keep_unencoded != 0) {
+        /*
+         * Allocate the next unencoded glyph.
+         */
+        if (font->unencoded_used == font->unencoded_size) {
+          if (font->unencoded_size == 0) {
+            if ( FT_ALLOC ( font->unencoded , sizeof(bdf_glyph_t) << 2 ) )
+              return BDF_OUT_OF_MEMORY;
+          }
+          else {
+            if ( FT_REALLOC ( font->unencoded ,
+                              sizeof(bdf_glyph_t) * font->unencoded_size,
+                              sizeof(bdf_glyph_t) *
+                              (font->unencoded_size + 4) ) )
+              return BDF_OUT_OF_MEMORY;
+          }
+          font->unencoded_size += 4;
+        }
+
+        glyph = font->unencoded + font->unencoded_used;
+        glyph->name = p->glyph_name;
+        glyph->encoding = font->unencoded_used++;
+      } else
+        /*
+         * Free up the glyph name if the unencoded shouldn't be
+         * kept.
+         */
+        FT_FREE( p->glyph_name );
+
+      p->glyph_name = 0;
+    }
+
+    /*
+     * Clear the flags that might be added when width and height are
+     * checked for consistency.
+     */
+    p->flags &= ~(_BDF_GLYPH_WIDTH_CHECK|_BDF_GLYPH_HEIGHT_CHECK);
+
+    p->flags |= _BDF_ENCODING;
+    return 0;
+  }
+
+  /*
+   * Point at the glyph being constructed.
+   */
+  if (p->glyph_enc == -1)
+    glyph = font->unencoded + (font->unencoded_used - 1);
+  else
+    glyph = font->glyphs + (font->glyphs_used - 1);
+
+  /*
+   * Check to see if a bitmap is being constructed.
+   */
+  if (p->flags & _BDF_BITMAP) {
+      /*
+       * If there are more rows than are specified in the glyph metrics,
+       * ignore the remaining lines.
+       */
+      if (p->row >= glyph->bbx.height) {
+          if (!(p->flags & _BDF_GLYPH_HEIGHT_CHECK)) {
+              sprintf(nbuf, ACMSG13, glyph->encoding);
+              _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+              p->flags |= _BDF_GLYPH_HEIGHT_CHECK;
+              font->modified = 1;
+          }
+          return 0;
+      }
+
+      /*
+       * Only collect the number of nibbles indicated by the glyph metrics.
+       * If there are more columns, they are simply ignored.
+       */
+      nibbles = p->bpr << 1;
+      bp = glyph->bitmap + (p->row * p->bpr);
+      for (i = 0, *bp = 0; i < nibbles; i++) {
+          c = line[i];
+          *bp = (*bp << 4) + a2i[c];
+          if (i + 1 < nibbles && (i & 1))
+            *++bp = 0;
+      }
+
+      /*
+       * If any line has extra columns, indicate they have been removed.
+       */
+      if ((line[nibbles] == '0' || a2i[(int) line[nibbles]] != 0) &&
+          !(p->flags & _BDF_GLYPH_WIDTH_CHECK)) {
+          sprintf(nbuf, ACMSG14, glyph->encoding);
+          _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+          p->flags |= _BDF_GLYPH_WIDTH_CHECK;
+          font->modified = 1;
+      }
+
+      p->row++;
+      return 0;
+  }
+
+  /*
+   * Expect the SWIDTH (scalable width) field next.
+   */
+  if (ft_memcmp(line, "SWIDTH", 6) == 0) {
+      if (!(p->flags & _BDF_ENCODING)) {
+          /*
+           * Missing ENCODING field.
+           */
+          sprintf(nbuf, ERRMSG1, lineno, "ENCODING");
+          _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+          return BDF_MISSING_ENCODING;
+      }
+      _bdf_split(" +", line, linelen, &p->list, memory);
+      glyph->swidth = _bdf_atoul(p->list.field[1], 0, 10);
+      p->flags |= _BDF_SWIDTH;
+      return 0;
+  }
+
+  /*
+   * Expect the DWIDTH (scalable width) field next.
+   */
+  if (ft_memcmp(line, "DWIDTH", 6) == 0) {
+      _bdf_split(" +", line, linelen, &p->list,memory);
+      glyph->dwidth = _bdf_atoul(p->list.field[1], 0, 10);
+
+      if (!(p->flags & _BDF_SWIDTH)) {
+          /*
+           * Missing SWIDTH field.  Add an auto correction message and set
+           * the scalable width from the device width.
+           */
+          sprintf(nbuf, ACMSG9, lineno);
+          _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+          ps = (double) font->point_size;
+          rx = (double) font->resolution_x;
+          dw = (double) glyph->dwidth;
+          glyph->swidth = (unsigned short) ((dw * 72000.0) / (ps * rx));
+      }
+
+      p->flags |= _BDF_DWIDTH;
+      return 0;
+  }
+
+  /*
+   * Expect the BBX field next.
+   */
+  if (ft_memcmp(line, "BBX", 3) == 0) {
+      _bdf_split(" +", line, linelen, &p->list, memory);
+      glyph->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
+      glyph->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
+      glyph->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
+      glyph->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
+
+      /*
+       * Generate the ascent and descent of the character.
+       */
+      glyph->bbx.ascent = glyph->bbx.height + glyph->bbx.y_offset;
+      glyph->bbx.descent = -glyph->bbx.y_offset;
+
+      /*
+       * Determine the overall font bounding box as the characters are
+       * loaded so corrections can be done later if indicated.
+       */
+      p->maxas = MAX(glyph->bbx.ascent, p->maxas);
+      p->maxds = MAX(glyph->bbx.descent, p->maxds);
+      p->rbearing = glyph->bbx.width + glyph->bbx.x_offset;
+      p->maxrb = MAX(p->rbearing, p->maxrb);
+      p->minlb = MIN(glyph->bbx.x_offset, p->minlb);
+      p->maxlb = MAX(glyph->bbx.x_offset, p->maxlb);
+
+      if (!(p->flags & _BDF_DWIDTH)) {
+          /*
+           * Missing DWIDTH field.  Add an auto correction message and set
+           * the device width to the glyph width.
+           */
+          sprintf(nbuf, ACMSG10, lineno);
+          _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+          glyph->dwidth = glyph->bbx.width;
+      }
+
+      /*
+       * If the BDF_CORRECT_METRICS flag is set, then adjust the SWIDTH
+       * value if necessary.
+       */
+      if (p->opts->correct_metrics != 0) {
+          /*
+           * Determine the point size of the glyph.
+           */
+          ps = (double) font->point_size;
+          rx = (double) font->resolution_x;
+          dw = (double) glyph->dwidth;
+          sw = (unsigned short) ((dw * 72000.0) / (ps * rx));
+
+          if (sw != glyph->swidth) {
+              glyph->swidth = sw;
+              if (p->glyph_enc == -1)
+                _bdf_set_glyph_modified(font->umod,
+                                        font->unencoded_used - 1);
+              else
+                _bdf_set_glyph_modified(font->nmod, glyph->encoding);
+              p->flags |= _BDF_SWIDTH_ADJ;
+              font->modified = 1;
+          }
+      }
+      p->flags |= _BDF_BBX;
+      return 0;
+  }
+
+  /*
+   * And finally, gather up the bitmap.
+   */
+  if (ft_memcmp(line, "BITMAP", 6) == 0) {
+      if (!(p->flags & _BDF_BBX)) {
+          /*
+           * Missing BBX field.
+           */
+          sprintf(nbuf, ERRMSG1, lineno, "BBX");
+          _bdf_add_acmsg(font, nbuf, ft_strlen(nbuf));
+          return BDF_MISSING_BBX;
+      }
+      /*
+       * Allocate enough space for the bitmap.
+       */
+      p->bpr = ((glyph->bbx.width * p->font->bpp) + 7) >> 3;
+      glyph->bytes = p->bpr * glyph->bbx.height;
+      if ( FT_ALLOC ( glyph->bitmap , glyph->bytes ) )
+        return BDF_OUT_OF_MEMORY;
+      p->row = 0;
+      p->flags |= _BDF_BITMAP;
+      return 0;
+  }
+
+  return BDF_INVALID_LINE;
+}
+
+/*
+* Load the font properties.
+*/
+static int
+_bdf_parse_properties(char *line, unsigned long linelen, unsigned long lineno,
+                    void *call_data, void *client_data)
+{
+  unsigned long vlen;
+  _bdf_line_func_t *next;
+  _bdf_parse_t *p;
+  char *name, *value, nbuf[128];
+  FT_Memory memory;
+
+  next = (_bdf_line_func_t *) call_data;
+  p = (_bdf_parse_t *) client_data;
+
+  memory = p->font->memory;
+  /*
+   * Check for the end of the properties.
+   */
+  if (ft_memcmp(line, "ENDPROPERTIES", 13) == 0) {
+      /*
+       * If the FONT_ASCENT or FONT_DESCENT properties have not been
+       * encountered yet, then make sure they are added as properties and
+       * make sure they are set from the font bounding box info.
+       *
+       * This is *always* done regardless of the options, because X11
+       * requires these two fields to compile fonts.
+       */
+      if (bdf_get_font_property(p->font, "FONT_ASCENT") == 0) {
+          p->font->font_ascent = p->font->bbx.ascent;
+          sprintf(nbuf, "%hd", p->font->bbx.ascent);
+          _bdf_add_property(p->font, "FONT_ASCENT", nbuf);
+          sprintf(nbuf, ACMSG1, p->font->bbx.ascent);
+          _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
+          p->font->modified = 1;
+      }
+      if (bdf_get_font_property(p->font, "FONT_DESCENT") == 0) {
+          p->font->font_descent = p->font->bbx.descent;
+          sprintf(nbuf, "%hd", p->font->bbx.descent);
+          _bdf_add_property(p->font, "FONT_DESCENT", nbuf);
+          sprintf(nbuf, ACMSG2, p->font->bbx.descent);
+          _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
+          p->font->modified = 1;
+      }
+      p->flags &= ~_BDF_PROPS;
+      *next = _bdf_parse_glyphs;
+      return 0;
+  }
+
+  /*
+   * Ignore the _XFREE86_GLYPH_RANGES properties.
+   */
+  if (ft_memcmp(line, "_XFREE86_GLYPH_RANGES", 21) == 0)
+    return 0;
+
+  /*
+   * Handle COMMENT fields and properties in a special way to preserve
+   * the spacing.
+   */
+  if (ft_memcmp(line, "COMMENT", 7) == 0) {
+      name = value = line;
+      value += 7;
+      if (*value)
+        *value++ = 0;
+      _bdf_add_property(p->font, name, value);
+  } else if (_bdf_is_atom(line, linelen, &name, &value, p->font))
+    _bdf_add_property(p->font, name, value);
+  else {
+      _bdf_split(" +", line, linelen, &p->list, memory);
+      name = p->list.field[0];
+      _bdf_shift(1, &p->list);
+      value = _bdf_join(' ', &vlen, &p->list);
+      _bdf_add_property(p->font, name, value);
+  }
+
+  return 0;
+}
+
+/*
+ * Load the font header.
+ */
+static int
+_bdf_parse_start(char *line, unsigned long linelen, unsigned long lineno,
+                 void *call_data, void *client_data)
+{
+    unsigned long slen;
+    _bdf_line_func_t *next;
+    _bdf_parse_t *p;
+    bdf_font_t *font;
+    char *s, nbuf[128];
+    /*    int test; */
+    FT_Memory memory;
+    FT_Error error;
+
+    next = (_bdf_line_func_t *) call_data;
+    p = (_bdf_parse_t *) client_data;
+    if (p->font)
+      memory = p->font->memory;
+
+    /*
+     * Check for a comment.  This is done to handle those fonts that have
+     * comments before the STARTFONT line for some reason.
+     */
+    if (ft_memcmp(line, "COMMENT", 7) == 0) {
+        if (p->opts->keep_comments != 0 && p->font != 0) {
+            linelen -= 7;
+            s = line + 7;
+            if (*s != 0) {
+                s++;
+                linelen--;
+            }
+            _bdf_add_comment(p->font, s, linelen);
+	    /* here font is not defined ! */
+        }
+        return 0;
+    }
+
+    if (!(p->flags & _BDF_START)) {
+
+        memory = p->memory;
+
+        if (ft_memcmp(line, "STARTFONT", 9) != 0)
+          /*
+           * No STARTFONT field is a good indication of a problem.
+           */
+          return BDF_MISSING_START;
+        p->flags = _BDF_START;
+        font = p->font = 0;
+
+	if ( FT_ALLOC ( font, sizeof(bdf_font_t) ) )
+	  return BDF_OUT_OF_MEMORY;
+	p->font = font;
+
+	font->memory = p->memory;
+	p->memory = 0;
+
+	/*	if (font == 0) {
+          fprintf(stderr,"failed font\n");
+	  }*/ /* XXX */
+
+	{ /* setup */
+	  unsigned long i;
+	  bdf_property_t *prop;
+
+	  hash_init(&(font->proptbl), memory);
+	  for (i = 0, prop = _bdf_properties;
+		 i < _num_bdf_properties; i++, prop++)
+	    hash_insert(prop->name, (void *) i, &(font->proptbl) , memory);
+	}
+
+	if ( FT_ALLOC ( p->font->internal , sizeof(hashtable) ) )
+	  return BDF_OUT_OF_MEMORY;
+	hash_init((hashtable *) p->font->internal,memory);
+	p->font->spacing = p->opts->font_spacing;
+        p->font->default_glyph = -1;
+	return 0;
+    }
+
+    /*
+     * Check for the start of the properties.
+     */
+    if (ft_memcmp(line, "STARTPROPERTIES", 15) == 0) {
+        _bdf_split(" +", line, linelen, &p->list, memory);
+        p->cnt = p->font->props_size = _bdf_atoul(p->list.field[1], 0, 10);
+
+	if ( FT_ALLOC ( p->font->props , (sizeof(bdf_property_t) * p->cnt) ) )
+	  return BDF_OUT_OF_MEMORY;
+        p->flags |= _BDF_PROPS;
+        *next = _bdf_parse_properties;
+        return 0;
+    }
+
+    /*
+     * Check for the FONTBOUNDINGBOX field.
+     */
+    if (ft_memcmp(line, "FONTBOUNDINGBOX", 15) == 0) {
+        if (!(p->flags & _BDF_SIZE)) {
+            /*
+             * Missing the SIZE field.
+             */
+            sprintf(nbuf, ERRMSG1, lineno, "SIZE");
+            _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
+            return BDF_MISSING_SIZE;
+        }
+        _bdf_split(" +", line, linelen, &p->list , memory);
+        p->font->bbx.width = _bdf_atos(p->list.field[1], 0, 10);
+        p->font->bbx.height = _bdf_atos(p->list.field[2], 0, 10);
+        p->font->bbx.x_offset = _bdf_atos(p->list.field[3], 0, 10);
+        p->font->bbx.y_offset = _bdf_atos(p->list.field[4], 0, 10);
+        p->font->bbx.ascent = p->font->bbx.height + p->font->bbx.y_offset;
+        p->font->bbx.descent = -p->font->bbx.y_offset;
+        p->flags |= _BDF_FONT_BBX;
+        return 0;
+    }
+
+    /*
+     * The next thing to check for is the FONT field.
+     */
+    if (ft_memcmp(line, "FONT", 4) == 0) {
+        _bdf_split(" +", line, linelen, &p->list , memory);
+        _bdf_shift(1, &p->list);
+        s = _bdf_join(' ', &slen, &p->list);
+	if ( FT_ALLOC ( p->font->name , slen + 1 ) )
+	  return BDF_OUT_OF_MEMORY;
+        (void) ft_memcpy(p->font->name, s, slen + 1);
+        /*
+         * If the font name is an XLFD name, set the spacing to the one in the
+         * font name.  If there is no spacing fall back on the default.
+         */
+        _bdf_set_default_spacing(p->font, p->opts);
+        p->flags |= _BDF_FONT_NAME;
+	return 0;
+    }
+
+    /*
+     * Check for the SIZE field.
+     */
+    if (ft_memcmp(line, "SIZE", 4) == 0) {
+        if (!(p->flags & _BDF_FONT_NAME)) {
+            /*
+             * Missing the FONT field.
+             */
+            sprintf(nbuf, ERRMSG1, lineno, "FONT");
+            _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
+            return BDF_MISSING_FONTNAME;
+        }
+        _bdf_split(" +", line, linelen, &p->list, memory);
+        p->font->point_size = _bdf_atoul(p->list.field[1], 0, 10);
+        p->font->resolution_x = _bdf_atoul(p->list.field[2], 0, 10);
+        p->font->resolution_y = _bdf_atoul(p->list.field[3], 0, 10);
+
+        /*
+         * Check for the bits per pixel field.
+         */
+        if (p->list.used == 5) {
+            p->font->bpp = _bdf_atos(p->list.field[4], 0, 10);
+            if (p->font->bpp > 1 && (p->font->bpp & 1)) {
+                /*
+                 * Move up to the next bits per pixel value if an odd number
+                 * is encountered.
+                 */
+                p->font->bpp++;
+                if (p->font->bpp <= 4) {
+                    sprintf(nbuf, ACMSG11, p->font->bpp);
+                    _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
+                }
+            }
+            if (p->font->bpp > 4) {
+                sprintf(nbuf, ACMSG11, p->font->bpp);
+                _bdf_add_acmsg(p->font, nbuf, ft_strlen(nbuf));
+                p->font->bpp = 4;
+            }
+        } else
+          p->font->bpp = 1;
+
+        p->flags |= _BDF_SIZE;
+        return 0;
+    }
+
+    return BDF_INVALID_LINE;
+}
+
+/**************************************************************************
+ *
+ * API.
+ *
+ **************************************************************************/
+
+
+FT_LOCAL_DEF( bdf_font_t* )
+bdf_load_font( FT_Stream       stream,
+               FT_Memory       extmemory,
+               bdf_options_t*  opts,
+               bdf_callback_t  callback,
+               void*           data)
+{
+    int n;
+    unsigned long lineno;
+    char msgbuf[128];
+    _bdf_parse_t p;
+    FT_Memory memory;
+    FT_Error error;
+
+    (void) ft_memset((char *) &p, 0, sizeof(_bdf_parse_t));
+    p.opts = (opts != 0) ? opts : &_bdf_opts;
+    p.minlb = 32767;
+    p.callback = callback;
+    p.client_data = data;
+
+    p.memory = extmemory;  /* only during font creation */
+
+    n = _bdf_readstream(stream, _bdf_parse_start, (void *) &p, &lineno);
+
+    if (p.font != 0) {
+        /*
+         * If the font is not proportional, set the fonts monowidth
+         * field to the width of the font bounding box.
+         */
+      memory = p.font->memory;
+
+        if (p.font->spacing != BDF_PROPORTIONAL)
+          p.font->monowidth = p.font->bbx.width;
+
+        /*
+         * If the number of glyphs loaded is not that of the original count,
+         * indicate the difference.
+         */
+        if (p.cnt != p.font->glyphs_used + p.font->unencoded_used) {
+            sprintf(msgbuf, ACMSG15, p.cnt,
+                    p.font->glyphs_used + p.font->unencoded_used);
+            _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
+            p.font->modified = 1;
+        }
+
+        /*
+         * Once the font has been loaded, adjust the overall font metrics if
+         * necessary.
+         */
+        if (p.opts->correct_metrics != 0 &&
+            (p.font->glyphs_used > 0 || p.font->unencoded_used > 0)) {
+            if (p.maxrb - p.minlb != p.font->bbx.width) {
+                sprintf(msgbuf, ACMSG3, p.font->bbx.width, p.maxrb - p.minlb);
+                _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
+                p.font->bbx.width = p.maxrb - p.minlb;
+                p.font->modified = 1;
+            }
+            if (p.font->bbx.x_offset != p.minlb) {
+                sprintf(msgbuf, ACMSG4, p.font->bbx.x_offset, p.minlb);
+                _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
+                p.font->bbx.x_offset = p.minlb;
+                p.font->modified = 1;
+            }
+            if (p.font->bbx.ascent != p.maxas) {
+                sprintf(msgbuf, ACMSG5, p.font->bbx.ascent, p.maxas);
+                _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
+                p.font->bbx.ascent = p.maxas;
+                p.font->modified = 1;
+            }
+            if (p.font->bbx.descent != p.maxds) {
+                sprintf(msgbuf, ACMSG6, p.font->bbx.descent, p.maxds);
+                _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
+                p.font->bbx.descent = p.maxds;
+                p.font->bbx.y_offset = -p.maxds;
+                p.font->modified = 1;
+            }
+            if (p.maxas + p.maxds != p.font->bbx.height) {
+                sprintf(msgbuf, ACMSG7, p.font->bbx.height, p.maxas + p.maxds);
+                _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
+            }
+            p.font->bbx.height = p.maxas + p.maxds;
+
+            if (p.flags & _BDF_SWIDTH_ADJ)
+              _bdf_add_acmsg(p.font, ACMSG8, ft_strlen(ACMSG8));
+        }
+    }
+
+    /*
+     * Last, if an error happened during loading, handle the messages.
+     */
+    if (n < 0 && callback != 0) {
+        /*
+         * An error was returned.  Alert the client.
+         */
+        p.cb.reason = BDF_ERROR;
+        p.cb.errlineno = lineno;
+        (*callback)(&p.cb, data);
+    } else if (p.flags & _BDF_START) {
+        if (p.font != 0) {
+            /*
+             * The ENDFONT field was never reached or did not exist.
+             */
+            if (!(p.flags & _BDF_GLYPHS))
+              /*
+               * Error happened while parsing header.
+               */
+              sprintf(msgbuf, ERRMSG2, lineno);
+            else
+              /*
+               * Error happened when parsing glyphs.
+               */
+              sprintf(msgbuf, ERRMSG3, lineno);
+
+            _bdf_add_acmsg(p.font, msgbuf, ft_strlen(msgbuf));
+        }
+
+        if (callback != 0) {
+            p.cb.reason = BDF_ERROR;
+            p.cb.errlineno = lineno;
+            (*callback)(&p.cb, data);
+        }
+    } else if (callback != 0) {
+        /*
+         * This forces the progress bar to always finish.
+         */
+        p.cb.current = p.cb.total;
+        (*p.callback)(&p.cb, p.client_data);
+    }
+
+    /*
+     * Free up the list used during the parsing.
+     */
+    if (p.list.size > 0)
+      FT_FREE( p.list.field );
+
+    if (p.font != 0) {
+        /*
+         * Make sure the comments are NULL terminated if they exist.
+         */
+        memory = p.font->memory;
+
+        if (p.font->comments_len > 0) {
+	  if ( FT_REALLOC ( p.font->comments , p.font->comments_len ,
+			 p.font->comments_len + 1 ) )
+	    return 0;
+            p.font->comments[p.font->comments_len] = 0;
+        }
+
+        /*
+         * Make sure the auto-correct messages are NULL terminated if they
+         * exist.
+         */
+        if (p.font->acmsgs_len > 0) {
+	  memory = p.font->memory;
+
+	  if ( FT_REALLOC ( p.font->acmsgs , p.font->acmsgs_len ,
+			 p.font->acmsgs_len + 1 ) )
+	    return 0;
+            p.font->acmsgs[p.font->acmsgs_len] = 0;
+        }
+    }
+
+    return p.font;
+}
+
+
+FT_LOCAL_DEF( void )
+bdf_free_font( bdf_font_t *font )
+{
+  bdf_property_t *prop;
+    unsigned long i;
+    bdf_glyph_t *glyphs;
+    FT_Memory memory;
+
+    if (font == 0)
+        return;
+
+    memory = font->memory;
+
+    if (font->name != 0)
+      FT_FREE(font->name);
+
+    /*
+     * Free up the internal hash table of property names.
+     */
+    if (font->internal) {
+      hash_free((hashtable *) font->internal, memory);
+      FT_FREE(font->internal);
+    }
+    /*
+     * Free up the comment info.
+     */
+    if (font->comments_len > 0)
+      FT_FREE(font->comments);
+
+    /*
+     * Free up the auto-correction messages.
+     */
+    if (font->acmsgs_len > 0)
+      FT_FREE(font->acmsgs);
+
+    /*
+     * Free up the properties.
+     */
+    for (i = 0; i < font->props_size; i++) {
+        if (font->props[i].format == BDF_ATOM && font->props[i].value.atom)
+          FT_FREE(font->props[i].value.atom);
+    }
+
+    if (font->props_size > 0 && font->props != 0)
+      FT_FREE(font->props);
+
+    /*
+     * Free up the character info.
+     */
+    for (i = 0, glyphs = font->glyphs; i < font->glyphs_used; i++, glyphs++) {
+        if (glyphs->name)
+          FT_FREE(glyphs->name);
+        if (glyphs->bytes > 0 && glyphs->bitmap != 0)
+          FT_FREE(glyphs->bitmap);
+    }
+
+    for (i = 0, glyphs = font->unencoded; i < font->unencoded_used;
+         i++, glyphs++) {
+        if (glyphs->name)
+          FT_FREE(glyphs->name);
+        if (glyphs->bytes > 0)
+          FT_FREE(glyphs->bitmap);
+    }
+
+    if (font->glyphs_size > 0)
+      FT_FREE( font->glyphs);
+
+    if (font->unencoded_size > 0)
+      FT_FREE( font->unencoded);
+
+    /*
+     * Free up the overflow storage if it was used.
+     */
+    for (i = 0, glyphs = font->overflow.glyphs; i < font->overflow.glyphs_used;
+         i++, glyphs++) {
+      if (glyphs->name != 0)
+	FT_FREE(glyphs->name);
+      if (glyphs->bytes > 0)
+	FT_FREE( glyphs->bitmap);;
+    }
+    if (font->overflow.glyphs_size > 0)
+      FT_FREE(font->overflow.glyphs);
+
+    /* bdf_cleanup */
+    hash_free(&(font->proptbl),memory);
+
+    /*
+     * Free up the user defined properties.
+     */
+    for (prop = font->user_props, i = 0; i < font->nuser_props; i++, prop++) {
+      FT_FREE(prop->name);
+      if (prop->format == BDF_ATOM && prop->value.atom != 0)
+	FT_FREE(prop->value.atom);
+    }
+    if (font->nuser_props > 0)
+      FT_FREE(font->user_props);
+
+    /*FREE( font);*/ /* XXX Fixme */
+}
+
+
+
+FT_LOCAL_DEF( bdf_property_t* )
+bdf_get_font_property( bdf_font_t*  font,
+                       char*        name)
+{
+    hashnode hn;
+
+    if (font == 0 || font->props_size == 0 || name == 0 || *name == 0)
+      return 0;
+
+    hn = hash_lookup(name, (hashtable *) font->internal);
+    return (hn) ? (font->props + ((unsigned long) hn->data)) : 0;
+}
--- /dev/null
+++ b/src/bdf/module.mk
@@ -1,0 +1,31 @@
+#
+# FreeType 2 BDF module definition
+#
+
+# Copyright 2001 by
+# Francesco Zappa Nardelli
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+make_module_list: add_bdf_driver
+
+add_bdf_driver:
+	$(OPEN_DRIVER)bdf_driver_class$(CLOSE_DRIVER)
+	$(ECHO_DRIVER)bdf    $(ECHO_DRIVER_DESC)bdf bitmap fonts$(ECHO_DRIVER_DONE)
+
--- /dev/null
+++ b/src/bdf/rules.mk
@@ -1,0 +1,80 @@
+#
+# FreeType 2 bdf driver configuration rules
+#
+
+
+# Copyright (C) 2001 by
+# Francesco Zappa Nardelli
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+
+
+
+# bdf driver directory
+#
+BDF_DIR  := $(SRC_)bdf
+BDF_DIR_ := $(BDF_DIR)$(SEP)
+
+
+BDF_COMPILE := $(FT_COMPILE) $I$(BDF_DIR)
+
+
+# bdf driver sources (i.e., C files)
+#
+BDF_DRV_SRC := $(BDF_DIR_)bdflib.c $(BDF_DIR_)bdfdriver.c
+
+
+# bdf driver headers
+#
+#BDF_DRV_H := $(BDF_DRV_SRC:%.c=%.h)
+BDF_DRV_H := $(BDF_DIR_)bdf.h \
+             $(BDF_DIR_)bdfdriver.h
+
+# bdf driver object(s)
+#
+#   BDF_DRV_OBJ_M is used during `multi' builds
+#   BDF_DRV_OBJ_S is used during `single' builds
+#
+BDF_DRV_OBJ_M := $(BDF_DRV_SRC:$(BDF_DIR_)%.c=$(OBJ_)%.$O)
+BDF_DRV_OBJ_S := $(OBJ_)bdf.$O
+
+# bdf driver source file for single build
+#
+BDF_DRV_SRC_S := $(BDF_DIR_)bdf.c
+
+
+# bdf driver - single object
+#
+$(BDF_DRV_OBJ_S): $(BDF_DRV_SRC_S) $(BDF_DRV_SRC) $(FREETYPE_H) $(BDF_DRV_H)
+	$(BDF_COMPILE) $T$@ $(BDF_DRV_SRC_S)
+
+
+# bdf driver - multiple objects
+#
+$(OBJ_)%.$O: $(BDF_DIR_)%.c $(FREETYPE_H) $(BDF_DRV_H)
+	$(BDF_COMPILE) $T$@ $<
+
+
+# update main driver object lists
+#
+DRV_OBJS_S += $(BDF_DRV_OBJ_S)
+DRV_OBJS_M += $(BDF_DRV_OBJ_M)
+
+# EOF