Mercurial
comparison markdown_converter/markdown_to_html.c @ 184:8c74204fd362
[MD to HTML] Updated so it can be used through readme to html
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Fri, 23 Jan 2026 22:20:35 -0800 |
| parents | 1c0878eb17de |
| children | a2725419f988 |
comparison
equal
deleted
inserted
replaced
| 183:a8976a008a9d | 184:8c74204fd362 |
|---|---|
| 1 #include <string.h> | 1 #include <string.h> |
| 2 #include <stdlib.h> | 2 #include <stdlib.h> |
| 3 #include <stdio.h> | 3 #include <stdio.h> |
| 4 #include <ctype.h> | 4 #include <ctype.h> |
| 5 #include "markdown_converter/markdown_to_html.h" | 5 #include "markdown_converter/markdown_to_html.h" |
| 6 | |
| 7 // JavaScript needs this to free the memory later | |
| 8 MDAPI void *wasm_alloc(size_t size) { | |
| 9 return malloc(size); | |
| 10 } | |
| 11 | |
| 12 MDAPI void wasm_free(void* ptr) { | |
| 13 free(ptr); | |
| 14 } | |
| 6 | 15 |
| 7 #define INITIAL_BUFFER_SIZE 1024 * 1024 // 1MB | 16 #define INITIAL_BUFFER_SIZE 1024 * 1024 // 1MB |
| 8 | 17 |
| 9 // String buffer for building HTML output | 18 // String buffer for building HTML output |
| 10 typedef struct { | 19 typedef struct { |
| 128 // Check if line is unordered list item | 137 // Check if line is unordered list item |
| 129 static int is_unordered_list(const char *line) | 138 static int is_unordered_list(const char *line) |
| 130 { | 139 { |
| 131 line = skip_whitespace(line); | 140 line = skip_whitespace(line); |
| 132 return (*line == '-' || *line == '*' || *line == '+') && line[1] == ' '; | 141 return (*line == '-' || *line == '*' || *line == '+') && line[1] == ' '; |
| 142 } | |
| 143 | |
| 144 // Check if line starts with an HTML tag | |
| 145 static int is_html_block_start(const char *line) | |
| 146 { | |
| 147 line = skip_whitespace(line); | |
| 148 if (*line != '<') return 0; | |
| 149 line++; | |
| 150 | |
| 151 // Check for closing tag or comment | |
| 152 if (*line == '/' || *line == '!') return 1; | |
| 153 | |
| 154 // Check for valid tag name (letter followed by alphanumeric) | |
| 155 if (!isalpha((unsigned char)*line)) return 0; | |
| 156 | |
| 157 return 1; | |
| 158 } | |
| 159 | |
| 160 // Check if line starts with a specific HTML tag (e.g., "script", "style") | |
| 161 static int is_html_tag(const char *line, const char *tag) | |
| 162 { | |
| 163 line = skip_whitespace(line); | |
| 164 if (*line != '<') return 0; | |
| 165 line++; | |
| 166 | |
| 167 // Skip optional / | |
| 168 int is_closing = 0; | |
| 169 if (*line == '/') { | |
| 170 is_closing = 1; | |
| 171 line++; | |
| 172 } | |
| 173 | |
| 174 size_t tag_len = strlen(tag); | |
| 175 if (strncasecmp(line, tag, tag_len) != 0) return 0; | |
| 176 | |
| 177 char next = line[tag_len]; | |
| 178 // Tag must be followed by space, >, or end for closing tags | |
| 179 return next == '>' || next == ' ' || next == '\t' || next == '\n' || next == '\0'; | |
| 133 } | 180 } |
| 134 | 181 |
| 135 // Check if line is ordered list item | 182 // Check if line is ordered list item |
| 136 static int is_ordered_list(const char *line) | 183 static int is_ordered_list(const char *line) |
| 137 { | 184 { |
| 483 | 530 |
| 484 buffer_append(buf, "</ol>"); | 531 buffer_append(buf, "</ol>"); |
| 485 continue; | 532 continue; |
| 486 } | 533 } |
| 487 | 534 |
| 535 // HTML block - pass through unchanged | |
| 536 if (is_html_block_start(line)) { | |
| 537 // Check if it's a script or style tag that needs special handling | |
| 538 int is_script = is_html_tag(line, "script"); | |
| 539 int is_style = is_html_tag(line, "style"); | |
| 540 | |
| 541 if (is_script || is_style) { | |
| 542 const char *end_tag = is_script ? "</script>" : "</style>"; | |
| 543 | |
| 544 // Output the opening line | |
| 545 buffer_append(buf, line); | |
| 546 buffer_append_char(buf, '\n'); | |
| 547 | |
| 548 free(line); | |
| 549 if (*ptr == '\n') ptr++; | |
| 550 | |
| 551 // Collect content until closing tag | |
| 552 while (*ptr) { | |
| 553 line_start = ptr; | |
| 554 while (*ptr && *ptr != '\n') ptr++; | |
| 555 line_len = ptr - line_start; | |
| 556 | |
| 557 line = (char *)malloc(line_len + 1); | |
| 558 if (!line) break; | |
| 559 memcpy(line, line_start, line_len); | |
| 560 line[line_len] = '\0'; | |
| 561 | |
| 562 buffer_append(buf, line); | |
| 563 buffer_append_char(buf, '\n'); | |
| 564 | |
| 565 int found_end = (strstr(line, end_tag) != NULL); | |
| 566 free(line); | |
| 567 if (*ptr == '\n') ptr++; | |
| 568 | |
| 569 if (found_end) break; | |
| 570 } | |
| 571 continue; | |
| 572 } | |
| 573 | |
| 574 // Regular HTML tag - just pass through the line | |
| 575 buffer_append(buf, line); | |
| 576 buffer_append_char(buf, '\n'); | |
| 577 free(line); | |
| 578 if (*ptr == '\n') ptr++; | |
| 579 continue; | |
| 580 } | |
| 581 | |
| 488 // Regular paragraph | 582 // Regular paragraph |
| 489 buffer_append(buf, "<p>"); | 583 buffer_append(buf, "<p>"); |
| 490 | 584 |
| 491 while (1) { | 585 while (1) { |
| 492 const char *content = skip_whitespace(line); | 586 const char *content = skip_whitespace(line); |
| 510 count_heading_level(line) > 0 || | 604 count_heading_level(line) > 0 || |
| 511 starts_with(line, "```") || | 605 starts_with(line, "```") || |
| 512 starts_with(line, ">") || | 606 starts_with(line, ">") || |
| 513 is_horizontal_rule(line) || | 607 is_horizontal_rule(line) || |
| 514 is_unordered_list(line) || | 608 is_unordered_list(line) || |
| 515 is_ordered_list(line)) { | 609 is_ordered_list(line) || |
| 610 is_html_block_start(line)) { | |
| 516 ptr = line_start; | 611 ptr = line_start; |
| 517 free(line); | 612 free(line); |
| 518 break; | 613 break; |
| 519 } | 614 } |
| 520 | 615 |