Implement FcPatternFormat and use it in cmdline tools (bug #17107)

Still need to add more features, but the API is there, and used
by cmdline tools with -f or --format.
This commit is contained in:
Behdad Esfahbod 2008-12-29 20:00:26 -05:00
parent 5cf04b201f
commit 0c93b91db0
12 changed files with 342 additions and 59 deletions

View File

@ -395,3 +395,21 @@ 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 using free().
@@
@RET@ FcChar8 *
@FUNC@ FcPatternFormat
@TYPE1@ FcPattern * @ARG1@ pat
@TYPE2@ const FcChar8 * @ARG2@ format
@PURPOSE@ Format a pattern into a string according to a format specifier
@DESC@
Converts the given pattern into text format described by the format specifier.
The format specifier is similar to a C style printf string, which the
printf(2) man page provides a good introduction to. However, as RPM already
knows the type of data that is being printed, you must omit the type
specifier. In its place put the element name you wish to print enclosed in
curly braces ({}). For example, to print the family name and style the
pattern, use the format "%{family} %{style}\n".
The return value refers to newly allocated memory which should be freed by the
caller using free().
@@

View File

@ -26,6 +26,7 @@
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
#else
@ -47,9 +48,10 @@
#define _GNU_SOURCE
#include <getopt.h>
const struct option longopts[] = {
{"version", 0, 0, 'V'},
{"verbose", 0, 0, 'v'},
{"format", 1, 0, 'f'},
{"quiet", 0, 0, 'q'},
{"version", 0, 0, 'V'},
{"help", 0, 0, 'h'},
{NULL,0,0,0},
};
@ -65,21 +67,23 @@ usage (char *program, int error)
{
FILE *file = error ? stderr : stdout;
#if HAVE_GETOPT_LONG
fprintf (file, "usage: %s [-vqVh] [--verbose] [--quiet] [--version] [--help] [pattern] {element ...} \n",
fprintf (file, "usage: %s [-vqVh] [-f FORMAT] [--verbose] [--format=FORMAT] [--quiet] [--version] [--help] [pattern] {element ...} \n",
program);
#else
fprintf (file, "usage: %s [-vqVh] [pattern] {element ...} \n",
fprintf (file, "usage: %s [-vqVh] [-f FORMAT] [pattern] {element ...} \n",
program);
#endif
fprintf (file, "List fonts matching [pattern]\n");
fprintf (file, "\n");
#if HAVE_GETOPT_LONG
fprintf (file, " -v, --verbose display entire font pattern\n");
fprintf (file, " -f, --format=FORMAT use the given output format\n");
fprintf (file, " -q, --quiet suppress all normal output, exit 1 if no fonts matched\n");
fprintf (file, " -V, --version display font config version and exit\n");
fprintf (file, " -h, --help display this help and exit\n");
#else
fprintf (file, " -v (verbose) display entire font pattern\n");
fprintf (file, " -f FORMAT (format) use the given output format\n");
fprintf (file, " -q, (quiet) suppress all normal output, exit 1 if no fonts matched\n");
fprintf (file, " -V (version) display font config version and exit\n");
fprintf (file, " -h (help) display this help and exit\n");
@ -92,6 +96,7 @@ main (int argc, char **argv)
{
int verbose = 0;
int quiet = 0;
FcChar8 *format = NULL;
int nfont = 0;
int i;
FcObjectSet *os = 0;
@ -101,22 +106,25 @@ main (int argc, char **argv)
int c;
#if HAVE_GETOPT_LONG
while ((c = getopt_long (argc, argv, "Vqvh", longopts, NULL)) != -1)
while ((c = getopt_long (argc, argv, "vf:qVh", longopts, NULL)) != -1)
#else
while ((c = getopt (argc, argv, "Vqvh")) != -1)
while ((c = getopt (argc, argv, "vf:qVh")) != -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;
case 'f':
format = (FcChar8 *) strdup (optarg);
break;
case 'q':
quiet = 1;
break;
case 'V':
fprintf (stderr, "fontconfig version %d.%d.%d\n",
FC_MAJOR, FC_MINOR, FC_REVISION);
exit (0);
case 'h':
usage (argv[0], 0);
default:
@ -148,7 +156,7 @@ main (int argc, char **argv)
pat = FcPatternCreate ();
if (quiet && !os)
os = FcObjectSetCreate ();
if (!verbose && !os)
if (!verbose && !format && !os)
os = FcObjectSetBuild (FC_FAMILY, FC_STYLE, (char *) 0);
fs = FcFontList (0, pat, os);
if (os)
@ -166,7 +174,17 @@ main (int argc, char **argv)
FcChar8 *file;
if (verbose)
{
FcPatternPrint (fs->fonts[j]);
}
else if (format)
{
FcChar8 *s;
s = FcPatternFormat (fs->fonts[j], format);
printf ("%s", s);
free (s);
}
else
{
font = FcNameUnparse (fs->fonts[j]);

View File

@ -65,6 +65,10 @@ manpage.1: manpage.sgml
<arg><option>-vVh</option></arg>
<arg><option>--verbose</option></arg>
<group>
<arg><option>-f</option> <option><replaceable>format</replaceable></option></arg>
<arg><option>--format</option> <option><replaceable>format</replaceable></option></arg>
</group>
<arg><option>--version</option></arg>
<arg><option>--help</option></arg>
<sbr>
@ -100,11 +104,13 @@ manpage.1: manpage.sgml
</listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option>
<option>--help</option>
<term><option>-f</option>
<option>--format</option>
<option><replaceable>format</replaceable></option>
</term>
<listitem>
<para>Show summary of options.</para>
<para>Format output according to the format specifier
<replaceable>format</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -115,6 +121,14 @@ manpage.1: manpage.sgml
<para>Show version of the program and exit.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option>
<option>--help</option>
</term>
<listitem>
<para>Show summary of options.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option><replaceable>pattern</replaceable></option>
</term>
@ -164,6 +178,8 @@ manpage.1: manpage.sgml
<command>fc-cache</command>(1)
<command>fc-match</command>(1)
<command>fc-query</command>(1)
<function>FcFontList</function>(3)
<function>FcPatternFormat</function>(3)
</para>
<para>The fontconfig user's guide, in HTML format:

View File

@ -51,8 +51,9 @@
static const struct option longopts[] = {
{"sort", 0, 0, 's'},
{"all", 0, 0, 'a'},
{"version", 0, 0, 'V'},
{"verbose", 0, 0, 'v'},
{"format", 1, 0, 'f'},
{"version", 0, 0, 'V'},
{"help", 0, 0, 'h'},
{NULL,0,0,0},
};
@ -68,10 +69,10 @@ usage (char *program, int error)
{
FILE *file = error ? stderr : stdout;
#if HAVE_GETOPT_LONG
fprintf (file, "usage: %s [-savVh] [--sort] [--all] [--verbose] [--version] [--help] [pattern]\n",
fprintf (file, "usage: %s [-savVh] [-f FORMAT] [--sort] [--all] [--verbose] [--format=FORMAT] [--version] [--help] [pattern]\n",
program);
#else
fprintf (file, "usage: %s [-savVh] [pattern]\n",
fprintf (file, "usage: %s [-savVh] [-f FORMAT] [pattern]\n",
program);
#endif
fprintf (file, "List fonts matching [pattern]\n");
@ -80,12 +81,14 @@ usage (char *program, int error)
fprintf (file, " -s, --sort display sorted list of matches\n");
fprintf (file, " -a, --all display unpruned sorted list of matches\n");
fprintf (file, " -v, --verbose display entire font pattern\n");
fprintf (file, " -f, --format=FORMAT use the given output format\n");
fprintf (file, " -V, --version display font config version and exit\n");
fprintf (file, " -h, --help display this help and exit\n");
#else
fprintf (file, " -s, (sort) display sorted list of matches\n");
fprintf (file, " -a (all) display unpruned sorted list of matches\n");
fprintf (file, " -v (verbose) display entire font pattern\n");
fprintf (file, " -f FORMAT (format) use the given output format\n");
fprintf (file, " -V (version) display font config version and exit\n");
fprintf (file, " -h (help) display this help and exit\n");
#endif
@ -97,6 +100,7 @@ main (int argc, char **argv)
{
int verbose = 0;
int sort = 0, all = 0;
FcChar8 *format = NULL;
int i;
FcFontSet *fs;
FcPattern *pat;
@ -105,9 +109,9 @@ main (int argc, char **argv)
int c;
#if HAVE_GETOPT_LONG
while ((c = getopt_long (argc, argv, "asVvh", longopts, NULL)) != -1)
while ((c = getopt_long (argc, argv, "asvf:Vh", longopts, NULL)) != -1)
#else
while ((c = getopt (argc, argv, "asVvh")) != -1)
while ((c = getopt (argc, argv, "asvf:Vh")) != -1)
#endif
{
switch (c) {
@ -117,13 +121,16 @@ main (int argc, char **argv)
case 's':
sort = 1;
break;
case 'v':
verbose = 1;
break;
case 'f':
format = (FcChar8 *) strdup (optarg);
break;
case 'V':
fprintf (stderr, "fontconfig version %d.%d.%d\n",
FC_MAJOR, FC_MINOR, FC_REVISION);
exit (0);
case 'v':
verbose = 1;
break;
case 'h':
usage (argv[0], 0);
default:
@ -189,6 +196,14 @@ main (int argc, char **argv)
{
FcPatternPrint (fs->fonts[j]);
}
else if (format)
{
FcChar8 *s;
s = FcPatternFormat (fs->fonts[j], format);
printf ("%s", s);
free (s);
}
else
{
FcChar8 *family;

View File

@ -67,6 +67,10 @@ manpage.1: manpage.sgml
<arg><option>--all</option></arg>
<arg><option>--sort</option></arg>
<arg><option>--verbose</option></arg>
<group>
<arg><option>-f</option> <option><replaceable>format</replaceable></option></arg>
<arg><option>--format</option> <option><replaceable>format</replaceable></option></arg>
</group>
<arg><option>--version</option></arg>
<arg><option>--help</option></arg>
<arg><option><replaceable>font-pattern</replaceable></option></arg>
@ -94,30 +98,6 @@ are printed. The <option>--all</option> option works like
options is included below.</para>
<variablelist>
<varlistentry>
<term><option>-v</option>
<option>--verbose</option>
</term>
<listitem>
<para>Print whole font pattern for each match.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option>
<option>--help</option>
</term>
<listitem>
<para>Show summary of options.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-V</option>
<option>--version</option>
</term>
<listitem>
<para>Show version of the program and exit.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-a</option>
<option>--all</option>
@ -135,6 +115,40 @@ are printed. The <option>--all</option> option works like
<para>Displays sorted list of best matching fonts.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option>
<option>--verbose</option>
</term>
<listitem>
<para>Print whole font pattern for each match.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-f</option>
<option>--format</option>
<option><replaceable>format</replaceable></option>
</term>
<listitem>
<para>Format output according to the format specifier
<replaceable>format</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-V</option>
<option>--version</option>
</term>
<listitem>
<para>Show version of the program and exit.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-h</option>
<option>--help</option>
</term>
<listitem>
<para>Show summary of options.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option><replaceable>font-pattern</replaceable></option>
</term>
@ -154,6 +168,9 @@ are printed. The <option>--all</option> option works like
<command>fc-cache</command>(1)
<command>fc-list</command>(1)
<command>fc-query</command>(1)
<function>FcFontMatch</function>(3)
<function>FcFontSort</function>(3)
<function>FcPatternFormat</function>(3)
</para>
<para>The fontconfig user's guide, in HTML format:

View File

@ -53,6 +53,7 @@
#include <getopt.h>
static const struct option longopts[] = {
{"index", 1, 0, 'i'},
{"format", 1, 0, 'f'},
{"version", 0, 0, 'V'},
{"help", 0, 0, 'h'},
{NULL,0,0,0},
@ -69,20 +70,22 @@ usage (char *program, int error)
{
FILE *file = error ? stderr : stdout;
#if HAVE_GETOPT_LONG
fprintf (file, "usage: %s [-Vh] [-i index] [--index index] [--version] [--help] font-file...\n",
fprintf (file, "usage: %s [-Vh] [-i index] [-f FORMAT] [--index index] [--format FORMAT] [--version] [--help] font-file...\n",
program);
#else
fprintf (file, "usage: %s [-Vh] [-i index] font-file...\n",
fprintf (file, "usage: %s [-Vh] [-i index] [-f FORMAT] font-file...\n",
program);
#endif
fprintf (file, "Query font files and print resulting pattern(s)\n");
fprintf (file, "\n");
#if HAVE_GETOPT_LONG
fprintf (file, " -i, --index INDEX display the INDEX face of each font file only\n");
fprintf (file, " -f, --format=FORMAT use the given output format\n");
fprintf (file, " -V, --version display font config version and exit\n");
fprintf (file, " -h, --help display this help and exit\n");
#else
fprintf (file, " -i INDEX (index) display the INDEX face of each font file only\n");
fprintf (file, " -f FORMAT (format) use the given output format\n");
fprintf (file, " -a (all) display unpruned sorted list of matches\n");
fprintf (file, " -V (version) display font config version and exit\n");
fprintf (file, " -h (help) display this help and exit\n");
@ -95,6 +98,7 @@ main (int argc, char **argv)
{
int index_set = 0;
int set_index = 0;
FcChar8 *format = NULL;
int err = 0;
int i;
FcBlanks *blanks;
@ -112,6 +116,9 @@ main (int argc, char **argv)
index_set = 1;
set_index = atoi (optarg);
break;
case 'f':
format = (FcChar8 *) strdup (optarg);
break;
case 'V':
fprintf (stderr, "fontconfig version %d.%d.%d\n",
FC_MAJOR, FC_MINOR, FC_REVISION);
@ -151,7 +158,19 @@ main (int argc, char **argv)
pat = FcFreeTypeQuery ((FcChar8 *) argv[i], index, blanks, &count);
if (pat)
{
FcPatternPrint (pat);
if (format)
{
FcChar8 *s;
s = FcPatternFormat (pat, format);
printf ("%s", s);
free (s);
}
else
{
FcPatternPrint (pat);
}
FcPatternDestroy (pat);
}
else

View File

@ -63,13 +63,17 @@ manpage.1: manpage.sgml
<command>&dhpackage;</command>
<arg><option>-Vh</option></arg>
<arg><option>--version</option></arg>
<arg><option>--help</option></arg>
<sbr>
<group>
<arg><option>-i</option> <option><replaceable>index</replaceable></option></arg>
<arg><option>--index</option> <option><replaceable>index</replaceable></option></arg>
</group>
<group>
<arg><option>-f</option> <option><replaceable>format</replaceable></option></arg>
<arg><option>--format</option> <option><replaceable>format</replaceable></option></arg>
</group>
<arg><option>--version</option></arg>
<arg><option>--help</option></arg>
<arg choice="req" rep="repeat"><option><replaceable>font-file</replaceable></option></arg>
</cmdsynopsis>
@ -93,11 +97,23 @@ manpage.1: manpage.sgml
<variablelist>
<varlistentry>
<term><option>-h</option>
<option>--help</option>
<term><option>-i</option>
<option>--index</option>
<option><replaceable>index</replaceable></option>
</term>
<listitem>
<para>Show summary of options.</para>
<para>Only query face indexed <replaceable>index</replaceable> of
each file.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-f</option>
<option>--format</option>
<option><replaceable>format</replaceable></option>
</term>
<listitem>
<para>Format output according to the format specifier
<replaceable>format</replaceable>.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -109,13 +125,11 @@ manpage.1: manpage.sgml
</listitem>
</varlistentry>
<varlistentry>
<term><option>-i</option>
<option>--index</option>
<option><replaceable>index</replaceable></option>
<term><option>-h</option>
<option>--help</option>
</term>
<listitem>
<para>Only query face indexed <replaceable>index</replaceable> of
each file.</para>
<para>Show summary of options.</para>
</listitem>
</varlistentry>
<varlistentry>
@ -142,6 +156,8 @@ manpage.1: manpage.sgml
<command>fc-cache</command>(1)
<command>fc-list</command>(1)
<command>fc-match</command>(1)
<function>FcFreeTypeQuery</function>(3)
<function>FcPatternFormat</function>(3)
</para>
<para>The fontconfig user's guide, in HTML format:

View File

@ -830,6 +830,9 @@ FcPatternVaBuild (FcPattern *p, va_list va);
FcPublic FcPattern *
FcPatternBuild (FcPattern *p, ...) FC_ATTRIBUTE_SENTINEL(0);
FcPublic FcChar8 *
FcPatternFormat (FcPattern *pat, const FcChar8 *format);
/* fcstr.c */
FcPublic FcChar8 *

View File

@ -94,6 +94,7 @@ libfontconfig_la_SOURCES = \
fcdbg.c \
fcdefault.c \
fcdir.c \
fcformat.c \
fcfreetype.c \
fcfs.c \
fcinit.c \

155
src/fcformat.c Normal file
View File

@ -0,0 +1,155 @@
/*
* Copyright © 2008 Red Hat, Inc.
*
* Red Hat Author(s): Behdad Esfahbod
*
* 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"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
static void
message (const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
fprintf (stderr, "Fontconfig: ");
vfprintf (stderr, fmt, args);
fprintf (stderr, "\n");
va_end (args);
}
static FcChar8 *scratch1;
static FcChar8 *scratch2;
static const FcChar8 *format_orig;
static const FcChar8 *
interpret_percent (FcPattern *pat,
FcStrBuf *buf,
const FcChar8 *format)
{
switch (*format) {
case '{':
{
FcChar8 *p;
FcPatternElt *e;
format++; /* skip over '{' */
p = (FcChar8 *) strpbrk ((const char *) format, "}");
if (!p)
{
message ("Pattern format missing closing brace");
return format;
}
/* extract the element name */
memcpy (scratch1, format, p - format);
scratch1[p - format] = '\0';
e = FcPatternObjectFindElt (pat, FcObjectFromName ((const char *) scratch1));
if (e)
{
FcValueListPtr l;
l = FcPatternEltValues(e);
FcNameUnparseValueList (buf, l, '\0');
}
p++; /* skip over '}' */
return p;
}
default:
message ("Pattern format has invalid character after '%%' at %d",
format - format_orig);
return format;
}
}
static char escaped_char(const char ch)
{
switch (ch) {
case 'a': return '\a';
case 'b': return '\b';
case 'f': return '\f';
case 'n': return '\n';
case 'r': return '\r';
case 't': return '\t';
case 'v': return '\v';
default: return ch;
}
}
static const FcChar8 *
interpret (FcPattern *pat,
FcStrBuf *buf,
const FcChar8 *format,
FcChar8 term)
{
const FcChar8 *end;
for (end = format; *end && *end != term;)
{
switch (*end)
{
case '\\':
end++; /* skip over '\\' */
FcStrBufChar (buf, escaped_char (*end++));
continue;
case '%':
end++; /* skip over '%' */
if (*end == '%')
break;
end = interpret_percent (pat, buf, end);
continue;
}
FcStrBufChar (buf, *end);
end++;
}
if (*end != term)
message ("Pattern format ended while looking for '%c'", term);
return end;
}
FcChar8 *
FcPatternFormat (FcPattern *pat, const FcChar8 *format)
{
int len;
FcStrBuf buf;
FcStrBufInit (&buf, 0, 0);
len = strlen ((const char *) format);
scratch1 = malloc (len);
scratch2 = malloc (len);
format_orig = format;
interpret (pat, &buf, format, '\0');
free (scratch1);
free (scratch2);
return FcStrBufDone (&buf);
}
#define __fcformat__
#include "fcaliastail.h"
#undef __fcformat__

View File

@ -645,6 +645,11 @@ FcNameUnparseCharSet (FcStrBuf *buf, const FcCharSet *c);
FcPrivate FcCharSet *
FcNameParseCharSet (FcChar8 *string);
FcPrivate FcBool
FcNameUnparseValueList (FcStrBuf *buf,
FcValueListPtr v,
FcChar8 *escape);
FcPrivate FcCharLeaf *
FcCharSetFindLeafCreate (FcCharSet *fcs, FcChar32 ucs4);

View File

@ -818,7 +818,7 @@ FcNameUnparseValue (FcStrBuf *buf,
return FcFalse;
}
static FcBool
FcBool
FcNameUnparseValueList (FcStrBuf *buf,
FcValueListPtr v,
FcChar8 *escape)