#include #include #include "markdown.h" static char * md_strdup(const char *s) { char *out; size_t len; len = strlen(s); out = malloc(len + 1); if (out == NULL) return NULL; memcpy(out, s, len + 1); return out; } static void markdown_inline(FILE *fp, const char *line, void (*esc_len)(FILE *, const char *, size_t)) { const char *code_end, *link_close, *link_end, *p, *url_start; size_t n; p = line; while (*p != '\0') { if (*p == '`') { code_end = strchr(p + 1, '`'); if (code_end != NULL) { fputs("", fp); esc_len(fp, p + 1, (size_t)(code_end - (p + 1))); fputs("", fp); p = code_end + 1; continue; } } if (*p == '[') { link_close = strchr(p + 1, ']'); if (link_close != NULL && *(link_close + 1) == '(') { url_start = link_close + 2; link_end = strchr(url_start, ')'); if (link_end != NULL) { fputs("", fp); esc_len(fp, p + 1, (size_t)(link_close - (p + 1))); fputs("", fp); p = link_end + 1; continue; } } } n = strcspn(p, "`["); if (n == 0) { esc_len(fp, p, 1); p++; } else { esc_len(fp, p, n); p += n; } } } void markdown_render(FILE *fp, const char *md, void (*esc_len)(FILE *, const char *, size_t)) { char *line; char *next; char *save; int in_code, in_list, in_p, level; save = md_strdup(md); if (save == NULL) return; in_code = 0; in_list = 0; in_p = 0; line = save; while (line != NULL) { next = strchr(line, '\n'); if (next != NULL) { *next = '\0'; next++; } while (*line == ' ' || *line == '\t') line++; if (strncmp(line, "```", 3) == 0) { if (in_p) { fputs("

\n", fp); in_p = 0; } if (in_list) { fputs("\n", fp); in_list = 0; } if (!in_code) fputs("
", fp);
			else
				fputs("
\n", fp); in_code = !in_code; line = next; continue; } if (in_code) { esc_len(fp, line, strlen(line)); fputc('\n', fp); line = next; continue; } if (*line == '\0') { if (in_p) { fputs("

\n", fp); in_p = 0; } if (in_list) { fputs("\n", fp); in_list = 0; } line = next; continue; } if (*line == '#') { if (in_p) { fputs("

\n", fp); in_p = 0; } if (in_list) { fputs("\n", fp); in_list = 0; } level = 0; while (*line == '#' && level < 6) { level++; line++; } while (*line == ' ') line++; fprintf(fp, "", level == 0 ? 1 : level); markdown_inline(fp, line, esc_len); fprintf(fp, "\n", level == 0 ? 1 : level); line = next; continue; } if ((line[0] == '-' || line[0] == '*') && line[1] == ' ') { if (in_p) { fputs("

\n", fp); in_p = 0; } if (!in_list) { fputs("\n", fp); free(save); }