Static template generator for C
git clone git://soophie.de/ductape
blob: eadef81687f11cbb5f50b934a00168606dddd6db (3259 bytes)[doc][blame][raw]
1
// Copyright (C) 2026 Sophie Sitzler2
//3
// This program is free software: you can redistribute it and/or modify4
// it under the terms of the GNU General Public License as published by5
// the Free Software Foundation, either version 3 of the License, or6
// (at your option) any later version.7
//8
// This program is distributed in the hope that it will be useful,9
// but WITHOUT ANY WARRANTY; without even the implied warranty of10
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the11
// GNU General Public License for more details.12
//13
// You should have received a copy of the GNU General Public License14
// along with this program. If not, see <https://www.gnu.org/licenses/>.16
// @file ductape.h17
// @desc Static template generator for C19
#pragma once21
#include <stdio.h>23
// @macro __DUC_TEMPLDEF_TYPE24
// @internal25
// @desc Creates the type definitions for the template.26
// @param name - The template name.27
// @param param_list - The exposed template parameters.28
#define __DUC_TEMPLDEF_TYPE(name, param_list) \29
typedef struct { \30
const char *__duc_unused; \31
param_list \32
} name##_t; \33
\34
typedef void (*name##_fn_t)(void *, name##_t *);36
// @macro __DUC_TEMPLDEF_RENDER37
// @internal38
// @desc Creates the render implementation for the template.39
// @param name - The template name.40
#define __DUC_TEMPLDEF_RENDER(name) \41
int name##_render(void *out, void *ctx) { \42
char *path = getenv("DUC_BUILDPATH"); \43
if (path == NULL) { \44
path = "./"; \45
} \46
char dl_path[strlen(path) + strlen(__DUC_UID_##name) + 4]; \47
snprintf(dl_path, sizeof(dl_path), "%s%s.so", path, __DUC_UID_##name); \48
void *handle = dlopen(dl_path, RTLD_NOW); \49
if (!handle) { \50
fprintf(stderr, "%s\n", dlerror()); \51
return 1; \52
} \53
const size_t *hash = (size_t *) dlsym(handle, "__DUC_SIG_HASH_" #name); \54
if (!hash) { \55
fprintf(stderr, "Missing signature hash!\n"); \56
dlclose(handle); \57
return 1; \58
} \59
if (__DUC_SIG_HASH_##name != *hash) { \60
fprintf(stderr, "Invalid signature hash! (%lx != %lx)\n", __DUC_SIG_HASH_##name, *hash); \61
dlclose(handle); \62
return 1; \63
} \64
void *sym = dlsym(handle, "duc_" #name); \65
char *err = dlerror(); \66
if (err) { \67
fprintf(stderr, "%s\n", err); \68
dlclose(handle); \69
return 1; \70
} \71
name##_fn_t fn = NULL; \72
memcpy(&fn, &sym, sizeof(fn)); \73
fn(out, (name##_t *) ctx); \74
dlclose(handle); \75
return 0; \76
}78
// @macro __DUC_TEMPLDEF_HEADER79
// @internal80
// @desc Creates the header definition for the template. Used in generated .h file.81
// @param name - The template name.82
// @param param_list - The exposed template parameters.83
#define __DUC_TEMPLDEF_HEADER(name, param_list) \84
__DUC_TEMPLDEF_TYPE(name, param_list) \85
__DUC_TEMPLDEF_RENDER(name)87
// @macro DUC_TEMPLDEF88
// @desc Marks the beginning of a template definition. Used in generated .so file.89
// @param name - The template name.90
// @param param_list - The exposed template parameters.91
#define DUC_TEMPLDEF(name, param_list) \92
__DUC_TEMPLDEF_TYPE(name, param_list) \93
\94
void duc_##name(void *out, name##_t *ctx) {96
// @macro DUC_ENDTEMPL97
// @desc Marks the end of a template definition.98
#define DUC_ENDTEMPL }