c-staticsite-generator/markdown_to_html.c

194 lines
6.5 KiB
C
Raw Permalink Normal View History

2024-08-29 14:36:45 -04:00
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <stdlib.h>
#define BUFFER_SIZE 1024
void convert_markdown_to_html(const char *markdown, FILE *output) {
const char *start = markdown;
const char *end;
bool in_code_block = false;
bool header_row_started = false;
while (*start) {
// Find the end of the current line
end = strchr(start, '\n');
if (end == NULL) {
end = start + strlen(start);
}
size_t length = end - start;
// Ensure we do not exceed the buffer size
if (length >= BUFFER_SIZE) {
length = BUFFER_SIZE - 1;
}
char line[BUFFER_SIZE];
strncpy(line, start, length);
line[length] = '\0';
// Check for code block delimiters
if (strcmp(line, "```") == 0) {
in_code_block = !in_code_block;
if (in_code_block) {
fprintf(output, "<pre><code>\n");
} else {
fprintf(output, "</code></pre>\n");
}
} else if (in_code_block) {
// If inside a code block, output the line as-is
fprintf(output, "%s\n", line);
} else if (line[0] == '|' && strstr(line, "-") != NULL) {
// Check if it's a header row
if (!header_row_started) {
fprintf(output, "<table>\n");
header_row_started = true;
}
fprintf(output, "<tr>\n");
char *token = strtok(line, "|");
while (token != NULL) {
if (strlen(token) > 0) {
fprintf(output, "<th style=\"border: 1px solid black;\">%s</th>\n", token);
}
token = strtok(NULL, "|");
}
fprintf(output, "</tr>\n");
} else if (header_row_started && (line[0] == '|' || line[0] == '-')) {
// Regular row
fprintf(output, "<tr>\n");
char *token = strtok(line, "|");
while (token != NULL) {
if (strlen(token) > 0) {
fprintf(output, "<td style=\"border: 1px solid black;\">%s</td>\n", token);
}
token = strtok(NULL, "|");
}
fprintf(output, "</tr>\n");
} else {
// If we were in a table and now we are not, close the table
if (header_row_started) {
fprintf(output, "</table>\n");
header_row_started = false;
}
// Handle headers
if (line[0] == '#') {
int level = 0;
while (line[level] == '#') {
level++;
}
fprintf(output, "<h%d>%s</h%d>\n", level, line + level + 1, level);
}
// Handle bold text
else if (strstr(line, "**") != NULL) {
char *bold_start = strstr(line, "**");
char *bold_end = strstr(bold_start + 2, "**");
if (bold_end != NULL) {
*bold_end = '\0';
fprintf(output, "%.*s<b>%s</b>%s\n", (int)(bold_start - line), line, bold_start + 2, bold_end + 2);
}
}
// Handle italic text
else if (strstr(line, "*") != NULL) {
char *italic_start = strstr(line, "*");
char *italic_end = strstr(italic_start + 1, "*");
if (italic_end != NULL) {
*italic_end = '\0';
fprintf(output, "%.*s<i>%s</i>%s\n", (int)(italic_start - line), line, italic_start + 1, italic_end + 1);
}
}
// Handle list items
else if (line[0] == '-') {
fprintf(output, "<li>%s</li>\n", line + 2);
}
// Handle links
else if (strstr(line, "[") != NULL && strstr(line, "](") != NULL) {
char *link_start = strstr(line, "[");
char *link_end = strstr(link_start, "]");
char *url_start = strstr(link_end, "(");
char *url_end = strstr(url_start, ")");
if (url_end != NULL) {
*link_end = '\0';
*url_end = '\0';
fprintf(output, "%.*s<a href=\"%s\">%s</a>%s\n", (int)(link_start - line), line, url_start + 1, link_start + 1, url_end + 1);
}
}
// Handle inline code to monospace
else if (strstr(line, "`") != NULL) {
char *monospace_start = strstr(line, "`");
char *monospace_end = strstr(monospace_start + 1, "`");
if (monospace_end != NULL) {
*monospace_end = '\0';
fprintf(output, "%.*s<code>%s</code>%s\n", (int)(monospace_start - line), line, monospace_start + 1, monospace_end + 1);
}
}
// Default to paragraph
else {
fprintf(output, "<p>%s</p>\n", line);
}
}
start = (*end) ? end + 1 : end;
}
// Close any open table at the end
if (header_row_started) {
fprintf(output, "</table>\n");
}
}
/**
* Generates a static site from a Markdown file.
*
* @param input_file The Markdown file to read from.
* @param output_file The HTML file to write to.
*/
void generate_static_site(const char *input_file, const char *output_file) {
FILE *md_file = fopen(input_file, "r");
if (!md_file) {
perror("Failed to open markdown file");
return;
}
FILE *html_file = fopen(output_file, "w");
if (!html_file) {
perror("Failed to create HTML file");
fclose(md_file);
return;
}
// Write the basic HTML structure with CSS
fprintf(html_file,
"<!DOCTYPE html>\n"
"<html>\n"
"<head>\n"
"<title>Static Site</title>\n"
"<link rel=\"stylesheet\" type=\"text/css\" href=\"styles.css\">\n"
"</head>\n"
"<body>\n"
"<div class=\"container\">\n");
// Read from markdown file and convert to HTML
char buffer[BUFFER_SIZE];
while (fgets(buffer, sizeof(buffer), md_file)) {
convert_markdown_to_html(buffer, html_file);
}
// End container
fprintf(html_file, "</div>\n</body>\n</html>\n");
fclose(md_file);
fclose(html_file);
}
int main(int argc, char *argv[]) {
if (argc != 3) {
fprintf(stderr, "Usage: %s <input.md> <output.html>\n", argv[0]);
return EXIT_FAILURE;
}
generate_static_site(argv[1], argv[2]);
return EXIT_SUCCESS;
}