23RCSID(
"$Id: 44331d5943621b7463c5e9a0ddb1e5f705f11c11 $")
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");
51 {
L(
"empty input is invalid"), FR_SBUFF_PARSE_ERROR_INPUT_EMPTY },
55#if defined(STATIC_ANALYZER) || !defined(NDEBUG)
56# define CHECK_SBUFF_INIT(_sbuff) do { if (!(_sbuff)->extend && (unlikely(!(_sbuff)->buff) || unlikely(!(_sbuff)->start) || unlikely(!(_sbuff)->end) || unlikely(!(_sbuff)->p))) return 0; } while (0)
57# define CHECK_SBUFF_WRITEABLE(_sbuff) do { CHECK_SBUFF_INIT(_sbuff); if (unlikely((_sbuff)->is_const)) return 0; } while (0)
60# define CHECK_SBUFF_INIT(_sbuff)
61# define CHECK_SBUFF_WRITEABLE(_sbuff)
71 [
'+'] =
true, [
'-'] =
true
76 [
'-'] =
true, [
'+'] =
true, [
'e'] =
true, [
'E'] =
true, [
'.'] =
true,
102 [
'-'] =
true, [
'_'] =
true,
105 [
'\t'] =
true, [
'\n'] =
true, [
'\r'] =
true, [
'\f'] =
true, [
'\v'] =
true, [
' '] =
true,
109 [
'\n'] =
true, [
'\r'] =
true
113 [
'\t'] =
true, [
' '] =
true,
128 char const *i_start,
char const *i_end)
131 size_t i_len = i_end - i_start;
133 if (
unlikely((o_end < o_start) || (i_end < i_start)))
return 0;
135 diff = (o_end - o_start) - (i_len);
136 if (diff < 0)
return diff;
138 if ((i_start > o_end) || (i_end < o_start)) {
139 memcpy(o_start, i_start, i_len);
141 memmove(o_start, i_start, i_len);
147static inline CC_HINT(always_inline)
size_t min(
size_t x,
size_t y)
149 return x < y ? x : y;
165 old_buff = sbuff->buff;
173 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
176 sbuff_i->buff = new_buff;
177 sbuff_i->start = new_buff +
min(new_len, sbuff_i->start - old_buff);
178 sbuff_i->end = sbuff_i->buff + new_len;
179 *(sbuff_i->end) =
'\0';
181 sbuff_i->
p = new_buff +
min(new_len, sbuff_i->
p - old_buff);
183 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);
205 size_t max_shift = shift;
206 bool reterminate =
false;
219 reterminate = (sbuff->
p < sbuff->end) && (*sbuff->
p ==
'\0') && !sbuff->is_const;
227 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
230 max_shift =
min(max_shift, sbuff_i->
p -
buff);
231 if (!max_shift)
return 0;
233 for (m_i = sbuff_i->m; m_i; m_i = m_i->
next) {
234 max_shift =
min(max_shift, m_i->p -
buff);
235 if (!max_shift)
return 0;
246 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
248 char *start = sbuff_i->start;
250 sbuff_i->start -=
min(max_shift, sbuff_i->start -
buff);
251 sbuff_i->
p -= max_shift;
252 if (move_end) sbuff_i->end -= max_shift;
253 sbuff_i->shifted += (max_shift - (start - sbuff_i->start));
254 for (m_i = sbuff_i->m; m_i; m_i = m_i->
next) m_i->p -= max_shift;
261 if ((
buff + max_shift) < end) memmove(
buff,
buff + max_shift, end - (
buff + max_shift));
263 if (reterminate) *sbuff->
p =
'\0';
274 size_t read, available, total_read, shift;
280 if (fctx->
eof)
return 0;
282 if (extension == SIZE_MAX) extension = 0;
284 total_read = fctx->
shifted + (sbuff->end - sbuff->buff);
285 if (total_read >= fctx->
max) {
315 available = fctx->
buff_end - sbuff->end;
316 if (available > (fctx->
max - total_read)) available = fctx->
max - total_read;
317 if (available < extension) {
322 read = fread(sbuff->end, 1, available, fctx->
file);
323 for (sbuff_i = sbuff; sbuff_i; sbuff_i = sbuff_i->parent) {
324 sbuff_i->end += read;
329 if (read < available) {
330 if (!feof(fctx->
file)) {
372 size_t clen, nlen, elen = extension;
377 clen = sbuff->buff ? talloc_array_length(sbuff->buff) : 0;
385 if ((clen + elen) < tctx->
init) {
386 elen = (tctx->
init - clen) + 1;
391 }
else if (elen < clen) {
399 if (tctx->
max && ((clen + elen + 1) > tctx->
max)) {
400 elen = tctx->
max - clen;
403 "%zu bytes, max is %zu bytes",
404 extension, clen + extension, tctx->
max);
411 new_buff = talloc_realloc(tctx->
ctx, sbuff->buff,
char, nlen);
435 size_t clen = 0, nlen = 1;
441 if (sbuff->buff) clen = talloc_array_length(sbuff->buff);
443 if (len != SIZE_MAX) {
445 }
else if (sbuff->buff){
446 nlen += (sbuff->
p - sbuff->start);
450 new_buff = talloc_realloc(tctx->
ctx, sbuff->buff,
char, nlen);
474 fr_sbuff_set_to_start(sbuff);
480 new_buff = talloc_realloc(tctx->
ctx, sbuff->buff,
char, tctx->
init);
483 talloc_array_length(sbuff->buff), tctx->
init);
486 sbuff->buff = new_buff;
499#define FILL_OR_GOTO_DONE(_out, _in, _len) if (fr_sbuff_move(_out, _in, _len) < (size_t)(_len)) goto done
508#define CONSTRAINED_END(_sbuff, _max, _used) \
509 (((_max) - (_used)) > fr_sbuff_remaining(_sbuff) ? (_sbuff)->end : (_sbuff)->p + ((_max) - (_used)))
523 size_t i, len, max = 0;
529 for (i = 0; i < term->
len; i++) {
531 if (len > max) max = len;
536 if (i > 0) *needle_len = max;
566 if (!term)
return false;
571 if (!term_idx)
return false;
577 if ((remaining == 0) && !fr_sbuff_is_extendable(
in)) {
578 if (idx[
'\0'] != 0)
return true;
582 if (remaining < needle_len) {
584 "Caller failed to extend buffer by %zu bytes before calling fr_sbuff_terminal_search",
595 while (start <= end) {
600 elem = &term->
elem[mid];
603 ret = memcmp(p, elem->
str, tlen < (
size_t)remaining ? tlen : (
size_t)remaining);
608 if (remaining >= tlen)
return true;
623 mid = start + ((end - start) / 2);
647 for (i = 0; i < len; i++)
FR_FAULT_LOG(
"\t\"%s\" (%zu)", elem[i] ? elem[i]->str :
"NULL", elem[i] ? elem[i]->len : 0);
669#if !defined(NDEBUG) && defined(WITH_VERIFY_PTR)
682 while ((i < a->len) && (j < b->len)) {
688 tmp[num++] = &a->
elem[i++];
690 }
else if (cmp < 0) {
691 tmp[num++] = &a->
elem[i++];
693 }
else if (cmp > 0) {
694 tmp[num++] = &b->
elem[j++];
703 while (i < a->len) tmp[num++] = &a->
elem[i++];
704 while (j < b->len) tmp[num++] = &b->
elem[j++];
716 for (i = 0; i < num; i++)
out->elem[i] = *tmp[i];
718#if !defined(NDEBUG) && defined(WITH_VERIFY_PTR)
751 if (chunk_len > remaining) chunk_len = remaining;
782 fr_sbuff_marker(&m,
out);
790 fr_sbuff_marker_release(&m);
795 if (chunk_len > remaining) chunk_len = remaining;
803 if (len == SIZE_MAX) {
804 fr_sbuff_marker_release(&m);
808 fr_sbuff_marker_release(&m);
809 return -(remaining - (chunk_len + copied));
814 fr_sbuff_marker_release(&m);
850 while ((p < end) && allowed[(
uint8_t)*p]) p++;
885 bool do_escape =
false;
888 size_t needle_len = 1;
889 char escape_chr = u_rules ? u_rules->
chr :
'\0';
910 if (escape_chr ==
'\0') {
916 }
else if (*p == escape_chr) {
958 bool do_escape =
false;
964 size_t needle_len = 1;
980 fr_sbuff_marker(&c_s, &our_in);
981 fr_sbuff_marker(&end, &our_in);
982 fr_sbuff_marker_update_end(&end, len);
984 fr_sbuff_marker(&o_s,
out);
1009 fr_sbuff_marker(&m, &our_in);
1012 if (fr_sbuff_out_uint8_hex(NULL, &escape, &our_in,
false) != 2) {
1014 fr_sbuff_marker_release(&m);
1020 fr_sbuff_marker_release(&m);
1023 fr_sbuff_marker_release(&m);
1035 fr_sbuff_marker(&m, &our_in);
1037 if (fr_sbuff_out_uint8_oct(NULL, &escape, &our_in,
false) != 3) {
1039 fr_sbuff_marker_release(&m);
1045 fr_sbuff_marker_release(&m);
1048 fr_sbuff_marker_release(&m);
1062 if (u_rules->
subs[c] ==
'\0') {
1063 if (u_rules->
skip[c] ==
true)
goto next;
1116 return fr_sbuff_marker_release_behind(&o_s);
1132 [
't'] =
true, [
'T'] =
true,
1133 [
'f'] =
true, [
'F'] =
true,
1134 [
'y'] =
true, [
'Y'] =
true,
1135 [
'n'] =
true, [
'N'] =
true,
1138 if (fr_sbuff_is_in_charset(&our_in, bool_prefix)) {
1175 fr_strerror_const(
"Not a valid boolean value. Accepted values are 'yes', 'no', 'true', 'false'");
1191#define SBUFF_PARSE_INT_DEF(_name, _type, _min, _max, _max_char, _base) \
1192fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \
1194 char buff[_max_char + 1]; \
1195 char *end, *a_end; \
1199 fr_sbuff_t our_in = FR_SBUFF(in); \
1201 len = fr_sbuff_out_bstrncpy(&FR_SBUFF_IN(buff, sizeof(buff)), &our_in, _max_char); \
1203 if (err) *err = (fr_sbuff_remaining(in) == 0) ? FR_SBUFF_PARSE_ERROR_INPUT_EMPTY : FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
1207 num = strtoll(buff, &end, _base); \
1208 cast_num = (_type)(num); \
1209 if (end == buff) { \
1210 if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
1213 if (num > cast_num) { \
1215 if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; \
1216 *out = (_type)(_max); \
1219 if (((errno == EINVAL) && (num == 0)) || ((errno == ERANGE) && (num == LLONG_MAX))) goto overflow; \
1220 if (num < cast_num) { \
1222 if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW; \
1223 *out = (_type)(_min); \
1226 if ((errno == ERANGE) && (num == LLONG_MIN)) goto underflow; \
1227 if (no_trailing && ((a_end = in->p + (end - buff)) < in->end)) { \
1228 if (isdigit((uint8_t) *a_end) || (((_base > 10) || ((_base == 0) && (len > 2) && (buff[0] == '0') && (buff[1] == 'x'))) && \
1229 ((tolower((uint8_t) *a_end) >= 'a') && (tolower((uint8_t) *a_end) <= 'f')))) { \
1230 if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \
1231 *out = (_type)(_max); \
1232 FR_SBUFF_ERROR_RETURN(&our_in); \
1236 if (err) *err = FR_SBUFF_PARSE_OK; \
1239 return fr_sbuff_advance(in, end - buff); \
1258#define SBUFF_PARSE_UINT_DEF(_name, _type, _max, _max_char, _base) \
1259fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \
1261 char buff[_max_char + 1]; \
1262 char *end, *a_end; \
1264 unsigned long long num; \
1266 fr_sbuff_t our_in = FR_SBUFF(in); \
1268 len = fr_sbuff_out_bstrncpy(&FR_SBUFF_IN(buff, sizeof(buff)), &our_in, _max_char); \
1270 if (err) *err = (fr_sbuff_remaining(in) == 0) ? FR_SBUFF_PARSE_ERROR_INPUT_EMPTY : FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
1273 if (buff[0] == '-') { \
1274 if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW; \
1278 num = strtoull(buff, &end, _base); \
1279 cast_num = (_type)(num); \
1280 if (end == buff) { \
1281 if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
1284 if (num > cast_num) { \
1286 if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; \
1287 *out = (_type)(_max); \
1290 if (((errno == EINVAL) && (num == 0)) || ((errno == ERANGE) && (num == ULLONG_MAX))) goto overflow; \
1291 if (no_trailing && ((a_end = in->p + (end - buff)) < in->end)) { \
1292 if (isdigit((uint8_t) *a_end) || (((_base > 10) || ((_base == 0) && (len > 2) && (buff[0] == '0') && (buff[1] == 'x'))) && \
1293 ((tolower((uint8_t) *a_end) >= 'a') && (tolower((uint8_t) *a_end) <= 'f')))) { \
1294 if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \
1295 *out = (_type)(_max); \
1296 FR_SBUFF_ERROR_RETURN(&our_in); \
1298 if (err) *err = FR_SBUFF_PARSE_OK; \
1301 if (err) *err = FR_SBUFF_PARSE_OK; \
1304 return fr_sbuff_advance(in, end - buff); \
1342#define SBUFF_PARSE_FLOAT_DEF(_name, _type, _func, _max_char) \
1343fr_slen_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \
1345 char buff[_max_char + 1] = ""; \
1347 fr_sbuff_t our_in = FR_SBUFF(in); \
1350 len = fr_sbuff_out_bstrncpy_allowed(&FR_SBUFF_OUT(buff, sizeof(buff)), &our_in, SIZE_MAX, sbuff_char_class_float); \
1351 if (len == sizeof(buff)) { \
1352 if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
1354 } else if (len == 0) { \
1355 if (err) *err = (fr_sbuff_remaining(in) == 0) ? FR_SBUFF_PARSE_ERROR_INPUT_EMPTY : FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
1359 res = _func(buff, &end); \
1360 if (errno == ERANGE) { \
1362 if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; \
1364 if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW; \
1368 if (no_trailing && (*end != '\0')) { \
1369 if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \
1370 FR_SBUFF_ERROR_RETURN(&our_in); \
1373 return fr_sbuff_advance(in, end - buff); \
1397 size_t to_copy = len;
1398 if (to_copy > o_remaining) to_copy = o_remaining;
1399 if (to_copy > i_remaining) to_copy = i_remaining;
1417 size_t to_copy = len;
1418 if (to_copy > o_remaining) to_copy = o_remaining;
1419 if (to_copy > i_remaining) to_copy = i_remaining;
1437 size_t to_copy = len;
1438 if (to_copy > o_remaining) to_copy = o_remaining;
1439 if (to_copy > i_remaining) to_copy = i_remaining;
1457 size_t to_copy = len;
1458 if (to_copy > o_remaining) to_copy = o_remaining;
1459 if (to_copy > i_remaining) to_copy = i_remaining;
1481 safecpy(sbuff->
p, sbuff->end, str, str + len);
1482 sbuff->
p[len] =
'\0';
1502 safecpy(sbuff->
p, sbuff->end, str, str + len);
1503 sbuff->
p[len] =
'\0';
1526 safecpy(sbuff->
p, sbuff->end, str, str + len);
1527 sbuff->
p[len] =
'\0';
1543 TALLOC_CTX *scratch;
1552 scratch = talloc_pool(NULL, 4096);
1576 TALLOC_CTX *scratch;
1662 sub = e_rules->subs[c];
1673 if (e_rules->esc[c]) {
1678 if (e_rules->do_oct) {
1681 }
else if (e_rules->do_hex) {
1724 char const *
const * p;
1726 .name = __FUNCTION__,
1730 if (sep) e_rules.subs[(
uint8_t)*sep] = *sep;
1734 for (p = array; *p; p++) {
1759 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
1768 found = memmem(sbuff->
p, needle_len, needle, needle_len);
1769 if (!found)
return 0;
1786 char const *p, *n_p;
1791 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
1801 end = p + needle_len;
1803 for (p = sbuff->
p, n_p = needle; p < end; p++, n_p++) {
1824 size_t needle_len = 0;
1830 while (total < len) {
1837 while ((p < end) && allowed[(
uint8_t)*p]) {
1838 if (needle_len == 0) {
1878 if (p != end)
break;
1897 bool do_escape =
false;
1900 size_t needle_len = 1;
1910 while (total < len) {
1918 if (escape_chr ==
'\0') {
1924 }
else if (*p == escape_chr) {
1934 if (p != end)
break;
1956 size_t clen = strlen(chr);
1963 if (len < clen)
return NULL;
1965 while (total <= (len - clen)) {
2004 while (total < len) {
2011 found = memchr(our_sbuff.
p, c, end - our_sbuff.
p);
2040 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
2041 if (!needle_len)
return NULL;
2046 if (len < needle_len)
return NULL;
2048 while (total <= (len - needle_len)) {
2059 found = memmem(our_sbuff.
p, end - our_sbuff.
p, needle, needle_len);
2070 total +=
fr_sbuff_set(&our_sbuff, (end - needle_len) + 1);
2093 if (needle_len == SIZE_MAX) needle_len = strlen(needle);
2094 if (!needle_len)
return NULL;
2099 if (len < needle_len)
return NULL;
2101 while (total <= (len - needle_len)) {
2107 for (p = our_sbuff.
p, n_p = needle, end = our_sbuff.
p + needle_len;
2135 if (*sbuff->
p != c)
return false;
2156 if (*sbuff->
p == c)
return false;
2171 char *p = sbuff->
p - 1;
2174 while ((p >= sbuff->start) && to_trim[(
uint8_t)*p]) p--;
2177 if (slen != 0) fr_sbuff_terminate(sbuff);
2196 size_t needle_len = 1;
2233 static _Thread_local
char str[10][5];
2234 static _Thread_local
size_t i = 0;
2261 if (unprintables[(
uint8_t)c]) {
2278 fprintf(fp,
"do_hex : %s\n",
escapes->do_hex ?
"yes" :
"no");
2279 fprintf(fp,
"do_oct : %s\n",
escapes->do_oct ?
"yes" :
"no");
2281 fprintf(fp,
"substitutions:\n");
2287 fprintf(fp,
"skips:\n");
2297 fprintf(fp,
"Terminal count %zu\n", tt->
len);
2299 for (i = 0; i < tt->
len; i++) fprintf(fp,
"\t\"%s\" (%zu)\n", tt->
elem[i].
str, tt->
elem[i].
len);
2304 fprintf(fp,
"Parse rules %p\n", p_rules);
2307 if (p_rules->escapes) {
2310 fprintf(fp,
"<none>\n");
2314 if (p_rules->terminals) {
2317 fprintf(fp,
"<none>\n");
2333 size_t len = talloc_array_length(array);
2334 char const *
const * p;
2335 char const *
const * end;
2337 .name = __FUNCTION__,
2341 if (sep) e_rules.subs[(
uint8_t)*sep] = *sep;
2343 for (p = array, end = array + len;
2348 if (sep && ((p + 1) < end)) {
static int const char * fmt
#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_assert_msg(_x, _msg,...)
Calls panic_action ifndef NDEBUG, else logs error and causes the server to exit immediately with code...
#define FR_FAULT_LOG(_fmt,...)
static const bool escapes[SBUFF_CHAR_CLASS]
@ FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW
Integer type would overflow.
@ FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW
Integer type would underflow.
@ FR_SBUFF_PARSE_ERROR_NOT_FOUND
String does not contain a token matching the output type.
@ FR_SBUFF_PARSE_ERROR_FORMAT
Format of data was invalid.
@ FR_SBUFF_PARSE_OK
No error.
@ FR_SBUFF_PARSE_ERROR_OUT_OF_SPACE
No space available in output buffer.
@ FR_SBUFF_PARSE_ERROR_TRAILING
Trailing characters found.
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.
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.
size_t fr_sbuff_out_unescape_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
Copy as many allowed characters as possible from a sbuff to a sbuff.
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.
static int sbuff_scratch_init(TALLOC_CTX **out)
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.
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]
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, size_t needle_len)
Efficient terminal string search.
size_t sbuff_parse_error_table_len
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)
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.
ssize_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.
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.
size_t fr_sbuff_out_bstrncpy_until(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, fr_sbuff_term_t const *tt, fr_sbuff_unescape_rules_t const *u_rules)
Copy as many allowed characters as possible from a sbuff to a sbuff.
char * fr_sbuff_adv_to_chr(fr_sbuff_t *sbuff, size_t len, char c)
Wind position to first instance of specified char.
size_t fr_sbuff_out_bstrncpy_allowed(fr_sbuff_t *out, fr_sbuff_t *in, size_t len, bool const allowed[static SBUFF_CHAR_CLASS])
Copy as many allowed characters as possible from a sbuff to a sbuff.
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.
static char const * sbuff_print_char(char c)
Print a char in a friendly format.
bool fr_sbuff_is_terminal(fr_sbuff_t *in, fr_sbuff_term_t const *tt)
Efficient terminal string search.
fr_slen_t fr_sbuff_out_bool(bool *out, fr_sbuff_t *in)
See if the string contains a truth value.
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_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.
#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.
ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str)
Copy bytes into the sbuff up to the first \0.
size_t fr_sbuff_out_bstrncpy(fr_sbuff_t *out, fr_sbuff_t *in, size_t len)
Copy as many bytes as possible from a sbuff to a sbuff.
#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.
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]
fr_table_num_ordered_t const sbuff_parse_error_table[]
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)
#define fr_sbuff_char(_sbuff_or_marker, _eob)
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(...)
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(_msg)
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out