From 0c93b91db0cdf7c5e901477c266b45c8baeadd00 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Mon, 29 Dec 2008 20:00:26 -0500 Subject: [PATCH] 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. --- doc/fcpattern.fncs | 18 +++++ fc-list/fc-list.c | 38 +++++++--- fc-list/fc-list.sgml | 22 +++++- fc-match/fc-match.c | 31 +++++--- fc-match/fc-match.sgml | 47 ++++++++---- fc-query/fc-query.c | 25 ++++++- fc-query/fc-query.sgml | 36 +++++++--- fontconfig/fontconfig.h | 3 + src/Makefile.am | 1 + src/fcformat.c | 155 ++++++++++++++++++++++++++++++++++++++++ src/fcint.h | 5 ++ src/fcname.c | 2 +- 12 files changed, 333 insertions(+), 50 deletions(-) create mode 100644 src/fcformat.c diff --git a/doc/fcpattern.fncs b/doc/fcpattern.fncs index 7297e01..c89706a 100644 --- a/doc/fcpattern.fncs +++ b/doc/fcpattern.fncs @@ -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(). +@@ diff --git a/fc-list/fc-list.c b/fc-list/fc-list.c index 89f4167..f7a66b5 100644 --- a/fc-list/fc-list.c +++ b/fc-list/fc-list.c @@ -26,6 +26,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include #else @@ -47,9 +48,10 @@ #define _GNU_SOURCE #include 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]); diff --git a/fc-list/fc-list.sgml b/fc-list/fc-list.sgml index 35bf899..5807ed1 100644 --- a/fc-list/fc-list.sgml +++ b/fc-list/fc-list.sgml @@ -65,6 +65,10 @@ manpage.1: manpage.sgml + + + + @@ -100,11 +104,13 @@ manpage.1: manpage.sgml - - + + + - Show summary of options. + Format output according to the format specifier + format. @@ -115,6 +121,14 @@ manpage.1: manpage.sgml Show version of the program and exit. + + + + + + Show summary of options. + + @@ -164,6 +178,8 @@ manpage.1: manpage.sgml fc-cache(1) fc-match(1) fc-query(1) + FcFontList(3) + FcPatternFormat(3) The fontconfig user's guide, in HTML format: diff --git a/fc-match/fc-match.c b/fc-match/fc-match.c index 5ed8def..c402905 100644 --- a/fc-match/fc-match.c +++ b/fc-match/fc-match.c @@ -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; diff --git a/fc-match/fc-match.sgml b/fc-match/fc-match.sgml index b5ca675..bb0d84e 100644 --- a/fc-match/fc-match.sgml +++ b/fc-match/fc-match.sgml @@ -67,6 +67,10 @@ manpage.1: manpage.sgml + + + + @@ -94,6 +98,23 @@ are printed. The option works like options is included below. + + + + + + Displays sorted list of best matching fonts, but do not do any + pruning on the list. + + + + + + + + Displays sorted list of best matching fonts. + + @@ -103,11 +124,13 @@ are printed. The option works like - - + + + - Show summary of options. + Format output according to the format specifier + format. @@ -119,20 +142,11 @@ are printed. The option works like - - - - - Displays sorted list of best matching fonts, but do not do any - pruning on the list. - - - - - + + - Displays sorted list of best matching fonts. + Show summary of options. @@ -154,6 +168,9 @@ are printed. The option works like fc-cache(1) fc-list(1) fc-query(1) + FcFontMatch(3) + FcFontSort(3) + FcPatternFormat(3) The fontconfig user's guide, in HTML format: diff --git a/fc-query/fc-query.c b/fc-query/fc-query.c index 6ea45ea..8fec7d4 100644 --- a/fc-query/fc-query.c +++ b/fc-query/fc-query.c @@ -53,6 +53,7 @@ #include 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 diff --git a/fc-query/fc-query.sgml b/fc-query/fc-query.sgml index 2c73129..e363db5 100644 --- a/fc-query/fc-query.sgml +++ b/fc-query/fc-query.sgml @@ -63,13 +63,17 @@ manpage.1: manpage.sgml &dhpackage; - - + + + + + + @@ -93,11 +97,23 @@ manpage.1: manpage.sgml - - + + + - Show summary of options. + Only query face indexed index of + each file. + + + + + + + + + Format output according to the format specifier + format. @@ -109,13 +125,11 @@ manpage.1: manpage.sgml - - - + + - Only query face indexed index of - each file. + Show summary of options. @@ -142,6 +156,8 @@ manpage.1: manpage.sgml fc-cache(1) fc-list(1) fc-match(1) + FcFreeTypeQuery(3) + FcPatternFormat(3) The fontconfig user's guide, in HTML format: diff --git a/fontconfig/fontconfig.h b/fontconfig/fontconfig.h index 4149072..529456f 100644 --- a/fontconfig/fontconfig.h +++ b/fontconfig/fontconfig.h @@ -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 * diff --git a/src/Makefile.am b/src/Makefile.am index e18f937..964b295 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,6 +94,7 @@ libfontconfig_la_SOURCES = \ fcdbg.c \ fcdefault.c \ fcdir.c \ + fcformat.c \ fcfreetype.c \ fcfs.c \ fcinit.c \ diff --git a/src/fcformat.c b/src/fcformat.c new file mode 100644 index 0000000..80c99c3 --- /dev/null +++ b/src/fcformat.c @@ -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 +#include +#include + + +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__ diff --git a/src/fcint.h b/src/fcint.h index 47925b0..c8ff228 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -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); diff --git a/src/fcname.c b/src/fcname.c index 0815cf3..02a2b82 100644 --- a/src/fcname.c +++ b/src/fcname.c @@ -818,7 +818,7 @@ FcNameUnparseValue (FcStrBuf *buf, return FcFalse; } -static FcBool +FcBool FcNameUnparseValueList (FcStrBuf *buf, FcValueListPtr v, FcChar8 *escape) -- 2.39.2