/* [ʞ] 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 fn(x)
#else
#	define fn(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
	bool heap;
	size_t len;
} safestr;

void delstr(safestr s) fn ({
	if (s.heap) { free(s.mutptr); }
});

void clrstr(safestr* s) fn ({
	delstr(*s);
	s->heap = false;
	s->ptr = NULL;
	s->len = 0;
})

char* compose(pstr* lst,size_t ct, size_t* strsz) fn({
	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;
	}
	if (strsz != NULL) *strsz = len;
	if (len == 0) return NULL;
	
	char* str = malloc(len + 1);
	char* ptr = str;
	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;
	}
	*ptr = 0;
	return str;
});

