fcstr.c revision 1cc69409
1/* 2 * fontconfig/src/fcstr.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 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 <stdlib.h> 27#include <ctype.h> 28#include <string.h> 29 30 31/* Objects MT-safe for readonly access. */ 32 33FcChar8 * 34FcStrCopy (const FcChar8 *s) 35{ 36 return FcStrdup (s); 37} 38 39static FcChar8 * 40FcStrMakeTriple (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *s3) 41{ 42 int s1l = s1 ? strlen ((char *) s1) : 0; 43 int s2l = s2 ? strlen ((char *) s2) : 0; 44 int s3l = s3 ? strlen ((char *) s3) : 0; 45 int l = s1l + 1 + s2l + 1 + s3l + 1; 46 FcChar8 *s = malloc (l); 47 48 if (!s) 49 return 0; 50 if (s1) 51 memcpy (s, s1, s1l + 1); 52 else 53 s[0] = '\0'; 54 if (s2) 55 memcpy (s + s1l + 1, s2, s2l + 1); 56 else 57 s[s1l + 1] = '\0'; 58 if (s3) 59 memcpy (s + s1l + 1 + s2l + 1, s3, s3l + 1); 60 else 61 s[s1l + 1 + s2l + 1] = '\0'; 62 return s; 63} 64 65FcChar8 * 66FcStrPlus (const FcChar8 *s1, const FcChar8 *s2) 67{ 68 int s1l = strlen ((char *) s1); 69 int s2l = strlen ((char *) s2); 70 int l = s1l + s2l + 1; 71 FcChar8 *s = malloc (l); 72 73 if (!s) 74 return 0; 75 memcpy (s, s1, s1l); 76 memcpy (s + s1l, s2, s2l + 1); 77 return s; 78} 79 80void 81FcStrFree (FcChar8 *s) 82{ 83 free (s); 84} 85 86 87#include "../fc-case/fccase.h" 88 89#define FcCaseFoldUpperCount(cf) \ 90 ((cf)->method == FC_CASE_FOLD_FULL ? 1 : (cf)->count) 91 92typedef struct _FcCaseWalker { 93 const FcChar8 *read; 94 const FcChar8 *src; 95 FcChar8 utf8[FC_MAX_CASE_FOLD_CHARS + 1]; 96} FcCaseWalker; 97 98static void 99FcStrCaseWalkerInit (const FcChar8 *src, FcCaseWalker *w) 100{ 101 w->src = src; 102 w->read = 0; 103} 104 105static FcChar8 106FcStrCaseWalkerLong (FcCaseWalker *w, FcChar8 r) 107{ 108 FcChar32 ucs4; 109 int slen; 110 int len = strlen((char*)w->src); 111 112 slen = FcUtf8ToUcs4 (w->src - 1, &ucs4, len + 1); 113 if (slen <= 0) 114 return r; 115 if (FC_MIN_FOLD_CHAR <= ucs4 && ucs4 <= FC_MAX_FOLD_CHAR) 116 { 117 int min = 0; 118 int max = FC_NUM_CASE_FOLD; 119 120 while (min <= max) 121 { 122 int mid = (min + max) >> 1; 123 FcChar32 low = fcCaseFold[mid].upper; 124 FcChar32 high = low + FcCaseFoldUpperCount (&fcCaseFold[mid]); 125 126 if (high <= ucs4) 127 min = mid + 1; 128 else if (ucs4 < low) 129 max = mid - 1; 130 else 131 { 132 const FcCaseFold *fold = &fcCaseFold[mid]; 133 int dlen; 134 135 switch (fold->method) { 136 case FC_CASE_FOLD_EVEN_ODD: 137 if ((ucs4 & 1) != (fold->upper & 1)) 138 return r; 139 /* fall through ... */ 140 default: 141 dlen = FcUcs4ToUtf8 (ucs4 + fold->offset, w->utf8); 142 break; 143 case FC_CASE_FOLD_FULL: 144 dlen = fold->count; 145 memcpy (w->utf8, fcCaseFoldChars + fold->offset, dlen); 146 break; 147 } 148 149 /* consume rest of src utf-8 bytes */ 150 w->src += slen - 1; 151 152 /* read from temp buffer */ 153 w->utf8[dlen] = '\0'; 154 w->read = w->utf8; 155 return *w->read++; 156 } 157 } 158 } 159 return r; 160} 161 162static FcChar8 163FcStrCaseWalkerNextNonDelim (FcCaseWalker *w, const char *delims) 164{ 165 FcChar8 r; 166 167 if (FC_UNLIKELY (w->read != NULL)) 168 { 169 if ((r = *w->read++)) 170 return r; 171 w->read = 0; 172 } 173 do 174 { 175 r = *w->src++; 176 } while (r != 0 && delims && strchr (delims, r)); 177 178 if (FC_UNLIKELY ((r & 0xc0) == 0xc0)) 179 return FcStrCaseWalkerLong (w, r); 180 if ('A' <= r && r <= 'Z') 181 r = r - 'A' + 'a'; 182 return r; 183} 184 185static FcChar8 186FcStrCaseWalkerNextNonBlank (FcCaseWalker *w) 187{ 188 FcChar8 r; 189 190 if (FC_UNLIKELY (w->read != NULL)) 191 { 192 if ((r = *w->read++)) 193 return r; 194 w->read = 0; 195 } 196 do 197 { 198 r = *w->src++; 199 } while (r == ' '); 200 201 if (FC_UNLIKELY ((r & 0xc0) == 0xc0)) 202 return FcStrCaseWalkerLong (w, r); 203 if ('A' <= r && r <= 'Z') 204 r = r - 'A' + 'a'; 205 return r; 206} 207 208static FcChar8 209FcStrCaseWalkerNext (FcCaseWalker *w) 210{ 211 FcChar8 r; 212 213 if (FC_UNLIKELY (w->read != NULL)) 214 { 215 if ((r = *w->read++)) 216 return r; 217 w->read = 0; 218 } 219 220 r = *w->src++; 221 222 if (FC_UNLIKELY ((r & 0xc0) == 0xc0)) 223 return FcStrCaseWalkerLong (w, r); 224 if ('A' <= r && r <= 'Z') 225 r = r - 'A' + 'a'; 226 return r; 227} 228 229FcChar8 * 230FcStrDowncase (const FcChar8 *s) 231{ 232 FcCaseWalker w; 233 int len = 0; 234 FcChar8 *dst, *d; 235 236 FcStrCaseWalkerInit (s, &w); 237 while (FcStrCaseWalkerNext (&w)) 238 len++; 239 d = dst = malloc (len + 1); 240 if (!d) 241 return 0; 242 FcStrCaseWalkerInit (s, &w); 243 while ((*d++ = FcStrCaseWalkerNext (&w))); 244 return dst; 245} 246 247int 248FcStrCmpIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 249{ 250 FcCaseWalker w1, w2; 251 FcChar8 c1, c2; 252 253 if (s1 == s2) return 0; 254 255 FcStrCaseWalkerInit (s1, &w1); 256 FcStrCaseWalkerInit (s2, &w2); 257 258 for (;;) 259 { 260 c1 = FcStrCaseWalkerNext (&w1); 261 c2 = FcStrCaseWalkerNext (&w2); 262 if (!c1 || (c1 != c2)) 263 break; 264 } 265 return (int) c1 - (int) c2; 266} 267 268int 269FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 270{ 271 FcCaseWalker w1, w2; 272 FcChar8 c1, c2; 273 274 if (s1 == s2) return 0; 275 276 FcStrCaseWalkerInit (s1, &w1); 277 FcStrCaseWalkerInit (s2, &w2); 278 279 for (;;) 280 { 281 c1 = FcStrCaseWalkerNextNonBlank (&w1); 282 c2 = FcStrCaseWalkerNextNonBlank (&w2); 283 if (!c1 || (c1 != c2)) 284 break; 285 } 286 return (int) c1 - (int) c2; 287} 288 289int 290FcStrCmp (const FcChar8 *s1, const FcChar8 *s2) 291{ 292 FcChar8 c1, c2; 293 294 if (s1 == s2) 295 return 0; 296 for (;;) 297 { 298 c1 = *s1++; 299 c2 = *s2++; 300 if (!c1 || c1 != c2) 301 break; 302 } 303 return (int) c1 - (int) c2; 304} 305 306/* 307 * Return a hash value for a string 308 */ 309 310FcChar32 311FcStrHashIgnoreCase (const FcChar8 *s) 312{ 313 FcChar32 h = 0; 314 FcCaseWalker w; 315 FcChar8 c; 316 317 FcStrCaseWalkerInit (s, &w); 318 while ((c = FcStrCaseWalkerNext (&w))) 319 h = ((h << 3) ^ (h >> 3)) ^ c; 320 return h; 321} 322 323FcChar32 324FcStrHashIgnoreBlanksAndCase (const FcChar8 *s) 325{ 326 FcChar32 h = 0; 327 FcCaseWalker w; 328 FcChar8 c; 329 330 FcStrCaseWalkerInit (s, &w); 331 while ((c = FcStrCaseWalkerNextNonBlank (&w))) 332 h = ((h << 3) ^ (h >> 3)) ^ c; 333 return h; 334} 335 336/* 337 * Is the head of s1 equal to s2? 338 */ 339 340static FcBool 341FcStrIsAtIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 342{ 343 FcCaseWalker w1, w2; 344 FcChar8 c1, c2; 345 346 FcStrCaseWalkerInit (s1, &w1); 347 FcStrCaseWalkerInit (s2, &w2); 348 349 for (;;) 350 { 351 c1 = FcStrCaseWalkerNextNonBlank (&w1); 352 c2 = FcStrCaseWalkerNextNonBlank (&w2); 353 if (!c1 || (c1 != c2)) 354 break; 355 } 356 return c1 == c2 || !c2; 357} 358 359/* 360 * Does s1 contain an instance of s2 (ignoring blanks and case)? 361 */ 362 363const FcChar8 * 364FcStrContainsIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2) 365{ 366 while (*s1) 367 { 368 if (FcStrIsAtIgnoreBlanksAndCase (s1, s2)) 369 return s1; 370 s1++; 371 } 372 return 0; 373} 374 375static FcBool 376FcCharIsPunct (const FcChar8 c) 377{ 378 if (c < '0') 379 return FcTrue; 380 if (c <= '9') 381 return FcFalse; 382 if (c < 'A') 383 return FcTrue; 384 if (c <= 'Z') 385 return FcFalse; 386 if (c < 'a') 387 return FcTrue; 388 if (c <= 'z') 389 return FcFalse; 390 if (c <= '~') 391 return FcTrue; 392 return FcFalse; 393} 394 395/* 396 * Is the head of s1 equal to s2? 397 */ 398 399static FcBool 400FcStrIsAtIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 401{ 402 FcCaseWalker w1, w2; 403 FcChar8 c1, c2; 404 405 FcStrCaseWalkerInit (s1, &w1); 406 FcStrCaseWalkerInit (s2, &w2); 407 408 for (;;) 409 { 410 c1 = FcStrCaseWalkerNext (&w1); 411 c2 = FcStrCaseWalkerNext (&w2); 412 if (!c1 || (c1 != c2)) 413 break; 414 } 415 return c1 == c2 || !c2; 416} 417 418/* 419 * Does s1 contain an instance of s2 (ignoring blanks and case)? 420 */ 421 422const FcChar8 * 423FcStrContainsIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 424{ 425 while (*s1) 426 { 427 if (FcStrIsAtIgnoreCase (s1, s2)) 428 return s1; 429 s1++; 430 } 431 return 0; 432} 433 434/* 435 * Does s1 contain an instance of s2 on a word boundary (ignoring case)? 436 */ 437 438const FcChar8 * 439FcStrContainsWord (const FcChar8 *s1, const FcChar8 *s2) 440{ 441 FcBool wordStart = FcTrue; 442 int s1len = strlen ((char *) s1); 443 int s2len = strlen ((char *) s2); 444 445 while (s1len >= s2len) 446 { 447 if (wordStart && 448 FcStrIsAtIgnoreCase (s1, s2) && 449 (s1len == s2len || FcCharIsPunct (s1[s2len]))) 450 { 451 return s1; 452 } 453 wordStart = FcFalse; 454 if (FcCharIsPunct (*s1)) 455 wordStart = FcTrue; 456 s1++; 457 s1len--; 458 } 459 return 0; 460} 461 462/* 463 * returns the number of strings (ignoring delimiters and case) being matched 464 */ 465 466int 467FcStrMatchIgnoreCaseAndDelims (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 *delims) 468{ 469 FcCaseWalker w1, w2; 470 FcChar8 c1, c2; 471 472 if (s1 == s2) return 0; 473 474 FcStrCaseWalkerInit (s1, &w1); 475 FcStrCaseWalkerInit (s2, &w2); 476 477 for (;;) 478 { 479 c1 = FcStrCaseWalkerNextNonDelim (&w1, (const char *)delims); 480 c2 = FcStrCaseWalkerNextNonDelim (&w2, (const char *)delims); 481 if (!c1 || (c1 != c2)) 482 break; 483 } 484 return w1.src - s1 - 1; 485} 486 487FcBool 488FcStrGlobMatch (const FcChar8 *glob, 489 const FcChar8 *string) 490{ 491 FcChar8 c; 492 493 while ((c = *glob++)) 494 { 495 switch (c) { 496 case '*': 497 /* short circuit common case */ 498 if (!*glob) 499 return FcTrue; 500 /* short circuit another common case */ 501 if (strchr ((char *) glob, '*') == 0) 502 { 503 size_t l1, l2; 504 505 l1 = strlen ((char *) string); 506 l2 = strlen ((char *) glob); 507 if (l1 < l2) 508 return FcFalse; 509 string += (l1 - l2); 510 } 511 while (*string) 512 { 513 if (FcStrGlobMatch (glob, string)) 514 return FcTrue; 515 string++; 516 } 517 return FcFalse; 518 case '?': 519 if (*string++ == '\0') 520 return FcFalse; 521 break; 522 default: 523 if (*string++ != c) 524 return FcFalse; 525 break; 526 } 527 } 528 return *string == '\0'; 529} 530 531const FcChar8 * 532FcStrStrIgnoreCase (const FcChar8 *s1, const FcChar8 *s2) 533{ 534 FcCaseWalker w1, w2; 535 FcChar8 c1, c2; 536 const FcChar8 *cur; 537 538 if (!s1 || !s2) 539 return 0; 540 541 if (s1 == s2) 542 return s1; 543 544 FcStrCaseWalkerInit (s1, &w1); 545 FcStrCaseWalkerInit (s2, &w2); 546 547 c2 = FcStrCaseWalkerNext (&w2); 548 549 for (;;) 550 { 551 cur = w1.src; 552 c1 = FcStrCaseWalkerNext (&w1); 553 if (!c1) 554 break; 555 if (c1 == c2) 556 { 557 FcCaseWalker w1t = w1; 558 FcCaseWalker w2t = w2; 559 FcChar8 c1t, c2t; 560 561 for (;;) 562 { 563 c1t = FcStrCaseWalkerNext (&w1t); 564 c2t = FcStrCaseWalkerNext (&w2t); 565 566 if (!c2t) 567 return cur; 568 if (c2t != c1t) 569 break; 570 } 571 } 572 } 573 return 0; 574} 575 576const FcChar8 * 577FcStrStr (const FcChar8 *s1, const FcChar8 *s2) 578{ 579 FcChar8 c1, c2; 580 const FcChar8 * p = s1; 581 const FcChar8 * b = s2; 582 583 if (!s1 || !s2) 584 return 0; 585 586 if (s1 == s2) 587 return s1; 588 589again: 590 c2 = *s2++; 591 592 if (!c2) 593 return 0; 594 595 for (;;) 596 { 597 p = s1; 598 c1 = *s1++; 599 if (!c1 || c1 == c2) 600 break; 601 } 602 603 if (c1 != c2) 604 return 0; 605 606 for (;;) 607 { 608 c1 = *s1; 609 c2 = *s2; 610 if (c1 && c2 && c1 != c2) 611 { 612 s1 = p + 1; 613 s2 = b; 614 goto again; 615 } 616 if (!c2) 617 return p; 618 if (!c1) 619 return 0; 620 ++ s1; 621 ++ s2; 622 } 623 /* never reached. */ 624} 625 626int 627FcUtf8ToUcs4 (const FcChar8 *src_orig, 628 FcChar32 *dst, 629 int len) 630{ 631 const FcChar8 *src = src_orig; 632 FcChar8 s; 633 int extra; 634 FcChar32 result; 635 636 if (len == 0) 637 return 0; 638 639 s = *src++; 640 len--; 641 642 if (!(s & 0x80)) 643 { 644 result = s; 645 extra = 0; 646 } 647 else if (!(s & 0x40)) 648 { 649 return -1; 650 } 651 else if (!(s & 0x20)) 652 { 653 result = s & 0x1f; 654 extra = 1; 655 } 656 else if (!(s & 0x10)) 657 { 658 result = s & 0xf; 659 extra = 2; 660 } 661 else if (!(s & 0x08)) 662 { 663 result = s & 0x07; 664 extra = 3; 665 } 666 else if (!(s & 0x04)) 667 { 668 result = s & 0x03; 669 extra = 4; 670 } 671 else if ( ! (s & 0x02)) 672 { 673 result = s & 0x01; 674 extra = 5; 675 } 676 else 677 { 678 return -1; 679 } 680 if (extra > len) 681 return -1; 682 683 while (extra--) 684 { 685 result <<= 6; 686 s = *src++; 687 688 if ((s & 0xc0) != 0x80) 689 return -1; 690 691 result |= s & 0x3f; 692 } 693 *dst = result; 694 return src - src_orig; 695} 696 697FcBool 698FcUtf8Len (const FcChar8 *string, 699 int len, 700 int *nchar, 701 int *wchar) 702{ 703 int n; 704 int clen; 705 FcChar32 c; 706 FcChar32 max; 707 708 n = 0; 709 max = 0; 710 while (len) 711 { 712 clen = FcUtf8ToUcs4 (string, &c, len); 713 if (clen <= 0) /* malformed UTF8 string */ 714 return FcFalse; 715 if (c > max) 716 max = c; 717 string += clen; 718 len -= clen; 719 n++; 720 } 721 *nchar = n; 722 if (max >= 0x10000) 723 *wchar = 4; 724 else if (max > 0x100) 725 *wchar = 2; 726 else 727 *wchar = 1; 728 return FcTrue; 729} 730 731int 732FcUcs4ToUtf8 (FcChar32 ucs4, 733 FcChar8 dest[FC_UTF8_MAX_LEN]) 734{ 735 int bits; 736 FcChar8 *d = dest; 737 738 if (ucs4 < 0x80) { *d++= ucs4; bits= -6; } 739 else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; } 740 else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; } 741 else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; } 742 else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; } 743 else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; } 744 else return 0; 745 746 for ( ; bits >= 0; bits-= 6) { 747 *d++= ((ucs4 >> bits) & 0x3F) | 0x80; 748 } 749 return d - dest; 750} 751 752#define GetUtf16(src,endian) \ 753 ((FcChar16) ((src)[endian == FcEndianBig ? 0 : 1] << 8) | \ 754 (FcChar16) ((src)[endian == FcEndianBig ? 1 : 0])) 755 756int 757FcUtf16ToUcs4 (const FcChar8 *src_orig, 758 FcEndian endian, 759 FcChar32 *dst, 760 int len) /* in bytes */ 761{ 762 const FcChar8 *src = src_orig; 763 FcChar16 a, b; 764 FcChar32 result; 765 766 if (len < 2) 767 return 0; 768 769 a = GetUtf16 (src, endian); src += 2; len -= 2; 770 771 /* 772 * Check for surrogate 773 */ 774 if ((a & 0xfc00) == 0xd800) 775 { 776 if (len < 2) 777 return 0; 778 b = GetUtf16 (src, endian); src += 2; len -= 2; 779 /* 780 * Check for invalid surrogate sequence 781 */ 782 if ((b & 0xfc00) != 0xdc00) 783 return 0; 784 result = ((((FcChar32) a & 0x3ff) << 10) | 785 ((FcChar32) b & 0x3ff)) + 0x10000; 786 } 787 else 788 result = a; 789 *dst = result; 790 return src - src_orig; 791} 792 793FcBool 794FcUtf16Len (const FcChar8 *string, 795 FcEndian endian, 796 int len, /* in bytes */ 797 int *nchar, 798 int *wchar) 799{ 800 int n; 801 int clen; 802 FcChar32 c; 803 FcChar32 max; 804 805 n = 0; 806 max = 0; 807 while (len) 808 { 809 clen = FcUtf16ToUcs4 (string, endian, &c, len); 810 if (clen <= 0) /* malformed UTF8 string */ 811 return FcFalse; 812 if (c > max) 813 max = c; 814 string += clen; 815 len -= clen; 816 n++; 817 } 818 *nchar = n; 819 if (max >= 0x10000) 820 *wchar = 4; 821 else if (max > 0x100) 822 *wchar = 2; 823 else 824 *wchar = 1; 825 return FcTrue; 826} 827 828void 829FcStrBufInit (FcStrBuf *buf, FcChar8 *init, int size) 830{ 831 if (init) 832 { 833 buf->buf = init; 834 buf->size = size; 835 } else 836 { 837 buf->buf = buf->buf_static; 838 buf->size = sizeof (buf->buf_static); 839 } 840 buf->allocated = FcFalse; 841 buf->failed = FcFalse; 842 buf->len = 0; 843} 844 845void 846FcStrBufDestroy (FcStrBuf *buf) 847{ 848 if (buf->allocated) 849 { 850 free (buf->buf); 851 FcStrBufInit (buf, 0, 0); 852 } 853} 854 855FcChar8 * 856FcStrBufDone (FcStrBuf *buf) 857{ 858 FcChar8 *ret; 859 860 if (buf->failed) 861 ret = NULL; 862 else 863 ret = malloc (buf->len + 1); 864 if (ret) 865 { 866 memcpy (ret, buf->buf, buf->len); 867 ret[buf->len] = '\0'; 868 } 869 FcStrBufDestroy (buf); 870 return ret; 871} 872 873FcChar8 * 874FcStrBufDoneStatic (FcStrBuf *buf) 875{ 876 FcStrBufChar (buf, '\0'); 877 878 if (buf->failed) 879 return NULL; 880 881 return buf->buf; 882} 883 884FcBool 885FcStrBufChar (FcStrBuf *buf, FcChar8 c) 886{ 887 if (buf->len == buf->size) 888 { 889 FcChar8 *new; 890 int size; 891 892 if (buf->failed) 893 return FcFalse; 894 895 if (buf->allocated) 896 { 897 size = buf->size * 2; 898 new = realloc (buf->buf, size); 899 } 900 else 901 { 902 size = buf->size + 64; 903 new = malloc (size); 904 if (new) 905 { 906 buf->allocated = FcTrue; 907 memcpy (new, buf->buf, buf->len); 908 } 909 } 910 if (!new) 911 { 912 buf->failed = FcTrue; 913 return FcFalse; 914 } 915 buf->size = size; 916 buf->buf = new; 917 } 918 buf->buf[buf->len++] = c; 919 return FcTrue; 920} 921 922FcBool 923FcStrBufString (FcStrBuf *buf, const FcChar8 *s) 924{ 925 FcChar8 c; 926 while ((c = *s++)) 927 if (!FcStrBufChar (buf, c)) 928 return FcFalse; 929 return FcTrue; 930} 931 932FcBool 933FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len) 934{ 935 while (len-- > 0) 936 if (!FcStrBufChar (buf, *s++)) 937 return FcFalse; 938 return FcTrue; 939} 940 941FcBool 942FcStrUsesHome (const FcChar8 *s) 943{ 944 return *s == '~'; 945} 946 947FcBool 948FcStrIsAbsoluteFilename (const FcChar8 *s) 949{ 950#ifdef _WIN32 951 if (*s == '\\' || 952 (isalpha (*s) && s[1] == ':' && (s[2] == '/' || s[2] == '\\'))) 953 return FcTrue; 954#endif 955 return *s == '/'; 956} 957 958FcChar8 * 959FcStrBuildFilename (const FcChar8 *path, 960 ...) 961{ 962 va_list ap; 963 FcStrSet *sset; 964 FcStrList *list; 965 FcChar8 *s, *ret = NULL, *p; 966 size_t len = 0; 967 968 if (!path) 969 return NULL; 970 971 sset = FcStrSetCreateEx (FCSS_ALLOW_DUPLICATES | FCSS_GROW_BY_64); 972 if (!sset) 973 return NULL; 974 975 if (!FcStrSetAdd (sset, path)) 976 goto bail0; 977 978 va_start (ap, path); 979 while (1) 980 { 981 s = (FcChar8 *)va_arg (ap, FcChar8 *); 982 if (!s) 983 break; 984 if (!FcStrSetAdd (sset, s)) 985 goto bail1; 986 } 987 list = FcStrListCreate (sset); 988 while ((s = FcStrListNext (list))) 989 { 990 len += strlen ((const char *)s) + 1; 991 } 992 list->n = 0; 993 ret = malloc (sizeof (FcChar8) * (len + 1)); 994 if (!ret) 995 goto bail2; 996 p = ret; 997 while ((s = FcStrListNext (list))) 998 { 999 if (p != ret) 1000 { 1001 p[0] = FC_DIR_SEPARATOR; 1002 p++; 1003 } 1004 len = strlen ((const char *)s); 1005 memcpy (p, s, len); 1006 p += len; 1007 } 1008 *p = 0; 1009 1010bail2: 1011 FcStrListDone (list); 1012bail1: 1013 va_end (ap); 1014bail0: 1015 FcStrSetDestroy (sset); 1016 1017 return ret; 1018} 1019 1020FcChar8 * 1021FcStrCopyFilename (const FcChar8 *s) 1022{ 1023 FcChar8 *new; 1024 1025 if (*s == '~') 1026 { 1027 FcChar8 *home = FcConfigHome (); 1028 FcChar8 *full; 1029 int size; 1030 if (!home) 1031 return NULL; 1032 size = strlen ((char *) home) + strlen ((char *) s); 1033 full = (FcChar8 *) malloc (size + 1); 1034 if (!full) 1035 return NULL; 1036 strcpy ((char *) full, (char *) home); 1037 strcat ((char *) full, (char *) s + 1); 1038 new = FcStrCanonFilename (full); 1039 free (full); 1040 } 1041 else 1042 new = FcStrCanonFilename (s); 1043 1044 return new; 1045} 1046 1047FcChar8 * 1048FcStrLastSlash (const FcChar8 *path) 1049{ 1050 FcChar8 *slash; 1051 1052 slash = (FcChar8 *) strrchr ((const char *) path, '/'); 1053#ifdef _WIN32 1054 { 1055 FcChar8 *backslash; 1056 1057 backslash = (FcChar8 *) strrchr ((const char *) path, '\\'); 1058 if (!slash || (backslash && backslash > slash)) 1059 slash = backslash; 1060 } 1061#endif 1062 1063 return slash; 1064} 1065 1066FcChar8 * 1067FcStrDirname (const FcChar8 *file) 1068{ 1069 FcChar8 *slash; 1070 FcChar8 *dir; 1071 1072 slash = FcStrLastSlash (file); 1073 if (!slash) 1074 return FcStrCopy ((FcChar8 *) "."); 1075 dir = malloc ((slash - file) + 1); 1076 if (!dir) 1077 return 0; 1078 strncpy ((char *) dir, (const char *) file, slash - file); 1079 dir[slash - file] = '\0'; 1080 return dir; 1081} 1082 1083FcChar8 * 1084FcStrBasename (const FcChar8 *file) 1085{ 1086 FcChar8 *slash; 1087 1088 slash = FcStrLastSlash (file); 1089 if (!slash) 1090 return FcStrCopy (file); 1091 return FcStrCopy (slash + 1); 1092} 1093 1094FcChar8 * 1095FcStrRealPath (const FcChar8 *path) 1096{ 1097 char resolved_name[FC_PATH_MAX+1]; 1098 char *resolved_ret; 1099 1100 if (!path) 1101 return NULL; 1102 1103#ifndef _WIN32 1104 resolved_ret = realpath((const char *) path, resolved_name); 1105#else 1106 if (GetFullPathNameA ((LPCSTR) path, FC_PATH_MAX, resolved_name, NULL) == 0) 1107 { 1108 fprintf (stderr, "Fontconfig warning: GetFullPathNameA failed.\n"); 1109 return NULL; 1110 } 1111 resolved_ret = resolved_name; 1112#endif 1113 if (resolved_ret) 1114 path = (FcChar8 *) resolved_ret; 1115 return FcStrCopyFilename(path); 1116} 1117 1118static FcChar8 * 1119FcStrCanonAbsoluteFilename (const FcChar8 *s) 1120{ 1121 FcChar8 *file; 1122 FcChar8 *f; 1123 const FcChar8 *slash; 1124 int size; 1125 1126 size = strlen ((char *) s) + 1; 1127 file = malloc (size); 1128 if (!file) 1129 return NULL; 1130 slash = NULL; 1131 f = file; 1132#ifdef _WIN32 1133 if (*s == '/' && *(s+1) == '/') /* Network path, do not squash // */ 1134 *f++ = *s++; 1135#endif 1136 for (;;) { 1137 if (*s == '/' || *s == '\0') 1138 { 1139 if (slash) 1140 { 1141 switch (s - slash) { 1142 case 1: 1143 f -= 1; /* squash // and trim final / from file */ 1144 break; 1145 case 2: 1146 if (!strncmp ((char *) slash, "/.", 2)) 1147 { 1148 f -= 2; /* trim /. from file */ 1149 } 1150 break; 1151 case 3: 1152 if (!strncmp ((char *) slash, "/..", 3)) 1153 { 1154 f -= 3; /* trim /.. from file */ 1155 while (f > file) { 1156 if (*--f == '/') 1157 break; 1158 } 1159 } 1160 break; 1161 } 1162 } 1163 slash = s; 1164 } 1165 if (!(*f++ = *s++)) 1166 break; 1167 } 1168 return file; 1169} 1170 1171#ifdef _WIN32 1172/* 1173 * Convert '\\' to '/' , remove double '/' 1174 */ 1175static void 1176FcConvertDosPath (char *str) 1177{ 1178 size_t len = strlen (str); 1179 char *p = str; 1180 char *dest = str; 1181 char *end = str + len; 1182 char last = 0; 1183 1184 if (*p == '\\') 1185 { 1186 *p = '/'; 1187 p++; 1188 dest++; 1189 } 1190 while (p < end) 1191 { 1192 if (*p == '\\') 1193 *p = '/'; 1194 1195 if (*p != '/' 1196 || last != '/') 1197 { 1198 *dest++ = *p; 1199 } 1200 1201 last = *p; 1202 p++; 1203 } 1204 1205 *dest = 0; 1206} 1207#endif 1208 1209FcChar8 * 1210FcStrCanonFilename (const FcChar8 *s) 1211{ 1212#ifdef _WIN32 1213 FcChar8 full[FC_MAX_FILE_LEN + 2]; 1214 int size = GetFullPathName ((LPCSTR) s, sizeof (full) -1, 1215 (LPSTR) full, NULL); 1216 1217 if (size == 0) 1218 perror ("GetFullPathName"); 1219 1220 FcConvertDosPath ((char *) full); 1221 return FcStrCanonAbsoluteFilename (full); 1222#else 1223 if (s[0] == '/') 1224 return FcStrCanonAbsoluteFilename (s); 1225 else 1226 { 1227 FcChar8 *full; 1228 FcChar8 *file; 1229 1230 FcChar8 cwd[FC_MAX_FILE_LEN + 2]; 1231 if (getcwd ((char *) cwd, FC_MAX_FILE_LEN) == NULL) 1232 return NULL; 1233 full = FcStrBuildFilename (cwd, s, NULL); 1234 file = FcStrCanonAbsoluteFilename (full); 1235 FcStrFree (full); 1236 return file; 1237 } 1238#endif 1239} 1240 1241 1242FcStrSet * 1243FcStrSetCreate (void) 1244{ 1245 return FcStrSetCreateEx (FCSS_DEFAULT); 1246} 1247 1248FcStrSet * 1249FcStrSetCreateEx (unsigned int control) 1250{ 1251 FcStrSet *set = malloc (sizeof (FcStrSet)); 1252 if (!set) 1253 return 0; 1254 FcRefInit (&set->ref, 1); 1255 set->num = 0; 1256 set->size = 0; 1257 set->strs = 0; 1258 set->control = control; 1259 return set; 1260} 1261 1262static FcBool 1263_FcStrSetGrow (FcStrSet *set, int growElements) 1264{ 1265 /* accommodate an additional NULL entry at the end of the array */ 1266 FcChar8 **strs = malloc ((set->size + growElements + 1) * sizeof (FcChar8 *)); 1267 if (!strs) 1268 return FcFalse; 1269 if (set->num) 1270 memcpy (strs, set->strs, set->num * sizeof (FcChar8 *)); 1271 if (set->strs) 1272 free (set->strs); 1273 set->size = set->size + growElements; 1274 set->strs = strs; 1275 return FcTrue; 1276} 1277 1278static FcBool 1279_FcStrSetInsert (FcStrSet *set, FcChar8 *s, int pos) 1280{ 1281 if (!FcStrSetHasControlBit (set, FCSS_ALLOW_DUPLICATES)) 1282 { 1283 if (FcStrSetMember (set, s)) 1284 { 1285 FcStrFree (s); 1286 return FcTrue; 1287 } 1288 } 1289 if (set->num == set->size) 1290 { 1291 int growElements = FcStrSetHasControlBit (set, FCSS_GROW_BY_64) ? 64 : 1; 1292 if (!_FcStrSetGrow(set, growElements)) 1293 return FcFalse; 1294 } 1295 if (pos >= set->num) 1296 { 1297 set->strs[set->num++] = s; 1298 set->strs[set->num] = 0; 1299 } 1300 else 1301 { 1302 int i; 1303 1304 set->num++; 1305 set->strs[set->num] = 0; 1306 for (i = set->num - 1; i > pos; i--) 1307 set->strs[i] = set->strs[i - 1]; 1308 set->strs[pos] = s; 1309 } 1310 return FcTrue; 1311} 1312 1313FcBool 1314FcStrSetMember (FcStrSet *set, const FcChar8 *s) 1315{ 1316 int i; 1317 1318 for (i = 0; i < set->num; i++) 1319 if (!FcStrCmp (set->strs[i], s)) 1320 return FcTrue; 1321 return FcFalse; 1322} 1323 1324static int 1325fc_strcmp_r (const FcChar8 *s1, const FcChar8 *s2, const FcChar8 **ret) 1326{ 1327 FcChar8 c1, c2; 1328 1329 if (s1 == s2) 1330 { 1331 if (ret) 1332 *ret = NULL; 1333 return 0; 1334 } 1335 for (;;) 1336 { 1337 if (s1) 1338 c1 = *s1++; 1339 else 1340 c1 = 0; 1341 if (s2) 1342 c2 = *s2++; 1343 else 1344 c2 = 0; 1345 if (!c1 || c1 != c2) 1346 break; 1347 } 1348 if (ret) 1349 *ret = s1; 1350 return (int) c1 - (int) c2; 1351} 1352 1353FcBool 1354FcStrSetMemberAB (FcStrSet *set, const FcChar8 *a, FcChar8 *b, FcChar8 **ret) 1355{ 1356 int i; 1357 const FcChar8 *s = NULL; 1358 1359 for (i = 0; i < set->num; i++) 1360 { 1361 if (!fc_strcmp_r (set->strs[i], a, &s) && s) 1362 { 1363 if (!fc_strcmp_r (s, b, NULL)) 1364 { 1365 if (ret) 1366 *ret = set->strs[i]; 1367 return FcTrue; 1368 } 1369 } 1370 } 1371 if (ret) 1372 *ret = NULL; 1373 return FcFalse; 1374} 1375 1376FcBool 1377FcStrSetEqual (FcStrSet *sa, FcStrSet *sb) 1378{ 1379 int i; 1380 if (sa->num != sb->num) 1381 return FcFalse; 1382 for (i = 0; i < sa->num; i++) 1383 if (!FcStrSetMember (sb, sa->strs[i])) 1384 return FcFalse; 1385 return FcTrue; 1386} 1387 1388FcBool 1389FcStrSetAdd (FcStrSet *set, const FcChar8 *s) 1390{ 1391 FcChar8 *new = FcStrCopy (s); 1392 if (!new) 1393 return FcFalse; 1394 if (!_FcStrSetInsert (set, new, set->num)) 1395 { 1396 FcStrFree (new); 1397 return FcFalse; 1398 } 1399 return FcTrue; 1400} 1401 1402FcBool 1403FcStrSetInsert (FcStrSet *set, const FcChar8 *s, int pos) 1404{ 1405 FcChar8 *new = FcStrCopy (s); 1406 if (!new) 1407 return FcFalse; 1408 if (!_FcStrSetInsert (set, new, pos)) 1409 { 1410 FcStrFree (new); 1411 return FcFalse; 1412 } 1413 return FcTrue; 1414} 1415 1416FcBool 1417FcStrSetAddTriple (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *c) 1418{ 1419 FcChar8 *new = FcStrMakeTriple (a, b, c); 1420 if (!new) 1421 return FcFalse; 1422 if (!_FcStrSetInsert (set, new, set->num)) 1423 { 1424 FcStrFree (new); 1425 return FcFalse; 1426 } 1427 return FcTrue; 1428} 1429 1430const FcChar8 * 1431FcStrTripleSecond (FcChar8 *str) 1432{ 1433 FcChar8 *second = str + strlen((char *) str) + 1; 1434 1435 if (*second == '\0') 1436 return 0; 1437 return second; 1438} 1439 1440const FcChar8 * 1441FcStrTripleThird (FcChar8 *str) 1442{ 1443 FcChar8 *second = str + strlen ((char *) str) + 1; 1444 FcChar8 *third = second + strlen ((char *) second) + 1; 1445 1446 if (*third == '\0') 1447 return 0; 1448 return third; 1449} 1450 1451FcBool 1452FcStrSetAddFilename (FcStrSet *set, const FcChar8 *s) 1453{ 1454 FcChar8 *new = FcStrCopyFilename (s); 1455 if (!new) 1456 return FcFalse; 1457 if (!_FcStrSetInsert (set, new, set->num)) 1458 { 1459 FcStrFree (new); 1460 return FcFalse; 1461 } 1462 return FcTrue; 1463} 1464 1465FcBool 1466FcStrSetAddFilenamePairWithSalt (FcStrSet *set, const FcChar8 *a, const FcChar8 *b, const FcChar8 *salt) 1467{ 1468 FcChar8 *new_a = NULL; 1469 FcChar8 *new_b = NULL; 1470 FcBool ret; 1471 1472 if (a) 1473 { 1474 new_a = FcStrCopyFilename (a); 1475 if (!new_a) 1476 return FcFalse; 1477 } 1478 if (b) 1479 { 1480 new_b = FcStrCopyFilename(b); 1481 if (!new_b) 1482 { 1483 if (new_a) 1484 FcStrFree(new_a); 1485 return FcFalse; 1486 } 1487 } 1488 /* Override maps with new one if exists */ 1489 FcStrSetDel (set, new_a); 1490 ret = FcStrSetAddTriple (set, new_a, new_b, salt); 1491 if (new_a) 1492 FcStrFree (new_a); 1493 if (new_b) 1494 FcStrFree (new_b); 1495 return ret; 1496} 1497 1498FcBool 1499FcStrSetAddLangs (FcStrSet *strs, const char *languages) 1500{ 1501 const char *p = languages, *next; 1502 FcChar8 lang[128] = {0}, *normalized_lang; 1503 size_t len; 1504 FcBool ret = FcFalse; 1505 1506 if (!languages) 1507 return FcFalse; 1508 1509 while ((next = strchr (p, ':'))) 1510 { 1511 len = next - p; 1512 len = FC_MIN (len, 127); 1513 strncpy ((char *) lang, p, len); 1514 lang[len] = 0; 1515 /* ignore an empty item */ 1516 if (*lang) 1517 { 1518 normalized_lang = FcLangNormalize ((const FcChar8 *) lang); 1519 if (normalized_lang) 1520 { 1521 FcStrSetAdd (strs, normalized_lang); 1522 FcStrFree (normalized_lang); 1523 ret = FcTrue; 1524 } 1525 } 1526 p = next + 1; 1527 } 1528 if (*p) 1529 { 1530 normalized_lang = FcLangNormalize ((const FcChar8 *) p); 1531 if (normalized_lang) 1532 { 1533 FcStrSetAdd (strs, normalized_lang); 1534 FcStrFree (normalized_lang); 1535 ret = FcTrue; 1536 } 1537 } 1538 1539 return ret; 1540} 1541 1542FcBool 1543FcStrSetDel (FcStrSet *set, const FcChar8 *s) 1544{ 1545 int i; 1546 1547 for (i = 0; i < set->num; i++) 1548 if (!FcStrCmp (set->strs[i], s)) 1549 { 1550 FcStrFree (set->strs[i]); 1551 /* 1552 * copy remaining string pointers and trailing 1553 * NULL 1554 */ 1555 memmove (&set->strs[i], &set->strs[i+1], 1556 (set->num - i) * sizeof (FcChar8 *)); 1557 set->num--; 1558 return FcTrue; 1559 } 1560 return FcFalse; 1561} 1562 1563FcBool 1564FcStrSetDeleteAll (FcStrSet *set) 1565{ 1566 int i; 1567 1568 if (FcRefIsConst (&set->ref)) 1569 return FcFalse; 1570 1571 for (i = set->num; i > 0; i--) 1572 { 1573 FcStrFree (set->strs[i - 1]); 1574 set->num--; 1575 } 1576 return FcTrue; 1577} 1578 1579/* TODO Make public */ 1580static FcStrSet * 1581FcStrSetReference (FcStrSet *set) 1582{ 1583 if (FcRefIsConst (&set->ref)) 1584 return set; 1585 1586 FcRefInc (&set->ref); 1587 return set; 1588} 1589 1590void 1591FcStrSetDestroy (FcStrSet *set) 1592{ 1593 if (set) 1594 { 1595 int i; 1596 1597 /* We rely on this in FcGetDefaultLangs for caching. */ 1598 if (FcRefIsConst (&set->ref)) 1599 return; 1600 1601 if (FcRefDec (&set->ref) != 1) 1602 return; 1603 1604 for (i = 0; i < set->num; i++) 1605 FcStrFree (set->strs[i]); 1606 if (set->strs) 1607 free (set->strs); 1608 free (set); 1609 } 1610} 1611 1612FcStrList * 1613FcStrListCreate (FcStrSet *set) 1614{ 1615 FcStrList *list; 1616 1617 list = malloc (sizeof (FcStrList)); 1618 if (!list) 1619 return 0; 1620 list->set = set; 1621 FcStrSetReference (set); 1622 list->n = 0; 1623 return list; 1624} 1625 1626void 1627FcStrListFirst (FcStrList *list) 1628{ 1629 list->n = 0; 1630} 1631 1632FcChar8 * 1633FcStrListNext (FcStrList *list) 1634{ 1635 if (list->n >= list->set->num) 1636 return 0; 1637 return list->set->strs[list->n++]; 1638} 1639 1640void 1641FcStrListDone (FcStrList *list) 1642{ 1643 FcStrSetDestroy (list->set); 1644 free (list); 1645} 1646 1647#define __fcstr__ 1648#include "fcaliastail.h" 1649#undef __fcstr__ 1650