/* [ʞ] compose.c * ~ lexi hale * © affero general public license v3 * $ cc -c compose.c * # include * * compose.c contains some useful string utilities * that libc lacks. TODO add macro to use homebrew strlen instead of dragging in */ #ifdef k_header // only emit the declarations # define k_impl(x) #else # define k_impl(x) x #endif #include typedef struct pstr { size_t len; union { const char* ptr; char* mutptr; }; } pstr; #define _p(str) { sizeof (str) - 1, (str) } typedef struct safestr { union { const char* ptr; char* mutptr; }; // im sorry okay # ifndef k_static bool heap; # endif size_t len; } safestr; #ifndef k_static void delstr(safestr s) k_impl ({ if (s.heap) { free(s.mutptr); } }); #endif void clrstr(safestr* s) k_impl ({ # ifndef k_static delstr(*s); s->heap = false; # endif s->ptr = NULL; s->len = 0; }) size_t pstrsum(pstr* lst,size_t ct) k_impl ({ size_t len = 0; for (size_t i = 0; i < ct; ++i) { if (lst[i].len == 0) { if (lst[i].ptr == NULL) continue; lst[i].len = strlen(lst[i].ptr); } len += lst[i].len; } return len; }) char* pstrcoll(pstr* lst, size_t ct, char* ptr) k_impl ({ for (size_t i = 0; i < ct; ++i) { if (lst[i].len == 0) continue; strncpy(ptr,lst[i].ptr,lst[i].len); ptr += lst[i].len; } return ptr; }) #ifndef k_static char* compose(pstr* lst,size_t ct, size_t* strsz) k_impl ({ size_t len = pstrsum(lst,ct) if (strsz != NULL) *strsz = len; if (len == 0) return NULL; char* str = malloc(len + 1); char* ptr = pstrcoll(lst, ct, ptr); *ptr = 0; return str; }); #endif char* impose(pstr* lst,size_t ct, size_t* strsz, char* buf) k_impl({ size_t len = pstrsum(lst,ct); if (strsz != NULL) *strsz = len; if (len == 0) return NULL; char* ptr = pstrcoll(lst, ct, buf); *ptr = 0; return ptr; }); char* imprint(pstr lst, size_t* strsz, char* buf) k_impl({ size_t len = pstrsum(&lst,1); if (strsz != NULL) *strsz = len; if (len == 0) return NULL; char* ptr = pstrcoll(&lst,1,buf); *ptr = 0; return ptr; }); #undef k_impl