|
// initially generated with https://aistudio.google.com/ |
|
|
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include <stdbool.h> |
|
#include <sys/stat.h> |
|
|
|
char const* filename = NULL; |
|
|
|
void print(char c) { |
|
if (c == '\"') printf("\\\""); |
|
else if (c == '\r') printf("\\r"); |
|
else if (c == '\n') printf("\\n"); |
|
else if (c == '\\') printf("\\\\"); |
|
else printf("%c", c); |
|
} |
|
|
|
void process(char const* text) { |
|
char const* cursor = text; |
|
char const* start_tag; |
|
|
|
while ((start_tag = strstr(cursor, "{{")) != NULL) { |
|
// Print text before tag |
|
if (start_tag != cursor) { |
|
printf(" sb_append(sb, \""); |
|
while (cursor < start_tag) { |
|
print(*cursor++); |
|
} |
|
printf("\");\n"); |
|
} |
|
|
|
// Find end of tag |
|
const char* end_tag = strstr(start_tag, "}}"); |
|
if (!end_tag) break; |
|
|
|
// Extract and print code |
|
printf(" "); |
|
const char* code_ptr = start_tag + 2; |
|
while (code_ptr < end_tag) { |
|
printf("%c", *code_ptr++); |
|
} |
|
|
|
cursor = end_tag + 2; |
|
} |
|
|
|
// Print remaining line content |
|
if (*cursor != '\0') { |
|
printf(" sb_append(sb, \""); |
|
while (*cursor) { |
|
print(*cursor++); |
|
} |
|
printf("\");\n"); |
|
} |
|
} |
|
|
|
int main(int argc, char** argv) { |
|
FILE* in; |
|
struct stat st; |
|
char *buffer; |
|
|
|
if (argc == 2) { |
|
filename = argv[1]; |
|
in = fopen(filename, "r"); |
|
if (!in) { |
|
perror("Can't open specified file"); |
|
return EXIT_FAILURE; |
|
} |
|
if (fstat(fileno(in), &st)) { |
|
perror("Can't get file stat"); |
|
return EXIT_FAILURE; |
|
} |
|
buffer = malloc(st.st_size + 1); |
|
if (fread(buffer, 1, st.st_size, in) == 0) { |
|
perror("Can't read specified file"); |
|
return EXIT_FAILURE; |
|
}; |
|
buffer[st.st_size] = '\0'; |
|
} |
|
|
|
printf("#include <string-builder.h>\n\n"); |
|
printf("struct Context;\n\n"); |
|
printf("void render_template(struct Context* ctx, struct StringBuilder* sb);\n\n"); |
|
printf("#ifdef IMPLEMENTATION\n\n"); |
|
printf("void render_template(struct Context* ctx, struct StringBuilder* sb) {\n"); |
|
|
|
process(buffer); |
|
|
|
printf("}\n\n"); |
|
printf("#endif // IMPLEMENTATION\n"); |
|
|
|
free(buffer); |
|
return EXIT_SUCCESS; |
|
} |
Or we could just give special meaning to the $ within the template. If it is inside the {{}}, it is the context and we replace it. It is a simple string replacement. No more magic. And no differentiating between underscores and dundersocres.
At this point it does seem as though, you introduced a problem because you did not like the ctx->, and now the whole implementation is being complicated based off a problem that should not even exist in the first place.