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