From: Alan T. DeKok Date: Mon, 25 Sep 2023 21:40:05 +0000 (-0400) Subject: start of %func() X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9ffaeadba3b750e5dc5120ed77cd716c7bf3b9d9;p=thirdparty%2Ffreeradius-server.git start of %func() --- diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index b31a3d55e8a..74a5d76e957 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -2257,6 +2257,49 @@ static size_t command_max_buffer_size(command_result_t *result, command_file_ctx RETURN_OK(snprintf(data, COMMAND_OUTPUT_MAX, "%ld", size)); } +/** Set or clear migration flags. + * + */ +static size_t command_migrate(command_result_t *result, command_file_ctx_t *cc, + UNUSED char *data, UNUSED size_t data_used, char *in, UNUSED size_t inlen) +{ + char *p; + bool *out; + + fr_skip_whitespace(in); + p = in; + + if (strncmp(p, "xlat_new_functions", sizeof("xlat_new_functions") - 1) == 0) { + p += sizeof("xlat_new_functions") - 1; + out = &cc->tmpl_rules.xlat.new_functions; + + } else { + fr_strerror_const("Unknown migration flag"); + RETURN_PARSE_ERROR(0); + } + + fr_skip_whitespace(p); + if (*p != '=') { + fr_strerror_const("Missing '=' after flag"); + RETURN_PARSE_ERROR(0); + } + p++; + + fr_skip_whitespace(p); + if ((strcmp(p, "yes") == 0) || (strcmp(p, "true") == 0) || (strcmp(p, "1") == 0)) { + *out = true; + + } else if ((strcmp(p, "no") == 0) || (strcmp(p, "false") == 0) || (strcmp(p, "0") == 0)) { + *out = false; + + } else { + fr_strerror_const("Invalid value for flag"); + RETURN_PARSE_ERROR(0); + } + + RETURN_OK(0); +} + /** Skip the test file if we're missing a particular feature * */ @@ -2649,6 +2692,7 @@ static size_t command_xlat_normalise(command_result_t *result, command_file_ctx_ .list_def = request_attr_request, .allow_unresolved = cc->tmpl_rules.attr.allow_unresolved }, + .xlat = cc->tmpl_rules.xlat, }); if (dec_len <= 0) { fr_strerror_printf_push_head("ERROR offset %d", (int) -dec_len); @@ -2930,6 +2974,11 @@ static fr_table_ptr_sorted_t commands[] = { .usage = "max-buffer-size[ ]", .description = "Limit the maximum temporary buffer space available for any command which uses it" }}, + { L("migrate "), &(command_entry_t){ + .func = command_migrate, + .usage = "migrate =", + .description = "Set migration flag" + }}, { L("need-feature "), &(command_entry_t){ .func = command_need_feature, .usage = "need-feature ", diff --git a/src/lib/server/tmpl.h b/src/lib/server/tmpl.h index 4d00e544b66..fea8a0d121f 100644 --- a/src/lib/server/tmpl.h +++ b/src/lib/server/tmpl.h @@ -328,6 +328,7 @@ struct tmpl_attr_rules_s { struct tmpl_xlat_rules_s { fr_event_list_t *runtime_el; //!< The eventlist to use for runtime instantiation ///< of xlats. + bool new_functions; //!< new function syntax }; /** Optional arguments passed to vp_tmpl functions diff --git a/src/lib/unlang/xlat_tokenize.c b/src/lib/unlang/xlat_tokenize.c index 4f558439b4d..1c48c3c5e7f 100644 --- a/src/lib/unlang/xlat_tokenize.c +++ b/src/lib/unlang/xlat_tokenize.c @@ -258,6 +258,12 @@ int xlat_validate_function_mono(xlat_exp_t *node) return 0; } +static bool const func_chars[UINT8_MAX + 1] = { + SBUFF_CHAR_CLASS_ALPHA_NUM, + ['.'] = true, ['-'] = true, ['_'] = true, +}; + + /** Parse an xlat function and its child argument * * Parses a function call string in the format @@ -279,11 +285,6 @@ static inline int xlat_tokenize_function_mono(xlat_exp_head_t *head, * Special characters, spaces, etc. cannot be * module names. */ - static bool const func_chars[UINT8_MAX + 1] = { - SBUFF_CHAR_CLASS_ALPHA_NUM, - ['.'] = true, ['-'] = true, ['_'] = true, - }; - XLAT_DEBUG("FUNC-MONO <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in))); /* @@ -541,11 +542,6 @@ int xlat_tokenize_function_args(xlat_exp_head_t *head, fr_sbuff_t *in, * Special characters, spaces, etc. cannot be * module names. */ - static bool const func_chars[UINT8_MAX + 1] = { - SBUFF_CHAR_CLASS_ALPHA_NUM, - ['.'] = true, ['-'] = true, ['_'] = true, - }; - XLAT_DEBUG("FUNC-ARGS <-- %pV", fr_box_strvalue_len(fr_sbuff_current(in), fr_sbuff_remaining(in))); /* @@ -1006,6 +1002,74 @@ static int xlat_tokenize_string(xlat_exp_head_t *head, if (slen == 0) TALLOC_FREE(node); /* Free the empty node */ if (xlat_tokenize_function_args(head, in, t_rules) < 0) goto error; + continue; + } + + /* + * More migration hacks: allow %foo(...) + */ + if (t_rules->xlat.new_functions && fr_sbuff_next_if_char(in, '%')) { + fr_sbuff_marker_t m_s; + + fr_sbuff_marker(&m_s, in); + fr_sbuff_adv_past_allowed(in, SIZE_MAX, func_chars, NULL); + + /* + * Special-case: %% is just % + */ + if ((fr_sbuff_diff(in, &m_s) == 0) && fr_sbuff_next_if_char(in, '%')) { + goto one_letter; + } + + if (fr_sbuff_diff(in, &m_s) == 1) { + if (!fr_sbuff_next_if_char(in, '(')) { + fr_strerror_const("Missing '('"); + goto error; + } + + if (!fr_sbuff_next_if_char(in, ')')) { + fr_strerror_const("Missing ')'"); + goto error; + } + + one_letter: + fr_sbuff_marker_release(&m_s); + + XLAT_DEBUG("ONE-LETTER <-- %pV", + fr_box_strvalue_len(str, talloc_array_length(str) - 1)); + + if (slen == 0) { + talloc_free_children(node); /* re-use empty nodes */ + } else { + node = xlat_exp_alloc_null(head); + } + + xlat_exp_set_type(node, XLAT_ONE_LETTER); + xlat_exp_set_name(node, fr_sbuff_current(&m_s), 1); + +#ifdef STATIC_ANALYZER + if (!node->fmt) goto error; +#endif + + /* + * %% is pure. Everything else is not. + */ + node->flags.pure = (node->fmt[0] == '%'); + + xlat_exp_insert_tail(head, node); + continue; + } + + if (!fr_sbuff_next_if_char(in, '(')) { + fr_strerror_const("Missing '('"); + goto error; + } + + /* + * The next bit is not finished. + */ + fr_assert(0); + continue; } diff --git a/src/tests/unit/xlat/func.txt b/src/tests/unit/xlat/func.txt new file mode 100644 index 00000000000..5d311eeea82 --- /dev/null +++ b/src/tests/unit/xlat/func.txt @@ -0,0 +1,18 @@ +# +# This file tests the new parser for the xlat functions. +# +proto-dictionary radius + +migrate xlat_new_functions = yes + +# +# Input is new. Output is old. +# +xlat %Y() +match %Y + +#xlat %md5(foo) +#match foo + +count +match 4