Coverage Report

Created: 2025-11-16 09:57

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