/* [ʞ] compose.c
 *  ~ lexi hale <lexi@hale.su>
 *  © affero general public license v3
 *  $ cc -c compose.c
 *  # include <string.h>
 *
 * compose.c contains some useful string utilities
 * that libc lacks.

   TODO add macro to use homebrew strlen instead of
        dragging in <string.h> */

#ifdef k_header // only emit the declarations
#	define k_impl(x)
#else
#	define k_impl(x) x
#endif

#include <string.h>

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, str);
	*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
