24RCSID(
"$Id: 89efb453464036168dd77e7eacac9485b2452565 $")
28#include <freeradius-devel/util/regex.h>
29#include <freeradius-devel/util/atexit.h>
31#if defined(HAVE_REGEX_PCRE) || (defined(HAVE_REGEX_PCRE2) && defined(PCRE2_CONFIG_JIT))
32#ifndef FR_PCRE_JIT_STACK_MIN
33# define FR_PCRE_JIT_STACK_MIN (128 * 1024)
35#ifndef FR_PCRE_JIT_STACK_MAX
36# define FR_PCRE_JIT_STACK_MAX (512 * 1024)
77#ifdef HAVE_REGEX_PCRE2
91 TALLOC_CTX *alloc_ctx;
92 pcre2_general_context *gcontext;
93 pcre2_compile_context *ccontext;
94 pcre2_match_context *mcontext;
95#ifdef PCRE2_CONFIG_JIT
96 pcre2_jit_stack *jit_stack;
104static _Thread_local fr_pcre2_tls_t *fr_pcre2_tls;
111static void *_pcre2_talloc(PCRE2_SIZE to_alloc,
UNUSED void *uctx)
113 return talloc_array(fr_pcre2_tls->alloc_ctx,
uint8_t, to_alloc);
121static void _pcre2_talloc_free(
void *to_free,
UNUSED void *uctx)
130static int _pcre2_tls_free(fr_pcre2_tls_t *tls)
132 if (tls->gcontext) pcre2_general_context_free(tls->gcontext);
133 if (tls->ccontext) pcre2_compile_context_free(tls->ccontext);
134 if (tls->mcontext) pcre2_match_context_free(tls->mcontext);
135#ifdef PCRE2_CONFIG_JIT
136 if (tls->jit_stack) pcre2_jit_stack_free(tls->jit_stack);
142static int _pcre2_tls_free_on_exit(
void *arg)
150static int fr_pcre2_tls_init(
void)
154 if (
unlikely(fr_pcre2_tls != NULL))
return 0;
156 fr_pcre2_tls = tls = talloc_zero(NULL, fr_pcre2_tls_t);
158 talloc_set_destructor(tls, _pcre2_tls_free);
160 tls->gcontext = pcre2_general_context_create(_pcre2_talloc, _pcre2_talloc_free, NULL);
161 if (!tls->gcontext) {
166 tls->ccontext = pcre2_compile_context_create(tls->gcontext);
167 if (!tls->ccontext) {
171 _pcre2_tls_free(tls);
175 tls->mcontext = pcre2_match_context_create(tls->gcontext);
176 if (!tls->mcontext) {
181#ifdef PCRE2_CONFIG_JIT
182 pcre2_config(PCRE2_CONFIG_JIT, &tls->do_jit);
184 tls->jit_stack = pcre2_jit_stack_create(FR_PCRE_JIT_STACK_MIN, FR_PCRE_JIT_STACK_MAX, tls->gcontext);
185 if (!tls->jit_stack) {
189 pcre2_jit_stack_assign(tls->mcontext, NULL, tls->jit_stack);
208static int _regex_free(regex_t *preg)
210 if (preg->compiled) pcre2_code_free(preg->compiled);
235ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **
out,
char const *pattern,
size_t len,
236 fr_regex_flags_t
const *flags,
bool subcaptures,
bool runtime)
251 if (
unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0))
return -1;
263 if (flags->ignore_case) cflags |= PCRE2_CASELESS;
264 if (flags->multiline) cflags |= PCRE2_MULTILINE;
265 if (flags->dot_all) cflags |= PCRE2_DOTALL;
266 if (flags->unicode) cflags |= PCRE2_UTF;
267 if (flags->extended) cflags |= PCRE2_EXTENDED;
270 if (!subcaptures) cflags |= PCRE2_NO_AUTO_CAPTURE;
272 preg = talloc_zero(ctx, regex_t);
273 talloc_set_destructor(preg, _regex_free);
275 preg->compiled = pcre2_compile((PCRE2_SPTR8)pattern, len,
276 cflags, &ret, &offset, fr_pcre2_tls->ccontext);
277 if (!preg->compiled) {
278 PCRE2_UCHAR errbuff[128];
280 pcre2_get_error_message(ret, errbuff,
sizeof(errbuff));
288 preg->precompiled =
true;
290#ifdef PCRE2_CONFIG_JIT
296 if (fr_pcre2_tls->do_jit) {
297 ret = pcre2_jit_compile(preg->compiled, PCRE2_JIT_COMPLETE);
299 PCRE2_UCHAR errbuff[128];
301 pcre2_get_error_message(ret, errbuff,
sizeof(errbuff));
328int regex_exec(regex_t *preg,
char const *subject,
size_t len, fr_regmatch_t *regmatch)
333 char *our_subject = NULL;
334 bool dup_subject =
true;
335 pcre2_match_data *match_data;
340 if (
unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0))
return -1;
343#ifdef PCRE2_COPY_MATCHED_SUBJECT
348# ifdef PCRE2_CONFIG_JIT
365 options |= PCRE2_COPY_MATCHED_SUBJECT;
366# ifdef PCRE2_CONFIG_JIT
383 regmatch->subject = subject;
394 match_data = pcre2_match_data_create_from_pattern(preg->compiled, fr_pcre2_tls->gcontext);
400 match_data = regmatch->match_data;
403#ifdef PCRE2_CONFIG_JIT
405 ret = pcre2_jit_match(preg->compiled, (PCRE2_SPTR8)subject, len, 0, options,
406 match_data, fr_pcre2_tls->mcontext);
410 ret = pcre2_match(preg->compiled, (PCRE2_SPTR8)subject, len, 0, options,
411 match_data, fr_pcre2_tls->mcontext);
413 if (!regmatch) pcre2_match_data_free(match_data);
415 PCRE2_UCHAR errbuff[128];
419 if (ret == PCRE2_ERROR_NOMATCH) {
420 if (regmatch) regmatch->used = 0;
424 pcre2_get_error_message(ret, errbuff,
sizeof(errbuff));
430 if (regmatch) regmatch->used = ret;
453int regex_substitute(TALLOC_CTX *ctx,
char **
out,
size_t max_out, regex_t *preg, fr_regex_flags_t
const *flags,
454 char const *subject,
size_t subject_len,
455 char const *replacement,
size_t replacement_len,
456 fr_regmatch_t *regmatch)
460 size_t buff_len, actual_len;
463#ifndef PCRE2_COPY_MATCHED_SUBJECT
464 char *our_subject = NULL;
470 if (
unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0))
return -1;
478#ifndef PCRE2_COPY_MATCHED_SUBJECT
485 subject = our_subject =
talloc_bstrndup(regmatch, subject, subject_len);
503 options |= PCRE2_COPY_MATCHED_SUBJECT;
510 actual_len = buff_len = subject_len + 1;
511 buff = talloc_array(ctx,
char, buff_len);
513#ifndef PCRE2_COPY_MATCHED_SUBJECT
520 options |= PCRE2_SUBSTITUTE_OVERFLOW_LENGTH;
521 if (flags->global) options |= PCRE2_SUBSTITUTE_GLOBAL;
533 ret = pcre2_substitute(preg->compiled,
534 (PCRE2_SPTR8)subject, (PCRE2_SIZE)subject_len, 0,
535 options, NULL, fr_pcre2_tls->mcontext,
536 (PCRE2_UCHAR
const *)replacement, replacement_len, (PCRE2_UCHAR *)
buff, &actual_len);
539 PCRE2_UCHAR errbuff[128];
541#ifndef PCRE2_COPY_MATCHED_SUBJECT
546 if (ret == PCRE2_ERROR_NOMEMORY) {
547 if ((max_out > 0) && (actual_len > max_out)) {
549 "exceeds max string length (%zu)", actual_len - 1, max_out - 1);
557 if (actual_len == buff_len) {
561 buff_len = actual_len;
562 buff = talloc_array(ctx,
char, buff_len);
566 if (ret == PCRE2_ERROR_NOMATCH) {
567 if (regmatch) regmatch->used = 0;
571 pcre2_get_error_message(ret, errbuff,
sizeof(errbuff));
582 if (actual_len < (buff_len - 1)) {
590 if (regmatch) regmatch->used = ret;
603uint32_t regex_subcapture_count(regex_t
const *preg)
607 if (pcre2_pattern_info(preg->compiled, PCRE2_INFO_CAPTURECOUNT, &
count) != 0) {
619static int _pcre2_match_data_free(fr_regmatch_t *regmatch)
621 pcre2_match_data_free(regmatch->match_data);
633fr_regmatch_t *regex_match_data_alloc(TALLOC_CTX *ctx,
uint32_t count)
635 fr_regmatch_t *regmatch;
640 if (
unlikely(!fr_pcre2_tls) && (fr_pcre2_tls_init() < 0))
return NULL;
642 regmatch = talloc(ctx, fr_regmatch_t);
649 regmatch->match_data = pcre2_match_data_create(
count, fr_pcre2_tls->gcontext);
650 if (!regmatch->match_data) {
654 talloc_set_type(regmatch->match_data, pcre2_match_data);
656 talloc_set_destructor(regmatch, _pcre2_match_data_free);
665#elif defined(HAVE_REGEX_PCRE)
670#if (PCRE_MAJOR >= 8) && (PCRE_MINOR >= 32) && defined(PCRE_CONFIG_JIT)
671# define HAVE_PCRE_JIT_EXEC 1
678 TALLOC_CTX *alloc_ctx;
679#ifdef HAVE_PCRE_JIT_EXEC
680 pcre_jit_stack *jit_stack;
684static _Thread_local fr_pcre_tls_t *fr_pcre_tls;
685static bool fr_pcre_study_flags;
692static void *_pcre_talloc(
size_t to_alloc)
694 return talloc_array(fr_pcre_tls->alloc_ctx,
uint8_t, to_alloc);
697static void _pcre_talloc_free(
void *to_free)
702static int _pcre_globals_reset(
UNUSED void *uctx)
709static int _pcre_globals_configure(
UNUSED void *uctx)
711#ifdef PCRE_CONFIG_JIT
720 pcre_config(PCRE_CONFIG_JIT, &do_jit);
722 if (do_jit) fr_pcre_study_flags |= PCRE_STUDY_JIT_COMPILE;
724 pcre_malloc = _pcre_talloc;
725 pcre_free = _pcre_talloc_free;
734static int _pcre_tls_free(fr_pcre_tls_t *tls)
736#ifdef HAVE_PCRE_JIT_EXEC
737 if (tls->jit_stack) pcre_jit_stack_free(tls->jit_stack);
742static int _pcre_tls_free_on_exit(
void *arg)
750static inline CC_HINT(always_inline)
int pcre_tls_init(
void)
754 if (fr_pcre_tls)
return 0;
756 tls = talloc_zero(NULL, fr_pcre_tls_t);
758 talloc_set_destructor(tls, _pcre_tls_free);
766#ifdef HAVE_PCRE_JIT_EXEC
770 tls->jit_stack = pcre_jit_stack_alloc(FR_PCRE_JIT_STACK_MIN, FR_PCRE_JIT_STACK_MAX);
782static int _regex_free(regex_t *preg)
784 if (preg->compiled) pcre_free(preg->compiled);
785#ifdef PCRE_CONFIG_JIT
786 if (preg->extra) pcre_free_study(preg->extra);
788 if (preg->extra) pcre_free(preg->extra);
814ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **
out,
char const *pattern,
size_t len,
815 fr_regex_flags_t
const *flags,
bool subcaptures,
bool runtime)
823 fr_atexit_global_once_ret(&ret, _pcre_globals_configure, _pcre_globals_reset, NULL);
827 if (
unlikely(pcre_tls_init() < 0))
return -1;
844 fr_strerror_const(
"g - Global matching/substitution not supported with libpcre");
847 if (flags->ignore_case) cflags |= PCRE_CASELESS;
848 if (flags->multiline) cflags |= PCRE_MULTILINE;
849 if (flags->dot_all) cflags |= PCRE_DOTALL;
850 if (flags->unicode) cflags |= PCRE_UTF8;
851 if (flags->extended) cflags |= PCRE_EXTENDED;
854 if (!subcaptures) cflags |= PCRE_NO_AUTO_CAPTURE;
856 preg = talloc_zero(ctx, regex_t);
861 talloc_set_destructor(preg, _regex_free);
863 preg->compiled = pcre_compile(pattern, cflags, &error, &offset, NULL);
864 if (!preg->compiled) {
872 preg->precompiled =
true;
873 preg->extra = pcre_study(preg->compiled, fr_pcre_study_flags, &error);
889 if (fr_pcre_study_flags & PCRE_STUDY_JIT_COMPILE) {
892 pcre_fullinfo(preg->compiled, preg->extra, PCRE_INFO_JIT, &jitd);
893 if (jitd) preg->jitd =
true;
904 {
L(
"PCRE_ERROR_NOMATCH"), PCRE_ERROR_NOMATCH },
905 {
L(
"PCRE_ERROR_NULL"), PCRE_ERROR_NULL },
906 {
L(
"PCRE_ERROR_BADOPTION"), PCRE_ERROR_BADOPTION },
907 {
L(
"PCRE_ERROR_BADMAGIC"), PCRE_ERROR_BADMAGIC },
908 {
L(
"PCRE_ERROR_UNKNOWN_OPCODE"), PCRE_ERROR_UNKNOWN_OPCODE },
909 {
L(
"PCRE_ERROR_NOMEMORY"), PCRE_ERROR_NOMEMORY },
910 {
L(
"PCRE_ERROR_NOSUBSTRING"), PCRE_ERROR_NOSUBSTRING },
911 {
L(
"PCRE_ERROR_MATCHLIMIT"), PCRE_ERROR_MATCHLIMIT },
912 {
L(
"PCRE_ERROR_CALLOUT"), PCRE_ERROR_CALLOUT },
913 {
L(
"PCRE_ERROR_BADUTF8"), PCRE_ERROR_BADUTF8 },
914 {
L(
"PCRE_ERROR_BADUTF8_OFFSET"), PCRE_ERROR_BADUTF8_OFFSET },
915 {
L(
"PCRE_ERROR_PARTIAL"), PCRE_ERROR_PARTIAL },
916 {
L(
"PCRE_ERROR_BADPARTIAL"), PCRE_ERROR_BADPARTIAL },
917 {
L(
"PCRE_ERROR_INTERNAL"), PCRE_ERROR_INTERNAL },
918 {
L(
"PCRE_ERROR_BADCOUNT"), PCRE_ERROR_BADCOUNT },
919 {
L(
"PCRE_ERROR_DFA_UITEM"), PCRE_ERROR_DFA_UITEM },
920 {
L(
"PCRE_ERROR_DFA_UCOND"), PCRE_ERROR_DFA_UCOND },
921 {
L(
"PCRE_ERROR_DFA_UMLIMIT"), PCRE_ERROR_DFA_UMLIMIT },
922 {
L(
"PCRE_ERROR_DFA_WSSIZE"), PCRE_ERROR_DFA_WSSIZE },
923 {
L(
"PCRE_ERROR_DFA_RECURSE"), PCRE_ERROR_DFA_RECURSE },
924 {
L(
"PCRE_ERROR_RECURSIONLIMIT"), PCRE_ERROR_RECURSIONLIMIT },
925 {
L(
"PCRE_ERROR_NULLWSLIMIT"), PCRE_ERROR_NULLWSLIMIT },
926 {
L(
"PCRE_ERROR_BADNEWLINE"), PCRE_ERROR_BADNEWLINE },
927 {
L(
"PCRE_ERROR_BADOFFSET"), PCRE_ERROR_BADOFFSET },
928 {
L(
"PCRE_ERROR_SHORTUTF8"), PCRE_ERROR_SHORTUTF8 },
929 {
L(
"PCRE_ERROR_RECURSELOOP"), PCRE_ERROR_RECURSELOOP },
930 {
L(
"PCRE_ERROR_JIT_STACKLIMIT"), PCRE_ERROR_JIT_STACKLIMIT },
931 {
L(
"PCRE_ERROR_BADMODE"), PCRE_ERROR_BADMODE },
932 {
L(
"PCRE_ERROR_BADENDIANNESS"), PCRE_ERROR_BADENDIANNESS },
933 {
L(
"PCRE_ERROR_DFA_BADRESTART"), PCRE_ERROR_DFA_BADRESTART },
934 {
L(
"PCRE_ERROR_JIT_BADOPTION"), PCRE_ERROR_JIT_BADOPTION },
935 {
L(
"PCRE_ERROR_BADLENGTH"), PCRE_ERROR_BADLENGTH },
936#ifdef PCRE_ERROR_UNSET
937 {
L(
"PCRE_ERROR_UNSET"), PCRE_ERROR_UNSET },
940static size_t regex_pcre_error_str_len =
NUM_ELEMENTS(regex_pcre_error_str);
953int regex_exec(regex_t *preg,
char const *subject,
size_t len, fr_regmatch_t *regmatch)
958 if (
unlikely(pcre_tls_init() < 0))
return -1;
966 matches = regmatch->allocd;
971 memset(regmatch->match_data, 0,
sizeof(regmatch->match_data[0]) * matches);
975#ifdef HAVE_PCRE_JIT_EXEC
977 ret = pcre_jit_exec(preg->compiled, preg->extra, subject, len, 0, 0,
978 regmatch ? (
int *)regmatch->match_data : NULL, matches * 3, fr_pcre_tls->jit_stack);
982 ret = pcre_exec(preg->compiled, preg->extra, subject, len, 0, 0,
983 regmatch ? (
int *)regmatch->match_data : NULL, matches * 3);
986 if (ret == PCRE_ERROR_NOMATCH)
return 0;
997 if (regmatch && (ret > 0)) {
998 regmatch->used = ret;
1002 if (!regmatch->subject) {
1017uint32_t regex_subcapture_count(regex_t
const *preg)
1021 if (pcre_fullinfo(preg->compiled, preg->extra, PCRE_INFO_CAPTURECOUNT, &
count) != 0) {
1046static int _regex_free(regex_t *preg)
1077ssize_t regex_compile(TALLOC_CTX *ctx, regex_t **
out,
char const *pattern,
size_t len,
1078 fr_regex_flags_t
const *flags,
bool subcaptures,
UNUSED bool runtime)
1081 int cflags = REG_EXTENDED;
1093 if (flags->global) {
1094 fr_strerror_const(
"g - Global matching/substitution not supported with posix-regex");
1097 if (flags->dot_all) {
1098 fr_strerror_const(
"s - Single line matching is not supported with posix-regex");
1101 if (flags->unicode) {
1105 if (flags->extended) {
1106 fr_strerror_const(
"x - Whitespace and comments not supported with posix-regex");
1110 if (flags->ignore_case) cflags |= REG_ICASE;
1111 if (flags->multiline) cflags |= REG_NEWLINE;
1115 if (!subcaptures) cflags |= REG_NOSUB;
1117#ifndef HAVE_REGNCOMP
1122 p += strlen(pattern);
1124 if ((
size_t)(p - pattern) != len) {
1125 fr_strerror_printf(
"Found null in pattern at offset %zu. Pattern unsafe for compilation",
1127 return -(p - pattern);
1130 preg = talloc_zero(ctx, regex_t);
1131 if (!preg)
return 0;
1133 ret = regcomp(preg, pattern, cflags);
1136 preg = talloc_zero(ctx, regex_t);
1137 if (!preg)
return 0;
1138 ret = regncomp(preg, pattern, len, cflags);
1143 regerror(ret, preg, errbuf,
sizeof(errbuf));
1151 talloc_set_destructor(preg, _regex_free);
1173int regex_exec(regex_t *preg,
char const *subject,
size_t len, fr_regmatch_t *regmatch)
1184 matches = regmatch->allocd;
1189 memset(regmatch->match_data, 0,
sizeof(regmatch->match_data[0]) * matches);
1193#ifndef HAVE_REGNEXEC
1198 p += strlen(subject);
1200 if ((
size_t)(p - subject) != len) {
1201 fr_strerror_printf(
"Found null in subject at offset %zu. String unsafe for evaluation",
1203 if (regmatch) regmatch->used = 0;
1206 ret = regexec(preg, subject, matches, regmatch ? regmatch->match_data : NULL, 0);
1209 ret = regnexec(preg, subject, len, matches, regmatch ? regmatch->match_data : NULL, 0);
1212 if (ret != REG_NOMATCH) {
1215 regerror(ret, preg, errbuf,
sizeof(errbuf));
1229 regmatch->used = preg->re_nsub + 1;
1233 if (!regmatch->subject) {
1252# if defined(HAVE_REGEX_POSIX) || defined(HAVE_REGEX_PCRE)
1261fr_regmatch_t *regex_match_data_alloc(TALLOC_CTX *ctx,
uint32_t count)
1263 fr_regmatch_t *regmatch;
1276 regmatch->match_data = talloc_array(regmatch, regmatch_t,
count);
1277 if (
unlikely(!regmatch->match_data))
goto error;
1279 regmatch->allocd =
count;
1281 regmatch->subject = NULL;
1318 switch (*our_in.
p) {
1319#define DO_REGEX_FLAG(_f, _c) \
1321 if (err_on_dup && out->_f) { \
1322 fr_strerror_printf("Duplicate regex flag '%c'", *our_in.p); \
1323 if (err) *err = -2; \
1324 FR_SBUFF_ERROR_RETURN(&our_in); \
1329 DO_REGEX_FLAG(global,
'g');
1330 DO_REGEX_FLAG(ignore_case,
'i');
1331 DO_REGEX_FLAG(multiline,
'm');
1332 DO_REGEX_FLAG(dot_all,
's');
1333 DO_REGEX_FLAG(unicode,
'u');
1334 DO_REGEX_FLAG(extended,
'x');
1361#define DO_REGEX_FLAG(_f, _c) \
1362 if (flags->_f) FR_SBUFF_IN_CHAR_RETURN(&our_sbuff, _c)
1364 DO_REGEX_FLAG(global,
'g');
1365 DO_REGEX_FLAG(ignore_case,
'i');
1366 DO_REGEX_FLAG(multiline,
'm');
1367 DO_REGEX_FLAG(dot_all,
's');
1368 DO_REGEX_FLAG(unicode,
'u');
1369 DO_REGEX_FLAG(extended,
'x');
1395 TALLOC_CTX *ctx = NULL;
1398 regex_t *regex = NULL;
1411 if (!ctx)
return -1;
1418 if (slen < 0)
return slen;
1424 lhs = a->vb_strvalue;
1425 lhs_len = a->vb_length;
1428 if (regex_compile(ctx, ®ex, b->vb_strvalue, b->vb_length, NULL,
false,
true) < 0) {
1433#ifdef STATIC_ANALYZER
1440 rcode = regex_exec(regex, lhs, lhs_len, NULL);
1442 if (rcode < 0)
return rcode;
#define fr_atexit_thread_local(_name, _free, _uctx)
#define L(_str)
Helper for initialising arrays of string literals.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_OCTETS
Raw octets.
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
#define fr_sbuff_extend(_sbuff_or_marker)
#define FR_SBUFF_ERROR_RETURN(_sbuff_or_marker)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define SBUFF_CHAR_UNPRINTABLES_EXTENDED
#define FR_SBUFF(_sbuff_or_marker)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
#define SBUFF_CHAR_UNPRINTABLES_LOW
Set of terminal elements.
static char buff[sizeof("18446744073709551615")+3]
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
An element in an arbitrarily ordered array of name to num mappings.
char * talloc_bstr_realloc(TALLOC_CTX *ctx, char *in, size_t inlen)
Trim a bstr (char) buffer.
char * talloc_bstrndup(TALLOC_CTX *ctx, char const *in, size_t inlen)
Binary safe strndup function.
#define talloc_zero_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
static int talloc_const_free(void const *ptr)
Free const'd memory.
static TALLOC_CTX * talloc_init_const(char const *name)
Allocate a top level chunk with a constant name.
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.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static fr_slen_t fr_value_box_aprint(TALLOC_CTX *ctx, char **out, fr_value_box_t const *data, fr_sbuff_escape_rules_t const *e_rules) 1(fr_value_box_print
static size_t char ** out