source: trunk/poppler/fontconfig-2.3.2-os2/src/fccfg.c @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 56.0 KB
Line 
1/*
2 * $RCSId: xc/lib/fontconfig/src/fccfg.c,v 1.23 2002/08/31 22:17:32 keithp Exp $
3 *
4 * Copyright © 2000 Keith Packard
5 *
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of Keith Packard not be used in
11 * advertising or publicity pertaining to distribution of the software without
12 * specific, written prior permission.  Keith Packard makes no
13 * representations about the suitability of this software for any purpose.  It
14 * is provided "as is" without express or implied warranty.
15 *
16 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
20 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
21 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22 * PERFORMANCE OF THIS SOFTWARE.
23 */
24
25#include "fcint.h"
26
27#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
28#define STRICT
29#include <windows.h>
30#undef STRICT
31#endif
32
33#if defined (_WIN32) && !defined (R_OK)
34#define R_OK 4
35#endif
36
37#ifdef __OS2__
38#define INCL_WINDIALOGS
39#include <os2.h>
40#define DEFAULT_OS2_CONFIG_FILE \
41  "<?xml version=\"1.0\"?>\n" \
42"<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">\n" \
43"<!-- /etc/fonts/fonts.conf file to configure system font access -->\n" \
44"<fontconfig>\n" \
45"\n" \
46"<!--\n" \
47"       DO NOT EDIT THIS FILE.\n" \
48"       IT WILL BE REPLACED WHEN FONTCONFIG IS UPDATED.\n" \
49"       LOCAL CHANGES BELONG IN 'local.conf'.\n" \
50"\n" \
51"       The intent of this standard configuration file is to be adequate for\n" \
52"       most environments.  If you have a reasonably normal environment and\n" \
53"       have found problems with this configuration, they are probably\n" \
54"       things that others will also want fixed.  Please submit any\n" \
55"       problems to the fontconfig bugzilla system located at fontconfig.org\n" \
56"\n" \
57"       Note that the normal 'make install' procedure for fontconfig is to\n" \
58"       replace any existing fonts.conf file with the new version.  Place\n" \
59"       any local customizations in local.conf which this file references.\n" \
60"\n" \
61"       Keith Packard\n" \
62"-->\n" \
63"\n" \
64"<!-- Font directory list -->\n" \
65"\n" \
66"       <dir></dir>\n" \
67"\n" \
68"<!--\n" \
69"  Accept deprecated 'mono' alias, replacing it with 'monospace'\n" \
70"-->\n" \
71"       <match target=\"pattern\">\n" \
72"               <test qual=\"any\" name=\"family\">\n" \
73"                       <string>mono</string>\n" \
74"               </test>\n" \
75"               <edit name=\"family\" mode=\"assign\">\n" \
76"                       <string>monospace</string>\n" \
77"               </edit>\n" \
78"       </match>\n" \
79"\n" \
80"<!--\n" \
81"  Accept alternate 'sans serif' spelling, replacing it with 'sans-serif'\n" \
82"-->\n" \
83"       <match target=\"pattern\">\n" \
84"               <test qual=\"any\" name=\"family\">\n" \
85"                       <string>sans serif</string>\n" \
86"               </test>\n" \
87"               <edit name=\"family\" mode=\"assign\">\n" \
88"                       <string>sans-serif</string>\n" \
89"               </edit>\n" \
90"       </match>\n" \
91"\n" \
92"<!--\n" \
93"  Accept deprecated 'sans' alias, replacing it with 'sans-serif'\n" \
94"-->\n" \
95"       <match target=\"pattern\">\n" \
96"               <test qual=\"any\" name=\"family\">\n" \
97"                       <string>sans</string>\n" \
98"               </test>\n" \
99"               <edit name=\"family\" mode=\"assign\">\n" \
100"                       <string>sans-serif</string>\n" \
101"               </edit>\n" \
102"       </match>\n" \
103"\n" \
104"<!--\n" \
105"  Mark common families with their generics so we'll get\n" \
106"  something reasonable\n" \
107"-->\n" \
108"\n" \
109"<!--\n" \
110"  Serif faces\n" \
111" -->\n" \
112"       <alias>\n" \
113"               <family>Bitstream Vera Serif</family>\n" \
114"               <family>Times New Roman</family>\n" \
115"               <family>Thorndale AMT</family>\n" \
116"               <family>Times</family>\n" \
117"               <family>Nimbus Roman No9 L</family>\n" \
118"               <family>Luxi Serif</family>\n" \
119"               <family>Kochi Mincho</family>\n" \
120"               <family>AR PL SungtiL GB</family>\n" \
121"               <family>AR PL Mingti2L Big5</family>\n" \
122"               <family> 明朝</family>\n" \
123"               <family>Baekmuk Batang</family>\n" \
124"               <family>FreeSerif</family>\n" \
125"               <default><family>serif</family></default>\n" \
126"       </alias>\n" \
127"<!--\n" \
128"  Sans-serif faces\n" \
129" -->\n" \
130"       <alias>\n" \
131"               <family>Bitstream Vera Sans</family>\n" \
132"               <family>Helvetica</family>\n" \
133"               <family>Arial</family>\n" \
134"               <family>Verdana</family>\n" \
135"               <family>Albany AMT</family>\n" \
136"               <family>Nimbus Sans L</family>\n" \
137"               <family>Luxi Sans</family>\n" \
138"               <family>Kochi Gothic</family>\n" \
139"               <family>AR PL KaitiM GB</family>\n" \
140"               <family>AR PL KaitiM Big5</family>\n" \
141"               <family> ゎシック</family>\n" \
142"               <family>Baekmuk Dotum</family>\n" \
143"               <family>SimSun</family>\n" \
144"               <family>FreeSans</family>\n" \
145"               <default><family>sans-serif</family></default>\n" \
146"       </alias>\n" \
147"<!--\n" \
148"  Monospace faces\n" \
149" -->\n" \
150"       <alias>\n" \
151"               <family>Bitstream Vera Sans Mono</family>\n" \
152"               <family>Courier</family>\n" \
153"               <family>Courier New</family>\n" \
154"               <family>Andale Mono</family>\n" \
155"               <family>Luxi Mono</family>\n" \
156"               <family>Cumberland AMT</family>\n" \
157"               <family>Nimbus Mono L</family>\n" \
158"               <family>NSimSun</family>\n" \
159"               <family>FreeMono</family>\n" \
160"               <default><family>monospace</family></default>\n" \
161"       </alias>\n" \
162"<!--\n" \
163"  If the font still has no generic name, add sans-serif\n" \
164" -->\n" \
165"       <match target=\"pattern\">\n" \
166"               <test qual=\"all\" name=\"family\" compare=\"not_eq\">\n" \
167"                       <string>sans-serif</string>\n" \
168"               </test>\n" \
169"               <test qual=\"all\" name=\"family\" compare=\"not_eq\">\n" \
170"                       <string>serif</string>\n" \
171"               </test>\n" \
172"               <test qual=\"all\" name=\"family\" compare=\"not_eq\">\n" \
173"                       <string>monospace</string>\n" \
174"               </test>\n" \
175"               <edit name=\"family\" mode=\"append_last\">\n" \
176"                       <string>sans-serif</string>\n" \
177"               </edit>\n" \
178"       </match>\n" \
179"\n" \
180"<!--\n" \
181"  URW provides metric and shape compatible fonts for these 3 Adobe families.\n" \
182"  -->\n" \
183"        <alias>\n" \
184"         <family>Times</family>\n" \
185"         <accept><family>Nimbus Roman No9 L</family></accept>\n" \
186"       </alias>\n" \
187"        <alias>\n" \
188"         <family>Helvetica</family>\n" \
189"         <accept><family>Nimbus Sans L</family></accept>\n" \
190"       </alias>\n" \
191"        <alias>\n" \
192"         <family>Courier</family>\n" \
193"         <accept><family>Nimbus Mono L</family></accept>\n" \
194"       </alias>\n" \
195"\n" \
196"<!--\n" \
197" AMT provides metric and shape compatible fonts for these three web font\n" \
198" families.\n" \
199" -->\n" \
200"       <alias>\n" \
201"               <family>Times New Roman</family>\n" \
202"               <accept><family>Thorndale AMT</family></accept>\n" \
203"       </alias>\n" \
204"       <alias>\n" \
205"               <family>Arial</family>\n" \
206"               <accept><family>Albany AMT</family></accept>\n" \
207"       </alias>\n" \
208"       <alias>\n" \
209"               <family>Courier New</family>\n" \
210"               <accept><family>Cumberland AMT</family></accept>\n" \
211"       </alias>\n" \
212" \n" \
213"<!--\n" \
214"  Some Asian fonts misadvertise themselves as monospaced when\n" \
215"  in fact they are dual-spaced (half and full).  This makes\n" \
216"  FreeType very confused as it forces all widths to match.\n" \
217"  Undo this magic by disabling the width forcing code -->\n" \
218"       <match target=\"font\">\n" \
219"               <test name=\"family\"><string>GulimChe</string></test>\n" \
220"               <edit name=\"globaladvance\"><bool>false</bool></edit>\n" \
221"       </match>\n" \
222"\n" \
223"       <match target=\"font\">\n" \
224"               <test name=\"family\"><string>DotumChe</string></test>\n" \
225"               <edit name=\"globaladvance\"><bool>false</bool></edit>\n" \
226"       </match>\n" \
227"\n" \
228"       <match target=\"font\">\n" \
229"               <test name=\"family\"><string>BatangChe</string></test>\n" \
230"               <edit name=\"globaladvance\"><bool>false</bool></edit>\n" \
231"       </match>\n" \
232"\n" \
233"       <match target=\"font\">\n" \
234"               <test name=\"family\"><string>GungsuhChe</string></test>\n" \
235"               <edit name=\"globaladvance\"><bool>false</bool></edit>\n" \
236"       </match>\n" \
237"\n" \
238"<!-- \n" \
239"       The Bitstream Vera fonts have GASP entries suggesting that hinting be\n" \
240"       disabled below 8 ppem, but FreeType ignores those, preferring to use\n" \
241"       the data found in the instructed hints.  The initial Vera release\n" \
242"       didn't include the right instructions in the 'prep' table. Fix this\n" \
243"       by disabling hinting manually at smaller sizes (< 8ppem)\n" \
244" -->\n" \
245"\n" \
246"       <match target=\"font\">\n" \
247"               <test name=\"family\">\n" \
248"                       <string>Bitstream Vera Sans</string>\n" \
249"               </test>\n" \
250"               <test name=\"pixelsize\" compare=\"less\">\n" \
251"                       <double>7.5</double>\n" \
252"               </test>\n" \
253"               <edit name=\"hinting\">\n" \
254"                       <bool>false</bool>\n" \
255"               </edit>\n" \
256"       </match>\n" \
257"\n" \
258"       <match target=\"font\">\n" \
259"               <test name=\"family\">\n" \
260"                       <string>Bitstream Vera Serif</string>\n" \
261"               </test>\n" \
262"               <test name=\"pixelsize\" compare=\"less\">\n" \
263"                       <double>7.5</double>\n" \
264"               </test>\n" \
265"               <edit name=\"hinting\">\n" \
266"                       <bool>false</bool>\n" \
267"               </edit>\n" \
268"       </match>\n" \
269"\n" \
270"       <match target=\"font\">\n" \
271"               <test name=\"family\">\n" \
272"                       <string>Bitstream Vera Sans Mono</string>\n" \
273"               </test>\n" \
274"               <test name=\"pixelsize\" compare=\"less\">\n" \
275"                       <double>7.5</double>\n" \
276"               </test>\n" \
277"               <edit name=\"hinting\">\n" \
278"                       <bool>false</bool>\n" \
279"               </edit>\n" \
280"       </match>\n" \
281"\n" \
282"<!--\n" \
283"  Provide required aliases for standard names\n" \
284"-->\n" \
285"       <alias>\n" \
286"               <family>serif</family>\n" \
287"               <prefer>\n" \
288"                       <family>Bitstream Vera Serif</family>\n" \
289"                       <family>Times New Roman</family>\n" \
290"                       <family>Thorndale AMT</family>\n" \
291"                       <family>Luxi Serif</family>\n" \
292"                       <family>Nimbus Roman No9 L</family>\n" \
293"                       <family>Times</family>\n" \
294"                       <family>Frank Ruehl</family>\n" \
295"                       <family>Kochi Mincho</family>\n" \
296"                       <family>AR PL SungtiL GB</family>\n" \
297"                       <family>AR PL Mingti2L Big5</family>\n" \
298"                       <family> 明朝</family>\n" \
299"                       <family>Baekmuk Batang</family>\n" \
300"                       <family>FreeSerif</family>\n" \
301"               </prefer>\n" \
302"       </alias>\n" \
303"       <alias>\n" \
304"               <family>sans-serif</family>\n" \
305"               <prefer>\n" \
306"                       <family>Bitstream Vera Sans</family>\n" \
307"                       <family>Verdana</family>\n" \
308"                       <family>Arial</family>\n" \
309"                       <family>Albany AMT</family>\n" \
310"                       <family>Luxi Sans</family>\n" \
311"                       <family>Nimbus Sans L</family>\n" \
312"                       <family>Helvetica</family>\n" \
313"                       <family>Nachlieli</family>\n" \
314"                       <family>Kochi Gothic</family>\n" \
315"                       <family>AR PL KaitiM GB</family>\n" \
316"                       <family>AR PL KaitiM Big5</family>\n" \
317"                       <family> ゎシック</family>\n" \
318"                       <family>Baekmuk Dotum</family>\n" \
319"                       <family>SimSun</family>\n" \
320"                       <family>FreeSans</family>\n" \
321"               </prefer>\n" \
322"       </alias>\n" \
323"       <alias>\n" \
324"               <family>monospace</family>\n" \
325"               <prefer>\n" \
326"                       <family>Bitstream Vera Sans Mono</family>\n" \
327"                       <family>Andale Mono</family>\n" \
328"                       <family>Courier New</family>\n" \
329"                       <family>Cumberland AMT</family>\n" \
330"                       <family>Luxi Mono</family>\n" \
331"                       <family>Nimbus Mono L</family>\n" \
332"                       <family>Courier</family>\n" \
333"                       <family>Miriam Mono</family>\n" \
334"                       <family>Kochi Gothic</family>\n" \
335"                       <family>AR PL KaitiM GB</family>\n" \
336"                       <family>Baekmuk Dotum</family>\n" \
337"                       <family>FreeMono</family>\n" \
338"               </prefer>\n" \
339"       </alias>\n" \
340"\n" \
341"<!-- \n" \
342" Artificial oblique for fonts without an italic or oblique version\n" \
343" -->\n" \
344" \n" \
345"       <match target=\"font\">\n" \
346"               <!-- check to see if the font is roman -->\n" \
347"               <test name=\"slant\">\n" \
348"                       <const>roman</const>\n" \
349"               </test>\n" \
350"               <!-- check to see if the pattern requested non-roman -->\n" \
351"               <test target=\"pattern\" name=\"slant\" compare=\"not_eq\">\n" \
352"                       <const>roman</const>\n" \
353"               </test>\n" \
354"               <!-- multiply the matrix to slant the font -->\n" \
355"               <edit name=\"matrix\" mode=\"assign\">\n" \
356"                       <times>\n" \
357"                               <name>matrix</name>\n" \
358"                               <matrix><double>1</double><double>0.2</double>\n" \
359"                                       <double>0</double><double>1</double>\n" \
360"                               </matrix>\n" \
361"                       </times>\n" \
362"               </edit>\n" \
363"               <!-- pretend the font is oblique now -->\n" \
364"               <edit name=\"slant\" mode=\"assign\">\n" \
365"                       <const>oblique</const>\n" \
366"               </edit>\n" \
367"       </match>\n" \
368"\n" \
369"<!--\n" \
370" Synthetic emboldening for fonts that do not have bold face available\n" \
371" -->\n" \
372"\n" \
373"       <match target=\"font\">\n" \
374"               <!-- check to see if the font is just regular -->\n" \
375"               <test name=\"weight\" compare=\"less_eq\">\n" \
376"                       <int>100</int>\n" \
377"               </test>\n" \
378"               <!-- check to see if the pattern requests bold -->\n" \
379"               <test target=\"pattern\" name=\"weight\" compare=\"more_eq\">\n" \
380"                       <int>200</int>\n" \
381"               </test>\n" \
382"               <!-- set the embolden flag -->\n" \
383"               <edit name=\"embolden\" mode=\"assign\">\n" \
384"                       <bool>true</bool>\n" \
385"               </edit>\n" \
386"       </match>\n" \
387"\n" \
388"\n" \
389"       <config>\n" \
390"<!--\n" \
391"  These are the default Unicode chars that are expected to be blank\n" \
392"  in fonts.  All other blank chars are assumed to be broken and\n" \
393"  won't appear in the resulting charsets\n" \
394" -->\n" \
395"               <blank>\n" \
396"                       <int>0x0020</int>       <!-- SPACE -->\n" \
397"                       <int>0x00A0</int>       <!-- NO-BREAK SPACE -->\n" \
398"                       <int>0x00AD</int>       <!-- SOFT HYPHEN -->\n" \
399"                       <int>0x034F</int>       <!-- COMBINING GRAPHEME JOINER -->\n" \
400"                       <int>0x0600</int>       <!-- ARABIC NUMBER SIGN -->\n" \
401"                       <int>0x0601</int>       <!-- ARABIC SIGN SANAH -->\n" \
402"                       <int>0x0602</int>       <!-- ARABIC FOOTNOTE MARKER -->\n" \
403"                       <int>0x0603</int>       <!-- ARABIC SIGN SAFHA -->\n" \
404"                       <int>0x06DD</int>       <!-- ARABIC END OF AYAH -->\n" \
405"                       <int>0x070F</int>       <!-- SYRIAC ABBREVIATION MARK -->\n" \
406"                       <int>0x115F</int>       <!-- HANGUL CHOSEONG FILLER -->\n" \
407"                       <int>0x1160</int>       <!-- HANGUL JUNGSEONG FILLER -->\n" \
408"                       <int>0x1680</int>       <!-- OGHAM SPACE MARK -->\n" \
409"                       <int>0x17B4</int>       <!-- KHMER VOWEL INHERENT AQ -->\n" \
410"                       <int>0x17B5</int>       <!-- KHMER VOWEL INHERENT AA -->\n" \
411"                       <int>0x180E</int>       <!-- MONGOLIAN VOWEL SEPARATOR -->\n" \
412"                       <int>0x2000</int>       <!-- EN QUAD -->\n" \
413"                       <int>0x2001</int>       <!-- EM QUAD -->\n" \
414"                       <int>0x2002</int>       <!-- EN SPACE -->\n" \
415"                       <int>0x2003</int>       <!-- EM SPACE -->\n" \
416"                       <int>0x2004</int>       <!-- THREE-PER-EM SPACE -->\n" \
417"                       <int>0x2005</int>       <!-- FOUR-PER-EM SPACE -->\n" \
418"                       <int>0x2006</int>       <!-- SIX-PER-EM SPACE -->\n" \
419"                       <int>0x2007</int>       <!-- FIGURE SPACE -->\n" \
420"                       <int>0x2008</int>       <!-- PUNCTUATION SPACE -->\n" \
421"                       <int>0x2009</int>       <!-- THIN SPACE -->\n" \
422"                       <int>0x200A</int>       <!-- HAIR SPACE -->\n" \
423"                       <int>0x200B</int>       <!-- ZERO WIDTH SPACE -->\n" \
424"                       <int>0x200C</int>       <!-- ZERO WIDTH NON-JOINER -->\n" \
425"                       <int>0x200D</int>       <!-- ZERO WIDTH JOINER -->\n" \
426"                       <int>0x200E</int>       <!-- LEFT-TO-RIGHT MARK -->\n" \
427"                       <int>0x200F</int>       <!-- RIGHT-TO-LEFT MARK -->\n" \
428"                       <int>0x2028</int>       <!-- LINE SEPARATOR -->\n" \
429"                       <int>0x2029</int>       <!-- PARAGRAPH SEPARATOR -->\n" \
430"                       <int>0x202A</int>       <!-- LEFT-TO-RIGHT EMBEDDING -->\n" \
431"                       <int>0x202B</int>       <!-- RIGHT-TO-LEFT EMBEDDING -->\n" \
432"                       <int>0x202C</int>       <!-- POP DIRECTIONAL FORMATTING -->\n" \
433"                       <int>0x202D</int>       <!-- LEFT-TO-RIGHT OVERRIDE -->\n" \
434"                       <int>0x202E</int>       <!-- RIGHT-TO-LEFT OVERRIDE -->\n" \
435"                       <int>0x202F</int>       <!-- NARROW NO-BREAK SPACE -->\n" \
436"                       <int>0x205F</int>       <!-- MEDIUM MATHEMATICAL SPACE -->\n" \
437"                       <int>0x2060</int>       <!-- WORD JOINER -->\n" \
438"                       <int>0x2061</int>       <!-- FUNCTION APPLICATION -->\n" \
439"                       <int>0x2062</int>       <!-- INVISIBLE TIMES -->\n" \
440"                       <int>0x2063</int>       <!-- INVISIBLE SEPARATOR -->\n" \
441"                       <int>0x206A</int>       <!-- INHIBIT SYMMETRIC SWAPPING -->\n" \
442"                       <int>0x206B</int>       <!-- ACTIVATE SYMMETRIC SWAPPING -->\n" \
443"                       <int>0x206C</int>       <!-- INHIBIT ARABIC FORM SHAPING -->\n" \
444"                       <int>0x206D</int>       <!-- ACTIVATE ARABIC FORM SHAPING -->\n" \
445"                       <int>0x206E</int>       <!-- NATIONAL DIGIT SHAPES -->\n" \
446"                       <int>0x206F</int>       <!-- NOMINAL DIGIT SHAPES -->\n" \
447"                       <int>0x3000</int>       <!-- IDEOGRAPHIC SPACE -->\n" \
448"                       <int>0x3164</int>       <!-- HANGUL FILLER -->\n" \
449"                       <int>0xFEFF</int>       <!-- ZERO WIDTH NO-BREAK SPACE -->\n" \
450"                       <int>0xFFA0</int>       <!-- HALFWIDTH HANGUL FILLER -->\n" \
451"                       <int>0xFFF9</int>       <!-- INTERLINEAR ANNOTATION ANCHOR -->\n" \
452"                       <int>0xFFFA</int>       <!-- INTERLINEAR ANNOTATION SEPARATOR -->\n" \
453"                       <int>0xFFFB</int>       <!-- INTERLINEAR ANNOTATION TERMINATOR -->\n" \
454"               </blank>\n" \
455"<!--\n" \
456"  Rescan configuration every 30 seconds when FcFontSetList is called\n" \
457" -->\n" \
458"               <rescan>\n" \
459"                       <int>30</int>\n" \
460"               </rescan>\n" \
461"       </config>\n" \
462"\n" \
463"</fontconfig>\n" \
464"\n"
465#endif
466
467FcConfig    *_fcConfig;
468
469FcConfig *
470FcConfigCreate (void)
471{
472    FcSetName   set;
473    FcConfig    *config;
474
475    config = malloc (sizeof (FcConfig));
476    if (!config)
477        goto bail0;
478    FcMemAlloc (FC_MEM_CONFIG, sizeof (FcConfig));
479   
480    config->configDirs = FcStrSetCreate ();
481    if (!config->configDirs)
482        goto bail1;
483   
484    config->configFiles = FcStrSetCreate ();
485    if (!config->configFiles)
486        goto bail2;
487   
488    config->fontDirs = FcStrSetCreate ();
489    if (!config->fontDirs)
490        goto bail3;
491   
492    config->acceptGlobs = FcStrSetCreate ();
493    if (!config->acceptGlobs)
494        goto bail4;
495
496    config->rejectGlobs = FcStrSetCreate ();
497    if (!config->rejectGlobs)
498        goto bail5;
499
500    config->acceptPatterns = FcFontSetCreate ();
501    if (!config->acceptPatterns)
502        goto bail6;
503   
504    config->rejectPatterns = FcFontSetCreate ();
505    if (!config->rejectPatterns)
506        goto bail7;
507
508    config->cache = 0;
509#ifdef __OS2__
510    {
511      char *pchHome = FcConfigHome();
512      if (pchHome)
513      {
514        char *pchFullPath = malloc(strlen(pchHome)+strlen(FC_USER_CACHE_FILE)+10);
515        int rc;
516
517        if (!pchFullPath)
518          goto bail8;
519        if (pchHome[strlen(pchHome)-1]!='\\')
520          sprintf(pchFullPath, "%s\\%s", pchHome, FC_USER_CACHE_FILE);
521        else
522          sprintf(pchFullPath, "%s%s", pchHome, FC_USER_CACHE_FILE);
523
524        rc = FcConfigSetCache (config, (FcChar8 *) pchFullPath);
525        free(pchFullPath);
526
527        if (!rc)
528          goto bail8;
529      }
530    }
531#else
532    if (FcConfigHome())
533        if (!FcConfigSetCache (config, (FcChar8 *) ("~/" FC_USER_CACHE_FILE)))
534            goto bail8;
535#endif
536
537#ifdef _WIN32
538    if (config->cache == 0)
539    {
540        /* If no home, use the temp folder. */
541        FcChar8     dummy[1];
542        int         templen = GetTempPath (1, dummy);
543        FcChar8     *temp = malloc (templen + 1);
544
545        if (temp)
546        {
547            FcChar8 *cache_dir;
548
549            GetTempPath (templen + 1, temp);
550            cache_dir = FcStrPlus (temp, FC_USER_CACHE_FILE);
551            free (temp);
552            if (!FcConfigSetCache (config, cache_dir))
553            {
554                FcStrFree (cache_dir);
555                goto bail6;
556            }
557            FcStrFree (cache_dir);
558        }
559    }
560#endif
561
562    config->blanks = 0;
563
564    config->substPattern = 0;
565    config->substFont = 0;
566    config->maxObjects = 0;
567    for (set = FcSetSystem; set <= FcSetApplication; set++)
568        config->fonts[set] = 0;
569
570    config->rescanTime = time(0);
571    config->rescanInterval = 30;   
572   
573    return config;
574
575bail8:
576    FcFontSetDestroy (config->rejectPatterns);
577bail7:
578    FcFontSetDestroy (config->acceptPatterns);
579bail6:
580    FcStrSetDestroy (config->rejectGlobs);
581bail5:
582    FcStrSetDestroy (config->acceptGlobs);
583bail4:
584    FcStrSetDestroy (config->fontDirs);
585bail3:
586    FcStrSetDestroy (config->configFiles);
587bail2:
588    FcStrSetDestroy (config->configDirs);
589bail1:
590    free (config);
591    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
592bail0:
593    return 0;
594}
595
596typedef struct _FcFileTime {
597    time_t  time;
598    FcBool  set;
599} FcFileTime;
600
601static FcFileTime
602FcConfigNewestFile (FcStrSet *files)
603{
604    FcStrList       *list = FcStrListCreate (files);
605    FcFileTime      newest = { 0, FcFalse };
606    FcChar8         *file;
607    struct  stat    statb;
608
609    if (list)
610    {
611        while ((file = FcStrListNext (list)))
612            if (stat ((char *) file, &statb) == 0)
613                if (!newest.set || statb.st_mtime - newest.time > 0)
614                {
615                    newest.set = FcTrue;
616                    newest.time = statb.st_mtime;
617                }
618        FcStrListDone (list);
619    }
620    return newest;
621}
622
623FcBool
624FcConfigUptoDate (FcConfig *config)
625{
626    FcFileTime  config_time, font_time;
627    time_t      now = time(0);
628    if (!config)
629    {
630        config = FcConfigGetCurrent ();
631        if (!config)
632            return FcFalse;
633    }
634    config_time = FcConfigNewestFile (config->configFiles);
635    font_time = FcConfigNewestFile (config->fontDirs);
636    if ((config_time.set && config_time.time - config->rescanTime > 0) ||
637        (font_time.set && (font_time.time - config->rescanTime) > 0))
638    {
639        return FcFalse;
640    }
641    config->rescanTime = now;
642    return FcTrue;
643}
644
645static void
646FcSubstDestroy (FcSubst *s)
647{
648    FcSubst *n;
649   
650    while (s)
651    {
652        n = s->next;
653        if (s->test)
654            FcTestDestroy (s->test);
655        if (s->edit)
656            FcEditDestroy (s->edit);
657        free (s);
658        FcMemFree (FC_MEM_SUBST, sizeof (FcSubst));
659        s = n;
660    }
661}
662
663void
664FcConfigDestroy (FcConfig *config)
665{
666    FcSetName   set;
667
668    if (config == _fcConfig)
669        _fcConfig = 0;
670
671    FcStrSetDestroy (config->configDirs);
672    FcStrSetDestroy (config->fontDirs);
673    FcStrSetDestroy (config->configFiles);
674    FcStrSetDestroy (config->acceptGlobs);
675    FcStrSetDestroy (config->rejectGlobs);
676    FcFontSetDestroy (config->acceptPatterns);
677    FcFontSetDestroy (config->rejectPatterns);
678
679    if (config->blanks)
680        FcBlanksDestroy (config->blanks);
681
682    if (config->cache)
683        FcStrFree (config->cache);
684
685    FcSubstDestroy (config->substPattern);
686    FcSubstDestroy (config->substFont);
687    for (set = FcSetSystem; set <= FcSetApplication; set++)
688        if (config->fonts[set])
689            FcFontSetDestroy (config->fonts[set]);
690
691    free (config);
692    FcMemFree (FC_MEM_CONFIG, sizeof (FcConfig));
693}
694
695/*
696 * Scan the current list of directories in the configuration
697 * and build the set of available fonts. Update the
698 * per-user cache file to reflect the new configuration
699 */
700
701FcBool
702FcConfigBuildFonts (FcConfig *config)
703{
704    FcFontSet       *fonts;
705    FcGlobalCache   *cache;
706    FcStrList       *list;
707    FcChar8         *dir;
708
709    fonts = FcFontSetCreate ();
710    if (!fonts)
711        goto bail0;
712   
713    cache = FcGlobalCacheCreate ();
714    if (!cache)
715        goto bail1;
716
717    if (config->cache)
718        FcGlobalCacheLoad (cache, config->cache);
719
720    list = FcConfigGetFontDirs (config);
721    if (!list)
722        goto bail1;
723
724    while ((dir = FcStrListNext (list)))
725    {
726        if (FcDebug () & FC_DBG_FONTSET)
727            printf ("scan dir %s\n", dir);
728        FcDirScanConfig (fonts, config->fontDirs, cache, 
729                         config->blanks, dir, FcFalse, config);
730    }
731   
732    FcStrListDone (list);
733   
734    if (FcDebug () & FC_DBG_FONTSET)
735        FcFontSetPrint (fonts);
736
737    if (config->cache)
738        FcGlobalCacheSave (cache, config->cache);
739    FcGlobalCacheDestroy (cache);
740
741    FcConfigSetFonts (config, fonts, FcSetSystem);
742   
743    return FcTrue;
744bail1:
745    FcFontSetDestroy (fonts);
746bail0:
747    return FcFalse;
748}
749
750FcBool
751FcConfigSetCurrent (FcConfig *config)
752{
753    if (!config->fonts)
754        if (!FcConfigBuildFonts (config))
755            return FcFalse;
756
757    if (_fcConfig)
758        FcConfigDestroy (_fcConfig);
759    _fcConfig = config;
760    return FcTrue;
761}
762
763FcConfig *
764FcConfigGetCurrent (void)
765{
766    if (!_fcConfig)
767        if (!FcInit ())
768            return 0;
769    return _fcConfig;
770}
771
772FcBool
773FcConfigAddConfigDir (FcConfig      *config,
774                      const FcChar8 *d)
775{
776    return FcStrSetAddFilename (config->configDirs, d);
777}
778
779FcStrList *
780FcConfigGetConfigDirs (FcConfig   *config)
781{
782    if (!config)
783    {
784        config = FcConfigGetCurrent ();
785        if (!config)
786            return 0;
787    }
788    return FcStrListCreate (config->configDirs);
789}
790
791FcBool
792FcConfigAddFontDir (FcConfig        *config,
793                    const FcChar8   *d)
794{
795    return FcStrSetAddFilename (config->fontDirs, d);
796}
797
798FcBool
799FcConfigAddDir (FcConfig            *config,
800                const FcChar8       *d)
801{
802    return (FcConfigAddConfigDir (config, d) && 
803            FcConfigAddFontDir (config, d));
804}
805
806FcStrList *
807FcConfigGetFontDirs (FcConfig   *config)
808{
809    if (!config)
810    {
811        config = FcConfigGetCurrent ();
812        if (!config)
813            return 0;
814    }
815    return FcStrListCreate (config->fontDirs);
816}
817
818FcBool
819FcConfigAddConfigFile (FcConfig     *config,
820                       const FcChar8   *f)
821{
822    FcBool      ret;
823    FcChar8     *file = FcConfigFilename (f);
824   
825    if (!file)
826        return FcFalse;
827   
828    ret = FcStrSetAdd (config->configFiles, file);
829    FcStrFree (file);
830    return ret;
831}
832
833FcStrList *
834FcConfigGetConfigFiles (FcConfig    *config)
835{
836    if (!config)
837    {
838        config = FcConfigGetCurrent ();
839        if (!config)
840            return 0;
841    }
842    return FcStrListCreate (config->configFiles);
843}
844
845FcBool
846FcConfigSetCache (FcConfig      *config,
847                  const FcChar8 *c)
848{
849    FcChar8    *new = FcStrCopyFilename (c);
850   
851    if (!new)
852        return FcFalse;
853    if (config->cache)
854        FcStrFree (config->cache);
855    config->cache = new;
856    return FcTrue;
857}
858
859FcChar8 *
860FcConfigGetCache (FcConfig  *config)
861{
862    if (!config)
863    {
864        config = FcConfigGetCurrent ();
865        if (!config)
866            return 0;
867    }
868    return config->cache;
869}
870
871FcFontSet *
872FcConfigGetFonts (FcConfig      *config,
873                  FcSetName     set)
874{
875    if (!config)
876    {
877        config = FcConfigGetCurrent ();
878        if (!config)
879            return 0;
880    }
881    return config->fonts[set];
882}
883
884void
885FcConfigSetFonts (FcConfig      *config,
886                  FcFontSet     *fonts,
887                  FcSetName     set)
888{
889    if (config->fonts[set])
890        FcFontSetDestroy (config->fonts[set]);
891    config->fonts[set] = fonts;
892}
893
894
895
896FcBlanks *
897FcConfigGetBlanks (FcConfig     *config)
898{
899    if (!config)
900    {
901        config = FcConfigGetCurrent ();
902        if (!config)
903            return 0;
904    }
905    return config->blanks;
906}
907
908FcBool
909FcConfigAddBlank (FcConfig      *config,
910                  FcChar32      blank)
911{
912    FcBlanks    *b;
913   
914    b = config->blanks;
915    if (!b)
916    {
917        b = FcBlanksCreate ();
918        if (!b)
919            return FcFalse;
920    }
921    if (!FcBlanksAdd (b, blank))
922        return FcFalse;
923    config->blanks = b;
924    return FcTrue;
925}
926
927int
928FcConfigGetRescanInverval (FcConfig *config)
929{
930    if (!config)
931    {
932        config = FcConfigGetCurrent ();
933        if (!config)
934            return 0;
935    }
936    return config->rescanInterval;
937}
938
939FcBool
940FcConfigSetRescanInverval (FcConfig *config, int rescanInterval)
941{
942    if (!config)
943    {
944        config = FcConfigGetCurrent ();
945        if (!config)
946            return FcFalse;
947    }
948    config->rescanInterval = rescanInterval;
949    return FcTrue;
950}
951
952FcBool
953FcConfigAddEdit (FcConfig       *config,
954                 FcTest         *test,
955                 FcEdit         *edit,
956                 FcMatchKind    kind)
957{
958    FcSubst     *subst, **prev;
959    FcTest      *t;
960    int         num;
961
962    subst = (FcSubst *) malloc (sizeof (FcSubst));
963    if (!subst)
964        return FcFalse;
965    FcMemAlloc (FC_MEM_SUBST, sizeof (FcSubst));
966    if (kind == FcMatchPattern)
967        prev = &config->substPattern;
968    else
969        prev = &config->substFont;
970    for (; *prev; prev = &(*prev)->next);
971    *prev = subst;
972    subst->next = 0;
973    subst->test = test;
974    subst->edit = edit;
975    num = 0;
976    for (t = test; t; t = t->next)
977    {
978        if (t->kind == FcMatchDefault)
979            t->kind = kind;
980        num++;
981    }
982    if (config->maxObjects < num)
983        config->maxObjects = num;
984    if (FcDebug () & FC_DBG_EDIT)
985    {
986        printf ("Add Subst ");
987        FcSubstPrint (subst);
988    }
989    return FcTrue;
990}
991
992typedef struct _FcSubState {
993    FcPatternElt   *elt;
994    FcValueList    *value;
995} FcSubState;
996
997static FcValue
998FcConfigPromote (FcValue v, FcValue u)
999{
1000    if (v.type == FcTypeInteger)
1001    {
1002        v.type = FcTypeDouble;
1003        v.u.d = (double) v.u.i;
1004    }
1005    else if (v.type == FcTypeVoid && u.type == FcTypeMatrix)
1006    {
1007        v.u.m = &FcIdentityMatrix;
1008        v.type = FcTypeMatrix;
1009    }
1010    else if (v.type == FcTypeString && u.type == FcTypeLangSet)
1011    {
1012        v.u.l = FcLangSetPromote (v.u.s);
1013        v.type = FcTypeLangSet;
1014    }
1015    return v;
1016}
1017
1018FcBool
1019FcConfigCompareValue (const FcValue     left_o,
1020                      FcOp              op,
1021                      const FcValue     right_o)
1022{
1023    FcValue     left = left_o;
1024    FcValue     right = right_o;
1025    FcBool      ret = FcFalse;
1026   
1027    left = FcConfigPromote (left, right);
1028    right = FcConfigPromote (right, left);
1029    if (left.type == right.type) 
1030    {
1031        switch (left.type) {
1032        case FcTypeInteger:
1033            break;      /* FcConfigPromote prevents this from happening */
1034        case FcTypeDouble:
1035            switch (op) {
1036            case FcOpEqual:
1037            case FcOpContains:
1038            case FcOpListing:
1039                ret = left.u.d == right.u.d;
1040                break;
1041            case FcOpNotEqual:
1042            case FcOpNotContains:
1043                ret = left.u.d != right.u.d;
1044                break;
1045            case FcOpLess:   
1046                ret = left.u.d < right.u.d;
1047                break;
1048            case FcOpLessEqual:   
1049                ret = left.u.d <= right.u.d;
1050                break;
1051            case FcOpMore:   
1052                ret = left.u.d > right.u.d;
1053                break;
1054            case FcOpMoreEqual:   
1055                ret = left.u.d >= right.u.d;
1056                break;
1057            default:
1058                break;
1059            }
1060            break;
1061        case FcTypeBool:
1062            switch (op) {
1063            case FcOpEqual:   
1064            case FcOpContains:
1065            case FcOpListing:
1066                ret = left.u.b == right.u.b;
1067                break;
1068            case FcOpNotEqual:
1069            case FcOpNotContains:
1070                ret = left.u.b != right.u.b;
1071                break;
1072            default:
1073                break;
1074            }
1075            break;
1076        case FcTypeString:
1077            switch (op) {
1078            case FcOpEqual:   
1079            case FcOpListing:
1080                ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) == 0;
1081                break;
1082            case FcOpContains:
1083                ret = FcStrStrIgnoreCase (left.u.s, right.u.s) != 0;
1084                break;
1085            case FcOpNotEqual:
1086            case FcOpNotContains:
1087                ret = FcStrCmpIgnoreCase (left.u.s, right.u.s) != 0;
1088                break;
1089            default:
1090                break;
1091            }
1092            break;
1093        case FcTypeMatrix:
1094            switch (op) {
1095            case FcOpEqual:
1096            case FcOpContains:
1097            case FcOpListing:
1098                ret = FcMatrixEqual (left.u.m, right.u.m);
1099                break;
1100            case FcOpNotEqual:
1101            case FcOpNotContains:
1102                ret = !FcMatrixEqual (left.u.m, right.u.m);
1103                break;
1104            default:
1105                break;
1106            }
1107            break;
1108        case FcTypeCharSet:
1109            switch (op) {
1110            case FcOpContains:
1111            case FcOpListing:
1112                /* left contains right if right is a subset of left */
1113                ret = FcCharSetIsSubset (right.u.c, left.u.c);
1114                break;
1115            case FcOpNotContains:
1116                /* left contains right if right is a subset of left */
1117                ret = !FcCharSetIsSubset (right.u.c, left.u.c);
1118                break;
1119            case FcOpEqual:
1120                ret = FcCharSetEqual (left.u.c, right.u.c);
1121                break;
1122            case FcOpNotEqual:
1123                ret = !FcCharSetEqual (left.u.c, right.u.c);
1124                break;
1125            default:
1126                break;
1127            }
1128            break;
1129        case FcTypeLangSet:
1130            switch (op) {
1131            case FcOpContains:
1132            case FcOpListing:
1133                ret = FcLangSetContains (left.u.l, right.u.l);
1134                break;
1135            case FcOpNotContains:
1136                ret = !FcLangSetContains (left.u.l, right.u.l);
1137                break;
1138            case FcOpEqual:
1139                ret = FcLangSetEqual (left.u.l, right.u.l);
1140                break;
1141            case FcOpNotEqual:
1142                ret = !FcLangSetEqual (left.u.l, right.u.l);
1143                break;
1144            default:
1145                break;
1146            }
1147            break;
1148        case FcTypeVoid:
1149            switch (op) {
1150            case FcOpEqual:
1151            case FcOpContains:
1152            case FcOpListing:
1153                ret = FcTrue;
1154                break;
1155            default:
1156                break;
1157            }
1158            break;
1159        case FcTypeFTFace:
1160            switch (op) {
1161            case FcOpEqual:
1162            case FcOpContains:
1163            case FcOpListing:
1164                ret = left.u.f == right.u.f;
1165                break;
1166            case FcOpNotEqual:
1167            case FcOpNotContains:
1168                ret = left.u.f != right.u.f;
1169                break;
1170            default:
1171                break;
1172            }
1173            break;
1174        }
1175    }
1176    else
1177    {
1178        if (op == FcOpNotEqual || op == FcOpNotContains)
1179            ret = FcTrue;
1180    }
1181    return ret;
1182}
1183
1184
1185#define _FcDoubleFloor(d)       ((int) (d))
1186#define _FcDoubleCeil(d)        ((double) (int) (d) == (d) ? (int) (d) : (int) ((d) + 1))
1187#define FcDoubleFloor(d)        ((d) >= 0 ? _FcDoubleFloor(d) : -_FcDoubleCeil(-(d)))
1188#define FcDoubleCeil(d)         ((d) >= 0 ? _FcDoubleCeil(d) : -_FcDoubleFloor(-(d)))
1189#define FcDoubleRound(d)        FcDoubleFloor ((d) + 0.5)
1190#define FcDoubleTrunc(d)        ((d) >= 0 ? _FcDoubleFloor (d) : -_FcDoubleFloor (-(d)))
1191
1192static FcValue
1193FcConfigEvaluate (FcPattern *p, FcExpr *e)
1194{
1195    FcValue     v, vl, vr;
1196    FcResult    r;
1197    FcMatrix    *m;
1198   
1199    switch (e->op) {
1200    case FcOpInteger:
1201        v.type = FcTypeInteger;
1202        v.u.i = e->u.ival;
1203        break;
1204    case FcOpDouble:
1205        v.type = FcTypeDouble;
1206        v.u.d = e->u.dval;
1207        break;
1208    case FcOpString:
1209        v.type = FcTypeString;
1210        v.u.s = e->u.sval;
1211        v = FcValueSave (v);
1212        break;
1213    case FcOpMatrix:
1214        v.type = FcTypeMatrix;
1215        v.u.m = e->u.mval;
1216        v = FcValueSave (v);
1217        break;
1218    case FcOpCharSet:
1219        v.type = FcTypeCharSet;
1220        v.u.c = e->u.cval;
1221        v = FcValueSave (v);
1222        break;
1223    case FcOpBool:
1224        v.type = FcTypeBool;
1225        v.u.b = e->u.bval;
1226        break;
1227    case FcOpField:
1228        r = FcPatternGet (p, e->u.field, 0, &v);
1229        if (r != FcResultMatch)
1230            v.type = FcTypeVoid;
1231        break;
1232    case FcOpConst:
1233        if (FcNameConstant (e->u.constant, &v.u.i))
1234            v.type = FcTypeInteger;
1235        else
1236            v.type = FcTypeVoid;
1237        break;
1238    case FcOpQuest:
1239        vl = FcConfigEvaluate (p, e->u.tree.left);
1240        if (vl.type == FcTypeBool)
1241        {
1242            if (vl.u.b)
1243                v = FcConfigEvaluate (p, e->u.tree.right->u.tree.left);
1244            else
1245                v = FcConfigEvaluate (p, e->u.tree.right->u.tree.right);
1246        }
1247        else
1248            v.type = FcTypeVoid;
1249        FcValueDestroy (vl);
1250        break;
1251    case FcOpEqual:
1252    case FcOpNotEqual:
1253    case FcOpLess:
1254    case FcOpLessEqual:
1255    case FcOpMore:
1256    case FcOpMoreEqual:
1257    case FcOpContains:
1258    case FcOpNotContains:
1259    case FcOpListing:
1260        vl = FcConfigEvaluate (p, e->u.tree.left);
1261        vr = FcConfigEvaluate (p, e->u.tree.right);
1262        v.type = FcTypeBool;
1263        v.u.b = FcConfigCompareValue (vl, e->op, vr);
1264        FcValueDestroy (vl);
1265        FcValueDestroy (vr);
1266        break; 
1267    case FcOpOr:
1268    case FcOpAnd:
1269    case FcOpPlus:
1270    case FcOpMinus:
1271    case FcOpTimes:
1272    case FcOpDivide:
1273        vl = FcConfigEvaluate (p, e->u.tree.left);
1274        vr = FcConfigEvaluate (p, e->u.tree.right);
1275        vl = FcConfigPromote (vl, vr);
1276        vr = FcConfigPromote (vr, vl);
1277        if (vl.type == vr.type)
1278        {
1279            switch (vl.type) {
1280            case FcTypeDouble:
1281                switch (e->op) {
1282                case FcOpPlus:     
1283                    v.type = FcTypeDouble;
1284                    v.u.d = vl.u.d + vr.u.d; 
1285                    break;
1286                case FcOpMinus:
1287                    v.type = FcTypeDouble;
1288                    v.u.d = vl.u.d - vr.u.d; 
1289                    break;
1290                case FcOpTimes:
1291                    v.type = FcTypeDouble;
1292                    v.u.d = vl.u.d * vr.u.d; 
1293                    break;
1294                case FcOpDivide:
1295                    v.type = FcTypeDouble;
1296                    v.u.d = vl.u.d / vr.u.d; 
1297                    break;
1298                default:
1299                    v.type = FcTypeVoid; 
1300                    break;
1301                }
1302                if (v.type == FcTypeDouble &&
1303                    v.u.d == (double) (int) v.u.d)
1304                {
1305                    v.type = FcTypeInteger;
1306                    v.u.i = (int) v.u.d;
1307                }
1308                break;
1309            case FcTypeBool:
1310                switch (e->op) {
1311                case FcOpOr:
1312                    v.type = FcTypeBool;
1313                    v.u.b = vl.u.b || vr.u.b;
1314                    break;
1315                case FcOpAnd:
1316                    v.type = FcTypeBool;
1317                    v.u.b = vl.u.b && vr.u.b;
1318                    break;
1319                default:
1320                    v.type = FcTypeVoid; 
1321                    break;
1322                }
1323                break;
1324            case FcTypeString:
1325                switch (e->op) {
1326                case FcOpPlus:
1327                    v.type = FcTypeString;
1328                    v.u.s = FcStrPlus (vl.u.s, vr.u.s);
1329                    if (!v.u.s)
1330                        v.type = FcTypeVoid;
1331                    break;
1332                default:
1333                    v.type = FcTypeVoid;
1334                    break;
1335                }
1336                break;
1337            case FcTypeMatrix:
1338                switch (e->op) {
1339                case FcOpTimes:
1340                    v.type = FcTypeMatrix;
1341                    m = malloc (sizeof (FcMatrix));
1342                    if (m)
1343                    {
1344                        FcMemAlloc (FC_MEM_MATRIX, sizeof (FcMatrix));
1345                        FcMatrixMultiply (m, vl.u.m, vr.u.m);
1346                        v.u.m = m;
1347                    }
1348                    else
1349                    {
1350                        v.type = FcTypeVoid;
1351                    }
1352                    break;
1353                default:
1354                    v.type = FcTypeVoid;
1355                    break;
1356                }
1357                break;
1358            default:
1359                v.type = FcTypeVoid;
1360                break;
1361            }
1362        }
1363        else
1364            v.type = FcTypeVoid;
1365        FcValueDestroy (vl);
1366        FcValueDestroy (vr);
1367        break;
1368    case FcOpNot:
1369        vl = FcConfigEvaluate (p, e->u.tree.left);
1370        switch (vl.type) {
1371        case FcTypeBool:
1372            v.type = FcTypeBool;
1373            v.u.b = !vl.u.b;
1374            break;
1375        default:
1376            v.type = FcTypeVoid;
1377            break;
1378        }
1379        FcValueDestroy (vl);
1380        break;
1381    case FcOpFloor:
1382        vl = FcConfigEvaluate (p, e->u.tree.left);
1383        switch (vl.type) {
1384        case FcTypeInteger:
1385            v = vl;
1386            break;
1387        case FcTypeDouble:
1388            v.type = FcTypeInteger;
1389            v.u.i = FcDoubleFloor (vl.u.d);
1390            break;
1391        default:
1392            v.type = FcTypeVoid;
1393            break;
1394        }
1395        FcValueDestroy (vl);
1396        break;
1397    case FcOpCeil:
1398        vl = FcConfigEvaluate (p, e->u.tree.left);
1399        switch (vl.type) {
1400        case FcTypeInteger:
1401            v = vl;
1402            break;
1403        case FcTypeDouble:
1404            v.type = FcTypeInteger;
1405            v.u.i = FcDoubleCeil (vl.u.d);
1406            break;
1407        default:
1408            v.type = FcTypeVoid;
1409            break;
1410        }
1411        FcValueDestroy (vl);
1412        break;
1413    case FcOpRound:
1414        vl = FcConfigEvaluate (p, e->u.tree.left);
1415        switch (vl.type) {
1416        case FcTypeInteger:
1417            v = vl;
1418            break;
1419        case FcTypeDouble:
1420            v.type = FcTypeInteger;
1421            v.u.i = FcDoubleRound (vl.u.d);
1422            break;
1423        default:
1424            v.type = FcTypeVoid;
1425            break;
1426        }
1427        FcValueDestroy (vl);
1428        break;
1429    case FcOpTrunc:
1430        vl = FcConfigEvaluate (p, e->u.tree.left);
1431        switch (vl.type) {
1432        case FcTypeInteger:
1433            v = vl;
1434            break;
1435        case FcTypeDouble:
1436            v.type = FcTypeInteger;
1437            v.u.i = FcDoubleTrunc (vl.u.d);
1438            break;
1439        default:
1440            v.type = FcTypeVoid;
1441            break;
1442        }
1443        FcValueDestroy (vl);
1444        break;
1445    default:
1446        v.type = FcTypeVoid;
1447        break;
1448    }
1449    return v;
1450}
1451
1452static FcValueList *
1453FcConfigMatchValueList (FcPattern       *p,
1454                        FcTest          *t,
1455                        FcValueList     *values)
1456{
1457    FcValueList     *ret = 0;
1458    FcExpr          *e = t->expr;
1459    FcValue         value;
1460    FcValueList     *v;
1461   
1462    while (e)
1463    {
1464        /* Compute the value of the match expression */
1465        if (e->op == FcOpComma)
1466        {
1467            value = FcConfigEvaluate (p, e->u.tree.left);
1468            e = e->u.tree.right;
1469        }
1470        else
1471        {
1472            value = FcConfigEvaluate (p, e);
1473            e = 0;
1474        }
1475
1476        for (v = values; v; v = v->next)
1477        {
1478            /* Compare the pattern value to the match expression value */
1479            if (FcConfigCompareValue (v->value, t->op, value))
1480            {
1481                if (!ret)
1482                    ret = v;
1483            }
1484            else
1485            {
1486                if (t->qual == FcQualAll)
1487                {
1488                    ret = 0;
1489                    break;
1490                }
1491            }
1492        }
1493        FcValueDestroy (value);
1494    }
1495    return ret;
1496}
1497
1498static FcValueList *
1499FcConfigValues (FcPattern *p, FcExpr *e, FcValueBinding binding)
1500{
1501    FcValueList *l;
1502   
1503    if (!e)
1504        return 0;
1505    l = (FcValueList *) malloc (sizeof (FcValueList));
1506    if (!l)
1507        return 0;
1508    FcMemAlloc (FC_MEM_VALLIST, sizeof (FcValueList));
1509    if (e->op == FcOpComma)
1510    {
1511        l->value = FcConfigEvaluate (p, e->u.tree.left);
1512        l->next  = FcConfigValues (p, e->u.tree.right, binding);
1513    }
1514    else
1515    {
1516        l->value = FcConfigEvaluate (p, e);
1517        l->next  = 0;
1518    }
1519    l->binding = binding;
1520    while (l && l->value.type == FcTypeVoid)
1521    {
1522        FcValueList     *next = l->next;
1523       
1524        FcMemFree (FC_MEM_VALLIST, sizeof (FcValueList));
1525        free (l);
1526        l = next;
1527    }
1528    return l;
1529}
1530
1531static FcBool
1532FcConfigAdd (FcValueList    **head,
1533             FcValueList    *position,
1534             FcBool         append,
1535             FcValueList    *new)
1536{
1537    FcValueList     **prev, *last, *v;
1538    FcValueBinding  sameBinding;
1539   
1540    if (position)
1541        sameBinding = position->binding;
1542    else
1543        sameBinding = FcValueBindingWeak;
1544    for (v = new; v; v = v->next)
1545        if (v->binding == FcValueBindingSame)
1546            v->binding = sameBinding;
1547    if (append)
1548    {
1549        if (position)
1550            prev = &position->next;
1551        else
1552            for (prev = head; *prev; prev = &(*prev)->next)
1553                ;
1554    }
1555    else
1556    {
1557        if (position)
1558        {
1559            for (prev = head; *prev; prev = &(*prev)->next)
1560            {
1561                if (*prev == position)
1562                    break;
1563            }
1564        }
1565        else
1566            prev = head;
1567
1568        if (FcDebug () & FC_DBG_EDIT)
1569        {
1570            if (!*prev)
1571                printf ("position not on list\n");
1572        }
1573    }
1574
1575    if (FcDebug () & FC_DBG_EDIT)
1576    {
1577        printf ("%s list before ", append ? "Append" : "Prepend");
1578        FcValueListPrint (*head);
1579        printf ("\n");
1580    }
1581   
1582    if (new)
1583    {
1584        last = new;
1585        while (last->next)
1586            last = last->next;
1587   
1588        last->next = *prev;
1589        *prev = new;
1590    }
1591   
1592    if (FcDebug () & FC_DBG_EDIT)
1593    {
1594        printf ("%s list after ", append ? "Append" : "Prepend");
1595        FcValueListPrint (*head);
1596        printf ("\n");
1597    }
1598   
1599    return FcTrue;
1600}
1601
1602static void
1603FcConfigDel (FcValueList    **head,
1604             FcValueList    *position)
1605{
1606    FcValueList    **prev;
1607
1608    for (prev = head; *prev; prev = &(*prev)->next)
1609    {
1610        if (*prev == position)
1611        {
1612            *prev = position->next;
1613            position->next = 0;
1614            FcValueListDestroy (position);
1615            break;
1616        }
1617    }
1618}
1619
1620static void
1621FcConfigPatternAdd (FcPattern   *p,
1622                    const char  *object,
1623                    FcValueList *list,
1624                    FcBool      append)
1625{
1626    if (list)
1627    {
1628        FcPatternElt    *e = FcPatternInsertElt (p, object);
1629   
1630        if (!e)
1631            return;
1632        FcConfigAdd (&e->values, 0, append, list);
1633    }
1634}
1635
1636/*
1637 * Delete all values associated with a field
1638 */
1639static void
1640FcConfigPatternDel (FcPattern   *p,
1641                    const char  *object)
1642{
1643    FcPatternElt    *e = FcPatternFindElt (p, object);
1644    if (!e)
1645        return;
1646    while (e->values)
1647        FcConfigDel (&e->values, e->values);
1648}
1649
1650static void
1651FcConfigPatternCanon (FcPattern     *p,
1652                      const char    *object)
1653{
1654    FcPatternElt    *e = FcPatternFindElt (p, object);
1655    if (!e)
1656        return;
1657    if (!e->values)
1658        FcPatternDel (p, object);
1659}
1660
1661FcBool
1662FcConfigSubstituteWithPat (FcConfig    *config,
1663                           FcPattern   *p,
1664                           FcPattern   *p_pat,
1665                           FcMatchKind kind)
1666{
1667    FcSubst         *s;
1668    FcSubState      *st;
1669    int             i;
1670    FcTest          *t;
1671    FcEdit          *e;
1672    FcValueList     *l;
1673    FcPattern       *m;
1674
1675    if (!config)
1676    {
1677        config = FcConfigGetCurrent ();
1678        if (!config)
1679            return FcFalse;
1680    }
1681
1682    st = (FcSubState *) malloc (config->maxObjects * sizeof (FcSubState));
1683    if (!st && config->maxObjects)
1684        return FcFalse;
1685    FcMemAlloc (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1686
1687    if (FcDebug () & FC_DBG_EDIT)
1688    {
1689        printf ("FcConfigSubstitute ");
1690        FcPatternPrint (p);
1691    }
1692    if (kind == FcMatchPattern)
1693        s = config->substPattern;
1694    else
1695        s = config->substFont;
1696    for (; s; s = s->next)
1697    {
1698        /*
1699         * Check the tests to see if
1700         * they all match the pattern
1701         */
1702        for (t = s->test, i = 0; t; t = t->next, i++)
1703        {
1704            if (FcDebug () & FC_DBG_EDIT)
1705            {
1706                printf ("FcConfigSubstitute test ");
1707                FcTestPrint (t);
1708            }
1709            st[i].elt = 0;
1710            if (kind == FcMatchFont && t->kind == FcMatchPattern)
1711                m = p_pat;
1712            else
1713                m = p;
1714            if (m)
1715                st[i].elt = FcPatternFindElt (m, t->field);
1716            else
1717                st[i].elt = 0;
1718            /*
1719             * If there's no such field in the font,
1720             * then FcQualAll matches while FcQualAny does not
1721             */
1722            if (!st[i].elt)
1723            {
1724                if (t->qual == FcQualAll)
1725                {
1726                    st[i].value = 0;
1727                    continue;
1728                }
1729                else
1730                    break;
1731            }
1732            /*
1733             * Check to see if there is a match, mark the location
1734             * to apply match-relative edits
1735             */
1736            st[i].value = FcConfigMatchValueList (m, t, st[i].elt->values);
1737            if (!st[i].value)
1738                break;
1739            if (t->qual == FcQualFirst && st[i].value != st[i].elt->values)
1740                break;
1741            if (t->qual == FcQualNotFirst && st[i].value == st[i].elt->values)
1742                break;
1743        }
1744        if (t)
1745        {
1746            if (FcDebug () & FC_DBG_EDIT)
1747                printf ("No match\n");
1748            continue;
1749        }
1750        if (FcDebug () & FC_DBG_EDIT)
1751        {
1752            printf ("Substitute ");
1753            FcSubstPrint (s);
1754        }
1755        for (e = s->edit; e; e = e->next)
1756        {
1757            /*
1758             * Evaluate the list of expressions
1759             */
1760            l = FcConfigValues (p, e->expr, e->binding);
1761            /*
1762             * Locate any test associated with this field, skipping
1763             * tests associated with the pattern when substituting in
1764             * the font
1765             */
1766            for (t = s->test, i = 0; t; t = t->next, i++)
1767            {
1768                if ((t->kind == FcMatchFont || kind == FcMatchPattern) &&
1769                    !FcStrCmpIgnoreCase ((FcChar8 *) t->field, 
1770                                         (FcChar8 *) e->field))
1771                {
1772                    /*
1773                     * KLUDGE - the pattern may have been reallocated or
1774                     * things may have been inserted or deleted above
1775                     * this element by other edits.  Go back and find
1776                     * the element again
1777                     */
1778                    if (e != s->edit && st[i].elt)
1779                        st[i].elt = FcPatternFindElt (p, t->field);
1780                    if (!st[i].elt)
1781                        t = 0;
1782                    break;
1783                }
1784            }
1785            switch (e->op) {
1786            case FcOpAssign:
1787                /*
1788                 * If there was a test, then replace the matched
1789                 * value with the new list of values
1790                 */
1791                if (t)
1792                {
1793                    FcValueList *thisValue = st[i].value;
1794                    FcValueList *nextValue = thisValue ? thisValue->next : 0;
1795                   
1796                    /*
1797                     * Append the new list of values after the current value
1798                     */
1799                    FcConfigAdd (&st[i].elt->values, thisValue, FcTrue, l);
1800                    /*
1801                     * Delete the marked value
1802                     */
1803                    FcConfigDel (&st[i].elt->values, thisValue);
1804                    /*
1805                     * Adjust any pointers into the value list to ensure
1806                     * future edits occur at the same place
1807                     */
1808                    for (t = s->test, i = 0; t; t = t->next, i++)
1809                    {
1810                        if (st[i].value == thisValue)
1811                            st[i].value = nextValue;
1812                    }
1813                    break;
1814                }
1815                /* fall through ... */
1816            case FcOpAssignReplace:
1817                /*
1818                 * Delete all of the values and insert
1819                 * the new set
1820                 */
1821                FcConfigPatternDel (p, e->field);
1822                FcConfigPatternAdd (p, e->field, l, FcTrue);
1823                /*
1824                 * Adjust any pointers into the value list as they no
1825                 * longer point to anything valid
1826                 */
1827                if (t)
1828                {
1829                    FcPatternElt    *thisElt = st[i].elt;
1830                    for (t = s->test, i = 0; t; t = t->next, i++)
1831                    {
1832                        if (st[i].elt == thisElt)
1833                            st[i].value = 0;
1834                    }
1835                }
1836                break;
1837            case FcOpPrepend:
1838                if (t)
1839                {
1840                    FcConfigAdd (&st[i].elt->values, st[i].value, FcFalse, l);
1841                    break;
1842                }
1843                /* fall through ... */
1844            case FcOpPrependFirst:
1845                FcConfigPatternAdd (p, e->field, l, FcFalse);
1846                break;
1847            case FcOpAppend:
1848                if (t)
1849                {
1850                    FcConfigAdd (&st[i].elt->values, st[i].value, FcTrue, l);
1851                    break;
1852                }
1853                /* fall through ... */
1854            case FcOpAppendLast:
1855                FcConfigPatternAdd (p, e->field, l, FcTrue);
1856                break;
1857            default:
1858                break;
1859            }
1860        }
1861        /*
1862         * Now go through the pattern and eliminate
1863         * any properties without data
1864         */
1865        for (e = s->edit; e; e = e->next)
1866            FcConfigPatternCanon (p, e->field);
1867
1868        if (FcDebug () & FC_DBG_EDIT)
1869        {
1870            printf ("FcConfigSubstitute edit");
1871            FcPatternPrint (p);
1872        }
1873    }
1874    FcMemFree (FC_MEM_SUBSTATE, config->maxObjects * sizeof (FcSubState));
1875    free (st);
1876    if (FcDebug () & FC_DBG_EDIT)
1877    {
1878        printf ("FcConfigSubstitute done");
1879        FcPatternPrint (p);
1880    }
1881    return FcTrue;
1882}
1883
1884FcBool
1885FcConfigSubstitute (FcConfig    *config,
1886                    FcPattern   *p,
1887                    FcMatchKind kind)
1888{
1889    return FcConfigSubstituteWithPat (config, p, 0, kind);
1890}
1891
1892#if defined (_WIN32) && (defined (PIC) || defined (DLL_EXPORT))
1893
1894static FcChar8 fontconfig_path[1000] = "";
1895
1896BOOL WINAPI
1897DllMain (HINSTANCE hinstDLL,
1898         DWORD     fdwReason,
1899         LPVOID    lpvReserved)
1900{
1901  FcChar8 *p;
1902
1903  switch (fdwReason) {
1904  case DLL_PROCESS_ATTACH:
1905      if (!GetModuleFileName ((HMODULE) hinstDLL, fontconfig_path,
1906                              sizeof (fontconfig_path)))
1907          break;
1908
1909      /* If the fontconfig DLL is in a "bin" or "lib" subfolder,
1910       * assume it's a Unix-style installation tree, and use
1911       * "etc/fonts" in there as FONTCONFIG_PATH. Otherwise use the
1912       * folder where the DLL is as FONTCONFIG_PATH.
1913       */
1914      p = strrchr (fontconfig_path, '\\');
1915      if (p)
1916      {
1917          *p = '\0';
1918          p = strrchr (fontconfig_path, '\\');
1919          if (p && (FcStrCmpIgnoreCase (p + 1, "bin") == 0 ||
1920                    FcStrCmpIgnoreCase (p + 1, "lib") == 0))
1921              *p = '\0';
1922          strcat (fontconfig_path, "\\etc\\fonts");
1923      }
1924      else
1925          fontconfig_path[0] = '\0';
1926     
1927      break;
1928  }
1929
1930  return TRUE;
1931}
1932
1933#undef FONTCONFIG_PATH
1934#define FONTCONFIG_PATH fontconfig_path
1935
1936#else /* !(_WIN32 && PIC) */
1937
1938#endif /* !(_WIN32 && PIC) */
1939
1940#ifndef FONTCONFIG_FILE
1941#define FONTCONFIG_FILE "fonts.conf"
1942#endif
1943
1944static FcChar8 *
1945FcConfigFileExists (const FcChar8 *dir, const FcChar8 *file)
1946{
1947    FcChar8    *path;
1948
1949    if (!dir)
1950        dir = (FcChar8 *) "";
1951    path = malloc (strlen ((char *) dir) + 1 + strlen ((char *) file) + 1);
1952    if (!path)
1953        return 0;
1954
1955    strcpy ((char *) path, (const char *) dir);
1956    /* make sure there's a single separator */
1957#if defined(_WIN32) || defined(__OS2__)
1958    if ((!path[0] || (path[strlen((char *) path)-1] != '/' &&
1959                      path[strlen((char *) path)-1] != '\\')) &&
1960        !(file[0] == '/' ||
1961          file[0] == '\\' ||
1962          (isalpha (file[0]) && file[1] == ':' && (file[2] == '/' || file[2] == '\\'))))
1963        strcat ((char *) path, "\\");
1964#else
1965    if ((!path[0] || path[strlen((char *) path)-1] != '/') && file[0] != '/')
1966        strcat ((char *) path, "/");
1967#endif
1968    strcat ((char *) path, (char *) file);
1969
1970    FcMemAlloc (FC_MEM_STRING, strlen ((char *) path) + 1);
1971    if (access ((char *) path, R_OK) == 0)
1972        return path;
1973   
1974    FcStrFree (path);
1975    return 0;
1976}
1977
1978static FcChar8 **
1979FcConfigGetPath (void)
1980{
1981    FcChar8    **path;
1982    FcChar8    *env, *e, *colon;
1983    FcChar8    *dir;
1984    int     npath;
1985    int     i;
1986
1987    npath = 2;  /* default dir + null */
1988    env = (FcChar8 *) getenv ("FONTCONFIG_PATH");
1989    if (env)
1990    {
1991        e = env;
1992        npath++;
1993        while (*e)
1994            if (*e++ == FC_SEARCH_PATH_SEPARATOR)
1995                npath++;
1996    }
1997    path = calloc (npath, sizeof (FcChar8 *));
1998    if (!path)
1999        goto bail0;
2000    i = 0;
2001
2002    if (env)
2003    {
2004        e = env;
2005        while (*e) 
2006        {
2007            colon = (FcChar8 *) strchr ((char *) e, FC_SEARCH_PATH_SEPARATOR);
2008            if (!colon)
2009                colon = e + strlen ((char *) e);
2010            path[i] = malloc (colon - e + 1);
2011            if (!path[i])
2012                goto bail1;
2013            strncpy ((char *) path[i], (const char *) e, colon - e);
2014            path[i][colon - e] = '\0';
2015            if (*colon)
2016                e = colon + 1;
2017            else
2018                e = colon;
2019            i++;
2020        }
2021    }
2022
2023#ifdef __OS2__
2024    // Add the home folder!
2025    dir = (FcChar8 *) FcConfigHome();
2026#else
2027    dir = (FcChar8 *) FONTCONFIG_PATH;
2028#endif
2029    path[i] = malloc (strlen ((char *) dir) + 1);
2030    if (!path[i])
2031        goto bail1;
2032    strcpy ((char *) path[i], (const char *) dir);
2033    return path;
2034
2035bail1:
2036    for (i = 0; path[i]; i++)
2037        free (path[i]);
2038    free (path);
2039bail0:
2040    return 0;
2041}
2042
2043static void
2044FcConfigFreePath (FcChar8 **path)
2045{
2046    FcChar8    **p;
2047
2048    for (p = path; *p; p++)
2049        free (*p);
2050    free (path);
2051}
2052
2053static FcBool   _FcConfigHomeEnabled = FcTrue;
2054
2055FcChar8 *
2056FcConfigHome (void)
2057{
2058    if (_FcConfigHomeEnabled)
2059    {
2060        char *home = getenv ("HOME");
2061
2062#ifdef _WIN32
2063        if (home == NULL)
2064            home = getenv ("USERPROFILE");
2065#endif
2066#ifdef __OS2__
2067        if (home == NULL)
2068            home = getenv ("ETC");
2069#endif
2070
2071        return home;
2072    }
2073    return 0;
2074}
2075
2076FcBool
2077FcConfigEnableHome (FcBool enable)
2078{
2079    FcBool  prev = _FcConfigHomeEnabled;
2080    _FcConfigHomeEnabled = enable;
2081    return prev;
2082}
2083
2084FcChar8 *
2085FcConfigFilename (const FcChar8 *url)
2086{
2087    FcChar8    *file, *dir, **path, **p;
2088   
2089    if (!url || !*url)
2090    {
2091        url = (FcChar8 *) getenv ("FONTCONFIG_FILE");
2092        if (!url)
2093          url = (FcChar8 *) FONTCONFIG_FILE;
2094    }
2095    file = 0;
2096
2097#if defined(_WIN32) || defined(__OS2__)
2098    if (isalpha (*url) &&
2099        url[1] == ':' &&
2100        (url[2] == '/' || url[2] == '\\'))
2101        goto absolute_path;
2102#endif
2103
2104    switch (*url) {
2105    case '~':
2106        dir = FcConfigHome ();
2107        if (dir)
2108            file = FcConfigFileExists (dir, url + 1);
2109        else
2110            file = 0;
2111        break;
2112#if defined(_WIN32) || defined(__OS2__)
2113    case '\\':
2114    absolute_path:
2115#endif
2116    case '/':
2117        file = FcConfigFileExists (0, url);
2118        break;
2119    default:
2120        path = FcConfigGetPath ();
2121        if (!path)
2122            return 0;
2123        for (p = path; *p; p++)
2124        {
2125            file = FcConfigFileExists (*p, url);
2126            if (file)
2127                break;
2128        }
2129        FcConfigFreePath (path);
2130#if defined(__OS2__)
2131        if (!file)
2132        {
2133          // Config file not found!
2134          // Creating default config file then in home, and try again!
2135          FILE *hFile;
2136          char *pchHome = FcConfigHome();
2137          if (pchHome)
2138          {
2139            char *pchFullPath = malloc(strlen(pchHome)+strlen(FONTCONFIG_FILE)+10);
2140   
2141            if (pchFullPath)
2142            {
2143              if (pchHome[strlen(pchHome)-1]!='\\')
2144                sprintf(pchFullPath, "%s\\%s", pchHome, FONTCONFIG_FILE);
2145              else
2146                sprintf(pchFullPath, "%s%s", pchHome, FONTCONFIG_FILE);
2147
2148              hFile = fopen(pchFullPath, "wt");
2149              free(pchFullPath);
2150              if (hFile)
2151              {
2152                fprintf(hFile, DEFAULT_OS2_CONFIG_FILE);
2153                fclose(hFile);
2154
2155                // Show info on text screens
2156                fprintf(stderr, "WARNING: New config file has been created for FontConfig!\n");
2157                fprintf(stderr, "         A scanning of all system fonts will be needed,\n");
2158                fprintf(stderr, "         which may take some minutes!\n");
2159                fprintf(stderr, "         Please be patient!\n");
2160
2161                // Also show info in window, if possible!
2162                // The MB_NONMODAL flag is missing from OpenWatcom's OS/2 header
2163                // files, so we define it here in case it's still missing:
2164#ifndef MB_NONMODAL
2165#define MB_NONMODAL 0x8000
2166#endif
2167                WinMessageBox(HWND_DESKTOP,
2168                              HWND_DESKTOP,
2169                              "New config file has been created for FontConfig!\n"
2170                              "A scanning of all system fonts will be needed,\n"
2171                              "which may take some minutes!\n"
2172                              "Please be patient!\n",
2173                              "First start of FontConfig",
2174                              0xca1f0,
2175                              MB_OK | MB_INFORMATION | MB_MOVEABLE | MB_NONMODAL);
2176
2177                // Now that we put there the default config file, start again!
2178                path = FcConfigGetPath ();
2179                if (!path)
2180                    return 0;
2181                for (p = path; *p; p++)
2182                {
2183                    file = FcConfigFileExists (*p, url);
2184                    if (file)
2185                        break;
2186                }
2187                FcConfigFreePath (path);
2188              }
2189            }
2190          }
2191        }
2192#endif
2193        break;
2194    }
2195    return file;
2196}
2197
2198/*
2199 * Manage the application-specific fonts
2200 */
2201
2202FcBool
2203FcConfigAppFontAddFile (FcConfig    *config,
2204                        const FcChar8  *file)
2205{
2206    FcFontSet   *set;
2207    FcStrSet    *subdirs;
2208    FcStrList   *sublist;
2209    FcChar8     *subdir;
2210
2211    if (!config)
2212    {
2213        config = FcConfigGetCurrent ();
2214        if (!config)
2215            return FcFalse;
2216    }
2217
2218    subdirs = FcStrSetCreate ();
2219    if (!subdirs)
2220        return FcFalse;
2221   
2222    set = FcConfigGetFonts (config, FcSetApplication);
2223    if (!set)
2224    {
2225        set = FcFontSetCreate ();
2226        if (!set)
2227        {
2228            FcStrSetDestroy (subdirs);
2229            return FcFalse;
2230        }
2231        FcConfigSetFonts (config, set, FcSetApplication);
2232    }
2233       
2234    if (!FcFileScanConfig (set, subdirs, 0, config->blanks, file, FcFalse, config))
2235    {
2236        FcStrSetDestroy (subdirs);
2237        return FcFalse;
2238    }
2239    if ((sublist = FcStrListCreate (subdirs)))
2240    {
2241        while ((subdir = FcStrListNext (sublist)))
2242        {
2243            FcConfigAppFontAddDir (config, subdir);
2244        }
2245        FcStrListDone (sublist);
2246    }
2247    return FcTrue;
2248}
2249
2250FcBool
2251FcConfigAppFontAddDir (FcConfig     *config,
2252                       const FcChar8   *dir)
2253{
2254    FcFontSet   *set;
2255    FcStrSet    *subdirs;
2256    FcStrList   *sublist;
2257    FcChar8     *subdir;
2258   
2259    if (!config)
2260    {
2261        config = FcConfigGetCurrent ();
2262        if (!config)
2263            return FcFalse;
2264    }
2265    subdirs = FcStrSetCreate ();
2266    if (!subdirs)
2267        return FcFalse;
2268   
2269    set = FcConfigGetFonts (config, FcSetApplication);
2270    if (!set)
2271    {
2272        set = FcFontSetCreate ();
2273        if (!set)
2274        {
2275            FcStrSetDestroy (subdirs);
2276            return FcFalse;
2277        }
2278        FcConfigSetFonts (config, set, FcSetApplication);
2279    }
2280   
2281    if (!FcDirScanConfig (set, subdirs, 0, config->blanks, dir, FcFalse, config))
2282    {
2283        FcStrSetDestroy (subdirs);
2284        return FcFalse;
2285    }
2286    if ((sublist = FcStrListCreate (subdirs)))
2287    {
2288        while ((subdir = FcStrListNext (sublist)))
2289        {
2290            FcConfigAppFontAddDir (config, subdir);
2291        }
2292        FcStrListDone (sublist);
2293    }
2294    return FcTrue;
2295}
2296
2297void
2298FcConfigAppFontClear (FcConfig      *config)
2299{
2300    if (!config)
2301    {
2302        config = FcConfigGetCurrent ();
2303        if (!config)
2304            return;
2305    }
2306
2307    FcConfigSetFonts (config, 0, FcSetApplication);
2308}
2309
2310/*
2311 * Manage filename-based font source selectors
2312 */
2313
2314FcBool
2315FcConfigGlobAdd (FcConfig       *config,
2316                 const FcChar8  *glob,
2317                 FcBool         accept)
2318{
2319    FcStrSet    *set = accept ? config->acceptGlobs : config->rejectGlobs;
2320
2321    return FcStrSetAdd (set, glob);
2322}
2323
2324static FcBool
2325FcConfigGlobMatch (const FcChar8    *glob,
2326                   const FcChar8    *string)
2327{
2328    FcChar8     c;
2329
2330    while ((c = *glob++)) 
2331    {
2332        switch (c) {
2333        case '*':
2334            /* short circuit common case */
2335            if (!*glob)
2336                return FcTrue;
2337            /* short circuit another common case */
2338            if (strchr ((char *) glob, '*') == 0)
2339                string += strlen ((char *) string) - strlen ((char *) glob);
2340            while (*string)
2341            {
2342                if (FcConfigGlobMatch (glob, string))
2343                    return FcTrue;
2344                string++;
2345            }
2346            return FcFalse;
2347        case '?':
2348            if (*string++ == '\0')
2349                return FcFalse;
2350            break;
2351        default:
2352            if (*string++ != c)
2353                return FcFalse;
2354            break;
2355        }
2356    }
2357    return *string == '\0';
2358}
2359
2360static FcBool
2361FcConfigGlobsMatch (const FcStrSet      *globs,
2362                    const FcChar8       *string)
2363{
2364    int i;
2365
2366    for (i = 0; i < globs->num; i++)
2367        if (FcConfigGlobMatch (globs->strs[i], string))
2368            return FcTrue;
2369    return FcFalse;
2370}
2371
2372FcBool
2373FcConfigAcceptFilename (FcConfig        *config,
2374                        const FcChar8   *filename)
2375{
2376    if (FcConfigGlobsMatch (config->acceptGlobs, filename))
2377        return FcTrue;
2378    if (FcConfigGlobsMatch (config->rejectGlobs, filename))
2379        return FcFalse;
2380    return FcTrue;
2381}
2382
2383/*
2384 * Manage font-pattern based font source selectors
2385 */
2386
2387FcBool
2388FcConfigPatternsAdd (FcConfig   *config,
2389                     FcPattern  *pattern,
2390                     FcBool     accept)
2391{
2392    FcFontSet   *set = accept ? config->acceptPatterns : config->rejectPatterns;
2393
2394    return FcFontSetAdd (set, pattern);
2395}
2396
2397static FcBool
2398FcConfigPatternsMatch (const FcFontSet  *patterns,
2399                       const FcPattern  *font)
2400{
2401    int i;
2402   
2403    for (i = 0; i < patterns->nfont; i++)
2404        if (FcListPatternMatchAny (patterns->fonts[i], font))
2405            return FcTrue;
2406    return FcFalse;
2407}
2408
2409FcBool
2410FcConfigAcceptFont (FcConfig        *config,
2411                    const FcPattern *font)
2412{
2413    if (FcConfigPatternsMatch (config->acceptPatterns, font))
2414        return FcTrue;
2415    if (FcConfigPatternsMatch (config->rejectPatterns, font))
2416        return FcFalse;
2417    return FcTrue;
2418}
Note: See TracBrowser for help on using the repository browser.