Commit 0c93b91d authored by Behdad Esfahbod's avatar Behdad Esfahbod

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.
parent 5cf04b20
......@@ -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().
@@
......@@ -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]);
......
......@@ -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:
......
......@@ -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;
......
......@@ -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,6 +98,23 @@ are printed. The <option>--all</option> option works like
options is included below.</para>
<variablelist>
<varlistentry>
<term><option>-a</option>
<option>--all</option>
</term>
<listitem>
<para>Displays sorted list of best matching fonts, but do not do any
pruning on the list.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-s</option>
<option>--sort</option>
</term>
<listitem>
<para>Displays sorted list of best matching fonts.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-v</option>
<option>--verbose</option>
......@@ -103,11 +124,13 @@ are printed. The <option>--all</option> option works like
</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>
......@@ -119,20 +142,11 @@ are printed. The <option>--all</option> option works like
</listitem>
</varlistentry>
<varlistentry>
<term><option>-a</option>
<option>--all</option>
</term>
<listitem>
<para>Displays sorted list of best matching fonts, but do not do any
pruning on the list.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>-s</option>
<option>--sort</option>
<term><option>-h</option>
<option>--help</option>
</term>
<listitem>
<para>Displays sorted list of best matching fonts.</para>
<para>Show summary of options.</para>
</listitem>
</varlistentry>
<varlistentry>
......@@ -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:
......
......@@ -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);
......@@ -150,8 +157,20 @@ main (int argc, char **argv)
pat = FcFreeTypeQuery ((FcChar8 *) argv[i], index, blanks, &count);
if (pat)
{
if (format)
{
FcChar8 *s;
s = FcPatternFormat (pat, format);
printf ("%s", s);
free (s);
}
else
{
FcPatternPrint (pat);
}
FcPatternDestroy (pat);
}
else
......
......@@ -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:
......
......@@ -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 *
......
......@@ -94,6 +94,7 @@ libfontconfig_la_SOURCES = \
fcdbg.c \
fcdefault.c \
fcdir.c \
fcformat.c \
fcfreetype.c \
fcfs.c \
fcinit.c \
......
/*
* 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__
......@@ -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);
......
......@@ -818,7 +818,7 @@ FcNameUnparseValue (FcStrBuf *buf,
return FcFalse;
}
static FcBool
FcBool
FcNameUnparseValueList (FcStrBuf *buf,
FcValueListPtr v,
FcChar8 *escape)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment