]>
git.wh0rd.org - fontconfig.git/blob - src/fcformat.c
2 * Copyright © 2008,2009 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 * - allow indexing subexprs using '%{[idx]elt1,elt2{subexpr}}'
35 * - allow indexing simple tags using '%{elt[idx]}'
36 * - conditional/filtering/deletion on binding (using '(w)'/'(s)' notation)
40 message (const char *fmt
, ...)
44 fprintf (stderr
, "Fontconfig: Pattern format error: ");
45 vfprintf (stderr
, fmt
, args
);
46 fprintf (stderr
, ".\n");
51 typedef struct _FcFormatContext
53 const FcChar8
*format_orig
;
54 const FcChar8
*format
;
60 FcFormatContextInit (FcFormatContext
*c
,
61 const FcChar8
*format
)
63 c
->format_orig
= c
->format
= format
;
64 c
->format_len
= strlen ((const char *) format
);
65 c
->word
= malloc (c
->format_len
+ 1);
67 return c
->word
!= NULL
;
71 FcFormatContextDone (FcFormatContext
*c
)
80 consume_char (FcFormatContext
*c
,
83 if (*c
->format
!= term
)
91 expect_char (FcFormatContext
*c
,
94 FcBool res
= consume_char (c
, term
);
97 if (c
->format
== c
->format_orig
+ c
->format_len
)
98 message ("format ended while expecting '%c'",
101 message ("expected '%c' at %d",
102 term
, c
->format
- c
->format_orig
+ 1);
108 FcCharIsPunct (const FcChar8 c
)
128 read_word (FcFormatContext
*c
)
136 if (*c
->format
== '\\')
143 else if (FcCharIsPunct (*c
->format
))
152 message ("expected element name at %d",
153 c
->format
- c
->format_orig
+ 1);
161 interpret_expr (FcFormatContext
*c
,
167 interpret_subexpr (FcFormatContext
*c
,
171 return expect_char (c
, '{') &&
172 interpret_expr (c
, pat
, buf
, '}') &&
173 expect_char (c
, '}');
177 maybe_interpret_subexpr (FcFormatContext
*c
,
181 return (*c
->format
== '{') ?
182 interpret_subexpr (c
, pat
, buf
) :
187 skip_subexpr (FcFormatContext
*c
);
190 skip_percent (FcFormatContext
*c
)
194 if (!expect_char (c
, '%'))
197 /* skip an optional width specifier */
198 width
= strtol ((const char *) c
->format
, (char **) &c
->format
, 10);
200 if (!expect_char (c
, '{'))
203 while(*c
->format
&& *c
->format
!= '}')
208 c
->format
++; /* skip over '\\' */
213 if (!skip_subexpr (c
))
220 return expect_char (c
, '}');
224 skip_expr (FcFormatContext
*c
)
226 while(*c
->format
&& *c
->format
!= '}')
231 c
->format
++; /* skip over '\\' */
236 if (!skip_percent (c
))
247 skip_subexpr (FcFormatContext
*c
)
249 return expect_char (c
, '{') &&
251 expect_char (c
, '}');
255 maybe_skip_subexpr (FcFormatContext
*c
)
257 return (*c
->format
== '{') ?
263 interpret_filter (FcFormatContext
*c
,
270 if (!expect_char (c
, '+'))
273 os
= FcObjectSetCreate ();
279 if (!read_word (c
) ||
280 !FcObjectSetAdd (os
, (const char *) c
->word
))
282 FcObjectSetDestroy (os
);
286 while (consume_char (c
, ','));
288 subpat
= FcPatternFilter (pat
, os
);
289 FcObjectSetDestroy (os
);
292 !interpret_subexpr (c
, subpat
, buf
))
295 FcPatternDestroy (subpat
);
300 interpret_delete (FcFormatContext
*c
,
306 if (!expect_char (c
, '-'))
309 subpat
= FcPatternDuplicate (pat
);
317 FcPatternDestroy (subpat
);
321 FcPatternDel (subpat
, (const char *) c
->word
);
323 while (consume_char (c
, ','));
325 if (!interpret_subexpr (c
, subpat
, buf
))
328 FcPatternDestroy (subpat
);
333 interpret_cond (FcFormatContext
*c
,
339 if (!expect_char (c
, '?'))
349 negate
= consume_char (c
, '!');
356 (FcResultMatch
== FcPatternGet (pat
,
357 (const char *) c
->word
,
360 while (consume_char (c
, ','));
364 if (!interpret_subexpr (c
, pat
, buf
) ||
365 !maybe_skip_subexpr (c
))
370 if (!skip_subexpr (c
) ||
371 !maybe_interpret_subexpr (c
, pat
, buf
))
379 interpret_count (FcFormatContext
*c
,
385 FcChar8 buf_static
[64];
387 if (!expect_char (c
, '#'))
394 e
= FcPatternObjectFindElt (pat
,
395 FcObjectFromName ((const char *) c
->word
));
400 for (l
= FcPatternEltValues(e
);
406 snprintf (buf_static
, sizeof (buf_static
), "%d", count
);
407 FcStrBufString (buf
, buf_static
);
413 interpret_simple (FcFormatContext
*c
,
418 FcBool add_colon
= FcFalse
;
419 FcBool add_elt_name
= FcFalse
;
421 if (consume_char (c
, ':'))
427 if (consume_char (c
, '='))
428 add_elt_name
= FcTrue
;
430 e
= FcPatternObjectFindElt (pat
,
431 FcObjectFromName ((const char *) c
->word
));
437 FcStrBufChar (buf
, ':');
440 FcStrBufString (buf
, c
->word
);
441 FcStrBufChar (buf
, '=');
444 l
= FcPatternEltValues(e
);
445 FcNameUnparseValueList (buf
, l
, '\0');
452 cescape (const FcChar8
*str
)
455 FcChar8 buf_static
[8192];
457 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
464 FcStrBufChar (&buf
, '\\');
467 FcStrBufChar (&buf
, *str
++);
469 return FcStrBufDone (&buf
);
473 shescape (const FcChar8
*str
)
476 FcChar8 buf_static
[8192];
478 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
479 FcStrBufChar (&buf
, '\'');
483 FcStrBufString (&buf
, (const FcChar8
*) "'\\''");
485 FcStrBufChar (&buf
, *str
);
488 FcStrBufChar (&buf
, '\'');
489 return FcStrBufDone (&buf
);
493 xmlescape (const FcChar8
*str
)
496 FcChar8 buf_static
[8192];
498 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
503 case '&': FcStrBufString (&buf
, (const FcChar8
*) "&"); break;
504 case '<': FcStrBufString (&buf
, (const FcChar8
*) "<"); break;
505 case '>': FcStrBufString (&buf
, (const FcChar8
*) ">"); break;
506 default: FcStrBufChar (&buf
, *str
); break;
510 return FcStrBufDone (&buf
);
514 convert (FcFormatContext
*c
,
519 #define CONVERTER(name, func) \
520 else if (0 == strcmp ((const char *) c->word, name))\
522 CONVERTER ("downcase", FcStrDowncase
);
523 CONVERTER ("basename", FcStrBasename
);
524 CONVERTER ("dirname", FcStrDirname
);
525 CONVERTER ("cescape", cescape
);
526 CONVERTER ("shescape", shescape
);
527 CONVERTER ("xmlescape", xmlescape
);
529 message ("unknown converter \"%s\"",
535 maybe_interpret_converts (FcFormatContext
*c
,
539 while (consume_char (c
, '|'))
544 /* nul-terminate the buffer */
545 FcStrBufChar (buf
, '\0');
548 str
= buf
->buf
+ start
;
550 if (!(new_str
= convert (c
, str
)))
553 /* replace in the buffer */
555 FcStrBufString (buf
, new_str
);
563 align_to_width (FcStrBuf
*buf
,
572 len
= buf
->len
- start
;
576 while (len
++ < -width
)
577 FcStrBufChar (buf
, ' ');
579 else if (len
< width
)
584 while (len
++ < width
)
585 FcStrBufChar (buf
, ' ');
589 memmove (buf
->buf
+ buf
->len
- len
,
590 buf
->buf
+ buf
->len
- width
,
592 memset (buf
->buf
+ buf
->len
- width
,
600 interpret_percent (FcFormatContext
*c
,
607 if (!expect_char (c
, '%'))
610 if (consume_char (c
, '%')) /* "%%" */
612 FcStrBufChar (buf
, '%');
616 /* parse an optional width specifier */
617 width
= strtol ((const char *) c
->format
, (char **) &c
->format
, 10);
619 if (!expect_char (c
, '{'))
624 switch (*c
->format
) {
625 case '{': ret
= interpret_subexpr (c
, pat
, buf
); break;
626 case '+': ret
= interpret_filter (c
, pat
, buf
); break;
627 case '-': ret
= interpret_delete (c
, pat
, buf
); break;
628 case '?': ret
= interpret_cond (c
, pat
, buf
); break;
629 case '#': ret
= interpret_count (c
, pat
, buf
); break;
630 default: ret
= interpret_simple (c
, pat
, buf
); break;
634 maybe_interpret_converts (c
, buf
, start
) &&
635 align_to_width (buf
, start
, width
) &&
636 expect_char (c
, '}');
639 static char escaped_char(const char ch
)
642 case 'a': return '\a';
643 case 'b': return '\b';
644 case 'f': return '\f';
645 case 'n': return '\n';
646 case 'r': return '\r';
647 case 't': return '\t';
648 case 'v': return '\v';
654 interpret_expr (FcFormatContext
*c
,
659 while (*c
->format
&& *c
->format
!= term
)
664 c
->format
++; /* skip over '\\' */
666 FcStrBufChar (buf
, escaped_char (*c
->format
++));
669 if (!interpret_percent (c
, pat
, buf
))
673 FcStrBufChar (buf
, *c
->format
++);
679 FcPatternFormat (FcPattern
*pat
, const FcChar8
*format
)
682 FcChar8 buf_static
[8192];
686 FcStrBufInit (&buf
, buf_static
, sizeof (buf_static
));
687 if (!FcFormatContextInit (&c
, format
))
690 ret
= interpret_expr (&c
, pat
, &buf
, '\0');
692 FcFormatContextDone (&c
);
694 return FcStrBufDone (&buf
);
697 FcStrBufDestroy (&buf
);
703 #include "fcaliastail.h"