diff options
Diffstat (limited to 'Cool')
| -rw-r--r-- | Cool/LICENSE | 39 | ||||
| -rw-r--r-- | Cool/README.md | 44 | ||||
| -rw-r--r-- | Cool/compile.py | 153 | ||||
| -rw-r--r-- | Cool/cool.h | 249 | ||||
| -rw-r--r-- | Cool/demos/cool.html | 56 | ||||
| -rwxr-xr-x | Cool/demos/doc_generator | bin | 0 -> 28016 bytes | |||
| -rw-r--r-- | Cool/demos/doc_generator.c | 80 | ||||
| -rw-r--r-- | Cool/demos/view.cool | 9 | ||||
| -rw-r--r-- | Cool/demos/view.cool.c | 10 |
9 files changed, 640 insertions, 0 deletions
diff --git a/Cool/LICENSE b/Cool/LICENSE new file mode 100644 index 0000000..1910a7a --- /dev/null +++ b/Cool/LICENSE @@ -0,0 +1,39 @@ +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2026 Vasco Alves +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ diff --git a/Cool/README.md b/Cool/README.md new file mode 100644 index 0000000..3c9f770 --- /dev/null +++ b/Cool/README.md @@ -0,0 +1,44 @@ +# Cool + +Build server-side components with C! Use the single-header library as a standalone HTML formatter +or use the transpiler to convert `.cool` files into `.c` files that you can include directly! + +## Example + +Write something like so: + +```code +COOL void Api(char *name, char *func, char *desc) { + <div class="api-card"> + <h3 class="api-name">{ name }</h3> + <code class="language-c">{ func } </code> + <div class="api-description"> + { desc } + </div> + </div> +} +``` + +Call `compiler.py` to get `view.cool.c` and include it into your code. + +```c +#include "views.cool.c" // include server side components directly + +int main() { + char func_name[256]; + char func_decl[256]; + char *comment_text = NULL; + /* ... */ + /* call you view directly! */ + if (feel_like_it) { + Api(func_name, func_decl, comment_text); + } + return 0; +} + +``` + +## Contributing + +This is one of the few open source projects where I'm very open to contribution. +Web is not my area of expertise. And this idea deserves fome fleshing out. diff --git a/Cool/compile.py b/Cool/compile.py new file mode 100644 index 0000000..9c19403 --- /dev/null +++ b/Cool/compile.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python3 +import sys +import re +import argparse + +TYPE_SPECIFIERS = { + 'int': '%d', + 'int32_t': '%d', + 'short': '%d', + 'long': '%ld', + 'unsigned': '%u', + 'unsigned int': '%u', + 'uint32_t': '%u', + 'size_t': '%zu', + 'float': '%f', + 'double': '%f', + 'char': '%c', + 'char*': '%s', + 'const char*': '%s', + 'char *': '%s', + 'const char *': '%s', +} + +def parse_parameters(args_str: str) -> dict: + param_map = {} + if not args_str or args_str == 'void': + return param_map + + params = args_str.split(',') + for param in params: + param = param.strip() + if not param: + continue + + match = re.match(r'^(.*?)\b([A-Za-z0-9_]+)$', param) + if match: + type_part = match.group(1).strip() + var_name = match.group(2).strip() + + type_clean = re.sub(r'\s*\*\s*', '*', type_part) + specifier = TYPE_SPECIFIERS.get(type_clean, '%d') + param_map[var_name] = (type_clean, specifier) + + return param_map + +def escape_c_string(text: str) -> str: + return (text.replace('\\', '\\\\') + .replace('"', '\\"') + .replace('\r', '') + .replace('\n', '\\n')) + +def transpile_cool(cool_code: str, filename: str = "<stdin>") -> str: + lines = cool_code.splitlines(keepends=True) + c_output = [] + + cool_func_re = re.compile(r'^\s*COOL\s+void\s+([A-Za-z0-9_]+)\s*\((.*?)\)\s*\{\s*$') + + in_cool_func = False + current_func = "" + raw_buffer = [] + local_scope = {} + + def flush_raw_buffer(): + nonlocal raw_buffer + if raw_buffer: + combined = "".join(raw_buffer) + if combined: + escaped = escape_c_string(combined) + c_output.append(f' cool_html_raw(COOL_SV("{escaped}"));\n') + raw_buffer = [] + + for line_num, line in enumerate(lines, start=1): + match = cool_func_re.match(line) + + if match and not in_cool_func: + in_cool_func = True + current_func, args = match.groups() + args_str = args.strip() if args.strip() else "void" + + local_scope = parse_parameters(args_str) + c_output.append(f"void {current_func}({args_str}) {{\n") + continue + + if in_cool_func: + if line.strip() == "}": + flush_raw_buffer() + c_output.append("}\n\n") + in_cool_func = False + current_func = "" + local_scope = {} + continue + + # Tokenize line into @Component(), { expression }, and plain HTML + tokens = re.split(r'(@[A-Za-z0-9_]+\s*\([^)]*\)|\{[^{}]+\})', line) + + for token in tokens: + if not token: + continue + + # @Component() + if token.startswith('@') and '(' in token: + flush_raw_buffer() + call_code = token[1:].strip() + c_output.append(f" {call_code};\n") + + # { expression } + elif token.startswith('{') and token.endswith('}'): + flush_raw_buffer() + expr = token[1:-1].strip() + + if expr in local_scope: + type_clean, specifier = local_scope[expr] + + if 'char*' in type_clean: + c_output.append(f" cool_html_txt({expr}, strlen({expr}));\n") + else: + c_output.append(f' cool_htmlf_raw("{specifier}", {expr});\n') + else: + available = ", ".join(f"'{p}'" for p in local_scope.keys()) if local_scope else "none" + sys.stderr.write( + f"\n[Transpiler Error] {filename}:{line_num}: " + f"Expression '{{{expr}}}' in function '{current_func}' does not match any parameter.\n" + f" -> Available parameter(s): {available}\n\n" + ) + sys.exit(1) + + # Raw HTML text + else: + raw_buffer.append(token) + else: + c_output.append(line) + + return "".join(c_output) + +def main(): + parser = argparse.ArgumentParser(description="Transpiles .cool template files to C source code.") + parser.add_argument("input", help="Input .cool file") + parser.add_argument("-o", "--output", help="Output .c file") + args = parser.parse_args() + + with open(args.input, "r", encoding="utf-8") as f: + cool_code = f.read() + + transpiled_c = transpile_cool(cool_code, filename=args.input) + + if args.output: + with open(args.output, "w", encoding="utf-8") as f: + f.write(transpiled_c) + else: + sys.stdout.write(transpiled_c) + +if __name__ == "__main__": + main() diff --git a/Cool/cool.h b/Cool/cool.h new file mode 100644 index 0000000..f26024b --- /dev/null +++ b/Cool/cool.h @@ -0,0 +1,249 @@ +/* =========================================================================== + * Cool - Server-side Components in C - Copyright (c) 2026 Vasco Alves + * + * _.-\ _.-\ + * __.-'' \ __.-'' \ + * -----------------------------------' + * \ X X / \ X X / + * \ X X / \ X X / + * \ X X / \ X X / + * \---------/ \---------/ + * + * "Hasta la vista, baby." + * + * --------------------------------------------------------------------------- + * + * PREFIX: COOL (macros) Cool_ (types) cool (function) + * + * USAGE: + * Can be used directly for very simple applications or through a transpiler + * that converts a separate "higher level" template language directly into + * C functions! + * + * --- view.cool --- + * COOL void GenDocs(char *name, char *func, char *desc) { + * <div class="api-card"> + * <h3 class="api-name">{ name }</h3> + * <code class="language-c">{ func } </code> + * <div class="api-description"> + * { desc } + * </div> + * </div> + * } + * + * --- main.c --- + * #include "view.cool.c" + * int main(int argc, char **argv) { + * + * if (argc < 2) { + * puts("Usage: doc_generator [FILE]"); + * return 1; + * } + * + * FILE *header_file = fopen(argv[1], "r"); + * + * char *line_buf = malloc(256); + * size_t len = 0; + * while (getline(&line_buf, &len, header_file) > 0) { + * char func_name[256]; + * char func_decl[256]; + * char *comment_text = NULL; + * + * if (parse_header_line(line_buf, func_name, func_decl, &comment_text)) { + * GenDocs(func_name, func_decl, comment_text); + * } + * } + * + * free(line_buf); + * + * return 0; + * } + * + * =========================================================================== */ + +#ifndef _COOL_H_ +#define _COOL_H_ + +#define COOL_MAJOR 0 // breaking API changes +#define COOL_MINOR 0 // non-breaking features +#define COOL_PATCH 0 // non-breaking patches and bug fixes + +/* CHANGE LOG + * 0.0.0 - @vasco - server-side HTML from C functions + */ + +#define COOLDEF static inline +#define COOL_OUTPUT stdout + +#include <stdarg.h> +#include <stdio.h> +#include <stddef.h> +#include <stdlib.h> +#include <assert.h> + +typedef struct { + char *cstr; // original cstring + size_t len; // len +} Cool_StrView; + +/* Macro to wrap string literal in a string view. Since we will be dealing with a lot of */ +#define COOL_SV(literal) ((Cool_StrView){ .cstr = (literal), .len = sizeof(literal) - 1 }) +COOLDEF void cool_sv_write(Cool_StrView sv); // Write string view to output. +COOLDEF void cool_html(Cool_StrView sv); // SAFELY write HTML to a buffer. Handles escaping malicious sequences. +COOLDEF void cool_html_raw(Cool_StrView sv); // Writes HTML to buffer without escaping sequences. Vulnerable to XSS. Use with caution. +COOLDEF void cool_html_raw_cstr(const char *str, size_t len); // Writes unsafe HTML using C strings. +COOLDEF void cool_html_txt(const char *str, size_t len); // Meant for inner text. Escapes '<', '>' and '&'. +COOLDEF void cool_htmlf(const char *fmt, ...); // SAFELY write formatted string to buffer. +COOLDEF void cool_htmlf_raw(const char *fmt, ...); // Writes formatting HTML string to buffer without escaping sequences. Vulnerable to XSS. Use with caution. + +#endif + +#define COOL_IMPLEMENTATION +#ifdef COOL_IMPLEMENTATION +#undef COOL_IMPLEMENTATION + +static const char* cool_url_escape_table[256] = { + "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", + "%08", "%09", "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", + "%10", "%11", "%12", "%13", "%14", "%15", "%16", "%17", + "%18", "%19", "%1a", "%1b", "%1c", "%1d", "%1e", "%1f", + "%20", NULL, "%22", "%23", NULL, "%25", "%26", "%27", + NULL, NULL, NULL, "%2b", NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "%3c", "%3d", "%3e", "%3f", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, "%5c", NULL, "%5e", NULL, + "%60", NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, "%7b", "%7c", "%7d", NULL, "%7f", + "%80", "%81", "%82", "%83", "%84", "%85", "%86", "%87", + "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f", + "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", + "%98", "%99", "%9a", "%9b", "%9c", "%9d", "%9e", "%9f", + "%a0", "%a1", "%a2", "%a3", "%a4", "%a5", "%a6", "%a7", + "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", "%ae", "%af", + "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", + "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", + "%c0", "%c1", "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", + "%c8", "%c9", "%ca", "%cb", "%cc", "%cd", "%ce", "%cf", + "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6", "%d7", + "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df", + "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7", + "%e8", "%e9", "%ea", "%eb", "%ec", "%ed", "%ee", "%ef", + "%f0", "%f1", "%f2", "%f3", "%f4", "%f5", "%f6", "%f7", + "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", "%fe", "%ff" +}; + +COOLDEF void +cool_sv_write(Cool_StrView sv) +{ + fwrite(sv.cstr, sizeof *sv.cstr, sv.len, COOL_OUTPUT); +} + +COOLDEF void +cool_html(Cool_StrView sv) +{ + assert(0 && "TODO"); +} + +COOLDEF void +cool_html_raw(Cool_StrView sv) +{ + fwrite(sv.cstr, sizeof *sv.cstr, sv.len, COOL_OUTPUT); +} + +COOLDEF void +cool_html_raw_cstr(const char *str, size_t len) +{ + fwrite(str, sizeof *str, len, COOL_OUTPUT); +} + +COOLDEF void +cool_html_txt(const char *str, size_t len) +{ + const char *s = str; + while (s && *s && len--) { + int c = *str; + if (c == '<' || c == '>' || c == '&') { + cool_html_raw_cstr(str, s - str); + switch (c) { + case '>': + cool_html_raw(COOL_SV(">")); + break; + case '<': + cool_html_raw(COOL_SV("<")); + break; + case '&': + cool_html_raw(COOL_SV("&")); + break; + } + str = s + 1; + } + s++; + } + + if (s != str) cool_html_raw_cstr(str, s - str); +} + +COOLDEF void +cool_htmlf(const char *fmt, ...) +{ + assert(0 && "TODO"); +} + +COOLDEF void +cool_htmlf_raw(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + vfprintf(COOL_OUTPUT, fmt, args); + va_end(args); +} + +#endif + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2026 Vasco Alves +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ + diff --git a/Cool/demos/cool.html b/Cool/demos/cool.html new file mode 100644 index 0000000..b75c841 --- /dev/null +++ b/Cool/demos/cool.html @@ -0,0 +1,56 @@ + <div class="api-card"> + <h3 class="api-name">cool_sv_write</h3> + <code class="language-c">COOLDEF void cool_sv_write(Cool_StrView sv) </code> + <div class="api-description"> + Write string view to output. + + </div> + </div> + <div class="api-card"> + <h3 class="api-name">cool_html</h3> + <code class="language-c">COOLDEF void cool_html(Cool_StrView sv) </code> + <div class="api-description"> + SAFELY write HTML to a buffer. Handles escaping malicious sequences. + + </div> + </div> + <div class="api-card"> + <h3 class="api-name">cool_html_raw</h3> + <code class="language-c">COOLDEF void cool_html_raw(Cool_StrView sv) </code> + <div class="api-description"> + Writes HTML to buffer without escaping sequences. Vulnerable to XSS. Use with caution. + + </div> + </div> + <div class="api-card"> + <h3 class="api-name">cool_html_raw_cstr</h3> + <code class="language-c">COOLDEF void cool_html_raw_cstr(const char *str, size_t len) </code> + <div class="api-description"> + Writes unsafe HTML using C strings. + + </div> + </div> + <div class="api-card"> + <h3 class="api-name">cool_html_txt</h3> + <code class="language-c">COOLDEF void cool_html_txt(const char *str, size_t len) </code> + <div class="api-description"> + Meant for inner text. Escapes '<', '>' and '&'. + + </div> + </div> + <div class="api-card"> + <h3 class="api-name">cool_htmlf</h3> + <code class="language-c">COOLDEF void cool_htmlf(const char *fmt, ...) </code> + <div class="api-description"> + SAFELY write formatted string to buffer. + + </div> + </div> + <div class="api-card"> + <h3 class="api-name">cool_htmlf_raw</h3> + <code class="language-c">COOLDEF void cool_htmlf_raw(const char *fmt, ...) </code> + <div class="api-description"> + Writes formatting HTML string to buffer without escaping sequences. Vulnerable to XSS. Use with caution. + + </div> + </div> diff --git a/Cool/demos/doc_generator b/Cool/demos/doc_generator Binary files differnew file mode 100755 index 0000000..a41a10c --- /dev/null +++ b/Cool/demos/doc_generator diff --git a/Cool/demos/doc_generator.c b/Cool/demos/doc_generator.c new file mode 100644 index 0000000..5074cf6 --- /dev/null +++ b/Cool/demos/doc_generator.c @@ -0,0 +1,80 @@ +/* + * This simple demo illustrates how I use this library to generate my documentation. + * Could be used either statically or live because it's as simple as executing doc_generator + * with the given header file and reading from stdout. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#define COOL_IMPLEMENTATION +#include "../cool.h" + +#include "view.cool.c" + +int parse_header_line(const char *line, char *func_name, char *func_decl, char **comment_out); + +int main(int argc, char **argv) { + + if (argc < 2) { + puts("Usage: doc_generator [FILE]"); + return 1; + } + + FILE *header_file = fopen(argv[1], "r"); + + char *line_buf = malloc(256); + size_t len = 0; + while (getline(&line_buf, &len, header_file) > 0) { + char func_name[256]; + char func_decl[256]; + char *comment_text = NULL; + + if (parse_header_line(line_buf, func_name, func_decl, &comment_text)) { + Api(func_name, func_decl, comment_text); + } + } + + free(line_buf); + + return 0; +} + +int parse_header_line(const char *line, char *func_name, char *func_decl, char **comment_out) { + char *comment_ptr = strstr(line, "//"); + if (!comment_ptr) return 0; + + *comment_out = comment_ptr + 2; + while (**comment_out == ' ' || **comment_out == '\t') { + (*comment_out)++; + } + + size_t decl_len = comment_ptr - line; + if (decl_len >= 256) decl_len = 255; + strncpy(func_decl, line, decl_len); + func_decl[decl_len] = '\0'; + + while (decl_len > 0 && (isspace((unsigned char)func_decl[decl_len - 1]) || func_decl[decl_len - 1] == ';')) { + func_decl[--decl_len] = '\0'; + } + + char *open_paren = strchr(func_decl, '('); + if (!open_paren) return 0; + + char *end_name = open_paren - 1; + while (end_name > func_decl && isspace((unsigned char)*end_name)) { + end_name--; + } + + char *start_name = end_name; + while (start_name > func_decl && (isalnum((unsigned char)start_name[-1]) || start_name[-1] == '_')) { + start_name--; + } + + size_t name_len = (end_name - start_name) + 1; + if (name_len >= 256) name_len = 255; + strncpy(func_name, start_name, name_len); + func_name[name_len] = '\0'; + + return 1; +} diff --git a/Cool/demos/view.cool b/Cool/demos/view.cool new file mode 100644 index 0000000..238cfaf --- /dev/null +++ b/Cool/demos/view.cool @@ -0,0 +1,9 @@ +COOL void Api(char *name, char *func, char *desc) { + <div class="api-card"> + <h3 class="api-name">{ name }</h3> + <code class="language-c">{ func } </code> + <div class="api-description"> + { desc } + </div> + </div> +} diff --git a/Cool/demos/view.cool.c b/Cool/demos/view.cool.c new file mode 100644 index 0000000..458072e --- /dev/null +++ b/Cool/demos/view.cool.c @@ -0,0 +1,10 @@ +void Api(char *name, char *func, char *desc) { + cool_html_raw(COOL_SV(" <div class=\"api-card\">\n <h3 class=\"api-name\">")); + cool_html_txt(name, strlen(name)); + cool_html_raw(COOL_SV("</h3>\n <code class=\"language-c\">")); + cool_html_txt(func, strlen(func)); + cool_html_raw(COOL_SV(" </code>\n <div class=\"api-description\">\n ")); + cool_html_txt(desc, strlen(desc)); + cool_html_raw(COOL_SV("\n </div>\n </div>\n")); +} + |
