#pragma once

/* "feature tests" */
#define _POSIX_C_SOURCE 200112L
	/*             <unistd.h> seteuid
	 * <sys/socket.h netdb.h> getnameinfo */
#define _GNU_SOURCE
	/* <net/if.h> IFNAMSIZ  [linux]
	 * <unistd.h> getresuid [linux]*/
#define _DEFAULT_SOURCE
	/* <unistd.h> daemon [glibc, BSD] */

/* arch headers */
#include <stdint.h>
#include <stddef.h>

#define _layout struct __attribute__((__packed__))
#define _zero(x) memset(&x, sizeof(x), 0)
#define _sz(x) (sizeof(x)/sizeof(x)[0])
#define __cat(a,b) a##b
#define _cat(a,b) __cat(a,b)
#define _strify(...) #__VA_ARGS__

#if __STDC_VERSION__ == 202000L
/* incomplete support */
#elif __STDC_VERSION__ > 202000L
#	define null nullptr
#endif
#if __STDC_VERSION__ <= 202000L
#	define null ((void*)0)
#	define thread_local _Thread_local
#	include <stdbool.h>
#endif

extern uint8_t g_loglevel;
extern thread_local char g_logbuf [2 * 1024];
#define _lprint(...) snprintf(g_logbuf, sizeof g_logbuf, __VA_ARGS__)

void msg(uint8_t lvl, char* tag, uint8_t color, char* msg);

#define _msgf(lvl, tag, color, ...) { \
	if (g_loglevel >= lvl) { \
		_lprint(__VA_ARGS__); \
		msg(lvl, tag, color, g_logbuf); \
	} \
}

#define _fatal(str) { msg(1, "fatal", 1, (str)); exit(1); }
#define _warn(str)    msg(2, "warn", 3, (str))
#define _info(str)    msg(3, "info", 4, (str))
#define _dbg(str)     msg(4, "debug", 2, (str))

#define _fatalf(...) _msgf(1, "fatal", 1, __VA_ARGS__)
#define _warnf(...)  _msgf(2, "warn",  3, __VA_ARGS__)
#define _infof(...)  _msgf(3, "info",  4, __VA_ARGS__)
#define _dbgf(...)   _msgf(4, "debug", 2, __VA_ARGS__)

typedef struct string {
	size_t sz; char* ptr;
} string;
