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