194 lines
6.5 KiB
C
194 lines
6.5 KiB
C
|
#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;
|
||
|
}
|