md4c

C Markdown parser. Fast. SAX-like interface. Compliant to CommonMark specification.
git clone https://noulin.net/git/md4c.git
Log | Files | Refs | README | LICENSE

commit ba504fda7412a232242004ca56d266094222900a
parent 80984c98c8eae61b5905a2c7ddaf8e3cae53068a
Author: Martin Mitas <mity@morous.org>
Date:   Tue,  4 Oct 2016 02:27:43 +0200

Implement Setext headers.

Diffstat:
MREADME.md | 2+-
Mmd4c/md4c.c | 46++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 47 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md @@ -83,7 +83,7 @@ more or less forms our to do list. - **Leaf Blocks:** - [x] 4.1 Thematic breaks - [x] 4.2 ATX headings - - [ ] 4.3 Setext headings + - [x] 4.3 Setext headings - [ ] 4.4 Indented code blocks - [ ] 4.5 Fenced code blocks - [ ] 4.6 HTML blocks diff --git a/md4c/md4c.c b/md4c/md4c.c @@ -85,6 +85,8 @@ enum MD_LINETYPE_tag { MD_LINE_BLANK, MD_LINE_HR, MD_LINE_ATXHEADER, + MD_LINE_SETEXTHEADER, + MD_LINE_SETEXTUNDERLINE, MD_LINE_TEXT }; @@ -304,6 +306,29 @@ md_is_atxheader_line(MD_CTX* ctx, OFF beg, OFF* p_beg, OFF* p_end) return 0; } +static int +md_is_setext_underline(MD_CTX* ctx, OFF beg, OFF* p_end) +{ + OFF off = beg + 1; + + while(off < ctx->size && CH(off) == CH(beg)) + off++; + + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* Optionally, space(s) can follow. */ + while(off < ctx->size && CH(off) == _T(' ')) + off++; + + /* But nothing more is allowed on the line. */ + if(off < ctx->size && !ISNEWLINE(off)) + return -1; + + ctx->header_level = (CH(beg) == _T('=') ? 1 : 2); + return 0; +} + /* Analyze type of the line and find some its properties. This serves as a * main input for determining type and boundaries of a block. */ static void @@ -335,6 +360,14 @@ md_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end, const MD_LINE* pivot_line, MD_ } } + /* Check whether we are setext underline. */ + if(pivot_line->type == MD_LINE_TEXT && (CH(off) == _T('=') || CH(off) == _T('-'))) { + if(md_is_setext_underline(ctx, off, &off) == 0) { + line->type = MD_LINE_SETEXTUNDERLINE; + goto done; + } + } + /* Check whether we are thematic break line. */ if(ISANYOF(off, _T("-_*"))) { if(md_is_hr_line(ctx, off, &off) == 0) { @@ -403,6 +436,7 @@ md_process_block(MD_CTX* ctx, const MD_LINE* lines, int n_lines) break; case MD_LINE_ATXHEADER: + case MD_LINE_SETEXTHEADER: block_type = MD_BLOCK_H; det.header.level = ctx->header_level; break; @@ -410,6 +444,11 @@ md_process_block(MD_CTX* ctx, const MD_LINE* lines, int n_lines) case MD_LINE_TEXT: block_type = MD_BLOCK_P; break; + + case MD_LINE_SETEXTUNDERLINE: + default: + MD_UNREACHABLE(); + break; } MD_ENTER_BLOCK(block_type, (void*) &det); @@ -486,6 +525,13 @@ md_process_doc(MD_CTX *ctx) continue; } + /* MD_LINE_SETEXTUNDERLINE changes meaning of the previous block. */ + if(line->type == MD_LINE_SETEXTUNDERLINE) { + MD_ASSERT(n_lines > 0); + lines[0].type = MD_LINE_SETEXTHEADER; + line->type = MD_LINE_BLANK; + } + /* New block also starts if line type changes. */ if(line->type != pivot_line->type) { ret = md_process_block(ctx, lines, n_lines);