fr_value_box_list_init(&result_copy);
thread_inst = xlat_thread_instance_find(node);
- XLAT_DEBUG("** [%i] %s(func-async) - %%{%s:%pM}", unlang_interpret_stack_depth(request), __FUNCTION__,
+ XLAT_DEBUG("** [%i] %s(func-async) - %%{%s:%pM}",
+ unlang_interpret_stack_depth(request), __FUNCTION__,
node->fmt, result);
/*
*/
if (RDEBUG_ENABLED2) fr_value_box_list_acopy(NULL, &result_copy, result);
- if (!fr_dlist_empty(result)) { fr_dlist_verify(result); }
+ if (!fr_dlist_empty(result)) fr_dlist_verify(result);
+
xa = xlat_process_args(ctx, result, request, node->call.func->input_type, node->call.func->args);
if (xa == XLAT_ACTION_FAIL) {
if (RDEBUG_ENABLED2) fr_dlist_talloc_free(&result_copy);
- return (xa);
+ return xa;
}
- xa = node->call.func->func.async(ctx, out, request, node->call.inst->data, thread_inst->data, result);
- if (!fr_dlist_empty(result)) { fr_dlist_verify(result); }
+
+ xa = node->call.func->func.async(ctx, out, request,
+ node->call.inst->data, thread_inst->data, result);
+
+ if (!fr_dlist_empty(result)) fr_dlist_verify(result);
if (RDEBUG_ENABLED2) {
xlat_debug_log_expansion(request, *in, &result_copy);
fr_dlist_talloc_free(&result_copy);
}
#endif
+static inline int xlat_validate_function_mono(xlat_exp_t *node)
+{
+ fr_assert(node->type == XLAT_FUNC_NORMAL);
+
+ if (node->call.func->args && node->call.func->args->required &&
+ (node->child->type == XLAT_LITERAL) && (talloc_array_length(node->child->fmt) == 1)) {
+ fr_strerror_const("Missing required input");
+ return -1;
+ }
+
+ return 0;
+}
+
/** Parse an xlat function and its child argument
*
* Parses a function call string in the format
* - 0 if the string was parsed into a function.
* - <0 on parse error.
*/
-static inline int xlat_tokenize_function_single_arg(TALLOC_CTX *ctx, xlat_exp_t **head,
- xlat_flags_t *flags, fr_sbuff_t *in,
- tmpl_rules_t const *rules)
+static inline int xlat_tokenize_function_mono(TALLOC_CTX *ctx, xlat_exp_t **head,
+ xlat_flags_t *flags, fr_sbuff_t *in,
+ tmpl_rules_t const *rules)
{
xlat_exp_t *node;
xlat_t *func;
goto error;
}
+ /*
+ * Check there's input if it's needed
+ */
+ if ((node->type == XLAT_FUNC_NORMAL) && (xlat_validate_function_mono(node) < 0)) goto error;
+
if (!fr_sbuff_next_if_char(in, '}')) {
fr_strerror_const("Missing closing brace");
goto error;
return 0;
}
+static inline int xlat_validate_function_args(xlat_exp_t *node)
+{
+ xlat_arg_parser_t const *arg_p;
+ xlat_exp_t *child = node->child;
+
+ fr_assert(node->type == XLAT_FUNC_NORMAL);
+
+ for (arg_p = node->call.func->args; arg_p->type != FR_TYPE_NULL; arg_p++) {
+ if (!arg_p->required) break;
+
+ if (!child) {
+ fr_strerror_printf("Missing required arg %u",
+ (unsigned int)(arg_p - node->call.func->args) + 1);
+ return -1;
+ }
+
+ child = child->next;
+ }
+
+ return 0;
+}
+
/** Parse an xlat function and its child arguments
*
* Parses a function call string in the format
* - 0 if the string was parsed into a function.
* - <0 on parse error.
*/
-static inline int xlat_tokenize_function_multi_arg(TALLOC_CTX *ctx, xlat_exp_t **head,
- xlat_flags_t *flags, fr_sbuff_t *in,
- tmpl_rules_t const *rules)
+static inline int xlat_tokenize_function_args(TALLOC_CTX *ctx, xlat_exp_t **head,
+ xlat_flags_t *flags, fr_sbuff_t *in,
+ tmpl_rules_t const *rules)
{
xlat_exp_t *node;
xlat_t *func;
goto error;
}
+ /*
+ * Check we have all the required arguments
+ */
+ if ((node->type == XLAT_FUNC_NORMAL) && (xlat_validate_function_args(node) < 0)) goto error;
+
if (!fr_sbuff_next_if_char(in, ')')) {
fr_strerror_const("Missing closing brace");
goto error;
fr_sbuff_set(in, &s_m); /* backtrack */
fr_sbuff_marker_release(&s_m);
- ret = xlat_tokenize_function_single_arg(ctx, head, flags, in, t_rules);
+ ret = xlat_tokenize_function_mono(ctx, head, flags, in, t_rules);
if (ret <= 0) return ret;
}
break;
if (fr_sbuff_adv_past_str_literal(in, "%(")) {
if (len == 0) TALLOC_FREE(node); /* Free the empty node */
- if (xlat_tokenize_function_multi_arg(ctx, &node, flags, in, t_rules) < 0) goto error;
+ if (xlat_tokenize_function_args(ctx, &node, flags, in, t_rules) < 0) goto error;
fr_cursor_insert(&cursor, node);
node = NULL;
continue;
xlat_exp_set_type(node, XLAT_FUNC);
node->call.func = func;
+ /*
+ * Check input arguments of our freshly
+ * resolved function
+ */
+ switch (node->call.func->input_type) {
+ case XLAT_INPUT_UNPROCESSED:
+ break;
+
+ case XLAT_INPUT_MONO:
+ if (xlat_validate_function_mono(node) < 0) return -1;
+ break;
+
+ case XLAT_INPUT_ARGS:
+ if (xlat_validate_function_args(node) < 0) return -1;
+ break;
+ }
+
/*
* Reset node flags
*/