fcxml.c revision c9710b42
1/* 2 * fontconfig/src/fcxml.c 3 * 4 * Copyright © 2002 Keith Packard 5 * 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 the author(s) not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. The authors make no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) 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. 23 */ 24 25#include "fcint.h" 26#include <fcntl.h> 27#include <stdarg.h> 28#include <dirent.h> 29 30#ifdef ENABLE_LIBXML2 31 32#include <libxml/parser.h> 33 34#define XML_Char xmlChar 35#define XML_Parser xmlParserCtxtPtr 36#define XML_ParserFree xmlFreeParserCtxt 37#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber 38#define XML_GetErrorCode xmlCtxtGetLastError 39#define XML_ErrorString(Error) (Error)->message 40 41#else /* ENABLE_LIBXML2 */ 42 43#ifndef HAVE_XMLPARSE_H 44#define HAVE_XMLPARSE_H 0 45#endif 46 47#if HAVE_XMLPARSE_H 48#include <xmlparse.h> 49#else 50#include <expat.h> 51#endif 52 53#endif /* ENABLE_LIBXML2 */ 54 55#ifdef _WIN32 56#include <mbstring.h> 57#endif 58 59static void 60FcExprDestroy (FcExpr *e); 61 62void 63FcTestDestroy (FcTest *test) 64{ 65 if (test->next) 66 FcTestDestroy (test->next); 67 FcExprDestroy (test->expr); 68 free (test); 69} 70 71static FcExpr * 72FcExprCreateInteger (FcConfig *config, int i) 73{ 74 FcExpr *e = FcConfigAllocExpr (config); 75 if (e) 76 { 77 e->op = FcOpInteger; 78 e->u.ival = i; 79 } 80 return e; 81} 82 83static FcExpr * 84FcExprCreateDouble (FcConfig *config, double d) 85{ 86 FcExpr *e = FcConfigAllocExpr (config); 87 if (e) 88 { 89 e->op = FcOpDouble; 90 e->u.dval = d; 91 } 92 return e; 93} 94 95static FcExpr * 96FcExprCreateString (FcConfig *config, const FcChar8 *s) 97{ 98 FcExpr *e = FcConfigAllocExpr (config); 99 if (e) 100 { 101 e->op = FcOpString; 102 e->u.sval = FcStrdup (s); 103 } 104 return e; 105} 106 107static FcExprMatrix * 108FcExprMatrixCopyShallow (const FcExprMatrix *matrix) 109{ 110 FcExprMatrix *m = malloc (sizeof (FcExprMatrix)); 111 if (m) 112 { 113 *m = *matrix; 114 } 115 return m; 116} 117 118static void 119FcExprMatrixFreeShallow (FcExprMatrix *m) 120{ 121 if (!m) 122 return; 123 124 free (m); 125} 126 127static void 128FcExprMatrixFree (FcExprMatrix *m) 129{ 130 if (!m) 131 return; 132 133 FcExprDestroy (m->xx); 134 FcExprDestroy (m->xy); 135 FcExprDestroy (m->yx); 136 FcExprDestroy (m->yy); 137 138 free (m); 139} 140 141static FcExpr * 142FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix) 143{ 144 FcExpr *e = FcConfigAllocExpr (config); 145 if (e) 146 { 147 e->op = FcOpMatrix; 148 e->u.mexpr = FcExprMatrixCopyShallow (matrix); 149 } 150 return e; 151} 152 153static FcExpr * 154FcExprCreateBool (FcConfig *config, FcBool b) 155{ 156 FcExpr *e = FcConfigAllocExpr (config); 157 if (e) 158 { 159 e->op = FcOpBool; 160 e->u.bval = b; 161 } 162 return e; 163} 164 165static FcExpr * 166FcExprCreateCharSet (FcConfig *config, FcCharSet *charset) 167{ 168 FcExpr *e = FcConfigAllocExpr (config); 169 if (e) 170 { 171 e->op = FcOpCharSet; 172 e->u.cval = FcCharSetCopy (charset); 173 } 174 return e; 175} 176 177static FcExpr * 178FcExprCreateLangSet (FcConfig *config, FcLangSet *langset) 179{ 180 FcExpr *e = FcConfigAllocExpr (config); 181 if (e) 182 { 183 e->op = FcOpLangSet; 184 e->u.lval = FcLangSetCopy (langset); 185 } 186 return e; 187} 188 189static FcExpr * 190FcExprCreateName (FcConfig *config, FcExprName name) 191{ 192 FcExpr *e = FcConfigAllocExpr (config); 193 if (e) 194 { 195 e->op = FcOpField; 196 e->u.name = name; 197 } 198 return e; 199} 200 201static FcExpr * 202FcExprCreateConst (FcConfig *config, const FcChar8 *constant) 203{ 204 FcExpr *e = FcConfigAllocExpr (config); 205 if (e) 206 { 207 e->op = FcOpConst; 208 e->u.constant = FcStrdup (constant); 209 } 210 return e; 211} 212 213static FcExpr * 214FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right) 215{ 216 FcExpr *e = FcConfigAllocExpr (config); 217 if (e) 218 { 219 e->op = op; 220 e->u.tree.left = left; 221 e->u.tree.right = right; 222 } 223 return e; 224} 225 226static void 227FcExprDestroy (FcExpr *e) 228{ 229 if (!e) 230 return; 231 switch (FC_OP_GET_OP (e->op)) { 232 case FcOpInteger: 233 break; 234 case FcOpDouble: 235 break; 236 case FcOpString: 237 FcFree (e->u.sval); 238 break; 239 case FcOpMatrix: 240 FcExprMatrixFree (e->u.mexpr); 241 break; 242 case FcOpRange: 243 break; 244 case FcOpCharSet: 245 FcCharSetDestroy (e->u.cval); 246 break; 247 case FcOpLangSet: 248 FcLangSetDestroy (e->u.lval); 249 break; 250 case FcOpBool: 251 break; 252 case FcOpField: 253 break; 254 case FcOpConst: 255 FcFree (e->u.constant); 256 break; 257 case FcOpAssign: 258 case FcOpAssignReplace: 259 case FcOpPrepend: 260 case FcOpPrependFirst: 261 case FcOpAppend: 262 case FcOpAppendLast: 263 case FcOpDelete: 264 case FcOpDeleteAll: 265 break; 266 case FcOpOr: 267 case FcOpAnd: 268 case FcOpEqual: 269 case FcOpNotEqual: 270 case FcOpLess: 271 case FcOpLessEqual: 272 case FcOpMore: 273 case FcOpMoreEqual: 274 case FcOpContains: 275 case FcOpListing: 276 case FcOpNotContains: 277 case FcOpPlus: 278 case FcOpMinus: 279 case FcOpTimes: 280 case FcOpDivide: 281 case FcOpQuest: 282 case FcOpComma: 283 FcExprDestroy (e->u.tree.right); 284 /* fall through */ 285 case FcOpNot: 286 case FcOpFloor: 287 case FcOpCeil: 288 case FcOpRound: 289 case FcOpTrunc: 290 FcExprDestroy (e->u.tree.left); 291 break; 292 case FcOpNil: 293 case FcOpInvalid: 294 break; 295 } 296 297 e->op = FcOpNil; 298} 299 300void 301FcEditDestroy (FcEdit *e) 302{ 303 if (e->next) 304 FcEditDestroy (e->next); 305 if (e->expr) 306 FcExprDestroy (e->expr); 307 free (e); 308} 309 310typedef enum _FcElement { 311 FcElementNone, 312 FcElementFontconfig, 313 FcElementDir, 314 FcElementCacheDir, 315 FcElementCache, 316 FcElementInclude, 317 FcElementConfig, 318 FcElementMatch, 319 FcElementAlias, 320 321 FcElementBlank, 322 FcElementRescan, 323 324 FcElementPrefer, 325 FcElementAccept, 326 FcElementDefault, 327 FcElementFamily, 328 329 FcElementSelectfont, 330 FcElementAcceptfont, 331 FcElementRejectfont, 332 FcElementGlob, 333 FcElementPattern, 334 FcElementPatelt, 335 336 FcElementTest, 337 FcElementEdit, 338 FcElementInt, 339 FcElementDouble, 340 FcElementString, 341 FcElementMatrix, 342 FcElementRange, 343 FcElementBool, 344 FcElementCharSet, 345 FcElementLangSet, 346 FcElementName, 347 FcElementConst, 348 FcElementOr, 349 FcElementAnd, 350 FcElementEq, 351 FcElementNotEq, 352 FcElementLess, 353 FcElementLessEq, 354 FcElementMore, 355 FcElementMoreEq, 356 FcElementContains, 357 FcElementNotContains, 358 FcElementPlus, 359 FcElementMinus, 360 FcElementTimes, 361 FcElementDivide, 362 FcElementNot, 363 FcElementIf, 364 FcElementFloor, 365 FcElementCeil, 366 FcElementRound, 367 FcElementTrunc, 368 FcElementUnknown 369} FcElement; 370 371static const struct { 372 const char name[16]; 373 FcElement element; 374} fcElementMap[] = { 375 { "fontconfig", FcElementFontconfig }, 376 { "dir", FcElementDir }, 377 { "cachedir", FcElementCacheDir }, 378 { "cache", FcElementCache }, 379 { "include", FcElementInclude }, 380 { "config", FcElementConfig }, 381 { "match", FcElementMatch }, 382 { "alias", FcElementAlias }, 383 384 { "blank", FcElementBlank }, 385 { "rescan", FcElementRescan }, 386 387 { "prefer", FcElementPrefer }, 388 { "accept", FcElementAccept }, 389 { "default", FcElementDefault }, 390 { "family", FcElementFamily }, 391 392 { "selectfont", FcElementSelectfont }, 393 { "acceptfont", FcElementAcceptfont }, 394 { "rejectfont", FcElementRejectfont }, 395 { "glob", FcElementGlob }, 396 { "pattern", FcElementPattern }, 397 { "patelt", FcElementPatelt }, 398 399 { "test", FcElementTest }, 400 { "edit", FcElementEdit }, 401 { "int", FcElementInt }, 402 { "double", FcElementDouble }, 403 { "string", FcElementString }, 404 { "matrix", FcElementMatrix }, 405 { "range", FcElementRange }, 406 { "bool", FcElementBool }, 407 { "charset", FcElementCharSet }, 408 { "langset", FcElementLangSet }, 409 { "name", FcElementName }, 410 { "const", FcElementConst }, 411 { "or", FcElementOr }, 412 { "and", FcElementAnd }, 413 { "eq", FcElementEq }, 414 { "not_eq", FcElementNotEq }, 415 { "less", FcElementLess }, 416 { "less_eq", FcElementLessEq }, 417 { "more", FcElementMore }, 418 { "more_eq", FcElementMoreEq }, 419 { "contains", FcElementContains }, 420 { "not_contains", FcElementNotContains }, 421 { "plus", FcElementPlus }, 422 { "minus", FcElementMinus }, 423 { "times", FcElementTimes }, 424 { "divide", FcElementDivide }, 425 { "not", FcElementNot }, 426 { "if", FcElementIf }, 427 { "floor", FcElementFloor }, 428 { "ceil", FcElementCeil }, 429 { "round", FcElementRound }, 430 { "trunc", FcElementTrunc }, 431}; 432#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0]) 433 434static FcElement 435FcElementMap (const XML_Char *name) 436{ 437 438 int i; 439 for (i = 0; i < NUM_ELEMENT_MAPS; i++) 440 if (!strcmp ((char *) name, fcElementMap[i].name)) 441 return fcElementMap[i].element; 442 return FcElementUnknown; 443} 444 445typedef struct _FcPStack { 446 struct _FcPStack *prev; 447 FcElement element; 448 FcChar8 **attr; 449 FcStrBuf str; 450 FcChar8 *attr_buf_static[16]; 451} FcPStack; 452 453typedef enum _FcVStackTag { 454 FcVStackNone, 455 456 FcVStackString, 457 FcVStackFamily, 458 FcVStackConstant, 459 FcVStackGlob, 460 FcVStackName, 461 FcVStackPattern, 462 463 FcVStackPrefer, 464 FcVStackAccept, 465 FcVStackDefault, 466 467 FcVStackInteger, 468 FcVStackDouble, 469 FcVStackMatrix, 470 FcVStackRange, 471 FcVStackBool, 472 FcVStackCharSet, 473 FcVStackLangSet, 474 475 FcVStackTest, 476 FcVStackExpr, 477 FcVStackEdit 478} FcVStackTag; 479 480typedef struct _FcVStack { 481 struct _FcVStack *prev; 482 FcPStack *pstack; /* related parse element */ 483 FcVStackTag tag; 484 union { 485 FcChar8 *string; 486 487 int integer; 488 double _double; 489 FcExprMatrix *matrix; 490 FcRange range; 491 FcBool bool_; 492 FcCharSet *charset; 493 FcLangSet *langset; 494 FcExprName name; 495 496 FcTest *test; 497 FcQual qual; 498 FcOp op; 499 FcExpr *expr; 500 FcEdit *edit; 501 502 FcPattern *pattern; 503 } u; 504} FcVStack; 505 506typedef struct _FcConfigParse { 507 FcPStack *pstack; 508 FcVStack *vstack; 509 FcBool error; 510 const FcChar8 *name; 511 FcConfig *config; 512 XML_Parser parser; 513 unsigned int pstack_static_used; 514 FcPStack pstack_static[8]; 515 unsigned int vstack_static_used; 516 FcVStack vstack_static[64]; 517} FcConfigParse; 518 519typedef enum _FcConfigSeverity { 520 FcSevereInfo, FcSevereWarning, FcSevereError 521} FcConfigSeverity; 522 523static void 524FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...) 525{ 526 const char *s = "unknown"; 527 va_list args; 528 529 va_start (args, fmt); 530 531 switch (severe) { 532 case FcSevereInfo: s = "info"; break; 533 case FcSevereWarning: s = "warning"; break; 534 case FcSevereError: s = "error"; break; 535 } 536 if (parse) 537 { 538 if (parse->name) 539 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s, 540 parse->name, (int)XML_GetCurrentLineNumber (parse->parser)); 541 else 542 fprintf (stderr, "Fontconfig %s: line %d: ", s, 543 (int)XML_GetCurrentLineNumber (parse->parser)); 544 if (severe >= FcSevereError) 545 parse->error = FcTrue; 546 } 547 else 548 fprintf (stderr, "Fontconfig %s: ", s); 549 vfprintf (stderr, fmt, args); 550 fprintf (stderr, "\n"); 551 va_end (args); 552} 553 554 555static FcExpr * 556FcPopExpr (FcConfigParse *parse); 557 558 559static const char * 560FcTypeName (FcType type) 561{ 562 switch (type) { 563 case FcTypeVoid: 564 return "void"; 565 case FcTypeInteger: 566 case FcTypeDouble: 567 return "number"; 568 case FcTypeString: 569 return "string"; 570 case FcTypeBool: 571 return "bool"; 572 case FcTypeMatrix: 573 return "matrix"; 574 case FcTypeCharSet: 575 return "charset"; 576 case FcTypeFTFace: 577 return "FT_Face"; 578 case FcTypeLangSet: 579 return "langset"; 580 default: 581 return "unknown"; 582 } 583} 584 585static void 586FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type) 587{ 588 if (value == FcTypeInteger) 589 value = FcTypeDouble; 590 if (type == FcTypeInteger) 591 type = FcTypeDouble; 592 if (value != type) 593 { 594 if ((value == FcTypeLangSet && type == FcTypeString) || 595 (value == FcTypeString && type == FcTypeLangSet)) 596 return; 597 if (type == (FcType) -1) 598 return; 599 /* It's perfectly fine to use user-define elements in expressions, 600 * so don't warn in that case. */ 601 if (value == (FcType) -1) 602 return; 603 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s", 604 FcTypeName (value), FcTypeName (type)); 605 } 606} 607 608static void 609FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type) 610{ 611 const FcObjectType *o; 612 const FcConstant *c; 613 614 /* If parsing the expression failed, some nodes may be NULL */ 615 if (!expr) 616 return; 617 618 switch (FC_OP_GET_OP (expr->op)) { 619 case FcOpInteger: 620 case FcOpDouble: 621 FcTypecheckValue (parse, FcTypeDouble, type); 622 break; 623 case FcOpString: 624 FcTypecheckValue (parse, FcTypeString, type); 625 break; 626 case FcOpMatrix: 627 FcTypecheckValue (parse, FcTypeMatrix, type); 628 break; 629 case FcOpBool: 630 FcTypecheckValue (parse, FcTypeBool, type); 631 break; 632 case FcOpCharSet: 633 FcTypecheckValue (parse, FcTypeCharSet, type); 634 break; 635 case FcOpLangSet: 636 FcTypecheckValue (parse, FcTypeLangSet, type); 637 break; 638 case FcOpNil: 639 break; 640 case FcOpField: 641 o = FcNameGetObjectType (FcObjectName (expr->u.name.object)); 642 if (o) 643 FcTypecheckValue (parse, o->type, type); 644 break; 645 case FcOpConst: 646 c = FcNameGetConstant (expr->u.constant); 647 if (c) 648 { 649 o = FcNameGetObjectType (c->object); 650 if (o) 651 FcTypecheckValue (parse, o->type, type); 652 } 653 else 654 FcConfigMessage (parse, FcSevereWarning, 655 "invalid constant used : %s", 656 expr->u.constant); 657 break; 658 case FcOpQuest: 659 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); 660 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type); 661 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type); 662 break; 663 case FcOpAssign: 664 case FcOpAssignReplace: 665 break; 666 case FcOpEqual: 667 case FcOpNotEqual: 668 case FcOpLess: 669 case FcOpLessEqual: 670 case FcOpMore: 671 case FcOpMoreEqual: 672 case FcOpContains: 673 case FcOpNotContains: 674 case FcOpListing: 675 FcTypecheckValue (parse, FcTypeBool, type); 676 break; 677 case FcOpComma: 678 case FcOpOr: 679 case FcOpAnd: 680 case FcOpPlus: 681 case FcOpMinus: 682 case FcOpTimes: 683 case FcOpDivide: 684 FcTypecheckExpr (parse, expr->u.tree.left, type); 685 FcTypecheckExpr (parse, expr->u.tree.right, type); 686 break; 687 case FcOpNot: 688 FcTypecheckValue (parse, FcTypeBool, type); 689 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool); 690 break; 691 case FcOpFloor: 692 case FcOpCeil: 693 case FcOpRound: 694 case FcOpTrunc: 695 FcTypecheckValue (parse, FcTypeDouble, type); 696 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble); 697 break; 698 default: 699 break; 700 } 701} 702 703static FcTest * 704FcTestCreate (FcConfigParse *parse, 705 FcMatchKind kind, 706 FcQual qual, 707 const FcChar8 *field, 708 FcOp compare, 709 FcExpr *expr) 710{ 711 FcTest *test = (FcTest *) malloc (sizeof (FcTest)); 712 713 if (test) 714 { 715 const FcObjectType *o; 716 717 test->next = 0; 718 test->kind = kind; 719 test->qual = qual; 720 test->object = FcObjectFromName ((const char *) field); 721 test->op = compare; 722 test->expr = expr; 723 o = FcNameGetObjectType (FcObjectName (test->object)); 724 if (o) 725 FcTypecheckExpr (parse, expr, o->type); 726 } 727 return test; 728} 729 730static FcEdit * 731FcEditCreate (FcConfigParse *parse, 732 FcObject object, 733 FcOp op, 734 FcExpr *expr, 735 FcValueBinding binding) 736{ 737 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit)); 738 739 if (e) 740 { 741 const FcObjectType *o; 742 743 e->next = 0; 744 e->object = object; 745 e->op = op; 746 e->expr = expr; 747 e->binding = binding; 748 o = FcNameGetObjectType (FcObjectName (e->object)); 749 if (o) 750 FcTypecheckExpr (parse, expr, o->type); 751 } 752 return e; 753} 754 755static FcVStack * 756FcVStackCreateAndPush (FcConfigParse *parse) 757{ 758 FcVStack *new; 759 760 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0])) 761 new = &parse->vstack_static[parse->vstack_static_used++]; 762 else 763 { 764 new = malloc (sizeof (FcVStack)); 765 if (!new) 766 return 0; 767 } 768 new->tag = FcVStackNone; 769 new->prev = 0; 770 771 new->prev = parse->vstack; 772 new->pstack = parse->pstack ? parse->pstack->prev : 0; 773 parse->vstack = new; 774 775 return new; 776} 777 778static FcBool 779FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string) 780{ 781 FcVStack *vstack = FcVStackCreateAndPush (parse); 782 if (!vstack) 783 return FcFalse; 784 vstack->u.string = string; 785 vstack->tag = tag; 786 return FcTrue; 787} 788 789static FcBool 790FcVStackPushInteger (FcConfigParse *parse, int integer) 791{ 792 FcVStack *vstack = FcVStackCreateAndPush (parse); 793 if (!vstack) 794 return FcFalse; 795 vstack->u.integer = integer; 796 vstack->tag = FcVStackInteger; 797 return FcTrue; 798} 799 800static FcBool 801FcVStackPushDouble (FcConfigParse *parse, double _double) 802{ 803 FcVStack *vstack = FcVStackCreateAndPush (parse); 804 if (!vstack) 805 return FcFalse; 806 vstack->u._double = _double; 807 vstack->tag = FcVStackDouble; 808 return FcTrue; 809} 810 811static FcBool 812FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix) 813{ 814 FcVStack *vstack; 815 vstack = FcVStackCreateAndPush (parse); 816 if (!vstack) 817 return FcFalse; 818 vstack->u.matrix = FcExprMatrixCopyShallow (matrix); 819 vstack->tag = FcVStackMatrix; 820 return FcTrue; 821} 822 823static FcBool 824FcVStackPushRange (FcConfigParse *parse, FcRange *range) 825{ 826 FcVStack *vstack = FcVStackCreateAndPush (parse); 827 if (!vstack) 828 return FcFalse; 829 vstack->u.range.begin = range->begin; 830 vstack->u.range.end = range->end; 831 vstack->tag = FcVStackRange; 832 return FcTrue; 833} 834 835static FcBool 836FcVStackPushBool (FcConfigParse *parse, FcBool bool_) 837{ 838 FcVStack *vstack = FcVStackCreateAndPush (parse); 839 if (!vstack) 840 return FcFalse; 841 vstack->u.bool_ = bool_; 842 vstack->tag = FcVStackBool; 843 return FcTrue; 844} 845 846static FcBool 847FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset) 848{ 849 FcVStack *vstack; 850 if (!charset) 851 return FcFalse; 852 vstack = FcVStackCreateAndPush (parse); 853 if (!vstack) 854 return FcFalse; 855 vstack->u.charset = charset; 856 vstack->tag = FcVStackCharSet; 857 return FcTrue; 858} 859 860static FcBool 861FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset) 862{ 863 FcVStack *vstack; 864 if (!langset) 865 return FcFalse; 866 vstack = FcVStackCreateAndPush (parse); 867 if (!vstack) 868 return FcFalse; 869 vstack->u.langset = langset; 870 vstack->tag = FcVStackLangSet; 871 return FcTrue; 872} 873 874static FcBool 875FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object) 876{ 877 FcVStack *vstack = FcVStackCreateAndPush (parse); 878 if (!vstack) 879 return FcFalse; 880 vstack->u.name.object = object; 881 vstack->u.name.kind = kind; 882 vstack->tag = FcVStackName; 883 return FcTrue; 884} 885 886static FcBool 887FcVStackPushTest (FcConfigParse *parse, FcTest *test) 888{ 889 FcVStack *vstack = FcVStackCreateAndPush (parse); 890 if (!vstack) 891 return FcFalse; 892 vstack->u.test = test; 893 vstack->tag = FcVStackTest; 894 return FcTrue; 895} 896 897static FcBool 898FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr) 899{ 900 FcVStack *vstack = FcVStackCreateAndPush (parse); 901 if (!vstack) 902 return FcFalse; 903 vstack->u.expr = expr; 904 vstack->tag = tag; 905 return FcTrue; 906} 907 908static FcBool 909FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit) 910{ 911 FcVStack *vstack = FcVStackCreateAndPush (parse); 912 if (!vstack) 913 return FcFalse; 914 vstack->u.edit = edit; 915 vstack->tag = FcVStackEdit; 916 return FcTrue; 917} 918 919static FcBool 920FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern) 921{ 922 FcVStack *vstack = FcVStackCreateAndPush (parse); 923 if (!vstack) 924 return FcFalse; 925 vstack->u.pattern = pattern; 926 vstack->tag = FcVStackPattern; 927 return FcTrue; 928} 929 930static FcVStack * 931FcVStackFetch (FcConfigParse *parse, int off) 932{ 933 FcVStack *vstack; 934 935 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev); 936 return vstack; 937} 938 939static FcVStack * 940FcVStackPeek (FcConfigParse *parse) 941{ 942 FcVStack *vstack = parse->vstack; 943 944 return vstack && vstack->pstack == parse->pstack ? vstack : 0; 945} 946 947static void 948FcVStackPopAndDestroy (FcConfigParse *parse) 949{ 950 FcVStack *vstack = parse->vstack; 951 952 if (!vstack || vstack->pstack != parse->pstack) 953 return; 954 955 parse->vstack = vstack->prev; 956 957 switch (vstack->tag) { 958 case FcVStackNone: 959 break; 960 case FcVStackName: 961 break; 962 case FcVStackFamily: 963 break; 964 case FcVStackString: 965 case FcVStackConstant: 966 case FcVStackGlob: 967 FcStrFree (vstack->u.string); 968 break; 969 case FcVStackPattern: 970 FcPatternDestroy (vstack->u.pattern); 971 break; 972 case FcVStackInteger: 973 case FcVStackDouble: 974 break; 975 case FcVStackMatrix: 976 FcExprMatrixFreeShallow (vstack->u.matrix); 977 break; 978 case FcVStackRange: 979 case FcVStackBool: 980 break; 981 case FcVStackCharSet: 982 FcCharSetDestroy (vstack->u.charset); 983 break; 984 case FcVStackLangSet: 985 FcLangSetDestroy (vstack->u.langset); 986 break; 987 case FcVStackTest: 988 FcTestDestroy (vstack->u.test); 989 break; 990 case FcVStackExpr: 991 case FcVStackPrefer: 992 case FcVStackAccept: 993 case FcVStackDefault: 994 FcExprDestroy (vstack->u.expr); 995 break; 996 case FcVStackEdit: 997 FcEditDestroy (vstack->u.edit); 998 break; 999 } 1000 1001 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1]) 1002 parse->vstack_static_used--; 1003 else 1004 free (vstack); 1005} 1006 1007static void 1008FcVStackClear (FcConfigParse *parse) 1009{ 1010 while (FcVStackPeek (parse)) 1011 FcVStackPopAndDestroy (parse); 1012} 1013 1014static int 1015FcVStackElements (FcConfigParse *parse) 1016{ 1017 int h = 0; 1018 FcVStack *vstack = parse->vstack; 1019 while (vstack && vstack->pstack == parse->pstack) 1020 { 1021 h++; 1022 vstack = vstack->prev; 1023 } 1024 return h; 1025} 1026 1027static FcChar8 ** 1028FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes) 1029{ 1030 int slen; 1031 int i; 1032 FcChar8 **new; 1033 FcChar8 *s; 1034 1035 if (!attr) 1036 return 0; 1037 slen = 0; 1038 for (i = 0; attr[i]; i++) 1039 slen += strlen ((char *) attr[i]) + 1; 1040 if (i == 0) 1041 return 0; 1042 slen += (i + 1) * sizeof (FcChar8 *); 1043 if (slen <= size_bytes) 1044 new = buf; 1045 else 1046 { 1047 new = malloc (slen); 1048 if (!new) 1049 { 1050 FcConfigMessage (0, FcSevereError, "out of memory"); 1051 return 0; 1052 } 1053 } 1054 s = (FcChar8 *) (new + (i + 1)); 1055 for (i = 0; attr[i]; i++) 1056 { 1057 new[i] = s; 1058 strcpy ((char *) s, (char *) attr[i]); 1059 s += strlen ((char *) s) + 1; 1060 } 1061 new[i] = 0; 1062 return new; 1063} 1064 1065static FcBool 1066FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr) 1067{ 1068 FcPStack *new; 1069 1070 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0])) 1071 new = &parse->pstack_static[parse->pstack_static_used++]; 1072 else 1073 { 1074 new = malloc (sizeof (FcPStack)); 1075 if (!new) 1076 return FcFalse; 1077 } 1078 1079 new->prev = parse->pstack; 1080 new->element = element; 1081 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static)); 1082 FcStrBufInit (&new->str, 0, 0); 1083 parse->pstack = new; 1084 return FcTrue; 1085} 1086 1087static FcBool 1088FcPStackPop (FcConfigParse *parse) 1089{ 1090 FcPStack *old; 1091 1092 if (!parse->pstack) 1093 { 1094 FcConfigMessage (parse, FcSevereError, "mismatching element"); 1095 return FcFalse; 1096 } 1097 1098 if (parse->pstack->attr) 1099 { 1100 /* Warn about unused attrs. */ 1101 FcChar8 **attrs = parse->pstack->attr; 1102 while (*attrs) 1103 { 1104 if (attrs[0][0]) 1105 { 1106 FcConfigMessage (parse, FcSevereError, "invalid attribute '%s'", attrs[0]); 1107 } 1108 attrs += 2; 1109 } 1110 } 1111 1112 FcVStackClear (parse); 1113 old = parse->pstack; 1114 parse->pstack = old->prev; 1115 FcStrBufDestroy (&old->str); 1116 1117 if (old->attr && old->attr != old->attr_buf_static) 1118 free (old->attr); 1119 1120 if (old == &parse->pstack_static[parse->pstack_static_used - 1]) 1121 parse->pstack_static_used--; 1122 else 1123 free (old); 1124 return FcTrue; 1125} 1126 1127static FcBool 1128FcConfigParseInit (FcConfigParse *parse, const FcChar8 *name, FcConfig *config, XML_Parser parser) 1129{ 1130 parse->pstack = 0; 1131 parse->pstack_static_used = 0; 1132 parse->vstack = 0; 1133 parse->vstack_static_used = 0; 1134 parse->error = FcFalse; 1135 parse->name = name; 1136 parse->config = config; 1137 parse->parser = parser; 1138 return FcTrue; 1139} 1140 1141static void 1142FcConfigCleanup (FcConfigParse *parse) 1143{ 1144 while (parse->pstack) 1145 FcPStackPop (parse); 1146} 1147 1148static const FcChar8 * 1149FcConfigGetAttribute (FcConfigParse *parse, const char *attr) 1150{ 1151 FcChar8 **attrs; 1152 if (!parse->pstack) 1153 return 0; 1154 1155 attrs = parse->pstack->attr; 1156 if (!attrs) 1157 return 0; 1158 1159 while (*attrs) 1160 { 1161 if (!strcmp ((char *) *attrs, attr)) 1162 { 1163 attrs[0][0] = '\0'; /* Mark as used. */ 1164 return attrs[1]; 1165 } 1166 attrs += 2; 1167 } 1168 return 0; 1169} 1170 1171static void 1172FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr) 1173{ 1174 FcConfigParse *parse = userData; 1175 FcElement element; 1176 1177 element = FcElementMap (name); 1178 if (element == FcElementUnknown) 1179 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name); 1180 1181 if (!FcPStackPush (parse, element, attr)) 1182 { 1183 FcConfigMessage (parse, FcSevereError, "out of memory"); 1184 return; 1185 } 1186 return; 1187} 1188 1189static void 1190FcParseBlank (FcConfigParse *parse) 1191{ 1192 int n = FcVStackElements (parse); 1193 FcChar32 i; 1194 while (n-- > 0) 1195 { 1196 FcVStack *v = FcVStackFetch (parse, n); 1197 if (!parse->config->blanks) 1198 { 1199 parse->config->blanks = FcBlanksCreate (); 1200 if (!parse->config->blanks) 1201 goto bail; 1202 } 1203 switch ((int) v->tag) { 1204 case FcVStackInteger: 1205 if (!FcBlanksAdd (parse->config->blanks, v->u.integer)) 1206 goto bail; 1207 break; 1208 case FcVStackRange: 1209 if (v->u.range.begin <= v->u.range.end) 1210 { 1211 for (i = v->u.range.begin; i <= v->u.range.end; i++) 1212 { 1213 if (!FcBlanksAdd (parse->config->blanks, i)) 1214 goto bail; 1215 } 1216 } 1217 break; 1218 default: 1219 FcConfigMessage (parse, FcSevereError, "invalid element in blank"); 1220 break; 1221 } 1222 } 1223 return; 1224 bail: 1225 FcConfigMessage (parse, FcSevereError, "out of memory"); 1226} 1227 1228static void 1229FcParseRescan (FcConfigParse *parse) 1230{ 1231 int n = FcVStackElements (parse); 1232 while (n-- > 0) 1233 { 1234 FcVStack *v = FcVStackFetch (parse, n); 1235 if (v->tag != FcVStackInteger) 1236 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan"); 1237 else 1238 parse->config->rescanInterval = v->u.integer; 1239 } 1240} 1241 1242static void 1243FcParseInt (FcConfigParse *parse) 1244{ 1245 FcChar8 *s, *end; 1246 int l; 1247 1248 if (!parse->pstack) 1249 return; 1250 s = FcStrBufDoneStatic (&parse->pstack->str); 1251 if (!s) 1252 { 1253 FcConfigMessage (parse, FcSevereError, "out of memory"); 1254 return; 1255 } 1256 end = 0; 1257 l = (int) strtol ((char *) s, (char **)&end, 0); 1258 if (end != s + strlen ((char *) s)) 1259 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s); 1260 else 1261 FcVStackPushInteger (parse, l); 1262 FcStrBufDestroy (&parse->pstack->str); 1263} 1264 1265/* 1266 * idea copied from glib g_ascii_strtod with 1267 * permission of the author (Alexander Larsson) 1268 */ 1269 1270#include <locale.h> 1271 1272static double 1273FcStrtod (char *s, char **end) 1274{ 1275 struct lconv *locale_data; 1276 char *dot; 1277 double v; 1278 1279 /* 1280 * Have to swap the decimal point to match the current locale 1281 * if that locale doesn't use 0x2e 1282 */ 1283 if ((dot = strchr (s, 0x2e)) && 1284 (locale_data = localeconv ()) && 1285 (locale_data->decimal_point[0] != 0x2e || 1286 locale_data->decimal_point[1] != 0)) 1287 { 1288 char buf[128]; 1289 int slen = strlen (s); 1290 int dlen = strlen (locale_data->decimal_point); 1291 1292 if (slen + dlen > (int) sizeof (buf)) 1293 { 1294 if (end) 1295 *end = s; 1296 v = 0; 1297 } 1298 else 1299 { 1300 char *buf_end; 1301 /* mantissa */ 1302 strncpy (buf, s, dot - s); 1303 /* decimal point */ 1304 strcpy (buf + (dot - s), locale_data->decimal_point); 1305 /* rest of number */ 1306 strcpy (buf + (dot - s) + dlen, dot + 1); 1307 buf_end = 0; 1308 v = strtod (buf, &buf_end); 1309 if (buf_end) { 1310 buf_end = s + (buf_end - buf); 1311 if (buf_end > dot) 1312 buf_end -= dlen - 1; 1313 } 1314 if (end) 1315 *end = buf_end; 1316 } 1317 } 1318 else 1319 v = strtod (s, end); 1320 return v; 1321} 1322 1323static void 1324FcParseDouble (FcConfigParse *parse) 1325{ 1326 FcChar8 *s, *end; 1327 double d; 1328 1329 if (!parse->pstack) 1330 return; 1331 s = FcStrBufDoneStatic (&parse->pstack->str); 1332 if (!s) 1333 { 1334 FcConfigMessage (parse, FcSevereError, "out of memory"); 1335 return; 1336 } 1337 end = 0; 1338 d = FcStrtod ((char *) s, (char **)&end); 1339 if (end != s + strlen ((char *) s)) 1340 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s); 1341 else 1342 FcVStackPushDouble (parse, d); 1343 FcStrBufDestroy (&parse->pstack->str); 1344} 1345 1346static void 1347FcParseString (FcConfigParse *parse, FcVStackTag tag) 1348{ 1349 FcChar8 *s; 1350 1351 if (!parse->pstack) 1352 return; 1353 s = FcStrBufDone (&parse->pstack->str); 1354 if (!s) 1355 { 1356 FcConfigMessage (parse, FcSevereError, "out of memory"); 1357 return; 1358 } 1359 if (!FcVStackPushString (parse, tag, s)) 1360 FcStrFree (s); 1361} 1362 1363static void 1364FcParseName (FcConfigParse *parse) 1365{ 1366 const FcChar8 *kind_string; 1367 FcMatchKind kind; 1368 FcChar8 *s; 1369 FcObject object; 1370 1371 kind_string = FcConfigGetAttribute (parse, "target"); 1372 if (!kind_string) 1373 kind = FcMatchDefault; 1374 else 1375 { 1376 if (!strcmp ((char *) kind_string, "pattern")) 1377 kind = FcMatchPattern; 1378 else if (!strcmp ((char *) kind_string, "font")) 1379 kind = FcMatchFont; 1380 else if (!strcmp ((char *) kind_string, "default")) 1381 kind = FcMatchDefault; 1382 else 1383 { 1384 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string); 1385 return; 1386 } 1387 } 1388 1389 if (!parse->pstack) 1390 return; 1391 s = FcStrBufDone (&parse->pstack->str); 1392 if (!s) 1393 { 1394 FcConfigMessage (parse, FcSevereError, "out of memory"); 1395 return; 1396 } 1397 object = FcObjectFromName ((const char *) s); 1398 1399 FcVStackPushName (parse, kind, object); 1400 1401 FcStrFree (s); 1402} 1403 1404static void 1405FcParseMatrix (FcConfigParse *parse) 1406{ 1407 FcExprMatrix m; 1408 1409 m.yy = FcPopExpr (parse); 1410 m.yx = FcPopExpr (parse); 1411 m.xy = FcPopExpr (parse); 1412 m.xx = FcPopExpr (parse); 1413 1414 if (FcPopExpr (parse)) 1415 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements"); 1416 else 1417 FcVStackPushMatrix (parse, &m); 1418} 1419 1420static void 1421FcParseRange (FcConfigParse *parse) 1422{ 1423 FcVStack *vstack; 1424 FcRange r = {0, 0}; 1425 FcChar32 n; 1426 int count = 1; 1427 1428 while ((vstack = FcVStackPeek (parse))) 1429 { 1430 if (count < 0) 1431 { 1432 FcConfigMessage (parse, FcSevereError, "too many elements in range"); 1433 return; 1434 } 1435 switch ((int) vstack->tag) { 1436 case FcVStackInteger: 1437 n = vstack->u.integer; 1438 break; 1439 default: 1440 FcConfigMessage (parse, FcSevereError, "invalid element in range"); 1441 n = 0; 1442 break; 1443 } 1444 if (count == 1) 1445 r.end = n; 1446 else 1447 r.begin = n; 1448 count--; 1449 FcVStackPopAndDestroy (parse); 1450 } 1451 if (count < 0) 1452 { 1453 if (r.begin > r.end) 1454 { 1455 FcConfigMessage (parse, FcSevereError, "invalid range"); 1456 return; 1457 } 1458 FcVStackPushRange (parse, &r); 1459 } 1460 else 1461 FcConfigMessage (parse, FcSevereError, "invalid range"); 1462} 1463 1464static FcBool 1465FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_) 1466{ 1467 FcBool result = FcFalse; 1468 1469 if (!FcNameBool (bool_, &result)) 1470 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean", 1471 bool_); 1472 return result; 1473} 1474 1475static void 1476FcParseBool (FcConfigParse *parse) 1477{ 1478 FcChar8 *s; 1479 1480 if (!parse->pstack) 1481 return; 1482 s = FcStrBufDoneStatic (&parse->pstack->str); 1483 if (!s) 1484 { 1485 FcConfigMessage (parse, FcSevereError, "out of memory"); 1486 return; 1487 } 1488 FcVStackPushBool (parse, FcConfigLexBool (parse, s)); 1489 FcStrBufDestroy (&parse->pstack->str); 1490} 1491 1492static void 1493FcParseCharSet (FcConfigParse *parse) 1494{ 1495 FcVStack *vstack; 1496 FcCharSet *charset = FcCharSetCreate (); 1497 FcChar32 i; 1498 int n = 0; 1499 1500 while ((vstack = FcVStackPeek (parse))) 1501 { 1502 switch ((int) vstack->tag) { 1503 case FcVStackInteger: 1504 if (!FcCharSetAddChar (charset, vstack->u.integer)) 1505 { 1506 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer); 1507 } 1508 else 1509 n++; 1510 break; 1511 case FcVStackRange: 1512 if (vstack->u.range.begin <= vstack->u.range.end) 1513 { 1514 for (i = vstack->u.range.begin; i <= vstack->u.range.end; i++) 1515 { 1516 if (!FcCharSetAddChar (charset, i)) 1517 { 1518 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i); 1519 } 1520 else 1521 n++; 1522 } 1523 } 1524 break; 1525 default: 1526 FcConfigMessage (parse, FcSevereError, "invalid element in charset"); 1527 break; 1528 } 1529 FcVStackPopAndDestroy (parse); 1530 } 1531 if (n > 0) 1532 FcVStackPushCharSet (parse, charset); 1533 else 1534 FcCharSetDestroy (charset); 1535} 1536 1537static void 1538FcParseLangSet (FcConfigParse *parse) 1539{ 1540 FcVStack *vstack; 1541 FcLangSet *langset = FcLangSetCreate (); 1542 int n = 0; 1543 1544 while ((vstack = FcVStackPeek (parse))) 1545 { 1546 switch ((int) vstack->tag) { 1547 case FcVStackString: 1548 if (!FcLangSetAdd (langset, vstack->u.string)) 1549 { 1550 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string); 1551 } 1552 else 1553 n++; 1554 break; 1555 default: 1556 FcConfigMessage (parse, FcSevereError, "invalid element in langset"); 1557 break; 1558 } 1559 FcVStackPopAndDestroy (parse); 1560 } 1561 if (n > 0) 1562 FcVStackPushLangSet (parse, langset); 1563 else 1564 FcLangSetDestroy (langset); 1565} 1566 1567static FcBool 1568FcConfigLexBinding (FcConfigParse *parse, 1569 const FcChar8 *binding_string, 1570 FcValueBinding *binding_ret) 1571{ 1572 FcValueBinding binding; 1573 1574 if (!binding_string) 1575 binding = FcValueBindingWeak; 1576 else 1577 { 1578 if (!strcmp ((char *) binding_string, "weak")) 1579 binding = FcValueBindingWeak; 1580 else if (!strcmp ((char *) binding_string, "strong")) 1581 binding = FcValueBindingStrong; 1582 else if (!strcmp ((char *) binding_string, "same")) 1583 binding = FcValueBindingSame; 1584 else 1585 { 1586 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string); 1587 return FcFalse; 1588 } 1589 } 1590 *binding_ret = binding; 1591 return FcTrue; 1592} 1593 1594static void 1595FcParseFamilies (FcConfigParse *parse, FcVStackTag tag) 1596{ 1597 FcVStack *vstack; 1598 FcExpr *left, *expr = 0, *new; 1599 1600 while ((vstack = FcVStackPeek (parse))) 1601 { 1602 if (vstack->tag != FcVStackFamily) 1603 { 1604 FcConfigMessage (parse, FcSevereWarning, "non-family"); 1605 FcVStackPopAndDestroy (parse); 1606 continue; 1607 } 1608 left = vstack->u.expr; 1609 vstack->tag = FcVStackNone; 1610 FcVStackPopAndDestroy (parse); 1611 if (expr) 1612 { 1613 new = FcExprCreateOp (parse->config, left, FcOpComma, expr); 1614 if (!new) 1615 { 1616 FcConfigMessage (parse, FcSevereError, "out of memory"); 1617 FcExprDestroy (left); 1618 FcExprDestroy (expr); 1619 break; 1620 } 1621 expr = new; 1622 } 1623 else 1624 expr = left; 1625 } 1626 if (expr) 1627 { 1628 if (!FcVStackPushExpr (parse, tag, expr)) 1629 { 1630 FcConfigMessage (parse, FcSevereError, "out of memory"); 1631 FcExprDestroy (expr); 1632 } 1633 } 1634} 1635 1636static void 1637FcParseFamily (FcConfigParse *parse) 1638{ 1639 FcChar8 *s; 1640 FcExpr *expr; 1641 1642 if (!parse->pstack) 1643 return; 1644 s = FcStrBufDoneStatic (&parse->pstack->str); 1645 if (!s) 1646 { 1647 FcConfigMessage (parse, FcSevereError, "out of memory"); 1648 return; 1649 } 1650 expr = FcExprCreateString (parse->config, s); 1651 FcStrBufDestroy (&parse->pstack->str); 1652 if (expr) 1653 FcVStackPushExpr (parse, FcVStackFamily, expr); 1654} 1655 1656static void 1657FcParseAlias (FcConfigParse *parse) 1658{ 1659 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0; 1660 FcEdit *edit = 0, *next; 1661 FcVStack *vstack; 1662 FcTest *test = NULL; 1663 FcValueBinding binding; 1664 1665 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) 1666 return; 1667 while ((vstack = FcVStackPeek (parse))) 1668 { 1669 switch ((int) vstack->tag) { 1670 case FcVStackFamily: 1671 if (family) 1672 { 1673 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected"); 1674 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family); 1675 if (!new) 1676 FcConfigMessage (parse, FcSevereError, "out of memory"); 1677 else 1678 family = new; 1679 } 1680 else 1681 new = vstack->u.expr; 1682 if (new) 1683 { 1684 family = new; 1685 vstack->tag = FcVStackNone; 1686 } 1687 break; 1688 case FcVStackPrefer: 1689 if (prefer) 1690 FcExprDestroy (prefer); 1691 prefer = vstack->u.expr; 1692 vstack->tag = FcVStackNone; 1693 break; 1694 case FcVStackAccept: 1695 if (accept) 1696 FcExprDestroy (accept); 1697 accept = vstack->u.expr; 1698 vstack->tag = FcVStackNone; 1699 break; 1700 case FcVStackDefault: 1701 if (def) 1702 FcExprDestroy (def); 1703 def = vstack->u.expr; 1704 vstack->tag = FcVStackNone; 1705 break; 1706 case FcVStackTest: 1707 vstack->u.test->next = test; 1708 test = vstack->u.test; 1709 vstack->tag = FcVStackNone; 1710 break; 1711 default: 1712 FcConfigMessage (parse, FcSevereWarning, "bad alias"); 1713 break; 1714 } 1715 FcVStackPopAndDestroy (parse); 1716 } 1717 if (!family) 1718 { 1719 FcConfigMessage (parse, FcSevereError, "missing family in alias"); 1720 if (prefer) 1721 FcExprDestroy (prefer); 1722 if (accept) 1723 FcExprDestroy (accept); 1724 if (def) 1725 FcExprDestroy (def); 1726 return; 1727 } 1728 if (prefer) 1729 { 1730 edit = FcEditCreate (parse, 1731 FC_FAMILY_OBJECT, 1732 FcOpPrepend, 1733 prefer, 1734 binding); 1735 if (edit) 1736 edit->next = 0; 1737 else 1738 FcExprDestroy (prefer); 1739 } 1740 if (accept) 1741 { 1742 next = edit; 1743 edit = FcEditCreate (parse, 1744 FC_FAMILY_OBJECT, 1745 FcOpAppend, 1746 accept, 1747 binding); 1748 if (edit) 1749 edit->next = next; 1750 else 1751 FcExprDestroy (accept); 1752 } 1753 if (def) 1754 { 1755 next = edit; 1756 edit = FcEditCreate (parse, 1757 FC_FAMILY_OBJECT, 1758 FcOpAppendLast, 1759 def, 1760 binding); 1761 if (edit) 1762 edit->next = next; 1763 else 1764 FcExprDestroy (def); 1765 } 1766 if (edit) 1767 { 1768 FcTest *t = FcTestCreate (parse, FcMatchPattern, 1769 FcQualAny, 1770 (FcChar8 *) FC_FAMILY, 1771 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks), 1772 family); 1773 if (test) 1774 { 1775 FcTest *p = test; 1776 1777 while (p->next) 1778 p = p->next; 1779 p->next = t; 1780 } 1781 else 1782 test = t; 1783 if (test) 1784 if (!FcConfigAddEdit (parse->config, test, edit, FcMatchPattern)) 1785 FcTestDestroy (test); 1786 } 1787 else 1788 FcExprDestroy (family); 1789} 1790 1791static FcExpr * 1792FcPopExpr (FcConfigParse *parse) 1793{ 1794 FcVStack *vstack = FcVStackPeek (parse); 1795 FcExpr *expr = 0; 1796 if (!vstack) 1797 return 0; 1798 switch ((int) vstack->tag) { 1799 case FcVStackNone: 1800 break; 1801 case FcVStackString: 1802 case FcVStackFamily: 1803 expr = FcExprCreateString (parse->config, vstack->u.string); 1804 break; 1805 case FcVStackName: 1806 expr = FcExprCreateName (parse->config, vstack->u.name); 1807 break; 1808 case FcVStackConstant: 1809 expr = FcExprCreateConst (parse->config, vstack->u.string); 1810 break; 1811 case FcVStackGlob: 1812 /* XXX: What's the correct action here? (CDW) */ 1813 break; 1814 case FcVStackPrefer: 1815 case FcVStackAccept: 1816 case FcVStackDefault: 1817 expr = vstack->u.expr; 1818 vstack->tag = FcVStackNone; 1819 break; 1820 case FcVStackInteger: 1821 expr = FcExprCreateInteger (parse->config, vstack->u.integer); 1822 break; 1823 case FcVStackDouble: 1824 expr = FcExprCreateDouble (parse->config, vstack->u._double); 1825 break; 1826 case FcVStackMatrix: 1827 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix); 1828 break; 1829 case FcVStackRange: 1830 break; 1831 case FcVStackBool: 1832 expr = FcExprCreateBool (parse->config, vstack->u.bool_); 1833 break; 1834 case FcVStackCharSet: 1835 expr = FcExprCreateCharSet (parse->config, vstack->u.charset); 1836 break; 1837 case FcVStackLangSet: 1838 expr = FcExprCreateLangSet (parse->config, vstack->u.langset); 1839 break; 1840 case FcVStackTest: 1841 break; 1842 case FcVStackExpr: 1843 expr = vstack->u.expr; 1844 vstack->tag = FcVStackNone; 1845 break; 1846 case FcVStackEdit: 1847 break; 1848 default: 1849 break; 1850 } 1851 FcVStackPopAndDestroy (parse); 1852 return expr; 1853} 1854 1855/* 1856 * This builds a tree of binary operations. Note 1857 * that every operator is defined so that if only 1858 * a single operand is contained, the value of the 1859 * whole expression is the value of the operand. 1860 * 1861 * This code reduces in that case to returning that 1862 * operand. 1863 */ 1864static FcExpr * 1865FcPopBinary (FcConfigParse *parse, FcOp op) 1866{ 1867 FcExpr *left, *expr = 0, *new; 1868 1869 while ((left = FcPopExpr (parse))) 1870 { 1871 if (expr) 1872 { 1873 new = FcExprCreateOp (parse->config, left, op, expr); 1874 if (!new) 1875 { 1876 FcConfigMessage (parse, FcSevereError, "out of memory"); 1877 FcExprDestroy (left); 1878 FcExprDestroy (expr); 1879 return 0; 1880 } 1881 expr = new; 1882 } 1883 else 1884 expr = left; 1885 } 1886 return expr; 1887} 1888 1889static void 1890FcParseBinary (FcConfigParse *parse, FcOp op) 1891{ 1892 FcExpr *expr = FcPopBinary (parse, op); 1893 if (expr) 1894 FcVStackPushExpr (parse, FcVStackExpr, expr); 1895} 1896 1897/* 1898 * This builds a a unary operator, it consumes only 1899 * a single operand 1900 */ 1901 1902static FcExpr * 1903FcPopUnary (FcConfigParse *parse, FcOp op) 1904{ 1905 FcExpr *operand, *new = 0; 1906 1907 if ((operand = FcPopExpr (parse))) 1908 { 1909 new = FcExprCreateOp (parse->config, operand, op, 0); 1910 if (!new) 1911 { 1912 FcExprDestroy (operand); 1913 FcConfigMessage (parse, FcSevereError, "out of memory"); 1914 } 1915 } 1916 return new; 1917} 1918 1919static void 1920FcParseUnary (FcConfigParse *parse, FcOp op) 1921{ 1922 FcExpr *expr = FcPopUnary (parse, op); 1923 if (expr) 1924 FcVStackPushExpr (parse, FcVStackExpr, expr); 1925} 1926 1927static void 1928FcParseDir (FcConfigParse *parse) 1929{ 1930 const FcChar8 *attr, *data; 1931 FcChar8 *prefix = NULL, *p; 1932#ifdef _WIN32 1933 FcChar8 buffer[1000]; 1934#endif 1935 1936 attr = FcConfigGetAttribute (parse, "prefix"); 1937 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) 1938 prefix = FcConfigXdgDataHome (); 1939 data = FcStrBufDoneStatic (&parse->pstack->str); 1940 if (!data) 1941 { 1942 FcConfigMessage (parse, FcSevereError, "out of memory"); 1943 data = prefix; 1944 goto bail; 1945 } 1946 if (prefix) 1947 { 1948 size_t plen = strlen ((const char *)prefix); 1949 size_t dlen = strlen ((const char *)data); 1950 1951 p = realloc (prefix, plen + 1 + dlen + 1); 1952 if (!p) 1953 { 1954 FcConfigMessage (parse, FcSevereError, "out of memory"); 1955 goto bail; 1956 } 1957 prefix = p; 1958 prefix[plen] = FC_DIR_SEPARATOR; 1959 memcpy (&prefix[plen + 1], data, dlen); 1960 prefix[plen + 1 + dlen] = 0; 1961 data = prefix; 1962 } 1963#ifdef _WIN32 1964 if (strcmp ((const char *) data, "CUSTOMFONTDIR") == 0) 1965 { 1966 FcChar8 *p; 1967 data = buffer; 1968 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20)) 1969 { 1970 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); 1971 goto bail; 1972 } 1973 /* 1974 * Must use the multi-byte aware function to search 1975 * for backslash because East Asian double-byte code 1976 * pages have characters with backslash as the second 1977 * byte. 1978 */ 1979 p = _mbsrchr (data, '\\'); 1980 if (p) *p = '\0'; 1981 strcat ((char *) data, "\\fonts"); 1982 } 1983 else if (strcmp ((const char *) data, "APPSHAREFONTDIR") == 0) 1984 { 1985 FcChar8 *p; 1986 data = buffer; 1987 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20)) 1988 { 1989 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed"); 1990 goto bail; 1991 } 1992 p = _mbsrchr (data, '\\'); 1993 if (p) *p = '\0'; 1994 strcat ((char *) data, "\\..\\share\\fonts"); 1995 } 1996 else if (strcmp ((const char *) data, "WINDOWSFONTDIR") == 0) 1997 { 1998 int rc; 1999 data = buffer; 2000 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20); 2001 if (rc == 0 || rc > sizeof (buffer) - 20) 2002 { 2003 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed"); 2004 goto bail; 2005 } 2006 if (data [strlen ((const char *) data) - 1] != '\\') 2007 strcat ((char *) data, "\\"); 2008 strcat ((char *) data, "fonts"); 2009 } 2010#endif 2011 if (strlen ((char *) data) == 0) 2012 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored"); 2013 else if (!FcStrUsesHome (data) || FcConfigHome ()) 2014 { 2015 if (!FcConfigAddDir (parse->config, data)) 2016 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", data); 2017 } 2018 FcStrBufDestroy (&parse->pstack->str); 2019 2020 bail: 2021 if (prefix) 2022 FcStrFree (prefix); 2023} 2024 2025static void 2026FcParseCacheDir (FcConfigParse *parse) 2027{ 2028 const FcChar8 *attr; 2029 FcChar8 *prefix = NULL, *p, *data; 2030 2031 attr = FcConfigGetAttribute (parse, "prefix"); 2032 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) 2033 prefix = FcConfigXdgCacheHome (); 2034 data = FcStrBufDone (&parse->pstack->str); 2035 if (!data) 2036 { 2037 FcConfigMessage (parse, FcSevereError, "out of memory"); 2038 goto bail; 2039 } 2040 if (prefix) 2041 { 2042 size_t plen = strlen ((const char *)prefix); 2043 size_t dlen = strlen ((const char *)data); 2044 2045 p = realloc (prefix, plen + 1 + dlen + 1); 2046 if (!p) 2047 { 2048 FcConfigMessage (parse, FcSevereError, "out of memory"); 2049 data = prefix; 2050 goto bail; 2051 } 2052 prefix = p; 2053 prefix[plen] = FC_DIR_SEPARATOR; 2054 memcpy (&prefix[plen + 1], data, dlen); 2055 prefix[plen + 1 + dlen] = 0; 2056 FcStrFree (data); 2057 data = prefix; 2058 } 2059#ifdef _WIN32 2060 if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) 2061 { 2062 int rc; 2063 FcStrFree (data); 2064 data = malloc (1000); 2065 if (!data) 2066 { 2067 FcConfigMessage (parse, FcSevereError, "out of memory"); 2068 goto bail; 2069 } 2070 rc = GetTempPath (800, (LPSTR) data); 2071 if (rc == 0 || rc > 800) 2072 { 2073 FcConfigMessage (parse, FcSevereError, "GetTempPath failed"); 2074 goto bail; 2075 } 2076 if (data [strlen ((const char *) data) - 1] != '\\') 2077 strcat ((char *) data, "\\"); 2078 strcat ((char *) data, "fontconfig\\cache"); 2079 } 2080 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0) 2081 { 2082 char szFPath[MAX_PATH + 1]; 2083 size_t len; 2084 2085 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath)))) 2086 { 2087 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed"); 2088 goto bail; 2089 } 2090 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath)); 2091 len = strlen(szFPath) + 1; 2092 FcStrFree (data); 2093 data = malloc(len); 2094 if (!data) 2095 { 2096 FcConfigMessage (parse, FcSevereError, "out of memory"); 2097 goto bail; 2098 } 2099 strncpy((char *) data, szFPath, len); 2100 } 2101#endif 2102 if (strlen ((char *) data) == 0) 2103 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored"); 2104 else if (!FcStrUsesHome (data) || FcConfigHome ()) 2105 { 2106 if (!FcConfigAddCacheDir (parse->config, data)) 2107 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data); 2108 } 2109 FcStrBufDestroy (&parse->pstack->str); 2110 2111 bail: 2112 if (data) 2113 FcStrFree (data); 2114} 2115 2116static void 2117FcParseInclude (FcConfigParse *parse) 2118{ 2119 FcChar8 *s; 2120 const FcChar8 *attr; 2121 FcBool ignore_missing = FcFalse; 2122 FcBool deprecated = FcFalse; 2123 FcChar8 *prefix = NULL, *p; 2124 2125 s = FcStrBufDoneStatic (&parse->pstack->str); 2126 if (!s) 2127 { 2128 FcConfigMessage (parse, FcSevereError, "out of memory"); 2129 goto bail; 2130 } 2131 attr = FcConfigGetAttribute (parse, "ignore_missing"); 2132 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue) 2133 ignore_missing = FcTrue; 2134 attr = FcConfigGetAttribute (parse, "deprecated"); 2135 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue) 2136 deprecated = FcTrue; 2137 attr = FcConfigGetAttribute (parse, "prefix"); 2138 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) 2139 prefix = FcConfigXdgConfigHome (); 2140 if (prefix) 2141 { 2142 size_t plen = strlen ((const char *)prefix); 2143 size_t dlen = strlen ((const char *)s); 2144 2145 p = realloc (prefix, plen + 1 + dlen + 1); 2146 if (!p) 2147 { 2148 FcConfigMessage (parse, FcSevereError, "out of memory"); 2149 goto bail; 2150 } 2151 prefix = p; 2152 prefix[plen] = FC_DIR_SEPARATOR; 2153 memcpy (&prefix[plen + 1], s, dlen); 2154 prefix[plen + 1 + dlen] = 0; 2155 s = prefix; 2156 } 2157 if (!FcConfigParseAndLoad (parse->config, s, !ignore_missing)) 2158 parse->error = FcTrue; 2159 else 2160 { 2161 FcChar8 *filename; 2162 2163 filename = FcConfigFilename(s); 2164 if (deprecated == FcTrue && 2165 filename != NULL && 2166 !FcFileIsLink (filename)) 2167 { 2168 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated.", s); 2169 } 2170 if(filename) 2171 FcStrFree(filename); 2172 } 2173 FcStrBufDestroy (&parse->pstack->str); 2174 2175 bail: 2176 if (prefix) 2177 FcStrFree (prefix); 2178} 2179 2180typedef struct _FcOpMap { 2181 char name[16]; 2182 FcOp op; 2183} FcOpMap; 2184 2185static FcOp 2186FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap) 2187{ 2188 int i; 2189 2190 for (i = 0; i < nmap; i++) 2191 if (!strcmp ((char *) op, map[i].name)) 2192 return map[i].op; 2193 return FcOpInvalid; 2194} 2195 2196static const FcOpMap fcCompareOps[] = { 2197 { "eq", FcOpEqual }, 2198 { "not_eq", FcOpNotEqual }, 2199 { "less", FcOpLess }, 2200 { "less_eq", FcOpLessEqual }, 2201 { "more", FcOpMore }, 2202 { "more_eq", FcOpMoreEqual }, 2203 { "contains", FcOpContains }, 2204 { "not_contains", FcOpNotContains } 2205}; 2206 2207#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0]) 2208 2209static FcOp 2210FcConfigLexCompare (const FcChar8 *compare) 2211{ 2212 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS); 2213} 2214 2215static void 2216FcParseTest (FcConfigParse *parse) 2217{ 2218 const FcChar8 *kind_string; 2219 FcMatchKind kind; 2220 const FcChar8 *qual_string; 2221 FcQual qual; 2222 const FcChar8 *name; 2223 const FcChar8 *compare_string; 2224 FcOp compare; 2225 FcExpr *expr; 2226 FcTest *test; 2227 const FcChar8 *iblanks_string; 2228 int flags = 0; 2229 2230 kind_string = FcConfigGetAttribute (parse, "target"); 2231 if (!kind_string) 2232 kind = FcMatchDefault; 2233 else 2234 { 2235 if (!strcmp ((char *) kind_string, "pattern")) 2236 kind = FcMatchPattern; 2237 else if (!strcmp ((char *) kind_string, "font")) 2238 kind = FcMatchFont; 2239 else if (!strcmp ((char *) kind_string, "scan")) 2240 kind = FcMatchScan; 2241 else if (!strcmp ((char *) kind_string, "default")) 2242 kind = FcMatchDefault; 2243 else 2244 { 2245 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string); 2246 return; 2247 } 2248 } 2249 qual_string = FcConfigGetAttribute (parse, "qual"); 2250 if (!qual_string) 2251 qual = FcQualAny; 2252 else 2253 { 2254 if (!strcmp ((char *) qual_string, "any")) 2255 qual = FcQualAny; 2256 else if (!strcmp ((char *) qual_string, "all")) 2257 qual = FcQualAll; 2258 else if (!strcmp ((char *) qual_string, "first")) 2259 qual = FcQualFirst; 2260 else if (!strcmp ((char *) qual_string, "not_first")) 2261 qual = FcQualNotFirst; 2262 else 2263 { 2264 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string); 2265 return; 2266 } 2267 } 2268 name = FcConfigGetAttribute (parse, "name"); 2269 if (!name) 2270 { 2271 FcConfigMessage (parse, FcSevereWarning, "missing test name"); 2272 return; 2273 } 2274 compare_string = FcConfigGetAttribute (parse, "compare"); 2275 if (!compare_string) 2276 compare = FcOpEqual; 2277 else 2278 { 2279 compare = FcConfigLexCompare (compare_string); 2280 if (compare == FcOpInvalid) 2281 { 2282 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string); 2283 return; 2284 } 2285 } 2286 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks"); 2287 if (iblanks_string) 2288 { 2289 FcBool f = FcFalse; 2290 2291 if (!FcNameBool (iblanks_string, &f)) 2292 { 2293 FcConfigMessage (parse, 2294 FcSevereWarning, 2295 "invalid test ignore-blanks \"%s\"", iblanks_string); 2296 } 2297 if (f) 2298 flags |= FcOpFlagIgnoreBlanks; 2299 } 2300 expr = FcPopBinary (parse, FcOpComma); 2301 if (!expr) 2302 { 2303 FcConfigMessage (parse, FcSevereWarning, "missing test expression"); 2304 return; 2305 } 2306 if (expr->op == FcOpComma) 2307 { 2308 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected"); 2309 } 2310 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr); 2311 if (!test) 2312 { 2313 FcConfigMessage (parse, FcSevereError, "out of memory"); 2314 return; 2315 } 2316 FcVStackPushTest (parse, test); 2317} 2318 2319static const FcOpMap fcModeOps[] = { 2320 { "assign", FcOpAssign }, 2321 { "assign_replace", FcOpAssignReplace }, 2322 { "prepend", FcOpPrepend }, 2323 { "prepend_first", FcOpPrependFirst }, 2324 { "append", FcOpAppend }, 2325 { "append_last", FcOpAppendLast }, 2326 { "delete", FcOpDelete }, 2327 { "delete_all", FcOpDeleteAll }, 2328}; 2329 2330#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0]) 2331 2332static FcOp 2333FcConfigLexMode (const FcChar8 *mode) 2334{ 2335 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS); 2336} 2337 2338static void 2339FcParseEdit (FcConfigParse *parse) 2340{ 2341 const FcChar8 *name; 2342 const FcChar8 *mode_string; 2343 FcOp mode; 2344 FcValueBinding binding; 2345 FcExpr *expr; 2346 FcEdit *edit; 2347 2348 name = FcConfigGetAttribute (parse, "name"); 2349 if (!name) 2350 { 2351 FcConfigMessage (parse, FcSevereWarning, "missing edit name"); 2352 return; 2353 } 2354 mode_string = FcConfigGetAttribute (parse, "mode"); 2355 if (!mode_string) 2356 mode = FcOpAssign; 2357 else 2358 { 2359 mode = FcConfigLexMode (mode_string); 2360 if (mode == FcOpInvalid) 2361 { 2362 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string); 2363 return; 2364 } 2365 } 2366 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding)) 2367 return; 2368 2369 expr = FcPopBinary (parse, FcOpComma); 2370 if ((mode == FcOpDelete || mode == FcOpDeleteAll) && 2371 expr != NULL) 2372 { 2373 FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all"); 2374 FcExprDestroy (expr); 2375 expr = NULL; 2376 } 2377 edit = FcEditCreate (parse, FcObjectFromName ((char *) name), 2378 mode, expr, binding); 2379 if (!edit) 2380 { 2381 FcConfigMessage (parse, FcSevereError, "out of memory"); 2382 FcExprDestroy (expr); 2383 return; 2384 } 2385 if (!FcVStackPushEdit (parse, edit)) 2386 FcEditDestroy (edit); 2387} 2388 2389typedef struct FcSubstStack { 2390 FcTest *test; 2391 FcEdit *edit; 2392} FcSubstStack; 2393 2394static void 2395FcParseMatch (FcConfigParse *parse) 2396{ 2397 const FcChar8 *kind_name; 2398 FcMatchKind kind; 2399 FcTest *test = 0; 2400 FcEdit *edit = 0; 2401 FcVStack *vstack; 2402 FcBool tested = FcFalse; 2403 FcSubstStack *sstack = NULL; 2404 int len, pos = 0; 2405 2406 kind_name = FcConfigGetAttribute (parse, "target"); 2407 if (!kind_name) 2408 kind = FcMatchPattern; 2409 else 2410 { 2411 if (!strcmp ((char *) kind_name, "pattern")) 2412 kind = FcMatchPattern; 2413 else if (!strcmp ((char *) kind_name, "font")) 2414 kind = FcMatchFont; 2415 else if (!strcmp ((char *) kind_name, "scan")) 2416 kind = FcMatchScan; 2417 else 2418 { 2419 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name); 2420 return; 2421 } 2422 } 2423 len = FcVStackElements(parse); 2424 if (len > 0) 2425 { 2426 sstack = malloc (sizeof (FcSubstStack) * (len + 1)); 2427 if (!sstack) 2428 { 2429 FcConfigMessage (parse, FcSevereError, "out of memory"); 2430 return; 2431 } 2432 } 2433 while ((vstack = FcVStackPeek (parse))) 2434 { 2435 switch ((int) vstack->tag) { 2436 case FcVStackTest: 2437 vstack->u.test->next = test; 2438 test = vstack->u.test; 2439 vstack->tag = FcVStackNone; 2440 tested = FcTrue; 2441 break; 2442 case FcVStackEdit: 2443 /* due to the reverse traversal, <edit> node appears faster than 2444 * <test> node if any. so we have to deal with it here rather than 2445 * the above in FcVStackTest, and put recipes in reverse order. 2446 */ 2447 if (tested) 2448 { 2449 sstack[pos].test = test; 2450 sstack[pos].edit = edit; 2451 pos++; 2452 test = NULL; 2453 edit = NULL; 2454 tested = FcFalse; 2455 } 2456 vstack->u.edit->next = edit; 2457 edit = vstack->u.edit; 2458 vstack->tag = FcVStackNone; 2459 if (kind == FcMatchScan && edit->object > FC_MAX_BASE_OBJECT) 2460 { 2461 FcConfigMessage (parse, FcSevereError, 2462 "<match target=\"scan\"> cannot edit user-defined object \"%s\"", 2463 FcObjectName(edit->object)); 2464 } 2465 break; 2466 default: 2467 FcConfigMessage (parse, FcSevereWarning, "invalid match element"); 2468 break; 2469 } 2470 FcVStackPopAndDestroy (parse); 2471 } 2472 if (!FcConfigAddEdit (parse->config, test, edit, kind)) 2473 FcConfigMessage (parse, FcSevereError, "out of memory"); 2474 if (sstack) 2475 { 2476 int i; 2477 2478 for (i = 0; i < pos; i++) 2479 { 2480 if (!FcConfigAddEdit (parse->config, sstack[pos - i - 1].test, sstack[pos - i - 1].edit, kind)) 2481 { 2482 FcConfigMessage (parse, FcSevereError, "out of memory"); 2483 return; 2484 } 2485 } 2486 free (sstack); 2487 } 2488} 2489 2490static void 2491FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element) 2492{ 2493 FcVStack *vstack; 2494 2495 while ((vstack = FcVStackPeek (parse))) 2496 { 2497 switch ((int) vstack->tag) { 2498 case FcVStackGlob: 2499 if (!FcConfigGlobAdd (parse->config, 2500 vstack->u.string, 2501 element == FcElementAcceptfont)) 2502 { 2503 FcConfigMessage (parse, FcSevereError, "out of memory"); 2504 } 2505 break; 2506 case FcVStackPattern: 2507 if (!FcConfigPatternsAdd (parse->config, 2508 vstack->u.pattern, 2509 element == FcElementAcceptfont)) 2510 { 2511 FcConfigMessage (parse, FcSevereError, "out of memory"); 2512 } 2513 else 2514 vstack->tag = FcVStackNone; 2515 break; 2516 default: 2517 FcConfigMessage (parse, FcSevereWarning, "bad font selector"); 2518 break; 2519 } 2520 FcVStackPopAndDestroy (parse); 2521 } 2522} 2523 2524 2525static FcValue 2526FcPopValue (FcConfigParse *parse) 2527{ 2528 FcVStack *vstack = FcVStackPeek (parse); 2529 FcValue value; 2530 2531 value.type = FcTypeVoid; 2532 2533 if (!vstack) 2534 return value; 2535 2536 switch ((int) vstack->tag) { 2537 case FcVStackString: 2538 value.u.s = FcStrdup (vstack->u.string); 2539 if (value.u.s) 2540 value.type = FcTypeString; 2541 break; 2542 case FcVStackConstant: 2543 if (FcNameConstant (vstack->u.string, &value.u.i)) 2544 value.type = FcTypeInteger; 2545 break; 2546 case FcVStackInteger: 2547 value.u.i = vstack->u.integer; 2548 value.type = FcTypeInteger; 2549 break; 2550 case FcVStackDouble: 2551 value.u.d = vstack->u._double; 2552 value.type = FcTypeDouble; 2553 break; 2554 case FcVStackBool: 2555 value.u.b = vstack->u.bool_; 2556 value.type = FcTypeBool; 2557 break; 2558 case FcVStackCharSet: 2559 value.u.c = FcCharSetCopy (vstack->u.charset); 2560 if (value.u.c) 2561 value.type = FcTypeCharSet; 2562 break; 2563 case FcVStackLangSet: 2564 value.u.l = FcLangSetCopy (vstack->u.langset); 2565 if (value.u.l) 2566 value.type = FcTypeLangSet; 2567 break; 2568 default: 2569 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", 2570 vstack->tag); 2571 break; 2572 } 2573 FcVStackPopAndDestroy (parse); 2574 2575 return value; 2576} 2577 2578static void 2579FcParsePatelt (FcConfigParse *parse) 2580{ 2581 FcValue value; 2582 FcPattern *pattern = FcPatternCreate (); 2583 const char *name; 2584 2585 if (!pattern) 2586 { 2587 FcConfigMessage (parse, FcSevereError, "out of memory"); 2588 return; 2589 } 2590 2591 name = (char *) FcConfigGetAttribute (parse, "name"); 2592 if (!name) 2593 { 2594 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); 2595 FcPatternDestroy (pattern); 2596 return; 2597 } 2598 2599 for (;;) 2600 { 2601 value = FcPopValue (parse); 2602 if (value.type == FcTypeVoid) 2603 break; 2604 if (!FcPatternAdd (pattern, name, value, FcTrue)) 2605 { 2606 FcConfigMessage (parse, FcSevereError, "out of memory"); 2607 FcValueDestroy(value); 2608 break; 2609 } 2610 FcValueDestroy(value); 2611 } 2612 2613 FcVStackPushPattern (parse, pattern); 2614} 2615 2616static void 2617FcParsePattern (FcConfigParse *parse) 2618{ 2619 FcVStack *vstack; 2620 FcPattern *pattern = FcPatternCreate (); 2621 2622 if (!pattern) 2623 { 2624 FcConfigMessage (parse, FcSevereError, "out of memory"); 2625 return; 2626 } 2627 2628 while ((vstack = FcVStackPeek (parse))) 2629 { 2630 switch ((int) vstack->tag) { 2631 case FcVStackPattern: 2632 if (!FcPatternAppend (pattern, vstack->u.pattern)) 2633 { 2634 FcConfigMessage (parse, FcSevereError, "out of memory"); 2635 FcPatternDestroy (pattern); 2636 return; 2637 } 2638 break; 2639 default: 2640 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); 2641 break; 2642 } 2643 FcVStackPopAndDestroy (parse); 2644 } 2645 2646 FcVStackPushPattern (parse, pattern); 2647} 2648 2649static void 2650FcEndElement(void *userData, const XML_Char *name FC_UNUSED) 2651{ 2652 FcConfigParse *parse = userData; 2653 FcChar8 *data; 2654 2655 if (!parse->pstack) 2656 return; 2657 switch (parse->pstack->element) { 2658 case FcElementNone: 2659 break; 2660 case FcElementFontconfig: 2661 break; 2662 case FcElementDir: 2663 FcParseDir (parse); 2664 break; 2665 case FcElementCacheDir: 2666 FcParseCacheDir (parse); 2667 break; 2668 case FcElementCache: 2669 data = FcStrBufDoneStatic (&parse->pstack->str); 2670 if (!data) 2671 { 2672 FcConfigMessage (parse, FcSevereError, "out of memory"); 2673 break; 2674 } 2675 /* discard this data; no longer used */ 2676 FcStrBufDestroy (&parse->pstack->str); 2677 break; 2678 case FcElementInclude: 2679 FcParseInclude (parse); 2680 break; 2681 case FcElementConfig: 2682 break; 2683 case FcElementMatch: 2684 FcParseMatch (parse); 2685 break; 2686 case FcElementAlias: 2687 FcParseAlias (parse); 2688 break; 2689 2690 case FcElementBlank: 2691 FcParseBlank (parse); 2692 break; 2693 case FcElementRescan: 2694 FcParseRescan (parse); 2695 break; 2696 2697 case FcElementPrefer: 2698 FcParseFamilies (parse, FcVStackPrefer); 2699 break; 2700 case FcElementAccept: 2701 FcParseFamilies (parse, FcVStackAccept); 2702 break; 2703 case FcElementDefault: 2704 FcParseFamilies (parse, FcVStackDefault); 2705 break; 2706 case FcElementFamily: 2707 FcParseFamily (parse); 2708 break; 2709 2710 case FcElementTest: 2711 FcParseTest (parse); 2712 break; 2713 case FcElementEdit: 2714 FcParseEdit (parse); 2715 break; 2716 2717 case FcElementInt: 2718 FcParseInt (parse); 2719 break; 2720 case FcElementDouble: 2721 FcParseDouble (parse); 2722 break; 2723 case FcElementString: 2724 FcParseString (parse, FcVStackString); 2725 break; 2726 case FcElementMatrix: 2727 FcParseMatrix (parse); 2728 break; 2729 case FcElementRange: 2730 FcParseRange (parse); 2731 break; 2732 case FcElementBool: 2733 FcParseBool (parse); 2734 break; 2735 case FcElementCharSet: 2736 FcParseCharSet (parse); 2737 break; 2738 case FcElementLangSet: 2739 FcParseLangSet (parse); 2740 break; 2741 case FcElementSelectfont: 2742 break; 2743 case FcElementAcceptfont: 2744 case FcElementRejectfont: 2745 FcParseAcceptRejectFont (parse, parse->pstack->element); 2746 break; 2747 case FcElementGlob: 2748 FcParseString (parse, FcVStackGlob); 2749 break; 2750 case FcElementPattern: 2751 FcParsePattern (parse); 2752 break; 2753 case FcElementPatelt: 2754 FcParsePatelt (parse); 2755 break; 2756 case FcElementName: 2757 FcParseName (parse); 2758 break; 2759 case FcElementConst: 2760 FcParseString (parse, FcVStackConstant); 2761 break; 2762 case FcElementOr: 2763 FcParseBinary (parse, FcOpOr); 2764 break; 2765 case FcElementAnd: 2766 FcParseBinary (parse, FcOpAnd); 2767 break; 2768 case FcElementEq: 2769 FcParseBinary (parse, FcOpEqual); 2770 break; 2771 case FcElementNotEq: 2772 FcParseBinary (parse, FcOpNotEqual); 2773 break; 2774 case FcElementLess: 2775 FcParseBinary (parse, FcOpLess); 2776 break; 2777 case FcElementLessEq: 2778 FcParseBinary (parse, FcOpLessEqual); 2779 break; 2780 case FcElementMore: 2781 FcParseBinary (parse, FcOpMore); 2782 break; 2783 case FcElementMoreEq: 2784 FcParseBinary (parse, FcOpMoreEqual); 2785 break; 2786 case FcElementContains: 2787 FcParseBinary (parse, FcOpContains); 2788 break; 2789 case FcElementNotContains: 2790 FcParseBinary (parse, FcOpNotContains); 2791 break; 2792 case FcElementPlus: 2793 FcParseBinary (parse, FcOpPlus); 2794 break; 2795 case FcElementMinus: 2796 FcParseBinary (parse, FcOpMinus); 2797 break; 2798 case FcElementTimes: 2799 FcParseBinary (parse, FcOpTimes); 2800 break; 2801 case FcElementDivide: 2802 FcParseBinary (parse, FcOpDivide); 2803 break; 2804 case FcElementNot: 2805 FcParseUnary (parse, FcOpNot); 2806 break; 2807 case FcElementIf: 2808 FcParseBinary (parse, FcOpQuest); 2809 break; 2810 case FcElementFloor: 2811 FcParseUnary (parse, FcOpFloor); 2812 break; 2813 case FcElementCeil: 2814 FcParseUnary (parse, FcOpCeil); 2815 break; 2816 case FcElementRound: 2817 FcParseUnary (parse, FcOpRound); 2818 break; 2819 case FcElementTrunc: 2820 FcParseUnary (parse, FcOpTrunc); 2821 break; 2822 case FcElementUnknown: 2823 break; 2824 } 2825 (void) FcPStackPop (parse); 2826} 2827 2828static void 2829FcCharacterData (void *userData, const XML_Char *s, int len) 2830{ 2831 FcConfigParse *parse = userData; 2832 2833 if (!parse->pstack) 2834 return; 2835 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len)) 2836 FcConfigMessage (parse, FcSevereError, "out of memory"); 2837} 2838 2839static void 2840FcStartDoctypeDecl (void *userData, 2841 const XML_Char *doctypeName, 2842 const XML_Char *sysid FC_UNUSED, 2843 const XML_Char *pubid FC_UNUSED, 2844 int has_internal_subset FC_UNUSED) 2845{ 2846 FcConfigParse *parse = userData; 2847 2848 if (strcmp ((char *) doctypeName, "fontconfig") != 0) 2849 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName); 2850} 2851 2852#ifdef ENABLE_LIBXML2 2853 2854static void 2855FcInternalSubsetDecl (void *userData, 2856 const XML_Char *doctypeName, 2857 const XML_Char *sysid, 2858 const XML_Char *pubid) 2859{ 2860 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1); 2861} 2862 2863static void 2864FcExternalSubsetDecl (void *userData, 2865 const XML_Char *doctypeName, 2866 const XML_Char *sysid, 2867 const XML_Char *pubid) 2868{ 2869 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0); 2870} 2871 2872#else /* ENABLE_LIBXML2 */ 2873 2874static void 2875FcEndDoctypeDecl (void *userData FC_UNUSED) 2876{ 2877} 2878 2879#endif /* ENABLE_LIBXML2 */ 2880 2881static int 2882FcSortCmpStr (const void *a, const void *b) 2883{ 2884 const FcChar8 *as = *((FcChar8 **) a); 2885 const FcChar8 *bs = *((FcChar8 **) b); 2886 return FcStrCmp (as, bs); 2887} 2888 2889static FcBool 2890FcConfigParseAndLoadDir (FcConfig *config, 2891 const FcChar8 *name, 2892 const FcChar8 *dir, 2893 FcBool complain) 2894{ 2895 DIR *d; 2896 struct dirent *e; 2897 FcBool ret = FcTrue; 2898 FcChar8 *file; 2899 FcChar8 *base; 2900 FcStrSet *files; 2901 2902 d = opendir ((char *) dir); 2903 if (!d) 2904 { 2905 if (complain) 2906 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"", 2907 name); 2908 ret = FcFalse; 2909 goto bail0; 2910 } 2911 /* freed below */ 2912 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 2913 if (!file) 2914 { 2915 ret = FcFalse; 2916 goto bail1; 2917 } 2918 2919 strcpy ((char *) file, (char *) dir); 2920 strcat ((char *) file, "/"); 2921 base = file + strlen ((char *) file); 2922 2923 files = FcStrSetCreate (); 2924 if (!files) 2925 { 2926 ret = FcFalse; 2927 goto bail2; 2928 } 2929 2930 if (FcDebug () & FC_DBG_CONFIG) 2931 printf ("\tScanning config dir %s\n", dir); 2932 2933 while (ret && (e = readdir (d))) 2934 { 2935 int d_len; 2936#define TAIL ".conf" 2937#define TAIL_LEN 5 2938 /* 2939 * Add all files of the form [0-9]*.conf 2940 */ 2941 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' && 2942 (d_len = strlen (e->d_name)) < FC_MAX_FILE_LEN && 2943 d_len > TAIL_LEN && 2944 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) 2945 { 2946 strcpy ((char *) base, (char *) e->d_name); 2947 if (!FcStrSetAdd (files, file)) 2948 { 2949 ret = FcFalse; 2950 goto bail3; 2951 } 2952 } 2953 } 2954 if (ret) 2955 { 2956 int i; 2957 qsort (files->strs, files->num, sizeof (FcChar8 *), 2958 (int (*)(const void *, const void *)) FcSortCmpStr); 2959 for (i = 0; ret && i < files->num; i++) 2960 ret = FcConfigParseAndLoad (config, files->strs[i], complain); 2961 } 2962bail3: 2963 FcStrSetDestroy (files); 2964bail2: 2965 free (file); 2966bail1: 2967 closedir (d); 2968bail0: 2969 return ret || !complain; 2970} 2971 2972#ifdef _WIN32 2973pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL; 2974pfnSHGetFolderPathA pSHGetFolderPathA = NULL; 2975#endif 2976 2977FcBool 2978FcConfigParseAndLoad (FcConfig *config, 2979 const FcChar8 *name, 2980 FcBool complain) 2981{ 2982 2983 XML_Parser p; 2984 FcChar8 *filename; 2985 int fd; 2986 int len; 2987 FcConfigParse parse; 2988 FcBool error = FcTrue; 2989 2990#ifdef ENABLE_LIBXML2 2991 xmlSAXHandler sax; 2992 char buf[BUFSIZ]; 2993#else 2994 void *buf; 2995#endif 2996 2997#ifdef _WIN32 2998 if (!pGetSystemWindowsDirectory) 2999 { 3000 HMODULE hk32 = GetModuleHandleA("kernel32.dll"); 3001 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetProcAddress(hk32, "GetSystemWindowsDirectoryA"))) 3002 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory) GetWindowsDirectory; 3003 } 3004 if (!pSHGetFolderPathA) 3005 { 3006 HMODULE hSh = LoadLibraryA("shfolder.dll"); 3007 /* the check is done later, because there is no provided fallback */ 3008 if (hSh) 3009 pSHGetFolderPathA = (pfnSHGetFolderPathA) GetProcAddress(hSh, "SHGetFolderPathA"); 3010 } 3011#endif 3012 3013 filename = FcConfigFilename (name); 3014 if (!filename) 3015 goto bail0; 3016 3017 if (FcStrSetMember (config->configFiles, filename)) 3018 { 3019 FcStrFree (filename); 3020 return FcTrue; 3021 } 3022 3023 if (!FcStrSetAdd (config->configFiles, filename)) 3024 { 3025 FcStrFree (filename); 3026 goto bail0; 3027 } 3028 3029 if (FcFileIsDir (filename)) 3030 { 3031 FcBool ret = FcConfigParseAndLoadDir (config, name, filename, complain); 3032 FcStrFree (filename); 3033 return ret; 3034 } 3035 3036 if (FcDebug () & FC_DBG_CONFIG) 3037 printf ("\tLoading config file %s\n", filename); 3038 3039 fd = FcOpen ((char *) filename, O_RDONLY); 3040 if (fd == -1) { 3041 FcStrFree (filename); 3042 goto bail0; 3043 } 3044 3045#ifdef ENABLE_LIBXML2 3046 memset(&sax, 0, sizeof(sax)); 3047 3048 sax.internalSubset = FcInternalSubsetDecl; 3049 sax.externalSubset = FcExternalSubsetDecl; 3050 sax.startElement = FcStartElement; 3051 sax.endElement = FcEndElement; 3052 sax.characters = FcCharacterData; 3053 3054 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename); 3055#else 3056 p = XML_ParserCreate ("UTF-8"); 3057#endif 3058 FcStrFree (filename); 3059 3060 if (!p) 3061 goto bail1; 3062 3063 if (!FcConfigParseInit (&parse, name, config, p)) 3064 goto bail2; 3065 3066#ifndef ENABLE_LIBXML2 3067 3068 XML_SetUserData (p, &parse); 3069 3070 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); 3071 XML_SetElementHandler (p, FcStartElement, FcEndElement); 3072 XML_SetCharacterDataHandler (p, FcCharacterData); 3073 3074#endif /* ENABLE_LIBXML2 */ 3075 3076 do { 3077#ifndef ENABLE_LIBXML2 3078 buf = XML_GetBuffer (p, BUFSIZ); 3079 if (!buf) 3080 { 3081 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer"); 3082 goto bail3; 3083 } 3084#endif 3085 len = read (fd, buf, BUFSIZ); 3086 if (len < 0) 3087 { 3088 FcConfigMessage (&parse, FcSevereError, "failed reading config file"); 3089 goto bail3; 3090 } 3091 3092#ifdef ENABLE_LIBXML2 3093 if (xmlParseChunk (p, buf, len, len == 0)) 3094#else 3095 if (!XML_ParseBuffer (p, len, len == 0)) 3096#endif 3097 { 3098 FcConfigMessage (&parse, FcSevereError, "%s", 3099 XML_ErrorString (XML_GetErrorCode (p))); 3100 goto bail3; 3101 } 3102 } while (len != 0); 3103 error = parse.error; 3104bail3: 3105 FcConfigCleanup (&parse); 3106bail2: 3107 XML_ParserFree (p); 3108bail1: 3109 close (fd); 3110 fd = -1; 3111bail0: 3112 if (error && complain) 3113 { 3114 if (name) 3115 FcConfigMessage (0, FcSevereError, "Cannot load config file \"%s\"", name); 3116 else 3117 FcConfigMessage (0, FcSevereError, "Cannot load default config file"); 3118 return FcFalse; 3119 } 3120 return FcTrue; 3121} 3122#define __fcxml__ 3123#include "fcaliastail.h" 3124#undef __fcxml__ 3125