1*a3cefe7fSPierre Pronchery /*
2*a3cefe7fSPierre Pronchery * tuple.c
3*a3cefe7fSPierre Pronchery * management of key->value tuples
4*a3cefe7fSPierre Pronchery *
5*a3cefe7fSPierre Pronchery * Copyright (c) 2011, 2012 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/stdinc.h>
17*a3cefe7fSPierre Pronchery #include <libpkgconf/libpkgconf.h>
18*a3cefe7fSPierre Pronchery
19*a3cefe7fSPierre Pronchery /*
20*a3cefe7fSPierre Pronchery * !doc
21*a3cefe7fSPierre Pronchery *
22*a3cefe7fSPierre Pronchery * libpkgconf `tuple` module
23*a3cefe7fSPierre Pronchery * =========================
24*a3cefe7fSPierre Pronchery *
25*a3cefe7fSPierre Pronchery * The `tuple` module provides key-value mappings backed by a linked list. The key-value
26*a3cefe7fSPierre Pronchery * mapping is mainly used for variable substitution when parsing .pc files.
27*a3cefe7fSPierre Pronchery *
28*a3cefe7fSPierre Pronchery * There are two sets of mappings: a ``pkgconf_pkg_t`` specific mapping, and a `global` mapping.
29*a3cefe7fSPierre Pronchery * The `tuple` module provides convenience wrappers for managing the `global` mapping, which is
30*a3cefe7fSPierre Pronchery * attached to a given client object.
31*a3cefe7fSPierre Pronchery */
32*a3cefe7fSPierre Pronchery
33*a3cefe7fSPierre Pronchery /*
34*a3cefe7fSPierre Pronchery * !doc
35*a3cefe7fSPierre Pronchery *
36*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value)
37*a3cefe7fSPierre Pronchery *
38*a3cefe7fSPierre Pronchery * Defines a global variable, replacing the previous declaration if one was set.
39*a3cefe7fSPierre Pronchery *
40*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object to modify.
41*a3cefe7fSPierre Pronchery * :param char* key: The key for the mapping (variable name).
42*a3cefe7fSPierre Pronchery * :param char* value: The value for the mapped entry.
43*a3cefe7fSPierre Pronchery * :return: nothing
44*a3cefe7fSPierre Pronchery */
45*a3cefe7fSPierre Pronchery void
pkgconf_tuple_add_global(pkgconf_client_t * client,const char * key,const char * value)46*a3cefe7fSPierre Pronchery pkgconf_tuple_add_global(pkgconf_client_t *client, const char *key, const char *value)
47*a3cefe7fSPierre Pronchery {
48*a3cefe7fSPierre Pronchery pkgconf_tuple_add(client, &client->global_vars, key, value, false, 0);
49*a3cefe7fSPierre Pronchery }
50*a3cefe7fSPierre Pronchery
51*a3cefe7fSPierre Pronchery static pkgconf_tuple_t *
lookup_global_tuple(const pkgconf_client_t * client,const char * key)52*a3cefe7fSPierre Pronchery lookup_global_tuple(const pkgconf_client_t *client, const char *key)
53*a3cefe7fSPierre Pronchery {
54*a3cefe7fSPierre Pronchery pkgconf_node_t *node;
55*a3cefe7fSPierre Pronchery
56*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(client->global_vars.head, node)
57*a3cefe7fSPierre Pronchery {
58*a3cefe7fSPierre Pronchery pkgconf_tuple_t *tuple = node->data;
59*a3cefe7fSPierre Pronchery
60*a3cefe7fSPierre Pronchery if (!strcmp(tuple->key, key))
61*a3cefe7fSPierre Pronchery return tuple;
62*a3cefe7fSPierre Pronchery }
63*a3cefe7fSPierre Pronchery
64*a3cefe7fSPierre Pronchery return NULL;
65*a3cefe7fSPierre Pronchery }
66*a3cefe7fSPierre Pronchery
67*a3cefe7fSPierre Pronchery /*
68*a3cefe7fSPierre Pronchery * !doc
69*a3cefe7fSPierre Pronchery *
70*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key)
71*a3cefe7fSPierre Pronchery *
72*a3cefe7fSPierre Pronchery * Looks up a global variable.
73*a3cefe7fSPierre Pronchery *
74*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object to access.
75*a3cefe7fSPierre Pronchery * :param char* key: The key or variable name to look up.
76*a3cefe7fSPierre Pronchery * :return: the contents of the variable or ``NULL``
77*a3cefe7fSPierre Pronchery * :rtype: char *
78*a3cefe7fSPierre Pronchery */
79*a3cefe7fSPierre Pronchery char *
pkgconf_tuple_find_global(const pkgconf_client_t * client,const char * key)80*a3cefe7fSPierre Pronchery pkgconf_tuple_find_global(const pkgconf_client_t *client, const char *key)
81*a3cefe7fSPierre Pronchery {
82*a3cefe7fSPierre Pronchery pkgconf_tuple_t *tuple;
83*a3cefe7fSPierre Pronchery
84*a3cefe7fSPierre Pronchery tuple = lookup_global_tuple(client, key);
85*a3cefe7fSPierre Pronchery if (tuple == NULL)
86*a3cefe7fSPierre Pronchery return NULL;
87*a3cefe7fSPierre Pronchery
88*a3cefe7fSPierre Pronchery return tuple->value;
89*a3cefe7fSPierre Pronchery }
90*a3cefe7fSPierre Pronchery
91*a3cefe7fSPierre Pronchery /*
92*a3cefe7fSPierre Pronchery * !doc
93*a3cefe7fSPierre Pronchery *
94*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_tuple_free_global(pkgconf_client_t *client)
95*a3cefe7fSPierre Pronchery *
96*a3cefe7fSPierre Pronchery * Delete all global variables associated with a pkgconf client object.
97*a3cefe7fSPierre Pronchery *
98*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object to modify.
99*a3cefe7fSPierre Pronchery * :return: nothing
100*a3cefe7fSPierre Pronchery */
101*a3cefe7fSPierre Pronchery void
pkgconf_tuple_free_global(pkgconf_client_t * client)102*a3cefe7fSPierre Pronchery pkgconf_tuple_free_global(pkgconf_client_t *client)
103*a3cefe7fSPierre Pronchery {
104*a3cefe7fSPierre Pronchery pkgconf_tuple_free(&client->global_vars);
105*a3cefe7fSPierre Pronchery }
106*a3cefe7fSPierre Pronchery
107*a3cefe7fSPierre Pronchery /*
108*a3cefe7fSPierre Pronchery * !doc
109*a3cefe7fSPierre Pronchery *
110*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_tuple_define_global(pkgconf_client_t *client, const char *kv)
111*a3cefe7fSPierre Pronchery *
112*a3cefe7fSPierre Pronchery * Parse and define a global variable.
113*a3cefe7fSPierre Pronchery *
114*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object to modify.
115*a3cefe7fSPierre Pronchery * :param char* kv: The variable in the form of ``key=value``.
116*a3cefe7fSPierre Pronchery * :return: nothing
117*a3cefe7fSPierre Pronchery */
118*a3cefe7fSPierre Pronchery void
pkgconf_tuple_define_global(pkgconf_client_t * client,const char * kv)119*a3cefe7fSPierre Pronchery pkgconf_tuple_define_global(pkgconf_client_t *client, const char *kv)
120*a3cefe7fSPierre Pronchery {
121*a3cefe7fSPierre Pronchery char *workbuf = strdup(kv);
122*a3cefe7fSPierre Pronchery char *value;
123*a3cefe7fSPierre Pronchery pkgconf_tuple_t *tuple;
124*a3cefe7fSPierre Pronchery
125*a3cefe7fSPierre Pronchery value = strchr(workbuf, '=');
126*a3cefe7fSPierre Pronchery if (value == NULL)
127*a3cefe7fSPierre Pronchery goto out;
128*a3cefe7fSPierre Pronchery
129*a3cefe7fSPierre Pronchery *value++ = '\0';
130*a3cefe7fSPierre Pronchery
131*a3cefe7fSPierre Pronchery tuple = pkgconf_tuple_add(client, &client->global_vars, workbuf, value, false, 0);
132*a3cefe7fSPierre Pronchery if (tuple != NULL)
133*a3cefe7fSPierre Pronchery tuple->flags = PKGCONF_PKG_TUPLEF_OVERRIDE;
134*a3cefe7fSPierre Pronchery
135*a3cefe7fSPierre Pronchery out:
136*a3cefe7fSPierre Pronchery free(workbuf);
137*a3cefe7fSPierre Pronchery }
138*a3cefe7fSPierre Pronchery
139*a3cefe7fSPierre Pronchery static void
pkgconf_tuple_find_delete(pkgconf_list_t * list,const char * key)140*a3cefe7fSPierre Pronchery pkgconf_tuple_find_delete(pkgconf_list_t *list, const char *key)
141*a3cefe7fSPierre Pronchery {
142*a3cefe7fSPierre Pronchery pkgconf_node_t *node, *next;
143*a3cefe7fSPierre Pronchery
144*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
145*a3cefe7fSPierre Pronchery {
146*a3cefe7fSPierre Pronchery pkgconf_tuple_t *tuple = node->data;
147*a3cefe7fSPierre Pronchery
148*a3cefe7fSPierre Pronchery if (!strcmp(tuple->key, key))
149*a3cefe7fSPierre Pronchery {
150*a3cefe7fSPierre Pronchery pkgconf_tuple_free_entry(tuple, list);
151*a3cefe7fSPierre Pronchery return;
152*a3cefe7fSPierre Pronchery }
153*a3cefe7fSPierre Pronchery }
154*a3cefe7fSPierre Pronchery }
155*a3cefe7fSPierre Pronchery
156*a3cefe7fSPierre Pronchery static char *
dequote(const char * value)157*a3cefe7fSPierre Pronchery dequote(const char *value)
158*a3cefe7fSPierre Pronchery {
159*a3cefe7fSPierre Pronchery char *buf = calloc(1, (strlen(value) + 1) * 2);
160*a3cefe7fSPierre Pronchery char *bptr = buf;
161*a3cefe7fSPierre Pronchery const char *i;
162*a3cefe7fSPierre Pronchery char quote = 0;
163*a3cefe7fSPierre Pronchery
164*a3cefe7fSPierre Pronchery if (*value == '\'' || *value == '"')
165*a3cefe7fSPierre Pronchery quote = *value;
166*a3cefe7fSPierre Pronchery
167*a3cefe7fSPierre Pronchery for (i = value; *i != '\0'; i++)
168*a3cefe7fSPierre Pronchery {
169*a3cefe7fSPierre Pronchery if (*i == '\\' && quote && *(i + 1) == quote)
170*a3cefe7fSPierre Pronchery {
171*a3cefe7fSPierre Pronchery i++;
172*a3cefe7fSPierre Pronchery *bptr++ = *i;
173*a3cefe7fSPierre Pronchery }
174*a3cefe7fSPierre Pronchery else if (*i != quote)
175*a3cefe7fSPierre Pronchery *bptr++ = *i;
176*a3cefe7fSPierre Pronchery }
177*a3cefe7fSPierre Pronchery
178*a3cefe7fSPierre Pronchery return buf;
179*a3cefe7fSPierre Pronchery }
180*a3cefe7fSPierre Pronchery
181*a3cefe7fSPierre Pronchery static const char *
find_sysroot(const pkgconf_client_t * client,pkgconf_list_t * vars)182*a3cefe7fSPierre Pronchery find_sysroot(const pkgconf_client_t *client, pkgconf_list_t *vars)
183*a3cefe7fSPierre Pronchery {
184*a3cefe7fSPierre Pronchery const char *sysroot_dir;
185*a3cefe7fSPierre Pronchery
186*a3cefe7fSPierre Pronchery sysroot_dir = pkgconf_tuple_find(client, vars, "pc_sysrootdir");
187*a3cefe7fSPierre Pronchery if (sysroot_dir == NULL)
188*a3cefe7fSPierre Pronchery sysroot_dir = client->sysroot_dir;
189*a3cefe7fSPierre Pronchery
190*a3cefe7fSPierre Pronchery return sysroot_dir;
191*a3cefe7fSPierre Pronchery }
192*a3cefe7fSPierre Pronchery
193*a3cefe7fSPierre Pronchery static bool
should_rewrite_sysroot(const pkgconf_client_t * client,pkgconf_list_t * vars,const char * buf,unsigned int flags)194*a3cefe7fSPierre Pronchery should_rewrite_sysroot(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *buf, unsigned int flags)
195*a3cefe7fSPierre Pronchery {
196*a3cefe7fSPierre Pronchery const char *sysroot_dir;
197*a3cefe7fSPierre Pronchery
198*a3cefe7fSPierre Pronchery if (flags & PKGCONF_PKG_PROPF_UNINSTALLED && !(client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES))
199*a3cefe7fSPierre Pronchery return false;
200*a3cefe7fSPierre Pronchery
201*a3cefe7fSPierre Pronchery sysroot_dir = find_sysroot(client, vars);
202*a3cefe7fSPierre Pronchery if (sysroot_dir == NULL)
203*a3cefe7fSPierre Pronchery return false;
204*a3cefe7fSPierre Pronchery
205*a3cefe7fSPierre Pronchery if (*buf != '/')
206*a3cefe7fSPierre Pronchery return false;
207*a3cefe7fSPierre Pronchery
208*a3cefe7fSPierre Pronchery if (!strcmp(sysroot_dir, "/"))
209*a3cefe7fSPierre Pronchery return false;
210*a3cefe7fSPierre Pronchery
211*a3cefe7fSPierre Pronchery if (strlen(buf) <= strlen(sysroot_dir))
212*a3cefe7fSPierre Pronchery return false;
213*a3cefe7fSPierre Pronchery
214*a3cefe7fSPierre Pronchery if (strstr(buf + strlen(sysroot_dir), sysroot_dir) == NULL)
215*a3cefe7fSPierre Pronchery return false;
216*a3cefe7fSPierre Pronchery
217*a3cefe7fSPierre Pronchery return true;
218*a3cefe7fSPierre Pronchery }
219*a3cefe7fSPierre Pronchery
220*a3cefe7fSPierre Pronchery /*
221*a3cefe7fSPierre Pronchery * !doc
222*a3cefe7fSPierre Pronchery *
223*a3cefe7fSPierre Pronchery * .. c:function:: pkgconf_tuple_t *pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key, const char *value, bool parse)
224*a3cefe7fSPierre Pronchery *
225*a3cefe7fSPierre Pronchery * Optionally parse and then define a variable.
226*a3cefe7fSPierre Pronchery *
227*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object to access.
228*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The variable list to add the new variable to.
229*a3cefe7fSPierre Pronchery * :param char* key: The name of the variable being added.
230*a3cefe7fSPierre Pronchery * :param char* value: The value of the variable being added.
231*a3cefe7fSPierre Pronchery * :param bool parse: Whether or not to parse the value for variable substitution.
232*a3cefe7fSPierre Pronchery * :return: a variable object
233*a3cefe7fSPierre Pronchery * :rtype: pkgconf_tuple_t *
234*a3cefe7fSPierre Pronchery */
235*a3cefe7fSPierre Pronchery pkgconf_tuple_t *
pkgconf_tuple_add(const pkgconf_client_t * client,pkgconf_list_t * list,const char * key,const char * value,bool parse,unsigned int flags)236*a3cefe7fSPierre Pronchery pkgconf_tuple_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key, const char *value, bool parse, unsigned int flags)
237*a3cefe7fSPierre Pronchery {
238*a3cefe7fSPierre Pronchery char *dequote_value;
239*a3cefe7fSPierre Pronchery pkgconf_tuple_t *tuple = calloc(1, sizeof(pkgconf_tuple_t));
240*a3cefe7fSPierre Pronchery
241*a3cefe7fSPierre Pronchery pkgconf_tuple_find_delete(list, key);
242*a3cefe7fSPierre Pronchery
243*a3cefe7fSPierre Pronchery dequote_value = dequote(value);
244*a3cefe7fSPierre Pronchery
245*a3cefe7fSPierre Pronchery tuple->key = strdup(key);
246*a3cefe7fSPierre Pronchery if (parse)
247*a3cefe7fSPierre Pronchery tuple->value = pkgconf_tuple_parse(client, list, dequote_value, flags);
248*a3cefe7fSPierre Pronchery else
249*a3cefe7fSPierre Pronchery tuple->value = strdup(dequote_value);
250*a3cefe7fSPierre Pronchery
251*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "adding tuple to @%p: %s => %s (parsed? %d)", list, key, tuple->value, parse);
252*a3cefe7fSPierre Pronchery
253*a3cefe7fSPierre Pronchery pkgconf_node_insert(&tuple->iter, tuple, list);
254*a3cefe7fSPierre Pronchery
255*a3cefe7fSPierre Pronchery free(dequote_value);
256*a3cefe7fSPierre Pronchery
257*a3cefe7fSPierre Pronchery return tuple;
258*a3cefe7fSPierre Pronchery }
259*a3cefe7fSPierre Pronchery
260*a3cefe7fSPierre Pronchery /*
261*a3cefe7fSPierre Pronchery * !doc
262*a3cefe7fSPierre Pronchery *
263*a3cefe7fSPierre Pronchery * .. c:function:: char *pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key)
264*a3cefe7fSPierre Pronchery *
265*a3cefe7fSPierre Pronchery * Look up a variable in a variable list.
266*a3cefe7fSPierre Pronchery *
267*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object to access.
268*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The variable list to search.
269*a3cefe7fSPierre Pronchery * :param char* key: The variable name to search for.
270*a3cefe7fSPierre Pronchery * :return: the value of the variable or ``NULL``
271*a3cefe7fSPierre Pronchery * :rtype: char *
272*a3cefe7fSPierre Pronchery */
273*a3cefe7fSPierre Pronchery char *
pkgconf_tuple_find(const pkgconf_client_t * client,pkgconf_list_t * list,const char * key)274*a3cefe7fSPierre Pronchery pkgconf_tuple_find(const pkgconf_client_t *client, pkgconf_list_t *list, const char *key)
275*a3cefe7fSPierre Pronchery {
276*a3cefe7fSPierre Pronchery pkgconf_node_t *node;
277*a3cefe7fSPierre Pronchery pkgconf_tuple_t *global_tuple;
278*a3cefe7fSPierre Pronchery
279*a3cefe7fSPierre Pronchery global_tuple = lookup_global_tuple(client, key);
280*a3cefe7fSPierre Pronchery if (global_tuple != NULL && global_tuple->flags & PKGCONF_PKG_TUPLEF_OVERRIDE)
281*a3cefe7fSPierre Pronchery return global_tuple->value;
282*a3cefe7fSPierre Pronchery
283*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
284*a3cefe7fSPierre Pronchery {
285*a3cefe7fSPierre Pronchery pkgconf_tuple_t *tuple = node->data;
286*a3cefe7fSPierre Pronchery
287*a3cefe7fSPierre Pronchery if (!strcmp(tuple->key, key))
288*a3cefe7fSPierre Pronchery return tuple->value;
289*a3cefe7fSPierre Pronchery }
290*a3cefe7fSPierre Pronchery
291*a3cefe7fSPierre Pronchery if (global_tuple != NULL)
292*a3cefe7fSPierre Pronchery return global_tuple->value;
293*a3cefe7fSPierre Pronchery
294*a3cefe7fSPierre Pronchery return NULL;
295*a3cefe7fSPierre Pronchery }
296*a3cefe7fSPierre Pronchery
297*a3cefe7fSPierre Pronchery /*
298*a3cefe7fSPierre Pronchery * !doc
299*a3cefe7fSPierre Pronchery *
300*a3cefe7fSPierre Pronchery * .. c:function:: char *pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value, unsigned int flags)
301*a3cefe7fSPierre Pronchery *
302*a3cefe7fSPierre Pronchery * Parse an expression for variable substitution.
303*a3cefe7fSPierre Pronchery *
304*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object to access.
305*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The variable list to search for variables (along side the global variable list).
306*a3cefe7fSPierre Pronchery * :param char* value: The ``key=value`` string to parse.
307*a3cefe7fSPierre Pronchery * :param uint flags: Any flags to consider while parsing.
308*a3cefe7fSPierre Pronchery * :return: the variable data with any variables substituted
309*a3cefe7fSPierre Pronchery * :rtype: char *
310*a3cefe7fSPierre Pronchery */
311*a3cefe7fSPierre Pronchery char *
pkgconf_tuple_parse(const pkgconf_client_t * client,pkgconf_list_t * vars,const char * value,unsigned int flags)312*a3cefe7fSPierre Pronchery pkgconf_tuple_parse(const pkgconf_client_t *client, pkgconf_list_t *vars, const char *value, unsigned int flags)
313*a3cefe7fSPierre Pronchery {
314*a3cefe7fSPierre Pronchery char buf[PKGCONF_BUFSIZE];
315*a3cefe7fSPierre Pronchery const char *ptr;
316*a3cefe7fSPierre Pronchery char *bptr = buf;
317*a3cefe7fSPierre Pronchery
318*a3cefe7fSPierre Pronchery if (!(client->flags & PKGCONF_PKG_PKGF_FDO_SYSROOT_RULES) &&
319*a3cefe7fSPierre Pronchery (!(flags & PKGCONF_PKG_PROPF_UNINSTALLED) || (client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES)))
320*a3cefe7fSPierre Pronchery {
321*a3cefe7fSPierre Pronchery if (*value == '/' && client->sysroot_dir != NULL && strncmp(value, client->sysroot_dir, strlen(client->sysroot_dir)))
322*a3cefe7fSPierre Pronchery bptr += pkgconf_strlcpy(buf, client->sysroot_dir, sizeof buf);
323*a3cefe7fSPierre Pronchery }
324*a3cefe7fSPierre Pronchery
325*a3cefe7fSPierre Pronchery for (ptr = value; *ptr != '\0' && bptr - buf < PKGCONF_BUFSIZE; ptr++)
326*a3cefe7fSPierre Pronchery {
327*a3cefe7fSPierre Pronchery if (*ptr != '$' || (*ptr == '$' && *(ptr + 1) != '{'))
328*a3cefe7fSPierre Pronchery *bptr++ = *ptr;
329*a3cefe7fSPierre Pronchery else if (*(ptr + 1) == '{')
330*a3cefe7fSPierre Pronchery {
331*a3cefe7fSPierre Pronchery char varname[PKGCONF_ITEM_SIZE];
332*a3cefe7fSPierre Pronchery char *vend = varname + PKGCONF_ITEM_SIZE - 1;
333*a3cefe7fSPierre Pronchery char *vptr = varname;
334*a3cefe7fSPierre Pronchery const char *pptr;
335*a3cefe7fSPierre Pronchery char *kv, *parsekv;
336*a3cefe7fSPierre Pronchery
337*a3cefe7fSPierre Pronchery *vptr = '\0';
338*a3cefe7fSPierre Pronchery
339*a3cefe7fSPierre Pronchery for (pptr = ptr + 2; *pptr != '\0'; pptr++)
340*a3cefe7fSPierre Pronchery {
341*a3cefe7fSPierre Pronchery if (*pptr != '}')
342*a3cefe7fSPierre Pronchery {
343*a3cefe7fSPierre Pronchery if (vptr < vend)
344*a3cefe7fSPierre Pronchery *vptr++ = *pptr;
345*a3cefe7fSPierre Pronchery else
346*a3cefe7fSPierre Pronchery {
347*a3cefe7fSPierre Pronchery *vptr = '\0';
348*a3cefe7fSPierre Pronchery break;
349*a3cefe7fSPierre Pronchery }
350*a3cefe7fSPierre Pronchery }
351*a3cefe7fSPierre Pronchery else
352*a3cefe7fSPierre Pronchery {
353*a3cefe7fSPierre Pronchery *vptr = '\0';
354*a3cefe7fSPierre Pronchery break;
355*a3cefe7fSPierre Pronchery }
356*a3cefe7fSPierre Pronchery }
357*a3cefe7fSPierre Pronchery
358*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "lookup tuple %s", varname);
359*a3cefe7fSPierre Pronchery
360*a3cefe7fSPierre Pronchery size_t remain = PKGCONF_BUFSIZE - (bptr - buf);
361*a3cefe7fSPierre Pronchery ptr += (pptr - ptr);
362*a3cefe7fSPierre Pronchery kv = pkgconf_tuple_find_global(client, varname);
363*a3cefe7fSPierre Pronchery if (kv != NULL)
364*a3cefe7fSPierre Pronchery {
365*a3cefe7fSPierre Pronchery size_t nlen = pkgconf_strlcpy(bptr, kv, remain);
366*a3cefe7fSPierre Pronchery if (nlen > remain)
367*a3cefe7fSPierre Pronchery {
368*a3cefe7fSPierre Pronchery pkgconf_warn(client, "warning: truncating very long variable to 64KB\n");
369*a3cefe7fSPierre Pronchery
370*a3cefe7fSPierre Pronchery bptr = buf + (PKGCONF_BUFSIZE - 1);
371*a3cefe7fSPierre Pronchery break;
372*a3cefe7fSPierre Pronchery }
373*a3cefe7fSPierre Pronchery
374*a3cefe7fSPierre Pronchery bptr += nlen;
375*a3cefe7fSPierre Pronchery }
376*a3cefe7fSPierre Pronchery else
377*a3cefe7fSPierre Pronchery {
378*a3cefe7fSPierre Pronchery kv = pkgconf_tuple_find(client, vars, varname);
379*a3cefe7fSPierre Pronchery
380*a3cefe7fSPierre Pronchery if (kv != NULL)
381*a3cefe7fSPierre Pronchery {
382*a3cefe7fSPierre Pronchery size_t nlen;
383*a3cefe7fSPierre Pronchery
384*a3cefe7fSPierre Pronchery parsekv = pkgconf_tuple_parse(client, vars, kv, flags);
385*a3cefe7fSPierre Pronchery nlen = pkgconf_strlcpy(bptr, parsekv, remain);
386*a3cefe7fSPierre Pronchery free(parsekv);
387*a3cefe7fSPierre Pronchery
388*a3cefe7fSPierre Pronchery if (nlen > remain)
389*a3cefe7fSPierre Pronchery {
390*a3cefe7fSPierre Pronchery pkgconf_warn(client, "warning: truncating very long variable to 64KB\n");
391*a3cefe7fSPierre Pronchery
392*a3cefe7fSPierre Pronchery bptr = buf + (PKGCONF_BUFSIZE - 1);
393*a3cefe7fSPierre Pronchery break;
394*a3cefe7fSPierre Pronchery }
395*a3cefe7fSPierre Pronchery
396*a3cefe7fSPierre Pronchery bptr += nlen;
397*a3cefe7fSPierre Pronchery }
398*a3cefe7fSPierre Pronchery }
399*a3cefe7fSPierre Pronchery }
400*a3cefe7fSPierre Pronchery }
401*a3cefe7fSPierre Pronchery
402*a3cefe7fSPierre Pronchery *bptr = '\0';
403*a3cefe7fSPierre Pronchery
404*a3cefe7fSPierre Pronchery /*
405*a3cefe7fSPierre Pronchery * Sigh. Somebody actually attempted to use freedesktop.org pkg-config's broken sysroot support,
406*a3cefe7fSPierre Pronchery * which was written by somebody who did not understand how sysroots are supposed to work. This
407*a3cefe7fSPierre Pronchery * results in an incorrect path being built as the sysroot will be prepended twice, once explicitly,
408*a3cefe7fSPierre Pronchery * and once by variable expansion (the pkgconf approach). We could simply make ${pc_sysrootdir} blank,
409*a3cefe7fSPierre Pronchery * but sometimes it is necessary to know the explicit sysroot path for other reasons, so we can't really
410*a3cefe7fSPierre Pronchery * do that.
411*a3cefe7fSPierre Pronchery *
412*a3cefe7fSPierre Pronchery * As a result, we check to see if ${pc_sysrootdir} is prepended as a duplicate, and if so, remove the
413*a3cefe7fSPierre Pronchery * prepend. This allows us to handle both our approach and the broken freedesktop.org implementation's
414*a3cefe7fSPierre Pronchery * approach. Because a path can be shorter than ${pc_sysrootdir}, we do some checks first to ensure it's
415*a3cefe7fSPierre Pronchery * safe to skip ahead in the string to scan for our sysroot dir.
416*a3cefe7fSPierre Pronchery *
417*a3cefe7fSPierre Pronchery * Finally, we call pkgconf_path_relocate() to clean the path of spurious elements.
418*a3cefe7fSPierre Pronchery *
419*a3cefe7fSPierre Pronchery * New in 1.9: Only attempt to rewrite the sysroot if we are not processing an uninstalled package.
420*a3cefe7fSPierre Pronchery */
421*a3cefe7fSPierre Pronchery if (should_rewrite_sysroot(client, vars, buf, flags))
422*a3cefe7fSPierre Pronchery {
423*a3cefe7fSPierre Pronchery char cleanpath[PKGCONF_ITEM_SIZE];
424*a3cefe7fSPierre Pronchery const char *sysroot_dir = find_sysroot(client, vars);
425*a3cefe7fSPierre Pronchery
426*a3cefe7fSPierre Pronchery pkgconf_strlcpy(cleanpath, buf + strlen(sysroot_dir), sizeof cleanpath);
427*a3cefe7fSPierre Pronchery pkgconf_path_relocate(cleanpath, sizeof cleanpath);
428*a3cefe7fSPierre Pronchery
429*a3cefe7fSPierre Pronchery return strdup(cleanpath);
430*a3cefe7fSPierre Pronchery }
431*a3cefe7fSPierre Pronchery
432*a3cefe7fSPierre Pronchery return strdup(buf);
433*a3cefe7fSPierre Pronchery }
434*a3cefe7fSPierre Pronchery
435*a3cefe7fSPierre Pronchery /*
436*a3cefe7fSPierre Pronchery * !doc
437*a3cefe7fSPierre Pronchery *
438*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_tuple_free_entry(pkgconf_tuple_t *tuple, pkgconf_list_t *list)
439*a3cefe7fSPierre Pronchery *
440*a3cefe7fSPierre Pronchery * Deletes a variable object, removing it from any variable lists and releasing any memory associated
441*a3cefe7fSPierre Pronchery * with it.
442*a3cefe7fSPierre Pronchery *
443*a3cefe7fSPierre Pronchery * :param pkgconf_tuple_t* tuple: The variable object to release.
444*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The variable list the variable object is attached to.
445*a3cefe7fSPierre Pronchery * :return: nothing
446*a3cefe7fSPierre Pronchery */
447*a3cefe7fSPierre Pronchery void
pkgconf_tuple_free_entry(pkgconf_tuple_t * tuple,pkgconf_list_t * list)448*a3cefe7fSPierre Pronchery pkgconf_tuple_free_entry(pkgconf_tuple_t *tuple, pkgconf_list_t *list)
449*a3cefe7fSPierre Pronchery {
450*a3cefe7fSPierre Pronchery pkgconf_node_delete(&tuple->iter, list);
451*a3cefe7fSPierre Pronchery
452*a3cefe7fSPierre Pronchery free(tuple->key);
453*a3cefe7fSPierre Pronchery free(tuple->value);
454*a3cefe7fSPierre Pronchery free(tuple);
455*a3cefe7fSPierre Pronchery }
456*a3cefe7fSPierre Pronchery
457*a3cefe7fSPierre Pronchery /*
458*a3cefe7fSPierre Pronchery * !doc
459*a3cefe7fSPierre Pronchery *
460*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_tuple_free(pkgconf_list_t *list)
461*a3cefe7fSPierre Pronchery *
462*a3cefe7fSPierre Pronchery * Deletes a variable list and any variables attached to it.
463*a3cefe7fSPierre Pronchery *
464*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The variable list to delete.
465*a3cefe7fSPierre Pronchery * :return: nothing
466*a3cefe7fSPierre Pronchery */
467*a3cefe7fSPierre Pronchery void
pkgconf_tuple_free(pkgconf_list_t * list)468*a3cefe7fSPierre Pronchery pkgconf_tuple_free(pkgconf_list_t *list)
469*a3cefe7fSPierre Pronchery {
470*a3cefe7fSPierre Pronchery pkgconf_node_t *node, *next;
471*a3cefe7fSPierre Pronchery
472*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
473*a3cefe7fSPierre Pronchery pkgconf_tuple_free_entry(node->data, list);
474*a3cefe7fSPierre Pronchery
475*a3cefe7fSPierre Pronchery pkgconf_list_zero(list);
476*a3cefe7fSPierre Pronchery }
477