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