so://phie

ductape

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

blob: 4e6d5386cabde0c6398df6013f0dad96999c4d11 (6675 bytes)[doc][blame][raw]

1#include <stdio.h>

2#include <stdlib.h>

3#include <getopt.h>

4

5#define SO_STR_IMPL

6#include <so/str.h>

7

8#define CTL_TMP_C_PATH ".ctl_tmp.c"

9#define CTL_TMP_SO_PATH ".ctl_tmp.so"

10

11typedef enum {

12 CTL_ERR_OK,

13 CTL_ERR_NO_ARGS,

14 CTL_ERR_NO_FILE,

15 CTL_ERR_NO_WRITE,

16 CTL_ERR_UNCLOSED_CODE,

17 CTL_ERR_NO_COMPILE,

18} ctl_err_t;

19

20typedef enum {

21 CTL_MODE_HEADER,

22 CTL_MODE_MODULE,

23} ctl_mode_t;

24

25void ctl_error_str(ctl_err_t err) {

26 switch (err) {

27 case CTL_ERR_OK:

28 break;

29 case CTL_ERR_NO_ARGS:

30 fprintf(stderr, "Usage: ctl -h <templ_path> (HEADER), ctl -o <templ_path> (MODULE)\n");

31 break;

32 case CTL_ERR_NO_FILE:

33 fprintf(stderr, "Error: No file found!\n");

34 break;

35 case CTL_ERR_NO_WRITE:

36 fprintf(stderr, "Error: Can't write to file!\n");

37 break;

38 case CTL_ERR_UNCLOSED_CODE:

39 fprintf(stderr, "Error: Unclosed code block!\n");

40 break;

41 case CTL_ERR_NO_COMPILE:

42 fprintf(stderr, "Error: Failed to compile!\n");

43 break;

44 }

45}

46

47ctl_err_t ctl_render(ctl_mode_t mode, str_t *template, char *content) {

48 int len = strlen(content);

49 int set = 0;

50 int is_code = 0;

51 int is_templ = 0;

52 str_append(template, "#include <dlfcn.h>\n");

53 str_append(template, "#include <so/ctl.h>\n");

54 for (int i = 0; i < len; i++) {

55 if (content[i] == '%') {

56 // ignore escaped %

57 if (i + 1 < len && content[i + 1] == '%') {

58 i += 1;

59 continue;

60 }

61 if (is_code) {

62 for (int j = 0; j < i - set; j++) {

63 if (strncmp(content + set + j, "TEMPLDEF", 8) == 0) {

64 is_templ = 1;

65 }

66 if (strncmp(content + set + j, "ENDTEMPL", 8) == 0) {

67 is_templ = 0;

68 }

69 }

70 if (mode == CTL_MODE_MODULE) {

71 str_append_len(template, content + set, i - set);

72 str_append(template, "\n");

73 }

74 if (mode == CTL_MODE_HEADER && is_templ == 1) {

75 is_templ = 0;

76 str_t templdef = STR_NULL;

77 str_append_len(&templdef, content + set, i - set);

78 str_append(&templdef, "\n");

79 str_repall(&templdef, "TEMPLDEF", "__TEMPLDEF_HEADER");

80 str_concat(template, templdef);

81 str_free(&templdef);

82 }

83 }

84 else {

85 const int STRING_LIMIT = 4095;

86 int str_len = i - set;

87 int rem_len = str_len;

88 int hex_len = 0;

89 int idx = 0;

90 while (rem_len > 0) {

91 if (rem_len > STRING_LIMIT) {

92 hex_len = STRING_LIMIT;

93 }

94 else {

95 hex_len = str_len - idx;

96 }

97 rem_len -= hex_len;

98 str_t hex = STR_NULL;

99 str_append_len(&hex, content + set + idx, hex_len);

100 str_repall(&hex, "%%", "%");

101 str_to_hex(&hex);

102 if (mode == CTL_MODE_MODULE && is_templ == 1) {

103 str_append(template, "CTL_WRITE(\"");

104 str_concat(template, hex);

105 str_append(template, "\")\n");

106 }

107 str_free(&hex);

108 idx += hex_len;

109 }

110 }

111 is_code = !is_code;

112 set = i + 1;

113 }

114 }

115 if (is_code) {

116 return CTL_ERR_UNCLOSED_CODE;

117 }

118 else {

119 const int STRING_LIMIT = 4095;

120 int str_len = len - set;

121 int rem_len = str_len;

122 int hex_len = 0;

123 int idx = 0;

124 while (rem_len > 0) {

125 if (rem_len > STRING_LIMIT) {

126 hex_len = STRING_LIMIT;

127 }

128 else {

129 hex_len = str_len - idx;

130 }

131 rem_len -= hex_len;

132 str_t hex = STR_NULL;

133 str_append_len(&hex, content + set + idx, hex_len);

134 str_repall(&hex, "%%", "%");

135 str_to_hex(&hex);

136 if (mode == CTL_MODE_MODULE && is_templ == 1) {

137 str_append(template, "CTL_WRITE(\"");

138 str_concat(template, hex);

139 str_append(template, "\")\n");

140 }

141 str_free(&hex);

142 idx += hex_len;

143 }

144 }

145 str_repall(template, "%%", "%");

146 return CTL_ERR_OK;

147}

148

149ctl_err_t ctl_file_read(char **content, const char *filename) {

150 FILE *fp = fopen(filename, "r");

151 if (fp == NULL) {

152 return CTL_ERR_NO_FILE;

153 }

154 fseek(fp, 0, SEEK_END);

155 int len = ftell(fp);

156 fseek(fp, 0, SEEK_SET);

157 *content = calloc(len + 1, sizeof(char));

158 fread(*content, sizeof(char), len, fp);

159 (*content)[len] = '\0';

160 fclose(fp);

161 return CTL_ERR_OK;

162}

163

164ctl_err_t ctl_file_read_binary(char **binary, size_t *len, const char *filename) {

165 FILE *fp = fopen(filename, "rb");

166 if (fp == NULL) {

167 return CTL_ERR_NO_FILE;

168 }

169 fseek(fp, 0, SEEK_END);

170 *len = ftell(fp);

171 fseek(fp, 0, SEEK_SET);

172 *binary = calloc(*len, sizeof(char));

173 fread(*binary, sizeof(char), *len, fp);

174 fclose(fp);

175 return CTL_ERR_OK;

176}

177

178ctl_err_t ctl_file_write(const char *content, const char *filename) {

179 FILE *fp = fopen(filename, "w");

180 if (fp == NULL) {

181 return CTL_ERR_NO_FILE;

182 }

183 size_t len = strlen(content);

184 if (fwrite(content, sizeof(char), len, fp) != len) {

185 return CTL_ERR_NO_WRITE;

186 }

187 fclose(fp);

188 return CTL_ERR_OK;

189}

190

191int main(int argc, char **argv) {

192 ctl_err_t err;

193 opterr = 0;

194 ctl_mode_t mode;

195 char *path = NULL;

196 int opt;

197 while ((opt = getopt(argc, argv, "h:o:")) != -1) {

198 switch (opt) {

199 case 'h':

200 mode = CTL_MODE_HEADER;

201 path = optarg;

202 break;

203 case 'o':

204 mode = CTL_MODE_MODULE;

205 path = optarg;

206 break;

207 default:

208 err = CTL_ERR_NO_ARGS;

209 ctl_error_str(err);

210 return err;

211 }

212 }

213 if (path == NULL) {

214 err = CTL_ERR_NO_ARGS;

215 ctl_error_str(err);

216 return err;

217 }

218 char *content = NULL;

219 err = ctl_file_read(&content, path);

220 if (err != CTL_ERR_OK) {

221 ctl_error_str(err);

222 return err;

223 }

224 str_t template = STR_NULL;

225 err = ctl_render(mode, &template, content);

226 free(content);

227 if (err != CTL_ERR_OK) {

228 str_free(&template);

229 ctl_error_str(err);

230 return err;

231 }

232 if (mode == CTL_MODE_HEADER) {

233 fprintf(stdout, "%s", str_get(&template));

234 str_free(&template);

235 return CTL_ERR_OK;

236 }

237 if (mode == CTL_MODE_MODULE) {

238 err = ctl_file_write(str_get(&template), CTL_TMP_C_PATH);

239 str_free(&template);

240 char cmd[500];

241 snprintf(cmd, sizeof(cmd), "cc -shared -fPIC -o %s %s", CTL_TMP_SO_PATH, CTL_TMP_C_PATH);

242 int rc = system(cmd);

243 remove(CTL_TMP_C_PATH);

244 if (rc != 0) {

245 err = CTL_ERR_NO_COMPILE;

246 ctl_error_str(err);

247 return err;

248 }

249 char *binary = NULL;

250 size_t len = 0;

251 err = ctl_file_read_binary(&binary, &len, CTL_TMP_SO_PATH);

252 remove(CTL_TMP_SO_PATH);

253 if (err != CTL_ERR_OK) {

254 ctl_error_str(err);

255 return err;

256 }

257 fwrite(binary, sizeof(char), len, stdout);

258 free(binary);

259 return CTL_ERR_OK;

260 }

261}