The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
foreach.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 5872b407ede65222c670772bb8fe030f3b52ede1 $
19 *
20 * @file unlang/foreach.c
21 * @brief Unlang "foreach" keyword evaluation.
22 *
23 * @copyright 2006-2019 The FreeRADIUS server project
24 */
25RCSID("$Id: 5872b407ede65222c670772bb8fe030f3b52ede1 $")
26
27#include <freeradius-devel/server/tmpl_dcursor.h>
28#include <freeradius-devel/server/rcode.h>
29#include <freeradius-devel/unlang/action.h>
30#include <freeradius-devel/unlang/unlang_priv.h>
31#include <freeradius-devel/unlang/xlat_func.h>
32
33#include "foreach_priv.h"
34#include "return_priv.h"
35#include "xlat_priv.h"
36
37#define BUFFER_SIZE (256)
38
39/** State of a foreach loop
40 *
41 */
42typedef struct {
43 request_t *request; //!< The current request.
44 fr_dcursor_t cursor; //!< Used to track our place in the list
45 fr_pair_t *key; //!< local variable which contains the key
46 fr_pair_t *value; //!< local variable which contains the value
47 tmpl_t const *vpt; //!< pointer to the vpt
48
49 uint32_t index; //!< for xlat results
50 char *buffer; //!< for key values
51
52 unlang_result_t exp_result; //!< for xlat expansion
53 fr_value_box_list_t list; //!< value box list for looping over xlats
54
55 tmpl_dcursor_ctx_t cc; //!< tmpl cursor state
56
57#ifndef NDEBUG
58 int indent; //!< for catching indentation issues
59#endif
61
62/*
63 * Brute-force things instead of doing it the "right" way.
64 *
65 * We would ideally like to have the local variable be a ref to the current vp from the cursor. However,
66 * that isn't (yet) supported. We do have #FR_TYPE_PAIR_CURSOR, but there is no way to save the cursor,
67 * or address it. See also xlat_expr.c for notes on using '$$' to refer to a cursor. Maybe we need a
68 * new magic "list", which is called "cursor", or "self"? That way we can also address parent cursors?
69 *
70 * In order to support that, we would have to update a lot of things:
71 *
72 * - the foreach code has not just create a local attribute, but mark up that attribute as it's really a cursor".
73 * - maybe we also need to put the cursor into its own stack frame? Or have it as a common field
74 * in every frame?
75 * - the tmpl code has to be updated so that when you reference a "cursor attribute", it finds the cursor,
76 * and edits the pair associated with the cursor
77 * - update tmpl_eval_pair(), because that's what's used in the xlat code. That gets us all
78 * references to the _source_ VP.
79 * - we also have to update the edit.c code, which calls tmpl_dcursor_init() to get pairs from
80 * a tmpl_t of type ATTR.
81 * - for LHS assignment, the edit code has to be updated: apply_edits_to_leaf() and apply_edits_to_list()
82 * which calls fr_edit_list_apply_pair_assignment() to do the actual work. But we could likely just
83 * check current->lhs.vp, and dereference that to get the underlying thing.
84 *
85 * What we ACTUALLY do instead is in the compiler when we call define_local_variable(), we clone the "da"
86 * hierarchy via fr_dict_attr_acopy_local(). That function which should go away when we add refs.
87 *
88 * Then this horrific function copies the pairs by number, which re-parents them to the correct
89 * destination da. It's brute-force and expensive, but it's easy. And for now, it's less work than
90 * re-doing substantial parts of the server core and utility libraries.
91 */
92static int unlang_foreach_pair_copy(fr_pair_t *to, fr_pair_t *from, fr_dict_attr_t const *from_parent)
93{
94 fr_assert(fr_type_is_structural(to->vp_type));
95 fr_assert(fr_type_is_structural(from->vp_type));
96
97 fr_pair_list_foreach(&from->vp_group, vp) {
98 fr_pair_t *child;
99
100 /*
101 * We only copy children of the parent TLV, but we can copy internal attributes, as they
102 * can exist anywhere.
103 */
104 if (vp->da->parent != from_parent) {
105 if (vp->da->flags.internal) {
106 child = fr_pair_copy(to, vp);
107 if (child) fr_pair_append(&to->vp_group, child);
108 }
109 continue;
110 }
111
112 child = fr_pair_afrom_child_num(to, to->da, vp->da->attr);
113 if (!child) continue;
114
115 fr_pair_append(&to->vp_group, child);
116
117 if (fr_type_is_leaf(child->vp_type)) {
118 if (fr_value_box_copy(child, &child->data, &vp->data) < 0) return -1;
119 continue;
120 }
121
123
124 if (unlang_foreach_pair_copy(child, vp, vp->da) < 0) return -1;
125 }
126
127 return 0;
128}
129
130/** Ensure request data is pulled out of the request if the frame is popped
131 *
132 */
134{
135 request_t *request = state->request;
136 fr_pair_t *vp;
137
138 fr_assert(state->value);
139
140 if (tmpl_is_xlat(state->vpt)) return 0;
141
142 tmpl_dcursor_clear(&state->cc);
143
144 /*
145 * Now that we're done, the leaf entries can be changed again.
146 */
147 vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
148 if (!vp) {
149 tmpl_dcursor_clear(&state->cc);
150 return 0;
151 }
152 do {
153 vp->vp_edit = false;
154 } while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
155 tmpl_dcursor_clear(&state->cc);
156
157 return 0;
158}
159
161{
162 fr_value_box_t box;
163
164 if (!state->key) return 0;
165
166 fr_value_box_clear_value(&state->key->data);
167
168 fr_value_box(&box, state->index, false);
169
170 if (fr_value_box_cast(state->key, &state->key->data, state->key->vp_type, state->key->da, &box) < 0) {
171 RDEBUG("Failed casting 'foreach' key variable '%s' from %u", state->key->da->name, state->index);
172 return -1;
173 }
174
175 return 0;
176}
177
178
180{
181 unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
182 fr_value_box_t *box;
183
184next:
185 state->index++;
186
187 box = fr_dcursor_next(&state->cursor);
188 if (!box) return UNLANG_ACTION_EXECUTE_NEXT; /* Don't change the section rcode */
189
190 if (unlang_foreach_xlat_key_update(request, state) < 0) goto next;
191
192 fr_value_box_clear_value(&state->value->data);
193 if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, box) < 0) {
194 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pV", state->value->da->name, box);
195 goto next;
196 }
197
198 repeatable_set(frame);
199
200 /*
201 * Push the child, and yield for a later return.
202 */
204}
205
206
208{
209 unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
210 fr_value_box_t *box;
211
212 if (!XLAT_RESULT_SUCCESS(&state->exp_result)) {
213 RDEBUG("Failed expanding 'foreach' list");
215 }
216
217 box = fr_dcursor_init(&state->cursor, fr_value_box_list_dlist_head(&state->list));
218 if (!box) {
219 done:
221 }
222
223 fr_value_box_clear_value(&state->value->data);
224
225next:
226 if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, box) < 0) {
227 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pV", state->value->da->name, box);
228 box = fr_dcursor_next(&state->cursor);
229 if (!box) goto done;
230
231 goto next;
232 }
233
235
236 /*
237 * Push the child, and yield for a later return.
238 */
240}
241
242
243/*
244 * Loop over an xlat expansion
245 */
248{
249 fr_value_box_list_init(&state->list);
250
251 if (unlang_xlat_push(state, &state->exp_result, &state->list, request, tmpl_xlat(state->vpt), false) < 0) {
252 REDEBUG("Failed starting expansion of %s", state->vpt->name);
254 }
255
256 if (unlang_foreach_xlat_key_update(request, state) < 0) {
258 }
259
261 repeatable_set(frame);
262
264}
265
267{
268 if (!state->key) return;
269
270 switch (state->key->vp_type) {
271 case FR_TYPE_UINT32:
272 state->key->vp_uint32++;
273 break;
274
275 case FR_TYPE_STRING:
276 fr_value_box_clear_value(&state->key->data);
277 if (tmpl_dcursor_print(&FR_SBUFF_IN(state->buffer, BUFFER_SIZE), &state->cc) > 0) {
278 fr_value_box_strdup(state->key, &state->key->data, NULL, state->buffer, false);
279 }
280 break;
281
282 default:
283 fr_assert(0);
284 break;
285
286 }
287}
288
290{
291 unlang_frame_state_foreach_t *state = talloc_get_type_abort(frame->state, unlang_frame_state_foreach_t);
292 fr_pair_t *vp;
293
294 vp = fr_dcursor_current(&state->cursor);
295 fr_assert(vp != NULL);
296
297 /*
298 * If we modified the value, copy it back to the original pair. Note that the copy does NOT
299 * check the "immutable" flag. That flag is for the people using unlang, not for the
300 * interpreter.
301 */
302 if (fr_type_is_leaf(vp->vp_type)) {
303 if (vp->vp_type == state->value->vp_type) {
305 (void) fr_value_box_copy(vp, &vp->data, &state->value->data);
306 } else {
307 /*
308 * @todo - this shouldn't happen?
309 */
310 }
311 } else {
313
314 /*
315 * @todo - copy the pairs back?
316 */
317 }
318
319next:
320 vp = fr_dcursor_next(&state->cursor);
321 if (!vp) {
322#ifndef NDEBUG
323 fr_assert(state->indent == request->log.indent.unlang);
324#endif
326 }
327
328 unlang_foreach_attr_key_update(request, state);
329
330 /*
331 * Copy the data.
332 */
333 if (vp->vp_type == FR_TYPE_GROUP) {
334 fr_assert(state->value->vp_type == FR_TYPE_GROUP);
335
336 fr_pair_list_free(&state->value->vp_group);
337
338 if (fr_pair_list_copy(state->value, &state->value->vp_group, &vp->vp_group) < 0) {
339 REDEBUG("Failed copying members of %s", state->value->da->name);
341 }
342
343 } else if (fr_type_is_structural(vp->vp_type)) {
344 if (state->value->vp_type != vp->vp_type) goto next;
345
346 fr_pair_list_free(&state->value->vp_group);
347
348 if (unlang_foreach_pair_copy(state->value, vp, vp->da) < 0) {
349 REDEBUG("Failed copying children of %s", state->value->da->name);
351 }
352
353 } else {
354 fr_value_box_clear_value(&state->value->data);
355 if (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, &vp->data) < 0) {
356 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pP", state->value->da->name, vp);
357 goto next;
358 }
359
360#ifndef NDEBUG
361 RDEBUG2("# looping with: %s = %pV", state->value->da->name, &vp->data);
362#endif
363 }
364
365 repeatable_set(frame);
366
367 /*
368 * Push the child, and yield for a later return.
369 */
371}
372
373/*
374 * Loop over an attribute
375 */
378{
379 fr_pair_t *vp;
380
381 /*
382 * No matching attributes, we can't do anything.
383 */
384 vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
385 if (!vp) {
386 tmpl_dcursor_clear(&state->cc);
388 }
389
390 /*
391 * Before we loop over the variables, ensure that the user can't pull the rug out from
392 * under us.
393 */
394 do {
395 if (vp->vp_edit) {
396 REDEBUG("Cannot do nested 'foreach' loops over the same attribute %pP", vp);
397 fail:
398 tmpl_dcursor_clear(&state->cc);
400 }
401
402 vp->vp_edit = true;
403 } while ((vp = fr_dcursor_next(&state->cursor)) != NULL);
404 tmpl_dcursor_clear(&state->cc);
405
406 vp = tmpl_dcursor_init(NULL, NULL, &state->cc, &state->cursor, request, state->vpt);
407 fr_assert(vp != NULL);
408
409next:
410 /*
411 * Update the key with the current path. Attribute indexes start at zero.
412 */
413 if (state->key && (state->key->vp_type == FR_TYPE_STRING)) unlang_foreach_attr_key_update(request, state);
414
415 if (vp->vp_type == FR_TYPE_GROUP) {
416 fr_assert(state->value->vp_type == FR_TYPE_GROUP);
417
418 if (fr_pair_list_copy(state->value, &state->value->vp_group, &vp->vp_group) < 0) {
419 REDEBUG("Failed copying members of %s", state->value->da->name);
420 goto fail;
421 }
422
423 } else if (fr_type_is_structural(vp->vp_type)) {
424 if (state->value->vp_type != vp->vp_type) {
425 vp = fr_dcursor_next(&state->cursor);
426 if (vp) goto next;
427
428 fr_assert(state->indent == request->log.indent.unlang);
430 }
431
432 if (unlang_foreach_pair_copy(state->value, vp, vp->da) < 0) {
433 REDEBUG("Failed copying children of %s", state->value->da->name);
434 goto fail;
435 }
436
437 } else {
438 fr_value_box_clear_value(&state->value->data);
439 while (vp && (fr_value_box_cast(state->value, &state->value->data, state->value->vp_type, state->value->da, &vp->data) < 0)) {
440 RDEBUG("Failed casting 'foreach' iteration variable '%s' from %pP", state->value->da->name, vp);
441 vp = fr_dcursor_next(&state->cursor);
442 }
443
444 /*
445 * Couldn't cast anything, the loop can't be run.
446 */
447 if (!vp) {
448 tmpl_dcursor_clear(&state->cc);
450 }
451 }
452
454
455 repeatable_set(frame);
456
457 /*
458 * Push the child, and go process it.
459 */
461}
462
463
465{
469
470 MEM(frame->state = state = talloc_zero(request->stack, unlang_frame_state_foreach_t));
471 talloc_set_destructor(state, _free_unlang_frame_state_foreach);
472
473 state->request = request;
474#ifndef NDEBUG
475 state->indent = request->log.indent.unlang;
476#endif
477
478 /*
479 * Get the value.
480 */
481 fr_assert(gext->value);
482
483 state->vpt = gext->vpt;
484
485 fr_assert(fr_pair_find_by_da(&request->local_pairs, NULL, gext->value) == NULL);
486
487 /*
488 * Create the local variable and populate its value.
489 */
490 if (fr_pair_append_by_da(request->local_ctx, &state->value, &request->local_pairs, gext->value) < 0) {
491 REDEBUG("Failed creating %s", gext->value->name);
493 }
494 fr_assert(state->value != NULL);
495
496 if (gext->key) {
497 fr_assert(fr_pair_find_by_da(&request->local_pairs, NULL, gext->key) == NULL);
498
499 if (fr_pair_append_by_da(request->local_ctx, &state->key, &request->local_pairs, gext->key) < 0) {
500 REDEBUG("Failed creating %s", gext->key->name);
502 }
503 fr_assert(state->key != NULL);
504 }
505
506 if (tmpl_is_attr(gext->vpt)) {
507 MEM(state->buffer = talloc_array(state, char, BUFFER_SIZE));
508 return unlang_foreach_attr_init(p_result, request, frame, state);
509 }
510
511 fr_assert(tmpl_is_xlat(gext->vpt));
512
513 return unlang_foreach_xlat_init(p_result, request, frame, state);
514}
515
517{
519 unlang_stack_t *stack = request->stack;
520 unsigned int break_depth;
521
522 RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
523
524 /*
525 * As we're unwinding intermediary frames we
526 * won't be taking their rcodes or priorities
527 * into account. We do however want to record
528 * the current section rcode.
529 */
530 *p_result = frame->section_result;
531
532 /*
533 * Stop at the next break point, or if we hit
534 * the a top frame.
535 */
536 ua = unwind_to_op_flag(&break_depth, request->stack, UNLANG_OP_FLAG_BREAK_POINT);
537 repeatable_clear(&stack->frame[break_depth]);
538 return ua;
539}
540
542{
543 unlang_stack_t *stack = request->stack;
544
545 RDEBUG2("%s", unlang_ops[frame->instruction->type].name);
546
548}
549
551{
553 &(unlang_op_t){
554 .name = "foreach",
555 .interpret = unlang_foreach,
557 });
558
560 &(unlang_op_t){
561 .name = "break",
562 .interpret = unlang_break,
563 });
564
566 &(unlang_op_t){
567 .name = "continue",
568 .interpret = unlang_continue,
569 });
570}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_PUSHED_CHILD
unlang_t pushed a new child onto the stack, execute it instead of continuing.
Definition action.h:39
@ UNLANG_ACTION_EXECUTE_NEXT
Execute the next unlang_t.
Definition action.h:38
#define RCSID(id)
Definition build.h:485
#define UNUSED
Definition build.h:317
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
Definition dcursor.h:290
#define fr_dcursor_init(_cursor, _head)
Initialise a cursor.
Definition dcursor.h:710
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
Definition dcursor.h:339
#define MEM(x)
Definition debug.h:36
static int unlang_foreach_pair_copy(fr_pair_t *to, fr_pair_t *from, fr_dict_attr_t const *from_parent)
Definition foreach.c:92
uint32_t index
for xlat results
Definition foreach.c:49
static void unlang_foreach_attr_key_update(UNUSED request_t *request, unlang_frame_state_foreach_t *state)
Definition foreach.c:266
char * buffer
for key values
Definition foreach.c:50
unlang_result_t exp_result
for xlat expansion
Definition foreach.c:52
static unlang_action_t unlang_foreach(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:464
fr_dcursor_t cursor
Used to track our place in the list.
Definition foreach.c:44
tmpl_t const * vpt
pointer to the vpt
Definition foreach.c:47
fr_pair_t * key
local variable which contains the key
Definition foreach.c:45
static unlang_action_t unlang_foreach_attr_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame, unlang_frame_state_foreach_t *state)
Definition foreach.c:376
static unlang_action_t unlang_foreach_xlat_expanded(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:207
fr_value_box_list_t list
value box list for looping over xlats
Definition foreach.c:53
#define BUFFER_SIZE
Definition foreach.c:37
static unlang_action_t unlang_foreach_xlat_init(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame, unlang_frame_state_foreach_t *state)
Definition foreach.c:246
fr_pair_t * value
local variable which contains the value
Definition foreach.c:46
tmpl_dcursor_ctx_t cc
tmpl cursor state
Definition foreach.c:55
int indent
for catching indentation issues
Definition foreach.c:58
request_t * request
The current request.
Definition foreach.c:43
static unlang_action_t unlang_foreach_xlat_next(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:179
static unlang_action_t unlang_continue(UNUSED unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:541
static unlang_action_t unlang_break(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:516
static unlang_action_t unlang_foreach_attr_next(unlang_result_t *p_result, request_t *request, unlang_stack_frame_t *frame)
Definition foreach.c:289
void unlang_foreach_init(void)
Definition foreach.c:550
static int unlang_foreach_xlat_key_update(request_t *request, unlang_frame_state_foreach_t *state)
Definition foreach.c:160
static int _free_unlang_frame_state_foreach(unlang_frame_state_foreach_t *state)
Ensure request data is pulled out of the request if the frame is popped.
Definition foreach.c:133
State of a foreach loop.
Definition foreach.c:42
static unlang_foreach_t * unlang_group_to_foreach(unlang_group_t *g)
Cast a group structure to the foreach keyword extension.
fr_dict_attr_t const * value
value variable in the foreach loop
fr_dict_attr_t const * key
key variable for the foreach loop
unlang_action_t unlang_interpret_push_children(unlang_result_t *p_result, request_t *request, rlm_rcode_t default_rcode, bool do_next_sibling)
Push the children of the current frame onto a new frame onto the stack.
Definition interpret.c:389
void unlang_register(int type, unlang_op_t *op)
Register an operation with the interpreter.
Definition base.c:63
unlang_op_t unlang_ops[UNLANG_TYPE_MAX]
Different operations the interpreter can execute.
Definition base.c:31
static char * stack[MAX_STACK]
Definition radmin.c:159
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_GROUP
A grouping of other attributes.
unsigned int uint32_t
int fr_pair_append_by_da(TALLOC_CTX *ctx, fr_pair_t **out, fr_pair_list_t *list, fr_dict_attr_t const *da)
Alloc a new fr_pair_t (and append)
Definition pair.c:1463
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition pair.c:2320
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:697
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
Definition pair.c:1342
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
Definition pair.c:493
fr_pair_t * fr_pair_afrom_child_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
Create a new valuepair.
Definition pair.c:375
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:81
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define RETURN_UNLANG_FAIL
Definition rcode.h:57
@ RLM_MODULE_NOT_SET
Error resolving rcode (should not be returned by modules).
Definition rcode.h:52
#define RETURN_UNLANG_NOOP
Definition rcode.h:63
Declarations for the "return" keyword, used to implement other keywords.
#define FR_SBUFF_IN(_start, _len_or_end)
#define tmpl_is_xlat(vpt)
Definition tmpl.h:210
#define tmpl_is_attr(vpt)
Definition tmpl.h:208
#define tmpl_xlat(_tmpl)
Definition tmpl.h:930
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
ssize_t tmpl_dcursor_print(fr_sbuff_t *out, tmpl_dcursor_ctx_t const *cc)
void tmpl_dcursor_clear(tmpl_dcursor_ctx_t *cc)
Clear any temporary state allocations.
#define tmpl_dcursor_init(_err, _ctx, _cc, _cursor, _request, _vpt)
Maintains state between cursor calls.
int unlang_xlat_push(TALLOC_CTX *ctx, unlang_result_t *p_result, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat, bool top_frame)
Push a pre-compiled xlat onto the stack for evaluation.
Definition xlat.c:282
#define XLAT_RESULT_SUCCESS(_p_result)
Definition xlat.h:503
unlang_result_t section_result
The aggregate result of executing all siblings in this section.
static unlang_action_t unwind_to_op_flag(unsigned int *depth_p, unlang_stack_t *stack, unlang_op_flag_t flag)
Mark the entire stack as cancelled.
#define UNLANG_NEXT_SIBLING
Definition unlang_priv.h:98
static void repeatable_clear(unlang_stack_frame_t *frame)
void * state
Stack frame specialisations.
static unlang_group_t * unlang_generic_to_group(unlang_t const *p)
@ UNLANG_TYPE_CONTINUE
Break statement (within a UNLANG_TYPE_FOREACH).
Definition unlang_priv.h:62
@ UNLANG_TYPE_BREAK
Break statement (within a UNLANG_TYPE_FOREACH or UNLANG_TYPE_CASE).
Definition unlang_priv.h:61
@ UNLANG_TYPE_FOREACH
Foreach section.
Definition unlang_priv.h:60
static void frame_repeat(unlang_stack_frame_t *frame, unlang_process_t process)
Mark the current stack frame up for repeat, and set a new process function.
unlang_t const * instruction
The unlang node we're evaluating.
char const * name
Name of the operation.
@ UNLANG_OP_FLAG_CONTINUE_POINT
Continue point.
@ UNLANG_OP_FLAG_DEBUG_BRACES
Print debug braces.
@ UNLANG_OP_FLAG_BREAK_POINT
Break point.
static void repeatable_set(unlang_stack_frame_t *frame)
unlang_process_t process
function to call for interpreting this stack frame
unlang_type_t type
The specialisation of this node.
Generic representation of a grouping.
An unlang operation.
Our interpreter stack, as distinct from the C stack.
An unlang stack associated with a request.
#define fr_pair_list_foreach(_list_head, _iter)
Iterate over the contents of a fr_pair_list_t.
Definition pair.h:261
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_type_is_structural(_x)
Definition types.h:388
#define fr_type_is_leaf(_x)
Definition types.h:389
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
Definition value.c:3574
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
Definition value.c:3962
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
Definition value.c:3899
int fr_value_box_strdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, bool tainted)
Copy a nul terminated string to a fr_value_box_t.
Definition value.c:4158
#define fr_value_box(_box, _var, _tainted)
Automagically fill in a box, determining the value type from the type of the C variable.
Definition value.h:894
String expansion ("translation").