so://phie

ductape

Static template generator for C
git clone git://soophie.de/ductape

blob: 822a65697b7d12b5e4407b70f4d1427218ea7095 (2962 bytes)[doc][blame][raw]

1// Copyright (C) 2026 Sophie Sitzler

2//

3// This program is free software: you can redistribute it and/or modify

4// it under the terms of the GNU General Public License as published by

5// the Free Software Foundation, either version 3 of the License, or

6// (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 of

10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

11// GNU General Public License for more details.

12//

13// You should have received a copy of the GNU General Public License

14// along with this program. If not, see <https://www.gnu.org/licenses/>.

15

16// @file ductape.h

17#pragma once

18

19#include <stdio.h>

20#include <stdlib.h>

21#include <string.h>

22

23// @type duc_render_fn_t

24typedef int (*duc_render_fn_t)(void *, void *);

25

26// @struct duc_templref_t

27typedef struct {

28 duc_render_fn_t fn;

29 void *data;

30 const char *dl_path;

31} duc_templref_t;

32

33// @macro __DUC_TEMPLDEF_MACRO

34// @internal

35#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 (!hash) { \

56 fprintf(stderr, "Missing signature hash!\n"); \

57 dlclose(handle); \

58 return 1; \

59 } \

60 if (__DUC_SIG_HASH_##$name != *hash) { \

61 fprintf(stderr, "Invalid signature hash! (%llx != %llx)\n", __DUC_SIG_HASH_##$name, *hash); \

62 dlclose(handle); \

63 return 1; \

64 } \

65 $name##_fn_t fn = ($name##_fn_t) dlsym(handle, "duc_" #$name); \

66 char *err = dlerror(); \

67 if (err) { \

68 fprintf(stderr, "%s\n", err); \

69 dlclose(handle); \

70 return 1; \

71 } \

72 fn(out, ($name##_t *) ctx); \

73 dlclose(handle); \

74 return 0; \

75 }

76

77// @macro __DUC_TEMPLDEF_HEADER

78// @internal

79#define __DUC_TEMPLDEF_HEADER($name, $params) \

80 __DUC_TEMPLDEF_MACRO($name, $params) \

81 \

82 void duc_##$name(void *out, $name##_t *ctx);

83

84// @macro DUC_TEMPLDEF

85#define DUC_TEMPLDEF($name, $params) \

86 __DUC_TEMPLDEF_MACRO($name, $params) \

87 \

88 void duc_##$name(void *out, $name##_t *ctx) {

89

90// @macro DUC_ENDTEMPL

91#define DUC_ENDTEMPL }

92

93// @macro DUC_TEMPLBIND

94#define DUC_TEMPLBIND($name, $data, $dl_path) \

95 (duc_templref_t) { \

96 .fn = $name##_render, \

97 .data = $data, \

98 .dl_path = $dl_path, \

99 },

100

101// @macro DUC_INCLUDE

102#define DUC_INCLUDE($name) ctx->$name.fn(duc, ctx->$name.data, ctx->$name.dl_path);