Template engine

FossilOrigin-Name: 80100717c5483087c985254616f3c784e79536ac4c161c77915a355e0fa04fc8
This commit is contained in:
nekobit 2022-05-27 03:37:47 +00:00
parent 0a580d0a32
commit cdbbfed221
3 changed files with 190 additions and 23 deletions

View file

@ -23,7 +23,7 @@ $(TARGET): filec template $(PAGES_CMP) $(OBJ) $(HEADERS)
$(CC) -o $(TARGET) $(OBJ) $(LDFLAGS)
template: src/template/main.o
$(CC) -o template $<
$(CC) $(LDFLATS) -o template $<
filec: src/file-to-c/main.o
$(CC) -o filec $<

View file

@ -20,6 +20,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// TODO error handling
enum args
{
@ -33,7 +36,14 @@ enum tmpl_type
TMPL_UINT,
TMPL_STR,
TMPL_STRLEN
}
};
struct tmpl_token
{
enum tmpl_type type;
char* token;
int used; // Internal use only
};
long filesize(FILE* file)
{
@ -44,27 +54,184 @@ long filesize(FILE* file)
return size;
}
void chexput(const char* buf, size_t size)
{
for (size_t i = 0; i < size; ++i)
{
printf("0X%hhX,", buf[i]);
}
}
char* strnws(char* str)
{
for (; isblank(*str); ++str);
return str;
}
char* strwsc(char* str, char stop)
{
for (; !isblank(*str) && *str != stop; ++str);
return str;
}
char* tkn_typetostr(enum tmpl_type tkn)
{
switch (tkn)
{
case TMPL_INT:
return "int";
case TMPL_STR:
case TMPL_STRLEN:
return "char*";
case TMPL_UINT:
return "unsigned";
}
return "";
}
enum tmpl_type tkn_type(char* str)
{
if (strcmp(str, "string") == 0 ||
strcmp(str, "str") == 0 ||
strcmp(str, "%s") == 0)
return TMPL_STR;
else if (strcmp(str, "stringlen") == 0 ||
strcmp(str, "strlen") == 0 ||
strcmp(str, "%.s") == 0)
return TMPL_STRLEN;
else if (strcmp(str, "int") == 0 ||
strcmp(str, "i") == 0 ||
strcmp(str, "%d") == 0)
return TMPL_INT;
else if (strcmp(str, "unsigned") == 0 ||
strcmp(str, "uint") == 0 ||
strcmp(str, "%u") == 0)
return TMPL_UINT;
// TODO Real error handling
return TMPL_INT;
}
char* parse_tmpl_token(char* buf, struct tmpl_token* tkn)
{
tkn->used = 0;
char* type_begin;
char* type_end;
char* tkn_begin;
char* tkn_end;
// skip {{
buf += 2;
type_begin = strnws(buf);
type_end = strwsc(type_begin, ':');
if (*type_end != ':') buf = strchr(buf, ':');
else buf = type_end;
*type_end = '\0';
tkn->type = tkn_type(type_begin);
++buf;
tkn_begin = strnws(buf);
tkn_end = strwsc(tkn_begin, '}');
if (*tkn_end == '}') buf = tkn_end + 2;
else buf = strstr(buf, "}}") + 2;
*tkn_end = '\0';
tkn->token = tkn_begin;
return buf;
}
void print_template(char* var, char* buf)
{
char* buf_prev = buf;
char* buf_curr = buf;
char** tokens;
// Store result
struct tmpl_token* tokens = NULL;
size_t tokens_len = 0;
printf("#ifndef __%s\n"
"#define __%s\n"
"static const char data_%s[] = {", var, var, var);
printf("#ifndef __%s\n", var);
printf("#define __%s\n", var);
printf("static const char data_%s[] = {", var);
while (1)
{
buf_curr = strstr(buf_curr, "{{");
if (!buf_curr) break;
// Create tokens array
tokens = realloc(tokens, sizeof(struct tmpl_token) * ++tokens_len);
if (!tokens)
{
perror("realloc");
break;
}
// Print up to this point
chexput(buf_prev, buf_curr - buf_prev);
buf_prev = buf_curr = parse_tmpl_token(buf_curr, tokens + (tokens_len-1));
// Print type
switch (tokens[tokens_len-1].type)
{
case TMPL_INT:
// I'm lazy so we'll use this
chexput("%d", 2);
break;
case TMPL_STR:
chexput("%s", 2);
break;
case TMPL_STRLEN:
chexput("%.s", 3);
break;
case TMPL_UINT:
chexput("%u", 2);
break;
}
}
/* for (size_t i = 0; i < size; ++i) */
/* { */
/* printf("0X%hhX,", buf[i]); */
/* } */
/* puts("0};\n#endif"); */
puts("#endif");
// Print remainder if any
chexput(buf_prev, strlen(buf_prev));
printf("};\n"
"struct %s {", var);
int should_print = 0;
// Print tokens
for (size_t i = 0; i < tokens_len; ++i)
{
should_print = 1;
// Check if used
for (size_t j = 0; j < tokens_len; ++j)
{
if (i != j &&
strcmp(tokens[i].token, tokens[j].token) == 0 &&
tokens[j].used)
should_print = 0;
}
if (should_print)
{
printf("%s %s;\n", tkn_typetostr(tokens[i].type), tokens[i].token);
if (tokens[i].type == TMPL_STRLEN)
printf("unsigned %s_len;\n", tokens[i].token);
tokens[i].used = 1;
}
}
// Generate function
printf("};\n"
"char* tmpl_gen_%s(struct %s* data, unsigned* size){\n"
"char* ret;\n"
"unsigned s = easprintf(&ret, data_%s, ", var, var, var);
for (size_t i = 0; i < tokens_len; ++i)
{
printf("data->%s%s", tokens[i].token, i < tokens_len-1 ? ", " : "");
}
fputs(");\n"
"if (size) *size = s;\n"
"return ret;\n}", stdout);
// Done!
puts("\n#endif");
// Cleanup
free(tokens);
}
int main(int argc, char** argv)

View file

@ -29,15 +29,15 @@
<tr>
<td id="leftbar" class="sidebar">
<ul>
<li><a class="sidebarbtn { %s : active_home" href="{{ %s : prefix}}/">{{ %s : home }}</a></li>
<li><a class="sidebarbtn { %s : active_local" href="{{ %s : prefix}}/local/">{{ %s : local}}</a></li>
<li><a class="sidebarbtn { %s : active_federated" href="{{ %s : prefix}}/federated/">{{ %s : federated }}</a></li>
<li><a class="sidebarbtn { %s : active_notifications" href="{{ %s : prefix}}/notifications">{{ %s : notifications }}</a></li>
<li><a class="sidebarbtn { %s : active_lists" href="{{ %s : prefix}}/lists">{{ %s : lists }}</a></li>
<li><a class="sidebarbtn { %s : active_favourites" href="{{ %s : prefix}}/favourites">{{ %s : favourites }}</a></li>
<li><a class="sidebarbtn { %s : active_bookmarks" href="{{ %s : prefix}}/bookmarks">{{ %s : bookmarks }}</a></li>
<li><a class="sidebarbtn { %s : active_direct" href="{{ %s : prefix}}/direct">{{ %s : direct }}</a></li>
<li><a class="sidebarbtn { %s : active_config" href="{{ %s : prefix}}/config">{{ %s : config }}</a></li>
<li><a class="sidebarbtn {{ %s : active_home }}" href="{{ %s : prefix}}/">{{ %s : home }}</a></li>
<li><a class="sidebarbtn {{ %s : active_local }}" href="{{ %s : prefix}}/local/">{{ %s : local}}</a></li>
<li><a class="sidebarbtn {{ %s : active_federated }}" href="{{ %s : prefix}}/federated/">{{ %s : federated }}</a></li>
<li><a class="sidebarbtn {{ %s : active_notifications }}" href="{{ %s : prefix}}/notifications">{{ %s : notifications }}</a></li>
<li><a class="sidebarbtn {{ %s : active_lists }}" href="{{ %s : prefix}}/lists">{{ %s : lists }}</a></li>
<li><a class="sidebarbtn {{ %s : active_favourites }}" href="{{ %s : prefix}}/favourites">{{ %s : favourites }}</a></li>
<li><a class="sidebarbtn {{ %s : active_bookmarks }}" href="{{ %s : prefix}}/bookmarks">{{ %s : bookmarks }}</a></li>
<li><a class="sidebarbtn {{ %s : active_direct }}" href="{{ %s : prefix}}/direct">{{ %s : direct }}</a></li>
<li><a class="sidebarbtn {{ %s : active_config }}" href="{{ %s : prefix}}/config">{{ %s : config }}</a></li>
</ul>
{{ %s : sidebar_leftbar }}
<div class="static-html" id="instance-panel">