1*a3cefe7fSPierre Pronchery /*
2*a3cefe7fSPierre Pronchery * fragment.c
3*a3cefe7fSPierre Pronchery * Management of fragment lists.
4*a3cefe7fSPierre Pronchery *
5*a3cefe7fSPierre Pronchery * Copyright (c) 2012, 2013, 2014 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 `fragment` module
23*a3cefe7fSPierre Pronchery * ============================
24*a3cefe7fSPierre Pronchery *
25*a3cefe7fSPierre Pronchery * The `fragment` module provides low-level management and rendering of fragment lists. A
26*a3cefe7fSPierre Pronchery * `fragment list` contains various `fragments` of text (such as ``-I /usr/include``) in a matter
27*a3cefe7fSPierre Pronchery * which is composable, mergeable and reorderable.
28*a3cefe7fSPierre Pronchery */
29*a3cefe7fSPierre Pronchery
30*a3cefe7fSPierre Pronchery struct pkgconf_fragment_check {
31*a3cefe7fSPierre Pronchery char *token;
32*a3cefe7fSPierre Pronchery size_t len;
33*a3cefe7fSPierre Pronchery };
34*a3cefe7fSPierre Pronchery
35*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_is_unmergeable(const char * string)36*a3cefe7fSPierre Pronchery pkgconf_fragment_is_unmergeable(const char *string)
37*a3cefe7fSPierre Pronchery {
38*a3cefe7fSPierre Pronchery static const struct pkgconf_fragment_check check_fragments[] = {
39*a3cefe7fSPierre Pronchery {"-framework", 10},
40*a3cefe7fSPierre Pronchery {"-isystem", 8},
41*a3cefe7fSPierre Pronchery {"-idirafter", 10},
42*a3cefe7fSPierre Pronchery {"-pthread", 8},
43*a3cefe7fSPierre Pronchery {"-Wa,", 4},
44*a3cefe7fSPierre Pronchery {"-Wl,", 4},
45*a3cefe7fSPierre Pronchery {"-Wp,", 4},
46*a3cefe7fSPierre Pronchery {"-trigraphs", 10},
47*a3cefe7fSPierre Pronchery {"-pedantic", 9},
48*a3cefe7fSPierre Pronchery {"-ansi", 5},
49*a3cefe7fSPierre Pronchery {"-std=", 5},
50*a3cefe7fSPierre Pronchery {"-stdlib=", 8},
51*a3cefe7fSPierre Pronchery {"-include", 8},
52*a3cefe7fSPierre Pronchery {"-nostdinc", 9},
53*a3cefe7fSPierre Pronchery {"-nostdlibinc", 12},
54*a3cefe7fSPierre Pronchery {"-nobuiltininc", 13},
55*a3cefe7fSPierre Pronchery {"-nodefaultlibs", 14},
56*a3cefe7fSPierre Pronchery };
57*a3cefe7fSPierre Pronchery
58*a3cefe7fSPierre Pronchery if (*string != '-')
59*a3cefe7fSPierre Pronchery return true;
60*a3cefe7fSPierre Pronchery
61*a3cefe7fSPierre Pronchery for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
62*a3cefe7fSPierre Pronchery if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
63*a3cefe7fSPierre Pronchery return true;
64*a3cefe7fSPierre Pronchery
65*a3cefe7fSPierre Pronchery /* only one pair of {-flag, arg} may be merged together */
66*a3cefe7fSPierre Pronchery if (strchr(string, ' ') != NULL)
67*a3cefe7fSPierre Pronchery return false;
68*a3cefe7fSPierre Pronchery
69*a3cefe7fSPierre Pronchery return false;
70*a3cefe7fSPierre Pronchery }
71*a3cefe7fSPierre Pronchery
72*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_should_munge(const char * string,const char * sysroot_dir)73*a3cefe7fSPierre Pronchery pkgconf_fragment_should_munge(const char *string, const char *sysroot_dir)
74*a3cefe7fSPierre Pronchery {
75*a3cefe7fSPierre Pronchery if (*string != '/')
76*a3cefe7fSPierre Pronchery return false;
77*a3cefe7fSPierre Pronchery
78*a3cefe7fSPierre Pronchery if (sysroot_dir != NULL && strncmp(sysroot_dir, string, strlen(sysroot_dir)))
79*a3cefe7fSPierre Pronchery return true;
80*a3cefe7fSPierre Pronchery
81*a3cefe7fSPierre Pronchery return false;
82*a3cefe7fSPierre Pronchery }
83*a3cefe7fSPierre Pronchery
84*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_is_groupable(const char * string)85*a3cefe7fSPierre Pronchery pkgconf_fragment_is_groupable(const char *string)
86*a3cefe7fSPierre Pronchery {
87*a3cefe7fSPierre Pronchery static const struct pkgconf_fragment_check check_fragments[] = {
88*a3cefe7fSPierre Pronchery {"-Wl,--start-group", 17},
89*a3cefe7fSPierre Pronchery {"-framework", 10},
90*a3cefe7fSPierre Pronchery {"-isystem", 8},
91*a3cefe7fSPierre Pronchery {"-idirafter", 10},
92*a3cefe7fSPierre Pronchery {"-include", 8},
93*a3cefe7fSPierre Pronchery };
94*a3cefe7fSPierre Pronchery
95*a3cefe7fSPierre Pronchery for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
96*a3cefe7fSPierre Pronchery if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
97*a3cefe7fSPierre Pronchery return true;
98*a3cefe7fSPierre Pronchery
99*a3cefe7fSPierre Pronchery return false;
100*a3cefe7fSPierre Pronchery }
101*a3cefe7fSPierre Pronchery
102*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_is_terminus(const char * string)103*a3cefe7fSPierre Pronchery pkgconf_fragment_is_terminus(const char *string)
104*a3cefe7fSPierre Pronchery {
105*a3cefe7fSPierre Pronchery static const struct pkgconf_fragment_check check_fragments[] = {
106*a3cefe7fSPierre Pronchery {"-Wl,--end-group", 15},
107*a3cefe7fSPierre Pronchery };
108*a3cefe7fSPierre Pronchery
109*a3cefe7fSPierre Pronchery for (size_t i = 0; i < PKGCONF_ARRAY_SIZE(check_fragments); i++)
110*a3cefe7fSPierre Pronchery if (!strncmp(string, check_fragments[i].token, check_fragments[i].len))
111*a3cefe7fSPierre Pronchery return true;
112*a3cefe7fSPierre Pronchery
113*a3cefe7fSPierre Pronchery return false;
114*a3cefe7fSPierre Pronchery }
115*a3cefe7fSPierre Pronchery
116*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_is_special(const char * string)117*a3cefe7fSPierre Pronchery pkgconf_fragment_is_special(const char *string)
118*a3cefe7fSPierre Pronchery {
119*a3cefe7fSPierre Pronchery if (*string != '-')
120*a3cefe7fSPierre Pronchery return true;
121*a3cefe7fSPierre Pronchery
122*a3cefe7fSPierre Pronchery if (!strncmp(string, "-lib:", 5))
123*a3cefe7fSPierre Pronchery return true;
124*a3cefe7fSPierre Pronchery
125*a3cefe7fSPierre Pronchery return pkgconf_fragment_is_unmergeable(string);
126*a3cefe7fSPierre Pronchery }
127*a3cefe7fSPierre Pronchery
128*a3cefe7fSPierre Pronchery static inline void
pkgconf_fragment_munge(const pkgconf_client_t * client,char * buf,size_t buflen,const char * source,const char * sysroot_dir,unsigned int flags)129*a3cefe7fSPierre Pronchery pkgconf_fragment_munge(const pkgconf_client_t *client, char *buf, size_t buflen, const char *source, const char *sysroot_dir, unsigned int flags)
130*a3cefe7fSPierre Pronchery {
131*a3cefe7fSPierre Pronchery *buf = '\0';
132*a3cefe7fSPierre Pronchery
133*a3cefe7fSPierre Pronchery if (!(flags & PKGCONF_PKG_PROPF_UNINSTALLED) || (client->flags & PKGCONF_PKG_PKGF_PKGCONF1_SYSROOT_RULES))
134*a3cefe7fSPierre Pronchery {
135*a3cefe7fSPierre Pronchery if (sysroot_dir == NULL)
136*a3cefe7fSPierre Pronchery sysroot_dir = pkgconf_tuple_find_global(client, "pc_sysrootdir");
137*a3cefe7fSPierre Pronchery
138*a3cefe7fSPierre Pronchery if (sysroot_dir != NULL && pkgconf_fragment_should_munge(source, sysroot_dir))
139*a3cefe7fSPierre Pronchery pkgconf_strlcat(buf, sysroot_dir, buflen);
140*a3cefe7fSPierre Pronchery }
141*a3cefe7fSPierre Pronchery
142*a3cefe7fSPierre Pronchery pkgconf_strlcat(buf, source, buflen);
143*a3cefe7fSPierre Pronchery
144*a3cefe7fSPierre Pronchery if (*buf == '/' && !(client->flags & PKGCONF_PKG_PKGF_DONT_RELOCATE_PATHS))
145*a3cefe7fSPierre Pronchery pkgconf_path_relocate(buf, buflen);
146*a3cefe7fSPierre Pronchery }
147*a3cefe7fSPierre Pronchery
148*a3cefe7fSPierre Pronchery static inline char *
pkgconf_fragment_copy_munged(const pkgconf_client_t * client,const char * source,unsigned int flags)149*a3cefe7fSPierre Pronchery pkgconf_fragment_copy_munged(const pkgconf_client_t *client, const char *source, unsigned int flags)
150*a3cefe7fSPierre Pronchery {
151*a3cefe7fSPierre Pronchery char mungebuf[PKGCONF_ITEM_SIZE];
152*a3cefe7fSPierre Pronchery pkgconf_fragment_munge(client, mungebuf, sizeof mungebuf, source, client->sysroot_dir, flags);
153*a3cefe7fSPierre Pronchery return strdup(mungebuf);
154*a3cefe7fSPierre Pronchery }
155*a3cefe7fSPierre Pronchery
156*a3cefe7fSPierre Pronchery /*
157*a3cefe7fSPierre Pronchery * !doc
158*a3cefe7fSPierre Pronchery *
159*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail)
160*a3cefe7fSPierre Pronchery *
161*a3cefe7fSPierre Pronchery * Adds a `fragment` of text to a `fragment list` directly without interpreting it.
162*a3cefe7fSPierre Pronchery *
163*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client being accessed.
164*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The fragment list.
165*a3cefe7fSPierre Pronchery * :param char type: The type of the fragment.
166*a3cefe7fSPierre Pronchery * :param char* data: The data of the fragment.
167*a3cefe7fSPierre Pronchery * :param bool tail: Whether to place the fragment at the beginning of the list or the end.
168*a3cefe7fSPierre Pronchery * :return: nothing
169*a3cefe7fSPierre Pronchery */
170*a3cefe7fSPierre Pronchery void
pkgconf_fragment_insert(const pkgconf_client_t * client,pkgconf_list_t * list,char type,const char * data,bool tail)171*a3cefe7fSPierre Pronchery pkgconf_fragment_insert(const pkgconf_client_t *client, pkgconf_list_t *list, char type, const char *data, bool tail)
172*a3cefe7fSPierre Pronchery {
173*a3cefe7fSPierre Pronchery pkgconf_fragment_t *frag;
174*a3cefe7fSPierre Pronchery
175*a3cefe7fSPierre Pronchery frag = calloc(1, sizeof(pkgconf_fragment_t));
176*a3cefe7fSPierre Pronchery frag->type = type;
177*a3cefe7fSPierre Pronchery frag->data = pkgconf_fragment_copy_munged(client, data, 0);
178*a3cefe7fSPierre Pronchery
179*a3cefe7fSPierre Pronchery if (tail)
180*a3cefe7fSPierre Pronchery {
181*a3cefe7fSPierre Pronchery pkgconf_node_insert_tail(&frag->iter, frag, list);
182*a3cefe7fSPierre Pronchery return;
183*a3cefe7fSPierre Pronchery }
184*a3cefe7fSPierre Pronchery
185*a3cefe7fSPierre Pronchery pkgconf_node_insert(&frag->iter, frag, list);
186*a3cefe7fSPierre Pronchery }
187*a3cefe7fSPierre Pronchery
188*a3cefe7fSPierre Pronchery /*
189*a3cefe7fSPierre Pronchery * !doc
190*a3cefe7fSPierre Pronchery *
191*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags)
192*a3cefe7fSPierre Pronchery *
193*a3cefe7fSPierre Pronchery * Adds a `fragment` of text to a `fragment list`, possibly modifying the fragment if a sysroot is set.
194*a3cefe7fSPierre Pronchery *
195*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client being accessed.
196*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The fragment list.
197*a3cefe7fSPierre Pronchery * :param char* string: The string of text to add as a fragment to the fragment list.
198*a3cefe7fSPierre Pronchery * :param uint flags: Parsing-related flags for the package.
199*a3cefe7fSPierre Pronchery * :return: nothing
200*a3cefe7fSPierre Pronchery */
201*a3cefe7fSPierre Pronchery void
pkgconf_fragment_add(const pkgconf_client_t * client,pkgconf_list_t * list,const char * string,unsigned int flags)202*a3cefe7fSPierre Pronchery pkgconf_fragment_add(const pkgconf_client_t *client, pkgconf_list_t *list, const char *string, unsigned int flags)
203*a3cefe7fSPierre Pronchery {
204*a3cefe7fSPierre Pronchery pkgconf_list_t *target = list;
205*a3cefe7fSPierre Pronchery pkgconf_fragment_t *frag;
206*a3cefe7fSPierre Pronchery
207*a3cefe7fSPierre Pronchery if (*string == '\0')
208*a3cefe7fSPierre Pronchery return;
209*a3cefe7fSPierre Pronchery
210*a3cefe7fSPierre Pronchery if (list->tail != NULL && list->tail->data != NULL &&
211*a3cefe7fSPierre Pronchery !(client->flags & PKGCONF_PKG_PKGF_DONT_MERGE_SPECIAL_FRAGMENTS))
212*a3cefe7fSPierre Pronchery {
213*a3cefe7fSPierre Pronchery pkgconf_fragment_t *parent = list->tail->data;
214*a3cefe7fSPierre Pronchery
215*a3cefe7fSPierre Pronchery /* only attempt to merge 'special' fragments together */
216*a3cefe7fSPierre Pronchery if (!parent->type && parent->data != NULL &&
217*a3cefe7fSPierre Pronchery pkgconf_fragment_is_unmergeable(parent->data) &&
218*a3cefe7fSPierre Pronchery !(parent->flags & PKGCONF_PKG_FRAGF_TERMINATED))
219*a3cefe7fSPierre Pronchery {
220*a3cefe7fSPierre Pronchery if (pkgconf_fragment_is_groupable(parent->data))
221*a3cefe7fSPierre Pronchery target = &parent->children;
222*a3cefe7fSPierre Pronchery
223*a3cefe7fSPierre Pronchery if (pkgconf_fragment_is_terminus(string))
224*a3cefe7fSPierre Pronchery parent->flags |= PKGCONF_PKG_FRAGF_TERMINATED;
225*a3cefe7fSPierre Pronchery
226*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "adding fragment as child to list @%p", target);
227*a3cefe7fSPierre Pronchery }
228*a3cefe7fSPierre Pronchery }
229*a3cefe7fSPierre Pronchery
230*a3cefe7fSPierre Pronchery frag = calloc(1, sizeof(pkgconf_fragment_t));
231*a3cefe7fSPierre Pronchery if (frag == NULL)
232*a3cefe7fSPierre Pronchery {
233*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "failed to add new fragment due to allocation failure to list @%p", target);
234*a3cefe7fSPierre Pronchery return;
235*a3cefe7fSPierre Pronchery }
236*a3cefe7fSPierre Pronchery
237*a3cefe7fSPierre Pronchery if (strlen(string) > 1 && !pkgconf_fragment_is_special(string))
238*a3cefe7fSPierre Pronchery {
239*a3cefe7fSPierre Pronchery frag->type = *(string + 1);
240*a3cefe7fSPierre Pronchery frag->data = pkgconf_fragment_copy_munged(client, string + 2, flags);
241*a3cefe7fSPierre Pronchery
242*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "added fragment {%c, '%s'} to list @%p", frag->type, frag->data, list);
243*a3cefe7fSPierre Pronchery }
244*a3cefe7fSPierre Pronchery else
245*a3cefe7fSPierre Pronchery {
246*a3cefe7fSPierre Pronchery frag->type = 0;
247*a3cefe7fSPierre Pronchery frag->data = pkgconf_fragment_copy_munged(client, string, flags);
248*a3cefe7fSPierre Pronchery
249*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "created special fragment {'%s'} in list @%p", frag->data, target);
250*a3cefe7fSPierre Pronchery }
251*a3cefe7fSPierre Pronchery
252*a3cefe7fSPierre Pronchery pkgconf_node_insert_tail(&frag->iter, frag, target);
253*a3cefe7fSPierre Pronchery }
254*a3cefe7fSPierre Pronchery
255*a3cefe7fSPierre Pronchery static inline pkgconf_fragment_t *
pkgconf_fragment_lookup(pkgconf_list_t * list,const pkgconf_fragment_t * base)256*a3cefe7fSPierre Pronchery pkgconf_fragment_lookup(pkgconf_list_t *list, const pkgconf_fragment_t *base)
257*a3cefe7fSPierre Pronchery {
258*a3cefe7fSPierre Pronchery pkgconf_node_t *node;
259*a3cefe7fSPierre Pronchery
260*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY_REVERSE(list->tail, node)
261*a3cefe7fSPierre Pronchery {
262*a3cefe7fSPierre Pronchery pkgconf_fragment_t *frag = node->data;
263*a3cefe7fSPierre Pronchery
264*a3cefe7fSPierre Pronchery if (base->type != frag->type)
265*a3cefe7fSPierre Pronchery continue;
266*a3cefe7fSPierre Pronchery
267*a3cefe7fSPierre Pronchery if (!strcmp(base->data, frag->data))
268*a3cefe7fSPierre Pronchery return frag;
269*a3cefe7fSPierre Pronchery }
270*a3cefe7fSPierre Pronchery
271*a3cefe7fSPierre Pronchery return NULL;
272*a3cefe7fSPierre Pronchery }
273*a3cefe7fSPierre Pronchery
274*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_can_merge_back(const pkgconf_fragment_t * base,unsigned int flags,bool is_private)275*a3cefe7fSPierre Pronchery pkgconf_fragment_can_merge_back(const pkgconf_fragment_t *base, unsigned int flags, bool is_private)
276*a3cefe7fSPierre Pronchery {
277*a3cefe7fSPierre Pronchery (void) flags;
278*a3cefe7fSPierre Pronchery
279*a3cefe7fSPierre Pronchery if (base->type == 'l')
280*a3cefe7fSPierre Pronchery {
281*a3cefe7fSPierre Pronchery if (is_private)
282*a3cefe7fSPierre Pronchery return false;
283*a3cefe7fSPierre Pronchery
284*a3cefe7fSPierre Pronchery return true;
285*a3cefe7fSPierre Pronchery }
286*a3cefe7fSPierre Pronchery
287*a3cefe7fSPierre Pronchery if (base->type == 'F')
288*a3cefe7fSPierre Pronchery return false;
289*a3cefe7fSPierre Pronchery if (base->type == 'L')
290*a3cefe7fSPierre Pronchery return false;
291*a3cefe7fSPierre Pronchery if (base->type == 'I')
292*a3cefe7fSPierre Pronchery return false;
293*a3cefe7fSPierre Pronchery
294*a3cefe7fSPierre Pronchery return true;
295*a3cefe7fSPierre Pronchery }
296*a3cefe7fSPierre Pronchery
297*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_can_merge(const pkgconf_fragment_t * base,unsigned int flags,bool is_private)298*a3cefe7fSPierre Pronchery pkgconf_fragment_can_merge(const pkgconf_fragment_t *base, unsigned int flags, bool is_private)
299*a3cefe7fSPierre Pronchery {
300*a3cefe7fSPierre Pronchery (void) flags;
301*a3cefe7fSPierre Pronchery
302*a3cefe7fSPierre Pronchery if (is_private)
303*a3cefe7fSPierre Pronchery return false;
304*a3cefe7fSPierre Pronchery
305*a3cefe7fSPierre Pronchery if (base->children.head != NULL)
306*a3cefe7fSPierre Pronchery return false;
307*a3cefe7fSPierre Pronchery
308*a3cefe7fSPierre Pronchery return pkgconf_fragment_is_unmergeable(base->data);
309*a3cefe7fSPierre Pronchery }
310*a3cefe7fSPierre Pronchery
311*a3cefe7fSPierre Pronchery static inline pkgconf_fragment_t *
pkgconf_fragment_exists(pkgconf_list_t * list,const pkgconf_fragment_t * base,unsigned int flags,bool is_private)312*a3cefe7fSPierre Pronchery pkgconf_fragment_exists(pkgconf_list_t *list, const pkgconf_fragment_t *base, unsigned int flags, bool is_private)
313*a3cefe7fSPierre Pronchery {
314*a3cefe7fSPierre Pronchery if (!pkgconf_fragment_can_merge_back(base, flags, is_private))
315*a3cefe7fSPierre Pronchery return NULL;
316*a3cefe7fSPierre Pronchery
317*a3cefe7fSPierre Pronchery if (!pkgconf_fragment_can_merge(base, flags, is_private))
318*a3cefe7fSPierre Pronchery return NULL;
319*a3cefe7fSPierre Pronchery
320*a3cefe7fSPierre Pronchery return pkgconf_fragment_lookup(list, base);
321*a3cefe7fSPierre Pronchery }
322*a3cefe7fSPierre Pronchery
323*a3cefe7fSPierre Pronchery static inline bool
pkgconf_fragment_should_merge(const pkgconf_fragment_t * base)324*a3cefe7fSPierre Pronchery pkgconf_fragment_should_merge(const pkgconf_fragment_t *base)
325*a3cefe7fSPierre Pronchery {
326*a3cefe7fSPierre Pronchery const pkgconf_fragment_t *parent;
327*a3cefe7fSPierre Pronchery
328*a3cefe7fSPierre Pronchery /* if we are the first fragment, that means the next fragment is the same, so it's always safe. */
329*a3cefe7fSPierre Pronchery if (base->iter.prev == NULL)
330*a3cefe7fSPierre Pronchery return true;
331*a3cefe7fSPierre Pronchery
332*a3cefe7fSPierre Pronchery /* this really shouldn't ever happen, but handle it */
333*a3cefe7fSPierre Pronchery parent = base->iter.prev->data;
334*a3cefe7fSPierre Pronchery if (parent == NULL)
335*a3cefe7fSPierre Pronchery return true;
336*a3cefe7fSPierre Pronchery
337*a3cefe7fSPierre Pronchery switch (parent->type)
338*a3cefe7fSPierre Pronchery {
339*a3cefe7fSPierre Pronchery case 'l':
340*a3cefe7fSPierre Pronchery case 'L':
341*a3cefe7fSPierre Pronchery case 'I':
342*a3cefe7fSPierre Pronchery return true;
343*a3cefe7fSPierre Pronchery default:
344*a3cefe7fSPierre Pronchery return !base->type || parent->type == base->type;
345*a3cefe7fSPierre Pronchery }
346*a3cefe7fSPierre Pronchery }
347*a3cefe7fSPierre Pronchery
348*a3cefe7fSPierre Pronchery /*
349*a3cefe7fSPierre Pronchery * !doc
350*a3cefe7fSPierre Pronchery *
351*a3cefe7fSPierre Pronchery * .. c:function:: bool pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag)
352*a3cefe7fSPierre Pronchery *
353*a3cefe7fSPierre Pronchery * Checks if a `fragment` contains a `system path`. System paths are detected at compile time and optionally overridden by
354*a3cefe7fSPierre Pronchery * the ``PKG_CONFIG_SYSTEM_INCLUDE_PATH`` and ``PKG_CONFIG_SYSTEM_LIBRARY_PATH`` environment variables.
355*a3cefe7fSPierre Pronchery *
356*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client object the fragment belongs to.
357*a3cefe7fSPierre Pronchery * :param pkgconf_fragment_t* frag: The fragment being checked.
358*a3cefe7fSPierre Pronchery * :return: true if the fragment contains a system path, else false
359*a3cefe7fSPierre Pronchery * :rtype: bool
360*a3cefe7fSPierre Pronchery */
361*a3cefe7fSPierre Pronchery bool
pkgconf_fragment_has_system_dir(const pkgconf_client_t * client,const pkgconf_fragment_t * frag)362*a3cefe7fSPierre Pronchery pkgconf_fragment_has_system_dir(const pkgconf_client_t *client, const pkgconf_fragment_t *frag)
363*a3cefe7fSPierre Pronchery {
364*a3cefe7fSPierre Pronchery const pkgconf_list_t *check_paths = NULL;
365*a3cefe7fSPierre Pronchery
366*a3cefe7fSPierre Pronchery switch (frag->type)
367*a3cefe7fSPierre Pronchery {
368*a3cefe7fSPierre Pronchery case 'L':
369*a3cefe7fSPierre Pronchery check_paths = &client->filter_libdirs;
370*a3cefe7fSPierre Pronchery break;
371*a3cefe7fSPierre Pronchery case 'I':
372*a3cefe7fSPierre Pronchery check_paths = &client->filter_includedirs;
373*a3cefe7fSPierre Pronchery break;
374*a3cefe7fSPierre Pronchery default:
375*a3cefe7fSPierre Pronchery return false;
376*a3cefe7fSPierre Pronchery }
377*a3cefe7fSPierre Pronchery
378*a3cefe7fSPierre Pronchery return pkgconf_path_match_list(frag->data, check_paths);
379*a3cefe7fSPierre Pronchery }
380*a3cefe7fSPierre Pronchery
381*a3cefe7fSPierre Pronchery /*
382*a3cefe7fSPierre Pronchery * !doc
383*a3cefe7fSPierre Pronchery *
384*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private)
385*a3cefe7fSPierre Pronchery *
386*a3cefe7fSPierre Pronchery * Copies a `fragment` to another `fragment list`, possibly removing a previous copy of the `fragment`
387*a3cefe7fSPierre Pronchery * in a process known as `mergeback`.
388*a3cefe7fSPierre Pronchery *
389*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client being accessed.
390*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The list the fragment is being added to.
391*a3cefe7fSPierre Pronchery * :param pkgconf_fragment_t* base: The fragment being copied.
392*a3cefe7fSPierre Pronchery * :param bool is_private: Whether the fragment list is a `private` fragment list (static linking).
393*a3cefe7fSPierre Pronchery * :return: nothing
394*a3cefe7fSPierre Pronchery */
395*a3cefe7fSPierre Pronchery void
pkgconf_fragment_copy(const pkgconf_client_t * client,pkgconf_list_t * list,const pkgconf_fragment_t * base,bool is_private)396*a3cefe7fSPierre Pronchery pkgconf_fragment_copy(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_fragment_t *base, bool is_private)
397*a3cefe7fSPierre Pronchery {
398*a3cefe7fSPierre Pronchery pkgconf_fragment_t *frag;
399*a3cefe7fSPierre Pronchery
400*a3cefe7fSPierre Pronchery if ((frag = pkgconf_fragment_exists(list, base, client->flags, is_private)) != NULL)
401*a3cefe7fSPierre Pronchery {
402*a3cefe7fSPierre Pronchery if (pkgconf_fragment_should_merge(frag))
403*a3cefe7fSPierre Pronchery pkgconf_fragment_delete(list, frag);
404*a3cefe7fSPierre Pronchery }
405*a3cefe7fSPierre Pronchery else if (!is_private && !pkgconf_fragment_can_merge_back(base, client->flags, is_private) && (pkgconf_fragment_lookup(list, base) != NULL))
406*a3cefe7fSPierre Pronchery return;
407*a3cefe7fSPierre Pronchery
408*a3cefe7fSPierre Pronchery frag = calloc(1, sizeof(pkgconf_fragment_t));
409*a3cefe7fSPierre Pronchery
410*a3cefe7fSPierre Pronchery frag->type = base->type;
411*a3cefe7fSPierre Pronchery pkgconf_fragment_copy_list(client, &frag->children, &base->children);
412*a3cefe7fSPierre Pronchery if (base->data != NULL)
413*a3cefe7fSPierre Pronchery frag->data = strdup(base->data);
414*a3cefe7fSPierre Pronchery
415*a3cefe7fSPierre Pronchery pkgconf_node_insert_tail(&frag->iter, frag, list);
416*a3cefe7fSPierre Pronchery }
417*a3cefe7fSPierre Pronchery
418*a3cefe7fSPierre Pronchery /*
419*a3cefe7fSPierre Pronchery * !doc
420*a3cefe7fSPierre Pronchery *
421*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base)
422*a3cefe7fSPierre Pronchery *
423*a3cefe7fSPierre Pronchery * Copies a `fragment list` to another `fragment list`, possibly removing a previous copy of the fragments
424*a3cefe7fSPierre Pronchery * in a process known as `mergeback`.
425*a3cefe7fSPierre Pronchery *
426*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client being accessed.
427*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The list the fragments are being added to.
428*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* base: The list the fragments are being copied from.
429*a3cefe7fSPierre Pronchery * :return: nothing
430*a3cefe7fSPierre Pronchery */
431*a3cefe7fSPierre Pronchery void
pkgconf_fragment_copy_list(const pkgconf_client_t * client,pkgconf_list_t * list,const pkgconf_list_t * base)432*a3cefe7fSPierre Pronchery pkgconf_fragment_copy_list(const pkgconf_client_t *client, pkgconf_list_t *list, const pkgconf_list_t *base)
433*a3cefe7fSPierre Pronchery {
434*a3cefe7fSPierre Pronchery pkgconf_node_t *node;
435*a3cefe7fSPierre Pronchery
436*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(base->head, node)
437*a3cefe7fSPierre Pronchery {
438*a3cefe7fSPierre Pronchery pkgconf_fragment_t *frag = node->data;
439*a3cefe7fSPierre Pronchery
440*a3cefe7fSPierre Pronchery pkgconf_fragment_copy(client, list, frag, true);
441*a3cefe7fSPierre Pronchery }
442*a3cefe7fSPierre Pronchery }
443*a3cefe7fSPierre Pronchery
444*a3cefe7fSPierre Pronchery /*
445*a3cefe7fSPierre Pronchery * !doc
446*a3cefe7fSPierre Pronchery *
447*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func)
448*a3cefe7fSPierre Pronchery *
449*a3cefe7fSPierre Pronchery * Copies a `fragment list` to another `fragment list` which match a user-specified filtering function.
450*a3cefe7fSPierre Pronchery *
451*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client being accessed.
452*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* dest: The destination list.
453*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* src: The source list.
454*a3cefe7fSPierre Pronchery * :param pkgconf_fragment_filter_func_t filter_func: The filter function to use.
455*a3cefe7fSPierre Pronchery * :param void* data: Optional data to pass to the filter function.
456*a3cefe7fSPierre Pronchery * :return: nothing
457*a3cefe7fSPierre Pronchery */
458*a3cefe7fSPierre Pronchery void
pkgconf_fragment_filter(const pkgconf_client_t * client,pkgconf_list_t * dest,pkgconf_list_t * src,pkgconf_fragment_filter_func_t filter_func,void * data)459*a3cefe7fSPierre Pronchery pkgconf_fragment_filter(const pkgconf_client_t *client, pkgconf_list_t *dest, pkgconf_list_t *src, pkgconf_fragment_filter_func_t filter_func, void *data)
460*a3cefe7fSPierre Pronchery {
461*a3cefe7fSPierre Pronchery pkgconf_node_t *node;
462*a3cefe7fSPierre Pronchery
463*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(src->head, node)
464*a3cefe7fSPierre Pronchery {
465*a3cefe7fSPierre Pronchery pkgconf_fragment_t *frag = node->data;
466*a3cefe7fSPierre Pronchery
467*a3cefe7fSPierre Pronchery if (filter_func(client, frag, data))
468*a3cefe7fSPierre Pronchery pkgconf_fragment_copy(client, dest, frag, true);
469*a3cefe7fSPierre Pronchery }
470*a3cefe7fSPierre Pronchery }
471*a3cefe7fSPierre Pronchery
472*a3cefe7fSPierre Pronchery static inline char *
fragment_quote(const pkgconf_fragment_t * frag)473*a3cefe7fSPierre Pronchery fragment_quote(const pkgconf_fragment_t *frag)
474*a3cefe7fSPierre Pronchery {
475*a3cefe7fSPierre Pronchery const char *src = frag->data;
476*a3cefe7fSPierre Pronchery ssize_t outlen = strlen(src) + 10;
477*a3cefe7fSPierre Pronchery char *out, *dst;
478*a3cefe7fSPierre Pronchery
479*a3cefe7fSPierre Pronchery if (frag->data == NULL)
480*a3cefe7fSPierre Pronchery return NULL;
481*a3cefe7fSPierre Pronchery
482*a3cefe7fSPierre Pronchery out = dst = calloc(1, outlen);
483*a3cefe7fSPierre Pronchery if (out == NULL)
484*a3cefe7fSPierre Pronchery return NULL;
485*a3cefe7fSPierre Pronchery
486*a3cefe7fSPierre Pronchery for (; *src; src++)
487*a3cefe7fSPierre Pronchery {
488*a3cefe7fSPierre Pronchery if (((*src < ' ') ||
489*a3cefe7fSPierre Pronchery (*src >= (' ' + (frag->children.head != NULL ? 1 : 0)) && *src < '$') ||
490*a3cefe7fSPierre Pronchery (*src > '$' && *src < '(') ||
491*a3cefe7fSPierre Pronchery (*src > ')' && *src < '+') ||
492*a3cefe7fSPierre Pronchery (*src > ':' && *src < '=') ||
493*a3cefe7fSPierre Pronchery (*src > '=' && *src < '@') ||
494*a3cefe7fSPierre Pronchery (*src > 'Z' && *src < '\\') ||
495*a3cefe7fSPierre Pronchery #ifndef _WIN32
496*a3cefe7fSPierre Pronchery (*src == '\\') ||
497*a3cefe7fSPierre Pronchery #endif
498*a3cefe7fSPierre Pronchery (*src > '\\' && *src < '^') ||
499*a3cefe7fSPierre Pronchery (*src == '`') ||
500*a3cefe7fSPierre Pronchery (*src > 'z' && *src < '~') ||
501*a3cefe7fSPierre Pronchery (*src > '~')))
502*a3cefe7fSPierre Pronchery *dst++ = '\\';
503*a3cefe7fSPierre Pronchery
504*a3cefe7fSPierre Pronchery *dst++ = *src;
505*a3cefe7fSPierre Pronchery
506*a3cefe7fSPierre Pronchery if ((ptrdiff_t)(dst - out) + 2 > outlen)
507*a3cefe7fSPierre Pronchery {
508*a3cefe7fSPierre Pronchery ptrdiff_t offset = dst - out;
509*a3cefe7fSPierre Pronchery outlen *= 2;
510*a3cefe7fSPierre Pronchery
511*a3cefe7fSPierre Pronchery char *newout = realloc(out, outlen);
512*a3cefe7fSPierre Pronchery if (newout == NULL)
513*a3cefe7fSPierre Pronchery {
514*a3cefe7fSPierre Pronchery free(out);
515*a3cefe7fSPierre Pronchery return NULL;
516*a3cefe7fSPierre Pronchery }
517*a3cefe7fSPierre Pronchery
518*a3cefe7fSPierre Pronchery out = newout;
519*a3cefe7fSPierre Pronchery dst = out + offset;
520*a3cefe7fSPierre Pronchery }
521*a3cefe7fSPierre Pronchery }
522*a3cefe7fSPierre Pronchery
523*a3cefe7fSPierre Pronchery *dst = 0;
524*a3cefe7fSPierre Pronchery return out;
525*a3cefe7fSPierre Pronchery }
526*a3cefe7fSPierre Pronchery
527*a3cefe7fSPierre Pronchery static inline size_t
pkgconf_fragment_len(const pkgconf_fragment_t * frag)528*a3cefe7fSPierre Pronchery pkgconf_fragment_len(const pkgconf_fragment_t *frag)
529*a3cefe7fSPierre Pronchery {
530*a3cefe7fSPierre Pronchery size_t len = 1;
531*a3cefe7fSPierre Pronchery
532*a3cefe7fSPierre Pronchery if (frag->type)
533*a3cefe7fSPierre Pronchery len += 2;
534*a3cefe7fSPierre Pronchery
535*a3cefe7fSPierre Pronchery if (frag->data != NULL)
536*a3cefe7fSPierre Pronchery {
537*a3cefe7fSPierre Pronchery pkgconf_node_t *iter;
538*a3cefe7fSPierre Pronchery
539*a3cefe7fSPierre Pronchery char *quoted = fragment_quote(frag);
540*a3cefe7fSPierre Pronchery len += strlen(quoted);
541*a3cefe7fSPierre Pronchery free(quoted);
542*a3cefe7fSPierre Pronchery
543*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(frag->children.head, iter)
544*a3cefe7fSPierre Pronchery {
545*a3cefe7fSPierre Pronchery const pkgconf_fragment_t *child_frag = iter->data;
546*a3cefe7fSPierre Pronchery len += pkgconf_fragment_len(child_frag) + 1;
547*a3cefe7fSPierre Pronchery }
548*a3cefe7fSPierre Pronchery }
549*a3cefe7fSPierre Pronchery
550*a3cefe7fSPierre Pronchery return len;
551*a3cefe7fSPierre Pronchery }
552*a3cefe7fSPierre Pronchery
553*a3cefe7fSPierre Pronchery static size_t
fragment_render_len(const pkgconf_list_t * list,bool escape)554*a3cefe7fSPierre Pronchery fragment_render_len(const pkgconf_list_t *list, bool escape)
555*a3cefe7fSPierre Pronchery {
556*a3cefe7fSPierre Pronchery (void) escape;
557*a3cefe7fSPierre Pronchery
558*a3cefe7fSPierre Pronchery size_t out = 1; /* trailing nul */
559*a3cefe7fSPierre Pronchery pkgconf_node_t *node;
560*a3cefe7fSPierre Pronchery
561*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
562*a3cefe7fSPierre Pronchery {
563*a3cefe7fSPierre Pronchery const pkgconf_fragment_t *frag = node->data;
564*a3cefe7fSPierre Pronchery out += pkgconf_fragment_len(frag);
565*a3cefe7fSPierre Pronchery }
566*a3cefe7fSPierre Pronchery
567*a3cefe7fSPierre Pronchery return out;
568*a3cefe7fSPierre Pronchery }
569*a3cefe7fSPierre Pronchery
570*a3cefe7fSPierre Pronchery static inline size_t
fragment_render_item(const pkgconf_fragment_t * frag,char * bptr,size_t bufremain)571*a3cefe7fSPierre Pronchery fragment_render_item(const pkgconf_fragment_t *frag, char *bptr, size_t bufremain)
572*a3cefe7fSPierre Pronchery {
573*a3cefe7fSPierre Pronchery const pkgconf_node_t *iter;
574*a3cefe7fSPierre Pronchery char *base = bptr;
575*a3cefe7fSPierre Pronchery
576*a3cefe7fSPierre Pronchery char *quoted = fragment_quote(frag);
577*a3cefe7fSPierre Pronchery if (quoted == NULL)
578*a3cefe7fSPierre Pronchery return 0;
579*a3cefe7fSPierre Pronchery
580*a3cefe7fSPierre Pronchery if (strlen(quoted) > bufremain)
581*a3cefe7fSPierre Pronchery {
582*a3cefe7fSPierre Pronchery free(quoted);
583*a3cefe7fSPierre Pronchery return 0;
584*a3cefe7fSPierre Pronchery }
585*a3cefe7fSPierre Pronchery
586*a3cefe7fSPierre Pronchery if (frag->type)
587*a3cefe7fSPierre Pronchery {
588*a3cefe7fSPierre Pronchery *bptr++ = '-';
589*a3cefe7fSPierre Pronchery *bptr++ = frag->type;
590*a3cefe7fSPierre Pronchery }
591*a3cefe7fSPierre Pronchery
592*a3cefe7fSPierre Pronchery if (quoted != NULL)
593*a3cefe7fSPierre Pronchery {
594*a3cefe7fSPierre Pronchery bptr += pkgconf_strlcpy(bptr, quoted, bufremain - (bptr - base));
595*a3cefe7fSPierre Pronchery free(quoted);
596*a3cefe7fSPierre Pronchery }
597*a3cefe7fSPierre Pronchery
598*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(frag->children.head, iter)
599*a3cefe7fSPierre Pronchery {
600*a3cefe7fSPierre Pronchery const pkgconf_fragment_t *child_frag = iter->data;
601*a3cefe7fSPierre Pronchery
602*a3cefe7fSPierre Pronchery *bptr++ = ' ';
603*a3cefe7fSPierre Pronchery bptr += fragment_render_item(child_frag, bptr, bufremain - (bptr - base));
604*a3cefe7fSPierre Pronchery }
605*a3cefe7fSPierre Pronchery
606*a3cefe7fSPierre Pronchery return bptr - base;
607*a3cefe7fSPierre Pronchery }
608*a3cefe7fSPierre Pronchery
609*a3cefe7fSPierre Pronchery static void
fragment_render_buf(const pkgconf_list_t * list,char * buf,size_t buflen,bool escape)610*a3cefe7fSPierre Pronchery fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape)
611*a3cefe7fSPierre Pronchery {
612*a3cefe7fSPierre Pronchery (void) escape;
613*a3cefe7fSPierre Pronchery
614*a3cefe7fSPierre Pronchery pkgconf_node_t *node;
615*a3cefe7fSPierre Pronchery char *bptr = buf;
616*a3cefe7fSPierre Pronchery
617*a3cefe7fSPierre Pronchery memset(buf, 0, buflen);
618*a3cefe7fSPierre Pronchery
619*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY(list->head, node)
620*a3cefe7fSPierre Pronchery {
621*a3cefe7fSPierre Pronchery const pkgconf_fragment_t *frag = node->data;
622*a3cefe7fSPierre Pronchery size_t buf_remaining = buflen - (bptr - buf);
623*a3cefe7fSPierre Pronchery size_t written = fragment_render_item(frag, bptr, buf_remaining);
624*a3cefe7fSPierre Pronchery
625*a3cefe7fSPierre Pronchery bptr += written;
626*a3cefe7fSPierre Pronchery
627*a3cefe7fSPierre Pronchery if (node->next != NULL)
628*a3cefe7fSPierre Pronchery *bptr++ = ' ';
629*a3cefe7fSPierre Pronchery }
630*a3cefe7fSPierre Pronchery }
631*a3cefe7fSPierre Pronchery
632*a3cefe7fSPierre Pronchery static const pkgconf_fragment_render_ops_t default_render_ops = {
633*a3cefe7fSPierre Pronchery .render_len = fragment_render_len,
634*a3cefe7fSPierre Pronchery .render_buf = fragment_render_buf
635*a3cefe7fSPierre Pronchery };
636*a3cefe7fSPierre Pronchery
637*a3cefe7fSPierre Pronchery /*
638*a3cefe7fSPierre Pronchery * !doc
639*a3cefe7fSPierre Pronchery *
640*a3cefe7fSPierre Pronchery * .. c:function:: size_t pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
641*a3cefe7fSPierre Pronchery *
642*a3cefe7fSPierre Pronchery * Calculates the required memory to store a `fragment list` when rendered as a string.
643*a3cefe7fSPierre Pronchery *
644*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The `fragment list` being rendered.
645*a3cefe7fSPierre Pronchery * :param bool escape: Whether or not to escape special shell characters (deprecated).
646*a3cefe7fSPierre Pronchery * :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
647*a3cefe7fSPierre Pronchery * :return: the amount of bytes required to represent the `fragment list` when rendered
648*a3cefe7fSPierre Pronchery * :rtype: size_t
649*a3cefe7fSPierre Pronchery */
650*a3cefe7fSPierre Pronchery size_t
pkgconf_fragment_render_len(const pkgconf_list_t * list,bool escape,const pkgconf_fragment_render_ops_t * ops)651*a3cefe7fSPierre Pronchery pkgconf_fragment_render_len(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
652*a3cefe7fSPierre Pronchery {
653*a3cefe7fSPierre Pronchery (void) escape;
654*a3cefe7fSPierre Pronchery
655*a3cefe7fSPierre Pronchery ops = ops != NULL ? ops : &default_render_ops;
656*a3cefe7fSPierre Pronchery return ops->render_len(list, true);
657*a3cefe7fSPierre Pronchery }
658*a3cefe7fSPierre Pronchery
659*a3cefe7fSPierre Pronchery /*
660*a3cefe7fSPierre Pronchery * !doc
661*a3cefe7fSPierre Pronchery *
662*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
663*a3cefe7fSPierre Pronchery *
664*a3cefe7fSPierre Pronchery * Renders a `fragment list` into a buffer.
665*a3cefe7fSPierre Pronchery *
666*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The `fragment list` being rendered.
667*a3cefe7fSPierre Pronchery * :param char* buf: The buffer to render the fragment list into.
668*a3cefe7fSPierre Pronchery * :param size_t buflen: The length of the buffer.
669*a3cefe7fSPierre Pronchery * :param bool escape: Whether or not to escape special shell characters (deprecated).
670*a3cefe7fSPierre Pronchery * :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
671*a3cefe7fSPierre Pronchery * :return: nothing
672*a3cefe7fSPierre Pronchery */
673*a3cefe7fSPierre Pronchery void
pkgconf_fragment_render_buf(const pkgconf_list_t * list,char * buf,size_t buflen,bool escape,const pkgconf_fragment_render_ops_t * ops)674*a3cefe7fSPierre Pronchery pkgconf_fragment_render_buf(const pkgconf_list_t *list, char *buf, size_t buflen, bool escape, const pkgconf_fragment_render_ops_t *ops)
675*a3cefe7fSPierre Pronchery {
676*a3cefe7fSPierre Pronchery (void) escape;
677*a3cefe7fSPierre Pronchery
678*a3cefe7fSPierre Pronchery ops = ops != NULL ? ops : &default_render_ops;
679*a3cefe7fSPierre Pronchery ops->render_buf(list, buf, buflen, true);
680*a3cefe7fSPierre Pronchery }
681*a3cefe7fSPierre Pronchery
682*a3cefe7fSPierre Pronchery /*
683*a3cefe7fSPierre Pronchery * !doc
684*a3cefe7fSPierre Pronchery *
685*a3cefe7fSPierre Pronchery * .. c:function:: char *pkgconf_fragment_render(const pkgconf_list_t *list)
686*a3cefe7fSPierre Pronchery *
687*a3cefe7fSPierre Pronchery * Allocate memory and render a `fragment list` into it.
688*a3cefe7fSPierre Pronchery *
689*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The `fragment list` being rendered.
690*a3cefe7fSPierre Pronchery * :param bool escape: Whether or not to escape special shell characters (deprecated).
691*a3cefe7fSPierre Pronchery * :param pkgconf_fragment_render_ops_t* ops: An optional ops structure to use for custom renderers, else ``NULL``.
692*a3cefe7fSPierre Pronchery * :return: An allocated string containing the rendered `fragment list`.
693*a3cefe7fSPierre Pronchery * :rtype: char *
694*a3cefe7fSPierre Pronchery */
695*a3cefe7fSPierre Pronchery char *
pkgconf_fragment_render(const pkgconf_list_t * list,bool escape,const pkgconf_fragment_render_ops_t * ops)696*a3cefe7fSPierre Pronchery pkgconf_fragment_render(const pkgconf_list_t *list, bool escape, const pkgconf_fragment_render_ops_t *ops)
697*a3cefe7fSPierre Pronchery {
698*a3cefe7fSPierre Pronchery (void) escape;
699*a3cefe7fSPierre Pronchery
700*a3cefe7fSPierre Pronchery size_t buflen = pkgconf_fragment_render_len(list, true, ops);
701*a3cefe7fSPierre Pronchery char *buf = calloc(1, buflen);
702*a3cefe7fSPierre Pronchery
703*a3cefe7fSPierre Pronchery pkgconf_fragment_render_buf(list, buf, buflen, true, ops);
704*a3cefe7fSPierre Pronchery
705*a3cefe7fSPierre Pronchery return buf;
706*a3cefe7fSPierre Pronchery }
707*a3cefe7fSPierre Pronchery
708*a3cefe7fSPierre Pronchery /*
709*a3cefe7fSPierre Pronchery * !doc
710*a3cefe7fSPierre Pronchery *
711*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node)
712*a3cefe7fSPierre Pronchery *
713*a3cefe7fSPierre Pronchery * Delete a `fragment node` from a `fragment list`.
714*a3cefe7fSPierre Pronchery *
715*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The `fragment list` to delete from.
716*a3cefe7fSPierre Pronchery * :param pkgconf_fragment_t* node: The `fragment node` to delete.
717*a3cefe7fSPierre Pronchery * :return: nothing
718*a3cefe7fSPierre Pronchery */
719*a3cefe7fSPierre Pronchery void
pkgconf_fragment_delete(pkgconf_list_t * list,pkgconf_fragment_t * node)720*a3cefe7fSPierre Pronchery pkgconf_fragment_delete(pkgconf_list_t *list, pkgconf_fragment_t *node)
721*a3cefe7fSPierre Pronchery {
722*a3cefe7fSPierre Pronchery pkgconf_node_delete(&node->iter, list);
723*a3cefe7fSPierre Pronchery
724*a3cefe7fSPierre Pronchery free(node->data);
725*a3cefe7fSPierre Pronchery free(node);
726*a3cefe7fSPierre Pronchery }
727*a3cefe7fSPierre Pronchery
728*a3cefe7fSPierre Pronchery /*
729*a3cefe7fSPierre Pronchery * !doc
730*a3cefe7fSPierre Pronchery *
731*a3cefe7fSPierre Pronchery * .. c:function:: void pkgconf_fragment_free(pkgconf_list_t *list)
732*a3cefe7fSPierre Pronchery *
733*a3cefe7fSPierre Pronchery * Delete an entire `fragment list`.
734*a3cefe7fSPierre Pronchery *
735*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The `fragment list` to delete.
736*a3cefe7fSPierre Pronchery * :return: nothing
737*a3cefe7fSPierre Pronchery */
738*a3cefe7fSPierre Pronchery void
pkgconf_fragment_free(pkgconf_list_t * list)739*a3cefe7fSPierre Pronchery pkgconf_fragment_free(pkgconf_list_t *list)
740*a3cefe7fSPierre Pronchery {
741*a3cefe7fSPierre Pronchery pkgconf_node_t *node, *next;
742*a3cefe7fSPierre Pronchery
743*a3cefe7fSPierre Pronchery PKGCONF_FOREACH_LIST_ENTRY_SAFE(list->head, next, node)
744*a3cefe7fSPierre Pronchery {
745*a3cefe7fSPierre Pronchery pkgconf_fragment_t *frag = node->data;
746*a3cefe7fSPierre Pronchery
747*a3cefe7fSPierre Pronchery pkgconf_fragment_free(&frag->children);
748*a3cefe7fSPierre Pronchery free(frag->data);
749*a3cefe7fSPierre Pronchery free(frag);
750*a3cefe7fSPierre Pronchery }
751*a3cefe7fSPierre Pronchery }
752*a3cefe7fSPierre Pronchery
753*a3cefe7fSPierre Pronchery /*
754*a3cefe7fSPierre Pronchery * !doc
755*a3cefe7fSPierre Pronchery *
756*a3cefe7fSPierre Pronchery * .. c:function:: bool pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value)
757*a3cefe7fSPierre Pronchery *
758*a3cefe7fSPierre Pronchery * Parse a string into a `fragment list`.
759*a3cefe7fSPierre Pronchery *
760*a3cefe7fSPierre Pronchery * :param pkgconf_client_t* client: The pkgconf client being accessed.
761*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* list: The `fragment list` to add the fragment entries to.
762*a3cefe7fSPierre Pronchery * :param pkgconf_list_t* vars: A list of variables to use for variable substitution.
763*a3cefe7fSPierre Pronchery * :param uint flags: Any parsing flags to be aware of.
764*a3cefe7fSPierre Pronchery * :param char* value: The string to parse into fragments.
765*a3cefe7fSPierre Pronchery * :return: true on success, false on parse error
766*a3cefe7fSPierre Pronchery */
767*a3cefe7fSPierre Pronchery bool
pkgconf_fragment_parse(const pkgconf_client_t * client,pkgconf_list_t * list,pkgconf_list_t * vars,const char * value,unsigned int flags)768*a3cefe7fSPierre Pronchery pkgconf_fragment_parse(const pkgconf_client_t *client, pkgconf_list_t *list, pkgconf_list_t *vars, const char *value, unsigned int flags)
769*a3cefe7fSPierre Pronchery {
770*a3cefe7fSPierre Pronchery int i, ret, argc;
771*a3cefe7fSPierre Pronchery char **argv;
772*a3cefe7fSPierre Pronchery char *repstr = pkgconf_tuple_parse(client, vars, value, flags);
773*a3cefe7fSPierre Pronchery
774*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "post-subst: [%s] -> [%s]", value, repstr);
775*a3cefe7fSPierre Pronchery
776*a3cefe7fSPierre Pronchery ret = pkgconf_argv_split(repstr, &argc, &argv);
777*a3cefe7fSPierre Pronchery if (ret < 0)
778*a3cefe7fSPierre Pronchery {
779*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "unable to parse fragment string [%s]", repstr);
780*a3cefe7fSPierre Pronchery free(repstr);
781*a3cefe7fSPierre Pronchery return false;
782*a3cefe7fSPierre Pronchery }
783*a3cefe7fSPierre Pronchery
784*a3cefe7fSPierre Pronchery for (i = 0; i < argc; i++)
785*a3cefe7fSPierre Pronchery {
786*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "processing %s", argv[i]);
787*a3cefe7fSPierre Pronchery
788*a3cefe7fSPierre Pronchery if (argv[i] == NULL)
789*a3cefe7fSPierre Pronchery {
790*a3cefe7fSPierre Pronchery PKGCONF_TRACE(client, "parsed fragment string is inconsistent: argc = %d while argv[%d] == NULL", argc, i);
791*a3cefe7fSPierre Pronchery pkgconf_argv_free(argv);
792*a3cefe7fSPierre Pronchery free(repstr);
793*a3cefe7fSPierre Pronchery return false;
794*a3cefe7fSPierre Pronchery }
795*a3cefe7fSPierre Pronchery
796*a3cefe7fSPierre Pronchery pkgconf_fragment_add(client, list, argv[i], flags);
797*a3cefe7fSPierre Pronchery }
798*a3cefe7fSPierre Pronchery
799*a3cefe7fSPierre Pronchery pkgconf_argv_free(argv);
800*a3cefe7fSPierre Pronchery free(repstr);
801*a3cefe7fSPierre Pronchery
802*a3cefe7fSPierre Pronchery return true;
803*a3cefe7fSPierre Pronchery }
804