so://phie

ductape

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

blob: bb89b772cda5cbd6d4b2d383a611634600ec3b99 (2846 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

18#ifndef _SO_DUCTAPE_H

19#define _SO_DUCTAPE_H

20

21#include <stdio.h>

22#include <stdlib.h>

23

24// @type duc_render_fn_t

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

26

27// @struct duc_templref_t

28typedef struct {

29 duc_render_fn_t fn;

30 void *data;

31 const char *dl_path;

32} duc_templref_t;

33

34// @macro __DUC_TEMPLDEF_MACRO

35// @internal

36#define __DUC_TEMPLDEF_MACRO($name, $params) \

37 typedef struct { \

38 $params \

39 } $name##_t; \

40 \

41 typedef void (*$name##_fn_t)(void *, $name##_t *); \

42 \

43 int $name##_render(void *out, void *ctx) { \

44 char *path = getenv("DUC_BUILDPATH"); \

45 if (path == NULL) { \

46 path = "./"; \

47 } \

48 char dl_path[strlen(path) + strlen(__DUC_UID_##$name) + 4]; \

49 snprintf(dl_path, sizeof(dl_path), "%s%s.so", path, __DUC_UID_##$name); \

50 void *handle = dlopen(dl_path, RTLD_NOW); \

51 if (!handle) { \

52 fprintf(stderr, "%s\n", dlerror()); \

53 return 1; \

54 } \

55 const size_t *hash = (size_t *) dlsym(handle, "__DUC_SIG_HASH_" #$name); \

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

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

58 return 1; \

59 } \

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

61 char *err = dlerror(); \

62 if (err) { \

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

64 dlclose(handle); \

65 return 1; \

66 } \

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

68 dlclose(handle); \

69 return 0; \

70 }

71

72// @macro __DUC_TEMPLDEF_HEADER

73// @internal

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

75 __DUC_TEMPLDEF_MACRO($name, $params) \

76 \

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

78

79// @macro DUC_TEMPLDEF

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

81 __DUC_TEMPLDEF_MACRO($name, $params) \

82 \

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

84

85// @macro DUC_ENDTEMPL

86#define DUC_ENDTEMPL }

87

88// @macro DUC_TEMPLBIND

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

90 (duc_templref_t) { \

91 .fn = $name##_render, \

92 .data = $data, \

93 .dl_path = $dl_path, \

94 },

95

96// @macro DUC_INCLUDE

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

98

99#endif // _SO_DUC_H