xref: /freebsd/contrib/pkgconf/libpkgconf/personality.c (revision a3cefe7f2b4df0f70ff92d4570ce18e517af43ec)
1*a3cefe7fSPierre Pronchery /*
2*a3cefe7fSPierre Pronchery  * personality.c
3*a3cefe7fSPierre Pronchery  * libpkgconf cross-compile personality database
4*a3cefe7fSPierre Pronchery  *
5*a3cefe7fSPierre Pronchery  * Copyright (c) 2018 pkgconf authors (see AUTHORS).
6*a3cefe7fSPierre Pronchery  *
7*a3cefe7fSPierre Pronchery  * Permission to use, copy, modify, and/or distribute this software for any
8*a3cefe7fSPierre Pronchery  * purpose with or without fee is hereby granted, provided that the above
9*a3cefe7fSPierre Pronchery  * copyright notice and this permission notice appear in all copies.
10*a3cefe7fSPierre Pronchery  *
11*a3cefe7fSPierre Pronchery  * This software is provided 'as is' and without any warranty, express or
12*a3cefe7fSPierre Pronchery  * implied.  In no event shall the authors be liable for any damages arising
13*a3cefe7fSPierre Pronchery  * from the use of this software.
14*a3cefe7fSPierre Pronchery  */
15*a3cefe7fSPierre Pronchery 
16*a3cefe7fSPierre Pronchery #include <libpkgconf/config.h>
17*a3cefe7fSPierre Pronchery #include <libpkgconf/stdinc.h>
18*a3cefe7fSPierre Pronchery #include <libpkgconf/libpkgconf.h>
19*a3cefe7fSPierre Pronchery 
20*a3cefe7fSPierre Pronchery /*
21*a3cefe7fSPierre Pronchery  * !doc
22*a3cefe7fSPierre Pronchery  *
23*a3cefe7fSPierre Pronchery  * libpkgconf `personality` module
24*a3cefe7fSPierre Pronchery  * =========================
25*a3cefe7fSPierre Pronchery  */
26*a3cefe7fSPierre Pronchery 
27*a3cefe7fSPierre Pronchery #ifdef _WIN32
28*a3cefe7fSPierre Pronchery #	define strcasecmp _stricmp
29*a3cefe7fSPierre Pronchery #endif
30*a3cefe7fSPierre Pronchery 
31*a3cefe7fSPierre Pronchery /*
32*a3cefe7fSPierre Pronchery  * Increment each time the default personality is inited, decrement each time
33*a3cefe7fSPierre Pronchery  * it's deinited. Whenever it is 0, then the deinit frees the personality. In
34*a3cefe7fSPierre Pronchery  * that case an additional call to init will create it anew.
35*a3cefe7fSPierre Pronchery  */
36*a3cefe7fSPierre Pronchery static unsigned default_personality_init = 0;
37*a3cefe7fSPierre Pronchery 
38*a3cefe7fSPierre Pronchery static pkgconf_cross_personality_t default_personality = {
39*a3cefe7fSPierre Pronchery 	.name = "default",
40*a3cefe7fSPierre Pronchery };
41*a3cefe7fSPierre Pronchery 
42*a3cefe7fSPierre Pronchery static inline void
build_default_search_path(pkgconf_list_t * dirlist)43*a3cefe7fSPierre Pronchery build_default_search_path(pkgconf_list_t* dirlist)
44*a3cefe7fSPierre Pronchery {
45*a3cefe7fSPierre Pronchery #ifdef _WIN32
46*a3cefe7fSPierre Pronchery 	char namebuf[MAX_PATH];
47*a3cefe7fSPierre Pronchery 	char outbuf[MAX_PATH];
48*a3cefe7fSPierre Pronchery 	char *p;
49*a3cefe7fSPierre Pronchery 
50*a3cefe7fSPierre Pronchery 	int sizepath = GetModuleFileName(NULL, namebuf, sizeof namebuf);
51*a3cefe7fSPierre Pronchery 	char * winslash;
52*a3cefe7fSPierre Pronchery 	namebuf[sizepath] = '\0';
53*a3cefe7fSPierre Pronchery 	while ((winslash = strchr (namebuf, '\\')) != NULL)
54*a3cefe7fSPierre Pronchery 	{
55*a3cefe7fSPierre Pronchery 		*winslash = '/';
56*a3cefe7fSPierre Pronchery 	}
57*a3cefe7fSPierre Pronchery 	p = strrchr(namebuf, '/');
58*a3cefe7fSPierre Pronchery 	if (p == NULL)
59*a3cefe7fSPierre Pronchery 		pkgconf_path_split(PKG_DEFAULT_PATH, dirlist, true);
60*a3cefe7fSPierre Pronchery 
61*a3cefe7fSPierre Pronchery 	*p = '\0';
62*a3cefe7fSPierre Pronchery 	pkgconf_strlcpy(outbuf, namebuf, sizeof outbuf);
63*a3cefe7fSPierre Pronchery 	pkgconf_strlcat(outbuf, "/", sizeof outbuf);
64*a3cefe7fSPierre Pronchery 	pkgconf_strlcat(outbuf, "../lib/pkgconfig", sizeof outbuf);
65*a3cefe7fSPierre Pronchery 	pkgconf_path_add(outbuf, dirlist, true);
66*a3cefe7fSPierre Pronchery 	pkgconf_strlcpy(outbuf, namebuf, sizeof outbuf);
67*a3cefe7fSPierre Pronchery 	pkgconf_strlcat(outbuf, "/", sizeof outbuf);
68*a3cefe7fSPierre Pronchery 	pkgconf_strlcat(outbuf, "../share/pkgconfig", sizeof outbuf);
69*a3cefe7fSPierre Pronchery 	pkgconf_path_add(outbuf, dirlist, true);
70*a3cefe7fSPierre Pronchery #elif __HAIKU__
71*a3cefe7fSPierre Pronchery 	char **paths;
72*a3cefe7fSPierre Pronchery 	size_t count;
73*a3cefe7fSPierre Pronchery 	if (find_paths(B_FIND_PATH_DEVELOP_LIB_DIRECTORY, "pkgconfig", &paths, &count) == B_OK) {
74*a3cefe7fSPierre Pronchery 		for (size_t i = 0; i < count; i++)
75*a3cefe7fSPierre Pronchery 			pkgconf_path_add(paths[i], dirlist, true);
76*a3cefe7fSPierre Pronchery 		free(paths);
77*a3cefe7fSPierre Pronchery 		paths = NULL;
78*a3cefe7fSPierre Pronchery 	}
79*a3cefe7fSPierre Pronchery 	if (find_paths(B_FIND_PATH_DATA_DIRECTORY, "pkgconfig", &paths, &count) == B_OK) {
80*a3cefe7fSPierre Pronchery 		for (size_t i = 0; i < count; i++)
81*a3cefe7fSPierre Pronchery 			pkgconf_path_add(paths[i], dirlist, true);
82*a3cefe7fSPierre Pronchery 		free(paths);
83*a3cefe7fSPierre Pronchery 		paths = NULL;
84*a3cefe7fSPierre Pronchery 	}
85*a3cefe7fSPierre Pronchery #else
86*a3cefe7fSPierre Pronchery 	pkgconf_path_split(PKG_DEFAULT_PATH, dirlist, true);
87*a3cefe7fSPierre Pronchery #endif
88*a3cefe7fSPierre Pronchery }
89*a3cefe7fSPierre Pronchery 
90*a3cefe7fSPierre Pronchery /*
91*a3cefe7fSPierre Pronchery  * !doc
92*a3cefe7fSPierre Pronchery  *
93*a3cefe7fSPierre Pronchery  * .. c:function:: const pkgconf_cross_personality_t *pkgconf_cross_personality_default(void)
94*a3cefe7fSPierre Pronchery  *
95*a3cefe7fSPierre Pronchery  *    Returns the default cross-compile personality.
96*a3cefe7fSPierre Pronchery  *
97*a3cefe7fSPierre Pronchery  *    Not thread safe.
98*a3cefe7fSPierre Pronchery  *
99*a3cefe7fSPierre Pronchery  *    :rtype: pkgconf_cross_personality_t*
100*a3cefe7fSPierre Pronchery  *    :return: the default cross-compile personality
101*a3cefe7fSPierre Pronchery  */
102*a3cefe7fSPierre Pronchery pkgconf_cross_personality_t *
pkgconf_cross_personality_default(void)103*a3cefe7fSPierre Pronchery pkgconf_cross_personality_default(void)
104*a3cefe7fSPierre Pronchery {
105*a3cefe7fSPierre Pronchery 	if (default_personality_init) {
106*a3cefe7fSPierre Pronchery 		++default_personality_init;
107*a3cefe7fSPierre Pronchery 		return &default_personality;
108*a3cefe7fSPierre Pronchery 	}
109*a3cefe7fSPierre Pronchery 
110*a3cefe7fSPierre Pronchery 	build_default_search_path(&default_personality.dir_list);
111*a3cefe7fSPierre Pronchery 
112*a3cefe7fSPierre Pronchery 	pkgconf_path_split(SYSTEM_LIBDIR, &default_personality.filter_libdirs, false);
113*a3cefe7fSPierre Pronchery 	pkgconf_path_split(SYSTEM_INCLUDEDIR, &default_personality.filter_includedirs, false);
114*a3cefe7fSPierre Pronchery 
115*a3cefe7fSPierre Pronchery 	++default_personality_init;
116*a3cefe7fSPierre Pronchery 	return &default_personality;
117*a3cefe7fSPierre Pronchery }
118*a3cefe7fSPierre Pronchery 
119*a3cefe7fSPierre Pronchery /*
120*a3cefe7fSPierre Pronchery  * !doc
121*a3cefe7fSPierre Pronchery  *
122*a3cefe7fSPierre Pronchery  * .. c:function:: void pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *)
123*a3cefe7fSPierre Pronchery  *
124*a3cefe7fSPierre Pronchery  *    Destroys a cross personality object and/or decreases the reference count on the
125*a3cefe7fSPierre Pronchery  *    default cross personality object.
126*a3cefe7fSPierre Pronchery  *
127*a3cefe7fSPierre Pronchery  *    Not thread safe.
128*a3cefe7fSPierre Pronchery  *
129*a3cefe7fSPierre Pronchery  *    :rtype: void
130*a3cefe7fSPierre Pronchery  */
131*a3cefe7fSPierre Pronchery void
pkgconf_cross_personality_deinit(pkgconf_cross_personality_t * personality)132*a3cefe7fSPierre Pronchery pkgconf_cross_personality_deinit(pkgconf_cross_personality_t *personality)
133*a3cefe7fSPierre Pronchery {
134*a3cefe7fSPierre Pronchery 	/* allow NULL parameter for API backwards compatibility */
135*a3cefe7fSPierre Pronchery 	if (personality == NULL)
136*a3cefe7fSPierre Pronchery 		return;
137*a3cefe7fSPierre Pronchery 
138*a3cefe7fSPierre Pronchery 	/* XXX: this hack is rather ugly, but it works for now... */
139*a3cefe7fSPierre Pronchery 	if (personality == &default_personality && --default_personality_init > 0)
140*a3cefe7fSPierre Pronchery 		return;
141*a3cefe7fSPierre Pronchery 
142*a3cefe7fSPierre Pronchery 	pkgconf_path_free(&personality->dir_list);
143*a3cefe7fSPierre Pronchery 	pkgconf_path_free(&personality->filter_libdirs);
144*a3cefe7fSPierre Pronchery 	pkgconf_path_free(&personality->filter_includedirs);
145*a3cefe7fSPierre Pronchery 
146*a3cefe7fSPierre Pronchery 	if (personality->sysroot_dir != NULL)
147*a3cefe7fSPierre Pronchery 		free(personality->sysroot_dir);
148*a3cefe7fSPierre Pronchery 
149*a3cefe7fSPierre Pronchery 	if (personality == &default_personality)
150*a3cefe7fSPierre Pronchery 		return;
151*a3cefe7fSPierre Pronchery 
152*a3cefe7fSPierre Pronchery 	if (personality->name != NULL)
153*a3cefe7fSPierre Pronchery 		free(personality->name);
154*a3cefe7fSPierre Pronchery 
155*a3cefe7fSPierre Pronchery 	free(personality);
156*a3cefe7fSPierre Pronchery }
157*a3cefe7fSPierre Pronchery 
158*a3cefe7fSPierre Pronchery #ifndef PKGCONF_LITE
159*a3cefe7fSPierre Pronchery static bool
valid_triplet(const char * triplet)160*a3cefe7fSPierre Pronchery valid_triplet(const char *triplet)
161*a3cefe7fSPierre Pronchery {
162*a3cefe7fSPierre Pronchery 	const char *c = triplet;
163*a3cefe7fSPierre Pronchery 
164*a3cefe7fSPierre Pronchery 	for (; *c; c++)
165*a3cefe7fSPierre Pronchery 		if (!isalnum((unsigned char)*c) && *c != '-' && *c != '_')
166*a3cefe7fSPierre Pronchery 			return false;
167*a3cefe7fSPierre Pronchery 
168*a3cefe7fSPierre Pronchery 	return true;
169*a3cefe7fSPierre Pronchery }
170*a3cefe7fSPierre Pronchery 
171*a3cefe7fSPierre Pronchery typedef void (*personality_keyword_func_t)(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value);
172*a3cefe7fSPierre Pronchery typedef struct {
173*a3cefe7fSPierre Pronchery 	const char *keyword;
174*a3cefe7fSPierre Pronchery 	const personality_keyword_func_t func;
175*a3cefe7fSPierre Pronchery 	const ptrdiff_t offset;
176*a3cefe7fSPierre Pronchery } personality_keyword_pair_t;
177*a3cefe7fSPierre Pronchery 
178*a3cefe7fSPierre Pronchery static void
personality_bool_func(pkgconf_cross_personality_t * p,const char * keyword,const size_t lineno,const ptrdiff_t offset,char * value)179*a3cefe7fSPierre Pronchery personality_bool_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
180*a3cefe7fSPierre Pronchery {
181*a3cefe7fSPierre Pronchery 	(void) keyword;
182*a3cefe7fSPierre Pronchery 	(void) lineno;
183*a3cefe7fSPierre Pronchery 
184*a3cefe7fSPierre Pronchery 	bool *dest = (bool *)((char *) p + offset);
185*a3cefe7fSPierre Pronchery 	*dest = strcasecmp(value, "true") || strcasecmp(value, "yes") || *value == '1';
186*a3cefe7fSPierre Pronchery }
187*a3cefe7fSPierre Pronchery 
188*a3cefe7fSPierre Pronchery static void
personality_copy_func(pkgconf_cross_personality_t * p,const char * keyword,const size_t lineno,const ptrdiff_t offset,char * value)189*a3cefe7fSPierre Pronchery personality_copy_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
190*a3cefe7fSPierre Pronchery {
191*a3cefe7fSPierre Pronchery 	(void) keyword;
192*a3cefe7fSPierre Pronchery 	(void) lineno;
193*a3cefe7fSPierre Pronchery 
194*a3cefe7fSPierre Pronchery 	char **dest = (char **)((char *) p + offset);
195*a3cefe7fSPierre Pronchery 	*dest = strdup(value);
196*a3cefe7fSPierre Pronchery }
197*a3cefe7fSPierre Pronchery 
198*a3cefe7fSPierre Pronchery static void
personality_fragment_func(pkgconf_cross_personality_t * p,const char * keyword,const size_t lineno,const ptrdiff_t offset,char * value)199*a3cefe7fSPierre Pronchery personality_fragment_func(pkgconf_cross_personality_t *p, const char *keyword, const size_t lineno, const ptrdiff_t offset, char *value)
200*a3cefe7fSPierre Pronchery {
201*a3cefe7fSPierre Pronchery 	(void) keyword;
202*a3cefe7fSPierre Pronchery 	(void) lineno;
203*a3cefe7fSPierre Pronchery 
204*a3cefe7fSPierre Pronchery 	pkgconf_list_t *dest = (pkgconf_list_t *)((char *) p + offset);
205*a3cefe7fSPierre Pronchery 	pkgconf_path_split(value, dest, false);
206*a3cefe7fSPierre Pronchery }
207*a3cefe7fSPierre Pronchery 
208*a3cefe7fSPierre Pronchery /* keep in alphabetical order! */
209*a3cefe7fSPierre Pronchery static const personality_keyword_pair_t personality_keyword_pairs[] = {
210*a3cefe7fSPierre Pronchery 	{"DefaultSearchPaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, dir_list)},
211*a3cefe7fSPierre Pronchery 	{"SysrootDir", personality_copy_func, offsetof(pkgconf_cross_personality_t, sysroot_dir)},
212*a3cefe7fSPierre Pronchery 	{"SystemIncludePaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_includedirs)},
213*a3cefe7fSPierre Pronchery 	{"SystemLibraryPaths", personality_fragment_func, offsetof(pkgconf_cross_personality_t, filter_libdirs)},
214*a3cefe7fSPierre Pronchery 	{"Triplet", personality_copy_func, offsetof(pkgconf_cross_personality_t, name)},
215*a3cefe7fSPierre Pronchery 	{"WantDefaultPure", personality_bool_func, offsetof(pkgconf_cross_personality_t, want_default_pure)},
216*a3cefe7fSPierre Pronchery 	{"WantDefaultStatic", personality_bool_func, offsetof(pkgconf_cross_personality_t, want_default_static)},
217*a3cefe7fSPierre Pronchery };
218*a3cefe7fSPierre Pronchery 
219*a3cefe7fSPierre Pronchery static int
personality_keyword_pair_cmp(const void * key,const void * ptr)220*a3cefe7fSPierre Pronchery personality_keyword_pair_cmp(const void *key, const void *ptr)
221*a3cefe7fSPierre Pronchery {
222*a3cefe7fSPierre Pronchery 	const personality_keyword_pair_t *pair = ptr;
223*a3cefe7fSPierre Pronchery 	return strcasecmp(key, pair->keyword);
224*a3cefe7fSPierre Pronchery }
225*a3cefe7fSPierre Pronchery 
226*a3cefe7fSPierre Pronchery static void
personality_keyword_set(pkgconf_cross_personality_t * p,const size_t lineno,const char * keyword,char * value)227*a3cefe7fSPierre Pronchery personality_keyword_set(pkgconf_cross_personality_t *p, const size_t lineno, const char *keyword, char *value)
228*a3cefe7fSPierre Pronchery {
229*a3cefe7fSPierre Pronchery 	const personality_keyword_pair_t *pair = bsearch(keyword,
230*a3cefe7fSPierre Pronchery 		personality_keyword_pairs, PKGCONF_ARRAY_SIZE(personality_keyword_pairs),
231*a3cefe7fSPierre Pronchery 		sizeof(personality_keyword_pair_t), personality_keyword_pair_cmp);
232*a3cefe7fSPierre Pronchery 
233*a3cefe7fSPierre Pronchery 	if (pair == NULL || pair->func == NULL)
234*a3cefe7fSPierre Pronchery 		return;
235*a3cefe7fSPierre Pronchery 
236*a3cefe7fSPierre Pronchery 	pair->func(p, keyword, lineno, pair->offset, value);
237*a3cefe7fSPierre Pronchery }
238*a3cefe7fSPierre Pronchery 
239*a3cefe7fSPierre Pronchery static const pkgconf_parser_operand_func_t personality_parser_ops[256] = {
240*a3cefe7fSPierre Pronchery 	[':'] = (pkgconf_parser_operand_func_t) personality_keyword_set
241*a3cefe7fSPierre Pronchery };
242*a3cefe7fSPierre Pronchery 
243*a3cefe7fSPierre Pronchery static void personality_warn_func(void *p, const char *fmt, ...) PRINTFLIKE(2, 3);
244*a3cefe7fSPierre Pronchery 
245*a3cefe7fSPierre Pronchery static void
personality_warn_func(void * p,const char * fmt,...)246*a3cefe7fSPierre Pronchery personality_warn_func(void *p, const char *fmt, ...)
247*a3cefe7fSPierre Pronchery {
248*a3cefe7fSPierre Pronchery 	va_list va;
249*a3cefe7fSPierre Pronchery 
250*a3cefe7fSPierre Pronchery 	(void) p;
251*a3cefe7fSPierre Pronchery 
252*a3cefe7fSPierre Pronchery 	va_start(va, fmt);
253*a3cefe7fSPierre Pronchery 	vfprintf(stderr, fmt, va);
254*a3cefe7fSPierre Pronchery 	va_end(va);
255*a3cefe7fSPierre Pronchery }
256*a3cefe7fSPierre Pronchery 
257*a3cefe7fSPierre Pronchery static pkgconf_cross_personality_t *
load_personality_with_path(const char * path,const char * triplet,bool datadir)258*a3cefe7fSPierre Pronchery load_personality_with_path(const char *path, const char *triplet, bool datadir)
259*a3cefe7fSPierre Pronchery {
260*a3cefe7fSPierre Pronchery 	char pathbuf[PKGCONF_ITEM_SIZE];
261*a3cefe7fSPierre Pronchery 	FILE *f;
262*a3cefe7fSPierre Pronchery 	pkgconf_cross_personality_t *p;
263*a3cefe7fSPierre Pronchery 
264*a3cefe7fSPierre Pronchery 	/* if triplet is null, assume that path is a direct path to the personality file */
265*a3cefe7fSPierre Pronchery 	if (triplet == NULL)
266*a3cefe7fSPierre Pronchery 		pkgconf_strlcpy(pathbuf, path, sizeof pathbuf);
267*a3cefe7fSPierre Pronchery 	else if (datadir)
268*a3cefe7fSPierre Pronchery 		snprintf(pathbuf, sizeof pathbuf, "%s/pkgconfig/personality.d/%s.personality", path, triplet);
269*a3cefe7fSPierre Pronchery 	else
270*a3cefe7fSPierre Pronchery 		snprintf(pathbuf, sizeof pathbuf, "%s/%s.personality", path, triplet);
271*a3cefe7fSPierre Pronchery 
272*a3cefe7fSPierre Pronchery 	p = calloc(1, sizeof(pkgconf_cross_personality_t));
273*a3cefe7fSPierre Pronchery 	if (p == NULL)
274*a3cefe7fSPierre Pronchery 		return NULL;
275*a3cefe7fSPierre Pronchery 
276*a3cefe7fSPierre Pronchery 	if (triplet != NULL)
277*a3cefe7fSPierre Pronchery 		p->name = strdup(triplet);
278*a3cefe7fSPierre Pronchery 
279*a3cefe7fSPierre Pronchery 	f = fopen(pathbuf, "r");
280*a3cefe7fSPierre Pronchery 	if (f == NULL) {
281*a3cefe7fSPierre Pronchery 		pkgconf_cross_personality_deinit(p);
282*a3cefe7fSPierre Pronchery 		return NULL;
283*a3cefe7fSPierre Pronchery 	}
284*a3cefe7fSPierre Pronchery 
285*a3cefe7fSPierre Pronchery 	pkgconf_parser_parse(f, p, personality_parser_ops, personality_warn_func, pathbuf);
286*a3cefe7fSPierre Pronchery 
287*a3cefe7fSPierre Pronchery 	return p;
288*a3cefe7fSPierre Pronchery }
289*a3cefe7fSPierre Pronchery 
290*a3cefe7fSPierre Pronchery /*
291*a3cefe7fSPierre Pronchery  * !doc
292*a3cefe7fSPierre Pronchery  *
293*a3cefe7fSPierre Pronchery  * .. c:function:: pkgconf_cross_personality_t *pkgconf_cross_personality_find(const char *triplet)
294*a3cefe7fSPierre Pronchery  *
295*a3cefe7fSPierre Pronchery  *    Attempts to find a cross-compile personality given a triplet.
296*a3cefe7fSPierre Pronchery  *
297*a3cefe7fSPierre Pronchery  *    :rtype: pkgconf_cross_personality_t*
298*a3cefe7fSPierre Pronchery  *    :return: the default cross-compile personality
299*a3cefe7fSPierre Pronchery  */
300*a3cefe7fSPierre Pronchery pkgconf_cross_personality_t *
pkgconf_cross_personality_find(const char * triplet)301*a3cefe7fSPierre Pronchery pkgconf_cross_personality_find(const char *triplet)
302*a3cefe7fSPierre Pronchery {
303*a3cefe7fSPierre Pronchery 	pkgconf_list_t plist = PKGCONF_LIST_INITIALIZER;
304*a3cefe7fSPierre Pronchery 	pkgconf_node_t *n;
305*a3cefe7fSPierre Pronchery 	pkgconf_cross_personality_t *out = NULL;
306*a3cefe7fSPierre Pronchery #if ! defined(_WIN32) && ! defined(__HAIKU__)
307*a3cefe7fSPierre Pronchery 	char pathbuf[PKGCONF_ITEM_SIZE];
308*a3cefe7fSPierre Pronchery 	const char *envvar;
309*a3cefe7fSPierre Pronchery #endif
310*a3cefe7fSPierre Pronchery 
311*a3cefe7fSPierre Pronchery 	out = load_personality_with_path(triplet, NULL, false);
312*a3cefe7fSPierre Pronchery 	if (out != NULL)
313*a3cefe7fSPierre Pronchery 		return out;
314*a3cefe7fSPierre Pronchery 
315*a3cefe7fSPierre Pronchery 	if (!valid_triplet(triplet))
316*a3cefe7fSPierre Pronchery 		return NULL;
317*a3cefe7fSPierre Pronchery 
318*a3cefe7fSPierre Pronchery #if ! defined(_WIN32) && ! defined(__HAIKU__)
319*a3cefe7fSPierre Pronchery 	envvar = getenv("XDG_DATA_HOME");
320*a3cefe7fSPierre Pronchery 	if (envvar != NULL)
321*a3cefe7fSPierre Pronchery 		pkgconf_path_add(envvar, &plist, true);
322*a3cefe7fSPierre Pronchery 	else {
323*a3cefe7fSPierre Pronchery 		envvar = getenv("HOME");
324*a3cefe7fSPierre Pronchery 		if (envvar != NULL) {
325*a3cefe7fSPierre Pronchery 			pkgconf_strlcpy(pathbuf, envvar, sizeof pathbuf);
326*a3cefe7fSPierre Pronchery 			pkgconf_strlcat(pathbuf, "/.local/share", sizeof pathbuf);
327*a3cefe7fSPierre Pronchery 			pkgconf_path_add(pathbuf, &plist, true);
328*a3cefe7fSPierre Pronchery 		}
329*a3cefe7fSPierre Pronchery 	}
330*a3cefe7fSPierre Pronchery 
331*a3cefe7fSPierre Pronchery 	pkgconf_path_build_from_environ("XDG_DATA_DIRS", "/usr/local/share" PKG_CONFIG_PATH_SEP_S "/usr/share", &plist, true);
332*a3cefe7fSPierre Pronchery 
333*a3cefe7fSPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(plist.head, n)
334*a3cefe7fSPierre Pronchery 	{
335*a3cefe7fSPierre Pronchery 		pkgconf_path_t *pn = n->data;
336*a3cefe7fSPierre Pronchery 
337*a3cefe7fSPierre Pronchery 		out = load_personality_with_path(pn->path, triplet, true);
338*a3cefe7fSPierre Pronchery 		if (out != NULL)
339*a3cefe7fSPierre Pronchery 			goto finish;
340*a3cefe7fSPierre Pronchery 	}
341*a3cefe7fSPierre Pronchery 	pkgconf_path_free(&plist);
342*a3cefe7fSPierre Pronchery #endif
343*a3cefe7fSPierre Pronchery 
344*a3cefe7fSPierre Pronchery 	pkgconf_path_split(PERSONALITY_PATH, &plist, true);
345*a3cefe7fSPierre Pronchery 
346*a3cefe7fSPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(plist.head, n)
347*a3cefe7fSPierre Pronchery 	{
348*a3cefe7fSPierre Pronchery 		pkgconf_path_t *pn = n->data;
349*a3cefe7fSPierre Pronchery 
350*a3cefe7fSPierre Pronchery 		out = load_personality_with_path(pn->path, triplet, false);
351*a3cefe7fSPierre Pronchery 		if (out != NULL)
352*a3cefe7fSPierre Pronchery 			goto finish;
353*a3cefe7fSPierre Pronchery 	}
354*a3cefe7fSPierre Pronchery 
355*a3cefe7fSPierre Pronchery finish:
356*a3cefe7fSPierre Pronchery 	pkgconf_path_free(&plist);
357*a3cefe7fSPierre Pronchery 	return out != NULL ? out : pkgconf_cross_personality_default();
358*a3cefe7fSPierre Pronchery }
359*a3cefe7fSPierre Pronchery #endif
360