From: Arran Cudbard-Bell Date: Fri, 17 Jul 2020 19:25:02 +0000 (-0400) Subject: sbuff: Add additional sbuff functions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0cfec90a28ea2c468943b0fef72e77bb9876061a;p=thirdparty%2Ffreeradius-server.git sbuff: Add additional sbuff functions --- diff --git a/src/lib/util/sbuff.c b/src/lib/util/sbuff.c index 781ff5dcbdf..d25ab75683d 100644 --- a/src/lib/util/sbuff.c +++ b/src/lib/util/sbuff.c @@ -22,23 +22,27 @@ */ RCSID("$Id$") -#include #include +#include +#include #include +#include #include #include #include #include +_Thread_local char *sbuff_scratch; + static_assert(sizeof(long long) >= sizeof(int64_t), "long long must be as wide or wider than an int64_t"); static_assert(sizeof(unsigned long long) >= sizeof(uint64_t), "long long must be as wide or wider than an uint64_t"); fr_table_num_ordered_t const sbuff_parse_error_table[] = { { "ok", FR_SBUFF_PARSE_OK }, { "token not found", FR_SBUFF_PARSE_ERROR_NOT_FOUND }, - { "integer overflow", FR_SBUFF_PARSE_ERROR_INTEGER_OVERFLOW }, - { "integer underflow", FR_SBUFF_PARSE_ERROR_INTEGER_UNDERFLOW }, + { "integer overflow", FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW }, + { "integer underflow", FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW }, }; size_t sbuff_parse_error_table_len = NUM_ELEMENTS(sbuff_parse_error_table); @@ -418,7 +422,7 @@ size_t fr_sbuff_bstrncpy_out_until(char *out, size_t outlen, fr_sbuff_t *in, siz * - >0 the number of bytes copied. */ #define PARSE_INT_DEF(_name, _type, _min, _max, _max_char) \ -size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \ +size_t fr_sbuff_out_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \ { \ char buff[_max_char + 1]; \ char *end; \ @@ -426,21 +430,25 @@ size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_ long long num; \ fr_sbuff_t our_in = FR_SBUFF_NO_ADVANCE(in); \ len = fr_sbuff_bstrncpy_out(buff, sizeof(buff), &our_in, _max_char); \ - if ((len == 0) && err) { \ - *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ + if (len == 0) { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ return 0; \ } \ num = strtoll(buff, &end, 10); \ if (end == buff) { \ - if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \ return 0; \ } \ - if ((num > (_max)) || ((errno == EINVAL) && (num == LLONG_MAX)) || (no_trailing && isdigit(*(in->p + (end - buff))))) { \ - if (err) *err = FR_SBUFF_PARSE_ERROR_INTEGER_OVERFLOW; \ + if ((num > (_max)) || ((errno == EINVAL) && (num == LLONG_MAX))) { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; \ + *out = (_type)(_max); \ + return 0; \ + } else if (no_trailing && (*end != '\0')) { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \ *out = (_type)(_max); \ return 0; \ } else if (num < (_min) || ((errno == EINVAL) && (num == LLONG_MIN))) { \ - if (err) *err = FR_SBUFF_PARSE_ERROR_INTEGER_UNDERFLOW; \ + if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW; \ *out = (_type)(_min); \ return 0; \ } else { \ @@ -466,7 +474,7 @@ PARSE_INT_DEF(int64, int64_t, INT64_MIN, INT64_MAX, 20) * used in . */ #define PARSE_UINT_DEF(_name, _type, _max, _max_char) \ -size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \ +size_t fr_sbuff_in_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \ { \ char buff[_max_char + 1]; \ char *end; \ @@ -474,17 +482,21 @@ size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_ unsigned long long num; \ fr_sbuff_t our_in = FR_SBUFF_NO_ADVANCE(in); \ len = fr_sbuff_bstrncpy_out(buff, sizeof(buff), &our_in, _max_char); \ - if ((len == 0) && err) { \ - *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ + if (len == 0) { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ return 0; \ } \ num = strtoull(buff, &end, 10); \ if (end == buff) { \ - if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \ + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \ return 0; \ } \ - if ((num > (_max)) || ((errno == EINVAL) && (num == ULLONG_MAX)) || (no_trailing && isdigit(*(in->p + (end - buff))))) { \ - if (err) *err = FR_SBUFF_PARSE_ERROR_INTEGER_OVERFLOW; \ + if ((num > (_max)) || ((errno == EINVAL) && (num == ULLONG_MAX))) { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; \ + *out = (_type)(_max); \ + return 0; \ + } else if (no_trailing && (*end != '\0')) { \ + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; \ *out = (_type)(_max); \ return 0; \ } else { \ @@ -499,3 +511,269 @@ PARSE_UINT_DEF(uint8, uint8_t, UINT8_MAX, 1) PARSE_UINT_DEF(uint16, uint16_t, UINT16_MAX, 5) PARSE_UINT_DEF(uint32, uint32_t, UINT32_MAX, 10) PARSE_UINT_DEF(uint64, uint64_t, UINT64_MAX, 20) + +static bool float_chars[UINT8_MAX + 1] = { + ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true, + ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true, + ['-'] = true, ['+'] = true, ['e'] = true, ['E'] = true, ['.'] = true, +}; + +/** Attempt to parse a float + * + * @param[out] err If non null, will be filled with any parse errors. + * @param[out] out Where to write the resulting float. + * @param[in] in Sbuff to parse float from. + * @param[in] no_trailing Emit a parse error if there are trailing characters + * after the float parsed. + * @return + * - >0 the number of bytes copied into the sbuff. + * - 0 a parse error occurred. + */ +size_t fr_sbuff_out_float32(fr_sbuff_parse_error_t *err, float *out, fr_sbuff_t *in, bool no_trailing) +{ + char buffer[100]; /* Should be sufficient */ + char *end; + fr_sbuff_t our_in = FR_SBUFF_NO_ADVANCE(in); + size_t len; + float res; + + len = fr_sbuff_bstrncpy_out_allowed(buffer, sizeof(buffer), &our_in, SIZE_MAX, float_chars); + if (len == sizeof(buffer)) { + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; + return 0; + } else if (len == 0) { + if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; + return 0; + } + + res = strtof(buffer, &end); + if (errno == ERANGE) { + if (err) *err = res == 0 ? FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW : FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; + return 0; + } + if (no_trailing && (*end != '\0')) { + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; + *out = res; + return 0; + } + + return fr_sbuff_advance(in, end - buffer); +} + +/** Attempt to parse a double + * + * @param[out] err If non null, will be filled with any parse errors. + * @param[out] out Where to write the resulting float. + * @param[in] in Sbuff to parse float from. + * @param[in] no_trailing Emit a parse error if there are trailing characters + * after the float parsed. + * @return + * - >0 the number of bytes copied into the sbuff. + * - 0 a parse error occurred. + */ +size_t fr_sbuff_out_float64(fr_sbuff_parse_error_t *err, double *out, fr_sbuff_t *in, bool no_trailing) +{ + char buffer[100]; /* Should be sufficient */ + char *end; + fr_sbuff_t our_in = FR_SBUFF_NO_ADVANCE(in); + size_t len; + float res; + + len = fr_sbuff_bstrncpy_out_allowed(buffer, sizeof(buffer), &our_in, SIZE_MAX, float_chars); + if (len == sizeof(buffer)) { + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; + return 0; + } else if (len == 0) { + if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; + return 0; + } + + res = strtof(buffer, &end); + if (errno == ERANGE) { + if (err) *err = res == 0 ? FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW : FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW; + return 0; + } + if (no_trailing && (*end != '\0')) { + if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING; + *out = res; + return 0; + } + + return fr_sbuff_advance(in, end - buffer); +} + +/** Copy bytes into the sbuff up to the first \0 + * + * @param[in] sbuff to copy into. + * @param[in] str to copy into buffer. + * @return + * - >= 0 the number of bytes copied into the sbuff. + * - <0 the number of bytes required to complete the copy operation. + */ +ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str) +{ + size_t len = strlen(str); + + FR_SBUFF_CHECK_REMAINING_RETURN(sbuff, len); + + strlcpy(sbuff->p, str, len + 1); + + return fr_sbuff_advance(sbuff, len); +} + +/** Copy bytes into the sbuff up to the first \0 + * + * @param[in] sbuff to copy into. + * @param[in] str to copy into buffer. + * @param[in] len number of bytes to copy. + * @return + * - >= 0 the number of bytes copied into the sbuff. + * - <0 the number of bytes required to complete the copy operation. + */ +ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len) +{ + FR_SBUFF_CHECK_REMAINING_RETURN(sbuff, len); + + memcpy(sbuff->p, str, len); + sbuff->p[len] = '\0'; + + return fr_sbuff_advance(sbuff, len); +} + +/** Copy bytes into the sbuff up to the first \0 + * + * @param[in] sbuff to copy into. + * @param[in] str talloced buffer to copy into sbuff. + * @return + * - >= 0 the number of bytes copied into the sbuff. + * - <0 the number of bytes required to complete the copy operation. + */ +ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str) +{ + size_t len = talloc_array_length(str) - 1; + + FR_SBUFF_CHECK_REMAINING_RETURN(sbuff, len); + + memcpy(sbuff->p, str, len); + sbuff->p[len] = '\0'; + + return fr_sbuff_advance(sbuff, len); +} + +/** Free the scratch buffer used for printf + * + */ +static void _sbuff_scratch_free(void *arg) +{ + talloc_free(arg); +} + +static inline CC_HINT(always_inline) int sbuff_scratch_init(TALLOC_CTX **out) +{ + TALLOC_CTX *scratch; + + scratch = sbuff_scratch; + if (!scratch) { + scratch = talloc_pool(NULL, 4096); + if (unlikely(!scratch)) { + fr_strerror_printf("Out of Memory"); + return -1; + } + fr_thread_local_set_destructor(sbuff_scratch, _sbuff_scratch_free, scratch); + } + + *out = scratch; + + return 0; +} + +/** Print using a fmt string to an sbuff + * + * @param[in] sbuff to print into. + * @param[in] fmt string. + * @param[in] ap arguments for format string. + * @return + * - >= 0 the number of bytes printed into the sbuff. + * - <0 the number of bytes required to complete the print operation. + */ +ssize_t fr_sbuff_in_vsprintf(fr_sbuff_t *sbuff, char const *fmt, va_list ap) +{ + TALLOC_CTX *scratch; + va_list ap_p; + char *tmp; + ssize_t slen; + + if (sbuff_scratch_init(&scratch) < 0) return 0; + + va_copy(ap_p, ap); + tmp = fr_vasprintf(scratch, fmt, ap_p); + va_end(ap_p); + if (!tmp) return 0; + + slen = fr_sbuff_in_bstrcpy_buffer(sbuff, tmp); + talloc_free(tmp); /* Free the temporary buffer */ + + return slen; +} + +/** Print using a fmt string to an sbuff + * + * @param[in] sbuff to print into. + * @param[in] fmt string. + * @param[in] ... arguments for format string. + * @return + * - >= 0 the number of bytes printed into the sbuff. + * - <0 the number of bytes required to complete the print operation. + */ +ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt, ...) +{ + va_list ap; + ssize_t slen; + + va_start(ap, fmt); + slen = fr_sbuff_in_vsprintf(sbuff, fmt, ap); + va_end(ap); + + return slen; +} + +/** Print an escaped string to an sbuff + * + * @param[in] sbuff to print into. + * @param[in] in to escape. + * @param[in] inlen of string to escape. + * @param[in] quote Which quoting character to escape. Also controls + * which characters are escaped. + * @return + * - >= 0 the number of bytes printed into the sbuff. + * - <0 the number of bytes required to complete the print operation. + */ +ssize_t fr_sbuff_in_snprint(fr_sbuff_t *sbuff, char const *in, size_t inlen, char quote) +{ + size_t len; + + len = fr_snprint_len(in, inlen, quote); + FR_SBUFF_CHECK_REMAINING_RETURN(sbuff, len); + + len = fr_snprint(fr_sbuff_current(sbuff), fr_sbuff_remaining(sbuff) + 1, in, inlen, quote); + fr_sbuff_advance(sbuff, len); + + return len; +} + +/** Print an escaped string to an sbuff taking a talloced buffer as input + * + * @param[in] sbuff to print into. + * @param[in] in to escape. + * @param[in] quote Which quoting character to escape. Also controls + * which characters are escaped. + * @return + * - >= 0 the number of bytes printed into the sbuff. + * - <0 the number of bytes required to complete the print operation. + */ +ssize_t fr_sbuff_in_snprint_buffer(fr_sbuff_t *sbuff, char const *in, char quote) +{ + if (unlikely(!in)) return 0; + + return fr_sbuff_in_snprint(sbuff, in, talloc_array_length(in) - 1, quote); +} diff --git a/src/lib/util/sbuff.h b/src/lib/util/sbuff.h index ee0625e945c..fe37927e52c 100644 --- a/src/lib/util/sbuff.h +++ b/src/lib/util/sbuff.h @@ -77,8 +77,9 @@ typedef enum { FR_SBUFF_PARSE_OK = 0, //!< No error. FR_SBUFF_PARSE_ERROR_NOT_FOUND = -1, //!< String does not contain a token ///< matching the output type. - FR_SBUFF_PARSE_ERROR_INTEGER_OVERFLOW = -2, //!< Integer type would overflow. - FR_SBUFF_PARSE_ERROR_INTEGER_UNDERFLOW = -3 //!< Integer type would underflow. + FR_SBUFF_PARSE_ERROR_TRAILING = -2, //!< Trailing characters found. + FR_SBUFF_PARSE_ERROR_NUM_OVERFLOW = -3, //!< Integer type would overflow. + FR_SBUFF_PARSE_ERROR_NUM_UNDERFLOW = -4 //!< Integer type would underflow. } fr_sbuff_parse_error_t; extern fr_table_num_ordered_t const sbuff_parse_error_table[]; @@ -204,6 +205,17 @@ static inline size_t fr_sbuff_marker_used(fr_sbuff_t const *sbuff, fr_sbuff_mark * */ #define FR_SBUFF_ERROR_RETURN(_sbuff) return -(fr_sbuff_used(_sbuff)) + +/** Check if _len bytes are available in the sbuff, and if not return the number of bytes we'd need + * + */ +#define FR_SBUFF_CHECK_REMAINING_RETURN(_sbuff, _len) \ +do { \ + if ((_len) > fr_sbuff_remaining(_sbuff)) { \ + return -((_len) - fr_sbuff_remaining(_sbuff)); \ + }\ +} while (0) + /** @} */ /** @name Sbuff position manipulation @@ -406,6 +418,21 @@ static inline bool fr_sbuff_next_if_str(fr_sbuff_t *sbuff, char const *needle, s return true; } +bool fr_sbuff_adv_if_str(fr_sbuff_t *sbuff, char const *needle, size_t len); + +#define fr_sbuff_adv_if_str_literal(_sbuff, _needle) fr_sbuff_adv_if_str(_sbuff, _needle, sizeof(_needle) - 1) + +bool fr_sbuff_adv_if_strcase(fr_sbuff_t *sbuff, char const *needle, size_t len); + +#define fr_sbuff_adv_if_strcase_literal(_sbuff, _needle) fr_sbuff_adv_if_strcase(_sbuff, _needle, sizeof(_needle) - 1) + +size_t fr_sbuff_adv_if_whitespace(fr_sbuff_t *sbuff); + +size_t fr_sbuff_adv_strstr(fr_sbuff_t *sbuff, char const *needle, ssize_t len); + +#define fr_sbuff_adv_strstr_literal(_sbuff, _needle) fr_sbuff_adv_strstr(_sbuff, _needle, sizeof(_needle) - 1) +/** @} */ + /** Return true and advance past the end of the needle if needle occurs next in the sbuff * * This function is similar to fr_sbuff_next_if_str but is case insensitive. @@ -441,6 +468,12 @@ static inline bool fr_sbuff_is_allowed(fr_sbuff_t *sbuff, bool const allowed_cha return allowed_chars[(uint8_t)*sbuff->p]; } +static inline bool fr_sbuff_is_char(fr_sbuff_t *sbuff, char c) +{ + if (sbuff->p >= sbuff->end) return false; + return *sbuff->p == c; +} + static inline bool fr_sbuff_is_digit(fr_sbuff_t *sbuff) { if (sbuff->p >= sbuff->end) return false; @@ -550,21 +583,25 @@ size_t fr_sbuff_bstrncpy_out_until(char *out, size_t outlen, fr_sbuff_t *sbuff, * so that if the output variable type changes, the parse rules are automatically changed. * @{ */ -size_t fr_sbuff_parse_int8(fr_sbuff_parse_error_t *err, int8_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_int8(fr_sbuff_parse_error_t *err, int8_t *out, fr_sbuff_t *sbuff, bool no_trailing); + +size_t fr_sbuff_out_int16(fr_sbuff_parse_error_t *err, int16_t *out, fr_sbuff_t *sbuff, bool no_trailing); -size_t fr_sbuff_parse_int16(fr_sbuff_parse_error_t *err, int16_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_int32(fr_sbuff_parse_error_t *err, int32_t *out, fr_sbuff_t *sbuff, bool no_trailing); -size_t fr_sbuff_parse_int32(fr_sbuff_parse_error_t *err, int32_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_int64(fr_sbuff_parse_error_t *err, int64_t *out, fr_sbuff_t *sbuff, bool no_trailing); -size_t fr_sbuff_parse_int64(fr_sbuff_parse_error_t *err, int64_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_uint8(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing); -size_t fr_sbuff_parse_uint8(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_uint16(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing); -size_t fr_sbuff_parse_uint16(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_uint32(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing); -size_t fr_sbuff_parse_uint32(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing); -size_t fr_sbuff_parse_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing); +size_t fr_sbuff_out_float32(fr_sbuff_parse_error_t *err, float *out, fr_sbuff_t *sbuff, bool no_trailing); + +size_t fr_sbuff_out_float64(fr_sbuff_parse_error_t *err, double *out, fr_sbuff_t *sbuff, bool no_trailing); /** Parse a value based on the output type * @@ -576,14 +613,16 @@ size_t fr_sbuff_parse_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuf */ #define fr_sbuff_parse(_err, _out, _in) \ _Generic((_out), \ - int8_t * : fr_sbuff_parse_int8(_err, (int8_t *)_out, _in, true), \ - int16_t * : fr_sbuff_parse_int16(_err, (int16_t *)_out, _in, true), \ - int32_t * : fr_sbuff_parse_int32(_err, (int32_t *)_out, _in, true), \ - int64_t * : fr_sbuff_parse_int64(_err, (int64_t *)_out, _in, true), \ - uint8_t * : fr_sbuff_parse_uint8(_err, (uint8_t *)_out, _in, true), \ - uint16_t * : fr_sbuff_parse_uint16(_err, (uint16_t *)_out, _in, true), \ - uint32_t * : fr_sbuff_parse_uint32(_err, (uint32_t *)_out, _in, true), \ - uint64_t * : fr_sbuff_parse_uint64(_err, (uint64_t *)_out, _in, true) \ + int8_t * : fr_sbuff_out_int8(_err, (int8_t *)_out, _in, true), \ + int16_t * : fr_sbuff_out_int16(_err, (int16_t *)_out, _in, true), \ + int32_t * : fr_sbuff_out_int32(_err, (int32_t *)_out, _in, true), \ + int64_t * : fr_sbuff_out_int64(_err, (int64_t *)_out, _in, true), \ + uint8_t * : fr_sbuff_out_uint8(_err, (uint8_t *)_out, _in, true), \ + uint16_t * : fr_sbuff_out_uint16(_err, (uint16_t *)_out, _in, true), \ + uint32_t * : fr_sbuff_out_uint32(_err, (uint32_t *)_out, _in, true), \ + uint64_t * : fr_sbuff_out_uint64(_err, (uint64_t *)_out, _in, true), \ + float * : fr_sbuff_out_float32(_err, (float *)_out, _in, true), \ + double * : fr_sbuff_out_float64(_err, (double *)_out, _in, true), \ ) /** @} */ @@ -659,6 +698,40 @@ static inline void _fr_sbuff_print_init(fr_sbuff_t *out, char *start, char *end, out->is_extendable = extendable; } +size_t fr_sbuff_in_int8(fr_sbuff_parse_error_t *err, int8_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_int16(fr_sbuff_parse_error_t *err, int16_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_int32(fr_sbuff_parse_error_t *err, int32_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_int64(fr_sbuff_parse_error_t *err, int64_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_uint8(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_uint16(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_uint32(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_float32(fr_sbuff_parse_error_t *err, float *out, fr_sbuff_t *in, bool no_trailing); + +size_t fr_sbuff_in_float64(fr_sbuff_parse_error_t *err, double *out, fr_sbuff_t *in, bool no_trailing); + +ssize_t fr_sbuff_in_strcpy(fr_sbuff_t *sbuff, char const *str); + +ssize_t fr_sbuff_in_bstrncpy(fr_sbuff_t *sbuff, char const *str, size_t len); + +ssize_t fr_sbuff_in_bstrcpy_buffer(fr_sbuff_t *sbuff, char const *str); + +ssize_t fr_sbuff_in_vsprintf(fr_sbuff_t *sbuff, char const *fmt, va_list ap); + +ssize_t fr_sbuff_in_sprintf(fr_sbuff_t *sbuff, char const *fmt, ...); + +ssize_t fr_sbuff_in_snprint(fr_sbuff_t *sbuff, char const *in, size_t inlen, char quote); + +ssize_t fr_sbuff_in_snprint_buffer(fr_sbuff_t *sbuff, char const *in, char quote); + #ifdef __cplusplus } #endif