]>
git.wh0rd.org - fontconfig.git/blob - src/fcformat.c
2 * Copyright © 2008 Red Hat, Inc.
4 * Red Hat Author(s): Behdad Esfahbod
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
13 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
32 * Some ideas for future syntax extensions:
34 * - number of values for element using '%{#elt}'
35 * - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}'
36 * - allow indexing simple tags using '%{elt[idx]}'
37 * - conditional/filtering/deletion on binding (using '(w)'/'(s)' notation)
41 message (const char *fmt
, ...)
45 fprintf (stderr
, "Fontconfig: Pattern format error: ");
46 vfprintf (stderr
, fmt
, args
);
47 fprintf (stderr
, ".\n");
52 typedef struct _FcFormatContext
54 const FcChar8
*format_orig
;
55 const FcChar8
*format
;
61 FcFormatContextInit (FcFormatContext
*c
,
62 const FcChar8
*format
)
64 c
->format_orig
= c
->format
= format
;
65 c
->format_len
= strlen ((const char *) format
);
66 c
->word
= malloc (c
->format_len
+ 1);
68 return c
->word
!= NULL
;
72 FcFormatContextDone (FcFormatContext
*c
)
81 consume_char (FcFormatContext
*c
,
84 if (*c
->format
!= term
)
92 expect_char (FcFormatContext
*c
,
95 FcBool res
= consume_char (c
, term
);
98 if (c
->format
== c
->format_orig
+ c
->format_len
)
99 message ("format ended while expecting '%c'",
102 message ("expected '%c' at %d",
103 term
, c
->format
- c
->format_orig
+ 1);
109 FcCharIsPunct (const FcChar8 c
)
129 read_word (FcFormatContext
*c
)
137 if (*c
->format
== '\\')
144 else if (FcCharIsPunct (*c
->format
))
153 message ("expected element name at %d",
154 c
->format
- c
->format_orig
+ 1);
162 interpret_expr (FcFormatContext
*c
,
168 interpret_subexpr (FcFormatContext
*c
,
172 return expect_char (c
, '{') &&
173 interpret_expr (c
, pat
, buf
, '}') &&
174 expect_char (c
, '}');
178 maybe_interpret_subexpr (FcFormatContext
*c
,
182 return (*c
->format
== '{') ?
183 interpret_subexpr (c
, pat
, buf
) :
188 skip_subexpr (FcFormatContext
*c
);
191 skip_percent (FcFormatContext
*c
)
195 if (!expect_char (c
, '%'))
198 /* skip an optional width specifier */
199 width
= strtol ((const char *) c
->format
, (char **) &c
->format
, 10);
201 if (!expect_char (c
, '{'))
204 while(*c
->format
&& *c
->format
!= '}')
209 c
->format
++; /* skip over '\\' */
214 if (!skip_subexpr (c
))
221 return expect_char (c
, '}');
225 skip_expr (FcFormatContext
*c
)
227 while(*c
->format
&& *c
->format
!= '}')
232 c
->format
++; /* skip over '\\' */
237 if (!skip_percent (c
))
248 skip_subexpr (FcFormatContext
*c
)
250 return expect_char (c
, '{') &&
252 expect_char (c
, '}');
256 maybe_skip_subexpr (FcFormatContext
*c
)
258 return (*c
->format
== '{') ?
264 interpret_simple (FcFormatContext
*c
,
269 FcBool add_colon
= FcFalse
;
270 FcBool add_elt_name
= FcFalse
;
272 if (consume_char (c
, ':'))
278 if (consume_char (c
, '='))
279 add_elt_name
= FcTrue
;
281 e
= FcPatternObjectFindElt (pat
,
282 FcObjectFromName ((const char *) c
->word
));
288 FcStrBufChar (buf
, ':');
291 FcStrBufString (buf
, c
->word
);
292 FcStrBufChar (buf
, '=');
295 l
= FcPatternEltValues(e
);
296 FcNameUnparseValueList (buf
, l
, '\0');
303 interpret_filter (FcFormatContext
*c
,
310 if (!expect_char (c
, '+'))
313 os
= FcObjectSetCreate ();
319 if (!read_word (c
) ||
320 !FcObjectSetAdd (os
, (const char *) c
->word
))
322 FcObjectSetDestroy (os
);
326 while (consume_char (c
, ','));
328 subpat
= FcPatternFilter (pat
, os
);
329 FcObjectSetDestroy (os
);
332 !interpret_subexpr (c
, subpat
, buf
))
335 FcPatternDestroy (subpat
);
340 interpret_delete (FcFormatContext
*c
,
346 if (!expect_char (c
, '-'))
349 subpat
= FcPatternDuplicate (pat
);
357 FcPatternDestroy (subpat
);
361 FcPatternDel (subpat
, (const char *) c
->word
);
363 while (consume_char (c
, ','));
365 if (!interpret_subexpr (c
, subpat
, buf
))
368 FcPatternDestroy (subpat
);
373 interpret_cond (FcFormatContext
*c
,
379 if (!expect_char (c
, '?'))
389 negate
= consume_char (c
, '!');
396 (FcResultMatch
== FcPatternGet (pat
,
397 (const char *) c
->word
,
400 while (consume_char (c
, ','));
404 if (!interpret_subexpr (c
, pat
, buf
) ||
405 !maybe_skip_subexpr (c
))
410 if (!skip_subexpr (c
) ||
411 !maybe_interpret_subexpr (c
, pat
, buf
))
419 cescape (const FcChar8
*str
)
422 FcChar8 buf_static
[8192];
424 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
431 FcStrBufChar (&buf
, '\\');
434 FcStrBufChar (&buf
, *str
++);
436 return FcStrBufDone (&buf
);
440 shescape (const FcChar8
*str
)
443 FcChar8 buf_static
[8192];
445 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
446 FcStrBufChar (&buf
, '\'');
450 FcStrBufString (&buf
, (const FcChar8
*) "'\\''");
452 FcStrBufChar (&buf
, *str
);
455 FcStrBufChar (&buf
, '\'');
456 return FcStrBufDone (&buf
);
460 xmlescape (const FcChar8
*str
)
463 FcChar8 buf_static
[8192];
465 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
470 case '&': FcStrBufString (&buf
, (const FcChar8
*) "&"); break;
471 case '<': FcStrBufString (&buf
, (const FcChar8
*) "<"); break;
472 case '>': FcStrBufString (&buf
, (const FcChar8
*) ">"); break;
473 default: FcStrBufChar (&buf
, *str
); break;
477 return FcStrBufDone (&buf
);
481 convert (FcFormatContext
*c
,
486 #define CONVERTER(name, func) \
487 else if (0 == strcmp ((const char *) c->word, name))\
489 CONVERTER ("downcase", FcStrDowncase
);
490 CONVERTER ("basename", FcStrBasename
);
491 CONVERTER ("dirname", FcStrDirname
);
492 CONVERTER ("cescape", cescape
);
493 CONVERTER ("shescape", shescape
);
494 CONVERTER ("xmlescape", xmlescape
);
496 message ("unknown converter \"%s\"",
502 maybe_interpret_converts (FcFormatContext
*c
,
506 while (consume_char (c
, '|'))
511 /* nul-terminate the buffer */
512 FcStrBufChar (buf
, '\0');
515 str
= buf
->buf
+ start
;
517 if (!(new_str
= convert (c
, str
)))
520 /* replace in the buffer */
522 FcStrBufString (buf
, new_str
);
530 align_to_width (FcStrBuf
*buf
,
539 len
= buf
->len
- start
;
543 while (len
++ < -width
)
544 FcStrBufChar (buf
, ' ');
546 else if (len
< width
)
551 while (len
++ < width
)
552 FcStrBufChar (buf
, ' ');
556 memmove (buf
->buf
+ buf
->len
- len
,
557 buf
->buf
+ buf
->len
- width
,
559 memset (buf
->buf
+ buf
->len
- width
,
567 interpret_percent (FcFormatContext
*c
,
574 if (!expect_char (c
, '%'))
577 if (consume_char (c
, '%')) /* "%%" */
579 FcStrBufChar (buf
, '%');
583 /* parse an optional width specifier */
584 width
= strtol ((const char *) c
->format
, (char **) &c
->format
, 10);
586 if (!expect_char (c
, '{'))
591 switch (*c
->format
) {
592 case '{': ret
= interpret_subexpr (c
, pat
, buf
); break;
593 case '+': ret
= interpret_filter (c
, pat
, buf
); break;
594 case '-': ret
= interpret_delete (c
, pat
, buf
); break;
595 case '?': ret
= interpret_cond (c
, pat
, buf
); break;
596 default: ret
= interpret_simple (c
, pat
, buf
); break;
600 maybe_interpret_converts (c
, buf
, start
) &&
601 align_to_width (buf
, start
, width
) &&
602 expect_char (c
, '}');
605 static char escaped_char(const char ch
)
608 case 'a': return '\a';
609 case 'b': return '\b';
610 case 'f': return '\f';
611 case 'n': return '\n';
612 case 'r': return '\r';
613 case 't': return '\t';
614 case 'v': return '\v';
620 interpret_expr (FcFormatContext
*c
,
625 while (*c
->format
&& *c
->format
!= term
)
630 c
->format
++; /* skip over '\\' */
632 FcStrBufChar (buf
, escaped_char (*c
->format
++));
635 if (!interpret_percent (c
, pat
, buf
))
639 FcStrBufChar (buf
, *c
->format
++);
645 FcPatternFormat (FcPattern
*pat
, const FcChar8
*format
)
648 FcChar8 buf_static
[8192];
652 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
653 if (!FcFormatContextInit (&c
, format
))
656 ret
= interpret_expr (&c
, pat
, &buf
, '\0');
658 FcFormatContextDone (&c
);
660 return FcStrBufDone (&buf
);
663 FcStrBufDestroy (&buf
);
669 #include "fcaliastail.h"