]> git.wh0rd.org - fontconfig.git/commitdiff
[fcformat] Add conditionals
authorBehdad Esfahbod <behdad@behdad.org>
Tue, 10 Feb 2009 05:15:08 +0000 (00:15 -0500)
committerBehdad Esfahbod <behdad@behdad.org>
Sun, 15 Feb 2009 21:40:27 +0000 (13:40 -0800)
The conditional '%{?elt1,elt2,!elt3{expr1}{expr2}}' will evaluate
expr1 if elt1 and elt2 exist in pattern and elt3 doesn't exist, and
expr2 otherwise.  The '{expr2}' part is optional.

src/fcformat.c

index 31f3a744af1f9bf9caba2b036316dd90e02ee13e..e1e05eed474d89fdb9f383485fcbeb8d9ac7a047 100644 (file)
@@ -150,10 +150,10 @@ read_elt_name_to_scratch (FcFormatContext *c)
 }
 
 static FcBool
-interpret (FcFormatContext *c,
-          FcPattern       *pat,
-          FcStrBuf        *buf,
-          FcChar8          term);
+interpret_expr (FcFormatContext *c,
+               FcPattern       *pat,
+               FcStrBuf        *buf,
+               FcChar8          term);
 
 static FcBool
 interpret_subexpr (FcFormatContext *c,
@@ -161,10 +161,94 @@ interpret_subexpr (FcFormatContext *c,
                   FcStrBuf        *buf)
 {
     return expect_char (c, '{') &&
-          interpret (c, pat, buf, '}') &&
+          interpret_expr (c, pat, buf, '}') &&
           expect_char (c, '}');
 }
 
+static FcBool
+maybe_interpret_subexpr (FcFormatContext *c,
+                        FcPattern       *pat,
+                        FcStrBuf        *buf)
+{
+    return (*c->format == '{') ?
+          interpret_subexpr (c, pat, buf) :
+          FcTrue;
+}
+
+static FcBool
+skip_subexpr (FcFormatContext *c);
+
+static FcBool
+skip_percent (FcFormatContext *c)
+{
+    if (!expect_char (c, '%'))
+       return FcFalse;
+
+    /* skip an optional width specifier */
+    strtol ((const char *) c->format, (char **) &c->format, 10);
+
+    if (!expect_char (c, '{'))
+       return FcFalse;
+
+    while(*c->format && *c->format != '}')
+    {
+       switch (*c->format)
+       {
+       case '\\':
+           c->format++; /* skip over '\\' */
+           if (*c->format)
+               c->format++;
+           continue;
+       case '{':
+           if (!skip_subexpr (c))
+               return FcFalse;
+           continue;
+       }
+       c->format++;
+    }
+
+    return expect_char (c, '}');
+}
+
+static FcBool
+skip_expr (FcFormatContext *c)
+{
+    while(*c->format && *c->format != '}')
+    {
+       switch (*c->format)
+       {
+       case '\\':
+           c->format++; /* skip over '\\' */
+           if (*c->format)
+               c->format++;
+           continue;
+       case '%':
+           if (!skip_percent (c))
+               return FcFalse;
+           continue;
+       }
+       c->format++;
+    }
+
+    return FcTrue;
+}
+
+static FcBool
+skip_subexpr (FcFormatContext *c)
+{
+    return expect_char (c, '{') &&
+          skip_expr (c) &&
+          expect_char (c, '}');
+}
+
+static FcBool
+maybe_skip_subexpr (FcFormatContext *c)
+{
+    return (*c->format == '{') ?
+          skip_subexpr (c) :
+          FcTrue;
+}
+
 static FcBool
 interpret_simple_tag (FcFormatContext *c,
                      FcPattern       *pat,
@@ -274,6 +358,52 @@ interpret_delete (FcFormatContext *c,
     return FcTrue;
 }
 
+static FcBool
+interpret_conditional (FcFormatContext *c,
+                      FcPattern       *pat,
+                      FcStrBuf        *buf)
+{
+    FcBool pass;
+
+    if (!expect_char (c, '?'))
+       return FcFalse;
+
+    pass = FcTrue;
+
+    do
+    {
+       FcBool negate;
+       FcValue v;
+
+       negate = consume_char (c, '!');
+
+       if (!read_elt_name_to_scratch (c))
+           return FcFalse;
+
+       pass = pass &&
+              (negate ^
+               FcResultMatch == FcPatternGet (pat,
+                                              (const char *) c->scratch,
+                                              0, &v));
+    }
+    while (consume_char (c, ','));
+
+    if (pass)
+    {
+       if (!interpret_subexpr  (c, pat, buf) ||
+           !maybe_skip_subexpr (c))
+           return FcFalse;
+    }
+    else
+    {
+       if (!skip_subexpr (c) ||
+           !maybe_interpret_subexpr  (c, pat, buf))
+           return FcFalse;
+    }
+
+    return FcTrue;
+}
+
 static FcBool
 interpret_percent (FcFormatContext *c,
                   FcPattern       *pat,
@@ -318,6 +448,12 @@ interpret_percent (FcFormatContext *c,
            return FcFalse;
        break;
 
+    case '?':
+       /* conditional on pattern elements */
+       if (!interpret_conditional (c, pat, buf))
+           return FcFalse;
+       break;
+
     default:
        /* simple tag */
        if (!interpret_simple_tag (c, pat, buf))
@@ -377,12 +513,12 @@ static char escaped_char(const char ch)
 }
 
 static FcBool
-interpret (FcFormatContext *c,
-          FcPattern       *pat,
-          FcStrBuf        *buf,
-          FcChar8          term)
+interpret_expr (FcFormatContext *c,
+               FcPattern       *pat,
+               FcStrBuf        *buf,
+               FcChar8          term)
 {
-    for (; *c->format && *c->format != term;)
+    while (*c->format && *c->format != term)
     {
        switch (*c->format)
        {
@@ -412,7 +548,7 @@ FcPatternFormat (FcPattern *pat, const FcChar8 *format)
     if (!FcFormatContextInit (&c, format))
        return NULL;
 
-    ret = interpret (&c, pat, &buf, '\0');
+    ret = interpret_expr (&c, pat, &buf, '\0');
     if (buf.failed)
        ret = FcFalse;