Rework to apply the intermixed test and edit elements in one-pass
authorAkira TAGOH <akira@tagoh.org>
Thu, 4 Jul 2013 10:51:03 +0000 (19:51 +0900)
committerAkira TAGOH <akira@tagoh.org>
Thu, 4 Jul 2013 10:51:03 +0000 (19:51 +0900)
src/fccfg.c
src/fcdbg.c
src/fcint.h
src/fcxml.c

index 3cf31e8..7ea94b8 100644 (file)
@@ -214,10 +214,8 @@ FcSubstDestroy (FcSubst *s)
     while (s)
     {
        n = s->next;
-       if (s->test)
-           FcTestDestroy (s->test);
-       if (s->edit)
-           FcEditDestroy (s->edit);
+       if (s->rule)
+           FcRuleDestroy (s->rule);
        free (s);
        s = n;
     }
@@ -226,8 +224,6 @@ FcSubstDestroy (FcSubst *s)
 FcExpr *
 FcConfigAllocExpr (FcConfig *config)
 {
-    FcExpr *e;
-
     if (!config->expr_pool || config->expr_pool->next == config->expr_pool->end)
     {
        FcExprPage *new_page;
@@ -241,10 +237,7 @@ FcConfigAllocExpr (FcConfig *config)
        config->expr_pool = new_page;
     }
 
-    e = config->expr_pool->next++;
-    FcRefInit (&e->ref, 1);
-
-    return e;
+    return config->expr_pool->next++;
 }
 
 FcConfig *
@@ -649,15 +642,13 @@ FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
     return FcConfigSetRescanInterval (config, rescanInterval);
 }
 
-
 FcBool
-FcConfigAddEdit (FcConfig      *config,
-                FcTest         *test,
-                FcEdit         *edit,
+FcConfigAddRule (FcConfig      *config,
+                FcRule         *rule,
                 FcMatchKind    kind)
 {
     FcSubst    *subst, **prev;
-    FcTest     *t;
+    FcRule     *r;
     int                num;
 
     switch (kind) {
@@ -678,15 +669,18 @@ FcConfigAddEdit (FcConfig *config,
        return FcFalse;
     for (; *prev; prev = &(*prev)->next);
     *prev = subst;
-    subst->next = 0;
-    subst->test = test;
-    subst->edit = edit;
+    subst->next = NULL;
+    subst->rule = rule;
     num = 0;
-    for (t = test; t; t = t->next)
+    for (r = rule; r; r = r->next)
     {
-       if (t->kind == FcMatchDefault)
-           t->kind = kind;
-       num++;
+       if (r->type == FcRuleTest)
+       {
+           if (r->u.test &&
+               r->u.test->kind == FcMatchDefault)
+               r->u.test->kind = kind;
+           num++;
+       }
     }
     if (config->maxObjects < num)
        config->maxObjects = num;
@@ -1491,13 +1485,12 @@ FcConfigSubstituteWithPat (FcConfig    *config,
 {
     FcValue v;
     FcSubst        *s;
-    FcSubState     *st;
-    int                    i;
-    FcTest         *t;
-    FcEdit         *e;
-    FcValueList            *l;
+    FcRule          *r;
+    FcValueList            *l, *value = NULL;
     FcPattern      *m;
     FcStrSet       *strs;
+    FcPatternElt    *elt = NULL;
+    FcObject       object = FC_INVALID_OBJECT;
 
     if (!config)
     {
@@ -1542,10 +1535,6 @@ FcConfigSubstituteWithPat (FcConfig    *config,
        return FcFalse;
     }
 
-    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
-    if (!st && config->maxObjects)
-       return FcFalse;
-
     if (FcDebug () & FC_DBG_EDIT)
     {
        printf ("FcConfigSubstitute ");
@@ -1553,194 +1542,174 @@ FcConfigSubstituteWithPat (FcConfig    *config,
     }
     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++)
+       r = s->rule;
+       for (; r; r = r->next)
        {
-           if (FcDebug () & FC_DBG_EDIT)
-           {
-               printf ("FcConfigSubstitute test ");
-               FcTestPrint (t);
-           }
-           st[i].elt = 0;
-           if (kind == FcMatchFont && t->kind == FcMatchPattern)
-               m = p_pat;
-           else
-               m = p;
-           if (m)
-               st[i].elt = FcPatternObjectFindElt (m, t->object);
-           else
-               st[i].elt = 0;
-           /*
-            * If there's no such field in the font,
-            * then FcQualAll matches while FcQualAny does not
-            */
-           if (!st[i].elt)
-           {
-               if (t->qual == FcQualAll)
+           switch (r->type) {
+           case FcRuleUnknown:
+               /* shouldn't be reached */
+               break;
+           case FcRuleTest:
+               /*
+                * Check the tests to see if
+                * they all match the pattern
+                */
+               if (FcDebug () & FC_DBG_EDIT)
                {
-                   st[i].value = 0;
-                   continue;
+                   printf ("FcConfigSubstitute test ");
+                   FcTestPrint (r->u.test);
                }
+               if (kind == FcMatchFont && r->u.test->kind == FcMatchPattern)
+                   m = p_pat;
                else
-                   break;
-           }
-           /*
-            * Check to see if there is a match, mark the location
-            * to apply match-relative edits
-            */
-           st[i].value = FcConfigMatchValueList (m, p_pat, kind, t, st[i].elt->values);
-           if (!st[i].value)
-               break;
-           if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
-               break;
-           if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
-               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, p_pat,kind,  e->expr, e->binding);
-           /*
-            * Locate any test associated with this field, skipping
-            * tests associated with the pattern when substituting in
-            * the font
-            */
-           for (t = s->test, i = 0; t; t = t->next, i++)
-           {
-               if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
-                   t->object == e->object)
+                   m = p;
+               if (m)
+                   elt = FcPatternObjectFindElt (m, r->u.test->object);
+               else
+                   elt = NULL;
+               /*
+                * If there's no such field in the font,
+                * then FcQualAll matches while FcQualAny does not
+                */
+               if (!elt)
                {
-                   /*
-                    * KLUDGE - the pattern may have been reallocated or
-                    * things may have been inserted or deleted above
-                    * this element by other edits.  Go back and find
-                    * the element again
-                    */
-                   if (e != s->edit && st[i].elt)
-                       st[i].elt = FcPatternObjectFindElt (p, t->object);
-                   if (!st[i].elt)
-                       t = 0;
-                   break;
+                   if (r->u.test->qual == FcQualAll)
+                   {
+                       value = NULL;
+                       continue;
+                   }
+                   else
+                   {
+                       if (FcDebug () & FC_DBG_EDIT)
+                           printf ("No match\n");
+                       goto bail;
+                   }
                }
-           }
-           switch (FC_OP_GET_OP (e->op)) {
-           case FcOpAssign:
                /*
-                * If there was a test, then replace the matched
-                * value with the new list of values
+                * Check to see if there is a match, mark the location
+                * to apply match-relative edits
                 */
-               if (t)
+               value = FcConfigMatchValueList (m, p_pat, kind, r->u.test, elt->values);
+               if (!value ||
+                   (r->u.test->qual == FcQualFirst && value != elt->values) ||
+                   (r->u.test->qual == FcQualNotFirst && value == elt->values))
                {
-                   FcValueList *thisValue = st[i].value;
-                   FcValueList *nextValue = thisValue;
-               
+                   if (FcDebug () & FC_DBG_EDIT)
+                       printf ("No match\n");
+                   goto bail;
+               }
+               object = r->u.test->object;
+               break;
+           case FcRuleEdit:
+               if (FcDebug () & FC_DBG_EDIT)
+               {
+                   printf ("Substitute ");
+                   FcEditPrint (r->u.edit);
+                   printf ("\n\n");
+               }
+               /*
+                * Evaluate the list of expressions
+                */
+               l = FcConfigValues (p, p_pat,kind,  r->u.edit->expr, r->u.edit->binding);
+               /*
+                * Locate any test associated with this field, skipping
+                * tests associated with the pattern when substituting in
+                * the font
+                */
+               if (object != r->u.edit->object)
+                   value = NULL;
+
+               switch (FC_OP_GET_OP (r->u.edit->op)) {
+               case FcOpAssign:
                    /*
-                    * Append the new list of values after the current value
+                    * If there was a test, then replace the matched
+                    * value with the new list of values
                     */
-                   FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l, e->object);
+                   if (value)
+                   {
+                       FcValueList     *thisValue = value;
+                       FcValueList     *nextValue = thisValue;
+
+                       /*
+                        * Append the new list of values after the current value
+                        */
+                       FcConfigAdd (&elt->values, thisValue, FcTrue, l, r->u.edit->object);
+                       /*
+                        * Delete the marked value
+                        */
+                       if (thisValue)
+                           FcConfigDel (&elt->values, thisValue);
+                       /*
+                        * Adjust a pointer into the value list to ensure
+                        * future edits occur at the same place
+                        */
+                       value = nextValue;
+                       break;
+                   }
+                   /* fall through ... */
+               case FcOpAssignReplace:
                    /*
-                    * Delete the marked value
+                    * Delete all of the values and insert
+                    * the new set
                     */
-                    if (thisValue)
-                       FcConfigDel (&st[i].elt->values, thisValue);
+                   FcConfigPatternDel (p, r->u.edit->object);
+                   FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
                    /*
-                    * Adjust any pointers into the value list to ensure
-                    * future edits occur at the same place
+                    * Adjust a pointer into the value list as they no
+                    * longer point to anything valid
                     */
-                   for (t = s->test, i = 0; t; t = t->next, i++)
+                   value = NULL;
+                   break;
+               case FcOpPrepend:
+                   if (value)
                    {
-                       if (st[i].value == thisValue)
-                           st[i].value = nextValue;
+                       FcConfigAdd (&elt->values, value, FcFalse, l, r->u.edit->object);
+                       break;
                    }
+                   /* fall through ... */
+               case FcOpPrependFirst:
+                   FcConfigPatternAdd (p, r->u.edit->object, l, FcFalse);
                    break;
-               }
-               /* fall through ... */
-           case FcOpAssignReplace:
-               /*
-                * Delete all of the values and insert
-                * the new set
-                */
-               FcConfigPatternDel (p, e->object);
-               FcConfigPatternAdd (p, e->object, 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++)
+               case FcOpAppend:
+                   if (value)
                    {
-                       if (st[i].elt == thisElt)
-                           st[i].value = 0;
+                       FcConfigAdd (&elt->values, value, FcTrue, l, r->u.edit->object);
+                       break;
                    }
-               }
-               break;
-           case FcOpPrepend:
-               if (t)
-               {
-                   FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l, e->object);
+                   /* fall through ... */
+               case FcOpAppendLast:
+                   FcConfigPatternAdd (p, r->u.edit->object, l, FcTrue);
                    break;
-               }
-               /* fall through ... */
-           case FcOpPrependFirst:
-               FcConfigPatternAdd (p, e->object, l, FcFalse);
-               break;
-           case FcOpAppend:
-               if (t)
-               {
-                   FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l, e->object);
+               case FcOpDelete:
+                   if (value)
+                   {
+                       FcConfigDel (&elt->values, value);
+                       break;
+                   }
+                   /* fall through ... */
+               case FcOpDeleteAll:
+                   FcConfigPatternDel (p, r->u.edit->object);
+                   break;
+               default:
+                   FcValueListDestroy (l);
                    break;
                }
-               /* fall through ... */
-           case FcOpAppendLast:
-               FcConfigPatternAdd (p, e->object, l, FcTrue);
-               break;
-           case FcOpDelete:
-               if (t)
+               /*
+                * Now go through the pattern and eliminate
+                * any properties without data
+                */
+               FcConfigPatternCanon (p, r->u.edit->object);
+
+               if (FcDebug () & FC_DBG_EDIT)
                {
-                   FcConfigDel (&st[i].elt->values, st[i].value);
-                   break;
+                   printf ("FcConfigSubstitute edit");
+                   FcPatternPrint (p);
                }
-               /* fall through ... */
-           case FcOpDeleteAll:
-               FcConfigPatternDel (p, e->object);
-               break;
-           default:
-                FcValueListDestroy (l);
                break;
            }
        }
-       /*
-        * Now go through the pattern and eliminate
-        * any properties without data
-        */
-       for (e = s->edit; e; e = e->next)
-           FcConfigPatternCanon (p, e->object);
-
-       if (FcDebug () & FC_DBG_EDIT)
-       {
-           printf ("FcConfigSubstitute edit");
-           FcPatternPrint (p);
-       }
+    bail:;
     }
-    free (st);
     if (FcDebug () & FC_DBG_EDIT)
     {
        printf ("FcConfigSubstitute done");
index ce64214..d74bc27 100644 (file)
@@ -427,21 +427,38 @@ FcEditPrint (const FcEdit *edit)
 void
 FcSubstPrint (const FcSubst *subst)
 {
-    FcEdit     *e;
-    FcTest     *t;
+    FcRule *r;
+    FcRuleType last_type = FcRuleUnknown;
 
     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)
+    for (r = subst->rule; r; r = r->next)
     {
+       if (last_type != r->type)
+       {
+           switch (r->type) {
+           case FcRuleTest:
+               printf ("[test]\n");
+               break;
+           case FcRuleEdit:
+               printf ("[edit]\n");
+               break;
+           default:
+               break;
+           }
+           last_type = r->type;
+       }
        printf ("\t");
-       FcEditPrint (e);
-       printf (";\n");
+       switch (r->type) {
+       case FcRuleTest:
+           FcTestPrint (r->u.test);
+           break;
+       case FcRuleEdit:
+           FcEditPrint (r->u.edit);
+           printf (";\n");
+           break;
+       default:
+           break;
+       }
     }
     printf ("\n");
 }
index 9dff033..fe523fb 100644 (file)
@@ -241,7 +241,6 @@ typedef struct _FcExprName {
 
 typedef struct _FcExpr {
     FcOp   op;
-    FcRef  ref;
     union {
        int         ival;
        double      dval;
@@ -275,7 +274,6 @@ typedef enum _FcQual {
 #define FcMatchDefault ((FcMatchKind) -1)
 
 typedef struct _FcTest {
-    struct _FcTest     *next;
     FcMatchKind                kind;
     FcQual             qual;
     FcObject           object;
@@ -284,17 +282,28 @@ typedef struct _FcTest {
 } FcTest;
 
 typedef struct _FcEdit {
-    struct _FcEdit *next;
     FcObject       object;
     FcOp           op;
     FcExpr         *expr;
     FcValueBinding  binding;
 } FcEdit;
 
+typedef enum _FcRuleType {
+    FcRuleUnknown, FcRuleTest, FcRuleEdit
+} FcRuleType;
+
+typedef struct _FcRule {
+    struct _FcRule *next;
+    FcRuleType      type;
+    union {
+       FcTest *test;
+       FcEdit *edit;
+    } u;
+} FcRule;
+
 typedef struct _FcSubst {
     struct _FcSubst    *next;
-    FcTest             *test;
-    FcEdit             *edit;
+    FcRule             *rule;
 } FcSubst;
 
 typedef struct _FcCharLeaf {
@@ -614,10 +623,9 @@ FcPrivate FcBool
 FcConfigAddBlank (FcConfig     *config,
                  FcChar32      blank);
 
-FcPrivate FcBool
-FcConfigAddEdit (FcConfig      *config,
-                FcTest         *test,
-                FcEdit         *edit,
+FcBool
+FcConfigAddRule (FcConfig      *config,
+                FcRule         *rule,
                 FcMatchKind    kind);
 
 FcPrivate void
@@ -844,6 +852,9 @@ FcTestDestroy (FcTest *test);
 FcPrivate void
 FcEditDestroy (FcEdit *e);
 
+void
+FcRuleDestroy (FcRule *rule);
+
 /* fclang.c */
 FcPrivate FcLangSet *
 FcFreeTypeLangSet (const FcCharSet  *charset,
index 4b8049f..61dc630 100644 (file)
@@ -62,12 +62,28 @@ FcExprDestroy (FcExpr *e);
 void
 FcTestDestroy (FcTest *test)
 {
-    if (test->next)
-       FcTestDestroy (test->next);
     FcExprDestroy (test->expr);
     free (test);
 }
 
+void
+FcRuleDestroy (FcRule *rule)
+{
+    if (rule->next)
+       FcRuleDestroy (rule->next);
+    switch (rule->type) {
+    case FcRuleTest:
+       FcTestDestroy (rule->u.test);
+       break;
+    case FcRuleEdit:
+       FcEditDestroy (rule->u.edit);
+       break;
+    default:
+       break;
+    }
+    free (rule);
+}
+
 static FcExpr *
 FcExprCreateInteger (FcConfig *config, int i)
 {
@@ -223,24 +239,11 @@ FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
     return e;
 }
 
-static FcExpr *
-FcExprReference (FcExpr *e)
-{
-    if (e)
-    {
-       FcRefInc (&e->ref);
-    }
-
-    return e;
-}
-
 static void
 FcExprDestroy (FcExpr *e)
 {
     if (!e)
        return;
-    if (FcRefDec (&e->ref) != 1)
-       return;
     switch (FC_OP_GET_OP (e->op)) {
     case FcOpInteger:
        break;
@@ -313,8 +316,6 @@ FcExprDestroy (FcExpr *e)
 void
 FcEditDestroy (FcEdit *e)
 {
-    if (e->next)
-       FcEditDestroy (e->next);
     if (e->expr)
        FcExprDestroy (e->expr);
     free (e);
@@ -727,7 +728,6 @@ FcTestCreate (FcConfigParse *parse,
     {
        const FcObjectType      *o;
        
-       test->next = 0;
        test->kind = kind;
        test->qual = qual;
        test->object = FcObjectFromName ((const char *) field);
@@ -740,21 +740,6 @@ FcTestCreate (FcConfigParse *parse,
     return test;
 }
 
-static FcTest *
-FcTestDuplicate (FcTest *test)
-{
-    FcTest *retval = (FcTest *) malloc (sizeof (FcTest));
-
-    if (retval)
-    {
-       memcpy (retval, test, sizeof (FcTest));
-       retval->next = NULL;
-       retval->expr = FcExprReference (test->expr);
-    }
-
-    return retval;
-}
-
 static FcEdit *
 FcEditCreate (FcConfigParse    *parse,
              FcObject          object,
@@ -768,7 +753,6 @@ FcEditCreate (FcConfigParse *parse,
     {
        const FcObjectType      *o;
 
-       e->next = 0;
        e->object = object;
        e->op = op;
        e->expr = expr;
@@ -780,6 +764,34 @@ FcEditCreate (FcConfigParse        *parse,
     return e;
 }
 
+static FcRule *
+FcRuleCreate (FcRuleType type,
+             void       *p)
+{
+    FcRule *r = (FcRule *) malloc (sizeof (FcRule));
+
+    if (!r)
+       return NULL;
+
+    r->next = NULL;
+    r->type = type;
+    switch (type)
+    {
+    case FcRuleTest:
+       r->u.test = (FcTest *) p;
+       break;
+    case FcRuleEdit:
+       r->u.edit = (FcEdit *) p;
+       break;
+    default:
+       free (r);
+       r = NULL;
+       break;
+    }
+
+    return r;
+}
+
 static FcVStack *
 FcVStackCreateAndPush (FcConfigParse *parse)
 {
@@ -1685,9 +1697,9 @@ static void
 FcParseAlias (FcConfigParse *parse)
 {
     FcExpr     *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
-    FcEdit     *edit = 0, *next;
+    FcEdit     *edit = 0;
     FcVStack   *vstack;
-    FcTest     *test = NULL;
+    FcRule     *rule = NULL, *r;
     FcValueBinding  binding;
 
     if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
@@ -1732,8 +1744,14 @@ FcParseAlias (FcConfigParse *parse)
            vstack->tag = FcVStackNone;
            break;
        case FcVStackTest:
-           vstack->u.test->next = test;
-           test = vstack->u.test;
+           if (rule)
+           {
+               r = FcRuleCreate (FcRuleTest, vstack->u.test);
+               r->next = rule;
+               rule = r;
+           }
+           else
+               rule = FcRuleCreate (FcRuleTest, vstack->u.test);
            vstack->tag = FcVStackNone;
            break;
        default:
@@ -1751,8 +1769,35 @@ FcParseAlias (FcConfigParse *parse)
            FcExprDestroy (accept);
        if (def)
            FcExprDestroy (def);
+       if (rule)
+           FcRuleDestroy (rule);
        return;
     }
+    if (!prefer &&
+       !accept &&
+       !def)
+    {
+       FcExprDestroy (family);
+       return;
+    }
+    else
+    {
+       FcTest *t = FcTestCreate (parse, FcMatchPattern,
+                                 FcQualAny,
+                                 (FcChar8 *) FC_FAMILY,
+                                 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
+                                 family);
+       if (rule)
+       {
+           for (r = rule; r->next; r = r->next);
+           r->next = FcRuleCreate (FcRuleTest, t);
+           r = r->next;
+       }
+       else
+       {
+           r = rule = FcRuleCreate (FcRuleTest, t);
+       }
+    }
     if (prefer)
     {
        edit = FcEditCreate (parse,
@@ -1760,60 +1805,46 @@ FcParseAlias (FcConfigParse *parse)
                             FcOpPrepend,
                             prefer,
                             binding);
-       if (edit)
-           edit->next = 0;
-       else
+       if (!edit)
            FcExprDestroy (prefer);
+       else
+       {
+           r->next = FcRuleCreate (FcRuleEdit, edit);
+           r = r->next;
+       }
     }
     if (accept)
     {
-       next = edit;
        edit = FcEditCreate (parse,
                             FC_FAMILY_OBJECT,
                             FcOpAppend,
                             accept,
                             binding);
-       if (edit)
-           edit->next = next;
-       else
+       if (!edit)
            FcExprDestroy (accept);
+       else
+       {
+           r->next = FcRuleCreate (FcRuleEdit, edit);
+           r = r->next;
+       }
     }
     if (def)
     {
-       next = edit;
        edit = FcEditCreate (parse,
                             FC_FAMILY_OBJECT,
                             FcOpAppendLast,
                             def,
                             binding);
-       if (edit)
-           edit->next = next;
-       else
+       if (!edit)
            FcExprDestroy (def);
-    }
-    if (edit)
-    {
-       FcTest *t = FcTestCreate (parse, FcMatchPattern,
-                                 FcQualAny,
-                                 (FcChar8 *) FC_FAMILY,
-                                 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
-                                 family);
-       if (test)
+       else
        {
-           FcTest *p = test;
-
-           while (p->next)
-               p = p->next;
-           p->next = t;
+           r->next = FcRuleCreate (FcRuleEdit, edit);
+           r = r->next;
        }
-       else
-           test = t;
-       if (test)
-           if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern))
-               FcTestDestroy (test);
     }
-    else
-       FcExprDestroy (family);
+    if (!FcConfigAddRule (parse->config, rule, FcMatchPattern))
+       FcRuleDestroy (rule);
 }
 
 static FcExpr *
@@ -2414,22 +2445,14 @@ FcParseEdit (FcConfigParse *parse)
        FcEditDestroy (edit);
 }
 
-typedef struct FcSubstStack {
-    FcTest *test;
-    FcEdit *edit;
-} FcSubstStack;
-
 static void
 FcParseMatch (FcConfigParse *parse)
 {
     const FcChar8   *kind_name;
     FcMatchKind            kind;
-    FcTest         *test = 0;
     FcEdit         *edit = 0;
     FcVStack       *vstack;
-    FcBool           tested = FcFalse;
-    FcSubstStack    *sstack = NULL;
-    int              len, pos = 0, i;
+    FcRule         *rule = NULL, *r;
 
     kind_name = FcConfigGetAttribute (parse, "target");
     if (!kind_name)
@@ -2448,55 +2471,29 @@ FcParseMatch (FcConfigParse *parse)
            return;
        }
     }
-    len = FcVStackElements(parse);
-    if (len > 0)
-    {
-       sstack = malloc (sizeof (FcSubstStack) * (len + 1));
-       if (!sstack)
-       {
-           FcConfigMessage (parse, FcSevereError, "out of memory");
-           return;
-       }
-    }
     while ((vstack = FcVStackPeek (parse)))
     {
        switch ((int) vstack->tag) {
        case FcVStackTest:
-           vstack->u.test->next = test;
-           test = vstack->u.test;
+           r = FcRuleCreate (FcRuleTest, vstack->u.test);
+           if (rule)
+               r->next = rule;
+           rule = r;
            vstack->tag = FcVStackNone;
-           tested = FcTrue;
-           for (i = 0; i < pos; i++)
-           {
-               FcTest *t = FcTestDuplicate(test);
-
-               t->next = sstack[i].test;
-               sstack[i].test = t;
-           }
            break;
        case FcVStackEdit:
-           /* due to the reverse traversal, <edit> node appears faster than
-            * <test> node if any. so we have to deal with it here rather than
-            * the above in FcVStackTest, and put recipes in reverse order.
-            */
-           if (tested)
-           {
-               sstack[pos].test = test;
-               sstack[pos].edit = edit;
-               pos++;
-               test = NULL;
-               edit = NULL;
-               tested = FcFalse;
-           }
-           vstack->u.edit->next = edit;
-           edit = vstack->u.edit;
-           vstack->tag = FcVStackNone;
-           if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT)
+           if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
            {
                FcConfigMessage (parse, FcSevereError,
                                 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
                                 FcObjectName(edit->object));
+               break;
            }
+           r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
+           if (rule)
+               r->next = rule;
+           rule = r;
+           vstack->tag = FcVStackNone;
            break;
        default:
            FcConfigMessage (parse, FcSevereWarning, "invalid match element");
@@ -2504,22 +2501,8 @@ FcParseMatch (FcConfigParse *parse)
        }
        FcVStackPopAndDestroy (parse);
     }
-    if (!FcConfigAddEdit (parse->config, test, edit, kind))
+    if (!FcConfigAddRule (parse->config, rule, kind))
        FcConfigMessage (parse, FcSevereError, "out of memory");
-    if (sstack)
-    {
-       int i;
-
-       for (i = 0; i < pos; i++)
-       {
-           if (!FcConfigAddEdit (parse->config, sstack[pos - i - 1].test, sstack[pos - i - 1].edit, kind))
-           {
-               FcConfigMessage (parse, FcSevereError, "out of memory");
-               return;
-           }
-       }
-       free (sstack);
-    }
 }
 
 static void