blob: c700f64614d43d930693d22703736a52970f48d3 [file] [log] [blame]
Keith Packard24330d22002-02-14 23:34:13 +00001/*
Behdad Esfahbod317b8492008-08-12 16:34:24 -04002 * fontconfig/src/fcxml.c
Keith Packard24330d22002-02-14 23:34:13 +00003 *
Keith Packard46b51142004-12-07 01:14:46 +00004 * Copyright © 2002 Keith Packard
Keith Packard24330d22002-02-14 23:34:13 +00005 *
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
Behdad Esfahbod5aaf4662010-11-10 16:45:42 -050010 * documentation, and that the name of the author(s) not be used in
Keith Packard24330d22002-02-14 23:34:13 +000011 * advertising or publicity pertaining to distribution of the software without
Behdad Esfahbod5aaf4662010-11-10 16:45:42 -050012 * specific, written prior permission. The authors make no
Keith Packard24330d22002-02-14 23:34:13 +000013 * representations about the suitability of this software for any purpose. It
14 * is provided "as is" without express or implied warranty.
15 *
Behdad Esfahbod3074a732009-03-12 16:00:08 -040016 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Keith Packard24330d22002-02-14 23:34:13 +000017 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
Behdad Esfahbod3074a732009-03-12 16:00:08 -040018 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Keith Packard24330d22002-02-14 23:34:13 +000019 * 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
Patrick Lamf0453762006-04-25 05:57:41 +000025#include "fcint.h"
Ryan Gonzalezbe453bd2021-11-10 19:41:50 -060026#include <string.h>
Patrick Lam3bfae752005-12-21 03:31:19 +000027#include <fcntl.h>
Keith Packard24330d22002-02-14 23:34:13 +000028#include <stdarg.h>
Tim-Philipp Müller03aa12c2020-07-18 17:21:09 +010029
30#ifdef HAVE_DIRENT_H
Keith Packard2d9c79c2004-12-05 05:03:52 +000031#include <dirent.h>
Tim-Philipp Müller03aa12c2020-07-18 17:21:09 +010032#endif
Keith Packard0ab36ca2002-05-22 04:37:07 +000033
Patrick Lam0d745812006-04-06 04:33:11 +000034#ifdef ENABLE_LIBXML2
Patrick Lame99f0f02005-09-29 20:53:30 +000035
36#include <libxml/parser.h>
37
38#define XML_Char xmlChar
39#define XML_Parser xmlParserCtxtPtr
40#define XML_ParserFree xmlFreeParserCtxt
41#define XML_GetCurrentLineNumber xmlSAX2GetLineNumber
42#define XML_GetErrorCode xmlCtxtGetLastError
43#define XML_ErrorString(Error) (Error)->message
44
45#else /* ENABLE_LIBXML2 */
46
Keith Packardd0f07b82002-06-08 17:32:05 +000047#ifndef HAVE_XMLPARSE_H
48#define HAVE_XMLPARSE_H 0
49#endif
Keith Packardfa244f32002-08-19 19:32:05 +000050
Keith Packard179c3992002-05-21 17:06:22 +000051#if HAVE_XMLPARSE_H
52#include <xmlparse.h>
53#else
54#include <expat.h>
55#endif
Keith Packard24330d22002-02-14 23:34:13 +000056
Patrick Lame99f0f02005-09-29 20:53:30 +000057#endif /* ENABLE_LIBXML2 */
58
Tor Lillqvistdaeed6e2003-03-22 21:25:34 +000059#ifdef _WIN32
Tor Lillqvist8b1ceef2009-08-14 00:16:18 +030060#include <mbstring.h>
Руслан Ижбулатовf6e6a8a2015-04-08 08:41:25 +000061extern FcChar8 fontconfig_instprefix[];
Francesco Pretto16bbb532021-10-26 19:31:23 +020062pfnGetSystemWindowsDirectory pGetSystemWindowsDirectory = NULL;
63pfnSHGetFolderPathA pSHGetFolderPathA = NULL;
64static void
65_ensureWin32GettersReady();
Tor Lillqvistdaeed6e2003-03-22 21:25:34 +000066#endif
67
Akira TAGOHfa6c6b52015-05-22 16:53:34 +090068static FcChar8 *__fc_userdir = NULL;
69static FcChar8 *__fc_userconf = NULL;
70
Behdad Esfahbod398d4362009-06-05 21:37:01 -040071static void
72FcExprDestroy (FcExpr *e);
Akira TAGOHef748b32018-01-23 22:27:17 +090073static FcBool
74_FcConfigParse (FcConfig *config,
75 const FcChar8 *name,
76 FcBool complain,
77 FcBool load);
Keith Packard24330d22002-02-14 23:34:13 +000078
79void
80FcTestDestroy (FcTest *test)
81{
Keith Packard24330d22002-02-14 23:34:13 +000082 FcExprDestroy (test->expr);
Keith Packard24330d22002-02-14 23:34:13 +000083 free (test);
84}
85
Akira TAGOHd420e1d2013-07-04 19:51:03 +090086void
87FcRuleDestroy (FcRule *rule)
88{
Akira TAGOH04bd9042013-07-09 16:43:26 +090089 FcRule *n = rule->next;
90
Akira TAGOHd420e1d2013-07-04 19:51:03 +090091 switch (rule->type) {
92 case FcRuleTest:
93 FcTestDestroy (rule->u.test);
94 break;
95 case FcRuleEdit:
96 FcEditDestroy (rule->u.edit);
97 break;
Behdad Esfahbod13a5ae92014-08-20 16:03:02 -040098 case FcRuleUnknown:
Akira TAGOHd420e1d2013-07-04 19:51:03 +090099 default:
100 break;
101 }
102 free (rule);
Akira TAGOH04bd9042013-07-09 16:43:26 +0900103 if (n)
104 FcRuleDestroy (n);
Akira TAGOHd420e1d2013-07-04 19:51:03 +0900105}
106
Behdad Esfahboda96ecbf2009-06-05 18:40:46 -0400107static FcExpr *
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400108FcExprCreateInteger (FcConfig *config, int i)
Keith Packard24330d22002-02-14 23:34:13 +0000109{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400110 FcExpr *e = FcConfigAllocExpr (config);
Behdad Esfahboda96ecbf2009-06-05 18:40:46 -0400111 if (e)
Keith Packard24330d22002-02-14 23:34:13 +0000112 {
113 e->op = FcOpInteger;
114 e->u.ival = i;
115 }
116 return e;
117}
118
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400119static FcExpr *
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400120FcExprCreateDouble (FcConfig *config, double d)
Keith Packard24330d22002-02-14 23:34:13 +0000121{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400122 FcExpr *e = FcConfigAllocExpr (config);
Keith Packard24330d22002-02-14 23:34:13 +0000123 if (e)
124 {
125 e->op = FcOpDouble;
126 e->u.dval = d;
127 }
128 return e;
129}
130
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400131static FcExpr *
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400132FcExprCreateString (FcConfig *config, const FcChar8 *s)
Keith Packard24330d22002-02-14 23:34:13 +0000133{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400134 FcExpr *e = FcConfigAllocExpr (config);
Keith Packard24330d22002-02-14 23:34:13 +0000135 if (e)
136 {
137 e->op = FcOpString;
Behdad Esfahbod93fb1d42013-01-02 02:06:15 -0600138 e->u.sval = FcStrdup (s);
Keith Packard24330d22002-02-14 23:34:13 +0000139 }
140 return e;
141}
142
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500143static FcExprMatrix *
144FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
145{
146 FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
147 if (m)
148 {
149 *m = *matrix;
150 }
151 return m;
152}
153
154static void
155FcExprMatrixFreeShallow (FcExprMatrix *m)
156{
157 if (!m)
158 return;
159
160 free (m);
161}
162
163static void
164FcExprMatrixFree (FcExprMatrix *m)
165{
166 if (!m)
167 return;
168
169 FcExprDestroy (m->xx);
170 FcExprDestroy (m->xy);
171 FcExprDestroy (m->yx);
172 FcExprDestroy (m->yy);
173
174 free (m);
175}
176
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400177static FcExpr *
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500178FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
Keith Packard24330d22002-02-14 23:34:13 +0000179{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400180 FcExpr *e = FcConfigAllocExpr (config);
Keith Packard24330d22002-02-14 23:34:13 +0000181 if (e)
182 {
183 e->op = FcOpMatrix;
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500184 e->u.mexpr = FcExprMatrixCopyShallow (matrix);
Keith Packard24330d22002-02-14 23:34:13 +0000185 }
186 return e;
187}
188
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400189static FcExpr *
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900190FcExprCreateRange (FcConfig *config, FcRange *range)
191{
192 FcExpr *e = FcConfigAllocExpr (config);
193 if (e)
194 {
195 e->op = FcOpRange;
196 e->u.rval = FcRangeCopy (range);
197 }
198 return e;
199}
200
201static FcExpr *
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400202FcExprCreateBool (FcConfig *config, FcBool b)
Keith Packard24330d22002-02-14 23:34:13 +0000203{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400204 FcExpr *e = FcConfigAllocExpr (config);
Keith Packard24330d22002-02-14 23:34:13 +0000205 if (e)
206 {
207 e->op = FcOpBool;
208 e->u.bval = b;
209 }
210 return e;
211}
212
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400213static FcExpr *
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900214FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
215{
216 FcExpr *e = FcConfigAllocExpr (config);
217 if (e)
218 {
219 e->op = FcOpCharSet;
220 e->u.cval = FcCharSetCopy (charset);
221 }
222 return e;
223}
224
225static FcExpr *
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900226FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
227{
228 FcExpr *e = FcConfigAllocExpr (config);
229 if (e)
230 {
231 e->op = FcOpLangSet;
232 e->u.lval = FcLangSetCopy (langset);
233 }
234 return e;
235}
236
237static FcExpr *
Behdad Esfahbod51b00442012-12-29 23:58:38 -0500238FcExprCreateName (FcConfig *config, FcExprName name)
Keith Packard24330d22002-02-14 23:34:13 +0000239{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400240 FcExpr *e = FcConfigAllocExpr (config);
Keith Packard24330d22002-02-14 23:34:13 +0000241 if (e)
242 {
243 e->op = FcOpField;
Behdad Esfahbod51b00442012-12-29 23:58:38 -0500244 e->u.name = name;
Keith Packard24330d22002-02-14 23:34:13 +0000245 }
246 return e;
247}
248
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400249static FcExpr *
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400250FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
Keith Packard24330d22002-02-14 23:34:13 +0000251{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400252 FcExpr *e = FcConfigAllocExpr (config);
Keith Packard24330d22002-02-14 23:34:13 +0000253 if (e)
254 {
255 e->op = FcOpConst;
Behdad Esfahbod93fb1d42013-01-02 02:06:15 -0600256 e->u.constant = FcStrdup (constant);
Keith Packard24330d22002-02-14 23:34:13 +0000257 }
258 return e;
259}
260
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400261static FcExpr *
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400262FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
Keith Packard24330d22002-02-14 23:34:13 +0000263{
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400264 FcExpr *e = FcConfigAllocExpr (config);
Keith Packard24330d22002-02-14 23:34:13 +0000265 if (e)
266 {
267 e->op = op;
268 e->u.tree.left = left;
269 e->u.tree.right = right;
270 }
271 return e;
272}
273
Behdad Esfahbod398d4362009-06-05 21:37:01 -0400274static void
Keith Packard24330d22002-02-14 23:34:13 +0000275FcExprDestroy (FcExpr *e)
276{
Keith Packard3f7653c2003-04-15 23:38:06 +0000277 if (!e)
278 return;
Akira TAGOHbc4517d2012-04-11 19:52:35 +0900279 switch (FC_OP_GET_OP (e->op)) {
Keith Packard24330d22002-02-14 23:34:13 +0000280 case FcOpInteger:
281 break;
282 case FcOpDouble:
283 break;
284 case FcOpString:
Behdad Esfahbod93fb1d42013-01-02 02:06:15 -0600285 FcFree (e->u.sval);
Keith Packard24330d22002-02-14 23:34:13 +0000286 break;
287 case FcOpMatrix:
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500288 FcExprMatrixFree (e->u.mexpr);
Keith Packard24330d22002-02-14 23:34:13 +0000289 break;
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900290 case FcOpRange:
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900291 FcRangeDestroy (e->u.rval);
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900292 break;
Keith Packard24330d22002-02-14 23:34:13 +0000293 case FcOpCharSet:
294 FcCharSetDestroy (e->u.cval);
295 break;
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900296 case FcOpLangSet:
297 FcLangSetDestroy (e->u.lval);
298 break;
Keith Packard24330d22002-02-14 23:34:13 +0000299 case FcOpBool:
300 break;
301 case FcOpField:
Keith Packard24330d22002-02-14 23:34:13 +0000302 break;
303 case FcOpConst:
Behdad Esfahbod93fb1d42013-01-02 02:06:15 -0600304 FcFree (e->u.constant);
Keith Packard24330d22002-02-14 23:34:13 +0000305 break;
306 case FcOpAssign:
307 case FcOpAssignReplace:
308 case FcOpPrepend:
309 case FcOpPrependFirst:
310 case FcOpAppend:
311 case FcOpAppendLast:
Akira TAGOH20191812013-01-29 20:19:36 +0900312 case FcOpDelete:
313 case FcOpDeleteAll:
Keith Packard24330d22002-02-14 23:34:13 +0000314 break;
315 case FcOpOr:
316 case FcOpAnd:
317 case FcOpEqual:
Keith Packard24330d22002-02-14 23:34:13 +0000318 case FcOpNotEqual:
319 case FcOpLess:
320 case FcOpLessEqual:
321 case FcOpMore:
322 case FcOpMoreEqual:
Keith Packard47d4f952002-08-22 18:53:22 +0000323 case FcOpContains:
Keith Packard74a623e2003-07-20 16:06:18 +0000324 case FcOpListing:
Keith Packard47d4f952002-08-22 18:53:22 +0000325 case FcOpNotContains:
Keith Packard24330d22002-02-14 23:34:13 +0000326 case FcOpPlus:
327 case FcOpMinus:
328 case FcOpTimes:
329 case FcOpDivide:
330 case FcOpQuest:
331 case FcOpComma:
332 FcExprDestroy (e->u.tree.right);
333 /* fall through */
334 case FcOpNot:
Keith Packard3f7653c2003-04-15 23:38:06 +0000335 case FcOpFloor:
336 case FcOpCeil:
337 case FcOpRound:
338 case FcOpTrunc:
Keith Packard24330d22002-02-14 23:34:13 +0000339 FcExprDestroy (e->u.tree.left);
340 break;
341 case FcOpNil:
342 case FcOpInvalid:
343 break;
344 }
Behdad Esfahbod390c05e2009-06-05 22:32:31 -0400345
346 e->op = FcOpNil;
Keith Packard24330d22002-02-14 23:34:13 +0000347}
348
Keith Packard24330d22002-02-14 23:34:13 +0000349void
350FcEditDestroy (FcEdit *e)
351{
Keith Packard24330d22002-02-14 23:34:13 +0000352 if (e->expr)
353 FcExprDestroy (e->expr);
Carl Worth34cd0512003-08-15 19:45:20 +0000354 free (e);
Keith Packard24330d22002-02-14 23:34:13 +0000355}
356
Keith Packardc2e7c612002-02-18 22:29:28 +0000357typedef enum _FcElement {
358 FcElementNone,
359 FcElementFontconfig,
360 FcElementDir,
Patrick Lam7410e402006-08-04 16:13:00 +0000361 FcElementCacheDir,
Keith Packardc2e7c612002-02-18 22:29:28 +0000362 FcElementCache,
363 FcElementInclude,
364 FcElementConfig,
365 FcElementMatch,
366 FcElementAlias,
Akira TAGOH9a0fcb92014-03-27 15:10:44 +0900367 FcElementDescription,
Akira TAGOHa563a182019-01-28 09:59:29 +0000368 FcElementRemapDir,
Akira TAGOHdef1d002019-01-31 07:52:09 +0000369 FcElementResetDirs,
Akira TAGOH6715a142022-11-25 21:15:32 +0900370
Keith Packard179c3992002-05-21 17:06:22 +0000371 FcElementRescan,
Keith Packardc2e7c612002-02-18 22:29:28 +0000372
373 FcElementPrefer,
374 FcElementAccept,
375 FcElementDefault,
376 FcElementFamily,
377
Keith Packardd47c9d62003-05-07 16:13:24 +0000378 FcElementSelectfont,
379 FcElementAcceptfont,
380 FcElementRejectfont,
381 FcElementGlob,
Keith Packard4f27c1c2004-12-04 19:41:10 +0000382 FcElementPattern,
383 FcElementPatelt,
Keith Packardd47c9d62003-05-07 16:13:24 +0000384
Keith Packardc2e7c612002-02-18 22:29:28 +0000385 FcElementTest,
386 FcElementEdit,
387 FcElementInt,
388 FcElementDouble,
389 FcElementString,
390 FcElementMatrix,
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900391 FcElementRange,
Keith Packardc2e7c612002-02-18 22:29:28 +0000392 FcElementBool,
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900393 FcElementCharSet,
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900394 FcElementLangSet,
Keith Packardc2e7c612002-02-18 22:29:28 +0000395 FcElementName,
396 FcElementConst,
397 FcElementOr,
398 FcElementAnd,
399 FcElementEq,
400 FcElementNotEq,
401 FcElementLess,
402 FcElementLessEq,
403 FcElementMore,
404 FcElementMoreEq,
Keith Packard47d4f952002-08-22 18:53:22 +0000405 FcElementContains,
406 FcElementNotContains,
Keith Packardc2e7c612002-02-18 22:29:28 +0000407 FcElementPlus,
408 FcElementMinus,
409 FcElementTimes,
410 FcElementDivide,
411 FcElementNot,
412 FcElementIf,
Keith Packard3f7653c2003-04-15 23:38:06 +0000413 FcElementFloor,
414 FcElementCeil,
415 FcElementRound,
416 FcElementTrunc,
Keith Packardc2e7c612002-02-18 22:29:28 +0000417 FcElementUnknown
418} FcElement;
419
Patrick Lam392fa272006-04-06 04:52:21 +0000420static const struct {
Patrick Lam67accef2005-09-22 23:45:53 +0000421 const char name[16];
422 FcElement element;
423} fcElementMap[] = {
424 { "fontconfig", FcElementFontconfig },
425 { "dir", FcElementDir },
Patrick Lam7410e402006-08-04 16:13:00 +0000426 { "cachedir", FcElementCacheDir },
Patrick Lam67accef2005-09-22 23:45:53 +0000427 { "cache", FcElementCache },
428 { "include", FcElementInclude },
429 { "config", FcElementConfig },
430 { "match", FcElementMatch },
431 { "alias", FcElementAlias },
Akira TAGOH9a0fcb92014-03-27 15:10:44 +0900432 { "description", FcElementDescription },
Akira TAGOHa563a182019-01-28 09:59:29 +0000433 { "remap-dir", FcElementRemapDir },
Akira TAGOHdef1d002019-01-31 07:52:09 +0000434 { "reset-dirs", FcElementResetDirs },
Behdad Esfahbod2b0f3f12010-04-12 11:52:09 -0400435
Patrick Lam67accef2005-09-22 23:45:53 +0000436 { "rescan", FcElementRescan },
437
438 { "prefer", FcElementPrefer },
439 { "accept", FcElementAccept },
440 { "default", FcElementDefault },
441 { "family", FcElementFamily },
442
443 { "selectfont", FcElementSelectfont },
444 { "acceptfont", FcElementAcceptfont },
445 { "rejectfont", FcElementRejectfont },
446 { "glob", FcElementGlob },
447 { "pattern", FcElementPattern },
448 { "patelt", FcElementPatelt },
449
450 { "test", FcElementTest },
451 { "edit", FcElementEdit },
452 { "int", FcElementInt },
453 { "double", FcElementDouble },
454 { "string", FcElementString },
455 { "matrix", FcElementMatrix },
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900456 { "range", FcElementRange },
Patrick Lam67accef2005-09-22 23:45:53 +0000457 { "bool", FcElementBool },
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900458 { "charset", FcElementCharSet },
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900459 { "langset", FcElementLangSet },
Patrick Lam67accef2005-09-22 23:45:53 +0000460 { "name", FcElementName },
461 { "const", FcElementConst },
462 { "or", FcElementOr },
463 { "and", FcElementAnd },
464 { "eq", FcElementEq },
465 { "not_eq", FcElementNotEq },
466 { "less", FcElementLess },
467 { "less_eq", FcElementLessEq },
468 { "more", FcElementMore },
469 { "more_eq", FcElementMoreEq },
470 { "contains", FcElementContains },
471 { "not_contains", FcElementNotContains },
472 { "plus", FcElementPlus },
473 { "minus", FcElementMinus },
474 { "times", FcElementTimes },
475 { "divide", FcElementDivide },
476 { "not", FcElementNot },
477 { "if", FcElementIf },
478 { "floor", FcElementFloor },
479 { "ceil", FcElementCeil },
480 { "round", FcElementRound },
481 { "trunc", FcElementTrunc },
482};
483#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])
484
Akira TAGOH9a0fcb92014-03-27 15:10:44 +0900485static const char *fcElementIgnoreName[16] = {
486 "its:",
487 NULL
488};
489
Keith Packardc2e7c612002-02-18 22:29:28 +0000490static FcElement
491FcElementMap (const XML_Char *name)
492{
Keith Packardc2e7c612002-02-18 22:29:28 +0000493
494 int i;
Patrick Lam67accef2005-09-22 23:45:53 +0000495 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
Keith Packardc2e7c612002-02-18 22:29:28 +0000496 if (!strcmp ((char *) name, fcElementMap[i].name))
497 return fcElementMap[i].element;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +0900498 for (i = 0; fcElementIgnoreName[i] != NULL; i++)
499 if (!strncmp ((char *) name, fcElementIgnoreName[i], strlen (fcElementIgnoreName[i])))
500 return FcElementNone;
Keith Packardc2e7c612002-02-18 22:29:28 +0000501 return FcElementUnknown;
502}
503
Akira TAGOHa563a182019-01-28 09:59:29 +0000504static const char *
505FcElementReverseMap (FcElement e)
506{
507 int i;
508
509 for (i = 0; i < NUM_ELEMENT_MAPS; i++)
510 if (fcElementMap[i].element == e)
511 return fcElementMap[i].name;
512
513 return NULL;
514}
515
516
Keith Packardc2e7c612002-02-18 22:29:28 +0000517typedef struct _FcPStack {
518 struct _FcPStack *prev;
519 FcElement element;
520 FcChar8 **attr;
521 FcStrBuf str;
Behdad Esfahbodde69ee12009-03-12 12:31:57 -0400522 FcChar8 *attr_buf_static[16];
Keith Packardc2e7c612002-02-18 22:29:28 +0000523} FcPStack;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -0400524
Keith Packardc2e7c612002-02-18 22:29:28 +0000525typedef enum _FcVStackTag {
526 FcVStackNone,
527
528 FcVStackString,
529 FcVStackFamily,
Keith Packardc2e7c612002-02-18 22:29:28 +0000530 FcVStackConstant,
Keith Packardd47c9d62003-05-07 16:13:24 +0000531 FcVStackGlob,
Behdad Esfahbod51b00442012-12-29 23:58:38 -0500532 FcVStackName,
Keith Packard4f27c1c2004-12-04 19:41:10 +0000533 FcVStackPattern,
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -0400534
Keith Packardc2e7c612002-02-18 22:29:28 +0000535 FcVStackPrefer,
536 FcVStackAccept,
537 FcVStackDefault,
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -0400538
Keith Packardc2e7c612002-02-18 22:29:28 +0000539 FcVStackInteger,
540 FcVStackDouble,
541 FcVStackMatrix,
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900542 FcVStackRange,
Keith Packardc2e7c612002-02-18 22:29:28 +0000543 FcVStackBool,
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900544 FcVStackCharSet,
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900545 FcVStackLangSet,
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -0400546
Keith Packardc2e7c612002-02-18 22:29:28 +0000547 FcVStackTest,
548 FcVStackExpr,
549 FcVStackEdit
550} FcVStackTag;
551
552typedef struct _FcVStack {
553 struct _FcVStack *prev;
554 FcPStack *pstack; /* related parse element */
555 FcVStackTag tag;
556 union {
557 FcChar8 *string;
558
559 int integer;
560 double _double;
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500561 FcExprMatrix *matrix;
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900562 FcRange *range;
Harald Fernengelfe8e8a12008-12-28 03:23:58 -0500563 FcBool bool_;
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900564 FcCharSet *charset;
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900565 FcLangSet *langset;
Behdad Esfahbod51b00442012-12-29 23:58:38 -0500566 FcExprName name;
Keith Packardc2e7c612002-02-18 22:29:28 +0000567
568 FcTest *test;
569 FcQual qual;
570 FcOp op;
571 FcExpr *expr;
572 FcEdit *edit;
Keith Packard4f27c1c2004-12-04 19:41:10 +0000573
574 FcPattern *pattern;
Keith Packardc2e7c612002-02-18 22:29:28 +0000575 } u;
576} FcVStack;
577
578typedef struct _FcConfigParse {
579 FcPStack *pstack;
580 FcVStack *vstack;
581 FcBool error;
582 const FcChar8 *name;
583 FcConfig *config;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +0900584 FcRuleSet *ruleset;
Keith Packardc2e7c612002-02-18 22:29:28 +0000585 XML_Parser parser;
Behdad Esfahboddd69d962012-12-29 22:47:49 -0500586 unsigned int pstack_static_used;
Behdad Esfahbod1d7b47d2009-03-12 11:58:04 -0400587 FcPStack pstack_static[8];
Behdad Esfahboddd69d962012-12-29 22:47:49 -0500588 unsigned int vstack_static_used;
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400589 FcVStack vstack_static[64];
Akira TAGOHef748b32018-01-23 22:27:17 +0900590 FcBool scanOnly;
Keith Packardc2e7c612002-02-18 22:29:28 +0000591} FcConfigParse;
592
Keith Packard179c3992002-05-21 17:06:22 +0000593typedef enum _FcConfigSeverity {
594 FcSevereInfo, FcSevereWarning, FcSevereError
595} FcConfigSeverity;
596
Keith Packard24330d22002-02-14 23:34:13 +0000597static void
Patrick Lam67accef2005-09-22 23:45:53 +0000598FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
Keith Packard24330d22002-02-14 23:34:13 +0000599{
Patrick Lam67accef2005-09-22 23:45:53 +0000600 const char *s = "unknown";
Keith Packard24330d22002-02-14 23:34:13 +0000601 va_list args;
602
603 va_start (args, fmt);
Keith Packard179c3992002-05-21 17:06:22 +0000604
605 switch (severe) {
606 case FcSevereInfo: s = "info"; break;
607 case FcSevereWarning: s = "warning"; break;
608 case FcSevereError: s = "error"; break;
609 }
Keith Packardc2e7c612002-02-18 22:29:28 +0000610 if (parse)
611 {
612 if (parse->name)
Keith Packard179c3992002-05-21 17:06:22 +0000613 fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
Patrick Lam68355f32006-02-05 02:57:21 +0000614 parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
Keith Packardc2e7c612002-02-18 22:29:28 +0000615 else
Keith Packard179c3992002-05-21 17:06:22 +0000616 fprintf (stderr, "Fontconfig %s: line %d: ", s,
Patrick Lam68355f32006-02-05 02:57:21 +0000617 (int)XML_GetCurrentLineNumber (parse->parser));
Keith Packard179c3992002-05-21 17:06:22 +0000618 if (severe >= FcSevereError)
619 parse->error = FcTrue;
Keith Packardc2e7c612002-02-18 22:29:28 +0000620 }
621 else
Keith Packard179c3992002-05-21 17:06:22 +0000622 fprintf (stderr, "Fontconfig %s: ", s);
Keith Packard24330d22002-02-14 23:34:13 +0000623 vfprintf (stderr, fmt, args);
624 fprintf (stderr, "\n");
625 va_end (args);
626}
627
Keith Packardca60d2b2005-01-28 23:55:14 +0000628
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500629static FcExpr *
630FcPopExpr (FcConfigParse *parse);
631
632
Patrick Lam67accef2005-09-22 23:45:53 +0000633static const char *
Keith Packardca60d2b2005-01-28 23:55:14 +0000634FcTypeName (FcType type)
635{
636 switch (type) {
637 case FcTypeVoid:
638 return "void";
639 case FcTypeInteger:
640 case FcTypeDouble:
641 return "number";
642 case FcTypeString:
643 return "string";
644 case FcTypeBool:
645 return "bool";
646 case FcTypeMatrix:
647 return "matrix";
648 case FcTypeCharSet:
649 return "charset";
650 case FcTypeFTFace:
651 return "FT_Face";
652 case FcTypeLangSet:
653 return "langset";
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900654 case FcTypeRange:
655 return "range";
Behdad Esfahbod13a5ae92014-08-20 16:03:02 -0400656 case FcTypeUnknown:
Keith Packardca60d2b2005-01-28 23:55:14 +0000657 default:
658 return "unknown";
659 }
660}
661
662static void
663FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
664{
665 if (value == FcTypeInteger)
666 value = FcTypeDouble;
667 if (type == FcTypeInteger)
668 type = FcTypeDouble;
669 if (value != type)
670 {
671 if ((value == FcTypeLangSet && type == FcTypeString) ||
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900672 (value == FcTypeString && type == FcTypeLangSet) ||
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900673 (value == FcTypeDouble && type == FcTypeRange))
Keith Packardca60d2b2005-01-28 23:55:14 +0000674 return;
Akira TAGOH38acb082013-11-11 11:53:09 +0900675 if (type == FcTypeUnknown)
Keith Packard9a9fd972006-09-04 12:46:01 -0700676 return;
Behdad Esfahbod1fbb0b32012-12-30 19:08:42 -0600677 /* It's perfectly fine to use user-define elements in expressions,
678 * so don't warn in that case. */
Akira TAGOH38acb082013-11-11 11:53:09 +0900679 if (value == FcTypeUnknown)
Behdad Esfahbod1fbb0b32012-12-30 19:08:42 -0600680 return;
Keith Packardca60d2b2005-01-28 23:55:14 +0000681 FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
682 FcTypeName (value), FcTypeName (type));
683 }
684}
685
686static void
687FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
688{
689 const FcObjectType *o;
690 const FcConstant *c;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -0400691
Mike FABIAN07e646c2007-10-18 05:44:28 -0700692 /* If parsing the expression failed, some nodes may be NULL */
693 if (!expr)
694 return;
695
Akira TAGOHbc4517d2012-04-11 19:52:35 +0900696 switch (FC_OP_GET_OP (expr->op)) {
Keith Packardca60d2b2005-01-28 23:55:14 +0000697 case FcOpInteger:
698 case FcOpDouble:
699 FcTypecheckValue (parse, FcTypeDouble, type);
700 break;
701 case FcOpString:
702 FcTypecheckValue (parse, FcTypeString, type);
703 break;
704 case FcOpMatrix:
705 FcTypecheckValue (parse, FcTypeMatrix, type);
706 break;
707 case FcOpBool:
708 FcTypecheckValue (parse, FcTypeBool, type);
709 break;
710 case FcOpCharSet:
711 FcTypecheckValue (parse, FcTypeCharSet, type);
712 break;
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900713 case FcOpLangSet:
714 FcTypecheckValue (parse, FcTypeLangSet, type);
715 break;
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900716 case FcOpRange:
717 FcTypecheckValue (parse, FcTypeRange, type);
718 break;
Keith Packardca60d2b2005-01-28 23:55:14 +0000719 case FcOpNil:
720 break;
721 case FcOpField:
Behdad Esfahbod51b00442012-12-29 23:58:38 -0500722 o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
Keith Packardca60d2b2005-01-28 23:55:14 +0000723 if (o)
724 FcTypecheckValue (parse, o->type, type);
725 break;
726 case FcOpConst:
727 c = FcNameGetConstant (expr->u.constant);
728 if (c)
729 {
730 o = FcNameGetObjectType (c->object);
731 if (o)
732 FcTypecheckValue (parse, o->type, type);
733 }
Akira TAGOH6715a142022-11-25 21:15:32 +0900734 else
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -0400735 FcConfigMessage (parse, FcSevereWarning,
Patrick Lamf28472f2005-11-17 16:17:05 +0000736 "invalid constant used : %s",
737 expr->u.constant);
Keith Packardca60d2b2005-01-28 23:55:14 +0000738 break;
739 case FcOpQuest:
740 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
741 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
742 FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
743 break;
744 case FcOpAssign:
745 case FcOpAssignReplace:
746 break;
747 case FcOpEqual:
748 case FcOpNotEqual:
749 case FcOpLess:
750 case FcOpLessEqual:
751 case FcOpMore:
752 case FcOpMoreEqual:
753 case FcOpContains:
754 case FcOpNotContains:
755 case FcOpListing:
756 FcTypecheckValue (parse, FcTypeBool, type);
757 break;
758 case FcOpComma:
759 case FcOpOr:
760 case FcOpAnd:
761 case FcOpPlus:
762 case FcOpMinus:
763 case FcOpTimes:
764 case FcOpDivide:
765 FcTypecheckExpr (parse, expr->u.tree.left, type);
766 FcTypecheckExpr (parse, expr->u.tree.right, type);
767 break;
768 case FcOpNot:
769 FcTypecheckValue (parse, FcTypeBool, type);
770 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
771 break;
772 case FcOpFloor:
773 case FcOpCeil:
774 case FcOpRound:
775 case FcOpTrunc:
776 FcTypecheckValue (parse, FcTypeDouble, type);
777 FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
778 break;
779 default:
780 break;
781 }
782}
783
784static FcTest *
785FcTestCreate (FcConfigParse *parse,
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -0400786 FcMatchKind kind,
Keith Packardca60d2b2005-01-28 23:55:14 +0000787 FcQual qual,
788 const FcChar8 *field,
Akira TAGOH197d06c2013-06-28 15:04:11 +0900789 unsigned int compare,
Keith Packardca60d2b2005-01-28 23:55:14 +0000790 FcExpr *expr)
791{
792 FcTest *test = (FcTest *) malloc (sizeof (FcTest));
793
794 if (test)
795 {
796 const FcObjectType *o;
Akira TAGOH6715a142022-11-25 21:15:32 +0900797
Keith Packardca60d2b2005-01-28 23:55:14 +0000798 test->kind = kind;
799 test->qual = qual;
Keith Packard7ce19672006-08-30 04:16:22 -0700800 test->object = FcObjectFromName ((const char *) field);
Keith Packardca60d2b2005-01-28 23:55:14 +0000801 test->op = compare;
802 test->expr = expr;
Keith Packard7ce19672006-08-30 04:16:22 -0700803 o = FcNameGetObjectType (FcObjectName (test->object));
Keith Packardca60d2b2005-01-28 23:55:14 +0000804 if (o)
805 FcTypecheckExpr (parse, expr, o->type);
806 }
807 return test;
808}
809
810static FcEdit *
811FcEditCreate (FcConfigParse *parse,
Keith Packard2d3387f2006-08-30 21:59:53 -0700812 FcObject object,
Keith Packardca60d2b2005-01-28 23:55:14 +0000813 FcOp op,
814 FcExpr *expr,
815 FcValueBinding binding)
816{
817 FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));
818
819 if (e)
820 {
821 const FcObjectType *o;
822
Keith Packard2d3387f2006-08-30 21:59:53 -0700823 e->object = object;
Keith Packardca60d2b2005-01-28 23:55:14 +0000824 e->op = op;
825 e->expr = expr;
826 e->binding = binding;
Keith Packard7ce19672006-08-30 04:16:22 -0700827 o = FcNameGetObjectType (FcObjectName (e->object));
Keith Packardca60d2b2005-01-28 23:55:14 +0000828 if (o)
829 FcTypecheckExpr (parse, expr, o->type);
830 }
831 return e;
832}
833
Akira TAGOHd420e1d2013-07-04 19:51:03 +0900834static FcRule *
835FcRuleCreate (FcRuleType type,
836 void *p)
837{
838 FcRule *r = (FcRule *) malloc (sizeof (FcRule));
839
840 if (!r)
841 return NULL;
842
843 r->next = NULL;
844 r->type = type;
845 switch (type)
846 {
847 case FcRuleTest:
848 r->u.test = (FcTest *) p;
849 break;
850 case FcRuleEdit:
851 r->u.edit = (FcEdit *) p;
852 break;
Behdad Esfahbod13a5ae92014-08-20 16:03:02 -0400853 case FcRuleUnknown:
Akira TAGOHd420e1d2013-07-04 19:51:03 +0900854 default:
855 free (r);
856 r = NULL;
857 break;
858 }
859
860 return r;
861}
862
Keith Packardc2e7c612002-02-18 22:29:28 +0000863static FcVStack *
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400864FcVStackCreateAndPush (FcConfigParse *parse)
Keith Packard24330d22002-02-14 23:34:13 +0000865{
Keith Packardc2e7c612002-02-18 22:29:28 +0000866 FcVStack *new;
867
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400868 if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
869 new = &parse->vstack_static[parse->vstack_static_used++];
870 else
871 {
872 new = malloc (sizeof (FcVStack));
873 if (!new)
874 return 0;
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400875 }
Keith Packardc2e7c612002-02-18 22:29:28 +0000876 new->tag = FcVStackNone;
877 new->prev = 0;
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400878
879 new->prev = parse->vstack;
880 new->pstack = parse->pstack ? parse->pstack->prev : 0;
881 parse->vstack = new;
882
Keith Packardc2e7c612002-02-18 22:29:28 +0000883 return new;
Keith Packard24330d22002-02-14 23:34:13 +0000884}
885
Keith Packard24330d22002-02-14 23:34:13 +0000886static FcBool
Keith Packardc2e7c612002-02-18 22:29:28 +0000887FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
888{
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400889 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +0000890 if (!vstack)
891 return FcFalse;
892 vstack->u.string = string;
893 vstack->tag = tag;
Keith Packardc2e7c612002-02-18 22:29:28 +0000894 return FcTrue;
895}
896
897static FcBool
898FcVStackPushInteger (FcConfigParse *parse, int integer)
899{
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400900 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +0000901 if (!vstack)
902 return FcFalse;
903 vstack->u.integer = integer;
904 vstack->tag = FcVStackInteger;
Keith Packardc2e7c612002-02-18 22:29:28 +0000905 return FcTrue;
906}
907
908static FcBool
909FcVStackPushDouble (FcConfigParse *parse, double _double)
910{
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400911 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +0000912 if (!vstack)
913 return FcFalse;
914 vstack->u._double = _double;
915 vstack->tag = FcVStackDouble;
Keith Packardc2e7c612002-02-18 22:29:28 +0000916 return FcTrue;
917}
918
919static FcBool
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500920FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
Keith Packardc2e7c612002-02-18 22:29:28 +0000921{
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400922 FcVStack *vstack;
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400923 vstack = FcVStackCreateAndPush (parse);
924 if (!vstack)
925 return FcFalse;
Behdad Esfahbod4f676742012-12-29 21:39:06 -0500926 vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
Keith Packardc2e7c612002-02-18 22:29:28 +0000927 vstack->tag = FcVStackMatrix;
Keith Packardc2e7c612002-02-18 22:29:28 +0000928 return FcTrue;
929}
930
931static FcBool
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900932FcVStackPushRange (FcConfigParse *parse, FcRange *range)
933{
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900934 FcVStack *vstack = FcVStackCreateAndPush (parse);
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900935 if (!vstack)
936 return FcFalse;
Akira TAGOH3cd573f2013-11-20 18:44:59 +0900937 vstack->u.range = range;
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900938 vstack->tag = FcVStackRange;
939 return FcTrue;
940}
941
942static FcBool
Harald Fernengelfe8e8a12008-12-28 03:23:58 -0500943FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
Keith Packardc2e7c612002-02-18 22:29:28 +0000944{
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400945 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +0000946 if (!vstack)
947 return FcFalse;
Harald Fernengelfe8e8a12008-12-28 03:23:58 -0500948 vstack->u.bool_ = bool_;
Keith Packardc2e7c612002-02-18 22:29:28 +0000949 vstack->tag = FcVStackBool;
Keith Packardc2e7c612002-02-18 22:29:28 +0000950 return FcTrue;
951}
952
953static FcBool
Akira TAGOH857b7ef2010-12-06 12:10:17 +0900954FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
955{
956 FcVStack *vstack;
957 if (!charset)
958 return FcFalse;
959 vstack = FcVStackCreateAndPush (parse);
960 if (!vstack)
961 return FcFalse;
962 vstack->u.charset = charset;
963 vstack->tag = FcVStackCharSet;
964 return FcTrue;
965}
966
967static FcBool
Akira TAGOH3c862aa2010-12-06 12:38:18 +0900968FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
969{
970 FcVStack *vstack;
971 if (!langset)
972 return FcFalse;
973 vstack = FcVStackCreateAndPush (parse);
974 if (!vstack)
975 return FcFalse;
976 vstack->u.langset = langset;
977 vstack->tag = FcVStackLangSet;
978 return FcTrue;
979}
980
981static FcBool
Behdad Esfahbod51b00442012-12-29 23:58:38 -0500982FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
983{
984 FcVStack *vstack = FcVStackCreateAndPush (parse);
985 if (!vstack)
986 return FcFalse;
987 vstack->u.name.object = object;
988 vstack->u.name.kind = kind;
989 vstack->tag = FcVStackName;
990 return FcTrue;
991}
992
993static FcBool
Keith Packardc2e7c612002-02-18 22:29:28 +0000994FcVStackPushTest (FcConfigParse *parse, FcTest *test)
995{
Behdad Esfahbod39861b72009-03-12 12:22:37 -0400996 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +0000997 if (!vstack)
998 return FcFalse;
999 vstack->u.test = test;
1000 vstack->tag = FcVStackTest;
Keith Packardc2e7c612002-02-18 22:29:28 +00001001 return FcTrue;
1002}
1003
1004static FcBool
1005FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
1006{
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001007 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00001008 if (!vstack)
1009 return FcFalse;
1010 vstack->u.expr = expr;
1011 vstack->tag = tag;
Keith Packardc2e7c612002-02-18 22:29:28 +00001012 return FcTrue;
1013}
1014
1015static FcBool
1016FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
1017{
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001018 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00001019 if (!vstack)
1020 return FcFalse;
1021 vstack->u.edit = edit;
1022 vstack->tag = FcVStackEdit;
Keith Packardc2e7c612002-02-18 22:29:28 +00001023 return FcTrue;
1024}
1025
Keith Packard4f27c1c2004-12-04 19:41:10 +00001026static FcBool
1027FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
1028{
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001029 FcVStack *vstack = FcVStackCreateAndPush (parse);
Keith Packard4f27c1c2004-12-04 19:41:10 +00001030 if (!vstack)
1031 return FcFalse;
1032 vstack->u.pattern = pattern;
1033 vstack->tag = FcVStackPattern;
Keith Packard4f27c1c2004-12-04 19:41:10 +00001034 return FcTrue;
1035}
1036
Keith Packardc2e7c612002-02-18 22:29:28 +00001037static FcVStack *
1038FcVStackFetch (FcConfigParse *parse, int off)
1039{
1040 FcVStack *vstack;
1041
1042 for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
1043 return vstack;
1044}
1045
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001046static FcVStack *
1047FcVStackPeek (FcConfigParse *parse)
Keith Packardc2e7c612002-02-18 22:29:28 +00001048{
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001049 FcVStack *vstack = parse->vstack;
1050
1051 return vstack && vstack->pstack == parse->pstack ? vstack : 0;
Keith Packardc2e7c612002-02-18 22:29:28 +00001052}
1053
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001054static void
1055FcVStackPopAndDestroy (FcConfigParse *parse)
Keith Packardc2e7c612002-02-18 22:29:28 +00001056{
1057 FcVStack *vstack = parse->vstack;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001058
Keith Packardc2e7c612002-02-18 22:29:28 +00001059 if (!vstack || vstack->pstack != parse->pstack)
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001060 return;
1061
Keith Packardc2e7c612002-02-18 22:29:28 +00001062 parse->vstack = vstack->prev;
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001063
1064 switch (vstack->tag) {
1065 case FcVStackNone:
1066 break;
Behdad Esfahbod51b00442012-12-29 23:58:38 -05001067 case FcVStackName:
1068 break;
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001069 case FcVStackFamily:
Behdad Esfahbod3164ac72009-06-05 22:59:06 -04001070 break;
Behdad Esfahbod16e55c72009-07-20 16:30:12 -04001071 case FcVStackString:
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001072 case FcVStackConstant:
1073 case FcVStackGlob:
1074 FcStrFree (vstack->u.string);
1075 break;
1076 case FcVStackPattern:
1077 FcPatternDestroy (vstack->u.pattern);
1078 break;
1079 case FcVStackInteger:
1080 case FcVStackDouble:
1081 break;
1082 case FcVStackMatrix:
Behdad Esfahbod4f676742012-12-29 21:39:06 -05001083 FcExprMatrixFreeShallow (vstack->u.matrix);
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001084 break;
1085 case FcVStackBool:
1086 break;
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001087 case FcVStackRange:
1088 FcRangeDestroy (vstack->u.range);
1089 break;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001090 case FcVStackCharSet:
1091 FcCharSetDestroy (vstack->u.charset);
1092 break;
Akira TAGOH3c862aa2010-12-06 12:38:18 +09001093 case FcVStackLangSet:
1094 FcLangSetDestroy (vstack->u.langset);
1095 break;
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001096 case FcVStackTest:
1097 FcTestDestroy (vstack->u.test);
1098 break;
1099 case FcVStackExpr:
1100 case FcVStackPrefer:
1101 case FcVStackAccept:
1102 case FcVStackDefault:
1103 FcExprDestroy (vstack->u.expr);
1104 break;
1105 case FcVStackEdit:
1106 FcEditDestroy (vstack->u.edit);
1107 break;
1108 }
1109
1110 if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
1111 parse->vstack_static_used--;
1112 else
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001113 free (vstack);
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001114}
1115
1116static void
1117FcVStackClear (FcConfigParse *parse)
1118{
1119 while (FcVStackPeek (parse))
1120 FcVStackPopAndDestroy (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00001121}
1122
1123static int
1124FcVStackElements (FcConfigParse *parse)
1125{
1126 int h = 0;
1127 FcVStack *vstack = parse->vstack;
1128 while (vstack && vstack->pstack == parse->pstack)
1129 {
1130 h++;
1131 vstack = vstack->prev;
1132 }
1133 return h;
1134}
1135
1136static FcChar8 **
Behdad Esfahbodde69ee12009-03-12 12:31:57 -04001137FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
Keith Packardc2e7c612002-02-18 22:29:28 +00001138{
Keith Packardc2e7c612002-02-18 22:29:28 +00001139 int slen;
1140 int i;
1141 FcChar8 **new;
1142 FcChar8 *s;
1143
1144 if (!attr)
1145 return 0;
1146 slen = 0;
1147 for (i = 0; attr[i]; i++)
Patrick Lam8f2a8072005-11-18 20:32:30 +00001148 slen += strlen ((char *) attr[i]) + 1;
Behdad Esfahbod532d8a12009-03-12 09:27:20 -04001149 if (i == 0)
1150 return 0;
Behdad Esfahbodde69ee12009-03-12 12:31:57 -04001151 slen += (i + 1) * sizeof (FcChar8 *);
1152 if (slen <= size_bytes)
1153 new = buf;
1154 else
Behdad Esfahbod532d8a12009-03-12 09:27:20 -04001155 {
Behdad Esfahbodde69ee12009-03-12 12:31:57 -04001156 new = malloc (slen);
1157 if (!new)
1158 {
1159 FcConfigMessage (0, FcSevereError, "out of memory");
1160 return 0;
1161 }
Behdad Esfahbod532d8a12009-03-12 09:27:20 -04001162 }
Keith Packardc2e7c612002-02-18 22:29:28 +00001163 s = (FcChar8 *) (new + (i + 1));
1164 for (i = 0; attr[i]; i++)
1165 {
1166 new[i] = s;
1167 strcpy ((char *) s, (char *) attr[i]);
1168 s += strlen ((char *) s) + 1;
1169 }
1170 new[i] = 0;
1171 return new;
1172}
1173
1174static FcBool
1175FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
1176{
Behdad Esfahbod1d7b47d2009-03-12 11:58:04 -04001177 FcPStack *new;
Keith Packardc2e7c612002-02-18 22:29:28 +00001178
Behdad Esfahbod1d7b47d2009-03-12 11:58:04 -04001179 if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
1180 new = &parse->pstack_static[parse->pstack_static_used++];
1181 else
1182 {
1183 new = malloc (sizeof (FcPStack));
1184 if (!new)
1185 return FcFalse;
Behdad Esfahbod1d7b47d2009-03-12 11:58:04 -04001186 }
1187
Keith Packardc2e7c612002-02-18 22:29:28 +00001188 new->prev = parse->pstack;
1189 new->element = element;
Behdad Esfahbodde69ee12009-03-12 12:31:57 -04001190 new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
Keith Packardc2e7c612002-02-18 22:29:28 +00001191 FcStrBufInit (&new->str, 0, 0);
1192 parse->pstack = new;
1193 return FcTrue;
1194}
1195
1196static FcBool
1197FcPStackPop (FcConfigParse *parse)
1198{
1199 FcPStack *old;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001200
1201 if (!parse->pstack)
Keith Packardc2e7c612002-02-18 22:29:28 +00001202 {
Keith Packard179c3992002-05-21 17:06:22 +00001203 FcConfigMessage (parse, FcSevereError, "mismatching element");
Keith Packardc2e7c612002-02-18 22:29:28 +00001204 return FcFalse;
1205 }
Behdad Esfahbod6047ce72013-01-02 01:31:34 -06001206
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09001207 /* Don't check the attributes for FcElementNone */
1208 if (parse->pstack->element != FcElementNone &&
1209 parse->pstack->attr)
Behdad Esfahbod6047ce72013-01-02 01:31:34 -06001210 {
1211 /* Warn about unused attrs. */
1212 FcChar8 **attrs = parse->pstack->attr;
1213 while (*attrs)
1214 {
1215 if (attrs[0][0])
1216 {
Jan Tojnar9133e792020-08-13 18:36:42 +02001217 FcConfigMessage (parse, FcSevereWarning, "invalid attribute '%s'", attrs[0]);
Behdad Esfahbod6047ce72013-01-02 01:31:34 -06001218 }
1219 attrs += 2;
1220 }
1221 }
1222
Keith Packardc2e7c612002-02-18 22:29:28 +00001223 FcVStackClear (parse);
1224 old = parse->pstack;
1225 parse->pstack = old->prev;
1226 FcStrBufDestroy (&old->str);
Behdad Esfahbod6047ce72013-01-02 01:31:34 -06001227
Behdad Esfahbodde69ee12009-03-12 12:31:57 -04001228 if (old->attr && old->attr != old->attr_buf_static)
Keith Packardc2e7c612002-02-18 22:29:28 +00001229 free (old->attr);
Behdad Esfahbod1d7b47d2009-03-12 11:58:04 -04001230
1231 if (old == &parse->pstack_static[parse->pstack_static_used - 1])
1232 parse->pstack_static_used--;
1233 else
Behdad Esfahbod1d7b47d2009-03-12 11:58:04 -04001234 free (old);
Keith Packardc2e7c612002-02-18 22:29:28 +00001235 return FcTrue;
1236}
1237
1238static FcBool
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09001239FcConfigParseInit (FcConfigParse *parse,
1240 const FcChar8 *name,
1241 FcConfig *config,
1242 XML_Parser parser,
1243 FcBool enabled)
Keith Packardc2e7c612002-02-18 22:29:28 +00001244{
1245 parse->pstack = 0;
Behdad Esfahbod1d7b47d2009-03-12 11:58:04 -04001246 parse->pstack_static_used = 0;
Keith Packardc2e7c612002-02-18 22:29:28 +00001247 parse->vstack = 0;
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001248 parse->vstack_static_used = 0;
Keith Packardc2e7c612002-02-18 22:29:28 +00001249 parse->error = FcFalse;
1250 parse->name = name;
1251 parse->config = config;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09001252 parse->ruleset = FcRuleSetCreate (name);
Keith Packardc2e7c612002-02-18 22:29:28 +00001253 parse->parser = parser;
Akira TAGOHef748b32018-01-23 22:27:17 +09001254 parse->scanOnly = !enabled;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09001255 FcRuleSetEnable (parse->ruleset, enabled);
1256
Keith Packardc2e7c612002-02-18 22:29:28 +00001257 return FcTrue;
1258}
1259
1260static void
1261FcConfigCleanup (FcConfigParse *parse)
1262{
1263 while (parse->pstack)
1264 FcPStackPop (parse);
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09001265 FcRuleSetDestroy (parse->ruleset);
1266 parse->ruleset = NULL;
Keith Packardc2e7c612002-02-18 22:29:28 +00001267}
1268
1269static const FcChar8 *
Patrick Lam67accef2005-09-22 23:45:53 +00001270FcConfigGetAttribute (FcConfigParse *parse, const char *attr)
Keith Packardc2e7c612002-02-18 22:29:28 +00001271{
1272 FcChar8 **attrs;
1273 if (!parse->pstack)
1274 return 0;
1275
1276 attrs = parse->pstack->attr;
Patrick Lam368104c2005-12-12 13:20:41 +00001277 if (!attrs)
1278 return 0;
1279
Keith Packardc2e7c612002-02-18 22:29:28 +00001280 while (*attrs)
1281 {
1282 if (!strcmp ((char *) *attrs, attr))
Behdad Esfahbod6047ce72013-01-02 01:31:34 -06001283 {
1284 attrs[0][0] = '\0'; /* Mark as used. */
Keith Packardc2e7c612002-02-18 22:29:28 +00001285 return attrs[1];
Behdad Esfahbod6047ce72013-01-02 01:31:34 -06001286 }
Keith Packardc2e7c612002-02-18 22:29:28 +00001287 attrs += 2;
1288 }
1289 return 0;
1290}
1291
Akira TAGOH6f27f422021-03-29 21:25:21 +09001292static FcStrSet *
1293_get_real_paths_from_prefix(FcConfigParse *parse, const FcChar8 *path, const FcChar8 *prefix)
Akira TAGOHa563a182019-01-28 09:59:29 +00001294{
1295#ifdef _WIN32
Akira TAGOHad3f3352019-03-25 10:58:15 +00001296 FcChar8 buffer[1000] = { 0 };
Akira TAGOHa563a182019-01-28 09:59:29 +00001297#endif
1298 FcChar8 *parent = NULL, *retval = NULL;
Akira TAGOH6f27f422021-03-29 21:25:21 +09001299 FcStrSet *e = NULL;
Akira TAGOHa563a182019-01-28 09:59:29 +00001300
1301 if (prefix)
1302 {
1303 if (FcStrCmp (prefix, (const FcChar8 *) "xdg") == 0)
1304 {
1305 parent = FcConfigXdgDataHome ();
Albert Astals Cidfd3eeba2021-03-31 22:11:31 +02001306 if (!parent)
Akira TAGOHa563a182019-01-28 09:59:29 +00001307 {
1308 /* Home directory might be disabled */
1309 return NULL;
1310 }
Albert Astals Cidfd3eeba2021-03-31 22:11:31 +02001311 e = FcConfigXdgDataDirs ();
1312 if (!e)
1313 {
1314 FcStrFree (parent);
1315 return NULL;
1316 }
Akira TAGOHa563a182019-01-28 09:59:29 +00001317 }
1318 else if (FcStrCmp (prefix, (const FcChar8 *) "default") == 0 ||
1319 FcStrCmp (prefix, (const FcChar8 *) "cwd") == 0)
1320 {
1321 /* Nothing to do */
1322 }
1323 else if (FcStrCmp (prefix, (const FcChar8 *) "relative") == 0)
1324 {
Akira TAGOH1d766992021-10-11 18:35:58 +09001325 FcChar8 *p = FcStrRealPath (parse->name);
1326
1327 if (!p)
Akira TAGOHa563a182019-01-28 09:59:29 +00001328 return NULL;
Akira TAGOH1d766992021-10-11 18:35:58 +09001329 parent = FcStrDirname (p);
1330 if (!parent)
1331 {
1332 free (p);
1333 return NULL;
1334 }
Akira TAGOHa563a182019-01-28 09:59:29 +00001335 }
1336 }
1337#ifndef _WIN32
1338 /* For Win32, check this later for dealing with special cases */
1339 else
1340 {
1341 if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1342 FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1343 }
Akira TAGOHad3f3352019-03-25 10:58:15 +00001344#else
Akira TAGOHa563a182019-01-28 09:59:29 +00001345 if (strcmp ((const char *) path, "CUSTOMFONTDIR") == 0)
1346 {
1347 FcChar8 *p;
Akira TAGOH83840fd2019-06-24 08:07:27 +00001348 path = buffer;
Akira TAGOHa563a182019-01-28 09:59:29 +00001349 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1350 {
1351 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
Akira TAGOHb1bcc0c2019-03-25 16:17:33 +09001352 return NULL;
Akira TAGOHa563a182019-01-28 09:59:29 +00001353 }
1354 /*
1355 * Must use the multi-byte aware function to search
1356 * for backslash because East Asian double-byte code
1357 * pages have characters with backslash as the second
1358 * byte.
1359 */
Akira TAGOH83840fd2019-06-24 08:07:27 +00001360 p = _mbsrchr (path, '\\');
Akira TAGOHa563a182019-01-28 09:59:29 +00001361 if (p) *p = '\0';
Akira TAGOH83840fd2019-06-24 08:07:27 +00001362 strcat ((char *) path, "\\fonts");
Akira TAGOHa563a182019-01-28 09:59:29 +00001363 }
1364 else if (strcmp ((const char *) path, "APPSHAREFONTDIR") == 0)
1365 {
1366 FcChar8 *p;
Akira TAGOH83840fd2019-06-24 08:07:27 +00001367 path = buffer;
Akira TAGOHa563a182019-01-28 09:59:29 +00001368 if (!GetModuleFileName (NULL, (LPCH) buffer, sizeof (buffer) - 20))
1369 {
1370 FcConfigMessage (parse, FcSevereError, "GetModuleFileName failed");
Akira TAGOHb1bcc0c2019-03-25 16:17:33 +09001371 return NULL;
Akira TAGOHa563a182019-01-28 09:59:29 +00001372 }
Akira TAGOH83840fd2019-06-24 08:07:27 +00001373 p = _mbsrchr (path, '\\');
Akira TAGOHa563a182019-01-28 09:59:29 +00001374 if (p) *p = '\0';
Akira TAGOH83840fd2019-06-24 08:07:27 +00001375 strcat ((char *) path, "\\..\\share\\fonts");
Akira TAGOHa563a182019-01-28 09:59:29 +00001376 }
Akira TAGOH55eb1ef2022-01-17 16:19:22 +09001377 else if (strcmp ((const char *) path, "WINDOWSUSERFONTDIR") == 0)
1378 {
1379 path = buffer;
1380 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, (char *) buffer))))
1381 {
1382 FcConfigMessage(parse, FcSevereError, "SHGetFolderPathA failed");
1383 return NULL;
1384 }
1385 strcat((char *) path, "\\Microsoft\\Windows\\Fonts");
1386 }
Akira TAGOHa563a182019-01-28 09:59:29 +00001387 else if (strcmp ((const char *) path, "WINDOWSFONTDIR") == 0)
1388 {
1389 int rc;
Akira TAGOH83840fd2019-06-24 08:07:27 +00001390 path = buffer;
Francesco Pretto16bbb532021-10-26 19:31:23 +02001391 _ensureWin32GettersReady();
Akira TAGOHa563a182019-01-28 09:59:29 +00001392 rc = pGetSystemWindowsDirectory ((LPSTR) buffer, sizeof (buffer) - 20);
1393 if (rc == 0 || rc > sizeof (buffer) - 20)
1394 {
1395 FcConfigMessage (parse, FcSevereError, "GetSystemWindowsDirectory failed");
Akira TAGOHb1bcc0c2019-03-25 16:17:33 +09001396 return NULL;
Akira TAGOHa563a182019-01-28 09:59:29 +00001397 }
Akira TAGOH83840fd2019-06-24 08:07:27 +00001398 if (path [strlen ((const char *) path) - 1] != '\\')
1399 strcat ((char *) path, "\\");
1400 strcat ((char *) path, "fonts");
Akira TAGOHa563a182019-01-28 09:59:29 +00001401 }
Akira TAGOHad3f3352019-03-25 10:58:15 +00001402 else
Akira TAGOHa563a182019-01-28 09:59:29 +00001403 {
Akira TAGOHad3f3352019-03-25 10:58:15 +00001404 if (!prefix)
1405 {
1406 if (!FcStrIsAbsoluteFilename (path) && path[0] != '~')
1407 FcConfigMessage (parse, FcSevereWarning, "Use of ambiguous path in <%s> element. please add prefix=\"cwd\" if current behavior is desired.", FcElementReverseMap (parse->pstack->element));
1408 }
Akira TAGOHa563a182019-01-28 09:59:29 +00001409 }
Akira TAGOHa563a182019-01-28 09:59:29 +00001410#endif
Akira TAGOH83840fd2019-06-24 08:07:27 +00001411 if (parent)
1412 {
1413 retval = FcStrBuildFilename (parent, path, NULL);
Akira TAGOH1a0391c2019-07-23 10:54:36 +00001414 FcStrFree (parent);
Akira TAGOH83840fd2019-06-24 08:07:27 +00001415 }
1416 else
1417 {
1418 retval = FcStrdup (path);
1419 }
Akira TAGOH6f27f422021-03-29 21:25:21 +09001420 if (!e)
1421 e = FcStrSetCreate ();
1422 else
1423 {
1424 FcChar8 *s;
1425 int i;
Akira TAGOHa563a182019-01-28 09:59:29 +00001426
Akira TAGOH6f27f422021-03-29 21:25:21 +09001427 for (i = 0; i < e->num; i++)
1428 {
1429 s = FcStrBuildFilename (e->strs[i], path, NULL);
1430 FcStrFree (e->strs[i]);
1431 e->strs[i] = s;
1432 }
1433 }
1434 if (!FcStrSetInsert (e, retval, 0))
1435 {
1436 FcStrSetDestroy (e);
1437 e = NULL;
1438 }
1439 FcStrFree (retval);
1440
1441 return e;
Akira TAGOHa563a182019-01-28 09:59:29 +00001442}
1443
Keith Packardc2e7c612002-02-18 22:29:28 +00001444static void
1445FcStartElement(void *userData, const XML_Char *name, const XML_Char **attr)
1446{
1447 FcConfigParse *parse = userData;
1448 FcElement element;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001449
Keith Packardc2e7c612002-02-18 22:29:28 +00001450 element = FcElementMap (name);
1451 if (element == FcElementUnknown)
Keith Packard179c3992002-05-21 17:06:22 +00001452 FcConfigMessage (parse, FcSevereWarning, "unknown element \"%s\"", name);
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001453
Keith Packardc2e7c612002-02-18 22:29:28 +00001454 if (!FcPStackPush (parse, element, attr))
1455 {
Keith Packard179c3992002-05-21 17:06:22 +00001456 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00001457 return;
1458 }
1459 return;
1460}
1461
1462static void
Keith Packard179c3992002-05-21 17:06:22 +00001463FcParseRescan (FcConfigParse *parse)
1464{
1465 int n = FcVStackElements (parse);
1466 while (n-- > 0)
1467 {
1468 FcVStack *v = FcVStackFetch (parse, n);
1469 if (v->tag != FcVStackInteger)
1470 FcConfigMessage (parse, FcSevereWarning, "non-integer rescan");
1471 else
1472 parse->config->rescanInterval = v->u.integer;
1473 }
1474}
1475
1476static void
Keith Packardc2e7c612002-02-18 22:29:28 +00001477FcParseInt (FcConfigParse *parse)
1478{
1479 FcChar8 *s, *end;
1480 int l;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001481
Keith Packardc2e7c612002-02-18 22:29:28 +00001482 if (!parse->pstack)
1483 return;
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001484 s = FcStrBufDoneStatic (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00001485 if (!s)
1486 {
Keith Packard179c3992002-05-21 17:06:22 +00001487 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00001488 return;
1489 }
1490 end = 0;
1491 l = (int) strtol ((char *) s, (char **)&end, 0);
1492 if (end != s + strlen ((char *) s))
Keith Packard179c3992002-05-21 17:06:22 +00001493 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid integer", s);
Keith Packardc2e7c612002-02-18 22:29:28 +00001494 else
1495 FcVStackPushInteger (parse, l);
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001496 FcStrBufDestroy (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00001497}
1498
Keith Packard223c0282002-06-26 16:11:29 +00001499/*
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001500 * idea copied from glib g_ascii_strtod with
1501 * permission of the author (Alexander Larsson)
Keith Packard223c0282002-06-26 16:11:29 +00001502 */
1503
1504#include <locale.h>
1505
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001506static double
Keith Packard223c0282002-06-26 16:11:29 +00001507FcStrtod (char *s, char **end)
1508{
Akira TAGOH7441dbe2016-05-27 11:16:09 +09001509#ifndef __BIONIC__
Keith Packard223c0282002-06-26 16:11:29 +00001510 struct lconv *locale_data;
Akira TAGOH7441dbe2016-05-27 11:16:09 +09001511#endif
1512 const char *decimal_point;
1513 int dlen;
Keith Packard223c0282002-06-26 16:11:29 +00001514 char *dot;
1515 double v;
1516
1517 /*
1518 * Have to swap the decimal point to match the current locale
1519 * if that locale doesn't use 0x2e
1520 */
Akira TAGOH7441dbe2016-05-27 11:16:09 +09001521#ifndef __BIONIC__
1522 locale_data = localeconv ();
1523 decimal_point = locale_data->decimal_point;
1524 dlen = strlen (decimal_point);
1525#else
1526 decimal_point = ".";
1527 dlen = 1;
1528#endif
1529
Keith Packard223c0282002-06-26 16:11:29 +00001530 if ((dot = strchr (s, 0x2e)) &&
Akira TAGOH7441dbe2016-05-27 11:16:09 +09001531 (decimal_point[0] != 0x2e ||
1532 decimal_point[1] != 0))
Keith Packard223c0282002-06-26 16:11:29 +00001533 {
1534 char buf[128];
1535 int slen = strlen (s);
Akira TAGOH6715a142022-11-25 21:15:32 +09001536
Patrick Lam67accef2005-09-22 23:45:53 +00001537 if (slen + dlen > (int) sizeof (buf))
Keith Packard223c0282002-06-26 16:11:29 +00001538 {
1539 if (end)
1540 *end = s;
1541 v = 0;
1542 }
1543 else
1544 {
1545 char *buf_end;
1546 /* mantissa */
1547 strncpy (buf, s, dot - s);
1548 /* decimal point */
Akira TAGOH7441dbe2016-05-27 11:16:09 +09001549 strcpy (buf + (dot - s), decimal_point);
Keith Packard223c0282002-06-26 16:11:29 +00001550 /* rest of number */
1551 strcpy (buf + (dot - s) + dlen, dot + 1);
1552 buf_end = 0;
1553 v = strtod (buf, &buf_end);
Roozbeh Pournader344a0e32003-11-10 17:34:36 +00001554 if (buf_end) {
1555 buf_end = s + (buf_end - buf);
1556 if (buf_end > dot)
1557 buf_end -= dlen - 1;
1558 }
Keith Packard223c0282002-06-26 16:11:29 +00001559 if (end)
1560 *end = buf_end;
1561 }
1562 }
1563 else
1564 v = strtod (s, end);
1565 return v;
1566}
1567
Keith Packardc2e7c612002-02-18 22:29:28 +00001568static void
1569FcParseDouble (FcConfigParse *parse)
1570{
1571 FcChar8 *s, *end;
1572 double d;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001573
Keith Packardc2e7c612002-02-18 22:29:28 +00001574 if (!parse->pstack)
1575 return;
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001576 s = FcStrBufDoneStatic (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00001577 if (!s)
1578 {
Keith Packard179c3992002-05-21 17:06:22 +00001579 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00001580 return;
1581 }
1582 end = 0;
Keith Packard223c0282002-06-26 16:11:29 +00001583 d = FcStrtod ((char *) s, (char **)&end);
Keith Packardc2e7c612002-02-18 22:29:28 +00001584 if (end != s + strlen ((char *) s))
Keith Packard179c3992002-05-21 17:06:22 +00001585 FcConfigMessage (parse, FcSevereError, "\"%s\": not a valid double", s);
Keith Packardc2e7c612002-02-18 22:29:28 +00001586 else
1587 FcVStackPushDouble (parse, d);
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001588 FcStrBufDestroy (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00001589}
1590
1591static void
1592FcParseString (FcConfigParse *parse, FcVStackTag tag)
1593{
1594 FcChar8 *s;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001595
Keith Packardc2e7c612002-02-18 22:29:28 +00001596 if (!parse->pstack)
1597 return;
1598 s = FcStrBufDone (&parse->pstack->str);
1599 if (!s)
1600 {
Keith Packard179c3992002-05-21 17:06:22 +00001601 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00001602 return;
1603 }
1604 if (!FcVStackPushString (parse, tag, s))
1605 FcStrFree (s);
1606}
1607
1608static void
Behdad Esfahbod51b00442012-12-29 23:58:38 -05001609FcParseName (FcConfigParse *parse)
1610{
1611 const FcChar8 *kind_string;
1612 FcMatchKind kind;
1613 FcChar8 *s;
1614 FcObject object;
1615
1616 kind_string = FcConfigGetAttribute (parse, "target");
1617 if (!kind_string)
1618 kind = FcMatchDefault;
1619 else
1620 {
1621 if (!strcmp ((char *) kind_string, "pattern"))
1622 kind = FcMatchPattern;
1623 else if (!strcmp ((char *) kind_string, "font"))
1624 kind = FcMatchFont;
1625 else if (!strcmp ((char *) kind_string, "default"))
1626 kind = FcMatchDefault;
1627 else
1628 {
1629 FcConfigMessage (parse, FcSevereWarning, "invalid name target \"%s\"", kind_string);
1630 return;
1631 }
1632 }
1633
1634 if (!parse->pstack)
1635 return;
1636 s = FcStrBufDone (&parse->pstack->str);
1637 if (!s)
1638 {
1639 FcConfigMessage (parse, FcSevereError, "out of memory");
1640 return;
1641 }
1642 object = FcObjectFromName ((const char *) s);
1643
1644 FcVStackPushName (parse, kind, object);
1645
1646 FcStrFree (s);
1647}
1648
1649static void
Keith Packardc2e7c612002-02-18 22:29:28 +00001650FcParseMatrix (FcConfigParse *parse)
1651{
Behdad Esfahbod4f676742012-12-29 21:39:06 -05001652 FcExprMatrix m;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001653
Behdad Esfahbod4f676742012-12-29 21:39:06 -05001654 m.yy = FcPopExpr (parse);
1655 m.yx = FcPopExpr (parse);
1656 m.xy = FcPopExpr (parse);
1657 m.xx = FcPopExpr (parse);
1658
Akira TAGOH699d6e42019-01-23 05:59:24 +00001659 if (!m.yy || !m.yx || !m.xy || !m.xx)
1660 {
1661 FcConfigMessage (parse, FcSevereWarning, "Missing values in matrix element");
1662 return;
1663 }
Behdad Esfahbod4f676742012-12-29 21:39:06 -05001664 if (FcPopExpr (parse))
1665 FcConfigMessage (parse, FcSevereError, "wrong number of matrix elements");
Keith Packardc2e7c612002-02-18 22:29:28 +00001666 else
Behdad Esfahbod4f676742012-12-29 21:39:06 -05001667 FcVStackPushMatrix (parse, &m);
Keith Packardc2e7c612002-02-18 22:29:28 +00001668}
1669
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001670static void
1671FcParseRange (FcConfigParse *parse)
1672{
1673 FcVStack *vstack;
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001674 FcRange *r;
1675 FcChar32 n[2] = {0, 0};
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001676 int count = 1;
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001677 double d[2] = {0.0L, 0.0L};
1678 FcBool dflag = FcFalse;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001679
1680 while ((vstack = FcVStackPeek (parse)))
1681 {
1682 if (count < 0)
1683 {
1684 FcConfigMessage (parse, FcSevereError, "too many elements in range");
1685 return;
1686 }
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05001687 switch ((int) vstack->tag) {
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001688 case FcVStackInteger:
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001689 if (dflag)
1690 d[count] = (double)vstack->u.integer;
1691 else
1692 n[count] = vstack->u.integer;
1693 break;
1694 case FcVStackDouble:
1695 if (count == 0 && !dflag)
1696 d[1] = (double)n[1];
1697 d[count] = vstack->u._double;
1698 dflag = FcTrue;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001699 break;
1700 default:
1701 FcConfigMessage (parse, FcSevereError, "invalid element in range");
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001702 if (dflag)
1703 d[count] = 0.0L;
1704 else
1705 n[count] = 0;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001706 break;
1707 }
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001708 count--;
1709 FcVStackPopAndDestroy (parse);
1710 }
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001711 if (count >= 0)
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001712 {
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001713 FcConfigMessage (parse, FcSevereError, "invalid range");
1714 return;
1715 }
1716 if (dflag)
1717 {
1718 if (d[0] > d[1])
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001719 {
1720 FcConfigMessage (parse, FcSevereError, "invalid range");
1721 return;
1722 }
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001723 r = FcRangeCreateDouble (d[0], d[1]);
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001724 }
1725 else
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001726 {
1727 if (n[0] > n[1])
1728 {
1729 FcConfigMessage (parse, FcSevereError, "invalid range");
1730 return;
1731 }
1732 r = FcRangeCreateInteger (n[0], n[1]);
1733 }
1734 FcVStackPushRange (parse, r);
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001735}
1736
Keith Packardc2e7c612002-02-18 22:29:28 +00001737static FcBool
Harald Fernengelfe8e8a12008-12-28 03:23:58 -05001738FcConfigLexBool (FcConfigParse *parse, const FcChar8 *bool_)
Keith Packard24330d22002-02-14 23:34:13 +00001739{
Keith Packardca60d2b2005-01-28 23:55:14 +00001740 FcBool result = FcFalse;
1741
Harald Fernengelfe8e8a12008-12-28 03:23:58 -05001742 if (!FcNameBool (bool_, &result))
Keith Packardca60d2b2005-01-28 23:55:14 +00001743 FcConfigMessage (parse, FcSevereWarning, "\"%s\" is not known boolean",
Harald Fernengelfe8e8a12008-12-28 03:23:58 -05001744 bool_);
Keith Packardca60d2b2005-01-28 23:55:14 +00001745 return result;
Keith Packard24330d22002-02-14 23:34:13 +00001746}
1747
Keith Packardc2e7c612002-02-18 22:29:28 +00001748static void
1749FcParseBool (FcConfigParse *parse)
Keith Packard24330d22002-02-14 23:34:13 +00001750{
Keith Packardc2e7c612002-02-18 22:29:28 +00001751 FcChar8 *s;
Keith Packard24330d22002-02-14 23:34:13 +00001752
Keith Packardc2e7c612002-02-18 22:29:28 +00001753 if (!parse->pstack)
1754 return;
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001755 s = FcStrBufDoneStatic (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00001756 if (!s)
Keith Packard24330d22002-02-14 23:34:13 +00001757 {
Keith Packard179c3992002-05-21 17:06:22 +00001758 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00001759 return;
Keith Packard24330d22002-02-14 23:34:13 +00001760 }
Keith Packardca60d2b2005-01-28 23:55:14 +00001761 FcVStackPushBool (parse, FcConfigLexBool (parse, s));
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001762 FcStrBufDestroy (&parse->pstack->str);
Keith Packard24330d22002-02-14 23:34:13 +00001763}
1764
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001765static void
1766FcParseCharSet (FcConfigParse *parse)
1767{
1768 FcVStack *vstack;
1769 FcCharSet *charset = FcCharSetCreate ();
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001770 FcChar32 i, begin, end;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001771 int n = 0;
1772
1773 while ((vstack = FcVStackPeek (parse)))
1774 {
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05001775 switch ((int) vstack->tag) {
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001776 case FcVStackInteger:
1777 if (!FcCharSetAddChar (charset, vstack->u.integer))
1778 {
1779 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", vstack->u.integer);
1780 }
1781 else
1782 n++;
1783 break;
1784 case FcVStackRange:
Behdad Esfahbod5bad26c2014-08-20 16:07:26 -04001785 begin = (FcChar32) vstack->u.range->begin;
1786 end = (FcChar32) vstack->u.range->end;
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001787
1788 if (begin <= end)
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001789 {
Akira TAGOH3cd573f2013-11-20 18:44:59 +09001790 for (i = begin; i <= end; i++)
Behdad Esfahbod43bf6592010-12-28 02:55:31 -06001791 {
1792 if (!FcCharSetAddChar (charset, i))
1793 {
1794 FcConfigMessage (parse, FcSevereWarning, "invalid character: 0x%04x", i);
1795 }
1796 else
1797 n++;
1798 }
Akira TAGOH857b7ef2010-12-06 12:10:17 +09001799 }
1800 break;
1801 default:
1802 FcConfigMessage (parse, FcSevereError, "invalid element in charset");
1803 break;
1804 }
1805 FcVStackPopAndDestroy (parse);
1806 }
1807 if (n > 0)
1808 FcVStackPushCharSet (parse, charset);
1809 else
1810 FcCharSetDestroy (charset);
1811}
1812
Akira TAGOH3c862aa2010-12-06 12:38:18 +09001813static void
1814FcParseLangSet (FcConfigParse *parse)
1815{
1816 FcVStack *vstack;
1817 FcLangSet *langset = FcLangSetCreate ();
1818 int n = 0;
1819
1820 while ((vstack = FcVStackPeek (parse)))
1821 {
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05001822 switch ((int) vstack->tag) {
Akira TAGOH3c862aa2010-12-06 12:38:18 +09001823 case FcVStackString:
1824 if (!FcLangSetAdd (langset, vstack->u.string))
1825 {
1826 FcConfigMessage (parse, FcSevereWarning, "invalid langset: %s", vstack->u.string);
1827 }
1828 else
1829 n++;
1830 break;
1831 default:
1832 FcConfigMessage (parse, FcSevereError, "invalid element in langset");
1833 break;
1834 }
1835 FcVStackPopAndDestroy (parse);
1836 }
1837 if (n > 0)
1838 FcVStackPushLangSet (parse, langset);
1839 else
1840 FcLangSetDestroy (langset);
1841}
1842
Keith Packard681bb372007-10-25 22:30:49 -07001843static FcBool
1844FcConfigLexBinding (FcConfigParse *parse,
1845 const FcChar8 *binding_string,
1846 FcValueBinding *binding_ret)
1847{
1848 FcValueBinding binding;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04001849
Keith Packard681bb372007-10-25 22:30:49 -07001850 if (!binding_string)
1851 binding = FcValueBindingWeak;
1852 else
1853 {
1854 if (!strcmp ((char *) binding_string, "weak"))
1855 binding = FcValueBindingWeak;
1856 else if (!strcmp ((char *) binding_string, "strong"))
1857 binding = FcValueBindingStrong;
1858 else if (!strcmp ((char *) binding_string, "same"))
1859 binding = FcValueBindingSame;
1860 else
1861 {
1862 FcConfigMessage (parse, FcSevereWarning, "invalid binding \"%s\"", binding_string);
1863 return FcFalse;
1864 }
1865 }
1866 *binding_ret = binding;
1867 return FcTrue;
1868}
1869
Keith Packardc2e7c612002-02-18 22:29:28 +00001870static void
1871FcParseFamilies (FcConfigParse *parse, FcVStackTag tag)
Keith Packard24330d22002-02-14 23:34:13 +00001872{
Keith Packardc2e7c612002-02-18 22:29:28 +00001873 FcVStack *vstack;
1874 FcExpr *left, *expr = 0, *new;
Keith Packard24330d22002-02-14 23:34:13 +00001875
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001876 while ((vstack = FcVStackPeek (parse)))
Keith Packard24330d22002-02-14 23:34:13 +00001877 {
Keith Packardc2e7c612002-02-18 22:29:28 +00001878 if (vstack->tag != FcVStackFamily)
Keith Packard24330d22002-02-14 23:34:13 +00001879 {
Keith Packard179c3992002-05-21 17:06:22 +00001880 FcConfigMessage (parse, FcSevereWarning, "non-family");
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001881 FcVStackPopAndDestroy (parse);
Keith Packard179c3992002-05-21 17:06:22 +00001882 continue;
Keith Packardc2e7c612002-02-18 22:29:28 +00001883 }
1884 left = vstack->u.expr;
1885 vstack->tag = FcVStackNone;
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001886 FcVStackPopAndDestroy (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00001887 if (expr)
1888 {
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04001889 new = FcExprCreateOp (parse->config, left, FcOpComma, expr);
Keith Packardc2e7c612002-02-18 22:29:28 +00001890 if (!new)
Keith Packard24330d22002-02-14 23:34:13 +00001891 {
Keith Packard179c3992002-05-21 17:06:22 +00001892 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00001893 FcExprDestroy (left);
1894 FcExprDestroy (expr);
Keith Packard24330d22002-02-14 23:34:13 +00001895 break;
Keith Packard24330d22002-02-14 23:34:13 +00001896 }
Keith Packardc2e7c612002-02-18 22:29:28 +00001897 expr = new;
Keith Packard24330d22002-02-14 23:34:13 +00001898 }
1899 else
Keith Packardc2e7c612002-02-18 22:29:28 +00001900 expr = left;
Keith Packard24330d22002-02-14 23:34:13 +00001901 }
Keith Packard24330d22002-02-14 23:34:13 +00001902 if (expr)
Keith Packardc2e7c612002-02-18 22:29:28 +00001903 {
1904 if (!FcVStackPushExpr (parse, tag, expr))
1905 {
Keith Packard179c3992002-05-21 17:06:22 +00001906 FcConfigMessage (parse, FcSevereError, "out of memory");
Patrick Lamf2fb9852006-02-21 15:50:19 +00001907 FcExprDestroy (expr);
Keith Packardc2e7c612002-02-18 22:29:28 +00001908 }
1909 }
Keith Packard24330d22002-02-14 23:34:13 +00001910}
1911
Keith Packardc2e7c612002-02-18 22:29:28 +00001912static void
1913FcParseFamily (FcConfigParse *parse)
Keith Packard24330d22002-02-14 23:34:13 +00001914{
Keith Packardc2e7c612002-02-18 22:29:28 +00001915 FcChar8 *s;
1916 FcExpr *expr;
1917
1918 if (!parse->pstack)
1919 return;
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001920 s = FcStrBufDoneStatic (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00001921 if (!s)
1922 {
Keith Packard179c3992002-05-21 17:06:22 +00001923 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00001924 return;
1925 }
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04001926 expr = FcExprCreateString (parse->config, s);
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04001927 FcStrBufDestroy (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00001928 if (expr)
1929 FcVStackPushExpr (parse, FcVStackFamily, expr);
1930}
1931
1932static void
1933FcParseAlias (FcConfigParse *parse)
1934{
Keith Packard179c3992002-05-21 17:06:22 +00001935 FcExpr *family = 0, *accept = 0, *prefer = 0, *def = 0, *new = 0;
Akira TAGOHd420e1d2013-07-04 19:51:03 +09001936 FcEdit *edit = 0;
Keith Packardc2e7c612002-02-18 22:29:28 +00001937 FcVStack *vstack;
Akira TAGOHd420e1d2013-07-04 19:51:03 +09001938 FcRule *rule = NULL, *r;
Keith Packard681bb372007-10-25 22:30:49 -07001939 FcValueBinding binding;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09001940 int n;
Keith Packard24330d22002-02-14 23:34:13 +00001941
Keith Packard681bb372007-10-25 22:30:49 -07001942 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
1943 return;
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001944 while ((vstack = FcVStackPeek (parse)))
Keith Packard24330d22002-02-14 23:34:13 +00001945 {
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05001946 switch ((int) vstack->tag) {
Keith Packardc2e7c612002-02-18 22:29:28 +00001947 case FcVStackFamily:
1948 if (family)
Keith Packard179c3992002-05-21 17:06:22 +00001949 {
Akira TAGOH375cdbc2012-08-16 20:33:12 +09001950 FcConfigMessage (parse, FcSevereWarning, "Having multiple <family> in <alias> isn't supported and may not work as expected");
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04001951 new = FcExprCreateOp (parse->config, vstack->u.expr, FcOpComma, family);
Keith Packard179c3992002-05-21 17:06:22 +00001952 if (!new)
1953 FcConfigMessage (parse, FcSevereError, "out of memory");
1954 else
1955 family = new;
1956 }
1957 else
1958 new = vstack->u.expr;
1959 if (new)
1960 {
1961 family = new;
1962 vstack->tag = FcVStackNone;
1963 }
Keith Packardc2e7c612002-02-18 22:29:28 +00001964 break;
1965 case FcVStackPrefer:
1966 if (prefer)
1967 FcExprDestroy (prefer);
1968 prefer = vstack->u.expr;
1969 vstack->tag = FcVStackNone;
1970 break;
1971 case FcVStackAccept:
1972 if (accept)
1973 FcExprDestroy (accept);
1974 accept = vstack->u.expr;
1975 vstack->tag = FcVStackNone;
1976 break;
1977 case FcVStackDefault:
1978 if (def)
1979 FcExprDestroy (def);
1980 def = vstack->u.expr;
1981 vstack->tag = FcVStackNone;
1982 break;
Akira TAGOHddefa502012-04-04 14:47:57 +09001983 case FcVStackTest:
Akira TAGOHd420e1d2013-07-04 19:51:03 +09001984 if (rule)
1985 {
1986 r = FcRuleCreate (FcRuleTest, vstack->u.test);
1987 r->next = rule;
1988 rule = r;
1989 }
1990 else
1991 rule = FcRuleCreate (FcRuleTest, vstack->u.test);
Akira TAGOHddefa502012-04-04 14:47:57 +09001992 vstack->tag = FcVStackNone;
1993 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00001994 default:
Keith Packard179c3992002-05-21 17:06:22 +00001995 FcConfigMessage (parse, FcSevereWarning, "bad alias");
Keith Packardc2e7c612002-02-18 22:29:28 +00001996 break;
1997 }
Behdad Esfahbod39861b72009-03-12 12:22:37 -04001998 FcVStackPopAndDestroy (parse);
Keith Packard24330d22002-02-14 23:34:13 +00001999 }
Keith Packardccb3e932002-02-15 06:01:28 +00002000 if (!family)
Keith Packardc2e7c612002-02-18 22:29:28 +00002001 {
Keith Packard179c3992002-05-21 17:06:22 +00002002 FcConfigMessage (parse, FcSevereError, "missing family in alias");
2003 if (prefer)
2004 FcExprDestroy (prefer);
2005 if (accept)
2006 FcExprDestroy (accept);
2007 if (def)
2008 FcExprDestroy (def);
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002009 if (rule)
2010 FcRuleDestroy (rule);
Keith Packardc2e7c612002-02-18 22:29:28 +00002011 return;
2012 }
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002013 if (!prefer &&
2014 !accept &&
2015 !def)
2016 {
2017 FcExprDestroy (family);
Akira TAGOH9f1b92f2018-07-25 13:41:47 +09002018 if (rule)
2019 FcRuleDestroy (rule);
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002020 return;
2021 }
2022 else
2023 {
2024 FcTest *t = FcTestCreate (parse, FcMatchPattern,
2025 FcQualAny,
2026 (FcChar8 *) FC_FAMILY,
2027 FC_OP (FcOpEqual, FcOpFlagIgnoreBlanks),
2028 family);
2029 if (rule)
2030 {
2031 for (r = rule; r->next; r = r->next);
2032 r->next = FcRuleCreate (FcRuleTest, t);
2033 r = r->next;
2034 }
2035 else
2036 {
2037 r = rule = FcRuleCreate (FcRuleTest, t);
2038 }
2039 }
Keith Packard24330d22002-02-14 23:34:13 +00002040 if (prefer)
2041 {
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04002042 edit = FcEditCreate (parse,
Keith Packard2d3387f2006-08-30 21:59:53 -07002043 FC_FAMILY_OBJECT,
Keith Packard24330d22002-02-14 23:34:13 +00002044 FcOpPrepend,
Keith Packard6fff2cd2002-07-31 01:36:37 +00002045 prefer,
Keith Packard681bb372007-10-25 22:30:49 -07002046 binding);
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002047 if (!edit)
Keith Packardc2e7c612002-02-18 22:29:28 +00002048 FcExprDestroy (prefer);
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002049 else
2050 {
2051 r->next = FcRuleCreate (FcRuleEdit, edit);
2052 r = r->next;
2053 }
Keith Packard24330d22002-02-14 23:34:13 +00002054 }
2055 if (accept)
2056 {
Keith Packardca60d2b2005-01-28 23:55:14 +00002057 edit = FcEditCreate (parse,
Keith Packard2d3387f2006-08-30 21:59:53 -07002058 FC_FAMILY_OBJECT,
Keith Packard24330d22002-02-14 23:34:13 +00002059 FcOpAppend,
Keith Packard6fff2cd2002-07-31 01:36:37 +00002060 accept,
Keith Packard681bb372007-10-25 22:30:49 -07002061 binding);
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002062 if (!edit)
Keith Packardc2e7c612002-02-18 22:29:28 +00002063 FcExprDestroy (accept);
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002064 else
2065 {
2066 r->next = FcRuleCreate (FcRuleEdit, edit);
2067 r = r->next;
2068 }
Keith Packard24330d22002-02-14 23:34:13 +00002069 }
2070 if (def)
2071 {
Keith Packardca60d2b2005-01-28 23:55:14 +00002072 edit = FcEditCreate (parse,
Keith Packard2d3387f2006-08-30 21:59:53 -07002073 FC_FAMILY_OBJECT,
Keith Packard6fff2cd2002-07-31 01:36:37 +00002074 FcOpAppendLast,
2075 def,
Keith Packard681bb372007-10-25 22:30:49 -07002076 binding);
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002077 if (!edit)
Keith Packardc2e7c612002-02-18 22:29:28 +00002078 FcExprDestroy (def);
Akira TAGOHddefa502012-04-04 14:47:57 +09002079 else
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002080 {
2081 r->next = FcRuleCreate (FcRuleEdit, edit);
2082 r = r->next;
2083 }
Keith Packard24330d22002-02-14 23:34:13 +00002084 }
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09002085 if ((n = FcRuleSetAdd (parse->ruleset, rule, FcMatchPattern)) == -1)
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002086 FcRuleDestroy (rule);
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09002087 else
2088 if (parse->config->maxObjects < n)
2089 parse->config->maxObjects = n;
2090}
2091
2092static void
2093FcParseDescription (FcConfigParse *parse)
2094{
2095 const FcChar8 *domain;
2096 FcChar8 *desc;
2097
2098 domain = FcConfigGetAttribute (parse, "domain");
2099 desc = FcStrBufDone (&parse->pstack->str);
2100 if (!desc)
2101 {
2102 FcConfigMessage (parse, FcSevereError, "out of memory");
2103 return;
2104 }
2105 FcRuleSetAddDescription (parse->ruleset, domain, desc);
2106
2107 FcStrFree (desc);
Keith Packard24330d22002-02-14 23:34:13 +00002108}
2109
Akira TAGOHa563a182019-01-28 09:59:29 +00002110static void
2111FcParseRemapDir (FcConfigParse *parse)
2112{
Akira TAGOH2e8ce632019-01-31 10:17:47 +00002113 const FcChar8 *path, *attr, *data, *salt;
Akira TAGOH6f27f422021-03-29 21:25:21 +09002114 FcStrSet *prefix_dirs = NULL;
Akira TAGOHa563a182019-01-28 09:59:29 +00002115
2116 data = FcStrBufDoneStatic (&parse->pstack->str);
2117 if (!data)
2118 {
2119 FcConfigMessage (parse, FcSevereError, "out of memory");
2120 return;
2121 }
Akira TAGOHcb1df8c2019-04-02 09:37:49 +00002122 if (data[0] == 0)
2123 {
2124 FcConfigMessage (parse, FcSevereWarning, "empty font directory name for remap ignored");
2125 return;
2126 }
Akira TAGOHa563a182019-01-28 09:59:29 +00002127 path = FcConfigGetAttribute (parse, "as-path");
2128 if (!path)
2129 {
2130 FcConfigMessage (parse, FcSevereWarning, "Missing as-path in remap-dir");
2131 return;
2132 }
2133 attr = FcConfigGetAttribute (parse, "prefix");
Akira TAGOH2e8ce632019-01-31 10:17:47 +00002134 salt = FcConfigGetAttribute (parse, "salt");
Akira TAGOH6f27f422021-03-29 21:25:21 +09002135 prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2136 if (prefix_dirs)
Akira TAGOHcb1df8c2019-04-02 09:37:49 +00002137 {
Akira TAGOH6f27f422021-03-29 21:25:21 +09002138 FcStrList *l = FcStrListCreate (prefix_dirs);
2139 FcChar8 *prefix;
Akira TAGOHa563a182019-01-28 09:59:29 +00002140
Akira TAGOH6f27f422021-03-29 21:25:21 +09002141 FcStrSetDestroy (prefix_dirs);
2142 while ((prefix = FcStrListNext (l)))
2143 {
2144 if (!prefix || prefix[0] == 0)
2145 {
2146 /* nop */
2147 }
2148 else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
2149 {
2150 if (!FcConfigAddFontDir (parse->config, prefix, path, salt))
2151 FcConfigMessage (parse, FcSevereError, "out of memory; cannot create remap data for %s as %s", prefix, path);
2152 }
2153 FcStrBufDestroy (&parse->pstack->str);
2154 }
2155 FcStrListDone (l);
2156 }
Akira TAGOHa563a182019-01-28 09:59:29 +00002157}
2158
Akira TAGOHdef1d002019-01-31 07:52:09 +00002159static void
2160FcParseResetDirs (FcConfigParse *parse)
2161{
2162 if (!parse->scanOnly)
2163 {
2164 if (!FcConfigResetFontDirs (parse->config))
2165 FcConfigMessage (parse, FcSevereError, "Unable to reset fonts dirs");
2166 }
2167}
2168
Keith Packardc2e7c612002-02-18 22:29:28 +00002169static FcExpr *
2170FcPopExpr (FcConfigParse *parse)
Keith Packard24330d22002-02-14 23:34:13 +00002171{
Behdad Esfahbod39861b72009-03-12 12:22:37 -04002172 FcVStack *vstack = FcVStackPeek (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00002173 FcExpr *expr = 0;
2174 if (!vstack)
2175 return 0;
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05002176 switch ((int) vstack->tag) {
Keith Packardc2e7c612002-02-18 22:29:28 +00002177 case FcVStackNone:
2178 break;
2179 case FcVStackString:
2180 case FcVStackFamily:
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002181 expr = FcExprCreateString (parse->config, vstack->u.string);
Keith Packardc2e7c612002-02-18 22:29:28 +00002182 break;
Behdad Esfahbod51b00442012-12-29 23:58:38 -05002183 case FcVStackName:
2184 expr = FcExprCreateName (parse->config, vstack->u.name);
Keith Packardbbbaac32002-02-22 18:54:07 +00002185 break;
2186 case FcVStackConstant:
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002187 expr = FcExprCreateConst (parse->config, vstack->u.string);
Keith Packardbbbaac32002-02-22 18:54:07 +00002188 break;
Carl Worth34cd0512003-08-15 19:45:20 +00002189 case FcVStackGlob:
2190 /* XXX: What's the correct action here? (CDW) */
2191 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00002192 case FcVStackPrefer:
2193 case FcVStackAccept:
2194 case FcVStackDefault:
2195 expr = vstack->u.expr;
2196 vstack->tag = FcVStackNone;
2197 break;
2198 case FcVStackInteger:
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002199 expr = FcExprCreateInteger (parse->config, vstack->u.integer);
Keith Packardc2e7c612002-02-18 22:29:28 +00002200 break;
2201 case FcVStackDouble:
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002202 expr = FcExprCreateDouble (parse->config, vstack->u._double);
Keith Packardc2e7c612002-02-18 22:29:28 +00002203 break;
2204 case FcVStackMatrix:
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002205 expr = FcExprCreateMatrix (parse->config, vstack->u.matrix);
Keith Packardc2e7c612002-02-18 22:29:28 +00002206 break;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09002207 case FcVStackRange:
Akira TAGOH3cd573f2013-11-20 18:44:59 +09002208 expr = FcExprCreateRange (parse->config, vstack->u.range);
Akira TAGOH857b7ef2010-12-06 12:10:17 +09002209 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00002210 case FcVStackBool:
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002211 expr = FcExprCreateBool (parse->config, vstack->u.bool_);
Keith Packardc2e7c612002-02-18 22:29:28 +00002212 break;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09002213 case FcVStackCharSet:
2214 expr = FcExprCreateCharSet (parse->config, vstack->u.charset);
2215 break;
Akira TAGOH3c862aa2010-12-06 12:38:18 +09002216 case FcVStackLangSet:
2217 expr = FcExprCreateLangSet (parse->config, vstack->u.langset);
2218 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00002219 case FcVStackTest:
2220 break;
2221 case FcVStackExpr:
2222 expr = vstack->u.expr;
Keith Packard8ec077f2002-06-02 19:51:36 +00002223 vstack->tag = FcVStackNone;
Keith Packardc2e7c612002-02-18 22:29:28 +00002224 break;
2225 case FcVStackEdit:
2226 break;
Keith Packard4f27c1c2004-12-04 19:41:10 +00002227 default:
2228 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00002229 }
Behdad Esfahbod39861b72009-03-12 12:22:37 -04002230 FcVStackPopAndDestroy (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00002231 return expr;
2232}
Keith Packard24330d22002-02-14 23:34:13 +00002233
Keith Packard3f7653c2003-04-15 23:38:06 +00002234/*
2235 * This builds a tree of binary operations. Note
2236 * that every operator is defined so that if only
2237 * a single operand is contained, the value of the
2238 * whole expression is the value of the operand.
2239 *
2240 * This code reduces in that case to returning that
2241 * operand.
2242 */
Keith Packardc2e7c612002-02-18 22:29:28 +00002243static FcExpr *
Keith Packard3f7653c2003-04-15 23:38:06 +00002244FcPopBinary (FcConfigParse *parse, FcOp op)
Keith Packardc2e7c612002-02-18 22:29:28 +00002245{
2246 FcExpr *left, *expr = 0, *new;
2247
2248 while ((left = FcPopExpr (parse)))
Keith Packard24330d22002-02-14 23:34:13 +00002249 {
Keith Packardc2e7c612002-02-18 22:29:28 +00002250 if (expr)
Keith Packard24330d22002-02-14 23:34:13 +00002251 {
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002252 new = FcExprCreateOp (parse->config, left, op, expr);
Keith Packardc2e7c612002-02-18 22:29:28 +00002253 if (!new)
2254 {
Keith Packard179c3992002-05-21 17:06:22 +00002255 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00002256 FcExprDestroy (left);
2257 FcExprDestroy (expr);
Patrick Lam2de24632006-04-11 16:54:24 +00002258 return 0;
Keith Packardc2e7c612002-02-18 22:29:28 +00002259 }
2260 expr = new;
Keith Packard24330d22002-02-14 23:34:13 +00002261 }
2262 else
Keith Packardc2e7c612002-02-18 22:29:28 +00002263 expr = left;
Keith Packard24330d22002-02-14 23:34:13 +00002264 }
Keith Packardc2e7c612002-02-18 22:29:28 +00002265 return expr;
2266}
2267
2268static void
Keith Packard3f7653c2003-04-15 23:38:06 +00002269FcParseBinary (FcConfigParse *parse, FcOp op)
Keith Packardc2e7c612002-02-18 22:29:28 +00002270{
Keith Packard3f7653c2003-04-15 23:38:06 +00002271 FcExpr *expr = FcPopBinary (parse, op);
2272 if (expr)
2273 FcVStackPushExpr (parse, FcVStackExpr, expr);
2274}
2275
2276/*
2277 * This builds a a unary operator, it consumes only
2278 * a single operand
2279 */
2280
2281static FcExpr *
2282FcPopUnary (FcConfigParse *parse, FcOp op)
2283{
2284 FcExpr *operand, *new = 0;
2285
2286 if ((operand = FcPopExpr (parse)))
2287 {
Behdad Esfahbod390c05e2009-06-05 22:32:31 -04002288 new = FcExprCreateOp (parse->config, operand, op, 0);
Keith Packard3f7653c2003-04-15 23:38:06 +00002289 if (!new)
2290 {
2291 FcExprDestroy (operand);
2292 FcConfigMessage (parse, FcSevereError, "out of memory");
2293 }
2294 }
2295 return new;
2296}
2297
2298static void
2299FcParseUnary (FcConfigParse *parse, FcOp op)
2300{
2301 FcExpr *expr = FcPopUnary (parse, op);
Keith Packardc2e7c612002-02-18 22:29:28 +00002302 if (expr)
2303 FcVStackPushExpr (parse, FcVStackExpr, expr);
2304}
2305
2306static void
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002307FcParseDir (FcConfigParse *parse)
2308{
Akira TAGOH2e8ce632019-01-31 10:17:47 +00002309 const FcChar8 *attr, *data, *salt;
Akira TAGOH6f27f422021-03-29 21:25:21 +09002310 FcStrSet *prefix_dirs = NULL;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002311
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002312 data = FcStrBufDoneStatic (&parse->pstack->str);
2313 if (!data)
2314 {
2315 FcConfigMessage (parse, FcSevereError, "out of memory");
Akira TAGOHa563a182019-01-28 09:59:29 +00002316 return;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002317 }
Akira TAGOHcb1df8c2019-04-02 09:37:49 +00002318 if (data[0] == 0)
2319 {
2320 FcConfigMessage (parse, FcSevereWarning, "empty font directory name ignored");
2321 return;
2322 }
Akira TAGOHa563a182019-01-28 09:59:29 +00002323 attr = FcConfigGetAttribute (parse, "prefix");
Akira TAGOH2e8ce632019-01-31 10:17:47 +00002324 salt = FcConfigGetAttribute (parse, "salt");
Akira TAGOH6f27f422021-03-29 21:25:21 +09002325 prefix_dirs = _get_real_paths_from_prefix (parse, data, attr);
2326 if (prefix_dirs)
Akira TAGOHcb1df8c2019-04-02 09:37:49 +00002327 {
Akira TAGOH6f27f422021-03-29 21:25:21 +09002328 FcStrList *l = FcStrListCreate (prefix_dirs);
2329 FcChar8 *prefix;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002330
Akira TAGOH6f27f422021-03-29 21:25:21 +09002331 FcStrSetDestroy (prefix_dirs);
2332 while ((prefix = FcStrListNext (l)))
2333 {
2334 if (!prefix || prefix[0] == 0)
2335 {
2336 /* nop */
2337 }
2338 else if (!parse->scanOnly && (!FcStrUsesHome (prefix) || FcConfigHome ()))
2339 {
2340 if (!FcConfigAddFontDir (parse->config, prefix, NULL, salt))
2341 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add directory %s", prefix);
2342 }
2343 FcStrBufDestroy (&parse->pstack->str);
2344 }
2345 FcStrListDone (l);
2346 }
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002347}
2348
2349static void
2350FcParseCacheDir (FcConfigParse *parse)
2351{
2352 const FcChar8 *attr;
Akira TAGOH5004e8e2014-06-30 12:37:36 +09002353 FcChar8 *prefix = NULL, *p, *data = NULL;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002354
2355 attr = FcConfigGetAttribute (parse, "prefix");
2356 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
Akira TAGOH5004e8e2014-06-30 12:37:36 +09002357 {
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002358 prefix = FcConfigXdgCacheHome ();
Akira TAGOH5004e8e2014-06-30 12:37:36 +09002359 /* home directory might be disabled.
2360 * simply ignore this element.
2361 */
2362 if (!prefix)
2363 goto bail;
2364 }
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002365 data = FcStrBufDone (&parse->pstack->str);
2366 if (!data)
2367 {
2368 FcConfigMessage (parse, FcSevereError, "out of memory");
Akira TAGOH37c9c162018-07-19 04:29:01 +00002369 data = prefix;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002370 goto bail;
2371 }
Akira TAGOH75eadca2019-10-08 19:35:10 +09002372 if (data[0] == 0)
2373 {
2374 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
Ben Wagnerd55eaa62020-12-11 11:54:43 -05002375 FcStrFree (data);
2376 data = prefix;
2377 goto bail;
Akira TAGOH75eadca2019-10-08 19:35:10 +09002378 }
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002379 if (prefix)
2380 {
2381 size_t plen = strlen ((const char *)prefix);
2382 size_t dlen = strlen ((const char *)data);
2383
Akira TAGOHe7954672012-12-07 19:09:36 +09002384 p = realloc (prefix, plen + 1 + dlen + 1);
2385 if (!p)
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002386 {
2387 FcConfigMessage (parse, FcSevereError, "out of memory");
Akira TAGOH37c9c162018-07-19 04:29:01 +00002388 FcStrFree (prefix);
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002389 goto bail;
2390 }
Akira TAGOHe7954672012-12-07 19:09:36 +09002391 prefix = p;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002392 prefix[plen] = FC_DIR_SEPARATOR;
2393 memcpy (&prefix[plen + 1], data, dlen);
2394 prefix[plen + 1 + dlen] = 0;
2395 FcStrFree (data);
2396 data = prefix;
2397 }
2398#ifdef _WIN32
Руслан Ижбулатовf6e6a8a2015-04-08 08:41:25 +00002399 else if (data[0] == '/' && fontconfig_instprefix[0] != '\0')
2400 {
2401 size_t plen = strlen ((const char *)fontconfig_instprefix);
2402 size_t dlen = strlen ((const char *)data);
2403
2404 prefix = malloc (plen + 1 + dlen + 1);
2405 if (!prefix)
2406 {
2407 FcConfigMessage (parse, FcSevereError, "out of memory");
2408 goto bail;
2409 }
2410 strcpy ((char *) prefix, (char *) fontconfig_instprefix);
2411 prefix[plen] = FC_DIR_SEPARATOR;
2412 memcpy (&prefix[plen + 1], data, dlen);
2413 prefix[plen + 1 + dlen] = 0;
2414 FcStrFree (data);
2415 data = prefix;
2416 }
2417 else if (strcmp ((const char *) data, "WINDOWSTEMPDIR_FONTCONFIG_CACHE") == 0)
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002418 {
2419 int rc;
Akira TAGOH37c9c162018-07-19 04:29:01 +00002420
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002421 FcStrFree (data);
2422 data = malloc (1000);
2423 if (!data)
2424 {
2425 FcConfigMessage (parse, FcSevereError, "out of memory");
2426 goto bail;
2427 }
Akira TAGOHcd280f62012-06-13 20:01:30 +09002428 rc = GetTempPath (800, (LPSTR) data);
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002429 if (rc == 0 || rc > 800)
2430 {
2431 FcConfigMessage (parse, FcSevereError, "GetTempPath failed");
2432 goto bail;
2433 }
Akira TAGOHcd280f62012-06-13 20:01:30 +09002434 if (data [strlen ((const char *) data) - 1] != '\\')
Behdad Esfahbodec8a40d2013-01-02 17:35:56 -06002435 strcat ((char *) data, "\\");
2436 strcat ((char *) data, "fontconfig\\cache");
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002437 }
Akira TAGOHcd280f62012-06-13 20:01:30 +09002438 else if (strcmp ((const char *) data, "LOCAL_APPDATA_FONTCONFIG_CACHE") == 0)
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002439 {
2440 char szFPath[MAX_PATH + 1];
2441 size_t len;
2442
2443 if (!(pSHGetFolderPathA && SUCCEEDED(pSHGetFolderPathA(NULL, /* CSIDL_LOCAL_APPDATA */ 28, NULL, 0, szFPath))))
2444 {
2445 FcConfigMessage (parse, FcSevereError, "SHGetFolderPathA failed");
2446 goto bail;
2447 }
2448 strncat(szFPath, "\\fontconfig\\cache", MAX_PATH - 1 - strlen(szFPath));
2449 len = strlen(szFPath) + 1;
2450 FcStrFree (data);
2451 data = malloc(len);
2452 if (!data)
2453 {
2454 FcConfigMessage (parse, FcSevereError, "out of memory");
2455 goto bail;
2456 }
Akira TAGOHcd280f62012-06-13 20:01:30 +09002457 strncpy((char *) data, szFPath, len);
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002458 }
2459#endif
2460 if (strlen ((char *) data) == 0)
2461 FcConfigMessage (parse, FcSevereWarning, "empty cache directory name ignored");
Akira TAGOHef748b32018-01-23 22:27:17 +09002462 else if (!parse->scanOnly && (!FcStrUsesHome (data) || FcConfigHome ()))
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002463 {
2464 if (!FcConfigAddCacheDir (parse->config, data))
2465 FcConfigMessage (parse, FcSevereError, "out of memory; cannot add cache directory %s", data);
2466 }
2467 FcStrBufDestroy (&parse->pstack->str);
2468
2469 bail:
2470 if (data)
2471 FcStrFree (data);
2472}
2473
Akira TAGOHfa6c6b52015-05-22 16:53:34 +09002474void
2475FcConfigPathFini (void)
2476{
2477 FcChar8 *s;
2478
2479retry_dir:
2480 s = fc_atomic_ptr_get (&__fc_userdir);
2481 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, s, NULL))
2482 goto retry_dir;
2483 free (s);
2484
2485retry_conf:
2486 s = fc_atomic_ptr_get (&__fc_userconf);
2487 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, s, NULL))
2488 goto retry_conf;
2489 free (s);
2490}
2491
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002492static void
Keith Packardc2e7c612002-02-18 22:29:28 +00002493FcParseInclude (FcConfigParse *parse)
2494{
2495 FcChar8 *s;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002496 const FcChar8 *attr;
Keith Packardc2e7c612002-02-18 22:29:28 +00002497 FcBool ignore_missing = FcFalse;
Akira TAGOHf43c5812015-02-24 15:01:14 +09002498#ifndef _WIN32
Marius Tolzmanne5a59ea2012-06-21 21:01:10 +02002499 FcBool deprecated = FcFalse;
Akira TAGOHf43c5812015-02-24 15:01:14 +09002500#endif
Akira TAGOHe7954672012-12-07 19:09:36 +09002501 FcChar8 *prefix = NULL, *p;
Akira TAGOH249306f2015-05-22 20:45:05 +09002502 FcChar8 *userdir = NULL, *userconf = NULL;
Akira TAGOH97898b12018-01-03 22:15:11 +09002503 FcRuleSet *ruleset;
2504 FcMatchKind k;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04002505
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04002506 s = FcStrBufDoneStatic (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00002507 if (!s)
2508 {
Keith Packard179c3992002-05-21 17:06:22 +00002509 FcConfigMessage (parse, FcSevereError, "out of memory");
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002510 goto bail;
Keith Packardc2e7c612002-02-18 22:29:28 +00002511 }
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002512 attr = FcConfigGetAttribute (parse, "ignore_missing");
2513 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
Keith Packardc2e7c612002-02-18 22:29:28 +00002514 ignore_missing = FcTrue;
Marius Tolzmanne5a59ea2012-06-21 21:01:10 +02002515 attr = FcConfigGetAttribute (parse, "deprecated");
Akira TAGOHe92c92f2015-03-25 12:10:48 +09002516#ifndef _WIN32
Marius Tolzmanne5a59ea2012-06-21 21:01:10 +02002517 if (attr && FcConfigLexBool (parse, (FcChar8 *) attr) == FcTrue)
2518 deprecated = FcTrue;
Akira TAGOHf43c5812015-02-24 15:01:14 +09002519#endif
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002520 attr = FcConfigGetAttribute (parse, "prefix");
2521 if (attr && FcStrCmp (attr, (const FcChar8 *)"xdg") == 0)
Akira TAGOH5004e8e2014-06-30 12:37:36 +09002522 {
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002523 prefix = FcConfigXdgConfigHome ();
Akira TAGOH5004e8e2014-06-30 12:37:36 +09002524 /* home directory might be disabled.
2525 * simply ignore this element.
2526 */
2527 if (!prefix)
2528 goto bail;
2529 }
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002530 if (prefix)
2531 {
2532 size_t plen = strlen ((const char *)prefix);
2533 size_t dlen = strlen ((const char *)s);
Akira TAGOHfa6c6b52015-05-22 16:53:34 +09002534 FcChar8 *u;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002535
Akira TAGOHe7954672012-12-07 19:09:36 +09002536 p = realloc (prefix, plen + 1 + dlen + 1);
2537 if (!p)
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002538 {
2539 FcConfigMessage (parse, FcSevereError, "out of memory");
2540 goto bail;
2541 }
Akira TAGOHe7954672012-12-07 19:09:36 +09002542 prefix = p;
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002543 prefix[plen] = FC_DIR_SEPARATOR;
2544 memcpy (&prefix[plen + 1], s, dlen);
2545 prefix[plen + 1 + dlen] = 0;
2546 s = prefix;
Akira TAGOH041deb02013-08-07 11:57:19 +09002547 if (FcFileIsDir (s))
2548 {
2549 userdir:
Akira TAGOHfa6c6b52015-05-22 16:53:34 +09002550 userdir = fc_atomic_ptr_get (&__fc_userdir);
Akira TAGOH041deb02013-08-07 11:57:19 +09002551 if (!userdir)
Akira TAGOHfa6c6b52015-05-22 16:53:34 +09002552 {
2553 u = FcStrdup (s);
2554 if (!fc_atomic_ptr_cmpexch (&__fc_userdir, userdir, u))
2555 {
2556 free (u);
2557 goto userdir;
2558 }
2559 userdir = u;
2560 }
Akira TAGOH041deb02013-08-07 11:57:19 +09002561 }
2562 else if (FcFileIsFile (s))
2563 {
2564 userconf:
Akira TAGOHfa6c6b52015-05-22 16:53:34 +09002565 userconf = fc_atomic_ptr_get (&__fc_userconf);
Akira TAGOH041deb02013-08-07 11:57:19 +09002566 if (!userconf)
Akira TAGOHfa6c6b52015-05-22 16:53:34 +09002567 {
2568 u = FcStrdup (s);
2569 if (!fc_atomic_ptr_cmpexch (&__fc_userconf, userconf, u))
2570 {
2571 free (u);
2572 goto userconf;
2573 }
2574 userconf = u;
2575 }
Akira TAGOH041deb02013-08-07 11:57:19 +09002576 }
2577 else
2578 {
2579 /* No config dir nor file on the XDG directory spec compliant place
2580 * so need to guess what it is supposed to be.
2581 */
Akira TAGOH041deb02013-08-07 11:57:19 +09002582 if (FcStrStr (s, (const FcChar8 *)"conf.d") != NULL)
2583 goto userdir;
2584 else
2585 goto userconf;
2586 }
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002587 }
Akira TAGOH97898b12018-01-03 22:15:11 +09002588 /* flush the ruleset into the queue */
2589 ruleset = parse->ruleset;
2590 parse->ruleset = FcRuleSetCreate (ruleset->name);
2591 FcRuleSetEnable (parse->ruleset, ruleset->enabled);
2592 FcRuleSetAddDescription (parse->ruleset, ruleset->domain, ruleset->description);
2593 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
2594 {
2595 FcPtrListIter iter;
2596
2597 FcPtrListIterInit (ruleset->subst[k], &iter);
2598 if (FcPtrListIterIsValid (ruleset->subst[k], &iter))
2599 {
2600 FcPtrListIterInitAtLast (parse->config->subst[k], &iter);
2601 FcRuleSetReference (ruleset);
2602 FcPtrListIterAdd (parse->config->subst[k], &iter, ruleset);
2603 }
2604 }
2605 FcRuleSetDestroy (ruleset);
Akira TAGOHef748b32018-01-23 22:27:17 +09002606 if (!_FcConfigParse (parse->config, s, !ignore_missing, !parse->scanOnly))
Keith Packardc2e7c612002-02-18 22:29:28 +00002607 parse->error = FcTrue;
Akira TAGOH041deb02013-08-07 11:57:19 +09002608#ifndef _WIN32
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002609 else
2610 {
Marius Tolzmanne5a59ea2012-06-21 21:01:10 +02002611 FcChar8 *filename;
Akira TAGOH041deb02013-08-07 11:57:19 +09002612 static FcBool warn_conf = FcFalse, warn_confd = FcFalse;
Marius Tolzmanne5a59ea2012-06-21 21:01:10 +02002613
Akira TAGOHcd51cb22019-10-21 16:17:42 +09002614 filename = FcConfigGetFilename(parse->config, s);
Akira TAGOH92315452012-12-05 18:13:25 +09002615 if (deprecated == FcTrue &&
2616 filename != NULL &&
Akira TAGOHf0532312015-05-22 20:46:54 +09002617 userdir != NULL &&
Akira TAGOH92315452012-12-05 18:13:25 +09002618 !FcFileIsLink (filename))
2619 {
Akira TAGOH041deb02013-08-07 11:57:19 +09002620 if (FcFileIsDir (filename))
2621 {
Akira TAGOH3e5f70a2013-09-02 20:51:46 +09002622 FcChar8 *parent = FcStrDirname (userdir);
2623
2624 if (!FcFileIsDir (parent))
2625 FcMakeDirectory (parent);
2626 FcStrFree (parent);
Akira TAGOH041deb02013-08-07 11:57:19 +09002627 if (FcFileIsDir (userdir) ||
2628 rename ((const char *)filename, (const char *)userdir) != 0 ||
2629 symlink ((const char *)userdir, (const char *)filename) != 0)
2630 {
2631 if (!warn_confd)
2632 {
2633 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userdir);
2634 warn_confd = FcTrue;
2635 }
2636 }
2637 }
2638 else
2639 {
Akira TAGOH3e5f70a2013-09-02 20:51:46 +09002640 FcChar8 *parent = FcStrDirname (userconf);
2641
2642 if (!FcFileIsDir (parent))
2643 FcMakeDirectory (parent);
2644 FcStrFree (parent);
Akira TAGOH041deb02013-08-07 11:57:19 +09002645 if (FcFileIsFile (userconf) ||
2646 rename ((const char *)filename, (const char *)userconf) != 0 ||
2647 symlink ((const char *)userconf, (const char *)filename) != 0)
2648 {
2649 if (!warn_conf)
2650 {
2651 FcConfigMessage (parse, FcSevereWarning, "reading configurations from %s is deprecated. please move it to %s manually", s, userconf);
2652 warn_conf = FcTrue;
2653 }
2654 }
2655 }
Marius Tolzmanne5a59ea2012-06-21 21:01:10 +02002656 }
2657 if(filename)
2658 FcStrFree(filename);
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002659 }
Akira TAGOH041deb02013-08-07 11:57:19 +09002660#endif
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04002661 FcStrBufDestroy (&parse->pstack->str);
Akira TAGOH8c255fb2012-03-12 19:18:19 +09002662
2663 bail:
2664 if (prefix)
Akira TAGOH1b692d82012-06-01 19:06:17 +09002665 FcStrFree (prefix);
Keith Packardc2e7c612002-02-18 22:29:28 +00002666}
2667
2668typedef struct _FcOpMap {
Patrick Lam67accef2005-09-22 23:45:53 +00002669 char name[16];
Keith Packardc2e7c612002-02-18 22:29:28 +00002670 FcOp op;
2671} FcOpMap;
2672
2673static FcOp
2674FcConfigLexOp (const FcChar8 *op, const FcOpMap *map, int nmap)
2675{
2676 int i;
2677
2678 for (i = 0; i < nmap; i++)
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04002679 if (!strcmp ((char *) op, map[i].name))
Keith Packardc2e7c612002-02-18 22:29:28 +00002680 return map[i].op;
2681 return FcOpInvalid;
2682}
2683
2684static const FcOpMap fcCompareOps[] = {
2685 { "eq", FcOpEqual },
2686 { "not_eq", FcOpNotEqual },
2687 { "less", FcOpLess },
2688 { "less_eq", FcOpLessEqual },
2689 { "more", FcOpMore },
Keith Packard47d4f952002-08-22 18:53:22 +00002690 { "more_eq", FcOpMoreEqual },
2691 { "contains", FcOpContains },
2692 { "not_contains", FcOpNotContains }
Keith Packardc2e7c612002-02-18 22:29:28 +00002693};
2694
Patrick Lam67accef2005-09-22 23:45:53 +00002695#define NUM_COMPARE_OPS (int) (sizeof fcCompareOps / sizeof fcCompareOps[0])
Keith Packardc2e7c612002-02-18 22:29:28 +00002696
2697static FcOp
2698FcConfigLexCompare (const FcChar8 *compare)
2699{
2700 return FcConfigLexOp (compare, fcCompareOps, NUM_COMPARE_OPS);
2701}
2702
Keith Packardc2e7c612002-02-18 22:29:28 +00002703static void
2704FcParseTest (FcConfigParse *parse)
2705{
Keith Packard938bc632002-08-11 18:11:04 +00002706 const FcChar8 *kind_string;
2707 FcMatchKind kind;
Keith Packardc2e7c612002-02-18 22:29:28 +00002708 const FcChar8 *qual_string;
2709 FcQual qual;
2710 const FcChar8 *name;
2711 const FcChar8 *compare_string;
2712 FcOp compare;
2713 FcExpr *expr;
2714 FcTest *test;
Akira TAGOHbc4517d2012-04-11 19:52:35 +09002715 const FcChar8 *iblanks_string;
2716 int flags = 0;
Keith Packardc2e7c612002-02-18 22:29:28 +00002717
Keith Packard938bc632002-08-11 18:11:04 +00002718 kind_string = FcConfigGetAttribute (parse, "target");
2719 if (!kind_string)
2720 kind = FcMatchDefault;
2721 else
2722 {
2723 if (!strcmp ((char *) kind_string, "pattern"))
2724 kind = FcMatchPattern;
2725 else if (!strcmp ((char *) kind_string, "font"))
2726 kind = FcMatchFont;
Keith Packardc2c69762006-09-02 17:52:12 -07002727 else if (!strcmp ((char *) kind_string, "scan"))
2728 kind = FcMatchScan;
Keith Packard938bc632002-08-11 18:11:04 +00002729 else if (!strcmp ((char *) kind_string, "default"))
2730 kind = FcMatchDefault;
2731 else
2732 {
2733 FcConfigMessage (parse, FcSevereWarning, "invalid test target \"%s\"", kind_string);
2734 return;
2735 }
2736 }
Keith Packardc2e7c612002-02-18 22:29:28 +00002737 qual_string = FcConfigGetAttribute (parse, "qual");
2738 if (!qual_string)
2739 qual = FcQualAny;
2740 else
2741 {
2742 if (!strcmp ((char *) qual_string, "any"))
2743 qual = FcQualAny;
2744 else if (!strcmp ((char *) qual_string, "all"))
2745 qual = FcQualAll;
Keith Packard6f6563e2002-06-19 20:08:22 +00002746 else if (!strcmp ((char *) qual_string, "first"))
2747 qual = FcQualFirst;
2748 else if (!strcmp ((char *) qual_string, "not_first"))
2749 qual = FcQualNotFirst;
Keith Packardc2e7c612002-02-18 22:29:28 +00002750 else
2751 {
Keith Packard179c3992002-05-21 17:06:22 +00002752 FcConfigMessage (parse, FcSevereWarning, "invalid test qual \"%s\"", qual_string);
Keith Packardb4a2c1f2002-07-12 19:19:16 +00002753 return;
Keith Packardc2e7c612002-02-18 22:29:28 +00002754 }
2755 }
2756 name = FcConfigGetAttribute (parse, "name");
2757 if (!name)
2758 {
Keith Packard179c3992002-05-21 17:06:22 +00002759 FcConfigMessage (parse, FcSevereWarning, "missing test name");
Keith Packardb4a2c1f2002-07-12 19:19:16 +00002760 return;
Keith Packardc2e7c612002-02-18 22:29:28 +00002761 }
2762 compare_string = FcConfigGetAttribute (parse, "compare");
2763 if (!compare_string)
2764 compare = FcOpEqual;
2765 else
2766 {
2767 compare = FcConfigLexCompare (compare_string);
2768 if (compare == FcOpInvalid)
2769 {
Keith Packard179c3992002-05-21 17:06:22 +00002770 FcConfigMessage (parse, FcSevereWarning, "invalid test compare \"%s\"", compare_string);
Keith Packardb4a2c1f2002-07-12 19:19:16 +00002771 return;
Keith Packardc2e7c612002-02-18 22:29:28 +00002772 }
2773 }
Akira TAGOHbc4517d2012-04-11 19:52:35 +09002774 iblanks_string = FcConfigGetAttribute (parse, "ignore-blanks");
2775 if (iblanks_string)
2776 {
2777 FcBool f = FcFalse;
2778
2779 if (!FcNameBool (iblanks_string, &f))
2780 {
2781 FcConfigMessage (parse,
2782 FcSevereWarning,
2783 "invalid test ignore-blanks \"%s\"", iblanks_string);
2784 }
2785 if (f)
2786 flags |= FcOpFlagIgnoreBlanks;
2787 }
Keith Packard3f7653c2003-04-15 23:38:06 +00002788 expr = FcPopBinary (parse, FcOpComma);
Keith Packardc2e7c612002-02-18 22:29:28 +00002789 if (!expr)
2790 {
Keith Packard179c3992002-05-21 17:06:22 +00002791 FcConfigMessage (parse, FcSevereWarning, "missing test expression");
Keith Packardc2e7c612002-02-18 22:29:28 +00002792 return;
2793 }
Akira TAGOH2837c632012-05-21 13:43:20 +09002794 if (expr->op == FcOpComma)
2795 {
Akira TAGOH375cdbc2012-08-16 20:33:12 +09002796 FcConfigMessage (parse, FcSevereWarning, "Having multiple values in <test> isn't supported and may not work as expected");
Akira TAGOH2837c632012-05-21 13:43:20 +09002797 }
Akira TAGOHbc4517d2012-04-11 19:52:35 +09002798 test = FcTestCreate (parse, kind, qual, name, FC_OP (compare, flags), expr);
Keith Packardc2e7c612002-02-18 22:29:28 +00002799 if (!test)
2800 {
Keith Packard179c3992002-05-21 17:06:22 +00002801 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00002802 return;
2803 }
2804 FcVStackPushTest (parse, test);
2805}
2806
2807static const FcOpMap fcModeOps[] = {
2808 { "assign", FcOpAssign },
2809 { "assign_replace", FcOpAssignReplace },
2810 { "prepend", FcOpPrepend },
2811 { "prepend_first", FcOpPrependFirst },
2812 { "append", FcOpAppend },
2813 { "append_last", FcOpAppendLast },
Akira TAGOH20191812013-01-29 20:19:36 +09002814 { "delete", FcOpDelete },
2815 { "delete_all", FcOpDeleteAll },
Keith Packardc2e7c612002-02-18 22:29:28 +00002816};
2817
Patrick Lam67accef2005-09-22 23:45:53 +00002818#define NUM_MODE_OPS (int) (sizeof fcModeOps / sizeof fcModeOps[0])
Keith Packardc2e7c612002-02-18 22:29:28 +00002819
2820static FcOp
2821FcConfigLexMode (const FcChar8 *mode)
2822{
2823 return FcConfigLexOp (mode, fcModeOps, NUM_MODE_OPS);
2824}
2825
2826static void
2827FcParseEdit (FcConfigParse *parse)
2828{
2829 const FcChar8 *name;
2830 const FcChar8 *mode_string;
2831 FcOp mode;
Keith Packard6fff2cd2002-07-31 01:36:37 +00002832 FcValueBinding binding;
Keith Packardc2e7c612002-02-18 22:29:28 +00002833 FcExpr *expr;
2834 FcEdit *edit;
2835
2836 name = FcConfigGetAttribute (parse, "name");
2837 if (!name)
2838 {
Keith Packard179c3992002-05-21 17:06:22 +00002839 FcConfigMessage (parse, FcSevereWarning, "missing edit name");
Keith Packardb4a2c1f2002-07-12 19:19:16 +00002840 return;
Keith Packardc2e7c612002-02-18 22:29:28 +00002841 }
2842 mode_string = FcConfigGetAttribute (parse, "mode");
2843 if (!mode_string)
Keith Packard8ec077f2002-06-02 19:51:36 +00002844 mode = FcOpAssign;
Keith Packardc2e7c612002-02-18 22:29:28 +00002845 else
2846 {
2847 mode = FcConfigLexMode (mode_string);
2848 if (mode == FcOpInvalid)
2849 {
Keith Packard179c3992002-05-21 17:06:22 +00002850 FcConfigMessage (parse, FcSevereWarning, "invalid edit mode \"%s\"", mode_string);
Keith Packardb4a2c1f2002-07-12 19:19:16 +00002851 return;
Keith Packardc2e7c612002-02-18 22:29:28 +00002852 }
2853 }
Keith Packard681bb372007-10-25 22:30:49 -07002854 if (!FcConfigLexBinding (parse, FcConfigGetAttribute (parse, "binding"), &binding))
2855 return;
2856
Keith Packard3f7653c2003-04-15 23:38:06 +00002857 expr = FcPopBinary (parse, FcOpComma);
Akira TAGOH20191812013-01-29 20:19:36 +09002858 if ((mode == FcOpDelete || mode == FcOpDeleteAll) &&
2859 expr != NULL)
2860 {
2861 FcConfigMessage (parse, FcSevereWarning, "Expression doesn't take any effects for delete and delete_all");
2862 FcExprDestroy (expr);
2863 expr = NULL;
2864 }
Keith Packard2d3387f2006-08-30 21:59:53 -07002865 edit = FcEditCreate (parse, FcObjectFromName ((char *) name),
2866 mode, expr, binding);
Keith Packardc2e7c612002-02-18 22:29:28 +00002867 if (!edit)
2868 {
Keith Packard179c3992002-05-21 17:06:22 +00002869 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00002870 FcExprDestroy (expr);
2871 return;
2872 }
2873 if (!FcVStackPushEdit (parse, edit))
2874 FcEditDestroy (edit);
2875}
2876
2877static void
2878FcParseMatch (FcConfigParse *parse)
2879{
2880 const FcChar8 *kind_name;
2881 FcMatchKind kind;
Keith Packardc2e7c612002-02-18 22:29:28 +00002882 FcVStack *vstack;
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002883 FcRule *rule = NULL, *r;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09002884 int n;
Keith Packardc2e7c612002-02-18 22:29:28 +00002885
2886 kind_name = FcConfigGetAttribute (parse, "target");
2887 if (!kind_name)
2888 kind = FcMatchPattern;
2889 else
2890 {
2891 if (!strcmp ((char *) kind_name, "pattern"))
2892 kind = FcMatchPattern;
2893 else if (!strcmp ((char *) kind_name, "font"))
2894 kind = FcMatchFont;
Keith Packardc2c69762006-09-02 17:52:12 -07002895 else if (!strcmp ((char *) kind_name, "scan"))
2896 kind = FcMatchScan;
Keith Packardc2e7c612002-02-18 22:29:28 +00002897 else
2898 {
Keith Packard179c3992002-05-21 17:06:22 +00002899 FcConfigMessage (parse, FcSevereWarning, "invalid match target \"%s\"", kind_name);
Keith Packardb4a2c1f2002-07-12 19:19:16 +00002900 return;
Keith Packardc2e7c612002-02-18 22:29:28 +00002901 }
2902 }
Behdad Esfahbod39861b72009-03-12 12:22:37 -04002903 while ((vstack = FcVStackPeek (parse)))
Keith Packardc2e7c612002-02-18 22:29:28 +00002904 {
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05002905 switch ((int) vstack->tag) {
Keith Packardc2e7c612002-02-18 22:29:28 +00002906 case FcVStackTest:
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002907 r = FcRuleCreate (FcRuleTest, vstack->u.test);
2908 if (rule)
2909 r->next = rule;
2910 rule = r;
Keith Packardc2e7c612002-02-18 22:29:28 +00002911 vstack->tag = FcVStackNone;
2912 break;
2913 case FcVStackEdit:
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002914 if (kind == FcMatchScan && vstack->u.edit->object > FC_MAX_BASE_OBJECT)
Keith Packard0f963b02006-12-02 13:57:45 -08002915 {
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04002916 FcConfigMessage (parse, FcSevereError,
Keith Packard0f963b02006-12-02 13:57:45 -08002917 "<match target=\"scan\"> cannot edit user-defined object \"%s\"",
Akira TAGOH6c664d52013-08-23 19:58:43 +09002918 FcObjectName(vstack->u.edit->object));
2919 if (rule)
2920 FcRuleDestroy (rule);
2921 return;
Keith Packard0f963b02006-12-02 13:57:45 -08002922 }
Akira TAGOHd420e1d2013-07-04 19:51:03 +09002923 r = FcRuleCreate (FcRuleEdit, vstack->u.edit);
2924 if (rule)
2925 r->next = rule;
2926 rule = r;
2927 vstack->tag = FcVStackNone;
Keith Packardc2e7c612002-02-18 22:29:28 +00002928 break;
2929 default:
Keith Packard179c3992002-05-21 17:06:22 +00002930 FcConfigMessage (parse, FcSevereWarning, "invalid match element");
Keith Packardc2e7c612002-02-18 22:29:28 +00002931 break;
2932 }
Behdad Esfahbod39861b72009-03-12 12:22:37 -04002933 FcVStackPopAndDestroy (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00002934 }
Akira TAGOHaa22e6e2013-01-24 19:48:48 +09002935 if (!rule)
2936 {
2937 FcConfigMessage (parse, FcSevereWarning, "No <test> nor <edit> elements in <match>");
2938 return;
2939 }
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09002940 if ((n = FcRuleSetAdd (parse->ruleset, rule, kind)) == -1)
2941 {
Keith Packard179c3992002-05-21 17:06:22 +00002942 FcConfigMessage (parse, FcSevereError, "out of memory");
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09002943 FcRuleDestroy (rule);
2944 }
2945 else
2946 if (parse->config->maxObjects < n)
2947 parse->config->maxObjects = n;
Keith Packardc2e7c612002-02-18 22:29:28 +00002948}
2949
2950static void
Keith Packardd47c9d62003-05-07 16:13:24 +00002951FcParseAcceptRejectFont (FcConfigParse *parse, FcElement element)
2952{
2953 FcVStack *vstack;
2954
Behdad Esfahbod39861b72009-03-12 12:22:37 -04002955 while ((vstack = FcVStackPeek (parse)))
Keith Packardd47c9d62003-05-07 16:13:24 +00002956 {
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05002957 switch ((int) vstack->tag) {
Keith Packardd47c9d62003-05-07 16:13:24 +00002958 case FcVStackGlob:
Akira TAGOHef748b32018-01-23 22:27:17 +09002959 if (!parse->scanOnly && !FcConfigGlobAdd (parse->config,
2960 vstack->u.string,
2961 element == FcElementAcceptfont))
Keith Packardd47c9d62003-05-07 16:13:24 +00002962 {
Ondrej Balaz50c55e92023-01-25 05:00:57 +09002963 if (FcStrUsesHome(vstack->u.string) && FcConfigHome() == NULL)
2964 FcConfigMessage (parse, FcSevereWarning, "Home is disabled");
2965 else
2966 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardd47c9d62003-05-07 16:13:24 +00002967 }
Akira TAGOH684c3ce2018-05-25 13:51:10 +09002968 else
2969 {
2970 if (parse->scanOnly && vstack->u.string)
Akira TAGOH14c23a52018-05-25 15:20:10 +09002971 {
Akira TAGOH684c3ce2018-05-25 13:51:10 +09002972 FcStrFree (vstack->u.string);
Akira TAGOH14c23a52018-05-25 15:20:10 +09002973 vstack->tag = FcVStackNone;
2974 }
Akira TAGOH684c3ce2018-05-25 13:51:10 +09002975 }
Keith Packardd47c9d62003-05-07 16:13:24 +00002976 break;
Keith Packard4f27c1c2004-12-04 19:41:10 +00002977 case FcVStackPattern:
Akira TAGOHef748b32018-01-23 22:27:17 +09002978 if (!parse->scanOnly && !FcConfigPatternsAdd (parse->config,
2979 vstack->u.pattern,
2980 element == FcElementAcceptfont))
Keith Packard4f27c1c2004-12-04 19:41:10 +00002981 {
2982 FcConfigMessage (parse, FcSevereError, "out of memory");
2983 }
2984 else
Akira TAGOH684c3ce2018-05-25 13:51:10 +09002985 {
2986 if (parse->scanOnly && vstack->u.pattern)
2987 FcPatternDestroy (vstack->u.pattern);
Keith Packard4f27c1c2004-12-04 19:41:10 +00002988 vstack->tag = FcVStackNone;
Akira TAGOH684c3ce2018-05-25 13:51:10 +09002989 }
Keith Packard4f27c1c2004-12-04 19:41:10 +00002990 break;
Keith Packardd47c9d62003-05-07 16:13:24 +00002991 default:
2992 FcConfigMessage (parse, FcSevereWarning, "bad font selector");
2993 break;
2994 }
Behdad Esfahbod39861b72009-03-12 12:22:37 -04002995 FcVStackPopAndDestroy (parse);
Keith Packardd47c9d62003-05-07 16:13:24 +00002996 }
2997}
2998
Keith Packard4f27c1c2004-12-04 19:41:10 +00002999
3000static FcValue
3001FcPopValue (FcConfigParse *parse)
3002{
Behdad Esfahbod39861b72009-03-12 12:22:37 -04003003 FcVStack *vstack = FcVStackPeek (parse);
Keith Packard4f27c1c2004-12-04 19:41:10 +00003004 FcValue value;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003005
Keith Packard4f27c1c2004-12-04 19:41:10 +00003006 value.type = FcTypeVoid;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003007
Keith Packard4f27c1c2004-12-04 19:41:10 +00003008 if (!vstack)
3009 return value;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003010
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05003011 switch ((int) vstack->tag) {
Keith Packard4f27c1c2004-12-04 19:41:10 +00003012 case FcVStackString:
Behdad Esfahbod93fb1d42013-01-02 02:06:15 -06003013 value.u.s = FcStrdup (vstack->u.string);
Patrick Lam4262e0b2005-08-24 06:21:30 +00003014 if (value.u.s)
Keith Packard4f27c1c2004-12-04 19:41:10 +00003015 value.type = FcTypeString;
3016 break;
3017 case FcVStackConstant:
3018 if (FcNameConstant (vstack->u.string, &value.u.i))
3019 value.type = FcTypeInteger;
3020 break;
3021 case FcVStackInteger:
3022 value.u.i = vstack->u.integer;
3023 value.type = FcTypeInteger;
3024 break;
3025 case FcVStackDouble:
3026 value.u.d = vstack->u._double;
Behdad Esfahbod927dd3d2012-12-29 20:14:07 -05003027 value.type = FcTypeDouble;
Keith Packard4f27c1c2004-12-04 19:41:10 +00003028 break;
Keith Packard4f27c1c2004-12-04 19:41:10 +00003029 case FcVStackBool:
Harald Fernengelfe8e8a12008-12-28 03:23:58 -05003030 value.u.b = vstack->u.bool_;
Keith Packard4f27c1c2004-12-04 19:41:10 +00003031 value.type = FcTypeBool;
3032 break;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09003033 case FcVStackCharSet:
3034 value.u.c = FcCharSetCopy (vstack->u.charset);
3035 if (value.u.c)
3036 value.type = FcTypeCharSet;
3037 break;
Akira TAGOH3c862aa2010-12-06 12:38:18 +09003038 case FcVStackLangSet:
3039 value.u.l = FcLangSetCopy (vstack->u.langset);
3040 if (value.u.l)
3041 value.type = FcTypeLangSet;
3042 break;
Akira TAGOH3cd573f2013-11-20 18:44:59 +09003043 case FcVStackRange:
3044 value.u.r = FcRangeCopy (vstack->u.range);
3045 if (value.u.r)
3046 value.type = FcTypeRange;
3047 break;
Keith Packard4f27c1c2004-12-04 19:41:10 +00003048 default:
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003049 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element %d",
Keith Packard4f27c1c2004-12-04 19:41:10 +00003050 vstack->tag);
3051 break;
3052 }
Behdad Esfahbod39861b72009-03-12 12:22:37 -04003053 FcVStackPopAndDestroy (parse);
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003054
Keith Packard4f27c1c2004-12-04 19:41:10 +00003055 return value;
3056}
3057
3058static void
3059FcParsePatelt (FcConfigParse *parse)
3060{
3061 FcValue value;
3062 FcPattern *pattern = FcPatternCreate ();
3063 const char *name;
3064
3065 if (!pattern)
3066 {
3067 FcConfigMessage (parse, FcSevereError, "out of memory");
3068 return;
3069 }
3070
Patrick Lam82457712005-09-11 02:16:09 +00003071 name = (char *) FcConfigGetAttribute (parse, "name");
Keith Packard4f27c1c2004-12-04 19:41:10 +00003072 if (!name)
3073 {
3074 FcConfigMessage (parse, FcSevereWarning, "missing pattern element name");
Patrick Lam2de24632006-04-11 16:54:24 +00003075 FcPatternDestroy (pattern);
Keith Packard4f27c1c2004-12-04 19:41:10 +00003076 return;
3077 }
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003078
Keith Packard4f27c1c2004-12-04 19:41:10 +00003079 for (;;)
3080 {
3081 value = FcPopValue (parse);
3082 if (value.type == FcTypeVoid)
3083 break;
3084 if (!FcPatternAdd (pattern, name, value, FcTrue))
3085 {
3086 FcConfigMessage (parse, FcSevereError, "out of memory");
Behdad Esfahbod799691c2008-09-22 18:16:30 -04003087 FcValueDestroy(value);
Keith Packard4f27c1c2004-12-04 19:41:10 +00003088 break;
3089 }
Behdad Esfahbod799691c2008-09-22 18:16:30 -04003090 FcValueDestroy(value);
Keith Packard4f27c1c2004-12-04 19:41:10 +00003091 }
3092
Keith Packard529291b2006-04-27 07:54:07 +00003093 FcVStackPushPattern (parse, pattern);
Keith Packard4f27c1c2004-12-04 19:41:10 +00003094}
3095
3096static void
3097FcParsePattern (FcConfigParse *parse)
3098{
3099 FcVStack *vstack;
3100 FcPattern *pattern = FcPatternCreate ();
3101
3102 if (!pattern)
3103 {
3104 FcConfigMessage (parse, FcSevereError, "out of memory");
3105 return;
3106 }
Akira TAGOH6715a142022-11-25 21:15:32 +09003107
Behdad Esfahbod39861b72009-03-12 12:22:37 -04003108 while ((vstack = FcVStackPeek (parse)))
Keith Packard4f27c1c2004-12-04 19:41:10 +00003109 {
Behdad Esfahbod24cdcf52012-12-29 22:11:09 -05003110 switch ((int) vstack->tag) {
Keith Packard4f27c1c2004-12-04 19:41:10 +00003111 case FcVStackPattern:
3112 if (!FcPatternAppend (pattern, vstack->u.pattern))
3113 {
3114 FcConfigMessage (parse, FcSevereError, "out of memory");
Patrick Lam2de24632006-04-11 16:54:24 +00003115 FcPatternDestroy (pattern);
Keith Packard4f27c1c2004-12-04 19:41:10 +00003116 return;
3117 }
3118 break;
3119 default:
3120 FcConfigMessage (parse, FcSevereWarning, "unknown pattern element");
3121 break;
3122 }
Behdad Esfahbod39861b72009-03-12 12:22:37 -04003123 FcVStackPopAndDestroy (parse);
Keith Packard4f27c1c2004-12-04 19:41:10 +00003124 }
3125
3126 FcVStackPushPattern (parse, pattern);
3127}
3128
Keith Packardd47c9d62003-05-07 16:13:24 +00003129static void
Behdad Esfahbod83d80192012-12-29 22:32:56 -05003130FcEndElement(void *userData, const XML_Char *name FC_UNUSED)
Keith Packardc2e7c612002-02-18 22:29:28 +00003131{
3132 FcConfigParse *parse = userData;
3133 FcChar8 *data;
Tor Lillqvistd1567812009-08-14 00:08:17 +03003134
Keith Packardc2e7c612002-02-18 22:29:28 +00003135 if (!parse->pstack)
3136 return;
3137 switch (parse->pstack->element) {
3138 case FcElementNone:
3139 break;
3140 case FcElementFontconfig:
3141 break;
3142 case FcElementDir:
Akira TAGOH8c255fb2012-03-12 19:18:19 +09003143 FcParseDir (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00003144 break;
Patrick Lam7410e402006-08-04 16:13:00 +00003145 case FcElementCacheDir:
Akira TAGOH8c255fb2012-03-12 19:18:19 +09003146 FcParseCacheDir (parse);
Patrick Lam7410e402006-08-04 16:13:00 +00003147 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00003148 case FcElementCache:
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04003149 data = FcStrBufDoneStatic (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00003150 if (!data)
3151 {
Keith Packard179c3992002-05-21 17:06:22 +00003152 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00003153 break;
3154 }
Keith Packard2d3387f2006-08-30 21:59:53 -07003155 /* discard this data; no longer used */
Behdad Esfahbod3ed70072009-03-11 14:07:15 -04003156 FcStrBufDestroy (&parse->pstack->str);
Keith Packardc2e7c612002-02-18 22:29:28 +00003157 break;
3158 case FcElementInclude:
3159 FcParseInclude (parse);
3160 break;
3161 case FcElementConfig:
3162 break;
3163 case FcElementMatch:
3164 FcParseMatch (parse);
3165 break;
3166 case FcElementAlias:
3167 FcParseAlias (parse);
3168 break;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003169 case FcElementDescription:
3170 FcParseDescription (parse);
3171 break;
Akira TAGOHa563a182019-01-28 09:59:29 +00003172 case FcElementRemapDir:
3173 FcParseRemapDir (parse);
3174 break;
Akira TAGOHdef1d002019-01-31 07:52:09 +00003175 case FcElementResetDirs:
3176 FcParseResetDirs (parse);
3177 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00003178
Keith Packard179c3992002-05-21 17:06:22 +00003179 case FcElementRescan:
3180 FcParseRescan (parse);
3181 break;
Akira TAGOH6715a142022-11-25 21:15:32 +09003182
Keith Packardc2e7c612002-02-18 22:29:28 +00003183 case FcElementPrefer:
3184 FcParseFamilies (parse, FcVStackPrefer);
3185 break;
3186 case FcElementAccept:
3187 FcParseFamilies (parse, FcVStackAccept);
3188 break;
3189 case FcElementDefault:
3190 FcParseFamilies (parse, FcVStackDefault);
3191 break;
3192 case FcElementFamily:
3193 FcParseFamily (parse);
3194 break;
3195
3196 case FcElementTest:
3197 FcParseTest (parse);
3198 break;
3199 case FcElementEdit:
3200 FcParseEdit (parse);
3201 break;
3202
3203 case FcElementInt:
3204 FcParseInt (parse);
3205 break;
3206 case FcElementDouble:
3207 FcParseDouble (parse);
3208 break;
3209 case FcElementString:
3210 FcParseString (parse, FcVStackString);
3211 break;
3212 case FcElementMatrix:
3213 FcParseMatrix (parse);
3214 break;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09003215 case FcElementRange:
3216 FcParseRange (parse);
3217 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00003218 case FcElementBool:
3219 FcParseBool (parse);
3220 break;
Akira TAGOH857b7ef2010-12-06 12:10:17 +09003221 case FcElementCharSet:
3222 FcParseCharSet (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00003223 break;
Akira TAGOH3c862aa2010-12-06 12:38:18 +09003224 case FcElementLangSet:
3225 FcParseLangSet (parse);
3226 break;
Keith Packardd47c9d62003-05-07 16:13:24 +00003227 case FcElementSelectfont:
3228 break;
3229 case FcElementAcceptfont:
3230 case FcElementRejectfont:
3231 FcParseAcceptRejectFont (parse, parse->pstack->element);
3232 break;
3233 case FcElementGlob:
3234 FcParseString (parse, FcVStackGlob);
3235 break;
Keith Packard4f27c1c2004-12-04 19:41:10 +00003236 case FcElementPattern:
3237 FcParsePattern (parse);
3238 break;
3239 case FcElementPatelt:
3240 FcParsePatelt (parse);
3241 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00003242 case FcElementName:
Behdad Esfahbod51b00442012-12-29 23:58:38 -05003243 FcParseName (parse);
Keith Packardc2e7c612002-02-18 22:29:28 +00003244 break;
3245 case FcElementConst:
3246 FcParseString (parse, FcVStackConstant);
3247 break;
3248 case FcElementOr:
Keith Packard3f7653c2003-04-15 23:38:06 +00003249 FcParseBinary (parse, FcOpOr);
Keith Packardc2e7c612002-02-18 22:29:28 +00003250 break;
3251 case FcElementAnd:
Keith Packard3f7653c2003-04-15 23:38:06 +00003252 FcParseBinary (parse, FcOpAnd);
Keith Packardc2e7c612002-02-18 22:29:28 +00003253 break;
3254 case FcElementEq:
Keith Packard3f7653c2003-04-15 23:38:06 +00003255 FcParseBinary (parse, FcOpEqual);
Keith Packardc2e7c612002-02-18 22:29:28 +00003256 break;
3257 case FcElementNotEq:
Keith Packard3f7653c2003-04-15 23:38:06 +00003258 FcParseBinary (parse, FcOpNotEqual);
Keith Packardc2e7c612002-02-18 22:29:28 +00003259 break;
3260 case FcElementLess:
Keith Packard3f7653c2003-04-15 23:38:06 +00003261 FcParseBinary (parse, FcOpLess);
Keith Packardc2e7c612002-02-18 22:29:28 +00003262 break;
3263 case FcElementLessEq:
Keith Packard3f7653c2003-04-15 23:38:06 +00003264 FcParseBinary (parse, FcOpLessEqual);
Keith Packardc2e7c612002-02-18 22:29:28 +00003265 break;
3266 case FcElementMore:
Keith Packard3f7653c2003-04-15 23:38:06 +00003267 FcParseBinary (parse, FcOpMore);
Keith Packardc2e7c612002-02-18 22:29:28 +00003268 break;
3269 case FcElementMoreEq:
Keith Packard3f7653c2003-04-15 23:38:06 +00003270 FcParseBinary (parse, FcOpMoreEqual);
Keith Packardc2e7c612002-02-18 22:29:28 +00003271 break;
Keith Packard47d4f952002-08-22 18:53:22 +00003272 case FcElementContains:
Keith Packard3f7653c2003-04-15 23:38:06 +00003273 FcParseBinary (parse, FcOpContains);
Keith Packard47d4f952002-08-22 18:53:22 +00003274 break;
3275 case FcElementNotContains:
Keith Packard3f7653c2003-04-15 23:38:06 +00003276 FcParseBinary (parse, FcOpNotContains);
Keith Packard47d4f952002-08-22 18:53:22 +00003277 break;
Keith Packardc2e7c612002-02-18 22:29:28 +00003278 case FcElementPlus:
Keith Packard3f7653c2003-04-15 23:38:06 +00003279 FcParseBinary (parse, FcOpPlus);
Keith Packardc2e7c612002-02-18 22:29:28 +00003280 break;
3281 case FcElementMinus:
Keith Packard3f7653c2003-04-15 23:38:06 +00003282 FcParseBinary (parse, FcOpMinus);
Keith Packardc2e7c612002-02-18 22:29:28 +00003283 break;
3284 case FcElementTimes:
Keith Packard3f7653c2003-04-15 23:38:06 +00003285 FcParseBinary (parse, FcOpTimes);
Keith Packardc2e7c612002-02-18 22:29:28 +00003286 break;
3287 case FcElementDivide:
Keith Packard3f7653c2003-04-15 23:38:06 +00003288 FcParseBinary (parse, FcOpDivide);
Keith Packardc2e7c612002-02-18 22:29:28 +00003289 break;
3290 case FcElementNot:
Keith Packard3f7653c2003-04-15 23:38:06 +00003291 FcParseUnary (parse, FcOpNot);
Keith Packardc2e7c612002-02-18 22:29:28 +00003292 break;
3293 case FcElementIf:
Keith Packard3f7653c2003-04-15 23:38:06 +00003294 FcParseBinary (parse, FcOpQuest);
3295 break;
3296 case FcElementFloor:
3297 FcParseUnary (parse, FcOpFloor);
3298 break;
3299 case FcElementCeil:
3300 FcParseUnary (parse, FcOpCeil);
3301 break;
3302 case FcElementRound:
3303 FcParseUnary (parse, FcOpRound);
3304 break;
3305 case FcElementTrunc:
3306 FcParseUnary (parse, FcOpTrunc);
Keith Packardc2e7c612002-02-18 22:29:28 +00003307 break;
3308 case FcElementUnknown:
3309 break;
3310 }
3311 (void) FcPStackPop (parse);
3312}
3313
3314static void
3315FcCharacterData (void *userData, const XML_Char *s, int len)
3316{
3317 FcConfigParse *parse = userData;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003318
Keith Packardc2e7c612002-02-18 22:29:28 +00003319 if (!parse->pstack)
3320 return;
3321 if (!FcStrBufData (&parse->pstack->str, (FcChar8 *) s, len))
Keith Packard179c3992002-05-21 17:06:22 +00003322 FcConfigMessage (parse, FcSevereError, "out of memory");
Keith Packardc2e7c612002-02-18 22:29:28 +00003323}
3324
3325static void
3326FcStartDoctypeDecl (void *userData,
3327 const XML_Char *doctypeName,
Behdad Esfahbod83d80192012-12-29 22:32:56 -05003328 const XML_Char *sysid FC_UNUSED,
3329 const XML_Char *pubid FC_UNUSED,
3330 int has_internal_subset FC_UNUSED)
Keith Packardc2e7c612002-02-18 22:29:28 +00003331{
3332 FcConfigParse *parse = userData;
3333
3334 if (strcmp ((char *) doctypeName, "fontconfig") != 0)
Keith Packard179c3992002-05-21 17:06:22 +00003335 FcConfigMessage (parse, FcSevereError, "invalid doctype \"%s\"", doctypeName);
Keith Packardc2e7c612002-02-18 22:29:28 +00003336}
3337
Patrick Lam0d745812006-04-06 04:33:11 +00003338#ifdef ENABLE_LIBXML2
Patrick Lame99f0f02005-09-29 20:53:30 +00003339
3340static void
3341FcInternalSubsetDecl (void *userData,
3342 const XML_Char *doctypeName,
3343 const XML_Char *sysid,
3344 const XML_Char *pubid)
3345{
3346 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 1);
3347}
3348
3349static void
3350FcExternalSubsetDecl (void *userData,
3351 const XML_Char *doctypeName,
3352 const XML_Char *sysid,
3353 const XML_Char *pubid)
3354{
3355 FcStartDoctypeDecl (userData, doctypeName, sysid, pubid, 0);
3356}
3357
3358#else /* ENABLE_LIBXML2 */
3359
Keith Packardc2e7c612002-02-18 22:29:28 +00003360static void
Behdad Esfahbod83d80192012-12-29 22:32:56 -05003361FcEndDoctypeDecl (void *userData FC_UNUSED)
Keith Packardc2e7c612002-02-18 22:29:28 +00003362{
Keith Packard24330d22002-02-14 23:34:13 +00003363}
3364
Patrick Lame99f0f02005-09-29 20:53:30 +00003365#endif /* ENABLE_LIBXML2 */
3366
Keith Packard9419bb32006-09-09 21:21:01 -07003367static int
3368FcSortCmpStr (const void *a, const void *b)
3369{
3370 const FcChar8 *as = *((FcChar8 **) a);
3371 const FcChar8 *bs = *((FcChar8 **) b);
3372 return FcStrCmp (as, bs);
3373}
3374
Keith Packard2d9c79c2004-12-05 05:03:52 +00003375static FcBool
3376FcConfigParseAndLoadDir (FcConfig *config,
3377 const FcChar8 *name,
3378 const FcChar8 *dir,
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003379 FcBool complain,
3380 FcBool load)
Keith Packard2d9c79c2004-12-05 05:03:52 +00003381{
3382 DIR *d;
3383 struct dirent *e;
3384 FcBool ret = FcTrue;
3385 FcChar8 *file;
3386 FcChar8 *base;
3387 FcStrSet *files;
3388
3389 d = opendir ((char *) dir);
3390 if (!d)
3391 {
3392 if (complain)
3393 FcConfigMessage (0, FcSevereError, "Cannot open config dir \"%s\"",
3394 name);
3395 ret = FcFalse;
3396 goto bail0;
3397 }
3398 /* freed below */
3399 file = (FcChar8 *) malloc (strlen ((char *) dir) + 1 + FC_MAX_FILE_LEN + 1);
3400 if (!file)
3401 {
3402 ret = FcFalse;
3403 goto bail1;
3404 }
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003405
Keith Packard2d9c79c2004-12-05 05:03:52 +00003406 strcpy ((char *) file, (char *) dir);
3407 strcat ((char *) file, "/");
3408 base = file + strlen ((char *) file);
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003409
Patrick Hallerd570a842016-01-09 03:06:31 +01003410 files = FcStrSetCreateEx (FCSS_GROW_BY_64);
Keith Packard2d9c79c2004-12-05 05:03:52 +00003411 if (!files)
3412 {
3413 ret = FcFalse;
3414 goto bail2;
3415 }
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003416
Keith Packard2d9c79c2004-12-05 05:03:52 +00003417 if (FcDebug () & FC_DBG_CONFIG)
3418 printf ("\tScanning config dir %s\n", dir);
Akira TAGOH34b5c942018-02-05 12:47:01 +09003419
3420 if (load)
3421 FcConfigAddConfigDir (config, dir);
3422
Keith Packard2d9c79c2004-12-05 05:03:52 +00003423 while (ret && (e = readdir (d)))
3424 {
Patrick Lam82457712005-09-11 02:16:09 +00003425 int d_len;
3426#define TAIL ".conf"
3427#define TAIL_LEN 5
Keith Packard2d9c79c2004-12-05 05:03:52 +00003428 /*
Patrick Lam82457712005-09-11 02:16:09 +00003429 * Add all files of the form [0-9]*.conf
Keith Packard2d9c79c2004-12-05 05:03:52 +00003430 */
Akira TAGOHa57647e2018-11-12 05:01:50 +00003431 d_len = strlen (e->d_name);
Keith Packard2d9c79c2004-12-05 05:03:52 +00003432 if ('0' <= e->d_name[0] && e->d_name[0] <= '9' &&
Patrick Lam82457712005-09-11 02:16:09 +00003433 d_len > TAIL_LEN &&
3434 strcmp (e->d_name + d_len - TAIL_LEN, TAIL) == 0)
Keith Packard2d9c79c2004-12-05 05:03:52 +00003435 {
3436 strcpy ((char *) base, (char *) e->d_name);
3437 if (!FcStrSetAdd (files, file))
3438 {
3439 ret = FcFalse;
3440 goto bail3;
3441 }
3442 }
3443 }
3444 if (ret)
3445 {
3446 int i;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003447 qsort (files->strs, files->num, sizeof (FcChar8 *),
Keith Packard9419bb32006-09-09 21:21:01 -07003448 (int (*)(const void *, const void *)) FcSortCmpStr);
Keith Packard2d9c79c2004-12-05 05:03:52 +00003449 for (i = 0; ret && i < files->num; i++)
Akira TAGOHef748b32018-01-23 22:27:17 +09003450 ret = _FcConfigParse (config, files->strs[i], complain, load);
Keith Packard2d9c79c2004-12-05 05:03:52 +00003451 }
3452bail3:
3453 FcStrSetDestroy (files);
3454bail2:
3455 free (file);
3456bail1:
3457 closedir (d);
3458bail0:
3459 return ret || !complain;
3460}
3461
Akira TAGOH12b75012015-06-11 17:30:04 +09003462static FcBool
3463FcConfigParseAndLoadFromMemoryInternal (FcConfig *config,
3464 const FcChar8 *filename,
3465 const FcChar8 *buffer,
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003466 FcBool complain,
3467 FcBool load)
Akira TAGOH12b75012015-06-11 17:30:04 +09003468{
3469
3470 XML_Parser p;
3471 size_t len;
3472 FcConfigParse parse;
3473 FcBool error = FcTrue;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003474 FcMatchKind k;
3475 FcPtrListIter liter;
Akira TAGOH12b75012015-06-11 17:30:04 +09003476
3477#ifdef ENABLE_LIBXML2
3478 xmlSAXHandler sax;
3479#else
Akira TAGOH5b6af242017-07-11 15:34:50 +09003480 void *buf;
Akira TAGOH12b75012015-06-11 17:30:04 +09003481 const FcChar8 *s;
3482 size_t buflen;
3483#endif
3484
3485 if (!buffer)
3486 return FcFalse;
3487 len = strlen ((const char *) buffer);
3488 if (FcDebug () & FC_DBG_CONFIG)
Akira TAGOHe73b5dc2017-11-16 11:37:36 +09003489 printf ("\t%s config file from %s\n", load ? "Loading" : "Scanning", filename);
Akira TAGOH12b75012015-06-11 17:30:04 +09003490
3491#ifdef ENABLE_LIBXML2
3492 memset(&sax, 0, sizeof(sax));
3493
3494 sax.internalSubset = FcInternalSubsetDecl;
3495 sax.externalSubset = FcExternalSubsetDecl;
3496 sax.startElement = FcStartElement;
3497 sax.endElement = FcEndElement;
3498 sax.characters = FcCharacterData;
3499
3500 p = xmlCreatePushParserCtxt (&sax, &parse, NULL, 0, (const char *) filename);
3501#else
3502 p = XML_ParserCreate ("UTF-8");
3503#endif
3504
3505 if (!p)
3506 goto bail1;
3507
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003508 if (!FcConfigParseInit (&parse, filename, config, p, load))
Akira TAGOH12b75012015-06-11 17:30:04 +09003509 goto bail2;
3510
3511#ifndef ENABLE_LIBXML2
3512
3513 XML_SetUserData (p, &parse);
3514
3515 XML_SetDoctypeDeclHandler (p, FcStartDoctypeDecl, FcEndDoctypeDecl);
3516 XML_SetElementHandler (p, FcStartElement, FcEndElement);
3517 XML_SetCharacterDataHandler (p, FcCharacterData);
Akira TAGOH6715a142022-11-25 21:15:32 +09003518
Akira TAGOH12b75012015-06-11 17:30:04 +09003519#endif /* ENABLE_LIBXML2 */
3520
3521#ifndef ENABLE_LIBXML2
3522 s = buffer;
3523 do {
3524 buf = XML_GetBuffer (p, BUFSIZ);
3525 if (!buf)
3526 {
3527 FcConfigMessage (&parse, FcSevereError, "cannot get parse buffer");
3528 goto bail3;
3529 }
3530 if (len > BUFSIZ)
3531 {
3532 buflen = BUFSIZ;
3533 len -= BUFSIZ;
3534 }
3535 else
3536 {
3537 buflen = len;
3538 len = 0;
3539 }
3540 memcpy (buf, s, buflen);
3541 s = s + buflen;
3542#endif
3543
3544#ifdef ENABLE_LIBXML2
Akira TAGOH5b6af242017-07-11 15:34:50 +09003545 if (xmlParseChunk (p, (const char *)buffer, len, len == 0))
Akira TAGOH12b75012015-06-11 17:30:04 +09003546#else
3547 if (!XML_ParseBuffer (p, buflen, buflen == 0))
3548#endif
3549 {
3550 FcConfigMessage (&parse, FcSevereError, "%s",
3551 XML_ErrorString (XML_GetErrorCode (p)));
3552 goto bail3;
3553 }
3554#ifndef ENABLE_LIBXML2
3555 } while (buflen != 0);
3556#endif
3557 error = parse.error;
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003558 if (load)
3559 {
3560 for (k = FcMatchKindBegin; k < FcMatchKindEnd; k++)
3561 {
3562 FcPtrListIter iter;
3563
3564 FcPtrListIterInit (parse.ruleset->subst[k], &iter);
3565 if (FcPtrListIterIsValid (parse.ruleset->subst[k], &iter))
3566 {
3567 FcPtrListIterInitAtLast (parse.config->subst[k], &iter);
3568 FcRuleSetReference (parse.ruleset);
3569 FcPtrListIterAdd (parse.config->subst[k], &iter, parse.ruleset);
3570 }
3571 }
3572 }
3573 FcPtrListIterInitAtLast (parse.config->rulesetList, &liter);
3574 FcRuleSetReference (parse.ruleset);
3575 FcPtrListIterAdd (parse.config->rulesetList, &liter, parse.ruleset);
Akira TAGOH12b75012015-06-11 17:30:04 +09003576bail3:
3577 FcConfigCleanup (&parse);
3578bail2:
3579 XML_ParserFree (p);
3580bail1:
3581 if (error && complain)
3582 {
Akira TAGOHe73b5dc2017-11-16 11:37:36 +09003583 FcConfigMessage (0, FcSevereError, "Cannot %s config file from %s", load ? "load" : "scan", filename);
Akira TAGOH12b75012015-06-11 17:30:04 +09003584 return FcFalse;
3585 }
Akira TAGOH97898b12018-01-03 22:15:11 +09003586 if (FcDebug () & FC_DBG_CONFIG)
3587 printf ("\t%s config file from %s done\n", load ? "Loading" : "Scanning", filename);
Akira TAGOH12b75012015-06-11 17:30:04 +09003588 return FcTrue;
3589}
3590
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003591static FcBool
3592_FcConfigParse (FcConfig *config,
3593 const FcChar8 *name,
3594 FcBool complain,
3595 FcBool load)
Akira TAGOH12b75012015-06-11 17:30:04 +09003596{
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003597 FcChar8 *filename = NULL, *realfilename = NULL;
Patrick Lam3bfae752005-12-21 03:31:19 +00003598 int fd;
Keith Packardc2e7c612002-02-18 22:29:28 +00003599 int len;
Akira TAGOH12b75012015-06-11 17:30:04 +09003600 FcStrBuf sbuf;
Patrick Lame99f0f02005-09-29 20:53:30 +00003601 char buf[BUFSIZ];
Akira TAGOHfcada522019-08-28 17:46:03 +09003602 FcBool ret = FcFalse, complain_again = complain;
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003603 FcStrBuf reason;
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003604
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003605 FcStrBufInit (&reason, NULL, 0);
Akira TAGOH470e92c2012-04-12 14:01:25 +09003606#ifdef _WIN32
Francesco Pretto16bbb532021-10-26 19:31:23 +02003607 _ensureWin32GettersReady();
Akira TAGOH470e92c2012-04-12 14:01:25 +09003608#endif
3609
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003610 filename = FcConfigGetFilename (config, name);
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003611 if (!filename)
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003612 {
3613 FcStrBufString (&reason, (FcChar8 *)"No such file: ");
3614 FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
Keith Packardc2e7c612002-02-18 22:29:28 +00003615 goto bail0;
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003616 }
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003617 realfilename = FcConfigRealFilename (config, name);
3618 if (!realfilename)
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003619 {
3620 FcStrBufString (&reason, (FcChar8 *)"No such realfile: ");
3621 FcStrBufString (&reason, name ? name : (FcChar8 *)"(null)");
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003622 goto bail0;
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003623 }
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003624 if (FcStrSetMember (config->availConfigFiles, realfilename))
Patrick Lamcb6d97e2005-11-30 22:13:21 +00003625 {
3626 FcStrFree (filename);
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003627 FcStrFree (realfilename);
Patrick Lamcb6d97e2005-11-30 22:13:21 +00003628 return FcTrue;
3629 }
3630
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003631 if (load)
Keith Packard9dac3c52002-08-31 22:17:32 +00003632 {
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003633 if (!FcStrSetAdd (config->configFiles, filename))
3634 goto bail0;
Keith Packard9dac3c52002-08-31 22:17:32 +00003635 }
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003636 if (!FcStrSetAdd (config->availConfigFiles, realfilename))
3637 goto bail0;
Keith Packard4aded3e2002-06-21 07:01:11 +00003638
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003639 if (FcFileIsDir (realfilename))
Keith Packard2d9c79c2004-12-05 05:03:52 +00003640 {
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003641 ret = FcConfigParseAndLoadDir (config, name, realfilename, complain, load);
Keith Packard2d9c79c2004-12-05 05:03:52 +00003642 FcStrFree (filename);
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003643 FcStrFree (realfilename);
Keith Packard2d9c79c2004-12-05 05:03:52 +00003644 return ret;
3645 }
3646
Akira TAGOH12b75012015-06-11 17:30:04 +09003647 FcStrBufInit (&sbuf, NULL, 0);
Keith Packard2d9c79c2004-12-05 05:03:52 +00003648
Tom Anderson7ad010e2018-04-11 17:24:43 -07003649 fd = FcOpen ((char *) realfilename, O_RDONLY);
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003650 if (fd == -1)
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003651 {
3652 FcStrBufString (&reason, (FcChar8 *)"Unable to open ");
3653 FcStrBufString (&reason, realfilename);
Akira TAGOH12b75012015-06-11 17:30:04 +09003654 goto bail1;
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003655 }
Behdad Esfahbodd0d1f392010-04-12 12:10:05 -04003656
Keith Packardc2e7c612002-02-18 22:29:28 +00003657 do {
Patrick Lam3bfae752005-12-21 03:31:19 +00003658 len = read (fd, buf, BUFSIZ);
Keith Packardc2e7c612002-02-18 22:29:28 +00003659 if (len < 0)
Keith Packard80c053b2002-02-28 16:51:48 +00003660 {
Akira TAGOHcfb21c72018-05-13 14:48:10 +09003661 int errno_ = errno;
3662 char ebuf[BUFSIZ+1];
3663
3664#if HAVE_STRERROR_R
Tom Anderson1451f822018-07-25 16:35:54 -07003665 strerror_r (errno_, ebuf, BUFSIZ);
Akira TAGOHcfb21c72018-05-13 14:48:10 +09003666#elif HAVE_STRERROR
3667 char *tmp = strerror (errno_);
3668 size_t len = strlen (tmp);
Akira TAGOH88156412020-10-30 17:39:37 +09003669 memcpy (ebuf, tmp, FC_MIN (BUFSIZ, len));
Akira TAGOHcfb21c72018-05-13 14:48:10 +09003670 ebuf[FC_MIN (BUFSIZ, len)] = 0;
3671#else
3672 ebuf[0] = 0;
3673#endif
3674 FcConfigMessage (0, FcSevereError, "failed reading config file: %s: %s (errno %d)", realfilename, ebuf, errno_);
Akira TAGOH12b75012015-06-11 17:30:04 +09003675 close (fd);
3676 goto bail1;
Keith Packard80c053b2002-02-28 16:51:48 +00003677 }
Akira TAGOH12b75012015-06-11 17:30:04 +09003678 FcStrBufData (&sbuf, (const FcChar8 *)buf, len);
Keith Packardc2e7c612002-02-18 22:29:28 +00003679 } while (len != 0);
Patrick Lam3bfae752005-12-21 03:31:19 +00003680 close (fd);
Akira TAGOH12b75012015-06-11 17:30:04 +09003681
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003682 ret = FcConfigParseAndLoadFromMemoryInternal (config, filename, FcStrBufDoneStatic (&sbuf), complain, load);
Akira TAGOHfcada522019-08-28 17:46:03 +09003683 complain_again = FcFalse; /* no need to reclaim here */
Akira TAGOH12b75012015-06-11 17:30:04 +09003684bail1:
Akira TAGOH12b75012015-06-11 17:30:04 +09003685 FcStrBufDestroy (&sbuf);
Keith Packardc2e7c612002-02-18 22:29:28 +00003686bail0:
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003687 if (filename)
3688 FcStrFree (filename);
3689 if (realfilename)
3690 FcStrFree (realfilename);
Akira TAGOHfcada522019-08-28 17:46:03 +09003691 if (!complain)
3692 return FcTrue;
3693 if (!ret && complain_again)
Keith Packard24330d22002-02-14 23:34:13 +00003694 {
Keith Packardc2e7c612002-02-18 22:29:28 +00003695 if (name)
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003696 FcConfigMessage (0, FcSevereError, "Cannot %s config file \"%s\": %s", load ? "load" : "scan", name, FcStrBufDoneStatic (&reason));
Keith Packard24330d22002-02-14 23:34:13 +00003697 else
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003698 FcConfigMessage (0, FcSevereError, "Cannot %s default config file: %s", load ? "load" : "scan", FcStrBufDoneStatic (&reason));
3699 FcStrBufDestroy (&reason);
Keith Packard24330d22002-02-14 23:34:13 +00003700 return FcFalse;
3701 }
Akira TAGOHcd51cb22019-10-21 16:17:42 +09003702 FcStrBufDestroy (&reason);
Akira TAGOH36f46ba2019-07-22 05:35:21 +00003703 return ret;
Keith Packard24330d22002-02-14 23:34:13 +00003704}
Akira TAGOH9a0fcb92014-03-27 15:10:44 +09003705
3706FcBool
3707FcConfigParseOnly (FcConfig *config,
3708 const FcChar8 *name,
3709 FcBool complain)
3710{
3711 return _FcConfigParse (config, name, complain, FcFalse);
3712}
3713
3714FcBool
3715FcConfigParseAndLoad (FcConfig *config,
3716 const FcChar8 *name,
3717 FcBool complain)
3718{
3719 return _FcConfigParse (config, name, complain, FcTrue);
3720}
3721
3722FcBool
3723FcConfigParseAndLoadFromMemory (FcConfig *config,
3724 const FcChar8 *buffer,
3725 FcBool complain)
3726{
3727 return FcConfigParseAndLoadFromMemoryInternal (config, (const FcChar8 *)"memory", buffer, complain, FcTrue);
3728}
3729
Francesco Pretto16bbb532021-10-26 19:31:23 +02003730#ifdef _WIN32
3731static void
3732_ensureWin32GettersReady()
3733{
3734 if (!pGetSystemWindowsDirectory)
3735 {
3736 HMODULE hk32 = GetModuleHandleA("kernel32.dll");
3737 if (!(pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetProcAddress(hk32, "GetSystemWindowsDirectoryA")))
3738 pGetSystemWindowsDirectory = (pfnGetSystemWindowsDirectory)GetWindowsDirectory;
3739 }
3740 if (!pSHGetFolderPathA)
3741 {
3742 HMODULE hSh = LoadLibraryA("shfolder.dll");
3743 /* the check is done later, because there is no provided fallback */
3744 if (hSh)
3745 pSHGetFolderPathA = (pfnSHGetFolderPathA)GetProcAddress(hSh, "SHGetFolderPathA");
3746 }
3747}
3748#endif // _WIN32
3749
Keith Packard23816bf2006-09-05 02:24:01 -07003750#define __fcxml__
3751#include "fcaliastail.h"
3752#undef __fcxml__