1a32e9e42Smrg/*
2a32e9e42Smrg * fontconfig/test/test-bz89617.c
3a32e9e42Smrg *
4a32e9e42Smrg * Copyright © 2000 Keith Packard
5a32e9e42Smrg * Copyright © 2018 Akira TAGOH
6a32e9e42Smrg *
7a32e9e42Smrg * Permission to use, copy, modify, distribute, and sell this software and its
8a32e9e42Smrg * documentation for any purpose is hereby granted without fee, provided that
9a32e9e42Smrg * the above copyright notice appear in all copies and that both that
10a32e9e42Smrg * copyright notice and this permission notice appear in supporting
11a32e9e42Smrg * documentation, and that the name of the author(s) not be used in
12a32e9e42Smrg * advertising or publicity pertaining to distribution of the software without
13a32e9e42Smrg * specific, written prior permission.  The authors make no
14a32e9e42Smrg * representations about the suitability of this software for any purpose.  It
15a32e9e42Smrg * is provided "as is" without express or implied warranty.
16a32e9e42Smrg *
17a32e9e42Smrg * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
18a32e9e42Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
19a32e9e42Smrg * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
20a32e9e42Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
21a32e9e42Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
22a32e9e42Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
23a32e9e42Smrg * PERFORMANCE OF THIS SOFTWARE.
24a32e9e42Smrg */
25a32e9e42Smrg#ifdef HAVE_CONFIG_H
26a32e9e42Smrg#include "config.h"
27a32e9e42Smrg#endif
28a4e54154Smrg#include <stdio.h>
29a32e9e42Smrg#include <stdlib.h>
30a4e54154Smrg#include <string.h>
31a32e9e42Smrg#include <dirent.h>
32a4e54154Smrg#include <errno.h>
33a4e54154Smrg#ifdef HAVE_UNISTD_H
34a4e54154Smrg#include <unistd.h>
35a4e54154Smrg#endif
36a32e9e42Smrg#ifndef HAVE_STRUCT_DIRENT_D_TYPE
37a32e9e42Smrg#include <sys/types.h>
38a32e9e42Smrg#include <sys/stat.h>
39a32e9e42Smrg#endif
40a32e9e42Smrg#include <fontconfig/fontconfig.h>
41a32e9e42Smrg
42a4e54154Smrg#ifdef _WIN32
43a4e54154Smrg#  define FC_DIR_SEPARATOR         '\\'
44a4e54154Smrg#  define FC_DIR_SEPARATOR_S       "\\"
45a4e54154Smrg#else
46a4e54154Smrg#  define FC_DIR_SEPARATOR         '/'
47a4e54154Smrg#  define FC_DIR_SEPARATOR_S       "/"
48a4e54154Smrg#endif
49a4e54154Smrg
50a4e54154Smrg#ifdef _WIN32
51a4e54154Smrg#include <direct.h>
52a4e54154Smrg#define mkdir(path,mode) _mkdir(path)
53a4e54154Smrg#endif
54a4e54154Smrg
55a32e9e42Smrg#ifdef HAVE_MKDTEMP
56a32e9e42Smrg#define fc_mkdtemp	mkdtemp
57a32e9e42Smrg#else
58a32e9e42Smrgchar *
59a32e9e42Smrgfc_mkdtemp (char *template)
60a32e9e42Smrg{
61a32e9e42Smrg    if (!mktemp (template) || mkdir (template, 0700))
62a32e9e42Smrg	return NULL;
63a32e9e42Smrg
64a32e9e42Smrg    return template;
65a32e9e42Smrg}
66a32e9e42Smrg#endif
67a32e9e42Smrg
68a32e9e42SmrgFcBool
69a32e9e42Smrgmkdir_p (const char *dir)
70a32e9e42Smrg{
71a32e9e42Smrg    char *parent;
72a32e9e42Smrg    FcBool ret;
73a32e9e42Smrg
74a32e9e42Smrg    if (strlen (dir) == 0)
75a32e9e42Smrg	return FcFalse;
76a32e9e42Smrg    parent = (char *) FcStrDirname ((const FcChar8 *) dir);
77a32e9e42Smrg    if (!parent)
78a32e9e42Smrg	return FcFalse;
79a32e9e42Smrg    if (access (parent, F_OK) == 0)
80a32e9e42Smrg	ret = mkdir (dir, 0755) == 0 && chmod (dir, 0755) == 0;
81a32e9e42Smrg    else if (access (parent, F_OK) == -1)
82a32e9e42Smrg	ret = mkdir_p (parent) && (mkdir (dir, 0755) == 0) && chmod (dir, 0755) == 0;
83a32e9e42Smrg    else
84a32e9e42Smrg	ret = FcFalse;
85a32e9e42Smrg    free (parent);
86a32e9e42Smrg
87a32e9e42Smrg    return ret;
88a32e9e42Smrg}
89a32e9e42Smrg
90a32e9e42SmrgFcBool
91a32e9e42Smrgunlink_dirs (const char *dir)
92a32e9e42Smrg{
93a32e9e42Smrg    DIR *d = opendir (dir);
94a32e9e42Smrg    struct dirent *e;
95a32e9e42Smrg    size_t len = strlen (dir);
96a32e9e42Smrg    char *n = NULL;
97a32e9e42Smrg    FcBool ret = FcTrue;
98a32e9e42Smrg#ifndef HAVE_STRUCT_DIRENT_D_TYPE
99a32e9e42Smrg    struct stat statb;
100a32e9e42Smrg#endif
101a32e9e42Smrg
102a32e9e42Smrg    if (!d)
103a32e9e42Smrg	return FcFalse;
104a32e9e42Smrg    while ((e = readdir (d)) != NULL)
105a32e9e42Smrg    {
106a32e9e42Smrg	size_t l;
107a32e9e42Smrg
108a32e9e42Smrg	if (strcmp (e->d_name, ".") == 0 ||
109a32e9e42Smrg	    strcmp (e->d_name, "..") == 0)
110a32e9e42Smrg	    continue;
111a32e9e42Smrg	l = strlen (e->d_name) + 1;
112a32e9e42Smrg	if (n)
113a32e9e42Smrg	    free (n);
114a32e9e42Smrg	n = malloc (l + len + 1);
115a32e9e42Smrg	if (!n)
116a32e9e42Smrg	{
117a32e9e42Smrg	    ret = FcFalse;
118a32e9e42Smrg	    break;
119a32e9e42Smrg	}
120a32e9e42Smrg	strcpy (n, dir);
121a32e9e42Smrg	n[len] = FC_DIR_SEPARATOR;
122a32e9e42Smrg	strcpy (&n[len + 1], e->d_name);
123a32e9e42Smrg#ifdef HAVE_STRUCT_DIRENT_D_TYPE
124a32e9e42Smrg	if (e->d_type == DT_DIR)
125a32e9e42Smrg#else
126a32e9e42Smrg	if (stat (n, &statb) == -1)
127a32e9e42Smrg	{
128a32e9e42Smrg	    fprintf (stderr, "E: %s\n", n);
129a32e9e42Smrg	    ret = FcFalse;
130a32e9e42Smrg	    break;
131a32e9e42Smrg	}
132a32e9e42Smrg	if (S_ISDIR (statb.st_mode))
133a32e9e42Smrg#endif
134a32e9e42Smrg	{
135a32e9e42Smrg	    if (!unlink_dirs (n))
136a32e9e42Smrg	    {
137a32e9e42Smrg		fprintf (stderr, "E: %s\n", n);
138a32e9e42Smrg		ret = FcFalse;
139a32e9e42Smrg		break;
140a32e9e42Smrg	    }
141a32e9e42Smrg	}
142a32e9e42Smrg	else
143a32e9e42Smrg	{
144a32e9e42Smrg	    if (unlink (n) == -1)
145a32e9e42Smrg	    {
146a32e9e42Smrg		fprintf (stderr, "E: %s\n", n);
147a32e9e42Smrg		ret = FcFalse;
148a32e9e42Smrg		break;
149a32e9e42Smrg	    }
150a32e9e42Smrg	}
151a32e9e42Smrg    }
152a32e9e42Smrg    if (n)
153a32e9e42Smrg	free (n);
154a32e9e42Smrg    closedir (d);
155a32e9e42Smrg
156a32e9e42Smrg    if (rmdir (dir) == -1)
157a32e9e42Smrg    {
158a32e9e42Smrg	fprintf (stderr, "E: %s\n", dir);
159a32e9e42Smrg	return FcFalse;
160a32e9e42Smrg    }
161a32e9e42Smrg
162a32e9e42Smrg    return ret;
163a32e9e42Smrg}
164a32e9e42Smrg
165a32e9e42Smrgint
166a32e9e42Smrgmain (void)
167a32e9e42Smrg{
168a4e54154Smrg    FcChar8 *fontdir = NULL, *cachedir = NULL;
169a32e9e42Smrg    char *basedir, template[512] = "/tmp/bz106632-XXXXXX";
170a32e9e42Smrg    char cmd[512];
171a32e9e42Smrg    FcConfig *config;
172a4e54154Smrg    const FcChar8 *tconf = (const FcChar8 *) "<fontconfig>\n"
173a32e9e42Smrg	"  <dir>%s</dir>\n"
174a32e9e42Smrg	"  <cachedir>%s</cachedir>\n"
175a32e9e42Smrg	"</fontconfig>\n";
176a32e9e42Smrg    char conf[1024];
177a32e9e42Smrg    int ret = 0;
178a32e9e42Smrg    FcFontSet *fs;
179a32e9e42Smrg    FcPattern *pat;
180a32e9e42Smrg
181a32e9e42Smrg    fprintf (stderr, "D: Creating tmp dir\n");
182a32e9e42Smrg    basedir = fc_mkdtemp (template);
183a32e9e42Smrg    if (!basedir)
184a32e9e42Smrg    {
185a32e9e42Smrg	fprintf (stderr, "%s: %s\n", template, strerror (errno));
186a32e9e42Smrg	goto bail;
187a32e9e42Smrg    }
188a4e54154Smrg    fontdir = FcStrBuildFilename ((const FcChar8 *) basedir, (const FcChar8 *) "fonts", NULL);
189a4e54154Smrg    cachedir = FcStrBuildFilename ((const FcChar8 *) basedir, (const FcChar8 *) "cache", NULL);
190a32e9e42Smrg    fprintf (stderr, "D: Creating %s\n", fontdir);
191a4e54154Smrg    mkdir_p ((const char *) fontdir);
192a32e9e42Smrg    fprintf (stderr, "D: Creating %s\n", cachedir);
193a4e54154Smrg    mkdir_p ((const char *) cachedir);
194a32e9e42Smrg
195a32e9e42Smrg    fprintf (stderr, "D: Copying %s to %s\n", FONTFILE, fontdir);
196a4e54154Smrg    snprintf (cmd, 512, "sleep 1; cp -a %s %s; sleep 1", FONTFILE, fontdir);
197a4e54154Smrg    (void) system (cmd);
198a32e9e42Smrg
199a32e9e42Smrg    fprintf (stderr, "D: Loading a config\n");
200a4e54154Smrg    snprintf (conf, 1024, (const char *) tconf, fontdir, cachedir);
201a32e9e42Smrg    config = FcConfigCreate ();
202a4e54154Smrg    if (!FcConfigParseAndLoadFromMemory (config, (const FcChar8 *) conf, FcTrue))
203a32e9e42Smrg    {
204a32e9e42Smrg	printf ("E: Unable to load config\n");
205a32e9e42Smrg	ret = 1;
206a32e9e42Smrg	goto bail;
207a32e9e42Smrg    }
208a32e9e42Smrg    if (!FcConfigBuildFonts (config))
209a32e9e42Smrg    {
210a32e9e42Smrg	printf ("E: unable to build fonts\n");
211a32e9e42Smrg	ret = 1;
212a32e9e42Smrg	goto bail;
213a32e9e42Smrg    }
214a32e9e42Smrg    fprintf (stderr, "D: Obtaining fonts information\n");
215a32e9e42Smrg    pat = FcPatternCreate ();
216a32e9e42Smrg    fs = FcFontList (config, pat, NULL);
217a32e9e42Smrg    FcPatternDestroy (pat);
218a32e9e42Smrg    if (!fs || fs->nfont != 1)
219a32e9e42Smrg    {
220a32e9e42Smrg	printf ("E: Unexpected the number of fonts: %d\n", !fs ? -1 : fs->nfont);
221a32e9e42Smrg	ret = 1;
222a32e9e42Smrg	goto bail;
223a32e9e42Smrg    }
224a4e54154Smrg    FcFontSetDestroy (fs);
225a32e9e42Smrg    fprintf (stderr, "D: Removing %s\n", fontdir);
226a4e54154Smrg    snprintf (cmd, 512, "sleep 1; rm -f %s%s*; sleep 1", fontdir, FC_DIR_SEPARATOR_S);
227a4e54154Smrg    (void) system (cmd);
228a32e9e42Smrg    fprintf (stderr, "D: Reinitializing\n");
229a4e54154Smrg    if (FcConfigUptoDate(config))
230a32e9e42Smrg    {
231a4e54154Smrg	fprintf (stderr, "E: Config reports up-to-date\n");
232a32e9e42Smrg	ret = 2;
233a32e9e42Smrg	goto bail;
234a32e9e42Smrg    }
235a4e54154Smrg    if (!FcInitReinitialize ())
236a4e54154Smrg    {
237a4e54154Smrg	fprintf (stderr, "E: Unable to reinitialize\n");
238a4e54154Smrg	ret = 3;
239a4e54154Smrg	goto bail;
240a4e54154Smrg    }
241a32e9e42Smrg    if (FcConfigGetCurrent () == config)
242a32e9e42Smrg    {
243a32e9e42Smrg	fprintf (stderr, "E: config wasn't reloaded\n");
244a32e9e42Smrg	ret = 3;
245a32e9e42Smrg	goto bail;
246a32e9e42Smrg    }
247a4e54154Smrg    FcConfigDestroy (config);
248a4e54154Smrg
249a32e9e42Smrg    config = FcConfigCreate ();
250a4e54154Smrg    if (!FcConfigParseAndLoadFromMemory (config, (const FcChar8 *) conf, FcTrue))
251a32e9e42Smrg    {
252a32e9e42Smrg	printf ("E: Unable to load config again\n");
253a32e9e42Smrg	ret = 4;
254a32e9e42Smrg	goto bail;
255a32e9e42Smrg    }
256a32e9e42Smrg    if (!FcConfigBuildFonts (config))
257a32e9e42Smrg    {
258a32e9e42Smrg	printf ("E: unable to build fonts again\n");
259a32e9e42Smrg	ret = 5;
260a32e9e42Smrg	goto bail;
261a32e9e42Smrg    }
262a32e9e42Smrg    fprintf (stderr, "D: Obtaining fonts information again\n");
263a32e9e42Smrg    pat = FcPatternCreate ();
264a32e9e42Smrg    fs = FcFontList (config, pat, NULL);
265a32e9e42Smrg    FcPatternDestroy (pat);
266a32e9e42Smrg    if (!fs || fs->nfont != 0)
267a32e9e42Smrg    {
268a32e9e42Smrg	printf ("E: Unexpected the number of fonts: %d\n", !fs ? -1 : fs->nfont);
269a32e9e42Smrg	ret = 1;
270a32e9e42Smrg	goto bail;
271a32e9e42Smrg    }
272a4e54154Smrg    FcFontSetDestroy (fs);
273a32e9e42Smrg    fprintf (stderr, "D: Copying %s to %s\n", FONTFILE, fontdir);
274a4e54154Smrg    snprintf (cmd, 512, "sleep 1; cp -a %s %s; sleep 1", FONTFILE, fontdir);
275a4e54154Smrg    (void) system (cmd);
276a32e9e42Smrg    fprintf (stderr, "D: Reinitializing\n");
277a4e54154Smrg    if (FcConfigUptoDate(config))
278a4e54154Smrg    {
279a4e54154Smrg	fprintf (stderr, "E: Config up-to-date after addition\n");
280a4e54154Smrg	ret = 3;
281a4e54154Smrg	goto bail;
282a4e54154Smrg    }
283a4e54154Smrg    if (!FcInitReinitialize ())
284a32e9e42Smrg    {
285a32e9e42Smrg	fprintf (stderr, "E: Unable to reinitialize\n");
286a32e9e42Smrg	ret = 2;
287a32e9e42Smrg	goto bail;
288a32e9e42Smrg    }
289a32e9e42Smrg    if (FcConfigGetCurrent () == config)
290a32e9e42Smrg    {
291a32e9e42Smrg	fprintf (stderr, "E: config wasn't reloaded\n");
292a32e9e42Smrg	ret = 3;
293a32e9e42Smrg	goto bail;
294a32e9e42Smrg    }
295a4e54154Smrg    FcConfigDestroy (config);
296a4e54154Smrg
297a32e9e42Smrg    config = FcConfigCreate ();
298a4e54154Smrg    if (!FcConfigParseAndLoadFromMemory (config, (const FcChar8 *) conf, FcTrue))
299a32e9e42Smrg    {
300a32e9e42Smrg	printf ("E: Unable to load config again\n");
301a32e9e42Smrg	ret = 4;
302a32e9e42Smrg	goto bail;
303a32e9e42Smrg    }
304a32e9e42Smrg    if (!FcConfigBuildFonts (config))
305a32e9e42Smrg    {
306a32e9e42Smrg	printf ("E: unable to build fonts again\n");
307a32e9e42Smrg	ret = 5;
308a32e9e42Smrg	goto bail;
309a32e9e42Smrg    }
310a32e9e42Smrg    fprintf (stderr, "D: Obtaining fonts information\n");
311a32e9e42Smrg    pat = FcPatternCreate ();
312a32e9e42Smrg    fs = FcFontList (config, pat, NULL);
313a32e9e42Smrg    FcPatternDestroy (pat);
314a32e9e42Smrg    if (!fs || fs->nfont != 1)
315a32e9e42Smrg    {
316a32e9e42Smrg	printf ("E: Unexpected the number of fonts: %d\n", !fs ? -1 : fs->nfont);
317a32e9e42Smrg	ret = 1;
318a32e9e42Smrg	goto bail;
319a32e9e42Smrg    }
320a4e54154Smrg    FcFontSetDestroy (fs);
321a4e54154Smrg    FcConfigDestroy (config);
322a32e9e42Smrg
323a32e9e42Smrgbail:
324a32e9e42Smrg    fprintf (stderr, "Cleaning up\n");
325a4e54154Smrg    if (basedir)
326a4e54154Smrg	unlink_dirs (basedir);
327a32e9e42Smrg    if (fontdir)
328a32e9e42Smrg	FcStrFree (fontdir);
329a32e9e42Smrg    if (cachedir)
330a32e9e42Smrg	FcStrFree (cachedir);
331a32e9e42Smrg
332a32e9e42Smrg    return ret;
333a32e9e42Smrg}
334