so://phie

ductape

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

blob: 1812ddbcd618374f0e59764c3ad8bb60488ba2cf (2813 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 (__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 }

70

71// @macro __DUC_TEMPLDEF_HEADER

72// @internal

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

74 __DUC_TEMPLDEF_MACRO($name, $params) \

75 \

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

77

78// @macro DUC_TEMPLDEF

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

80 __DUC_TEMPLDEF_MACRO($name, $params) \

81 \

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

83

84// @macro DUC_ENDTEMPL

85#define DUC_ENDTEMPL }

86

87// @macro DUC_TEMPLBIND

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

89 (duc_templref_t) { \

90 .fn = $name##_render, \

91 .data = $data, \

92 .dl_path = $dl_path, \

93 },

94

95// @macro DUC_INCLUDE

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