Re: FcPattern Gotcha

Lawrence D'Oliveiro <[email protected]>
Newsgroups gmane.comp.fonts.fontconfig
Organization Geek Central
Message-ID <[email protected]>
On Tue, 29 Nov 2016 16:30:35 +0900, Akira TAGOH wrote:

> Can you attach the example that can reproduce your issue?
> 
> FcNameParse() should generates the same FcPattern with the strings
> generated by FcNameUnparse().

OK, I have narrowed it down. Attached is the simplest C program I could
come up with to demonstrate the issue. Pass it a pattern string on the
command line, e.g.

    fc_pattern_2 sans-serif

and it will print out some information about what it found. Having
found a matching pattern, it calls FcNameUnparse to convert that to a
pattern string, followed by FcNameParse to convert the string back to a
pattern.

If the pattern includes the “charset” property, the FcNameParse call
fails, possibly even segfaults. Removing this property causes the parse
(and the subsequent match) to succeed. I helpfully put the call
“FcPatternDel(found_pat, FC_CHARSET);” inside an “if (true)” block, so
you can try changing it to “if (false)” to observe the effect.

I have libconfig 2.11.0 installed from the repo package on Debian
Unstable.

_______________________________________________
Fontconfig mailing list
[email protected]
https://lists.freedesktop.org/mailman/listinfo/fontconfig
fc_pattern_2.c (text/x-c++src, 3.2 KB)
/*
    Try to investigate oddity with parsing/unparsing of Fontconfig patterns.

    Build command:
        gcc -o fc_pattern_2 -lfontconfig fc_pattern_2.c

    Usage:
        fc_pattern_2 «pat-string»
*/

#include <stdbool.h>
#include <iso646.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <fontconfig/fontconfig.h>

static char *
    progname;
static int
    exit_status = 0;

int main
  (
    int argc,
    char ** argv
  )
  {
    FcPattern * find_pat = 0;
    FcPattern * found_pat = 0;
    char * pat_str = 0;
    FcPattern * parsed_pat = 0;
    FcPattern * found_pat_2 = 0;
    FcResult fc_result;
    progname = argv[0];
    do /*once*/
      {
        if (argc != 2)
          {
            fprintf(stderr, "Usage:\n\t%s «pat-string»\n", progname);
            exit_status = 1;
            break;
          } /*if*/
        find_pat = FcNameParse(argv[1]);
        if (find_pat == 0)
          {
            fprintf(stderr, "%s: initial FcNameParse failed\n", progname);
            exit_status = 3;
            break;
          } /*if*/
        if (not FcConfigSubstitute(0, find_pat, FcMatchPattern))
          {
            fprintf(stderr, "%s: FcConfigSubstitute failed\n", progname);
            exit_status = 3;
            break;
          } /*if*/
        FcDefaultSubstitute(find_pat);
        found_pat = FcFontMatch(0, find_pat, &fc_result);
        if (found_pat == 0)
          {
            fprintf(stderr, "%s: first FcFontMatch failed with status %d\n", progname, fc_result);
            exit_status = 3;
            break;
          } /*if*/
          {
            char * namestr;
            FcPatternGetString(found_pat, FC_FAMILY, 0, (FcChar8 **)&namestr);
            fprintf(stderr, "found font with family name “%s”\n", namestr);
          }
        if (true)
          {
          /* if this is disabled, the following FcNameParse call will fail */
            FcPatternDel(found_pat, FC_CHARSET);
          } /*if*/
        pat_str = FcNameUnparse(found_pat);
        if (pat_str == 0)
          {
            fprintf(stderr, "%s: FcNameUnparse failed\n", progname);
            exit_status = 3;
            break;
          } /*if*/
        fprintf(stdout, "Found pat (%d): %s\n", fc_result, pat_str);
        parsed_pat = FcNameParse(pat_str);
        if (parsed_pat == 0)
          {
            fprintf(stderr, "%s: second FcNameParse failed\n", progname);
            exit_status = 3;
            break;
          } /*if*/
        found_pat_2 = FcFontMatch(0, find_pat, &fc_result);
        if (found_pat_2 == 0)
          {
            fprintf(stderr, "%s: second FcFontMatch failed with status %d\n", progname, fc_result);
            exit_status = 3;
            break;
          } /*if*/
          {
            char * namestr;
            FcPatternGetString(found_pat_2, FC_FAMILY, 0, (FcChar8 **)&namestr);
            fprintf(stderr, "found second font with family name “%s”\n", namestr);
          }
      }
    while (false);
    FcPatternDestroy(found_pat_2);
    FcPatternDestroy(parsed_pat);
    free(pat_str);
    FcPatternDestroy(found_pat);
    FcPatternDestroy(find_pat);
    return
        exit_status;
  } /*main*/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.