fcname.c revision 2eed41b2
1/* 2 * fontconfig/src/fcname.c 3 * 4 * Copyright © 2000 Keith Packard 5 * 6 * Permission to use, copy, modify, distribute, and sell this software and its 7 * documentation for any purpose is hereby granted without fee, provided that 8 * the above copyright notice appear in all copies and that both that 9 * copyright notice and this permission notice appear in supporting 10 * documentation, and that the name of Keith Packard not be used in 11 * advertising or publicity pertaining to distribution of the software without 12 * specific, written prior permission. Keith Packard makes no 13 * representations about the suitability of this software for any purpose. It 14 * is provided "as is" without express or implied warranty. 15 * 16 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 18 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR 19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 22 * PERFORMANCE OF THIS SOFTWARE. 23 */ 24 25#include "fcint.h" 26#include <ctype.h> 27#include <stdlib.h> 28#include <string.h> 29#include <stdio.h> 30 31/* 32 * Please do not change this list, it is used to initialize the object 33 * list in this order to match the FC_foo_OBJECT constants. Those 34 * constants are written into cache files. 35 */ 36 37static const FcObjectType _FcBaseObjectTypes[] = { 38 { FC_FAMILY, FcTypeString, }, /* 1 */ 39 { FC_FAMILYLANG, FcTypeString, }, 40 { FC_STYLE, FcTypeString, }, 41 { FC_STYLELANG, FcTypeString, }, 42 { FC_FULLNAME, FcTypeString, }, 43 { FC_FULLNAMELANG, FcTypeString, }, 44 { FC_SLANT, FcTypeInteger, }, 45 { FC_WEIGHT, FcTypeInteger, }, 46 { FC_WIDTH, FcTypeInteger, }, 47 { FC_SIZE, FcTypeDouble, }, 48 { FC_ASPECT, FcTypeDouble, }, 49 { FC_PIXEL_SIZE, FcTypeDouble, }, 50 { FC_SPACING, FcTypeInteger, }, 51 { FC_FOUNDRY, FcTypeString, }, 52 { FC_ANTIALIAS, FcTypeBool, }, 53 { FC_HINT_STYLE, FcTypeInteger, }, 54 { FC_HINTING, FcTypeBool, }, 55 { FC_VERTICAL_LAYOUT, FcTypeBool, }, 56 { FC_AUTOHINT, FcTypeBool, }, 57 { FC_GLOBAL_ADVANCE, FcTypeBool, }, 58 { FC_FILE, FcTypeString, }, 59 { FC_INDEX, FcTypeInteger, }, 60 { FC_RASTERIZER, FcTypeString, }, 61 { FC_OUTLINE, FcTypeBool, }, 62 { FC_SCALABLE, FcTypeBool, }, 63 { FC_DPI, FcTypeDouble }, 64 { FC_RGBA, FcTypeInteger, }, 65 { FC_SCALE, FcTypeDouble, }, 66 { FC_MINSPACE, FcTypeBool, }, 67 { FC_CHAR_WIDTH, FcTypeInteger }, 68 { FC_CHAR_HEIGHT, FcTypeInteger }, 69 { FC_MATRIX, FcTypeMatrix }, 70 { FC_CHARSET, FcTypeCharSet }, 71 { FC_LANG, FcTypeLangSet }, 72 { FC_FONTVERSION, FcTypeInteger }, 73 { FC_CAPABILITY, FcTypeString }, 74 { FC_FONTFORMAT, FcTypeString }, 75 { FC_EMBOLDEN, FcTypeBool }, 76 { FC_EMBEDDED_BITMAP, FcTypeBool }, 77 { FC_DECORATIVE, FcTypeBool }, 78 { FC_LCD_FILTER, FcTypeInteger }, /* 41 */ 79}; 80 81#define NUM_OBJECT_TYPES (sizeof _FcBaseObjectTypes / sizeof _FcBaseObjectTypes[0]) 82 83typedef struct _FcObjectTypeList FcObjectTypeList; 84 85struct _FcObjectTypeList { 86 const FcObjectTypeList *next; 87 const FcObjectType *types; 88 int ntypes; 89}; 90 91static const FcObjectTypeList _FcBaseObjectTypesList = { 92 0, 93 _FcBaseObjectTypes, 94 NUM_OBJECT_TYPES, 95}; 96 97static const FcObjectTypeList *_FcObjectTypes = &_FcBaseObjectTypesList; 98 99#define OBJECT_HASH_SIZE 31 100 101typedef struct _FcObjectBucket { 102 struct _FcObjectBucket *next; 103 FcChar32 hash; 104 FcObject id; 105} FcObjectBucket; 106 107static FcObjectBucket *FcObjectBuckets[OBJECT_HASH_SIZE]; 108 109static FcObjectType *FcObjects = (FcObjectType *) _FcBaseObjectTypes; 110static int FcObjectsNumber = NUM_OBJECT_TYPES; 111static int FcObjectsSize = 0; 112static FcBool FcObjectsInited; 113 114static FcObjectType * 115FcObjectInsert (const char *name, FcType type) 116{ 117 FcObjectType *o; 118 if (FcObjectsNumber >= FcObjectsSize) 119 { 120 int newsize = FcObjectsNumber * 2; 121 FcObjectType *newobjects; 122 123 if (FcObjectsSize) 124 newobjects = realloc (FcObjects, newsize * sizeof (FcObjectType)); 125 else 126 { 127 newobjects = malloc (newsize * sizeof (FcObjectType)); 128 if (newobjects) 129 memcpy (newobjects, FcObjects, 130 FcObjectsNumber * sizeof (FcObjectType)); 131 } 132 if (!newobjects) 133 return NULL; 134 FcObjects = newobjects; 135 FcObjectsSize = newsize; 136 } 137 o = &FcObjects[FcObjectsNumber]; 138 o->object = name; 139 o->type = type; 140 ++FcObjectsNumber; 141 return o; 142} 143 144static FcObject 145FcObjectId (FcObjectType *o) 146{ 147 return o - FcObjects + 1; 148} 149 150static FcObjectType * 151FcObjectFindByName (const char *object, FcBool insert) 152{ 153 FcChar32 hash = FcStringHash ((const FcChar8 *) object); 154 FcObjectBucket **p; 155 FcObjectBucket *b; 156 FcObjectType *o; 157 158 if (!FcObjectsInited) 159 FcObjectInit (); 160 for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) 161 { 162 o = FcObjects + b->id - 1; 163 if (b->hash == hash && !strcmp (object, (o->object))) 164 return o; 165 } 166 if (!insert) 167 return NULL; 168 /* 169 * Hook it into the hash chain 170 */ 171 b = malloc (sizeof(FcObjectBucket)); 172 if (!b) 173 return NULL; 174 object = (const char *) FcStrCopy ((FcChar8 *) object); 175 if (!object) { 176 free (b); 177 return NULL; 178 } 179 o = FcObjectInsert (object, -1); 180 b->next = NULL; 181 b->hash = hash; 182 b->id = FcObjectId (o); 183 *p = b; 184 return o; 185} 186 187static FcObjectType * 188FcObjectFindById (FcObject object) 189{ 190 if (1 <= object && object <= FcObjectsNumber) 191 return FcObjects + object - 1; 192 return NULL; 193} 194 195static FcBool 196FcObjectHashInsert (const FcObjectType *object, FcBool copy) 197{ 198 FcChar32 hash = FcStringHash ((const FcChar8 *) object->object); 199 FcObjectBucket **p; 200 FcObjectBucket *b; 201 FcObjectType *o; 202 203 if (!FcObjectsInited) 204 FcObjectInit (); 205 for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) 206 { 207 o = FcObjects + b->id - 1; 208 if (b->hash == hash && !strcmp (object->object, o->object)) 209 return FcFalse; 210 } 211 /* 212 * Hook it into the hash chain 213 */ 214 b = malloc (sizeof(FcObjectBucket)); 215 if (!b) 216 return FcFalse; 217 if (copy) 218 { 219 o = FcObjectInsert (object->object, object->type); 220 if (!o) 221 { 222 free (b); 223 return FcFalse; 224 } 225 } 226 else 227 o = (FcObjectType *) object; 228 b->next = NULL; 229 b->hash = hash; 230 b->id = FcObjectId (o); 231 *p = b; 232 return FcTrue; 233} 234 235static void 236FcObjectHashRemove (const FcObjectType *object, FcBool cleanobj) 237{ 238 FcChar32 hash = FcStringHash ((const FcChar8 *) object->object); 239 FcObjectBucket **p; 240 FcObjectBucket *b; 241 FcObjectType *o; 242 243 if (!FcObjectsInited) 244 FcObjectInit (); 245 for (p = &FcObjectBuckets[hash%OBJECT_HASH_SIZE]; (b = *p); p = &(b->next)) 246 { 247 o = FcObjects + b->id - 1; 248 if (b->hash == hash && !strcmp (object->object, o->object)) 249 { 250 *p = b->next; 251 free (b); 252 if (cleanobj) 253 { 254 /* Clean up object array */ 255 o->object = NULL; 256 o->type = -1; 257 while (FcObjects[FcObjectsNumber-1].object == NULL) 258 --FcObjectsNumber; 259 } 260 break; 261 } 262 } 263} 264 265FcBool 266FcNameRegisterObjectTypes (const FcObjectType *types, int ntypes) 267{ 268 int i; 269 270 for (i = 0; i < ntypes; i++) 271 if (!FcObjectHashInsert (&types[i], FcTrue)) 272 return FcFalse; 273 return FcTrue; 274} 275 276FcBool 277FcNameUnregisterObjectTypes (const FcObjectType *types, int ntypes) 278{ 279 int i; 280 281 for (i = 0; i < ntypes; i++) 282 FcObjectHashRemove (&types[i], FcTrue); 283 return FcTrue; 284} 285 286const FcObjectType * 287FcNameGetObjectType (const char *object) 288{ 289 return FcObjectFindByName (object, FcFalse); 290} 291 292FcBool 293FcObjectValidType (FcObject object, FcType type) 294{ 295 FcObjectType *t = FcObjectFindById (object); 296 297 if (t) { 298 switch (t->type) { 299 case -1: 300 return FcTrue; 301 case FcTypeDouble: 302 case FcTypeInteger: 303 if (type == FcTypeDouble || type == FcTypeInteger) 304 return FcTrue; 305 break; 306 case FcTypeLangSet: 307 if (type == FcTypeLangSet || type == FcTypeString) 308 return FcTrue; 309 break; 310 default: 311 if (type == t->type) 312 return FcTrue; 313 break; 314 } 315 return FcFalse; 316 } 317 return FcTrue; 318} 319 320FcObject 321FcObjectFromName (const char * name) 322{ 323 FcObjectType *o = FcObjectFindByName (name, FcTrue); 324 325 if (o) 326 return FcObjectId (o); 327 return 0; 328} 329 330FcObjectSet * 331FcObjectGetSet (void) 332{ 333 int i; 334 FcObjectSet *os = NULL; 335 336 337 os = FcObjectSetCreate (); 338 for (i = 0; i < FcObjectsNumber; i++) 339 FcObjectSetAdd (os, FcObjects[i].object); 340 341 return os; 342} 343 344FcBool 345FcObjectInit (void) 346{ 347 int i; 348 349 if (FcObjectsInited) 350 return FcTrue; 351 352 FcObjectsInited = FcTrue; 353 for (i = 0; i < NUM_OBJECT_TYPES; i++) 354 if (!FcObjectHashInsert (&_FcBaseObjectTypes[i], FcFalse)) 355 return FcFalse; 356 return FcTrue; 357} 358 359void 360FcObjectFini (void) 361{ 362 int i; 363 FcObjectBucket *b, *next; 364 365 for (i = 0; i < OBJECT_HASH_SIZE; i++) 366 { 367 for (b = FcObjectBuckets[i]; b; b = next) 368 { 369 next = b->next; 370 free (b); 371 } 372 FcObjectBuckets[i] = 0; 373 } 374 for (i = 0; i < FcObjectsNumber; i++) 375 if (FcObjects[i].type == (FcType)-1) 376 free ((void*) FcObjects[i].object); 377 if (FcObjects != _FcBaseObjectTypes) 378 free (FcObjects); 379 FcObjects = (FcObjectType *) _FcBaseObjectTypes; 380 FcObjectsNumber = NUM_OBJECT_TYPES; 381 FcObjectsSize = 0; 382 FcObjectsInited = FcFalse; 383} 384 385const char * 386FcObjectName (FcObject object) 387{ 388 FcObjectType *o = FcObjectFindById (object); 389 390 if (o) 391 return o->object; 392 return NULL; 393} 394 395static const FcConstant _FcBaseConstants[] = { 396 { (FcChar8 *) "thin", "weight", FC_WEIGHT_THIN, }, 397 { (FcChar8 *) "extralight", "weight", FC_WEIGHT_EXTRALIGHT, }, 398 { (FcChar8 *) "ultralight", "weight", FC_WEIGHT_EXTRALIGHT, }, 399 { (FcChar8 *) "light", "weight", FC_WEIGHT_LIGHT, }, 400 { (FcChar8 *) "book", "weight", FC_WEIGHT_BOOK, }, 401 { (FcChar8 *) "regular", "weight", FC_WEIGHT_REGULAR, }, 402 { (FcChar8 *) "medium", "weight", FC_WEIGHT_MEDIUM, }, 403 { (FcChar8 *) "demibold", "weight", FC_WEIGHT_DEMIBOLD, }, 404 { (FcChar8 *) "semibold", "weight", FC_WEIGHT_DEMIBOLD, }, 405 { (FcChar8 *) "bold", "weight", FC_WEIGHT_BOLD, }, 406 { (FcChar8 *) "extrabold", "weight", FC_WEIGHT_EXTRABOLD, }, 407 { (FcChar8 *) "ultrabold", "weight", FC_WEIGHT_EXTRABOLD, }, 408 { (FcChar8 *) "black", "weight", FC_WEIGHT_BLACK, }, 409 { (FcChar8 *) "heavy", "weight", FC_WEIGHT_HEAVY, }, 410 411 { (FcChar8 *) "roman", "slant", FC_SLANT_ROMAN, }, 412 { (FcChar8 *) "italic", "slant", FC_SLANT_ITALIC, }, 413 { (FcChar8 *) "oblique", "slant", FC_SLANT_OBLIQUE, }, 414 415 { (FcChar8 *) "ultracondensed", "width", FC_WIDTH_ULTRACONDENSED }, 416 { (FcChar8 *) "extracondensed", "width", FC_WIDTH_EXTRACONDENSED }, 417 { (FcChar8 *) "condensed", "width", FC_WIDTH_CONDENSED }, 418 { (FcChar8 *) "semicondensed", "width", FC_WIDTH_SEMICONDENSED }, 419 { (FcChar8 *) "normal", "width", FC_WIDTH_NORMAL }, 420 { (FcChar8 *) "semiexpanded", "width", FC_WIDTH_SEMIEXPANDED }, 421 { (FcChar8 *) "expanded", "width", FC_WIDTH_EXPANDED }, 422 { (FcChar8 *) "extraexpanded", "width", FC_WIDTH_EXTRAEXPANDED }, 423 { (FcChar8 *) "ultraexpanded", "width", FC_WIDTH_ULTRAEXPANDED }, 424 425 { (FcChar8 *) "proportional", "spacing", FC_PROPORTIONAL, }, 426 { (FcChar8 *) "dual", "spacing", FC_DUAL, }, 427 { (FcChar8 *) "mono", "spacing", FC_MONO, }, 428 { (FcChar8 *) "charcell", "spacing", FC_CHARCELL, }, 429 430 { (FcChar8 *) "unknown", "rgba", FC_RGBA_UNKNOWN }, 431 { (FcChar8 *) "rgb", "rgba", FC_RGBA_RGB, }, 432 { (FcChar8 *) "bgr", "rgba", FC_RGBA_BGR, }, 433 { (FcChar8 *) "vrgb", "rgba", FC_RGBA_VRGB }, 434 { (FcChar8 *) "vbgr", "rgba", FC_RGBA_VBGR }, 435 { (FcChar8 *) "none", "rgba", FC_RGBA_NONE }, 436 437 { (FcChar8 *) "hintnone", "hintstyle", FC_HINT_NONE }, 438 { (FcChar8 *) "hintslight", "hintstyle", FC_HINT_SLIGHT }, 439 { (FcChar8 *) "hintmedium", "hintstyle", FC_HINT_MEDIUM }, 440 { (FcChar8 *) "hintfull", "hintstyle", FC_HINT_FULL }, 441 442 { (FcChar8 *) "antialias", "antialias", FcTrue }, 443 { (FcChar8 *) "hinting", "hinting", FcTrue }, 444 { (FcChar8 *) "verticallayout", "verticallayout", FcTrue }, 445 { (FcChar8 *) "autohint", "autohint", FcTrue }, 446 { (FcChar8 *) "globaladvance", "globaladvance", FcTrue }, 447 { (FcChar8 *) "outline", "outline", FcTrue }, 448 { (FcChar8 *) "scalable", "scalable", FcTrue }, 449 { (FcChar8 *) "minspace", "minspace", FcTrue }, 450 { (FcChar8 *) "embolden", "embolden", FcTrue }, 451 { (FcChar8 *) "embeddedbitmap", "embeddedbitmap", FcTrue }, 452 { (FcChar8 *) "decorative", "decorative", FcTrue }, 453 { (FcChar8 *) "lcdnone", "lcdfilter", FC_LCD_NONE }, 454 { (FcChar8 *) "lcddefault", "lcdfilter", FC_LCD_DEFAULT }, 455 { (FcChar8 *) "lcdlight", "lcdfilter", FC_LCD_LIGHT }, 456 { (FcChar8 *) "lcdlegacy", "lcdfilter", FC_LCD_LEGACY }, 457}; 458 459#define NUM_FC_CONSTANTS (sizeof _FcBaseConstants/sizeof _FcBaseConstants[0]) 460 461typedef struct _FcConstantList FcConstantList; 462 463struct _FcConstantList { 464 const FcConstantList *next; 465 const FcConstant *consts; 466 int nconsts; 467}; 468 469static const FcConstantList _FcBaseConstantList = { 470 0, 471 _FcBaseConstants, 472 NUM_FC_CONSTANTS 473}; 474 475static const FcConstantList *_FcConstants = &_FcBaseConstantList; 476 477FcBool 478FcNameRegisterConstants (const FcConstant *consts, int nconsts) 479{ 480 FcConstantList *l; 481 482 l = (FcConstantList *) malloc (sizeof (FcConstantList)); 483 if (!l) 484 return FcFalse; 485 FcMemAlloc (FC_MEM_CONSTANT, sizeof (FcConstantList)); 486 l->consts = consts; 487 l->nconsts = nconsts; 488 l->next = _FcConstants; 489 _FcConstants = l; 490 return FcTrue; 491} 492 493FcBool 494FcNameUnregisterConstants (const FcConstant *consts, int nconsts) 495{ 496 const FcConstantList *l, **prev; 497 498 for (prev = &_FcConstants; 499 (l = *prev); 500 prev = (const FcConstantList **) &(l->next)) 501 { 502 if (l->consts == consts && l->nconsts == nconsts) 503 { 504 *prev = l->next; 505 FcMemFree (FC_MEM_CONSTANT, sizeof (FcConstantList)); 506 free ((void *) l); 507 return FcTrue; 508 } 509 } 510 return FcFalse; 511} 512 513const FcConstant * 514FcNameGetConstant (FcChar8 *string) 515{ 516 const FcConstantList *l; 517 int i; 518 519 for (l = _FcConstants; l; l = l->next) 520 { 521 for (i = 0; i < l->nconsts; i++) 522 if (!FcStrCmpIgnoreCase (string, l->consts[i].name)) 523 return &l->consts[i]; 524 } 525 return 0; 526} 527 528FcBool 529FcNameConstant (FcChar8 *string, int *result) 530{ 531 const FcConstant *c; 532 533 if ((c = FcNameGetConstant(string))) 534 { 535 *result = c->value; 536 return FcTrue; 537 } 538 return FcFalse; 539} 540 541FcBool 542FcNameBool (const FcChar8 *v, FcBool *result) 543{ 544 char c0, c1; 545 546 c0 = *v; 547 c0 = FcToLower (c0); 548 if (c0 == 't' || c0 == 'y' || c0 == '1') 549 { 550 *result = FcTrue; 551 return FcTrue; 552 } 553 if (c0 == 'f' || c0 == 'n' || c0 == '0') 554 { 555 *result = FcFalse; 556 return FcTrue; 557 } 558 if (c0 == 'o') 559 { 560 c1 = v[1]; 561 c1 = FcToLower (c1); 562 if (c1 == 'n') 563 { 564 *result = FcTrue; 565 return FcTrue; 566 } 567 if (c1 == 'f') 568 { 569 *result = FcFalse; 570 return FcTrue; 571 } 572 } 573 return FcFalse; 574} 575 576static FcValue 577FcNameConvert (FcType type, FcChar8 *string, FcMatrix *m) 578{ 579 FcValue v; 580 581 v.type = type; 582 switch (v.type) { 583 case FcTypeInteger: 584 if (!FcNameConstant (string, &v.u.i)) 585 v.u.i = atoi ((char *) string); 586 break; 587 case FcTypeString: 588 v.u.s = FcStrStaticName(string); 589 if (!v.u.s) 590 v.type = FcTypeVoid; 591 break; 592 case FcTypeBool: 593 if (!FcNameBool (string, &v.u.b)) 594 v.u.b = FcFalse; 595 break; 596 case FcTypeDouble: 597 v.u.d = strtod ((char *) string, 0); 598 break; 599 case FcTypeMatrix: 600 v.u.m = m; 601 sscanf ((char *) string, "%lg %lg %lg %lg", &m->xx, &m->xy, &m->yx, &m->yy); 602 break; 603 case FcTypeCharSet: 604 v.u.c = FcNameParseCharSet (string); 605 if (!v.u.c) 606 v.type = FcTypeVoid; 607 break; 608 case FcTypeLangSet: 609 v.u.l = FcNameParseLangSet (string); 610 if (!v.u.l) 611 v.type = FcTypeVoid; 612 break; 613 default: 614 break; 615 } 616 return v; 617} 618 619static const FcChar8 * 620FcNameFindNext (const FcChar8 *cur, const char *delim, FcChar8 *save, FcChar8 *last) 621{ 622 FcChar8 c; 623 624 while ((c = *cur)) 625 { 626 if (c == '\\') 627 { 628 ++cur; 629 if (!(c = *cur)) 630 break; 631 } 632 else if (strchr (delim, c)) 633 break; 634 ++cur; 635 *save++ = c; 636 } 637 *save = 0; 638 *last = *cur; 639 if (*cur) 640 cur++; 641 return cur; 642} 643 644FcPattern * 645FcNameParse (const FcChar8 *name) 646{ 647 FcChar8 *save; 648 FcPattern *pat; 649 double d; 650 FcChar8 *e; 651 FcChar8 delim; 652 FcValue v; 653 FcMatrix m; 654 const FcObjectType *t; 655 const FcConstant *c; 656 657 /* freed below */ 658 save = malloc (strlen ((char *) name) + 1); 659 if (!save) 660 goto bail0; 661 pat = FcPatternCreate (); 662 if (!pat) 663 goto bail1; 664 665 for (;;) 666 { 667 name = FcNameFindNext (name, "-,:", save, &delim); 668 if (save[0]) 669 { 670 if (!FcPatternAddString (pat, FC_FAMILY, save)) 671 goto bail2; 672 } 673 if (delim != ',') 674 break; 675 } 676 if (delim == '-') 677 { 678 for (;;) 679 { 680 name = FcNameFindNext (name, "-,:", save, &delim); 681 d = strtod ((char *) save, (char **) &e); 682 if (e != save) 683 { 684 if (!FcPatternAddDouble (pat, FC_SIZE, d)) 685 goto bail2; 686 } 687 if (delim != ',') 688 break; 689 } 690 } 691 while (delim == ':') 692 { 693 name = FcNameFindNext (name, "=_:", save, &delim); 694 if (save[0]) 695 { 696 if (delim == '=' || delim == '_') 697 { 698 t = FcNameGetObjectType ((char *) save); 699 for (;;) 700 { 701 name = FcNameFindNext (name, ":,", save, &delim); 702 if (t) 703 { 704 v = FcNameConvert (t->type, save, &m); 705 if (!FcPatternAdd (pat, t->object, v, FcTrue)) 706 { 707 switch (v.type) { 708 case FcTypeCharSet: 709 FcCharSetDestroy ((FcCharSet *) v.u.c); 710 break; 711 case FcTypeLangSet: 712 FcLangSetDestroy ((FcLangSet *) v.u.l); 713 break; 714 default: 715 break; 716 } 717 goto bail2; 718 } 719 switch (v.type) { 720 case FcTypeCharSet: 721 FcCharSetDestroy ((FcCharSet *) v.u.c); 722 break; 723 case FcTypeLangSet: 724 FcLangSetDestroy ((FcLangSet *) v.u.l); 725 break; 726 default: 727 break; 728 } 729 } 730 if (delim != ',') 731 break; 732 } 733 } 734 else 735 { 736 if ((c = FcNameGetConstant (save))) 737 { 738 t = FcNameGetObjectType ((char *) c->object); 739 switch (t->type) { 740 case FcTypeInteger: 741 case FcTypeDouble: 742 if (!FcPatternAddInteger (pat, c->object, c->value)) 743 goto bail2; 744 break; 745 case FcTypeBool: 746 if (!FcPatternAddBool (pat, c->object, c->value)) 747 goto bail2; 748 break; 749 default: 750 break; 751 } 752 } 753 } 754 } 755 } 756 757 free (save); 758 return pat; 759 760bail2: 761 FcPatternDestroy (pat); 762bail1: 763 free (save); 764bail0: 765 return 0; 766} 767static FcBool 768FcNameUnparseString (FcStrBuf *buf, 769 const FcChar8 *string, 770 const FcChar8 *escape) 771{ 772 FcChar8 c; 773 while ((c = *string++)) 774 { 775 if (escape && strchr ((char *) escape, (char) c)) 776 { 777 if (!FcStrBufChar (buf, escape[0])) 778 return FcFalse; 779 } 780 if (!FcStrBufChar (buf, c)) 781 return FcFalse; 782 } 783 return FcTrue; 784} 785 786FcBool 787FcNameUnparseValue (FcStrBuf *buf, 788 FcValue *v0, 789 FcChar8 *escape) 790{ 791 FcChar8 temp[1024]; 792 FcValue v = FcValueCanonicalize(v0); 793 794 switch (v.type) { 795 case FcTypeVoid: 796 return FcTrue; 797 case FcTypeInteger: 798 sprintf ((char *) temp, "%d", v.u.i); 799 return FcNameUnparseString (buf, temp, 0); 800 case FcTypeDouble: 801 sprintf ((char *) temp, "%g", v.u.d); 802 return FcNameUnparseString (buf, temp, 0); 803 case FcTypeString: 804 return FcNameUnparseString (buf, v.u.s, escape); 805 case FcTypeBool: 806 return FcNameUnparseString (buf, v.u.b ? (FcChar8 *) "True" : (FcChar8 *) "False", 0); 807 case FcTypeMatrix: 808 sprintf ((char *) temp, "%g %g %g %g", 809 v.u.m->xx, v.u.m->xy, v.u.m->yx, v.u.m->yy); 810 return FcNameUnparseString (buf, temp, 0); 811 case FcTypeCharSet: 812 return FcNameUnparseCharSet (buf, v.u.c); 813 case FcTypeLangSet: 814 return FcNameUnparseLangSet (buf, v.u.l); 815 case FcTypeFTFace: 816 return FcTrue; 817 } 818 return FcFalse; 819} 820 821FcBool 822FcNameUnparseValueList (FcStrBuf *buf, 823 FcValueListPtr v, 824 FcChar8 *escape) 825{ 826 while (v) 827 { 828 if (!FcNameUnparseValue (buf, &v->value, escape)) 829 return FcFalse; 830 if ((v = FcValueListNext(v)) != NULL) 831 if (!FcNameUnparseString (buf, (FcChar8 *) ",", 0)) 832 return FcFalse; 833 } 834 return FcTrue; 835} 836 837#define FC_ESCAPE_FIXED "\\-:," 838#define FC_ESCAPE_VARIABLE "\\=_:," 839 840FcChar8 * 841FcNameUnparse (FcPattern *pat) 842{ 843 return FcNameUnparseEscaped (pat, FcTrue); 844} 845 846FcChar8 * 847FcNameUnparseEscaped (FcPattern *pat, FcBool escape) 848{ 849 FcStrBuf buf; 850 FcChar8 buf_static[8192]; 851 int i; 852 FcPatternElt *e; 853 const FcObjectTypeList *l; 854 const FcObjectType *o; 855 856 FcStrBufInit (&buf, buf_static, sizeof (buf_static)); 857 e = FcPatternObjectFindElt (pat, FC_FAMILY_OBJECT); 858 if (e) 859 { 860 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) 861 goto bail0; 862 } 863 e = FcPatternObjectFindElt (pat, FC_SIZE_OBJECT); 864 if (e) 865 { 866 if (!FcNameUnparseString (&buf, (FcChar8 *) "-", 0)) 867 goto bail0; 868 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? (FcChar8 *) FC_ESCAPE_FIXED : 0)) 869 goto bail0; 870 } 871 for (l = _FcObjectTypes; l; l = l->next) 872 { 873 for (i = 0; i < l->ntypes; i++) 874 { 875 o = &l->types[i]; 876 if (!strcmp (o->object, FC_FAMILY) || 877 !strcmp (o->object, FC_SIZE) || 878 !strcmp (o->object, FC_FILE)) 879 continue; 880 881 e = FcPatternObjectFindElt (pat, FcObjectFromName (o->object)); 882 if (e) 883 { 884 if (!FcNameUnparseString (&buf, (FcChar8 *) ":", 0)) 885 goto bail0; 886 if (!FcNameUnparseString (&buf, (FcChar8 *) o->object, escape ? (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) 887 goto bail0; 888 if (!FcNameUnparseString (&buf, (FcChar8 *) "=", 0)) 889 goto bail0; 890 if (!FcNameUnparseValueList (&buf, FcPatternEltValues(e), escape ? 891 (FcChar8 *) FC_ESCAPE_VARIABLE : 0)) 892 goto bail0; 893 } 894 } 895 } 896 return FcStrBufDone (&buf); 897bail0: 898 FcStrBufDestroy (&buf); 899 return 0; 900} 901#define __fcname__ 902#include "fcaliastail.h" 903#undef __fcname__ 904