1*a3cefe7fSPierre Pronchery /*
2*a3cefe7fSPierre Pronchery * path.c
3*a3cefe7fSPierre Pronchery * filesystem path management
4*a3cefe7fSPierre Pronchery *
5*a3cefe7fSPierre Pronchery * Copyright (c) 2016 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 #if defined(HAVE_SYS_STAT_H) && ! defined(_WIN32)
21*a3cefe7fSPierre Pronchery # include <sys/stat.h>
22*a3cefe7fSPierre Pronchery # define PKGCONF_CACHE_INODES
23*a3cefe7fSPierre Pronchery #endif
24*a3cefe7fSPierre Pronchery
25*a3cefe7fSPierre Pronchery #ifdef _WIN32
26*a3cefe7fSPierre Pronchery # define PKG_CONFIG_REG_KEY "Software\\pkgconfig\\PKG_CONFIG_PATH"
27*a3cefe7fSPierre Pronchery #endif
28*a3cefe7fSPierre Pronchery
29*a3cefe7fSPierre Pronchery static bool
30*a3cefe7fSPierre Pronchery #ifdef PKGCONF_CACHE_INODES
path_list_contains_entry(const char * text,pkgconf_list_t * dirlist,struct stat * st)31*a3cefe7fSPierre Pronchery path_list_contains_entry(const char *text, pkgconf_list_t *dirlist, struct stat *st)
32*a3cefe7fSPierre Pronchery #else
33*a3cefe7fSPierre Pronchery path_list_contains_entry(const char *text, pkgconf_list_t *dirlist)
34*a3cefe7fSPierre Pronchery #endif
35*a3cefe7fSPierre Pronchery {
36*a3cefe7fSPierre Pronchery pkgconf_node_t *n;
37*a3cefe7fSPierre Pronchery
38*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(dirlist->head, n)
39*a3cefe7fSPierre Pronchery {
40*a3cefe7fSPierre Pronchery pkgconf_path_t *pn = n->data;
41*a3cefe7fSPierre Pronchery
42*a3cefe7fSPierre Pronchery #ifdef PKGCONF_CACHE_INODES
43*a3cefe7fSPierre Pronchery if (pn->handle_device == (void *)(intptr_t)st->st_dev && pn->handle_path == (void *)(intptr_t)st->st_ino)
44*a3cefe7fSPierre Pronchery return true;
45*a3cefe7fSPierre Pronchery #endif
46*a3cefe7fSPierre Pronchery
47*a3cefe7fSPierre Pronchery if (!strcmp(text, pn->path))
48*a3cefe7fSPierre Pronchery return true;
49*a3cefe7fSPierre Pronchery }
50*a3cefe7fSPierre Pronchery
51*a3cefe7fSPierre Pronchery return false;
52*a3cefe7fSPierre Pronchery }
53*a3cefe7fSPierre Pronchery
54*a3cefe7fSPierre Pronchery /*
55*a3cefe7fSPierre Pronchery * !doc
56*a3cefe7fSPierre Pronchery *
57*a3cefe7fSPierre Pronchery * libpkgconf `path` module
58*a3cefe7fSPierre Pronchery * ========================
59*a3cefe7fSPierre Pronchery *
60*a3cefe7fSPierre Pronchery * The `path` module provides functions for manipulating lists of paths in a cross-platform manner. Notably,
61*a3cefe7fSPierre Pronchery * it is used by the `pkgconf client` to parse the ``PKG_CONFIG_PATH``, ``PKG_CONFIG_LIBDIR`` and related environment
62*a3cefe7fSPierre Pronchery * variables.
63*a3cefe7fSPierre Pronchery */
64*a3cefe7fSPierre Pronchery
65*a3cefe7fSPierre Pronchery static pkgconf_path_t *
prepare_path_node(const char * text,pkgconf_list_t * dirlist,bool filter)66*a3cefe7fSPierre Pronchery prepare_path_node(const char *text, pkgconf_list_t *dirlist, bool filter)
67*a3cefe7fSPierre Pronchery {
68*a3cefe7fSPierre Pronchery pkgconf_path_t *node;
69*a3cefe7fSPierre Pronchery char path[PKGCONF_ITEM_SIZE];
70*a3cefe7fSPierre Pronchery
71*a3cefe7fSPierre Pronchery pkgconf_strlcpy(path, text, sizeof path);
72*a3cefe7fSPierre Pronchery pkgconf_path_relocate(path, sizeof path);
73*a3cefe7fSPierre Pronchery
74*a3cefe7fSPierre Pronchery #ifdef PKGCONF_CACHE_INODES
75*a3cefe7fSPierre Pronchery struct stat st;
76*a3cefe7fSPierre Pronchery
77*a3cefe7fSPierre Pronchery if (filter)
78*a3cefe7fSPierre Pronchery {
79*a3cefe7fSPierre Pronchery if (lstat(path, &st) == -1)
80*a3cefe7fSPierre Pronchery return NULL;
81*a3cefe7fSPierre Pronchery if (S_ISLNK(st.st_mode))
82*a3cefe7fSPierre Pronchery {
83*a3cefe7fSPierre Pronchery char pathbuf[PKGCONF_ITEM_SIZE * 4];
84*a3cefe7fSPierre Pronchery char *linkdest = realpath(path, pathbuf);
85*a3cefe7fSPierre Pronchery
86*a3cefe7fSPierre Pronchery if (linkdest != NULL && stat(linkdest, &st) == -1)
87*a3cefe7fSPierre Pronchery return NULL;
88*a3cefe7fSPierre Pronchery }
89*a3cefe7fSPierre Pronchery if (path_list_contains_entry(path, dirlist, &st))
90*a3cefe7fSPierre Pronchery return NULL;
91*a3cefe7fSPierre Pronchery }
92*a3cefe7fSPierre Pronchery #else
93*a3cefe7fSPierre Pronchery if (filter && path_list_contains_entry(path, dirlist))
94*a3cefe7fSPierre Pronchery return NULL;
95*a3cefe7fSPierre Pronchery #endif
96*a3cefe7fSPierre Pronchery
97*a3cefe7fSPierre Pronchery node = calloc(1, sizeof(pkgconf_path_t));
98*a3cefe7fSPierre Pronchery if (node == NULL)
99*a3cefe7fSPierre Pronchery return NULL;
100*a3cefe7fSPierre Pronchery
101*a3cefe7fSPierre Pronchery node->path = strdup(path);
102*a3cefe7fSPierre Pronchery
103*a3cefe7fSPierre Pronchery #ifdef PKGCONF_CACHE_INODES
104*a3cefe7fSPierre Pronchery if (filter) {
105*a3cefe7fSPierre Pronchery node->handle_path = (void *)(intptr_t) st.st_ino;
106*a3cefe7fSPierre Pronchery node->handle_device = (void *)(intptr_t) st.st_dev;
107*a3cefe7fSPierre Pronchery }
108*a3cefe7fSPierre Pronchery #endif
109*a3cefe7fSPierre Pronchery
110*a3cefe7fSPierre Pronchery return node;
111*a3cefe7fSPierre Pronchery }
112*a3cefe7fSPierre Pronchery
113*a3cefe7fSPierre Pronchery /*
114*a3cefe7fSPierre Pronchery * !doc
115*a3cefe7fSPierre Pronchery *
116*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_path_add(const char *text, pkgconf_list_t *dirlist)
117*a3cefe7fSPierre Pronchery *
118*a3cefe7fSPierre Pronchery * Adds a path node to a path list. If the path is already in the list, do nothing.
119*a3cefe7fSPierre Pronchery *
120*a3cefe7fSPierre Pronchery * :param char* text: The path text to add as a path node.
121*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dirlist: The path list to add the path node to.
122*a3cefe7fSPierre Pronchery * :param bool filter: Whether to perform duplicate filtering.
123*a3cefe7fSPierre Pronchery * :return: nothing
124*a3cefe7fSPierre Pronchery */
125*a3cefe7fSPierre Pronchery void
pkgconf_path_add(const char * text,pkgconf_list_t * dirlist,bool filter)126*a3cefe7fSPierre Pronchery pkgconf_path_add(const char *text, pkgconf_list_t *dirlist, bool filter)
127*a3cefe7fSPierre Pronchery {
128*a3cefe7fSPierre Pronchery pkgconf_path_t *node = prepare_path_node(text, dirlist, filter);
129*a3cefe7fSPierre Pronchery if (node == NULL)
130*a3cefe7fSPierre Pronchery return;
131*a3cefe7fSPierre Pronchery
132*a3cefe7fSPierre Pronchery pkgconf_node_insert_tail(&node->lnode, node, dirlist);
133*a3cefe7fSPierre Pronchery }
134*a3cefe7fSPierre Pronchery
135*a3cefe7fSPierre Pronchery /*
136*a3cefe7fSPierre Pronchery * !doc
137*a3cefe7fSPierre Pronchery *
138*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_path_prepend(const char *text, pkgconf_list_t *dirlist)
139*a3cefe7fSPierre Pronchery *
140*a3cefe7fSPierre Pronchery * Prepends a path node to a path list. If the path is already in the list, do nothing.
141*a3cefe7fSPierre Pronchery *
142*a3cefe7fSPierre Pronchery * :param char* text: The path text to add as a path node.
143*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dirlist: The path list to add the path node to.
144*a3cefe7fSPierre Pronchery * :param bool filter: Whether to perform duplicate filtering.
145*a3cefe7fSPierre Pronchery * :return: nothing
146*a3cefe7fSPierre Pronchery */
147*a3cefe7fSPierre Pronchery void
pkgconf_path_prepend(const char * text,pkgconf_list_t * dirlist,bool filter)148*a3cefe7fSPierre Pronchery pkgconf_path_prepend(const char *text, pkgconf_list_t *dirlist, bool filter)
149*a3cefe7fSPierre Pronchery {
150*a3cefe7fSPierre Pronchery pkgconf_path_t *node = prepare_path_node(text, dirlist, filter);
151*a3cefe7fSPierre Pronchery if (node == NULL)
152*a3cefe7fSPierre Pronchery return;
153*a3cefe7fSPierre Pronchery
154*a3cefe7fSPierre Pronchery pkgconf_node_insert(&node->lnode, node, dirlist);
155*a3cefe7fSPierre Pronchery }
156*a3cefe7fSPierre Pronchery
157*a3cefe7fSPierre Pronchery /*
158*a3cefe7fSPierre Pronchery * !doc
159*a3cefe7fSPierre Pronchery *
160*a3cefe7fSPierre Pronchery * .. c:function:: size_t pkgconf_path_split(const char *text, pkgconf_list_t *dirlist)
161*a3cefe7fSPierre Pronchery *
162*a3cefe7fSPierre Pronchery * Splits a given text input and inserts paths into a path list.
163*a3cefe7fSPierre Pronchery *
164*a3cefe7fSPierre Pronchery * :param char* text: The path text to split and add as path nodes.
165*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dirlist: The path list to have the path nodes added to.
166*a3cefe7fSPierre Pronchery * :param bool filter: Whether to perform duplicate filtering.
167*a3cefe7fSPierre Pronchery * :return: number of path nodes added to the path list
168*a3cefe7fSPierre Pronchery * :rtype: size_t
169*a3cefe7fSPierre Pronchery */
170*a3cefe7fSPierre Pronchery size_t
pkgconf_path_split(const char * text,pkgconf_list_t * dirlist,bool filter)171*a3cefe7fSPierre Pronchery pkgconf_path_split(const char *text, pkgconf_list_t *dirlist, bool filter)
172*a3cefe7fSPierre Pronchery {
173*a3cefe7fSPierre Pronchery size_t count = 0;
174*a3cefe7fSPierre Pronchery char *workbuf, *p, *iter;
175*a3cefe7fSPierre Pronchery
176*a3cefe7fSPierre Pronchery if (text == NULL)
177*a3cefe7fSPierre Pronchery return 0;
178*a3cefe7fSPierre Pronchery
179*a3cefe7fSPierre Pronchery iter = workbuf = strdup(text);
180*a3cefe7fSPierre Pronchery while ((p = strtok(iter, PKG_CONFIG_PATH_SEP_S)) != NULL)
181*a3cefe7fSPierre Pronchery {
182*a3cefe7fSPierre Pronchery pkgconf_path_add(p, dirlist, filter);
183*a3cefe7fSPierre Pronchery
184*a3cefe7fSPierre Pronchery count++, iter = NULL;
185*a3cefe7fSPierre Pronchery }
186*a3cefe7fSPierre Pronchery free(workbuf);
187*a3cefe7fSPierre Pronchery
188*a3cefe7fSPierre Pronchery return count;
189*a3cefe7fSPierre Pronchery }
190*a3cefe7fSPierre Pronchery
191*a3cefe7fSPierre Pronchery /*
192*a3cefe7fSPierre Pronchery * !doc
193*a3cefe7fSPierre Pronchery *
194*a3cefe7fSPierre Pronchery * .. c:function:: size_t pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist)
195*a3cefe7fSPierre Pronchery *
196*a3cefe7fSPierre Pronchery * Adds the paths specified in an environment variable to a path list. If the environment variable is not set,
197*a3cefe7fSPierre Pronchery * an optional default set of paths is added.
198*a3cefe7fSPierre Pronchery *
199*a3cefe7fSPierre Pronchery * :param char* envvarname: The environment variable to look up.
200*a3cefe7fSPierre Pronchery * :param char* fallback: The fallback paths to use if the environment variable is not set.
201*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dirlist: The path list to add the path nodes to.
202*a3cefe7fSPierre Pronchery * :param bool filter: Whether to perform duplicate filtering.
203*a3cefe7fSPierre Pronchery * :return: number of path nodes added to the path list
204*a3cefe7fSPierre Pronchery * :rtype: size_t
205*a3cefe7fSPierre Pronchery */
206*a3cefe7fSPierre Pronchery size_t
pkgconf_path_build_from_environ(const char * envvarname,const char * fallback,pkgconf_list_t * dirlist,bool filter)207*a3cefe7fSPierre Pronchery pkgconf_path_build_from_environ(const char *envvarname, const char *fallback, pkgconf_list_t *dirlist, bool filter)
208*a3cefe7fSPierre Pronchery {
209*a3cefe7fSPierre Pronchery const char *data;
210*a3cefe7fSPierre Pronchery
211*a3cefe7fSPierre Pronchery data = getenv(envvarname);
212*a3cefe7fSPierre Pronchery if (data != NULL)
213*a3cefe7fSPierre Pronchery return pkgconf_path_split(data, dirlist, filter);
214*a3cefe7fSPierre Pronchery
215*a3cefe7fSPierre Pronchery if (fallback != NULL)
216*a3cefe7fSPierre Pronchery return pkgconf_path_split(fallback, dirlist, filter);
217*a3cefe7fSPierre Pronchery
218*a3cefe7fSPierre Pronchery /* no fallback and no environment variable, thusly no nodes added */
219*a3cefe7fSPierre Pronchery return 0;
220*a3cefe7fSPierre Pronchery }
221*a3cefe7fSPierre Pronchery
222*a3cefe7fSPierre Pronchery /*
223*a3cefe7fSPierre Pronchery * !doc
224*a3cefe7fSPierre Pronchery *
225*a3cefe7fSPierre Pronchery * .. c:function:: bool pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
226*a3cefe7fSPierre Pronchery *
227*a3cefe7fSPierre Pronchery * Checks whether a path has a matching prefix in a path list.
228*a3cefe7fSPierre Pronchery *
229*a3cefe7fSPierre Pronchery * :param char* path: The path to check against a path list.
230*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dirlist: The path list to check the path against.
231*a3cefe7fSPierre Pronchery * :return: true if the path list has a matching prefix, otherwise false
232*a3cefe7fSPierre Pronchery * :rtype: bool
233*a3cefe7fSPierre Pronchery */
234*a3cefe7fSPierre Pronchery bool
pkgconf_path_match_list(const char * path,const pkgconf_list_t * dirlist)235*a3cefe7fSPierre Pronchery pkgconf_path_match_list(const char *path, const pkgconf_list_t *dirlist)
236*a3cefe7fSPierre Pronchery {
237*a3cefe7fSPierre Pronchery pkgconf_node_t *n = NULL;
238*a3cefe7fSPierre Pronchery char relocated[PKGCONF_ITEM_SIZE];
239*a3cefe7fSPierre Pronchery const char *cpath = path;
240*a3cefe7fSPierre Pronchery
241*a3cefe7fSPierre Pronchery pkgconf_strlcpy(relocated, path, sizeof relocated);
242*a3cefe7fSPierre Pronchery if (pkgconf_path_relocate(relocated, sizeof relocated))
243*a3cefe7fSPierre Pronchery cpath = relocated;
244*a3cefe7fSPierre Pronchery
245*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(dirlist->head, n)
246*a3cefe7fSPierre Pronchery {
247*a3cefe7fSPierre Pronchery pkgconf_path_t *pnode = n->data;
248*a3cefe7fSPierre Pronchery
249*a3cefe7fSPierre Pronchery if (!strcmp(pnode->path, cpath))
250*a3cefe7fSPierre Pronchery return true;
251*a3cefe7fSPierre Pronchery }
252*a3cefe7fSPierre Pronchery
253*a3cefe7fSPierre Pronchery return false;
254*a3cefe7fSPierre Pronchery }
255*a3cefe7fSPierre Pronchery
256*a3cefe7fSPierre Pronchery /*
257*a3cefe7fSPierre Pronchery * !doc
258*a3cefe7fSPierre Pronchery *
259*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
260*a3cefe7fSPierre Pronchery *
261*a3cefe7fSPierre Pronchery * Copies a path list to another path list.
262*a3cefe7fSPierre Pronchery *
263*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dst: The path list to copy to.
264*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* src: The path list to copy from.
265*a3cefe7fSPierre Pronchery * :return: nothing
266*a3cefe7fSPierre Pronchery */
267*a3cefe7fSPierre Pronchery void
pkgconf_path_copy_list(pkgconf_list_t * dst,const pkgconf_list_t * src)268*a3cefe7fSPierre Pronchery pkgconf_path_copy_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
269*a3cefe7fSPierre Pronchery {
270*a3cefe7fSPierre Pronchery pkgconf_node_t *n;
271*a3cefe7fSPierre Pronchery
272*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(src->head, n)
273*a3cefe7fSPierre Pronchery {
274*a3cefe7fSPierre Pronchery pkgconf_path_t *srcpath = n->data, *path;
275*a3cefe7fSPierre Pronchery
276*a3cefe7fSPierre Pronchery path = calloc(1, sizeof(pkgconf_path_t));
277*a3cefe7fSPierre Pronchery if (path == NULL)
278*a3cefe7fSPierre Pronchery continue;
279*a3cefe7fSPierre Pronchery
280*a3cefe7fSPierre Pronchery path->path = strdup(srcpath->path);
281*a3cefe7fSPierre Pronchery
282*a3cefe7fSPierre Pronchery #ifdef PKGCONF_CACHE_INODES
283*a3cefe7fSPierre Pronchery path->handle_path = srcpath->handle_path;
284*a3cefe7fSPierre Pronchery path->handle_device = srcpath->handle_device;
285*a3cefe7fSPierre Pronchery #endif
286*a3cefe7fSPierre Pronchery
287*a3cefe7fSPierre Pronchery pkgconf_node_insert_tail(&path->lnode, path, dst);
288*a3cefe7fSPierre Pronchery }
289*a3cefe7fSPierre Pronchery }
290*a3cefe7fSPierre Pronchery
291*a3cefe7fSPierre Pronchery /*
292*a3cefe7fSPierre Pronchery * !doc
293*a3cefe7fSPierre Pronchery *
294*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
295*a3cefe7fSPierre Pronchery *
296*a3cefe7fSPierre Pronchery * Copies a path list to another path list.
297*a3cefe7fSPierre Pronchery *
298*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dst: The path list to copy to.
299*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* src: The path list to copy from.
300*a3cefe7fSPierre Pronchery * :return: nothing
301*a3cefe7fSPierre Pronchery */
302*a3cefe7fSPierre Pronchery void
pkgconf_path_prepend_list(pkgconf_list_t * dst,const pkgconf_list_t * src)303*a3cefe7fSPierre Pronchery pkgconf_path_prepend_list(pkgconf_list_t *dst, const pkgconf_list_t *src)
304*a3cefe7fSPierre Pronchery {
305*a3cefe7fSPierre Pronchery pkgconf_node_t *n;
306*a3cefe7fSPierre Pronchery
307*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(src->head, n)
308*a3cefe7fSPierre Pronchery {
309*a3cefe7fSPierre Pronchery pkgconf_path_t *srcpath = n->data, *path;
310*a3cefe7fSPierre Pronchery
311*a3cefe7fSPierre Pronchery path = calloc(1, sizeof(pkgconf_path_t));
312*a3cefe7fSPierre Pronchery if (path == NULL)
313*a3cefe7fSPierre Pronchery continue;
314*a3cefe7fSPierre Pronchery
315*a3cefe7fSPierre Pronchery path->path = strdup(srcpath->path);
316*a3cefe7fSPierre Pronchery
317*a3cefe7fSPierre Pronchery #ifdef PKGCONF_CACHE_INODES
318*a3cefe7fSPierre Pronchery path->handle_path = srcpath->handle_path;
319*a3cefe7fSPierre Pronchery path->handle_device = srcpath->handle_device;
320*a3cefe7fSPierre Pronchery #endif
321*a3cefe7fSPierre Pronchery
322*a3cefe7fSPierre Pronchery pkgconf_node_insert(&path->lnode, path, dst);
323*a3cefe7fSPierre Pronchery }
324*a3cefe7fSPierre Pronchery }
325*a3cefe7fSPierre Pronchery
326*a3cefe7fSPierre Pronchery /*
327*a3cefe7fSPierre Pronchery * !doc
328*a3cefe7fSPierre Pronchery *
329*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_path_free(pkgconf_list_t *dirlist)
330*a3cefe7fSPierre Pronchery *
331*a3cefe7fSPierre Pronchery * Releases any path nodes attached to the given path list.
332*a3cefe7fSPierre Pronchery *
333*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dirlist: The path list to clean up.
334*a3cefe7fSPierre Pronchery * :return: nothing
335*a3cefe7fSPierre Pronchery */
336*a3cefe7fSPierre Pronchery void
pkgconf_path_free(pkgconf_list_t * dirlist)337*a3cefe7fSPierre Pronchery pkgconf_path_free(pkgconf_list_t *dirlist)
338*a3cefe7fSPierre Pronchery {
339*a3cefe7fSPierre Pronchery pkgconf_node_t *n, *tn;
340*a3cefe7fSPierre Pronchery
341*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY_SAFE(dirlist->head, tn, n)
342*a3cefe7fSPierre Pronchery {
343*a3cefe7fSPierre Pronchery pkgconf_path_t *pnode = n->data;
344*a3cefe7fSPierre Pronchery
345*a3cefe7fSPierre Pronchery free(pnode->path);
346*a3cefe7fSPierre Pronchery free(pnode);
347*a3cefe7fSPierre Pronchery }
348*a3cefe7fSPierre Pronchery
349*a3cefe7fSPierre Pronchery pkgconf_list_zero(dirlist);
350*a3cefe7fSPierre Pronchery }
351*a3cefe7fSPierre Pronchery
352*a3cefe7fSPierre Pronchery static char *
normpath(const char * path)353*a3cefe7fSPierre Pronchery normpath(const char *path)
354*a3cefe7fSPierre Pronchery {
355*a3cefe7fSPierre Pronchery if (!path)
356*a3cefe7fSPierre Pronchery return NULL;
357*a3cefe7fSPierre Pronchery
358*a3cefe7fSPierre Pronchery char *copy = strdup(path);
359*a3cefe7fSPierre Pronchery if (NULL == copy)
360*a3cefe7fSPierre Pronchery return NULL;
361*a3cefe7fSPierre Pronchery char *ptr = copy;
362*a3cefe7fSPierre Pronchery
363*a3cefe7fSPierre Pronchery for (int ii = 0; copy[ii]; ii++)
364*a3cefe7fSPierre Pronchery {
365*a3cefe7fSPierre Pronchery *ptr++ = path[ii];
366*a3cefe7fSPierre Pronchery if ('/' == path[ii])
367*a3cefe7fSPierre Pronchery {
368*a3cefe7fSPierre Pronchery ii++;
369*a3cefe7fSPierre Pronchery while ('/' == path[ii])
370*a3cefe7fSPierre Pronchery ii++;
371*a3cefe7fSPierre Pronchery ii--;
372*a3cefe7fSPierre Pronchery }
373*a3cefe7fSPierre Pronchery }
374*a3cefe7fSPierre Pronchery *ptr = '\0';
375*a3cefe7fSPierre Pronchery
376*a3cefe7fSPierre Pronchery return copy;
377*a3cefe7fSPierre Pronchery }
378*a3cefe7fSPierre Pronchery
379*a3cefe7fSPierre Pronchery /*
380*a3cefe7fSPierre Pronchery * !doc
381*a3cefe7fSPierre Pronchery *
382*a3cefe7fSPierre Pronchery * .. c:function:: bool pkgconf_path_relocate(char *buf, size_t buflen)
383*a3cefe7fSPierre Pronchery *
384*a3cefe7fSPierre Pronchery * Relocates a path, possibly calling normpath() on it.
385*a3cefe7fSPierre Pronchery *
386*a3cefe7fSPierre Pronchery * :param char* buf: The path to relocate.
387*a3cefe7fSPierre Pronchery * :param size_t buflen: The buffer length the path is contained in.
388*a3cefe7fSPierre Pronchery * :return: true on success, false on error
389*a3cefe7fSPierre Pronchery * :rtype: bool
390*a3cefe7fSPierre Pronchery */
391*a3cefe7fSPierre Pronchery bool
pkgconf_path_relocate(char * buf,size_t buflen)392*a3cefe7fSPierre Pronchery pkgconf_path_relocate(char *buf, size_t buflen)
393*a3cefe7fSPierre Pronchery {
394*a3cefe7fSPierre Pronchery char *tmpbuf;
395*a3cefe7fSPierre Pronchery
396*a3cefe7fSPierre Pronchery if ((tmpbuf = normpath(buf)) != NULL)
397*a3cefe7fSPierre Pronchery {
398*a3cefe7fSPierre Pronchery size_t tmpbuflen = strlen(tmpbuf);
399*a3cefe7fSPierre Pronchery if (tmpbuflen > buflen)
400*a3cefe7fSPierre Pronchery {
401*a3cefe7fSPierre Pronchery free(tmpbuf);
402*a3cefe7fSPierre Pronchery return false;
403*a3cefe7fSPierre Pronchery }
404*a3cefe7fSPierre Pronchery
405*a3cefe7fSPierre Pronchery pkgconf_strlcpy(buf, tmpbuf, buflen);
406*a3cefe7fSPierre Pronchery free(tmpbuf);
407*a3cefe7fSPierre Pronchery }
408*a3cefe7fSPierre Pronchery
409*a3cefe7fSPierre Pronchery return true;
410*a3cefe7fSPierre Pronchery }
411*a3cefe7fSPierre Pronchery
412*a3cefe7fSPierre Pronchery #ifdef _WIN32
413*a3cefe7fSPierre Pronchery /*
414*a3cefe7fSPierre Pronchery * !doc
415*a3cefe7fSPierre Pronchery *
416*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_path_build_from_registry(HKEY hKey, pkgconf_list_t *dir_list, bool filter)
417*a3cefe7fSPierre Pronchery *
418*a3cefe7fSPierre Pronchery * Adds paths to a directory list discovered from a given registry key.
419*a3cefe7fSPierre Pronchery *
420*a3cefe7fSPierre Pronchery * :param HKEY hKey: The registry key to enumerate.
421*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dir_list: The directory list to append enumerated paths to.
422*a3cefe7fSPierre Pronchery * :param bool filter: Whether duplicate paths should be filtered.
423*a3cefe7fSPierre Pronchery * :return: number of path nodes added to the list
424*a3cefe7fSPierre Pronchery * :rtype: size_t
425*a3cefe7fSPierre Pronchery */
426*a3cefe7fSPierre Pronchery size_t
pkgconf_path_build_from_registry(void * hKey,pkgconf_list_t * dir_list,bool filter)427*a3cefe7fSPierre Pronchery pkgconf_path_build_from_registry(void *hKey, pkgconf_list_t *dir_list, bool filter)
428*a3cefe7fSPierre Pronchery {
429*a3cefe7fSPierre Pronchery HKEY key;
430*a3cefe7fSPierre Pronchery int i = 0;
431*a3cefe7fSPierre Pronchery size_t added = 0;
432*a3cefe7fSPierre Pronchery
433*a3cefe7fSPierre Pronchery char buf[16384]; /* per registry limits */
434*a3cefe7fSPierre Pronchery DWORD bufsize = sizeof buf;
435*a3cefe7fSPierre Pronchery if (RegOpenKeyEx(hKey, PKG_CONFIG_REG_KEY,
436*a3cefe7fSPierre Pronchery 0, KEY_READ, &key) != ERROR_SUCCESS)
437*a3cefe7fSPierre Pronchery return 0;
438*a3cefe7fSPierre Pronchery
439*a3cefe7fSPierre Pronchery while (RegEnumValue(key, i++, buf, &bufsize, NULL, NULL, NULL, NULL)
440*a3cefe7fSPierre Pronchery == ERROR_SUCCESS)
441*a3cefe7fSPierre Pronchery {
442*a3cefe7fSPierre Pronchery char pathbuf[PKGCONF_ITEM_SIZE];
443*a3cefe7fSPierre Pronchery DWORD type;
444*a3cefe7fSPierre Pronchery DWORD pathbuflen = sizeof pathbuf;
445*a3cefe7fSPierre Pronchery
446*a3cefe7fSPierre Pronchery if (RegQueryValueEx(key, buf, NULL, &type, (LPBYTE) pathbuf, &pathbuflen)
447*a3cefe7fSPierre Pronchery == ERROR_SUCCESS && type == REG_SZ)
448*a3cefe7fSPierre Pronchery {
449*a3cefe7fSPierre Pronchery pkgconf_path_add(pathbuf, dir_list, filter);
450*a3cefe7fSPierre Pronchery added++;
451*a3cefe7fSPierre Pronchery }
452*a3cefe7fSPierre Pronchery
453*a3cefe7fSPierre Pronchery bufsize = sizeof buf;
454*a3cefe7fSPierre Pronchery }
455*a3cefe7fSPierre Pronchery
456*a3cefe7fSPierre Pronchery RegCloseKey(key);
457*a3cefe7fSPierre Pronchery return added;
458*a3cefe7fSPierre Pronchery }
459*a3cefe7fSPierre Pronchery #endif
460