/** * @file staticstring.h * @brief A fixed-capacity string object handed out by the akgl string heap layer. * * The library allocates nothing at runtime, so a "string" here is a * PATH_MAX-sized buffer claimed from the pool with akgl_heap_next_string and * given back with akgl_heap_release_string. Capacity is fixed at compile time: * these functions truncate rather than grow, and truncation is silent. */ #ifndef _STRING_H_ #define _STRING_H_ #include "string.h" #include #include #define AKGL_MAX_STRING_LENGTH PATH_MAX /** @brief Provides a fixed-capacity, heap-managed string buffer. */ typedef struct { int refcount; /**< Pool bookkeeping; 0 means the slot is free. Owned by the heap layer. */ char data[AKGL_MAX_STRING_LENGTH]; /**< The characters. Not guaranteed NUL-terminated when filled to capacity. */ } akgl_String; /** * @brief Set a pooled string's contents and mark the slot in use. * * Copies at most #AKGL_MAX_STRING_LENGTH bytes out of @p init, or zeroes the * buffer when @p init is `NULL`, then sets `refcount` to 1. Callers normally * reach this through akgl_heap_next_string rather than calling it directly. * * @param obj The pooled string to (re)initialize. Required. Its previous * contents are discarded without inspection. * @param init Initial contents, NUL-terminated. Optional -- `NULL` zero-fills * the buffer instead. An @p init longer than * #AKGL_MAX_STRING_LENGTH is truncated *and left unterminated*, * because this is `strncpy` semantics, not `strlcpy`. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER If @p obj is `NULL`. * * @note Known defect: the `NULL` @p init path zeroes `sizeof(akgl_String)` * bytes starting at `data`, which is four bytes past the end of the * buffer -- `refcount` sits in front of it. TODO.md, "Known and still * open" item 6. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_string_initialize(akgl_String *obj, char *init); /** * @brief Copy the contents of one pooled string into another. * * A bounded `strncpy` between two already-claimed pool slots. It copies bytes * only: `refcount` is left alone, so @p dst keeps whatever pool state it had. * * @param src Source string. Required. Read up to @p count bytes. * @param dst Destination string. Required. Overwritten in place; the pool * slot must already have been claimed. * @param count Maximum bytes to copy. 0 selects #AKGL_MAX_STRING_LENGTH, the * whole buffer. A @p count shorter than the source truncates * without writing a terminator; a @p count longer than the source * zero-pads the remainder, per `strncpy`. Values above * #AKGL_MAX_STRING_LENGTH overrun both buffers and are not * rejected. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER If @p src or @p dst is `NULL`. * @throws errno Whatever `errno` holds if `strncpy` returns something other * than @p dst. In practice `strncpy` always returns its destination, so * this path is unreachable rather than merely rare. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_string_copy(akgl_String *src, akgl_String *dst, int count); #endif //_STRING_H_