summaryrefslogtreecommitdiff
path: root/Cool
diff options
context:
space:
mode:
authorVasco <[email protected]>2026-08-24 17:47:30 +0100
committerVasco <[email protected]>2026-08-24 17:50:52 +0100
commitcc3429220b19df8c5ca6abf28a02cd38d08de32d (patch)
treedd6fe3911535cc75570e5fe34ff84c758028aa81 /Cool
parentad5248a3e1bafc1b7dec4c8af82d56ed324ef314 (diff)
Cool 0.0.0. Rend 1.0.4.
Diffstat (limited to 'Cool')
-rw-r--r--Cool/LICENSE39
-rw-r--r--Cool/README.md44
-rw-r--r--Cool/compile.py153
-rw-r--r--Cool/cool.h249
-rw-r--r--Cool/demos/cool.html56
-rwxr-xr-xCool/demos/doc_generatorbin0 -> 28016 bytes
-rw-r--r--Cool/demos/doc_generator.c80
-rw-r--r--Cool/demos/view.cool9
-rw-r--r--Cool/demos/view.cool.c10
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("&gt;"));
+ break;
+ case '<':
+ cool_html_raw(COOL_SV("&lt;"));
+ break;
+ case '&':
+ cool_html_raw(COOL_SV("&amp;"));
+ 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
new file mode 100755
index 0000000..a41a10c
--- /dev/null
+++ b/Cool/demos/doc_generator
Binary files differ
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"));
+}
+