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 if (FcStrUsesHome(vstack->u.string) && FcConfigHome() == NULL) 2964 FcConfigMessage (parse, FcSevereWarning, "Home is disabled"); 2965 else 2966 FcConfigMessage (parse, FcSevereError, "out of memory"); 2967 } 2968 else 2969 { 2970 if (parse->scanOnly && vstack->u.string) 2971 { 2972 FcStrFree (vstack->u.string); 2973 vstack->tag = FcVStackNone; 2974 } 2975 } 2976 break; 2977 case FcVStackPattern: 2978 if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config, 2979 vstack->u.pattern, 2980 element == FcElementAcceptfont)) 2981 { 2982 FcConfigMessage (parse, FcSevereError, "out of memory"); 2983 } 2984 else 2985 { 2986 if (parse->scanOnly && vstack->u.pattern) 2987 FcPatternDestroy (vstack->u.pattern); 2988 vstack->tag = FcVStackNone; 2989 } 2990 break; 2991 default: 2992 FcConfigMessage (parse, FcSevereWarning, "bad font selector"); 2993 break; 2994 } 2995 FcVStackPopAndDestroy (parse); 2996 } 2997} 2998 2999 3000static FcValue 3001FcPopValue (FcConfigParse *parse) 3002{ 3003 FcVStack *vstack = FcVStackPeek (parse); 3004 FcValue value; 3005 3006 value.type = FcTypeVoid; 3007 3008 if (!vstack) 3009 return value; 3010 3011 switch ((int) vstack->tag) { 3012 case FcVStackString: 3013 value.u.s = FcStrdup (vstack->u.string); 3014 if (value.u.s) 3015 value.type = FcTypeString; 3016 break; 3017 case FcVStackConstant: 3018 if (FcNameConstant (vstack->u.string, &value.u.i)) 3019 value.type = FcTypeInteger; 3020 break; 3021 case FcVStackInteger: 3022 value.u.i = vstack->u.integer; 3023 value.type = FcTypeInteger; 3024 break; 3025 case FcVStackDouble: 3026 value.u.d = vstack->u._double; 3027 value.type = FcTypeDouble; 3028 break; 3029 case FcVStackBool: 3030 value.u.b = vstack->u.bool_; 3031 value.type = FcTypeBool; 3032 break; 3033 case FcVStackCharSet: 3034 value.u.c = FcCharSetCopy (vstack->u.charset); 3035 if (value.u.c) 3036 value.type = FcTypeCharSet; 3037 break; 3038 case FcVStackLangSet: 3039 value.u.l = FcLangSetCopy (vstack->u.langset); 3040 if (value.u.l) 3041 value.type = FcTypeLangSet; 3042 break; 3043 case FcVStackRange: 3044 value.u.r = FcRangeCopy (vstack->u.range); 3045 if (value.u.r) 3046 value.type = FcTypeRange; 3047 break; 3048 default: 3049 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d", 3050 vstack->tag); 3051 break; 3052 } 3053 FcVStackPopAndDestroy (parse); 3054 3055 return value; 3056} 3057 3058static void 3059FcParsePatelt (FcConfigParse *parse) 3060{ 3061 FcValue value; 3062 FcPattern *pattern = FcPatternCreate (); 3063 const char *name; 3064 3065 if (!pattern) 3066 { 3067 FcConfigMessage (parse, FcSevereError, "out of memory"); 3068 return; 3069 } 3070 3071 name = (char *) FcConfigGetAttribute (parse, "name"); 3072 if (!name) 3073 { 3074 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name"); 3075 FcPatternDestroy (pattern); 3076 return; 3077 } 3078 3079 for (;;) 3080 { 3081 value = FcPopValue (parse); 3082 if (value.type == FcTypeVoid) 3083 break; 3084 if (!FcPatternAdd (pattern, name, value, FcTrue)) 3085 { 3086 FcConfigMessage (parse, FcSevereError, "out of memory"); 3087 FcValueDestroy(value); 3088 break; 3089 } 3090 FcValueDestroy(value); 3091 } 3092 3093 FcVStackPushPattern (parse, pattern); 3094} 3095 3096static void 3097FcParsePattern (FcConfigParse *parse) 3098{ 3099 FcVStack *vstack; 3100 FcPattern *pattern = FcPatternCreate (); 3101 3102 if (!pattern) 3103 { 3104 FcConfigMessage (parse, FcSevereError, "out of memory"); 3105 return; 3106 } 3107 3108 while ((vstack = FcVStackPeek (parse))) 3109 { 3110 switch ((int) vstack->tag) { 3111 case FcVStackPattern: 3112 if (!FcPatternAppend (pattern, vstack->u.pattern)) 3113 { 3114 FcConfigMessage (parse, FcSevereError, "out of memory"); 3115 FcPatternDestroy (pattern); 3116 return; 3117 } 3118 break; 3119 default: 3120 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element"); 3121 break; 3122 } 3123 FcVStackPopAndDestroy (parse); 3124 } 3125 3126 FcVStackPushPattern (parse, pattern); 3127} 3128 3129static void 3130FcEndElement(void *userData, const XML_Char *name FC_UNUSED) 3131{ 3132 FcConfigParse *parse = userData; 3133 FcChar8 *data; 3134 3135 if (!parse->pstack) 3136 return; 3137 switch (parse->pstack->element) { 3138 case FcElementNone: 3139 break; 3140 case FcElementFontconfig: 3141 break; 3142 case FcElementDir: 3143 FcParseDir (parse); 3144 break; 3145 case FcElementCacheDir: 3146 FcParseCacheDir (parse); 3147 break; 3148 case FcElementCache: 3149 data = FcStrBufDoneStatic (&parse->pstack->str); 3150 if (!data) 3151 { 3152 FcConfigMessage (parse, FcSevereError, "out of memory"); 3153 break; 3154 } 3155 /* discard this data; no longer used */ 3156 FcStrBufDestroy (&parse->pstack->str); 3157 break; 3158 case FcElementInclude: 3159 FcParseInclude (parse); 3160 break; 3161 case FcElementConfig: 3162 break; 3163 case FcElementMatch: 3164 FcParseMatch (parse); 3165 break; 3166 case FcElementAlias: 3167 FcParseAlias (parse); 3168 break; 3169 case FcElementDescription: 3170 FcParseDescription (parse); 3171 break; 3172 case FcElementRemapDir: 3173 FcParseRemapDir (parse); 3174 break; 3175 case FcElementResetDirs: 3176 FcParseResetDirs (parse); 3177 break; 3178 3179 case FcElementRescan: 3180 FcParseRescan (parse); 3181 break; 3182 3183 case FcElementPrefer: 3184 FcParseFamilies (parse, FcVStackPrefer); 3185 break; 3186 case FcElementAccept: 3187 FcParseFamilies (parse, FcVStackAccept); 3188 break; 3189 case FcElementDefault: 3190 FcParseFamilies (parse, FcVStackDefault); 3191 break; 3192 case FcElementFamily: 3193 FcParseFamily (parse); 3194 break; 3195 3196 case FcElementTest: 3197 FcParseTest (parse); 3198 break; 3199 case FcElementEdit: 3200 FcParseEdit (parse); 3201 break; 3202 3203 case FcElementInt: 3204 FcParseInt (parse); 3205 break; 3206 case FcElementDouble: 3207 FcParseDouble (parse); 3208 break; 3209 case FcElementString: 3210 FcParseString (parse, FcVStackString); 3211 break; 3212 case FcElementMatrix: 3213 FcParseMatrix (parse); 3214 break; 3215 case FcElementRange: 3216 FcParseRange (parse); 3217 break; 3218 case FcElementBool: 3219 FcParseBool (parse); 3220 break; 3221 case FcElementCharSet: 3222 FcParseCharSet (parse); 3223 break; 3224 case FcElementLangSet: 3225 FcParseLangSet (parse); 3226 break; 3227 case FcElementSelectfont: 3228 break; 3229 case FcElementAcceptfont: 3230 case FcElementRejectfont: 3231 FcParseAcceptRejectFont (parse, parse->pstack->element); 3232 break; 3233 case FcElementGlob: 3234 FcParseString (parse, FcVStackGlob); 3235 break; 3236 case FcElementPattern: 3237 FcParsePattern (parse); 3238 break; 3239 case FcElementPatelt: 3240 FcParsePatelt (parse); 3241 break; 3242 case FcElementName: 3243 FcParseName (parse); 3244 break; 3245 case FcElementConst: 3246 FcParseString (parse, FcVStackConstant); 3247 break; 3248 case FcElementOr: 3249 FcParseBinary (parse, FcOpOr); 3250 break; 3251 case FcElementAnd: 3252 FcParseBinary (parse, FcOpAnd); 3253 break; 3254 case FcElementEq: 3255 FcParseBinary (parse, FcOpEqual); 3256 break; 3257 case FcElementNotEq: 3258 FcParseBinary (parse, FcOpNotEqual); 3259 break; 3260 case FcElementLess: 3261 FcParseBinary (parse, FcOpLess); 3262 break; 3263 case FcElementLessEq: 3264 FcParseBinary (parse, FcOpLessEqual); 3265 break; 3266 case FcElementMore: 3267 FcParseBinary (parse, FcOpMore); 3268 break; 3269 case FcElementMoreEq: 3270 FcParseBinary (parse, FcOpMoreEqual); 3271 break; 3272 case FcElementContains: 3273 FcParseBinary (parse, FcOpContains); 3274 break; 3275 case FcElementNotContains: 3276 FcParseBinary (parse, FcOpNotContains); 3277 break; 3278 case FcElementPlus: 3279 FcParseBinary (parse, FcOpPlus); 3280 break; 3281 case FcElementMinus: 3282 FcParseBinary (parse, FcOpMinus); 3283 break; 3284 case FcElementTimes: 3285 FcParseBinary (parse, FcOpTimes); 3286 break; 3287 case FcElementDivide: 3288 FcParseBinary (parse, FcOpDivide); 3289 break; 3290 case FcElementNot: 3291 FcParseUnary (parse, FcOpNot); 3292 break; 3293 case FcElementIf: 3294 FcParseBinary (parse, FcOpQuest); 3295 break; 3296 case FcElementFloor: 3297 FcParseUnary (parse, FcOpFloor); 3298 break; 3299 case FcElementCeil: 3300 FcParseUnary (parse, FcOpCeil); 3301 break; 3302 case FcElementRound: 3303 FcParseUnary (parse, FcOpRound); 3304 break; 3305 case FcElementTrunc: 3306 FcParseUnary (parse, FcOpTrunc); 3307 break; 3308 case FcElementUnknown: 3309 break; 3310 } 3311 (void) FcPStackPop (parse); 3312} 3313 3314static void 3315FcCharacterData (void *userData, const XML_Char *s, int len) 3316{ 3317 FcConfigParse *parse = userData; 3318 3319 if (!parse->pstack) 3320 return; 3321 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len)) 3322 FcConfigMessage (parse, FcSevereError, "out of memory"); 3323} 3324 3325static void 3326FcStartDoctypeDecl (void *userData, 3327 const XML_Char *doctypeName, 3328 const XML_Char *sysid FC_UNUSED, 3329 const XML_Char *pubid FC_UNUSED, 3330 int has_internal_subset FC_UNUSED) 3331{ 3332 FcConfigParse *parse = userData; 3333 3334 if (strcmp ((char *) doctypeName, "fontconfig") != 0) 3335 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName); 3336} 3337 3338#ifdef ENABLE_LIBXML2 3339 3340static void 3341FcInternalSubsetDecl (void *userData, 3342 const XML_Char *doctypeName, 3343 const XML_Char *sysid, 3344 const XML_Char *pubid) 3345{ 3346 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1); 3347} 3348 3349static void 3350FcExternalSubsetDecl (void *userData, 3351 const XML_Char *doctypeName, 3352 const XML_Char *sysid, 3353 const XML_Char *pubid) 3354{ 3355 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0); 3356} 3357 3358#else /* ENABLE_LIBXML2 */ 3359 3360static void 3361FcEndDoctypeDecl (void *userData FC_UNUSED) 3362{ 3363} 3364 3365#endif /* ENABLE_LIBXML2 */ 3366 3367static int 3368FcSortCmpStr (const void *a, const void *b) 3369{ 3370 const FcChar8 *as = *((FcChar8 **) a); 3371 const FcChar8 *bs = *((FcChar8 **) b); 3372 return FcStrCmp (as, bs); 3373} 3374 3375static FcBool 3376FcConfigParseAndLoadDir (FcConfig *config, 3377 const FcChar8 *name, 3378 const FcChar8 *dir, 3379 FcBool complain, 3380 FcBool load) 3381{ 3382 DIR *d; 3383 struct dirent *e; 3384 FcBool ret = FcTrue; 3385 FcChar8 *file; 3386 FcChar8 *base; 3387 FcStrSet *files; 3388 3389 d = opendir ((char *) dir); 3390 if (!d) 3391 { 3392 if (complain) 3393 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"", 3394 name); 3395 ret = FcFalse; 3396 goto bail0; 3397 } 3398 /* freed below */ 3399 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1); 3400 if (!file) 3401 { 3402 ret = FcFalse; 3403 goto bail1; 3404 } 3405 3406 strcpy ((char *) file, (char *) dir); 3407 strcat ((char *) file, "/"); 3408 base = file + strlen ((char *) file); 3409 3410 files = FcStrSetCreateEx (FCSS_GROW_BY_64); 3411 if (!files) 3412 { 3413 ret = FcFalse; 3414 goto bail2; 3415 } 3416 3417 if (FcDebug () & FC_DBG_CONFIG) 3418 printf ("\tScanning config dir %s\n", dir); 3419 3420 if (load) 3421 FcConfigAddConfigDir (config, dir); 3422 3423 while (ret && (e = readdir (d))) 3424 { 3425 int d_len; 3426#define TAIL ".conf" 3427#define TAIL_LEN 5 3428 /* 3429 * Add all files of the form [0-9]*.conf 3430 */ 3431 d_len = strlen (e->d_name); 3432 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' && 3433 d_len > TAIL_LEN && 3434 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) 3435 { 3436 strcpy ((char *) base, (char *) e->d_name); 3437 if (!FcStrSetAdd (files, file)) 3438 { 3439 ret = FcFalse; 3440 goto bail3; 3441 } 3442 } 3443 } 3444 if (ret) 3445 { 3446 int i; 3447 qsort (files->strs, files->num, sizeof (FcChar8 *), 3448 (int (*)(const void *, const void *)) FcSortCmpStr); 3449 for (i = 0; ret && i < files->num; i++) 3450 ret = _FcConfigParse (config, files->strs[i], complain, load); 3451 } 3452bail3: 3453 FcStrSetDestroy (files); 3454bail2: 3455 free (file); 3456bail1: 3457 closedir (d); 3458bail0: 3459 return ret || !complain; 3460} 3461 3462static FcBool 3463FcConfigParseAndLoadFromMemoryInternal (FcConfig *config, 3464 const FcChar8 *filename, 3465 const FcChar8 *buffer, 3466 FcBool complain, 3467 FcBool load) 3468{ 3469 3470 XML_Parser p; 3471 size_t len; 3472 FcConfigParse parse; 3473 FcBool error = FcTrue; 3474 FcMatchKind k; 3475 FcPtrListIter liter; 3476 3477#ifdef ENABLE_LIBXML2 3478 xmlSAXHandler sax; 3479#else 3480 void *buf; 3481 const FcChar8 *s; 3482 size_t buflen; 3483#endif 3484 3485 if (!buffer) 3486 return FcFalse; 3487 len = strlen ((const char *) buffer); 3488 if (FcDebug () & FC_DBG_CONFIG) 3489 printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename); 3490 3491#ifdef ENABLE_LIBXML2 3492 memset(&sax, 0, sizeof(sax)); 3493 3494 sax.internalSubset = FcInternalSubsetDecl; 3495 sax.externalSubset = FcExternalSubsetDecl; 3496 sax.startElement = FcStartElement; 3497 sax.endElement = FcEndElement; 3498 sax.characters = FcCharacterData; 3499 3500 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename); 3501#else 3502 p = XML_ParserCreate ("UTF-8"); 3503#endif 3504 3505 if (!p) 3506 goto bail1; 3507 3508 if (!FcConfigParseInit (&parse, filename, config, p, load)) 3509 goto bail2; 3510 3511#ifndef ENABLE_LIBXML2 3512 3513 XML_SetUserData (p, &parse); 3514 3515 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl); 3516 XML_SetElementHandler (p, FcStartElement, FcEndElement); 3517 XML_SetCharacterDataHandler (p, FcCharacterData); 3518 3519#endif /* ENABLE_LIBXML2 */ 3520 3521#ifndef ENABLE_LIBXML2 3522 s = buffer; 3523 do { 3524 buf = XML_GetBuffer (p, BUFSIZ); 3525 if (!buf) 3526 { 3527 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer"); 3528 goto bail3; 3529 } 3530 if (len > BUFSIZ) 3531 { 3532 buflen = BUFSIZ; 3533 len -= BUFSIZ; 3534 } 3535 else 3536 { 3537 buflen = len; 3538 len = 0; 3539 } 3540 memcpy (buf, s, buflen); 3541 s = s + buflen; 3542#endif 3543 3544#ifdef ENABLE_LIBXML2 3545 if (xmlParseChunk (p, (const char *)buffer, len, len == 0)) 3546#else 3547 if (!XML_ParseBuffer (p, buflen, buflen == 0)) 3548#endif 3549 { 3550 FcConfigMessage (&parse, FcSevereError, "%s", 3551 XML_ErrorString (XML_GetErrorCode (p))); 3552 goto bail3; 3553 } 3554#ifndef ENABLE_LIBXML2 3555 } while (buflen != 0); 3556#endif 3557 error = parse.error; 3558 if (load) 3559 { 3560 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) 3561 { 3562 FcPtrListIter iter; 3563 3564 FcPtrListIterInit (parse.ruleset->subst[k], &iter); 3565 if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter)) 3566 { 3567 FcPtrListIterInitAtLast (parse.config->subst[k], &iter); 3568 FcRuleSetReference (parse.ruleset); 3569 FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset); 3570 } 3571 } 3572 } 3573 FcPtrListIterInitAtLast (parse.config->rulesetList, &liter); 3574 FcRuleSetReference (parse.ruleset); 3575 FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset); 3576bail3: 3577 FcConfigCleanup (&parse); 3578bail2: 3579 XML_ParserFree (p); 3580bail1: 3581 if (error && complain) 3582 { 3583 FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename); 3584 return FcFalse; 3585 } 3586 if (FcDebug () & FC_DBG_CONFIG) 3587 printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename); 3588 return FcTrue; 3589} 3590 3591static FcBool 3592_FcConfigParse (FcConfig *config, 3593 const FcChar8 *name, 3594 FcBool complain, 3595 FcBool load) 3596{ 3597 FcChar8 *filename = NULL, *realfilename = NULL; 3598 int fd; 3599 int len; 3600 FcStrBuf sbuf; 3601 char buf[BUFSIZ]; 3602 FcBool ret = FcFalse, complain_again = complain; 3603 FcStrBuf reason; 3604 3605 FcStrBufInit (&reason, NULL, 0); 3606#ifdef _WIN32 3607 _ensureWin32GettersReady(); 3608#endif 3609 3610 filename = FcConfigGetFilename (config, name); 3611 if (!filename) 3612 { 3613 FcStrBufString (&reason, (FcChar8 *)"No such file: "); 3614 FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)"); 3615 goto bail0; 3616 } 3617 realfilename = FcConfigRealFilename (config, name); 3618 if (!realfilename) 3619 { 3620 FcStrBufString (&reason, (FcChar8 *)"No such realfile: "); 3621 FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)"); 3622 goto bail0; 3623 } 3624 if (FcStrSetMember (config->availConfigFiles, realfilename)) 3625 { 3626 FcStrFree (filename); 3627 FcStrFree (realfilename); 3628 return FcTrue; 3629 } 3630 3631 if (load) 3632 { 3633 if (!FcStrSetAdd (config->configFiles, filename)) 3634 goto bail0; 3635 } 3636 if (!FcStrSetAdd (config->availConfigFiles, realfilename)) 3637 goto bail0; 3638 3639 if (FcFileIsDir (realfilename)) 3640 { 3641 ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load); 3642 FcStrFree (filename); 3643 FcStrFree (realfilename); 3644 return ret; 3645 } 3646 3647 FcStrBufInit (&sbuf, NULL, 0); 3648 3649 fd = FcOpen ((char *) realfilename, O_RDONLY); 3650 if (fd == -1) 3651 { 3652 FcStrBufString (&reason, (FcChar8 *)"Unable to open "); 3653 FcStrBufString (&reason, realfilename); 3654 goto bail1; 3655 } 3656 3657 do { 3658 len = read (fd, buf, BUFSIZ); 3659 if (len < 0) 3660 { 3661 int errno_ = errno; 3662 char ebuf[BUFSIZ+1]; 3663 3664#if HAVE_STRERROR_R 3665 strerror_r (errno_, ebuf, BUFSIZ); 3666#elif HAVE_STRERROR 3667 char *tmp = strerror (errno_); 3668 size_t len = strlen (tmp); 3669 memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len)); 3670 ebuf[FC_MIN (BUFSIZ, len)] = 0; 3671#else 3672 ebuf[0] = 0; 3673#endif 3674 FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_); 3675 close (fd); 3676 goto bail1; 3677 } 3678 FcStrBufData (&sbuf, (const FcChar8 *)buf, len); 3679 } while (len != 0); 3680 close (fd); 3681 3682 ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load); 3683 complain_again = FcFalse; /* no need to reclaim here */ 3684bail1: 3685 FcStrBufDestroy (&sbuf); 3686bail0: 3687 if (filename) 3688 FcStrFree (filename); 3689 if (realfilename) 3690 FcStrFree (realfilename); 3691 if (!complain) 3692 { 3693 FcStrBufDestroy (&reason); 3694 return FcTrue; 3695 } 3696 if (!ret && complain_again) 3697 { 3698 if (name) 3699 FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason)); 3700 else 3701 FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason)); 3702 FcStrBufDestroy (&reason); 3703 return FcFalse; 3704 } 3705 FcStrBufDestroy (&reason); 3706 return ret; 3707} 3708 3709FcBool 3710FcConfigParseOnly (FcConfig *config, 3711 const FcChar8 *name, 3712 FcBool complain) 3713{ 3714 return _FcConfigParse (config, name, complain, FcFalse); 3715} 3716 3717FcBool 3718FcConfigParseAndLoad (FcConfig *config, 3719 const FcChar8 *name, 3720 FcBool complain) 3721{ 3722 return _FcConfigParse (config, name, complain, FcTrue); 3723} 3724 3725FcBool 3726FcConfigParseAndLoadFromMemory (FcConfig *config, 3727 const FcChar8 *buffer, 3728 FcBool complain) 3729{ 3730 return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue); 3731} 3732 3733#ifdef _WIN32 3734static void 3735_ensureWin32GettersReady() 3736{ 3737 if (!pGetSystemWindowsDirectory) 3738 { 3739 HMODULE hk32 = GetModuleHandleA("kernel32.dll"); 3740 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress(hk32, "GetSystemWindowsDirectoryA"))) 3741 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory; 3742 } 3743 if (!pSHGetFolderPathA) 3744 { 3745 HMODULE hSh = LoadLibraryA("shfolder.dll"); 3746 /* the check is done later, because there is no provided fallback */ 3747 if (hSh) 3748 pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress(hSh, "SHGetFolderPathA"); 3749 } 3750} 3751#endif // _WIN32 3752 3753#define __fcxml__ 3754#include "fcaliastail.h" 3755#undef __fcxml__ 3756