87 lines
3.0 KiB
Python
87 lines
3.0 KiB
Python
# htmlcc - Statically compiled HTML templates for C
|
|
# Copyright (C) 2025 Lee Yingtong Li
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
from . import Emitter, register_emitter
|
|
|
|
class StdoutEmitter(Emitter):
|
|
"""Emitter which prints templates to stdout (useful for testing/demonstration)"""
|
|
|
|
def emit_preamble(self) -> None:
|
|
self.emit(r'''#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
void output_variable_encoded(char *variable, bool encode_quotes) {
|
|
// First compute size of buffer required
|
|
size_t extra_chars = 0;
|
|
char *ptr = variable;
|
|
for (; *ptr != '\0'; ptr++) {
|
|
if (*ptr == '&') { extra_chars += 4; }
|
|
if (*ptr == '<') { extra_chars += 3; }
|
|
if (*ptr == '"' && encode_quotes) { extra_chars += 5; }
|
|
if (*ptr == '\'' && encode_quotes) { extra_chars += 4; }
|
|
}
|
|
|
|
size_t len = ptr - variable;
|
|
char *buf = malloc(len + extra_chars + 1);
|
|
|
|
// Replace characters
|
|
char *c_inp = variable;
|
|
char *c_out = buf;
|
|
for (; *c_inp != '\0'; c_inp++) {
|
|
if (*c_inp == '&') {
|
|
*c_out++ = '&'; *c_out++ = 'a'; *c_out++ = 'm'; *c_out++ = 'p'; *c_out++ = ';';
|
|
} else if (*c_inp == '<') {
|
|
*c_out++ = '&'; *c_out++ = 'l'; *c_out++ = 't'; *c_out++ = ';';
|
|
} else if (*c_inp == '"' && encode_quotes) {
|
|
*c_out++ = '&'; *c_out++ = 'q'; *c_out++ = 'u'; *c_out++ = 'o'; *c_out++ = 't'; *c_out++ = ';';
|
|
} else if (*c_inp == '\'' && encode_quotes) {
|
|
*c_out++ = '&'; *c_out++ = '#'; *c_out++ = '3'; *c_out++ = '9'; *c_out++ = ';';
|
|
} else {
|
|
*c_out++ = *c_inp;
|
|
}
|
|
}
|
|
*c_out = '\0';
|
|
|
|
printf("%s", buf);
|
|
free(buf);
|
|
}
|
|
|
|
void output_variable_as_attr(char *variable) {
|
|
output_variable_encoded(variable, true);
|
|
}
|
|
|
|
void output_variable_as_text(char *variable) {
|
|
output_variable_encoded(variable, false);
|
|
}''')
|
|
|
|
def output_literal_string(self, literal_string: str) -> None:
|
|
self.emit(f'printf("%s", {self.escape_cstr(literal_string)});')
|
|
|
|
def output_variable_as_attr(self, variable: str) -> None:
|
|
self.emit(f'output_variable_as_attr({variable});')
|
|
|
|
def output_variable_as_text(self, variable: str) -> None:
|
|
self.emit(f'output_variable_as_text({variable});')
|
|
|
|
def output_variable_formatted(self, format_string: str, variable: str) -> None:
|
|
self.emit(f'printf({self.escape_cstr(format_string)}, {variable});')
|
|
|
|
def output_variable_urlencoded(self, variable: str) -> None:
|
|
raise NotImplementedError('urlencode filter is not implemented for the stdout emitter')
|
|
|
|
register_emitter('stdout', StdoutEmitter)
|