/* parse_block • parsing of one block, returning next char to parse */ static void parse_block(struct buf *ob, struct render *rndr, char *data, size_t size) { size_t beg, end, i; char *txt_data; beg = 0; if (rndr->work.size > rndr->max_nesting) return; while (beg < size) { txt_data = data + beg; end = size - beg; if (data[beg] == '#') beg += parse_atxheader(ob, rndr, txt_data, end); else if (data[beg] == '<' && rndr->make.blockhtml && (i = parse_htmlblock(ob, rndr, txt_data, end, 1)) != 0) beg += i; else if ((i = is_empty(txt_data, end)) != 0) beg += i; else if (is_hrule(txt_data, end)) { if (rndr->make.hrule) rndr->make.hrule(ob, rndr->make.opaque); while (beg < size && data[beg] != '\n') beg++; beg++; } else if ((rndr->ext_flags & MKDEXT_FENCED_CODE) != 0 && (i = parse_fencedcode(ob, rndr, txt_data, end)) != 0) beg += i; else if ((rndr->ext_flags & MKDEXT_TABLES) != 0 && (i = parse_table(ob, rndr, txt_data, end)) != 0) beg += i; else if (prefix_quote(txt_data, end)) beg += parse_blockquote(ob, rndr, txt_data, end); else if (prefix_code(txt_data, end)) beg += parse_blockcode(ob, rndr, txt_data, end); else if (prefix_uli(txt_data, end)) beg += parse_list(ob, rndr, txt_data, end, 0); else if (prefix_oli(txt_data, end)) beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED); else beg += parse_paragraph(ob, rndr, txt_data, end); } }
/* parse_blockquote • hanldes parsing of a regular paragraph */ static size_t parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size) { size_t i = 0, end = 0; int level = 0; struct buf work = { data, 0, 0, 0, 0 }; /* volatile working buffer */ while (i < size) { for (end = i + 1; end < size && data[end - 1] != '\n'; end += 1); if (is_empty(data + i, size - i) || (level = is_headerline(data + i, size - i)) != 0) break; if ((i && data[i] == '#') || is_hrule(data + i, size - i)) { end = i; break; } i = end; } work.size = i; while (work.size && data[work.size - 1] == '\n') work.size -= 1; if (!level) { struct buf *tmp = new_work_buffer(rndr); parse_inline(tmp, rndr, work.data, work.size); if (rndr->make.paragraph) rndr->make.paragraph(ob, tmp, rndr->make.opaque); release_work_buffer(rndr, tmp); } else { if (work.size) { size_t beg; i = work.size; work.size -= 1; while (work.size && data[work.size] != '\n') work.size -= 1; beg = work.size + 1; while (work.size && data[work.size - 1] == '\n') work.size -= 1; if (work.size) { struct buf *tmp = new_work_buffer(rndr); parse_inline(tmp, rndr, work.data, work.size); if (rndr->make.paragraph) rndr->make.paragraph(ob, tmp, rndr->make.opaque); release_work_buffer(rndr, tmp); work.data += beg; work.size = i - beg; } else work.size = i; } if (rndr->make.header) { struct buf *span = new_work_buffer(rndr); parse_inline(span, rndr, work.data, work.size); rndr->make.header(ob, span, level,rndr->make.opaque); release_work_buffer(rndr, span); } } return end; }
/* parse_block • parsing of one block, returning next char to parse */ static void parse_block(struct buf *ob, struct render *rndr, char *data, size_t size) { size_t beg, end, i; char *txt_data; int has_table = (rndr->make.table && rndr->make.table_row && rndr->make.table_cell); if (rndr->work.size > rndr->make.max_work_stack) { if (size) bufput(ob, data, size); return; } beg = 0; while (beg < size) { txt_data = data + beg; end = size - beg; if (data[beg] == '#') beg += parse_atxheader(ob, rndr, txt_data, end); else if (data[beg] == '<' && rndr->make.blockhtml && (i = parse_htmlblock(ob, rndr, txt_data, end)) != 0) beg += i; else if ((i = is_empty(txt_data, end)) != 0) beg += i; else if (is_hrule(txt_data, end)) { if (rndr->make.hrule) rndr->make.hrule(ob, rndr->make.opaque); while (beg < size && data[beg] != '\n') beg += 1; beg += 1; } else if (prefix_quote(txt_data, end)) beg += parse_blockquote(ob, rndr, txt_data, end); else if (prefix_code(txt_data, end)) beg += parse_blockcode(ob, rndr, txt_data, end); else if (prefix_uli(txt_data, end)) beg += parse_list(ob, rndr, txt_data, end, 0); else if (prefix_oli(txt_data, end)) beg += parse_list(ob, rndr, txt_data, end, MKD_LIST_ORDERED); else if (has_table && is_tableline(txt_data, end)) beg += parse_table(ob, rndr, txt_data, end); else beg += parse_paragraph(ob, rndr, txt_data, end); } }
/* assuming initial prefix is already removed */ static size_t parse_listitem(struct buf *ob, struct render *rndr, char *data, size_t size, int *flags) { struct buf *work = 0, *inter = 0; size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; int in_empty = 0, has_inside_empty = 0; /* keeping book of the first indentation prefix */ if (size > 1 && data[0] == ' ') { orgpre = 1; if (size > 2 && data[1] == ' ') { orgpre = 2; if (size > 3 && data[2] == ' ') { orgpre = 3; } } } beg = prefix_uli(data, size); if (!beg) beg = prefix_oli(data, size); if (!beg) return 0; /* skipping to the beginning of the following line */ end = beg; while (end < size && data[end - 1] != '\n') end += 1; /* getting working buffers */ work = new_work_buffer(rndr); inter = new_work_buffer(rndr); /* putting the first line into the working buffer */ bufput(work, data + beg, end - beg); beg = end; /* process the following lines */ while (beg < size) { end += 1; while (end < size && data[end - 1] != '\n') end += 1; /* process an empty line */ if (is_empty(data + beg, end - beg)) { in_empty = 1; beg = end; continue; } /* calculating the indentation */ i = 0; if (end - beg > 1 && data[beg] == ' ') { i = 1; if (end - beg > 2 && data[beg + 1] == ' ') { i = 2; if (end - beg > 3 && data[beg + 2] == ' ') { i = 3; if (end - beg > 3 && data[beg + 3] == ' ') { i = 4; } } } } pre = i; if (data[beg] == '\t') { i = 1; pre = 8; } /* checking for a new item */ if ((prefix_uli(data + beg + i, end - beg - i) && !is_hrule(data + beg + i, end - beg - i)) || prefix_oli(data + beg + i, end - beg - i)) { if (in_empty) has_inside_empty = 1; if (pre == orgpre) /* the following item must have */ break; /* the same indentation */ if (!sublist) sublist = work->size; } /* joining only indented stuff after empty lines */ else if (in_empty && i < 4 && data[beg] != '\t') { *flags |= MKD_LI_END; break; } else if (in_empty) { bufputc(work, '\n'); has_inside_empty = 1; } in_empty = 0; /* adding the line without prefix into the working buffer */ bufput(work, data + beg + i, end - beg - i); beg = end; } /* render of li contents */ if (has_inside_empty) *flags |= MKD_LI_BLOCK; if (*flags & MKD_LI_BLOCK) { /* intermediate render of block li */ if (sublist && sublist < work->size) { parse_block(inter, rndr, work->data, sublist); parse_block(inter, rndr, work->data + sublist, work->size - sublist); } else parse_block(inter, rndr, work->data, work->size); } else { /* intermediate render of inline li */ if (sublist && sublist < work->size) { parse_inline(inter, rndr, work->data, sublist); parse_block(inter, rndr, work->data + sublist, work->size - sublist); } else parse_inline(inter, rndr, work->data, work->size); } /* render of li itself */ if (rndr->make.listitem) rndr->make.listitem(ob, inter, *flags, rndr->make.opaque); release_work_buffer(rndr, inter); release_work_buffer(rndr, work); return beg; }
/* parse_blockquote • hanldes parsing of a regular paragraph */ static size_t parse_paragraph(struct buf *ob, struct render *rndr, char *data, size_t size) { size_t i = 0, end = 0; int level = 0; struct buf work = { data, 0, 0, 0, 0 }; /* volatile working buffer */ while (i < size) { for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; if (is_empty(data + i, size - i) || (level = is_headerline(data + i, size - i)) != 0) break; if (rndr->ext_flags & MKDEXT_LAX_HTML_BLOCKS) { if (data[i] == '<' && rndr->make.blockhtml && parse_htmlblock(ob, rndr, data + i, size - i, 0)) { end = i; break; } } if (data[i] == '#' || is_hrule(data + i, size - i)) { end = i; break; } i = end; } work.size = i; while (work.size && data[work.size - 1] == '\n') work.size--; if (!level) { struct buf *tmp = rndr_newbuf(rndr); parse_inline(tmp, rndr, work.data, work.size); if (rndr->make.paragraph) rndr->make.paragraph(ob, tmp, rndr->make.opaque); rndr_popbuf(rndr); } else { struct buf *header_work; if (work.size) { size_t beg; i = work.size; work.size -= 1; while (work.size && data[work.size] != '\n') work.size -= 1; beg = work.size + 1; while (work.size && data[work.size - 1] == '\n') work.size -= 1; if (work.size > 0) { struct buf *tmp = rndr_newbuf(rndr); parse_inline(tmp, rndr, work.data, work.size); if (rndr->make.paragraph) rndr->make.paragraph(ob, tmp, rndr->make.opaque); rndr_popbuf(rndr); work.data += beg; work.size = i - beg; } else work.size = i; } header_work = rndr_newbuf(rndr); parse_inline(header_work, rndr, work.data, work.size); if (rndr->make.header) rndr->make.header(ob, header_work, (int)level, rndr->make.opaque); rndr_popbuf(rndr); } return end; }