Coverage Report

Created: 2026-08-11 07:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fontconfig/src/fcxml.c
Line
Count
Source
1
/*
2
 * fontconfig/src/fcxml.c
3
 *
4
 * Copyright © 2002 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 <fcntl.h>
28
#include <stdarg.h>
29
#include <string.h>
30
31
#ifdef HAVE_DIRENT_H
32
#  include <dirent.h>
33
#endif
34
35
#ifdef ENABLE_LIBXML2
36
37
#  include <libxml/parser.h>
38
39
#  define XML_Char                 xmlChar
40
#  define XML_Parser               xmlParserCtxtPtr
41
#  define XML_ParserFree           xmlFreeParserCtxt
42
#  define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
43
#  define XML_GetErrorCode         xmlCtxtGetLastError
44
#  define XML_ErrorString(Error)   (Error)->message
45
46
#else /* ENABLE_LIBXML2 */
47
48
#  ifndef HAVE_XMLPARSE_H
49
#    define HAVE_XMLPARSE_H 0
50
#  endif
51
52
#  if HAVE_XMLPARSE_H
53
#    include <xmlparse.h>
54
#  else
55
#    include <expat.h>
56
#  endif
57
58
#endif /* ENABLE_LIBXML2 */
59
60
#ifdef _WIN32
61
#  include <mbstring.h>
62
extern FcChar8               fontconfig_instprefix[];
63
pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
64
pfnSHGetFolderPathA          pSHGetFolderPathA = NULL;
65
static void
66
_ensureWin32GettersReady ();
67
#endif
68
69
static void
70
FcExprDestroy (FcExpr *e);
71
static FcBool
72
_FcConfigParse (FcConfig      *config,
73
                const FcChar8 *name,
74
                FcBool         complain,
75
                FcBool         load);
76
77
void
78
FcTestDestroy (FcTest *test)
79
0
{
80
0
    FcExprDestroy (test->expr);
81
0
    free (test);
82
0
}
83
84
void
85
FcRuleDestroy (FcRule *rule)
86
0
{
87
0
    FcRule *n = rule->next;
88
89
0
    switch (rule->type) {
90
0
    case FcRuleTest:
91
0
  FcTestDestroy (rule->u.test);
92
0
  break;
93
0
    case FcRuleEdit:
94
0
  FcEditDestroy (rule->u.edit);
95
0
  break;
96
0
    case FcRuleUnknown:
97
0
    default:
98
0
  break;
99
0
    }
100
0
    free (rule);
101
0
    if (n)
102
0
  FcRuleDestroy (n);
103
0
}
104
105
static FcExpr *
106
FcExprCreateNil (FcConfig *config)
107
0
{
108
0
    FcExpr *e = FcConfigAllocExpr (config);
109
0
    if (e) {
110
0
  e->op = FcOpNil;
111
0
    }
112
0
    return e;
113
0
}
114
115
static FcExpr *
116
FcExprCreateInteger (FcConfig *config, int i)
117
0
{
118
0
    FcExpr *e = FcConfigAllocExpr (config);
119
0
    if (e) {
120
0
  e->op = FcOpInteger;
121
0
  e->u.ival = i;
122
0
    }
123
0
    return e;
124
0
}
125
126
static FcExpr *
127
FcExprCreateDouble (FcConfig *config, double d)
128
0
{
129
0
    FcExpr *e = FcConfigAllocExpr (config);
130
0
    if (e) {
131
0
  e->op = FcOpDouble;
132
0
  e->u.dval = d;
133
0
    }
134
0
    return e;
135
0
}
136
137
static FcExpr *
138
FcExprCreateString (FcConfig *config, const FcChar8 *s)
139
0
{
140
0
    FcExpr *e = FcConfigAllocExpr (config);
141
0
    if (e) {
142
0
  e->op = FcOpString;
143
0
  e->u.sval = FcStrCopy (s);
144
0
    }
145
0
    return e;
146
0
}
147
148
static FcExprMatrix *
149
FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
150
0
{
151
0
    FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
152
0
    if (m) {
153
0
  *m = *matrix;
154
0
    }
155
0
    return m;
156
0
}
157
158
static void
159
FcExprMatrixFreeShallow (FcExprMatrix *m)
160
0
{
161
0
    if (!m)
162
0
  return;
163
164
0
    free (m);
165
0
}
166
167
static void
168
FcExprMatrixFree (FcExprMatrix *m)
169
0
{
170
0
    if (!m)
171
0
  return;
172
173
0
    FcExprDestroy (m->xx);
174
0
    FcExprDestroy (m->xy);
175
0
    FcExprDestroy (m->yx);
176
0
    FcExprDestroy (m->yy);
177
178
0
    free (m);
179
0
}
180
181
static FcExpr *
182
FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
183
0
{
184
0
    FcExpr *e = FcConfigAllocExpr (config);
185
0
    if (e) {
186
0
  e->op = FcOpMatrix;
187
0
  e->u.mexpr = FcExprMatrixCopyShallow (matrix);
188
0
    }
189
0
    return e;
190
0
}
191
192
static FcExpr *
193
FcExprCreateRange (FcConfig *config, FcRange *range)
194
0
{
195
0
    FcExpr *e = FcConfigAllocExpr (config);
196
0
    if (e) {
197
0
  e->op = FcOpRange;
198
0
  e->u.rval = FcRangeCopy (range);
199
0
    }
200
0
    return e;
201
0
}
202
203
static FcExpr *
204
FcExprCreateBool (FcConfig *config, FcBool b)
205
0
{
206
0
    FcExpr *e = FcConfigAllocExpr (config);
207
0
    if (e) {
208
0
  e->op = FcOpBool;
209
0
  e->u.bval = b;
210
0
    }
211
0
    return e;
212
0
}
213
214
static FcExpr *
215
FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
216
0
{
217
0
    FcExpr *e = FcConfigAllocExpr (config);
218
0
    if (e) {
219
0
  e->op = FcOpCharSet;
220
0
  e->u.cval = FcCharSetCopy (charset);
221
0
    }
222
0
    return e;
223
0
}
224
225
static FcExpr *
226
FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
227
0
{
228
0
    FcExpr *e = FcConfigAllocExpr (config);
229
0
    if (e) {
230
0
  e->op = FcOpLangSet;
231
0
  e->u.lval = FcLangSetCopy (langset);
232
0
    }
233
0
    return e;
234
0
}
235
236
static FcExpr *
237
FcExprCreateName (FcConfig *config, FcExprName name)
238
0
{
239
0
    FcExpr *e = FcConfigAllocExpr (config);
240
0
    if (e) {
241
0
  e->op = FcOpField;
242
0
  e->u.name = name;
243
0
    }
244
0
    return e;
245
0
}
246
247
static FcExpr *
248
FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
249
0
{
250
0
    FcExpr *e = FcConfigAllocExpr (config);
251
0
    if (e) {
252
0
  e->op = FcOpConst;
253
0
  e->u.constant = FcStrCopy (constant);
254
0
    }
255
0
    return e;
256
0
}
257
258
static FcExpr *
259
FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
260
0
{
261
0
    FcExpr *e = FcConfigAllocExpr (config);
262
0
    if (e) {
263
0
  e->op = op;
264
0
  e->u.tree.left = left;
265
0
  e->u.tree.right = right;
266
0
    }
267
0
    return e;
268
0
}
269
270
static FcExpr *
271
FcExprDup (FcConfig *config, const FcExpr *e)
272
0
{
273
0
    FcExpr *ret = NULL;
274
275
0
    if (!e)
276
0
  return NULL;
277
0
    switch (FC_OP_GET_OP (e->op)) {
278
0
    case FcOpInteger:
279
0
  ret = FcExprCreateInteger (config, e->u.ival);
280
0
  break;
281
0
    case FcOpDouble:
282
0
  ret = FcExprCreateDouble (config, e->u.dval);
283
0
  break;
284
0
    case FcOpString:
285
0
  ret = FcExprCreateString (config, e->u.sval);
286
0
  break;
287
0
    case FcOpMatrix: {
288
0
  FcExpr      *xx = NULL, *xy = NULL, *yx = NULL, *yy = NULL;
289
0
  FcExprMatrix m;
290
291
0
  xx = FcExprDup (config, e->u.mexpr->xx);
292
0
  xy = FcExprDup (config, e->u.mexpr->xy);
293
0
  yx = FcExprDup (config, e->u.mexpr->yx);
294
0
  yy = FcExprDup (config, e->u.mexpr->yy);
295
0
  if (!xx || !xy || !yx || !yy)
296
0
      goto bail_matrix;
297
0
  m.xx = xx;
298
0
  m.xy = xy;
299
0
  m.yx = yx;
300
0
  m.yy = yy;
301
0
  ret = FcExprCreateMatrix (config, &m);
302
0
  break;
303
0
    bail_matrix:
304
0
  if (xx)
305
0
      FcExprDestroy (xx);
306
0
  if (xy)
307
0
      FcExprDestroy (xy);
308
0
  if (yx)
309
0
      FcExprDestroy (yx);
310
0
  if (yy)
311
0
      FcExprDestroy (yy);
312
0
  break;
313
0
    }
314
0
    case FcOpRange:
315
0
  ret = FcExprCreateRange (config, e->u.rval);
316
0
  break;
317
0
    case FcOpBool:
318
0
  ret = FcExprCreateBool (config, e->u.bval);
319
0
  break;
320
0
    case FcOpCharSet:
321
0
  ret = FcExprCreateCharSet (config, e->u.cval);
322
0
  break;
323
0
    case FcOpLangSet:
324
0
  ret = FcExprCreateLangSet (config, e->u.lval);
325
0
  break;
326
0
    case FcOpNil:
327
0
  ret = FcExprCreateNil (config);
328
0
  break;
329
0
    case FcOpField:
330
0
  ret = FcExprCreateName (config, e->u.name);
331
0
  break;
332
0
    case FcOpConst:
333
0
  ret = FcExprCreateConst (config, e->u.constant);
334
0
  break;
335
0
    case FcOpAssign:
336
0
    case FcOpAssignReplace:
337
0
    case FcOpPrependFirst:
338
0
    case FcOpPrepend:
339
0
    case FcOpAppend:
340
0
    case FcOpAppendLast:
341
0
    case FcOpDelete:
342
0
    case FcOpDeleteAll:
343
0
    case FcOpQuest:
344
0
    case FcOpOr:
345
0
    case FcOpAnd:
346
0
    case FcOpEqual:
347
0
    case FcOpNotEqual:
348
0
    case FcOpContains:
349
0
    case FcOpListing:
350
0
    case FcOpNotContains:
351
0
    case FcOpLess:
352
0
    case FcOpLessEqual:
353
0
    case FcOpMore:
354
0
    case FcOpMoreEqual:
355
0
    case FcOpPlus:
356
0
    case FcOpMinus:
357
0
    case FcOpTimes:
358
0
    case FcOpDivide:
359
0
    case FcOpNot:
360
0
    case FcOpComma:
361
0
    case FcOpFloor:
362
0
    case FcOpCeil:
363
0
    case FcOpRound:
364
0
    case FcOpTrunc:
365
0
    case FcOpInvalid: {
366
0
  ret = FcConfigAllocExpr (config);
367
0
  if (ret) {
368
0
      ret->op = e->op;
369
0
      ret->u.tree.left = FcExprDup (config, e->u.tree.left);
370
0
      ret->u.tree.right = NULL;
371
0
      if (e->u.tree.left && !ret->u.tree.left) {
372
0
    FcExprDestroy (ret);
373
0
    return NULL;
374
0
      }
375
0
      ret->u.tree.right = FcExprDup (config, e->u.tree.right);
376
0
      if (e->u.tree.right && !ret->u.tree.right) {
377
0
    FcExprDestroy (ret);
378
0
    return NULL;
379
0
      }
380
0
  }
381
0
  break;
382
0
    }
383
0
    default:
384
  /* unlikely */
385
0
  break;
386
0
    }
387
0
    return ret;
388
0
}
389
390
static void
391
FcExprDestroy (FcExpr *e)
392
0
{
393
0
    if (!e)
394
0
  return;
395
0
    switch (FC_OP_GET_OP (e->op)) {
396
0
    case FcOpInteger:
397
0
  break;
398
0
    case FcOpDouble:
399
0
  break;
400
0
    case FcOpString:
401
0
  FcFree (e->u.sval);
402
0
  break;
403
0
    case FcOpMatrix:
404
0
  FcExprMatrixFree (e->u.mexpr);
405
0
  break;
406
0
    case FcOpRange:
407
0
  FcRangeDestroy (e->u.rval);
408
0
  break;
409
0
    case FcOpCharSet:
410
0
  FcCharSetDestroy (e->u.cval);
411
0
  break;
412
0
    case FcOpLangSet:
413
0
  FcLangSetDestroy (e->u.lval);
414
0
  break;
415
0
    case FcOpBool:
416
0
  break;
417
0
    case FcOpField:
418
0
  break;
419
0
    case FcOpConst:
420
0
  FcFree (e->u.constant);
421
0
  break;
422
0
    case FcOpAssign:
423
0
    case FcOpAssignReplace:
424
0
    case FcOpPrepend:
425
0
    case FcOpPrependFirst:
426
0
    case FcOpAppend:
427
0
    case FcOpAppendLast:
428
0
    case FcOpDelete:
429
0
    case FcOpDeleteAll:
430
0
  break;
431
0
    case FcOpOr:
432
0
    case FcOpAnd:
433
0
    case FcOpEqual:
434
0
    case FcOpNotEqual:
435
0
    case FcOpLess:
436
0
    case FcOpLessEqual:
437
0
    case FcOpMore:
438
0
    case FcOpMoreEqual:
439
0
    case FcOpContains:
440
0
    case FcOpListing:
441
0
    case FcOpNotContains:
442
0
    case FcOpPlus:
443
0
    case FcOpMinus:
444
0
    case FcOpTimes:
445
0
    case FcOpDivide:
446
0
    case FcOpQuest:
447
0
    case FcOpComma:
448
0
  FcExprDestroy (e->u.tree.right);
449
  /* fall through */
450
0
    case FcOpNot:
451
0
    case FcOpFloor:
452
0
    case FcOpCeil:
453
0
    case FcOpRound:
454
0
    case FcOpTrunc:
455
0
  FcExprDestroy (e->u.tree.left);
456
0
  break;
457
0
    case FcOpNil:
458
0
    case FcOpInvalid:
459
0
  break;
460
0
    }
461
462
0
    e->op = FcOpNil;
463
0
}
464
465
void
466
FcEditDestroy (FcEdit *e)
467
0
{
468
0
    if (e->expr)
469
0
  FcExprDestroy (e->expr);
470
0
    free (e);
471
0
}
472
473
typedef enum _FcElement {
474
    FcElementNone,
475
    FcElementFontconfig,
476
    FcElementDir,
477
    FcElementCacheDir,
478
    FcElementCache,
479
    FcElementInclude,
480
    FcElementConfig,
481
    FcElementMatch,
482
    FcElementAlias,
483
    FcElementDescription,
484
    FcElementRemapDir,
485
    FcElementResetDirs,
486
487
    FcElementRescan,
488
489
    FcElementPrefer,
490
    FcElementAccept,
491
    FcElementDefault,
492
    FcElementFamily,
493
494
    FcElementSelectfont,
495
    FcElementAcceptfont,
496
    FcElementRejectfont,
497
    FcElementGlob,
498
    FcElementPattern,
499
    FcElementPatelt,
500
501
    FcElementTest,
502
    FcElementEdit,
503
    FcElementInt,
504
    FcElementDouble,
505
    FcElementString,
506
    FcElementMatrix,
507
    FcElementRange,
508
    FcElementBool,
509
    FcElementCharSet,
510
    FcElementLangSet,
511
    FcElementName,
512
    FcElementConst,
513
    FcElementOr,
514
    FcElementAnd,
515
    FcElementEq,
516
    FcElementNotEq,
517
    FcElementLess,
518
    FcElementLessEq,
519
    FcElementMore,
520
    FcElementMoreEq,
521
    FcElementContains,
522
    FcElementNotContains,
523
    FcElementPlus,
524
    FcElementMinus,
525
    FcElementTimes,
526
    FcElementDivide,
527
    FcElementNot,
528
    FcElementIf,
529
    FcElementFloor,
530
    FcElementCeil,
531
    FcElementRound,
532
    FcElementTrunc,
533
    FcElementUnknown
534
} FcElement;
535
536
static const struct {
537
    const char name[16];
538
    FcElement  element;
539
} fcElementMap[] = {
540
    { "fontconfig",   FcElementFontconfig  },
541
    { "dir",          FcElementDir         },
542
    { "cachedir",     FcElementCacheDir    },
543
    { "cache",        FcElementCache       },
544
    { "include",      FcElementInclude     },
545
    { "config",       FcElementConfig      },
546
    { "match",        FcElementMatch       },
547
    { "alias",        FcElementAlias       },
548
    { "description",  FcElementDescription },
549
    { "remap-dir",    FcElementRemapDir    },
550
    { "reset-dirs",   FcElementResetDirs   },
551
552
    { "rescan",       FcElementRescan      },
553
554
    { "prefer",       FcElementPrefer      },
555
    { "accept",       FcElementAccept      },
556
    { "default",      FcElementDefault     },
557
    { "family",       FcElementFamily      },
558
559
    { "selectfont",   FcElementSelectfont  },
560
    { "acceptfont",   FcElementAcceptfont  },
561
    { "rejectfont",   FcElementRejectfont  },
562
    { "glob",         FcElementGlob        },
563
    { "pattern",      FcElementPattern     },
564
    { "patelt",       FcElementPatelt      },
565
566
    { "test",         FcElementTest        },
567
    { "edit",         FcElementEdit        },
568
    { "int",          FcElementInt         },
569
    { "double",       FcElementDouble      },
570
    { "string",       FcElementString      },
571
    { "matrix",       FcElementMatrix      },
572
    { "range",        FcElementRange       },
573
    { "bool",         FcElementBool        },
574
    { "charset",      FcElementCharSet     },
575
    { "langset",      FcElementLangSet     },
576
    { "name",         FcElementName        },
577
    { "const",        FcElementConst       },
578
    { "or",           FcElementOr          },
579
    { "and",          FcElementAnd         },
580
    { "eq",           FcElementEq          },
581
    { "not_eq",       FcElementNotEq       },
582
    { "less",         FcElementLess        },
583
    { "less_eq",      FcElementLessEq      },
584
    { "more",         FcElementMore        },
585
    { "more_eq",      FcElementMoreEq      },
586
    { "contains",     FcElementContains    },
587
    { "not_contains", FcElementNotContains },
588
    { "plus",         FcElementPlus        },
589
    { "minus",        FcElementMinus       },
590
    { "times",        FcElementTimes       },
591
    { "divide",       FcElementDivide      },
592
    { "not",          FcElementNot         },
593
    { "if",           FcElementIf          },
594
    { "floor",        FcElementFloor       },
595
    { "ceil",         FcElementCeil        },
596
    { "round",        FcElementRound       },
597
    { "trunc",        FcElementTrunc       },
598
};
599
0
#define NUM_ELEMENT_MAPS (int)(sizeof fcElementMap / sizeof fcElementMap[0])
600
601
static const char *fcElementIgnoreName[16] = {
602
    "its:",
603
    NULL
604
};
605
606
static FcElement
607
FcElementMap (const XML_Char *name)
608
0
{
609
0
    int i;
610
0
    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
611
0
  if (!strcmp ((char *)name, fcElementMap[i].name))
612
0
      return fcElementMap[i].element;
613
0
    for (i = 0; fcElementIgnoreName[i] != NULL; i++)
614
0
  if (!strncmp ((char *)name, fcElementIgnoreName[i], strlen (fcElementIgnoreName[i])))
615
0
      return FcElementNone;
616
0
    return FcElementUnknown;
617
0
}
618
619
static const char *
620
FcElementReverseMap (FcElement e)
621
0
{
622
0
    int i;
623
624
0
    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
625
0
  if (fcElementMap[i].element == e)
626
0
      return fcElementMap[i].name;
627
628
0
    return NULL;
629
0
}
630
631
typedef struct _FcPStack {
632
    struct _FcPStack *prev;
633
    FcElement         element;
634
    FcChar8         **attr;
635
    FcStrBuf          str;
636
    FcChar8          *attr_buf_static[16];
637
} FcPStack;
638
639
typedef enum _FcVStackTag {
640
    FcVStackNone,
641
642
    FcVStackString,
643
    FcVStackFamily,
644
    FcVStackConstant,
645
    FcVStackGlob,
646
    FcVStackName,
647
    FcVStackPattern,
648
649
    FcVStackPrefer,
650
    FcVStackAccept,
651
    FcVStackDefault,
652
653
    FcVStackInteger,
654
    FcVStackDouble,
655
    FcVStackMatrix,
656
    FcVStackRange,
657
    FcVStackBool,
658
    FcVStackCharSet,
659
    FcVStackLangSet,
660
661
    FcVStackTest,
662
    FcVStackExpr,
663
    FcVStackEdit,
664
    FcVStackNil,
665
} FcVStackTag;
666
667
typedef struct _FcVStack {
668
    struct _FcVStack *prev;
669
    FcPStack         *pstack; /* related parse element */
670
    FcVStackTag       tag;
671
    union {
672
  FcChar8 *string;
673
674
  int           integer;
675
  double        _double;
676
  FcExprMatrix *matrix;
677
  FcRange      *range;
678
  FcBool        bool_;
679
  FcCharSet    *charset;
680
  FcLangSet    *langset;
681
  FcExprName    name;
682
683
  FcTest *test;
684
  FcQual  qual;
685
  FcOp    op;
686
  FcExpr *expr;
687
  FcEdit *edit;
688
689
  FcPattern *pattern;
690
    } u;
691
} FcVStack;
692
693
typedef struct _FcConfigParse {
694
    FcPStack      *pstack;
695
    FcVStack      *vstack;
696
    FcBool         error;
697
    const FcChar8 *name;
698
    FcConfig      *config;
699
    FcRuleSet     *ruleset;
700
    XML_Parser     parser;
701
    unsigned int   pstack_static_used;
702
    FcPStack       pstack_static[8];
703
    unsigned int   vstack_static_used;
704
    FcVStack       vstack_static[64];
705
    FcBool         scanOnly;
706
} FcConfigParse;
707
708
typedef enum _FcConfigSeverity {
709
    FcSevereInfo,
710
    FcSevereWarning,
711
    FcSevereError
712
} FcConfigSeverity;
713
714
static FcBool
715
FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_);
716
717
static void
718
FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
719
0
{
720
0
    const char *s = "unknown";
721
0
    va_list     args;
722
723
0
    va_start (args, fmt);
724
725
0
    switch (severe) {
726
0
    case FcSevereInfo: s = "info"; break;
727
0
    case FcSevereWarning: s = "warning"; break;
728
0
    case FcSevereError: s = "error"; break;
729
0
    }
730
0
    if (parse) {
731
0
  if (parse->name)
732
0
      fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
733
0
               parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
734
0
  else
735
0
      fprintf (stderr, "Fontconfig %s: line %d: ", s,
736
0
               (int)XML_GetCurrentLineNumber (parse->parser));
737
0
  if (severe >= FcSevereError)
738
0
      parse->error = FcTrue;
739
0
    } else
740
0
  fprintf (stderr, "Fontconfig %s: ", s);
741
0
    vfprintf (stderr, fmt, args);
742
0
    fprintf (stderr, "\n");
743
0
    va_end (args);
744
0
}
745
746
static FcExpr *
747
FcPopExpr (FcConfigParse *parse);
748
749
static const char *
750
FcTypeName (FcType type)
751
0
{
752
0
    switch (type) {
753
0
    case FcTypeVoid:
754
0
  return "void";
755
0
    case FcTypeInteger:
756
0
    case FcTypeDouble:
757
0
  return "number";
758
0
    case FcTypeString:
759
0
  return "string";
760
0
    case FcTypeBool:
761
0
  return "bool";
762
0
    case FcTypeMatrix:
763
0
  return "matrix";
764
0
    case FcTypeCharSet:
765
0
  return "charset";
766
0
    case FcTypeFTFace:
767
0
  return "FT_Face";
768
0
    case FcTypeLangSet:
769
0
  return "langset";
770
0
    case FcTypeRange:
771
0
  return "range";
772
0
    case FcTypeUnknown:
773
0
    default:
774
0
  return "unknown";
775
0
    }
776
0
}
777
778
static void
779
FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
780
0
{
781
0
    if (value == FcTypeInteger)
782
0
  value = FcTypeDouble;
783
0
    if (type == FcTypeInteger)
784
0
  type = FcTypeDouble;
785
0
    if (value != type) {
786
0
  if ((value == FcTypeLangSet && type == FcTypeString) ||
787
0
      (value == FcTypeString && type == FcTypeLangSet) ||
788
0
      (value == FcTypeDouble && type == FcTypeRange))
789
0
      return;
790
0
  if (type == FcTypeUnknown)
791
0
      return;
792
  /* It's perfectly fine to use user-define elements in expressions,
793
   * so don't warn in that case. */
794
0
  if (value == FcTypeUnknown)
795
0
      return;
796
0
  FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
797
0
                   FcTypeName (value), FcTypeName (type));
798
0
    }
799
0
}
800
801
static void
802
FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
803
0
{
804
0
    const FcObjectType *o;
805
0
    const FcConstant   *c;
806
807
    /* If parsing the expression failed, some nodes may be NULL */
808
0
    if (!expr)
809
0
  return;
810
811
0
    switch (FC_OP_GET_OP (expr->op)) {
812
0
    case FcOpInteger:
813
0
    case FcOpDouble:
814
0
  FcTypecheckValue (parse, FcTypeDouble, type);
815
0
  break;
816
0
    case FcOpString:
817
0
  FcTypecheckValue (parse, FcTypeString, type);
818
0
  break;
819
0
    case FcOpMatrix:
820
0
  FcTypecheckValue (parse, FcTypeMatrix, type);
821
0
  break;
822
0
    case FcOpBool:
823
0
  FcTypecheckValue (parse, FcTypeBool, type);
824
0
  break;
825
0
    case FcOpCharSet:
826
0
  FcTypecheckValue (parse, FcTypeCharSet, type);
827
0
  break;
828
0
    case FcOpLangSet:
829
0
  FcTypecheckValue (parse, FcTypeLangSet, type);
830
0
  break;
831
0
    case FcOpRange:
832
0
  FcTypecheckValue (parse, FcTypeRange, type);
833
0
  break;
834
0
    case FcOpNil:
835
0
  break;
836
0
    case FcOpField:
837
0
  o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
838
0
  if (o)
839
0
      FcTypecheckValue (parse, o->type, type);
840
0
  break;
841
0
    case FcOpConst:
842
0
  c = FcNameGetConstant (expr->u.constant);
843
0
  if (c) {
844
0
      o = FcNameGetObjectType (c->object);
845
0
      if (o)
846
0
    FcTypecheckValue (parse, o->type, type);
847
0
  } else
848
0
      FcConfigMessage (parse, FcSevereWarning,
849
0
                       "invalid constant used : %s",
850
0
                       expr->u.constant);
851
0
  break;
852
0
    case FcOpQuest:
853
0
  FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
854
0
  FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
855
0
  FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
856
0
  break;
857
0
    case FcOpAssign:
858
0
    case FcOpAssignReplace:
859
0
  break;
860
0
    case FcOpEqual:
861
0
    case FcOpNotEqual:
862
0
    case FcOpLess:
863
0
    case FcOpLessEqual:
864
0
    case FcOpMore:
865
0
    case FcOpMoreEqual:
866
0
    case FcOpContains:
867
0
    case FcOpNotContains:
868
0
    case FcOpListing:
869
0
  FcTypecheckValue (parse, FcTypeBool, type);
870
0
  break;
871
0
    case FcOpComma:
872
0
    case FcOpOr:
873
0
    case FcOpAnd:
874
0
    case FcOpPlus:
875
0
    case FcOpMinus:
876
0
    case FcOpTimes:
877
0
    case FcOpDivide:
878
0
  FcTypecheckExpr (parse, expr->u.tree.left, type);
879
0
  FcTypecheckExpr (parse, expr->u.tree.right, type);
880
0
  break;
881
0
    case FcOpNot:
882
0
  FcTypecheckValue (parse, FcTypeBool, type);
883
0
  FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
884
0
  break;
885
0
    case FcOpFloor:
886
0
    case FcOpCeil:
887
0
    case FcOpRound:
888
0
    case FcOpTrunc:
889
0
  FcTypecheckValue (parse, FcTypeDouble, type);
890
0
  FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
891
0
  break;
892
0
    default:
893
0
  break;
894
0
    }
895
0
}
896
897
static FcTest *
898
FcTestCreate (FcConfigParse *parse,
899
              FcMatchKind    kind,
900
              FcQual         qual,
901
              const FcChar8 *field,
902
              unsigned int   compare,
903
              FcExpr        *expr)
904
0
{
905
0
    FcTest *test = (FcTest *)malloc (sizeof (FcTest));
906
907
0
    if (test) {
908
0
  const FcObjectType *o;
909
910
0
  test->kind = kind;
911
0
  test->qual = qual;
912
0
  test->object = FcObjectFromName ((const char *)field);
913
0
  test->op = compare;
914
0
  test->expr = expr;
915
0
  o = FcNameGetObjectType (FcObjectName (test->object));
916
0
  if (o)
917
0
      FcTypecheckExpr (parse, expr, o->type);
918
0
    }
919
0
    return test;
920
0
}
921
922
static FcEdit *
923
FcEditCreate (FcConfigParse *parse,
924
              FcObject       object,
925
              FcOp           op,
926
              FcExpr        *expr,
927
              FcValueBinding binding)
928
0
{
929
0
    FcEdit *e = (FcEdit *)malloc (sizeof (FcEdit));
930
931
0
    if (e) {
932
0
  const FcObjectType *o;
933
934
0
  e->object = object;
935
0
  e->op = op;
936
0
  e->expr = expr;
937
0
  e->binding = binding;
938
0
  o = FcNameGetObjectType (FcObjectName (e->object));
939
0
  if (o)
940
0
      FcTypecheckExpr (parse, expr, o->type);
941
0
    }
942
0
    return e;
943
0
}
944
945
static FcRule *
946
FcRuleCreate (FcRuleType type,
947
              void      *p)
948
0
{
949
0
    FcRule *r = (FcRule *)malloc (sizeof (FcRule));
950
951
0
    if (!r)
952
0
  return NULL;
953
954
0
    r->next = NULL;
955
0
    r->type = type;
956
0
    switch (type) {
957
0
    case FcRuleTest:
958
0
  r->u.test = (FcTest *)p;
959
0
  break;
960
0
    case FcRuleEdit:
961
0
  r->u.edit = (FcEdit *)p;
962
0
  break;
963
0
    case FcRuleUnknown:
964
0
    default:
965
0
  free (r);
966
0
  r = NULL;
967
0
  break;
968
0
    }
969
970
0
    return r;
971
0
}
972
973
static FcVStack *
974
FcVStackCreateAndPush (FcConfigParse *parse)
975
0
{
976
0
    FcVStack *newp;
977
978
0
    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
979
0
  newp = &parse->vstack_static[parse->vstack_static_used++];
980
0
    else {
981
0
  newp = malloc (sizeof (FcVStack));
982
0
  if (!newp)
983
0
      return 0;
984
0
    }
985
0
    newp->tag = FcVStackNone;
986
0
    newp->prev = 0;
987
988
0
    newp->prev = parse->vstack;
989
0
    newp->pstack = parse->pstack ? parse->pstack->prev : 0;
990
0
    parse->vstack = newp;
991
992
0
    return newp;
993
0
}
994
995
static FcBool
996
FcVStackPushNil (FcConfigParse *parse)
997
0
{
998
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
999
1000
0
    if (!vstack)
1001
0
  return FcFalse;
1002
0
    vstack->tag = FcVStackNil;
1003
1004
0
    return FcTrue;
1005
0
}
1006
1007
static FcBool
1008
FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
1009
0
{
1010
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1011
0
    if (!vstack)
1012
0
  return FcFalse;
1013
0
    vstack->u.string = string;
1014
0
    vstack->tag = tag;
1015
0
    return FcTrue;
1016
0
}
1017
1018
static FcBool
1019
FcVStackPushInteger (FcConfigParse *parse, int integer)
1020
0
{
1021
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1022
0
    if (!vstack)
1023
0
  return FcFalse;
1024
0
    vstack->u.integer = integer;
1025
0
    vstack->tag = FcVStackInteger;
1026
0
    return FcTrue;
1027
0
}
1028
1029
static FcBool
1030
FcVStackPushDouble (FcConfigParse *parse, double _double)
1031
0
{
1032
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1033
0
    if (!vstack)
1034
0
  return FcFalse;
1035
0
    vstack->u._double = _double;
1036
0
    vstack->tag = FcVStackDouble;
1037
0
    return FcTrue;
1038
0
}
1039
1040
static FcBool
1041
FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
1042
0
{
1043
0
    FcVStack *vstack;
1044
0
    vstack = FcVStackCreateAndPush (parse);
1045
0
    if (!vstack)
1046
0
  return FcFalse;
1047
0
    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
1048
0
    vstack->tag = FcVStackMatrix;
1049
0
    return FcTrue;
1050
0
}
1051
1052
static FcBool
1053
FcVStackPushRange (FcConfigParse *parse, FcRange *range)
1054
0
{
1055
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1056
0
    if (!vstack)
1057
0
  return FcFalse;
1058
0
    vstack->u.range = range;
1059
0
    vstack->tag = FcVStackRange;
1060
0
    return FcTrue;
1061
0
}
1062
1063
static FcBool
1064
FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
1065
0
{
1066
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1067
0
    if (!vstack)
1068
0
  return FcFalse;
1069
0
    vstack->u.bool_ = bool_;
1070
0
    vstack->tag = FcVStackBool;
1071
0
    return FcTrue;
1072
0
}
1073
1074
static FcBool
1075
FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
1076
0
{
1077
0
    FcVStack *vstack;
1078
0
    if (!charset)
1079
0
  return FcFalse;
1080
0
    vstack = FcVStackCreateAndPush (parse);
1081
0
    if (!vstack)
1082
0
  return FcFalse;
1083
0
    vstack->u.charset = charset;
1084
0
    vstack->tag = FcVStackCharSet;
1085
0
    return FcTrue;
1086
0
}
1087
1088
static FcBool
1089
FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
1090
0
{
1091
0
    FcVStack *vstack;
1092
0
    if (!langset)
1093
0
  return FcFalse;
1094
0
    vstack = FcVStackCreateAndPush (parse);
1095
0
    if (!vstack)
1096
0
  return FcFalse;
1097
0
    vstack->u.langset = langset;
1098
0
    vstack->tag = FcVStackLangSet;
1099
0
    return FcTrue;
1100
0
}
1101
1102
static FcBool
1103
FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
1104
0
{
1105
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1106
0
    if (!vstack)
1107
0
  return FcFalse;
1108
0
    vstack->u.name.object = object;
1109
0
    vstack->u.name.kind = kind;
1110
0
    vstack->tag = FcVStackName;
1111
0
    return FcTrue;
1112
0
}
1113
1114
static FcBool
1115
FcVStackPushTest (FcConfigParse *parse, FcTest *test)
1116
0
{
1117
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1118
0
    if (!vstack)
1119
0
  return FcFalse;
1120
0
    vstack->u.test = test;
1121
0
    vstack->tag = FcVStackTest;
1122
0
    return FcTrue;
1123
0
}
1124
1125
static FcBool
1126
FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
1127
0
{
1128
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1129
0
    if (!vstack)
1130
0
  return FcFalse;
1131
0
    vstack->u.expr = expr;
1132
0
    vstack->tag = tag;
1133
0
    return FcTrue;
1134
0
}
1135
1136
static FcBool
1137
FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
1138
0
{
1139
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1140
0
    if (!vstack)
1141
0
  return FcFalse;
1142
0
    vstack->u.edit = edit;
1143
0
    vstack->tag = FcVStackEdit;
1144
0
    return FcTrue;
1145
0
}
1146
1147
static FcBool
1148
FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
1149
0
{
1150
0
    FcVStack *vstack = FcVStackCreateAndPush (parse);
1151
0
    if (!vstack)
1152
0
  return FcFalse;
1153
0
    vstack->u.pattern = pattern;
1154
0
    vstack->tag = FcVStackPattern;
1155
0
    return FcTrue;
1156
0
}
1157
1158
static FcVStack *
1159
FcVStackFetch (FcConfigParse *parse, int off)
1160
0
{
1161
0
    FcVStack *vstack;
1162
1163
0
    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev)
1164
0
  ;
1165
0
    return vstack;
1166
0
}
1167
1168
static FcVStack *
1169
FcVStackPeek (FcConfigParse *parse)
1170
0
{
1171
0
    FcVStack *vstack = parse->vstack;
1172
1173
0
    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
1174
0
}
1175
1176
static void
1177
FcVStackPopAndDestroy (FcConfigParse *parse)
1178
0
{
1179
0
    FcVStack *vstack = parse->vstack;
1180
1181
0
    if (!vstack || vstack->pstack != parse->pstack)
1182
0
  return;
1183
1184
0
    parse->vstack = vstack->prev;
1185
1186
0
    switch (vstack->tag) {
1187
0
    case FcVStackNone:
1188
0
  break;
1189
0
    case FcVStackName:
1190
0
  break;
1191
0
    case FcVStackFamily:
1192
0
  break;
1193
0
    case FcVStackString:
1194
0
    case FcVStackConstant:
1195
0
    case FcVStackGlob:
1196
0
  FcStrFree (vstack->u.string);
1197
0
  break;
1198
0
    case FcVStackPattern:
1199
0
  FcPatternDestroy (vstack->u.pattern);
1200
0
  break;
1201
0
    case FcVStackInteger:
1202
0
    case FcVStackDouble:
1203
0
    case FcVStackNil:
1204
0
  break;
1205
0
    case FcVStackMatrix:
1206
0
  FcExprMatrixFreeShallow (vstack->u.matrix);
1207
0
  break;
1208
0
    case FcVStackBool:
1209
0
  break;
1210
0
    case FcVStackRange:
1211
0
  FcRangeDestroy (vstack->u.range);
1212
0
  break;
1213
0
    case FcVStackCharSet:
1214
0
  FcCharSetDestroy (vstack->u.charset);
1215
0
  break;
1216
0
    case FcVStackLangSet:
1217
0
  FcLangSetDestroy (vstack->u.langset);
1218
0
  break;
1219
0
    case FcVStackTest:
1220
0
  FcTestDestroy (vstack->u.test);
1221
0
  break;
1222
0
    case FcVStackExpr:
1223
0
    case FcVStackPrefer:
1224
0
    case FcVStackAccept:
1225
0
    case FcVStackDefault:
1226
0
  FcExprDestroy (vstack->u.expr);
1227
0
  break;
1228
0
    case FcVStackEdit:
1229
0
  FcEditDestroy (vstack->u.edit);
1230
0
  break;
1231
0
    }
1232
1233
0
    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1234
0
  parse->vstack_static_used--;
1235
0
    else
1236
0
  free (vstack);
1237
0
}
1238
1239
static void
1240
FcVStackClear (FcConfigParse *parse)
1241
0
{
1242
0
    while (FcVStackPeek (parse))
1243
0
  FcVStackPopAndDestroy (parse);
1244
0
}
1245
1246
static int
1247
FcVStackElements (FcConfigParse *parse)
1248
0
{
1249
0
    int       h = 0;
1250
0
    FcVStack *vstack = parse->vstack;
1251
0
    while (vstack && vstack->pstack == parse->pstack) {
1252
0
  h++;
1253
0
  vstack = vstack->prev;
1254
0
    }
1255
0
    return h;
1256
0
}
1257
1258
static FcChar8 **
1259
FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
1260
0
{
1261
0
    int       slen;
1262
0
    int       i;
1263
0
    FcChar8 **newp;
1264
0
    FcChar8  *s;
1265
1266
0
    if (!attr)
1267
0
  return 0;
1268
0
    slen = 0;
1269
0
    for (i = 0; attr[i]; i++)
1270
0
  slen += strlen ((char *)attr[i]) + 1;
1271
0
    if (i == 0)
1272
0
  return 0;
1273
0
    slen += (i + 1) * sizeof (FcChar8 *);
1274
0
    if (slen <= size_bytes)
1275
0
  newp = buf;
1276
0
    else {
1277
0
  newp = malloc (slen);
1278
0
  if (!newp) {
1279
0
      FcConfigMessage (0, FcSevereError, "out of memory");
1280
0
      return 0;
1281
0
  }
1282
0
    }
1283
0
    s = (FcChar8 *)(newp + (i + 1));
1284
0
    for (i = 0; attr[i]; i++) {
1285
0
  newp[i] = s;
1286
0
  strcpy ((char *)s, (char *)attr[i]);
1287
0
  s += strlen ((char *)s) + 1;
1288
0
    }
1289
0
    newp[i] = 0;
1290
0
    return newp;
1291
0
}
1292
1293
static FcBool
1294
FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1295
0
{
1296
0
    FcPStack *newp;
1297
1298
0
    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1299
0
  newp = &parse->pstack_static[parse->pstack_static_used++];
1300
0
    else {
1301
0
  newp = malloc (sizeof (FcPStack));
1302
0
  if (!newp)
1303
0
      return FcFalse;
1304
0
    }
1305
1306
0
    newp->prev = parse->pstack;
1307
0
    newp->element = element;
1308
0
    newp->attr = FcConfigSaveAttr (attr, newp->attr_buf_static, sizeof (newp->attr_buf_static));
1309
0
    FcStrBufInit (&newp->str, 0, 0);
1310
0
    parse->pstack = newp;
1311
0
    return FcTrue;
1312
0
}
1313
1314
static FcBool
1315
FcPStackPop (FcConfigParse *parse)
1316
0
{
1317
0
    FcPStack     *old;
1318
0
    static FcBool retrieved = FcFalse;
1319
0
    const char   *env = NULL;
1320
1321
0
    if (!parse->pstack) {
1322
0
  FcConfigMessage (parse, FcSevereError, "mismatching element");
1323
0
  return FcFalse;
1324
0
    }
1325
1326
    /* Don't check the attributes for FcElementNone */
1327
0
    if (parse->pstack->element != FcElementNone &&
1328
0
        parse->pstack->attr) {
1329
0
  if (!retrieved) {
1330
0
      FcBool flag = FcFalse;
1331
1332
0
      env = getenv ("FONTCONFIG_WARN_INVALID_ATTRS");
1333
0
      if (env && FcNameBool ((const FcChar8 *)env, &flag)) {
1334
0
    retrieved = FcTrue;
1335
0
    FcConfigSetWarningFlags (parse->config, FC_WARN_INVALID_ATTR, flag);
1336
0
      }
1337
0
  }
1338
  /* Warn only when a flag is turned on */
1339
0
  if (FcConfigGetWarningFlags (parse->config) & FC_WARN_INVALID_ATTR) {
1340
      /* Warn about unused attrs. */
1341
0
      FcChar8 **attrs = parse->pstack->attr;
1342
0
      while (*attrs) {
1343
0
    if (attrs[0][0]) {
1344
0
        FcConfigMessage (parse, FcSevereWarning, "invalid attribute '%s'", attrs[0]);
1345
0
    }
1346
0
    attrs += 2;
1347
0
      }
1348
0
  }
1349
0
    }
1350
1351
0
    FcVStackClear (parse);
1352
0
    old = parse->pstack;
1353
0
    parse->pstack = old->prev;
1354
0
    FcStrBufDestroy (&old->str);
1355
1356
0
    if (old->attr && old->attr != old->attr_buf_static)
1357
0
  free (old->attr);
1358
1359
0
    if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1360
0
  parse->pstack_static_used--;
1361
0
    else
1362
0
  free (old);
1363
0
    return FcTrue;
1364
0
}
1365
1366
static FcBool
1367
FcConfigParseInit (FcConfigParse *parse,
1368
                   const FcChar8 *name,
1369
                   FcConfig      *config,
1370
                   XML_Parser     parser,
1371
                   FcBool         enabled)
1372
0
{
1373
0
    parse->pstack = 0;
1374
0
    parse->pstack_static_used = 0;
1375
0
    parse->vstack = 0;
1376
0
    parse->vstack_static_used = 0;
1377
0
    parse->error = FcFalse;
1378
0
    parse->name = name;
1379
0
    parse->config = config;
1380
0
    parse->ruleset = FcRuleSetCreate (name);
1381
0
    parse->parser = parser;
1382
0
    parse->scanOnly = !enabled;
1383
0
    FcRuleSetEnable (parse->ruleset, enabled);
1384
1385
0
    return FcTrue;
1386
0
}
1387
1388
static void
1389
FcConfigCleanup (FcConfigParse *parse)
1390
0
{
1391
0
    while (parse->pstack)
1392
0
  FcPStackPop (parse);
1393
0
    FcRuleSetDestroy (parse->ruleset);
1394
0
    parse->ruleset = NULL;
1395
0
}
1396
1397
static const FcChar8 *
1398
FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
1399
0
{
1400
0
    FcChar8 **attrs;
1401
0
    if (!parse->pstack)
1402
0
  return 0;
1403
1404
0
    attrs = parse->pstack->attr;
1405
0
    if (!attrs)
1406
0
  return 0;
1407
1408
0
    while (*attrs) {
1409
0
  if (!strcmp ((char *)*attrs, attr)) {
1410
0
      attrs[0][0] = '\0'; /* Mark as used. */
1411
0
      return attrs[1];
1412
0
  }
1413
0
  attrs += 2;
1414
0
    }
1415
0
    return 0;
1416
0
}
1417
1418
static FcStrSet *
1419
_get_real_paths_from_prefix (FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
1420
0
{
1421
#ifdef _WIN32
1422
    FcChar8 buffer[1000] = { 0 };
1423
#endif
1424
0
    FcChar8  *parent = NULL, *retval = NULL;
1425
0
    FcStrSet *e = NULL;
1426
1427
0
    if (prefix) {
1428
0
  if (FcStrCmp (prefix, (const FcChar8 *)"xdg") == 0) {
1429
0
      parent = FcConfigXdgDataHome();
1430
0
      if (!parent) {
1431
    /* Home directory might be disabled */
1432
0
    return NULL;
1433
0
      }
1434
0
      e = FcConfigXdgDataDirs();
1435
0
      if (!e) {
1436
0
    FcStrFree (parent);
1437
0
    return NULL;
1438
0
      }
1439
0
  } else if (FcStrCmp (prefix, (const FcChar8 *)"default") == 0 ||
1440
0
             FcStrCmp (prefix, (const FcChar8 *)"cwd") == 0) {
1441
      /* Nothing to do */
1442
0
  } else if (FcStrCmp (prefix, (const FcChar8 *)"relative") == 0) {
1443
0
      FcChar8 *p = FcStrRealPath (parse->name);
1444
1445
0
      if (!p)
1446
0
    return NULL;
1447
0
      parent = FcStrDirname (p);
1448
0
      FcStrFree (p);
1449
0
      if (!parent)
1450
0
    return NULL;
1451
0
  }
1452
0
    }
1453
0
#ifndef _WIN32
1454
    /* For Win32, check this later for dealing with special cases */
1455
0
    else {
1456
0
  if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1457
0
      FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1458
0
    }
1459
#else
1460
    if (strcmp ((const char *)path, "CUSTOMFONTDIR") == 0) {
1461
  FcChar8 *p;
1462
  path = buffer;
1463
  if (!GetModuleFileName (NULL, (LPCH)buffer, sizeof (buffer) - 20)) {
1464
      FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1465
      return NULL;
1466
  }
1467
  /*
1468
   * Must use the multi-byte aware function to search
1469
   * for backslash because East Asian double-byte code
1470
   * pages have characters with backslash as the second
1471
   * byte.
1472
   */
1473
  p = _mbsrchr (path, '\\');
1474
  if (p)
1475
      *p = '\0';
1476
  strcat ((char *)path, "\\fonts");
1477
    } else if (strcmp ((const char *)path, "APPSHAREFONTDIR") == 0) {
1478
  FcChar8 *p;
1479
  path = buffer;
1480
  if (!GetModuleFileName (NULL, (LPCH)buffer, sizeof (buffer) - 20)) {
1481
      FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
1482
      return NULL;
1483
  }
1484
  p = _mbsrchr (path, '\\');
1485
  if (p)
1486
      *p = '\0';
1487
  strcat ((char *)path, "\\..\\share\\fonts");
1488
    } else if (strcmp ((const char *)path, "WINDOWSUSERFONTDIR") == 0) {
1489
  path = buffer;
1490
  if (!(pSHGetFolderPathA && SUCCEEDED (pSHGetFolderPathA (NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, (char *)buffer)))) {
1491
      FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
1492
      return NULL;
1493
  }
1494
  strcat ((char *)path, "\\Microsoft\\Windows\\Fonts");
1495
    } else if (strcmp ((const char *)path, "WINDOWSFONTDIR") == 0) {
1496
  int rc;
1497
  path = buffer;
1498
  _ensureWin32GettersReady();
1499
  rc = pGetSystemWindowsDirectory ((LPSTR)buffer, sizeof (buffer) - 20);
1500
  if (rc == 0 || rc > sizeof (buffer) - 20) {
1501
      FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
1502
      return NULL;
1503
  }
1504
  if (path[strlen ((const char *)path) - 1] != '\\')
1505
      strcat ((char *)path, "\\");
1506
  strcat ((char *)path, "fonts");
1507
    } else {
1508
  if (!prefix) {
1509
      if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1510
    FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1511
  }
1512
    }
1513
#endif
1514
0
    if (parent) {
1515
0
  retval = FcStrBuildFilename (parent, path, NULL);
1516
0
  FcStrFree (parent);
1517
0
    } else {
1518
0
  retval = FcStrCopy (path);
1519
0
    }
1520
0
    if (!e)
1521
0
  e = FcStrSetCreate();
1522
0
    else {
1523
0
  FcChar8 *s;
1524
0
  int      i;
1525
1526
0
  for (i = 0; i < e->num; i++) {
1527
0
      s = FcStrBuildFilename (e->strs[i], path, NULL);
1528
0
      FcStrFree (e->strs[i]);
1529
0
      e->strs[i] = s;
1530
0
  }
1531
0
    }
1532
0
    if (!FcStrSetInsert (e, retval, 0)) {
1533
0
  FcStrSetDestroy (e);
1534
0
  e = NULL;
1535
0
    }
1536
0
    FcStrFree (retval);
1537
1538
0
    return e;
1539
0
}
1540
1541
static void
1542
FcStartElement (void *userData, const XML_Char *name, const XML_Char **attr)
1543
0
{
1544
0
    FcConfigParse *parse = userData;
1545
0
    FcElement      element;
1546
1547
0
    element = FcElementMap (name);
1548
0
    if (element == FcElementUnknown)
1549
0
  FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
1550
1551
0
    if (!FcPStackPush (parse, element, attr)) {
1552
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1553
0
  return;
1554
0
    }
1555
0
    return;
1556
0
}
1557
1558
static void
1559
FcParseRescan (FcConfigParse *parse)
1560
0
{
1561
0
    int n = FcVStackElements (parse);
1562
0
    while (n-- > 0) {
1563
0
  FcVStack *v = FcVStackFetch (parse, n);
1564
0
  if (v->tag != FcVStackInteger)
1565
0
      FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1566
0
  else
1567
0
      parse->config->rescanInterval = v->u.integer;
1568
0
    }
1569
0
}
1570
1571
static FcBool
1572
FcParseNil (FcConfigParse *parse)
1573
0
{
1574
0
    const FcChar8 *nil;
1575
1576
0
    if (!parse->pstack)
1577
0
  return FcFalse;
1578
0
    nil = FcConfigGetAttribute (parse, "xsi:nil");
1579
0
    if (!nil)
1580
0
  return FcFalse;
1581
0
    if (!FcConfigLexBool (parse, nil))
1582
0
  return FcFalse;
1583
0
    FcVStackPushNil (parse);
1584
1585
0
    return FcTrue;
1586
0
}
1587
1588
static void
1589
FcParseInt (FcConfigParse *parse)
1590
0
{
1591
0
    FcChar8 *s, *end;
1592
0
    int      l;
1593
1594
0
    if (!parse->pstack)
1595
0
  return;
1596
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1597
0
    if (!s) {
1598
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1599
0
  return;
1600
0
    }
1601
0
    if (FcParseNil (parse))
1602
0
  goto bail;
1603
0
    end = 0;
1604
0
    l = (int)strtol ((char *)s, (char **)&end, 0);
1605
0
    if (end != s + strlen ((char *)s))
1606
0
  FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
1607
0
    else
1608
0
  FcVStackPushInteger (parse, l);
1609
0
bail:
1610
0
    FcStrBufDestroy (&parse->pstack->str);
1611
0
}
1612
1613
static void
1614
FcParseDouble (FcConfigParse *parse)
1615
0
{
1616
0
    FcChar8 *s, *end;
1617
0
    double   d;
1618
1619
0
    if (!parse->pstack)
1620
0
  return;
1621
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1622
0
    if (!s) {
1623
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1624
0
  return;
1625
0
    }
1626
0
    if (FcParseNil (parse))
1627
0
  goto bail;
1628
0
    end = 0;
1629
0
    d = FcStrtod ((char *)s, (char **)&end);
1630
0
    if (end != s + strlen ((char *)s))
1631
0
  FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
1632
0
    else
1633
0
  FcVStackPushDouble (parse, d);
1634
0
bail:
1635
0
    FcStrBufDestroy (&parse->pstack->str);
1636
0
}
1637
1638
static void
1639
FcParseString (FcConfigParse *parse, FcVStackTag tag)
1640
0
{
1641
0
    FcChar8 *s;
1642
1643
0
    if (!parse->pstack)
1644
0
  return;
1645
0
    s = FcStrBufDone (&parse->pstack->str);
1646
0
    if (!s) {
1647
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1648
0
  return;
1649
0
    }
1650
0
    if (FcParseNil (parse)) {
1651
0
  FcStrFree (s);
1652
0
  return;
1653
0
    }
1654
0
    if (!FcVStackPushString (parse, tag, s))
1655
0
  FcStrFree (s);
1656
0
}
1657
1658
static void
1659
FcParseName (FcConfigParse *parse)
1660
0
{
1661
0
    const FcChar8 *kind_string;
1662
0
    FcMatchKind    kind;
1663
0
    FcChar8       *s;
1664
0
    FcObject       object;
1665
1666
0
    kind_string = FcConfigGetAttribute (parse, "target");
1667
0
    if (!kind_string)
1668
0
  kind = FcMatchDefault;
1669
0
    else {
1670
0
  if (!strcmp ((char *)kind_string, "pattern"))
1671
0
      kind = FcMatchPattern;
1672
0
  else if (!strcmp ((char *)kind_string, "font"))
1673
0
      kind = FcMatchFont;
1674
0
  else if (!strcmp ((char *)kind_string, "default"))
1675
0
      kind = FcMatchDefault;
1676
0
  else {
1677
0
      FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1678
0
      return;
1679
0
  }
1680
0
    }
1681
1682
0
    if (!parse->pstack)
1683
0
  return;
1684
0
    s = FcStrBufDone (&parse->pstack->str);
1685
0
    if (!s) {
1686
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1687
0
  return;
1688
0
    }
1689
0
    object = FcObjectFromName ((const char *)s);
1690
1691
0
    FcVStackPushName (parse, kind, object);
1692
1693
0
    FcStrFree (s);
1694
0
}
1695
1696
static void
1697
FcParseMatrix (FcConfigParse *parse)
1698
0
{
1699
0
    FcExprMatrix m;
1700
1701
0
    m.yy = FcPopExpr (parse);
1702
0
    m.yx = FcPopExpr (parse);
1703
0
    m.xy = FcPopExpr (parse);
1704
0
    m.xx = FcPopExpr (parse);
1705
1706
0
    if (!m.yy || !m.yx || !m.xy || !m.xx) {
1707
0
  FcConfigMessage (parse, FcSevereWarning, "Missing values in matrix element");
1708
0
  return;
1709
0
    }
1710
0
    if (FcPopExpr (parse))
1711
0
  FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
1712
0
    else
1713
0
  FcVStackPushMatrix (parse, &m);
1714
0
}
1715
1716
static void
1717
FcParseRange (FcConfigParse *parse)
1718
0
{
1719
0
    FcVStack *vstack;
1720
0
    FcRange  *r;
1721
0
    FcChar32  n[2] = { 0, 0 };
1722
0
    int       count = 1;
1723
0
    double    d[2] = { 0.0L, 0.0L };
1724
0
    FcBool    dflag = FcFalse;
1725
1726
0
    while ((vstack = FcVStackPeek (parse))) {
1727
0
  if (count < 0) {
1728
0
      FcConfigMessage (parse, FcSevereError, "too many elements in range");
1729
0
      return;
1730
0
  }
1731
0
  switch ((int)vstack->tag) {
1732
0
  case FcVStackInteger:
1733
0
      if (dflag)
1734
0
    d[count] = (double)vstack->u.integer;
1735
0
      else
1736
0
    n[count] = vstack->u.integer;
1737
0
      break;
1738
0
  case FcVStackDouble:
1739
0
      if (count == 0 && !dflag)
1740
0
    d[1] = (double)n[1];
1741
0
      d[count] = vstack->u._double;
1742
0
      dflag = FcTrue;
1743
0
      break;
1744
0
  default:
1745
0
      FcConfigMessage (parse, FcSevereError, "invalid element in range");
1746
0
      if (dflag)
1747
0
    d[count] = 0.0L;
1748
0
      else
1749
0
    n[count] = 0;
1750
0
      break;
1751
0
  }
1752
0
  count--;
1753
0
  FcVStackPopAndDestroy (parse);
1754
0
    }
1755
0
    if (count >= 0) {
1756
0
  FcConfigMessage (parse, FcSevereError, "invalid range");
1757
0
  return;
1758
0
    }
1759
0
    if (dflag) {
1760
0
  if (d[0] > d[1]) {
1761
0
      FcConfigMessage (parse, FcSevereError, "invalid range");
1762
0
      return;
1763
0
  }
1764
0
  r = FcRangeCreateDouble (d[0], d[1]);
1765
0
    } else {
1766
0
  if (n[0] > n[1]) {
1767
0
      FcConfigMessage (parse, FcSevereError, "invalid range");
1768
0
      return;
1769
0
  }
1770
0
  r = FcRangeCreateInteger (n[0], n[1]);
1771
0
    }
1772
0
    FcVStackPushRange (parse, r);
1773
0
}
1774
1775
static FcBool
1776
FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
1777
0
{
1778
0
    FcBool result = FcFalse;
1779
1780
0
    if (!FcNameBool (bool_, &result))
1781
0
  FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
1782
0
                   bool_);
1783
0
    return result;
1784
0
}
1785
1786
static void
1787
FcParseBool (FcConfigParse *parse)
1788
0
{
1789
0
    FcChar8 *s;
1790
1791
0
    if (!parse->pstack)
1792
0
  return;
1793
0
    if (FcParseNil (parse))
1794
0
  goto bail;
1795
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1796
0
    if (!s) {
1797
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1798
0
  return;
1799
0
    }
1800
0
    FcVStackPushBool (parse, FcConfigLexBool (parse, s));
1801
0
bail:
1802
0
    FcStrBufDestroy (&parse->pstack->str);
1803
0
}
1804
1805
static void
1806
FcParseCharSet (FcConfigParse *parse)
1807
0
{
1808
0
    FcVStack  *vstack;
1809
0
    FcCharSet *charset = FcCharSetCreate();
1810
0
    FcChar32   i, begin, end;
1811
0
    int        n = 0;
1812
1813
0
    if (FcParseNil (parse))
1814
0
  goto bail;
1815
0
    while ((vstack = FcVStackPeek (parse))) {
1816
0
  switch ((int)vstack->tag) {
1817
0
  case FcVStackInteger:
1818
0
      if (!FcCharSetAddChar (charset, vstack->u.integer)) {
1819
0
    FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1820
0
      } else
1821
0
    n++;
1822
0
      break;
1823
0
  case FcVStackRange:
1824
0
      begin = (FcChar32)vstack->u.range->begin;
1825
0
      end = (FcChar32)vstack->u.range->end;
1826
1827
0
      if (begin <= end) {
1828
0
    for (i = begin; i <= end; i++) {
1829
0
        if (!FcCharSetAddChar (charset, i)) {
1830
0
      FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1831
0
        } else
1832
0
      n++;
1833
0
    }
1834
0
      }
1835
0
      break;
1836
0
  default:
1837
0
      FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1838
0
      break;
1839
0
  }
1840
0
  FcVStackPopAndDestroy (parse);
1841
0
    }
1842
0
bail:
1843
0
    if (n > 0)
1844
0
  FcVStackPushCharSet (parse, charset);
1845
0
    else
1846
0
  FcCharSetDestroy (charset);
1847
0
}
1848
1849
static void
1850
FcParseLangSet (FcConfigParse *parse)
1851
0
{
1852
0
    FcVStack  *vstack;
1853
0
    FcLangSet *langset = FcLangSetCreate();
1854
0
    int        n = 0;
1855
1856
0
    if (FcParseNil (parse))
1857
0
  goto bail;
1858
0
    while ((vstack = FcVStackPeek (parse))) {
1859
0
  switch ((int)vstack->tag) {
1860
0
  case FcVStackString:
1861
0
      if (!FcLangSetAdd (langset, vstack->u.string)) {
1862
0
    FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1863
0
      } else
1864
0
    n++;
1865
0
      break;
1866
0
  default:
1867
0
      FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1868
0
      break;
1869
0
  }
1870
0
  FcVStackPopAndDestroy (parse);
1871
0
    }
1872
0
bail:
1873
0
    if (n > 0)
1874
0
  FcVStackPushLangSet (parse, langset);
1875
0
    else
1876
0
  FcLangSetDestroy (langset);
1877
0
}
1878
1879
static FcBool
1880
FcConfigLexBinding (FcConfigParse  *parse,
1881
                    const FcChar8  *binding_string,
1882
                    FcValueBinding *binding_ret)
1883
0
{
1884
0
    FcValueBinding binding;
1885
1886
0
    if (!binding_string)
1887
0
  binding = FcValueBindingWeak;
1888
0
    else {
1889
0
  if (!strcmp ((char *)binding_string, "weak"))
1890
0
      binding = FcValueBindingWeak;
1891
0
  else if (!strcmp ((char *)binding_string, "strong"))
1892
0
      binding = FcValueBindingStrong;
1893
0
  else if (!strcmp ((char *)binding_string, "same"))
1894
0
      binding = FcValueBindingSame;
1895
0
  else {
1896
0
      FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1897
0
      return FcFalse;
1898
0
  }
1899
0
    }
1900
0
    *binding_ret = binding;
1901
0
    return FcTrue;
1902
0
}
1903
1904
static void
1905
FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
1906
0
{
1907
0
    FcVStack *vstack;
1908
0
    FcExpr   *left, *expr = 0, *newp;
1909
1910
0
    while ((vstack = FcVStackPeek (parse))) {
1911
0
  if (vstack->tag != FcVStackFamily) {
1912
0
      FcConfigMessage (parse, FcSevereWarning, "non-family");
1913
0
      FcVStackPopAndDestroy (parse);
1914
0
      continue;
1915
0
  }
1916
0
  left = vstack->u.expr;
1917
0
  vstack->tag = FcVStackNone;
1918
0
  FcVStackPopAndDestroy (parse);
1919
0
  if (expr) {
1920
0
      newp = FcExprCreateOp (parse->config, left, FcOpComma, expr);
1921
0
      if (!newp) {
1922
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
1923
0
    FcExprDestroy (left);
1924
0
    FcExprDestroy (expr);
1925
0
    break;
1926
0
      }
1927
0
      expr = newp;
1928
0
  } else
1929
0
      expr = left;
1930
0
    }
1931
0
    if (expr) {
1932
0
  if (!FcVStackPushExpr (parse, tag, expr)) {
1933
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
1934
0
      FcExprDestroy (expr);
1935
0
  }
1936
0
    }
1937
0
}
1938
1939
static void
1940
FcParseFamily (FcConfigParse *parse)
1941
0
{
1942
0
    FcChar8 *s;
1943
0
    FcExpr  *expr;
1944
1945
0
    if (!parse->pstack)
1946
0
  return;
1947
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
1948
0
    if (!s) {
1949
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
1950
0
  return;
1951
0
    }
1952
0
    expr = FcExprCreateString (parse->config, s);
1953
0
    FcStrBufDestroy (&parse->pstack->str);
1954
0
    if (expr)
1955
0
  FcVStackPushExpr (parse, FcVStackFamily, expr);
1956
0
}
1957
1958
static FcBool
1959
_FcParseAliasAddScanDeleteRule (FcConfigParse *parse,
1960
                                const FcExpr  *leaf,
1961
                                int            gf_value)
1962
0
{
1963
0
    FcExpr *e, *ex;
1964
0
    FcTest *t, *t2;
1965
0
    FcEdit *ed;
1966
0
    FcRule *r1, *r2, *r3;
1967
0
    int     n;
1968
1969
0
    e = FcExprDup (parse->config, leaf);
1970
0
    if (!e)
1971
0
  return FcFalse;
1972
0
    t = FcTestCreate (parse, FcMatchScan, FcQualAny,
1973
0
                      (FcChar8 *)FC_FAMILY,
1974
0
                      FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks), e);
1975
0
    if (!t) {
1976
0
  FcExprDestroy (e);
1977
0
  return FcFalse;
1978
0
    }
1979
0
    r1 = FcRuleCreate (FcRuleTest, t);
1980
0
    if (!r1) {
1981
0
  FcTestDestroy (t);
1982
0
  return FcFalse;
1983
0
    }
1984
0
    ex = FcExprCreateInteger (parse->config, gf_value);
1985
0
    if (!ex) {
1986
0
  FcRuleDestroy (r1);
1987
0
  return FcFalse;
1988
0
    }
1989
0
    t2 = FcTestCreate (parse, FcMatchScan, FcQualAny,
1990
0
                       (FcChar8 *)FC_GENERIC_FAMILY,
1991
0
                       FcOpEqual, ex);
1992
0
    if (!t2) {
1993
0
  FcExprDestroy (ex);
1994
0
  FcRuleDestroy (r1);
1995
0
  return FcFalse;
1996
0
    }
1997
0
    r2 = FcRuleCreate (FcRuleTest, t2);
1998
0
    if (!r2) {
1999
0
  FcTestDestroy (t2);
2000
0
  FcRuleDestroy (r1);
2001
0
  return FcFalse;
2002
0
    }
2003
0
    r1->next = r2;
2004
0
    ed = FcEditCreate (parse, FC_GENERIC_FAMILY_OBJECT,
2005
0
                       FcOpDelete, NULL, FcValueBindingWeak);
2006
0
    if (!ed) {
2007
0
  FcRuleDestroy (r1);
2008
0
  return FcFalse;
2009
0
    }
2010
0
    r3 = FcRuleCreate (FcRuleEdit, ed);
2011
0
    if (!r3) {
2012
0
  FcEditDestroy (ed);
2013
0
  FcRuleDestroy (r1);
2014
0
  return FcFalse;
2015
0
    }
2016
0
    r2->next = r3;
2017
0
    if ((n = FcRuleSetAdd (parse->ruleset, r1, FcMatchScan)) == -1) {
2018
0
  FcRuleDestroy (r1);
2019
0
  return FcFalse;
2020
0
    }
2021
0
    if (parse->config->maxObjects < n)
2022
0
  parse->config->maxObjects = n;
2023
0
    return FcTrue;
2024
0
}
2025
2026
static void
2027
_FcParseAliasAddScanRule (FcConfigParse *parse,
2028
                          const FcExpr  *leaf,
2029
                          const FcChar8 *generic,
2030
                          FcOp           op,
2031
                          FcValueBinding binding)
2032
0
{
2033
0
    FcExpr           *e, *ex;
2034
0
    FcTest           *t;
2035
0
    FcEdit           *ed;
2036
0
    FcRule           *rt, *re;
2037
0
    int               n;
2038
0
    const FcConstant *c;
2039
2040
0
    c = FcNameGetConstantFor (generic, FC_GENERIC_FAMILY);
2041
0
    if (!c)
2042
0
  return;
2043
2044
0
    if (c->value != FC_FAMILY_UNKNOWN)
2045
0
  _FcParseAliasAddScanDeleteRule (parse, leaf, FC_FAMILY_UNKNOWN);
2046
0
    _FcParseAliasAddScanDeleteRule (parse, leaf, c->value);
2047
2048
0
    e = FcExprDup (parse->config, leaf);
2049
0
    if (!e)
2050
0
  return;
2051
0
    t = FcTestCreate (parse, FcMatchScan, FcQualAny,
2052
0
                      (FcChar8 *)FC_FAMILY,
2053
0
                      FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks), e);
2054
0
    if (!t) {
2055
0
  FcExprDestroy (e);
2056
0
  return;
2057
0
    }
2058
0
    rt = FcRuleCreate (FcRuleTest, t);
2059
0
    if (!rt) {
2060
0
  FcTestDestroy (t);
2061
0
  return;
2062
0
    }
2063
0
    ex = FcExprCreateConst (parse->config, generic);
2064
0
    if (!ex) {
2065
0
  FcRuleDestroy (rt);
2066
0
  return;
2067
0
    }
2068
0
    ed = FcEditCreate (parse, FC_GENERIC_FAMILY_OBJECT,
2069
0
                       FcOpAppend, ex, binding);
2070
0
    if (!ed) {
2071
0
  FcExprDestroy (ex);
2072
0
  FcRuleDestroy (rt);
2073
0
  return;
2074
0
    }
2075
0
    re = FcRuleCreate (FcRuleEdit, ed);
2076
0
    if (!re) {
2077
0
  FcEditDestroy (ed);
2078
0
  FcRuleDestroy (rt);
2079
0
  return;
2080
0
    }
2081
0
    rt->next = re;
2082
0
    if ((n = FcRuleSetAdd (parse->ruleset, rt, FcMatchScan)) == -1)
2083
0
  FcRuleDestroy (rt);
2084
0
    else if (parse->config->maxObjects < n)
2085
0
  parse->config->maxObjects = n;
2086
0
}
2087
2088
static void
2089
_FcParseAliasForGenericFamilyWalk (FcConfigParse *parse,
2090
                                   const FcExpr  *edit,
2091
                                   const FcChar8 *generic,
2092
                                   FcOp           op,
2093
                                   FcValueBinding binding)
2094
0
{
2095
0
    while (edit) {
2096
0
  if (edit->op == FcOpString) {
2097
0
      _FcParseAliasAddScanRule (parse, edit, generic, op, binding);
2098
0
      break;
2099
0
  } else if (edit->op == FcOpComma) {
2100
0
      if (edit->u.tree.left)
2101
0
    _FcParseAliasForGenericFamilyWalk (parse, edit->u.tree.left, generic, op, binding);
2102
0
      edit = edit->u.tree.right;
2103
0
  } else {
2104
0
      break;
2105
0
  }
2106
0
    }
2107
0
}
2108
2109
static void
2110
FcParseAliasForGenericFamily (FcConfigParse *parse,
2111
                              const FcExpr  *test,
2112
                              const FcExpr  *edit,
2113
                              FcOp           op,
2114
                              FcValueBinding binding)
2115
0
{
2116
0
    const FcConstant *c;
2117
2118
0
    if (!test || test->op != FcOpString || !edit)
2119
0
  return;
2120
0
    c = FcNameGetConstantFor (test->u.sval, FC_GENERIC_FAMILY);
2121
0
    if (!c)
2122
0
  return;
2123
0
    _FcParseAliasForGenericFamilyWalk (parse, edit, test->u.sval, op, binding);
2124
0
}
2125
2126
static void
2127
FcParseAliasAddEdit (FcConfigParse *parse,
2128
                     FcExpr        *texpr,
2129
                     FcExpr        *eexpr,
2130
                     FcOp           op,
2131
                     FcValueBinding binding,
2132
                     FcRule       **tail_for_pat)
2133
0
{
2134
0
    FcEdit *edit;
2135
2136
0
    edit = FcEditCreate (parse, FC_FAMILY_OBJECT, op, eexpr, binding);
2137
0
    if (!edit) {
2138
0
  FcExprDestroy (eexpr);
2139
0
  return;
2140
0
    }
2141
0
    (*tail_for_pat)->next = FcRuleCreate (FcRuleEdit, edit);
2142
0
    if (!(*tail_for_pat)->next) {
2143
0
  FcEditDestroy (edit);
2144
0
  return;
2145
0
    }
2146
0
    *tail_for_pat = (*tail_for_pat)->next;
2147
0
    FcParseAliasForGenericFamily (parse, texpr, eexpr, op, binding);
2148
0
}
2149
2150
static void
2151
FcParseAlias (FcConfigParse *parse)
2152
0
{
2153
0
    FcExpr        *family = 0, *accept = 0, *prefer = 0, *def = 0, *newp = 0;
2154
0
    FcVStack      *vstack;
2155
0
    FcRule        *rule = NULL, *r;
2156
0
    FcValueBinding binding;
2157
0
    int            n;
2158
2159
0
    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2160
0
  return;
2161
0
    while ((vstack = FcVStackPeek (parse))) {
2162
0
  switch ((int)vstack->tag) {
2163
0
  case FcVStackFamily:
2164
0
      if (family) {
2165
0
    FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
2166
0
    newp = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
2167
0
    if (!newp)
2168
0
        FcConfigMessage (parse, FcSevereError, "out of memory");
2169
0
    else
2170
0
        family = newp;
2171
0
      } else
2172
0
    newp = vstack->u.expr;
2173
0
      if (newp) {
2174
0
    family = newp;
2175
0
    vstack->tag = FcVStackNone;
2176
0
      }
2177
0
      break;
2178
0
  case FcVStackPrefer:
2179
0
      if (prefer)
2180
0
    FcExprDestroy (prefer);
2181
0
      prefer = vstack->u.expr;
2182
0
      vstack->tag = FcVStackNone;
2183
0
      break;
2184
0
  case FcVStackAccept:
2185
0
      if (accept)
2186
0
    FcExprDestroy (accept);
2187
0
      accept = vstack->u.expr;
2188
0
      vstack->tag = FcVStackNone;
2189
0
      break;
2190
0
  case FcVStackDefault:
2191
0
      if (def)
2192
0
    FcExprDestroy (def);
2193
0
      def = vstack->u.expr;
2194
0
      vstack->tag = FcVStackNone;
2195
0
      break;
2196
0
  case FcVStackTest:
2197
0
      if (rule) {
2198
0
    r = FcRuleCreate (FcRuleTest, vstack->u.test);
2199
0
    r->next = rule;
2200
0
    rule = r;
2201
0
      } else
2202
0
    rule = FcRuleCreate (FcRuleTest, vstack->u.test);
2203
0
      vstack->tag = FcVStackNone;
2204
0
      break;
2205
0
  default:
2206
0
      FcConfigMessage (parse, FcSevereWarning, "bad alias");
2207
0
      break;
2208
0
  }
2209
0
  FcVStackPopAndDestroy (parse);
2210
0
    }
2211
0
    if (!family) {
2212
0
  FcConfigMessage (parse, FcSevereError, "missing family in alias");
2213
0
  if (prefer)
2214
0
      FcExprDestroy (prefer);
2215
0
  if (accept)
2216
0
      FcExprDestroy (accept);
2217
0
  if (def)
2218
0
      FcExprDestroy (def);
2219
0
  if (rule)
2220
0
      FcRuleDestroy (rule);
2221
0
  return;
2222
0
    }
2223
0
    if (!prefer &&
2224
0
        !accept &&
2225
0
        !def) {
2226
0
  FcExprDestroy (family);
2227
0
  if (rule)
2228
0
      FcRuleDestroy (rule);
2229
0
  return;
2230
0
    } else {
2231
0
  FcTest *t = FcTestCreate (parse, FcMatchPattern,
2232
0
                            FcQualAny,
2233
0
                            (FcChar8 *)FC_FAMILY,
2234
0
                            FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
2235
0
                            family);
2236
0
  if (rule) {
2237
0
      for (r = rule; r->next; r = r->next)
2238
0
    ;
2239
0
      r->next = FcRuleCreate (FcRuleTest, t);
2240
0
      r = r->next;
2241
0
  } else {
2242
0
      r = rule = FcRuleCreate (FcRuleTest, t);
2243
0
  }
2244
0
    }
2245
0
    if (prefer)
2246
0
  FcParseAliasAddEdit (parse, family, prefer, FcOpPrepend, binding, &r);
2247
0
    if (accept)
2248
0
  FcParseAliasAddEdit (parse, family, accept, FcOpAppend, binding, &r);
2249
0
    if (def)
2250
0
  FcParseAliasAddEdit (parse, family, def, FcOpAppendLast, binding, &r);
2251
2252
0
    if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1) {
2253
0
  FcRuleDestroy (rule);
2254
0
  return;
2255
0
    } else if (parse->config->maxObjects < n) {
2256
0
  parse->config->maxObjects = n;
2257
0
    }
2258
0
}
2259
2260
static void
2261
FcParseDescription (FcConfigParse *parse)
2262
0
{
2263
0
    const FcChar8 *domain;
2264
0
    FcChar8       *desc;
2265
2266
0
    domain = FcConfigGetAttribute (parse, "domain");
2267
0
    desc = FcStrBufDone (&parse->pstack->str);
2268
0
    if (!desc) {
2269
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2270
0
  return;
2271
0
    }
2272
0
    FcRuleSetAddDescription (parse->ruleset, domain, desc);
2273
2274
0
    FcStrFree (desc);
2275
0
}
2276
2277
static void
2278
FcParseRemapDir (FcConfigParse *parse)
2279
0
{
2280
0
    const FcChar8 *path, *attr, *data, *salt;
2281
0
    FcStrSet      *prefix_dirs = NULL;
2282
2283
0
    data = FcStrBufDoneStatic (&parse->pstack->str);
2284
0
    if (!data) {
2285
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2286
0
  return;
2287
0
    }
2288
0
    if (data[0] == 0) {
2289
0
  FcConfigMessage (parse, FcSevereWarning, "empty font directory name for remap ignored");
2290
0
  return;
2291
0
    }
2292
0
    path = FcConfigGetAttribute (parse, "as-path");
2293
0
    if (!path) {
2294
0
  FcConfigMessage (parse, FcSevereWarning, "Missing as-path in remap-dir");
2295
0
  return;
2296
0
    }
2297
0
    attr = FcConfigGetAttribute (parse, "prefix");
2298
0
    salt = FcConfigGetAttribute (parse, "salt");
2299
0
    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2300
0
    if (prefix_dirs) {
2301
0
  FcStrList *l = FcStrListCreate (prefix_dirs);
2302
0
  FcChar8   *prefix;
2303
2304
0
  FcStrSetDestroy (prefix_dirs);
2305
0
  while ((prefix = FcStrListNext (l))) {
2306
0
      if (!prefix || prefix[0] == 0) {
2307
    /* nop */
2308
0
      } else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome())) {
2309
0
    if (!FcConfigAddFontDir (parse->config, prefix, path, salt))
2310
0
        FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path);
2311
0
      }
2312
0
      FcStrBufDestroy (&parse->pstack->str);
2313
0
  }
2314
0
  FcStrListDone (l);
2315
0
    }
2316
0
}
2317
2318
static void
2319
FcParseResetDirs (FcConfigParse *parse)
2320
0
{
2321
0
    if (!parse->scanOnly) {
2322
0
  if (!FcConfigResetFontDirs (parse->config))
2323
0
      FcConfigMessage (parse, FcSevereError, "Unable to reset fonts dirs");
2324
0
    }
2325
0
}
2326
2327
static FcExpr *
2328
FcPopExpr (FcConfigParse *parse)
2329
0
{
2330
0
    FcVStack *vstack = FcVStackPeek (parse);
2331
0
    FcExpr   *expr = 0;
2332
0
    if (!vstack)
2333
0
  return 0;
2334
0
    switch ((int)vstack->tag) {
2335
0
    case FcVStackNone:
2336
0
  break;
2337
0
    case FcVStackString:
2338
0
    case FcVStackFamily:
2339
0
  expr = FcExprCreateString (parse->config, vstack->u.string);
2340
0
  break;
2341
0
    case FcVStackName:
2342
0
  expr = FcExprCreateName (parse->config, vstack->u.name);
2343
0
  break;
2344
0
    case FcVStackConstant:
2345
0
  expr = FcExprCreateConst (parse->config, vstack->u.string);
2346
0
  break;
2347
0
    case FcVStackGlob:
2348
  /* XXX: What's the correct action here? (CDW) */
2349
0
  break;
2350
0
    case FcVStackPrefer:
2351
0
    case FcVStackAccept:
2352
0
    case FcVStackDefault:
2353
0
  expr = vstack->u.expr;
2354
0
  vstack->tag = FcVStackNone;
2355
0
  break;
2356
0
    case FcVStackInteger:
2357
0
  expr = FcExprCreateInteger (parse->config, vstack->u.integer);
2358
0
  break;
2359
0
    case FcVStackDouble:
2360
0
  expr = FcExprCreateDouble (parse->config, vstack->u._double);
2361
0
  break;
2362
0
    case FcVStackMatrix:
2363
0
  expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
2364
0
  break;
2365
0
    case FcVStackRange:
2366
0
  expr = FcExprCreateRange (parse->config, vstack->u.range);
2367
0
  break;
2368
0
    case FcVStackBool:
2369
0
  expr = FcExprCreateBool (parse->config, vstack->u.bool_);
2370
0
  break;
2371
0
    case FcVStackCharSet:
2372
0
  expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
2373
0
  break;
2374
0
    case FcVStackLangSet:
2375
0
  expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
2376
0
  break;
2377
0
    case FcVStackTest:
2378
0
  break;
2379
0
    case FcVStackExpr:
2380
0
  expr = vstack->u.expr;
2381
0
  vstack->tag = FcVStackNone;
2382
0
  break;
2383
0
    case FcVStackEdit:
2384
0
  break;
2385
0
    case FcVStackNil:
2386
0
  expr = FcExprCreateNil (parse->config);
2387
0
  break;
2388
0
    default:
2389
0
  break;
2390
0
    }
2391
0
    FcVStackPopAndDestroy (parse);
2392
0
    return expr;
2393
0
}
2394
2395
/*
2396
 * This builds a tree of binary operations.  Note
2397
 * that every operator is defined so that if only
2398
 * a single operand is contained, the value of the
2399
 * whole expression is the value of the operand.
2400
 *
2401
 * This code reduces in that case to returning that
2402
 * operand.
2403
 */
2404
static FcExpr *
2405
FcPopBinary (FcConfigParse *parse, FcOp op)
2406
0
{
2407
0
    FcExpr *left, *expr = 0, *newp;
2408
2409
0
    while ((left = FcPopExpr (parse))) {
2410
0
  if (expr) {
2411
0
      newp = FcExprCreateOp (parse->config, left, op, expr);
2412
0
      if (!newp) {
2413
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2414
0
    FcExprDestroy (left);
2415
0
    FcExprDestroy (expr);
2416
0
    return 0;
2417
0
      }
2418
0
      expr = newp;
2419
0
  } else
2420
0
      expr = left;
2421
0
    }
2422
0
    return expr;
2423
0
}
2424
2425
static void
2426
FcParseBinary (FcConfigParse *parse, FcOp op)
2427
0
{
2428
0
    FcExpr *expr = FcPopBinary (parse, op);
2429
0
    if (expr)
2430
0
  FcVStackPushExpr (parse, FcVStackExpr, expr);
2431
0
}
2432
2433
/*
2434
 * This builds a a unary operator, it consumes only
2435
 * a single operand
2436
 */
2437
2438
static FcExpr *
2439
FcPopUnary (FcConfigParse *parse, FcOp op)
2440
0
{
2441
0
    FcExpr *operand, *newp = 0;
2442
2443
0
    if ((operand = FcPopExpr (parse))) {
2444
0
  newp = FcExprCreateOp (parse->config, operand, op, 0);
2445
0
  if (!newp) {
2446
0
      FcExprDestroy (operand);
2447
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2448
0
  }
2449
0
    }
2450
0
    return newp;
2451
0
}
2452
2453
static void
2454
FcParseUnary (FcConfigParse *parse, FcOp op)
2455
0
{
2456
0
    FcExpr *expr = FcPopUnary (parse, op);
2457
0
    if (expr)
2458
0
  FcVStackPushExpr (parse, FcVStackExpr, expr);
2459
0
}
2460
2461
static void
2462
FcParseDir (FcConfigParse *parse)
2463
0
{
2464
0
    const FcChar8 *attr, *data, *salt;
2465
0
    FcStrSet      *prefix_dirs = NULL;
2466
2467
0
    data = FcStrBufDoneStatic (&parse->pstack->str);
2468
0
    if (!data) {
2469
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2470
0
  return;
2471
0
    }
2472
0
    if (data[0] == 0) {
2473
0
  FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2474
0
  return;
2475
0
    }
2476
0
    attr = FcConfigGetAttribute (parse, "prefix");
2477
0
    salt = FcConfigGetAttribute (parse, "salt");
2478
0
    prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2479
0
    if (prefix_dirs) {
2480
0
  FcStrList *l = FcStrListCreate (prefix_dirs);
2481
0
  FcChar8   *prefix;
2482
2483
0
  FcStrSetDestroy (prefix_dirs);
2484
0
  while ((prefix = FcStrListNext (l))) {
2485
0
      if (!prefix || prefix[0] == 0) {
2486
    /* nop */
2487
0
      } else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome())) {
2488
0
    if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt))
2489
0
        FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix);
2490
0
      }
2491
0
      FcStrBufDestroy (&parse->pstack->str);
2492
0
  }
2493
0
  FcStrListDone (l);
2494
0
    }
2495
0
}
2496
2497
static void
2498
FcParseCacheDir (FcConfigParse *parse)
2499
0
{
2500
0
    const FcChar8 *attr;
2501
0
    FcChar8       *prefix = NULL, *p, *data = NULL;
2502
2503
0
    attr = FcConfigGetAttribute (parse, "prefix");
2504
0
    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) {
2505
0
  prefix = FcConfigXdgCacheHome();
2506
  /* home directory might be disabled.
2507
   * simply ignore this element.
2508
   */
2509
0
  if (!prefix)
2510
0
      goto bail;
2511
0
    }
2512
0
    data = FcStrBufDone (&parse->pstack->str);
2513
0
    if (!data) {
2514
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2515
0
  data = prefix;
2516
0
  goto bail;
2517
0
    }
2518
0
    if (data[0] == 0) {
2519
0
  FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2520
0
  FcStrFree (data);
2521
0
  data = prefix;
2522
0
  goto bail;
2523
0
    }
2524
0
    if (prefix) {
2525
0
  size_t plen = strlen ((const char *)prefix);
2526
0
  size_t dlen = strlen ((const char *)data);
2527
2528
0
  p = realloc (prefix, plen + 1 + dlen + 1);
2529
0
  if (!p) {
2530
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2531
0
      FcStrFree (prefix);
2532
0
      goto bail;
2533
0
  }
2534
0
  prefix = p;
2535
0
  prefix[plen] = FC_DIR_SEPARATOR;
2536
0
  memcpy (&prefix[plen + 1], data, dlen);
2537
0
  prefix[plen + 1 + dlen] = 0;
2538
0
  FcStrFree (data);
2539
0
  data = prefix;
2540
0
    }
2541
#ifdef _WIN32
2542
    else if (data[0] == '/' && fontconfig_instprefix[0] != '\0') {
2543
  size_t plen = strlen ((const char *)fontconfig_instprefix);
2544
  size_t dlen = strlen ((const char *)data);
2545
2546
  prefix = malloc (plen + 1 + dlen + 1);
2547
  if (!prefix) {
2548
      FcConfigMessage (parse, FcSevereError, "out of memory");
2549
      goto bail;
2550
  }
2551
  strcpy ((char *)prefix, (char *)fontconfig_instprefix);
2552
  prefix[plen] = FC_DIR_SEPARATOR;
2553
  memcpy (&prefix[plen + 1], data, dlen);
2554
  prefix[plen + 1 + dlen] = 0;
2555
  FcStrFree (data);
2556
  data = prefix;
2557
    } else if (strcmp ((const char *)data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0) {
2558
  int rc;
2559
2560
  FcStrFree (data);
2561
  data = malloc (1000);
2562
  if (!data) {
2563
      FcConfigMessage (parse, FcSevereError, "out of memory");
2564
      goto bail;
2565
  }
2566
  rc = GetTempPath (800, (LPSTR)data);
2567
  if (rc == 0 || rc > 800) {
2568
      FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2569
      goto bail;
2570
  }
2571
  if (data[strlen ((const char *)data) - 1] != '\\')
2572
      strcat ((char *)data, "\\");
2573
  strcat ((char *)data, "fontconfig\\cache");
2574
    } else if (strcmp ((const char *)data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0) {
2575
  char   szFPath[MAX_PATH + 1];
2576
  size_t len;
2577
2578
  if (!(pSHGetFolderPathA && SUCCEEDED (pSHGetFolderPathA (NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath)))) {
2579
      FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2580
      goto bail;
2581
  }
2582
  strncat (szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen (szFPath));
2583
  len = strlen (szFPath) + 1;
2584
  FcStrFree (data);
2585
  data = malloc (len);
2586
  if (!data) {
2587
      FcConfigMessage (parse, FcSevereError, "out of memory");
2588
      goto bail;
2589
  }
2590
  strncpy ((char *)data, szFPath, len);
2591
    }
2592
#endif
2593
0
    if (strlen ((char *)data) == 0)
2594
0
  FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
2595
0
    else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome())) {
2596
0
  if (!FcConfigAddCacheDir (parse->config, data))
2597
0
      FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2598
0
    }
2599
0
    FcStrBufDestroy (&parse->pstack->str);
2600
2601
0
bail:
2602
0
    if (data)
2603
0
  FcStrFree (data);
2604
0
}
2605
2606
static void
2607
FcParseInclude (FcConfigParse *parse)
2608
0
{
2609
0
    FcChar8       *s;
2610
0
    const FcChar8 *attr;
2611
0
    FcBool         ignore_missing = FcFalse;
2612
0
    FcChar8       *prefix = NULL, *p;
2613
0
    FcRuleSet     *ruleset;
2614
0
    FcMatchKind    k;
2615
2616
0
    s = FcStrBufDoneStatic (&parse->pstack->str);
2617
0
    if (!s) {
2618
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2619
0
  goto bail;
2620
0
    }
2621
0
    attr = FcConfigGetAttribute (parse, "ignore_missing");
2622
0
    ignore_missing = attr ? FcConfigLexBool (parse, (FcChar8 *)attr) : FcFalse;
2623
    /* deprecated attribute has ever been used to mark
2624
     * old configuration path as deprecated.
2625
     * We don't have any code for it but just keep it for
2626
     * backward compatibility.
2627
     */
2628
0
    attr = FcConfigGetAttribute (parse, "deprecated");
2629
0
    attr = FcConfigGetAttribute (parse, "prefix");
2630
0
    if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0) {
2631
0
  prefix = FcConfigXdgConfigHome();
2632
  /* home directory might be disabled.
2633
   * simply ignore this element.
2634
   */
2635
0
  if (!prefix)
2636
0
      goto bail;
2637
0
    }
2638
0
    if (prefix) {
2639
0
  size_t plen = strlen ((const char *)prefix);
2640
0
  size_t dlen = strlen ((const char *)s);
2641
2642
0
  p = realloc (prefix, plen + 1 + dlen + 1);
2643
0
  if (!p) {
2644
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
2645
0
      goto bail;
2646
0
  }
2647
0
  prefix = p;
2648
0
  prefix[plen] = FC_DIR_SEPARATOR;
2649
0
  memcpy (&prefix[plen + 1], s, dlen);
2650
0
  prefix[plen + 1 + dlen] = 0;
2651
0
  s = prefix;
2652
0
    }
2653
    /* flush the ruleset into the queue */
2654
0
    ruleset = parse->ruleset;
2655
0
    parse->ruleset = FcRuleSetCreate (ruleset->name);
2656
0
    FcRuleSetEnable (parse->ruleset, ruleset->enabled);
2657
0
    FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
2658
0
    for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) {
2659
0
  FcPtrListIter iter;
2660
2661
0
  FcPtrListIterInit (ruleset->subst[k], &iter);
2662
0
  if (FcPtrListIterIsValid (ruleset->subst[k], &iter)) {
2663
0
      FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
2664
0
      FcRuleSetReference (ruleset);
2665
0
      FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
2666
0
  }
2667
0
    }
2668
0
    FcRuleSetDestroy (ruleset);
2669
0
    if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
2670
0
  parse->error = FcTrue;
2671
0
    FcStrBufDestroy (&parse->pstack->str);
2672
2673
0
bail:
2674
0
    if (prefix)
2675
0
  FcStrFree (prefix);
2676
0
}
2677
2678
typedef struct _FcOpMap {
2679
    char name[16];
2680
    FcOp op;
2681
} FcOpMap;
2682
2683
static FcOp
2684
FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2685
0
{
2686
0
    int i;
2687
2688
0
    for (i = 0; i < nmap; i++)
2689
0
  if (!strcmp ((char *)op, map[i].name))
2690
0
      return map[i].op;
2691
0
    return FcOpInvalid;
2692
0
}
2693
2694
static const FcOpMap fcCompareOps[] = {
2695
    { "eq",           FcOpEqual       },
2696
    { "not_eq",       FcOpNotEqual    },
2697
    { "less",         FcOpLess        },
2698
    { "less_eq",      FcOpLessEqual   },
2699
    { "more",         FcOpMore        },
2700
    { "more_eq",      FcOpMoreEqual   },
2701
    { "contains",     FcOpContains    },
2702
    { "not_contains", FcOpNotContains }
2703
};
2704
2705
0
#define NUM_COMPARE_OPS (int)(sizeof fcCompareOps / sizeof fcCompareOps[0])
2706
2707
static FcOp
2708
FcConfigLexCompare (const FcChar8 *compare)
2709
0
{
2710
0
    return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2711
0
}
2712
2713
static void
2714
FcParseTest (FcConfigParse *parse)
2715
0
{
2716
0
    const FcChar8 *kind_string;
2717
0
    FcMatchKind    kind;
2718
0
    const FcChar8 *qual_string;
2719
0
    FcQual         qual;
2720
0
    const FcChar8 *name;
2721
0
    const FcChar8 *compare_string;
2722
0
    FcOp           compare;
2723
0
    FcExpr        *expr;
2724
0
    FcTest        *test;
2725
0
    const FcChar8 *iblanks_string;
2726
0
    int            flags = 0;
2727
2728
0
    kind_string = FcConfigGetAttribute (parse, "target");
2729
0
    if (!kind_string)
2730
0
  kind = FcMatchDefault;
2731
0
    else {
2732
0
  if (!strcmp ((char *)kind_string, "pattern"))
2733
0
      kind = FcMatchPattern;
2734
0
  else if (!strcmp ((char *)kind_string, "font"))
2735
0
      kind = FcMatchFont;
2736
0
  else if (!strcmp ((char *)kind_string, "scan"))
2737
0
      kind = FcMatchScan;
2738
0
  else if (!strcmp ((char *)kind_string, "default"))
2739
0
      kind = FcMatchDefault;
2740
0
  else {
2741
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2742
0
      return;
2743
0
  }
2744
0
    }
2745
0
    qual_string = FcConfigGetAttribute (parse, "qual");
2746
0
    if (!qual_string)
2747
0
  qual = FcQualAny;
2748
0
    else {
2749
0
  if (!strcmp ((char *)qual_string, "any"))
2750
0
      qual = FcQualAny;
2751
0
  else if (!strcmp ((char *)qual_string, "all"))
2752
0
      qual = FcQualAll;
2753
0
  else if (!strcmp ((char *)qual_string, "first"))
2754
0
      qual = FcQualFirst;
2755
0
  else if (!strcmp ((char *)qual_string, "not_first"))
2756
0
      qual = FcQualNotFirst;
2757
0
  else {
2758
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
2759
0
      return;
2760
0
  }
2761
0
    }
2762
0
    name = FcConfigGetAttribute (parse, "name");
2763
0
    if (!name) {
2764
0
  FcConfigMessage (parse, FcSevereWarning, "missing test name");
2765
0
  return;
2766
0
    }
2767
0
    compare_string = FcConfigGetAttribute (parse, "compare");
2768
0
    if (!compare_string)
2769
0
  compare = FcOpEqual;
2770
0
    else {
2771
0
  compare = FcConfigLexCompare (compare_string);
2772
0
  if (compare == FcOpInvalid) {
2773
0
      FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
2774
0
      return;
2775
0
  }
2776
0
    }
2777
0
    iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2778
0
    if (iblanks_string) {
2779
0
  if (FcConfigLexBool (parse, iblanks_string)) {
2780
0
      flags |= FcOpFlagIgnoreBlanks;
2781
0
  }
2782
0
    }
2783
0
    expr = FcPopBinary (parse, FcOpComma);
2784
0
    if (!expr) {
2785
0
  FcConfigMessage (parse, FcSevereWarning, "missing test expression");
2786
0
  return;
2787
0
    }
2788
0
    if (expr->op == FcOpComma) {
2789
0
  FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
2790
0
    }
2791
0
    test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
2792
0
    if (!test) {
2793
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2794
0
  return;
2795
0
    }
2796
0
    FcVStackPushTest (parse, test);
2797
0
}
2798
2799
static const FcOpMap fcModeOps[] = {
2800
    { "assign",         FcOpAssign        },
2801
    { "assign_replace", FcOpAssignReplace },
2802
    { "prepend",        FcOpPrepend       },
2803
    { "prepend_first",  FcOpPrependFirst  },
2804
    { "append",         FcOpAppend        },
2805
    { "append_last",    FcOpAppendLast    },
2806
    { "delete",         FcOpDelete        },
2807
    { "delete_all",     FcOpDeleteAll     },
2808
};
2809
2810
0
#define NUM_MODE_OPS (int)(sizeof fcModeOps / sizeof fcModeOps[0])
2811
2812
static FcOp
2813
FcConfigLexMode (const FcChar8 *mode)
2814
0
{
2815
0
    return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2816
0
}
2817
2818
static void
2819
FcParseEdit (FcConfigParse *parse)
2820
0
{
2821
0
    const FcChar8 *name;
2822
0
    const FcChar8 *mode_string;
2823
0
    FcOp           mode;
2824
0
    FcValueBinding binding;
2825
0
    FcExpr        *expr;
2826
0
    FcEdit        *edit;
2827
2828
0
    name = FcConfigGetAttribute (parse, "name");
2829
0
    if (!name) {
2830
0
  FcConfigMessage (parse, FcSevereWarning, "missing edit name");
2831
0
  return;
2832
0
    }
2833
0
    mode_string = FcConfigGetAttribute (parse, "mode");
2834
0
    if (!mode_string)
2835
0
  mode = FcOpAssign;
2836
0
    else {
2837
0
  mode = FcConfigLexMode (mode_string);
2838
0
  if (mode == FcOpInvalid) {
2839
0
      FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
2840
0
      return;
2841
0
  }
2842
0
    }
2843
0
    if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2844
0
  return;
2845
2846
0
    expr = FcPopBinary (parse, FcOpComma);
2847
0
    if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2848
0
        expr != NULL) {
2849
0
  FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2850
0
  FcExprDestroy (expr);
2851
0
  expr = NULL;
2852
0
    }
2853
0
    edit = FcEditCreate (parse, FcObjectFromName ((char *)name),
2854
0
                         mode, expr, binding);
2855
0
    if (!edit) {
2856
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2857
0
  FcExprDestroy (expr);
2858
0
  return;
2859
0
    }
2860
0
    if (!FcVStackPushEdit (parse, edit))
2861
0
  FcEditDestroy (edit);
2862
0
}
2863
2864
static void
2865
FcParseMatch (FcConfigParse *parse)
2866
0
{
2867
0
    const FcChar8 *kind_name;
2868
0
    FcMatchKind    kind;
2869
0
    FcVStack      *vstack;
2870
0
    FcRule        *rule = NULL, *r;
2871
0
    int            n;
2872
2873
0
    kind_name = FcConfigGetAttribute (parse, "target");
2874
0
    if (!kind_name)
2875
0
  kind = FcMatchPattern;
2876
0
    else {
2877
0
  if (!strcmp ((char *)kind_name, "pattern"))
2878
0
      kind = FcMatchPattern;
2879
0
  else if (!strcmp ((char *)kind_name, "font"))
2880
0
      kind = FcMatchFont;
2881
0
  else if (!strcmp ((char *)kind_name, "scan"))
2882
0
      kind = FcMatchScan;
2883
0
  else {
2884
0
      FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
2885
0
      return;
2886
0
  }
2887
0
    }
2888
0
    while ((vstack = FcVStackPeek (parse))) {
2889
0
  switch ((int)vstack->tag) {
2890
0
  case FcVStackTest:
2891
0
      r = FcRuleCreate (FcRuleTest, vstack->u.test);
2892
0
      if (rule)
2893
0
    r->next = rule;
2894
0
      rule = r;
2895
0
      vstack->tag = FcVStackNone;
2896
0
      break;
2897
0
  case FcVStackEdit:
2898
0
      if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT) {
2899
0
    FcConfigMessage (parse, FcSevereError,
2900
0
                     "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
2901
0
                     FcObjectName (vstack->u.edit->object));
2902
0
    if (rule)
2903
0
        FcRuleDestroy (rule);
2904
0
    return;
2905
0
      }
2906
0
      r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2907
0
      if (rule)
2908
0
    r->next = rule;
2909
0
      rule = r;
2910
0
      vstack->tag = FcVStackNone;
2911
0
      break;
2912
0
  default:
2913
0
      FcConfigMessage (parse, FcSevereWarning, "invalid match element");
2914
0
      break;
2915
0
  }
2916
0
  FcVStackPopAndDestroy (parse);
2917
0
    }
2918
0
    if (!rule) {
2919
0
  FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2920
0
  return;
2921
0
    }
2922
0
    if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1) {
2923
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
2924
0
  FcRuleDestroy (rule);
2925
0
    } else if (parse->config->maxObjects < n)
2926
0
  parse->config->maxObjects = n;
2927
0
}
2928
2929
static void
2930
FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2931
0
{
2932
0
    FcVStack *vstack;
2933
2934
0
    while ((vstack = FcVStackPeek (parse))) {
2935
0
  switch ((int)vstack->tag) {
2936
0
  case FcVStackGlob:
2937
0
      if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
2938
0
                                                vstack->u.string,
2939
0
                                                element == FcElementAcceptfont)) {
2940
0
    if (FcStrUsesHome (vstack->u.string) && FcConfigHome() == NULL)
2941
0
        FcConfigMessage (parse, FcSevereWarning, "Home is disabled");
2942
0
    else
2943
0
        FcConfigMessage (parse, FcSevereError, "out of memory");
2944
0
      } else {
2945
0
    if (parse->scanOnly && vstack->u.string) {
2946
0
        FcStrFree (vstack->u.string);
2947
0
        vstack->tag = FcVStackNone;
2948
0
    }
2949
0
      }
2950
0
      break;
2951
0
  case FcVStackPattern:
2952
0
      if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2953
0
                                                    vstack->u.pattern,
2954
0
                                                    element == FcElementAcceptfont)) {
2955
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
2956
0
      } else {
2957
0
    if (parse->scanOnly && vstack->u.pattern)
2958
0
        FcPatternDestroy (vstack->u.pattern);
2959
0
    vstack->tag = FcVStackNone;
2960
0
      }
2961
0
      break;
2962
0
  default:
2963
0
      FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2964
0
      break;
2965
0
  }
2966
0
  FcVStackPopAndDestroy (parse);
2967
0
    }
2968
0
}
2969
2970
static FcValue
2971
FcPopValue (FcConfigParse *parse)
2972
0
{
2973
0
    FcVStack *vstack = FcVStackPeek (parse);
2974
0
    FcValue   value;
2975
2976
0
    value.type = FcTypeVoid;
2977
2978
0
    if (!vstack)
2979
0
  return value;
2980
2981
0
    switch ((int)vstack->tag) {
2982
0
    case FcVStackString:
2983
0
  value.u.s = FcStrCopy (vstack->u.string);
2984
0
  if (value.u.s)
2985
0
      value.type = FcTypeString;
2986
0
  break;
2987
0
    case FcVStackConstant:
2988
0
  if (FcNameConstant (vstack->u.string, &value.u.i))
2989
0
      value.type = FcTypeInteger;
2990
0
  break;
2991
0
    case FcVStackInteger:
2992
0
  value.u.i = vstack->u.integer;
2993
0
  value.type = FcTypeInteger;
2994
0
  break;
2995
0
    case FcVStackDouble:
2996
0
  value.u.d = vstack->u._double;
2997
0
  value.type = FcTypeDouble;
2998
0
  break;
2999
0
    case FcVStackBool:
3000
0
  value.u.b = vstack->u.bool_;
3001
0
  value.type = FcTypeBool;
3002
0
  break;
3003
0
    case FcVStackCharSet:
3004
0
  value.u.c = FcCharSetCopy (vstack->u.charset);
3005
0
  if (value.u.c)
3006
0
      value.type = FcTypeCharSet;
3007
0
  break;
3008
0
    case FcVStackLangSet:
3009
0
  value.u.l = FcLangSetCopy (vstack->u.langset);
3010
0
  if (value.u.l)
3011
0
      value.type = FcTypeLangSet;
3012
0
  break;
3013
0
    case FcVStackRange:
3014
0
  value.u.r = FcRangeCopy (vstack->u.range);
3015
0
  if (value.u.r)
3016
0
      value.type = FcTypeRange;
3017
0
  break;
3018
0
    default:
3019
0
  FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
3020
0
                   vstack->tag);
3021
0
  break;
3022
0
    }
3023
0
    FcVStackPopAndDestroy (parse);
3024
3025
0
    return value;
3026
0
}
3027
3028
static void
3029
FcParsePatelt (FcConfigParse *parse)
3030
0
{
3031
0
    FcValue     value;
3032
0
    FcPattern  *pattern = FcPatternCreate();
3033
0
    const char *name;
3034
3035
0
    if (!pattern) {
3036
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
3037
0
  return;
3038
0
    }
3039
3040
0
    name = (char *)FcConfigGetAttribute (parse, "name");
3041
0
    if (!name) {
3042
0
  FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
3043
0
  FcPatternDestroy (pattern);
3044
0
  return;
3045
0
    }
3046
3047
0
    for (;;) {
3048
0
  value = FcPopValue (parse);
3049
0
  if (value.type == FcTypeVoid)
3050
0
      break;
3051
0
  if (!FcPatternAdd (pattern, name, value, FcTrue)) {
3052
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
3053
0
      FcValueDestroy (value);
3054
0
      break;
3055
0
  }
3056
0
  FcValueDestroy (value);
3057
0
    }
3058
3059
0
    FcVStackPushPattern (parse, pattern);
3060
0
}
3061
3062
static void
3063
FcParsePattern (FcConfigParse *parse)
3064
0
{
3065
0
    FcVStack  *vstack;
3066
0
    FcPattern *pattern = FcPatternCreate();
3067
3068
0
    if (!pattern) {
3069
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
3070
0
  return;
3071
0
    }
3072
3073
0
    while ((vstack = FcVStackPeek (parse))) {
3074
0
  switch ((int)vstack->tag) {
3075
0
  case FcVStackPattern:
3076
0
      if (!FcPatternAppend (pattern, vstack->u.pattern)) {
3077
0
    FcConfigMessage (parse, FcSevereError, "out of memory");
3078
0
    FcPatternDestroy (pattern);
3079
0
    return;
3080
0
      }
3081
0
      break;
3082
0
  default:
3083
0
      FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
3084
0
      break;
3085
0
  }
3086
0
  FcVStackPopAndDestroy (parse);
3087
0
    }
3088
3089
0
    FcVStackPushPattern (parse, pattern);
3090
0
}
3091
3092
static void
3093
FcEndElement (void *userData, const XML_Char *name FC_UNUSED)
3094
0
{
3095
0
    FcConfigParse *parse = userData;
3096
0
    FcChar8       *data;
3097
3098
0
    if (!parse->pstack)
3099
0
  return;
3100
0
    switch (parse->pstack->element) {
3101
0
    case FcElementNone:
3102
0
  break;
3103
0
    case FcElementFontconfig:
3104
0
  break;
3105
0
    case FcElementDir:
3106
0
  FcParseDir (parse);
3107
0
  break;
3108
0
    case FcElementCacheDir:
3109
0
  FcParseCacheDir (parse);
3110
0
  break;
3111
0
    case FcElementCache:
3112
0
  data = FcStrBufDoneStatic (&parse->pstack->str);
3113
0
  if (!data) {
3114
0
      FcConfigMessage (parse, FcSevereError, "out of memory");
3115
0
      break;
3116
0
  }
3117
  /* discard this data; no longer used */
3118
0
  FcStrBufDestroy (&parse->pstack->str);
3119
0
  break;
3120
0
    case FcElementInclude:
3121
0
  FcParseInclude (parse);
3122
0
  break;
3123
0
    case FcElementConfig:
3124
0
  break;
3125
0
    case FcElementMatch:
3126
0
  FcParseMatch (parse);
3127
0
  break;
3128
0
    case FcElementAlias:
3129
0
  FcParseAlias (parse);
3130
0
  break;
3131
0
    case FcElementDescription:
3132
0
  FcParseDescription (parse);
3133
0
  break;
3134
0
    case FcElementRemapDir:
3135
0
  FcParseRemapDir (parse);
3136
0
  break;
3137
0
    case FcElementResetDirs:
3138
0
  FcParseResetDirs (parse);
3139
0
  break;
3140
3141
0
    case FcElementRescan:
3142
0
  FcParseRescan (parse);
3143
0
  break;
3144
3145
0
    case FcElementPrefer:
3146
0
  FcParseFamilies (parse, FcVStackPrefer);
3147
0
  break;
3148
0
    case FcElementAccept:
3149
0
  FcParseFamilies (parse, FcVStackAccept);
3150
0
  break;
3151
0
    case FcElementDefault:
3152
0
  FcParseFamilies (parse, FcVStackDefault);
3153
0
  break;
3154
0
    case FcElementFamily:
3155
0
  FcParseFamily (parse);
3156
0
  break;
3157
3158
0
    case FcElementTest:
3159
0
  FcParseTest (parse);
3160
0
  break;
3161
0
    case FcElementEdit:
3162
0
  FcParseEdit (parse);
3163
0
  break;
3164
3165
0
    case FcElementInt:
3166
0
  FcParseInt (parse);
3167
0
  break;
3168
0
    case FcElementDouble:
3169
0
  FcParseDouble (parse);
3170
0
  break;
3171
0
    case FcElementString:
3172
0
  FcParseString (parse, FcVStackString);
3173
0
  break;
3174
0
    case FcElementMatrix:
3175
0
  FcParseMatrix (parse);
3176
0
  break;
3177
0
    case FcElementRange:
3178
0
  FcParseRange (parse);
3179
0
  break;
3180
0
    case FcElementBool:
3181
0
  FcParseBool (parse);
3182
0
  break;
3183
0
    case FcElementCharSet:
3184
0
  FcParseCharSet (parse);
3185
0
  break;
3186
0
    case FcElementLangSet:
3187
0
  FcParseLangSet (parse);
3188
0
  break;
3189
0
    case FcElementSelectfont:
3190
0
  break;
3191
0
    case FcElementAcceptfont:
3192
0
    case FcElementRejectfont:
3193
0
  FcParseAcceptRejectFont (parse, parse->pstack->element);
3194
0
  break;
3195
0
    case FcElementGlob:
3196
0
  FcParseString (parse, FcVStackGlob);
3197
0
  break;
3198
0
    case FcElementPattern:
3199
0
  FcParsePattern (parse);
3200
0
  break;
3201
0
    case FcElementPatelt:
3202
0
  FcParsePatelt (parse);
3203
0
  break;
3204
0
    case FcElementName:
3205
0
  FcParseName (parse);
3206
0
  break;
3207
0
    case FcElementConst:
3208
0
  FcParseString (parse, FcVStackConstant);
3209
0
  break;
3210
0
    case FcElementOr:
3211
0
  FcParseBinary (parse, FcOpOr);
3212
0
  break;
3213
0
    case FcElementAnd:
3214
0
  FcParseBinary (parse, FcOpAnd);
3215
0
  break;
3216
0
    case FcElementEq:
3217
0
  FcParseBinary (parse, FcOpEqual);
3218
0
  break;
3219
0
    case FcElementNotEq:
3220
0
  FcParseBinary (parse, FcOpNotEqual);
3221
0
  break;
3222
0
    case FcElementLess:
3223
0
  FcParseBinary (parse, FcOpLess);
3224
0
  break;
3225
0
    case FcElementLessEq:
3226
0
  FcParseBinary (parse, FcOpLessEqual);
3227
0
  break;
3228
0
    case FcElementMore:
3229
0
  FcParseBinary (parse, FcOpMore);
3230
0
  break;
3231
0
    case FcElementMoreEq:
3232
0
  FcParseBinary (parse, FcOpMoreEqual);
3233
0
  break;
3234
0
    case FcElementContains:
3235
0
  FcParseBinary (parse, FcOpContains);
3236
0
  break;
3237
0
    case FcElementNotContains:
3238
0
  FcParseBinary (parse, FcOpNotContains);
3239
0
  break;
3240
0
    case FcElementPlus:
3241
0
  FcParseBinary (parse, FcOpPlus);
3242
0
  break;
3243
0
    case FcElementMinus:
3244
0
  FcParseBinary (parse, FcOpMinus);
3245
0
  break;
3246
0
    case FcElementTimes:
3247
0
  FcParseBinary (parse, FcOpTimes);
3248
0
  break;
3249
0
    case FcElementDivide:
3250
0
  FcParseBinary (parse, FcOpDivide);
3251
0
  break;
3252
0
    case FcElementNot:
3253
0
  FcParseUnary (parse, FcOpNot);
3254
0
  break;
3255
0
    case FcElementIf:
3256
0
  FcParseBinary (parse, FcOpQuest);
3257
0
  break;
3258
0
    case FcElementFloor:
3259
0
  FcParseUnary (parse, FcOpFloor);
3260
0
  break;
3261
0
    case FcElementCeil:
3262
0
  FcParseUnary (parse, FcOpCeil);
3263
0
  break;
3264
0
    case FcElementRound:
3265
0
  FcParseUnary (parse, FcOpRound);
3266
0
  break;
3267
0
    case FcElementTrunc:
3268
0
  FcParseUnary (parse, FcOpTrunc);
3269
0
  break;
3270
0
    case FcElementUnknown:
3271
0
  break;
3272
0
    }
3273
0
    (void)FcPStackPop (parse);
3274
0
}
3275
3276
static void
3277
FcCharacterData (void *userData, const XML_Char *s, int len)
3278
0
{
3279
0
    FcConfigParse *parse = userData;
3280
3281
0
    if (!parse->pstack)
3282
0
  return;
3283
0
    if (!FcStrBufData (&parse->pstack->str, (FcChar8 *)s, len))
3284
0
  FcConfigMessage (parse, FcSevereError, "out of memory");
3285
0
}
3286
3287
static void
3288
FcStartDoctypeDecl (void           *userData,
3289
                    const XML_Char *doctypeName,
3290
                    const XML_Char *sysid FC_UNUSED,
3291
                    const XML_Char *pubid FC_UNUSED,
3292
                    int             has_internal_subset FC_UNUSED)
3293
0
{
3294
0
    FcConfigParse *parse = userData;
3295
3296
0
    if (strcmp ((char *)doctypeName, "fontconfig") != 0)
3297
0
  FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
3298
0
}
3299
3300
#ifdef ENABLE_LIBXML2
3301
3302
static void
3303
FcInternalSubsetDecl (void           *userData,
3304
                      const XML_Char *doctypeName,
3305
                      const XML_Char *sysid,
3306
                      const XML_Char *pubid)
3307
{
3308
    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3309
}
3310
3311
static void
3312
FcExternalSubsetDecl (void           *userData,
3313
                      const XML_Char *doctypeName,
3314
                      const XML_Char *sysid,
3315
                      const XML_Char *pubid)
3316
{
3317
    FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3318
}
3319
3320
#else /* ENABLE_LIBXML2 */
3321
3322
static void
3323
FcEndDoctypeDecl (void *userData FC_UNUSED)
3324
0
{
3325
0
}
3326
3327
#endif /* ENABLE_LIBXML2 */
3328
3329
static int
3330
FcSortCmpStr (const void *a, const void *b)
3331
0
{
3332
0
    const FcChar8 *as = *((FcChar8 **)a);
3333
0
    const FcChar8 *bs = *((FcChar8 **)b);
3334
0
    return FcStrCmp (as, bs);
3335
0
}
3336
3337
static FcBool
3338
FcConfigParseAndLoadDir (FcConfig      *config,
3339
                         const FcChar8 *name,
3340
                         const FcChar8 *dir,
3341
                         FcBool         complain,
3342
                         FcBool         load)
3343
0
{
3344
0
    DIR           *d;
3345
0
    struct dirent *e;
3346
0
    FcBool         ret = FcTrue;
3347
0
    FcChar8       *file;
3348
0
    FcChar8       *base;
3349
0
    FcStrSet      *files;
3350
3351
0
    d = opendir ((char *)dir);
3352
0
    if (!d) {
3353
0
  if (complain)
3354
0
      FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3355
0
                       name);
3356
0
  ret = FcFalse;
3357
0
  goto bail0;
3358
0
    }
3359
    /* freed below */
3360
0
    file = (FcChar8 *)malloc (strlen ((char *)dir) + 1 + FC_MAX_FILE_LEN + 1);
3361
0
    if (!file) {
3362
0
  ret = FcFalse;
3363
0
  goto bail1;
3364
0
    }
3365
3366
0
    strcpy ((char *)file, (char *)dir);
3367
0
    strcat ((char *)file, "/");
3368
0
    base = file + strlen ((char *)file);
3369
3370
0
    files = FcStrSetCreateEx (FCSS_GROW_BY_64);
3371
0
    if (!files) {
3372
0
  ret = FcFalse;
3373
0
  goto bail2;
3374
0
    }
3375
3376
0
    if (FcDebug() & FC_DBG_CONFIG)
3377
0
  printf ("\tScanning config dir %s\n", dir);
3378
3379
0
    if (load)
3380
0
  FcConfigAddConfigDir (config, dir);
3381
3382
0
    while (ret && (e = readdir (d))) {
3383
0
  int d_len;
3384
0
#define TAIL     ".conf"
3385
0
#define TAIL_LEN 5
3386
  /*
3387
   * Add all files of the form [0-9]*.conf
3388
   */
3389
0
  d_len = strlen (e->d_name);
3390
0
  if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
3391
0
      d_len > TAIL_LEN &&
3392
0
      strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0) {
3393
0
      strcpy ((char *)base, (char *)e->d_name);
3394
0
      if (!FcStrSetAdd (files, file)) {
3395
0
    ret = FcFalse;
3396
0
    goto bail3;
3397
0
      }
3398
0
  }
3399
0
    }
3400
0
    if (ret && files->num > 0) {
3401
0
  int i;
3402
0
  qsort (files->strs, files->num, sizeof (FcChar8 *),
3403
0
         (int (*) (const void *, const void *))FcSortCmpStr);
3404
0
  for (i = 0; ret && i < files->num; i++)
3405
0
      ret = _FcConfigParse (config, files->strs[i], complain, load);
3406
0
    }
3407
0
bail3:
3408
0
    FcStrSetDestroy (files);
3409
0
bail2:
3410
0
    free (file);
3411
0
bail1:
3412
0
    closedir (d);
3413
0
bail0:
3414
0
    return ret || !complain;
3415
0
}
3416
3417
static FcBool
3418
FcConfigParseAndLoadFromMemoryInternal (FcConfig      *config,
3419
                                        const FcChar8 *filename,
3420
                                        const FcChar8 *buffer,
3421
                                        FcBool         complain,
3422
                                        FcBool         load)
3423
0
{
3424
0
    XML_Parser    p;
3425
0
    size_t        len;
3426
0
    FcConfigParse parse;
3427
0
    FcBool        error = FcTrue;
3428
0
    FcMatchKind   k;
3429
0
    FcPtrListIter liter;
3430
3431
#ifdef ENABLE_LIBXML2
3432
    xmlSAXHandler sax;
3433
#else
3434
0
    void          *buf;
3435
0
    const FcChar8 *s;
3436
0
    size_t         buflen;
3437
0
#endif
3438
3439
0
    FcInitDebug();
3440
3441
0
    if (!buffer)
3442
0
  return FcFalse;
3443
0
    len = strlen ((const char *)buffer);
3444
0
    if (FcDebug() & FC_DBG_CONFIG)
3445
0
  printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
3446
3447
#ifdef ENABLE_LIBXML2
3448
    memset (&sax, 0, sizeof (sax));
3449
3450
    sax.internalSubset = FcInternalSubsetDecl;
3451
    sax.externalSubset = FcExternalSubsetDecl;
3452
    sax.startElement = FcStartElement;
3453
    sax.endElement = FcEndElement;
3454
    sax.characters = FcCharacterData;
3455
3456
    p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *)filename);
3457
#else
3458
0
    p = XML_ParserCreate ("UTF-8");
3459
0
#endif
3460
3461
0
    if (!p)
3462
0
  goto bail1;
3463
3464
0
    if (!FcConfigParseInit (&parse, filename, config, p, load))
3465
0
  goto bail2;
3466
3467
0
#ifndef ENABLE_LIBXML2
3468
3469
0
    XML_SetUserData (p, &parse);
3470
3471
0
    XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3472
0
    XML_SetElementHandler (p, FcStartElement, FcEndElement);
3473
0
    XML_SetCharacterDataHandler (p, FcCharacterData);
3474
3475
0
#endif /* ENABLE_LIBXML2 */
3476
3477
0
#ifndef ENABLE_LIBXML2
3478
0
    s = buffer;
3479
0
    do {
3480
0
  buf = XML_GetBuffer (p, BUFSIZ);
3481
0
  if (!buf) {
3482
0
      FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3483
0
      goto bail3;
3484
0
  }
3485
0
  if (len > BUFSIZ) {
3486
0
      buflen = BUFSIZ;
3487
0
      len -= BUFSIZ;
3488
0
  } else {
3489
0
      buflen = len;
3490
0
      len = 0;
3491
0
  }
3492
0
  memcpy (buf, s, buflen);
3493
0
  s = s + buflen;
3494
0
#endif
3495
3496
#ifdef ENABLE_LIBXML2
3497
  if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
3498
#else
3499
0
    if (!XML_ParseBuffer (p, buflen, buflen == 0))
3500
0
#endif
3501
0
  {
3502
0
      FcConfigMessage (&parse, FcSevereError, "%s",
3503
0
                       XML_ErrorString (XML_GetErrorCode (p)));
3504
0
      goto bail3;
3505
0
  }
3506
0
#ifndef ENABLE_LIBXML2
3507
0
    } while (buflen != 0);
3508
0
#endif
3509
0
    error = parse.error;
3510
0
    if (load) {
3511
0
  for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++) {
3512
0
      FcPtrListIter iter;
3513
3514
0
      FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3515
0
      if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter)) {
3516
0
    FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3517
0
    FcRuleSetReference (parse.ruleset);
3518
0
    FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3519
0
      }
3520
0
  }
3521
0
    }
3522
0
    FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3523
0
    FcRuleSetReference (parse.ruleset);
3524
0
    FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
3525
0
bail3:
3526
0
    FcConfigCleanup (&parse);
3527
0
bail2:
3528
0
    XML_ParserFree (p);
3529
0
bail1:
3530
0
    if (error && complain) {
3531
0
  FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
3532
0
  return FcFalse;
3533
0
    }
3534
0
    if (FcDebug() & FC_DBG_CONFIG)
3535
0
  printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
3536
0
    return FcTrue;
3537
0
}
3538
3539
static FcBool
3540
_FcConfigParse (FcConfig      *config,
3541
                const FcChar8 *name,
3542
                FcBool         complain,
3543
                FcBool         load)
3544
0
{
3545
0
    FcChar8 *filename = NULL, *realfilename = NULL;
3546
0
    int      fd;
3547
0
    int      len;
3548
0
    FcStrBuf sbuf;
3549
0
    char     buf[BUFSIZ];
3550
0
    FcBool   ret = FcFalse, complain_again = complain;
3551
0
    FcStrBuf reason;
3552
3553
0
    FcStrBufInit (&reason, NULL, 0);
3554
#ifdef _WIN32
3555
    _ensureWin32GettersReady();
3556
#endif
3557
3558
0
    filename = FcConfigGetFilename (config, name);
3559
0
    if (!filename) {
3560
0
  FcStrBufString (&reason, (FcChar8 *)"File not found");
3561
0
  if (name) {
3562
0
      FcStrBufString (&reason, (FcChar8 *)": ");
3563
0
      FcStrBufString (&reason, name);
3564
0
  } else {
3565
0
      FcChar8 *e = (FcChar8 *)getenv ("FONTCONFIG_FILE");
3566
0
      if (e) {
3567
0
    FcStrBufString (&reason, (FcChar8 *)": ");
3568
0
    FcStrBufString (&reason, e);
3569
0
      }
3570
0
  }
3571
0
  goto bail0;
3572
0
    }
3573
0
    realfilename = FcConfigRealFilename (config, name);
3574
0
    if (!realfilename) {
3575
0
  FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
3576
0
  FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
3577
0
  goto bail0;
3578
0
    }
3579
0
    if (FcStrSetMember (config->availConfigFiles, realfilename)) {
3580
0
  FcStrFree (filename);
3581
0
  FcStrFree (realfilename);
3582
0
  return FcTrue;
3583
0
    }
3584
3585
0
    if (load) {
3586
0
  if (!FcStrSetAdd (config->configFiles, filename))
3587
0
      goto bail0;
3588
0
    }
3589
0
    if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3590
0
  goto bail0;
3591
3592
0
    if (FcFileIsDir (realfilename)) {
3593
0
  ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
3594
0
  FcStrFree (filename);
3595
0
  FcStrFree (realfilename);
3596
0
  return ret;
3597
0
    }
3598
3599
0
    FcStrBufInit (&sbuf, NULL, 0);
3600
3601
0
    fd = FcOpen ((char *)realfilename, O_RDONLY);
3602
0
    if (fd == -1) {
3603
0
  FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
3604
0
  FcStrBufString (&reason, realfilename);
3605
0
  goto bail1;
3606
0
    }
3607
3608
0
    do {
3609
0
  len = read (fd, buf, BUFSIZ);
3610
0
  if (len < 0) {
3611
0
      int  errno_ = errno;
3612
0
      char ebuf[BUFSIZ + 1];
3613
3614
0
#if HAVE_STRERROR_R
3615
0
      strerror_r (errno_, ebuf, BUFSIZ);
3616
#elif HAVE_STRERROR
3617
      char  *tmp = strerror (errno_);
3618
      size_t len = strlen (tmp);
3619
      memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
3620
      ebuf[FC_MIN (BUFSIZ, len)] = 0;
3621
#else
3622
      ebuf[0] = 0;
3623
#endif
3624
0
      FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
3625
0
      close (fd);
3626
0
      goto bail1;
3627
0
  }
3628
0
  FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
3629
0
    } while (len != 0);
3630
0
    close (fd);
3631
3632
0
    ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
3633
0
    complain_again = FcFalse; /* no need to reclaim here */
3634
0
bail1:
3635
0
    FcStrBufDestroy (&sbuf);
3636
0
bail0:
3637
0
    if (filename)
3638
0
  FcStrFree (filename);
3639
0
    if (realfilename)
3640
0
  FcStrFree (realfilename);
3641
0
    if (!complain) {
3642
0
  FcStrBufDestroy (&reason);
3643
0
  return FcTrue;
3644
0
    }
3645
0
    if (!ret && complain_again) {
3646
0
  if (name)
3647
0
      FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
3648
0
  else
3649
0
      FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
3650
0
  FcStrBufDestroy (&reason);
3651
0
  return FcFalse;
3652
0
    }
3653
0
    FcStrBufDestroy (&reason);
3654
0
    return ret;
3655
0
}
3656
3657
FcBool
3658
FcConfigParseOnly (FcConfig      *config,
3659
                   const FcChar8 *name,
3660
                   FcBool         complain)
3661
0
{
3662
0
    return _FcConfigParse (config, name, complain, FcFalse);
3663
0
}
3664
3665
FcBool
3666
FcConfigParseAndLoad (FcConfig      *config,
3667
                      const FcChar8 *name,
3668
                      FcBool         complain)
3669
0
{
3670
0
    return _FcConfigParse (config, name, complain, FcTrue);
3671
0
}
3672
3673
FcBool
3674
FcConfigParseAndLoadFromMemory (FcConfig      *config,
3675
                                const FcChar8 *buffer,
3676
                                FcBool         complain)
3677
0
{
3678
0
    return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3679
0
}
3680
3681
#ifdef _WIN32
3682
static void
3683
_ensureWin32GettersReady ()
3684
{
3685
    if (!pGetSystemWindowsDirectory) {
3686
  HMODULE hk32 = GetModuleHandleA ("kernel32.dll");
3687
  if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress (hk32, "GetSystemWindowsDirectoryA")))
3688
      pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory;
3689
    }
3690
    if (!pSHGetFolderPathA) {
3691
  HMODULE hSh = LoadLibraryA ("shfolder.dll");
3692
  /* the check is done later, because there is no provided fallback */
3693
  if (hSh)
3694
      pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress (hSh, "SHGetFolderPathA");
3695
    }
3696
}
3697
#endif  // _WIN32
3698
3699
#define __fcxml__
3700
#include "fcaliastail.h"
3701
#undef __fcxml__