}
#endif
-static unlang_t *compile_xlat_inline(unlang_t *parent,
- unlang_compile_t *unlang_ctx, CONF_PAIR const *cp)
+static unlang_t *compile_tmpl(unlang_t *parent,
+ unlang_compile_t *unlang_ctx, CONF_PAIR *cp)
{
unlang_t *c;
- unlang_xlat_inline_t *mx;
+ unlang_tmpl_t *ut;
+ ssize_t slen;
+ FR_TOKEN type;
+ char const *p = cf_pair_attr(cp);
+ size_t len;
+ vp_tmpl_t *vpt;
- mx = talloc_zero(parent, unlang_xlat_inline_t);
+ ut = talloc_zero(parent, unlang_tmpl_t);
- c = unlang_xlat_inline_to_generic(mx);
+ c = unlang_tmpl_to_generic(ut);
c->parent = parent;
c->next = NULL;
- c->name = "expand";
+ c->name = p;
c->debug_name = c->name;
- c->type = UNLANG_TYPE_XLAT_INLINE;
+ c->type = UNLANG_TYPE_TMPL;
+
+ if (*p == '`') {
+ type = T_BACK_QUOTED_STRING;
+ p++;
+ len = strlen(p);
+ if (!len || (p[len - 1] != '`')) {
+ talloc_free(ut);
+ cf_log_err(cp, "String is missing trailing quotation character");
+ return NULL;
+ }
+
+ p = talloc_bstrndup(ut, p, len - 1);
+ len--;
+
+ } else {
+ type = T_DOUBLE_QUOTED_STRING;
+ len = strlen(p);
+ }
(void) compile_action_defaults(c, unlang_ctx);
- mx->xlat_name = talloc_typed_strdup(mx, cf_pair_attr(cp));
- if (mx->xlat_name[0] == '%') {
- ssize_t slen;
+ slen = tmpl_afrom_str(ut, &vpt, p, len, type, unlang_ctx->rules, true);
+ if (slen <= 0) {
+ char *spaces, *text;
- slen = xlat_tokenize(mx, &mx->exp, mx->xlat_name, talloc_array_length(mx->xlat_name) - 1, unlang_ctx->rules);
- if (slen < 0) {
- cf_log_err(cp, "%s", fr_strerror());
- talloc_free(mx);
- return NULL;
+ error:
+ fr_canonicalize_error(cp, &spaces, &text, slen, fr_strerror());
+
+ cf_log_err(cp, "Syntax error");
+ cf_log_err(cp, "%s", p);
+ cf_log_err(cp, "%s^ %s", spaces, text);
+
+ talloc_free(ut);
+ talloc_free(spaces);
+ talloc_free(text);
+
+ return NULL;
+ }
+
+ if (vpt->type == TMPL_TYPE_XLAT) {
+ xlat_exp_t *head;
+
+ /*
+ * Re-write it to be a pre-parsed XLAT structure.
+ */
+ slen = xlat_tokenize(vpt, &head, vpt->name, talloc_array_length(vpt->name) - 1, unlang_ctx->rules);
+ if (slen <= 0) {
+ p = vpt->name;
+ goto error;
}
- } else {
- char *p;
- mx->exec = true;
- memmove(mx->xlat_name, mx->xlat_name + 1, strlen(mx->xlat_name)); /* including trailing NUL */
- p = strrchr(mx->xlat_name, '`');
- if (p) *p = '\0';
+ vpt->type = TMPL_TYPE_XLAT_STRUCT;
+ vpt->tmpl_xlat = head;
}
+ ut->tmpl = vpt; /* const issues */
return c;
}
*/
if (((modrefname[0] == '%') && (modrefname[1] == '{')) ||
(modrefname[0] == '`')) {
- return compile_xlat_inline(parent, unlang_ctx, cp);
+ return compile_tmpl(parent, unlang_ctx, cp);
}
}
unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
unlang_frame_state_tmpl_t);
- unlang_t *instruction;
+ unlang_tmpl_t *ut;
- static unlang_t const tmpl_instruction = {
+ static unlang_t tmpl_instruction = {
.type = UNLANG_TYPE_TMPL,
.name = "tmpl",
.debug_name = "tmpl",
};
state->out = out;
- state->tmpl = tmpl;
- memcpy(&instruction, &tmpl_instruction, sizeof(instruction)); /* const issues */
+ MEM(ut = talloc(state, unlang_tmpl_t));
+ ut->self = tmpl_instruction;
+ ut->tmpl = tmpl;
/*
* Push a new tmpl frame onto the stack
*/
- unlang_interpret_push(request, instruction, RLM_MODULE_UNKNOWN, UNLANG_NEXT_STOP, false);
+ unlang_interpret_push(request, unlang_tmpl_to_generic(ut), RLM_MODULE_UNKNOWN, UNLANG_NEXT_STOP, false);
}
/** Wrapper to call a resumption function after a tmpl has been expanded
unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
unlang_frame_state_tmpl_t);
- if (!tmpl_async_required(state->tmpl)) {
- if (tmpl_aexpand_type(request, state->out, FR_TYPE_VALUE_BOX, request, state->tmpl, NULL, NULL) < 0) {
- return RLM_MODULE_FAIL;
- }
-
- return RLM_MODULE_OK;
- }
state->rctx = rctx;
state->resume = resume;
+ frame->interpret = unlang_tmpl_resume;
+
/*
* We set the repeatable flag here, so that the resume
* function is always called going back up the stack.
*/
frame->interpret = unlang_tmpl_resume;
repeatable_set(frame);
-
- /*
- * Not implemented.
- */
- return RLM_MODULE_FAIL;
+ return RLM_MODULE_YIELD;
}
static unlang_action_t unlang_tmpl(UNUSED REQUEST *request, rlm_rcode_t *presult)
{
-#if 0
unlang_stack_t *stack = request->stack;
unlang_stack_frame_t *frame = &stack->frame[stack->depth];
unlang_frame_state_tmpl_t *state = talloc_get_type_abort(frame->state,
unlang_frame_state_tmpl_t);
-#endif
+ unlang_tmpl_t *ut = unlang_generic_to_tmpl(frame->instruction);
+ if (!state->out) {
+ state->out = fr_value_box_alloc(state, FR_TYPE_STRING, NULL, false);
+ }
+
+ if (!tmpl_async_required(ut->tmpl)) {
+ if (tmpl_aexpand_type(request, state->out, FR_TYPE_STRING, request, ut->tmpl, NULL, NULL) < 0) {
+ REDEBUG("Failed expanding %s - %s", ut->tmpl->name, fr_strerror());
+ *presult = RLM_MODULE_FAIL;
+ }
+
+ *presult = RLM_MODULE_OK;
+ return UNLANG_ACTION_CALCULATE_RESULT;
+ }
+
+ REDEBUG("Async xlats are not implemented!");
+
+ /*
+ * Not implemented.
+ */
*presult = RLM_MODULE_FAIL;
return UNLANG_ACTION_CALCULATE_RESULT;
* Represents a single tmpl
*/
typedef struct {
- vp_tmpl_t const *tmpl; //!< the tmpl to expand
fr_value_box_t **out; //!< where the expansion is stored
void *rctx; //!< for resume / signal
fr_unlang_tmpl_resume_t resume; //!< resumption handler
UNLANG_TYPE_CALL, //!< call another virtual server
#endif
UNLANG_TYPE_POLICY, //!< Policy section.
- UNLANG_TYPE_XLAT_INLINE, //!< xlat statement, inline in "unlang"
UNLANG_TYPE_XLAT, //!< Represents one level of an xlat expansion.
UNLANG_TYPE_TMPL, //!< asynchronously expand a vp_tmpl_t
UNLANG_TYPE_MAX
*/
typedef struct {
unlang_t self;
- int exec;
- char *xlat_name;
- xlat_exp_t *exp; //!< First xlat node to execute.
-} unlang_xlat_inline_t;
+ vp_tmpl_t const *tmpl;
+} unlang_tmpl_t;
/** State of a redundant operation
*
return (unlang_t *)p;
}
-static inline unlang_xlat_inline_t *unlang_generic_to_xlat_inline(unlang_t *p)
+static inline unlang_tmpl_t *unlang_generic_to_tmpl(unlang_t *p)
{
- rad_assert(p->type == UNLANG_TYPE_XLAT_INLINE);
- return talloc_get_type_abort(p, unlang_xlat_inline_t);
+ rad_assert(p->type == UNLANG_TYPE_TMPL);
+ return talloc_get_type_abort(p, unlang_tmpl_t);
}
-static inline unlang_t *unlang_xlat_inline_to_generic(unlang_xlat_inline_t *p)
+static inline unlang_t *unlang_tmpl_to_generic(unlang_tmpl_t *p)
{
return (unlang_t *)p;
}
#include <freeradius-devel/unlang/xlat_priv.h>
#include "unlang_priv.h" /* Fixme - Should create a proper semi-public interface for the interpret */
-/** Hold the result of an inline xlat expansion
- *
- */
-typedef struct {
- fr_value_box_t *result; //!< Where to store the result of the
- ///< xlat expansion. This is usually discarded.
-} unlang_frame_state_xlat_inline_t;
-
/** State of an xlat expansion
*
* State of one level of nesting within an xlat expansion.
return XLAT_ACTION_YIELD;
}
-/** Evaluates "naked" xlats in the config
- *
- */
-static unlang_action_t unlang_xlat_inline(REQUEST *request, UNUSED rlm_rcode_t *presult)
-{
- unlang_stack_t *stack = request->stack;
- unlang_stack_frame_t *frame = &stack->frame[stack->depth];
- unlang_t *instruction = frame->instruction;
- unlang_xlat_inline_t *mx = unlang_generic_to_xlat_inline(instruction);
-
- if (!mx->exec) {
- TALLOC_CTX *pool;
- unlang_frame_state_xlat_inline_t *state;
-
- MEM(frame->state = state = talloc_zero(stack, unlang_frame_state_xlat_inline_t));
- MEM(pool = talloc_pool(frame->state, 1024)); /* Pool to absorb some allocs */
-
- unlang_xlat_push(pool, &state->result, request, mx->exp, false);
- return UNLANG_ACTION_PUSHED_CHILD;
- } else {
- RDEBUG2("`%s`", mx->xlat_name);
- radius_exec_program(request, NULL, 0, NULL, request, mx->xlat_name, request->packet->vps,
- false, true, fr_time_delta_from_sec(EXEC_TIMEOUT));
- return UNLANG_ACTION_EXECUTE_NEXT;
- }
-}
/** Register xlat operation with the interpreter
*
.frame_state_size = sizeof(unlang_frame_state_xlat_t),
.frame_state_name = "unlang_frame_state_xlat_t",
});
-
-
- unlang_register(UNLANG_TYPE_XLAT_INLINE,
- &(unlang_op_t){
- .name = "xlat_inline",
- .interpret = unlang_xlat_inline,
- .debug_braces = false
- });
}