From 8e114d6fe4b0a567a13c8ad613af2c9c9f5ceb9c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sat, 24 Mar 2018 08:42:15 +0100 Subject: [PATCH] Add bounded string definition so that you can easily use them for a container. --- m-string.h | 239 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 2 deletions(-) diff --git a/m-string.h b/m-string.h index 2743084c..04a20580 100644 --- a/m-string.h +++ b/m-string.h @@ -43,7 +43,7 @@ // This macro defines the contract of a string. // Note: A ==> B is represented as not(A) or B // Note: use of strlen can slow down a lot the program in some cases. -#define STRINGI_CONTRACT(v) do { \ +#define STRINGI_CONTRACT(v) do { \ M_ASSUME (v != NULL); \ M_ASSUME (v->ptr != NULL || (v->size == 0 && v->alloc == 0)); \ STRINGI_ASSUME (v->ptr == NULL || v->size == strlen(v->ptr)); \ @@ -52,7 +52,13 @@ } while (0) -/********************************** EXTERNAL ************************************/ +/****************************** EXTERNAL *******************************/ + +/***********************************************************************/ +/* */ +/* DYNAMIC STRING */ +/* */ +/***********************************************************************/ /* Index returned in case of error */ #define STRING_FAILURE ((size_t)-1) @@ -137,6 +143,7 @@ string_empty_p(const string_t v) return v->size == 0; } +// Size includes the final null char static inline void stringi_fit2size (string_t v, size_t size) { @@ -1161,4 +1168,232 @@ namespace m_string { #endif + +/***********************************************************************/ +/* */ +/* BOUNDED STRING, aka char[N+1] */ +/* */ +/***********************************************************************/ + +#define BOUNDED_STRING_DEF(name, size) \ + \ + typedef struct M_C(name, _s) { \ + char s[size+1]; \ + } M_C(name,_t)[1]; \ + \ + static inline void \ + M_C(name, _init)(M_C(name,_t) s) \ + { \ + assert(s != NULL); \ + s->s[0] = 0; \ + } \ + \ + static inline void \ + M_C(name, _clear)(M_C(name,_t) s) \ + { \ + assert(s != NULL); \ + /* nothing to do */ \ + } \ + \ + static inline void \ + M_C(name, _clean)(M_C(name,_t) s) \ + { \ + assert(s != NULL); \ + s->s[0] = 0; \ + } \ + \ + static inline size_t \ + M_C(name, _size)(const M_C(name,_t) s) \ + { \ + assert(s != NULL); \ + return strlen(s->s); \ + } \ + \ + static inline size_t \ + M_C(name, _capacity)(const M_C(name,_t) s) \ + { \ + assert(s != NULL); \ + (void)s; /* unused */ \ + return size+1; \ + } \ + \ + static inline char \ + M_C(name, _get_char)(const M_C(name,_t) s, size_t index) \ + { \ + assert(s != NULL); \ + assert(index < size); \ + return s->s[index]; \ + } \ + \ + static inline bool \ + M_C(name, _empty_p)(const M_C(name,_t) s) \ + { \ + assert(s != NULL); \ + return s->s[0] == 0; \ + } \ + \ + static inline void \ + M_C(name, _set_str)(M_C(name,_t) s, const char str[]) \ + { \ + assert (s != NULL && str != NULL); \ + strncpy(s->s, str, size+1); \ + s->s[size] = 0; \ + } \ + \ + static inline void \ + M_C(name, _set_strn)(M_C(name,_t) s, const char str[], size_t n) \ + { \ + assert (s != NULL && str != NULL); \ + size_t len = M_MIN(size, n); \ + strncpy(s->s, str, len+1); \ + s->s[len] = 0; \ + } \ + \ + static inline const char * \ + M_C(name, _get_cstr)(const M_C(name,_t) s) \ + { \ + assert (s != NULL); \ + return s->s; \ + } \ + \ + static inline void \ + M_C(name, _set)(M_C(name,_t) s, const M_C(name,_t) str) \ + { \ + assert (s != NULL && str != NULL); \ + M_C(name, _set_str)(s, str->s); \ + } \ + \ + static inline void \ + M_C(name, _set_n)(M_C(name,_t) s, const M_C(name,_t) str, \ + size_t offset, size_t length) \ + { \ + assert (s != NULL && str != NULL); \ + assert (offset <= size); \ + M_C(name, _set_strn)(s, str->s+offset, length); \ + } \ + \ + static inline void \ + M_C(name, _init_set)(M_C(name,_t) s, const M_C(name,_t) str) \ + { \ + M_C(name,_init)(s); \ + M_C(name,_set)(s, str); \ + } \ + \ + static inline void \ + M_C(name, _init_set_str)(M_C(name,_t) s, const char str[]) \ + { \ + M_C(name,_init)(s); \ + M_C(name,_set_str)(s, str); \ + } \ + \ + static inline void \ + M_C(name, _cat_str)(M_C(name,_t) s, const char str[]) \ + { \ + assert (s != NULL && str != NULL); \ + assert (strlen(s->s) <= size); \ + strncat(s->s, str, size-strlen(s->s)); \ + } \ + \ + static inline void \ + M_C(name, _cat)(M_C(name,_t) s, const M_C(name,_t) str) \ + { \ + M_C(name, _cat_str)(s, str->s); \ + } \ + \ + static inline int \ + M_C(name, _cmp_str)(const M_C(name,_t) s, const char str[]) \ + { \ + assert (s != NULL && str != NULL); \ + return strcmp(s->s, str); \ + } \ + \ + static inline int \ + M_C(name, _cmp)(const M_C(name,_t) s, const M_C(name,_t) str) \ + { \ + assert (s != NULL && str != NULL); \ + return strcmp(s->s, str->s); \ + } \ + \ + static inline int \ + M_C(name, _equal_str_p)(const M_C(name,_t) s, const char str[]) \ + { \ + assert (s != NULL && str != NULL); \ + return strcmp(s->s, str) == 0; \ + } \ + \ + static inline int \ + M_C(name, _equal_p)(const M_C(name,_t) s, const M_C(name,_t) str) \ + { \ + assert (s != NULL && str != NULL); \ + return strcmp(s->s, str->s) == 0; \ + } \ + \ + static inline int \ + M_C(name, _printf)(M_C(name,_t) s, const char format[], ...) \ + { \ + assert (s != NULL && format != NULL); \ + va_list args; \ + int ret; \ + va_start (args, format); \ + ret = vsnprintf (s->s, size+1, format, args); \ + va_end (args); \ + return ret; \ + } \ + \ + static inline int \ + M_C(name, _cat_printf)(M_C(name,_t) s, const char format[], ...) \ + { \ + assert (s != NULL && format != NULL); \ + va_list args; \ + int ret; \ + va_start (args, format); \ + size_t length = strlen(s->s); \ + assert(length <= size); \ + ret = vsnprintf (&s->s[length], size+1-length, format, args); \ + va_end (args); \ + return ret; \ + } \ + \ + static inline bool \ + M_C(name, _fgets)(M_C(name,_t)s, FILE *f, string_fgets_t arg) \ + { \ + assert (s != NULL && f != NULL); \ + assert (arg != STRING_READ_FILE); \ + char *ret = fgets(s->s, size+1, f); \ + s->s[size] = 0; \ + if (ret != NULL && arg == STRING_READ_PURE_LINE) { \ + size_t length = strlen(s->s); \ + if (length > 0 && s->s[length-1] == '\n') \ + s->s[length-1] = 0; \ + } \ + return ret != NULL; \ + } \ + \ + static inline bool \ + M_C(name, _fputs)(FILE *f, const M_C(name,_t) s) \ + { \ + assert(f != NULL && s != NULL); \ + return fputs(s->s, f) >= 0; \ + } \ + \ + static inline size_t \ + M_C(name, _hash)(const M_C(name,_t) s) \ + { \ + assert (s != NULL); \ + /* Cannot use m_core_hash: not aligned on an int */ \ + M_HASH_DECL(hash); \ + const char *str = s->s; \ + while (*str) M_HASH_UP(hash, *str++); \ + return M_HASH_FINAL(hash); \ + } \ + + +/* Define the OPLIST of a BOUNDED_STRING */ +#define BOUNDED_STRING_OPLIST(name) \ + (INIT(M_C(name,_init)), INIT_SET(M_C(name,_init_set)), \ + SET(M_C(name,_set)), CLEAR(M_C(name,_clear)), HASH(M_C(name,_hash)), \ + EQUAL(M_C(name,_equal_p)), CMP(M_C(name,_cmp)), TYPE(M_C(name,_t)), \ + ) + + #endif