so://phie

ductape

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

blob: db2c6f9db3a83154fc47e1baa43d902aee2b0d9a (4252 bytes)[doc][blame][raw]

1#include <stdio.h>

2#include <stdlib.h>

3#include <string.h>

4

5#define LIB_STR_IMPL

6#include <libstr.h>

7

8typedef enum {

9 CTL_ERR_OK,

10 CTL_ERR_NO_ARGS,

11 CTL_ERR_NO_FILE,

12 CTL_ERR_UNCLOSED_CODE,

13} ctl_error_t;

14

15void ctl_error_str(ctl_error_t err) {

16 switch (err) {

17 case CTL_ERR_OK:

18 break;

19 case CTL_ERR_NO_ARGS:

20 printf("Usage: ctl <filename>\n");

21 break;

22 case CTL_ERR_NO_FILE:

23 printf("Error: No file found!\n");

24 break;

25 case CTL_ERR_UNCLOSED_CODE:

26 printf("Error: Unclosed code block!\n");

27 break;

28 }

29}

30

31char *str_replace_all_len(char *buffer, char *str, char *replacement, int len) {

32 char *ret = NULL;

33 int str_len = strlen(str);

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

35 char *ptr = &buffer[i];

36 if (strncmp(ptr, str, str_len) == 0) {

37 str_append(&ret, replacement);

38 i += str_len - 1;

39 }

40 else {

41 str_append_len(&ret, &buffer[i], 1);

42 }

43 }

44 return ret;

45}

46

47char *str_hex_len(char *str, int len) {

48 const int HEX = 4;

49 char *ret = calloc(HEX * len + 1, sizeof(char));

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

51 unsigned char hex = str[i] & 0xff;

52 snprintf(ret + HEX * i, HEX * len, "\\x%02x", hex);

53 }

54 ret[HEX * len] = '\0';

55 return ret;

56}

57

58ctl_error_t ctl_render(char **template, char *content) {

59 int len = strlen(content);

60 int set = 0;

61 int is_code = 0;

62 str_append(template, "{\n");

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

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

65 // ignore escaped %

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

67 i += 1;

68 continue;

69 }

70 if (is_code) {

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

72 str_append(template, "\n");

73 }

74 else {

75 const int STRING_LIMIT = 4095;

76 int str_len = i - set;

77 int rem_len = str_len;

78 int hex_len = 0;

79 int idx = 0;

80 while (rem_len > 0) {

81 if (rem_len > STRING_LIMIT) {

82 hex_len = STRING_LIMIT;

83 }

84 else {

85 hex_len = str_len - idx;

86 }

87 rem_len -= hex_len;

88 char *str = str_replace_all_len(content + set + idx, "%%", "%", hex_len);

89 char *hex = str_hex_len(str, strlen(str));

90 str_append(template, "CTL_OUT(ctl_out, \"");

91 str_append(template, hex);

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

93 free(str);

94 free(hex);

95 idx += hex_len;

96 }

97 }

98 is_code = !is_code;

99 set = i + 1;

100 }

101 }

102 if (is_code) {

103 return CTL_ERR_UNCLOSED_CODE;

104 }

105 else {

106 const int STRING_LIMIT = 4095;

107 int str_len = len - set;

108 int rem_len = str_len;

109 int hex_len = 0;

110 int idx = 0;

111 while (rem_len > 0) {

112 if (rem_len > STRING_LIMIT) {

113 hex_len = STRING_LIMIT;

114 }

115 else {

116 hex_len = str_len - idx;

117 }

118 rem_len -= hex_len;

119 char *str = str_replace_all_len(content + set + idx, "%%", "%", hex_len);

120 char *hex = str_hex_len(str, strlen(str));

121 str_append(template, "CTL_OUT(ctl_out, \"");

122 str_append(template, hex);

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

124 free(str);

125 free(hex);

126 idx += hex_len;

127 }

128 }

129 str_append(template, "}\n");

130 *template = str_replace_all(*template, "%%", "%");

131 return CTL_ERR_OK;

132}

133

134ctl_error_t ctl_file_read(char **content, const char *filename) {

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

136 if (fp == NULL) {

137 return CTL_ERR_NO_FILE;

138 }

139 fseek(fp, 0, SEEK_END);

140 int len = ftell(fp);

141 fseek(fp, 0, SEEK_SET);

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

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

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

145 fclose(fp);

146 return CTL_ERR_OK;

147}

148

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

150 ctl_error_t err;

151 if (argc < 2) {

152 err = CTL_ERR_NO_ARGS;

153 ctl_error_str(err);

154 return err;

155 }

156 char *filename = argv[1];

157 char *content = NULL;

158 err = ctl_file_read(&content, filename);

159 if (err != CTL_ERR_OK) {

160 ctl_error_str(err);

161 return err;

162 }

163 char *template = NULL;

164 err = ctl_render(&template, content);

165 if (err != CTL_ERR_OK) {

166 ctl_error_str(err);

167 free(content);

168 if (template != NULL) {

169 free(template);

170 }

171 return err;

172 }

173 printf("%s\n", template);

174 free(template);

175 free(content);

176 return CTL_ERR_OK;

177}