26RCSID(
"$Id: 968a9943dc5719068696c50d981290b54a3e8a50 $")
28#include <freeradius-devel/util/strerror.h>
29#include <freeradius-devel/util/regex.h>
33#define swap(_a, _b) do { __typeof__ (_a) _tmp = _a; _a = _b; _b = _tmp; } while (0)
36#define ERR_UNDERFLOW (-4)
37#define ERR_OVERFLOW (-3)
38#define ERR_INVALID (-2)
40#define COERCE(_vb, _box, _type, _enumv) do { \
41 if (_vb->type != _type) { \
42 if (fr_value_box_cast(NULL, &_box, _type, _enumv, _vb) < 0) return -1; \
47#define COERCE_A(_type, _enumv) COERCE(a, one, _type, _enumv)
48#define COERCE_B(_type, _enumv) COERCE(b, two, _type, _enumv)
743 dst->vb_bool = a->vb_bool | b->vb_bool;
752 dst->vb_bool = a->vb_bool - b->vb_bool;
757 dst->vb_bool = a->vb_bool & b->vb_bool;
761 dst->vb_bool = a->vb_bool | b->vb_bool;
765 dst->vb_bool = a->vb_bool ^ b->vb_bool;
784 fr_strerror_const(
"Cannot perform operation on two values of type 'date'. One value must be a number.");
924 len = a->vb_length + b->vb_length;
928 buf = talloc_array(ctx,
uint8_t, len);
935 memcpy(buf, a->vb_octets, a->vb_length);
936 memcpy(buf + a->vb_length, b->vb_octets, b->vb_length);
947 if (a->vb_length < b->vb_length) {
952 if (memcmp(a->vb_octets + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
957 len = a->vb_length - b->vb_length;
958 buf = talloc_array(ctx,
uint8_t, len);
961 memcpy(buf, a->vb_strvalue, len);
968 if (a->vb_length != b->vb_length) {
974 buf = talloc_array(ctx,
uint8_t, a->vb_length);
977 for (len = 0; len < a->vb_length; len++) {
978 buf[len] = a->vb_octets[len] & b->vb_octets[len];
988 if (a->vb_length != b->vb_length)
goto length_error;
990 buf = talloc_array(ctx,
uint8_t, a->vb_length);
993 for (len = 0; len < a->vb_length; len++) {
994 buf[len] = a->vb_octets[len] | b->vb_octets[len];
999 if (a->vb_length != b->vb_length)
goto length_error;
1001 buf = talloc_array(ctx,
uint8_t, a->vb_length);
1004 for (len = 0; len < a->vb_length; len++) {
1005 buf[len] = a->vb_octets[len] ^ b->vb_octets[len];
1013 len = a->vb_length - b->vb_uint32;
1014 buf = talloc_array(ctx,
uint8_t, len);
1017 memcpy(buf, a->vb_octets, len);
1026 len = a->vb_length - b->vb_uint32;
1028 buf = talloc_array(ctx,
uint8_t, len);
1031 memcpy(buf, a->vb_octets + b->vb_uint32, len);
1068 len = a->vb_length + b->vb_length;
1072 buf = talloc_array(ctx,
char, len + 1);
1079 len = a->vb_length + b->vb_length;
1080 memcpy(buf, a->vb_strvalue, a->vb_length);
1081 memcpy(buf + a->vb_length, b->vb_strvalue, b->vb_length);
1090 buf = talloc_array(ctx,
char, len + 1);
1093 len = a->vb_length + b->vb_length;
1094 memcpy(buf, b->vb_strvalue, b->vb_length);
1095 memcpy(buf + b->vb_length, a->vb_strvalue, a->vb_length);
1107 if (a->vb_length < b->vb_length) {
1112 if (memcmp(a->vb_strvalue + a->vb_length - b->vb_length, b->vb_strvalue, b->vb_length) != 0) {
1113 fr_strerror_const(
"Right side of substract is not a suffix of the input string");
1117 len = a->vb_length - b->vb_length;
1118 buf = talloc_array(ctx,
char, len + 1);
1121 memcpy(buf, a->vb_strvalue, len);
1131 len = a->vb_length - b->vb_uint32;
1132 buf = talloc_array(ctx,
char, len + 1);
1135 memcpy(buf, a->vb_strvalue, len);
1145 len = a->vb_length - b->vb_uint32;
1147 buf = talloc_array(ctx,
char, len + 1);
1150 memcpy(buf, a->vb_strvalue + b->vb_uint32, len);
1179 out->vb_ip =
in->vb_ip;
1183 if (
in->vb_ip.af == AF_INET6)
goto cast_ipv6_prefix;
1186 out->vb_ip =
in->vb_ip;
1269 dst->vb_ip.af = AF_INET;
1270 dst->vb_ip.addr.v4.s_addr = htonl(ntohl(a->vb_ip.addr.v4.s_addr) | b->vb_uint32);
1271 dst->vb_ip.prefix = 32;
1324 if (b->vb_uint32 == 0) {
1325 dst->vb_ip.addr.v4.s_addr = 0;
1328 }
else if ((~b->vb_uint32) == 0) {
1329 dst->vb_ip.addr.v4.s_addr = a->vb_ip.addr.v4.s_addr;
1335 mask = ~b->vb_uint32;
1337 if ((
mask & b->vb_uint32) !=
mask) {
1345 while (prefix > 0) {
1346 if (
mask == b->vb_uint32)
break;
1354 dst->vb_ip.addr.v4.s_addr = htonl(ntohl(a->vb_ip.addr.v4.s_addr) & b->vb_uint32);
1357 dst->vb_ip.af = AF_INET;
1358 dst->vb_ip.prefix = prefix;
1380 out->vb_ip =
in->vb_ip;
1384 if (
in->vb_ip.af == AF_INET)
goto cast_ipv4_prefix;
1387 out->vb_ip =
in->vb_ip;
1475 if (b->vb_uint64 >= (((uint64_t) 1) << (128 - a->vb_ip.prefix)))
return ERR_OVERFLOW;
1480 mask = b->vb_uint64;
1481 for (i = 15; i >= ((a->vb_ip.prefix + 7) >> 3); i--) {
1482 dst->vb_ip.addr.v6.s6_addr[i] |=
mask & 0xff;
1486 dst->vb_ip.af = AF_INET6;
1487 dst->vb_ip.prefix = 0;
1488 dst->vb_ip.scope_id = a->vb_ip.scope_id;
1504 for (i = 15; i >= 0; i--) {
1510 for (j = 0; j < 8; j++) {
1511 if ((
in[i] & (1 << j)) == 0) {
1524 int i, prefix = 128;
1531 if (a->vb_length != (128 / 8)) {
1539 pa = (
const uint8_t *) &a->vb_ip.addr.v6.s6_addr;
1546 if (b->vb_length != (128 / 8)) {
1554 pb = (
const uint8_t *) &b->vb_ip.addr.v6;
1563 pdst = (
uint8_t *) &dst->vb_ip.addr.v6;
1565 for (i = 0; i < 16; i++) {
1566 pdst[i] = pa[i] & pb[i];
1569 dst->vb_ip.af = AF_INET6;
1570 dst->vb_ip.prefix = prefix;
1582#define is_ipv6(_x) (((_x)->type == FR_TYPE_IPV6_ADDR) || ((_x)->type == FR_TYPE_IPV6_PREFIX) || ((((_x)->type == FR_TYPE_COMBO_IP_ADDR) || ((_x)->type == FR_TYPE_COMBO_IP_PREFIX)) && ((_x)->vb_ip.af == AF_INET6)))
1622 dst->vb_float32 = a->vb_float64 + b->vb_float64;
1626 dst->vb_float32 = a->vb_float64 - b->vb_float64;
1630 dst->vb_float32 = a->vb_float64 * b->vb_float64;
1634 if (fpclassify(b->vb_float64) == FP_ZERO)
return ERR_ZERO;
1636 dst->vb_float32 = a->vb_float64 / b->vb_float64;
1640 if (fpclassify(b->vb_float64) == FP_ZERO)
return ERR_ZERO;
1642 dst->vb_float32 = fmod(a->vb_float64, b->vb_float64);
1669 dst->vb_float64 = a->vb_float64 + b->vb_float64;
1673 dst->vb_float64 = a->vb_float64 - b->vb_float64;
1677 dst->vb_float64 = a->vb_float64 * b->vb_float64;
1681 if (fpclassify(b->vb_float64) == FP_ZERO)
return ERR_ZERO;
1683 dst->vb_float64 = a->vb_float64 / b->vb_float64;
1687 if (fpclassify(b->vb_float64) == FP_ZERO)
return ERR_ZERO;
1689 dst->vb_float64 = fmod(a->vb_float64, b->vb_float64);
1739 if (b->vb_uint64 == 0)
return ERR_ZERO;
1741 result.vb_uint64 = a->vb_uint64 / b->vb_uint64;
1745 if (b->vb_uint64 == 0)
return ERR_ZERO;
1747 result.vb_uint64 = a->vb_uint64 % in2->vb_uint64;
1751 result.vb_uint64 = a->vb_uint64 & b->vb_uint64;
1755 result.vb_uint64 = a->vb_uint64 | b->vb_uint64;
1759 result.vb_uint64 = a->vb_uint64 ^ b->vb_uint64;
1763 if (b->vb_uint32 >= (8 *
sizeof(a->vb_uint64)))
return ERR_UNDERFLOW;
1765 result.vb_uint64 = a->vb_uint64 >> b->vb_uint32;
1769 if (b->vb_uint32 >= (8 *
sizeof(a->vb_uint64)))
return ERR_OVERFLOW;
1771 result.vb_uint64 = a->vb_uint64 << b->vb_uint32;
1826 if (b->vb_int64 == 0)
return ERR_ZERO;
1828 result.vb_int64 = a->vb_int64 / b->vb_int64;
1832 if (b->vb_int64 == 0)
return ERR_ZERO;
1834 result.vb_int64 = a->vb_int64 % in2->vb_int64;
1838 result.vb_int64 = a->vb_int64 & b->vb_int64;
1842 result.vb_int64 = a->vb_int64 | b->vb_int64;
1846 result.vb_int64 = a->vb_int64 ^ b->vb_int64;
1850 if (b->vb_uint32 >= (8 *
sizeof(a->vb_int64)))
return ERR_UNDERFLOW;
1852 result.vb_int64 = a->vb_int64 >> b->vb_uint32;
1856 if (b->vb_uint32 >= (8 *
sizeof(a->vb_int64)))
return ERR_OVERFLOW;
1858 result.vb_int64 = a->vb_int64 << b->vb_uint32;
1946 if (a->type != b->type) {
1949 dst->vb_bool =
false;
1956 if (a->type != b->type)
goto mismatch_type;
1969 if (rcode < 0)
return rcode;
1972 dst->vb_bool = (rcode != 0);
2069 }
else if (a->type != b->type) {
2130 if (a->type != b->type) {
2169 if (hint == a->type) enumv = a->enumv;
2170 if (hint == b->type) enumv = b->enumv;
2185 if (a->type != hint) {
2190 if (b->type != hint) {
2197 if (rcode < 0)
goto done;
2200 dst->vb_bool = (rcode > 0);
2244 rcode = func(ctx, &
out, a, op, b);
2245 if (rcode < 0)
goto done;
2248 dst->tainted = a->tainted | b->tainted;
2371 vb = fr_value_box_list_head(&group->vb_group);
2379 while ((vb = fr_value_box_list_next(&group->vb_group, vb)) != NULL) {
2383 if (vb->type ==
type) {
2384 rcode = calc(ctx, &
out, &
out, op, vb);
2385 if (rcode < 0)
return rcode;
2390 rcode = calc(ctx, &
out, &
out, op, &box);
2391 if (rcode < 0)
return rcode;
2399#define T(_x) [T_OP_ ## _x ## _EQ] = T_ ## _x
2427 if (dst->immutable) {
2440 if (src == dst)
return 0;
2466 while ((vb = fr_value_box_list_next(&src->vb_group, vb)) != NULL) {
2468 if (rcode < 0)
break;
2488 if (dst->immutable) {
2498 switch (src->type) {
2558#define COMP(_type, _field) case FR_TYPE_ ## _type: dst->vb_ ##_field = (_field ## _t) ~src->vb_ ##_field; break
2559 switch (src->type) {
2561 COMP(UINT16, uint16);
2562 COMP(UINT32, uint32);
2563 COMP(UINT64, uint64);
2577 }
else if (op ==
T_SUB) {
2593 }
else if (op ==
T_NOT) {
2598 dst->vb_bool = !
value;
2622 switch (
item->type) {
2632 if (
item->vb_length != 0)
return false;
2650 bool invert =
false;
2651 bool a_empty, b_empty;
2679 if (a_empty && b_empty) {
2700 if (rcode < 0)
return rcode;
2706 if (!dst->vb_bool)
continue;
2711 dst->vb_bool = !invert;
2722 dst->vb_bool = invert;
#define UNCONST(_type, _ptr)
Remove const qualification from a pointer.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
static int calc_date(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
static const fr_type_t upcast_cmp[FR_TYPE_MAX+1][FR_TYPE_MAX+1]
Updates type (a,b) -> c.
static int calc_ipv4_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
static int get_ipv6_prefix(uint8_t const *in)
static const fr_binary_op_t calc_type[FR_TYPE_MAX+1]
Map output type to its associated function.
static int calc_ipv6_addr(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
static int invalid_type(fr_type_t type)
static const fr_type_t upcast_op[FR_TYPE_MAX+1][FR_TYPE_MAX+1]
Updates type (a,b) -> c.
static int calc_float32(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
#define COERCE_A(_type, _enumv)
static int calc_ipv4_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
static const fr_type_t upcast_unsigned[FR_TYPE_MAX+1]
static int calc_uint64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
static int calc_octets(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
static int calc_combo_ip_addr(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
static int calc_ipv6_prefix(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
static int cast_ipv6_addr(fr_value_box_t *out, fr_value_box_t const *in)
static int handle_result(fr_type_t type, fr_token_t op, int rcode)
static int calc_int64(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
static int calc_bool(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
static int calc_string(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
int fr_value_calc_list_cmp(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_list_t const *list1, fr_token_t op, fr_value_box_list_t const *list2)
static int calc_combo_ip_prefix(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
static int calc_time_delta(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
int(* fr_binary_op_t)(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
static int cast_ipv4_addr(fr_value_box_t *out, fr_value_box_t const *in)
static bool fr_value_calc_list_empty(fr_value_box_list_t const *list)
static int calc_float64(UNUSED TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *in1, fr_token_t op, fr_value_box_t const *in2)
int fr_value_calc_nary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_token_t op, fr_value_box_t const *group)
Calculate DST = OP { A, B, C, ... }.
#define COERCE_B(_type, _enumv)
static const fr_token_t assignment2op[T_TOKEN_LAST]
int fr_value_calc_assignment_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
Calculate DST OP SRC.
int fr_value_calc_binary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t hint, fr_value_box_t const *a, fr_token_t op, fr_value_box_t const *b)
Calculate DST = A OP B.
#define COMP(_type, _field)
int fr_value_calc_unary_op(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_token_t op, fr_value_box_t const *src)
Calculate unary operations.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#define FR_DBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
Create a function local and thread local extensible dbuff.
static void * item(fr_lst_t const *lst, fr_lst_index_t idx)
#define fr_sub(_out, _a, _b)
Subtracts two integers.
#define fr_add(_out, _a, _b)
Adds two integers.
#define fr_multiply(_out, _a, _b)
Multiplies two integers together.
@ FR_TYPE_TIME_DELTA
A period of time measured in nanoseconds.
@ FR_TYPE_FLOAT32
Single precision floating point.
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_INT8
8 Bit signed integer.
@ FR_TYPE_ETHERNET
48 Bit Mac-Address.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_UINT16
16 Bit unsigned integer.
@ FR_TYPE_INT64
64 Bit signed integer.
@ FR_TYPE_INT16
16 Bit signed integer.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_INT32
32 Bit signed integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_BOOL
A truth value.
@ FR_TYPE_SIZE
Unsigned integer capable of representing any memory address on the local system.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_IFID
Interface ID.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
@ FR_TYPE_FLOAT64
Double precision floating point.
#define fr_sbuff_start(_sbuff_or_marker)
#define fr_sbuff_used(_sbuff_or_marker)
#define FR_SBUFF_TALLOC_THREAD_LOCAL(_out, _init, _max)
fr_aka_sim_id_type_t type
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
#define fr_time_delta_wrap(_time)
#define fr_time_delta_ispos(_a)
static fr_unix_time_t fr_unix_time_from_integer(bool *overflow, int64_t integer, fr_time_res_t res)
static uint64_t fr_unix_time_unwrap(fr_unix_time_t time)
char const * fr_tokens[T_TOKEN_LAST]
const bool fr_comparison_op[T_TOKEN_LAST]
int fr_regex_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two boxes using an operator.
char const * fr_strerror(void)
Get the last library error.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
#define fr_type_is_structural(_x)
#define fr_type_is_numeric(_x)
#define fr_type_is_signed(_x)
#define fr_type_is_leaf(_x)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
#define fr_type_is_integer(_x)
ssize_t fr_value_box_list_concat_as_string(fr_value_box_t *safety, fr_sbuff_t *sbuff, fr_value_box_list_t *list, char const *sep, size_t sep_len, fr_sbuff_escape_rules_t const *e_rules, fr_value_box_list_action_t proc_action, fr_value_box_safe_for_t safe_for, bool flatten)
Concatenate a list of value boxes together.
int fr_value_box_cast(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t dst_type, fr_dict_attr_t const *dst_enumv, fr_value_box_t const *src)
Convert one type of fr_value_box_t to another.
int fr_value_box_copy(TALLOC_CTX *ctx, fr_value_box_t *dst, const fr_value_box_t *src)
Copy value data verbatim duplicating any buffers.
int fr_value_box_cmp_op(fr_token_t op, fr_value_box_t const *a, fr_value_box_t const *b)
Compare two attributes using an operator.
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
void fr_value_box_memdup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Assign a buffer to a box, but don't copy it.
void fr_value_box_copy_shallow(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_value_box_t const *src)
Perform a shallow copy of a value_box.
ssize_t fr_value_box_list_concat_as_octets(fr_value_box_t *safety, fr_dbuff_t *dbuff, fr_value_box_list_t *list, uint8_t const *sep, size_t sep_len, fr_value_box_list_action_t proc_action, bool flatten)
Concatenate a list of value boxes together.
void fr_value_box_clear_value(fr_value_box_t *data)
Clear/free any existing value.
void fr_value_box_safety_merge(fr_value_box_t *out, fr_value_box_t const *in)
Merge safety results.
void fr_value_box_safety_copy(fr_value_box_t *out, fr_value_box_t const *in)
Copy the safety values from one box to another.
void fr_value_box_clear(fr_value_box_t *data)
Clear/free any existing value and metadata.
int fr_value_box_bstrndup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Copy a string to to a fr_value_box_t.
void fr_value_box_bstrndup_shallow(fr_value_box_t *dst, fr_dict_attr_t const *enumv, char const *src, size_t len, bool tainted)
Assign a string to to a fr_value_box_t.
int fr_value_box_memdup(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_dict_attr_t const *enumv, uint8_t const *src, size_t len, bool tainted)
Copy a buffer to a fr_value_box_t.
@ FR_VALUE_BOX_LIST_NONE
Do nothing to processed boxes.
#define fr_value_box_init_null(_vb)
Initialise an empty/null box that will be filled later.
#define fr_value_box_init(_vb, _type, _enumv, _tainted)
Initialise a fr_value_box_t.
#define fr_value_box_list_foreach(_list_head, _iter)
static size_t char ** out
#define FR_VALUE_BOX_SAFE_FOR_ANY