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