Static template generator for C
git clone git://soophie.de/ductape
blob: 1812ddbcd618374f0e59764c3ad8bb60488ba2cf (2813 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
#pragma once19
#include <stdio.h>20
#include <stdlib.h>21
#include <string.h>23
// @type duc_render_fn_t24
typedef int (*duc_render_fn_t)(void *, void *);26
// @struct duc_templref_t27
typedef struct {28
duc_render_fn_t fn;29
void *data;30
const char *dl_path;31
} duc_templref_t;33
// @macro __DUC_TEMPLDEF_MACRO34
// @internal35
#define __DUC_TEMPLDEF_MACRO($name, $params) \36
typedef struct { \37
$params \38
} $name##_t; \39
\40
typedef void (*$name##_fn_t)(void *, $name##_t *); \41
\42
int $name##_render(void *out, void *ctx) { \43
char *path = getenv("DUC_BUILDPATH"); \44
if (path == NULL) { \45
path = "./"; \46
} \47
char dl_path[strlen(path) + strlen(__DUC_UID_##$name) + 4]; \48
snprintf(dl_path, sizeof(dl_path), "%s%s.so", path, __DUC_UID_##$name); \49
void *handle = dlopen(dl_path, RTLD_NOW); \50
if (!handle) { \51
fprintf(stderr, "%s\n", dlerror()); \52
return 1; \53
} \54
const size_t *hash = (size_t *) dlsym(handle, "__DUC_SIG_HASH_" #$name); \55
if (__DUC_SIG_HASH_##$name != *hash) { \56
fprintf(stderr, "Invalid signature hash! (%llx != %llx)\n", __DUC_SIG_HASH_##$name, *hash); \57
return 1; \58
} \59
$name##_fn_t fn = ($name##_fn_t) dlsym(handle, "duc_" #$name); \60
char *err = dlerror(); \61
if (err) { \62
fprintf(stderr, "%s\n", err); \63
dlclose(handle); \64
return 1; \65
} \66
fn(out, ($name##_t *) ctx); \67
dlclose(handle); \68
return 0; \69
}71
// @macro __DUC_TEMPLDEF_HEADER72
// @internal73
#define __DUC_TEMPLDEF_HEADER($name, $params) \74
__DUC_TEMPLDEF_MACRO($name, $params) \75
\76
void duc_##$name(void *out, $name##_t *ctx);78
// @macro DUC_TEMPLDEF79
#define DUC_TEMPLDEF($name, $params) \80
__DUC_TEMPLDEF_MACRO($name, $params) \81
\82
void duc_##$name(void *out, $name##_t *ctx) {84
// @macro DUC_ENDTEMPL85
#define DUC_ENDTEMPL }87
// @macro DUC_TEMPLBIND88
#define DUC_TEMPLBIND($name, $data, $dl_path) \89
(duc_templref_t) { \90
.fn = $name##_render, \91
.data = $data, \92
.dl_path = $dl_path, \93
},95
// @macro DUC_INCLUDE96
#define DUC_INCLUDE($name) ctx->$name.fn(duc, ctx->$name.data, ctx->$name.dl_path);