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