xref: /freebsd/contrib/pkgconf/libpkgconf/bytecode.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery  * bytecode.c
3*592efe25SPierre Pronchery  * variable expansion bytecode evaluator
4*592efe25SPierre Pronchery  *
5*592efe25SPierre Pronchery  * SPDX-License-Identifier: pkgconf
6*592efe25SPierre Pronchery  *
7*592efe25SPierre Pronchery  * Copyright (c) 2026 pkgconf authors (see AUTHORS).
8*592efe25SPierre Pronchery  *
9*592efe25SPierre Pronchery  * Permission to use, copy, modify, and/or distribute this software for any
10*592efe25SPierre Pronchery  * purpose with or without fee is hereby granted, provided that the above
11*592efe25SPierre Pronchery  * copyright notice and this permission notice appear in all copies.
12*592efe25SPierre Pronchery  *
13*592efe25SPierre Pronchery  * This software is provided 'as is' and without any warranty, express or
14*592efe25SPierre Pronchery  * implied.  In no event shall the authors be liable for any damages arising
15*592efe25SPierre Pronchery  * from the use of this software.
16*592efe25SPierre Pronchery  */
17*592efe25SPierre Pronchery 
18*592efe25SPierre Pronchery #include <libpkgconf/stdinc.h>
19*592efe25SPierre Pronchery #include <libpkgconf/libpkgconf.h>
20*592efe25SPierre Pronchery 
21*592efe25SPierre Pronchery /*
22*592efe25SPierre Pronchery  * !doc
23*592efe25SPierre Pronchery  *
24*592efe25SPierre Pronchery  * libpkgconf `bytecode` module
25*592efe25SPierre Pronchery  * ============================
26*592efe25SPierre Pronchery  *
27*592efe25SPierre Pronchery  * The libpkgconf `bytecode` module contains the functions related to
28*592efe25SPierre Pronchery  * evaluating variable expansion bytecode.
29*592efe25SPierre Pronchery  */
30*592efe25SPierre Pronchery 
31*592efe25SPierre Pronchery #define PKGCONF_EVAL_MAX_OUTPUT (PKGCONF_BUFSIZE - 1)
32*592efe25SPierre Pronchery #define PKGCONF_EVAL_MAX_ITERATIONS (512)
33*592efe25SPierre Pronchery 
34*592efe25SPierre Pronchery static bool
pkgconf_bytecode_eval_append_slice(pkgconf_bytecode_eval_ctx_t * ctx,pkgconf_buffer_t * out,const char * p,size_t n)35*592efe25SPierre Pronchery pkgconf_bytecode_eval_append_slice(pkgconf_bytecode_eval_ctx_t *ctx, pkgconf_buffer_t *out, const char *p, size_t n)
36*592efe25SPierre Pronchery {
37*592efe25SPierre Pronchery 	size_t cur = pkgconf_buffer_len(out);
38*592efe25SPierre Pronchery 	if (cur >= PKGCONF_EVAL_MAX_OUTPUT)
39*592efe25SPierre Pronchery 		return false;
40*592efe25SPierre Pronchery 
41*592efe25SPierre Pronchery 	if (n > PKGCONF_EVAL_MAX_OUTPUT - cur)
42*592efe25SPierre Pronchery 	{
43*592efe25SPierre Pronchery 		pkgconf_warn(ctx->client, "warning: truncating very long variable to 64KB\n");
44*592efe25SPierre Pronchery 
45*592efe25SPierre Pronchery 		n = PKGCONF_EVAL_MAX_OUTPUT - cur;
46*592efe25SPierre Pronchery 		if (!pkgconf_buffer_append_slice(out, p, n))
47*592efe25SPierre Pronchery 			pkgconf_error(ctx->client, "pkgconf_bytecode_eval_append_slice: failed to append to slice");
48*592efe25SPierre Pronchery 
49*592efe25SPierre Pronchery 		return false;
50*592efe25SPierre Pronchery 	}
51*592efe25SPierre Pronchery 
52*592efe25SPierre Pronchery 	return pkgconf_buffer_append_slice(out, p, n);
53*592efe25SPierre Pronchery }
54*592efe25SPierre Pronchery 
55*592efe25SPierre Pronchery static bool
pkgconf_bytecode_eval_append(pkgconf_bytecode_eval_ctx_t * ctx,pkgconf_buffer_t * out,const char * s)56*592efe25SPierre Pronchery pkgconf_bytecode_eval_append(pkgconf_bytecode_eval_ctx_t *ctx, pkgconf_buffer_t *out, const char *s)
57*592efe25SPierre Pronchery {
58*592efe25SPierre Pronchery 	if (s == NULL || *s == '\0')
59*592efe25SPierre Pronchery 		return true;
60*592efe25SPierre Pronchery 
61*592efe25SPierre Pronchery 	return pkgconf_bytecode_eval_append_slice(ctx, out, s, strlen(s));
62*592efe25SPierre Pronchery }
63*592efe25SPierre Pronchery 
64*592efe25SPierre Pronchery static bool
65*592efe25SPierre Pronchery pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_bytecode_t *bc, pkgconf_buffer_t *out, bool *saw_sysroot);
66*592efe25SPierre Pronchery 
67*592efe25SPierre Pronchery static pkgconf_variable_t *
pkgconf_bytecode_eval_scan(const pkgconf_list_t * vars,const char * name,size_t nlen,unsigned int require_flags,unsigned int forbid_flags)68*592efe25SPierre Pronchery pkgconf_bytecode_eval_scan(const pkgconf_list_t *vars, const char *name, size_t nlen, unsigned int require_flags, unsigned int forbid_flags)
69*592efe25SPierre Pronchery {
70*592efe25SPierre Pronchery 	const pkgconf_node_t *node;
71*592efe25SPierre Pronchery 
72*592efe25SPierre Pronchery 	PKGCONF_FOREACH_LIST_ENTRY(vars->head, node)
73*592efe25SPierre Pronchery 	{
74*592efe25SPierre Pronchery 		pkgconf_variable_t *v = node->data;
75*592efe25SPierre Pronchery 
76*592efe25SPierre Pronchery 		if ((v->flags & require_flags) != require_flags)
77*592efe25SPierre Pronchery 			continue;
78*592efe25SPierre Pronchery 
79*592efe25SPierre Pronchery 		if ((v->flags & forbid_flags) != 0)
80*592efe25SPierre Pronchery 			continue;
81*592efe25SPierre Pronchery 
82*592efe25SPierre Pronchery 		if (pkgconf_str_eq_slice(v->key, name, nlen))
83*592efe25SPierre Pronchery 			return v;
84*592efe25SPierre Pronchery 	}
85*592efe25SPierre Pronchery 
86*592efe25SPierre Pronchery 	return NULL;
87*592efe25SPierre Pronchery }
88*592efe25SPierre Pronchery 
89*592efe25SPierre Pronchery pkgconf_variable_t *
pkgconf_bytecode_eval_lookup_var(pkgconf_bytecode_eval_ctx_t * ctx,const char * name,size_t nlen)90*592efe25SPierre Pronchery pkgconf_bytecode_eval_lookup_var(pkgconf_bytecode_eval_ctx_t *ctx, const char *name, size_t nlen)
91*592efe25SPierre Pronchery {
92*592efe25SPierre Pronchery 	pkgconf_variable_t *v;
93*592efe25SPierre Pronchery 
94*592efe25SPierre Pronchery 	if ((v = pkgconf_bytecode_eval_scan(&ctx->client->global_vars, name, nlen, PKGCONF_VARIABLEF_OVERRIDE, 0)) != NULL)
95*592efe25SPierre Pronchery 		return v;
96*592efe25SPierre Pronchery 
97*592efe25SPierre Pronchery 	if (ctx->vars != NULL && (v = pkgconf_bytecode_eval_scan(ctx->vars, name, nlen, 0, 0)) != NULL)
98*592efe25SPierre Pronchery 		return v;
99*592efe25SPierre Pronchery 
100*592efe25SPierre Pronchery 	if ((v = pkgconf_bytecode_eval_scan(&ctx->client->global_vars, name, nlen, 0, PKGCONF_VARIABLEF_OVERRIDE)) != NULL)
101*592efe25SPierre Pronchery 		return v;
102*592efe25SPierre Pronchery 
103*592efe25SPierre Pronchery 	return NULL;
104*592efe25SPierre Pronchery }
105*592efe25SPierre Pronchery 
106*592efe25SPierre Pronchery static bool
pkgconf_bytecode_eval_var(pkgconf_bytecode_eval_ctx_t * ctx,const char * name,size_t nlen,pkgconf_buffer_t * out,bool * saw_sysroot)107*592efe25SPierre Pronchery pkgconf_bytecode_eval_var(pkgconf_bytecode_eval_ctx_t *ctx, const char *name, size_t nlen, pkgconf_buffer_t *out, bool *saw_sysroot)
108*592efe25SPierre Pronchery {
109*592efe25SPierre Pronchery 	pkgconf_variable_t *v;
110*592efe25SPierre Pronchery 
111*592efe25SPierre Pronchery 	v = pkgconf_bytecode_eval_lookup_var(ctx, name, nlen);
112*592efe25SPierre Pronchery 	if (v == NULL)
113*592efe25SPierre Pronchery 		return true;
114*592efe25SPierre Pronchery 
115*592efe25SPierre Pronchery 	if (v->expanding)
116*592efe25SPierre Pronchery 		return false;
117*592efe25SPierre Pronchery 
118*592efe25SPierre Pronchery 	v->expanding = true;
119*592efe25SPierre Pronchery 
120*592efe25SPierre Pronchery 	bool inner_saw = false;
121*592efe25SPierre Pronchery 	bool ok = pkgconf_bytecode_eval_internal(ctx, &v->bc, out, &inner_saw);
122*592efe25SPierre Pronchery 
123*592efe25SPierre Pronchery 	v->expanding = false;
124*592efe25SPierre Pronchery 
125*592efe25SPierre Pronchery 	if (!ok)
126*592efe25SPierre Pronchery 		return false;
127*592efe25SPierre Pronchery 
128*592efe25SPierre Pronchery 	if (saw_sysroot != NULL)
129*592efe25SPierre Pronchery 		*saw_sysroot |= inner_saw;
130*592efe25SPierre Pronchery 
131*592efe25SPierre Pronchery 	return true;
132*592efe25SPierre Pronchery }
133*592efe25SPierre Pronchery 
134*592efe25SPierre Pronchery static bool
pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t * ctx,const pkgconf_bytecode_t * bc,pkgconf_buffer_t * out,bool * saw_sysroot)135*592efe25SPierre Pronchery pkgconf_bytecode_eval_internal(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_bytecode_t *bc, pkgconf_buffer_t *out, bool *saw_sysroot)
136*592efe25SPierre Pronchery {
137*592efe25SPierre Pronchery 	(void) ctx;
138*592efe25SPierre Pronchery 
139*592efe25SPierre Pronchery 	if (bc == NULL || out == NULL)
140*592efe25SPierre Pronchery 		return false;
141*592efe25SPierre Pronchery 
142*592efe25SPierre Pronchery 	const uint8_t *p = bc->base;
143*592efe25SPierre Pronchery 	const uint8_t *end = bc->base + bc->len;
144*592efe25SPierre Pronchery 
145*592efe25SPierre Pronchery 	if (++ctx->expansions > PKGCONF_EVAL_MAX_ITERATIONS)
146*592efe25SPierre Pronchery 	{
147*592efe25SPierre Pronchery 		pkgconf_warn(ctx->client,
148*592efe25SPierre Pronchery 			"warning: bytecode program exceeds iteration limit (" SIZE_FMT_SPECIFIER ")\n",
149*592efe25SPierre Pronchery 			ctx->expansions - 1);
150*592efe25SPierre Pronchery 		return false;
151*592efe25SPierre Pronchery 	}
152*592efe25SPierre Pronchery 
153*592efe25SPierre Pronchery 	while (p < end)
154*592efe25SPierre Pronchery 	{
155*592efe25SPierre Pronchery 		const pkgconf_bytecode_op_t *op =
156*592efe25SPierre Pronchery 			(const pkgconf_bytecode_op_t *)p;
157*592efe25SPierre Pronchery 
158*592efe25SPierre Pronchery 		if ((const uint8_t *)op + sizeof(*op) > end)
159*592efe25SPierre Pronchery 			return false;
160*592efe25SPierre Pronchery 
161*592efe25SPierre Pronchery 		if ((const uint8_t *)op + sizeof(*op) + op->size > end)
162*592efe25SPierre Pronchery 			return false;
163*592efe25SPierre Pronchery 
164*592efe25SPierre Pronchery 		switch (op->tag)
165*592efe25SPierre Pronchery 		{
166*592efe25SPierre Pronchery 		case PKGCONF_BYTECODE_OP_TEXT:
167*592efe25SPierre Pronchery 			/* this only fails due to truncation */
168*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_eval_append_slice(ctx, out, op->data, op->size))
169*592efe25SPierre Pronchery 				return false;
170*592efe25SPierre Pronchery 			break;
171*592efe25SPierre Pronchery 
172*592efe25SPierre Pronchery 		case PKGCONF_BYTECODE_OP_VAR:
173*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_eval_var(ctx, op->data, op->size, out, saw_sysroot))
174*592efe25SPierre Pronchery 				return false;
175*592efe25SPierre Pronchery 			break;
176*592efe25SPierre Pronchery 
177*592efe25SPierre Pronchery 		case PKGCONF_BYTECODE_OP_SYSROOT:
178*592efe25SPierre Pronchery 			if (saw_sysroot != NULL)
179*592efe25SPierre Pronchery 				*saw_sysroot = true;
180*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_eval_append(ctx, out, pkgconf_buffer_str_or_empty(&ctx->sysroot)))
181*592efe25SPierre Pronchery 				return false;
182*592efe25SPierre Pronchery 			break;
183*592efe25SPierre Pronchery 
184*592efe25SPierre Pronchery 		default:
185*592efe25SPierre Pronchery 			/* reserved/unimplemented */
186*592efe25SPierre Pronchery 			return false;
187*592efe25SPierre Pronchery 		}
188*592efe25SPierre Pronchery 
189*592efe25SPierre Pronchery 		p = (const uint8_t *)pkgconf_bytecode_op_next(op);
190*592efe25SPierre Pronchery 	}
191*592efe25SPierre Pronchery 
192*592efe25SPierre Pronchery 	return true;
193*592efe25SPierre Pronchery }
194*592efe25SPierre Pronchery 
195*592efe25SPierre Pronchery static bool
pkgconf_bytecode_eval_ctx_init(pkgconf_bytecode_eval_ctx_t * ctx,const pkgconf_client_t * client,const pkgconf_list_t * vars)196*592efe25SPierre Pronchery pkgconf_bytecode_eval_ctx_init(pkgconf_bytecode_eval_ctx_t *ctx, const pkgconf_client_t *client, const pkgconf_list_t *vars)
197*592efe25SPierre Pronchery {
198*592efe25SPierre Pronchery 	memset(ctx, 0, sizeof(*ctx));
199*592efe25SPierre Pronchery 
200*592efe25SPierre Pronchery 	ctx->client = client;
201*592efe25SPierre Pronchery 	ctx->vars = vars;
202*592efe25SPierre Pronchery 
203*592efe25SPierre Pronchery 	const char *raw = pkgconf_client_get_sysroot_dir(client);
204*592efe25SPierre Pronchery 
205*592efe25SPierre Pronchery 	/* disabled sysroot cases */
206*592efe25SPierre Pronchery 	if (raw == NULL || *raw == '\0')
207*592efe25SPierre Pronchery 		return true;
208*592efe25SPierre Pronchery 
209*592efe25SPierre Pronchery 	if (raw[0] == '.' && raw[1] == '\0')
210*592efe25SPierre Pronchery 		return true;
211*592efe25SPierre Pronchery 
212*592efe25SPierre Pronchery 	if (raw[0] == '/' && raw[1] == '\0')
213*592efe25SPierre Pronchery 		return true;
214*592efe25SPierre Pronchery 
215*592efe25SPierre Pronchery 	if (!pkgconf_buffer_append(&ctx->sysroot, raw))
216*592efe25SPierre Pronchery 		return false;
217*592efe25SPierre Pronchery 
218*592efe25SPierre Pronchery 	while (pkgconf_buffer_len(&ctx->sysroot) > 1 && ctx->sysroot.end[-1] == '/')
219*592efe25SPierre Pronchery 	{
220*592efe25SPierre Pronchery 		if (!pkgconf_buffer_trim_byte(&ctx->sysroot))
221*592efe25SPierre Pronchery 			return false;
222*592efe25SPierre Pronchery 	}
223*592efe25SPierre Pronchery 
224*592efe25SPierre Pronchery 	/* if normalization yields "/", disable by making buffer empty */
225*592efe25SPierre Pronchery 	if (pkgconf_buffer_len(&ctx->sysroot) == 1 && ctx->sysroot.base[0] == '/')
226*592efe25SPierre Pronchery 	{
227*592efe25SPierre Pronchery 		if (!pkgconf_buffer_trim_byte(&ctx->sysroot))
228*592efe25SPierre Pronchery 			return false;
229*592efe25SPierre Pronchery 	}
230*592efe25SPierre Pronchery 
231*592efe25SPierre Pronchery 	return true;
232*592efe25SPierre Pronchery }
233*592efe25SPierre Pronchery 
234*592efe25SPierre Pronchery bool
pkgconf_bytecode_eval(const pkgconf_client_t * client,const pkgconf_list_t * vars,const pkgconf_bytecode_t * bc,pkgconf_buffer_t * out,bool * saw_sysroot)235*592efe25SPierre Pronchery pkgconf_bytecode_eval(const pkgconf_client_t *client, const pkgconf_list_t *vars, const pkgconf_bytecode_t *bc, pkgconf_buffer_t *out, bool *saw_sysroot)
236*592efe25SPierre Pronchery {
237*592efe25SPierre Pronchery 	bool ret;
238*592efe25SPierre Pronchery 
239*592efe25SPierre Pronchery 	if (client == NULL || bc == NULL || out == NULL)
240*592efe25SPierre Pronchery 		return false;
241*592efe25SPierre Pronchery 
242*592efe25SPierre Pronchery 	pkgconf_bytecode_eval_ctx_t ctx;
243*592efe25SPierre Pronchery 	if (!pkgconf_bytecode_eval_ctx_init(&ctx, client, vars))
244*592efe25SPierre Pronchery 		return false;
245*592efe25SPierre Pronchery 
246*592efe25SPierre Pronchery 	if (saw_sysroot != NULL)
247*592efe25SPierre Pronchery 		*saw_sysroot = false;
248*592efe25SPierre Pronchery 
249*592efe25SPierre Pronchery 	ret = pkgconf_bytecode_eval_internal(&ctx, bc, out, saw_sysroot);
250*592efe25SPierre Pronchery 
251*592efe25SPierre Pronchery 	pkgconf_buffer_finalize(&ctx.sysroot);
252*592efe25SPierre Pronchery 
253*592efe25SPierre Pronchery 	return ret;
254*592efe25SPierre Pronchery }
255*592efe25SPierre Pronchery 
256*592efe25SPierre Pronchery bool
pkgconf_bytecode_emit(pkgconf_buffer_t * buf,enum pkgconf_bytecode_op tag,const void * data,uint32_t size)257*592efe25SPierre Pronchery pkgconf_bytecode_emit(pkgconf_buffer_t *buf, enum pkgconf_bytecode_op tag, const void *data, uint32_t size)
258*592efe25SPierre Pronchery {
259*592efe25SPierre Pronchery 	pkgconf_bytecode_op_t op = {
260*592efe25SPierre Pronchery 		.tag = tag,
261*592efe25SPierre Pronchery 		.size = size,
262*592efe25SPierre Pronchery 	};
263*592efe25SPierre Pronchery 
264*592efe25SPierre Pronchery 	if (!pkgconf_buffer_append_slice(buf, (const char *) &op, sizeof(op)))
265*592efe25SPierre Pronchery 		return false;
266*592efe25SPierre Pronchery 
267*592efe25SPierre Pronchery 	if (size != 0)
268*592efe25SPierre Pronchery 	{
269*592efe25SPierre Pronchery 		if (!pkgconf_buffer_append_slice(buf, (const char *) data, (size_t) size))
270*592efe25SPierre Pronchery 			return false;
271*592efe25SPierre Pronchery 	}
272*592efe25SPierre Pronchery 
273*592efe25SPierre Pronchery 	return true;
274*592efe25SPierre Pronchery }
275*592efe25SPierre Pronchery 
276*592efe25SPierre Pronchery bool
pkgconf_bytecode_emit_text(pkgconf_buffer_t * buf,const char * p,size_t n)277*592efe25SPierre Pronchery pkgconf_bytecode_emit_text(pkgconf_buffer_t *buf, const char *p, size_t n)
278*592efe25SPierre Pronchery {
279*592efe25SPierre Pronchery 	if (p == NULL || n == 0)
280*592efe25SPierre Pronchery 		return true;
281*592efe25SPierre Pronchery 
282*592efe25SPierre Pronchery 	return pkgconf_bytecode_emit(buf, PKGCONF_BYTECODE_OP_TEXT, p, (uint32_t) n);
283*592efe25SPierre Pronchery }
284*592efe25SPierre Pronchery 
285*592efe25SPierre Pronchery bool
pkgconf_bytecode_emit_var(pkgconf_buffer_t * buf,const char * name,size_t nlen)286*592efe25SPierre Pronchery pkgconf_bytecode_emit_var(pkgconf_buffer_t *buf, const char *name, size_t nlen)
287*592efe25SPierre Pronchery {
288*592efe25SPierre Pronchery 	if (name == NULL || nlen == 0)
289*592efe25SPierre Pronchery 		return true;
290*592efe25SPierre Pronchery 
291*592efe25SPierre Pronchery 	return pkgconf_bytecode_emit(buf, PKGCONF_BYTECODE_OP_VAR, name, (uint32_t) nlen);
292*592efe25SPierre Pronchery }
293*592efe25SPierre Pronchery 
294*592efe25SPierre Pronchery bool
pkgconf_bytecode_emit_sysroot(pkgconf_buffer_t * buf)295*592efe25SPierre Pronchery pkgconf_bytecode_emit_sysroot(pkgconf_buffer_t *buf)
296*592efe25SPierre Pronchery {
297*592efe25SPierre Pronchery 	return pkgconf_bytecode_emit(buf, PKGCONF_BYTECODE_OP_SYSROOT, NULL, 0);
298*592efe25SPierre Pronchery }
299*592efe25SPierre Pronchery 
300*592efe25SPierre Pronchery void
pkgconf_bytecode_from_buffer(pkgconf_bytecode_t * bc,const pkgconf_buffer_t * buf)301*592efe25SPierre Pronchery pkgconf_bytecode_from_buffer(pkgconf_bytecode_t *bc, const pkgconf_buffer_t *buf)
302*592efe25SPierre Pronchery {
303*592efe25SPierre Pronchery 	bc->base = (const uint8_t *)buf->base;
304*592efe25SPierre Pronchery 	bc->len = (size_t)(buf->end - buf->base);
305*592efe25SPierre Pronchery }
306*592efe25SPierre Pronchery 
307*592efe25SPierre Pronchery bool
pkgconf_bytecode_compile(pkgconf_buffer_t * out,const char * value)308*592efe25SPierre Pronchery pkgconf_bytecode_compile(pkgconf_buffer_t *out, const char *value)
309*592efe25SPierre Pronchery {
310*592efe25SPierre Pronchery 	const char *p, *text_start;
311*592efe25SPierre Pronchery 
312*592efe25SPierre Pronchery 	if (out == NULL || value == NULL)
313*592efe25SPierre Pronchery 		return false;
314*592efe25SPierre Pronchery 
315*592efe25SPierre Pronchery 	p = value;
316*592efe25SPierre Pronchery 	text_start = value;
317*592efe25SPierre Pronchery 
318*592efe25SPierre Pronchery 	for (; *p != '\0'; p++)
319*592efe25SPierre Pronchery 	{
320*592efe25SPierre Pronchery 		const char *name, *q;
321*592efe25SPierre Pronchery 
322*592efe25SPierre Pronchery 		if (*p != '$')
323*592efe25SPierre Pronchery 			continue;
324*592efe25SPierre Pronchery 
325*592efe25SPierre Pronchery 		/* $$ escapes to a literal $ */
326*592efe25SPierre Pronchery 		if (p[1] == '$')
327*592efe25SPierre Pronchery 		{
328*592efe25SPierre Pronchery 			if (p > text_start)
329*592efe25SPierre Pronchery 			{
330*592efe25SPierre Pronchery 				if (!pkgconf_bytecode_emit_text(out, text_start, (size_t)(p - text_start)))
331*592efe25SPierre Pronchery 					return false;
332*592efe25SPierre Pronchery 			}
333*592efe25SPierre Pronchery 
334*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_emit_text(out, "$", 1))
335*592efe25SPierre Pronchery 				return false;
336*592efe25SPierre Pronchery 
337*592efe25SPierre Pronchery 			p++;
338*592efe25SPierre Pronchery 			text_start = p + 1;
339*592efe25SPierre Pronchery 			continue;
340*592efe25SPierre Pronchery 		}
341*592efe25SPierre Pronchery 
342*592efe25SPierre Pronchery 		if (p[1] != '{')
343*592efe25SPierre Pronchery 			continue;
344*592efe25SPierre Pronchery 
345*592efe25SPierre Pronchery 		if (p > text_start)
346*592efe25SPierre Pronchery 		{
347*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_emit_text(out, text_start, (size_t)(p - text_start)))
348*592efe25SPierre Pronchery 				return false;
349*592efe25SPierre Pronchery 		}
350*592efe25SPierre Pronchery 
351*592efe25SPierre Pronchery 		name = p + 2;
352*592efe25SPierre Pronchery 		q = name;
353*592efe25SPierre Pronchery 
354*592efe25SPierre Pronchery 		for (; *q != '\0' && *q != '}'; q++)
355*592efe25SPierre Pronchery 			;
356*592efe25SPierre Pronchery 
357*592efe25SPierre Pronchery 		/* make sure a variable expansion ends with } */
358*592efe25SPierre Pronchery 		if (*q != '}')
359*592efe25SPierre Pronchery 		{
360*592efe25SPierre Pronchery 			text_start = p;
361*592efe25SPierre Pronchery 			continue;
362*592efe25SPierre Pronchery 		}
363*592efe25SPierre Pronchery 
364*592efe25SPierre Pronchery 		/* if this is not a valid variable, emit it as text */
365*592efe25SPierre Pronchery 		size_t nlen = (size_t)(q - name);
366*592efe25SPierre Pronchery 		if (nlen == 0 || nlen >= PKGCONF_ITEM_SIZE)
367*592efe25SPierre Pronchery 		{
368*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_emit_text(out, p, (size_t)((q + 1) - p)))
369*592efe25SPierre Pronchery 				return false;
370*592efe25SPierre Pronchery 
371*592efe25SPierre Pronchery 			p = q;
372*592efe25SPierre Pronchery 			text_start = p + 1;
373*592efe25SPierre Pronchery 			continue;
374*592efe25SPierre Pronchery 		}
375*592efe25SPierre Pronchery 
376*592efe25SPierre Pronchery 		/* we need to special-case ${pc_sysrootdir} and emit OP_SYSROOT instead... */
377*592efe25SPierre Pronchery 		if (nlen == strlen("pc_sysrootdir") && !memcmp(name, "pc_sysrootdir", nlen))
378*592efe25SPierre Pronchery 		{
379*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_emit_sysroot(out))
380*592efe25SPierre Pronchery 				return false;
381*592efe25SPierre Pronchery 		}
382*592efe25SPierre Pronchery 		else
383*592efe25SPierre Pronchery 		{
384*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_emit_var(out, name, nlen))
385*592efe25SPierre Pronchery 				return false;
386*592efe25SPierre Pronchery 		}
387*592efe25SPierre Pronchery 
388*592efe25SPierre Pronchery 		p = q;
389*592efe25SPierre Pronchery 		text_start = p + 1;
390*592efe25SPierre Pronchery 	}
391*592efe25SPierre Pronchery 
392*592efe25SPierre Pronchery 	if (p > text_start)
393*592efe25SPierre Pronchery 	{
394*592efe25SPierre Pronchery 		if (!pkgconf_bytecode_emit_text(out, text_start, (size_t)(p - text_start)))
395*592efe25SPierre Pronchery 			return false;
396*592efe25SPierre Pronchery 	}
397*592efe25SPierre Pronchery 
398*592efe25SPierre Pronchery 	return true;
399*592efe25SPierre Pronchery }
400*592efe25SPierre Pronchery 
401*592efe25SPierre Pronchery bool
pkgconf_bytecode_eval_str_to_buf(const pkgconf_client_t * client,const pkgconf_list_t * vars,const char * input,bool * saw_sysroot,pkgconf_buffer_t * out)402*592efe25SPierre Pronchery pkgconf_bytecode_eval_str_to_buf(const pkgconf_client_t *client, const pkgconf_list_t *vars, const char *input, bool *saw_sysroot, pkgconf_buffer_t *out)
403*592efe25SPierre Pronchery {
404*592efe25SPierre Pronchery 	pkgconf_buffer_t bcbuf = PKGCONF_BUFFER_INITIALIZER;
405*592efe25SPierre Pronchery 	pkgconf_bytecode_t bc;
406*592efe25SPierre Pronchery 	bool ret = false;
407*592efe25SPierre Pronchery 
408*592efe25SPierre Pronchery 	if (!pkgconf_bytecode_compile(&bcbuf, input))
409*592efe25SPierre Pronchery 	{
410*592efe25SPierre Pronchery 		pkgconf_buffer_finalize(&bcbuf);
411*592efe25SPierre Pronchery 		return false;
412*592efe25SPierre Pronchery 	}
413*592efe25SPierre Pronchery 
414*592efe25SPierre Pronchery 	pkgconf_bytecode_from_buffer(&bc, &bcbuf);
415*592efe25SPierre Pronchery 
416*592efe25SPierre Pronchery 	ret = pkgconf_bytecode_eval(client, vars, &bc, out, saw_sysroot);
417*592efe25SPierre Pronchery 
418*592efe25SPierre Pronchery 	pkgconf_buffer_finalize(&bcbuf);
419*592efe25SPierre Pronchery 
420*592efe25SPierre Pronchery 	return ret;
421*592efe25SPierre Pronchery }
422*592efe25SPierre Pronchery 
423*592efe25SPierre Pronchery char *
pkgconf_bytecode_eval_str(const pkgconf_client_t * client,const pkgconf_list_t * vars,const char * input,bool * saw_sysroot)424*592efe25SPierre Pronchery pkgconf_bytecode_eval_str(const pkgconf_client_t *client, const pkgconf_list_t *vars, const char *input, bool *saw_sysroot)
425*592efe25SPierre Pronchery {
426*592efe25SPierre Pronchery 	pkgconf_buffer_t out = PKGCONF_BUFFER_INITIALIZER;
427*592efe25SPierre Pronchery 
428*592efe25SPierre Pronchery 	if (!pkgconf_bytecode_eval_str_to_buf(client, vars, input, saw_sysroot, &out))
429*592efe25SPierre Pronchery 	{
430*592efe25SPierre Pronchery 		if (pkgconf_buffer_len(&out) > 0)
431*592efe25SPierre Pronchery 			return pkgconf_buffer_freeze(&out);
432*592efe25SPierre Pronchery 
433*592efe25SPierre Pronchery 		pkgconf_buffer_finalize(&out);
434*592efe25SPierre Pronchery 		return NULL;
435*592efe25SPierre Pronchery 	}
436*592efe25SPierre Pronchery 
437*592efe25SPierre Pronchery 	if (pkgconf_buffer_len(&out) == 0)
438*592efe25SPierre Pronchery 	{
439*592efe25SPierre Pronchery 		pkgconf_buffer_finalize(&out);
440*592efe25SPierre Pronchery 		return strdup("");
441*592efe25SPierre Pronchery 	}
442*592efe25SPierre Pronchery 
443*592efe25SPierre Pronchery 	return pkgconf_buffer_freeze(&out);
444*592efe25SPierre Pronchery }
445*592efe25SPierre Pronchery 
446*592efe25SPierre Pronchery bool
pkgconf_bytecode_references_var(const pkgconf_buffer_t * buf,const char * key)447*592efe25SPierre Pronchery pkgconf_bytecode_references_var(const pkgconf_buffer_t *buf, const char *key)
448*592efe25SPierre Pronchery {
449*592efe25SPierre Pronchery 	const uint8_t *p, *end;
450*592efe25SPierre Pronchery 	size_t klen;
451*592efe25SPierre Pronchery 
452*592efe25SPierre Pronchery 	if (buf == NULL || key == NULL)
453*592efe25SPierre Pronchery 		return false;
454*592efe25SPierre Pronchery 
455*592efe25SPierre Pronchery 	klen = strlen(key);
456*592efe25SPierre Pronchery 	p = (uint8_t *) buf->base;
457*592efe25SPierre Pronchery 	end = (uint8_t *) buf->end;
458*592efe25SPierre Pronchery 
459*592efe25SPierre Pronchery 	while (p < end)
460*592efe25SPierre Pronchery 	{
461*592efe25SPierre Pronchery 		const pkgconf_bytecode_op_t *op = (const pkgconf_bytecode_op_t *)p;
462*592efe25SPierre Pronchery 
463*592efe25SPierre Pronchery 		if (p + sizeof(*op) > end)
464*592efe25SPierre Pronchery 			return false;
465*592efe25SPierre Pronchery 
466*592efe25SPierre Pronchery 		if (p + sizeof(*op) + op->size > end)
467*592efe25SPierre Pronchery 			return false;
468*592efe25SPierre Pronchery 
469*592efe25SPierre Pronchery 		if (op->tag == PKGCONF_BYTECODE_OP_VAR)
470*592efe25SPierre Pronchery 		{
471*592efe25SPierre Pronchery 			if (op->size == (uint32_t) klen && memcmp(op->data, key, klen) == 0)
472*592efe25SPierre Pronchery 				return true;
473*592efe25SPierre Pronchery 		}
474*592efe25SPierre Pronchery 
475*592efe25SPierre Pronchery 		p += sizeof(*op) + op->size;
476*592efe25SPierre Pronchery 	}
477*592efe25SPierre Pronchery 
478*592efe25SPierre Pronchery 	return false;
479*592efe25SPierre Pronchery }
480*592efe25SPierre Pronchery 
481*592efe25SPierre Pronchery static bool
pkgconf_bytecode_op_is_selfref(const pkgconf_bytecode_op_t * op,const char * key)482*592efe25SPierre Pronchery pkgconf_bytecode_op_is_selfref(const pkgconf_bytecode_op_t *op, const char *key)
483*592efe25SPierre Pronchery {
484*592efe25SPierre Pronchery 	const size_t klen = strlen(key);
485*592efe25SPierre Pronchery 
486*592efe25SPierre Pronchery 	if (op->tag != PKGCONF_BYTECODE_OP_VAR)
487*592efe25SPierre Pronchery 		return false;
488*592efe25SPierre Pronchery 
489*592efe25SPierre Pronchery 	if (op->size != (uint32_t) klen)
490*592efe25SPierre Pronchery 		return false;
491*592efe25SPierre Pronchery 
492*592efe25SPierre Pronchery 	return memcmp(op->data, key, klen) == 0;
493*592efe25SPierre Pronchery }
494*592efe25SPierre Pronchery 
495*592efe25SPierre Pronchery static bool
pkgconf_bytecode_append_stream(pkgconf_buffer_t * dst,const pkgconf_buffer_t * bcbuf)496*592efe25SPierre Pronchery pkgconf_bytecode_append_stream(pkgconf_buffer_t *dst, const pkgconf_buffer_t *bcbuf)
497*592efe25SPierre Pronchery {
498*592efe25SPierre Pronchery 	if (dst == NULL || bcbuf == NULL || pkgconf_buffer_str(bcbuf) == NULL)
499*592efe25SPierre Pronchery 		return true;
500*592efe25SPierre Pronchery 
501*592efe25SPierre Pronchery 	return pkgconf_buffer_append_slice(dst, pkgconf_buffer_str(bcbuf), pkgconf_buffer_len(bcbuf));
502*592efe25SPierre Pronchery }
503*592efe25SPierre Pronchery 
504*592efe25SPierre Pronchery bool
pkgconf_bytecode_rewrite_selfrefs(pkgconf_buffer_t * out,const pkgconf_buffer_t * rhs,const char * key,const pkgconf_buffer_t * prev)505*592efe25SPierre Pronchery pkgconf_bytecode_rewrite_selfrefs(pkgconf_buffer_t *out, const pkgconf_buffer_t *rhs, const char *key, const pkgconf_buffer_t *prev)
506*592efe25SPierre Pronchery {
507*592efe25SPierre Pronchery 	const uint8_t *p = (uint8_t *) rhs->base;
508*592efe25SPierre Pronchery 	const uint8_t *end = (uint8_t *) rhs->end;
509*592efe25SPierre Pronchery 
510*592efe25SPierre Pronchery 	while (p < end)
511*592efe25SPierre Pronchery 	{
512*592efe25SPierre Pronchery 		const pkgconf_bytecode_op_t *op = (const pkgconf_bytecode_op_t *)p;
513*592efe25SPierre Pronchery 
514*592efe25SPierre Pronchery 		if (p + sizeof(*op) > end)
515*592efe25SPierre Pronchery 			return false;
516*592efe25SPierre Pronchery 
517*592efe25SPierre Pronchery 		if (p + sizeof(*op) + op->size > end)
518*592efe25SPierre Pronchery 			return false;
519*592efe25SPierre Pronchery 
520*592efe25SPierre Pronchery 		if (pkgconf_bytecode_op_is_selfref(op, key))
521*592efe25SPierre Pronchery 		{
522*592efe25SPierre Pronchery 			if (!pkgconf_bytecode_append_stream(out, prev))
523*592efe25SPierre Pronchery 				return false;
524*592efe25SPierre Pronchery 		}
525*592efe25SPierre Pronchery 		else
526*592efe25SPierre Pronchery 		{
527*592efe25SPierre Pronchery 			if (!pkgconf_buffer_append_slice(out, (const char *) op, sizeof(*op) + op->size))
528*592efe25SPierre Pronchery 				return false;
529*592efe25SPierre Pronchery 		}
530*592efe25SPierre Pronchery 
531*592efe25SPierre Pronchery 		p += sizeof(*op) + op->size;
532*592efe25SPierre Pronchery 	}
533*592efe25SPierre Pronchery 
534*592efe25SPierre Pronchery 	return true;
535*592efe25SPierre Pronchery }
536