Files
2025-08-14 20:25:43 -03:00

81 lines
3.7 KiB
C

#ifndef _INIT_H
#define _INIT_H
#include <stddef.h>
#define INIT_ROUTINE_FLAGS_NONE 0
#define INIT_ROUTINE_FLAGS_ALREADY_DONE 1
#define INIT_ROUTINE_FLAGS_QUIET 2
#define INIT_ROUTINE_FLAGS_PHONY 4
typedef struct init_routine_t {
const char *name;
int flags;
void (*fn)(void);
struct init_routine_t ***dependencies;
size_t dependency_count;
} init_routine_t;
// tasty tasty macro soup!
// this will make it cleaner overall and keep the ugly here
// if any routine has more than 10 deps add more here
#define INIT_MACRO_ARG_COUNT_(n0, n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n, ...) n
#define INIT_MACRO_ARG_COUNT(...) INIT_MACRO_ARG_COUNT_(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define INIT_CONCAT_(a, b) a##b
#define INIT_CONCAT(a, b) INIT_CONCAT_(a, b)
#define INIT_GET_DEP_NAME(x) init_routine_ ## x
#define INIT_DEFINE_EXTERN(x) extern init_routine_t * INIT_GET_DEP_NAME(x)
#define INIT_DEFINE_EXTERN_0(...)
#define INIT_DEFINE_EXTERN_1(x) INIT_DEFINE_EXTERN(x)
#define INIT_DEFINE_EXTERN_2(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_1(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_3(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_2(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_4(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_3(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_5(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_4(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_6(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_5(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_7(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_6(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_8(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_7(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_9(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_8(__VA_ARGS__)
#define INIT_DEFINE_EXTERN_10(x, ...) INIT_DEFINE_EXTERN(x); INIT_DEFINE_EXTERN_9(__VA_ARGS__)
#define INIT_GET_DEP_0(...)
#define INIT_GET_DEP_1(x) &INIT_GET_DEP_NAME(x)
#define INIT_GET_DEP_2(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_1(__VA_ARGS__)
#define INIT_GET_DEP_3(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_2(__VA_ARGS__)
#define INIT_GET_DEP_4(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_3(__VA_ARGS__)
#define INIT_GET_DEP_5(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_4(__VA_ARGS__)
#define INIT_GET_DEP_6(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_5(__VA_ARGS__)
#define INIT_GET_DEP_7(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_6(__VA_ARGS__)
#define INIT_GET_DEP_8(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_7(__VA_ARGS__)
#define INIT_GET_DEP_9(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_8(__VA_ARGS__)
#define INIT_GET_DEP_10(x, ...) &INIT_GET_DEP_NAME(x), INIT_GET_DEP_9(__VA_ARGS__)
#define INIT_GET_ROUTINE(name) init_routine_##name
// ... is deps
#define INIT_ROUTINE_DEFINE(name_, flags_, fn_, ...) \
/* first define all dependencies as extern. if none, then it will not define any
* but since it will not be used, then there is no harm done. */ \
INIT_CONCAT(INIT_DEFINE_EXTERN_, INIT_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__); \
/* then, create the array of the dependencies for the use in the main struct.
* if none, then it will just be empty */ \
static init_routine_t **init_routine_deps_##name_ [] = { \
INIT_CONCAT(INIT_GET_DEP_, INIT_MACRO_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__) \
}; \
/* finally, define the init routine struct and keep a pointer to it in the special section */ \
static init_routine_t struct_init_routine_##name_ = { \
.name = #name_, \
.flags = flags_, \
.fn = fn_, \
.dependencies = init_routine_deps_##name_, \
.dependency_count = INIT_MACRO_ARG_COUNT(__VA_ARGS__) \
}; \
__attribute__((section(".init_routines"), used)) init_routine_t *init_routine_##name_ = &struct_init_routine_##name_;
void init_run_routine(init_routine_t *routine);
void init_run_all_routines(void);
#endif