our_out = FR_SBUFF(out);
FR_SBUFF_IN_SPRINTF_RETURN(&our_out, "%%%s(", node->call.func->name);
- xlat_exp_foreach(node->call.args, arg) {
- if ((first_done) && (node->call.func->input_type == XLAT_INPUT_ARGS)) {
- FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
- }
+ if (node->call.args) {
+ xlat_exp_foreach(node->call.args, arg) {
+ if (first_done && (node->call.func->args)) {
+ FR_SBUFF_IN_CHAR_RETURN(&our_out, ',');
+ }
- slen = xlat_fmt_print(&our_out, arg);
- if (slen < 0) return slen - fr_sbuff_used(&our_out);
+ slen = xlat_fmt_print(&our_out, arg);
+ if (slen < 0) return slen - fr_sbuff_used(&our_out);
- first_done = true;
+ first_done = true;
+ }
}
FR_SBUFF_IN_CHAR_RETURN(&our_out, ')');
if (!func->args) return XLAT_ACTION_DONE;
/*
- * xlat needs no input processing just return.
- */
- switch (func->input_type) {
- case XLAT_INPUT_UNPROCESSED:
- return XLAT_ACTION_DONE;
-
- /*
- * xlat takes all input as a single vb.
+ * Manage the arguments.
*/
- case XLAT_INPUT_ARGS:
- vb = fr_value_box_list_head(list);
- arg = xlat_exp_head(node->call.args);
-
- while (arg_p->type != FR_TYPE_NULL) {
- /*
- * Separate check to see if the group
- * box is there. Check in
- * xlat_process_arg_list verifies it
- * has a value.
- */
- if (!vb) {
- if (arg_p->required) {
- missing:
- REDEBUG("Function \"%s\" is missing required argument %u",
- func->name, (unsigned int)((arg_p - func->args) + 1));
- return XLAT_ACTION_FAIL;
- }
+ vb = fr_value_box_list_head(list);
+ arg = xlat_exp_head(node->call.args);
- /*
- * The argument isn't required. Just omit it. xlat_func_args_set() enforces
- * that optional arguments are at the end of the argument list.
- */
- return XLAT_ACTION_DONE;
+ while (arg_p->type != FR_TYPE_NULL) {
+ /*
+ * Separate check to see if the group
+ * box is there. Check in
+ * xlat_process_arg_list verifies it
+ * has a value.
+ */
+ if (!vb) {
+ if (arg_p->required) {
+ missing:
+ REDEBUG("Function \"%s\" is missing required argument %u",
+ func->name, (unsigned int)((arg_p - func->args) + 1));
+ return XLAT_ACTION_FAIL;
}
/*
- * Everything in the top level list should be
- * groups
+ * The argument isn't required. Just omit it. xlat_func_args_set() enforces
+ * that optional arguments are at the end of the argument list.
*/
- if (!fr_cond_assert(vb->type == FR_TYPE_GROUP)) return XLAT_ACTION_FAIL;
+ return XLAT_ACTION_DONE;
+ }
- /*
- * pre-advance, in case the vb is replaced
- * during processing.
- */
- vb_next = fr_value_box_list_next(list, vb);
- arg_next = xlat_exp_next(node->call.args, arg);
+ /*
+ * Everything in the top level list should be
+ * groups
+ */
+ if (!fr_cond_assert(vb->type == FR_TYPE_GROUP)) return XLAT_ACTION_FAIL;
+
+ /*
+ * pre-advance, in case the vb is replaced
+ * during processing.
+ */
+ vb_next = fr_value_box_list_next(list, vb);
+ arg_next = xlat_exp_next(node->call.args, arg);
- xa = xlat_process_arg_list(ctx, &vb->vb_group, request, func->name, arg_p, arg,
- (unsigned int)((arg_p - func->args) + 1));
- if (xa != XLAT_ACTION_DONE) return xa;
+ xa = xlat_process_arg_list(ctx, &vb->vb_group, request, func->name, arg_p, arg,
+ (unsigned int)((arg_p - func->args) + 1));
+ if (xa != XLAT_ACTION_DONE) return xa;
+ /*
+ * This argument doesn't exist. That might be OK, or it may be a fatal error.
+ */
+ if (fr_value_box_list_empty(&vb->vb_group)) {
/*
- * This argument doesn't exist. That might be OK, or it may be a fatal error.
+ * Variadic rules deal with empty boxes differently...
*/
- if (fr_value_box_list_empty(&vb->vb_group)) {
- /*
- * Variadic rules deal with empty boxes differently...
- */
- switch (arg_p->variadic) {
- case XLAT_ARG_VARIADIC_EMPTY_SQUASH:
- fr_value_box_list_talloc_free_head(list);
- goto do_next;
+ switch (arg_p->variadic) {
+ case XLAT_ARG_VARIADIC_EMPTY_SQUASH:
+ fr_value_box_list_talloc_free_head(list);
+ goto do_next;
- case XLAT_ARG_VARIADIC_EMPTY_KEEP:
- goto empty_ok;
+ case XLAT_ARG_VARIADIC_EMPTY_KEEP:
+ goto empty_ok;
- case XLAT_ARG_VARIADIC_DISABLED:
- break;
- }
+ case XLAT_ARG_VARIADIC_DISABLED:
+ break;
+ }
+ /*
+ * Empty groups for optional arguments are OK, we can just stop processing the list.
+ */
+ if (!arg_p->required) {
/*
- * Empty groups for optional arguments are OK, we can just stop processing the list.
+ * If the caller doesn't care about the type, then we leave the
+ * empty group there.
*/
- if (!arg_p->required) {
- /*
- * If the caller doesn't care about the type, then we leave the
- * empty group there.
- */
- if (arg_p->type == FR_TYPE_VOID) goto do_next;
-
- /*
- * The caller does care about the type, and we don't have any
- * matching data. Omit this argument, and all arguments after it.
- *
- * i.e. if the caller has 3 optional arguments, all
- * FR_TYPE_UINT8, and the first one is missing, then we MUST
- * either supply boxes all of FR_TYPE_UINT8, OR we supply nothing.
- *
- * We can't supply a box of any other type, because the caller
- * has declared that it wants FR_TYPE_UINT8, and is naively
- * accessing the box as vb_uint8, hoping that it's being passed
- * the right thing.
- */
- fr_value_box_list_talloc_free_head(list);
- break;
- }
+ if (arg_p->type == FR_TYPE_VOID) goto do_next;
/*
- * If the caller is expecting a particular type, then getting nothing is
- * an error.
+ * The caller does care about the type, and we don't have any
+ * matching data. Omit this argument, and all arguments after it.
+ *
+ * i.e. if the caller has 3 optional arguments, all
+ * FR_TYPE_UINT8, and the first one is missing, then we MUST
+ * either supply boxes all of FR_TYPE_UINT8, OR we supply nothing.
*
- * If the caller manually checks the input type, then we can leave it as
- * an empty group.
+ * We can't supply a box of any other type, because the caller
+ * has declared that it wants FR_TYPE_UINT8, and is naively
+ * accessing the box as vb_uint8, hoping that it's being passed
+ * the right thing.
*/
- if (arg_p->type != FR_TYPE_VOID) goto missing;
+ fr_value_box_list_talloc_free_head(list);
+ break;
}
- empty_ok:
/*
- * In some cases we replace the current argument with the head of the group.
+ * If the caller is expecting a particular type, then getting nothing is
+ * an error.
*
- * xlat_process_arg_list() has already done concatenations for us.
+ * If the caller manually checks the input type, then we can leave it as
+ * an empty group.
*/
- if (arg_p->single || arg_p->concat) {
- fr_value_box_t *head = fr_value_box_list_pop_head(&vb->vb_group);
+ if (arg_p->type != FR_TYPE_VOID) goto missing;
+ }
- /*
- * If we're meant to be smashing the argument
- * to a single box, but the group was empty,
- * add a null box instead so ordering is maintained
- * for subsequent boxes.
- */
- if (!head) head = fr_value_box_alloc_null(ctx);
- fr_value_box_list_replace(list, vb, head);
- talloc_free(vb);
- }
+ empty_ok:
+ /*
+ * In some cases we replace the current argument with the head of the group.
+ *
+ * xlat_process_arg_list() has already done concatenations for us.
+ */
+ if (arg_p->single || arg_p->concat) {
+ fr_value_box_t *head = fr_value_box_list_pop_head(&vb->vb_group);
- do_next:
- if (arg_p->variadic) {
- if (!vb_next) break;
- } else {
- arg_p++;
- arg = arg_next;
- }
- vb = vb_next;
+ /*
+ * If we're meant to be smashing the argument
+ * to a single box, but the group was empty,
+ * add a null box instead so ordering is maintained
+ * for subsequent boxes.
+ */
+ if (!head) head = fr_value_box_alloc_null(ctx);
+ fr_value_box_list_replace(list, vb, head);
+ talloc_free(vb);
}
- break;
+
+ do_next:
+ if (arg_p->variadic) {
+ if (!vb_next) break;
+ } else {
+ arg_p++;
+ arg = arg_next;
+ }
+ vb = vb_next;
}
return XLAT_ACTION_DONE;
MEM(node = xlat_exp_alloc(ctx, XLAT_FUNC, func->name, strlen(func->name)));
node->call.func = func;
- if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
- talloc_free(node);
- return NULL;
- }
+
node->flags = func->flags;
node->flags.impure_func = !func->flags.pure;
- xlat_flags_merge(&node->flags, &args->flags);
- if (func->input_type == XLAT_INPUT_ARGS) {
- xlat_arg_parser_t const *arg_p;
- xlat_exp_t *arg = xlat_exp_head(node->call.args);
+ if (args) {
+ xlat_flags_merge(&node->flags, &args->flags);
/*
- * The original tokenizing is done using the redundant xlat argument parser
- * so the boxes haven't been marked up with the appropriate "safe for".
+ * If the function is pure, AND it's arguments are pure,
+ * then remember that we need to call a pure function.
*/
+ node->flags.can_purify = (func->flags.pure && args->flags.pure) | args->flags.can_purify;
+
+ MEM(node->call.args = xlat_exp_head_alloc(node));
+ node->call.args->is_argv = true;
+
+ if (unlikely(xlat_copy(node, node->call.args, args) < 0)) {
+ talloc_free(node);
+ return NULL;
+ }
+ }
+
+ /*
+ * The original tokenizing is done using the redundant xlat argument parser so the boxes need to
+ * have their "safe_for" value changed to the new one.
+ */
+ if (func->args) {
+ xlat_arg_parser_t const *arg_p;
+ xlat_exp_t *arg;
+
+ fr_assert(args);
+
+ arg = xlat_exp_head(node->call.args);
+
for (arg_p = node->call.func->args; arg_p->type != FR_TYPE_NULL; arg_p++) {
if (!arg) break;
}
}
- /*
- * If the function is pure, AND it's arguments are pure,
- * then remember that we need to call a pure function.
- */
- node->flags.can_purify = (func->flags.pure && args->flags.pure) | args->flags.can_purify;
-
return node;
}
* becomes an error when the user tries
* to use the redundant xlat.
*/
- if (first->func->input_type != xrf->func->input_type) {
+ if ((!first->func->args && xrf->func->args) ||
+ (first->func->args && !xrf->func->args)) {
cf_log_err(xr->cs, "Expansion functions \"%s\" and \"%s\" use different argument styles "
"cannot be used in the same redundant section", first->func->name, xrf->func->name);
error:
MEM(node = xlat_exp_func_alloc(head, xrf->func, xctx->ex->call.args));
xlat_exp_insert_tail(head, node);
- switch (xrf->func->input_type) {
- case XLAT_INPUT_UNPROCESSED:
- break;
-
- case XLAT_INPUT_ARGS:
- if (xlat_validate_function_args(node) < 0) {
- PERROR("Invalid arguments for redundant expansion function \"%s\"",
- xrf->func->name);
- goto error;
- }
- break;
+ if (xlat_validate_function_args(node) < 0) {
+ PERROR("Invalid arguments for redundant expansion function \"%s\"",
+ xrf->func->name);
+ goto error;
}
/*
return 0;
}
-fr_slen_t xlat_validate_function_args(xlat_exp_t *node)
+int xlat_validate_function_args(xlat_exp_t *node)
{
xlat_arg_parser_t const *arg_p;
xlat_exp_t *arg = xlat_exp_head(node->call.args);
fr_assert(node->type == XLAT_FUNC);
+ /*
+ * Check the function definition against what the user passed in.
+ */
+ if (!node->call.func->args) {
+ if (node->call.args) {
+ fr_strerror_const("Too many arguments to function call, expected 0");
+ return -1;
+ }
+
+ /*
+ * Function takes no arguments, and none were passed in. There's nothing to verify.
+ */
+ return 0;
+ }
+
+ if (!node->call.args) {
+ fr_strerror_const("Too few arguments to function call");
+ return -1;
+ }
+
+ /*
+ * The function both has arguments defined, and the user has supplied them.
+ */
for (arg_p = node->call.func->args, i = 0; arg_p->type != FR_TYPE_NULL; arg_p++) {
if (!arg_p->required) break;
node->call.dict = t_rules->attr.dict_def;
node->flags = func->flags;
node->flags.impure_func = !func->flags.pure;
- node->call.input_type = func->input_type;
}
fr_sbuff_marker_release(&m_s);
talloc_free(node);
return -1;
}
+ fr_assert(node->call.args != NULL);
xlat_flags_merge(&node->flags, &node->call.args->flags);
+ node->call.args->is_argv = true;
if (!fr_sbuff_next_if_char(in, ')')) {
fr_strerror_const("Missing closing brace ')'");
}
/*
- * Validate the arguments.
+ * Set the flags.
*/
- if (node->type == XLAT_FUNC) {
- switch (node->call.input_type) {
- case XLAT_INPUT_UNPROCESSED:
- break;
-
- case XLAT_INPUT_ARGS:
- /*
- * We might not be able to purify the function call, but perhaps we can purify the arguments to it.
- */
- node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
- break;
- }
+ if ((node->type == XLAT_FUNC) && node->call.args) {
+ /*
+ * We might not be able to purify the function call, but perhaps we can purify the arguments to it.
+ */
+ node->flags.can_purify = (node->call.func->flags.pure && node->call.args->flags.pure) | node->call.args->flags.can_purify;
}
xlat_exp_insert_tail(head, node);
}
MEM(head = xlat_exp_head_alloc(ctx));
- head->is_argv = true;
/*
* skip spaces at the beginning as we don't want them to become a whitespace literal.
node->call.dict = xr_rules->tr_rules->dict_def;
/*
- * Check input arguments of our freshly
- * resolved function
+ * Check input arguments of our freshly resolved function
*/
- switch (node->call.func->input_type) {
- case XLAT_INPUT_UNPROCESSED:
- break;
-
- case XLAT_INPUT_ARGS:
- if (node->call.input_type != XLAT_INPUT_ARGS) {
- fr_strerror_const("Function takes defined arguments and should "
- "be called using %func(args) syntax");
- return -1;
- }
- if (xlat_validate_function_args(node) < 0) return -1;
- break;
- }
+ if (xlat_validate_function_args(node) < 0) return -1;
/*
* Add the freshly resolved function