fcxml.c 75.1 KB
Newer Older
Keith Packard's avatar
Keith Packard committed
1
/*
2
 * fontconfig/src/fcxml.c
Keith Packard's avatar
Keith Packard committed
3
 *
4
 * Copyright © 2002 Keith Packard
Keith Packard's avatar
Keith Packard committed
5 6 7 8 9
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
10
 * documentation, and that the name of the author(s) not be used in
Keith Packard's avatar
Keith Packard committed
11
 * advertising or publicity pertaining to distribution of the software without
12
 * specific, written prior permission.  The authors make no
Keith Packard's avatar
Keith Packard committed
13 14 15
 * representations about the suitability of this software for any purpose.  It
 * is provided "as is" without express or implied warranty.
 *
16
 * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
Keith Packard's avatar
Keith Packard committed
17
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18
 * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
Keith Packard's avatar
Keith Packard committed
19 20 21 22 23 24
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 */

25
#include "fcint.h"
Patrick Lam's avatar
Patrick Lam committed
26
#include <fcntl.h>
Keith Packard's avatar
Keith Packard committed
27
#include <stdarg.h>
28
#include <dirent.h>
29

30
#ifdef ENABLE_LIBXML2
31 32 33 34 35 36 37 38 39 40 41 42

#include <libxml/parser.h>

#define XML_Char			xmlChar
#define XML_Parser			xmlParserCtxtPtr
#define XML_ParserFree			xmlFreeParserCtxt
#define XML_GetCurrentLineNumber	xmlSAX2GetLineNumber
#define XML_GetErrorCode		xmlCtxtGetLastError
#define XML_ErrorString(Error)		(Error)->message

#else /* ENABLE_LIBXML2 */

43 44 45
#ifndef HAVE_XMLPARSE_H
#define HAVE_XMLPARSE_H 0
#endif
46

47 48 49 50 51
#if HAVE_XMLPARSE_H
#include <xmlparse.h>
#else
#include <expat.h>
#endif
Keith Packard's avatar
Keith Packard committed
52

53 54
#endif /* ENABLE_LIBXML2 */

Tor Lillqvist's avatar
Tor Lillqvist committed
55
#ifdef _WIN32
56
#include <mbstring.h>
57
extern FcChar8 fontconfig_instprefix[];
Tor Lillqvist's avatar
Tor Lillqvist committed
58 59
#endif

Akira TAGOH's avatar
Akira TAGOH committed
60 61 62
static FcChar8  *__fc_userdir = NULL;
static FcChar8  *__fc_userconf = NULL;

63 64
static void
FcExprDestroy (FcExpr *e);
Keith Packard's avatar
Keith Packard committed
65 66 67 68 69 70 71 72

void
FcTestDestroy (FcTest *test)
{
    FcExprDestroy (test->expr);
    free (test);
}

73 74 75
void
FcRuleDestroy (FcRule *rule)
{
Akira TAGOH's avatar
Akira TAGOH committed
76 77
    FcRule *n = rule->next;

78 79 80 81 82 83 84
    switch (rule->type) {
    case FcRuleTest:
	FcTestDestroy (rule->u.test);
	break;
    case FcRuleEdit:
	FcEditDestroy (rule->u.edit);
	break;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
85
    case FcRuleUnknown:
86 87 88 89
    default:
	break;
    }
    free (rule);
Akira TAGOH's avatar
Akira TAGOH committed
90 91
    if (n)
	FcRuleDestroy (n);
92 93
}

94
static FcExpr *
95
FcExprCreateInteger (FcConfig *config, int i)
Keith Packard's avatar
Keith Packard committed
96
{
97
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
98 99 100 101 102 103 104 105
    if (e)
    {
	e->op = FcOpInteger;
	e->u.ival = i;
    }
    return e;
}

106
static FcExpr *
107
FcExprCreateDouble (FcConfig *config, double d)
Keith Packard's avatar
Keith Packard committed
108
{
109
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
110 111 112 113 114 115 116 117
    if (e)
    {
	e->op = FcOpDouble;
	e->u.dval = d;
    }
    return e;
}

118
static FcExpr *
119
FcExprCreateString (FcConfig *config, const FcChar8 *s)
Keith Packard's avatar
Keith Packard committed
120
{
121
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
122 123 124
    if (e)
    {
	e->op = FcOpString;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
125
	e->u.sval = FcStrdup (s);
Keith Packard's avatar
Keith Packard committed
126 127 128 129
    }
    return e;
}

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
static FcExprMatrix *
FcExprMatrixCopyShallow (const FcExprMatrix *matrix)
{
  FcExprMatrix *m = malloc (sizeof (FcExprMatrix));
  if (m)
  {
    *m = *matrix;
  }
  return m;
}

static void
FcExprMatrixFreeShallow (FcExprMatrix *m)
{
  if (!m)
    return;

  free (m);
}

static void
FcExprMatrixFree (FcExprMatrix *m)
{
  if (!m)
    return;

  FcExprDestroy (m->xx);
  FcExprDestroy (m->xy);
  FcExprDestroy (m->yx);
  FcExprDestroy (m->yy);

  free (m);
}

164
static FcExpr *
165
FcExprCreateMatrix (FcConfig *config, const FcExprMatrix *matrix)
Keith Packard's avatar
Keith Packard committed
166
{
167
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
168 169 170
    if (e)
    {
	e->op = FcOpMatrix;
171
	e->u.mexpr = FcExprMatrixCopyShallow (matrix);
Keith Packard's avatar
Keith Packard committed
172 173 174 175
    }
    return e;
}

176 177 178 179 180 181 182 183 184 185 186 187
static FcExpr *
FcExprCreateRange (FcConfig *config, FcRange *range)
{
    FcExpr *e = FcConfigAllocExpr (config);
    if (e)
    {
	e->op = FcOpRange;
	e->u.rval = FcRangeCopy (range);
    }
    return e;
}

188
static FcExpr *
189
FcExprCreateBool (FcConfig *config, FcBool b)
Keith Packard's avatar
Keith Packard committed
190
{
191
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
192 193 194 195 196 197 198 199
    if (e)
    {
	e->op = FcOpBool;
	e->u.bval = b;
    }
    return e;
}

Akira TAGOH's avatar
Akira TAGOH committed
200 201 202 203 204 205 206 207 208 209 210 211
static FcExpr *
FcExprCreateCharSet (FcConfig *config, FcCharSet *charset)
{
    FcExpr *e = FcConfigAllocExpr (config);
    if (e)
    {
	e->op = FcOpCharSet;
	e->u.cval = FcCharSetCopy (charset);
    }
    return e;
}

Akira TAGOH's avatar
Akira TAGOH committed
212 213 214 215 216 217 218 219 220 221 222 223
static FcExpr *
FcExprCreateLangSet (FcConfig *config, FcLangSet *langset)
{
    FcExpr *e = FcConfigAllocExpr (config);
    if (e)
    {
	e->op = FcOpLangSet;
	e->u.lval = FcLangSetCopy (langset);
    }
    return e;
}

224
static FcExpr *
225
FcExprCreateName (FcConfig *config, FcExprName name)
Keith Packard's avatar
Keith Packard committed
226
{
227
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
228 229 230
    if (e)
    {
	e->op = FcOpField;
231
	e->u.name = name;
Keith Packard's avatar
Keith Packard committed
232 233 234 235
    }
    return e;
}

236
static FcExpr *
237
FcExprCreateConst (FcConfig *config, const FcChar8 *constant)
Keith Packard's avatar
Keith Packard committed
238
{
239
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
240 241 242
    if (e)
    {
	e->op = FcOpConst;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
243
	e->u.constant = FcStrdup (constant);
Keith Packard's avatar
Keith Packard committed
244 245 246 247
    }
    return e;
}

248
static FcExpr *
249
FcExprCreateOp (FcConfig *config, FcExpr *left, FcOp op, FcExpr *right)
Keith Packard's avatar
Keith Packard committed
250
{
251
    FcExpr *e = FcConfigAllocExpr (config);
Keith Packard's avatar
Keith Packard committed
252 253 254 255 256 257 258 259 260
    if (e)
    {
	e->op = op;
	e->u.tree.left = left;
	e->u.tree.right = right;
    }
    return e;
}

261
static void
Keith Packard's avatar
Keith Packard committed
262 263
FcExprDestroy (FcExpr *e)
{
264 265
    if (!e)
	return;
266
    switch (FC_OP_GET_OP (e->op)) {
Keith Packard's avatar
Keith Packard committed
267 268 269 270 271
    case FcOpInteger:
	break;
    case FcOpDouble:
	break;
    case FcOpString:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
272
	FcFree (e->u.sval);
Keith Packard's avatar
Keith Packard committed
273 274
	break;
    case FcOpMatrix:
275
	FcExprMatrixFree (e->u.mexpr);
Keith Packard's avatar
Keith Packard committed
276
	break;
Akira TAGOH's avatar
Akira TAGOH committed
277
    case FcOpRange:
278
	FcRangeDestroy (e->u.rval);
Akira TAGOH's avatar
Akira TAGOH committed
279
	break;
Keith Packard's avatar
Keith Packard committed
280 281 282
    case FcOpCharSet:
	FcCharSetDestroy (e->u.cval);
	break;
Akira TAGOH's avatar
Akira TAGOH committed
283 284 285
    case FcOpLangSet:
	FcLangSetDestroy (e->u.lval);
	break;
Keith Packard's avatar
Keith Packard committed
286 287 288 289 290
    case FcOpBool:
	break;
    case FcOpField:
	break;
    case FcOpConst:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
291
	FcFree (e->u.constant);
Keith Packard's avatar
Keith Packard committed
292 293 294 295 296 297 298
	break;
    case FcOpAssign:
    case FcOpAssignReplace:
    case FcOpPrepend:
    case FcOpPrependFirst:
    case FcOpAppend:
    case FcOpAppendLast:
299 300
    case FcOpDelete:
    case FcOpDeleteAll:
Keith Packard's avatar
Keith Packard committed
301 302 303 304 305 306 307 308 309
	break;
    case FcOpOr:
    case FcOpAnd:
    case FcOpEqual:
    case FcOpNotEqual:
    case FcOpLess:
    case FcOpLessEqual:
    case FcOpMore:
    case FcOpMoreEqual:
310
    case FcOpContains:
311
    case FcOpListing:
312
    case FcOpNotContains:
Keith Packard's avatar
Keith Packard committed
313 314 315 316 317 318 319 320 321
    case FcOpPlus:
    case FcOpMinus:
    case FcOpTimes:
    case FcOpDivide:
    case FcOpQuest:
    case FcOpComma:
	FcExprDestroy (e->u.tree.right);
	/* fall through */
    case FcOpNot:
322 323 324 325
    case FcOpFloor:
    case FcOpCeil:
    case FcOpRound:
    case FcOpTrunc:
Keith Packard's avatar
Keith Packard committed
326 327 328 329 330 331
	FcExprDestroy (e->u.tree.left);
	break;
    case FcOpNil:
    case FcOpInvalid:
	break;
    }
332 333

    e->op = FcOpNil;
Keith Packard's avatar
Keith Packard committed
334 335 336 337 338 339 340
}

void
FcEditDestroy (FcEdit *e)
{
    if (e->expr)
	FcExprDestroy (e->expr);
341
    free (e);
Keith Packard's avatar
Keith Packard committed
342 343
}

344 345 346 347
typedef enum _FcElement {
    FcElementNone,
    FcElementFontconfig,
    FcElementDir,
348
    FcElementCacheDir,
349 350 351 352 353 354 355
    FcElementCache,
    FcElementInclude,
    FcElementConfig,
    FcElementMatch,
    FcElementAlias,
	
    FcElementBlank,
356
    FcElementRescan,
357 358 359 360 361 362

    FcElementPrefer,
    FcElementAccept,
    FcElementDefault,
    FcElementFamily,

363 364 365 366
    FcElementSelectfont,
    FcElementAcceptfont,
    FcElementRejectfont,
    FcElementGlob,
367 368
    FcElementPattern,
    FcElementPatelt,
369

370 371 372 373 374 375
    FcElementTest,
    FcElementEdit,
    FcElementInt,
    FcElementDouble,
    FcElementString,
    FcElementMatrix,
Akira TAGOH's avatar
Akira TAGOH committed
376
    FcElementRange,
377
    FcElementBool,
Akira TAGOH's avatar
Akira TAGOH committed
378
    FcElementCharSet,
Akira TAGOH's avatar
Akira TAGOH committed
379
    FcElementLangSet,
380 381 382 383 384 385 386 387 388 389
    FcElementName,
    FcElementConst,
    FcElementOr,
    FcElementAnd,
    FcElementEq,
    FcElementNotEq,
    FcElementLess,
    FcElementLessEq,
    FcElementMore,
    FcElementMoreEq,
390 391
    FcElementContains,
    FcElementNotContains,
392 393 394 395 396 397
    FcElementPlus,
    FcElementMinus,
    FcElementTimes,
    FcElementDivide,
    FcElementNot,
    FcElementIf,
398 399 400 401
    FcElementFloor,
    FcElementCeil,
    FcElementRound,
    FcElementTrunc,
402 403 404
    FcElementUnknown
} FcElement;

405
static const struct {
Patrick Lam's avatar
Patrick Lam committed
406 407 408 409 410
    const char  name[16];
    FcElement   element;
} fcElementMap[] = {
    { "fontconfig",	FcElementFontconfig },
    { "dir",		FcElementDir },
411
    { "cachedir",	FcElementCacheDir },
Patrick Lam's avatar
Patrick Lam committed
412 413 414 415 416
    { "cache",		FcElementCache },
    { "include",	FcElementInclude },
    { "config",		FcElementConfig },
    { "match",		FcElementMatch },
    { "alias",		FcElementAlias },
Behdad Esfahbod's avatar
Behdad Esfahbod committed
417

Patrick Lam's avatar
Patrick Lam committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438
    { "blank",		FcElementBlank },
    { "rescan",		FcElementRescan },

    { "prefer",		FcElementPrefer },
    { "accept",		FcElementAccept },
    { "default",	FcElementDefault },
    { "family",		FcElementFamily },

    { "selectfont",	FcElementSelectfont },
    { "acceptfont",	FcElementAcceptfont },
    { "rejectfont",	FcElementRejectfont },
    { "glob",		FcElementGlob },
    { "pattern",	FcElementPattern },
    { "patelt",		FcElementPatelt },

    { "test",		FcElementTest },
    { "edit",		FcElementEdit },
    { "int",		FcElementInt },
    { "double",		FcElementDouble },
    { "string",		FcElementString },
    { "matrix",		FcElementMatrix },
Akira TAGOH's avatar
Akira TAGOH committed
439
    { "range",		FcElementRange },
Patrick Lam's avatar
Patrick Lam committed
440
    { "bool",		FcElementBool },
Akira TAGOH's avatar
Akira TAGOH committed
441
    { "charset",	FcElementCharSet },
Akira TAGOH's avatar
Akira TAGOH committed
442
    { "langset",	FcElementLangSet },
Patrick Lam's avatar
Patrick Lam committed
443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    { "name",		FcElementName },
    { "const",		FcElementConst },
    { "or",		FcElementOr },
    { "and",		FcElementAnd },
    { "eq",		FcElementEq },
    { "not_eq",		FcElementNotEq },
    { "less",		FcElementLess },
    { "less_eq",	FcElementLessEq },
    { "more",		FcElementMore },
    { "more_eq",	FcElementMoreEq },
    { "contains",	FcElementContains },
    { "not_contains",	FcElementNotContains },
    { "plus",		FcElementPlus },
    { "minus",		FcElementMinus },
    { "times",		FcElementTimes },
    { "divide",		FcElementDivide },
    { "not",		FcElementNot },
    { "if",		FcElementIf },
    { "floor",		FcElementFloor },
    { "ceil",		FcElementCeil },
    { "round",		FcElementRound },
    { "trunc",		FcElementTrunc },
};
#define NUM_ELEMENT_MAPS (int) (sizeof fcElementMap / sizeof fcElementMap[0])

468 469 470 471 472
static FcElement
FcElementMap (const XML_Char *name)
{

    int	    i;
Patrick Lam's avatar
Patrick Lam committed
473
    for (i = 0; i < NUM_ELEMENT_MAPS; i++)
474 475 476 477 478 479 480 481 482 483
	if (!strcmp ((char *) name, fcElementMap[i].name))
	    return fcElementMap[i].element;
    return FcElementUnknown;
}

typedef struct _FcPStack {
    struct _FcPStack   *prev;
    FcElement		element;
    FcChar8		**attr;
    FcStrBuf		str;
484
    FcChar8            *attr_buf_static[16];
485
} FcPStack;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
486

487 488 489 490 491 492
typedef enum _FcVStackTag {
    FcVStackNone,

    FcVStackString,
    FcVStackFamily,
    FcVStackConstant,
493
    FcVStackGlob,
494
    FcVStackName,
495
    FcVStackPattern,
Behdad Esfahbod's avatar
Behdad Esfahbod committed
496

497 498 499
    FcVStackPrefer,
    FcVStackAccept,
    FcVStackDefault,
Behdad Esfahbod's avatar
Behdad Esfahbod committed
500

501 502 503
    FcVStackInteger,
    FcVStackDouble,
    FcVStackMatrix,
Akira TAGOH's avatar
Akira TAGOH committed
504
    FcVStackRange,
505
    FcVStackBool,
Akira TAGOH's avatar
Akira TAGOH committed
506
    FcVStackCharSet,
Akira TAGOH's avatar
Akira TAGOH committed
507
    FcVStackLangSet,
Behdad Esfahbod's avatar
Behdad Esfahbod committed
508

509 510 511 512 513 514 515 516 517 518 519 520 521 522
    FcVStackTest,
    FcVStackExpr,
    FcVStackEdit
} FcVStackTag;

typedef struct _FcVStack {
    struct _FcVStack	*prev;
    FcPStack		*pstack;	/* related parse element */
    FcVStackTag		tag;
    union {
	FcChar8		*string;

	int		integer;
	double		_double;
523
	FcExprMatrix	*matrix;
524
	FcRange		*range;
525
	FcBool		bool_;
Akira TAGOH's avatar
Akira TAGOH committed
526
	FcCharSet	*charset;
Akira TAGOH's avatar
Akira TAGOH committed
527
	FcLangSet	*langset;
528
	FcExprName	name;
529 530 531 532 533 534

	FcTest		*test;
	FcQual		qual;
	FcOp		op;
	FcExpr		*expr;
	FcEdit		*edit;
535 536

	FcPattern	*pattern;
537 538 539 540 541 542 543 544 545 546
    } u;
} FcVStack;

typedef struct _FcConfigParse {
    FcPStack	    *pstack;
    FcVStack	    *vstack;
    FcBool	    error;
    const FcChar8   *name;
    FcConfig	    *config;
    XML_Parser	    parser;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
547
    unsigned int    pstack_static_used;
548
    FcPStack        pstack_static[8];
Behdad Esfahbod's avatar
Behdad Esfahbod committed
549
    unsigned int    vstack_static_used;
550
    FcVStack        vstack_static[64];
551 552
} FcConfigParse;

553 554 555 556
typedef enum _FcConfigSeverity {
    FcSevereInfo, FcSevereWarning, FcSevereError
} FcConfigSeverity;

Keith Packard's avatar
Keith Packard committed
557
static void
Patrick Lam's avatar
Patrick Lam committed
558
FcConfigMessage (FcConfigParse *parse, FcConfigSeverity severe, const char *fmt, ...)
Keith Packard's avatar
Keith Packard committed
559
{
Patrick Lam's avatar
Patrick Lam committed
560
    const char	*s = "unknown";
Keith Packard's avatar
Keith Packard committed
561 562 563
    va_list	args;

    va_start (args, fmt);
564 565 566 567 568 569

    switch (severe) {
    case FcSevereInfo: s = "info"; break;
    case FcSevereWarning: s = "warning"; break;
    case FcSevereError: s = "error"; break;
    }
570 571 572
    if (parse)
    {
	if (parse->name)
573
	    fprintf (stderr, "Fontconfig %s: \"%s\", line %d: ", s,
574
		     parse->name, (int)XML_GetCurrentLineNumber (parse->parser));
575
	else
576
	    fprintf (stderr, "Fontconfig %s: line %d: ", s,
577
		     (int)XML_GetCurrentLineNumber (parse->parser));
578 579
	if (severe >= FcSevereError)
	    parse->error = FcTrue;
580 581
    }
    else
582
	fprintf (stderr, "Fontconfig %s: ", s);
Keith Packard's avatar
Keith Packard committed
583 584 585 586 587
    vfprintf (stderr, fmt, args);
    fprintf (stderr, "\n");
    va_end (args);
}

588

589 590 591 592
static FcExpr *
FcPopExpr (FcConfigParse *parse);


Patrick Lam's avatar
Patrick Lam committed
593
static const char *
594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613
FcTypeName (FcType type)
{
    switch (type) {
    case FcTypeVoid:
	return "void";
    case FcTypeInteger:
    case FcTypeDouble:
	return "number";
    case FcTypeString:
	return "string";
    case FcTypeBool:
	return "bool";
    case FcTypeMatrix:
	return "matrix";
    case FcTypeCharSet:
	return "charset";
    case FcTypeFTFace:
	return "FT_Face";
    case FcTypeLangSet:
	return "langset";
614 615
    case FcTypeRange:
	return "range";
Behdad Esfahbod's avatar
Behdad Esfahbod committed
616
    case FcTypeUnknown:
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
    default:
	return "unknown";
    }
}

static void
FcTypecheckValue (FcConfigParse *parse, FcType value, FcType type)
{
    if (value == FcTypeInteger)
	value = FcTypeDouble;
    if (type == FcTypeInteger)
	type = FcTypeDouble;
    if (value != type)
    {
	if ((value == FcTypeLangSet && type == FcTypeString) ||
632 633 634
	    (value == FcTypeString && type == FcTypeLangSet) ||
	    (value == FcTypeInteger && type == FcTypeRange) ||
	    (value == FcTypeDouble && type == FcTypeRange))
635
	    return;
Akira TAGOH's avatar
Akira TAGOH committed
636
	if (type ==  FcTypeUnknown)
637
	    return;
638 639
	/* It's perfectly fine to use user-define elements in expressions,
	 * so don't warn in that case. */
Akira TAGOH's avatar
Akira TAGOH committed
640
	if (value == FcTypeUnknown)
641
	    return;
642 643 644 645 646 647 648 649 650 651
	FcConfigMessage (parse, FcSevereWarning, "saw %s, expected %s",
			 FcTypeName (value), FcTypeName (type));
    }
}

static void
FcTypecheckExpr (FcConfigParse *parse, FcExpr *expr, FcType type)
{
    const FcObjectType	*o;
    const FcConstant	*c;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
652

653 654 655 656
    /* If parsing the expression failed, some nodes may be NULL */
    if (!expr)
	return;

657
    switch (FC_OP_GET_OP (expr->op)) {
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673
    case FcOpInteger:
    case FcOpDouble:
	FcTypecheckValue (parse, FcTypeDouble, type);
	break;
    case FcOpString:
	FcTypecheckValue (parse, FcTypeString, type);
	break;
    case FcOpMatrix:
	FcTypecheckValue (parse, FcTypeMatrix, type);
	break;
    case FcOpBool:
	FcTypecheckValue (parse, FcTypeBool, type);
	break;
    case FcOpCharSet:
	FcTypecheckValue (parse, FcTypeCharSet, type);
	break;
Akira TAGOH's avatar
Akira TAGOH committed
674 675 676
    case FcOpLangSet:
	FcTypecheckValue (parse, FcTypeLangSet, type);
	break;
677 678 679
    case FcOpRange:
	FcTypecheckValue (parse, FcTypeRange, type);
	break;
680 681 682
    case FcOpNil:
	break;
    case FcOpField:
683
	o = FcNameGetObjectType (FcObjectName (expr->u.name.object));
684 685 686 687 688 689 690 691 692 693 694
	if (o)
	    FcTypecheckValue (parse, o->type, type);
	break;
    case FcOpConst:
	c = FcNameGetConstant (expr->u.constant);
	if (c)
	{
	    o = FcNameGetObjectType (c->object);
	    if (o)
		FcTypecheckValue (parse, o->type, type);
	}
Behdad Esfahbod's avatar
Behdad Esfahbod committed
695 696
        else
            FcConfigMessage (parse, FcSevereWarning,
697 698
                             "invalid constant used : %s",
                             expr->u.constant);
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746
	break;
    case FcOpQuest:
	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.left, type);
	FcTypecheckExpr (parse, expr->u.tree.right->u.tree.right, type);
	break;
    case FcOpAssign:
    case FcOpAssignReplace:
	break;
    case FcOpEqual:
    case FcOpNotEqual:
    case FcOpLess:
    case FcOpLessEqual:
    case FcOpMore:
    case FcOpMoreEqual:
    case FcOpContains:
    case FcOpNotContains:
    case FcOpListing:
	FcTypecheckValue (parse, FcTypeBool, type);
	break;
    case FcOpComma:
    case FcOpOr:
    case FcOpAnd:
    case FcOpPlus:
    case FcOpMinus:
    case FcOpTimes:
    case FcOpDivide:
	FcTypecheckExpr (parse, expr->u.tree.left, type);
	FcTypecheckExpr (parse, expr->u.tree.right, type);
	break;
    case FcOpNot:
	FcTypecheckValue (parse, FcTypeBool, type);
	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeBool);
	break;
    case FcOpFloor:
    case FcOpCeil:
    case FcOpRound:
    case FcOpTrunc:
	FcTypecheckValue (parse, FcTypeDouble, type);
	FcTypecheckExpr (parse, expr->u.tree.left, FcTypeDouble);
	break;
    default:
	break;
    }
}

static FcTest *
FcTestCreate (FcConfigParse *parse,
Behdad Esfahbod's avatar
Behdad Esfahbod committed
747
	      FcMatchKind   kind,
748 749
	      FcQual	    qual,
	      const FcChar8 *field,
750
	      unsigned int  compare,
751 752 753 754 755 756 757 758 759 760
	      FcExpr	    *expr)
{
    FcTest	*test = (FcTest *) malloc (sizeof (FcTest));

    if (test)
    {
	const FcObjectType	*o;
	
	test->kind = kind;
	test->qual = qual;
761
	test->object = FcObjectFromName ((const char *) field);
762 763
	test->op = compare;
	test->expr = expr;
764
	o = FcNameGetObjectType (FcObjectName (test->object));
765 766 767 768 769 770 771 772
	if (o)
	    FcTypecheckExpr (parse, expr, o->type);
    }
    return test;
}

static FcEdit *
FcEditCreate (FcConfigParse	*parse,
773
	      FcObject		object,
774 775 776 777 778 779 780 781 782 783
	      FcOp		op,
	      FcExpr		*expr,
	      FcValueBinding	binding)
{
    FcEdit *e = (FcEdit *) malloc (sizeof (FcEdit));

    if (e)
    {
	const FcObjectType	*o;

784
	e->object = object;
785 786 787
	e->op = op;
	e->expr = expr;
	e->binding = binding;
788
	o = FcNameGetObjectType (FcObjectName (e->object));
789 790 791 792 793 794
	if (o)
	    FcTypecheckExpr (parse, expr, o->type);
    }
    return e;
}

795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813
static FcRule *
FcRuleCreate (FcRuleType type,
	      void       *p)
{
    FcRule *r = (FcRule *) malloc (sizeof (FcRule));

    if (!r)
	return NULL;

    r->next = NULL;
    r->type = type;
    switch (type)
    {
    case FcRuleTest:
	r->u.test = (FcTest *) p;
	break;
    case FcRuleEdit:
	r->u.edit = (FcEdit *) p;
	break;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
814
    case FcRuleUnknown:
815 816 817 818 819 820 821 822 823
    default:
	free (r);
	r = NULL;
	break;
    }

    return r;
}

824
static FcVStack *
825
FcVStackCreateAndPush (FcConfigParse *parse)
Keith Packard's avatar
Keith Packard committed
826
{
827
    FcVStack    *new;
Keith Packard's avatar
Keith Packard committed
828

829 830 831 832 833 834 835 836
    if (parse->vstack_static_used < sizeof (parse->vstack_static) / sizeof (parse->vstack_static[0]))
	new = &parse->vstack_static[parse->vstack_static_used++];
    else
    {
	new = malloc (sizeof (FcVStack));
	if (!new)
	    return 0;
    }
837 838
    new->tag = FcVStackNone;
    new->prev = 0;
Keith Packard's avatar
Keith Packard committed
839

840 841 842
    new->prev = parse->vstack;
    new->pstack = parse->pstack ? parse->pstack->prev : 0;
    parse->vstack = new;
Keith Packard's avatar
Keith Packard committed
843

844
    return new;
Keith Packard's avatar
Keith Packard committed
845 846 847
}

static FcBool
848
FcVStackPushString (FcConfigParse *parse, FcVStackTag tag, FcChar8 *string)
Keith Packard's avatar
Keith Packard committed
849
{
850
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
851 852 853 854 855
    if (!vstack)
	return FcFalse;
    vstack->u.string = string;
    vstack->tag = tag;
    return FcTrue;
Keith Packard's avatar
Keith Packard committed
856 857 858
}

static FcBool
859
FcVStackPushInteger (FcConfigParse *parse, int integer)
Keith Packard's avatar
Keith Packard committed
860
{
861
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
862
    if (!vstack)
Keith Packard's avatar
Keith Packard committed
863
	return FcFalse;
864 865 866
    vstack->u.integer = integer;
    vstack->tag = FcVStackInteger;
    return FcTrue;
Keith Packard's avatar
Keith Packard committed
867 868 869
}

static FcBool
870
FcVStackPushDouble (FcConfigParse *parse, double _double)
Keith Packard's avatar
Keith Packard committed
871
{
872
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
873
    if (!vstack)
Keith Packard's avatar
Keith Packard committed
874
	return FcFalse;
875 876 877
    vstack->u._double = _double;
    vstack->tag = FcVStackDouble;
    return FcTrue;
Keith Packard's avatar
Keith Packard committed
878 879 880
}

static FcBool
881
FcVStackPushMatrix (FcConfigParse *parse, FcExprMatrix *matrix)
Keith Packard's avatar
Keith Packard committed
882
{
883 884 885 886
    FcVStack    *vstack;
    vstack = FcVStackCreateAndPush (parse);
    if (!vstack)
	return FcFalse;
887
    vstack->u.matrix = FcExprMatrixCopyShallow (matrix);
888 889
    vstack->tag = FcVStackMatrix;
    return FcTrue;
Keith Packard's avatar
Keith Packard committed
890 891
}

Akira TAGOH's avatar
Akira TAGOH committed
892 893 894
static FcBool
FcVStackPushRange (FcConfigParse *parse, FcRange *range)
{
895
    FcVStack 	*vstack = FcVStackCreateAndPush (parse);
Akira TAGOH's avatar
Akira TAGOH committed
896 897
    if (!vstack)
	return FcFalse;
898
    vstack->u.range = range;
Akira TAGOH's avatar
Akira TAGOH committed
899 900 901 902
    vstack->tag = FcVStackRange;
    return FcTrue;
}

Keith Packard's avatar
Keith Packard committed
903
static FcBool
904
FcVStackPushBool (FcConfigParse *parse, FcBool bool_)
Keith Packard's avatar
Keith Packard committed
905
{
906
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
907 908
    if (!vstack)
	return FcFalse;
909
    vstack->u.bool_ = bool_;
910 911 912
    vstack->tag = FcVStackBool;
    return FcTrue;
}
Keith Packard's avatar
Keith Packard committed
913

Akira TAGOH's avatar
Akira TAGOH committed
914 915 916 917 918 919 920 921 922 923 924 925 926 927
static FcBool
FcVStackPushCharSet (FcConfigParse *parse, FcCharSet *charset)
{
    FcVStack	*vstack;
    if (!charset)
	return FcFalse;
    vstack = FcVStackCreateAndPush (parse);
    if (!vstack)
	return FcFalse;
    vstack->u.charset = charset;
    vstack->tag = FcVStackCharSet;
    return FcTrue;
}

Akira TAGOH's avatar
Akira TAGOH committed
928 929 930 931 932 933 934 935 936 937 938 939 940 941
static FcBool
FcVStackPushLangSet (FcConfigParse *parse, FcLangSet *langset)
{
    FcVStack	*vstack;
    if (!langset)
	return FcFalse;
    vstack = FcVStackCreateAndPush (parse);
    if (!vstack)
	return FcFalse;
    vstack->u.langset = langset;
    vstack->tag = FcVStackLangSet;
    return FcTrue;
}

942 943 944 945 946 947 948 949 950 951 952 953
static FcBool
FcVStackPushName (FcConfigParse *parse, FcMatchKind kind, FcObject object)
{
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
    if (!vstack)
	return FcFalse;
    vstack->u.name.object = object;
    vstack->u.name.kind = kind;
    vstack->tag = FcVStackName;
    return FcTrue;
}

954 955 956
static FcBool
FcVStackPushTest (FcConfigParse *parse, FcTest *test)
{
957
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
958
    if (!vstack)
Keith Packard's avatar
Keith Packard committed
959
	return FcFalse;
960 961
    vstack->u.test = test;
    vstack->tag = FcVStackTest;
Keith Packard's avatar
Keith Packard committed
962 963 964 965
    return FcTrue;
}

static FcBool
966
FcVStackPushExpr (FcConfigParse *parse, FcVStackTag tag, FcExpr *expr)
Keith Packard's avatar
Keith Packard committed
967
{
968
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
969 970 971 972 973 974
    if (!vstack)
	return FcFalse;
    vstack->u.expr = expr;
    vstack->tag = tag;
    return FcTrue;
}
Keith Packard's avatar
Keith Packard committed
975

976 977 978
static FcBool
FcVStackPushEdit (FcConfigParse *parse, FcEdit *edit)
{
979
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
980
    if (!vstack)
Keith Packard's avatar
Keith Packard committed
981
	return FcFalse;
982 983
    vstack->u.edit = edit;
    vstack->tag = FcVStackEdit;
Keith Packard's avatar
Keith Packard committed
984 985 986
    return FcTrue;
}

987 988 989
static FcBool
FcVStackPushPattern (FcConfigParse *parse, FcPattern *pattern)
{
990
    FcVStack    *vstack = FcVStackCreateAndPush (parse);
991 992 993 994 995 996 997
    if (!vstack)
	return FcFalse;
    vstack->u.pattern = pattern;
    vstack->tag = FcVStackPattern;
    return FcTrue;
}

998 999
static FcVStack *
FcVStackFetch (FcConfigParse *parse, int off)
Keith Packard's avatar
Keith Packard committed
1000
{
1001
    FcVStack    *vstack;
Keith Packard's avatar
Keith Packard committed
1002

1003 1004 1005 1006
    for (vstack = parse->vstack; vstack && off-- > 0; vstack = vstack->prev);
    return vstack;
}

1007 1008
static FcVStack *
FcVStackPeek (FcConfigParse *parse)
1009
{
1010 1011 1012
    FcVStack	*vstack = parse->vstack;

    return vstack && vstack->pstack == parse->pstack ? vstack : 0;
Keith Packard's avatar
Keith Packard committed
1013 1014
}

1015 1016
static void
FcVStackPopAndDestroy (FcConfigParse *parse)
Keith Packard's avatar
Keith Packard committed
1017
{
1018
    FcVStack	*vstack = parse->vstack;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1019

1020
    if (!vstack || vstack->pstack != parse->pstack)
1021 1022
	return;

1023
    parse->vstack = vstack->prev;
1024 1025 1026 1027

    switch (vstack->tag) {
    case FcVStackNone:
	break;
1028 1029
    case FcVStackName:
	break;
1030
    case FcVStackFamily:
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1031
	break;
1032
    case FcVStackString:
1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
    case FcVStackConstant:
    case FcVStackGlob:
	FcStrFree (vstack->u.string);
	break;
    case FcVStackPattern:
	FcPatternDestroy (vstack->u.pattern);
	break;
    case FcVStackInteger:
    case FcVStackDouble:
	break;
    case FcVStackMatrix:
1044
	FcExprMatrixFreeShallow (vstack->u.matrix);
1045 1046 1047
	break;
    case FcVStackBool:
	break;
1048 1049 1050
    case FcVStackRange:
	FcRangeDestroy (vstack->u.range);
	break;
Akira TAGOH's avatar
Akira TAGOH committed
1051 1052 1053
    case FcVStackCharSet:
	FcCharSetDestroy (vstack->u.charset);
	break;
Akira TAGOH's avatar
Akira TAGOH committed
1054 1055 1056
    case FcVStackLangSet:
	FcLangSetDestroy (vstack->u.langset);
	break;
1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081
    case FcVStackTest:
	FcTestDestroy (vstack->u.test);
	break;
    case FcVStackExpr:
    case FcVStackPrefer:
    case FcVStackAccept:
    case FcVStackDefault:
	FcExprDestroy (vstack->u.expr);
	break;
    case FcVStackEdit:
	FcEditDestroy (vstack->u.edit);
	break;
    }

    if (vstack == &parse->vstack_static[parse->vstack_static_used - 1])
	parse->vstack_static_used--;
    else
	free (vstack);
}

static void
FcVStackClear (FcConfigParse *parse)
{
    while (FcVStackPeek (parse))
	FcVStackPopAndDestroy (parse);
1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092
}

static int
FcVStackElements (FcConfigParse *parse)
{
    int		h = 0;
    FcVStack	*vstack = parse->vstack;
    while (vstack && vstack->pstack == parse->pstack)
    {
	h++;
	vstack = vstack->prev;
Keith Packard's avatar
Keith Packard committed
1093
    }
1094
    return h;
Keith Packard's avatar
Keith Packard committed
1095 1096
}

1097
static FcChar8 **
1098
FcConfigSaveAttr (const XML_Char **attr, FcChar8 **buf, int size_bytes)
Keith Packard's avatar
Keith Packard committed
1099
{
1100 1101 1102 1103
    int		slen;
    int		i;
    FcChar8	**new;
    FcChar8	*s;
Keith Packard's avatar
Keith Packard committed
1104

1105 1106 1107 1108
    if (!attr)
	return 0;
    slen = 0;
    for (i = 0; attr[i]; i++)
1109
	slen += strlen ((char *) attr[i]) + 1;
1110 1111
    if (i == 0)
	return 0;
1112 1113 1114 1115
    slen += (i + 1) * sizeof (FcChar8 *);
    if (slen <= size_bytes)
	new = buf;
    else
1116
    {
1117 1118 1119 1120 1121 1122
	new = malloc (slen);
	if (!new)
	{
	    FcConfigMessage (0, FcSevereError, "out of memory");
	    return 0;
	}
1123
    }
1124 1125
    s = (FcChar8 *) (new + (i + 1));
    for (i = 0; attr[i]; i++)
Keith Packard's avatar
Keith Packard committed
1126
    {
1127 1128 1129
	new[i] = s;
	strcpy ((char *) s, (char *) attr[i]);
	s += strlen ((char *) s) + 1;
Keith Packard's avatar
Keith Packard committed
1130
    }
1131 1132 1133
    new[i] = 0;
    return new;
}
Keith Packard's avatar
Keith Packard committed
1134

1135 1136 1137
static FcBool
FcPStackPush (FcConfigParse *parse, FcElement element, const XML_Char **attr)
{
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
    FcPStack   *new;

    if (parse->pstack_static_used < sizeof (parse->pstack_static) / sizeof (parse->pstack_static[0]))
	new = &parse->pstack_static[parse->pstack_static_used++];
    else
    {
	new = malloc (sizeof (FcPStack));
	if (!new)
	    return FcFalse;
    }
1148 1149 1150

    new->prev = parse->pstack;
    new->element = element;
1151
    new->attr = FcConfigSaveAttr (attr, new->attr_buf_static, sizeof (new->attr_buf_static));
1152 1153 1154 1155
    FcStrBufInit (&new->str, 0, 0);
    parse->pstack = new;
    return FcTrue;
}
Keith Packard's avatar
Keith Packard committed
1156

1157 1158 1159 1160
static FcBool
FcPStackPop (FcConfigParse *parse)
{
    FcPStack   *old;
Behdad Esfahbod's avatar
Behdad Esfahbod committed
1161 1162

    if (!parse->pstack)