diff mrjunejune/create_html_from_md.c @ 169:295ac2e5ec00

[MrJuneJune] Created separate target for generating html from md.
author MrJuneJune <me@mrjunejune.com>
date Mon, 19 Jan 2026 17:33:18 -0800
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mrjunejune/create_html_from_md.c	Mon Jan 19 17:33:18 2026 -0800
@@ -0,0 +1,147 @@
+#include "markdown_converter/markdown_to_html.h"
+#include "dowa/dowa.h"
+#include <fcntl.h>
+
+#define BLOG_PATH "/home/june/zenbu/mrjunejune/src/blog/"
+#define BLOG_HTML "<!DOCTYPE html>" \
+"<html lang=\"en\">" \
+"<head>" \
+"    <meta charset=\"UTF-8\">" \
+"    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">" \
+"    <meta name=\"description\" content=\"%s\">" \
+"    <title>%s - June's Blog</title>" \
+"    {{/parts/base_head.html}}" \
+"    <link rel=\"stylesheet\" href=\"/public/highlight/a11y-dark.min.css\"  media=\"(prefers-color-scheme: dark)\">" \
+"    <link rel=\"stylesheet\" href=\"/public/highlight/a11y-light.min.css\" media=\"(prefers-color-scheme: light)\">" \
+"    <script src=\"/public/highlight/highlight.min.js\"></script>" \
+"</head>" \
+"<body>" \
+"  {{/parts/header.html}}" \
+"  <main>" \
+"%s" \
+"  </main>" \
+"  {{/parts/footer.html}}" \
+"  <script>hljs.highlightAll();</script>"\
+"</body>" 
+
+
+typedef struct {
+  char title[256];
+  char description[512];
+  char *content;       // markdown content after frontmatter
+} Blog_Metadata;
+
+// Parse frontmatter from markdown content
+// Expected format:
+// ---
+// title: My Title
+// description: My description
+// ---
+// markdown
+static Blog_Metadata Parse_Blog_Frontmatter(const char *md_content)
+{
+  Blog_Metadata meta = {0};
+  strcpy(meta.title, "Untitled");
+  strcpy(meta.description, "A blog post by June");
+  meta.content = (char *)md_content;
+
+  if (!md_content) return meta;
+
+  if (strncmp(md_content, "---", 3) != 0)
+    return meta;
+
+  const char *end_delim = strstr(md_content + 3, "\n---");
+  if (!end_delim)
+    return meta;
+
+  const char *cursor = md_content + 4; // skip "---\n"
+  while (cursor < end_delim)
+  {
+    // whitespaces
+    while (cursor < end_delim && (*cursor == ' ' || *cursor == '\t')) cursor++;
+
+    const char *line_end = cursor;
+    while (line_end < end_delim && *line_end != '\n') line_end++;
+
+    const char *colon = cursor;
+    while (colon < line_end && *colon != ':') colon++;
+
+    if (colon < line_end) {
+      size_t key_len = colon - cursor;
+      const char *value_start = colon + 1;
+      while (value_start < line_end && (*value_start == ' ' || *value_start == '\t')) value_start++;
+      size_t value_len = line_end - value_start;
+
+      if (key_len == 5 && strncmp(cursor, "title", 5) == 0)
+      {
+        size_t copy_len = value_len < sizeof(meta.title) - 1 ? value_len : sizeof(meta.title) - 1;
+        strncpy(meta.title, value_start, copy_len);
+        meta.title[copy_len] = '\0';
+      }
+      else if (key_len == 11 && strncmp(cursor, "description", 11) == 0)
+      {
+        size_t copy_len = value_len < sizeof(meta.description) - 1 ? value_len : sizeof(meta.description) - 1;
+        strncpy(meta.description, value_start, copy_len);
+        meta.description[copy_len] = '\0';
+      }
+    }
+
+    cursor = line_end + 1;
+  }
+
+  meta.content = (char *)(end_delim + 4); 
+  if (*meta.content == '\n') meta.content++;
+
+  return meta;
+}
+
+int main()
+{
+  Dowa_Arena *arena = Dowa_Arena_Create(1024 * 1024 * 5);
+  size_t buffer_sizes = 100 * 1024;
+
+  char *files[] = {
+    BLOG_PATH"thoughts-on-ide/index.md",
+    BLOG_PATH"multithread-in-js/index.md",
+    BLOG_PATH"thoughts-on-tdd/index.md",
+    BLOG_PATH"my-seobeo-journey/index.md",
+    BLOG_PATH"wasm-bunny/index.md",
+    BLOG_PATH"optimizing-data-structures/index.md",
+    BLOG_PATH"websocket-demystified/index.md",
+    BLOG_PATH"optimizing-grass-rendering/index.md",
+    BLOG_PATH"wsl2-ssh/index.md"
+  };
+
+  for (int i = 0; i < 9; i++)
+  {
+    char *md_file_path = files[i];
+    char *md_file = Dowa_Arena_Allocate(arena, buffer_sizes);
+
+    FILE *file = fopen(md_file_path, "ro");
+    fseek(file, 0, SEEK_END);
+    size_t file_length = ftell(file);
+    fseek(file, 0, SEEK_SET);
+    fread(md_file, 1, file_length, file);
+
+    Blog_Metadata meta = Parse_Blog_Frontmatter(md_file);
+    char *md = markdown_to_html(meta.content);
+    char *ssr_body = Dowa_Arena_Allocate(arena, buffer_sizes);
+    char *final_body = Dowa_Arena_Allocate(arena, buffer_sizes);
+    snprintf(ssr_body, buffer_sizes, BLOG_HTML, meta.description, meta.title, md);
+
+    int open_flags = O_RDWR | O_CREAT | O_EXCL;
+    size_t md_file_path_length = strlen(md_file_path);
+    md_file_path_length -= 3; // html
+    char *new_file_path = Dowa_Arena_Allocate(arena, 1024);
+    snprintf(new_file_path, 1024, "%.*s.html", (int)md_file_path_length, md_file_path);
+
+    FILE *new_file_fd = fopen(new_file_path, "w+");
+    if (!new_file_fd)
+      return;
+    printf("Saving to %s...\n", new_file_path);
+    fwrite(ssr_body, 1, buffer_sizes, new_file_fd);
+    fclose(new_file_fd);
+  }
+  return 0;
+}
+