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