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