Coverage Report

Created: 2026-06-30 11:14

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