]> git.wh0rd.org Git - fontconfig.git/commitdiff
Initial revision
authorKeith Packard <keithp@keithp.com>
Thu, 14 Feb 2002 23:34:13 +0000 (23:34 +0000)
committerKeith Packard <keithp@keithp.com>
Thu, 14 Feb 2002 23:34:13 +0000 (23:34 +0000)
46 files changed:
AUTHORS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Imakefile [new file with mode: 0644]
NEWS [new file with mode: 0644]
README [new file with mode: 0644]
acconfig.h [new file with mode: 0644]
configure.in [new file with mode: 0644]
cvscompile.sh [new file with mode: 0644]
doc/fontconfig.tex [new file with mode: 0644]
fc-cache/Imakefile [new file with mode: 0644]
fc-cache/fc-cache.c [new file with mode: 0644]
fc-cache/fc-cache.man [new file with mode: 0644]
fc-list/Imakefile [new file with mode: 0644]
fc-list/fc-list.c [new file with mode: 0644]
fc-list/fc-list.man [new file with mode: 0644]
findfonts [new file with mode: 0755]
fontconfig/Imakefile [new file with mode: 0644]
fontconfig/fcfreetype.h [new file with mode: 0644]
fontconfig/fcprivate.h [new file with mode: 0644]
fontconfig/fcxml.h [new file with mode: 0644]
fontconfig/fontconfig.h [new file with mode: 0644]
fonts.conf.in [new file with mode: 0644]
fonts.dtd [new file with mode: 0644]
setfontdirs [new file with mode: 0755]
src/Imakefile [new file with mode: 0644]
src/fcblanks.c [new file with mode: 0644]
src/fccache.c [new file with mode: 0644]
src/fccfg.c [new file with mode: 0644]
src/fccharset.c [new file with mode: 0644]
src/fcdbg.c [new file with mode: 0644]
src/fcdefault.c [new file with mode: 0644]
src/fcdir.c [new file with mode: 0644]
src/fcfreetype.c [new file with mode: 0644]
src/fcfs.c [new file with mode: 0644]
src/fcinit.c [new file with mode: 0644]
src/fcint.h [new file with mode: 0644]
src/fclist.c [new file with mode: 0644]
src/fcmatch.c [new file with mode: 0644]
src/fcmatrix.c [new file with mode: 0644]
src/fcname.c [new file with mode: 0644]
src/fcpat.c [new file with mode: 0644]
src/fcstr.c [new file with mode: 0644]
src/fcxml.c [new file with mode: 0644]
src/fontconfig.man [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
new file mode 100644 (file)
index 0000000..9cee037
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Keith Packard <keithp@keithp.com>
diff --git a/COPYING b/COPYING
new file mode 100644 (file)
index 0000000..6a4d888
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,22 @@
+$XFree86: $
+
+Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of Keith Packard not be used in
+advertising or publicity pertaining to distribution of the software without
+specific, written prior permission.  Keith Packard makes no
+representations about the suitability of this software for any purpose.  It
+is provided "as is" without express or implied warranty.
+
+KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
diff --git a/ChangeLog b/ChangeLog
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..6798b36
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,3 @@
+The configuration files (fonts.conf, fonts.dtd) go in a new directory
+/etc/fonts, the install step doesn't current create this directory or copy
+the config files.
diff --git a/Imakefile b/Imakefile
new file mode 100644 (file)
index 0000000..3c26d2d
--- /dev/null
+++ b/Imakefile
@@ -0,0 +1,25 @@
+#define IHaveSubdirs
+#define PassCDebugFlags
+
+LINTSUBDIRS=src fc-cache fc-list
+
+SUBDIRS=fontconfig $(LINTSUBDIRS)
+
+#ifndef FontconfigDir
+#define FontconfigDir /etc/fonts
+#endif
+
+FONTCONFIGDIR=FontconfigDir
+
+MakeSubdirs($(SUBDIRS))
+DependSubdirs($(SUBDIRS))
+MakeLintLibSubdirs($(LINTSUBDIRS))
+MakeLintSubdirs($(LINTSUBDIRS),install.ln,install.ln)
+
+InstallNonExecFileNoClobber(fonts.conf,$(FONTCONFIGDIR))
+InstallNonExecFileNoClobber(fonts.dtd,$(FONTCONFIGDIR))
+
+all:: fonts.conf
+
+fonts.conf: fonts.conf.in
+       sh ./setfontdirs
diff --git a/NEWS b/NEWS
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..98f0fca
--- /dev/null
+++ b/README
@@ -0,0 +1,2 @@
+                       Fontconfig
+       Font configuration and customization library
diff --git a/acconfig.h b/acconfig.h
new file mode 100644 (file)
index 0000000..8ed6317
--- /dev/null
@@ -0,0 +1,2 @@
+#undef HAVE_FREETYPE 
+#undef FC_FALLBACK_FONTS
diff --git a/configure.in b/configure.in
new file mode 100644 (file)
index 0000000..0cfcba0
--- /dev/null
@@ -0,0 +1,202 @@
+AC_INIT(fontconfig/fontconfig.h)
+
+AC_PREREQ(2.13)
+
+FC_MAJOR=1
+FC_MINOR=0
+FC_SUB=1
+FC_PRE=
+FC_IFACE_AGE=0
+FC_BIN_AGE=0
+
+AC_SUBST(FC_MAJOR)
+AC_SUBST(FC_MINOR)
+AC_SUBST(FC_SUB)
+AC_SUBST(FC_IFACE_AGE)
+AC_SUBST(FC_BIN_AGE)
+
+LT_RELEASE=$FC_MAJOR.$FC_MINOR
+LT_CURRENT=`expr $FC_SUB - $FC_IFACE_AGE`
+LT_REVISION=$FC_IFACE_AGE
+LT_AGE=`expr $FC_BIN_AGE - $FC_IFACE_AGE`
+AC_SUBST(LT_RELEASE)
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+
+AM_INIT_AUTOMAKE("fontconfig", $FC_MAJOR.$FC_MINOR.$FC_SUB$FC_PRE)
+
+AC_CANONICAL_HOST
+AM_CONFIG_HEADER(config.h)
+
+AC_ARG_WITH(freetype_includes, [  --with-freetype-includes=DIR  Use FreeType includes in DIR], freetype_includes=$withval, freetype_includes=yes)
+AC_ARG_WITH(freetype_lib,      [  --with-freetype-lib=DIR       Use FreeType library in DIR], freetype_lib=$withval, freetype_lib=yes)
+AC_ARG_WITH(freetype_config,   [  --with-freeetype-config=PROG  Use FreeType configuration program PROG], freetype_config=$withval, freetype_config=yes)
+AC_ARG_WITH(xml2_includes,     [  --with-xml2-includes=DIR      Use xml2 includes in DIR], xml2_includes=$withval, xml2_includes=yes)
+AC_ARG_WITH(xml2_lib,          [  --with-xml2-lib=DIR           Use xml2 library in DIR], xml2_lib=$withval, xml2_lib=yes)
+AC_ARG_WITH(xml2_config,       [  --with-freeetype-config=PROG  Use FreeType configuration program PROG], xml2_config=$withval, xml2_config=yes)
+AC_ARG_WITH(fallback_fonts,    [  --with-fallback-fonts=DIR     Use fonts from DIR when config is busted], fallback_fonts="$withval", fallback_fonts=yes)
+AC_ISC_POSIX
+AC_PROG_CC
+AC_STDC_HEADERS
+AC_PROG_MAKE_SET
+AC_PROG_INSTALL
+
+AC_PROG_LN_S
+
+dnl
+dnl Libtool
+dnl
+AM_DISABLE_STATIC
+AM_PROG_LIBTOOL
+AC_SUBST(LIBTOOL_DEPS)
+if libtool --features | grep "enable static" >/dev/null; then
+  STATIC="-static"
+else
+  STATIC=
+fi
+AC_SUBST(STATIC)
+
+AC_SUBST(DEBUG_CFLAGS)
+AC_SUBST(GLOBAL_CFLAGS)
+
+AC_CHECK_FUNCS(getopt_long getopt)
+
+case "$freetype_config" in
+no)
+       ;;
+yes)
+       AC_CHECK_PROG(ft_config, freetype-config, freetype-config, no)
+       ;;
+*)
+       ft_config="$freetype_config"
+       ;;
+esac
+
+case "$freetype_includes" in
+no)
+       freetype_includes=""
+       ;;
+yes)
+       case "$ft_config" in
+       no)
+               freetype_includes=""
+               ;;
+       *)
+               freetype_includes="`$ft_config --cflags`"
+               ;;
+       esac
+       ;;
+*)
+       freetype_includes="-I$freetype_includes"
+       ;;
+esac
+
+case "$freetype_lib" in
+no)
+       freetype_lib=""
+       ;;
+yes)
+       case "$ft_config" in
+       no)
+               freetype_lib=""
+               ;;
+       *)
+               freetype_lib="`$ft_config --libs`"
+               ;;
+       esac
+       ;;
+*)
+       freetype_lib="-L$freetype_lib -lfreetype"
+       ;;
+esac
+
+case "$fallback_fonts" in
+yes)
+       AC_DEFINE_UNQUOTED(FC_FALLBACK_FONTS, "/usr/X11R6/lib/X11/fonts/Type1")
+       ;;
+*)
+       AC_DEFINE_UNQUOTED(FC_FALLBACK_FONTS, "$fallback_fonts")
+       ;;
+esac
+
+saved_LIBS="$LIBS"
+LIBS="$LIBS $freetype_lib"
+saved_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $freetype_includes"
+AC_CHECK_HEADERS(ft2build.h)
+
+case "$ac_cv_header_ft2build_h" in
+no)
+       CPPFLAGS="$saved_CPPFLAGS"
+       LIBS="$saved_LIBS"
+       ;;
+yes)
+       AC_CHECK_FUNCS(FT_Init_FreeType)
+       case "$ac_cv_func_FT_Init_FreeType" in
+       no)
+               CPPFLAGS="$saved_CPPFLAGS"
+               LIBS="$saved_LIBS"
+               ;;
+       yes)
+               AC_DEFINE(HAVE_FREETYPE)
+               ;;
+       esac
+       ;;
+esac
+
+case "$xml2_config" in
+no)
+       ;;
+yes)
+       AC_CHECK_PROG(xml2_config_prog, xml2-config, xml2-config, no)
+       ;;
+*)
+       ;;
+esac
+
+case "$xml2_includes" in
+no)
+       xml2_includes=""
+       ;;
+yes)
+       case "$xml2_config_prog" in
+       no)
+               xml2_includes=""
+               ;;
+       *)
+               xml2_includes="`$xml2_config_prog --cflags`"
+               ;;
+       esac
+       ;;
+*)
+       xml2_includes="-I$xml2_includes"
+       ;;
+esac
+
+case "$xml2_lib" in
+no)
+       xml2_lib=""
+       ;;
+yes)
+       case "$xml2_config_prog" in
+       no)
+               xml2_lib=""
+               ;;
+       *)
+               xml2_lib="`$xml2_config_prog --libs`"
+               ;;
+       esac
+       ;;
+*)
+       xml2_lib="-L$xml2_lib -lxml2"
+       ;;
+esac
+
+saved_LIBS="$LIBS"
+LIBS="$LIBS $xml2_lib"
+saved_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="$CPPFLAGS $xml2_includes"
+AC_CHECK_HEADERS(xmlversion.h)
+
+AC_OUTPUT(Makefile src/Makefile fontconfig/Makefile fc-cache/Makefile fc-list/Makefile)
diff --git a/cvscompile.sh b/cvscompile.sh
new file mode 100644 (file)
index 0000000..371f458
--- /dev/null
@@ -0,0 +1,6 @@
+#!/bin/sh
+aclocal
+autoheader
+automake -a
+autoconf
+
diff --git a/doc/fontconfig.tex b/doc/fontconfig.tex
new file mode 100644 (file)
index 0000000..2e60a51
--- /dev/null
@@ -0,0 +1,55 @@
+\documentclass[10pt]{article}
+\usepackage{latexsym}
+\usepackage{epsfig}
+\usepackage{times}
+
+\begin{document}
+\date{}
+\title{The Fontconfig Library:\\
+Architecture and Users Guide}
+\author{Keith Packard\\
+{\em XFree86 Core Team}\\
+keithp@keithp.com}
+\maketitle
+\thispagestyle{empty}
+
+\abstract
+
+The Fontconfig library provides for central administration and configuration
+of fonts in a POSIX system.  All font consumers can share a common database
+of fonts and use common matching rules for font names.  The set of available
+fonts can be configured for each user and a set of configurable matching
+rules allow for customizing the selection of fonts and configuring various
+parameters related to rasterizing of those fonts for display in a variety of
+media.  The Fontconfig library is designed to co-exist peacefully with
+existing font configuration and rasterization mechanisms; while it uses the
+FreeType library to discover characteristics of available fonts, there
+is no requirement to use FreeType for rasterization.
+
+\section                               {Introduction}
+
+\section                               {Configuration Files}
+
+\section                               {Application Interface}
+
+\subsection                            {Datatypes}
+
+\subsection                            {Font Set Interface}
+
+\subsection                            {Font Patterns}
+
+\subsection                            {Listing Available Fonts}
+
+\subsection                            {Using Font Names}
+
+\subsection                            {Manipulating Matrices}
+
+\subsection                            {UTF-8 Helper Functions}
+
+\section                               {Font Sub-System Interface}
+
+\subsection                            {Extending Font Names}
+
+\subsection                            {Executing Configuration Rules}
+
+\end{document}
diff --git a/fc-cache/Imakefile b/fc-cache/Imakefile
new file mode 100644 (file)
index 0000000..12216e7
--- /dev/null
@@ -0,0 +1,19 @@
+#include "../../libxml2/config.h"
+#if HAVE_ZLIB_H
+ZLIB=-lz
+#endif
+
+INCLUDES=-I../../freetype2 -I/usr/include/libxml2 -I..
+FREETYPE2REQLIB = ../../freetype2/libfreetype.a
+XML2REQLIB=../../libxml2/.libs/libxml2.a $(ZLIB) -lm
+
+LOCAL_LIBRARIES=-L../src -lfontconfig $(FREETYPE2REQLIB) $(XML2REQLIB)
+
+SRCS=fc-cache.c
+OBJS=fc-cache.o
+
+ComplexProgramTarget(fc-cache)
+LinkBuildBinary(ProgramTargetName(fc-cache))
+
+install::
+       FC_DEBUG=128 FONTCONFIG_PATH=.. ./fc-cache -v
diff --git a/fc-cache/fc-cache.c b/fc-cache/fc-cache.c
new file mode 100644 (file)
index 0000000..6e84ccd
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <fontconfig/fontconfig.h>
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#define HAVE_GETOPT 1
+#endif
+
+#if HAVE_GETOPT_LONG
+#define _GNU_SOURCE
+#include <getopt.h>
+const struct option longopts[] = {
+    {"version", 0, 0, 'V'},
+    {"verbose", 0, 0, 'v'},
+    {"help", 0, 0, '?'},
+    {NULL,0,0,0},
+};
+#else
+#if HAVE_GETOPT
+extern char *optarg;
+extern int optind, opterr, optopt;
+#endif
+#endif
+
+void usage (char *program)
+{
+    fprintf (stderr, "usage: %s [-vV?] [--verbose] [--version] [--help] [dirs]\n",
+            program);
+    fprintf (stderr, "Build font information caches in [dirs]\n"
+            "(all directories in font configuration by default).\n");
+    fprintf (stderr, "\n");
+    fprintf (stderr, "  -v, --verbose        display status information while busy\n");
+    fprintf (stderr, "  -V, --version        display font config version and exit\n");
+    fprintf (stderr, "  -?, --help           display this help and exit\n");
+    exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+    int                ret = 0;
+    FcFontSet  *set;
+    char       **dirs;
+    int                verbose = 0;
+    int                i;
+#if HAVE_GETOPT_LONG || HAVE_GETOPT
+    int                c;
+
+#if HAVE_GETOPT_LONG
+    while ((c = getopt_long (argc, argv, "Vv?", longopts, NULL)) != -1)
+#else
+    while ((c = getopt (argc, argv, "Vv?")) != -1)
+#endif
+    {
+       switch (c) {
+       case 'V':
+           fprintf (stderr, "fontconfig version %d.%d.%d\n", 
+                    FC_MAJOR, FC_MINOR, FC_REVISION);
+           exit (0);
+       case 'v':
+           verbose = 1;
+           break;
+       default:
+           usage (argv[0]);
+       }
+    }
+    i = optind;
+#else
+    i = 1;
+#endif
+
+    if (!FcInitConfig ())
+    {
+       fprintf (stderr, "Can't init font config library\n");
+       return 1;
+    }
+    if (argv[i])
+       dirs = argv+i;
+    else
+       dirs = FcConfigGetDirs (0);
+    /*
+     * Now scan all of the directories into separate databases
+     * and write out the results
+     */
+    while (dirs && *dirs)
+    {
+       if (verbose)
+           printf ("%s: Scanning directory \"%s\"\n", argv[0], *dirs);
+       set = FcFontSetCreate ();
+       if (!set)
+       {
+           fprintf (stderr, "Out of memory in \"%s\"\n", *dirs);
+           ret++;
+       }
+       else
+       {
+           if (!FcDirScan (set, 0, FcConfigGetBlanks (0), *dirs, FcTrue))
+           {
+               fprintf (stderr, "Can't scan directory \"%s\"\n", *dirs);
+               ret++;
+           }
+           else
+           {
+               if (verbose)
+                   printf ("%s: Saving %d font names for \"%s\"\n", 
+                           argv[0], set->nfont, *dirs);
+               if (!FcDirSave (set, *dirs))
+               {
+                   fprintf (stderr, "Can't save cache in \"%s\"\n", *dirs);
+                   ret++;
+               }
+           }
+           FcFontSetDestroy (set);
+       }
+       ++dirs;
+    }
+    if (verbose)
+       printf ("%s: %s\n", argv[0], ret ? "failed" : "succeeded");
+    return ret;
+}
diff --git a/fc-cache/fc-cache.man b/fc-cache/fc-cache.man
new file mode 100644 (file)
index 0000000..6fc4ed9
--- /dev/null
@@ -0,0 +1,45 @@
+.\"
+.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of Keith Packard not be used in
+.\" advertising or publicity pertaining to distribution of the software without
+.\" specific, written prior permission.  Keith Packard makes no
+.\" representations about the suitability of this software for any purpose.  It
+.\" is provided "as is" without express or implied warranty.
+.\"
+.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+.\" CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+.\" DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+.\" PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\"
+.\" $XFree86: xc/programs/fc-cache/fc-cache.man,v 1.3 2001/02/09 03:47:56 tsi Exp $
+.\"
+.TH FC-CACHE 1 __vendorversion__
+.SH NAME
+fc-cache, fonts.cache \- create an index of FreeType font files in a directory
+.SH SYNOPSIS
+.B "fc-cache"
+.RI [ directory-name
+\|.\|.\|. ]
+.SH DESCRIPTION
+If directory arguments are not given,
+.I fc-cache
+uses each directory in the current font configuration.  Each directory is
+scanned for font files readable by FreeType.  A cache is created which
+contains properties of each font and the associated filename.  This cache is
+used to speed application startup when using the fontconfig library.
+.SH FILES
+.TP 15
+.B fonts.cache
+Maps file names to font properties.  Read by the fontconfig library at
+application startup to locate appropriate fonts.
+.SH "SEE ALSO"
+fontconfig(3)
diff --git a/fc-list/Imakefile b/fc-list/Imakefile
new file mode 100644 (file)
index 0000000..a773b45
--- /dev/null
@@ -0,0 +1,17 @@
+#include "../../libxml2/config.h"
+#if HAVE_ZLIB_H
+ZLIB=-lz
+#endif
+
+INCLUDES=-I../../freetype2 -I/usr/include/libxml2 -I..
+FREETYPE2REQLIB = ../../freetype2/libfreetype.a
+XML2REQLIB=../../libxml2/.libs/libxml2.a $(ZLIB) -lm
+
+LOCAL_LIBRARIES=-L../src -lfontconfig $(FREETYPE2REQLIB) $(XML2REQLIB)
+DEPLIBS=../src/libfontconfig.a
+
+SRCS=fc-list.c
+OBJS=fc-list.o
+
+ComplexProgramTarget(fc-list)
+LinkBuildBinary(ProgramTargetName(fc-list))
diff --git a/fc-list/fc-list.c b/fc-list/fc-list.c
new file mode 100644 (file)
index 0000000..67d7120
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <fontconfig/fontconfig.h>
+#include <stdio.h>
+#include <unistd.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#else
+#define HAVE_GETOPT 1
+#endif
+
+#if HAVE_GETOPT_LONG
+#define _GNU_SOURCE
+#include <getopt.h>
+const struct option longopts[] = {
+    {"version", 0, 0, 'V'},
+    {"verbose", 0, 0, 'v'},
+    {"help", 0, 0, '?'},
+    {NULL,0,0,0},
+};
+#else
+#if HAVE_GETOPT
+extern char *optarg;
+extern int optind, opterr, optopt;
+#endif
+#endif
+
+void usage (char *program)
+{
+    fprintf (stderr, "usage: %s [-vV?] [--verbose] [--version] [--help] [dirs]\n",
+            program);
+    fprintf (stderr, "Build font information caches in [dirs]\n"
+            "(all directories in font configuration by default).\n");
+    fprintf (stderr, "\n");
+    fprintf (stderr, "  -v, --verbose        display status information while busy\n");
+    fprintf (stderr, "  -V, --version        display font config version and exit\n");
+    fprintf (stderr, "  -?, --help           display this help and exit\n");
+    exit (1);
+}
+
+int
+main (int argc, char **argv)
+{
+    int                ret = 0;
+    FcFontSet  *set;
+    int                verbose = 0;
+    int                i;
+    FcObjectSet *os = FcObjectSetBuild (FC_FAMILY, FC_LANG, 0);
+    FcFontSet  *fs;
+    FcPattern   *pat;
+#if HAVE_GETOPT_LONG || HAVE_GETOPT
+    int                c;
+
+#if HAVE_GETOPT_LONG
+    while ((c = getopt_long (argc, argv, "Vv?", longopts, NULL)) != -1)
+#else
+    while ((c = getopt (argc, argv, "Vv?")) != -1)
+#endif
+    {
+       switch (c) {
+       case 'V':
+           fprintf (stderr, "fontconfig version %d.%d.%d\n", 
+                    FC_MAJOR, FC_MINOR, FC_REVISION);
+           exit (0);
+       case 'v':
+           verbose = 1;
+           break;
+       default:
+           usage (argv[0]);
+       }
+    }
+    i = optind;
+#else
+    i = 1;
+#endif
+
+    if (!FcInit ())
+    {
+       fprintf (stderr, "Can't init font config library\n");
+       return 1;
+    }
+    if (argv[i])
+       pat = FcNameParse (argv[i]);
+    else
+       pat = FcPatternCreate ();
+    
+    fs = FcFontList (0, pat, os);
+    if (pat)
+       FcPatternDestroy (pat);
+
+    if (fs)
+    {
+       int     j;
+
+       for (j = 0; j < fs->nfont; j++)
+       {
+           FcChar8 *font;
+
+           font = FcNameUnparse (fs->fonts[j]);
+           printf ("%s\n", font);
+           free (font);
+       }
+       FcFontSetDestroy (fs);
+    }
+    return 0;
+}
diff --git a/fc-list/fc-list.man b/fc-list/fc-list.man
new file mode 100644 (file)
index 0000000..87eb792
--- /dev/null
@@ -0,0 +1,36 @@
+.\"
+.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of Keith Packard not be used in
+.\" advertising or publicity pertaining to distribution of the software without
+.\" specific, written prior permission.  Keith Packard makes no
+.\" representations about the suitability of this software for any purpose.  It
+.\" is provided "as is" without express or implied warranty.
+.\"
+.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+.\" CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+.\" DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+.\" PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\"
+.\" $XFree86: xc/programs/fc-list/fc-list.man,v 1.3 2001/02/09 03:47:56 tsi Exp $
+.\"
+.TH FC-LIST 1 __vendorversion__
+.SH NAME
+fc-list \- list available fonts
+.SH SYNOPSIS
+.B "fc-list"
+.RI [ font-pattern ]
+.SH DESCRIPTION
+If font pattern is not given,
+.I fc-list
+lists all available faces and styles in the current font configuration.
+.SH "SEE ALSO"
+fontconfig(3)
diff --git a/findfonts b/findfonts
new file mode 100755 (executable)
index 0000000..2666f8d
--- /dev/null
+++ b/findfonts
@@ -0,0 +1,8 @@
+#!/bin/sh
+dirs="/usr/share/fonts /usr/X11R6/lib/X11/fonts"
+for d in $dirs; do
+    find $d \( -name '*.[Tt][Tt][Ff]' -o -name '*.[Pp][Ff][BbAa]' \) -print
+done | while read f; do
+       dir=`dirname $f`
+       echo $dir
+done | sort -u | sed 's/^/     <dir>/' | sed 's;$;</dir>;'
diff --git a/fontconfig/Imakefile b/fontconfig/Imakefile
new file mode 100644 (file)
index 0000000..be1f65c
--- /dev/null
@@ -0,0 +1,8 @@
+#define IncSubdir fontconfig
+
+HEADERS=fcfreetype.h fcprivate.h fcxml.h fontconfig.h
+
+BuildIncludes($(HEADERS),IncSubdir,..)
+#if BuildLibraries
+InstallMultipleFlags($(HEADERS),$(INCDIR)/IncSubdir,$(INSTINCFLAGS))
+#endif
diff --git a/fontconfig/fcfreetype.h b/fontconfig/fcfreetype.h
new file mode 100644 (file)
index 0000000..14f342b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FCFREETYPE_H_
+#define _FCFREETYPE_H_
+
+FT_UInt
+FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4);
+
+FcCharSet *
+FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks);
+
+#endif
diff --git a/fontconfig/fcprivate.h b/fontconfig/fcprivate.h
new file mode 100644 (file)
index 0000000..490ca33
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FCPRIVATE_H_
+#define _FCPRIVATE_H_
+
+/*
+ * I tried this with functions that took va_list* arguments
+ * but portability concerns made me change these functions
+ * into macros (sigh).
+ */
+
+#define FcPatternVapBuild(result, orig, va)                        \
+{                                                                  \
+    FcPattern  *__p__ = (orig);                                    \
+    const char *__o__;                                             \
+    FcValue    __v__;                                              \
+                                                                   \
+    if (!__p__)                                                            \
+    {                                                              \
+       __p__ = FcPatternCreate ();                                 \
+       if (!__p__)                                                 \
+           goto _FcPatternVapBuild_bail0;                          \
+    }                                                              \
+    for (;;)                                                       \
+    {                                                              \
+       __o__ = va_arg (va, const char *);                          \
+       if (!__o__)                                                 \
+           break;                                                  \
+       __v__.type = va_arg (va, FcType);                           \
+       switch (__v__.type) {                                       \
+       case FcTypeVoid:                                            \
+           goto _FcPatternVapBuild_bail1;                          \
+       case FcTypeInteger:                                         \
+           __v__.u.i = va_arg (va, int);                           \
+           break;                                                  \
+       case FcTypeDouble:                                          \
+           __v__.u.d = va_arg (va, double);                        \
+           break;                                                  \
+       case FcTypeString:                                          \
+           __v__.u.s = va_arg (va, char *);                        \
+           break;                                                  \
+       case FcTypeBool:                                            \
+           __v__.u.b = va_arg (va, FcBool);                        \
+           break;                                                  \
+       case FcTypeMatrix:                                          \
+           __v__.u.m = va_arg (va, FcMatrix *);                    \
+           break;                                                  \
+       case FcTypeCharSet:                                         \
+           __v__.u.c = va_arg (va, FcCharSet *);                   \
+           break;                                                  \
+       }                                                           \
+       if (!FcPatternAdd (__p__, __o__, __v__, FcTrue))            \
+           goto _FcPatternVapBuild_bail1;                          \
+    }                                                              \
+    result = __p__;                                                \
+    goto _FcPatternVapBuild_return;                                \
+                                                                   \
+_FcPatternVapBuild_bail1:                                          \
+    if (!orig)                                                     \
+       FcPatternDestroy (__p__);                                   \
+_FcPatternVapBuild_bail0:                                          \
+    result = 0;                                                            \
+                                                                   \
+_FcPatternVapBuild_return:                                         \
+    ;                                                              \
+}
+
+
+#define FcObjectSetVapBuild(__ret__, __first__, __va__)                \
+{                                                                      \
+    FcObjectSet    *__os__;                                            \
+    const char     *__ob__;                                            \
+                                                                       \
+    __ret__ = 0;                                                       \
+    __os__ = FcObjectSetCreate ();                                     \
+    if (!__os__)                                                       \
+       goto _FcObjectSetVapBuild_bail0;                                \
+    __ob__ = __first__;                                                        \
+    while (__ob__)                                                     \
+    {                                                                  \
+       if (!FcObjectSetAdd (__os__, __ob__))                           \
+           goto _FcObjectSetVapBuild_bail1;                            \
+       __ob__ = va_arg (__va__, const char *);                         \
+    }                                                                  \
+    __ret__ = __os__;                                                  \
+                                                                       \
+_FcObjectSetVapBuild_bail1:                                            \
+    if (!__ret__ && __os__)                                            \
+       FcObjectSetDestroy (__os__);                                    \
+_FcObjectSetVapBuild_bail0:                                            \
+    ;                                                                  \
+}
+
+#endif /* _FCPRIVATE_H_ */
+
diff --git a/fontconfig/fcxml.h b/fontconfig/fcxml.h
new file mode 100644 (file)
index 0000000..b5d1b7d
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FCXML_H_
+#define _FCXML_H_
+
+#include <libxml/parser.h>
+
+xmlDocPtr
+FcConfigLoad (const char *file);
+
+FcBool
+FcConfigParse (FcConfig            *config,
+              xmlDocPtr    doc);
+
+#endif /* _FCXML_H_ */
diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h
new file mode 100644 (file)
index 0000000..c7105e0
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FONTCONFIG_H_
+#define _FONTCONFIG_H_
+
+#include <stdarg.h>
+
+typedef unsigned char  FcChar8;
+typedef unsigned short FcChar16;
+typedef unsigned int   FcChar32;
+typedef int            FcBool;
+
+/*
+ * Current Fontconfig version number
+ */
+#define FC_MAJOR       1
+#define FC_MINOR       0
+#define FC_REVISION    0
+
+#define FC_VERSION     ((FC_MAJOR * 10000) + (FC_MINOR * 100) + (FC_REVISION))
+
+#define FcTrue         1
+#define FcFalse                0
+
+#define FC_FAMILY          "family"            /* String */
+#define FC_STYLE           "style"             /* String */
+#define FC_SLANT           "slant"             /* Int */
+#define FC_WEIGHT          "weight"            /* Int */
+#define FC_SIZE                    "size"              /* Double */
+#define FC_PIXEL_SIZE      "pixelsize"         /* Double */
+#define FC_SPACING         "spacing"           /* Int */
+#define FC_FOUNDRY         "foundry"           /* String */
+#define FC_ANTIALIAS       "antialias"         /* Bool (depends) */
+#define FC_HINTING         "hinting"           /* Bool (true) */
+#define FC_VERTICAL_LAYOUT  "verticallayout"   /* Bool (false) */
+#define FC_AUTOHINT        "autohint"          /* Bool (false) */
+#define FC_GLOBAL_ADVANCE   "globaladvance"    /* Bool (true) */
+#define FC_FILE                    "file"              /* String */
+#define FC_INDEX           "index"             /* Int */
+#define FC_RASTERIZER      "rasterizer"        /* String */
+#define FC_OUTLINE         "outline"           /* Bool */
+#define FC_SCALABLE        "scalable"          /* Bool */
+#define FC_SCALE           "scale"             /* double */
+#define FC_DPI             "dpi"               /* double */
+#define FC_RGBA                    "rgba"              /* Int */
+#define FC_MINSPACE        "minspace"          /* Bool use minimum line spacing */
+#define FC_SOURCE          "source"            /* String (X11, freetype) */
+#define FC_CHARSET         "charset"           /* CharSet */
+#define FC_LANG                    "lang"              /* String OS/2 CodePageRange */
+
+#define FC_DIR_CACHE_FILE          "fonts.cache"
+#define FC_USER_CACHE_FILE         ".fonts.cache"
+
+/* Adjust outline rasterizer */
+#define FC_CHAR_WIDTH      "charwidth" /* Int */
+#define FC_CHAR_HEIGHT     "charheight"/* Int */
+#define FC_MATRIX          "matrix"    /* FcMatrix */
+
+#define FC_WEIGHT_LIGHT            0
+#define FC_WEIGHT_MEDIUM    100
+#define FC_WEIGHT_DEMIBOLD  180
+#define FC_WEIGHT_BOLD     200
+#define FC_WEIGHT_BLACK            210
+
+#define FC_SLANT_ROMAN     0
+#define FC_SLANT_ITALIC            100
+#define FC_SLANT_OBLIQUE    110
+
+#define FC_PROPORTIONAL            0
+#define FC_MONO                    100
+#define FC_CHARCELL        110
+
+/* sub-pixel order */
+#define FC_RGBA_NONE       0
+#define FC_RGBA_RGB        1
+#define FC_RGBA_BGR        2
+#define FC_RGBA_VRGB       3
+#define FC_RGBA_VBGR       4
+
+/* language groups from the OS/2 CodePageRange bits */
+#define FC_LANG_LATIN_1                        "latin1"                /* 0 */
+#define FC_LANG_LATIN_2_EASTERN_EUROPE "latin2easterneurope"   /* 1 */
+#define FC_LANG_CYRILLIC               "cyrillic"              /* 2 */
+#define FC_LANG_GREEK                  "greek"                 /* 3 */
+#define FC_LANG_TURKISH                        "turkish"               /* 4 */
+#define FC_LANG_HEBREW                 "hebrew"                /* 5 */
+#define FC_LANG_ARABIC                 "arabic"                /* 6 */
+#define FC_LANG_WINDOWS_BALTIC         "windowsbaltic"         /* 7 */
+#define FC_LANG_VIETNAMESE             "vietnamese"            /* 8 */
+/* 9-15 reserved for Alternate ANSI */
+#define FC_LANG_THAI                   "thai"                  /* 16 */
+#define FC_LANG_JAPANESE               "japanese"              /* 17 */
+#define FC_LANG_SIMPLIFIED_CHINESE     "simplifiedchinese"     /* 18 */
+#define FC_LANG_KOREAN_WANSUNG         "koreanwansung"         /* 19 */
+#define FC_LANG_TRADITIONAL_CHINESE    "traditionalchinese"    /* 20 */
+#define FC_LANG_KOREAN_JOHAB           "koreanjohab"           /* 21 */
+/* 22-28 reserved for Alternate ANSI & OEM */
+#define FC_LANG_MACINTOSH              "macintosh"             /* 29 */
+#define FC_LANG_OEM                    "oem"                   /* 30 */
+#define FC_LANG_SYMBOL                 "symbol"                /* 31 */
+/* 32-47 reserved for OEM */
+#define FC_LANG_IBM_GREEK              "ibmgreek"              /* 48 */
+#define FC_LANG_MSDOS_RUSSIAN          "msdosrussian"          /* 49 */
+#define FC_LANG_MSDOS_NORDIC           "msdosnordic"           /* 50 */
+#define FC_LANG_ARABIC_864             "arabic864"             /* 51 */
+#define FC_LANG_MSDOS_CANADIAN_FRENCH  "msdoscanadianfrench"   /* 52 */
+#define FC_LANG_HEBREW_862             "hebrew862"             /* 53 */
+#define FC_LANG_MSDOS_ICELANDIC                "msdosicelandic"        /* 54 */
+#define FC_LANG_MSDOS_PORTUGUESE       "msdosportuguese"       /* 55 */
+#define FC_LANG_IBM_TURKISH            "ibmturkish"            /* 56 */
+#define FC_LANG_IBM_CYRILLIC           "ibmcyrillic"           /* 57 */
+#define FC_LANG_LATIN_2                        "latin2"                /* 58 */
+#define FC_LANG_MSDOS_BALTIC           "msdosbaltic"           /* 59 */
+#define FC_LANG_GREEK_437_G            "greek437g"             /* 60 */
+#define FC_LANG_ARABIC_ASMO_708                "arabicasmo708"         /* 61 */
+#define FC_LANG_WE_LATIN_1             "welatin1"              /* 62 */
+#define FC_LANG_US                     "us"                    /* 63 */
+
+typedef enum _FcType {
+    FcTypeVoid, 
+    FcTypeInteger, 
+    FcTypeDouble, 
+    FcTypeString, 
+    FcTypeBool,
+    FcTypeMatrix,
+    FcTypeCharSet
+} FcType;
+
+typedef struct _FcMatrix {
+    double xx, xy, yx, yy;
+} FcMatrix;
+
+#define FcMatrixInit(m)        ((m)->xx = (m)->yy = 1, \
+                        (m)->xy = (m)->yx = 0)
+
+/*
+ * A data structure to represent the available glyphs in a font.
+ * This is represented as a sparse boolean btree.
+ */
+
+typedef struct _FcCharSet FcCharSet;
+
+typedef struct _FcObjectType {
+    const char *object;
+    FcType     type;
+} FcObjectType;
+
+typedef struct _FcConstant {
+    const char  *name;
+    const char *object;
+    int                value;
+} FcConstant;
+
+typedef enum _FcResult {
+    FcResultMatch, FcResultNoMatch, FcResultTypeMismatch, FcResultNoId
+} FcResult;
+
+typedef struct _FcValue {
+    FcType     type;
+    union {
+       const FcChar8   *s;
+       int             i;
+       FcBool          b;
+       double          d;
+       const FcMatrix  *m;
+       const FcCharSet *c;
+    } u;
+} FcValue;
+
+typedef struct _FcPattern   FcPattern;
+
+typedef struct _FcFontSet {
+    int                nfont;
+    int                sfont;
+    FcPattern  **fonts;
+} FcFontSet;
+
+typedef struct _FcObjectSet {
+    int                nobject;
+    int                sobject;
+    const char **objects;
+} FcObjectSet;
+    
+typedef enum _FcMatchKind {
+    FcMatchPattern, FcMatchFont 
+} FcMatchKind;
+
+typedef enum _FcSetName {
+    FcSetSystem = 0,
+    FcSetApplication = 1
+} FcSetName;
+
+#if defined(__cplusplus) || defined(c_plusplus) /* for C++ V2.0 */
+#define _FCFUNCPROTOBEGIN extern "C" { /* do not leave open across includes */
+#define _FCFUNCPROTOEND }
+#else
+#define _FCFUNCPROTOBEGIN
+#define _FCFUNCPROTOEND
+#endif
+
+typedef struct _FcConfig    FcConfig;
+
+typedef struct _FcFileCache FcFileCache;
+
+typedef struct _FcBlanks    FcBlanks;
+
+_FCFUNCPROTOBEGIN
+
+/* fcblanks.c */
+FcBlanks *
+FcBlanksCreate (void);
+
+void
+FcBlanksDestroy (FcBlanks *b);
+
+FcBool
+FcBlanksAdd (FcBlanks *b, FcChar32 ucs4);
+
+FcBool
+FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4);
+
+/* fccfg.c */
+char *
+FcConfigFilename (const char *url);
+    
+FcConfig *
+FcConfigCreate (void);
+
+void
+FcConfigDestroy (FcConfig *config);
+
+FcBool
+FcConfigSetCurrent (FcConfig *config);
+
+FcConfig *
+FcConfigGetCurrent (void);
+
+FcBool
+FcConfigBuildFonts (FcConfig *config);
+
+char **
+FcConfigGetDirs (FcConfig   *config);
+
+char **
+FcConfigGetConfigFiles (FcConfig    *config);
+
+char *
+FcConfigGetCache (FcConfig  *config);
+
+FcBlanks *
+FcConfigGetBlanks (FcConfig *config);
+
+FcFontSet *
+FcConfigGetFonts (FcConfig     *config,
+                 FcSetName     set);
+
+FcBool
+FcConfigAppFontAddFile (FcConfig    *config,
+                       const char  *file);
+
+FcBool
+FcConfigAppFontAddDir (FcConfig            *config,
+                      const char   *dir);
+
+void
+FcConfigAppFontClear (FcConfig     *config);
+
+FcBool
+FcConfigSubstitute (FcConfig   *config,
+                   FcPattern   *p,
+                   FcMatchKind kind);
+
+/* fccharset.c */
+FcCharSet *
+FcCharSetCreate (void);
+
+void
+FcCharSetDestroy (FcCharSet *fcs);
+
+FcBool
+FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4);
+
+FcCharSet *
+FcCharSetCopy (FcCharSet *src);
+
+FcBool
+FcCharSetEqual (const FcCharSet *a, const FcCharSet *b);
+
+FcCharSet *
+FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b);
+
+FcCharSet *
+FcCharSetUnion (const FcCharSet *a, const FcCharSet *b);
+
+FcCharSet *
+FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b);
+
+FcBool
+FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4);
+
+FcChar32
+FcCharSetCount (const FcCharSet *a);
+
+FcChar32
+FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b);
+
+FcChar32
+FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b);
+
+#ifndef FONTCONFIG_NO_FREETYPE
+#include <freetype/freetype.h>
+FT_UInt
+FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4);
+#endif
+
+/* fcdbg.c */
+void
+FcPatternPrint (FcPattern *p);
+
+/* fcdefault.c */
+void
+FcDefaultSubstitute (FcPattern *pattern);
+
+/* fcdir.c */
+FcBool
+FcDirScan (FcFontSet   *set,
+          FcFileCache  *cache,
+          FcBlanks     *blanks,
+          const char   *dir,
+          FcBool       force);
+
+FcBool
+FcDirSave (FcFontSet *set, const char *dir);
+
+/* fcfreetype.c */
+FcPattern *
+FcFreeTypeQuery (const char *file, int id, FcBlanks *blanks, int *count);
+
+/* fcfs.c */
+
+FcFontSet *
+FcFontSetCreate (void);
+
+void
+FcFontSetDestroy (FcFontSet *s);
+
+FcBool
+FcFontSetAdd (FcFontSet *s, FcPattern *font);
+
+/* fcinit.c */
+FcBool
+FcInitFonts (void);
+
+FcBool
+FcInitConfig (void);
+
+FcBool
+FcInit (void);
+
+/* fclist.c */
+FcObjectSet *
+FcObjectSetCreate (void);
+
+FcBool
+FcObjectSetAdd (FcObjectSet *os, const char *object);
+
+void
+FcObjectSetDestroy (FcObjectSet *os);
+
+FcObjectSet *
+FcObjectSetVaBuild (const char *first, va_list va);
+
+FcObjectSet *
+FcObjectSetBuild (const char *first, ...);
+
+FcFontSet *
+FcFontList (FcConfig   *config,
+           FcPattern   *p,
+           FcObjectSet *os);
+
+/* fcmatch.c */
+FcPattern *
+FcFontMatch (FcConfig  *config,
+            FcPattern  *p, 
+            FcResult   *result);
+
+/* fcmatrix.c */
+FcMatrix *
+FcMatrixCopy (const FcMatrix *mat);
+
+FcBool
+FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2);
+
+void
+FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b);
+
+void
+FcMatrixRotate (FcMatrix *m, double c, double s);
+
+void
+FcMatrixScale (FcMatrix *m, double sx, double sy);
+
+void
+FcMatrixShear (FcMatrix *m, double sh, double sv);
+
+/* fcname.c */
+
+FcBool
+FcNameRegisterObjectTypes (const FcObjectType *types, int ntype);
+
+FcBool
+FcNameUnregisterObjectTypes (const FcObjectType *types, int ntype);
+    
+const FcObjectType *
+FcNameGetObjectType (const char *object);
+
+FcBool
+FcNameRegisterConstants (const FcConstant *consts, int nconsts);
+
+FcBool
+FcNameUnregisterConstants (const FcConstant *consts, int nconsts);
+    
+const FcConstant *
+FcNameGetConstant (char *string);
+
+FcBool
+FcNameConstant (char *string, int *result);
+
+FcPattern *
+FcNameParse (const char *name);
+
+FcChar8 *
+FcNameUnparse (FcPattern *pat);
+
+/* fcpat.c */
+FcPattern *
+FcPatternCreate (void);
+
+FcPattern *
+FcPatternDuplicate (FcPattern *p);
+
+void
+FcValueDestroy (FcValue v);
+
+FcValue
+FcValueSave (FcValue v);
+
+void
+FcPatternDestroy (FcPattern *p);
+
+FcBool
+FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append);
+    
+FcResult
+FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v);
+    
+FcBool
+FcPatternDel (FcPattern *p, const char *object);
+
+FcBool
+FcPatternAddInteger (FcPattern *p, const char *object, int i);
+
+FcBool
+FcPatternAddDouble (FcPattern *p, const char *object, double d);
+
+FcBool
+FcPatternAddString (FcPattern *p, const char *object, const char *s);
+
+FcBool
+FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s);
+
+FcBool
+FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c);
+
+FcBool
+FcPatternAddBool (FcPattern *p, const char *object, FcBool b);
+
+FcResult
+FcPatternGetInteger (FcPattern *p, const char *object, int n, int *i);
+
+FcResult
+FcPatternGetDouble (FcPattern *p, const char *object, int n, double *d);
+
+FcResult
+FcPatternGetString (FcPattern *p, const char *object, int n, char **const s);
+
+FcResult
+FcPatternGetMatrix (FcPattern *p, const char *object, int n, FcMatrix **s);
+
+FcResult
+FcPatternGetCharSet (FcPattern *p, const char *object, int n, FcCharSet **c);
+
+FcResult
+FcPatternGetBool (FcPattern *p, const char *object, int n, FcBool *b);
+
+FcPattern *
+FcPatternVaBuild (FcPattern *orig, va_list va);
+    
+FcPattern *
+FcPatternBuild (FcPattern *orig, ...);
+
+/* fcstr.c */
+
+char *
+FcStrCopy (const char *s);
+
+#define FcToLower(c)   (('A' <= (c) && (c) <= 'Z') ? (c) - 'A' + 'a' : (c))
+
+int
+FcStrCmpIgnoreCase (const char *s1, const char *s2);
+
+int
+FcUtf8ToUcs4 (FcChar8   *src_orig,
+             FcChar32  *dst,
+             int       len);
+
+FcBool
+FcUtf8Len (FcChar8     *string,
+          int          len,
+          int          *nchar,
+          int          *wchar);
+
+/* fcxml.c */
+FcBool
+FcConfigParseAndLoad (FcConfig *config, const char *file, FcBool complain);
+
+_FCFUNCPROTOEND
+
+#endif /* _FONTCONFIG_H_ */
diff --git a/fonts.conf.in b/fonts.conf.in
new file mode 100644 (file)
index 0000000..e85c0c4
--- /dev/null
@@ -0,0 +1,191 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts.conf file to configure system font access -->
+<fontconfig>
+
+<!-- FONTPATH_START -->
+
+<!-- 
+  Common X11R6 font directories
+-->
+
+       <dir>/usr/X11R6/lib/X11/fonts/truetype</dir>
+       <dir>/usr/X11R6/lib/X11/fonts/Type1</dir>
+       <dir>/usr/X11R6/lib/X11/fonts/TrueType</dir>
+
+<!-- FONTPATH_END -->
+
+<!--
+  Accept deprecated 'mono' alias, replacing it with 'monospace'
+-->
+       <match target="pattern">
+               <test qual="any" name="family">
+                       <string>mono</string>
+               </test>
+               <edit name="family" mode="assign">
+                       <string>monospace</string>
+               </edit>
+       </match>
+
+<!--
+  Accept deprecated 'sans' alias, replacing it with 'sans-serif'
+-->
+       <match target="pattern">
+               <test qual="any" name="family">
+                       <string>sans</string>
+               </test>
+               <edit name="family" mode="assign">
+                       <string>sans-serif</string>
+               </edit>
+       </match>
+
+<!--
+  Mark common families with their generics so we'll get
+  something reasonable
+-->
+
+<!--
+  Serif faces
+ -->
+       <alias>
+               <family>Times</family>
+               <default><family>serif</family></default>
+       </alias>
+       <alias>
+               <family>Times New Roman</family>
+               <default><family>serif</family></default>
+       </alias>
+<!--
+  Sans-serif faces
+ -->
+       <alias>
+               <family>Helvetica</family>
+               <default><family>sans-serif</family></default>
+       </alias>
+       <alias>
+               <family>Arial</family>
+               <default><family>sans-serif</family></default>
+       </alias>
+       <alias>
+               <family>Verdana</family>
+               <default><family>sans-serif</family></default>
+       </alias>
+<!--
+  Monospace faces
+ -->
+       <alias>
+               <family>Courier</family>
+               <default><family>monospace</family></default>
+       </alias>
+       <alias>
+               <family>Courier New</family>
+               <default><family>monospace</family></default>
+       </alias>
+       <alias>
+               <family>Andale Mono</family>
+               <default><family>monospace</family></default>
+       </alias>
+<!--
+  If the font still has no generic name, add sans-serif
+ -->
+       <match target="pattern">
+               <test qual="all" name="family" compare="not_eq">
+                       <string>sans-serif</string>
+               </test>
+               <test qual="all" name="family" compare="not_eq">
+                       <string>serif</string>
+               </test>
+               <test qual="all" name="family" compare="not_eq">
+                       <string>monospace</string>
+               </test>
+               <edit name="family" mode="append_last">
+                       <string>sans-serif</string>
+               </edit>
+       </match>
+       
+<!--
+  Load per-user customization file
+-->
+       <include ignore_missing="yes">~/.fonts.conf</include>
+
+<!--
+  Alias well known font names to available TrueType fonts
+-->
+       <alias>
+               <family>Times</family>
+               <prefer><family>Times New Roman</family></prefer>
+               <default><family>serif</family></default>
+       </alias>
+       <alias>
+               <family>Helvetica</family>
+               <prefer><family>Verdana</family></prefer>
+               <default><family>sans-serif</family></default>
+       </alias>
+       <alias>
+               <family>Arial</family>
+               <prefer><family>Verdana</family></prefer>
+               <default><family>sans-serif</family></default>
+       </alias>
+       <alias>
+               <family>Courier</family>
+               <prefer><family>Courier New</family></prefer>
+               <default><family>monospace</family></default>
+       </alias>
+
+<!--
+  Provide required aliases for standard names
+-->
+       <alias>
+               <family>serif</family>
+               <prefer>
+                       <family>Times New Roman</family>
+                       <family>Nimbus Roman No9 L</family>
+                       <family>Luxi Serif</family>
+                       <family>Times</family>
+               </prefer>
+       </alias>
+       <alias>
+               <family>sans-serif</family>
+               <prefer>
+                       <family>Verdana</family>
+                       <family>Nimbus Sans L</family>
+                       <family>Luxi Sans</family>
+                       <family>Arial</family>
+                       <family>Helvetica</family>
+               </prefer>
+       </alias>
+       <alias>
+               <family>monospace</family>
+               <prefer>
+                       <family>Andale Mono</family>
+                       <family>Courier New</family>
+                       <family>Nimbus Mono L</family>
+                       <family>Luxi Mono</family>
+               </prefer>
+       </alias>
+
+<!--
+  These are the default Unicode chars that are expected to be blank
+  in fonts.  All other blank chars are assumed to be broken and
+  won't appear in the resulting charsets
+ -->
+       <config><blank>
+               <int>0x20</int>         <!-- space -->
+               <int>0xa0</int>         <!-- nsbp  -->
+               <int>0x2000</int>       <!-- general punctuation spaces -->
+               <int>0x2001</int>
+               <int>0x2002</int>
+               <int>0x2003</int>
+               <int>0x2004</int>
+               <int>0x2005</int>
+               <int>0x2005</int>
+               <int>0x2006</int>
+               <int>0x2007</int>
+               <int>0x2008</int>
+               <int>0x2009</int>
+               <int>0x200a</int>
+               <int>0x200b</int>
+               <int>0x3000</int>       <!-- CJK space -->
+       </blank></config>
+
+</fontconfig>
diff --git a/fonts.dtd b/fonts.dtd
new file mode 100644 (file)
index 0000000..a3c987b
--- /dev/null
+++ b/fonts.dtd
@@ -0,0 +1,165 @@
+<!-- This is the Document Type Definition for font configuration files -->
+<!ELEMENT fontconfig (dir | 
+                     cache | 
+                     include | 
+                     config |
+                     match | 
+                     alias)* >
+
+<!-- 
+    Add a directory that provides fonts
+-->
+<!ELEMENT dir (#PCDATA)>
+<!ATTLIST dir xml:space (default|preserve) 'preserve'>
+
+<!--
+    Define the per-user file that holds cache font information.
+
+    If the filename begins with '~', it is replaced with the users
+    home directory path.
+-->
+<!ELEMENT cache (#PCDATA)>
+<!ATTLIST cache xml:space (default|preserve) 'preserve'>
+
+<!--
+    Reference another configuration file; note that this
+    is another complete font configuration file and not
+    just a file included by the XML parser.
+
+    Set 'ignore_missing' to 'yes' if errors are to be ignored.
+
+    If the filename begins with '~', it is replaced with the users
+    home directory path.
+-->
+<!ELEMENT include (#PCDATA)>
+<!ATTLIST include
+         ignore_missing    (no|yes)            "no"
+         xml:space         (default|preserve)  "preserve">
+
+<!--
+    Global library configuration data
+ -->
+<!ELEMENT config (blanks)*>
+
+<!--
+    Specify the set of Unicode encoding values which
+    represent glyphs that are allowed to contain no
+    data.  With this list, fontconfig can examine
+    fonts for broken glyphs and eliminate them from
+    the set of valid Unicode chars.  This idea
+    was borrowed from Mozilla
+ -->
+<!ELEMENT blanks (int)*>
+
+<!--
+    Aliases are just a special case for multiple match elements
+
+    They are syntactically equivalent to:
+
+    <match>
+       <test name="family">
+           <string value=[family]/>
+       </test>
+       <edit name="family" mode="prepend">
+           <string value=[prefer]/>
+           ...
+       </edit>
+       <edit name="family" mode="append">
+           <string value=[accept]/>
+           ...
+       </edit>
+       <edit name="family" mode="append_last">
+           <string value=[default]/>
+           ...
+       </edit>
+    </match>
+-->
+<!ELEMENT alias (family, prefer?, accept?, default?)>
+<!ELEMENT prefer (family)*>
+<!ELEMENT accept (family)*>
+<!ELEMENT default (family)*>
+<!ELEMENT family (#PCDATA)>
+<!ATTLIST family xml:space (default|preserve) 'preserve'>
+
+<!ENTITY % expr 'int|double|string|matrix|bool|charset
+               |name|const
+               |or|and|eq|not_eq|less|less_eq|more|more_eq
+               |plus|minus|times|divide|not|if'>
+
+<!--
+    Match and edit patterns.
+
+    If 'target' is 'pattern', execute the match before selecting a font.
+    if 'target' is 'font', execute the match on the result of a font
+    selection.
+-->
+<!ELEMENT match (test*, edit*)>
+<!ATTLIST match
+         target (pattern|font) "pattern">
+
+<!--
+    Match a field in a pattern
+
+    if 'qual' is 'any', then the match succeeds if any value in the field matches.
+    if 'qual' is 'all', then the match succeeds only if all values match.
+-->
+<!ELEMENT test (%expr;)>
+<!ATTLIST test 
+         qual (any|all)    "any"
+         name CDATA        #REQUIRED
+         compare (eq|not_eq|less|less_eq|more|more_eq) "eq">
+
+<!--
+    Edit a field in a pattern
+
+    The enclosed values are used together to edit the list of values
+    associated with 'name'.
+
+    If 'name' matches one of those used in a test element for this match element:
+       if 'mode' is 'assign', replace the matched value.
+       if 'mode' is 'assign_replace', replace all of the values
+       if 'mode' is 'prepend', insert before the matched value
+       if 'mode' is 'append', insert after the matched value
+       if 'mode' is 'prepend_first', insert before all of the values
+       if 'mode' is 'append_last', insert after all of the values
+    If 'name' doesn't match any of those used in a test element:
+       if 'mode' is 'assign' or 'assign_replace, replace all of the values
+       if 'mode' is 'prepend' or 'prepend_first', insert before all of the values
+       if 'mode' is 'append' or 'append_last', insert after all of the values
+-->
+<!ELEMENT edit (%expr;)*>
+<!ATTLIST edit
+         name CDATA        #REQUIRED
+         mode (assign|assign_replace|prepend|append|prepend_first|append_last) "assign">
+
+<!--
+    Elements of expressions follow
+-->
+<!ELEMENT int (#PCDATA)>
+<!ATTLIST int xml:space (default|preserve) 'preserve'>
+<!ELEMENT double (#PCDATA)>
+<!ATTLIST double xml:space (default|preserve) 'preserve'>
+<!ELEMENT string (#PCDATA)>
+<!ATTLIST string xml:space (default|preserve) 'preserve'>
+<!ELEMENT matrix (double,double,double,double)>
+<!ELEMENT bool (true|false)>
+<!ELEMENT charset (#PCDATA)>
+<!ATTLIST charset xml:space (default|preserve) 'preserve'>
+<!ELEMENT name (#PCDATA)>
+<!ATTLIST name xml:space (default|preserve) 'preserve'>
+<!ELEMENT const (#PCDATA)>
+<!ATTLIST const xml:space (default|preserve) 'preserve'>
+<!ELEMENT or (%expr;)*>
+<!ELEMENT and (%expr;)*>
+<!ELEMENT eq ((%expr;), (%expr;))>
+<!ELEMENT not_eq ((%expr;), (%expr;))>
+<!ELEMENT less ((%expr;), (%expr;))>
+<!ELEMENT less_eq ((%expr;), (%expr;))>
+<!ELEMENT more ((%expr;), (%expr;))>
+<!ELEMENT more_eq ((%expr;), (%expr;))>
+<!ELEMENT plus (%expr;)*>
+<!ELEMENT minus (%expr;)*>
+<!ELEMENT times (%expr;)*>
+<!ELEMENT divide (%expr;)*>
+<!ELEMENT not (%expr;)>
+<!ELEMENT if ((%expr;), (%expr;), (%expr;))>
diff --git a/setfontdirs b/setfontdirs
new file mode 100755 (executable)
index 0000000..7bed787
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/sh
+FONTDIRS=fontdirs$$
+trap "rm $FONTDIRS" 0
+sh ./findfonts > $FONTDIRS
+cp fonts.conf.in fonts.conf
+chmod +w fonts.conf
+ed fonts.conf << EOF
+/FONTPATH_END/a
+<!-- Font directories found on `date` -->
+.
++r $FONTDIRS
+a
+
+.
+/FONTPATH_START/,/FONTPATH_END/d
+w
+q
+EOF
+
diff --git a/src/Imakefile b/src/Imakefile
new file mode 100644 (file)
index 0000000..1ba4cb5
--- /dev/null
@@ -0,0 +1,90 @@
+#include "../../libxml2/config.h"
+#if HAVE_ZLIB_H
+ZLIB=-lz
+#endif
+
+#if 0
+#define SharedLibFontconfig YES
+#endif
+
+#ifndef SharedLibFontconfig
+#define SharedLibFontconfig NO
+#endif
+
+#ifndef NormalLibFontconfig
+#define NormalLibFontconfig (!SharedLibFontConfig | ForceNormalLib)
+#endif
+
+#ifndef DebugLibFontconfig
+#define DebugLibFontconfig             NO
+#endif
+
+#ifndef ProfileLibFontconfig
+#define ProfileLibFontconfig           NO
+#endif
+
+#define LibHeaders NO
+
+FONTCONFIGSRC=.
+
+FALLBACK_FONTS=$(FONTDIR)/Type1
+
+#if SharedLibFontconfig
+#ifndef SharedFontconfigRev
+#define SharedFontconfigRev 1.0
+#endif
+SharedLibReferences(FONTCONFIG,Fontconfig,$(FONTCONFIGSRC),SOXLIBREV,SharedFontconfigRev)
+#else
+ProjectUnsharedLibReferences(FONTCONFIG,Fontconfig,$(FONTCONFIGSRC),BuildLibDir)
+#endif
+
+#define DoNormalLib NormalLibFontconfig
+#define DoSharedLib SharedLibFontconfig
+#define DoExtraLib SharedLibFontconfig
+#define DoDebugLib DebugLibFontconfig
+#define DoProfileLib ProfileLibFontconfig
+#define HasSharedData YES
+#define LibName fontconfig
+SOFONTCONFIGREV=1.0
+#define SoRev SOFONTCONFIGREV
+
+#include <Threads.tmpl>
+
+#if SharedLibFontconfig
+INCLUDES=-I/usr/local/include/freetype2 -I/usr/include/libxml2 -I..
+FREETYPE2REQLIB = -L/usr/local/lib -lfreetype
+XML2REQLIB=-lxml2
+#else
+INCLUDES=-I../../freetype2 -I../../libxml2/include -I..
+FREETYPE2REQLIB = ../../freetype2/libfreetype.a
+XML2REQLIB=../../libxml2/.libs/libxml2.a $(ZLIB) -lm
+#endif
+DEFINES=-DFC_FALLBACK_FONTS='"$(FALLBACK_FONTS)"'
+
+REQUIREDLIBS=$(LDPRELIBS) $(FREETYPE2REQLIB) $(XML2REQLIB)
+
+SRCS=fcblanks.c fccache.c fccfg.c fccharset.c fcdbg.c fcdefault.c fcdir.c \
+     fcfreetype.c fcfs.c fcinit.c fclist.c fcmatch.c fcmatrix.c fcname.c \
+     fcpat.c fcstr.c fcxml.c
+
+OBJS=fcblanks.o fccache.o fccfg.o fccharset.o fcdbg.o fcdefault.o fcdir.o \
+     fcfreetype.o fcfs.o fcinit.o fclist.o fcmatch.o fcmatrix.o fcname.o \
+     fcpat.o fcstr.o fcxml.o
+
+#define LibInstallBuild YES
+#undef LinkBuildLibrary
+#define LinkBuildLibrary(lib) MakeDir($(BUILDLIBDIR))                  @@\
+       RemoveFile($(BUILDLIBDIR)/lib)                                  @@\
+       cd $(BUILDLIBDIR) && $(LN) $(BUILDLIBTOP)/$(CURRENT_DIR)/lib .
+
+
+#include <Library.tmpl>
+
+#if DoSharedLib && SharedDataSeparation
+SpecialCObjectRule(sharedlib,NullParameter,$(SHLIBDEF))
+#endif
+
+MANSUFFIX = $(LIBMANSUFFIX)
+InstallManPage(fontconfig,$(LIBMANDIR))
+DependTarget()
+
diff --git a/src/fcblanks.c b/src/fcblanks.c
new file mode 100644 (file)
index 0000000..8b3a9a9
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * $XFree86$
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+
+FcBlanks *
+FcBlanksCreate (void)
+{
+    FcBlanks   *b;
+
+    b = malloc (sizeof (FcBlanks));
+    if (!b)
+       return 0;
+    b->nblank = 0;
+    b->sblank = 0;
+    b->blanks = 0;
+    return b;
+}
+
+void
+FcBlanksDestroy (FcBlanks *b)
+{
+    if (b->blanks)
+       free (b->blanks);
+    free (b);
+}
+
+FcBool
+FcBlanksAdd (FcBlanks *b, FcChar32 ucs4)
+{
+    FcChar32   *c;
+    int                sblank;
+
+    for (sblank = 0; sblank < b->nblank; sblank++)
+       if (b->blanks[sblank] == ucs4)
+           return FcTrue;
+
+    if (b->nblank == b->sblank)
+    {
+       sblank = b->sblank + 32;
+       if (b->blanks)
+           c = (FcChar32 *) realloc (b->blanks, sblank * sizeof (FcChar32));
+       else
+           c = (FcChar32 *) malloc (sblank * sizeof (FcChar32));
+       if (!c)
+           return FcFalse;
+       b->sblank = sblank;
+       b->blanks = c;
+    }
+    b->blanks[b->nblank++] = ucs4;
+    return FcTrue;
+}
+
+FcBool
+FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4)
+{
+    int        i;
+
+    for (i = 0; i < b->nblank; i++)
+       if (b->blanks[i] == ucs4)
+           return FcTrue;
+    return FcFalse;
+}
diff --git a/src/fccache.c b/src/fccache.c
new file mode 100644 (file)
index 0000000..2251286
--- /dev/null
@@ -0,0 +1,592 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+
+static unsigned int
+FcFileCacheHash (const char *string)
+{
+    unsigned int    h = 0;
+    char           c;
+
+    while ((c = *string++))
+       h = (h << 1) ^ c;
+    return h;
+}
+
+char *
+FcFileCacheFind (FcFileCache   *cache,
+                const char     *file,
+                int            id,
+                int            *count)
+{
+    unsigned int    hash;
+    const char     *match;
+    FcFileCacheEnt *c, *name;
+    int                    maxid;
+    struct stat            statb;
+    
+    match = file;
+    
+    hash = FcFileCacheHash (match);
+    name = 0;
+    maxid = -1;
+    for (c = cache->ents[hash % FC_FILE_CACHE_HASH_SIZE]; c; c = c->next)
+    {
+       if (c->hash == hash && !strcmp (match, c->file))
+       {
+           if (c->id > maxid)
+               maxid = c->id;
+           if (c->id == id)
+           {
+               if (stat (file, &statb) < 0)
+               {
+                   if (FcDebug () & FC_DBG_CACHE)
+                       printf (" file missing\n");
+                   return 0;
+               }
+               if (statb.st_mtime != c->time)
+               {
+                   if (FcDebug () & FC_DBG_CACHE)
+                       printf (" timestamp mismatch (was %d is %d)\n",
+                               (int) c->time, (int) statb.st_mtime);
+                   return 0;
+               }
+               if (!c->referenced)
+               {
+                   cache->referenced++;
+                   c->referenced = FcTrue;
+               }
+               name = c;
+           }
+       }
+    }
+    if (!name)
+       return 0;
+    *count = maxid + 1;
+    return name->name;
+}
+
+/*
+ * Cache file syntax is quite simple:
+ *
+ * "file_name" id time "font_name" \n
+ */
+static FcBool
+FcFileCacheReadString (FILE *f, char *dest, int len)
+{
+    int            c;
+    FcBool    escape;
+
+    while ((c = getc (f)) != EOF)
+       if (c == '"')
+           break;
+    if (c == EOF)
+       return FcFalse;
+    if (len == 0)
+       return FcFalse;
+    
+    escape = FcFalse;
+    while ((c = getc (f)) != EOF)
+    {
+       if (!escape)
+       {
+           switch (c) {
+           case '"':
+               *dest++ = '\0';
+               return FcTrue;
+           case '\\':
+               escape = FcTrue;
+               continue;
+           }
+       }
+        if (--len <= 1)
+           return FcFalse;
+       *dest++ = c;
+       escape = FcFalse;
+    }
+    return FcFalse;
+}
+
+static FcBool
+FcFileCacheReadUlong (FILE *f, unsigned long *dest)
+{
+    unsigned long   t;
+    int                    c;
+
+    while ((c = getc (f)) != EOF)
+    {
+       if (!isspace (c))
+           break;
+    }
+    if (c == EOF)
+       return FcFalse;
+    t = 0;
+    for (;;)
+    {
+       if (c == EOF || isspace (c))
+           break;
+       if (!isdigit (c))
+           return FcFalse;
+       t = t * 10 + (c - '0');
+       c = getc (f);
+    }
+    *dest = t;
+    return FcTrue;
+}
+
+static FcBool
+FcFileCacheReadInt (FILE *f, int *dest)
+{
+    unsigned long   t;
+    FcBool         ret;
+
+    ret = FcFileCacheReadUlong (f, &t);
+    if (ret)
+       *dest = (int) t;
+    return ret;
+}
+
+static FcBool
+FcFileCacheReadTime (FILE *f, time_t *dest)
+{
+    unsigned long   t;
+    FcBool         ret;
+
+    ret = FcFileCacheReadUlong (f, &t);
+    if (ret)
+       *dest = (time_t) t;
+    return ret;
+}
+
+static FcBool
+FcFileCacheAdd (FcFileCache    *cache,
+                const char     *file,
+                int            id,
+                time_t         time,
+                const char     *name,
+                FcBool         replace)
+{
+    FcFileCacheEnt    *c;
+    FcFileCacheEnt    **prev, *old;
+    unsigned int    hash;
+
+    if (FcDebug () & FC_DBG_CACHE)
+    {
+       printf ("%s face %s/%d as %s\n", replace ? "Replace" : "Add",
+               file, id, name);
+    }
+    hash = FcFileCacheHash (file);
+    for (prev = &cache->ents[hash % FC_FILE_CACHE_HASH_SIZE]; 
+        (old = *prev);
+        prev = &(*prev)->next)
+    {
+       if (old->hash == hash && old->id == id && !strcmp (old->file, file))
+           break;
+    }
+    if (*prev)
+    {
+       if (!replace)
+           return FcFalse;
+
+       old = *prev;
+       if (old->referenced)
+           cache->referenced--;
+       *prev = old->next;
+       free (old);
+       cache->entries--;
+    }
+       
+    c = malloc (sizeof (FcFileCacheEnt) +
+               strlen (file) + 1 +
+               strlen (name) + 1);
+    if (!c)
+       return FcFalse;
+    c->next = *prev;
+    *prev = c;
+    c->hash = hash;
+    c->file = (char *) (c + 1);
+    c->id = id;
+    c->name = c->file + strlen (file) + 1;
+    strcpy (c->file, file);
+    c->time = time;
+    c->referenced = replace;
+    strcpy (c->name, name);
+    cache->entries++;
+    return FcTrue;
+}
+
+FcFileCache *
+FcFileCacheCreate (void)
+{
+    FcFileCache        *cache;
+    int                h;
+
+    cache = malloc (sizeof (FcFileCache));
+    if (!cache)
+       return 0;
+    for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
+       cache->ents[h] = 0;
+    cache->entries = 0;
+    cache->referenced = 0;
+    cache->updated = FcFalse;
+    return cache;
+}
+
+void
+FcFileCacheDestroy (FcFileCache *cache)
+{
+    FcFileCacheEnt *c, *next;
+    int                    h;
+
+    for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
+    {
+       for (c = cache->ents[h]; c; c = next)
+       {
+           next = c->next;
+           free (c);
+       }
+    }
+    free (cache);
+}
+
+void
+FcFileCacheLoad (FcFileCache   *cache,
+                const char     *cache_file)
+{
+    FILE           *f;
+    char           file[8192];
+    int                    id;
+    time_t         time;
+    char           name[8192];
+
+    f = fopen (cache_file, "r");
+    if (!f)
+       return;
+
+    cache->updated = FcFalse;
+    while (FcFileCacheReadString (f, file, sizeof (file)) &&
+          FcFileCacheReadInt (f, &id) &&
+          FcFileCacheReadTime (f, &time) &&
+          FcFileCacheReadString (f, name, sizeof (name)))
+    {
+       (void) FcFileCacheAdd (cache, file, id, time, name, FcFalse);
+    }
+    fclose (f);
+}
+
+FcBool
+FcFileCacheUpdate (FcFileCache *cache,
+                  const char   *file,
+                  int          id,
+                  const char   *name)
+{
+    const char     *match;
+    struct stat            statb;
+    FcBool         ret;
+
+    match = file;
+
+    if (stat (file, &statb) < 0)
+       return FcFalse;
+    ret = FcFileCacheAdd (cache, match, id, 
+                           statb.st_mtime, name, FcTrue);
+    if (ret)
+       cache->updated = FcTrue;
+    return ret;
+}
+
+static FcBool
+FcFileCacheWriteString (FILE *f, char *string)
+{
+    char    c;
+
+    if (putc ('"', f) == EOF)
+       return FcFalse;
+    while ((c = *string++))
+    {
+       switch (c) {
+       case '"':
+       case '\\':
+           if (putc ('\\', f) == EOF)
+               return FcFalse;
+           /* fall through */
+       default:
+           if (putc (c, f) == EOF)
+               return FcFalse;
+       }
+    }
+    if (putc ('"', f) == EOF)
+       return FcFalse;
+    return FcTrue;
+}
+
+static FcBool
+FcFileCacheWriteUlong (FILE *f, unsigned long t)
+{
+    int            pow;
+    unsigned long   temp, digit;
+
+    temp = t;
+    pow = 1;
+    while (temp >= 10)
+    {
+       temp /= 10;
+       pow *= 10;
+    }
+    temp = t;
+    while (pow)
+    {
+       digit = temp / pow;
+       if (putc ((char) digit + '0', f) == EOF)
+           return FcFalse;
+       temp = temp - pow * digit;
+       pow = pow / 10;
+    }
+    return FcTrue;
+}
+
+static FcBool
+FcFileCacheWriteInt (FILE *f, int i)
+{
+    return FcFileCacheWriteUlong (f, (unsigned long) i);
+}
+
+static FcBool
+FcFileCacheWriteTime (FILE *f, time_t t)
+{
+    return FcFileCacheWriteUlong (f, (unsigned long) t);
+}
+
+FcBool
+FcFileCacheSave (FcFileCache   *cache,
+                const char     *cache_file)
+{
+    char           *lck;
+    char           *tmp;
+    FILE           *f;
+    int                    h;
+    FcFileCacheEnt *c;
+
+    if (!cache->updated && cache->referenced == cache->entries)
+       return FcTrue;
+    
+    lck = malloc (strlen (cache_file)*2 + 4);
+    if (!lck)
+       goto bail0;
+    tmp = lck + strlen (cache_file) + 2;
+    strcpy (lck, cache_file);
+    strcat (lck, "L");
+    strcpy (tmp, cache_file);
+    strcat (tmp, "T");
+    if (link (lck, cache_file) < 0 && errno != ENOENT)
+       goto bail1;
+    if (access (tmp, F_OK) == 0)
+       goto bail2;
+    f = fopen (tmp, "w");
+    if (!f)
+       goto bail2;
+
+    for (h = 0; h < FC_FILE_CACHE_HASH_SIZE; h++)
+    {
+       for (c = cache->ents[h]; c; c = c->next)
+       {
+           if (!c->referenced)
+               continue;
+           if (!FcFileCacheWriteString (f, c->file))
+               goto bail4;
+           if (putc (' ', f) == EOF)
+               goto bail4;
+           if (!FcFileCacheWriteInt (f, c->id))
+               goto bail4;
+           if (putc (' ', f) == EOF)
+               goto bail4;
+           if (!FcFileCacheWriteTime (f, c->time))
+               goto bail4;
+           if (putc (' ', f) == EOF)
+               goto bail4;
+           if (!FcFileCacheWriteString (f, c->name))
+               goto bail4;
+           if (putc ('\n', f) == EOF)
+               goto bail4;
+       }
+    }
+
+    if (fclose (f) == EOF)
+       goto bail3;
+    
+    if (rename (tmp, cache_file) < 0)
+       goto bail3;
+    
+    unlink (lck);
+    cache->updated = FcFalse;
+    return FcTrue;
+
+bail4:
+    fclose (f);
+bail3:
+    unlink (tmp);
+bail2:
+    unlink (lck);
+bail1:
+    free (lck);
+bail0:
+    return FcFalse;
+}
+
+FcBool
+FcFileCacheReadDir (FcFontSet *set, const char *cache_file)
+{
+    FcPattern      *font;
+    FILE           *f;
+    char           *path;
+    char           *base;
+    char           file[8192];
+    int                    id;
+    char           name[8192];
+    FcBool         ret = FcFalse;
+
+    if (FcDebug () & FC_DBG_CACHE)
+    {
+       printf ("FcFileCacheReadDir cache_file \"%s\"\n", cache_file);
+    }
+    
+    f = fopen (cache_file, "r");
+    if (!f)
+    {
+       if (FcDebug () & FC_DBG_CACHE)
+       {
+           printf (" no cache file\n");
+       }
+       goto bail0;
+    }
+
+    base = strrchr (cache_file, '/');
+    if (!base)
+       goto bail1;
+    base++;
+    path = malloc (base - cache_file + 8192 + 1);
+    if (!path)
+       goto bail1;
+    memcpy (path, cache_file, base - cache_file);
+    base = path + (base - cache_file);
+    
+    while (FcFileCacheReadString (f, file, sizeof (file)) &&
+          FcFileCacheReadInt (f, &id) &&
+          FcFileCacheReadString (f, name, sizeof (name)))
+    {
+       font = FcNameParse (name);
+       if (font)
+       {
+           strcpy (base, file);
+           if (FcDebug () & FC_DBG_CACHEV)
+           {
+               printf (" dir cache file \"%s\"\n", file);
+           }
+           FcPatternAddString (font, FC_FILE, path);
+           if (!FcFontSetAdd (set, font))
+               goto bail2;
+       }
+    }
+    if (FcDebug () & FC_DBG_CACHE)
+    {
+       printf (" cache loaded\n");
+    }
+    
+    ret = FcTrue;
+bail2:
+    free (path);
+bail1:
+    fclose (f);
+bail0:
+    return ret;
+}
+
+FcBool
+FcFileCacheWriteDir (FcFontSet *set, const char *cache_file)
+{
+    FcPattern      *font;
+    FILE           *f;
+    char           *name;
+    char           *file, *base;
+    int                    n;
+    int                    id;
+    FcBool         ret;
+
+    if (FcDebug () & FC_DBG_CACHE)
+       printf ("FcFileCacheWriteDir cache_file \"%s\"\n", cache_file);
+    
+    f = fopen (cache_file, "w");
+    if (!f)
+    {
+       if (FcDebug () & FC_DBG_CACHE)
+           printf (" can't create \"%s\"\n", cache_file);
+       goto bail0;
+    }
+    for (n = 0; n < set->nfont; n++)
+    {
+       font = set->fonts[n];
+       if (FcPatternGetString (font, FC_FILE, 0, &file) != FcResultMatch)
+           goto bail1;
+       base = strrchr (file, '/');
+       if (base)
+           base = base + 1;
+       else
+           base = file;
+       if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch)
+           goto bail1;
+       if (FcDebug () & FC_DBG_CACHEV)
+           printf (" write file \"%s\"\n", base);
+       if (!FcFileCacheWriteString (f, base))
+           goto bail1;
+       if (putc (' ', f) == EOF)
+           goto bail1;
+       if (!FcFileCacheWriteInt (f, id))
+           goto bail1;
+        if (putc (' ', f) == EOF)
+           goto bail1;
+       name = FcNameUnparse (font);
+       if (!name)
+           goto bail1;
+       ret = FcFileCacheWriteString (f, name);
+       free (name);
+       if (!ret)
+           goto bail1;
+       if (putc ('\n', f) == EOF)
+           goto bail1;
+    }
+    if (fclose (f) == EOF)
+       goto bail0;
+    
+    if (FcDebug () & FC_DBG_CACHE)
+       printf (" cache written\n");
+    return FcTrue;
+    
+bail1:
+    fclose (f);
+bail0:
+    unlink (cache_file);
+    return FcFalse;
+}
diff --git a/src/fccfg.c b/src/fccfg.c
new file mode 100644 (file)
index 0000000..0280ee1
--- /dev/null
@@ -0,0 +1,1369 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "fcint.h"
+
+static FcConfig    *fcConfig;
+
+FcConfig *
+FcConfigCreate (void)
+{
+    FcSetName  set;
+    FcConfig   *config;
+
+    config = malloc (sizeof (FcConfig));
+    if (!config)
+       goto bail0;
+    
+    config->dirs = malloc (sizeof (char *));
+    if (!config->dirs)
+       goto bail1;
+    config->dirs[0] = 0;
+    
+    config->configFiles = malloc (sizeof (char *));
+    if (!config->configFiles)
+       goto bail2;
+    config->configFiles[0] = 0;
+    
+    config->cache = 0;
+    if (!FcConfigSetCache (config, "~/" FC_USER_CACHE_FILE))
+       goto bail3;
+
+    config->blanks = 0;
+
+    config->substPattern = 0;
+    config->substFont = 0;
+    config->maxObjects = 0;
+    for (set = FcSetSystem; set <= FcSetApplication; set++)
+       config->fonts[set] = 0;
+    
+    return config;
+
+bail3:
+    free (config->configFiles);
+bail2:
+    free (config->dirs);
+bail1:
+    free (config);
+bail0:
+    return 0;
+}
+
+static void
+FcSubstDestroy (FcSubst *s)
+{
+    FcSubst *n;
+    
+    while (s)
+    {
+       n = s->next;
+       FcTestDestroy (s->test);
+       FcEditDestroy (s->edit);
+       s = n;
+    }
+}
+
+static void
+FcConfigDestroyStrings (char **strings)
+{
+    char    **s;
+
+    for (s = strings; s && *s; s++)
+       free (*s);
+    if (strings)
+       free (strings);
+}
+    
+static FcBool
+FcConfigAddString (char ***strings, char *string)
+{
+    int            n;
+    char    **s;
+    
+    n = 0;
+    for (s = *strings; s && *s; s++)
+       n++;
+    s = malloc ((n + 2) * sizeof (char *));
+    if (!s)
+       return FcFalse;
+    s[n] = string;
+    s[n+1] = 0;
+    memcpy (s, *strings, n * sizeof (char *));
+    free (*strings);
+    *strings = s;
+    return FcTrue;
+}
+
+void
+FcConfigDestroy (FcConfig *config)
+{
+    FcSetName  set;
+    FcConfigDestroyStrings (config->dirs);
+    FcConfigDestroyStrings (config->configFiles);
+
+    free (config->cache);
+
+    FcSubstDestroy (config->substPattern);
+    FcSubstDestroy (config->substFont);
+    for (set = FcSetSystem; set <= FcSetApplication; set++)
+       if (config->fonts[set])
+           FcFontSetDestroy (config->fonts[set]);
+}
+
+/*
+ * Scan the current list of directories in the configuration
+ * and build the set of available fonts. Update the
+ * per-user cache file to reflect the new configuration
+ */
+
+FcBool
+FcConfigBuildFonts (FcConfig *config)
+{
+    FcFontSet   *fonts;
+    FcFileCache *cache;
+    char       **d;
+
+    fonts = FcFontSetCreate ();
+    if (!fonts)
+       goto bail0;
+    
+    cache = FcFileCacheCreate ();
+    if (!cache)
+       goto bail1;
+
+    FcFileCacheLoad (cache, config->cache);
+
+    for (d = config->dirs; d && *d; d++)
+    {
+       if (FcDebug () & FC_DBG_FONTSET)
+           printf ("scan dir %s\n", *d);
+       FcDirScan (fonts, cache, config->blanks, *d, FcFalse);
+    }
+    
+    if (FcDebug () & FC_DBG_FONTSET)
+       FcFontSetPrint (fonts);
+
+    FcFileCacheSave (cache, config->cache);
+    FcFileCacheDestroy (cache);
+
+    FcConfigSetFonts (config, fonts, FcSetSystem);
+    
+    return FcTrue;
+bail1:
+    FcFontSetDestroy (fonts);
+bail0:
+    return FcFalse;
+}
+
+FcBool
+FcConfigSetCurrent (FcConfig *config)
+{
+    if (!config->fonts)
+       if (!FcConfigBuildFonts (config))
+           return FcFalse;
+
+    if (fcConfig)
+       FcConfigDestroy (fcConfig);
+    fcConfig = config;
+    return FcTrue;
+}
+
+FcConfig *
+FcConfigGetCurrent (void)
+{
+    return fcConfig;
+}
+
+FcBool
+FcConfigAddDir (FcConfig    *config,
+               const char  *d)
+{
+    char    *dir;
+    char    *h;
+
+    if (*d == '~')
+    {
+       h = getenv ("HOME");
+       if (!h)
+           return FcFalse;
+       dir = (char *) malloc (strlen (h) + strlen (d));
+       if (!dir)
+           return FcFalse;
+       strcpy (dir, h);
+       strcat (dir, d+1);
+    }
+    else
+    {
+       dir = (char *) malloc (strlen (d) + 1);
+       if (!dir)
+           return FcFalse;
+       strcpy (dir, d);
+    }
+    if (!FcConfigAddString (&config->dirs, dir))
+    {
+       free (dir);
+       return FcFalse;
+    }
+    return FcTrue;
+}
+
+char **
+FcConfigGetDirs (FcConfig   *config)
+{
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+    return config->dirs;
+}
+
+FcBool
+FcConfigAddConfigFile (FcConfig            *config,
+                      const char   *f)
+{
+    char    *file;
+    file = FcConfigFilename (f);
+    if (!file)
+       return FcFalse;
+    if (!FcConfigAddString (&config->configFiles, file))
+    {
+       free (file);
+       return FcFalse;
+    }
+    return FcTrue;
+}
+
+char **
+FcConfigGetConfigFiles (FcConfig    *config)
+{
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+    return config->configFiles;
+}
+
+FcBool
+FcConfigSetCache (FcConfig     *config,
+                 const char    *c)
+{
+    char    *new;
+    char    *h;
+
+    if (*c == '~')
+    {
+       h = getenv ("HOME");
+       if (!h)
+           return FcFalse;
+       new = (char *) malloc (strlen (h) + strlen (c));
+       if (!new)
+           return FcFalse;
+       strcpy (new, h);
+       strcat (new, c+1);
+    }
+    else
+    {
+       new = FcStrCopy (c);
+    }
+    if (config->cache)
+       free (config->cache);
+    config->cache = new;
+    return FcTrue;
+}
+
+char *
+FcConfigGetCache (FcConfig  *config)
+{
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+    return config->cache;
+}
+
+FcFontSet *
+FcConfigGetFonts (FcConfig     *config,
+                 FcSetName     set)
+{
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+    return config->fonts[set];
+}
+
+void
+FcConfigSetFonts (FcConfig     *config,
+                 FcFontSet     *fonts,
+                 FcSetName     set)
+{
+    if (config->fonts[set])
+       FcFontSetDestroy (config->fonts[set]);
+    config->fonts[set] = fonts;
+}
+
+FcBlanks *
+FcConfigGetBlanks (FcConfig    *config)
+{
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+    return config->blanks;
+}
+
+FcBool
+FcConfigAddBlank (FcConfig     *config,
+                 FcChar32      blank)
+{
+    FcBlanks   *b;
+    
+    b = config->blanks;
+    if (!b)
+    {
+       b = FcBlanksCreate ();
+       if (!b)
+           return FcFalse;
+    }
+    if (!FcBlanksAdd (b, blank))
+       return FcFalse;
+    config->blanks = b;
+    return FcTrue;
+}
+
+FcBool
+FcConfigAddEdit (FcConfig      *config,
+                FcTest         *test,
+                FcEdit         *edit,
+                FcMatchKind    kind)
+{
+    FcSubst    *subst, **prev;
+    FcTest     *t;
+    int                num;
+
+    subst = (FcSubst *) malloc (sizeof (FcSubst));
+    if (!subst)
+       return FcFalse;
+    if (kind == FcMatchPattern)
+       prev = &config->substPattern;
+    else
+       prev = &config->substFont;
+    for (; *prev; prev = &(*prev)->next);
+    *prev = subst;
+    subst->next = 0;
+    subst->test = test;
+    subst->edit = edit;
+    if (FcDebug () & FC_DBG_EDIT)
+    {
+       printf ("Add Subst ");
+       FcSubstPrint (subst);
+    }
+    num = 0;
+    for (t = test; t; t = t->next)
+       num++;
+    if (config->maxObjects < num)
+       config->maxObjects = num;
+    return FcTrue;
+}
+
+typedef struct _FcSubState {
+    FcPatternElt   *elt;
+    FcValueList    *value;
+} FcSubState;
+
+static const FcMatrix    FcIdentityMatrix = { 1, 0, 0, 1 };
+
+static FcValue
+FcConfigPromote (FcValue v, FcValue u)
+{
+    if (v.type == FcTypeInteger)
+    {
+       v.type = FcTypeDouble;
+       v.u.d = (double) v.u.i;
+    }
+    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
+    {
+       v.u.m = (FcMatrix *) &FcIdentityMatrix;
+       v.type = FcTypeMatrix;
+    }
+    return v;
+}
+
+FcBool
+FcConfigCompareValue (FcValue  m,
+                     FcOp      op,
+                     FcValue   v)
+{
+    FcBool    ret = FcFalse;
+    
+    m = FcConfigPromote (m, v);
+    v = FcConfigPromote (v, m);
+    if (m.type == v.type) 
+    {
+       ret = FcFalse;
+       switch (m.type) {
+       case FcTypeInteger:
+           break;      /* FcConfigPromote prevents this from happening */
+       case FcTypeDouble:
+           switch (op) {
+           case FcOpEqual:
+           case FcOpContains:
+               ret = m.u.d == v.u.d;
+               break;
+           case FcOpNotEqual:    
+               ret = m.u.d != v.u.d;
+               break;
+           case FcOpLess:    
+               ret = m.u.d < v.u.d;
+               break;
+           case FcOpLessEqual:    
+               ret = m.u.d <= v.u.d;
+               break;
+           case FcOpMore:    
+               ret = m.u.d > v.u.d;
+               break;
+           case FcOpMoreEqual:    
+               ret = m.u.d >= v.u.d;
+               break;
+           default:
+               break;
+           }
+           break;
+       case FcTypeBool:
+           switch (op) {
+           case FcOpEqual:    
+           case FcOpContains:
+               ret = m.u.b == v.u.b;
+               break;
+           case FcOpNotEqual:    
+               ret = m.u.b != v.u.b;
+               break;
+           default:
+               break;
+           }
+           break;
+       case FcTypeString:
+           switch (op) {
+           case FcOpEqual:    
+           case FcOpContains:
+               ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) == 0;
+               break;
+           case FcOpNotEqual:    
+               ret = FcStrCmpIgnoreCase (m.u.s, v.u.s) != 0;
+               break;
+           default:
+               break;
+           }
+           break;
+       case FcTypeMatrix:
+           switch (op) {
+           case FcOpEqual:
+           case FcOpContains:
+               ret = FcMatrixEqual (m.u.m, v.u.m);
+               break;
+           case FcOpNotEqual:
+               ret = !FcMatrixEqual (m.u.m, v.u.m);
+               break;
+           default:
+               break;
+           }
+           break;
+       case FcTypeCharSet:
+           switch (op) {
+           case FcOpContains:
+               /* m contains v if v - m is empty */
+               ret = FcCharSetSubtractCount (v.u.c, m.u.c) == 0;
+               break;
+           case FcOpEqual:
+               ret = FcCharSetEqual (m.u.c, v.u.c);
+               break;
+           case FcOpNotEqual:
+               ret = !FcCharSetEqual (m.u.c, v.u.c);
+               break;
+           default:
+               break;
+           }
+           break;
+       case FcTypeVoid:
+           switch (op) {
+           case FcOpEqual:
+           case FcOpContains:
+               ret = FcTrue;
+               break;
+           default:
+               break;
+           }
+           break;
+       }
+    }
+    else
+    {
+       if (op == FcOpNotEqual)
+           ret = FcTrue;
+    }
+    return ret;
+}
+
+
+static FcValue
+FcConfigEvaluate (FcPattern *p, FcExpr *e)
+{
+    FcValue    v, vl, vr;
+    FcResult   r;
+    FcMatrix   *m;
+    FcChar8    *s;
+    
+    switch (e->op) {
+    case FcOpInteger:
+       v.type = FcTypeInteger;
+       v.u.i = e->u.ival;
+       break;
+    case FcOpDouble:
+       v.type = FcTypeDouble;
+       v.u.d = e->u.dval;
+       break;
+    case FcOpString:
+       v.type = FcTypeString;
+       v.u.s = e->u.sval;
+       v = FcValueSave (v);
+       break;
+    case FcOpMatrix:
+       v.type = FcTypeMatrix;
+       v.u.m = e->u.mval;
+       v = FcValueSave (v);
+       break;
+    case FcOpCharSet:
+       v.type = FcTypeCharSet;
+       v.u.c = e->u.cval;
+       v = FcValueSave (v);
+       break;
+    case FcOpBool:
+       v.type = FcTypeBool;
+       v.u.b = e->u.bval;
+       break;
+    case FcOpField:
+       r = FcPatternGet (p, e->u.field, 0, &v);
+       if (r != FcResultMatch)
+           v.type = FcTypeVoid;
+       break;
+    case FcOpConst:
+       if (FcNameConstant (e->u.constant, &v.u.i))
+           v.type = FcTypeInteger;
+       else
+           v.type = FcTypeVoid;
+       break;
+    case FcOpQuest:
+       vl = FcConfigEvaluate (p, e->u.tree.left);
+       if (vl.type == FcTypeBool)
+       {
+           if (vl.u.b)
+               v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
+           else
+               v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
+       }
+       else
+           v.type = FcTypeVoid;
+       FcValueDestroy (vl);
+       break;
+    case FcOpOr:
+    case FcOpAnd:
+    case FcOpEqual:
+    case FcOpContains:
+    case FcOpNotEqual:
+    case FcOpLess:
+    case FcOpLessEqual:
+    case FcOpMore:
+    case FcOpMoreEqual:
+    case FcOpPlus:
+    case FcOpMinus:
+    case FcOpTimes:
+    case FcOpDivide:
+       vl = FcConfigEvaluate (p, e->u.tree.left);
+       vr = FcConfigEvaluate (p, e->u.tree.right);
+       vl = FcConfigPromote (vl, vr);
+       vr = FcConfigPromote (vr, vl);
+       if (vl.type == vr.type)
+       {
+           switch (vl.type) {
+           case FcTypeDouble:
+               switch (e->op) {
+               case FcOpPlus:     
+                   v.type = FcTypeDouble;
+                   v.u.d = vl.u.d + vr.u.d; 
+                   break;
+               case FcOpMinus:
+                   v.type = FcTypeDouble;
+                   v.u.d = vl.u.d - vr.u.d; 
+                   break;
+               case FcOpTimes:
+                   v.type = FcTypeDouble;
+                   v.u.d = vl.u.d * vr.u.d; 
+                   break;
+               case FcOpDivide:
+                   v.type = FcTypeDouble;
+                   v.u.d = vl.u.d / vr.u.d; 
+                   break;
+               case FcOpEqual:
+               case FcOpContains:
+                   v.type = FcTypeBool; 
+                   v.u.b = vl.u.d == vr.u.d;
+                   break;
+               case FcOpNotEqual:    
+                   v.type = FcTypeBool; 
+                   v.u.b = vl.u.d != vr.u.d;
+                   break;
+               case FcOpLess:    
+                   v.type = FcTypeBool; 
+                   v.u.b = vl.u.d < vr.u.d;
+                   break;
+               case FcOpLessEqual:    
+                   v.type = FcTypeBool; 
+                   v.u.b = vl.u.d <= vr.u.d;
+                   break;
+               case FcOpMore:    
+                   v.type = FcTypeBool; 
+                   v.u.b = vl.u.d > vr.u.d;
+                   break;
+               case FcOpMoreEqual:    
+                   v.type = FcTypeBool; 
+                   v.u.b = vl.u.d >= vr.u.d;
+                   break;
+               default:
+                   v.type = FcTypeVoid; 
+                   break;
+               }
+               if (v.type == FcTypeDouble &&
+                   v.u.d == (double) (int) v.u.d)
+               {
+                   v.type = FcTypeInteger;
+                   v.u.i = (int) v.u.d;
+               }
+               break;
+           case FcTypeBool:
+               switch (e->op) {
+               case FcOpOr:
+                   v.type = FcTypeBool;
+                   v.u.b = vl.u.b || vr.u.b;
+                   break;
+               case FcOpAnd:
+                   v.type = FcTypeBool;
+                   v.u.b = vl.u.b && vr.u.b;
+                   break;
+               case FcOpEqual:
+               case FcOpContains:
+                   v.type = FcTypeBool;
+                   v.u.b = vl.u.b == vr.u.b;
+                   break;
+               case FcOpNotEqual:
+                   v.type = FcTypeBool;
+                   v.u.b = vl.u.b != vr.u.b;
+                   break;
+               default:
+                   v.type = FcTypeVoid; 
+                   break;
+               }
+               break;
+           case FcTypeString:
+               switch (e->op) {
+               case FcOpEqual:
+               case FcOpContains:
+                   v.type = FcTypeBool;
+                   v.u.b = FcStrCmpIgnoreCase (vl.u.s, vr.u.s) == 0;
+                   break;
+               case FcOpNotEqual:
+                   v.type = FcTypeBool;
+                   v.u.b = FcStrCmpIgnoreCase (vl.u.s, vr.u.s) != 0;
+                   break;
+               case FcOpPlus:
+                   v.type = FcTypeString;
+                   v.u.s = FcStrPlus (vl.u.s, vr.u.s);
+                   if (!v.u.s)
+                       v.type = FcTypeVoid;
+                   break;
+               default:
+                   v.type = FcTypeVoid;
+                   break;
+               }
+           case FcTypeMatrix:
+               switch (e->op) {
+               case FcOpEqual:
+               case FcOpContains:
+                   v.type = FcTypeBool;
+                   v.u.b = FcMatrixEqual (vl.u.m, vr.u.m);
+                   break;
+               case FcOpNotEqual:
+                   v.type = FcTypeBool;
+                   v.u.b = FcMatrixEqual (vl.u.m, vr.u.m);
+                   break;
+               case FcOpTimes:
+                   v.type = FcTypeMatrix;
+                   m = malloc (sizeof (FcMatrix));
+                   if (m)
+                   {
+                       FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
+                       FcMatrixMultiply (m, vl.u.m, vr.u.m);
+                       v.u.m = m;
+                   }
+                   else
+                   {
+                       v.type = FcTypeVoid;
+                   }
+                   break;
+               default:
+                   v.type = FcTypeVoid;
+                   break;
+               }
+               break;
+           case FcTypeCharSet:
+               switch (e->op) {
+               case FcOpContains:
+                   /* vl contains vr if vr - vl is empty */
+                   v.type = FcTypeBool;
+                   v.u.b = FcCharSetSubtractCount (vr.u.c, vl.u.c) == 0;
+                   break;
+               case FcOpEqual:
+                   v.type = FcTypeBool;
+                   v.u.b = FcCharSetEqual (vl.u.c, vr.u.c);
+                   break;
+               case FcOpNotEqual:
+                   v.type = FcTypeBool;
+                   v.u.b = !FcCharSetEqual (vl.u.c, vr.u.c);
+                   break;
+               default:
+                   v.type = FcTypeVoid;
+                   break;
+               }
+               break;
+           default:
+               v.type = FcTypeVoid;
+               break;
+           }
+       }
+       else
+           v.type = FcTypeVoid;
+       FcValueDestroy (vl);
+       FcValueDestroy (vr);
+       break;
+    case FcOpNot:
+       vl = FcConfigEvaluate (p, e->u.tree.left);
+       switch (vl.type) {
+       case FcTypeBool:
+           v.type = FcTypeBool;
+           v.u.b = !vl.u.b;
+           break;
+       default:
+           v.type = FcTypeVoid;
+           break;
+       }
+       FcValueDestroy (vl);
+       break;
+    default:
+       v.type = FcTypeVoid;
+       break;
+    }
+    return v;
+}
+
+static FcValueList *
+FcConfigMatchValueList (FcPattern      *p,
+                       FcTest          *t,
+                       FcValueList     *v)
+{
+    FcValueList    *ret = 0;
+    FcValue        value = FcConfigEvaluate (p, t->expr);
+    
+    for (; v; v = v->next)
+    {
+       if (FcConfigCompareValue (v->value, t->op, value))
+       {
+           if (!ret)
+               ret = v;
+       }
+       else
+       {
+           if (t->qual == FcQualAll)
+           {
+               ret = 0;
+               break;
+           }
+       }
+    }
+    FcValueDestroy (value);
+    return ret;
+}
+
+static FcValueList *
+FcConfigValues (FcPattern *p, FcExpr *e)
+{
+    FcValueList        *l;
+    
+    if (!e)
+       return 0;
+    l = (FcValueList *) malloc (sizeof (FcValueList));
+    if (!l)
+       return 0;
+    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
+    if (e->op == FcOpComma)
+    {
+       l->value = FcConfigEvaluate (p, e->u.tree.left);
+       l->next  = FcConfigValues (p, e->u.tree.right);
+    }
+    else
+    {
+       l->value = FcConfigEvaluate (p, e);
+       l->next  = 0;
+    }
+    while (l->value.type == FcTypeVoid)
+    {
+       FcValueList     *next = l->next;
+       
+       FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
+       free (l);
+       l = next;
+    }
+    return l;
+}
+
+static FcBool
+FcConfigAdd (FcValueList    **head,
+            FcValueList    *position,
+            FcBool         append,
+            FcValueList    *new)
+{
+    FcValueList    **prev, *last;
+    
+    if (append)
+    {
+       if (position)
+           prev = &position->next;
+       else
+           for (prev = head; *prev; prev = &(*prev)->next)
+               ;
+    }
+    else
+    {
+       if (position)
+       {
+           for (prev = head; *prev; prev = &(*prev)->next)
+           {
+               if (*prev == position)
+                   break;
+           }
+       }
+       else
+           prev = head;
+
+       if (FcDebug () & FC_DBG_EDIT)
+       {
+           if (!*prev)
+               printf ("position not on list\n");
+       }
+    }
+
+    if (FcDebug () & FC_DBG_EDIT)
+    {
+       printf ("%s list before ", append ? "Append" : "Prepend");
+       FcValueListPrint (*head);
+       printf ("\n");
+    }
+    
+    if (new)
+    {
+       last = new;
+       while (last->next)
+           last = last->next;
+    
+       last->next = *prev;
+       *prev = new;
+    }
+    
+    if (FcDebug () & FC_DBG_EDIT)
+    {
+       printf ("%s list after ", append ? "Append" : "Prepend");
+       FcValueListPrint (*head);
+       printf ("\n");
+    }
+    
+    return FcTrue;
+}
+
+static void
+FcConfigDel (FcValueList    **head,
+            FcValueList    *position)
+{
+    FcValueList    **prev;
+
+    for (prev = head; *prev; prev = &(*prev)->next)
+    {
+       if (*prev == position)
+       {
+           *prev = position->next;
+           position->next = 0;
+           FcValueListDestroy (position);
+           break;
+       }
+    }
+}
+
+static void
+FcConfigPatternAdd (FcPattern  *p,
+                   const char  *object,
+                   FcValueList *list,
+                   FcBool      append)
+{
+    if (list)
+    {
+       FcPatternElt    *e = FcPatternFind (p, object, FcTrue);
+    
+       if (!e)
+           return;
+       FcConfigAdd (&e->values, 0, append, list);
+    }
+}
+
+/*
+ * Delete all values associated with a field
+ */
+static void
+FcConfigPatternDel (FcPattern  *p,
+                   const char  *object)
+{
+    FcPatternElt    *e = FcPatternFind (p, object, FcFalse);
+    if (!e)
+       return;
+    while (e->values)
+       FcConfigDel (&e->values, e->values);
+}
+
+static void
+FcConfigPatternCanon (FcPattern            *p,
+                     const char    *object)
+{
+    FcPatternElt    *e = FcPatternFind (p, object, FcFalse);
+    if (!e)
+       return;
+    if (!e->values)
+       FcPatternDel (p, object);
+}
+
+FcBool
+FcConfigSubstitute (FcConfig   *config,
+                   FcPattern   *p,
+                   FcMatchKind kind)
+{
+    FcSubst        *s;
+    FcSubState     *st;
+    int                    i;
+    FcTest         *t;
+    FcEdit         *e;
+    FcValueList            *l;
+
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return FcFalse;
+    }
+
+    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
+    if (!st && config->maxObjects)
+       return FcFalse;
+    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
+
+    if (FcDebug () & FC_DBG_EDIT)
+    {
+       printf ("FcConfigSubstitute ");
+       FcPatternPrint (p);
+    }
+    if (kind == FcMatchPattern)
+       s = config->substPattern;
+    else
+       s = config->substFont;
+    for (; s; s = s->next)
+    {
+       /*
+        * Check the tests to see if
+        * they all match the pattern
+        */
+       for (t = s->test, i = 0; t; t = t->next, i++)
+       {
+           if (FcDebug () & FC_DBG_EDIT)
+           {
+               printf ("FcConfigSubstitute test ");
+               FcTestPrint (t);
+           }
+           st[i].elt = FcPatternFind (p, t->field, FcFalse);
+           /*
+            * If there's no such field in the font,
+            * then FcQualAll matches while FcQualAny does not
+            */
+           if (!st[i].elt)
+           {
+               if (t->qual == FcQualAll)
+               {
+                   st[i].value = 0;
+                   continue;
+               }
+               else
+                   break;
+           }
+           /*
+            * Check to see if there is a match, mark the location
+            * to apply match-relative edits
+            */
+           st[i].value = FcConfigMatchValueList (p, t, st[i].elt->values);
+           if (!st[i].value)
+               break;
+       }
+       if (t)
+       {
+           if (FcDebug () & FC_DBG_EDIT)
+               printf ("No match\n");
+           continue;
+       }
+       if (FcDebug () & FC_DBG_EDIT)
+       {
+           printf ("Substitute ");
+           FcSubstPrint (s);
+       }
+       for (e = s->edit; e; e = e->next)
+       {
+           /*
+            * Evaluate the list of expressions
+            */
+           l = FcConfigValues (p, e->expr);
+           /*
+            * Locate any test associated with this field
+            */
+           for (t = s->test, i = 0; t; t = t->next, i++)
+               if (!FcStrCmpIgnoreCase (t->field, e->field))
+                   break;
+           switch (e->op) {
+           case FcOpAssign:
+               /*
+                * If there was a test, then replace the matched
+                * value with the new list of values
+                */
+               if (t)
+               {
+                   FcValueList *thisValue = st[i].value;
+                   FcValueList *nextValue = thisValue ? thisValue->next : 0;
+                   
+                   /*
+                    * Append the new list of values after the current value
+                    */
+                   FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
+                   /*
+                    * Adjust any pointers into the value list to ensure
+                    * future edits occur at the same place
+                    */
+                   for (t = s->test, i = 0; t; t = t->next, i++)
+                   {
+                       if (st[i].value == thisValue)
+                           st[i].value = nextValue;
+                   }
+                   /*
+                    * Delete the marked value
+                    */
+                   FcConfigDel (&st[i].elt->values, thisValue);
+                   break;
+               }
+               /* fall through ... */
+           case FcOpAssignReplace:
+               /*
+                * Delete all of the values and insert
+                * the new set
+                */
+               FcConfigPatternDel (p, e->field);
+               FcConfigPatternAdd (p, e->field, l, FcTrue);
+               /*
+                * Adjust any pointers into the value list as they no
+                * longer point to anything valid
+                */
+               if (t)
+               {
+                   FcPatternElt    *thisElt = st[i].elt;
+                   for (t = s->test, i = 0; t; t = t->next, i++)
+                   {
+                       if (st[i].elt == thisElt)
+                           st[i].value = 0;
+                   }
+               }
+               break;
+           case FcOpPrepend:
+               if (t)
+               {
+                   FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
+                   break;
+               }
+               /* fall through ... */
+           case FcOpPrependFirst:
+               FcConfigPatternAdd (p, e->field, l, FcFalse);
+               break;
+           case FcOpAppend:
+               if (t)
+               {
+                   FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
+                   break;
+               }
+               /* fall through ... */
+           case FcOpAppendLast:
+               FcConfigPatternAdd (p, e->field, l, FcTrue);
+               break;
+           default:
+               break;
+           }
+       }
+       /*
+        * Now go through the pattern and eliminate
+        * any properties without data
+        */
+       for (e = s->edit; e; e = e->next)
+           FcConfigPatternCanon (p, e->field);
+
+       if (FcDebug () & FC_DBG_EDIT)
+       {
+           printf ("FcConfigSubstitute edit");
+           FcPatternPrint (p);
+       }
+    }
+    FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
+    free (st);
+    if (FcDebug () & FC_DBG_EDIT)
+    {
+       printf ("FcConfigSubstitute done");
+       FcPatternPrint (p);
+    }
+    return FcTrue;
+}
+
+#ifndef FONTCONFIG_PATH
+#define FONTCONFIG_PATH        "/etc/fonts"
+#endif
+
+#ifndef FONTCONFIG_FILE
+#define FONTCONFIG_FILE        "fonts.conf"
+#endif
+
+static char *
+FcConfigFileExists (const char *dir, const char *file)
+{
+    char    *path;
+
+    if (!dir)
+       dir = "";
+    path = malloc (strlen (dir) + 1 + strlen (file) + 1);
+    if (!path)
+       return 0;
+
+    strcpy (path, dir);
+    /* make sure there's a single separating / */
+    if ((!path[0] || path[strlen(path)-1] != '/') && file[0] != '/')
+       strcat (path, "/");
+    strcat (path, file);
+
+    if (access (path, R_OK) == 0)
+       return path;
+    
+    free (path);
+    return 0;
+}
+
+static char **
+FcConfigGetPath (void)
+{
+    char    **path;
+    char    *env, *e, *colon;
+    char    *dir;
+    int            npath;
+    int            i;
+
+    npath = 2; /* default dir + null */
+    env = getenv ("FONTCONFIG_PATH");
+    if (env)
+    {
+       e = env;
+       npath++;
+       while (*e)
+           if (*e++ == ':')
+               npath++;
+    }
+    path = calloc (npath, sizeof (char *));
+    if (!path)
+       goto bail0;
+    i = 0;
+
+    if (env)
+    {
+       e = env;
+       while (*e) 
+       {
+           colon = strchr (e, ':');
+           if (!colon)
+               colon = e + strlen (e);
+           path[i] = malloc (colon - e + 1);
+           if (!path[i])
+               goto bail1;
+           strncpy (path[i], e, colon - e);
+           path[i][colon - e] = '\0';
+           if (*colon)
+               e = colon + 1;
+           else
+               e = colon;
+           i++;
+       }
+    }
+    
+    dir = FONTCONFIG_PATH;
+    path[i] = malloc (strlen (dir) + 1);
+    if (!path[i])
+       goto bail1;
+    strcpy (path[i], dir);
+    return path;
+
+bail1:
+    for (i = 0; path[i]; i++)
+       free (path[i]);
+    free (path);
+bail0:
+    return 0;
+}
+
+static void
+FcConfigFreePath (char **path)
+{
+    char    **p;
+
+    for (p = path; *p; p++)
+       free (*p);
+    free (path);
+}
+
+char *
+FcConfigFilename (const char *url)
+{
+    char    *file, *dir, **path, **p;
+    
+    if (!url || !*url)
+    {
+       url = getenv ("FONTCONFIG_FILE");
+       if (!url)
+           url = FONTCONFIG_FILE;
+    }
+    switch (*url) {
+    case '~':
+       dir = getenv ("HOME");
+       if (dir)
+           file = FcConfigFileExists (dir, url + 1);
+       else
+           file = 0;
+       break;
+    case '/':
+       file = FcConfigFileExists (0, url);
+       break;
+    default:
+       path = FcConfigGetPath ();
+       if (!path)
+           return 0;
+       for (p = path; *p; p++)
+       {
+           file = FcConfigFileExists (*p, url);
+           if (file)
+               break;
+       }
+       FcConfigFreePath (path);
+       break;
+    }
+    return file;
+}
+
+/*
+ * Manage the application-specific fonts
+ */
+
+FcBool
+FcConfigAppFontAddFile (FcConfig    *config,
+                       const char  *file)
+{
+    FcFontSet  *set;
+
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return FcFalse;
+    }
+
+    set = FcConfigGetFonts (config, FcSetApplication);
+    if (!set)
+    {
+       set = FcFontSetCreate ();
+       if (!set)
+           return FcFalse;
+       FcConfigSetFonts (config, set, FcSetApplication);
+    }
+    return FcFileScan (set, 0, config->blanks, file, FcFalse);
+}
+
+FcBool
+FcConfigAppFontAddDir (FcConfig            *config,
+                      const char   *dir)
+{
+    FcFontSet  *set;
+    
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return FcFalse;
+    }
+    set = FcConfigGetFonts (config, FcSetApplication);
+    if (!set)
+    {
+       set = FcFontSetCreate ();
+       if (!set)
+           return FcFalse;
+       FcConfigSetFonts (config, set, FcSetApplication);
+    }
+    return FcDirScan (set, 0, config->blanks, dir, FcFalse);
+}
+
+void
+FcConfigAppFontClear (FcConfig     *config)
+{
+    FcConfigSetFonts (config, 0, FcSetApplication);
+}
diff --git a/src/fccharset.c b/src/fccharset.c
new file mode 100644 (file)
index 0000000..b29a48a
--- /dev/null
@@ -0,0 +1,1521 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+/* #define CHECK */
+
+static int
+FcCharSetLevels (FcChar32 ucs4)
+{
+    if (ucs4 <= 0xff)
+       return 1;
+    if (ucs4 <= 0xffff)
+       return 2;
+    if (ucs4 <= 0xffffff)
+       return 3;
+    return 4;
+}
+
+static FcBool
+FcCharSetCheckLevel (FcCharSet *fcs, FcChar32 ucs4)
+{
+    int        level = FcCharSetLevels (ucs4);
+    
+    if (level <= fcs->levels)
+       return FcTrue;
+    while (fcs->levels < level)
+    {
+       if (fcs->levels == 0)
+       {
+           FcCharLeaf      *leaf;
+
+           leaf = (FcCharLeaf *) calloc (1, sizeof (FcCharLeaf));
+           if (!leaf)
+               return FcFalse;
+           FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharLeaf));
+           fcs->node.leaf = leaf;
+       }
+       else
+       {
+           FcCharBranch    *branch;
+    
+           branch = (FcCharBranch *) calloc (1, sizeof (FcCharBranch));
+           if (!branch)
+               return FcFalse;
+           FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharBranch));
+           branch->nodes[0] = fcs->node;
+           fcs->node.branch = branch;
+       }
+       ++fcs->levels;
+    }
+    return FcTrue;
+}
+
+FcCharSet *
+FcCharSetCreate (void)
+{
+    FcCharSet  *fcs;
+
+    fcs = (FcCharSet *) malloc (sizeof (FcCharSet));
+    if (!fcs)
+       return 0;
+    FcMemAlloc (FC_MEM_CHARSET, sizeof (FcCharSet));
+    fcs->ref = 1;
+    fcs->levels = 0;
+    fcs->node.leaf = 0;
+    fcs->constant = FcFalse;
+    return fcs;
+}
+
+FcCharSet *
+FcCharSetNew (void);
+    
+FcCharSet *
+FcCharSetNew (void)
+{
+    return FcCharSetCreate ();
+}
+
+static void
+FcCharNodeDestroy (FcCharNode node, int level)
+{
+    int        i;
+
+    switch (level) {
+    case 0:
+       break;
+    case 1:
+       FcMemFree (FC_MEM_CHARNODE, sizeof (FcCharLeaf));
+       free (node.leaf);
+       break;
+    default:
+       for (i = 0; i < 256; i++)
+           if (node.branch->nodes[i].branch)
+               FcCharNodeDestroy (node.branch->nodes[i], level - 1);
+        FcMemFree (FC_MEM_CHARNODE, sizeof (FcCharBranch));
+       free (node.branch);
+    }
+}
+
+void
+FcCharSetDestroy (FcCharSet *fcs)
+{
+    if (fcs->constant)
+       return;
+    if (--fcs->ref <= 0)
+    {
+       FcCharNodeDestroy (fcs->node, fcs->levels);
+       FcMemFree (FC_MEM_CHARSET, sizeof (FcCharSet));
+       free (fcs);
+    }
+}
+
+/*
+ * Locate the leaf containing the specified char, returning
+ * null if it doesn't exist
+ */
+
+static FcCharLeaf *
+FcCharSetFindLeaf (const FcCharSet *fcs, FcChar32 ucs4)
+{
+    int                        l;
+    const FcCharNode   *prev;
+    FcCharNode         node;
+    FcChar8            i;
+
+    prev = &fcs->node;
+    l = fcs->levels;
+    while (--l > 0)
+    {
+       node = *prev;
+       if (!node.branch)
+           return 0;
+       i = (ucs4 >> (l << 3)) & 0xff;
+       prev = &node.branch->nodes[i];
+    }
+    return prev->leaf;
+}
+
+/*
+ * Locate the leaf containing the specified char, creating it
+ * if desired
+ */
+
+static FcCharLeaf *
+FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4)
+{
+    int                l;
+    FcCharNode  *prev, node;
+    FcChar8    i;
+
+    if (!FcCharSetCheckLevel (fcs, ucs4))
+       return FcFalse;
+    prev = &fcs->node;
+    l = fcs->levels;
+    while (--l > 0)
+    {
+       node = *prev;
+       if (!node.branch)
+       {
+           node.branch = calloc (1, sizeof (FcCharBranch));
+           if (!node.branch)
+               return 0;
+           FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharBranch));
+           *prev = node;
+       }
+       i = (ucs4 >> (l << 3)) & 0xff;
+       prev = &node.branch->nodes[i];
+    }
+    node = *prev;
+    if (!node.leaf)
+    {
+       node.leaf = calloc (1, sizeof (FcCharLeaf));
+       if (!node.leaf)
+           return 0;
+       FcMemAlloc (FC_MEM_CHARNODE, sizeof (FcCharLeaf));
+       *prev = node;
+    }
+    return node.leaf;
+}
+
+FcBool
+FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
+{
+    FcCharLeaf *leaf;
+    FcChar32   *b;
+    
+    if (fcs->constant)
+       return FcFalse;
+    leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+    if (!leaf)
+       return FcFalse;
+    b = &leaf->map[(ucs4 & 0xff) >> 5];
+    *b |= (1 << (ucs4 & 0x1f));
+    return FcTrue;
+}
+
+/*
+ * An iterator for the leaves of a charset
+ */
+
+typedef struct _fcCharSetIter {
+    FcCharLeaf     *leaf;
+    FcChar32       ucs4;
+} FcCharSetIter;
+
+/*
+ * Find the nearest leaf at or beyond *ucs4, return 0 if no leaf
+ * exists
+ */
+static FcCharLeaf *
+FcCharSetIterLeaf (FcCharNode node, int level, FcChar32 *ucs4)
+{
+    if (level <= 1)
+        return node.leaf;
+    else if (!node.branch)
+       return 0;
+    else
+    {
+       int         shift = ((level - 1) << 3);
+       FcChar32    inc = 1 << shift;
+       FcChar32    mask = ~(inc - 1);
+       FcChar8     byte = (*ucs4 >> shift) & 0xff;
+       FcCharLeaf  *leaf;
+
+       for (;;)
+       {
+           leaf = FcCharSetIterLeaf (node.branch->nodes[byte], 
+                                     level - 1, 
+                                     ucs4);
+           if (leaf)
+               break;
+           /* step to next branch, resetting lower indices */
+           *ucs4 = (*ucs4 & mask) + inc;
+           byte++;
+           if (byte == 0)
+               break;
+       }
+       return leaf;
+    }
+}
+
+static void
+FcCharSetIterSet (const FcCharSet *fcs, FcCharSetIter *iter)
+{
+    if (FcCharSetLevels (iter->ucs4) > fcs->levels)
+       iter->leaf = 0;
+    else
+       iter->leaf = FcCharSetIterLeaf (fcs->node, fcs->levels,
+                                       &iter->ucs4);
+    if (!iter->leaf)
+       iter->ucs4 = ~0;
+}
+
+static void
+FcCharSetIterNext (const FcCharSet *fcs, FcCharSetIter *iter)
+{
+    iter->ucs4 += 0x100;
+    FcCharSetIterSet (fcs, iter);
+}
+
+static void
+FcCharSetIterStart (const FcCharSet *fcs, FcCharSetIter *iter)
+{
+    iter->ucs4 = 0;
+    FcCharSetIterSet (fcs, iter);
+}
+
+FcCharSet *
+FcCharSetCopy (FcCharSet *src)
+{
+    src->ref++;
+    return src;
+}
+
+FcBool
+FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
+{
+    FcCharSetIter   ai, bi;
+    int                    i;
+    
+    if (a == b)
+       return FcTrue;
+    for (FcCharSetIterStart (a, &ai), FcCharSetIterStart (b, &bi);
+        ai.leaf && bi.leaf;
+        FcCharSetIterNext (a, &ai), FcCharSetIterNext (b, &bi))
+    {
+       if (ai.ucs4 != bi.ucs4)
+           return FcFalse;
+       for (i = 0; i < 256/32; i++)
+           if (ai.leaf->map[i] != bi.leaf->map[i])
+               return FcFalse;
+    }
+    return ai.leaf == bi.leaf;
+}
+
+static FcBool
+FcCharSetAddLeaf (FcCharSet    *fcs,
+                 FcChar32      ucs4,
+                 FcCharLeaf    *leaf)
+{
+    FcCharLeaf   *new = FcCharSetFindLeafCreate (fcs, ucs4);
+    if (!new)
+       return FcFalse;
+    *new = *leaf;
+    return FcTrue;
+}
+
+static FcCharSet *
+FcCharSetOperate (const FcCharSet   *a,
+                 const FcCharSet   *b,
+                 FcBool            (*overlap) (FcCharLeaf          *result,
+                                               const FcCharLeaf    *al,
+                                               const FcCharLeaf    *bl),
+                 FcBool        aonly,
+                 FcBool        bonly)
+{
+    FcCharSet      *fcs;
+    FcCharSetIter   ai, bi;
+
+    fcs = FcCharSetCreate ();
+    if (!fcs)
+       goto bail0;
+    FcCharSetIterStart (a, &ai);
+    FcCharSetIterStart (b, &bi);
+    while ((ai.leaf || bonly) && (bi.leaf || aonly))
+    {
+       if (ai.ucs4 < bi.ucs4)
+       {
+           if (aonly)
+           {
+               if (!FcCharSetAddLeaf (fcs, ai.ucs4, ai.leaf))
+                   goto bail1;
+               FcCharSetIterNext (a, &ai);
+           }
+           else
+           {
+               ai.ucs4 = bi.ucs4;
+               FcCharSetIterSet (a, &ai);
+           }
+       }
+       else if (bi.ucs4 < ai.ucs4 )
+       {
+           if (bonly)
+           {
+               if (!FcCharSetAddLeaf (fcs, bi.ucs4, bi.leaf))
+                   goto bail1;
+               FcCharSetIterNext (b, &bi);
+           }
+           else
+           {
+               bi.ucs4 = ai.ucs4;
+               FcCharSetIterSet (b, &bi);
+           }
+       }
+       else
+       {
+           FcCharLeaf  leaf;
+
+           if ((*overlap) (&leaf, ai.leaf, bi.leaf))
+           {
+               if (!FcCharSetAddLeaf (fcs, ai.ucs4, &leaf))
+                   goto bail1;
+           }
+           FcCharSetIterNext (a, &ai);
+           FcCharSetIterNext (b, &bi);
+       }
+    }
+    return fcs;
+bail1:
+    FcCharSetDestroy (fcs);
+bail0:
+    return 0;
+}
+
+static FcBool
+FcCharSetIntersectLeaf (FcCharLeaf *result,
+                       const FcCharLeaf *al,
+                       const FcCharLeaf *bl)
+{
+    int            i;
+    FcBool  nonempty = FcFalse;
+
+    for (i = 0; i < 256/32; i++)
+       if ((result->map[i] = al->map[i] & bl->map[i]))
+           nonempty = FcTrue;
+    return nonempty;
+}
+
+FcCharSet *
+FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
+{
+    return FcCharSetOperate (a, b, FcCharSetIntersectLeaf, FcFalse, FcFalse);
+}
+
+static FcBool
+FcCharSetUnionLeaf (FcCharLeaf *result,
+                   const FcCharLeaf *al,
+                   const FcCharLeaf *bl)
+{
+    int        i;
+
+    for (i = 0; i < 256/32; i++)
+       result->map[i] = al->map[i] | bl->map[i];
+    return FcTrue;
+}
+
+FcCharSet *
+FcCharSetUnion (const FcCharSet *a, const FcCharSet *b)
+{
+    return FcCharSetOperate (a, b, FcCharSetUnionLeaf, FcTrue, FcTrue);
+}
+
+static FcBool
+FcCharSetSubtractLeaf (FcCharLeaf *result,
+                      const FcCharLeaf *al,
+                      const FcCharLeaf *bl)
+{
+    int            i;
+    FcBool  nonempty = FcFalse;
+
+    for (i = 0; i < 256/32; i++)
+       if ((result->map[i] = al->map[i] & ~bl->map[i]))
+           nonempty = FcTrue;
+    return nonempty;
+}
+
+FcCharSet *
+FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
+{
+    return FcCharSetOperate (a, b, FcCharSetSubtractLeaf, FcTrue, FcFalse);
+}
+
+FcBool
+FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
+{
+    FcCharLeaf *leaf = FcCharSetFindLeaf (fcs, ucs4);
+    if (!leaf)
+       return FcFalse;
+    return (leaf->map[(ucs4 & 0xff) >> 5] & (1 << (ucs4 & 0x1f))) != 0;
+}
+
+static FcChar32
+FcCharSetPopCount (FcChar32 c1)
+{
+    /* hackmem 169 */
+    FcChar32   c2 = (c1 >> 1) & 033333333333;
+    c2 = c1 - c2 - ((c2 >> 1) & 033333333333);
+    return (((c2 + (c2 >> 3)) & 030707070707) % 077);
+}
+
+FcChar32
+FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
+{
+    FcCharSetIter   ai, bi;
+    FcChar32       count = 0;
+    
+    FcCharSetIterStart (a, &ai);
+    FcCharSetIterStart (b, &bi);
+    while (ai.leaf && bi.leaf)
+    {
+       if (ai.ucs4 == bi.ucs4)
+       {
+           FcChar32    *am = ai.leaf->map;
+           FcChar32    *bm = bi.leaf->map;
+           int         i = 256/32;
+           while (i--)
+               count += FcCharSetPopCount (*am++ & *bm++);
+           FcCharSetIterNext (a, &ai);
+       } 
+       else if (ai.ucs4 < bi.ucs4)
+       {
+           ai.ucs4 = bi.ucs4;
+           FcCharSetIterSet (a, &ai);
+       }
+       if (bi.ucs4 < ai.ucs4)
+       {
+           bi.ucs4 = ai.ucs4;
+           FcCharSetIterSet (b, &bi);
+       }
+    }
+    return count;
+}
+
+FcChar32
+FcCharSetCount (const FcCharSet *a)
+{
+    FcCharSetIter   ai;
+    FcChar32       count = 0;
+    
+    for (FcCharSetIterStart (a, &ai); ai.leaf; FcCharSetIterNext (a, &ai))
+    {
+       int                 i = 256/32;
+       FcChar32            *am = ai.leaf->map;
+
+       while (i--)
+           count += FcCharSetPopCount (*am++);
+    }
+    return count;
+}
+
+FcChar32
+FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
+{
+    FcCharSetIter   ai, bi;
+    FcChar32       count = 0;
+    
+    FcCharSetIterStart (a, &ai);
+    FcCharSetIterStart (b, &bi);
+    while (ai.leaf)
+    {
+       if (ai.ucs4 <= bi.ucs4)
+       {
+           FcChar32    *am = ai.leaf->map;
+           int         i = 256/32;
+           if (ai.ucs4 == bi.ucs4)
+           {
+               FcChar32        *bm = bi.leaf->map;;
+               while (i--)
+                   count += FcCharSetPopCount (*am++ & ~*bm++);
+           }
+           else
+           {
+               while (i--)
+                   count += FcCharSetPopCount (*am++);
+           }
+           FcCharSetIterNext (a, &ai);
+       }
+       else if (bi.leaf)
+       {
+           bi.ucs4 = ai.ucs4;
+           FcCharSetIterSet (b, &bi);
+       }
+    }
+    return count;
+}
+
+/*
+ * ASCII representation of charsets.
+ * 
+ * Each leaf is represented as 9 32-bit values, the code of the first character followed
+ * by 8 32 bit values for the leaf itself.  Each value is encoded as 5 ASCII characters,
+ * only 85 different values are used to avoid control characters as well as the other
+ * characters used to encode font names.  85**5 > 2^32 so things work out, but
+ * it's not exactly human readable output.  As a special case, 0 is encoded as a space
+ */
+
+static FcChar8 charToValue[256] = {
+    /*     "" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /*   "\b" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\020" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\030" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /*    " " */ 0xff,  0x00,  0xff,  0x01,  0x02,  0x03,  0x04,  0xff, 
+    /*    "(" */ 0x05,  0x06,  0x07,  0x08,  0xff,  0xff,  0x09,  0x0a, 
+    /*    "0" */ 0x0b,  0x0c,  0x0d,  0x0e,  0x0f,  0x10,  0x11,  0x12, 
+    /*    "8" */ 0x13,  0x14,  0xff,  0x15,  0x16,  0xff,  0x17,  0x18, 
+    /*    "@" */ 0x19,  0x1a,  0x1b,  0x1c,  0x1d,  0x1e,  0x1f,  0x20, 
+    /*    "H" */ 0x21,  0x22,  0x23,  0x24,  0x25,  0x26,  0x27,  0x28, 
+    /*    "P" */ 0x29,  0x2a,  0x2b,  0x2c,  0x2d,  0x2e,  0x2f,  0x30, 
+    /*    "X" */ 0x31,  0x32,  0x33,  0x34,  0xff,  0x35,  0x36,  0xff, 
+    /*    "`" */ 0xff,  0x37,  0x38,  0x39,  0x3a,  0x3b,  0x3c,  0x3d, 
+    /*    "h" */ 0x3e,  0x3f,  0x40,  0x41,  0x42,  0x43,  0x44,  0x45, 
+    /*    "p" */ 0x46,  0x47,  0x48,  0x49,  0x4a,  0x4b,  0x4c,  0x4d, 
+    /*    "x" */ 0x4e,  0x4f,  0x50,  0x51,  0x52,  0x53,  0x54,  0xff, 
+    /* "\200" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\210" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\220" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\230" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\240" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\250" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\260" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\270" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\300" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\310" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\320" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\330" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\340" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\350" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\360" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+    /* "\370" */ 0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff,  0xff, 
+};
+
+static FcChar8 valueToChar[0x55] = {
+    /* 0x00 */ '!', '#', '$', '%', '&', '(', ')', '*',
+    /* 0x08 */ '+', '.', '/', '0', '1', '2', '3', '4',
+    /* 0x10 */ '5', '6', '7', '8', '9', ';', '<', '>',
+    /* 0x18 */ '?', '@', 'A', 'B', 'C', 'D', 'E', 'F',
+    /* 0x20 */ 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
+    /* 0x28 */ 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+    /* 0x30 */ 'W', 'X', 'Y', 'Z', '[', ']', '^', 'a',
+    /* 0x38 */ 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
+    /* 0x40 */ 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
+    /* 0x48 */ 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
+    /* 0x50 */ 'z', '{', '|', '}', '~',
+};
+
+static FcChar8 *
+FcCharSetParseValue (FcChar8 *string, FcChar32 *value)
+{
+    int                i;
+    FcChar32   v;
+    FcChar8    c;
+    
+    if (*string == ' ')
+    {
+       v = 0;
+       string++;
+    }
+    else
+    {
+       v = 0;
+       for (i = 0; i < 5; i++)
+       {
+           if (!(c = *string++))
+               return 0;
+           c = charToValue[c];
+           if (c == 0xff)
+               return 0;
+           v = v * 85 + c;
+       }
+    }
+    *value = v;
+    return string;
+}
+
+static FcBool
+FcCharSetUnparseValue (FcNameBuf *buf, FcChar32 value)
+{
+    int            i;
+    if (value == 0)
+    {
+       return FcNameBufChar (buf, ' ');
+    }
+    else
+    {
+       FcChar8 string[6];
+       FcChar8 *s = string + 5;
+       string[5] = '\0';
+       for (i = 0; i < 5; i++)
+       {
+           *--s = valueToChar[value % 85];
+           value /= 85;
+       }
+       for (i = 0; i < 5; i++)
+           if (!FcNameBufChar (buf, *s++))
+               return FcFalse;
+    }
+    return FcTrue;
+}
+
+FcCharSet *
+FcNameParseCharSet (FcChar8 *string)
+{
+    FcCharSet  *c;
+    FcChar32   ucs4;
+    FcCharLeaf *leaf;
+    int                i;
+
+    c = FcCharSetCreate ();
+    if (!c)
+       goto bail0;
+    while (*string)
+    {
+       string = FcCharSetParseValue (string, &ucs4);
+       if (!string)
+           goto bail1;
+       leaf = FcCharSetFindLeafCreate (c, ucs4);
+       if (!leaf)
+           goto bail1;
+       for (i = 0; i < 256/32; i++)
+       {
+           string = FcCharSetParseValue (string, &leaf->map[i]);
+           if (!string)
+               goto bail1;
+       }
+    }
+    return c;
+bail1:
+    FcCharSetDestroy (c);
+bail0:
+    return 0;
+}
+
+FcBool
+FcNameUnparseCharSet (FcNameBuf *buf, const FcCharSet *c)
+{
+    FcCharSetIter   ci;
+    int                    i;
+#ifdef CHECK
+    int                    len = buf->len;
+#endif
+
+    for (FcCharSetIterStart (c, &ci);
+        ci.leaf;
+        FcCharSetIterNext (c, &ci))
+    {
+       if (!FcCharSetUnparseValue (buf, ci.ucs4))
+           return FcFalse;
+       for (i = 0; i < 256/32; i++)
+           if (!FcCharSetUnparseValue (buf, ci.leaf->map[i]))
+               return FcFalse;
+    }
+#ifdef CHECK
+    {
+       FcCharSet       *check;
+       FcChar32        missing;
+       FcCharSetIter   ci, checki;
+       
+       /* null terminate for parser */
+       FcNameBufChar (buf, '\0');
+       /* step back over null for life after test */
+       buf->len--;
+       check = FcNameParseCharSet (buf->buf + len);
+       FcCharSetIterStart (c, &ci);
+       FcCharSetIterStart (check, &checki);
+       while (ci.leaf || checki.leaf)
+       {
+           if (ci.ucs4 < checki.ucs4)
+           {
+               printf ("Missing leaf node at 0x%x\n", ci.ucs4);
+               FcCharSetIterNext (c, &ci);
+           }
+           else if (checki.ucs4 < ci.ucs4)
+           {
+               printf ("Extra leaf node at 0x%x\n", checki.ucs4);
+               FcCharSetIterNext (check, &checki);
+           }
+           else
+           {
+               int         i = 256/32;
+               FcChar32    *cm = ci.leaf->map;
+               FcChar32    *checkm = checki.leaf->map;
+
+               for (i = 0; i < 256; i += 32)
+               {
+                   if (*cm != *checkm)
+                       printf ("Mismatching sets at 0x%08x: 0x%08x != 0x%08x\n",
+                               ci.ucs4 + i, *cm, *checkm);
+                   cm++;
+                   checkm++;
+               }
+               FcCharSetIterNext (c, &ci);
+               FcCharSetIterNext (check, &checki);
+           }
+       }
+       if ((missing = FcCharSetSubtractCount (c, check)))
+           printf ("%d missing in reparsed result\n", missing);
+       if ((missing = FcCharSetSubtractCount (check, c)))
+           printf ("%d extra in reparsed result\n", missing);
+       FcCharSetDestroy (check);
+    }
+#endif
+    
+    return FcTrue;
+}
+
+#include <freetype/freetype.h>
+#include <fontconfig/fcfreetype.h>
+
+/*
+ * Figure out whether the available freetype has FT_Get_Next_Char
+ */
+
+#if FREETYPE_MAJOR > 2
+# define HAS_NEXT_CHAR
+#else
+# if FREETYPE_MAJOR == 2
+#  if FREETYPE_MINOR > 0
+#   define HAS_NEXT_CHAR
+#  else
+#   if FREETYPE_MINOR == 0
+#    if FREETYPE_PATCH >= 8
+#     define HAS_NEXT_CHAR
+#    endif
+#   endif
+#  endif
+# endif
+#endif
+
+/*
+ * For our purposes, this approximation is sufficient
+ */
+#ifndef HAS_NEXT_CHAR
+#define FT_Get_Next_Char(face, ucs4) ((ucs4) >= 0xffffff ? 0 : (ucs4) + 1)
+#warning "No FT_Get_Next_Char"
+#endif
+
+typedef struct _FcCharEnt {
+    FcChar16   bmp;
+    FcChar8    encode;
+} FcCharEnt;
+
+typedef struct _FcCharMap {
+    const FcCharEnt *ent;
+    int                    nent;
+} FcCharMap;
+
+typedef struct _FcFontDecode {
+    FT_Encoding            encoding;
+    const FcCharMap *map;
+    FcChar32       max;
+} FcFontDecode;
+
+static const FcCharMap AppleRoman;
+static const FcCharMap AdobeSymbol;
+    
+static const FcFontDecode fcFontDecoders[] = {
+    { ft_encoding_unicode,     0,              (1 << 21) - 1 },
+    { ft_encoding_symbol,      &AdobeSymbol,   (1 << 16) - 1 },
+    { ft_encoding_apple_roman, &AppleRoman,    (1 << 16) - 1 },
+};
+
+#define NUM_DECODE  (sizeof (fcFontDecoders) / sizeof (fcFontDecoders[0]))
+
+static FT_ULong
+FcFreeTypeMapChar (FcChar32 ucs4, const FcCharMap *map)
+{
+    int                low, high, mid;
+    FcChar16   bmp;
+
+    low = 0;
+    high = map->nent - 1;
+    if (ucs4 < map->ent[low].bmp || map->ent[high].bmp < ucs4)
+       return ~0;
+    while (high - low > 1)
+    {
+       mid = (high + low) >> 1;
+       bmp = map->ent[mid].bmp;
+       if (ucs4 == bmp)
+           return (FT_ULong) map->ent[mid].encode;
+       if (ucs4 < bmp)
+           high = mid;
+       else
+           low = mid;
+    }
+    for (mid = low; mid <= high; mid++)
+    {
+       if (ucs4 == map->ent[mid].bmp)
+           return (FT_ULong) map->ent[mid].encode;
+    }
+    return ~0;
+}
+
+/*
+ * Map a UCS4 glyph to a glyph index.  Use all available encoding
+ * tables to try and find one that works.  This information is expected
+ * to be cached by higher levels, so performance isn't critical
+ */
+
+FT_UInt
+FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
+{
+    int                    initial, offset, decode;
+    FT_UInt        glyphindex;
+    FT_ULong       charcode;
+
+    initial = 0;
+    /*
+     * Find the current encoding
+     */
+    if (face->charmap)
+    {
+       for (; initial < NUM_DECODE; initial++)
+           if (fcFontDecoders[initial].encoding == face->charmap->encoding)
+               break;
+       if (initial == NUM_DECODE)
+           initial = 0;
+    }
+    /*
+     * Check each encoding for the glyph, starting with the current one
+     */
+    for (offset = 0; offset < NUM_DECODE; offset++)
+    {
+       decode = (initial + offset) % NUM_DECODE;
+       if (!face->charmap || face->charmap->encoding != fcFontDecoders[decode].encoding)
+           if (FT_Select_Charmap (face, fcFontDecoders[decode].encoding) != 0)
+               continue;
+       if (fcFontDecoders[decode].map)
+       {
+           charcode = FcFreeTypeMapChar (ucs4, fcFontDecoders[decode].map);
+           if (charcode == ~0)
+               continue;
+       }
+       else
+           charcode = (FT_ULong) ucs4;
+       glyphindex = FT_Get_Char_Index (face, charcode);
+       if (glyphindex)
+           return glyphindex;
+    }
+    return 0;
+}
+
+static FcBool
+FcFreeTypeCheckGlyph (FT_Face face, FcChar32 ucs4, 
+                     FT_UInt glyph, FcBlanks *blanks)
+{
+    FT_Int         load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_HINTING;
+    FT_GlyphSlot    slot;
+    
+    /*
+     * When using scalable fonts, only report those glyphs
+     * which can be scaled; otherwise those fonts will
+     * only be available at some sizes, and never when
+     * transformed.  Avoid this by simply reporting bitmap-only
+     * glyphs as missing
+     */
+    if (face->face_flags & FT_FACE_FLAG_SCALABLE)
+       load_flags |= FT_LOAD_NO_BITMAP;
+    
+    if (FT_Load_Glyph (face, glyph, load_flags))
+       return FcFalse;
+    
+    slot = face->glyph;
+    if (!glyph)
+       return FcFalse;
+    
+    switch (slot->format) {
+    case ft_glyph_format_bitmap:
+       /*
+        * Bitmaps are assumed to be reasonable; if
+        * this proves to be a rash assumption, this
+        * code can be easily modified
+        */
+       return FcTrue;
+    case ft_glyph_format_outline:
+       /*
+        * Glyphs with contours are always OK
+        */
+       if (slot->outline.n_contours != 0)
+           return FcTrue;
+       /*
+        * Glyphs with no contours are only OK if
+        * they're members of the Blanks set specified
+        * in the configuration.  If blanks isn't set,
+        * then allow any glyph to be blank
+        */
+       if (!blanks || FcBlanksIsMember (blanks, ucs4))
+           return FcTrue;
+       /* fall through ... */
+    default:
+    }
+    return FcFalse;
+}
+
+FcCharSet *
+FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks)
+{
+    FcChar32       page, off, max, ucs4;
+#ifdef CHECK
+    FcChar32       font_max = 0;
+#endif
+    FcCharSet      *fcs;
+    FcCharLeaf     *leaf;
+    const FcCharMap *map;
+    int                    o;
+    int                    i;
+    FT_UInt        glyph;
+
+    fcs = FcCharSetCreate ();
+    if (!fcs)
+       goto bail0;
+    
+    for (o = 0; o < NUM_DECODE; o++)
+    {
+       if (FT_Select_Charmap (face, fcFontDecoders[o].encoding) != 0)
+           continue;
+       map = fcFontDecoders[o].map;
+       if (map)
+       {
+           /*
+            * Non-Unicode tables are easy; there's a list of all possible
+            * characters
+            */
+           for (i = 0; i < map->nent; i++)
+           {
+               ucs4 = map->ent[i].bmp;
+               glyph = FT_Get_Char_Index (face, map->ent[i].encode);
+               if (glyph && FcFreeTypeCheckGlyph (face, ucs4, glyph, blanks))
+               {
+                   leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+                   if (!leaf)
+                       goto bail1;
+                   leaf->map[(ucs4 & 0xff) >> 5] |= (1 << (ucs4 & 0x1f));
+#ifdef CHECK
+                   if (ucs4 > font_max)
+                       font_max = ucs4;
+#endif
+               }
+           }
+       }
+       else
+       {
+           max = fcFontDecoders[o].max;
+         
+           /*
+            * Find the first encoded character in the font
+            */
+           ucs4 = 0;
+           if (FT_Get_Char_Index (face, 0))
+               ucs4 = 0;
+           else
+               ucs4 = FT_Get_Next_Char (face, 0);
+
+           for (;;)
+           {
+               page = ucs4 >> 8;
+               leaf = 0;
+               while ((ucs4 >> 8) == page)
+               {
+                   glyph = FT_Get_Char_Index (face, ucs4);
+                   if (glyph && FcFreeTypeCheckGlyph (face, ucs4, 
+                                                      glyph, blanks))
+                   {
+                       if (!leaf)
+                       {
+                           leaf = FcCharSetFindLeafCreate (fcs, ucs4);
+                           if (!leaf)
+                               goto bail1;
+                       }
+                       off = ucs4 & 0xff;
+                       leaf->map[off >> 5] |= (1 << (off & 0x1f));
+#ifdef CHECK
+                       if (ucs4 > font_max)
+                           font_max = ucs4;
+#endif
+                   }
+                   ucs4++;
+               }
+               ucs4 = FT_Get_Next_Char (face, ucs4 - 1);
+               if (!ucs4)
+                   break;
+           }
+#ifdef CHECK
+           for (ucs4 = 0; ucs4 < 0x10000; ucs4++)
+           {
+               FcBool      FT_Has, FC_Has;
+
+               FT_Has = FT_Get_Char_Index (face, ucs4) != 0;
+               FC_Has = FcCharSetHasChar (fcs, ucs4);
+               if (FT_Has != FC_Has)
+               {
+                   printf ("0x%08x FT says %d FC says %d\n", ucs4, FT_Has, FC_Has);
+               }
+           }
+#endif
+       }
+    }
+#ifdef CHECK
+    printf ("%d glyphs %d encoded\n", (int) face->num_glyphs, FcCharSetCount (fcs));
+    for (ucs4 = 0; ucs4 <= font_max; ucs4++)
+    {
+       FcBool  has_char = FcFreeTypeCharIndex (face, ucs4) != 0;
+       FcBool  has_bit = FcCharSetHasChar (fcs, ucs4);
+
+       if (has_char && !has_bit)
+           printf ("Bitmap missing char 0x%x\n", ucs4);
+       else if (!has_char && has_bit)
+           printf ("Bitmap extra char 0x%x\n", ucs4);
+    }
+#endif
+    return fcs;
+bail1:
+    FcCharSetDestroy (fcs);
+bail0:
+    return 0;
+}
+
+static const FcCharEnt AppleRomanEnt[] = {
+    { 0x0020, 0x20 }, /* SPACE */
+    { 0x0021, 0x21 }, /* EXCLAMATION MARK */
+    { 0x0022, 0x22 }, /* QUOTATION MARK */
+    { 0x0023, 0x23 }, /* NUMBER SIGN */
+    { 0x0024, 0x24 }, /* DOLLAR SIGN */
+    { 0x0025, 0x25 }, /* PERCENT SIGN */
+    { 0x0026, 0x26 }, /* AMPERSAND */
+    { 0x0027, 0x27 }, /* APOSTROPHE */
+    { 0x0028, 0x28 }, /* LEFT PARENTHESIS */
+    { 0x0029, 0x29 }, /* RIGHT PARENTHESIS */
+    { 0x002A, 0x2A }, /* ASTERISK */
+    { 0x002B, 0x2B }, /* PLUS SIGN */
+    { 0x002C, 0x2C }, /* COMMA */
+    { 0x002D, 0x2D }, /* HYPHEN-MINUS */
+    { 0x002E, 0x2E }, /* FULL STOP */
+    { 0x002F, 0x2F }, /* SOLIDUS */
+    { 0x0030, 0x30 }, /* DIGIT ZERO */
+    { 0x0031, 0x31 }, /* DIGIT ONE */
+    { 0x0032, 0x32 }, /* DIGIT TWO */
+    { 0x0033, 0x33 }, /* DIGIT THREE */
+    { 0x0034, 0x34 }, /* DIGIT FOUR */
+    { 0x0035, 0x35 }, /* DIGIT FIVE */
+    { 0x0036, 0x36 }, /* DIGIT SIX */
+    { 0x0037, 0x37 }, /* DIGIT SEVEN */
+    { 0x0038, 0x38 }, /* DIGIT EIGHT */
+    { 0x0039, 0x39 }, /* DIGIT NINE */
+    { 0x003A, 0x3A }, /* COLON */
+    { 0x003B, 0x3B }, /* SEMICOLON */
+    { 0x003C, 0x3C }, /* LESS-THAN SIGN */
+    { 0x003D, 0x3D }, /* EQUALS SIGN */
+    { 0x003E, 0x3E }, /* GREATER-THAN SIGN */
+    { 0x003F, 0x3F }, /* QUESTION MARK */
+    { 0x0040, 0x40 }, /* COMMERCIAL AT */
+    { 0x0041, 0x41 }, /* LATIN CAPITAL LETTER A */
+    { 0x0042, 0x42 }, /* LATIN CAPITAL LETTER B */
+    { 0x0043, 0x43 }, /* LATIN CAPITAL LETTER C */
+    { 0x0044, 0x44 }, /* LATIN CAPITAL LETTER D */
+    { 0x0045, 0x45 }, /* LATIN CAPITAL LETTER E */
+    { 0x0046, 0x46 }, /* LATIN CAPITAL LETTER F */
+    { 0x0047, 0x47 }, /* LATIN CAPITAL LETTER G */
+    { 0x0048, 0x48 }, /* LATIN CAPITAL LETTER H */
+    { 0x0049, 0x49 }, /* LATIN CAPITAL LETTER I */
+    { 0x004A, 0x4A }, /* LATIN CAPITAL LETTER J */
+    { 0x004B, 0x4B }, /* LATIN CAPITAL LETTER K */
+    { 0x004C, 0x4C }, /* LATIN CAPITAL LETTER L */
+    { 0x004D, 0x4D }, /* LATIN CAPITAL LETTER M */
+    { 0x004E, 0x4E }, /* LATIN CAPITAL LETTER N */
+    { 0x004F, 0x4F }, /* LATIN CAPITAL LETTER O */
+    { 0x0050, 0x50 }, /* LATIN CAPITAL LETTER P */
+    { 0x0051, 0x51 }, /* LATIN CAPITAL LETTER Q */
+    { 0x0052, 0x52 }, /* LATIN CAPITAL LETTER R */
+    { 0x0053, 0x53 }, /* LATIN CAPITAL LETTER S */
+    { 0x0054, 0x54 }, /* LATIN CAPITAL LETTER T */
+    { 0x0055, 0x55 }, /* LATIN CAPITAL LETTER U */
+    { 0x0056, 0x56 }, /* LATIN CAPITAL LETTER V */
+    { 0x0057, 0x57 }, /* LATIN CAPITAL LETTER W */
+    { 0x0058, 0x58 }, /* LATIN CAPITAL LETTER X */
+    { 0x0059, 0x59 }, /* LATIN CAPITAL LETTER Y */
+    { 0x005A, 0x5A }, /* LATIN CAPITAL LETTER Z */
+    { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET */
+    { 0x005C, 0x5C }, /* REVERSE SOLIDUS */
+    { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET */
+    { 0x005E, 0x5E }, /* CIRCUMFLEX ACCENT */
+    { 0x005F, 0x5F }, /* LOW LINE */
+    { 0x0060, 0x60 }, /* GRAVE ACCENT */
+    { 0x0061, 0x61 }, /* LATIN SMALL LETTER A */
+    { 0x0062, 0x62 }, /* LATIN SMALL LETTER B */
+    { 0x0063, 0x63 }, /* LATIN SMALL LETTER C */
+    { 0x0064, 0x64 }, /* LATIN SMALL LETTER D */
+    { 0x0065, 0x65 }, /* LATIN SMALL LETTER E */
+    { 0x0066, 0x66 }, /* LATIN SMALL LETTER F */
+    { 0x0067, 0x67 }, /* LATIN SMALL LETTER G */
+    { 0x0068, 0x68 }, /* LATIN SMALL LETTER H */
+    { 0x0069, 0x69 }, /* LATIN SMALL LETTER I */
+    { 0x006A, 0x6A }, /* LATIN SMALL LETTER J */
+    { 0x006B, 0x6B }, /* LATIN SMALL LETTER K */
+    { 0x006C, 0x6C }, /* LATIN SMALL LETTER L */
+    { 0x006D, 0x6D }, /* LATIN SMALL LETTER M */
+    { 0x006E, 0x6E }, /* LATIN SMALL LETTER N */
+    { 0x006F, 0x6F }, /* LATIN SMALL LETTER O */
+    { 0x0070, 0x70 }, /* LATIN SMALL LETTER P */
+    { 0x0071, 0x71 }, /* LATIN SMALL LETTER Q */
+    { 0x0072, 0x72 }, /* LATIN SMALL LETTER R */
+    { 0x0073, 0x73 }, /* LATIN SMALL LETTER S */
+    { 0x0074, 0x74 }, /* LATIN SMALL LETTER T */
+    { 0x0075, 0x75 }, /* LATIN SMALL LETTER U */
+    { 0x0076, 0x76 }, /* LATIN SMALL LETTER V */
+    { 0x0077, 0x77 }, /* LATIN SMALL LETTER W */
+    { 0x0078, 0x78 }, /* LATIN SMALL LETTER X */
+    { 0x0079, 0x79 }, /* LATIN SMALL LETTER Y */
+    { 0x007A, 0x7A }, /* LATIN SMALL LETTER Z */
+    { 0x007B, 0x7B }, /* LEFT CURLY BRACKET */
+    { 0x007C, 0x7C }, /* VERTICAL LINE */
+    { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET */
+    { 0x007E, 0x7E }, /* TILDE */
+    { 0x00A0, 0xCA }, /* NO-BREAK SPACE */
+    { 0x00A1, 0xC1 }, /* INVERTED EXCLAMATION MARK */
+    { 0x00A2, 0xA2 }, /* CENT SIGN */
+    { 0x00A3, 0xA3 }, /* POUND SIGN */
+    { 0x00A5, 0xB4 }, /* YEN SIGN */
+    { 0x00A7, 0xA4 }, /* SECTION SIGN */
+    { 0x00A8, 0xAC }, /* DIAERESIS */
+    { 0x00A9, 0xA9 }, /* COPYRIGHT SIGN */
+    { 0x00AA, 0xBB }, /* FEMININE ORDINAL INDICATOR */
+    { 0x00AB, 0xC7 }, /* LEFT-POINTING DOUBLE ANGLE QUOTATION MARK */
+    { 0x00AC, 0xC2 }, /* NOT SIGN */
+    { 0x00AE, 0xA8 }, /* REGISTERED SIGN */
+    { 0x00AF, 0xF8 }, /* MACRON */
+    { 0x00B0, 0xA1 }, /* DEGREE SIGN */
+    { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN */
+    { 0x00B4, 0xAB }, /* ACUTE ACCENT */
+    { 0x00B5, 0xB5 }, /* MICRO SIGN */
+    { 0x00B6, 0xA6 }, /* PILCROW SIGN */
+    { 0x00B7, 0xE1 }, /* MIDDLE DOT */
+    { 0x00B8, 0xFC }, /* CEDILLA */
+    { 0x00BA, 0xBC }, /* MASCULINE ORDINAL INDICATOR */
+    { 0x00BB, 0xC8 }, /* RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK */
+    { 0x00BF, 0xC0 }, /* INVERTED QUESTION MARK */
+    { 0x00C0, 0xCB }, /* LATIN CAPITAL LETTER A WITH GRAVE */
+    { 0x00C1, 0xE7 }, /* LATIN CAPITAL LETTER A WITH ACUTE */
+    { 0x00C2, 0xE5 }, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */
+    { 0x00C3, 0xCC }, /* LATIN CAPITAL LETTER A WITH TILDE */
+    { 0x00C4, 0x80 }, /* LATIN CAPITAL LETTER A WITH DIAERESIS */
+    { 0x00C5, 0x81 }, /* LATIN CAPITAL LETTER A WITH RING ABOVE */
+    { 0x00C6, 0xAE }, /* LATIN CAPITAL LETTER AE */
+    { 0x00C7, 0x82 }, /* LATIN CAPITAL LETTER C WITH CEDILLA */
+    { 0x00C8, 0xE9 }, /* LATIN CAPITAL LETTER E WITH GRAVE */
+    { 0x00C9, 0x83 }, /* LATIN CAPITAL LETTER E WITH ACUTE */
+    { 0x00CA, 0xE6 }, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */
+    { 0x00CB, 0xE8 }, /* LATIN CAPITAL LETTER E WITH DIAERESIS */
+    { 0x00CC, 0xED }, /* LATIN CAPITAL LETTER I WITH GRAVE */
+    { 0x00CD, 0xEA }, /* LATIN CAPITAL LETTER I WITH ACUTE */
+    { 0x00CE, 0xEB }, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */
+    { 0x00CF, 0xEC }, /* LATIN CAPITAL LETTER I WITH DIAERESIS */
+    { 0x00D1, 0x84 }, /* LATIN CAPITAL LETTER N WITH TILDE */
+    { 0x00D2, 0xF1 }, /* LATIN CAPITAL LETTER O WITH GRAVE */
+    { 0x00D3, 0xEE }, /* LATIN CAPITAL LETTER O WITH ACUTE */
+    { 0x00D4, 0xEF }, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */
+    { 0x00D5, 0xCD }, /* LATIN CAPITAL LETTER O WITH TILDE */
+    { 0x00D6, 0x85 }, /* LATIN CAPITAL LETTER O WITH DIAERESIS */
+    { 0x00D8, 0xAF }, /* LATIN CAPITAL LETTER O WITH STROKE */
+    { 0x00D9, 0xF4 }, /* LATIN CAPITAL LETTER U WITH GRAVE */
+    { 0x00DA, 0xF2 }, /* LATIN CAPITAL LETTER U WITH ACUTE */
+    { 0x00DB, 0xF3 }, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */
+    { 0x00DC, 0x86 }, /* LATIN CAPITAL LETTER U WITH DIAERESIS */
+    { 0x00DF, 0xA7 }, /* LATIN SMALL LETTER SHARP S */
+    { 0x00E0, 0x88 }, /* LATIN SMALL LETTER A WITH GRAVE */
+    { 0x00E1, 0x87 }, /* LATIN SMALL LETTER A WITH ACUTE */
+    { 0x00E2, 0x89 }, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */
+    { 0x00E3, 0x8B }, /* LATIN SMALL LETTER A WITH TILDE */
+    { 0x00E4, 0x8A }, /* LATIN SMALL LETTER A WITH DIAERESIS */
+    { 0x00E5, 0x8C }, /* LATIN SMALL LETTER A WITH RING ABOVE */
+    { 0x00E6, 0xBE }, /* LATIN SMALL LETTER AE */
+    { 0x00E7, 0x8D }, /* LATIN SMALL LETTER C WITH CEDILLA */
+    { 0x00E8, 0x8F }, /* LATIN SMALL LETTER E WITH GRAVE */
+    { 0x00E9, 0x8E }, /* LATIN SMALL LETTER E WITH ACUTE */
+    { 0x00EA, 0x90 }, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */
+    { 0x00EB, 0x91 }, /* LATIN SMALL LETTER E WITH DIAERESIS */
+    { 0x00EC, 0x93 }, /* LATIN SMALL LETTER I WITH GRAVE */
+    { 0x00ED, 0x92 }, /* LATIN SMALL LETTER I WITH ACUTE */
+    { 0x00EE, 0x94 }, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */
+    { 0x00EF, 0x95 }, /* LATIN SMALL LETTER I WITH DIAERESIS */
+    { 0x00F1, 0x96 }, /* LATIN SMALL LETTER N WITH TILDE */
+    { 0x00F2, 0x98 }, /* LATIN SMALL LETTER O WITH GRAVE */
+    { 0x00F3, 0x97 }, /* LATIN SMALL LETTER O WITH ACUTE */
+    { 0x00F4, 0x99 }, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */
+    { 0x00F5, 0x9B }, /* LATIN SMALL LETTER O WITH TILDE */
+    { 0x00F6, 0x9A }, /* LATIN SMALL LETTER O WITH DIAERESIS */
+    { 0x00F7, 0xD6 }, /* DIVISION SIGN */
+    { 0x00F8, 0xBF }, /* LATIN SMALL LETTER O WITH STROKE */
+    { 0x00F9, 0x9D }, /* LATIN SMALL LETTER U WITH GRAVE */
+    { 0x00FA, 0x9C }, /* LATIN SMALL LETTER U WITH ACUTE */
+    { 0x00FB, 0x9E }, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */
+    { 0x00FC, 0x9F }, /* LATIN SMALL LETTER U WITH DIAERESIS */
+    { 0x00FF, 0xD8 }, /* LATIN SMALL LETTER Y WITH DIAERESIS */
+    { 0x0131, 0xF5 }, /* LATIN SMALL LETTER DOTLESS I */
+    { 0x0152, 0xCE }, /* LATIN CAPITAL LIGATURE OE */
+    { 0x0153, 0xCF }, /* LATIN SMALL LIGATURE OE */
+    { 0x0178, 0xD9 }, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */
+    { 0x0192, 0xC4 }, /* LATIN SMALL LETTER F WITH HOOK */
+    { 0x02C6, 0xF6 }, /* MODIFIER LETTER CIRCUMFLEX ACCENT */
+    { 0x02C7, 0xFF }, /* CARON */
+    { 0x02D8, 0xF9 }, /* BREVE */
+    { 0x02D9, 0xFA }, /* DOT ABOVE */
+    { 0x02DA, 0xFB }, /* RING ABOVE */
+    { 0x02DB, 0xFE }, /* OGONEK */
+    { 0x02DC, 0xF7 }, /* SMALL TILDE */
+    { 0x02DD, 0xFD }, /* DOUBLE ACUTE ACCENT */
+    { 0x03A9, 0xBD }, /* GREEK CAPITAL LETTER OMEGA */
+    { 0x03C0, 0xB9 }, /* GREEK SMALL LETTER PI */
+    { 0x2013, 0xD0 }, /* EN DASH */
+    { 0x2014, 0xD1 }, /* EM DASH */
+    { 0x2018, 0xD4 }, /* LEFT SINGLE QUOTATION MARK */
+    { 0x2019, 0xD5 }, /* RIGHT SINGLE QUOTATION MARK */
+    { 0x201A, 0xE2 }, /* SINGLE LOW-9 QUOTATION MARK */
+    { 0x201C, 0xD2 }, /* LEFT DOUBLE QUOTATION MARK */
+    { 0x201D, 0xD3 }, /* RIGHT DOUBLE QUOTATION MARK */
+    { 0x201E, 0xE3 }, /* DOUBLE LOW-9 QUOTATION MARK */
+    { 0x2020, 0xA0 }, /* DAGGER */
+    { 0x2021, 0xE0 }, /* DOUBLE DAGGER */
+    { 0x2022, 0xA5 }, /* BULLET */
+    { 0x2026, 0xC9 }, /* HORIZONTAL ELLIPSIS */
+    { 0x2030, 0xE4 }, /* PER MILLE SIGN */
+    { 0x2039, 0xDC }, /* SINGLE LEFT-POINTING ANGLE QUOTATION MARK */
+    { 0x203A, 0xDD }, /* SINGLE RIGHT-POINTING ANGLE QUOTATION MARK */
+    { 0x2044, 0xDA }, /* FRACTION SLASH */
+    { 0x20AC, 0xDB }, /* EURO SIGN */
+    { 0x2122, 0xAA }, /* TRADE MARK SIGN */
+    { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL */
+    { 0x2206, 0xC6 }, /* INCREMENT */
+    { 0x220F, 0xB8 }, /* N-ARY PRODUCT */
+    { 0x2211, 0xB7 }, /* N-ARY SUMMATION */
+    { 0x221A, 0xC3 }, /* SQUARE ROOT */
+    { 0x221E, 0xB0 }, /* INFINITY */
+    { 0x222B, 0xBA }, /* INTEGRAL */
+    { 0x2248, 0xC5 }, /* ALMOST EQUAL TO */
+    { 0x2260, 0xAD }, /* NOT EQUAL TO */
+    { 0x2264, 0xB2 }, /* LESS-THAN OR EQUAL TO */
+    { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO */
+    { 0x25CA, 0xD7 }, /* LOZENGE */
+    { 0xF8FF, 0xF0 }, /* Apple logo */
+    { 0xFB01, 0xDE }, /* LATIN SMALL LIGATURE FI */
+    { 0xFB02, 0xDF }, /* LATIN SMALL LIGATURE FL */
+};
+
+static const FcCharMap AppleRoman = {
+    AppleRomanEnt,
+    sizeof (AppleRomanEnt) / sizeof (AppleRomanEnt[0])
+};
+
+static const FcCharEnt AdobeSymbolEnt[] = {
+    { 0x0020, 0x20 }, /* SPACE # space */
+    { 0x0021, 0x21 }, /* EXCLAMATION MARK      # exclam */
+    { 0x0023, 0x23 }, /* NUMBER SIGN   # numbersign */
+    { 0x0025, 0x25 }, /* PERCENT SIGN  # percent */
+    { 0x0026, 0x26 }, /* AMPERSAND     # ampersand */
+    { 0x0028, 0x28 }, /* LEFT PARENTHESIS      # parenleft */
+    { 0x0029, 0x29 }, /* RIGHT PARENTHESIS     # parenright */
+    { 0x002B, 0x2B }, /* PLUS SIGN     # plus */
+    { 0x002C, 0x2C }, /* COMMA # comma */
+    { 0x002E, 0x2E }, /* FULL STOP     # period */
+    { 0x002F, 0x2F }, /* SOLIDUS       # slash */
+    { 0x0030, 0x30 }, /* DIGIT ZERO    # zero */
+    { 0x0031, 0x31 }, /* DIGIT ONE     # one */
+    { 0x0032, 0x32 }, /* DIGIT TWO     # two */
+    { 0x0033, 0x33 }, /* DIGIT THREE   # three */
+    { 0x0034, 0x34 }, /* DIGIT FOUR    # four */
+    { 0x0035, 0x35 }, /* DIGIT FIVE    # five */
+    { 0x0036, 0x36 }, /* DIGIT SIX     # six */
+    { 0x0037, 0x37 }, /* DIGIT SEVEN   # seven */
+    { 0x0038, 0x38 }, /* DIGIT EIGHT   # eight */
+    { 0x0039, 0x39 }, /* DIGIT NINE    # nine */
+    { 0x003A, 0x3A }, /* COLON # colon */
+    { 0x003B, 0x3B }, /* SEMICOLON     # semicolon */
+    { 0x003C, 0x3C }, /* LESS-THAN SIGN        # less */
+    { 0x003D, 0x3D }, /* EQUALS SIGN   # equal */
+    { 0x003E, 0x3E }, /* GREATER-THAN SIGN     # greater */
+    { 0x003F, 0x3F }, /* QUESTION MARK # question */
+    { 0x005B, 0x5B }, /* LEFT SQUARE BRACKET   # bracketleft */
+    { 0x005D, 0x5D }, /* RIGHT SQUARE BRACKET  # bracketright */
+    { 0x005F, 0x5F }, /* LOW LINE      # underscore */
+    { 0x007B, 0x7B }, /* LEFT CURLY BRACKET    # braceleft */
+    { 0x007C, 0x7C }, /* VERTICAL LINE # bar */
+    { 0x007D, 0x7D }, /* RIGHT CURLY BRACKET   # braceright */
+    { 0x00A0, 0x20 }, /* NO-BREAK SPACE        # space */
+    { 0x00AC, 0xD8 }, /* NOT SIGN      # logicalnot */
+    { 0x00B0, 0xB0 }, /* DEGREE SIGN   # degree */
+    { 0x00B1, 0xB1 }, /* PLUS-MINUS SIGN       # plusminus */
+    { 0x00B5, 0x6D }, /* MICRO SIGN    # mu */
+    { 0x00D7, 0xB4 }, /* MULTIPLICATION SIGN   # multiply */
+    { 0x00F7, 0xB8 }, /* DIVISION SIGN # divide */
+    { 0x0192, 0xA6 }, /* LATIN SMALL LETTER F WITH HOOK        # florin */
+    { 0x0391, 0x41 }, /* GREEK CAPITAL LETTER ALPHA    # Alpha */
+    { 0x0392, 0x42 }, /* GREEK CAPITAL LETTER BETA     # Beta */
+    { 0x0393, 0x47 }, /* GREEK CAPITAL LETTER GAMMA    # Gamma */
+    { 0x0394, 0x44 }, /* GREEK CAPITAL LETTER DELTA    # Delta */
+    { 0x0395, 0x45 }, /* GREEK CAPITAL LETTER EPSILON  # Epsilon */
+    { 0x0396, 0x5A }, /* GREEK CAPITAL LETTER ZETA     # Zeta */
+    { 0x0397, 0x48 }, /* GREEK CAPITAL LETTER ETA      # Eta */
+    { 0x0398, 0x51 }, /* GREEK CAPITAL LETTER THETA    # Theta */
+    { 0x0399, 0x49 }, /* GREEK CAPITAL LETTER IOTA     # Iota */
+    { 0x039A, 0x4B }, /* GREEK CAPITAL LETTER KAPPA    # Kappa */
+    { 0x039B, 0x4C }, /* GREEK CAPITAL LETTER LAMDA    # Lambda */
+    { 0x039C, 0x4D }, /* GREEK CAPITAL LETTER MU       # Mu */
+    { 0x039D, 0x4E }, /* GREEK CAPITAL LETTER NU       # Nu */
+    { 0x039E, 0x58 }, /* GREEK CAPITAL LETTER XI       # Xi */
+    { 0x039F, 0x4F }, /* GREEK CAPITAL LETTER OMICRON  # Omicron */
+    { 0x03A0, 0x50 }, /* GREEK CAPITAL LETTER PI       # Pi */
+    { 0x03A1, 0x52 }, /* GREEK CAPITAL LETTER RHO      # Rho */
+    { 0x03A3, 0x53 }, /* GREEK CAPITAL LETTER SIGMA    # Sigma */
+    { 0x03A4, 0x54 }, /* GREEK CAPITAL LETTER TAU      # Tau */
+    { 0x03A5, 0x55 }, /* GREEK CAPITAL LETTER UPSILON  # Upsilon */
+    { 0x03A6, 0x46 }, /* GREEK CAPITAL LETTER PHI      # Phi */
+    { 0x03A7, 0x43 }, /* GREEK CAPITAL LETTER CHI      # Chi */
+    { 0x03A8, 0x59 }, /* GREEK CAPITAL LETTER PSI      # Psi */
+    { 0x03A9, 0x57 }, /* GREEK CAPITAL LETTER OMEGA    # Omega */
+    { 0x03B1, 0x61 }, /* GREEK SMALL LETTER ALPHA      # alpha */
+    { 0x03B2, 0x62 }, /* GREEK SMALL LETTER BETA       # beta */
+    { 0x03B3, 0x67 }, /* GREEK SMALL LETTER GAMMA      # gamma */
+    { 0x03B4, 0x64 }, /* GREEK SMALL LETTER DELTA      # delta */
+    { 0x03B5, 0x65 }, /* GREEK SMALL LETTER EPSILON    # epsilon */
+    { 0x03B6, 0x7A }, /* GREEK SMALL LETTER ZETA       # zeta */
+    { 0x03B7, 0x68 }, /* GREEK SMALL LETTER ETA        # eta */
+    { 0x03B8, 0x71 }, /* GREEK SMALL LETTER THETA      # theta */
+    { 0x03B9, 0x69 }, /* GREEK SMALL LETTER IOTA       # iota */
+    { 0x03BA, 0x6B }, /* GREEK SMALL LETTER KAPPA      # kappa */
+    { 0x03BB, 0x6C }, /* GREEK SMALL LETTER LAMDA      # lambda */
+    { 0x03BC, 0x6D }, /* GREEK SMALL LETTER MU # mu */
+    { 0x03BD, 0x6E }, /* GREEK SMALL LETTER NU # nu */
+    { 0x03BE, 0x78 }, /* GREEK SMALL LETTER XI # xi */
+    { 0x03BF, 0x6F }, /* GREEK SMALL LETTER OMICRON    # omicron */
+    { 0x03C0, 0x70 }, /* GREEK SMALL LETTER PI # pi */
+    { 0x03C1, 0x72 }, /* GREEK SMALL LETTER RHO        # rho */
+    { 0x03C2, 0x56 }, /* GREEK SMALL LETTER FINAL SIGMA        # sigma1 */
+    { 0x03C3, 0x73 }, /* GREEK SMALL LETTER SIGMA      # sigma */
+    { 0x03C4, 0x74 }, /* GREEK SMALL LETTER TAU        # tau */
+    { 0x03C5, 0x75 }, /* GREEK SMALL LETTER UPSILON    # upsilon */
+    { 0x03C6, 0x66 }, /* GREEK SMALL LETTER PHI        # phi */
+    { 0x03C7, 0x63 }, /* GREEK SMALL LETTER CHI        # chi */
+    { 0x03C8, 0x79 }, /* GREEK SMALL LETTER PSI        # psi */
+    { 0x03C9, 0x77 }, /* GREEK SMALL LETTER OMEGA      # omega */
+    { 0x03D1, 0x4A }, /* GREEK THETA SYMBOL    # theta1 */
+    { 0x03D2, 0xA1 }, /* GREEK UPSILON WITH HOOK SYMBOL        # Upsilon1 */
+    { 0x03D5, 0x6A }, /* GREEK PHI SYMBOL      # phi1 */
+    { 0x03D6, 0x76 }, /* GREEK PI SYMBOL       # omega1 */
+    { 0x2022, 0xB7 }, /* BULLET        # bullet */
+    { 0x2026, 0xBC }, /* HORIZONTAL ELLIPSIS   # ellipsis */
+    { 0x2032, 0xA2 }, /* PRIME # minute */
+    { 0x2033, 0xB2 }, /* DOUBLE PRIME  # second */
+    { 0x2044, 0xA4 }, /* FRACTION SLASH        # fraction */
+    { 0x20AC, 0xA0 }, /* EURO SIGN     # Euro */
+    { 0x2111, 0xC1 }, /* BLACK-LETTER CAPITAL I        # Ifraktur */
+    { 0x2118, 0xC3 }, /* SCRIPT CAPITAL P      # weierstrass */
+    { 0x211C, 0xC2 }, /* BLACK-LETTER CAPITAL R        # Rfraktur */
+    { 0x2126, 0x57 }, /* OHM SIGN      # Omega */
+    { 0x2135, 0xC0 }, /* ALEF SYMBOL   # aleph */
+    { 0x2190, 0xAC }, /* LEFTWARDS ARROW       # arrowleft */
+    { 0x2191, 0xAD }, /* UPWARDS ARROW # arrowup */
+    { 0x2192, 0xAE }, /* RIGHTWARDS ARROW      # arrowright */
+    { 0x2193, 0xAF }, /* DOWNWARDS ARROW       # arrowdown */
+    { 0x2194, 0xAB }, /* LEFT RIGHT ARROW      # arrowboth */
+    { 0x21B5, 0xBF }, /* DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn */
+    { 0x21D0, 0xDC }, /* LEFTWARDS DOUBLE ARROW        # arrowdblleft */
+    { 0x21D1, 0xDD }, /* UPWARDS DOUBLE ARROW  # arrowdblup */
+    { 0x21D2, 0xDE }, /* RIGHTWARDS DOUBLE ARROW       # arrowdblright */
+    { 0x21D3, 0xDF }, /* DOWNWARDS DOUBLE ARROW        # arrowdbldown */
+    { 0x21D4, 0xDB }, /* LEFT RIGHT DOUBLE ARROW       # arrowdblboth */
+    { 0x2200, 0x22 }, /* FOR ALL       # universal */
+    { 0x2202, 0xB6 }, /* PARTIAL DIFFERENTIAL  # partialdiff */
+    { 0x2203, 0x24 }, /* THERE EXISTS  # existential */
+    { 0x2205, 0xC6 }, /* EMPTY SET     # emptyset */
+    { 0x2206, 0x44 }, /* INCREMENT     # Delta */
+    { 0x2207, 0xD1 }, /* NABLA # gradient */
+    { 0x2208, 0xCE }, /* ELEMENT OF    # element */
+    { 0x2209, 0xCF }, /* NOT AN ELEMENT OF     # notelement */
+    { 0x220B, 0x27 }, /* CONTAINS AS MEMBER    # suchthat */
+    { 0x220F, 0xD5 }, /* N-ARY PRODUCT # product */
+    { 0x2211, 0xE5 }, /* N-ARY SUMMATION       # summation */
+    { 0x2212, 0x2D }, /* MINUS SIGN    # minus */
+    { 0x2215, 0xA4 }, /* DIVISION SLASH        # fraction */
+    { 0x2217, 0x2A }, /* ASTERISK OPERATOR     # asteriskmath */
+    { 0x221A, 0xD6 }, /* SQUARE ROOT   # radical */
+    { 0x221D, 0xB5 }, /* PROPORTIONAL TO       # proportional */
+    { 0x221E, 0xA5 }, /* INFINITY      # infinity */
+    { 0x2220, 0xD0 }, /* ANGLE # angle */
+    { 0x2227, 0xD9 }, /* LOGICAL AND   # logicaland */
+    { 0x2228, 0xDA }, /* LOGICAL OR    # logicalor */
+    { 0x2229, 0xC7 }, /* INTERSECTION  # intersection */
+    { 0x222A, 0xC8 }, /* UNION # union */
+    { 0x222B, 0xF2 }, /* INTEGRAL      # integral */
+    { 0x2234, 0x5C }, /* THEREFORE     # therefore */
+    { 0x223C, 0x7E }, /* TILDE OPERATOR        # similar */
+    { 0x2245, 0x40 }, /* APPROXIMATELY EQUAL TO        # congruent */
+    { 0x2248, 0xBB }, /* ALMOST EQUAL TO       # approxequal */
+    { 0x2260, 0xB9 }, /* NOT EQUAL TO  # notequal */
+    { 0x2261, 0xBA }, /* IDENTICAL TO  # equivalence */
+    { 0x2264, 0xA3 }, /* LESS-THAN OR EQUAL TO # lessequal */
+    { 0x2265, 0xB3 }, /* GREATER-THAN OR EQUAL TO      # greaterequal */
+    { 0x2282, 0xCC }, /* SUBSET OF     # propersubset */
+    { 0x2283, 0xC9 }, /* SUPERSET OF   # propersuperset */
+    { 0x2284, 0xCB }, /* NOT A SUBSET OF       # notsubset */
+    { 0x2286, 0xCD }, /* SUBSET OF OR EQUAL TO # reflexsubset */
+    { 0x2287, 0xCA }, /* SUPERSET OF OR EQUAL TO       # reflexsuperset */
+    { 0x2295, 0xC5 }, /* CIRCLED PLUS  # circleplus */
+    { 0x2297, 0xC4 }, /* CIRCLED TIMES # circlemultiply */
+    { 0x22A5, 0x5E }, /* UP TACK       # perpendicular */
+    { 0x22C5, 0xD7 }, /* DOT OPERATOR  # dotmath */
+    { 0x2320, 0xF3 }, /* TOP HALF INTEGRAL     # integraltp */
+    { 0x2321, 0xF5 }, /* BOTTOM HALF INTEGRAL  # integralbt */
+    { 0x2329, 0xE1 }, /* LEFT-POINTING ANGLE BRACKET   # angleleft */
+    { 0x232A, 0xF1 }, /* RIGHT-POINTING ANGLE BRACKET  # angleright */
+    { 0x25CA, 0xE0 }, /* LOZENGE       # lozenge */
+    { 0x2660, 0xAA }, /* BLACK SPADE SUIT      # spade */
+    { 0x2663, 0xA7 }, /* BLACK CLUB SUIT       # club */
+    { 0x2665, 0xA9 }, /* BLACK HEART SUIT      # heart */
+    { 0x2666, 0xA8 }, /* BLACK DIAMOND SUIT    # diamond */
+    { 0xF6D9, 0xD3 }, /* COPYRIGHT SIGN SERIF  # copyrightserif (CUS) */
+    { 0xF6DA, 0xD2 }, /* REGISTERED SIGN SERIF # registerserif (CUS) */
+    { 0xF6DB, 0xD4 }, /* TRADE MARK SIGN SERIF # trademarkserif (CUS) */
+    { 0xF8E5, 0x60 }, /* RADICAL EXTENDER      # radicalex (CUS) */
+    { 0xF8E6, 0xBD }, /* VERTICAL ARROW EXTENDER       # arrowvertex (CUS) */
+    { 0xF8E7, 0xBE }, /* HORIZONTAL ARROW EXTENDER     # arrowhorizex (CUS) */
+    { 0xF8E8, 0xE2 }, /* REGISTERED SIGN SANS SERIF    # registersans (CUS) */
+    { 0xF8E9, 0xE3 }, /* COPYRIGHT SIGN SANS SERIF     # copyrightsans (CUS) */
+    { 0xF8EA, 0xE4 }, /* TRADE MARK SIGN SANS SERIF    # trademarksans (CUS) */
+    { 0xF8EB, 0xE6 }, /* LEFT PAREN TOP        # parenlefttp (CUS) */
+    { 0xF8EC, 0xE7 }, /* LEFT PAREN EXTENDER   # parenleftex (CUS) */
+    { 0xF8ED, 0xE8 }, /* LEFT PAREN BOTTOM     # parenleftbt (CUS) */
+    { 0xF8EE, 0xE9 }, /* LEFT SQUARE BRACKET TOP       # bracketlefttp (CUS) */
+    { 0xF8EF, 0xEA }, /* LEFT SQUARE BRACKET EXTENDER  # bracketleftex (CUS) */
+    { 0xF8F0, 0xEB }, /* LEFT SQUARE BRACKET BOTTOM    # bracketleftbt (CUS) */
+    { 0xF8F1, 0xEC }, /* LEFT CURLY BRACKET TOP        # bracelefttp (CUS) */
+    { 0xF8F2, 0xED }, /* LEFT CURLY BRACKET MID        # braceleftmid (CUS) */
+    { 0xF8F3, 0xEE }, /* LEFT CURLY BRACKET BOTTOM     # braceleftbt (CUS) */
+    { 0xF8F4, 0xEF }, /* CURLY BRACKET EXTENDER        # braceex (CUS) */
+    { 0xF8F5, 0xF4 }, /* INTEGRAL EXTENDER     # integralex (CUS) */
+    { 0xF8F6, 0xF6 }, /* RIGHT PAREN TOP       # parenrighttp (CUS) */
+    { 0xF8F7, 0xF7 }, /* RIGHT PAREN EXTENDER  # parenrightex (CUS) */
+    { 0xF8F8, 0xF8 }, /* RIGHT PAREN BOTTOM    # parenrightbt (CUS) */
+    { 0xF8F9, 0xF9 }, /* RIGHT SQUARE BRACKET TOP      # bracketrighttp (CUS) */
+    { 0xF8FA, 0xFA }, /* RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS) */
+    { 0xF8FB, 0xFB }, /* RIGHT SQUARE BRACKET BOTTOM   # bracketrightbt (CUS) */
+    { 0xF8FC, 0xFC }, /* RIGHT CURLY BRACKET TOP       # bracerighttp (CUS) */
+    { 0xF8FD, 0xFD }, /* RIGHT CURLY BRACKET MID       # bracerightmid (CUS) */
+    { 0xF8FE, 0xFE }, /* RIGHT CURLY BRACKET BOTTOM    # bracerightbt (CUS) */
+};
+
+static const FcCharMap AdobeSymbol = {
+    AdobeSymbolEnt,
+    sizeof (AdobeSymbolEnt) / sizeof (AdobeSymbolEnt[0]),
+};
diff --git a/src/fcdbg.c b/src/fcdbg.c
new file mode 100644 (file)
index 0000000..78af630
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "fcint.h"
+
+void
+FcValuePrint (FcValue v)
+{
+    switch (v.type) {
+    case FcTypeVoid:
+       printf (" <void>");
+       break;
+    case FcTypeInteger:
+       printf (" %d", v.u.i);
+       break;
+    case FcTypeDouble:
+       printf (" %g", v.u.d);
+       break;
+    case FcTypeString:
+       printf (" \"%s\"", v.u.s);
+       break;
+    case FcTypeBool:
+       printf (" %s", v.u.b ? "FcTrue" : "FcFalse");
+       break;
+    case FcTypeMatrix:
+       printf (" (%f %f; %f %f)", v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
+       break;
+    case FcTypeCharSet:        /* XXX */
+       printf (" set");
+       break;
+    }
+}
+
+void
+FcValueListPrint (FcValueList *l)
+{
+    for (; l; l = l->next)
+       FcValuePrint (l->value);
+}
+
+void
+FcPatternPrint (FcPattern *p)
+{
+    int                    i;
+    FcPatternElt   *e;
+    
+    if (!p)
+    {
+       printf ("Null pattern\n");
+       return;
+    }
+    printf ("Pattern %d of %d\n", p->num, p->size);
+    for (i = 0; i < p->num; i++)
+    {
+       e = &p->elts[i];
+       printf ("\t%s:", e->object);
+       FcValueListPrint (e->values);
+       printf ("\n");
+    }
+    printf ("\n");
+}
+
+void
+FcOpPrint (FcOp op)
+{
+    switch (op) {
+    case FcOpInteger: printf ("Integer"); break;
+    case FcOpDouble: printf ("Double"); break;
+    case FcOpString: printf ("String"); break;
+    case FcOpMatrix: printf ("Matrix"); break;
+    case FcOpBool: printf ("Bool"); break;
+    case FcOpCharSet: printf ("CharSet"); break;
+    case FcOpField: printf ("Field"); break;
+    case FcOpConst: printf ("Const"); break;
+    case FcOpAssign: printf ("Assign"); break;
+    case FcOpAssignReplace: printf ("AssignReplace"); break;
+    case FcOpPrepend: printf ("Prepend"); break;
+    case FcOpPrependFirst: printf ("PrependFirst"); break;
+    case FcOpAppend: printf ("Append"); break;
+    case FcOpAppendLast: printf ("AppendLast"); break;
+    case FcOpQuest: printf ("Quest"); break;
+    case FcOpOr: printf ("Or"); break;
+    case FcOpAnd: printf ("And"); break;
+    case FcOpEqual: printf ("Equal"); break;
+    case FcOpContains: printf ("Contains"); break;
+    case FcOpNotEqual: printf ("NotEqual"); break;
+    case FcOpLess: printf ("Less"); break;
+    case FcOpLessEqual: printf ("LessEqual"); break;
+    case FcOpMore: printf ("More"); break;
+    case FcOpMoreEqual: printf ("MoreEqual"); break;
+    case FcOpPlus: printf ("Plus"); break;
+    case FcOpMinus: printf ("Minus"); break;
+    case FcOpTimes: printf ("Times"); break;
+    case FcOpDivide: printf ("Divide"); break;
+    case FcOpNot: printf ("Not"); break;
+    case FcOpNil: printf ("Nil"); break;
+    case FcOpComma: printf ("Comma"); break;
+    case FcOpInvalid: printf ("Invalid"); break;
+    }
+}
+
+void
+FcExprPrint (FcExpr *expr)
+{
+    switch (expr->op) {
+    case FcOpInteger: printf ("%d", expr->u.ival); break;
+    case FcOpDouble: printf ("%g", expr->u.dval); break;
+    case FcOpString: printf ("\"%s\"", expr->u.sval); break;
+    case FcOpMatrix: printf ("[%g %g %g %g]",
+                             expr->u.mval->xx,
+                             expr->u.mval->xy,
+                             expr->u.mval->yx,
+                             expr->u.mval->yy);
+    case FcOpBool: printf ("%s", expr->u.bval ? "true" : "false"); break;
+    case FcOpField: printf ("%s", expr->u.field); break;
+    case FcOpQuest:
+       FcExprPrint (expr->u.tree.left);
+       printf (" quest ");
+       FcExprPrint (expr->u.tree.right->u.tree.left);
+       printf (" colon ");
+       FcExprPrint (expr->u.tree.right->u.tree.right);
+       break;
+    case FcOpOr:
+    case FcOpAnd:
+    case FcOpEqual:
+    case FcOpContains:
+    case FcOpNotEqual:
+    case FcOpLess:
+    case FcOpLessEqual:
+    case FcOpMore:
+    case FcOpMoreEqual:
+    case FcOpPlus:
+    case FcOpMinus:
+    case FcOpTimes:
+    case FcOpDivide:
+       FcExprPrint (expr->u.tree.left);
+       printf (" ");
+       switch (expr->op) {
+       case FcOpOr: printf ("Or"); break;
+       case FcOpAnd: printf ("And"); break;
+       case FcOpEqual: printf ("Equal"); break;
+       case FcOpContains: printf ("Contains"); break;
+       case FcOpNotEqual: printf ("NotEqual"); break;
+       case FcOpLess: printf ("Less"); break;
+       case FcOpLessEqual: printf ("LessEqual"); break;
+       case FcOpMore: printf ("More"); break;
+       case FcOpMoreEqual: printf ("MoreEqual"); break;
+       case FcOpPlus: printf ("Plus"); break;
+       case FcOpMinus: printf ("Minus"); break;
+       case FcOpTimes: printf ("Times"); break;
+       case FcOpDivide: printf ("Divide"); break;
+       default: break;
+       }
+       printf (" ");
+       FcExprPrint (expr->u.tree.right);
+       break;
+    case FcOpNot:
+       printf ("Not ");
+       FcExprPrint (expr->u.tree.left);
+       break;
+    default:
+       break;
+    }
+}
+
+void
+FcTestPrint (FcTest *test)
+{
+    switch (test->qual) {
+    case FcQualAny:
+       printf ("any ");
+       break;
+    case FcQualAll:
+       printf ("all ");
+       break;
+    }
+    printf ("%s ", test->field);
+    FcOpPrint (test->op);
+    printf (" ");
+    FcExprPrint (test->expr);
+    printf ("\n");
+}
+
+void
+FcEditPrint (FcEdit *edit)
+{
+    printf ("Edit %s ", edit->field);
+    FcOpPrint (edit->op);
+    printf (" ");
+    FcExprPrint (edit->expr);
+}
+
+void
+FcSubstPrint (FcSubst *subst)
+{
+    FcEdit     *e;
+    FcTest     *t;
+    
+    printf ("match\n");
+    for (t = subst->test; t; t = t->next)
+    {
+       printf ("\t");
+       FcTestPrint (t);
+    }
+    printf ("edit\n");
+    for (e = subst->edit; e; e = e->next)
+    {
+       printf ("\t");
+       FcEditPrint (e);
+       printf (";\n");
+    }
+    printf ("\n");
+}
+
+void
+FcFontSetPrint (FcFontSet *s)
+{
+    int            i;
+
+    printf ("FontSet %d of %d\n", s->nfont, s->sfont);
+    for (i = 0; i < s->nfont; i++)
+    {
+       printf ("Font %d ", i);
+       FcPatternPrint (s->fonts[i]);
+    }
+}
+
+int
+FcDebug (void)
+{
+    static int  initialized;
+    static int  debug;
+
+    if (!initialized)
+    {
+       char    *e;
+
+       initialized = 1;
+       e = getenv ("FC_DEBUG");
+       if (e)
+       {
+           printf ("FC_DEBUG=%s\n", e);
+           debug = atoi (e);
+           if (debug < 0)
+               debug = 0;
+       }
+    }
+    return debug;
+}
diff --git a/src/fcdefault.c b/src/fcdefault.c
new file mode 100644 (file)
index 0000000..365595d
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "fcint.h"
+
+static struct {
+    char       *field;
+    FcBool     value;
+} FcBoolDefaults[] = {
+    { FC_HINTING,          FcTrue      },  /* !FT_LOAD_NO_HINTING */
+    { FC_VERTICAL_LAYOUT,   FcFalse    },  /* FC_LOAD_VERTICAL_LAYOUT */
+    { FC_AUTOHINT,         FcFalse     },  /* FC_LOAD_FORCE_AUTOHINT */
+    { FC_GLOBAL_ADVANCE,    FcTrue     },  /* !FC_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH */
+};
+
+#define NUM_FC_BOOL_DEFAULTS   (sizeof FcBoolDefaults / sizeof FcBoolDefaults[0])
+
+void
+FcDefaultSubstitute (FcPattern *pattern)
+{
+    FcValue v;
+    int            i;
+
+    if (FcPatternGet (pattern, FC_STYLE, 0, &v) == FcResultNoMatch)
+    {
+       if (FcPatternGet (pattern, FC_WEIGHT, 0, &v) == FcResultNoMatch )
+       {
+           FcPatternAddInteger (pattern, FC_WEIGHT, FC_WEIGHT_MEDIUM);
+       }
+       if (FcPatternGet (pattern, FC_SLANT, 0, &v) == FcResultNoMatch)
+       {
+           FcPatternAddInteger (pattern, FC_SLANT, FC_SLANT_ROMAN);
+       }
+    }
+
+    for (i = 0; i < NUM_FC_BOOL_DEFAULTS; i++)
+       if (FcPatternGet (pattern, FcBoolDefaults[i].field, 0, &v) == FcResultNoMatch)
+           FcPatternAddBool (pattern, FcBoolDefaults[i].field, FcBoolDefaults[i].value);
+    
+    if (FcPatternGet (pattern, FC_PIXEL_SIZE, 0, &v) == FcResultNoMatch)
+    {
+       double  dpi, size, scale;
+
+       if (FcPatternGetDouble (pattern, FC_SIZE, 0, &size) != FcResultMatch)
+       {
+           size = 12.0;
+           (void) FcPatternDel (pattern, FC_SIZE);
+           FcPatternAddDouble (pattern, FC_SIZE, size);
+       }
+       if (FcPatternGetDouble (pattern, FC_SCALE, 0, &scale) != FcResultMatch)
+       {
+           scale = 1.0;
+           (void) FcPatternDel (pattern, FC_SCALE);
+           FcPatternAddDouble (pattern, FC_SCALE, scale);
+       }
+       size *= scale;
+       if (FcPatternGetDouble (pattern, FC_DPI, 0, &dpi) != FcResultMatch)
+       {
+           dpi = 75.0;
+           (void) FcPatternDel (pattern, FC_DPI);
+           FcPatternAddDouble (pattern, FC_DPI, dpi);
+       }
+       size *= dpi / 72.0;
+       FcPatternAddDouble (pattern, FC_PIXEL_SIZE, size);
+    }
+}
diff --git a/src/fcdir.c b/src/fcdir.c
new file mode 100644 (file)
index 0000000..a49cb54
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <string.h>
+#include "fcint.h"
+
+#define FC_INVALID_FONT_FILE "."
+
+FcBool
+FcFileScan (FcFontSet  *set,
+           FcFileCache *cache,
+           FcBlanks    *blanks,
+           const char  *file,
+           FcBool      force)
+{
+    int                    id;
+    char           *name;
+    FcPattern      *font;
+    FcBool         ret = FcTrue;
+    int                    count;
+    
+    id = 0;
+    do
+    {
+       if (!force && cache)
+           name = FcFileCacheFind (cache, file, id, &count);
+       else
+           name = 0;
+       if (name)
+       {
+           /* "." means the file doesn't contain a font */
+           if (strcmp (name, FC_INVALID_FONT_FILE) != 0)
+           {
+               font = FcNameParse (name);
+               if (font)
+                   FcPatternAddString (font, FC_FILE, file);
+           }
+           else
+               font = 0;
+       }
+       else
+       {
+           if (FcDebug () & FC_DBG_SCAN)
+           {
+               printf ("\tScanning file %s...", file);
+               fflush (stdout);
+           }
+           font = FcFreeTypeQuery (file, id, blanks, &count);
+           if (FcDebug () & FC_DBG_SCAN)
+               printf ("done\n");
+           if (!force && cache)
+           {
+               if (font)
+               {
+                   FcChar8     *unparse;
+
+                   unparse = FcNameUnparse (font);
+                   if (unparse)
+                   {
+                       (void) FcFileCacheUpdate (cache, file, id, unparse);
+                       free (unparse);
+                   }
+               }
+               else
+               {
+                   /* negative cache files not containing fonts */
+                   FcFileCacheUpdate (cache, file, id, FC_INVALID_FONT_FILE);
+               }
+           }
+       }
+       if (font)
+       {
+           if (!FcFontSetAdd (set, font))
+           {
+               FcPatternDestroy (font);
+               font = 0;
+               ret = FcFalse;
+           }
+       }
+       id++;
+    } while (font && ret && id < count);
+    return ret;
+}
+
+FcBool
+FcDirScan (FcFontSet   *set,
+          FcFileCache  *cache,
+          FcBlanks     *blanks,
+          const char   *dir,
+          FcBool       force)
+{
+    DIR                    *d;
+    struct dirent   *e;
+    char           *file;
+    char           *base;
+    FcBool         ret = FcTrue;
+
+    file = (char *) malloc (strlen (dir) + 1 + 256 + 1);
+    if (!file)
+       return FcFalse;
+
+    strcpy (file, dir);
+    strcat (file, "/");
+    base = file + strlen (file);
+    if (!force)
+    {
+       strcpy (base, FC_DIR_CACHE_FILE);
+       
+       if (FcFileCacheReadDir (set, file))
+       {
+           free (file);
+           return FcTrue;
+       }
+    }
+    
+    d = opendir (dir);
+    if (!d)
+    {
+       free (file);
+       return FcFalse;
+    }
+    while (ret && (e = readdir (d)))
+    {
+       if (e->d_name[0] != '.')
+       {
+           strcpy (base, e->d_name);
+           FcFileScan (set, cache, blanks, file, force);
+       }
+    }
+    free (file);
+    closedir (d);
+    return ret;
+}
+
+FcBool
+FcDirSave (FcFontSet *set, const char *dir)
+{
+    char           *file;
+    char           *base;
+    FcBool         ret;
+    
+    file = (char *) malloc (strlen (dir) + 1 + 256 + 1);
+    if (!file)
+       return FcFalse;
+
+    strcpy (file, dir);
+    strcat (file, "/");
+    base = file + strlen (file);
+    strcpy (base, FC_DIR_CACHE_FILE);
+    ret = FcFileCacheWriteDir (set, file);
+    free (file);
+    return ret;
+}
+
diff --git a/src/fcfreetype.c b/src/fcfreetype.c
new file mode 100644 (file)
index 0000000..788b85a
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "fcint.h"
+#include <freetype/freetype.h>
+#include <freetype/internal/ftobjs.h>
+#include <freetype/tttables.h>
+#include <fontconfig/fcfreetype.h>
+
+static const struct {
+    int            bit;
+    char    *name;
+} FcCodePageRange[] = {
+    { 0,       FC_LANG_LATIN_1 },
+    { 1,       FC_LANG_LATIN_2_EASTERN_EUROPE },
+    { 2,       FC_LANG_CYRILLIC },
+    { 3,       FC_LANG_GREEK },
+    { 4,       FC_LANG_TURKISH },
+    { 5,       FC_LANG_HEBREW },
+    { 6,       FC_LANG_ARABIC },
+    { 7,       FC_LANG_WINDOWS_BALTIC },
+    { 8,       FC_LANG_VIETNAMESE },
+/* 9-15 reserved for Alternate ANSI */
+    { 16,      FC_LANG_THAI },
+    { 17,      FC_LANG_JAPANESE },
+    { 18,      FC_LANG_SIMPLIFIED_CHINESE },
+    { 19,      FC_LANG_KOREAN_WANSUNG },
+    { 20,      FC_LANG_TRADITIONAL_CHINESE },
+    { 21,      FC_LANG_KOREAN_JOHAB },
+/* 22-28 reserved for Alternate ANSI & OEM */
+    { 29,      FC_LANG_MACINTOSH },
+    { 30,      FC_LANG_OEM },
+    { 31,      FC_LANG_SYMBOL },
+/* 32-47 reserved for OEM */
+    { 48,      FC_LANG_IBM_GREEK },
+    { 49,      FC_LANG_MSDOS_RUSSIAN },
+    { 50,      FC_LANG_MSDOS_NORDIC },
+    { 51,      FC_LANG_ARABIC_864 },
+    { 52,      FC_LANG_MSDOS_CANADIAN_FRENCH },
+    { 53,      FC_LANG_HEBREW_862 },
+    { 54,      FC_LANG_MSDOS_ICELANDIC },
+    { 55,      FC_LANG_MSDOS_PORTUGUESE },
+    { 56,      FC_LANG_IBM_TURKISH },
+    { 57,      FC_LANG_IBM_CYRILLIC },
+    { 58,      FC_LANG_LATIN_2 },
+    { 59,      FC_LANG_MSDOS_BALTIC },
+    { 60,      FC_LANG_GREEK_437_G },
+    { 61,      FC_LANG_ARABIC_ASMO_708 },
+    { 62,      FC_LANG_WE_LATIN_1 },
+    { 63,      FC_LANG_US },
+};
+
+#define NUM_CODE_PAGE_RANGE (sizeof FcCodePageRange / sizeof FcCodePageRange[0])
+
+FcPattern *
+FcFreeTypeQuery (const char *file,
+                int        id,
+                FcBlanks   *blanks,
+                int        *count)
+{
+    FT_Face    face;
+    FcPattern  *pat;
+    int                slant;
+    int                weight;
+    int                i;
+    FcCharSet  *cs;
+    FT_Library ftLibrary;
+    const char *family;
+    TT_OS2     *os2;
+
+    if (FT_Init_FreeType (&ftLibrary))
+       return 0;
+    
+    if (FT_New_Face (ftLibrary, file, id, &face))
+       goto bail;
+
+    *count = face->num_faces;
+
+    pat = FcPatternCreate ();
+    if (!pat)
+       goto bail0;
+
+    if (!FcPatternAddBool (pat, FC_OUTLINE,
+                          (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
+       goto bail1;
+
+    if (!FcPatternAddBool (pat, FC_SCALABLE,
+                          (face->face_flags & FT_FACE_FLAG_SCALABLE) != 0))
+       goto bail1;
+
+
+    slant = FC_SLANT_ROMAN;
+    if (face->style_flags & FT_STYLE_FLAG_ITALIC)
+       slant = FC_SLANT_ITALIC;
+
+    if (!FcPatternAddInteger (pat, FC_SLANT, slant))
+       goto bail1;
+
+    weight = FC_WEIGHT_MEDIUM;
+    if (face->style_flags & FT_STYLE_FLAG_BOLD)
+       weight = FC_WEIGHT_BOLD;
+
+    if (!FcPatternAddInteger (pat, FC_WEIGHT, weight))
+       goto bail1;
+
+    family = face->family_name;
+    if (!family)
+    {
+       family = strrchr (file, '/');
+       if (family)
+           family++;
+       else
+           family = file;
+    }
+    if (!FcPatternAddString (pat, FC_FAMILY, family))
+       goto bail1;
+
+    if (face->style_name)
+    {
+       if (!FcPatternAddString (pat, FC_STYLE, face->style_name))
+           goto bail1;
+    }
+
+    if (!FcPatternAddString (pat, FC_FILE, file))
+       goto bail1;
+
+    if (!FcPatternAddInteger (pat, FC_INDEX, id))
+       goto bail1;
+
+    if (!FcPatternAddString (pat, FC_SOURCE, "FreeType"))
+       goto bail1;
+
+#if 0
+    if ((face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) != 0)
+       if (!FcPatternAddInteger (pat, FC_SPACING, FC_MONO))
+           goto bail1;
+#endif
+
+    cs = FcFreeTypeCharSet (face, blanks);
+    if (!cs)
+       goto bail1;
+
+    /*
+     * Skip over PCF fonts that have no encoded characters; they're
+     * usually just Unicode fonts transcoded to some legacy encoding
+     */
+    if (FcCharSetCount (cs) == 0)
+    {
+       if (!strcmp(FT_MODULE_CLASS(&face->driver->root)->module_name, "pcf"))
+           goto bail2;
+    }
+
+    if (!FcPatternAddCharSet (pat, FC_CHARSET, cs))
+       goto bail2;
+    /*
+     * Drop our reference to the charset
+     */
+    FcCharSetDestroy (cs);
+    
+    if (!(face->face_flags & FT_FACE_FLAG_SCALABLE))
+    {
+       for (i = 0; i < face->num_fixed_sizes; i++)
+           if (!FcPatternAddDouble (pat, FC_PIXEL_SIZE,
+                                    (double) face->available_sizes[i].height))
+               goto bail1;
+       if (!FcPatternAddBool (pat, FC_ANTIALIAS, FcFalse))
+           goto bail1;
+    }
+
+    /*
+     * Get the OS/2 table and poke about
+     */
+    os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
+    if (os2 && os2->version >= 0x0001 && os2->version != 0xffff)
+    {
+       for (i = 0; i < NUM_CODE_PAGE_RANGE; i++)
+       {
+           FT_ULong    bits;
+           int         bit;
+           if (FcCodePageRange[i].bit < 32)
+           {
+               bits = os2->ulCodePageRange1;
+               bit = FcCodePageRange[i].bit;
+           }
+           else
+           {
+               bits = os2->ulCodePageRange2;
+               bit = FcCodePageRange[i].bit - 32;
+           }
+           if (bits & (1 << bit))
+           {
+               if (!FcPatternAddString (pat, FC_LANG,
+                                        FcCodePageRange[i].name))
+                   goto bail1;
+           }
+       }
+    }
+
+    FT_Done_Face (face);
+    FT_Done_FreeType (ftLibrary);
+    return pat;
+
+bail2:
+    FcCharSetDestroy (cs);
+bail1:
+    FcPatternDestroy (pat);
+bail0:
+    FT_Done_Face (face);
+bail:
+    FT_Done_FreeType (ftLibrary);
+    return 0;
+}
diff --git a/src/fcfs.c b/src/fcfs.c
new file mode 100644 (file)
index 0000000..afc071f
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+FcFontSet *
+FcFontSetCreate (void)
+{
+    FcFontSet  *s;
+
+    s = (FcFontSet *) malloc (sizeof (FcFontSet));
+    if (!s)
+       return 0;
+    FcMemAlloc (FC_MEM_FONTSET, sizeof (FcFontSet));
+    s->nfont = 0;
+    s->sfont = 0;
+    s->fonts = 0;
+    return s;
+}
+
+void
+FcFontSetDestroy (FcFontSet *s)
+{
+    int            i;
+
+    for (i = 0; i < s->nfont; i++)
+       FcPatternDestroy (s->fonts[i]);
+    if (s->fonts)
+    {
+       FcMemFree (FC_MEM_FONTPTR, s->sfont * sizeof (FcPattern *));
+       free (s->fonts);
+    }
+    FcMemFree (FC_MEM_FONTSET, sizeof (FcFontSet));
+    free (s);
+}
+
+FcBool
+FcFontSetAdd (FcFontSet *s, FcPattern *font)
+{
+    FcPattern  **f;
+    int                sfont;
+    
+    if (s->nfont == s->sfont)
+    {
+       sfont = s->sfont + 32;
+       if (s->fonts)
+           f = (FcPattern **) realloc (s->fonts, sfont * sizeof (FcPattern *));
+       else
+           f = (FcPattern **) malloc (sfont * sizeof (FcPattern *));
+       if (!f)
+           return FcFalse;
+       if (s->sfont)
+           FcMemFree (FC_MEM_FONTPTR, s->sfont * sizeof (FcPattern *));
+       FcMemAlloc (FC_MEM_FONTPTR, sfont * sizeof (FcPattern *));
+       s->sfont = sfont;
+       s->fonts = f;
+    }
+    s->fonts[s->nfont++] = font;
+    return FcTrue;
+}
diff --git a/src/fcinit.c b/src/fcinit.c
new file mode 100644 (file)
index 0000000..f82e018
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2001 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+FcBool
+FcInitFonts (void)
+{
+    FcConfig   *config;
+
+    config = FcConfigGetCurrent ();
+    if (!config)
+       return FcFalse;
+
+    if (FcConfigGetFonts (config, FcSetSystem))
+       return FcTrue;
+
+    return FcConfigBuildFonts (config);
+}
+
+static FcBool
+FcInitFallbackConfig (void)
+{
+    FcConfig   *config;
+
+    config = FcConfigCreate ();
+    if (!config)
+       goto bail0;
+    if (!FcConfigAddDir (config, FC_FALLBACK_FONTS))
+       goto bail1;
+    FcConfigSetCurrent (config);
+    return FcTrue;
+
+bail1:
+    FcConfigDestroy (config);
+bail0:
+    return FcFalse;
+}
+
+/*
+ * Locate and parse the configuration file
+ */
+FcBool
+FcInitConfig (void)
+{
+    FcConfig    *config;
+    
+    if (FcConfigGetCurrent ())
+       return FcTrue;
+    
+    config = FcConfigCreate ();
+    if (!config)
+       return FcFalse;
+    
+    if (!FcConfigParseAndLoad (config, 0, FcTrue))
+    {
+       FcConfigDestroy (config);
+       return FcInitFallbackConfig ();
+    }
+    
+    FcConfigSetCurrent (config);
+    return FcTrue;
+}
+
+FcBool
+FcInit (void)
+{
+    return FcInitConfig () && FcInitFonts ();
+}
+
+static struct {
+    char    *name;
+    int            alloc_count;
+    int            alloc_mem;
+    int            free_count;
+    int            free_mem;
+} FcInUse[FC_MEM_NUM] = {
+    { "charset", 0, 0 },
+    { "charnode", 0 ,0 },
+    { "fontset", 0, 0 },
+    { "fontptr", 0, 0 },
+    { "objectset", 0, 0 },
+    { "objectptr", 0, 0 },
+    { "matrix", 0, 0 },
+    { "pattern", 0, 0 },
+    { "patelt", 0, 0 },
+    { "vallist", 0, 0 },
+    { "substate", 0, 0 },
+    { "string", 0, 0 },
+    { "listbuck", 0, 0 },
+};
+
+static int  FcAllocCount, FcAllocMem;
+static int  FcFreeCount, FcFreeMem;
+
+static int  FcMemNotice = 1*1024*1024;
+
+static int  FcAllocNotify, FcFreeNotify;
+
+void
+FcMemReport (void)
+{
+    int        i;
+    printf ("Fc Memory Usage:\n");
+    printf ("\t   Which       Alloc           Free           Active\n");
+    printf ("\t           count   bytes   count   bytes   count   bytes\n");
+    for (i = 0; i < FC_MEM_NUM; i++)
+       printf ("\t%8.8s%8d%8d%8d%8d%8d%8d\n",
+               FcInUse[i].name,
+               FcInUse[i].alloc_count, FcInUse[i].alloc_mem,
+               FcInUse[i].free_count, FcInUse[i].free_mem,
+               FcInUse[i].alloc_count - FcInUse[i].free_count,
+               FcInUse[i].alloc_mem - FcInUse[i].free_mem);
+    printf ("\t%8.8s%8d%8d%8d%8d%8d%8d\n",
+           "Total",
+           FcAllocCount, FcAllocMem,
+           FcFreeCount, FcFreeMem,
+           FcAllocCount - FcFreeCount,
+           FcAllocMem - FcFreeMem);
+    FcAllocNotify = 0;
+    FcFreeNotify = 0;
+}
+
+void
+FcMemAlloc (int kind, int size)
+{
+    if (FcDebug() & FC_DBG_MEMORY)
+    {
+       FcInUse[kind].alloc_count++;
+       FcInUse[kind].alloc_mem += size;
+       FcAllocCount++;
+       FcAllocMem += size;
+       FcAllocNotify += size;
+       if (FcAllocNotify > FcMemNotice)
+           FcMemReport ();
+    }
+}
+
+void
+FcMemFree (int kind, int size)
+{
+    if (FcDebug() & FC_DBG_MEMORY)
+    {
+       FcInUse[kind].free_count++;
+       FcInUse[kind].free_mem += size;
+       FcFreeCount++;
+       FcFreeMem += size;
+       FcFreeNotify += size;
+       if (FcFreeNotify > FcMemNotice)
+           FcMemReport ();
+    }
+}
diff --git a/src/fcint.h b/src/fcint.h
new file mode 100644 (file)
index 0000000..139df3b
--- /dev/null
@@ -0,0 +1,480 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _FCINT_H_
+#define _FCINT_H_
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <libxml/parserInternals.h>
+#include <fontconfig/fontconfig.h>
+#include <fontconfig/fcprivate.h>
+#include <fontconfig/fcxml.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+typedef struct _FcMatcher {
+    char    *object;
+    double  (*compare) (char *object, FcValue value1, FcValue value2);
+} FcMatcher;
+
+typedef struct _FcSymbolic {
+    const char *name;
+    int                value;
+} FcSymbolic;
+
+#ifndef FC_CONFIG_PATH
+#define FC_CONFIG_PATH "fonts.conf"
+#endif
+
+#define FC_DBG_MATCH   1
+#define FC_DBG_MATCHV  2
+#define FC_DBG_EDIT    4
+#define FC_DBG_FONTSET 8
+#define FC_DBG_CACHE   16
+#define FC_DBG_CACHEV  32
+#define FC_DBG_PARSE   64
+#define FC_DBG_SCAN    128
+#define FC_DBG_MEMORY  512
+
+#define FC_MEM_CHARSET     0
+#define FC_MEM_CHARNODE            1
+#define FC_MEM_FONTSET     2
+#define FC_MEM_FONTPTR     3
+#define FC_MEM_OBJECTSET    4
+#define FC_MEM_OBJECTPTR    5
+#define FC_MEM_MATRIX      6
+#define FC_MEM_PATTERN     7
+#define FC_MEM_PATELT      8
+#define FC_MEM_VALLIST     9
+#define FC_MEM_SUBSTATE            10
+#define FC_MEM_STRING      11
+#define FC_MEM_LISTBUCK            12
+#define FC_MEM_NUM         13
+
+typedef struct _FcValueList {
+    struct _FcValueList    *next;
+    FcValue                value;
+} FcValueList;
+
+typedef struct _FcPatternElt {
+    const char     *object;
+    FcValueList    *values;
+} FcPatternElt;
+
+struct _FcPattern {
+    int                    num;
+    int                    size;
+    FcPatternElt   *elts;
+};
+
+typedef enum _FcOp {
+    FcOpInteger, FcOpDouble, FcOpString, FcOpMatrix, FcOpBool, FcOpCharSet, 
+    FcOpNil,
+    FcOpField, FcOpConst,
+    FcOpAssign, FcOpAssignReplace, 
+    FcOpPrependFirst, FcOpPrepend, FcOpAppend, FcOpAppendLast,
+    FcOpQuest,
+    FcOpOr, FcOpAnd, FcOpEqual, FcOpNotEqual, FcOpContains,
+    FcOpLess, FcOpLessEqual, FcOpMore, FcOpMoreEqual,
+    FcOpPlus, FcOpMinus, FcOpTimes, FcOpDivide,
+    FcOpNot, FcOpComma, FcOpInvalid
+} FcOp;
+
+typedef struct _FcExpr {
+    FcOp   op;
+    union {
+       int         ival;
+       double      dval;
+       char        *sval;
+       FcMatrix    *mval;
+       FcBool      bval;
+       FcCharSet   *cval;
+       char        *field;
+       char        *constant;
+       struct {
+           struct _FcExpr *left, *right;
+       } tree;
+    } u;
+} FcExpr;
+
+typedef enum _FcQual {
+    FcQualAny, FcQualAll
+} FcQual;
+
+typedef struct _FcTest {
+    struct _FcTest     *next;
+    FcQual             qual;
+    const char         *field;
+    FcOp               op;
+    FcExpr             *expr;
+} FcTest;
+
+typedef struct _FcEdit {
+    struct _FcEdit *next;
+    const char     *field;
+    FcOp           op;
+    FcExpr         *expr;
+} FcEdit;
+
+typedef struct _FcSubst {
+    struct _FcSubst    *next;
+    FcTest             *test;
+    FcEdit             *edit;
+} FcSubst;
+
+typedef struct _FcCharLeaf FcCharLeaf;
+typedef struct _FcCharBranch FcCharBranch;
+typedef union  _FcCharNode FcCharNode;
+
+struct _FcCharLeaf {
+    FcChar32   map[256/32];
+};
+
+union _FcCharNode {
+    FcCharBranch    *branch;
+    FcCharLeaf     *leaf;
+};
+
+struct _FcCharBranch {
+    FcCharNode     nodes[256];
+};
+
+struct _FcCharSet {
+    int                    levels;
+    int                    ref;        /* reference count */
+    FcBool         constant;   /* shared constant */
+    FcCharNode     node;
+};
+
+typedef struct _FcNameBuf {
+    FcChar8 *buf;
+    FcBool  allocated;
+    FcBool  failed;
+    int            len;
+    int            size;
+} FcNameBuf;
+
+typedef struct _FcFileCacheEnt {
+    struct _FcFileCacheEnt *next;
+    unsigned int           hash;
+    char                   *file;
+    int                            id;
+    time_t                 time;
+    char                   *name;
+    FcBool                 referenced;
+} FcFileCacheEnt;
+
+#define FC_FILE_CACHE_HASH_SIZE   509
+
+struct _FcFileCache {
+    FcFileCacheEnt     *ents[FC_FILE_CACHE_HASH_SIZE];
+    FcBool             updated;
+    int                        entries;
+    int                        referenced;
+};
+
+struct _FcBlanks {
+    int                nblank;
+    int                sblank;
+    FcChar32   *blanks;
+};
+
+struct _FcConfig {
+    /*
+     * File names loaded from the configuration -- saved here as the
+     * cache file must be consulted before the directories are scanned,
+     * and those directives may occur in any order
+     */
+    char       **dirs;             /* directories containing fonts */
+    char       *cache;             /* name of per-user cache file */
+    /*
+     * Set of allowed blank chars -- used to
+     * trim fonts of bogus glyphs
+     */
+    FcBlanks   *blanks;
+    /*
+     * Names of all of the configuration files used
+     * to create this configuration
+     */
+    char       **configFiles;      /* config files loaded */
+    /*
+     * Substitution instructions for patterns and fonts;
+     * maxObjects is used to allocate appropriate intermediate storage
+     * while performing a whole set of substitutions
+     */
+    FcSubst    *substPattern;      /* substitutions for patterns */
+    FcSubst    *substFont;         /* substitutions for fonts */
+    int                maxObjects;         /* maximum number of tests in all substs */
+    /*
+     * The set of fonts loaded from the listed directories; the
+     * order within the set does not determine the font selection,
+     * except in the case of identical matches in which case earlier fonts
+     * match preferrentially
+     */
+    FcFontSet  *fonts[FcSetApplication + 1];
+};
+/* fcblanks.c */
+
+/* fccache.c */
+
+FcFileCache *
+FcFileCacheCreate (void);
+
+char *
+FcFileCacheFind (FcFileCache   *cache,
+                const char     *file,
+                int            id,
+                int            *count);
+
+void
+FcFileCacheDestroy (FcFileCache        *cache);
+
+void
+FcFileCacheLoad (FcFileCache   *cache,
+                const char     *cache_file);
+
+FcBool
+FcFileCacheUpdate (FcFileCache *cache,
+                  const char   *file,
+                  int          id,
+                  const char   *name);
+
+FcBool
+FcFileCacheSave (FcFileCache   *cache,
+                const char     *cache_file);
+
+FcBool
+FcFileCacheReadDir (FcFontSet *set, const char *cache_file);
+
+FcBool
+FcFileCacheWriteDir (FcFontSet *set, const char *cache_file);
+    
+/* fccfg.c */
+
+FcBool
+FcConfigAddDir (FcConfig    *config,
+               const char  *d);
+
+FcBool
+FcConfigAddConfigFile (FcConfig            *config,
+                      const char   *f);
+
+FcBool
+FcConfigSetCache (FcConfig     *config,
+                 const char    *c);
+
+FcBool
+FcConfigAddBlank (FcConfig     *config,
+                 FcChar32      blank);
+
+FcBool
+FcConfigAddEdit (FcConfig      *config,
+                FcTest         *test,
+                FcEdit         *edit,
+                FcMatchKind    kind);
+
+void
+FcConfigSetFonts (FcConfig     *config,
+                 FcFontSet     *fonts,
+                 FcSetName     set);
+
+FcBool
+FcConfigCompareValue (const FcValue m,
+                     FcOp          op,
+                     const FcValue v);
+
+/* fccharset.c */
+FcBool
+FcNameUnparseCharSet (FcNameBuf *buf, const FcCharSet *c);
+
+FcCharSet *
+FcNameParseCharSet (FcChar8 *string);
+
+/* fcdbg.c */
+void
+FcValuePrint (FcValue v);
+
+void
+FcValueListPrint (FcValueList *l);
+
+void
+FcPatternPrint (FcPattern *p);
+
+void
+FcOpPrint (FcOp op);
+
+void
+FcTestPrint (FcTest *test);
+
+void
+FcExprPrint (FcExpr *expr);
+
+void
+FcEditPrint (FcEdit *edit);
+
+void
+FcSubstPrint (FcSubst *subst);
+
+void
+FcFontSetPrint (FcFontSet *s);
+
+int
+FcDebug (void);
+
+/* fcdir.c */
+FcBool
+FcFileScan (FcFontSet  *set,
+           FcFileCache *cache,
+           FcBlanks    *blanks,
+           const char  *file,
+           FcBool      force);
+
+FcBool
+FcDirScan (FcFontSet   *set,
+          FcFileCache  *cache,
+          FcBlanks     *blanks,
+          const char   *dir,
+          FcBool       force);
+
+FcBool
+FcDirSave (FcFontSet *set, const char *dir);
+
+/* fcfont.c */
+int
+FcFontDebug (void);
+    
+/* fcfs.c */
+/* fcgram.y */
+int
+FcConfigparse (void);
+
+int
+FcConfigwrap (void);
+    
+void
+FcConfigerror (char *fmt, ...);
+    
+char *
+FcConfigSaveField (const char *field);
+
+FcTest *
+FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr);
+
+void
+FcTestDestroy (FcTest *test);
+
+FcExpr *
+FcExprCreateInteger (int i);
+
+FcExpr *
+FcExprCreateDouble (double d);
+
+FcExpr *
+FcExprCreateString (const char *s);
+
+FcExpr *
+FcExprCreateMatrix (const FcMatrix *m);
+
+FcExpr *
+FcExprCreateBool (FcBool b);
+
+FcExpr *
+FcExprCreateNil (void);
+
+FcExpr *
+FcExprCreateField (const char *field);
+
+FcExpr *
+FcExprCreateConst (const char *constant);
+
+FcExpr *
+FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right);
+
+void
+FcExprDestroy (FcExpr *e);
+
+FcEdit *
+FcEditCreate (const char *field, FcOp op, FcExpr *expr);
+
+void
+FcEditDestroy (FcEdit *e);
+
+/* fcinit.c */
+
+void
+FcMemReport (void);
+
+void
+FcMemAlloc (int kind, int size);
+
+void
+FcMemFree (int kind, int size);
+
+/* fclist.c */
+
+/* fcmatch.c */
+
+/* fcname.c */
+FcBool
+FcNameConstant (char *string, int *result);
+
+FcBool
+FcNameBool (char *v, FcBool *result);
+
+FcBool
+FcNameBufChar (FcNameBuf *buf, FcChar8 c);
+
+FcBool
+FcNameBufString (FcNameBuf *buf, const FcChar8 *s);
+
+/* fcpat.c */
+void
+FcValueListDestroy (FcValueList *l);
+    
+FcPatternElt *
+FcPatternFind (FcPattern *p, const char *object, FcBool insert);
+
+/* fcrender.c */
+
+/* fcmatrix.c */
+void
+FcMatrixFree (FcMatrix *mat);
+
+/* fcstr.c */
+char *
+FcStrPlus (const char *s1, const char *s2);
+    
+void
+FcStrFree (char *s);
+
+#endif /* _FC_INT_H_ */
diff --git a/src/fclist.c b/src/fclist.c
new file mode 100644 (file)
index 0000000..4cbfed2
--- /dev/null
@@ -0,0 +1,442 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "fcint.h"
+
+FcObjectSet *
+FcObjectSetCreate (void)
+{
+    FcObjectSet    *os;
+
+    os = (FcObjectSet *) malloc (sizeof (FcObjectSet));
+    if (!os)
+       return 0;
+    FcMemAlloc (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
+    os->nobject = 0;
+    os->sobject = 0;
+    os->objects = 0;
+    return os;
+}
+
+FcBool
+FcObjectSetAdd (FcObjectSet *os, const char *object)
+{
+    int                s;
+    const char **objects;
+    
+    if (os->nobject == os->sobject)
+    {
+       s = os->sobject + 4;
+       if (os->objects)
+           objects = (const char **) realloc ((void *) os->objects,
+                                              s * sizeof (const char *));
+       else
+           objects = (const char **) malloc (s * sizeof (const char *));
+       if (!objects)
+           return FcFalse;
+       if (os->sobject)
+           FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
+       FcMemAlloc (FC_MEM_OBJECTPTR, s * sizeof (const char *));
+       os->objects = objects;
+       os->sobject = s;
+    }
+    os->objects[os->nobject++] = object;
+    return FcTrue;
+}
+
+void
+FcObjectSetDestroy (FcObjectSet *os)
+{
+    if (os->objects)
+    {
+       FcMemFree (FC_MEM_OBJECTPTR, os->sobject * sizeof (const char *));
+       free ((void *) os->objects);
+    }
+    FcMemFree (FC_MEM_OBJECTSET, sizeof (FcObjectSet));
+    free (os);
+}
+
+FcObjectSet *
+FcObjectSetVaBuild (const char *first, va_list va)
+{
+    FcObjectSet    *ret;
+
+    FcObjectSetVapBuild (ret, first, va);
+    return ret;
+}
+
+FcObjectSet *
+FcObjectSetBuild (const char *first, ...)
+{
+    va_list        va;
+    FcObjectSet    *os;
+
+    va_start (va, first);
+    FcObjectSetVapBuild (os, first, va);
+    va_end (va);
+    return os;
+}
+
+static FcBool
+FcListValueListMatchAny (FcValueList *v1orig,
+                        FcValueList *v2orig)
+{
+    FcValueList            *v1, *v2;
+
+    for (v1 = v1orig; v1; v1 = v1->next)
+       for (v2 = v2orig; v2; v2 = v2->next)
+           if (FcConfigCompareValue (v2->value, FcOpContains, v1->value))
+               return FcTrue;
+    return FcFalse;
+}
+
+static FcBool
+FcListValueListEqual (FcValueList   *v1orig,
+                     FcValueList   *v2orig)
+{
+    FcValueList            *v1, *v2;
+
+    for (v1 = v1orig; v1; v1 = v1->next)
+    {
+       for (v2 = v2orig; v2; v2 = v2->next)
+           if (FcConfigCompareValue (v1->value, FcOpEqual, v2->value))
+               break;
+       if (!v2)
+           return FcFalse;
+    }
+    for (v2 = v2orig; v2; v2 = v2->next)
+    {
+       for (v1 = v1orig; v1; v1 = v1->next)
+           if (FcConfigCompareValue (v1->value, FcOpEqual, v2->value))
+               break;
+       if (!v1)
+           return FcFalse;
+    }
+    return FcTrue;
+}
+
+/*
+ * FcTrue iff all objects in "p" match "font"
+ */
+
+static FcBool
+FcListPatternMatchAny (FcPattern *p,
+                      FcPattern *font)
+{
+    int                    i;
+    FcPatternElt   *e;
+
+    for (i = 0; i < p->num; i++)
+    {
+       e = FcPatternFind (font, p->elts[i].object, FcFalse);
+       if (!e)
+           return FcFalse;
+       if (!FcListValueListMatchAny (p->elts[i].values, e->values))
+           return FcFalse;
+    }
+    return FcTrue;
+}
+
+static FcBool
+FcListPatternEqual (FcPattern  *p1,
+                   FcPattern   *p2,
+                   FcObjectSet *os)
+{
+    int                    i;
+    FcPatternElt    *e1, *e2;
+
+    for (i = 0; i < os->nobject; i++)
+    {
+       e1 = FcPatternFind (p1, os->objects[i], FcFalse);
+       e2 = FcPatternFind (p2, os->objects[i], FcFalse);
+       if (!e1 && !e2)
+           return FcTrue;
+       if (!e1 || !e2)
+           return FcFalse;
+       if (!FcListValueListEqual (e1->values, e2->values))
+           return FcFalse;
+    }
+    return FcTrue;
+}
+
+static FcChar32
+FcListStringHash (const FcChar8        *s)
+{
+    FcChar32   h = 0;
+    FcChar8    c;
+
+    while ((c = *s++))
+    {
+       c = FcToLower (c);
+       h = ((h << 3) ^ (h >> 3)) ^ c;
+    }
+    return h;
+}
+
+static FcChar32
+FcListMatrixHash (const FcMatrix *m)
+{
+    int            xx = (int) (m->xx * 100), 
+           xy = (int) (m->xy * 100), 
+           yx = (int) (m->yx * 100),
+           yy = (int) (m->yy * 100);
+
+    return ((FcChar32) xx) ^ ((FcChar32) xy) ^ ((FcChar32) yx) ^ ((FcChar32) yy);
+}
+
+static FcChar32
+FcListValueHash (FcValue    v)
+{
+    switch (v.type) {
+    case FcTypeVoid:
+       return 0;
+    case FcTypeInteger:
+       return (FcChar32) v.u.i;
+    case FcTypeDouble:
+       return (FcChar32) (int) v.u.d;
+    case FcTypeString:
+       return FcListStringHash (v.u.s);
+    case FcTypeBool:
+       return (FcChar32) v.u.b;
+    case FcTypeMatrix:
+       return FcListMatrixHash (v.u.m);
+    case FcTypeCharSet:
+       return FcCharSetCount (v.u.c);
+    }
+    return 0;
+}
+
+static FcChar32
+FcListValueListHash (FcValueList    *list)
+{
+    FcChar32   h = 0;
+    
+    while (list)
+    {
+       h = h ^ FcListValueHash (list->value);
+       list = list->next;
+    }
+    return h;
+}
+
+static FcChar32
+FcListPatternHash (FcPattern   *font,
+                  FcObjectSet  *os)
+{
+    int                    n;
+    FcPatternElt    *e;
+    FcChar32       h = 0;
+
+    for (n = 0; n < os->nobject; n++)
+    {
+       e = FcPatternFind (font, os->objects[n], FcFalse);
+       if (e)
+           h = h ^ FcListValueListHash (e->values);
+    }
+    return h;
+}
+
+typedef struct _FcListBucket {
+    struct _FcListBucket    *next;
+    FcChar32               hash;
+    FcPattern              *pattern;
+} FcListBucket;
+
+#define FC_LIST_HASH_SIZE   4099
+
+typedef struct _FcListHashTable {
+    int                    entries;
+    FcListBucket    *buckets[FC_LIST_HASH_SIZE];
+} FcListHashTable;
+    
+static void
+FcListHashTableInit (FcListHashTable *table)
+{
+    table->entries = 0;
+    memset (table->buckets, '\0', sizeof (table->buckets));
+}
+
+static void
+FcListHashTableCleanup (FcListHashTable *table)
+{
+    int        i;
+    FcListBucket    *bucket, *next;
+
+    for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+    {
+       for (bucket = table->buckets[i]; bucket; bucket = next)
+       {
+           next = bucket->next;
+           FcPatternDestroy (bucket->pattern);
+           FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+           free (bucket);
+       }
+       table->buckets[i] = 0;
+    }
+    table->entries = 0;
+}
+
+static FcBool
+FcListAppend (FcListHashTable  *table,
+             FcPattern         *font,
+             FcObjectSet       *os)
+{
+    int                    o;
+    FcPatternElt    *e;
+    FcValueList            *v;
+    FcChar32       hash;
+    FcListBucket    **prev, *bucket;
+
+    hash = FcListPatternHash (font, os);
+    for (prev = &table->buckets[hash % FC_LIST_HASH_SIZE];
+        (bucket = *prev); prev = &(bucket->next))
+    {
+       if (bucket->hash == hash && 
+           FcListPatternEqual (bucket->pattern, font, os))
+           return FcTrue;
+    }
+    bucket = (FcListBucket *) malloc (sizeof (FcListBucket));
+    if (!bucket)
+       goto bail0;
+    FcMemAlloc (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+    bucket->next = 0;
+    bucket->hash = hash;
+    bucket->pattern = FcPatternCreate ();
+    if (!bucket->pattern)
+       goto bail1;
+    
+    for (o = 0; o < os->nobject; o++)
+    {
+       e = FcPatternFind (font, os->objects[o], FcFalse);
+       if (e)
+       {
+           for (v = e->values; v; v = v->next)
+           {
+               if (!FcPatternAdd (bucket->pattern, 
+                                  os->objects[o], 
+                                  v->value, FcTrue))
+                   goto bail2;
+           }
+       }
+    }
+    *prev = bucket;
+    ++table->entries;
+
+    return FcTrue;
+    
+bail2:
+    FcPatternDestroy (bucket->pattern);
+bail1:
+    FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+    free (bucket);
+bail0:
+    return FcFalse;
+}
+
+FcFontSet *
+FcFontList (FcConfig   *config,
+           FcPattern   *p,
+           FcObjectSet *os)
+{
+    FcFontSet      *ret;
+    FcFontSet      *s;
+    int                    f;
+    FcSetName      set;
+    FcListHashTable table;
+    int                    i;
+    FcListBucket    *bucket;
+
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           goto bail0;
+    }
+    FcListHashTableInit (&table);
+    /*
+     * Walk all available fonts adding those that
+     * match to the hash table
+     */
+    for (set = FcSetSystem; set <= FcSetApplication; set++)
+    {
+       s = config->fonts[set];
+       if (!s)
+           continue;
+       for (f = 0; f < s->nfont; f++)
+           if (FcListPatternMatchAny (p, s->fonts[f]))
+               if (!FcListAppend (&table, s->fonts[f], os))
+                   goto bail1;
+    }
+#if 0
+    {
+       int     max = 0;
+       int     full = 0;
+       int     ents = 0;
+       int     len;
+       for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+       {
+           if ((bucket = table.buckets[i]))
+           {
+               len = 0;
+               for (; bucket; bucket = bucket->next)
+               {
+                   ents++;
+                   len++;
+               }
+               if (len > max)
+                   max = len;
+               full++;
+           }
+       }
+       printf ("used: %d max: %d avg: %g\n", full, max, 
+               (double) ents / FC_LIST_HASH_SIZE);
+    }
+#endif
+    /*
+     * Walk the hash table and build
+     * a font set
+     */
+    ret = FcFontSetCreate ();
+    if (!ret)
+       goto bail0;
+    for (i = 0; i < FC_LIST_HASH_SIZE; i++)
+       while ((bucket = table.buckets[i]))
+       {
+           if (!FcFontSetAdd (ret, bucket->pattern))
+               goto bail2;
+           table.buckets[i] = bucket->next;
+           FcMemFree (FC_MEM_LISTBUCK, sizeof (FcListBucket));
+           free (bucket);
+       }
+    
+    return ret;
+
+bail2:
+    FcFontSetDestroy (ret);
+bail1:
+    FcListHashTableCleanup (&table);
+bail0:
+    return 0;
+}
diff --git a/src/fcmatch.c b/src/fcmatch.c
new file mode 100644 (file)
index 0000000..069f69f
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+#include <ctype.h>
+#include "fcint.h"
+#include <stdio.h>
+
+static double
+FcCompareInteger (char *object, FcValue value1, FcValue value2)
+{
+    int        v;
+    
+    if (value2.type != FcTypeInteger || value1.type != FcTypeInteger)
+       return -1.0;
+    v = value2.u.i - value1.u.i;
+    if (v < 0)
+       v = -v;
+    return (double) v;
+}
+
+static double
+FcCompareString (char *object, FcValue value1, FcValue value2)
+{
+    if (value2.type != FcTypeString || value1.type != FcTypeString)
+       return -1.0;
+    return (double) FcStrCmpIgnoreCase (value1.u.s, value2.u.s) != 0;
+}
+
+static double
+FcCompareBool (char *object, FcValue value1, FcValue value2)
+{
+    if (value2.type != FcTypeBool || value1.type != FcTypeBool)
+       return -1.0;
+    return (double) value2.u.b != value1.u.b;
+}
+
+static double
+FcCompareCharSet (char *object, FcValue value1, FcValue value2)
+{
+    if (value2.type != FcTypeCharSet || value1.type != FcTypeCharSet)
+       return -1.0;
+    return (double) FcCharSetSubtractCount (value1.u.c, value2.u.c);
+}
+
+static double
+FcCompareSize (char *object, FcValue value1, FcValue value2)
+{
+    double  v1, v2, v;
+
+    switch (value1.type) {
+    case FcTypeInteger:
+       v1 = value1.u.i;
+       break;
+    case FcTypeDouble:
+       v1 = value1.u.d;
+       break;
+    default:
+       return -1;
+    }
+    switch (value2.type) {
+    case FcTypeInteger:
+       v2 = value2.u.i;
+       break;
+    case FcTypeDouble:
+       v2 = value2.u.d;
+       break;
+    default:
+       return -1;
+    }
+    if (v2 == 0)
+       return 0;
+    v = v2 - v1;
+    if (v < 0)
+       v = -v;
+    return v;
+}
+
+/*
+ * Order is significant, it defines the precedence of
+ * each value, earlier values are more significant than
+ * later values
+ */
+static FcMatcher _FcMatchers [] = {
+    { FC_FOUNDRY,      FcCompareString, },
+    { FC_CHARSET,      FcCompareCharSet },
+    { FC_ANTIALIAS,    FcCompareBool, },
+    { FC_LANG,         FcCompareString },
+    { FC_FAMILY,       FcCompareString, },
+    { FC_SPACING,      FcCompareInteger, },
+    { FC_PIXEL_SIZE,   FcCompareSize, },
+    { FC_STYLE,                FcCompareString, },
+    { FC_SLANT,                FcCompareInteger, },
+    { FC_WEIGHT,       FcCompareInteger, },
+    { FC_RASTERIZER,   FcCompareString, },
+    { FC_OUTLINE,      FcCompareBool, },
+};
+
+#define NUM_MATCHER (sizeof _FcMatchers / sizeof _FcMatchers[0])
+
+static FcBool
+FcCompareValueList (const char  *object,
+                   FcValueList *v1orig,        /* pattern */
+                   FcValueList *v2orig,        /* target */
+                   FcValue     *bestValue,
+                   double      *value,
+                   FcResult    *result)
+{
+    FcValueList    *v1, *v2;
+    double         v, best;
+    int                    j;
+    int                    i;
+    
+    for (i = 0; i < NUM_MATCHER; i++)
+    {
+       if (!FcStrCmpIgnoreCase (_FcMatchers[i].object, object))
+           break;
+    }
+    if (i == NUM_MATCHER)
+    {
+       if (bestValue)
+           *bestValue = v2orig->value;
+       return FcTrue;
+    }
+    
+    best = 1e99;
+    j = 0;
+    for (v1 = v1orig; v1; v1 = v1->next)
+    {
+       for (v2 = v2orig; v2; v2 = v2->next)
+       {
+           v = (*_FcMatchers[i].compare) (_FcMatchers[i].object,
+                                           v1->value,
+                                           v2->value);
+           if (v < 0)
+           {
+               *result = FcResultTypeMismatch;
+               return FcFalse;
+           }
+           if (FcDebug () & FC_DBG_MATCHV)
+               printf (" v %g j %d ", v, j);
+           v = v * 100 + j;
+           if (v < best)
+           {
+               if (bestValue)
+                   *bestValue = v2->value;
+               best = v;
+           }
+       }
+       j++;
+    }
+    if (FcDebug () & FC_DBG_MATCHV)
+    {
+       printf (" %s: %g ", object, best);
+       FcValueListPrint (v1orig);
+       printf (", ");
+       FcValueListPrint (v2orig);
+       printf ("\n");
+    }
+    value[i] += best;
+    return FcTrue;
+}
+
+/*
+ * Return a value indicating the distance between the two lists of
+ * values
+ */
+
+static FcBool
+FcCompare (FcPattern   *pat,
+          FcPattern    *fnt,
+          double       *value,
+          FcResult     *result)
+{
+    int                    i, i1, i2;
+    
+    for (i = 0; i < NUM_MATCHER; i++)
+       value[i] = 0.0;
+    
+    for (i1 = 0; i1 < pat->num; i1++)
+    {
+       for (i2 = 0; i2 < fnt->num; i2++)
+       {
+           if (!FcStrCmpIgnoreCase (pat->elts[i1].object,
+                                    fnt->elts[i2].object))
+           {
+               if (!FcCompareValueList (pat->elts[i1].object,
+                                        pat->elts[i1].values,
+                                        fnt->elts[i2].values,
+                                        0,
+                                        value,
+                                        result))
+                   return FcFalse;
+               break;
+           }
+       }
+#if 0
+       /*
+        * Overspecified patterns are slightly penalized in
+        * case some other font includes the requested field
+        */
+       if (i2 == fnt->num)
+       {
+           for (i2 = 0; i2 < NUM_MATCHER; i2++)
+           {
+               if (!FcStrCmpIgnoreCase (_FcMatchers[i2].object,
+                                        pat->elts[i1].object))
+               {
+                   value[i2] = 1.0;
+                   break;
+               }
+           }
+       }
+#endif
+    }
+    return FcTrue;
+}
+
+FcPattern *
+FcFontMatch (FcConfig  *config,
+            FcPattern  *p, 
+            FcResult   *result)
+{
+    double         score[NUM_MATCHER], bestscore[NUM_MATCHER];
+    int                    f;
+    FcFontSet      *s;
+    FcPattern      *best;
+    FcPattern      *new;
+    FcPatternElt   *fe, *pe;
+    FcValue        v;
+    int                    i;
+    FcSetName      set;
+
+    for (i = 0; i < NUM_MATCHER; i++)
+       bestscore[i] = 0;
+    best = 0;
+    if (FcDebug () & FC_DBG_MATCH)
+    {
+       printf ("Match ");
+       FcPatternPrint (p);
+    }
+    if (!config)
+    {
+       config = FcConfigGetCurrent ();
+       if (!config)
+           return 0;
+    }
+    for (set = FcSetSystem; set <= FcSetApplication; set++)
+    {
+       s = config->fonts[set];
+       if (!s)
+           continue;
+       for (f = 0; f < s->nfont; f++)
+       {
+           if (FcDebug () & FC_DBG_MATCHV)
+           {
+               printf ("Font %d ", f);
+               FcPatternPrint (s->fonts[f]);
+           }
+           if (!FcCompare (p, s->fonts[f], score, result))
+               return 0;
+           if (FcDebug () & FC_DBG_MATCHV)
+           {
+               printf ("Score");
+               for (i = 0; i < NUM_MATCHER; i++)
+               {
+                   printf (" %g", score[i]);
+               }
+               printf ("\n");
+           }
+           for (i = 0; i < NUM_MATCHER; i++)
+           {
+               if (best && bestscore[i] < score[i])
+                   break;
+               if (!best || score[i] < bestscore[i])
+               {
+                   for (i = 0; i < NUM_MATCHER; i++)
+                       bestscore[i] = score[i];
+                   best = s->fonts[f];
+                   break;
+               }
+           }
+       }
+    }
+    if (FcDebug () & FC_DBG_MATCH)
+    {
+       printf ("Best score");
+       for (i = 0; i < NUM_MATCHER; i++)
+           printf (" %g", bestscore[i]);
+       FcPatternPrint (best);
+    }
+    if (!best)
+    {
+       *result = FcResultNoMatch;
+       return 0;
+    }
+    new = FcPatternCreate ();
+    if (!new)
+       return 0;
+    for (i = 0; i < best->num; i++)
+    {
+       fe = &best->elts[i];
+       pe = FcPatternFind (p, fe->object, FcFalse);
+       if (pe)
+       {
+           if (!FcCompareValueList (pe->object, pe->values, 
+                                    fe->values, &v, score, result))
+           {
+               FcPatternDestroy (new);
+               return 0;
+           }
+       }
+       else
+           v = fe->values->value;
+       FcPatternAdd (new, fe->object, v, FcTrue);
+    }
+    for (i = 0; i < p->num; i++)
+    {
+       pe = &p->elts[i];
+       fe = FcPatternFind (best, pe->object, FcFalse);
+       if (!fe)
+           FcPatternAdd (new, pe->object, pe->values->value, FcTrue);
+    }
+    FcConfigSubstitute (config, new, FcMatchFont);
+    return new;
+}
diff --git a/src/fcmatrix.c b/src/fcmatrix.c
new file mode 100644 (file)
index 0000000..d2a9f1e
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Tuomas J. Lukka
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Tuomas Lukka not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Tuomas Lukka makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * TUOMAS LUKKA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL TUOMAS LUKKA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "fcint.h"
+
+FcMatrix *
+FcMatrixCopy (const FcMatrix *mat) 
+{
+    FcMatrix *r;
+    if(!mat) 
+       return 0;
+    r = (FcMatrix *) malloc (sizeof (*r) );
+    if (!r)
+       return 0;
+    FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
+    *r = *mat;
+    return r;
+}
+
+void
+FcMatrixFree (FcMatrix *mat)
+{
+    FcMemFree (FC_MEM_MATRIX, sizeof (FcMatrix));
+    free (mat);
+}
+
+FcBool
+FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2)
+{
+    if(mat1 == mat2) return FcTrue;
+    if(mat1 == 0 || mat2 == 0) return FcFalse;
+    return mat1->xx == mat2->xx && 
+          mat1->xy == mat2->xy &&
+          mat1->yx == mat2->yx &&
+          mat1->yy == mat2->yy;
+}
+
+void
+FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b)
+{
+    FcMatrix   r;
+
+    r.xx = a->xx * b->xx + a->xy * b->yx;
+    r.xy = a->xx * b->xy + a->xy * b->yy;
+    r.yx = a->yx * b->xx + a->yy * b->yx;
+    r.yy = a->yx * b->xy + a->yy * b->yy;
+    *result = r;
+}
+
+void
+FcMatrixRotate (FcMatrix *m, double c, double s)
+{
+    FcMatrix   r;
+
+    /*
+     * X Coordinate system is upside down, swap to make
+     * rotations counterclockwise
+     */
+    r.xx = c;
+    r.xy = -s;
+    r.yx = s;
+    r.yy = c;
+    FcMatrixMultiply (m, &r, m);
+}
+
+void
+FcMatrixScale (FcMatrix *m, double sx, double sy)
+{
+    FcMatrix   r;
+
+    r.xx = sx;
+    r.xy = 0;
+    r.yx = 0;
+    r.yy = sy;
+    FcMatrixMultiply (m, &r, m);
+}
+
+void
+FcMatrixShear (FcMatrix *m, double sh, double sv)
+{
+    FcMatrix   r;
+
+    r.xx = 1;
+    r.xy = sh;
+    r.yx = sv;
+    r.yy = 1;
+    FcMatrixMultiply (m, &r, m);
+}
diff --git a/src/fcname.c b/src/fcname.c
new file mode 100644 (file)
index 0000000..ed7c6c5
--- /dev/null
@@ -0,0 +1,621 @@
+/*
+ * $XFree86: xc/lib/Fc/xftname.c,v 1.10 2001/03/30 18:50:18 keithp Exp $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "fcint.h"
+
+static const FcObjectType _FcBaseObjectTypes[] = {
+    { FC_FAMILY,       FcTypeString, },
+    { FC_STYLE,                FcTypeString, },
+    { FC_SLANT,                FcTypeInteger, },
+    { FC_WEIGHT,       FcTypeInteger, },
+    { FC_SIZE,         FcTypeDouble, },
+    { FC_PIXEL_SIZE,   FcTypeDouble, },
+    { FC_SPACING,      FcTypeInteger, },
+    { FC_FOUNDRY,      FcTypeString, },
+/*    { FC_CORE,               FcTypeBool, }, */
+    { FC_ANTIALIAS,    FcTypeBool, },
+/*    { FC_XLFD,               FcTypeString, }, */
+    { FC_FILE,         FcTypeString, },
+    { FC_INDEX,                FcTypeInteger, },
+    { FC_RASTERIZER,   FcTypeString, },
+    { FC_OUTLINE,      FcTypeBool, },
+    { FC_SCALABLE,     FcTypeBool, },
+    { FC_RGBA,         FcTypeInteger, },
+    { FC_SCALE,                FcTypeDouble, },
+/*    { FC_RENDER,     FcTypeBool, },*/
+    { FC_MINSPACE,     FcTypeBool, },
+    { FC_CHAR_WIDTH,   FcTypeInteger },
+    { FC_CHAR_HEIGHT,  FcTypeInteger },
+    { FC_MATRIX,       FcTypeMatrix },
+    { FC_CHARSET,      FcTypeCharSet },
+    { FC_LANG,         FcTypeString },
+};
+
+#define NUM_OBJECT_TYPES    (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0])
+
+typedef struct _FcObjectTypeList    FcObjectTypeList;
+
+struct _FcObjectTypeList {
+    const FcObjectTypeList  *next;
+    const FcObjectType     *types;
+    int                            ntypes;
+};
+
+static const FcObjectTypeList _FcBaseObjectTypesList = {
+    0,
+    _FcBaseObjectTypes,
+    NUM_OBJECT_TYPES
+};
+
+static const FcObjectTypeList  *_FcObjectTypes = &_FcBaseObjectTypesList;
+
+FcBool
+FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes)
+{
+    FcObjectTypeList   *l;
+
+    l = (FcObjectTypeList *) malloc (sizeof (FcObjectTypeList));
+    if (!l)
+       return FcFalse;
+    l->types = types;
+    l->ntypes = ntypes;
+    l->next = _FcObjectTypes;
+    _FcObjectTypes = l;
+    return FcTrue;
+}
+
+FcBool
+FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes)
+{
+    const FcObjectTypeList     *l, **prev;
+
+    for (prev = &_FcObjectTypes; 
+        (l = *prev); 
+        prev = (const FcObjectTypeList **) &(l->next))
+    {
+       if (l->types == types && l->ntypes == ntypes)
+       {
+           *prev = l->next;
+           free ((void *) l);
+           return FcTrue;
+       }
+    }
+    return FcFalse;
+}
+
+const FcObjectType *
+FcNameGetObjectType (const char *object)
+{
+    int                            i;
+    const FcObjectTypeList  *l;
+    const FcObjectType     *t;
+    
+    for (l = _FcObjectTypes; l; l = l->next)
+    {
+       for (i = 0; i < l->ntypes; i++)
+       {
+           t = &l->types[i];
+           if (!FcStrCmpIgnoreCase (object, t->object))
+               return t;
+       }
+    }
+    return 0;
+}
+
+static const FcConstant _FcBaseConstants[] = {
+    { "light",         "weight",   FC_WEIGHT_LIGHT, },
+    { "medium",                "weight",   FC_WEIGHT_MEDIUM, },
+    { "demibold",      "weight",   FC_WEIGHT_DEMIBOLD, },
+    { "bold",          "weight",   FC_WEIGHT_BOLD, },
+    { "black",         "weight",   FC_WEIGHT_BLACK, },
+
+    { "roman",         "slant",    FC_SLANT_ROMAN, },
+    { "italic",                "slant",    FC_SLANT_ITALIC, },
+    { "oblique",       "slant",    FC_SLANT_OBLIQUE, },
+
+    { "proportional",  "spacing",  FC_PROPORTIONAL, },
+    { "mono",          "spacing",  FC_MONO, },
+    { "charcell",      "spacing",  FC_CHARCELL, },
+
+    { "rgb",           "rgba",     FC_RGBA_RGB, },
+    { "bgr",           "rgba",     FC_RGBA_BGR, },
+    { "vrgb",          "rgba",     FC_RGBA_VRGB },
+    { "vbgr",          "rgba",     FC_RGBA_VBGR },
+};
+
+#define NUM_FC_CONSTANTS   (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0])
+
+typedef struct _FcConstantList FcConstantList;
+
+struct _FcConstantList {
+    const FcConstantList    *next;
+    const FcConstant       *consts;
+    int                            nconsts;
+};
+
+static const FcConstantList _FcBaseConstantList = {
+    0,
+    _FcBaseConstants,
+    NUM_FC_CONSTANTS
+};
+
+static const FcConstantList    *_FcConstants = &_FcBaseConstantList;
+
+FcBool
+FcNameRegisterConstants (const FcConstant *consts, int nconsts)
+{
+    FcConstantList     *l;
+
+    l = (FcConstantList *) malloc (sizeof (FcConstantList));
+    if (!l)
+       return FcFalse;
+    l->consts = consts;
+    l->nconsts = nconsts;
+    l->next = _FcConstants;
+    _FcConstants = l;
+    return FcTrue;
+}
+
+FcBool
+FcNameUnregisterConstants (const FcConstant *consts, int nconsts)
+{
+    const FcConstantList       *l, **prev;
+
+    for (prev = &_FcConstants; 
+        (l = *prev); 
+        prev = (const FcConstantList **) &(l->next))
+    {
+       if (l->consts == consts && l->nconsts == nconsts)
+       {
+           *prev = l->next;
+           free ((void *) l);
+           return FcTrue;
+       }
+    }
+    return FcFalse;
+}
+
+const FcConstant *
+FcNameGetConstant (char *string)
+{
+    const FcConstantList    *l;
+    int                            i;
+    
+    for (l = _FcConstants; l; l = l->next)
+    {
+       for (i = 0; i < l->nconsts; i++)
+           if (!FcStrCmpIgnoreCase (string, l->consts[i].name))
+               return &l->consts[i];
+    }
+    return 0;
+}
+
+FcBool
+FcNameConstant (char *string, int *result)
+{
+    const FcConstant   *c;
+
+    if ((c = FcNameGetConstant(string)))
+    {
+       *result = c->value;
+       return FcTrue;
+    }
+    return FcFalse;
+}
+
+FcBool
+FcNameBool (char *v, FcBool *result)
+{
+    char    c0, c1;
+
+    c0 = *v;
+    if (isupper (c0))
+       c0 = tolower (c0);
+    if (c0 == 't' || c0 == 'y' || c0 == '1')
+    {
+       *result = FcTrue;
+       return FcTrue;
+    }
+    if (c0 == 'f' || c0 == 'n' || c0 == '0')
+    {
+       *result = FcFalse;
+       return FcTrue;
+    }
+    if (c0 == 'o')
+    {
+       c1 = v[1];
+       if (isupper (c1))
+           c1 = tolower (c1);
+       if (c1 == 'n')
+       {
+           *result = FcTrue;
+           return FcTrue;
+       }
+       if (c1 == 'f')
+       {
+           *result = FcFalse;
+           return FcTrue;
+       }
+    }
+    return FcFalse;
+}
+
+static FcValue
+FcNameConvert (FcType type, char *string, FcMatrix *m)
+{
+    FcValue    v;
+
+    v.type = type;
+    switch (v.type) {
+    case FcTypeInteger:
+       if (!FcNameConstant (string, &v.u.i))
+           v.u.i = atoi (string);
+       break;
+    case FcTypeString:
+       v.u.s = string;
+       break;
+    case FcTypeBool:
+       if (!FcNameBool (string, &v.u.b))
+           v.u.b = FcFalse;
+       break;
+    case FcTypeDouble:
+       v.u.d = strtod (string, 0);
+       break;
+    case FcTypeMatrix:
+       v.u.m = m;
+       sscanf (string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy);
+       break;
+    case FcTypeCharSet:
+       v.u.c = FcNameParseCharSet (string);
+       break;
+    default:
+       break;
+    }
+    return v;
+}
+
+static const char *
+FcNameFindNext (const char *cur, const char *delim, char *save, char *last)
+{
+    char    c;
+    
+    while ((c = *cur))
+    {
+       if (c == '\\')
+       {
+           ++cur;
+           if (!(c = *cur))
+               break;
+       }
+       else if (strchr (delim, c))
+           break;
+       ++cur;
+       *save++ = c;
+    }
+    *save = 0;
+    *last = *cur;
+    if (*cur)
+       cur++;
+    return cur;
+}
+
+FcPattern *
+FcNameParse (const char *name)
+{
+    char               *save;
+    FcPattern          *pat;
+    double             d;
+    char               *e;
+    char               delim;
+    FcValue            v;
+    FcMatrix           m;
+    const FcObjectType *t;
+    const FcConstant   *c;
+
+    save = malloc (strlen (name) + 1);
+    if (!save)
+       goto bail0;
+    pat = FcPatternCreate ();
+    if (!pat)
+       goto bail1;
+
+    for (;;)
+    {
+       name = FcNameFindNext (name, "-,:", save, &delim);
+       if (save[0])
+       {
+           if (!FcPatternAddString (pat, FC_FAMILY, save))
+               goto bail2;
+       }
+       if (delim != ',')
+           break;
+    }
+    if (delim == '-')
+    {
+       for (;;)
+       {
+           name = FcNameFindNext (name, "-,:", save, &delim);
+           d = strtod (save, &e);
+           if (e != save)
+           {
+               if (!FcPatternAddDouble (pat, FC_SIZE, d))
+                   goto bail2;
+           }
+           if (delim != ',')
+               break;
+       }
+    }
+    while (delim == ':')
+    {
+       name = FcNameFindNext (name, "=_:", save, &delim);
+       if (save[0])
+       {
+           if (delim == '=' || delim == '_')
+           {
+               t = FcNameGetObjectType (save);
+               for (;;)
+               {
+                   name = FcNameFindNext (name, ":,", save, &delim);
+                   if (save[0] && t)
+                   {
+                       v = FcNameConvert (t->type, save, &m);
+                       if (!FcPatternAdd (pat, t->object, v, FcTrue))
+                       {
+                           if (v.type == FcTypeCharSet)
+                               FcCharSetDestroy ((FcCharSet *) v.u.c);
+                           goto bail2;
+                       }
+                       if (v.type == FcTypeCharSet)
+                           FcCharSetDestroy ((FcCharSet *) v.u.c);
+                   }
+                   if (delim != ',')
+                       break;
+               }
+           }
+           else
+           {
+               if ((c = FcNameGetConstant (save)))
+               {
+                   if (!FcPatternAddInteger (pat, c->object, c->value))
+                       goto bail2;
+               }
+           }
+       }
+    }
+
+    free (save);
+    return pat;
+
+bail2:
+    FcPatternDestroy (pat);
+bail1:
+    free (save);
+bail0:
+    return 0;
+}
+
+static void
+FcNameBufInit (FcNameBuf *buf, FcChar8 *init, int size)
+{
+    buf->buf = init;
+    buf->allocated = FcFalse;
+    buf->failed = FcFalse;
+    buf->len = 0;
+    buf->size = size;
+}
+
+static void
+FcNameBufDestroy (FcNameBuf *buf)
+{
+    if (buf->allocated)
+       free (buf->buf);
+}
+
+static FcChar8 *
+FcNameBufDone (FcNameBuf *buf)
+{
+    FcChar8 *ret;
+
+    ret = malloc (buf->len + 1);
+    if (ret)
+    {
+       memcpy (ret, buf->buf, buf->len);
+       ret[buf->len] = '\0';
+    }
+    FcNameBufDestroy (buf);
+    return ret;
+}
+
+FcBool
+FcNameBufChar (FcNameBuf *buf, FcChar8 c)
+{
+    if (buf->len == buf->size)
+    {
+       FcChar8     *new;
+       int         size;
+
+       if (buf->allocated)
+       {
+           size = buf->size * 2;
+           new = realloc (buf->buf, size);
+       }
+       else
+       {
+           size = buf->size + 1024;
+           new = malloc (size);
+           if (new)
+           {
+               buf->allocated = FcTrue;
+               memcpy (new, buf->buf, buf->len);
+           }
+       }
+       if (!new)
+       {
+           buf->failed = FcTrue;
+           return FcFalse;
+       }
+       buf->size = size;
+       buf->buf = new;
+    }
+    buf->buf[buf->len++] = c;
+    return FcTrue;
+}
+
+FcBool
+FcNameBufString (FcNameBuf *buf, const FcChar8 *s)
+{
+    FcChar8 c;
+    while ((c = *s++))
+       if (!FcNameBufChar (buf, c))
+           return FcFalse;
+    return FcTrue;
+}
+
+static FcBool
+FcNameUnparseString (FcNameBuf     *buf, 
+                    const FcChar8  *string,
+                    const FcChar8  *escape)
+{
+    FcChar8 c;
+    while ((c = *string++))
+    {
+       if (escape && strchr ((char *) escape, (char) c))
+       {
+           if (!FcNameBufChar (buf, escape[0]))
+               return FcFalse;
+       }
+       if (!FcNameBufChar (buf, c))
+           return FcFalse;
+    }
+    return FcTrue;
+}
+
+static FcBool
+FcNameUnparseValue (FcNameBuf  *buf,
+                   FcValue     v,
+                   FcChar8     *escape)
+{
+    FcChar8    temp[1024];
+    
+    switch (v.type) {
+    case FcTypeVoid:
+       return FcTrue;
+    case FcTypeInteger:
+       sprintf ((char *) temp, "%d", v.u.i);
+       return FcNameUnparseString (buf, temp, 0);
+    case FcTypeDouble:
+       sprintf ((char *) temp, "%g", v.u.d);
+       return FcNameUnparseString (buf, temp, 0);
+    case FcTypeString:
+       return FcNameUnparseString (buf, v.u.s, escape);
+    case FcTypeBool:
+       return FcNameUnparseString (buf, v.u.b ? "True" : "False", 0);
+    case FcTypeMatrix:
+       sprintf ((char *) temp, "%g %g %g %g", 
+                v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy);
+       return FcNameUnparseString (buf, temp, 0);
+    case FcTypeCharSet:
+       return FcNameUnparseCharSet (buf, v.u.c);
+    }
+    return FcFalse;
+}
+
+static FcBool
+FcNameUnparseValueList (FcNameBuf      *buf,
+                       FcValueList     *v,
+                       char            *escape)
+{
+    while (v)
+    {
+       if (!FcNameUnparseValue (buf, v->value, escape))
+           return FcFalse;
+       if ((v = v->next))
+           if (!FcNameUnparseString (buf, ",", 0))
+               return FcFalse;
+    }
+    return FcTrue;
+}
+
+#define FC_ESCAPE_FIXED    "\\-:,"
+#define FC_ESCAPE_VARIABLE "\\=_:,"
+
+FcChar8 *
+FcNameUnparse (FcPattern *pat)
+{
+    FcNameBuf              buf;
+    FcChar8                buf_static[8192];
+    int                            i;
+    FcPatternElt           *e;
+    const FcObjectTypeList  *l;
+    const FcObjectType     *o;
+
+    FcNameBufInit (&buf, buf_static, sizeof (buf_static));
+    e = FcPatternFind (pat, FC_FAMILY, FcFalse);
+    if (e)
+    {
+       if (!FcNameUnparseValueList (&buf, e->values, FC_ESCAPE_FIXED))
+           goto bail0;
+    }
+    e = FcPatternFind (pat, FC_SIZE, FcFalse);
+    if (e)
+    {
+       if (!FcNameUnparseString (&buf, "-", 0))
+           goto bail0;
+       if (!FcNameUnparseValueList (&buf, e->values, FC_ESCAPE_FIXED))
+           goto bail0;
+    }
+    for (l = _FcObjectTypes; l; l = l->next)
+    {
+       for (i = 0; i < l->ntypes; i++)
+       {
+           o = &l->types[i];
+           if (!strcmp (o->object, FC_FAMILY) || 
+               !strcmp (o->object, FC_SIZE) ||
+               !strcmp (o->object, FC_FILE))
+               continue;
+           
+           e = FcPatternFind (pat, o->object, FcFalse);
+           if (e)
+           {
+               if (!FcNameUnparseString (&buf, ":", 0))
+                   goto bail0;
+               if (!FcNameUnparseString (&buf, o->object, FC_ESCAPE_VARIABLE))
+                   goto bail0;
+               if (!FcNameUnparseString (&buf, "=", 0))
+                   goto bail0;
+               if (!FcNameUnparseValueList (&buf, e->values, 
+                                            FC_ESCAPE_VARIABLE))
+                   goto bail0;
+           }
+       }
+    }
+    return FcNameBufDone (&buf);
+bail0:
+    FcNameBufDestroy (&buf);
+    return 0;
+}
diff --git a/src/fcpat.c b/src/fcpat.c
new file mode 100644 (file)
index 0000000..a1fd774
--- /dev/null
@@ -0,0 +1,491 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include "fcint.h"
+
+FcPattern *
+FcPatternCreate (void)
+{
+    FcPattern  *p;
+
+    p = (FcPattern *) malloc (sizeof (FcPattern));
+    if (!p)
+       return 0;
+    FcMemAlloc (FC_MEM_PATTERN, sizeof (FcPattern));
+    p->num = 0;
+    p->size = 0;
+    p->elts = 0;
+    return p;
+}
+
+void
+FcValueDestroy (FcValue v)
+{
+    switch (v.type) {
+    case FcTypeString:
+       FcStrFree ((FcChar8 *) v.u.s);
+       break;
+    case FcTypeMatrix:
+       FcMatrixFree ((FcMatrix *) v.u.m);
+       break;
+    case FcTypeCharSet:
+       FcCharSetDestroy ((FcCharSet *) v.u.c);
+       break;
+    default:
+       break;
+    }
+}
+
+FcValue
+FcValueSave (FcValue v)
+{
+    switch (v.type) {
+    case FcTypeString:
+       v.u.s = FcStrCopy (v.u.s);
+       if (!v.u.s)
+           v.type = FcTypeVoid;
+       break;
+    case FcTypeMatrix:
+       v.u.m = FcMatrixCopy (v.u.m);
+       if (!v.u.m)
+           v.type = FcTypeVoid;
+       break;
+    case FcTypeCharSet:
+       v.u.c = FcCharSetCopy ((FcCharSet *) v.u.c);
+       if (!v.u.c)
+           v.type = FcTypeVoid;
+       break;
+    default:
+       break;
+    }
+    return v;
+}
+
+void
+FcValueListDestroy (FcValueList *l)
+{
+    FcValueList    *next;
+    for (; l; l = next)
+    {
+       switch (l->value.type) {
+       case FcTypeString:
+           FcStrFree ((FcChar8 *) l->value.u.s);
+           break;
+       case FcTypeMatrix:
+           FcMatrixFree ((FcMatrix *) l->value.u.m);
+           break;
+       case FcTypeCharSet:
+           FcCharSetDestroy ((FcCharSet *) l->value.u.c);
+           break;
+       default:
+           break;
+       }
+       next = l->next;
+       FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
+       free (l);
+    }
+}
+
+void
+FcPatternDestroy (FcPattern *p)
+{
+    int                    i;
+    
+    for (i = 0; i < p->num; i++)
+       FcValueListDestroy (p->elts[i].values);
+
+    p->num = 0;
+    if (p->elts)
+    {
+       FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
+       free (p->elts);
+       p->elts = 0;
+    }
+    p->size = 0;
+    FcMemFree (FC_MEM_PATTERN, sizeof (FcPattern));
+    free (p);
+}
+
+FcPatternElt *
+FcPatternFind (FcPattern *p, const char *object, FcBool insert)
+{
+    int                    i;
+    int                    s;
+    FcPatternElt   *e;
+    
+    /* match existing */
+    for (i = 0; i < p->num; i++)
+    {
+       if (!FcStrCmpIgnoreCase (object, p->elts[i].object))
+           return &p->elts[i];
+    }
+
+    if (!insert)
+       return FcFalse;
+
+    /* grow array */
+    if (i == p->size)
+    {
+       s = p->size + 16;
+       if (p->elts)
+           e = (FcPatternElt *) realloc (p->elts, s * sizeof (FcPatternElt));
+       else
+           e = (FcPatternElt *) malloc (s * sizeof (FcPatternElt));
+       if (!e)
+           return FcFalse;
+       p->elts = e;
+       if (p->size)
+           FcMemFree (FC_MEM_PATELT, p->size * sizeof (FcPatternElt));
+       FcMemAlloc (FC_MEM_PATELT, s * sizeof (FcPatternElt));
+       while (p->size < s)
+       {
+           p->elts[p->size].object = 0;
+           p->elts[p->size].values = 0;
+           p->size++;
+       }
+    }
+    
+    /* bump count */
+    p->num++;
+    
+    p->elts[i].object = object;
+    
+    return &p->elts[i];
+}
+
+FcBool
+FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
+{
+    FcPatternElt   *e;
+    FcValueList    *new, **prev;
+
+    new = (FcValueList *) malloc (sizeof (FcValueList));
+    if (!new)
+       goto bail0;
+
+    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
+    /* dup string */
+    value = FcValueSave (value);
+    if (value.type == FcTypeVoid)
+       goto bail1;
+
+    new->value = value;
+    new->next = 0;
+    
+    e = FcPatternFind (p, object, FcTrue);
+    if (!e)
+       goto bail2;
+    
+    if (append)
+    {
+       for (prev = &e->values; *prev; prev = &(*prev)->next);
+       *prev = new;
+    }
+    else
+    {
+       new->next = e->values;
+       e->values = new;
+    }
+    
+    return FcTrue;
+
+bail2:    
+    switch (value.type) {
+    case FcTypeString:
+       FcStrFree ((FcChar8 *) value.u.s);
+       break;
+    case FcTypeMatrix:
+       FcMatrixFree ((FcMatrix *) value.u.m);
+       break;
+    case FcTypeCharSet:
+       FcCharSetDestroy ((FcCharSet *) value.u.c);
+       break;
+    default:
+       break;
+    }
+bail1:
+    FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
+    free (new);
+bail0:
+    return FcFalse;
+}
+
+FcBool
+FcPatternDel (FcPattern *p, const char *object)
+{
+    FcPatternElt   *e;
+    int                    i;
+
+    e = FcPatternFind (p, object, FcFalse);
+    if (!e)
+       return FcFalse;
+
+    i = e - p->elts;
+    
+    /* destroy value */
+    FcValueListDestroy (e->values);
+    
+    /* shuffle existing ones down */
+    memmove (e, e+1, (p->elts + p->num - (e + 1)) * sizeof (FcPatternElt));
+    p->num--;
+    p->elts[p->num].object = 0;
+    p->elts[p->num].values = 0;
+    return FcTrue;
+}
+
+FcBool
+FcPatternAddInteger (FcPattern *p, const char *object, int i)
+{
+    FcValue    v;
+
+    v.type = FcTypeInteger;
+    v.u.i = i;
+    return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcBool
+FcPatternAddDouble (FcPattern *p, const char *object, double d)
+{
+    FcValue    v;
+
+    v.type = FcTypeDouble;
+    v.u.d = d;
+    return FcPatternAdd (p, object, v, FcTrue);
+}
+
+
+FcBool
+FcPatternAddString (FcPattern *p, const char *object, const char *s)
+{
+    FcValue    v;
+
+    v.type = FcTypeString;
+    v.u.s = (char *) s;
+    return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcBool
+FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
+{
+    FcValue    v;
+
+    v.type = FcTypeMatrix;
+    v.u.m = (FcMatrix *) s;
+    return FcPatternAdd (p, object, v, FcTrue);
+}
+
+
+FcBool
+FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
+{
+    FcValue    v;
+
+    v.type = FcTypeBool;
+    v.u.b = b;
+    return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcBool
+FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
+{
+    FcValue    v;
+
+    v.type = FcTypeCharSet;
+    v.u.c = (FcCharSet *) c;
+    return FcPatternAdd (p, object, v, FcTrue);
+}
+
+FcResult
+FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
+{
+    FcPatternElt   *e;
+    FcValueList    *l;
+
+    e = FcPatternFind (p, object, FcFalse);
+    if (!e)
+       return FcResultNoMatch;
+    for (l = e->values; l; l = l->next)
+    {
+       if (!id)
+       {
+           *v = l->value;
+           return FcResultMatch;
+       }
+       id--;
+    }
+    return FcResultNoId;
+}
+
+FcResult
+FcPatternGetInteger (FcPattern *p, const char *object, int id, int *i)
+{
+    FcValue    v;
+    FcResult   r;
+
+    r = FcPatternGet (p, object, id, &v);
+    if (r != FcResultMatch)
+       return r;
+    switch (v.type) {
+    case FcTypeDouble:
+       *i = (int) v.u.d;
+       break;
+    case FcTypeInteger:
+       *i = v.u.i;
+       break;
+    default:
+        return FcResultTypeMismatch;
+    }
+    return FcResultMatch;
+}
+
+FcResult
+FcPatternGetDouble (FcPattern *p, const char *object, int id, double *d)
+{
+    FcValue    v;
+    FcResult   r;
+
+    r = FcPatternGet (p, object, id, &v);
+    if (r != FcResultMatch)
+       return r;
+    switch (v.type) {
+    case FcTypeDouble:
+       *d = v.u.d;
+       break;
+    case FcTypeInteger:
+       *d = (double) v.u.i;
+       break;
+    default:
+        return FcResultTypeMismatch;
+    }
+    return FcResultMatch;
+}
+
+FcResult
+FcPatternGetString (FcPattern *p, const char *object, int id, char ** s)
+{
+    FcValue    v;
+    FcResult   r;
+
+    r = FcPatternGet (p, object, id, &v);
+    if (r != FcResultMatch)
+       return r;
+    if (v.type != FcTypeString)
+        return FcResultTypeMismatch;
+    *s = (char *) v.u.s;
+    return FcResultMatch;
+}
+
+FcResult
+FcPatternGetMatrix (FcPattern *p, const char *object, int id, FcMatrix **m)
+{
+    FcValue    v;
+    FcResult   r;
+
+    r = FcPatternGet (p, object, id, &v);
+    if (r != FcResultMatch)
+       return r;
+    if (v.type != FcTypeMatrix)
+        return FcResultTypeMismatch;
+    *m = (FcMatrix *) v.u.m;
+    return FcResultMatch;
+}
+
+
+FcResult
+FcPatternGetBool (FcPattern *p, const char *object, int id, FcBool *b)
+{
+    FcValue    v;
+    FcResult   r;
+
+    r = FcPatternGet (p, object, id, &v);
+    if (r != FcResultMatch)
+       return r;
+    if (v.type != FcTypeBool)
+        return FcResultTypeMismatch;
+    *b = v.u.b;
+    return FcResultMatch;
+}
+
+FcResult
+FcPatternGetCharSet (FcPattern *p, const char *object, int id, FcCharSet **c)
+{
+    FcValue    v;
+    FcResult   r;
+
+    r = FcPatternGet (p, object, id, &v);
+    if (r != FcResultMatch)
+       return r;
+    if (v.type != FcTypeCharSet)
+        return FcResultTypeMismatch;
+    *c = (FcCharSet *) v.u.c;
+    return FcResultMatch;
+}
+
+FcPattern *
+FcPatternDuplicate (FcPattern *orig)
+{
+    FcPattern      *new;
+    int                    i;
+    FcValueList    *l;
+
+    new = FcPatternCreate ();
+    if (!new)
+       goto bail0;
+
+    for (i = 0; i < orig->num; i++)
+    {
+       for (l = orig->elts[i].values; l; l = l->next)
+           if (!FcPatternAdd (new, orig->elts[i].object, l->value, FcTrue))
+               goto bail1;
+    }
+
+    return new;
+
+bail1:
+    FcPatternDestroy (new);
+bail0:
+    return 0;
+}
+
+FcPattern *
+FcPatternVaBuild (FcPattern *orig, va_list va)
+{
+    FcPattern  *ret;
+    
+    FcPatternVapBuild (ret, orig, va);
+    return ret;
+}
+
+FcPattern *
+FcPatternBuild (FcPattern *orig, ...)
+{
+    va_list    va;
+    
+    va_start (va, orig);
+    FcPatternVapBuild (orig, orig, va);
+    va_end (va);
+    return orig;
+}
diff --git a/src/fcstr.c b/src/fcstr.c
new file mode 100644 (file)
index 0000000..658890e
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2000 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "fcint.h"
+
+char *
+FcStrCopy (const char *s)
+{
+    char       *r;
+
+    if (!s)
+       return 0;
+    r = (char *) malloc (strlen (s) + 1);
+    if (!r)
+       return 0;
+    FcMemAlloc (FC_MEM_STRING, strlen (s) + 1);
+    strcpy (r, s);
+    return r;
+}
+
+char *
+FcStrPlus (const char *s1, const char *s2)
+{
+    int            l = strlen (s1) + strlen (s2) + 1;
+    char    *s = malloc (l);
+
+    if (!s)
+       return 0;
+    FcMemAlloc (FC_MEM_STRING, l);
+    strcpy (s, s1);
+    strcat (s, s2);
+    return s;
+}
+
+void
+FcStrFree (char *s)
+{
+    FcMemFree (FC_MEM_STRING, strlen (s) + 1);
+    free (s);
+}
+
+int
+FcStrCmpIgnoreCase (const char *s1, const char *s2)
+{
+    char    c1, c2;
+    
+    for (;;) 
+    {
+       c1 = *s1++;
+       c2 = *s2++;
+       if (!c1 || !c2)
+           break;
+       c1 = FcToLower (c1);
+       c2 = FcToLower (c2);
+       if (c1 != c2)
+           break;
+    }
+    return (int) c2 - (int) c1;
+}
+
+int
+FcUtf8ToUcs4 (FcChar8   *src_orig,
+             FcChar32  *dst,
+             int       len)
+{
+    FcChar8    *src = src_orig;
+    FcChar8    s;
+    int                extra;
+    FcChar32   result;
+
+    if (len == 0)
+       return 0;
+    
+    s = *src++;
+    len--;
+    
+    if (!(s & 0x80))
+    {
+       result = s;
+       extra = 0;
+    } 
+    else if (!(s & 0x40))
+    {
+       return -1;
+    }
+    else if (!(s & 0x20))
+    {
+       result = s & 0x1f;
+       extra = 1;
+    }
+    else if (!(s & 0x10))
+    {
+       result = s & 0xf;
+       extra = 2;
+    }
+    else if (!(s & 0x08))
+    {
+       result = s & 0x07;
+       extra = 3;
+    }
+    else if (!(s & 0x04))
+    {
+       result = s & 0x03;
+       extra = 4;
+    }
+    else if ( ! (s & 0x02))
+    {
+       result = s & 0x01;
+       extra = 5;
+    }
+    else
+    {
+       return -1;
+    }
+    if (extra > len)
+       return -1;
+    
+    while (extra--)
+    {
+       result <<= 6;
+       s = *src++;
+       
+       if ((s & 0xc0) != 0x80)
+           return -1;
+       
+       result |= s & 0x3f;
+    }
+    *dst = result;
+    return src - src_orig;
+}
+
+FcBool
+FcUtf8Len (FcChar8     *string,
+           int         len,
+           int         *nchar,
+           int         *wchar)
+{
+    int                n;
+    int                clen;
+    FcChar32   c;
+    FcChar32   max;
+    
+    n = 0;
+    max = 0;
+    while (len)
+    {
+       clen = FcUtf8ToUcs4 (string, &c, len);
+       if (clen <= 0)  /* malformed UTF8 string */
+           return FcFalse;
+       if (c > max)
+           max = c;
+       string += clen;
+       len -= clen;
+       n++;
+    }
+    *nchar = n;
+    if (max >= 0x10000)
+       *wchar = 4;
+    else if (max > 0x100)
+       *wchar = 2;
+    else
+       *wchar = 1;
+    return FcTrue;
+}
diff --git a/src/fcxml.c b/src/fcxml.c
new file mode 100644 (file)
index 0000000..07e24df
--- /dev/null
@@ -0,0 +1,1032 @@
+/*
+ * $XFree86: $
+ *
+ * Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of Keith Packard not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission.  Keith Packard makes no
+ * representations about the suitability of this software for any purpose.  It
+ * is provided "as is" without express or implied warranty.
+ *
+ * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdarg.h>
+#include "fcint.h"
+
+static xmlParserInputPtr
+FcEntityLoader (const char *url, const char *id, xmlParserCtxtPtr ctxt)
+{
+    xmlParserInputPtr  ret;
+    char               *file;
+
+    file = FcConfigFilename (url);
+    if (!file)
+       return 0;
+    ret = xmlNewInputFromFile (ctxt, file);
+    free (file);
+    return ret;
+}
+
+xmlDocPtr
+FcConfigLoad (const char *file)
+{
+    xmlDocPtr              doc;
+    xmlExternalEntityLoader previous;
+
+    previous = xmlGetExternalEntityLoader ();
+    xmlSetExternalEntityLoader (FcEntityLoader);
+    doc = xmlParseFile (file);
+    xmlSetExternalEntityLoader (previous);
+    return doc;
+}
+
+#if 0
+int
+FcConfigSave (char *file, xmlDocPtr doc)
+{
+}
+#endif
+
+FcTest *
+FcTestCreate (FcQual qual, const char *field, FcOp compare, FcExpr *expr)
+{
+    FcTest     *test = (FcTest *) malloc (sizeof (FcTest));;
+
+    if (test)
+    {
+       test->next = 0;
+       test->qual = qual;
+       test->field = FcStrCopy (field);
+       test->op = compare;
+       test->expr = expr;
+    }
+    return test;
+}
+
+void
+FcTestDestroy (FcTest *test)
+{
+    if (test->next)
+       FcTestDestroy (test->next);
+    FcExprDestroy (test->expr);
+    FcStrFree ((FcChar8 *) test->field);
+    free (test);
+}
+
+FcExpr *
+FcExprCreateInteger (int i)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpInteger;
+       e->u.ival = i;
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateDouble (double d)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpDouble;
+       e->u.dval = d;
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateString (const char *s)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpString;
+       e->u.sval = FcStrCopy (s);
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateMatrix (const FcMatrix *m)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpMatrix;
+       e->u.mval = FcMatrixCopy (m);
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateBool (FcBool b)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpBool;
+       e->u.bval = b;
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateNil (void)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpNil;
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateField (const char *field)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpField;
+       e->u.field = FcStrCopy (field);
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateConst (const char *constant)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = FcOpConst;
+       e->u.constant = FcStrCopy (constant);
+    }
+    return e;
+}
+
+FcExpr *
+FcExprCreateOp (FcExpr *left, FcOp op, FcExpr *right)
+{
+    FcExpr *e = (FcExpr *) malloc (sizeof (FcExpr));
+
+    if (e)
+    {
+       e->op = op;
+       e->u.tree.left = left;
+       e->u.tree.right = right;
+    }
+    return e;
+}
+
+void
+FcExprDestroy (FcExpr *e)
+{
+    switch (e->op) {
+    case FcOpInteger:
+       break;
+    case FcOpDouble:
+       break;
+    case FcOpString:
+       FcStrFree (e->u.sval);
+       break;
+    case FcOpMatrix:
+       FcMatrixFree (e->u.mval);
+       break;
+    case FcOpCharSet:
+       FcCharSetDestroy (e->u.cval);
+       break;
+    case FcOpBool:
+       break;
+    case FcOpField:
+       FcStrFree (e->u.field);
+       break;
+    case FcOpConst:
+       FcStrFree (e->u.constant);
+       break;
+    case FcOpAssign:
+    case FcOpAssignReplace:
+    case FcOpPrepend:
+    case FcOpPrependFirst:
+    case FcOpAppend:
+    case FcOpAppendLast:
+       break;
+    case FcOpOr:
+    case FcOpAnd:
+    case FcOpEqual:
+    case FcOpContains:
+    case FcOpNotEqual:
+    case FcOpLess:
+    case FcOpLessEqual:
+    case FcOpMore:
+    case FcOpMoreEqual:
+    case FcOpPlus:
+    case FcOpMinus:
+    case FcOpTimes:
+    case FcOpDivide:
+    case FcOpQuest:
+    case FcOpComma:
+       FcExprDestroy (e->u.tree.right);
+       /* fall through */
+    case FcOpNot:
+       FcExprDestroy (e->u.tree.left);
+       break;
+    case FcOpNil:
+    case FcOpInvalid:
+       break;
+    }
+    free (e);
+}
+
+FcEdit *
+FcEditCreate (const char *field, FcOp op, FcExpr *expr)
+{
+    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
+
+    if (e)
+    {
+       e->next = 0;
+       e->field = field;   /* already saved in grammar */
+       e->op = op;
+       e->expr = expr;
+    }
+    return e;
+}
+
+void
+FcEditDestroy (FcEdit *e)
+{
+    if (e->next)
+       FcEditDestroy (e->next);
+    FcStrFree ((FcChar8 *) e->field);
+    if (e->expr)
+       FcExprDestroy (e->expr);
+}
+
+char *
+FcConfigSaveField (const char *field)
+{
+    return FcStrCopy (field);
+}
+
+static void
+FcConfigParseError (char *fmt, ...)
+{
+    va_list    args;
+
+    va_start (args, fmt);
+    fprintf (stderr, "font configuration error: ");
+    vfprintf (stderr, fmt, args);
+    fprintf (stderr, "\n");
+    va_end (args);
+}
+
+static char *
+FcConfigContent (xmlDocPtr    doc,
+                xmlNodePtr   node)
+{
+    char           *content;
+    
+    content = xmlNodeListGetString (doc, node->children, 1);
+    if (!content)
+    {
+       FcConfigParseError ("<%s> must have content",
+                           node->name);
+       return FcFalse;
+    }
+    return content;
+}
+
+static char *
+FcConfigAttr (xmlDocPtr            doc,
+             xmlAttrPtr    attr)
+{
+    char           *content;
+    
+    content = xmlNodeListGetString (doc, attr->children, 1);
+    if (!content)
+    {
+       FcConfigParseError ("attribute %s must have a value",
+                           attr->name);
+       return FcFalse;
+    }
+    return content;
+}
+
+static struct {
+    char    *name;
+    FcOp    op;
+} fcOps[] = {
+    { "int",           FcOpInteger         },
+    { "double",                FcOpDouble          },
+    { "string",                FcOpString          },
+    { "matrix",                FcOpMatrix          },
+    { "bool",          FcOpBool            },
+    { "charset",       FcOpCharSet         },
+    { "name",          FcOpField           },
+    { "const",         FcOpConst           },
+    { "field",         FcOpField           },
+    { "if",            FcOpQuest           },
+    { "or",            FcOpOr              },
+    { "and",           FcOpAnd             },
+    { "eq",            FcOpEqual           },
+    { "not_eq",                FcOpNotEqual        },
+    { "less",          FcOpLess            },
+    { "less_eq",       FcOpLessEqual       },
+    { "more",          FcOpMore            },
+    { "more_eq",       FcOpMoreEqual       },
+    { "plus",          FcOpPlus            },
+    { "minus",         FcOpMinus           },
+    { "times",         FcOpTimes           },
+    { "divide",                FcOpDivide          },
+    { "not",           FcOpNot             },
+    { "assign",                FcOpAssign          },
+    { "assign_replace",        FcOpAssignReplace   },
+    { "prepend",       FcOpPrepend         },
+    { "prepend_first", FcOpPrependFirst    },
+    { "append",                FcOpAppend          },
+    { "append_last",   FcOpAppendLast      },
+};
+
+#define NUM_OPS (sizeof fcOps / sizeof fcOps[0])
+
+static FcOp
+FcConfigLexOp (const char *op)
+{
+    int        i;
+
+    for (i = 0; i < NUM_OPS; i++)
+       if (!strcmp (op, fcOps[i].name)) return fcOps[i].op;
+    return FcOpInvalid;
+}
+
+static FcBool
+FcConfigLexBool (const char *bool)
+{
+    if (*bool == 't' || *bool == 'T')
+       return FcTrue;
+    if (*bool == 'y' || *bool == 'Y')
+       return FcTrue;
+    if (*bool == '1')
+       return FcTrue;
+    return FcFalse;
+}
+
+static FcBool
+FcConfigParseDir (FcConfig     *config,
+                 xmlDocPtr     doc,
+                 xmlNodePtr    dir)
+{
+    char    *content = FcConfigContent (doc, dir);
+
+    if (!content)
+       return FcFalse;
+    return FcConfigAddDir (config, content);
+}
+
+static FcBool
+FcConfigParseCache (FcConfig   *config,
+                   xmlDocPtr   doc,
+                   xmlNodePtr  dir)
+{
+    char    *content = FcConfigContent (doc, dir);
+
+    if (!content)
+       return FcFalse;
+    return FcConfigSetCache (config, content);
+}
+
+static FcBool
+FcConfigParseInclude (FcConfig     *config,
+                     xmlDocPtr     doc,
+                     xmlNodePtr    inc)
+{
+    char       *content = FcConfigContent (doc, inc);
+    xmlAttr    *attr;
+    FcBool     complain = FcTrue;
+
+    if (!content)
+       return FcFalse;
+    
+    for (attr = inc->properties; attr; attr = attr->next)
+    {
+       if (attr->type != XML_ATTRIBUTE_NODE)
+           continue;
+       if (!strcmp (attr->name, "ignore_missing"))
+           complain = !FcConfigLexBool (FcConfigAttr (doc, attr));
+    }
+    return FcConfigParseAndLoad (config, content, complain);
+}
+
+static FcBool
+FcConfigParseBlank (FcConfig       *config,
+                   xmlDocPtr       doc,
+                   xmlNodePtr      blank)
+{
+    xmlNode    *node;
+    FcChar32   ucs4;
+
+    for (node = blank->children; node; node = node->next)
+    {
+       if (node->type != XML_ELEMENT_NODE)
+           continue;
+       if (!strcmp (node->name, "int"))
+       {
+           ucs4 = (FcChar32) strtol (FcConfigContent (doc, node), 0, 0);
+           if (!config->blanks)
+           {
+               config->blanks = FcBlanksCreate ();
+               if (!config->blanks)
+                   break;
+           }
+           if (!FcBlanksAdd (config->blanks, ucs4))
+               break;
+       }
+    }
+    if (node)
+       return FcFalse;
+    return FcTrue;
+}
+
+static FcBool
+FcConfigParseConfig (FcConfig      *config,
+                    xmlDocPtr      doc,
+                    xmlNodePtr     cfg)
+{
+    xmlNode    *node;
+
+    for (node = cfg->children; node; node = node->next)
+    {
+       if (node->type != XML_ELEMENT_NODE)
+           continue;
+       if (!strcmp (node->name, "blank"))
+       {
+           if (!FcConfigParseBlank (config, doc, node))
+               break;
+       }
+    }
+    if (node)
+       return FcFalse;
+    return FcTrue;
+}
+
+static FcMatrix *
+FcConfigParseMatrix (xmlDocPtr doc,
+                    xmlNodePtr node)
+{
+    static FcMatrix m;
+    enum { m_xx, m_xy, m_yx, m_yy, m_done } matrix_state = m_xx;
+    double  v;
+    char    *text;
+    
+    FcMatrixInit (&m);
+
+    for (; node; node = node->next)
+    {
+       if (node->type != XML_ELEMENT_NODE)
+           continue;
+       if (strcmp (node->name, "double"))
+           continue;
+       text = FcConfigContent (doc, node);
+       if (!text)
+           continue;
+       v = strtod (text, 0);
+       switch (matrix_state) {
+       case m_xx: m.xx = v; break;
+       case m_xy: m.xy = v; break;
+       case m_yx: m.yx = v; break;
+       case m_yy: m.yy = v; break;
+       default: break;
+       }
+       matrix_state++;
+    }
+        
+    return &m;
+}
+
+static FcExpr *
+FcConfigParseExpr (xmlDocPtr   doc,
+                  xmlNodePtr   expr)
+{
+    FcOp       op = FcConfigLexOp (expr->name);
+    xmlNodePtr node;
+    FcExpr     *l = 0, *e = 0, *r = 0, *c = 0;
+
+    switch (op) {
+    case FcOpInteger:
+       l = FcExprCreateInteger (strtol (FcConfigContent (doc, expr), 0, 0));
+       break;
+    case FcOpDouble:
+       l = FcExprCreateDouble (strtod (FcConfigContent (doc, expr), 0));
+       break;
+    case FcOpString:
+       l = FcExprCreateString (FcConfigContent (doc, expr));
+       break;
+    case FcOpMatrix:
+       l = FcExprCreateMatrix (FcConfigParseMatrix (doc, expr));
+       break;
+    case FcOpBool:
+       l = FcExprCreateBool (FcConfigLexBool(FcConfigContent (doc, expr)));
+       break;
+    case FcOpCharSet:
+       /* not sure what to do here yet */
+       break;
+    case FcOpField:
+       l = FcExprCreateField (FcConfigContent (doc, expr));
+       break;
+    case FcOpConst:
+       l = FcExprCreateConst (FcConfigContent (doc, expr));
+       break;
+    case FcOpQuest:
+       for (node = expr->children; node; node = node->next)
+       {
+           if (node->type != XML_ELEMENT_NODE)
+               continue;
+           e = FcConfigParseExpr (doc, node);
+           if (!e)
+               break;
+           if (!l)
+               l = e;
+           else if (!c)
+               c = e;
+           else if (!r)
+               r = e;
+           else
+               FcExprDestroy (e);
+       }
+       e = 0;
+       if (!node && l && c && r)
+       {
+           e = FcExprCreateOp (c, FcOpQuest, r);
+           if (e)
+           {
+               r = e;
+               c = 0;
+               e = FcExprCreateOp (l, FcOpQuest, r);
+           }
+           if (!e)
+               node = expr->children;
+       }
+       if (node || !l || !c || !r || !e)
+       {
+           if (l)
+               FcExprDestroy (l);
+           if (c)
+               FcExprDestroy (c);
+           if (r)
+               FcExprDestroy (r);
+           return 0;
+       }
+       break;
+    default:
+       for (node = expr->children; node; node = node->next)
+       {
+           if (node->type != XML_ELEMENT_NODE)
+               continue;
+           e = FcConfigParseExpr (doc, node);
+           if (!e)
+               break;
+           if (!l)
+               l = e;
+           else
+           {
+               r = e;
+               e = FcExprCreateOp (l, op, r);
+               if (!e)
+               {
+                   FcExprDestroy (r);
+                   break;
+               }
+               l = e;
+           }
+       }
+       if (node || !l)
+       {
+           if (l)
+               FcExprDestroy (l);
+           return 0;
+       }
+       /*
+        * Special case for unary ops 
+        */
+       if (!r)
+       {
+           e = FcExprCreateOp (l, op, 0);
+           if (!e)
+           {
+               FcExprDestroy (l);
+               return 0;
+           }
+       }
+       break;
+    
+    case FcOpInvalid:
+       return 0;
+    }
+    return l;
+}
+
+static FcTest *
+FcConfigParseTest (xmlDocPtr   doc,
+                  xmlNodePtr   test)
+{
+    xmlNodePtr node;
+    xmlAttrPtr attr;
+    FcQual     qual = FcQualAny;
+    FcOp       op = FcOpEqual;
+    char       *field = 0;
+    FcExpr     *expr = 0;
+
+    for (attr = test->properties; attr; attr = attr->next)
+    {
+       if (attr->type != XML_ATTRIBUTE_NODE)
+           continue;
+       if (!strcmp (attr->name, "qual"))
+       {
+           char    *qual_name = FcConfigAttr (doc, attr);
+           if (!qual_name)
+               ;
+           else if (!strcmp (qual_name, "any"))
+               qual = FcQualAny;
+           else if (!strcmp (qual_name, "all"))
+               qual = FcQualAll;
+       }
+       else if (!strcmp (attr->name, "name"))
+       {
+           field = FcConfigAttr (doc, attr);
+       }
+       else if (!strcmp (attr->name, "compare"))
+       {
+           char    *compare = FcConfigAttr (doc, attr);
+           
+           if (!compare || (op = FcConfigLexOp (compare)) == FcOpInvalid)
+           {
+               FcConfigParseError ("Invalid comparison %s", 
+                                   compare ? compare : "<missing>");
+               return 0;
+           }
+       }
+    }
+    if (attr)
+       return 0;
+
+    for (node = test->children; node; node = node->next)
+    {
+       if (node->type != XML_ELEMENT_NODE)
+           continue;
+       expr = FcConfigParseExpr (doc, node);
+       if (!expr)
+           return 0;
+       break;
+    }
+
+    if (!expr)
+    {
+       FcConfigParseError ("Missing test expression");
+       return 0;
+    }
+    
+    return FcTestCreate (qual, field, op, expr);
+}
+
+static FcExpr *
+FcConfigParseExprList (xmlDocPtr    doc,
+                      xmlNodePtr   expr)
+{
+    FcExpr  *l, *e, *r;
+    
+    if (!expr)
+       return 0;
+    
+    e = FcConfigParseExprList (doc, expr->next);
+
+    if (expr->type == XML_ELEMENT_NODE)
+    {
+       r = e;
+       l = FcConfigParseExpr (doc, expr);
+       if (!l)
+           goto bail;
+       if (r)
+       {
+           e = FcExprCreateOp (l, FcOpComma, r);
+           if (!e)
+               goto bail;
+       }
+       else
+           e = l;
+    }
+    
+    return e;
+bail:
+    if (l)
+       FcExprDestroy (l);
+    if (r)
+       FcExprDestroy (r);
+    return 0;
+}
+
+static FcEdit *
+FcConfigParseEdit (xmlDocPtr   doc,
+                  xmlNodePtr   edit)
+{
+    xmlAttrPtr attr;
+    char       *name = 0;
+    FcOp       mode = FcOpAssign;
+    FcExpr     *e;
+    FcEdit     *ed;
+
+    for (attr = edit->properties; attr; attr = attr->next)
+    {
+       if (attr->type != XML_ATTRIBUTE_NODE)
+           continue;
+       if (!strcmp (attr->name, "name"))
+           name = FcConfigAttr (doc, attr);
+       else if (!strcmp (attr->name, "mode"))
+           mode = FcConfigLexOp (FcConfigAttr (doc, attr));
+    }
+
+    e = FcConfigParseExprList (doc, edit->children);
+
+    ed = FcEditCreate (name, mode, e);
+    if (!ed)
+       FcExprDestroy (e);
+    return ed;
+}
+
+static FcBool
+FcConfigParseMatch (FcConfig   *config,
+                   xmlDocPtr   doc,
+                   xmlNodePtr  match)
+{
+    xmlNodePtr node;
+    xmlAttrPtr attr;
+    FcTest     *tests = 0, **prevTest = &tests, *test;
+    FcEdit     *edits = 0, **prevEdit = &edits, *edit;
+    FcMatchKind        kind;
+    FcBool     found_kind = FcFalse;
+
+    for (node = match->children; node; node = node->next)
+    {
+       if (node->type != XML_ELEMENT_NODE)
+           continue;
+       if (!strcmp (node->name, "test"))
+       {
+           test = FcConfigParseTest (doc, node);
+           if (!test)
+               break;
+           *prevTest = test;
+           prevTest = &test->next;
+       }
+       else if (!strcmp (node->name, "edit"))
+       {
+           edit = FcConfigParseEdit (doc, node);
+           if (!edit)
+               break;
+           *prevEdit = edit;
+           prevEdit = &edit->next;
+       }
+    }
+
+    for (attr = match->properties; attr; attr = attr->next)
+    {
+       if (attr->type != XML_ATTRIBUTE_NODE)
+           continue;
+       if (!strcmp (attr->name, "target"))
+       {
+           char    *target = FcConfigAttr (doc, attr);
+           if (!target)
+           {
+               FcConfigParseError ("Missing match target");
+               break;
+           }
+           else if (!strcmp (target, "pattern"))
+           {
+               kind = FcMatchPattern;
+               found_kind = FcTrue;
+           }
+           else if (!strcmp (target, "font"))
+           {
+               kind = FcMatchFont;
+               found_kind = FcTrue;
+           }
+       }
+    }
+
+    if (node || attr || !found_kind || 
+       !FcConfigAddEdit (config, tests, edits, kind))
+    {
+       if (tests)
+           FcTestDestroy (tests);
+       if (edits)
+           FcEditDestroy (edits);
+       return FcFalse;
+    }
+
+    return FcTrue;
+}
+
+static FcExpr *
+FcConfigParseFamilies (xmlDocPtr    doc,
+                      xmlNodePtr   family)
+{
+    FcExpr  *next = 0, *this = 0, *expr = 0;
+    
+    if (!family)
+       return 0;
+    next = FcConfigParseFamilies (doc, family->next);
+    
+    if (family->type == XML_ELEMENT_NODE && !strcmp (family->name, "family"))
+    {
+       this = FcExprCreateString (FcConfigContent (doc, family));
+       if (!this)
+           goto bail;
+       if (next)
+       {
+           expr = FcExprCreateOp (this, FcOpComma, next);
+           if (!expr)
+               goto bail;
+       }
+       else
+           expr = this;
+    }
+    else
+       expr = next;
+    return expr;
+
+bail:
+    if (expr)
+       FcExprDestroy (expr);
+    if (this)
+       FcExprDestroy (this);
+    if (next)
+       FcExprDestroy (next);
+    return 0;
+}
+
+static FcBool
+FcConfigParseAlias (FcConfig   *config,
+                   xmlDocPtr   doc,
+                   xmlNodePtr  alias)
+{
+    xmlNodePtr node;
+    FcExpr     *prefer = 0, *accept = 0, *def = 0;
+    FcExpr     *family;
+    FcEdit     *edit = 0, *next;
+    FcTest     *test;
+
+    for (node = alias->children; node; node = node->next)
+    {
+       if (node->type != XML_ELEMENT_NODE)
+           continue;
+       if (!strcmp (node->name, "family"))
+           family = FcExprCreateString (FcConfigContent (doc, node));
+       else if (!strcmp (node->name, "prefer"))
+           prefer = FcConfigParseFamilies (doc, node->children);
+       else if (!strcmp (node->name, "accept"))
+           accept = FcConfigParseFamilies (doc, node->children);
+       else if (!strcmp (node->name, "default"))
+           def = FcConfigParseFamilies (doc, node->children);
+    }
+    
+    if (prefer)
+    {
+       edit = FcEditCreate (FcConfigSaveField ("family"),
+                            FcOpPrepend,
+                            prefer);
+       if (edit)
+           edit->next = 0;
+    }
+    if (accept)
+    {
+       next = edit;
+       edit = FcEditCreate (FcConfigSaveField ("family"),
+                            FcOpAppend,
+                            accept);
+       if (edit)
+           edit->next = next;
+    }
+    if (def)
+    {
+       next = edit;
+       edit = FcEditCreate (FcConfigSaveField ("family"),
+                             FcOpAppendLast,
+                             def);
+       if (edit)
+           edit->next = next;
+    }
+    if (edit)
+    {
+       test = FcTestCreate (FcQualAny,
+                            FcConfigSaveField ("family"),
+                            FcOpEqual,
+                            family);
+       if (test)
+           FcConfigAddEdit (config, test, edit, FcMatchPattern);
+    }
+    return FcTrue;
+}
+
+FcBool
+FcConfigParse (FcConfig            *config,
+              xmlDocPtr    doc)
+{
+    xmlNodePtr cur;
+    xmlNodePtr node;
+    
+    cur = xmlDocGetRootElement (doc);
+
+    for (node = cur->children; node; node = node->next)
+    {
+       if (node->type != XML_ELEMENT_NODE)
+           continue;
+       if (!strcmp (node->name, "dir"))
+       {
+           if (!FcConfigParseDir (config, doc, node))
+               break;
+       }
+       else if (!strcmp (node->name, "cache"))
+       {
+           if (!FcConfigParseCache (config, doc, node))
+               break;
+       }
+       else if (!strcmp (node->name, "include"))
+       {
+           if (!FcConfigParseInclude (config, doc, node))
+               break;
+       }
+       else if (!strcmp (node->name, "config"))
+       {
+           if (!FcConfigParseConfig (config, doc, node))
+               break;
+       }
+       else if (!strcmp (node->name, "match"))
+       {
+           if (!FcConfigParseMatch (config, doc, node))
+               break;
+       }
+       else if (!strcmp (node->name, "alias"))
+       {
+           if (!FcConfigParseAlias (config, doc, node))
+               break;
+       }
+       else
+       {
+           FcConfigParseError ("invalid element %s", node->name);
+           break;
+       }   
+    }
+    if (node)
+       return FcFalse;
+    return FcTrue;
+}
+
+FcBool
+FcConfigParseAndLoad (FcConfig     *config,
+                     const char    *file,
+                     FcBool        complain)
+{
+    xmlDocPtr  doc;
+    FcBool     ret;
+
+    doc = FcConfigLoad (file);
+    if (doc)
+    {
+       ret = FcConfigAddConfigFile (config, file);
+       if (ret)
+           ret = FcConfigParse (config, doc);
+       xmlFreeDoc (doc);
+       return ret;
+    }
+    if (complain)
+    {
+       if (file)
+           FcConfigParseError ("Cannot load config file \"%s\"", file);
+       else
+           FcConfigParseError ("Cannot load default config file");
+       return FcFalse;
+    }
+    return FcTrue;
+}
diff --git a/src/fontconfig.man b/src/fontconfig.man
new file mode 100644 (file)
index 0000000..eb9915f
--- /dev/null
@@ -0,0 +1,1113 @@
+.\"
+.\" $XFree86: fontconfig.man,v 1.2 2000/11/30 06:59:45 keithp Exp $
+.\"
+.\" Copyright © 2002 Keith Packard, member of The XFree86 Project, Inc.
+.\"
+.\" Permission to use, copy, modify, distribute, and sell this software and its
+.\" documentation for any purpose is hereby granted without fee, provided that
+.\" the above copyright notice appear in all copies and that both that
+.\" copyright notice and this permission notice appear in supporting
+.\" documentation, and that the name of Keith Packard not be used in
+.\" advertising or publicity pertaining to distribution of the software without
+.\" specific, written prior permission.  Keith Packard makes no
+.\" representations about the suitability of this software for any purpose.  It
+.\" is provided "as is" without express or implied warranty.
+.\"
+.\" KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+.\" INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+.\" EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+.\" CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+.\" DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+.\" TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+.\" PERFORMANCE OF THIS SOFTWARE.
+.\"
+.de TQ
+.br
+.ns
+.TP \\$1
+..
+.TH FONTCONFIG 3 "Version 1.0" "XFree86"
+
+.SH NAME
+fontconfig \- Font configuration and customization library
+
+.SH SYNOPSIS
+.nf
+.B #include <fontconfig/fontconfig.h>
+.B #include <fontconfig/fcfreetype.h>
+.B #include <fontconfig/fcxml.h>
+.fi
+.SH DESCRIPTION
+.B Fontconfig
+is a library designed to provide system-wide font configuration,
+customization and application access.
+
+.SH FUNCTIONAL OVERVIEW
+Fontconfig contains two essential modules, the configuration module which
+builds an internal configuration from XML files and the matching module
+which accepts font patterns and returns the nearest matching font.
+
+.SS FONT CONFIGURATION
+The configuration module consists of the FcConfig datatype, libxml2 and
+FcConfigParse which walks over an XML tree and ammends a configuration with
+data found within.  From an external perspective, configuration of the
+library consists of generating a valid XML tree and feeding that to
+FcConfigParse.  The only other mechanism provided to applications for
+changing the running configuration is to add fonts and directories to the
+list of application-provided font files.  
+.P
+The intent is to make font configurations relatively static, and shared by
+as many applications as possible.  It is hoped that this will lead to more
+stable font selection when passing names from one application to another.
+XML was chosen as a configuration file format because it provides a format
+which is easy for external agents to edit while retaining the correct
+structure and syntax.
+.P
+Font configuration is separate from font matching; applications needing to
+do their own matching can access the available fonts from the library and
+perform private matching.  The intent is to permit applications to pick and
+choose appropriate functionality from the library instead of forcing them to
+choose between this library and a private configuration mechanism.  The hope
+is that this will ensure that configuration of fonts for all applications
+can be centralized in one place.  Centralizing font configuration will make
+simplify and regularize font installation and customization.
+
+.SS FONT PROPERTIES
+While font patterns may contain essentially any properties, there are some
+well known properties with associated types.  Fontconfig uses some of these
+properties for font matching and font completion.  Others are provided as a
+convenience for the applications rendering mechanism.
+.sp
+.nf
+.ta 1i 2.75i 3.5i 5.5i
+.lc \(em
+Property       CPP symbol      Type    Description
+\ 1\ 1\ 1\ 1
+family FC_FAMILY       String  Font family name
+style  FC_STYLE        String  Font style. Overrides weight and slant
+slant  FC_SLANT        Int     Italic, oblique or roman
+weight FC_WEIGHT       Int     Light, medium, demibold, bold or black
+size   FC_SIZE Double  Point size
+pixelsize      FC_PIXEL_SIZE   Double  Pixel size
+spacing        FC_SPACING      Int     Proportional, monospace or charcell
+foundry        FC_FOUNDRY      String  Font foundry name
+antialias      FC_ANTIALIAS    Bool    Whether glyphs can be antialiased
+hinting        FC_HINTING      Bool    Whether the rasterizer should use hinting
+verticallayout FC_VERTICAL_LAYOUT      Bool    Use vertical layout
+globaladvance  FC_GLOBAL_ADVANCE       Bool    Use font global advance data
+file   FC_FILE String  The filename holding the font
+index  FC_INDEX        Int     The index of the font within the file
+rasterizer     FC_RASTERIZER   String  Which rasterizer is in use
+outline        FC_OUTLINE      Bool    Whether the glyphs are outlines
+scalable       FC_SCALABLE     Bool    Whether glyphs can be scaled
+scale  FC_SCALE        Double  Scale factor for point->pixel conversions
+dpi    FC_DPI  Double  Target dots per inch
+rgba   FC_RGBA Int     rgb, bgr, vrgb, vbgr - subpixel geometry
+minspace       FC_MINSPACE     Bool    Eliminate leading from line spacing
+charset        FC_CHARSET      CharSet Unicode chars encoded by the font
+lang   FC_LANG String  List of language groups this font is designed for
+.DT
+.fi
+
+.SS FONT MATCHING
+Fontconfig performs matching by measuring the distance from a provided
+pattern to all of the available fonts in the system.  The closest matching
+font is selected.  This ensures that a font will always be returned, but
+doesn't ensure that it is anything like the requested pattern.
+.P
+Font matching starts with an application constructed pattern.  The desired
+attributes of the resulting font are collected together in an FcPattern
+object.  Each property of the pattern can contain one or more values; these
+are listed in priority order; matches earlier in the list are considered
+"closer" than matches later in the list.
+.P
+The initial pattern is modified by applying the list of editing instructions
+specific to patterns found in the configuration; each consists of a match
+predicate and a set of editing operations.  They are executed in the order
+they appeared in the configuration.  Each match causes the associated
+sequence of editing operations to be applied.
+.P
+After the pattern has been edited, a sequence of default substitutions are
+performed to canonicalize the set of available properties; this avoids the
+need for the lower layers to constantly provide default values for various
+font properties during rendering.
+.P
+The canonical font pattern is finally matched against all available fonts.
+The distance from the pattern to the font is measured for each of several
+properties: foundry, charset, antialias, family, spacing, pixelsize, style,
+slant, weight, rasterizer and outline.  This list is in priority order --
+results of comparing earlier elements of this list weigh more heavily than
+later elements.
+.P
+The pattern representing that font is augmented to include any properties
+found in the pattern but not found in the font itself; this permits the
+application to pass rendering instructions or any other data through the
+matching system.  Finally, the list of editing instructions specific to
+fonts found in the configuration are applied to the pattern.  This modified
+pattern is returned to the application.
+.P
+The return value contains sufficient information to locate and rasterize the
+font, including the file name, pixel size and other rendering data.  As
+none of the information involved pertains to the FreeType library,
+applications are free to use any rasterization engine or even to take
+the identified font file and access it directly.
+.P
+The match/edit sequences in the configuration are performed in two passes
+because there are essentially two different operations necessary -- the
+first is to modify how fonts are selected; aliasing families and adding
+suitable defaults.  The second is to modify how the selected fonts are
+rasterized.  Those must apply to the selected font, not the original pattern
+as false matches will often occur.
+.SS FONT NAMES
+Fontconfig provides a textual representation for patterns that the library
+can both accept and generate.  The representation is in three parts, first a
+list of family names, second a list of point sizes and finally a list of
+additional properties:
+.nf
+       <families>-<point sizes>:<name1>=<values1>:<name2>=<values2>...
+.fi
+Values in a list are separated with commas.  The name needn't include either
+families or point sizes; they can be elided.  In addition, there are
+symbolic constants that simultaneously indicate both a name and a value.
+Here are some examples:
+.sp
+.nf
+.ta 1i 3i
+       Times-12        12 point Times Roman
+       Times-12:bold   12 point Times Bold
+       Courier:italic  Courier Italic in the default size
+       Monospace:matrix=1 .1 0 1       The users preferred monospace font
+               with artificial obliquing
+.fi
+.DT
+
+.SH DATATYPES
+
+.TP
+.B FcChar8
+.TQ
+.B FcChar16
+.TQ
+.B FcChar32
+.TQ
+.B FcBool
+These are primitive datatypes; the FcChar* types hold precisely the number
+of bits stated (if supported by the C implementation).  FcBool holds
+one of two CPP symbols: FcFalse or FcTrue.
+
+.TP
+.B FcMatrix
+An FcMatrix holds an affine transformation, usually used to reshape glyphs.
+A small set of matrix operations are provided to manipulate these.
+.sp
+.nf
+       typedef struct _FcMatrix {
+               double xx, xy, yx, yy;
+       } FcMatrix;
+.fi
+
+.TP
+.B FcCharSet
+An FcCharSet is an abstract type that holds the set of encoded unicode chars
+in a font.  Operations to build and compare these sets are provided.
+
+.TP
+.B FcType
+Tags the kind of data stored in an FcValue.
+
+.TP
+.B FcValue
+An FcValue object holds a single value with one of a number of different
+types.  The 'type' tag indicates which member is valid.
+.sp
+.nf
+       typedef struct _FcValue {
+               FcType type;
+               union {
+                       const FcChar8 *s;
+                       int i;
+                       FcBool b;
+                       double d;
+                       const FcMatrix *m;
+                       const FcCharSet *c;
+               } u;
+       } FcValue;
+.fi
+.P
+.ta 1i 2i 3i 4i
+.nf
+.lc \(em
+       type    Union member    Datatype
+       \ 1\ 1\ 1
+       FcTypeVoid      (none)  (none)
+       FcTypeInteger   i       int
+       FcTypeDouble    d       double
+       FcTypeString    s       char *
+       FcTypeBool      b       b
+       FcTypeMatrix    m       FcMatrix *
+       FcTypeCharSet   c       FcCharSet *
+.fi
+.DT
+.TP
+.B FcPattern
+holds a set of names with associated value lists; each name refers to a
+property of a font.  FcPatterns are used as inputs to the matching code as
+well as holding information about specific fonts.  Each property can hold
+one or more values; conventionally all of the same type, although the
+interface doesn't demand that.
+
+.TP
+.B FcFontSet
+.sp
+.nf
+       typedef struct _FcFontSet {
+               int nfont;
+               int sfont;
+               FcPattern **fonts;
+       } FcFontSet;
+.fi    
+An FcFontSet contains a list of FcPatterns.  Internally fontconfig uses this
+data structure to hold sets of fonts.  Externally, fontconfig returns the
+results of listing fonts in this format.  'nfont' holds the number of
+patterns in the 'fonts' array; 'sfont' is used to indicate the size of that
+array.
+
+.TP
+.B FcObjectSet
+.sp
+.nf
+       typedef struct _FcObjectSet {
+               int nobject;
+               int sobject;
+               const char **objects;
+       } FcObjectSet;
+.fi
+holds a set of names and is used to specify which fields from fonts are
+placed in the the list of returned patterns when listing fonts.
+
+.TP
+.B FcBlanks
+holds a list of Unicode chars which are expected to be blank; unexpectedly
+blank chars are assumed to be invalid and are elided from the charset
+associated with the font.
+
+.TP
+.B FcFileCache
+holds the per-user cache information for use while loading the font
+database. This is built automatically for the current configuration when
+that is loaded.  Applications must always pass '0' when one is requested.
+
+.TP
+.B FcConfig
+holds a complete configuration of the library; there is one default
+configuration, other can be constructed from XML data structures.  All
+public entry points that need global data can take an optional FcConfig*
+argument; passing 0 uses the default configuration.  FcConfig objects hold two
+sets of fonts, the first contains those specified by the configuration, the
+second set holds those added by the application at run-time.  Interfaces
+that need to reference a particulat set use one of the FcSetName enumerated
+values.
+
+.TP
+.B FcSetName
+Specifies one of the two sets of fonts available in a configuration;
+FcSetSystem for those fonts specified in the configuration and
+FcSetApplication which holds fonts provided by the application.
+
+.TP
+.B FcResult
+Used as a return type for functions manipulating FcPattern objects.
+.P
+.ta 1i 3i 4i
+.lc \(em
+       Result code     Meaning
+.br
+       \ 1\ 1
+.br
+       FcResultMatch   Object exists with the specified ID
+.br
+       FcResultNoMatch Object doesn't exist at all
+.br
+       FcResultTypeMismatch    Object exists, but the type doesn't match
+.br
+       FcResultNoId    Object exists, but has fewer values than specified
+.br
+.DT
+
+.SH FUNCTIONS
+
+.SS FcMatrix
+FcMatrix structures hold an affine transformation in matrix form.
+.TP
+#define FcMatrixInit(m)        ((m)->xx = (m)->yy = 1, (m)->xy = (m)->yx = 0)
+Initializes a matrix to the identify transformation.
+
+.TP
+FcMatrix *FcMatrixCopy (const FcMatrix *mat)
+Allocates a new FcMatrix and copies 'mat' into it.
+
+.TP
+FcBool FcMatrixEqual (const FcMatrix *mat1, const FcMatrix *mat2)
+Returns FcTrue if 'mat1' and 'mat2' are equal, else FcFalse.
+
+.TP
+void FcMatrixMultiply (FcMatrix *result, const FcMatrix *a, const FcMatrix *b)
+Multiplies 'a' and 'b' together, placing the result in
+'result'.  'result' may refer to the sam matrix as either 'a' or 'b'.
+
+.TP
+void FcMatrixRotate (FcMatrix *m, double c, double s)
+If 'c' is cos(angle) and 's' is sin(angle), FcMatrixRotate rotates the
+matrix by 'angle'.
+
+.TP
+void FcMatrixScale (FcMatrix *m, double sx, double sy)
+Scales 'm' by 'sx' in the horizontal dimension and 'sy' in the
+vertical dimension.
+
+.TP
+void FcMatrixShear (FcMatrix *m, double sh, double sv)
+Shears 'm' by 'sh' in the horizontal direction and 'sv' in the
+vertical direction.
+
+.SS FcCharSet
+An FcCharSet is a boolean array indicating a set of unicode chars.  Those
+associated with a font are marked constant and cannot be edited.
+FcCharSets may be reference counted internally to reduce memory consumption;
+this may be visible to applications as the result of FcCharSetCopy may
+return it's argument, and that CharSet may remain unmodifiable.
+
+.TP
+FcCharSet *FcCharSetCreate (void)
+Creates an empty FcCharSet object.
+
+.TP
+void FcCharSetDestroy (FcCharSet *fcs)
+Frees an FcCharSet object.
+
+.TP
+FcBool FcCharSetAddChar (FcCharSet *fcs, FcChar32 ucs4)
+Adds a single unicode char to the set, returning FcFalse on
+failure, either as a result of a constant set or from running out of memory.
+
+.TP
+FcCharSet *FcCharSetCopy (FcCharSet *src)
+Makes a copy of 'src'; note that this may not actually do anything more than
+increment the reference count on 'src'.
+
+.TP
+FcBool FcCharSetEqual (const FcCharSet *a, const FcCharSet *b)
+Returns whether 'a' and 'b' contain the same set of unicode chars.
+
+.TP
+FcCharSet *FcCharSetIntersect (const FcCharSet *a, const FcCharSet *b)
+Returns a set including only those chars found in both 'a' and 'b'.
+
+.TP
+FcCharSet *FcCharSetUnion (const FcCharSet *a, const FcCharSet *b);
+Returns a set including only those chars found in either 'a' or 'b'.
+
+.TP 
+FcCharSet *FcCharSetSubtract (const FcCharSet *a, const FcCharSet *b)
+Returns a set including only those chars found in 'a' but not 'b'.
+
+.TP
+FcBool FcCharSetHasChar (const FcCharSet *fcs, FcChar32 ucs4)
+Returns whether 'fcs' contains the char 'ucs4'.
+
+.TP
+FcChar32 FcCharSetCount (const FcCharSet *a)
+Returns the total number of unicode chars in 'a'.
+
+.TP
+FcChar32 FcCharSetIntersectCount (const FcCharSet *a, const FcCharSet *b)
+Returns the number of chars that are in both 'a' and 'b'.
+
+.TP
+FcChar32 FcCharSetSubtractCount (const FcCharSet *a, const FcCharSet *b)
+Returns the number of chars that are in 'a' but not in 'b'.
+
+.SS FcValue
+FcValue is a structure containing a type tag and a union of all possible
+datatypes.  The tag is an enum of type 
+.B FcType
+and is intended to provide a measure of run-time
+typechecking, although that depends on careful programming.
+
+.TP
+void FcValueDestroy (FcValue v)
+Frees any memory referenced by `v'.  Values of type FcTypeString,
+FcTypeMatrix and FcTypeCharSet reference memory, the other types do not.
+
+.TP
+FcValue FcValueSave (FcValue v)
+Returns a copy of `v' duplicating any object referenced by it so that `v'
+may be safely destroyed without harming the new value.
+
+.SS FcPattern
+An FcPattern is an opaque type that holds both patterns to match against the
+available fonts, as well as the information about each font.
+
+.TP
+FcPattern *FcPatternCreate (void)
+Creates a pattern with no properties; used to build patterns from scratch.
+
+.TP
+void FcPatternDestroy (FcPattern *p)
+Destroys a pattern, in the process destroying all related values.
+
+.TP
+FcBool FcPatternAdd (FcPattern *p, const char *object, FcValue value, FcBool append)
+Adds a single value to the list of values associated with the property named
+`object'.  If `append' is FcTrue, the value is added at the end of any
+existing list, otherwise it is inserted at the begining.  `value' is saved
+(with FcValueSave) when inserted into the pattern so that the library
+retains no reference to any application-supplied data structure.
+
+.TP
+FcBool FcPatternAddInteger (FcPattern *p, const char *object, int i)
+.TQ
+FcBool FcPatternAddDouble (FcPattern *p, const char *object, double d)
+.TQ
+FcBool FcPatternAddString (FcPattern *p, const char *object, const char *s)
+.TQ
+FcBool FcPatternAddMatrix (FcPattern *p, const char *object, const FcMatrix *s)
+.TQ
+FcBool FcPatternAddCharSet (FcPattern *p, const char *object, const FcCharSet *c)
+.TQ
+FcBool FcPatternAddBool (FcPattern *p, const char *object, FcBool b)
+These are all convenience functions that insert objects of the specified
+type into the pattern.  Use these in preference to FcPatternAdd as they
+will provide compile-time typechecking.  These all append values to
+any existing list of values.
+
+.TP
+FcResult FcPatternGet (FcPattern *p, const char *object, int id, FcValue *v)
+Returns in `v' the `id'th value associated with the property `object'.
+The value returned is not a copy, but rather refers to the data stored
+within the pattern directly.  Applications must not free this value.
+
+.TP
+FcResult FcPatternGetInteger (FcPattern *p, const char *object, int n, int *i);
+.TQ
+FcResult FcPatternGetDouble (FcPattern *p, const char *object, int n, double *d);
+.TQ
+FcResult FcPatternGetString (FcPattern *p, const char *object, int n, char **const s);
+.TQ
+FcResult FcPatternGetMatrix (FcPattern *p, const char *object, int n, FcMatrix **s);
+.TQ
+FcResult FcPatternGetCharSet (FcPattern *p, const char *object, int n, FcCharSet **c);
+.TQ
+FcResult FcPatternGetBool (FcPattern *p, const char *object, int n, FcBool *b);
+These are convenience functions that call FcPatternGet and verify that the
+returned data is of the expected type. They return FcResultTypeMismatch if
+this is not the case.  Note that these (like FcPatternGet) do not make a
+copy of any data structure referenced by the return value.  Use these
+in preference to FcPatternGet to provide compile-time typechecking.
+
+.TP
+FcPattern *FcPatternBuild (FcPattern *orig, ...);
+.TQ
+FcPattern *FcPatternVaBuild (FcPattern *orig, va_list va)
+Builds a pattern using a list of objects, types and values.  Each
+value to be entered in the pattern is specified with three arguments:
+.IP
+1. Object name, a string describing the property to be added.
+.IP
+2. Object type, one of the FcType enumerated values
+.IP
+3. Value, not an FcValue, but the raw type as passed to any of the
+FcPatternAdd<type> functions.  Must match the type of the second argument.
+.IP
+The argument list is terminated by a null object name, no object type nor
+value need be passed for this.  The values are added to `pattern', if
+`pattern' is null, a new pattern is created.  In either case, the pattern is
+returned. Example:
+.RS
+.IP
+pattern = FcPatternBuild (0, FC_FAMILY, FtTypeString, "Times", (char *) 0);
+.RE
+.IP
+FcPatternVaBuild is used when the arguments are already in the form of a
+varargs value.
+
+.TP
+FcBool FcPatternDel (FcPattern *p, const char *object)
+Deletes all values associated with the property `object', returning 
+whether the property existed or not.
+
+.TP
+void FcPatternPrint (FcPattern *p)
+Prints an easily readable version of the pattern to stdout.  There is
+no provision for reparsing data in this format, it's just for diagnostics
+and debugging.
+
+.TP
+void FcDefaultSubstitute (FcPattern *pattern)
+Supplies default values for underspecified font patterns:
+.RS
+.IP \(bu 
+Patterns without a specified style or weight are set to Medium
+.IP \(bu
+Patterns without a specified style or slant are set to Roman
+.IP \(bu
+Patterns without a specified pixel size are given one computed from
+any specified point size (default 12), dpi (default 75) and scale (default
+1).
+.RE
+
+.TP
+FcPattern *FcNameParse (const char *name)
+Converts 'name' from the standard text format described above into a pattern.
+
+.TP
+FcChar8 *FcNameUnparse (FcPattern *pat)
+Converts the given pattern into the standard text format described above.
+The return value is not static, but instead refers to newly allocated memory
+which should be freed by the caller.
+
+.SS FcFontSet
+An FcFontSet simply holds a list of patterns; these are used to return the
+results of listing available fonts.
+.TP
+FcFontSet *FcFontSetCreate (void)
+Creates an empty font set.
+
+.TP
+void FcFontSetDestroy (FcFontSet *s);
+Destroys a font set.  Note that this destroys any referenced patterns as
+well.
+
+.TP 
+FcBool FcFontSetAdd (FcFontSet *s, FcPattern *font)
+Adds a pattern to a font set.  Note that the pattern is not copied before
+being inserted into the set.
+
+.SS FcObjectSet
+An FcObjectSet holds a list of pattern property names; it is used to
+indiciate which properties are to be returned in the patterns from
+FcFontList.
+
+.TP
+FcObjectSet *FcObjectSetCreate (void)
+Creates an empty set.
+
+.TP
+FcBool FcObjectSetAdd (FcObjectSet *os, const char *object)
+Adds a proprety name to the set.
+
+.TP
+void FcObjectSetDestroy (FcObjectSet *os)
+Destroys an object set.
+
+
+.TP
+FcObjectSet *FcObjectSetBuild (const char *first, ...)
+.TQ
+FcObjectSet *FcObjectSetVaBuild (const char *first, va_list va)
+These build an object set from a null-terminated list of property names.
+
+.SS FcBlanks
+An FcBlanks object holds a list of Unicode chars which are expected to
+be blank when drawn.  When scanning new fonts, any glyphs which are
+empty and not in this list will be assumed to be broken and not placed in
+the FcCharSet associated with the font.  This provides a significantly more
+accurate CharSet for applications.
+
+.TP
+FcBlanks *FcBlanksCreate (void)
+Creates an empty FcBlanks object.
+
+.TP
+void FcBlanksDestroy (FcBlanks *b)
+Destroys an FcBlanks object, freeing any associated memory.
+
+.TP
+FcBool FcBlanksAdd (FcBlanks *b, FcChar32 ucs4)
+Adds a single character to an FcBlanks object, returning FcFalse
+if this process ran out of memory.
+
+.TP
+FcBool FcBlanksIsMember (FcBlanks *b, FcChar32 ucs4)
+Returns whether the specified FcBlanks object contains the indicated Unicode
+value.
+
+.SS FcConfig
+An FcConfig object holds the internal representation of a configuration.
+There is a default configuration which applications may use by passing 0 to
+any function using the data within an FcConfig.
+
+.TP
+FcConfig *FcConfigCreate (void)
+Creates an empty configuration.
+
+.TP 
+void FcConfigDestroy (FcConfig *config)
+Destroys a configuration and any data associated with it.  Note that calling
+this function with the return from FcConfigGetCurrent will place the library
+in an indeterminate state.
+
+.TP
+FcBool FcConfigSetCurrent (FcConfig *config)
+Sets the current default configuration to 'config'.  Implicitly calls
+FcConfigBuildFonts if necessary, returning FcFalse if that call fails.
+
+.TP
+FcConfig *FcConfigGetCurrent (void)
+Returns the current default configuration.
+
+.TP
+FcBool FcConfigBuildFonts (FcConfig *config)
+Builds the set of available fonts for the given configuration.  Note that
+any changes to the configuration after this call have indeterminate effects.
+Returns FcFalse if this operation runs out of memory.
+
+.TP
+char **FcConfigGetDirs (FcConfig *config)
+Returns the list of font directories specified in 'config'.
+
+.TP 
+char **FcConfigGetConfigFiles (FcConfig *config)
+Returns the list of known configuration files used to generate 'config'.
+Note that this will not include any configuration done with FcConfigParse.
+
+.TP
+char *FcConfigGetCache (FcConfig *config)
+Returns the name of the file used to store per-user font information.
+
+.TP
+FcFontSet *FcConfigGetFonts (FcConfig *config, FcSetName set)
+Returns one of the two sets of fonts from the configuration as specified 
+by 'set'.
+
+.TP
+FcBlanks *FcConfigGetBlanks (FcConfig *config)
+Returns the FcBlanks object associated with the given configuration, if no
+blanks were present in the configuration, this function will return 0.
+
+.TP
+FcBool FcConfigAppFontAddFile (FcConfig *config, const char *file)
+Adds an application-specific font to the configuration.
+
+.TP 
+FcBool FcConfigAppFontAddDir (FcConfig *config, const char *dir)
+Scans the specified directory for fonts, adding each one found to the
+application-specific set of fonts.
+
+.TP 
+void FcConfigAppFontClear (FcConfig *config)
+Clears the set of application-specific fonts.
+
+.TP
+FcBool FcConfigSubstitute (FcConfig *config, FcPattern *p, FcMatchKind kind)
+Performs the sequence of pattern modification operations, if 'kind' is
+FcMatchPattern, then those tagged as pattern operations are applied, else 
+if 'kind' is FcMatchFont, those tagged as font operations are applied.
+
+.TP
+FcPattern *FcFontMatch (FcConfig *config, FcPattern *p, FcResult *result)
+Returns the font in 'config' most close matching 'p'.  This function
+should be called only after FcConfigSubstitute and FcDefaultSubstitute have
+been called; otherwise the results will be less useful.
+
+.TP
+FcFontSet *FcFontList (FcConfig *config, FcPattern *p, FcObjectSet *os)
+Selects fonts matching 'p', creates patterns from those fonts containing
+only the objects in 'os' and returns the set of unique such patterns.
+
+.TP
+char *FcConfigFilename (const char *name)
+Given the specified external entity name, return the associated filename.
+This provides applications a way to convert various configuration file
+references into filename form. 
+.P
+A null or empty 'name' indicates that the default configuration file should
+be used; which file this references can be overridden with the
+FC_CONFIG_FILE environment variable.  Next, if the name starts with '~', it
+refers to a file in the current users home directory.  Otherwise if the name
+doesn't start with '/', it refers to a file in the default configuration
+directory; the built-in default directory can be overridden with the
+FC_CONFIG_DIR environment variable.
+
+.SS Initialization
+These functions provide some control over how the library is initialized.
+
+.TP
+FcBool FcInitConfig (void)
+Initializes the default configuration using the default configuration file
+
+.TP
+FcBool FcInitFonts (void)
+Initializes the set of fonts available in the default configuration
+
+.TP
+FcBool FcInit (void)
+Calls FcInitConfig and FcInitFonts to completely initialize the default
+configuration.
+
+.SS FreeType specific functions
+.nf
+.B #include <fontconfig/fcfreetype.h>
+.fi
+While the fontconfig library doesn't insist that FreeType be used as the
+rasterization mechanism for fonts, it does provide some convenience
+functions.
+
+.TP
+FT_UInt FcFreeTypeCharIndex (FT_Face face, FcChar32 ucs4)
+Maps a Unicode char to a glyph index.  This function uses information from
+several possible underlying encoding tables to work around broken fonts.
+As a result, this function isn't designed to be used in performance
+sensitive areas; results from this function are intended to be cached by
+higher level functions.
+
+.TP
+FcCharSet *FcFreeTypeCharSet (FT_Face face, FcBlanks *blanks) Scans a
+FreeType face and returns the set of encoded Unicode chars.  This scans
+several encoding tables to build as complete a list as possible.  If
+'blanks' is not 0, the glyphs in the font are examined and any blank glyphs
+not in 'blanks' are not placed in the returned FcCharSet.
+
+.TP
+FcPattern *FcFreeTypeQuery (const char *file, int id, FcBlanks *blanks, int *count)
+Constructs a pattern representing the 'id'th font in 'file'.  The number
+of fonts in 'file' is returned in 'count'.
+
+.SS XML specific functions
+.nf
+.B #include <fontconfig/fcxml.h>
+.fi
+These functions expose the libxml2 datatypes used for font configuration.
+
+.TP
+xmlDocPtr FcConfigLoad (const char *file)
+Loads a configuration file mapping 'file' into a filename with
+FcConfigFilename.  This doesn't load a complete configuration as any
+include files referenced from 'file' will not be loaded.
+
+.TP
+FcBool FcConfigParse (FcConfig *config, xmlDocPtr doc)
+Walks the given configuration and constructs the internal representation in
+'config'.  Any include files referenced from within 'doc' will be loaded
+with FcConfigLoad and also parsed.
+
+.SS File and Directory routines
+
+.TP
+FcBool FcFileScan (FcFontSet *set, FcFileCache *cache, FcBlanks *blanks, const char *file, FcBool force)
+Scans a single file and adds all fonts found to 'set'.  If 'force' is FcTrue,
+then the file is scanned even if associated information is found in 'cache'.
+
+.TP
+FcBool FcDirScan (FcFontSet *set, FcFileCache *cache, FcBlanks *blanks, const char *dir, FcBool force)
+Scans an entire directory and adds all fonts found to 'set'.  If 'force' is
+FcTrue, then the directory and all files within it are scanned even if
+information is present in the per-directory cache file or 'cache'.
+
+.TP
+FcBool FcDirSave (FcFontSet *set, const char *dir)
+Creates the per-directory cache file for 'dir' and populates it with the
+fonts in 'set'.
+
+.SS String utilities
+
+.TP
+int FcUtf8ToUcs4 (FcChar8 *src, FcChar32 *dst, int len)
+Converts the next Unicode char from 'src' into 'dst' and returns the number
+of bytes containing the char.  'src' nust be at least 'len' bytes long.
+
+.TP
+FcBool FcUtf8Len (FcChar8 *string, int len, int *nchar, int *wchar)
+Counts the number of Unicode chars in 'len' bytes of 'string'.  Places that
+count in 'nchar'.  'wchar' contains 1, 2 or 4 depending on the number of
+bytes needed to hold the largest unicode char counted.  The return value
+indicates whether 'string' is a well-formed UTF8 string.
+
+.TP
+char *FcStrCopy (const char *s)
+Allocates memory, copies 's' and returns the resulting buffer.  Yes, this is
+'strdup', but that function isn't available on every platform.
+
+.TP
+int FcStrCmpIgnoreCase (const char *s1, const char *s2)
+Returns the usual <0, 0, >0 result of comparing 's1' and 's2'.  This test
+is case-insensitive in the ASCII range and will operate properly with UTF8
+encoded strings, although it does not check for well formed strings.
+
+.SH CONFIGURATION FILE FORMAT
+Configuration files for fontconfig are stored in XML format; this
+format makes external configuration tools easier to write and ensures that
+they will generate syntactically correct configuration files.  As XML
+files are plain text, they can also be manipulated by the expert user using
+a text editor.
+.P
+The fontconfig document type definition resides in the external entity
+"fonts.dtd"; this is normally stored in the default font configuration
+directory (/etc/fonts).  Each configuration file should contain the
+following structure:
+.sp
+.nf
+       <?xml version="1.0"?>
+       <!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+       <fontconfig>
+       ...
+       </fontconfig>
+.fi
+.P
+.SS <fontconfig>
+This is the top level element for a font configuration and can contain
+<dir>, <cache>, <include>, <match> and <alias> elements in any order.
+
+.SS <dir>
+This element contains a directory name which will be scanned for font files
+to include in the set of available fonts.
+
+.SS <cache>
+This element contains a file name for the per-user cache of font
+information.  If it starts with '~', it refers to a file in the users
+home directory.  This file is used to hold information about fonts that
+isn't present in the per-directory cache files.  It is automatically
+maintained by the fontconfig library.  The default for this file 
+is ``~/.fonts.cache''.
+
+.SS <include ignore_missing="no">
+This element contains the name of an additional configuration file.  When
+the XML datatype is traversed by FcConfigParse, the contents of the file
+will also be incorporated into the configuration by passing the filename to
+FcConfigLoadAndParse.  If 'ignore_missing' is set to "yes" instead of the
+default "no", a missing file will elicit no warning message from the library.
+
+.SS <match target="pattern">
+This element holds first a (possibly empty) list of tests and then a
+(possibly empty) list of edits.  Patterns which match all of the tests are
+subjected to all the edits.  If 'target' is set to "font" instead of the
+default "pattern", then this element applies to the font name resulting from
+a match rather than a font pattern to be matched.
+
+.SS <test qual="any" name="property" compare="eq">
+This element contains a single value which is compared with the pattern
+property "property" (substitute any of the property names seen above).
+'compare' can be one of "eq", "not_eq", "less", "less_eq", "more", or
+"more_eq".  'qual' may either be the default, "any", in which case the match
+succeeds if any value associated with the property matches the test value, or
+"all", in which case all of the values associated with the property must
+match the test value.
+
+.SS <edit name="property" mode="assign">
+This element contains a list of expression elements (any of the value or
+operator elements).  The expression elements are evaluated at run-time and
+modify the property "property".  The modification depends on whether
+"property" was matched by one of the associated <test> elements, if so, the
+modification may affect the first matched value.  'mode' is one of:
+.nf
+.RS
+.ta 1i 3i 5i
+Mode   Operation with match    Operation without match
+\ 1\ 1\ 1
+"assign"       Replace matching value  Replace all values
+"assign_replace"       Replace all values      Replace all values
+"prepend"      Insert before matching value    Insert at head of list
+"prepend_first"        Insert at head of list  Insert at head of list
+"append"       Append after matching value     Append at end of list
+"append_last"  Append at end of list   Append at end of list
+.RE
+.DT
+.fi
+.SS <int>
+.SS <double>
+.SS <string>
+.SS <bool>
+These elements hold a single value of the indicated type.  <bool> elements
+hold either true or false.
+.SS <matrix>
+This element holds the four <double> elements of an affine transformation.
+.SS <name>
+Holds a property name.  Evaluates to the first value from the property of
+the font, not the pattern.
+.SS <const>
+Holds the name of a constant; these are always integers and serve as
+symbolic names for common font values:
+.RS
+.sp
+.nf
+.ta 1i 2i 3i
+.lc \(em
+Constant       Property        CPP symbol
+\ 1\ 1\ 1
+light  weight  FC_WEIGHT_LIGHT
+medium weight  FC_WEIGHT_MEDIUM
+demibold       weight  FC_WEIGHT_DEMIBOLD
+bold   weight  FC_WEIGHT_BOLD
+black  weight  FC_WEIGHT_BLACK
+roman  slant   FC_SLANT_ROMAN
+italic slant   FC_SLANT_ITALIC
+oblique        slant   FC_SLANT_OBLIQUE
+proportional   spacing FC_PROPORTIONAL
+mono   spacing FC_MONO
+charcell       spacing FC_CHARCELL
+rgb    rgba    FC_RGBA_RGB
+bgr    rgba    FC_RGBA_BGR
+vrgb   rgba    FC_RGBA_VRGB
+vbgr   rgba    FC_RGBA_VBGR
+.DT
+.fi
+.RE
+.SS <or>
+.SS <and>
+.SS <plus>
+.SS <minus>
+.SS <times>
+.SS <divide>
+These elements perform the specified operation on a list of expression
+elements.  <or> and <and> are boolean, not bitwise.
+.SS <eq>
+.SS <not_eq>
+.SS <less>
+.SS <less_eq>
+.SS <more>
+.SS <more_eq>
+These elements compare two values, producing a boolean result.
+.SS <not>
+Inverts the boolean sense of its one expression element
+.SS <if>
+This element takes three expression elements; if the value of the first is
+true, it produces the value of the second, otherwise it produces the value
+of the third.
+.SS <alias>
+Alias elements provide a shorthand notation for the set of common match
+operations needed to substitute one font family for another.  They contain a
+<family> element followed by optional <prefer>, <accept> and <default>
+elements.  Fonts matching the <family> element are edited to prepend the
+list of <prefer>ed families before the matching <family>, append the
+<accept>able familys after the matching <family> and append the <default>
+families to the end of the family list.
+.SS <family>
+Holds a single font family name
+.SS <prefer>
+.SS <accept>
+.SS <default>
+These hold a list of <family> elements to be used by the <alias> element.
+.SH EXAMPLE CONFIGURATION FILE
+.SS System configuration file
+This is an example of a system-wide configuration file
+.sp
+.nf
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts/fonts.conf file to configure system font access -->
+<fontconfig>
+<!-- 
+       Find fonts in these directories
+-->
+<dir>/usr/X11R6/lib/X11/fonts/truetype</dir>
+<dir>/usr/X11R6/lib/X11/fonts/Type1</dir>
+
+<!--
+       Accept deprecated 'mono' alias, replacing it with 'monospace'
+-->
+<match target="pattern">
+       <test qual="any" name="family"><string>mono</string></test>
+       <edit name="family" mode="assign"><string>monospace</string></edit>
+</match>
+
+<!--
+       Names not including any well known alias are given 'sans'
+-->
+<match target="pattern">
+       <test qual="all" name="family" mode="not_eq">sans</test>
+       <test qual="all" name="family" mode="not_eq">serif</test>
+       <test qual="all" name="family" mode="not_eq">monospace</test>
+       <edit name="family" mode="append_last"><string>sans</string></edit>
+</match>
+
+<!--
+       Load per-user customization file, but don't complain
+       if it doesn't exist
+-->
+<include ignore_missing="yes">~/.fonts.conf</include>
+
+<!--
+       Alias well known font names to available TrueType fonts.
+       These substitute TrueType faces for similar Type1
+       faces to improve screen appearance.
+-->
+<alias>
+       <family>Times</family>
+       <prefer><family>Times New Roman</family></prefer>
+       <default><family>serif</family></default>
+</alias>
+<alias>
+       <family>Helvetica</family>
+       <prefer><family>Verdana</family></prefer>
+       <default><family>sans</family></default>
+</alias>
+<alias>
+       <family>Courier</family>
+       <prefer><family>Courier New</family></prefer>
+       <default><family>monospace</family></default>
+</alias>
+
+<!--
+       Provide required aliases for standard names
+       Do these after the users configuration file so that
+       any aliases there are used preferentially
+-->
+<alias>
+       <family>serif</family>
+       <prefer><family>Times New Roman</family></prefer>
+</alias>
+<alias>
+       <family>sans</family>
+       <prefer><family>Verdana</family></prefer>
+</alias>
+<alias>
+       <family>monospace</family>
+       <prefer><family>Andale Mono</family></prefer>
+</alias>
+</fontconfig>
+.fi
+.SS User configuration file
+This is an example of a per-user configuration file that lives in
+~/.fonts.conf
+.sp
+.nf
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- ~/.fonts.conf for per-user font configuration -->
+<fontconfig>
+
+<!--
+       Private font directory
+-->
+<dir>~/misc/fonts</dir>
+
+<!--
+       use rgb sub-pixel ordering to improve glyph appearance on
+       LCD screens.  Changes affecting rendering, but not matching
+       should always use target="font".
+-->
+<match target="font">
+       <edit name="rgba" mode="assign"><const>rgb</const></edit>
+</match>
+</fontconfig>
+.fi
+.SH FILES
+.B fonts.conf
+contains configuration information for the fontconfig library
+consisting of directories to look at for font information as well as
+instructions on editing program specified font patterns before attempting to
+match the available fonts.  It is in xml format.
+
+.B fonts.dtd 
+is a DTD that describes the format of the configuration files.
+
+.B ~/.fonts.conf
+is the conventional location for per-user font configuration, although the
+actual location is specified in the global fonts.conf file.
+
+.B ~/.fonts.cache
+is the conventional repository of font information that isn't found in the
+per-directory caches.  This file is automatically maintained by fontconfig.
+
+.SH AUTHOR
+Keith Packard, member of the XFree86 Project, Inc.