== Attribute Manipulation
-=== %{length: ... }
+=== %(length: ... )
The `length` expansion returns the size of the input as an integer.
When the input is a string, then the output is identical to the
}
update reply {
- &Reply-Message := "The length of %{control.Tmp-String-0} is %{length:&control.Tmp-String-0}"
- &Reply-Message += "The length of %{control.Framed-IP-Address} is %{length:&control.Framed-IP-Address}"
+ &Reply-Message := "The length of %{control.Tmp-String-0} is %(length:&control.Tmp-String-0)"
+ &Reply-Message += "The length of %{control.Framed-IP-Address} is %(length:&control.Framed-IP-Address)"
}
----
return XLAT_ACTION_DONE;
}
+static xlat_arg_parser_t const xlat_func_length_args[] = {
+ { .single = true, .variadic = true, .type = FR_TYPE_VOID },
+ XLAT_ARG_PARSER_TERMINATOR
+};
+
/** Return the on-the-wire size of the boxes in bytes
*
* Example:
@verbatim
-"%{length:foobar}" == 6
-"%{length:%{bin:0102030005060708}}" == 8
+"%(length:foobar)" == 6
+"%(length:%{bin:0102030005060708})" == 8
@endverbatim
*
* @see #xlat_func_strlen
UNUSED void *xlat_thread_inst, fr_value_box_list_t *in)
{
- fr_value_box_t *vb;
- fr_dcursor_t cursor;
+ fr_value_box_t *vb = NULL;
- for (vb = fr_dcursor_talloc_init(&cursor, in, fr_value_box_t);
- vb;
- vb = fr_dcursor_next(&cursor)) {
+ while ((vb = fr_dlist_next(in, vb))) {
fr_value_box_t *my;
MEM(my = fr_value_box_alloc(ctx, FR_TYPE_SIZE, NULL, false));
XLAT_REGISTER_ARGS("hmacsha1", xlat_func_hmac_sha1, xlat_hmac_args);
XLAT_REGISTER_ARGS("integer", xlat_func_integer, xlat_func_integer_args);
XLAT_REGISTER_ARGS("join", xlat_func_join, xlat_func_join_args);
+ XLAT_REGISTER_ARGS("length", xlat_func_length, xlat_func_length_args);
XLAT_REGISTER_ARGS("nexttime", xlat_func_next_time, xlat_func_next_time_args);
XLAT_REGISTER_ARGS("pairs", xlat_func_pairs, xlat_func_pairs_args);
XLAT_REGISTER_ARGS("lpad", xlat_func_lpad, xlat_func_pad_args);
XLAT_REGISTER_MONO("base64decode", xlat_func_base64_decode, xlat_func_base64_decode_arg);
XLAT_REGISTER_MONO("bin", xlat_func_bin, xlat_func_bin_arg);
XLAT_REGISTER_MONO("hex", xlat_func_hex, xlat_func_hex_arg);
- xlat_register(NULL, "length", xlat_func_length, false);
XLAT_REGISTER_MONO("map", xlat_func_map, xlat_func_map_arg);
XLAT_REGISTER_MONO("md4", xlat_func_md4, xlat_func_md4_arg);
XLAT_REGISTER_MONO("md5", xlat_func_md5, xlat_func_md5_arg);
xlat_exp_t const *child = node->child;
char *out, *n_out;
TALLOC_CTX *pool;
+ char open = '{', close = '}';
+ bool first_done = false;
- if (!child) return talloc_asprintf(ctx, "%%{%s:}", node->call.func->name);
+ if (node->call.func->input_type == XLAT_INPUT_ARGS) {
+ open = '(';
+ close = ')';
+ }
+ if (!child) return talloc_asprintf(ctx, "%%%c%s:%c", open, node->call.func->name, close);
- out = talloc_asprintf(ctx, "%%{%s:", node->call.func->name);
+ out = talloc_asprintf(ctx, "%%%c%s:", open, node->call.func->name);
pool = talloc_pool(NULL, 128); /* Size of a single child (probably ok...) */
do {
char *child_str;
child_str = xlat_fmt_aprint(pool, child);
if (child_str) {
- n_out = talloc_buffer_append_buffer(ctx, out, child_str);
- if (!n_out) {
- talloc_free(out);
- talloc_free(pool);
- return NULL;
+ if ((first_done) && (node->call.func->input_type == XLAT_INPUT_ARGS)) {
+ n_out = talloc_strdup_append_buffer(out, " ");
+ if (!n_out) {
+ child_error:
+ talloc_free(out);
+ talloc_free(pool);
+ return NULL;
+ }
+ out = n_out;
}
+
+ n_out = talloc_buffer_append_buffer(ctx, out, child_str);
+ if (!n_out) goto child_error;
out = n_out;
+ first_done = true;
}
talloc_free_children(pool); /* Clear pool contents */
} while ((child = child->next));
talloc_free(pool);
- n_out = talloc_strdup_append_buffer(out, "}");
+ n_out = talloc_strndup_append_buffer(out, &close, 1);
if (!n_out) {
talloc_free(out);
return NULL;
ssize_t slen;
size_t at_in = fr_sbuff_used_total(out);
xlat_exp_t const *node = head;
+ char close;
if (!node) return 0;
break;
}
- FR_SBUFF_IN_STRCPY_LITERAL_RETURN(out, "%{");
+ if ((node->type == XLAT_FUNC) && (node->call.func->input_type == XLAT_INPUT_ARGS)) {
+ FR_SBUFF_IN_STRCPY_LITERAL_RETURN(out, "%(");
+ close = ')';
+ } else {
+ FR_SBUFF_IN_STRCPY_LITERAL_RETURN(out, "%{");
+ close = '}';
+ }
switch (node->type) {
case XLAT_ATTRIBUTE:
slen = tmpl_attr_print(out, node->attr, TMPL_ATTR_REF_PREFIX_NO);
fr_assert_fail(NULL);
break;
}
- FR_SBUFF_IN_CHAR_RETURN(out, '}');
+ FR_SBUFF_IN_CHAR_RETURN(out, close);
next:
node = node->next;
}
}
-if ("%{length:%{Tmp-String-0}}" != 39) {
+if ("%(length:%{Tmp-String-0})" != 39) {
test_fail
}
-if ("%{length:%{Tmp-String-1}}" != 42) {
+if ("%(length:%{Tmp-String-1})" != 42) {
test_fail
}
}
update request {
- &Tmp-Integer-0 := "%{length:%{Tmp-String-0}}"
+ &Tmp-Integer-0 := "%(length:%{Tmp-String-0})"
}
if (&Tmp-Integer-0 != 260) {
}
update request {
- &Tmp-Integer-0 := "%{length:%{Tmp-String-2}}"
- &Tmp-Integer-1 := "%{length:%{Tmp-Octets-0}}"
- &Tmp-Integer-2 := "%{length:%{Tmp-IP-Address-0}}"
- &Tmp-Integer-4 := "%{length:%{Tmp-Integer-0}}"
- &Tmp-Integer-6 := "%{length:%{Tmp-Cast-Ifid}}"
- &Tmp-Integer-7 := "%{length:%{Tmp-Cast-IPv6Addr}}"
- &Tmp-Integer-8 := "%{length:%{Tmp-Cast-IPv6Prefix}}"
- &Tmp-Integer-9 := "%{length:%{Tmp-Cast-Byte}}"
+ &Tmp-Integer-0 := "%(length:%{Tmp-String-2})"
+ &Tmp-Integer-1 := "%(length:%{Tmp-Octets-0})"
+ &Tmp-Integer-2 := "%(length:%{Tmp-IP-Address-0})"
+ &Tmp-Integer-4 := "%(length:%{Tmp-Integer-0})"
+ &Tmp-Integer-6 := "%(length:%{Tmp-Cast-Ifid})"
+ &Tmp-Integer-7 := "%(length:%{Tmp-Cast-IPv6Addr})"
+ &Tmp-Integer-8 := "%(length:%{Tmp-Cast-IPv6Prefix})"
+ &Tmp-Integer-9 := "%(length:%{Tmp-Cast-Byte})"
}
# String - bin 0x39383730
}
update request {
- &Tmp-Integer-0 := "%{length:%{Tmp-Cast-Short}}"
- &Tmp-Integer-1 := "%{length:%{Tmp-Cast-Ether}}"
- &Tmp-Integer-2 := "%{length:%{Tmp-Cast-Integer64}}"
- &Tmp-Integer-3 := "%{length:%{Tmp-Cast-IPv4Prefix}}"
+ &Tmp-Integer-0 := "%(length:%{Tmp-Cast-Short})"
+ &Tmp-Integer-1 := "%(length:%{Tmp-Cast-Ether})"
+ &Tmp-Integer-2 := "%(length:%{Tmp-Cast-Integer64})"
+ &Tmp-Integer-3 := "%(length:%{Tmp-Cast-IPv4Prefix})"
}
# short - bin 0x373b
#
# Check repetition of binary output
#
-if ("%{length:%{Tmp-String-5}}" != 10) {
+if ("%(length:%{Tmp-String-5})" != 10) {
test_fail
}
# Actual length of octet string is 4083 bytes
update request {
- &Tmp-Integer-0 := "%{length:%{Tmp-Octets-0}}"
+ &Tmp-Integer-0 := "%(length:%{Tmp-Octets-0})"
}
if (&Tmp-Integer-0 != 4083) {
&Tmp-String-0 := "%{1}"
}
-if ("%{length:%{Tmp-String-0}}" != 8166) {
+if ("%(length:%{Tmp-String-0})" != 8166) {
test_fail
}
#
# Check that newlines really are newlines
-if ("%{length:%{Tmp-String-1}}" != 3) {
+if ("%(length:%{Tmp-String-1})" != 3) {
test_fail
}
test_fail
}
-if ("%{length:%{Tmp-String-1}}" == 11) {
+if ("%(length:%{Tmp-String-1})" == 11) {
test_pass
}
else {
test_fail
}
-if ("%{length:%{Tmp-String-1}}" == 7) {
+if ("%(length:%{Tmp-String-1})" == 7) {
test_pass
}
else {
test_fail
}
-if ("%{length:%{Tmp-String-1}}" == 11) {
+if ("%(length:%{Tmp-String-1})" == 11) {
test_pass
}
else {
test_fail
}
-if ("%{length:%{Tmp-String-1}}" == 7) {
+if ("%(length:%{Tmp-String-1})" == 7) {
test_pass
}
else {
xlat /([A-Z0-9\\-]*)_%{Calling-Station-Id}/
match /([A-Z0-9\\-]*)_%{Calling-Station-Id}/
-xlat %{length}
-match %{length}
+xlat %(length:)
+match %(length:)
-xlat %{length:
+xlat %(length:
match ERROR offset 9: Missing closing brace
-xlat %{length:1 + 2
+xlat %(length:1 + 2
match ERROR offset 14: Missing closing brace
xlat \"%t\tfoo\"