* - >0 the number of bytes copied.
*/
#define PARSE_INT_DEF(_name, _type, _min, _max) \
-size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in) \
+size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \
{ \
char buff[sizeof(STRINGIFY(_min)) + 1]; \
char *end; \
size_t len; \
long long num; \
- len = fr_sbuff_strncpy(buff, sizeof(buff), &FR_SBUFF_NO_ADVANCE(in), sizeof(STRINGIFY(_min))); \
+ fr_sbuff_t our_in = FR_SBUFF_NO_ADVANCE(in); \
+ len = fr_sbuff_strncpy(buff, sizeof(buff), &our_in, sizeof(STRINGIFY(_min))); \
if ((len == 0) && err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
num = strtoll(buff, &end, 10); \
if (end == buff) { \
if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
return 0; \
} \
- if ((num > (_max)) || ((errno == EINVAL) && (num == LLONG_MAX))) { \
+ if ((num > (_max)) || ((errno == EINVAL) && (num == LLONG_MAX)) || (no_trailing && fr_sbuff_is_digit(&our_in))) { \
if (err) *err = FR_SBUFF_PARSE_ERROR_INTEGER_OVERFLOW; \
*out = (_type)(_max); \
} else if (num < (_min) || ((errno == EINVAL) && (num == LLONG_MIN))) { \
if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
*out = (_type)(num); \
} \
- fr_sbuff_advance(in, end - buff); \
+ fr_sbuff_set(in, &our_in); \
return end - buff; \
}
* @param[in] _max value.
*/
#define PARSE_UINT_DEF(_name, _type, _max) \
-size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in) \
+size_t fr_sbuff_parse_##_name(fr_sbuff_parse_error_t *err, _type *out, fr_sbuff_t *in, bool no_trailing) \
{ \
char buff[sizeof(STRINGIFY(_max)) + 1]; \
char *end; \
size_t len; \
unsigned long long num; \
- len = fr_sbuff_strncpy(buff, sizeof(buff), &FR_SBUFF_NO_ADVANCE(in), sizeof(STRINGIFY(_max))); \
+ fr_sbuff_t our_in = FR_SBUFF_NO_ADVANCE(in); \
+ len = fr_sbuff_strncpy(buff, sizeof(buff), &our_in, sizeof(STRINGIFY(_max))); \
if ((len == 0) && err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
num = strtoull(buff, &end, 10); \
if (end == buff) { \
if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
return 0; \
} \
- if ((num > (_max)) || ((errno == EINVAL) && (num == ULLONG_MAX))) { \
+ if ((num > (_max)) || ((errno == EINVAL) && (num == ULLONG_MAX)) || (no_trailing && fr_sbuff_is_digit(&our_in))) { \
if (err) *err = FR_SBUFF_PARSE_ERROR_INTEGER_OVERFLOW; \
*out = (_type)(_max); \
} else { \
if (err) *err = FR_SBUFF_PARSE_ERROR_NOT_FOUND; \
*out = (_type)(num); \
} \
- fr_sbuff_advance(in, end - buff); \
+ fr_sbuff_set(in, &our_in); \
return end - buff; \
}
extern "C" {
# endif
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
-#include <limits.h>
-#include <errno.h>
typedef struct fr_sbuff_ptr_s fr_sbuff_marker_t;
struct fr_sbuff_ptr_s {
size_t : ((_dst)->p += (uintptr_t)(_src)) \
))
+/** Find the longest prefix in an sbuff
+ *
+ * @param[out] _match_len The length of the matched string.
+ * May be NULL.
+ * @param[out] _out The value resolve in the table.
+ * @param[in] _table to find longest match in.
+ * @param[in] _sbuff containing the needle.
+ * @param[in] _def Default value if no match is found.
+ */
+#define fr_sbuff_table_value_by_longest_prefix(_match_len, _out, _table, _sbuff, _def) \
+do { \
+ size_t _match_len_tmp; \
+ fr_sbuff_t _sbuff_tmp = FR_SBUFF_COPY(_sbuff); \
+ *(_out) = fr_table_value_by_longest_prefix(&_match_len_tmp, _table, &_sbuff_tmp, \
+ fr_sbuff_available(&_sbuff_tmp), _def); \
+ (void) fr_sbuff_advance(_match_len); \
+ if (_match_len) *(_match_len) = _match_len_tmp; \
+} while (0)
+
/** Advance position in sbuff by N bytes
*
* @param[in] sbuff to advance.
}
#define FR_SBUFF_ADVANCE_RETURN(_sbuff, _n) FR_SBUFF_RETURN(fr_sbuff_advance, _sbuff, _n)
-/** Return the current char and advance
+/** Advance the sbuff by one char
*
*/
-static inline char fr_sbuff_next_char(fr_sbuff_t *sbuff)
+static inline char fr_sbuff_next(fr_sbuff_t *sbuff)
{
if (sbuff->p >= sbuff->end) return '\0';
- return *(sbuff->p++);
+ sbuff->p++;
+
+ return *sbuff->p;
}
/** Set the start pointer to the current value of p
_fr_sbuff_set_recurse(sbuff, sbuff->end);
}
+/** @name Conditions
+ * @{
+ */
+
+/** Return true if the current char matches, and if it does, advance
+ *
+ */
+static inline bool fr_sbuff_next_if_char(fr_sbuff_t *sbuff, char c)
+{
+ if (sbuff->p >= sbuff->end) return false;
+ if (*sbuff->p != c) return false;
+
+ fr_sbuff_advance(sbuff, 1);
+
+ return true;
+}
+
+static inline bool fr_sbuff_next_unless_char(fr_sbuff_t *sbuff, char c)
+{
+ if (sbuff->p >= sbuff->end) return false;
+ if (*sbuff->p == c) return false;
+
+ fr_sbuff_advance(sbuff, 1);
+
+ return true;
+}
+
+/** Return true if the current char matches, and advance
+ *
+ */
+static inline bool fr_sbuff_next_char(fr_sbuff_t *sbuff, char c)
+{
+ bool ret;
+
+ if (sbuff->p >= sbuff->end) return false;
+
+ ret = *sbuff->p == c;
+
+ fr_sbuff_advance(sbuff, 1);
+
+ return ret;
+}
+
+static inline bool fr_sbuff_is_digit(fr_sbuff_t *sbuff)
+{
+ if (sbuff->p >= sbuff->end) return false;
+ return isdigit(*sbuff->p);
+}
+
+static inline bool fr_sbuff_is_upper(fr_sbuff_t *sbuff)
+{
+ if (sbuff->p >= sbuff->end) return false;
+ return isupper(*sbuff->p);
+}
+
+static inline bool fr_sbuff_is_lower(fr_sbuff_t *sbuff)
+{
+ if (sbuff->p >= sbuff->end) return false;
+ return islower(*sbuff->p);
+}
+
+static inline bool fr_sbuff_is_alpha(fr_sbuff_t *sbuff)
+{
+ if (sbuff->p >= sbuff->end) return false;
+ return isalpha(*sbuff->p);
+}
+
+static inline bool fr_sbuff_is_space(fr_sbuff_t *sbuff)
+{
+ if (sbuff->p >= sbuff->end) return false;
+ return isspace(*sbuff->p);
+}
+/** @} */
+
/** Adds a new pointer to the beginning of the list of pointers to update
*
*/
* 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);
-
-size_t fr_sbuff_parse_int16(fr_sbuff_parse_error_t *err, int16_t *out, fr_sbuff_t *sbuff);
+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_parse_int32(fr_sbuff_parse_error_t *err, int32_t *out, fr_sbuff_t *sbuff);
+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_parse_int64(fr_sbuff_parse_error_t *err, int64_t *out, fr_sbuff_t *sbuff);
+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_parse_uint8(fr_sbuff_parse_error_t *err, uint8_t *out, fr_sbuff_t *sbuff);
+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_parse_uint16(fr_sbuff_parse_error_t *err, uint16_t *out, fr_sbuff_t *sbuff);
+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_parse_uint32(fr_sbuff_parse_error_t *err, uint32_t *out, fr_sbuff_t *sbuff);
+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_parse_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff);
+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_parse_uint64(fr_sbuff_parse_error_t *err, uint64_t *out, fr_sbuff_t *sbuff, bool no_trailing);
/** Parse a value based on the output type
*
*/
#define fr_sbuff_parse(_err, _out, _in) \
_Generic((_out), \
- int8_t * : fr_sbuff_parse_int8(_err, _out, _in), \
- int16_t * : fr_sbuff_parse_int16(_err, _out, _in), \
- int32_t * : fr_sbuff_parse_int32(_err, _out, _in), \
- int64_t * : fr_sbuff_parse_int64(_err, _out, _in), \
- uint8_t * : fr_sbuff_parse_uint8(_err, _out, _in), \
- uint16_t * : fr_sbuff_parse_uint16(_err, _out, _in), \
- uint32_t * : fr_sbuff_parse_uint32(_err, _out, _in), \
- uint64_t * : fr_sbuff_parse_uint64(_err, _out, _in) \
+ 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) \
)
/** @} */