/* 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_table_cell • parse a cell inside a table */ static void parse_table_cell(struct buf *ob, struct render *rndr, char *data, size_t size, int flags) { struct buf *span = new_work_buffer(rndr); parse_inline(span, rndr, data, size); rndr->make.table_cell(ob, span, flags, rndr->make.opaque); release_work_buffer(rndr, span); }
/* parse_emph2 • parsing single emphase */ static size_t parse_emph2(struct buf *ob, struct render *rndr, char *data, size_t size, char c) { int (*render_method)(struct buf *ob, struct buf *text, void *opaque); size_t i = 0, len; struct buf *work = 0; int r; render_method = (c == '~') ? rndr->make.strikethrough : rndr->make.double_emphasis; if (!render_method) return 0; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !isspace(data[i - 1])) { work = rndr_newbuf(rndr); parse_inline(work, rndr, data, i); r = render_method(ob, work, rndr->make.opaque); rndr_popbuf(rndr); return r ? i + 2 : 0; } i++; } return 0; }
void ifcmd(u_char *command, u_char *args, u_char *subargs) { u_char *expr; u_char *sub; int flag = 0; int result; if (!(expr = next_expr(&args, '('))) { yell("Missing CONDITION in IF"); return; } sub = parse_inline(expr, subargs ? subargs : empty_string(), &flag); if (get_int_var(DEBUG_VAR) & DEBUG_EXPANSIONS) yell("If expression expands to: (%s)", sub); if (!*sub || *sub == '0') result = 0; else result = 1; new_free(&sub); if (!(expr = next_expr(&args, '{'))) { yell("Missing THEN portion in IF"); return; } if (!result && !(expr = next_expr(&args, '{'))) return; parse_line(NULL, expr, subargs ? subargs : empty_string(), 0, 0, 0); return; }
/* parse_atxheader • parsing of atx-style headers */ static size_t parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size) { int level = 0; size_t i, end, skip, span_beg, span_size; if (!size || data[0] != '#') return 0; while (level < size && level < 6 && data[level] == '#') level += 1; for (i = level; i < size && (data[i] == ' ' || data[i] == '\t'); i += 1); span_beg = i; for (end = i; end < size && data[end] != '\n'; end += 1); skip = end; if (end <= i) return parse_paragraph(ob, rndr, data, size); while (end && data[end - 1] == '#') end -= 1; while (end && (data[end - 1] == ' ' || data[end - 1] == '\t')) end -= 1; if (end <= i) return parse_paragraph(ob, rndr, data, size); span_size = end - span_beg; if (rndr->make.header) { struct buf *span = new_work_buffer(rndr); parse_inline(span, rndr, data + span_beg, span_size); rndr->make.header(ob, span, level, rndr->make.opaque); release_work_buffer(rndr, span); } return skip; }
/* closed by a symbol not preceded by whitespace and not followed by symbol */ static size_t parse_emph1(struct buf *ob, struct render *rndr, char *data, size_t size, char c) { size_t i = 0, len; struct buf *work = 0; int r; if (!rndr->make.emphasis) return 0; /* skipping one symbol if coming from emph3 */ if (size > 1 && data[0] == c && data[1] == c) i = 1; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; if (i >= size) return 0; if (i + 1 < size && data[i + 1] == c) { i += 1; continue; } if (data[i] == c && data[i - 1] != ' ' && data[i - 1] != '\t' && data[i - 1] != '\n') { work = new_work_buffer(rndr); parse_inline(work, rndr, data, i); r = rndr->make.emphasis(ob, work, c, rndr->make.opaque); release_work_buffer(rndr, work); return r ? i + 1 : 0; } } return 0; }
static VALUE epic_expr (VALUE module, VALUE string) { char *exprval; RUBY_STARTUP exprval = parse_inline(my_string, ""); return rb_str_new(exprval, strlen(exprval)); }
// Parse inlines from parent's string_content, adding as children of parent. extern void cmark_parse_inlines(cmark_node* parent, cmark_reference_map *refmap, int options) { subject subj; subject_from_buf(&subj, &parent->string_content, refmap); while (!is_eof(&subj) && parse_inline(&subj, parent, options)) ; process_emphasis(&subj, NULL); }
static XS (XS_expr) { int foo = 0; char* retval=NULL; char* arg=NULL; dXSARGS; for (foo=0; foo<items; foo++) { arg = malloc_strdup((char*)SvPV_nolen(ST(foo))); retval = (char*)parse_inline(arg, ""); XST_mPV(foo, retval); new_free(&arg); new_free(&retval); } XSRETURN(items); }
static void parse_table_row(struct buf *ob, struct render *rndr, char *data, size_t size, size_t columns, int *col_data) { size_t i = 0, col; struct buf *row_work = 0; row_work = rndr_newbuf(rndr); if (i < size && data[i] == '|') i++; for (col = 0; col < columns && i < size; ++col) { size_t cell_start, cell_end; struct buf *cell_work; cell_work = rndr_newbuf(rndr); while (i < size && isspace(data[i])) i++; cell_start = i; while (i < size && data[i] != '|') i++; cell_end = i - 1; while (cell_end > cell_start && isspace(data[cell_end])) cell_end--; parse_inline(cell_work, rndr, data + cell_start, 1 + cell_end - cell_start); if (rndr->make.table_cell) rndr->make.table_cell(row_work, cell_work, col_data ? col_data[col] : 0, rndr->make.opaque); rndr_popbuf(rndr); i++; } for (; col < columns; ++col) { struct buf empty_cell = {0, 0, 0, 0, 0}; if (rndr->make.table_cell) rndr->make.table_cell(row_work, &empty_cell, col_data ? col_data[col] : 0, rndr->make.opaque); } if (rndr->make.table_row) rndr->make.table_row(ob, row_work, rndr->make.opaque); rndr_popbuf(rndr); }
// Parse inlines from parent's string_content, adding as children of parent. extern void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent, cmark_reference_map *refmap, int options) { subject subj; subject_from_buf(mem, &subj, &parent->content, refmap); cmark_chunk_rtrim(&subj.input); while (!is_eof(&subj) && parse_inline(&subj, parent, options)) ; process_emphasis(&subj, NULL); // free bracket and delim stack while (subj.last_delim) { remove_delimiter(&subj, subj.last_delim); } while (subj.last_bracket) { pop_bracket(&subj); } }
void whilecmd(u_char *command, u_char *args, u_char *subargs) { u_char *expr = NULL, *ptr, *body = NULL, *newexp = NULL; int args_used; /* this isn't used here, but is passed * to expand_alias() */ if ((ptr = next_expr(&args, '(')) == NULL) { yell("WHILE: missing boolean expression"); return; } malloc_strcpy(&expr, ptr); if ((ptr = next_expr(&args, '{')) == NULL) { say("WHILE: missing expression"); new_free(&expr); return; } malloc_strcpy(&body, ptr); while (1) { malloc_strcpy(&newexp, expr); ptr = parse_inline(newexp, subargs ? subargs : empty_string(), &args_used); if (*ptr && *ptr !='0') { new_free(&ptr); parse_line(NULL, body, subargs ? subargs : empty_string(), 0, 0, 0); } else break; } new_free(&newexp); new_free(&ptr); new_free(&expr); new_free(&body); }
/* closed by a symbol not preceded by whitespace and not followed by symbol */ static size_t parse_emph1(struct buf *ob, struct render *rndr, char *data, size_t size, char c) { size_t i = 0, len; struct buf *work = 0; int r; if (!rndr->make.emphasis) return 0; /* skipping one symbol if coming from emph3 */ if (size > 1 && data[0] == c && data[1] == c) i = 1; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; if (i >= size) return 0; if (i + 1 < size && data[i + 1] == c) { i += 1; continue; } if (data[i] == c && !isspace(data[i - 1])) { if ((rndr->ext_flags & MKDEXT_LAX_EMPHASIS) == 0) { if (!(i + 1 == size || isspace(data[i + 1]) || ispunct(data[i + 1]))) continue; } work = rndr_newbuf(rndr); parse_inline(work, rndr, data, i); r = rndr->make.emphasis(ob, work, rndr->make.opaque); rndr_popbuf(rndr); return r ? i + 1 : 0; } } return 0; }
/* finds the first closing tag, and delegates to the other emph */ static size_t parse_emph3(struct buf *ob, struct render *rndr, char *data, size_t size, char c) { size_t i = 0, len; int r; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; /* skip whitespace preceded symbols */ if (data[i] != c || isspace(data[i - 1])) continue; if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && rndr->make.triple_emphasis) { /* triple symbol found */ struct buf *work = rndr_newbuf(rndr); parse_inline(work, rndr, data, i); r = rndr->make.triple_emphasis(ob, work, rndr->make.opaque); rndr_popbuf(rndr); return r ? i + 3 : 0; } else if (i + 1 < size && data[i + 1] == c) { /* double symbol found, handing over to emph1 */ len = parse_emph1(ob, rndr, data - 2, size + 2, c); if (!len) return 0; else return len - 2; } else { /* single symbol found, handing over to emph2 */ len = parse_emph2(ob, rndr, data - 1, size + 1, c); if (!len) return 0; else return len - 1; } } return 0; }
/* parse_emph2 • parsing single emphase */ static size_t parse_emph2(struct buf *ob, struct render *rndr, char *data, size_t size, char c) { size_t i = 0, len; struct buf *work = 0; int r; if (!rndr->make.double_emphasis) return 0; while (i < size) { len = find_emph_char(data + i, size - i, c); if (!len) return 0; i += len; if (i + 1 < size && data[i] == c && data[i + 1] == c && i && data[i - 1] != ' ' && data[i - 1] != '\t' && data[i - 1] != '\n') { work = new_work_buffer(rndr); parse_inline(work, rndr, data, i); r = rndr->make.double_emphasis(ob, work, c, rndr->make.opaque); release_work_buffer(rndr, work); return r ? i + 2 : 0; } i += 1; } return 0; }
/* parse_atxheader • parsing of atx-style headers */ static size_t parse_atxheader(struct buf *ob, struct render *rndr, char *data, size_t size) { size_t level = 0; size_t i, end, skip; if (!size || data[0] != '#') return 0; while (level < size && level < 6 && data[level] == '#') level++; for (i = level; i < size && (data[i] == ' ' || data[i] == '\t'); i++); for (end = i; end < size && data[end] != '\n'; end++); skip = end; while (end && data[end - 1] == '#') end--; while (end && (data[end - 1] == ' ' || data[end - 1] == '\t')) end--; if (end > i) { struct buf *work = rndr_newbuf(rndr); parse_inline(work, rndr, data + i, end - i); if (rndr->make.header) rndr->make.header(ob, work, (int)level, rndr->make.opaque); rndr_popbuf(rndr); } return skip; }
/* 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; }
/* I suppose someone could make a case that since the * foreach_handler() routine weeds out any for command that doesnt have * two commands, that checking for those 2 commas is a waste. I suppose. */ void forcmd(u_char *command, u_char *args, u_char *subargs) { u_char *working = NULL; u_char *commence = NULL; u_char *evaluation = NULL; u_char *lameeval = NULL; u_char *iteration = NULL; u_char *sa = NULL; int argsused = 0; u_char *line = NULL; u_char *commands = NULL; /* Get the whole () thing */ if ((working = next_expr(&args, '(')) == NULL) /* ) */ { yell("FOR: missing closing parenthesis"); return; } malloc_strcpy(&commence, working); /* Find the beginning of the second expression */ evaluation = my_index(commence, ','); if (!evaluation) { yell("FOR: no components!"); new_free(&commence); return; } do *evaluation++ = '\0'; while (isspace(*evaluation)); /* Find the beginning of the third expression */ iteration = my_index(evaluation, ','); if (!iteration) { yell("FOR: Only two components!"); new_free(&commence); return; } do { *iteration++ = '\0'; } while (isspace(*iteration)); working = args; while (isspace(*working)) *working++ = '\0'; if ((working = next_expr(&working, '{')) == NULL) /* } */ { yell("FOR: badly formed commands"); new_free(&commence); return; } malloc_strcpy(&commands, working); sa = subargs ? subargs : empty_string(); parse_line(NULL, commence, sa, 0, 0, 0); while (1) { malloc_strcpy(&lameeval, evaluation); line = parse_inline(lameeval, sa, &argsused); if (*line && *line != '0') { new_free(&line); parse_line(NULL, commands, sa, 0, 0, 0); parse_line(NULL, iteration, sa, 0, 0, 0); } else break; } new_free(&line); new_free(&lameeval); new_free(&commence); new_free(&commands); }
/* char_link • '[': parsing a link or an image */ static size_t char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size) { int is_img = (offset && data[-1] == '!'), level; size_t i = 1, txt_e; struct buf *content = 0; struct buf *link = 0; struct buf *title = 0; int text_has_nl = 0, ret; /* checking whether the correct renderer exists */ if ((is_img && !rndr->make.image) || (!is_img && !rndr->make.link)) return 0; /* looking for the matching closing bracket */ for (level = 1; i < size; i += 1) if (data[i] == '\n') text_has_nl = 1; else if (data[i - 1] == '\\') continue; else if (data[i] == '[') level += 1; else if (data[i] == ']') { level -= 1; if (level <= 0) break; } if (i >= size) return 0; txt_e = i; i += 1; /* skip any amount of whitespace or newline */ /* (this is much more laxist than original markdown syntax) */ while (i < size && (data[i] == ' ' || data[i] == '\t' || data[i] == '\n')) i += 1; /* allocate temporary buffers to store content, link and title */ content = new_work_buffer(rndr); link = new_work_buffer(rndr); title = new_work_buffer(rndr); ret = 0; /* error if we don't get to the callback */ /* inline style link */ if (i < size && data[i] == '(') { size_t span_end = i; while (span_end < size && !(data[span_end] == ')' && (span_end == i || data[span_end - 1] != '\\'))) span_end += 1; if (span_end >= size || get_link_inline(link, title, data + i+1, span_end - (i+1)) < 0) goto char_link_cleanup; i = span_end + 1; } /* reference style link */ else if (i < size && data[i] == '[') { char *id_data; size_t id_size, id_end = i; while (id_end < size && data[id_end] != ']') id_end += 1; if (id_end >= size) goto char_link_cleanup; if (i + 1 == id_end) { /* implicit id - use the contents */ id_data = data + 1; id_size = txt_e - 1; } else { /* explici id - between brackets */ id_data = data + i + 1; id_size = id_end - (i + 1); } if (get_link_ref(rndr, link, title, id_data, id_size) < 0) goto char_link_cleanup; i = id_end + 1; } /* shortcut reference style link */ else { if (get_link_ref(rndr, link, title, data + 1, txt_e - 1) < 0) goto char_link_cleanup; /* rewinding the whitespace */ i = txt_e + 1; } /* building content: img alt is escaped, link content is parsed */ if (txt_e > 1) { if (is_img) bufput(content, data + 1, txt_e - 1); else parse_inline(content, rndr, data + 1, txt_e - 1); } /* calling the relevant rendering function */ if (is_img) { if (ob->size && ob->data[ob->size - 1] == '!') ob->size -= 1; ret = rndr->make.image(ob, link, title, content, rndr->make.opaque); } else ret = rndr->make.link(ob, link, title, content, rndr->make.opaque); /* cleanup */ char_link_cleanup: release_work_buffer(rndr, title); release_work_buffer(rndr, link); release_work_buffer(rndr, content); return ret ? i : 0; }
/* char_link • '[': parsing a link or an image */ static size_t char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size) { int is_img = (offset && data[-1] == '!'), level; size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0; struct buf *content = 0; struct buf *link = 0; struct buf *title = 0; struct buf *u_link = 0; size_t org_work_size = rndr->work.size; int text_has_nl = 0, ret = 0; /* checking whether the correct renderer exists */ if ((is_img && !rndr->make.image) || (!is_img && !rndr->make.link)) goto cleanup; /* looking for the matching closing bracket */ for (level = 1; i < size; i += 1) { if (data[i] == '\n') text_has_nl = 1; else if (data[i - 1] == '\\') continue; else if (data[i] == '[') level++; else if (data[i] == ']') { level--; if (level <= 0) break; } } if (i >= size) goto cleanup; txt_e = i; i += 1; /* skip any amount of whitespace or newline */ /* (this is much more laxist than original markdown syntax) */ while (i < size && isspace(data[i])) i++; /* inline style link */ if (i < size && data[i] == '(') { /* skipping initial whitespace */ i += 1; while (i < size && isspace(data[i])) i++; link_b = i; /* looking for link end: ' " ) */ while (i < size) { if (data[i] == '\\') i += 2; else if (data[i] == ')' || data[i] == '\'' || data[i] == '"') break; else i += 1; } if (i >= size) goto cleanup; link_e = i; /* looking for title end if present */ if (data[i] == '\'' || data[i] == '"') { i++; title_b = i; while (i < size) { if (data[i] == '\\') i += 2; else if (data[i] == ')') break; else i += 1; } if (i >= size) goto cleanup; /* skipping whitespaces after title */ title_e = i - 1; while (title_e > title_b && isspace(data[title_e])) title_e--; /* checking for closing quote presence */ if (data[title_e] != '\'' && data[title_e] != '"') { title_b = title_e = 0; link_e = i; } } /* remove whitespace at the end of the link */ while (link_e > link_b && isspace(data[link_e - 1])) link_e--; /* remove optional angle brackets around the link */ if (data[link_b] == '<') link_b++; if (data[link_e - 1] == '>') link_e--; /* building escaped link and title */ if (link_e > link_b) { link = rndr_newbuf(rndr); bufput(link, data + link_b, link_e - link_b); } if (title_e > title_b) { title = rndr_newbuf(rndr); bufput(title, data + title_b, title_e - title_b); } i++; } /* reference style link */ else if (i < size && data[i] == '[') { struct buf id = { 0, 0, 0, 0, 0 }; struct link_ref *lr; /* looking for the id */ i += 1; link_b = i; while (i < size && data[i] != ']') i++; if (i >= size) goto cleanup; link_e = i; /* finding the link_ref */ if (link_b == link_e) { if (text_has_nl) { struct buf *b = rndr_newbuf(rndr); size_t j; for (j = 1; j < txt_e; j++) { if (data[j] != '\n') bufputc(b, data[j]); else if (data[j - 1] != ' ') bufputc(b, ' '); } id.data = b->data; id.size = b->size; } else { id.data = data + 1; id.size = txt_e - 1; } } else { id.data = data + link_b; id.size = link_e - link_b; } lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref); if (!lr) goto cleanup; /* keeping link and title from link_ref */ link = lr->link; title = lr->title; i += 1; } /* shortcut reference style link */ else { struct buf id = { 0, 0, 0, 0, 0 }; struct link_ref *lr; /* crafting the id */ if (text_has_nl) { struct buf *b = rndr_newbuf(rndr); size_t j; for (j = 1; j < txt_e; j++) { if (data[j] != '\n') bufputc(b, data[j]); else if (data[j - 1] != ' ') bufputc(b, ' '); } id.data = b->data; id.size = b->size; } else { id.data = data + 1; id.size = txt_e - 1; } /* finding the link_ref */ lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref); if (!lr) goto cleanup; /* keeping link and title from link_ref */ link = lr->link; title = lr->title; /* rewinding the whitespace */ i = txt_e + 1; } /* building content: img alt is escaped, link content is parsed */ if (txt_e > 1) { content = rndr_newbuf(rndr); if (is_img) bufput(content, data + 1, txt_e - 1); else parse_inline(content, rndr, data + 1, txt_e - 1); } if (link) { u_link = rndr_newbuf(rndr); unscape_text(u_link, link); } /* calling the relevant rendering function */ if (is_img) { if (ob->size && ob->data[ob->size - 1] == '!') ob->size -= 1; ret = rndr->make.image(ob, u_link, title, content, rndr->make.opaque); } else { ret = rndr->make.link(ob, u_link, title, content, rndr->make.opaque); } /* cleanup */ cleanup: rndr->work.size = (int)org_work_size; return ret ? i : 0; }
/* 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; }