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