23RCSID(
"$Id: 661334bc89b7716c9388376c5ad1d5e448ed7191 $")
25#include <freeradius-devel/util/misc.h>
26#include <freeradius-devel/util/syserror.h>
27#include <freeradius-devel/util/atexit.h>
40static_assert(
sizeof(
long long) >=
sizeof(int64_t),
"long long must be as wide or wider than an int64_t");
41static_assert(
sizeof(
unsigned long long) >=
sizeof(uint64_t),
"long long must be as wide or wider than an uint64_t");
58#if defined(STATIC_ANALYZER) || !defined(NDEBUG)
59# define _CHECK_SBUFF_INIT(_sbuff, _ret) do { if (!(_sbuff)->extend && (unlikely(!(_sbuff)->buff) || unlikely(!(_sbuff)->start) || unlikely(!(_sbuff)->end) || unlikely(!(_sbuff)->p))) return _ret; } while (0)
60# define CHECK_SBUFF_INIT(_sbuff) _CHECK_SBUFF_INIT(_sbuff, 0)
66# define CHECK_SBUFF_INIT_ERR(_sbuff) _CHECK_SBUFF_INIT(_sbuff, FR_SBUFF_ERR_UNINITIALISED)
67# define CHECK_SBUFF_WRITEABLE(_sbuff) do { CHECK_SBUFF_INIT(_sbuff); if (unlikely((_sbuff)->is_const)) return 0; } while (0)
70# define CHECK_SBUFF_INIT(_sbuff)
71# define CHECK_SBUFF_INIT_ERR(_sbuff)
72# define CHECK_SBUFF_WRITEABLE(_sbuff)
82 [
'+'] =
true, [
'-'] =
true
87 [
'-'] =
true, [
'+'] =
true, [
'e'] =
true, [
'E'] =
true, [
'.'] =
true,
113 [
'-'] =
true, [
'_'] =
true,
116 [
'\t'] =
true, [
'\n'] =
true, [
'\r'] =
true, [
'\f'] =
true, [
'\v'] =
true, [
' '] =
true,
120 [
'\n'] =
true, [
'\r'] =
true
124 [
'\t'] =
true, [
' '] =
true,
139 char const *i_start,
char const *i_end)
142 size_t i_len = i_end - i_start;
144 if (
unlikely((o_end < o_start) || (i_end < i_start)))
return 0;
146 diff = (o_end - o_start) - (i_len);
147 if (diff < 0)
return -1;
149 if ((i_start > o_end) || (i_end < o_start)) {
150 memcpy(o_start, i_start, i_len);
152 memmove(o_start, i_start, i_len);
158static inline CC_HINT(always_inline)
size_t min(
size_t x,
size_t y)
160 return x < y ? x : y;
176 old_buff = sbuff->
buff;
184 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
187 sbuff_i->
buff = new_buff;
188 sbuff_i->
start = new_buff +
min(new_len, sbuff_i->
start - old_buff);
189 sbuff_i->
end = sbuff_i->
buff + new_len;
190 *(sbuff_i->
end) =
'\0';
192 sbuff_i->
p = new_buff +
min(new_len, sbuff_i->
p - old_buff);
194 for (m_i = sbuff_i->m; m_i; m_i = m_i->
next) m_i->p = new_buff +
min(new_len, m_i->p - old_buff);
216 size_t max_shift = shift;
217 bool reterminate =
false;
230 reterminate = (sbuff->
p < sbuff->
end) && (*sbuff->
p ==
'\0') && !sbuff->is_const;
238 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
241 max_shift =
min(max_shift, sbuff_i->
p -
buff);
242 if (!max_shift)
return 0;
244 for (m_i = sbuff_i->m; m_i; m_i = m_i->
next) {
245 max_shift =
min(max_shift, m_i->p -
buff);
246 if (!max_shift)
return 0;
257 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
259 char *start = sbuff_i->
start;
262 sbuff_i->
p -= max_shift;
263 if (move_end) sbuff_i->
end -= max_shift;
264 sbuff_i->shifted += (max_shift - (start - sbuff_i->
start));
265 for (m_i = sbuff_i->m; m_i; m_i = m_i->
next) m_i->p -= max_shift;
272 if ((
buff + max_shift) < end) memmove(
buff,
buff + max_shift, end - (
buff + max_shift));
274 if (reterminate) *sbuff->
p =
'\0';
285 size_t read, available, total_read, shift;
291 if (fctx->
eof)
return 0;
293 if (extension == SIZE_MAX) extension = 0;
296 if (total_read >= fctx->
max) {
327 if (available > (fctx->
max - total_read)) available = fctx->
max - total_read;
328 if (available < extension) {
333 read = fread(sbuff->
end, 1, available, fctx->
file);
334 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
335 sbuff_i->
end += read;
340 if (read < available) {
341 if (!feof(fctx->
file)) {
383 size_t clen, nlen, elen = extension;
388 clen = sbuff->
buff ? talloc_array_length(sbuff->
buff) : 0;
396 if ((clen + elen) < tctx->
init) {
397 elen = (tctx->
init - clen) + 1;
402 }
else if (elen < clen) {
410 if (tctx->
max && ((clen + elen + 1) > tctx->
max)) {
411 elen = tctx->
max - clen;
414 "%zu bytes, max is %zu bytes",
415 extension, clen + extension, tctx->
max);
422 new_buff = talloc_realloc(tctx->
ctx, sbuff->
buff,
char, nlen);
446 size_t clen = 0, nlen = 1;
452 if (sbuff->
buff) clen = talloc_array_length(sbuff->
buff);
454 if (
len != SIZE_MAX) {
456 }
else if (sbuff->
buff){
457 nlen += (sbuff->
p - sbuff->
start);
461 new_buff = talloc_realloc(tctx->
ctx, sbuff->
buff,
char, nlen);
485 fr_sbuff_set_to_start(sbuff);
491 new_buff = talloc_realloc(tctx->
ctx, sbuff->
buff,
char, tctx->
init);
494 talloc_array_length(sbuff->
buff), tctx->
init);
497 sbuff->
buff = new_buff;
510#define FILL_OR_GOTO_DONE(_out, _in, _len) \
512 size_t _to_move = (_len); \
513 if (fr_sbuff_move(_out, _in, _to_move) < _to_move) { \
514 err = FR_SBUFF_ERR_NO_SPACE; \
526#define CONSTRAINED_END(_sbuff, _max, _used) \
527 (((_max) - (_used)) > fr_sbuff_remaining(_sbuff) ? (_sbuff)->end : (_sbuff)->p + ((_max) - (_used)))
547 for (i = 0; i < term->
len; i++) {
554 if (i > 0) *needle_len =
max;
584 if (!term)
return false;
586 if (p >
in->
end)
return false;
601 if (remaining == 0) {
602 if (!fr_sbuff_is_extendable(
in) && (idx[
'\0'] != 0))
return true;
607 if (!term_idx)
return false;
612 while (start <= end) {
617 elem = &term->
elem[mid];
620 ret = memcmp(p, elem->
str, tlen < (
size_t)remaining ? tlen : (
size_t)remaining);
625 if (remaining >= tlen)
return true;
640 mid = start + ((end - start) / 2);
664 for (i = 0; i <
len; i++)
FR_FAULT_LOG(
"\t\"%s\" (%zu)", elem[i] ? elem[i]->str :
"NULL", elem[i] ? elem[i]->
len : 0);
686#if !defined(NDEBUG) && defined(WITH_VERIFY_PTR)
699 while ((i < a->
len) && (j < b->
len)) {
705 tmp[num++] = &a->
elem[i++];
707 }
else if (cmp < 0) {
708 tmp[num++] = &a->
elem[i++];
710 }
else if (cmp > 0) {
711 tmp[num++] = &b->
elem[j++];
720 while (i < a->
len) tmp[num++] = &a->
elem[i++];
721 while (j < b->
len) tmp[num++] = &b->
elem[j++];
733 for (i = 0; i < num; i++)
out->elem[i] = *tmp[i];
735#if !defined(NDEBUG) && defined(WITH_VERIFY_PTR)
775 if (chunk_len > remaining) chunk_len = remaining;
809 fr_sbuff_marker(&m,
out);
826 if (
len == SIZE_MAX)
break;
833 if (chunk_len > remaining) chunk_len = remaining;
840 fr_sbuff_marker_release(&m);
846 fr_sbuff_marker_release(&m);
890 while ((p < end) && allowed[(
uint8_t)*p]) p++;
928 bool do_escape =
false;
932 size_t needle_len = 1;
933 char escape_chr = u_rules ? u_rules->
chr :
'\0';
958 if (escape_chr ==
'\0') {
964 }
else if (*p == escape_chr) {
1007 bool do_escape =
false;
1015 size_t needle_len = 1;
1031 fr_sbuff_marker(&c_s, &our_in);
1032 fr_sbuff_marker(&end, &our_in);
1033 fr_sbuff_marker_update_end(&end,
max);
1035 fr_sbuff_marker(&o_s,
out);
1071 fr_sbuff_marker(&m, &our_in);
1077 if ((fr_sbuff_out_uint8_hex(&escape, &our_in,
false) < 0) || (
fr_sbuff_behind(&m) != 3)) {
1079 fr_sbuff_marker_release(&m);
1085 fr_sbuff_marker_release(&m);
1089 fr_sbuff_marker_release(&m);
1106 fr_sbuff_marker(&m, &our_in);
1111 if ((fr_sbuff_out_uint8_oct(&escape, &our_in,
false) < 0) || (
fr_sbuff_behind(&m) != 3)) {
1113 fr_sbuff_marker_release(&m);
1119 fr_sbuff_marker_release(&m);
1123 fr_sbuff_marker_release(&m);
1137 if (u_rules->
subs[c] ==
'\0') {
1138 if (u_rules->
skip[c] ==
true)
goto next;
1194 copied = fr_sbuff_marker_release_behind(&o_s);
1214 [
't'] =
true, [
'T'] =
true,
1215 [
'f'] =
true, [
'F'] =
true,
1216 [
'y'] =
true, [
'Y'] =
true,
1217 [
'n'] =
true, [
'N'] =
true,
1220 if (fr_sbuff_is_in_charset(&our_in, bool_prefix)) {
1259 fr_strerror_const(
"Not a valid boolean value. Accepted values are 'yes', 'no', 'true', 'false'");
1275#define SBUFF_PARSE_INT_DEF(_name, _type, _min, _max, _max_char, _base) \
1276fr_sbuff_err_t fr_sbuff_out_##_name(_type *out, fr_sbuff_t *in, bool no_trailing) \
1278 char buff[_max_char + 1]; \
1279 char *end, *a_end; \
1281 fr_sbuff_err_t err; \
1284 fr_sbuff_t our_in = FR_SBUFF(in); \
1286 err = fr_sbuff_out_bstrncpy(&len, &FR_SBUFF_IN(buff, sizeof(buff)), &our_in, _max_char); \
1287 if (err != FR_SBUFF_OK) return err; \
1288 if (len == 0) return (fr_sbuff_remaining(in) == 0) ? FR_SBUFF_ERR_INPUT_EMPTY : FR_SBUFF_ERR_NOT_FOUND; \
1290 num = strtoll(buff, &end, _base); \
1291 cast_num = (_type)(num); \
1292 if (end == buff) return FR_SBUFF_ERR_NOT_FOUND; \
1293 if (num > cast_num) { \
1295 *out = (_type)(_max); \
1296 return FR_SBUFF_ERR_OVERFLOW; \
1298 if (((errno == EINVAL) && (num == 0)) || ((errno == ERANGE) && (num == LLONG_MAX))) goto overflow; \
1299 if (num < cast_num) { \
1301 *out = (_type)(_min); \
1302 return FR_SBUFF_ERR_UNDERFLOW; \
1304 if ((errno == ERANGE) && (num == LLONG_MIN)) goto underflow; \
1305 if (no_trailing && ((a_end = in->p + (end - buff)) < in->end)) { \
1306 if (isdigit((uint8_t) *a_end) || (((_base > 10) || ((_base == 0) && (len > 2) && (buff[0] == '0') && (buff[1] == 'x'))) && \
1307 ((tolower((uint8_t) *a_end) >= 'a') && (tolower((uint8_t) *a_end) <= 'f')))) { \
1308 *out = (_type)(_max); \
1309 return FR_SBUFF_ERR_TRAILING; \
1313 fr_sbuff_advance(in, end - buff); \
1314 return FR_SBUFF_OK; \
1333#define SBUFF_PARSE_UINT_DEF(_name, _type, _max, _max_char, _base) \
1334fr_sbuff_err_t fr_sbuff_out_##_name(_type *out, fr_sbuff_t *in, bool no_trailing) \
1336 char buff[_max_char + 1]; \
1337 char *end, *a_end; \
1339 fr_sbuff_err_t err; \
1340 unsigned long long num; \
1342 fr_sbuff_t our_in = FR_SBUFF(in); \
1344 err = fr_sbuff_out_bstrncpy(&len, &FR_SBUFF_IN(buff, sizeof(buff)), &our_in, _max_char); \
1345 if (err != FR_SBUFF_OK) return err; \
1346 if (len == 0) return (fr_sbuff_remaining(in) == 0) ? FR_SBUFF_ERR_INPUT_EMPTY : FR_SBUFF_ERR_NOT_FOUND; \
1347 if (buff[0] == '-') return FR_SBUFF_ERR_UNDERFLOW; \
1349 num = strtoull(buff, &end, _base); \
1350 cast_num = (_type)(num); \
1351 if (end == buff) return FR_SBUFF_ERR_NOT_FOUND; \
1352 if (num > cast_num) { \
1354 *out = (_type)(_max); \
1355 return FR_SBUFF_ERR_OVERFLOW; \
1357 if (((errno == EINVAL) && (num == 0)) || ((errno == ERANGE) && (num == ULLONG_MAX))) goto overflow; \
1358 if (no_trailing && ((a_end = in->p + (end - buff)) < in->end)) { \
1359 if (isdigit((uint8_t) *a_end) || (((_base > 10) || ((_base == 0) && (len > 2) && (buff[0] == '0') && (buff[1] == 'x'))) && \
1360 ((tolower((uint8_t) *a_end) >= 'a') && (tolower((uint8_t) *a_end) <= 'f')))) { \
1361 *out = (_type)(_max); \
1362 return FR_SBUFF_ERR_TRAILING; \
1366 fr_sbuff_advance(in, end - buff); \
1367 return FR_SBUFF_OK; \
1405#define SBUFF_PARSE_FLOAT_DEF(_name, _type, _func, _max_char) \
1406fr_sbuff_err_t fr_sbuff_out_##_name(_type *out, fr_sbuff_t *in, bool no_trailing) \
1408 char buff[_max_char + 1] = ""; \
1410 fr_sbuff_t our_in = FR_SBUFF(in); \
1411 fr_sbuff_err_t err; \
1414 err = fr_sbuff_out_bstrncpy_allowed(&len, &FR_SBUFF_OUT(buff, sizeof(buff)), &our_in, SIZE_MAX, sbuff_char_class_float); \
1418 case FR_SBUFF_ERR_NO_SPACE: \
1419 return FR_SBUFF_ERR_NOT_FOUND; \
1423 if (len == 0) return (fr_sbuff_remaining(in) == 0) ? FR_SBUFF_ERR_INPUT_EMPTY : FR_SBUFF_ERR_NOT_FOUND; \
1425 res = _func(buff, &end); \
1426 if (errno == ERANGE) return (res > 0) ? FR_SBUFF_ERR_OVERFLOW : FR_SBUFF_ERR_UNDERFLOW; \
1427 if (no_trailing && (*end != '\0')) return FR_SBUFF_ERR_TRAILING; \
1429 fr_sbuff_advance(in, end - buff); \
1430 return FR_SBUFF_OK; \
1454 size_t to_copy =
len;
1455 if (to_copy > o_remaining) to_copy = o_remaining;
1456 if (to_copy > i_remaining) to_copy = i_remaining;
1474 size_t to_copy =
len;
1475 if (to_copy > o_remaining) to_copy = o_remaining;
1476 if (to_copy > i_remaining) to_copy = i_remaining;
1494 size_t to_copy =
len;
1495 if (to_copy > o_remaining) to_copy = o_remaining;
1496 if (to_copy > i_remaining) to_copy = i_remaining;
1514 size_t to_copy =
len;
1515 if (to_copy > o_remaining) to_copy = o_remaining;
1516 if (to_copy > i_remaining) to_copy = i_remaining;
1539 sbuff->
p[
len] =
'\0';
1560 sbuff->
p[
len] =
'\0';
1584 sbuff->
p[
len] =
'\0';
1608 TALLOC_CTX *scratch;
1624 scratch = talloc_pool(NULL, 4096);
1648 TALLOC_CTX *scratch;
1707 char const *end =
in + inlen;
1737 sub = e_rules->subs[c];
1748 if (e_rules->esc[c]) {
1753 if (e_rules->do_oct) {
1756 }
else if (e_rules->do_hex) {
1787 char const *end =
in + inlen;
1790 if (!e_rules || !e_rules->chr)
return false;
1801 if (e_rules->subs[c] !=
'\0')
return false;
1803 if (e_rules->esc[c])
return false;
1842 char const *
const * p;
1844 .name = __FUNCTION__,
1848 if (sep) e_rules.subs[(
uint8_t)*sep] = *sep;
1852 for (p = array; *p; p++) {
1877 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
1886 found = memmem(sbuff->
p, needle_len, needle, needle_len);
1887 if (!found)
return 0;
1904 char const *p, *n_p;
1909 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
1919 end = p + needle_len;
1921 for (p = sbuff->
p, n_p = needle; p < end; p++, n_p++) {
1942 size_t needle_len = 0;
1948 while (total <
len) {
1955 while ((p < end) && allowed[(
uint8_t)*p]) {
1956 if (needle_len == 0) {
1996 if (p != end)
break;
2015 bool do_escape =
false;
2018 size_t needle_len = 1;
2028 while (total <
len) {
2036 if (escape_chr ==
'\0') {
2042 }
else if (*p == escape_chr) {
2052 if (p != end)
break;
2074 size_t clen = strlen(chr);
2081 if (
len < clen)
return NULL;
2083 while (total <= (
len - clen)) {
2122 while (total <
len) {
2129 found = memchr(our_sbuff.
p, c, end - our_sbuff.
p);
2158 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
2159 if (!needle_len)
return NULL;
2164 if (
len < needle_len)
return NULL;
2166 while (total <= (
len - needle_len)) {
2177 found = memmem(our_sbuff.
p, end - our_sbuff.
p, needle, needle_len);
2188 total +=
fr_sbuff_set(&our_sbuff, (end - needle_len) + 1);
2211 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
2212 if (!needle_len)
return NULL;
2217 if (
len < needle_len)
return NULL;
2219 while (total <= (
len - needle_len)) {
2225 for (p = our_sbuff.
p, n_p = needle, end = our_sbuff.
p + needle_len;
2253 if (*sbuff->
p != c)
return false;
2274 if (*sbuff->
p == c)
return false;
2289 char *p = sbuff->
p - 1;
2292 while ((p >= sbuff->
start) && to_trim[(
uint8_t)*p]) p--;
2295 if (slen != 0) fr_sbuff_terminate(sbuff);
2314 size_t needle_len = 1;
2379 if (unprintables[(
uint8_t)c]) {
2396 fprintf(fp,
"do_hex : %s\n",
escapes->do_hex ?
"yes" :
"no");
2397 fprintf(fp,
"do_oct : %s\n",
escapes->do_oct ?
"yes" :
"no");
2399 fprintf(fp,
"substitutions:\n");
2405 fprintf(fp,
"skips:\n");
2415 fprintf(fp,
"Terminal count %zu\n", tt->
len);
2417 for (i = 0; i < tt->
len; i++) fprintf(fp,
"\t\"%s\" (%zu)\n", tt->
elem[i].
str, tt->
elem[i].
len);
2422 fprintf(fp,
"Parse rules %p\n", p_rules);
2425 if (p_rules->escapes) {
2428 fprintf(fp,
"<none>\n");
2432 if (p_rules->terminals) {
2435 fprintf(fp,
"<none>\n");
2451 size_t len = talloc_array_length(array);
2452 char const *
const * p;
2453 char const *
const * end;
2455 .name = __FUNCTION__,
2459 if (sep) e_rules.subs[(
uint8_t)*sep] = *sep;
2461 for (p = array, end = array +
len;
2466 if (sep && ((p + 1) < end)) {
static int const char * fmt
bool fr_atexit_thread_local_alloc_disabled(void)
Has fr_atexit_thread_local_disable_alloc been called yet.
#define fr_atexit_thread_local(_name, _free, _uctx)
#define L(_str)
Helper for initialising arrays of string literals.
#define MEMCMP_FIELDS(_a, _b, _field, _len_field)
Return the comparison of two opaque fields of a structure.
#define FR_FAULT_LOG(_fmt,...)
static const bool escapes[SBUFF_CHAR_CLASS]
@ FR_SBUFF_ERR_INPUT_EMPTY
@ FR_SBUFF_ERR_UNINITIALISED
@ FR_SBUFF_ERR_INPUT_SHORT
char const * fr_utf8_strchr(int *out_chr_len, char const *str, ssize_t inlen, char const *chr)
Return a pointer to the first UTF8 char in a string.
size_t fr_utf8_char(uint8_t const *str, ssize_t inlen)
Checks for utf-8, taken from http://www.w3.org/International/questions/qa-forms-utf-8.
char * fr_vasprintf(TALLOC_CTX *ctx, char const *fmt, va_list ap)
size_t fr_sbuff_adv_past_allowed(fr_sbuff_t *sbuff, size_t len, bool const allowed[static SBUFF_CHAR_CLASS], fr_sbuff_term_t const *tt)
Wind position past characters in the allowed set.
static void fr_sbuff_terminal_idx_init(size_t *needle_len, uint8_t idx[static SBUFF_CHAR_CLASS], fr_sbuff_term_t const *term)
Populate a terminal index.
int fr_sbuff_trim_talloc(fr_sbuff_t *sbuff, size_t len)
Trim a talloced sbuff to the minimum length required to represent the contained string.
fr_sbuff_err_t fr_sbuff_out_bstrncpy_exact(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
Copy exactly len bytes from a sbuff to a sbuff or fail.
ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
#define SBUFF_PARSE_FLOAT_DEF(_name, _type, _func, _max_char)
Used to define a number parsing functions for floats.
ssize_t fr_sbuff_in_escape(fr_sbuff_t *sbuff, char const *in, size_t inlen, fr_sbuff_escape_rules_t const *e_rules)
Print an escaped string to an sbuff.
size_t fr_sbuff_trim(fr_sbuff_t *sbuff, bool const to_trim[static SBUFF_CHAR_CLASS])
Trim trailing characters from a string we're composing.
static _Thread_local char * sbuff_scratch
#define FILL_OR_GOTO_DONE(_out, _in, _len)
Fill as much of the output buffer we can and break on partial copy.
char * fr_sbuff_adv_to_chr_utf8(fr_sbuff_t *sbuff, size_t len, char const *chr)
Wind position to first instance of specified multibyte utf8 char.
bool const sbuff_char_class_hex[SBUFF_CHAR_CLASS]
size_t fr_sbuff_extend_talloc(fr_sbuff_extend_status_t *status, fr_sbuff_t *sbuff, size_t extension)
Reallocate the current buffer.
bool fr_sbuff_eof_file(fr_sbuff_t *sbuff)
Accessor function for the EOF state of the file extendor.
#define SBUFF_PARSE_UINT_DEF(_name, _type, _max, _max_char, _base)
Used to define a number parsing functions for signed integers.
bool const sbuff_char_word[SBUFF_CHAR_CLASS]
bool const sbuff_char_class_float[SBUFF_CHAR_CLASS]
#define CHECK_SBUFF_INIT(_sbuff)
void fr_sbuff_update(fr_sbuff_t *sbuff, char *new_buff, size_t new_len)
Update all markers and pointers in the set of sbuffs to point to new_buff.
char * fr_sbuff_adv_to_str(fr_sbuff_t *sbuff, size_t len, char const *needle, size_t needle_len)
Wind position to the first instance of the specified needle.
bool fr_sbuff_in_needs_escaping(char const *in, size_t inlen, fr_sbuff_escape_rules_t const *e_rules)
Walk an input string and report whether fr_sbuff_in_escape() would escape any characters in it.
size_t _fr_sbuff_move_marker_to_sbuff(fr_sbuff_t *out, fr_sbuff_marker_t *in, size_t len)
Move data from a marker to an sbuff.
bool const sbuff_char_class_uint[SBUFF_CHAR_CLASS]
bool const sbuff_char_class_hostname[SBUFF_CHAR_CLASS]
ssize_t fr_sbuff_in_escape_buffer(fr_sbuff_t *sbuff, char const *in, fr_sbuff_escape_rules_t const *e_rules)
Print an escaped string to an sbuff taking a talloced buffer as input.
char * fr_sbuff_adv_to_strcase(fr_sbuff_t *sbuff, size_t len, char const *needle, size_t needle_len)
Wind position to the first instance of the specified needle.
static size_t min(size_t x, size_t y)
size_t sbuff_err_table_len
void fr_sbuff_unescape_debug(FILE *fp, fr_sbuff_unescape_rules_t const *escapes)
size_t fr_sbuff_extend_file(fr_sbuff_extend_status_t *status, fr_sbuff_t *sbuff, size_t extension)
Refresh the buffer with more data from the file.
static void sbuff_scratch_init(TALLOC_CTX **out)
Initialise a thread local scratch context.
fr_sbuff_err_t fr_sbuff_out_bstrncpy_allowed(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max, bool const allowed[static SBUFF_CHAR_CLASS])
Copy as many allowed characters as possible from a sbuff to a sbuff.
size_t fr_sbuff_adv_past_str(fr_sbuff_t *sbuff, char const *needle, size_t needle_len)
Return true and advance past the end of the needle if needle occurs next in the sbuff.
bool const sbuff_char_blank[SBUFF_CHAR_CLASS]
size_t fr_sbuff_shift(fr_sbuff_t *sbuff, size_t shift, bool move_end)
Shift the contents of the sbuff, returning the number of bytes we managed to shift.
char * fr_sbuff_adv_to_chr(fr_sbuff_t *sbuff, size_t len, char c)
Wind position to first instance of specified char.
bool const sbuff_char_class_int[SBUFF_CHAR_CLASS]
void fr_sbuff_terminal_debug(FILE *fp, fr_sbuff_term_t const *tt)
bool const sbuff_char_whitespace[SBUFF_CHAR_CLASS]
int fr_sbuff_reset_talloc(fr_sbuff_t *sbuff)
Reset a talloced buffer to its initial length, clearing any data stored.
fr_table_num_ordered_t const sbuff_err_table[]
static char const * sbuff_print_char(char c)
Print a char in a friendly format.
fr_sbuff_err_t fr_sbuff_out_bstrncpy_until(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
Copy from a sbuff to a sbuff until a terminal sequence is found.
static bool fr_sbuff_terminal_search(fr_sbuff_t *in, char const *p, uint8_t idx[static SBUFF_CHAR_CLASS], fr_sbuff_term_t const *term, UNUSED size_t needle_len)
Efficient terminal string search.
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
size_t _fr_sbuff_move_marker_to_marker(fr_sbuff_marker_t *out, fr_sbuff_marker_t *in, size_t len)
Move data from one marker to another.
bool const sbuff_char_line_endings[SBUFF_CHAR_CLASS]
size_t _fr_sbuff_move_sbuff_to_marker(fr_sbuff_marker_t *out, fr_sbuff_t *in, size_t len)
Move data from an sbuff to a marker.
ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len)
Copy bytes into the sbuff up to the first \0.
size_t fr_sbuff_adv_past_strcase(fr_sbuff_t *sbuff, char const *needle, size_t needle_len)
Return true and advance past the end of the needle if needle occurs next in the sbuff.
static ssize_t safecpy(char *o_start, char *o_end, char const *i_start, char const *i_end)
Copy function that allows overlapping memory ranges to be copied.
bool const sbuff_char_alpha_num[SBUFF_CHAR_CLASS]
bool fr_sbuff_next_unless_char(fr_sbuff_t *sbuff, char c)
Return true and advance if the next char does not match.
size_t fr_sbuff_adv_until(fr_sbuff_t *sbuff, size_t len, fr_sbuff_term_t const *tt, char escape_chr)
Wind position until we hit a character in the terminal set.
fr_sbuff_err_t fr_sbuff_out_bool(bool *out, fr_sbuff_t *in)
See if the string contains a truth value.
fr_slen_t fr_sbuff_array_concat(fr_sbuff_t *out, char const *const *array, char const *sep)
Concat an array of strings (not NULL terminated), with a string separator.
fr_sbuff_err_t fr_sbuff_out_bstrncpy(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max)
Copy as many bytes as possible from a sbuff to a sbuff.
#define CONSTRAINED_END(_sbuff, _max, _used)
Constrain end pointer to prevent advancing more than the amount the caller specified.
static int8_t terminal_cmp(fr_sbuff_term_elem_t const *a, fr_sbuff_term_elem_t const *b)
Compare two terminal elements for ordering purposes.
fr_sbuff_err_t fr_sbuff_out_unescape_until(size_t *len, fr_sbuff_t *out, fr_sbuff_t *in, size_t max, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
Copy from a sbuff to a sbuff until a terminal sequence is found, unescaping as we go.
ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
#define CHECK_SBUFF_WRITEABLE(_sbuff)
fr_sbuff_term_t * fr_sbuff_terminals_amerge(TALLOC_CTX *ctx, fr_sbuff_term_t const *a, fr_sbuff_term_t const *b)
Merge two sets of terminal strings.
#define CHECK_SBUFF_INIT_ERR(_sbuff)
size_t _fr_sbuff_move_sbuff_to_sbuff(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
Move data from one sbuff to another.
#define SBUFF_PARSE_INT_DEF(_name, _type, _min, _max, _max_char, _base)
Used to define a number parsing functions for signed integers.
bool const sbuff_char_class_zero[SBUFF_CHAR_CLASS]
ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt,...)
Print using a fmt string to an sbuff.
bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
Return true if the current char matches, and if it does, advance.
void fr_sbuff_parse_rules_debug(FILE *fp, fr_sbuff_parse_rules_t const *p_rules)
static _Thread_local bool sbuff_scratch_freed
When true, prevent use of the scratch space.
fr_slen_t fr_sbuff_in_array(fr_sbuff_t *out, char const *const *array, char const *sep)
Concat an array of strings (NULL terminated), with a string separator.
ssize_t fr_sbuff_in_vsprintf(fr_sbuff_t *sbuff, char const *fmt, va_list ap)
Print using a fmt string to an sbuff.
static int _sbuff_scratch_free(void *arg)
Free the scratch buffer used for printf.
TALLOC_CTX * ctx
Context to alloc new buffers in.
#define SBUFF_CHAR_CLASS_HEX
#define SBUFF_CHAR_CLASS_NUM
#define FR_SBUFF_IN_CHAR_RETURN(_sbuff,...)
#define fr_sbuff_set(_dst, _src)
#define fr_sbuff_diff(_a, _b)
size_t shifted
How much we've read from this file.
#define FR_SBUFF_BIND_CURRENT(_sbuff_or_marker)
#define fr_sbuff_adv_past_strcase_literal(_sbuff, _needle)
#define fr_sbuff_was_extended(_status)
char const * str
Terminal string.
#define fr_sbuff_current(_sbuff_or_marker)
size_t init
How much to allocate initially.
char chr
Character at the start of an escape sequence.
bool do_oct
Process oct sequences i.e.
#define fr_sbuff_extend(_sbuff_or_marker)
#define fr_sbuff_buff(_sbuff_or_marker)
#define fr_sbuff_used_total(_sbuff_or_marker)
size_t len
Length of the list.
#define SBUFF_CHAR_CLASS_ALPHA_NUM
#define FR_SBUFF_RETURN(_func, _sbuff,...)
#define fr_sbuff_is_char(_sbuff_or_marker, _c)
#define FR_SBUFF_SET_RETURN(_dst, _src)
#define fr_sbuff_is_digit(_sbuff_or_marker)
#define FR_SBUFF_IN_SPRINTF_RETURN(...)
#define fr_sbuff_uint8(_sbuff_or_marker, _eob)
bool do_hex
Process hex sequences i.e.
size_t max
Maximum size of the buffer.
#define fr_sbuff_end(_sbuff_or_marker)
#define SBUFF_CHAR_UNPRINTABLES_EXTENDED
#define FR_SBUFF(_sbuff_or_marker)
size_t len
Length of string.
#define FR_SBUFF_IN_BSTRNCPY_RETURN(...)
#define fr_sbuff_advance(_sbuff_or_marker, _len)
char * buff_end
The true end of the buffer.
#define fr_sbuff_remaining(_sbuff_or_marker)
bool skip[SBUFF_CHAR_CLASS]
Characters that are escaped, but left in the output along with the escape character.
char subs[SBUFF_CHAR_CLASS]
Special characters and their substitutions.
#define FR_SBUFF_EXTEND_LOWAT_OR_RETURN(_sbuff, _len)
#define SBUFF_CHAR_UNPRINTABLES_LOW
fr_sbuff_marker_t * next
Next m in the list.
#define fr_sbuff_used(_sbuff_or_marker)
fr_sbuff_term_elem_t * elem
A sorted list of terminal strings.
#define fr_sbuff_behind(_sbuff_or_marker)
#define fr_sbuff_extend_lowat(_status, _sbuff_or_marker, _lowat)
FILE * file
FILE * we're reading from.
size_t max
Maximum number of bytes to read.
fr_sbuff_extend_status_t
Whether the buffer is currently extendable and whether it was extended.
@ FR_SBUFF_FLAG_EXTEND_ERROR
The last call to an extend function resulted in an error.
#define fr_sbuff_in_char(_sbuff,...)
Terminal element with pre-calculated lengths.
Set of terminal elements.
File sbuff extension structure.
Talloc sbuff extension structure.
Set of parsing rules for *unescape_until functions.
static char buff[sizeof("18446744073709551615")+3]
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
An element in an arbitrarily ordered array of name to num mappings.
#define talloc_pooled_object(_ctx, _type, _num_subobjects, _total_subobjects_size)
static size_t talloc_strlen(char const *s)
Returns the length of a talloc array containing a string.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const_push(_msg)
#define fr_strerror_const(_msg)
static fr_sbuff_err_t char size_t fr_sbuff_t * in
static fr_sbuff_err_t char size_t fr_sbuff_t size_t max
static fr_sbuff_err_t char ** out
static fr_sbuff_err_t char size_t * len