#pragma once #include #include #include #define SV_LIT(S) ((void)(S "LITERAL_CHECK"), (str_view_t) { S, sizeof(S) - 1 }) #define SV_NULL ((str_view_t) { NULL, 0 }) #define SB_NULL ((str_buf_t) { NULL, 0 }) #define SB_SCOPED(NAME) str_buf_t NAME __attribute__((cleanup(sb_free))) = SB_NULL #define SV_PRI "%.*s" #define SV_PRI_ARGS(S) (int)((S).len), (S).ptr // String which is: // - Not owned // - Not necessarily heap-allocated // - Not necessarily nul-terminated typedef struct { const char *ptr; size_t len; } str_view_t; // String which is: // - Owned // - Heap-allocated // - Nul-terminated // The length does not include the nul terminator. typedef struct { char *ptr; size_t len; } str_buf_t; static inline bool sv_is_null(str_view_t s) { return !s.ptr; } static inline bool sv_is_empty(str_view_t s) { return !s.len; } static inline bool sb_is_null(str_buf_t buf) { return !buf.ptr; } static inline bool sb_is_empty(str_buf_t buf) { return !buf.len; } static inline str_view_t sv_from_parts(const char *ptr, size_t len) { return (str_view_t) { ptr, len }; } static inline str_view_t sv_from_cstr(const char *ptr, size_t maxlen) { size_t len; len = strnlen(ptr, maxlen); return sv_from_parts(ptr, len); } static inline str_view_t sv_from_cstr_unbounded(const char *ptr) { size_t len = strlen(ptr); return sv_from_parts(ptr, len); } static inline bool sv_eq(str_view_t s1, str_view_t s2) { return (s1.len == s2.len) && ((!s1.ptr || !s2.ptr) ? (s1.ptr == s2.ptr) : !memcmp(s1.ptr, s2.ptr, s1.len)); } static inline str_view_t sv_substr(str_view_t s, size_t start, size_t end) { if ((start > end) || (start > s.len) || (end > s.len)) return SV_NULL; return sv_from_parts(s.ptr + start, end - start); } static inline str_view_t sb_view(str_buf_t buf) { return sv_from_parts(buf.ptr, buf.len); } str_buf_t sb_from_sv(str_view_t s); static inline void sb_free(str_buf_t *buf) { free(buf->ptr); buf->ptr = NULL; buf->len = 0; }