]> git.wh0rd.org - fontconfig.git/blame - src/fclang.c
Bug 23419 - "contains" expression seems not working on the fontconfig rule
[fontconfig.git] / src / fclang.c
CommitLineData
3de8881e 1/*
317b8492 2 * fontconfig/src/fclang.c
3de8881e 3 *
46b51147 4 * Copyright © 2002 Keith Packard
3de8881e
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
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission. Keith Packard makes no
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,
3de8881e 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
3de8881e
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
25#include "fcint.h"
dbd065ad 26#include "fcftint.h"
3de8881e
KP
27
28typedef struct {
e85789a9 29 const FcChar8 lang[8];
21696e5b 30 const FcCharSet charset;
3de8881e
KP
31} FcLangCharSet;
32
793e946c
KP
33typedef struct {
34 int begin;
35 int end;
36} FcLangCharSetRange;
37
e50b9ae7 38#include "../fc-lang/fclang.h"
3de8881e 39
d8d73958
KP
40struct _FcLangSet {
41 FcChar32 map[NUM_LANG_SET_MAP];
4262e0b3 42 FcStrSet *extra;
d8d73958
KP
43};
44
ffd6668b
BE
45#define FcLangSetBitSet(ls, id) ((ls)->map[(fcLangCharSetIndices[id])>>5] |= ((FcChar32) 1 << ((fcLangCharSetIndices[id]) & 0x1f)))
46#define FcLangSetBitGet(ls, id) (((ls)->map[(fcLangCharSetIndices[id])>>5] >> ((fcLangCharSetIndices[id]) & 0x1f)) & 1)
d8d73958
KP
47
48FcLangSet *
49FcFreeTypeLangSet (const FcCharSet *charset,
e50b9ae7 50 const FcChar8 *exclusiveLang)
3de8881e 51{
cd2ec1a9 52 int i, j;
e50b9ae7 53 FcChar32 missing;
e50b9ae7 54 const FcCharSet *exclusiveCharset = 0;
d8d73958 55 FcLangSet *ls;
82f35f8b 56
e50b9ae7 57 if (exclusiveLang)
cf223cc7 58 exclusiveCharset = FcLangGetCharSet (exclusiveLang);
d8d73958
KP
59 ls = FcLangSetCreate ();
60 if (!ls)
61 return 0;
7ce19673
KP
62 if (FcDebug() & FC_DBG_LANGSET)
63 {
7c12181f 64 printf ("font charset");
7ce19673
KP
65 FcCharSetPrint (charset);
66 printf ("\n");
67 }
3de8881e
KP
68 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
69 {
7ce19673
KP
70 if (FcDebug() & FC_DBG_LANGSET)
71 {
7c12181f 72 printf ("%s charset", fcLangCharSets[i].lang);
7ce19673
KP
73 FcCharSetPrint (&fcLangCharSets[i].charset);
74 printf ("\n");
75 }
76
e50b9ae7
KP
77 /*
78 * Check for Han charsets to make fonts
79 * which advertise support for a single language
80 * not support other Han languages
81 */
82 if (exclusiveCharset &&
cd2ec1a9 83 FcFreeTypeIsExclusiveLang (fcLangCharSets[i].lang))
e50b9ae7 84 {
cd2ec1a9
PL
85 if (fcLangCharSets[i].charset.num != exclusiveCharset->num)
86 continue;
87
88 for (j = 0; j < fcLangCharSets[i].charset.num; j++)
7ce19673
KP
89 if (FcCharSetLeaf(&fcLangCharSets[i].charset, j) !=
90 FcCharSetLeaf(exclusiveCharset, j))
cd2ec1a9 91 continue;
e50b9ae7 92 }
3de8881e
KP
93 missing = FcCharSetSubtractCount (&fcLangCharSets[i].charset, charset);
94 if (FcDebug() & FC_DBG_SCANV)
c80d2ac4
KP
95 {
96 if (missing && missing < 10)
97 {
98 FcCharSet *missed = FcCharSetSubtract (&fcLangCharSets[i].charset,
99 charset);
100 FcChar32 ucs4;
101 FcChar32 map[FC_CHARSET_MAP_SIZE];
102 FcChar32 next;
103
0d745819 104 printf ("\n%s(%u) ", fcLangCharSets[i].lang, missing);
c80d2ac4
KP
105 printf ("{");
106 for (ucs4 = FcCharSetFirstPage (missed, map, &next);
107 ucs4 != FC_CHARSET_DONE;
108 ucs4 = FcCharSetNextPage (missed, map, &next))
109 {
110 int i, j;
111 for (i = 0; i < FC_CHARSET_MAP_SIZE; i++)
112 if (map[i])
113 {
114 for (j = 0; j < 32; j++)
115 if (map[i] & (1 << j))
116 printf (" %04x", ucs4 + i * 32 + j);
117 }
118 }
119 printf (" }\n\t");
120 FcCharSetDestroy (missed);
121 }
122 else
0d745819 123 printf ("%s(%u) ", fcLangCharSets[i].lang, missing);
c80d2ac4 124 }
e50b9ae7 125 if (!missing)
d8d73958 126 FcLangSetBitSet (ls, i);
3de8881e 127 }
e50b9ae7 128
3de8881e
KP
129 if (FcDebug() & FC_DBG_SCANV)
130 printf ("\n");
d8d73958
KP
131
132
133 return ls;
3de8881e
KP
134}
135
d8d73958 136#define FcLangEnd(c) ((c) == '-' || (c) == '\0')
3de8881e
KP
137
138FcLangResult
139FcLangCompare (const FcChar8 *s1, const FcChar8 *s2)
140{
3de8881e 141 FcChar8 c1, c2;
d8d73958
KP
142 FcLangResult result = FcLangDifferentLang;
143
3de8881e
KP
144 for (;;)
145 {
146 c1 = *s1++;
147 c2 = *s2++;
d8d73958 148
3de8881e
KP
149 c1 = FcToLower (c1);
150 c2 = FcToLower (c2);
151 if (c1 != c2)
d8d73958
KP
152 {
153 if (FcLangEnd (c1) && FcLangEnd (c2))
c833409f 154 result = FcLangDifferentTerritory;
d8d73958
KP
155 return result;
156 }
157 else if (!c1)
158 return FcLangEqual;
159 else if (c1 == '-')
c833409f 160 result = FcLangDifferentTerritory;
3de8881e 161 }
3de8881e
KP
162}
163
793e946c 164/*
74a623e0 165 * Return FcTrue when super contains sub.
793e946c 166 *
74a623e0
KP
167 * super contains sub if super and sub have the same
168 * language and either the same country or one
169 * is missing the country
793e946c
KP
170 */
171
172static FcBool
74a623e0 173FcLangContains (const FcChar8 *super, const FcChar8 *sub)
793e946c
KP
174{
175 FcChar8 c1, c2;
176
177 for (;;)
178 {
74a623e0
KP
179 c1 = *super++;
180 c2 = *sub++;
793e946c
KP
181
182 c1 = FcToLower (c1);
183 c2 = FcToLower (c2);
184 if (c1 != c2)
185 {
74a623e0 186 /* see if super has a country while sub is mising one */
793e946c
KP
187 if (c1 == '-' && c2 == '\0')
188 return FcTrue;
74a623e0
KP
189 /* see if sub has a country while super is mising one */
190 if (c1 == '\0' && c2 == '-')
191 return FcTrue;
793e946c
KP
192 return FcFalse;
193 }
194 else if (!c1)
195 return FcTrue;
196 }
197}
198
3de8881e 199const FcCharSet *
cf223cc7 200FcLangGetCharSet (const FcChar8 *lang)
3de8881e
KP
201{
202 int i;
203 int country = -1;
82f35f8b 204
3de8881e
KP
205 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
206 {
207 switch (FcLangCompare (lang, fcLangCharSets[i].lang)) {
208 case FcLangEqual:
209 return &fcLangCharSets[i].charset;
c833409f 210 case FcLangDifferentTerritory:
3de8881e
KP
211 if (country == -1)
212 country = i;
213 default:
214 break;
215 }
216 }
217 if (country == -1)
218 return 0;
b36f2a39 219 return &fcLangCharSets[country].charset;
3de8881e 220}
d8d73958 221
cf223cc7
BE
222FcStrSet *
223FcGetLangs (void)
224{
225 FcStrSet *langs;
226 int i;
227
228 langs = FcStrSetCreate();
229 if (!langs)
230 return 0;
231
232 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
233 FcStrSetAdd (langs, fcLangCharSets[i].lang);
234
235 return langs;
236}
237
d8d73958
KP
238FcLangSet *
239FcLangSetCreate (void)
240{
241 FcLangSet *ls;
242
243 ls = malloc (sizeof (FcLangSet));
244 if (!ls)
245 return 0;
246 FcMemAlloc (FC_MEM_LANGSET, sizeof (FcLangSet));
247 memset (ls->map, '\0', sizeof (ls->map));
4262e0b3 248 ls->extra = 0;
d8d73958
KP
249 return ls;
250}
251
252void
253FcLangSetDestroy (FcLangSet *ls)
254{
4262e0b3
PL
255 if (ls->extra)
256 FcStrSetDestroy (ls->extra);
d8d73958
KP
257 FcMemFree (FC_MEM_LANGSET, sizeof (FcLangSet));
258 free (ls);
259}
260
261FcLangSet *
262FcLangSetCopy (const FcLangSet *ls)
263{
264 FcLangSet *new;
265
266 new = FcLangSetCreate ();
267 if (!new)
268 goto bail0;
269 memcpy (new->map, ls->map, sizeof (new->map));
4262e0b3 270 if (ls->extra)
d8d73958
KP
271 {
272 FcStrList *list;
273 FcChar8 *extra;
274
4262e0b3
PL
275 new->extra = FcStrSetCreate ();
276 if (!new->extra)
d8d73958
KP
277 goto bail1;
278
4262e0b3 279 list = FcStrListCreate (ls->extra);
d8d73958
KP
280 if (!list)
281 goto bail1;
282
283 while ((extra = FcStrListNext (list)))
4262e0b3 284 if (!FcStrSetAdd (new->extra, extra))
d8d73958
KP
285 {
286 FcStrListDone (list);
287 goto bail1;
288 }
289 FcStrListDone (list);
290 }
291 return new;
292bail1:
293 FcLangSetDestroy (new);
294bail0:
295 return 0;
296}
297
298static int
299FcLangSetIndex (const FcChar8 *lang)
300{
12d49d3c
CW
301 int low, high, mid = 0;
302 int cmp = 0;
793e946c 303 FcChar8 firstChar = FcToLower(lang[0]);
947afeb5 304 FcChar8 secondChar = firstChar ? FcToLower(lang[1]) : '\0';
793e946c
KP
305
306 if (firstChar < 'a')
307 {
308 low = 0;
309 high = fcLangCharSetRanges[0].begin;
310 }
311 else if(firstChar > 'z')
312 {
313 low = fcLangCharSetRanges[25].begin;
314 high = NUM_LANG_CHAR_SET - 1;
315 }
316 else
317 {
318 low = fcLangCharSetRanges[firstChar - 'a'].begin;
319 high = fcLangCharSetRanges[firstChar - 'a'].end;
320 /* no matches */
321 if (low > high)
322 return -low; /* next entry after where it would be */
323 }
d8d73958 324
d8d73958
KP
325 while (low <= high)
326 {
327 mid = (high + low) >> 1;
793e946c
KP
328 if(fcLangCharSets[mid].lang[0] != firstChar)
329 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang, lang);
330 else
331 { /* fast path for resolving 2-letter languages (by far the most common) after
332 * finding the first char (probably already true because of the hash table) */
947afeb5
KP
333 cmp = fcLangCharSets[mid].lang[1] - secondChar;
334 if (cmp == 0 &&
335 (fcLangCharSets[mid].lang[2] != '\0' ||
336 lang[2] != '\0'))
793e946c 337 {
947afeb5
KP
338 cmp = FcStrCmpIgnoreCase(fcLangCharSets[mid].lang+2,
339 lang+2);
793e946c 340 }
793e946c
KP
341 }
342 if (cmp == 0)
d8d73958
KP
343 return mid;
344 if (cmp < 0)
345 low = mid + 1;
346 else
347 high = mid - 1;
348 }
349 if (cmp < 0)
350 mid++;
351 return -(mid + 1);
352}
353
354FcBool
355FcLangSetAdd (FcLangSet *ls, const FcChar8 *lang)
356{
357 int id;
358
359 id = FcLangSetIndex (lang);
360 if (id >= 0)
361 {
362 FcLangSetBitSet (ls, id);
363 return FcTrue;
364 }
4262e0b3 365 if (!ls->extra)
d8d73958 366 {
4262e0b3
PL
367 ls->extra = FcStrSetCreate ();
368 if (!ls->extra)
d8d73958
KP
369 return FcFalse;
370 }
4262e0b3 371 return FcStrSetAdd (ls->extra, lang);
d8d73958
KP
372}
373
374FcLangResult
375FcLangSetHasLang (const FcLangSet *ls, const FcChar8 *lang)
376{
377 int id;
378 FcLangResult best, r;
379 int i;
380
381 id = FcLangSetIndex (lang);
2458a6d8
KP
382 if (id < 0)
383 id = -id - 1;
384 else if (FcLangSetBitGet (ls, id))
d8d73958 385 return FcLangEqual;
d8d73958
KP
386 best = FcLangDifferentLang;
387 for (i = id - 1; i >= 0; i--)
388 {
389 r = FcLangCompare (lang, fcLangCharSets[i].lang);
390 if (r == FcLangDifferentLang)
391 break;
392 if (FcLangSetBitGet (ls, i) && r < best)
393 best = r;
394 }
395 for (i = id; i < NUM_LANG_CHAR_SET; i++)
396 {
397 r = FcLangCompare (lang, fcLangCharSets[i].lang);
398 if (r == FcLangDifferentLang)
399 break;
400 if (FcLangSetBitGet (ls, i) && r < best)
401 best = r;
402 }
4262e0b3 403 if (ls->extra)
d8d73958 404 {
4262e0b3 405 FcStrList *list = FcStrListCreate (ls->extra);
d8d73958 406 FcChar8 *extra;
d8d73958
KP
407
408 if (list)
409 {
410 while (best > FcLangEqual && (extra = FcStrListNext (list)))
411 {
412 r = FcLangCompare (lang, extra);
413 if (r < best)
414 best = r;
415 }
416 FcStrListDone (list);
417 }
418 }
419 return best;
420}
421
422static FcLangResult
423FcLangSetCompareStrSet (const FcLangSet *ls, FcStrSet *set)
424{
425 FcStrList *list = FcStrListCreate (set);
426 FcLangResult r, best = FcLangDifferentLang;
427 FcChar8 *extra;
428
429 if (list)
430 {
431 while (best > FcLangEqual && (extra = FcStrListNext (list)))
432 {
433 r = FcLangSetHasLang (ls, extra);
434 if (r < best)
435 best = r;
436 }
437 FcStrListDone (list);
438 }
439 return best;
440}
441
442FcLangResult
443FcLangSetCompare (const FcLangSet *lsa, const FcLangSet *lsb)
444{
234397b4 445 int i, j;
d8d73958
KP
446 FcLangResult best, r;
447
448 for (i = 0; i < NUM_LANG_SET_MAP; i++)
449 if (lsa->map[i] & lsb->map[i])
450 return FcLangEqual;
451 best = FcLangDifferentLang;
234397b4
DD
452 for (j = 0; j < NUM_COUNTRY_SET; j++)
453 for (i = 0; i < NUM_LANG_SET_MAP; i++)
454 if ((lsa->map[i] & fcLangCountrySets[j][i]) &&
455 (lsb->map[i] & fcLangCountrySets[j][i]))
456 {
c833409f 457 best = FcLangDifferentTerritory;
234397b4
DD
458 break;
459 }
4262e0b3 460 if (lsa->extra)
d8d73958 461 {
4262e0b3 462 r = FcLangSetCompareStrSet (lsb, lsa->extra);
d8d73958
KP
463 if (r < best)
464 best = r;
465 }
4262e0b3 466 if (best > FcLangEqual && lsb->extra)
d8d73958 467 {
4262e0b3 468 r = FcLangSetCompareStrSet (lsa, lsb->extra);
d8d73958
KP
469 if (r < best)
470 best = r;
471 }
472 return best;
473}
474
475/*
476 * Used in computing values -- mustn't allocate any storage
477 */
478FcLangSet *
479FcLangSetPromote (const FcChar8 *lang)
480{
481 static FcLangSet ls;
482 static FcStrSet strs;
483 static FcChar8 *str;
484 int id;
485
486 memset (ls.map, '\0', sizeof (ls.map));
4262e0b3 487 ls.extra = 0;
d8d73958
KP
488 id = FcLangSetIndex (lang);
489 if (id > 0)
490 {
491 FcLangSetBitSet (&ls, id);
492 }
493 else
494 {
4262e0b3 495 ls.extra = &strs;
d8d73958
KP
496 strs.num = 1;
497 strs.size = 1;
4262e0b3 498 strs.strs = &str;
47d4f950 499 strs.ref = 1;
d8d73958
KP
500 str = (FcChar8 *) lang;
501 }
502 return &ls;
503}
504
505FcChar32
506FcLangSetHash (const FcLangSet *ls)
507{
508 FcChar32 h = 0;
509 int i;
510
511 for (i = 0; i < NUM_LANG_SET_MAP; i++)
512 h ^= ls->map[i];
4262e0b3
PL
513 if (ls->extra)
514 h ^= ls->extra->num;
d8d73958
KP
515 return h;
516}
517
518FcLangSet *
519FcNameParseLangSet (const FcChar8 *string)
520{
793e946c
KP
521 FcChar8 lang[32],c;
522 int i;
d8d73958
KP
523 FcLangSet *ls;
524
525 ls = FcLangSetCreate ();
526 if (!ls)
527 goto bail0;
528
793e946c 529 for(;;)
d8d73958 530 {
793e946c 531 for(i = 0; i < 31;i++)
d8d73958 532 {
793e946c
KP
533 c = *string++;
534 if(c == '\0' || c == '|')
535 break; /* end of this code */
536 lang[i] = c;
d8d73958 537 }
793e946c
KP
538 lang[i] = '\0';
539 if (!FcLangSetAdd (ls, lang))
540 goto bail1;
541 if(c == '\0')
542 break;
d8d73958
KP
543 }
544 return ls;
545bail1:
546 FcLangSetDestroy (ls);
547bail0:
548 return 0;
549}
550
551FcBool
552FcNameUnparseLangSet (FcStrBuf *buf, const FcLangSet *ls)
553{
5c6d1ff2 554 int i;
d8d73958
KP
555 FcBool first = FcTrue;
556
5c6d1ff2
BE
557 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
558 if (FcLangSetBitGet (ls, i))
559 {
560 if (!first)
561 if (!FcStrBufChar (buf, '|'))
d8d73958 562 return FcFalse;
5c6d1ff2
BE
563 if (!FcStrBufString (buf, fcLangCharSets[i].lang))
564 return FcFalse;
565 first = FcFalse;
566 }
567
4262e0b3 568 if (ls->extra)
d8d73958 569 {
4262e0b3 570 FcStrList *list = FcStrListCreate (ls->extra);
d8d73958
KP
571 FcChar8 *extra;
572
573 if (!list)
574 return FcFalse;
575 while ((extra = FcStrListNext (list)))
576 {
577 if (!first)
578 if (!FcStrBufChar (buf, '|'))
04f7d3e7
PL
579 {
580 FcStrListDone (list);
d8d73958 581 return FcFalse;
04f7d3e7 582 }
793e946c 583 if (!FcStrBufString (buf, extra))
04f7d3e7
PL
584 {
585 FcStrListDone (list);
586 return FcFalse;
587 }
d8d73958
KP
588 first = FcFalse;
589 }
2de24638 590 FcStrListDone (list);
d8d73958
KP
591 }
592 return FcTrue;
593}
594
595FcBool
596FcLangSetEqual (const FcLangSet *lsa, const FcLangSet *lsb)
597{
598 int i;
599
600 for (i = 0; i < NUM_LANG_SET_MAP; i++)
601 {
602 if (lsa->map[i] != lsb->map[i])
603 return FcFalse;
604 }
4262e0b3 605 if (!lsa->extra && !lsb->extra)
d8d73958 606 return FcTrue;
4262e0b3
PL
607 if (lsa->extra && lsb->extra)
608 return FcStrSetEqual (lsa->extra, lsb->extra);
d8d73958
KP
609 return FcFalse;
610}
793e946c
KP
611
612static FcBool
613FcLangSetContainsLang (const FcLangSet *ls, const FcChar8 *lang)
614{
615 int id;
793e946c
KP
616 int i;
617
618 id = FcLangSetIndex (lang);
619 if (id < 0)
620 id = -id - 1;
621 else if (FcLangSetBitGet (ls, id))
622 return FcTrue;
623 /*
624 * search up and down among equal languages for a match
625 */
626 for (i = id - 1; i >= 0; i--)
627 {
628 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
629 break;
630 if (FcLangSetBitGet (ls, i) &&
631 FcLangContains (fcLangCharSets[i].lang, lang))
632 return FcTrue;
633 }
634 for (i = id; i < NUM_LANG_CHAR_SET; i++)
635 {
636 if (FcLangCompare (fcLangCharSets[i].lang, lang) == FcLangDifferentLang)
637 break;
638 if (FcLangSetBitGet (ls, i) &&
639 FcLangContains (fcLangCharSets[i].lang, lang))
640 return FcTrue;
641 }
4262e0b3 642 if (ls->extra)
793e946c 643 {
4262e0b3 644 FcStrList *list = FcStrListCreate (ls->extra);
793e946c 645 FcChar8 *extra;
793e946c
KP
646
647 if (list)
648 {
649 while ((extra = FcStrListNext (list)))
650 {
651 if (FcLangContains (extra, lang))
652 break;
653 }
654 FcStrListDone (list);
655 if (extra)
656 return FcTrue;
657 }
658 }
659 return FcFalse;
660}
661
662/*
663 * return FcTrue if lsa contains every language in lsb
664 */
665FcBool
666FcLangSetContains (const FcLangSet *lsa, const FcLangSet *lsb)
667{
668 int i, j;
669 FcChar32 missing;
670
671 if (FcDebug() & FC_DBG_MATCHV)
672 {
673 printf ("FcLangSet "); FcLangSetPrint (lsa);
674 printf (" contains "); FcLangSetPrint (lsb);
675 printf ("\n");
676 }
677 /*
678 * check bitmaps for missing language support
679 */
680 for (i = 0; i < NUM_LANG_SET_MAP; i++)
681 {
682 missing = lsb->map[i] & ~lsa->map[i];
683 if (missing)
684 {
685 for (j = 0; j < 32; j++)
686 if (missing & (1 << j))
687 {
688 if (!FcLangSetContainsLang (lsa,
d354a321 689 fcLangCharSets[fcLangCharSetIndicesInv[i*32 + j]].lang))
793e946c
KP
690 {
691 if (FcDebug() & FC_DBG_MATCHV)
d354a321 692 printf ("\tMissing bitmap %s\n", fcLangCharSets[fcLangCharSetIndicesInv[i*32+j]].lang);
793e946c
KP
693 return FcFalse;
694 }
695 }
696 }
697 }
4262e0b3 698 if (lsb->extra)
793e946c 699 {
4262e0b3 700 FcStrList *list = FcStrListCreate (lsb->extra);
793e946c
KP
701 FcChar8 *extra;
702
703 if (list)
704 {
705 while ((extra = FcStrListNext (list)))
706 {
707 if (!FcLangSetContainsLang (lsa, extra))
708 {
709 if (FcDebug() & FC_DBG_MATCHV)
710 printf ("\tMissing string %s\n", extra);
711 break;
712 }
713 }
714 FcStrListDone (list);
715 if (extra)
716 return FcFalse;
717 }
718 }
719 return FcTrue;
720}
cd2ec1a9 721
7ce19673
KP
722FcBool
723FcLangSetSerializeAlloc (FcSerialize *serialize, const FcLangSet *l)
cd2ec1a9 724{
7ce19673
KP
725 if (!FcSerializeAlloc (serialize, l, sizeof (FcLangSet)))
726 return FcFalse;
4262e0b3 727 return FcTrue;
cd2ec1a9 728}
212c9f43 729
4262e0b3 730FcLangSet *
7ce19673 731FcLangSetSerialize(FcSerialize *serialize, const FcLangSet *l)
4262e0b3 732{
7ce19673 733 FcLangSet *l_serialize = FcSerializePtr (serialize, l);
4262e0b3 734
7ce19673
KP
735 if (!l_serialize)
736 return NULL;
737 *l_serialize = *l;
738 return l_serialize;
212c9f43 739}
d62b85af
BE
740
741FcStrSet *
742FcLangSetGetLangs (const FcLangSet *ls)
743{
744 FcStrSet *langs;
745 int i;
746
747 langs = FcStrSetCreate();
748 if (!langs)
749 return 0;
750
751 for (i = 0; i < NUM_LANG_CHAR_SET; i++)
752 if (FcLangSetBitGet (ls, i))
753 FcStrSetAdd (langs, fcLangCharSets[i].lang);
754
755 if (ls->extra)
756 {
757 FcStrList *list = FcStrListCreate (ls->extra);
758 FcChar8 *extra;
759
760 if (list)
761 {
762 while ((extra = FcStrListNext (list)))
763 FcStrSetAdd (langs, extra);
764
765 FcStrListDone (list);
766 }
767 }
768
769 return langs;
770}
771
23816bf9
KP
772#define __fclang__
773#include "fcaliastail.h"
a0a1da22 774#include "fcftaliastail.h"
23816bf9 775#undef __fclang__