\"), 9)) {\n *p_end = off + 9;\n return TRUE;\n }\n\n if(md_ascii_case_eq(STR(off), _T(\"\"), 8)) {\n *p_end = off + 8;\n return TRUE;\n }\n\n if(md_ascii_case_eq(STR(off), _T(\"\"), 6)) {\n *p_end = off + 6;\n return TRUE;\n }\n }\n\n off++;\n }\n *p_end = off;\n return FALSE;\n }\n\n case 2:\n return (md_line_contains(ctx, beg, _T(\"-->\"), 3, p_end) ? 2 : FALSE);\n\n case 3:\n return (md_line_contains(ctx, beg, _T(\"?>\"), 2, p_end) ? 3 : FALSE);\n\n case 4:\n return (md_line_contains(ctx, beg, _T(\">\"), 1, p_end) ? 4 : FALSE);\n\n case 5:\n return (md_line_contains(ctx, beg, _T(\"]]>\"), 3, p_end) ? 5 : FALSE);\n\n case 6: /* Pass through */\n case 7:\n *p_end = beg;\n return (ISNEWLINE(beg) ? ctx->html_block_type : FALSE);\n\n default:\n MD_UNREACHABLE();\n }\n return FALSE;\n}\n\n\nstatic int\nmd_is_container_compatible(const MD_CONTAINER* pivot, const MD_CONTAINER* container)\n{\n /* Block quote has no \"items\" like lists. */\n if(container->ch == _T('>'))\n return FALSE;\n\n if(container->ch != pivot->ch)\n return FALSE;\n if(container->mark_indent > pivot->contents_indent)\n return FALSE;\n\n return TRUE;\n}\n\nstatic int\nmd_push_container(MD_CTX* ctx, const MD_CONTAINER* container)\n{\n if(ctx->n_containers >= ctx->alloc_containers) {\n MD_CONTAINER* new_containers;\n\n ctx->alloc_containers = (ctx->alloc_containers > 0\n ? ctx->alloc_containers + ctx->alloc_containers / 2\n : 16);\n new_containers = realloc(ctx->containers, ctx->alloc_containers * sizeof(MD_CONTAINER));\n if(new_containers == NULL) {\n MD_LOG(\"realloc() failed.\");\n return -1;\n }\n\n ctx->containers = new_containers;\n }\n\n memcpy(&ctx->containers[ctx->n_containers++], container, sizeof(MD_CONTAINER));\n return 0;\n}\n\nstatic int\nmd_enter_child_containers(MD_CTX* ctx, int n_children, unsigned data)\n{\n int i;\n int ret = 0;\n\n for(i = ctx->n_containers - n_children; i < ctx->n_containers; i++) {\n MD_CONTAINER* c = &ctx->containers[i];\n int is_ordered_list = FALSE;\n\n switch(c->ch) {\n case _T(')'):\n case _T('.'):\n is_ordered_list = TRUE;\n /* Pass through */\n\n case _T('-'):\n case _T('+'):\n case _T('*'):\n /* Remember offset in ctx->block_bytes so we can revisit the\n * block if we detect it is a loose list. */\n md_end_current_block(ctx);\n c->block_byte_off = ctx->n_block_bytes;\n\n MD_CHECK(md_push_container_bytes(ctx,\n (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL),\n c->start, data, MD_BLOCK_CONTAINER_OPENER));\n MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI,\n c->task_mark_off,\n (c->is_task ? CH(c->task_mark_off) : 0),\n MD_BLOCK_CONTAINER_OPENER));\n break;\n\n case _T('>'):\n MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0, 0, MD_BLOCK_CONTAINER_OPENER));\n break;\n\n default:\n MD_UNREACHABLE();\n break;\n }\n }\n\nabort:\n return ret;\n}\n\nstatic int\nmd_leave_child_containers(MD_CTX* ctx, int n_keep)\n{\n int ret = 0;\n\n while(ctx->n_containers > n_keep) {\n MD_CONTAINER* c = &ctx->containers[ctx->n_containers-1];\n int is_ordered_list = FALSE;\n\n switch(c->ch) {\n case _T(')'):\n case _T('.'):\n is_ordered_list = TRUE;\n /* Pass through */\n\n case _T('-'):\n case _T('+'):\n case _T('*'):\n MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI,\n c->task_mark_off, (c->is_task ? CH(c->task_mark_off) : 0),\n MD_BLOCK_CONTAINER_CLOSER));\n MD_CHECK(md_push_container_bytes(ctx,\n (is_ordered_list ? MD_BLOCK_OL : MD_BLOCK_UL), 0,\n c->ch, MD_BLOCK_CONTAINER_CLOSER));\n break;\n\n case _T('>'):\n MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_QUOTE, 0,\n 0, MD_BLOCK_CONTAINER_CLOSER));\n break;\n\n default:\n MD_UNREACHABLE();\n break;\n }\n\n ctx->n_containers--;\n }\n\nabort:\n return ret;\n}\n\nstatic int\nmd_is_container_mark(MD_CTX* ctx, unsigned indent, OFF beg, OFF* p_end, MD_CONTAINER* p_container)\n{\n OFF off = beg;\n OFF max_end;\n\n if(indent >= ctx->code_indent_offset)\n return FALSE;\n\n /* Check for block quote mark. */\n if(off < ctx->size && CH(off) == _T('>')) {\n off++;\n p_container->ch = _T('>');\n p_container->is_loose = FALSE;\n p_container->is_task = FALSE;\n p_container->mark_indent = indent;\n p_container->contents_indent = indent + 1;\n *p_end = off;\n return TRUE;\n }\n\n /* Check for list item bullet mark. */\n if(off+1 < ctx->size && ISANYOF(off, _T(\"-+*\")) && (ISBLANK(off+1) || ISNEWLINE(off+1))) {\n p_container->ch = CH(off);\n p_container->is_loose = FALSE;\n p_container->is_task = FALSE;\n p_container->mark_indent = indent;\n p_container->contents_indent = indent + 1;\n *p_end = off + 1;\n return TRUE;\n }\n\n /* Check for ordered list item marks. */\n max_end = off + 9;\n if(max_end > ctx->size)\n max_end = ctx->size;\n p_container->start = 0;\n while(off < max_end && ISDIGIT(off)) {\n p_container->start = p_container->start * 10 + CH(off) - _T('0');\n off++;\n }\n if(off > beg && off+1 < ctx->size &&\n (CH(off) == _T('.') || CH(off) == _T(')')) &&\n (ISBLANK(off+1) || ISNEWLINE(off+1)))\n {\n p_container->ch = CH(off);\n p_container->is_loose = FALSE;\n p_container->is_task = FALSE;\n p_container->mark_indent = indent;\n p_container->contents_indent = indent + off - beg + 1;\n *p_end = off + 1;\n return TRUE;\n }\n\n return FALSE;\n}\n\nstatic unsigned\nmd_line_indentation(MD_CTX* ctx, unsigned total_indent, OFF beg, OFF* p_end)\n{\n OFF off = beg;\n unsigned indent = total_indent;\n\n while(off < ctx->size && ISBLANK(off)) {\n if(CH(off) == _T('\\t'))\n indent = (indent + 4) & ~3;\n else\n indent++;\n off++;\n }\n\n *p_end = off;\n return indent - total_indent;\n}\n\nstatic const MD_LINE_ANALYSIS md_dummy_blank_line = { MD_LINE_BLANK, 0 };\n\n/* Analyze type of the line and find some its properties. This serves as a\n * main input for determining type and boundaries of a block. */\nstatic int\nmd_analyze_line(MD_CTX* ctx, OFF beg, OFF* p_end,\n const MD_LINE_ANALYSIS* pivot_line, MD_LINE_ANALYSIS* line)\n{\n unsigned total_indent = 0;\n int n_parents = 0;\n int n_brothers = 0;\n int n_children = 0;\n MD_CONTAINER container = { 0 };\n int prev_line_has_list_loosening_effect = ctx->last_line_has_list_loosening_effect;\n OFF off = beg;\n OFF hr_killer = 0;\n int ret = 0;\n\n line->indent = md_line_indentation(ctx, total_indent, off, &off);\n total_indent += line->indent;\n line->beg = off;\n\n /* Given the indentation and block quote marks '>', determine how many of\n * the current containers are our parents. */\n while(n_parents < ctx->n_containers) {\n MD_CONTAINER* c = &ctx->containers[n_parents];\n\n if(c->ch == _T('>') && line->indent < ctx->code_indent_offset &&\n off < ctx->size && CH(off) == _T('>'))\n {\n /* Block quote mark. */\n off++;\n total_indent++;\n line->indent = md_line_indentation(ctx, total_indent, off, &off);\n total_indent += line->indent;\n\n /* The optional 1st space after '>' is part of the block quote mark. */\n if(line->indent > 0)\n line->indent--;\n\n line->beg = off;\n\n } else if(c->ch != _T('>') && line->indent >= c->contents_indent) {\n /* List. */\n line->indent -= c->contents_indent;\n } else {\n break;\n }\n\n n_parents++;\n }\n\n if(off >= ctx->size || ISNEWLINE(off)) {\n /* Blank line does not need any real indentation to be nested inside\n * a list. */\n if(n_brothers + n_children == 0) {\n while(n_parents < ctx->n_containers && ctx->containers[n_parents].ch != _T('>'))\n n_parents++;\n }\n }\n\n while(TRUE) {\n /* Check whether we are fenced code continuation. */\n if(pivot_line->type == MD_LINE_FENCEDCODE) {\n line->beg = off;\n\n /* We are another MD_LINE_FENCEDCODE unless we are closing fence\n * which we transform into MD_LINE_BLANK. */\n if(line->indent < ctx->code_indent_offset) {\n if(md_is_closing_code_fence(ctx, CH(pivot_line->beg), off, &off)) {\n line->type = MD_LINE_BLANK;\n ctx->last_line_has_list_loosening_effect = FALSE;\n break;\n }\n }\n\n /* Change indentation accordingly to the initial code fence. */\n if(n_parents == ctx->n_containers) {\n if(line->indent > pivot_line->indent)\n line->indent -= pivot_line->indent;\n else\n line->indent = 0;\n\n line->type = MD_LINE_FENCEDCODE;\n break;\n }\n }\n\n /* Check whether we are HTML block continuation. */\n if(pivot_line->type == MD_LINE_HTML && ctx->html_block_type > 0) {\n int html_block_type;\n\n html_block_type = md_is_html_block_end_condition(ctx, off, &off);\n if(html_block_type > 0) {\n MD_ASSERT(html_block_type == ctx->html_block_type);\n\n /* Make sure this is the last line of the block. */\n ctx->html_block_type = 0;\n\n /* Some end conditions serve as blank lines at the same time. */\n if(html_block_type == 6 || html_block_type == 7) {\n line->type = MD_LINE_BLANK;\n line->indent = 0;\n break;\n }\n }\n\n if(n_parents == ctx->n_containers) {\n line->type = MD_LINE_HTML;\n break;\n }\n }\n\n /* Check for blank line. */\n if(off >= ctx->size || ISNEWLINE(off)) {\n if(pivot_line->type == MD_LINE_INDENTEDCODE && n_parents == ctx->n_containers) {\n line->type = MD_LINE_INDENTEDCODE;\n if(line->indent > ctx->code_indent_offset)\n line->indent -= ctx->code_indent_offset;\n else\n line->indent = 0;\n ctx->last_line_has_list_loosening_effect = FALSE;\n } else {\n line->type = MD_LINE_BLANK;\n ctx->last_line_has_list_loosening_effect = (n_parents > 0 &&\n n_brothers + n_children == 0 &&\n ctx->containers[n_parents-1].ch != _T('>'));\n\n #if 1\n /* See https://github.com/mity/md4c/issues/6\n *\n * This ugly checking tests we are in (yet empty) list item but not\n * its very first line (with the list item mark).\n *\n * If we are such blank line, then any following non-blank line\n * which would be part of this list item actually ends the list\n * because \"a list item can begin with at most one blank line.\"\n */\n if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') &&\n n_brothers + n_children == 0 && ctx->current_block == NULL &&\n ctx->n_block_bytes > (int) sizeof(MD_BLOCK))\n {\n MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK));\n if(top_block->type == MD_BLOCK_LI)\n ctx->last_list_item_starts_with_two_blank_lines = TRUE;\n }\n #endif\n }\n break;\n } else {\n #if 1\n /* This is 2nd half of the hack. If the flag is set (that is there\n * were 2nd blank line at the start of the list item) and we would also\n * belonging to such list item, then interrupt the list. */\n ctx->last_line_has_list_loosening_effect = FALSE;\n if(ctx->last_list_item_starts_with_two_blank_lines) {\n if(n_parents > 0 && ctx->containers[n_parents-1].ch != _T('>') &&\n n_brothers + n_children == 0 && ctx->current_block == NULL &&\n ctx->n_block_bytes > (int) sizeof(MD_BLOCK))\n {\n MD_BLOCK* top_block = (MD_BLOCK*) ((char*)ctx->block_bytes + ctx->n_block_bytes - sizeof(MD_BLOCK));\n if(top_block->type == MD_BLOCK_LI)\n n_parents--;\n }\n\n ctx->last_list_item_starts_with_two_blank_lines = FALSE;\n }\n #endif\n }\n\n /* Check whether we are Setext underline. */\n if(line->indent < ctx->code_indent_offset && pivot_line->type == MD_LINE_TEXT\n && (CH(off) == _T('=') || CH(off) == _T('-'))\n && (n_parents == ctx->n_containers))\n {\n unsigned level;\n\n if(md_is_setext_underline(ctx, off, &off, &level)) {\n line->type = MD_LINE_SETEXTUNDERLINE;\n line->data = level;\n break;\n }\n }\n\n /* Check for thematic break line. */\n if(line->indent < ctx->code_indent_offset && ISANYOF(off, _T(\"-_*\")) && off >= hr_killer) {\n if(md_is_hr_line(ctx, off, &off, &hr_killer)) {\n line->type = MD_LINE_HR;\n break;\n }\n }\n\n /* Check for \"brother\" container. I.e. whether we are another list item\n * in already started list. */\n if(n_parents < ctx->n_containers && n_brothers + n_children == 0) {\n OFF tmp;\n\n if(md_is_container_mark(ctx, line->indent, off, &tmp, &container) &&\n md_is_container_compatible(&ctx->containers[n_parents], &container))\n {\n pivot_line = &md_dummy_blank_line;\n\n off = tmp;\n\n total_indent += container.contents_indent - container.mark_indent;\n line->indent = md_line_indentation(ctx, total_indent, off, &off);\n total_indent += line->indent;\n line->beg = off;\n\n /* Some of the following whitespace actually still belongs to the mark. */\n if(off >= ctx->size || ISNEWLINE(off)) {\n container.contents_indent++;\n } else if(line->indent <= ctx->code_indent_offset) {\n container.contents_indent += line->indent;\n line->indent = 0;\n } else {\n container.contents_indent += 1;\n line->indent--;\n }\n\n ctx->containers[n_parents].mark_indent = container.mark_indent;\n ctx->containers[n_parents].contents_indent = container.contents_indent;\n\n n_brothers++;\n continue;\n }\n }\n\n /* Check for indented code.\n * Note indented code block cannot interrupt a paragraph. */\n if(line->indent >= ctx->code_indent_offset &&\n (pivot_line->type == MD_LINE_BLANK || pivot_line->type == MD_LINE_INDENTEDCODE))\n {\n line->type = MD_LINE_INDENTEDCODE;\n MD_ASSERT(line->indent >= ctx->code_indent_offset);\n line->indent -= ctx->code_indent_offset;\n line->data = 0;\n break;\n }\n\n /* Check for start of a new container block. */\n if(line->indent < ctx->code_indent_offset &&\n md_is_container_mark(ctx, line->indent, off, &off, &container))\n {\n if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers &&\n (off >= ctx->size || ISNEWLINE(off)) && container.ch != _T('>'))\n {\n /* Noop. List mark followed by a blank line cannot interrupt a paragraph. */\n } else if(pivot_line->type == MD_LINE_TEXT && n_parents == ctx->n_containers &&\n (container.ch == _T('.') || container.ch == _T(')')) && container.start != 1)\n {\n /* Noop. Ordered list cannot interrupt a paragraph unless the start index is 1. */\n } else {\n total_indent += container.contents_indent - container.mark_indent;\n line->indent = md_line_indentation(ctx, total_indent, off, &off);\n total_indent += line->indent;\n\n line->beg = off;\n line->data = container.ch;\n\n /* Some of the following whitespace actually still belongs to the mark. */\n if(off >= ctx->size || ISNEWLINE(off)) {\n container.contents_indent++;\n } else if(line->indent <= ctx->code_indent_offset) {\n container.contents_indent += line->indent;\n line->indent = 0;\n } else {\n container.contents_indent += 1;\n line->indent--;\n }\n\n if(n_brothers + n_children == 0)\n pivot_line = &md_dummy_blank_line;\n\n if(n_children == 0)\n MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers));\n\n n_children++;\n MD_CHECK(md_push_container(ctx, &container));\n continue;\n }\n }\n\n /* Check whether we are table continuation. */\n if(pivot_line->type == MD_LINE_TABLE && n_parents == ctx->n_containers) {\n line->type = MD_LINE_TABLE;\n break;\n }\n\n /* Check for ATX header. */\n if(line->indent < ctx->code_indent_offset && CH(off) == _T('#')) {\n unsigned level;\n\n if(md_is_atxheader_line(ctx, off, &line->beg, &off, &level)) {\n line->type = MD_LINE_ATXHEADER;\n line->data = level;\n break;\n }\n }\n\n /* Check whether we are starting code fence. */\n if(CH(off) == _T('`') || CH(off) == _T('~')) {\n if(md_is_opening_code_fence(ctx, off, &off)) {\n line->type = MD_LINE_FENCEDCODE;\n line->data = 1;\n break;\n }\n }\n\n /* Check for start of raw HTML block. */\n if(CH(off) == _T('<') && !(ctx->parser.flags & MD_FLAG_NOHTMLBLOCKS))\n {\n ctx->html_block_type = md_is_html_block_start_condition(ctx, off);\n\n /* HTML block type 7 cannot interrupt paragraph. */\n if(ctx->html_block_type == 7 && pivot_line->type == MD_LINE_TEXT)\n ctx->html_block_type = 0;\n\n if(ctx->html_block_type > 0) {\n /* The line itself also may immediately close the block. */\n if(md_is_html_block_end_condition(ctx, off, &off) == ctx->html_block_type) {\n /* Make sure this is the last line of the block. */\n ctx->html_block_type = 0;\n }\n\n line->type = MD_LINE_HTML;\n break;\n }\n }\n\n /* Check for table underline. */\n if((ctx->parser.flags & MD_FLAG_TABLES) && pivot_line->type == MD_LINE_TEXT &&\n (CH(off) == _T('|') || CH(off) == _T('-') || CH(off) == _T(':')) &&\n n_parents == ctx->n_containers)\n {\n unsigned col_count;\n\n if(ctx->current_block != NULL && ctx->current_block->n_lines == 1 &&\n md_is_table_underline(ctx, off, &off, &col_count))\n {\n line->data = col_count;\n line->type = MD_LINE_TABLEUNDERLINE;\n break;\n }\n }\n\n /* By default, we are normal text line. */\n line->type = MD_LINE_TEXT;\n if(pivot_line->type == MD_LINE_TEXT && n_brothers + n_children == 0) {\n /* Lazy continuation. */\n n_parents = ctx->n_containers;\n }\n\n /* Check for task mark. */\n if((ctx->parser.flags & MD_FLAG_TASKLISTS) && n_brothers + n_children > 0 &&\n ISANYOF_(ctx->containers[ctx->n_containers-1].ch, _T(\"-+*.)\")))\n {\n OFF tmp = off;\n\n while(tmp < ctx->size && tmp < off + 3 && ISBLANK(tmp))\n tmp++;\n if(tmp + 2 < ctx->size && CH(tmp) == _T('[') &&\n ISANYOF(tmp+1, _T(\"xX \")) && CH(tmp+2) == _T(']') &&\n (tmp + 3 == ctx->size || ISBLANK(tmp+3) || ISNEWLINE(tmp+3)))\n {\n MD_CONTAINER* task_container = (n_children > 0 ? &ctx->containers[ctx->n_containers-1] : &container);\n task_container->is_task = TRUE;\n task_container->task_mark_off = tmp + 1;\n off = tmp + 3;\n while(ISWHITESPACE(off))\n off++;\n line->beg = off;\n }\n }\n\n break;\n }\n\n /* Scan for end of the line.\n *\n * Note this is quite a bottleneck of the parsing as we here iterate almost\n * over compete document.\n */\n#if defined __linux__ && !defined MD4C_USE_UTF16\n /* Recent glibc versions have superbly optimized strcspn(), even using\n * vectorization if available. */\n if(ctx->doc_ends_with_newline && off < ctx->size) {\n while(TRUE) {\n off += (OFF) strcspn(STR(off), \"\\r\\n\");\n\n /* strcspn() can stop on zero terminator; but that can appear\n * anywhere in the Markfown input... */\n if(CH(off) == _T('\\0'))\n off++;\n else\n break;\n }\n } else\n#endif\n {\n /* Optimization: Use some loop unrolling. */\n while(off + 3 < ctx->size && !ISNEWLINE(off+0) && !ISNEWLINE(off+1)\n && !ISNEWLINE(off+2) && !ISNEWLINE(off+3))\n off += 4;\n while(off < ctx->size && !ISNEWLINE(off))\n off++;\n }\n\n /* Set end of the line. */\n line->end = off;\n\n /* But for ATX header, we should exclude the optional trailing mark. */\n if(line->type == MD_LINE_ATXHEADER) {\n OFF tmp = line->end;\n while(tmp > line->beg && CH(tmp-1) == _T(' '))\n tmp--;\n while(tmp > line->beg && CH(tmp-1) == _T('#'))\n tmp--;\n if(tmp == line->beg || CH(tmp-1) == _T(' ') || (ctx->parser.flags & MD_FLAG_PERMISSIVEATXHEADERS))\n line->end = tmp;\n }\n\n /* Trim trailing spaces. */\n if(line->type != MD_LINE_INDENTEDCODE && line->type != MD_LINE_FENCEDCODE) {\n while(line->end > line->beg && CH(line->end-1) == _T(' '))\n line->end--;\n }\n\n /* Eat also the new line. */\n if(off < ctx->size && CH(off) == _T('\\r'))\n off++;\n if(off < ctx->size && CH(off) == _T('\\n'))\n off++;\n\n *p_end = off;\n\n /* If we belong to a list after seeing a blank line, the list is loose. */\n if(prev_line_has_list_loosening_effect && line->type != MD_LINE_BLANK && n_parents + n_brothers > 0) {\n MD_CONTAINER* c = &ctx->containers[n_parents + n_brothers - 1];\n if(c->ch != _T('>')) {\n MD_BLOCK* block = (MD_BLOCK*) (((char*)ctx->block_bytes) + c->block_byte_off);\n block->flags |= MD_BLOCK_LOOSE_LIST;\n }\n }\n\n /* Leave any containers we are not part of anymore. */\n if(n_children == 0 && n_parents + n_brothers < ctx->n_containers)\n MD_CHECK(md_leave_child_containers(ctx, n_parents + n_brothers));\n\n /* Enter any container we found a mark for. */\n if(n_brothers > 0) {\n MD_ASSERT(n_brothers == 1);\n MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI,\n ctx->containers[n_parents].task_mark_off,\n (ctx->containers[n_parents].is_task ? CH(ctx->containers[n_parents].task_mark_off) : 0),\n MD_BLOCK_CONTAINER_CLOSER));\n MD_CHECK(md_push_container_bytes(ctx, MD_BLOCK_LI,\n container.task_mark_off,\n (container.is_task ? CH(container.task_mark_off) : 0),\n MD_BLOCK_CONTAINER_OPENER));\n ctx->containers[n_parents].is_task = container.is_task;\n ctx->containers[n_parents].task_mark_off = container.task_mark_off;\n }\n\n if(n_children > 0)\n MD_CHECK(md_enter_child_containers(ctx, n_children, line->data));\n\nabort:\n return ret;\n}\n\nstatic int\nmd_process_line(MD_CTX* ctx, const MD_LINE_ANALYSIS** p_pivot_line, MD_LINE_ANALYSIS* line)\n{\n const MD_LINE_ANALYSIS* pivot_line = *p_pivot_line;\n int ret = 0;\n\n /* Blank line ends current leaf block. */\n if(line->type == MD_LINE_BLANK) {\n MD_CHECK(md_end_current_block(ctx));\n *p_pivot_line = &md_dummy_blank_line;\n return 0;\n }\n\n /* Some line types form block on their own. */\n if(line->type == MD_LINE_HR || line->type == MD_LINE_ATXHEADER) {\n MD_CHECK(md_end_current_block(ctx));\n\n /* Add our single-line block. */\n MD_CHECK(md_start_new_block(ctx, line));\n MD_CHECK(md_add_line_into_current_block(ctx, line));\n MD_CHECK(md_end_current_block(ctx));\n *p_pivot_line = &md_dummy_blank_line;\n return 0;\n }\n\n /* MD_LINE_SETEXTUNDERLINE changes meaning of the current block and ends it. */\n if(line->type == MD_LINE_SETEXTUNDERLINE) {\n MD_ASSERT(ctx->current_block != NULL);\n ctx->current_block->type = MD_BLOCK_H;\n ctx->current_block->data = line->data;\n ctx->current_block->flags |= MD_BLOCK_SETEXT_HEADER;\n MD_CHECK(md_add_line_into_current_block(ctx, line));\n MD_CHECK(md_end_current_block(ctx));\n if(ctx->current_block == NULL) {\n *p_pivot_line = &md_dummy_blank_line;\n } else {\n /* This happens if we have consumed all the body as link ref. defs.\n * and downgraded the underline into start of a new paragraph block. */\n line->type = MD_LINE_TEXT;\n *p_pivot_line = line;\n }\n return 0;\n }\n\n /* MD_LINE_TABLEUNDERLINE changes meaning of the current block. */\n if(line->type == MD_LINE_TABLEUNDERLINE) {\n MD_ASSERT(ctx->current_block != NULL);\n MD_ASSERT(ctx->current_block->n_lines == 1);\n ctx->current_block->type = MD_BLOCK_TABLE;\n ctx->current_block->data = line->data;\n MD_ASSERT(pivot_line != &md_dummy_blank_line);\n ((MD_LINE_ANALYSIS*)pivot_line)->type = MD_LINE_TABLE;\n MD_CHECK(md_add_line_into_current_block(ctx, line));\n return 0;\n }\n\n /* The current block also ends if the line has different type. */\n if(line->type != pivot_line->type)\n MD_CHECK(md_end_current_block(ctx));\n\n /* The current line may start a new block. */\n if(ctx->current_block == NULL) {\n MD_CHECK(md_start_new_block(ctx, line));\n *p_pivot_line = line;\n }\n\n /* In all other cases the line is just a continuation of the current block. */\n MD_CHECK(md_add_line_into_current_block(ctx, line));\n\nabort:\n return ret;\n}\n\nstatic int\nmd_process_doc(MD_CTX *ctx)\n{\n const MD_LINE_ANALYSIS* pivot_line = &md_dummy_blank_line;\n MD_LINE_ANALYSIS line_buf[2];\n MD_LINE_ANALYSIS* line = &line_buf[0];\n OFF off = 0;\n int ret = 0;\n\n MD_ENTER_BLOCK(MD_BLOCK_DOC, NULL);\n\n while(off < ctx->size) {\n if(line == pivot_line)\n line = (line == &line_buf[0] ? &line_buf[1] : &line_buf[0]);\n\n MD_CHECK(md_analyze_line(ctx, off, &off, pivot_line, line));\n MD_CHECK(md_process_line(ctx, &pivot_line, line));\n }\n\n md_end_current_block(ctx);\n\n MD_CHECK(md_build_ref_def_hashtable(ctx));\n\n /* Process all blocks. */\n MD_CHECK(md_leave_child_containers(ctx, 0));\n MD_CHECK(md_process_all_blocks(ctx));\n\n MD_LEAVE_BLOCK(MD_BLOCK_DOC, NULL);\n\nabort:\n\n#if 0\n /* Output some memory consumption statistics. */\n {\n char buffer[256];\n sprintf(buffer, \"Alloced %u bytes for block buffer.\",\n (unsigned)(ctx->alloc_block_bytes));\n MD_LOG(buffer);\n\n sprintf(buffer, \"Alloced %u bytes for containers buffer.\",\n (unsigned)(ctx->alloc_containers * sizeof(MD_CONTAINER)));\n MD_LOG(buffer);\n\n sprintf(buffer, \"Alloced %u bytes for marks buffer.\",\n (unsigned)(ctx->alloc_marks * sizeof(MD_MARK)));\n MD_LOG(buffer);\n\n sprintf(buffer, \"Alloced %u bytes for aux. buffer.\",\n (unsigned)(ctx->alloc_buffer * sizeof(MD_CHAR)));\n MD_LOG(buffer);\n }\n#endif\n\n return ret;\n}\n\n\n/********************\n *** Public API ***\n ********************/\n\nint\nmd_parse(const MD_CHAR* text, MD_SIZE size, const MD_PARSER* parser, void* userdata)\n{\n MD_CTX ctx;\n int i;\n int ret;\n\n if(parser->abi_version != 0) {\n if(parser->debug_log != NULL)\n parser->debug_log(\"Unsupported abi_version.\", userdata);\n return -1;\n }\n\n /* Setup context structure. */\n memset(&ctx, 0, sizeof(MD_CTX));\n ctx.text = text;\n ctx.size = size;\n memcpy(&ctx.parser, parser, sizeof(MD_PARSER));\n ctx.userdata = userdata;\n ctx.code_indent_offset = (ctx.parser.flags & MD_FLAG_NOINDENTEDCODEBLOCKS) ? (OFF)(-1) : 4;\n md_build_mark_char_map(&ctx);\n ctx.doc_ends_with_newline = (size > 0 && ISNEWLINE_(text[size-1]));\n\n /* Reset all unresolved opener mark chains. */\n for(i = 0; i < (int) SIZEOF_ARRAY(ctx.mark_chains); i++) {\n ctx.mark_chains[i].head = -1;\n ctx.mark_chains[i].tail = -1;\n }\n ctx.unresolved_link_head = -1;\n ctx.unresolved_link_tail = -1;\n\n /* All the work. */\n ret = md_process_doc(&ctx);\n\n /* Clean-up. */\n md_free_ref_defs(&ctx);\n md_free_ref_def_hashtable(&ctx);\n free(ctx.buffer);\n free(ctx.marks);\n free(ctx.block_bytes);\n free(ctx.containers);\n\n return ret;\n}\n"}}, "reports": [{"events": [{"location": {"col": 49, "file": 0, "line": 65}, "message": "() (fixit)"}, {"location": {"col": 49, "file": 0, "line": 65}, "message": "macro argument should be enclosed in parentheses"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "6aefa36282ee04c33064cc8e73e7b042", "checkerName": "misc-macro-parentheses", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 12, "file": 0, "line": 388}, "message": "() (fixit)"}, {"location": {"col": 12, "file": 0, "line": 388}, "message": "macro argument should be enclosed in parentheses"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "7dded65c1a63766afa9dc4d8c3202eff", "checkerName": "misc-macro-parentheses", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 12, "file": 0, "line": 443}, "message": "() (fixit)"}, {"location": {"col": 12, "file": 0, "line": 443}, "message": "macro argument should be enclosed in parentheses"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "372f7bd55a9bc219c174a128c7cd24d0", "checkerName": "misc-macro-parentheses", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 12, "file": 0, "line": 454}, "message": "() (fixit)"}, {"location": {"col": 12, "file": 0, "line": 454}, "message": "macro argument should be enclosed in parentheses"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "372f7bd55a9bc219c174a128c7cd24d0", "checkerName": "misc-macro-parentheses", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 73, "file": 0, "line": 889}, "message": "unused parameter 'n_lines'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "0282a05fde352de3bfb65cef3eb6e626", "checkerName": "clang-diagnostic-unused-parameter", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 35, "file": 0, "line": 1234}, "message": "unused parameter 'ctx'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "794c8f5613789592ba72609e09c3f222", "checkerName": "clang-diagnostic-unused-parameter", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 35, "file": 0, "line": 1250}, "message": "unused parameter 'ctx'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "ac6fe16d168387cabdd353c11906a1e8", "checkerName": "clang-diagnostic-unused-parameter", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 37, "file": 0, "line": 1266}, "message": "unused parameter 'ctx'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "c91f633ad1739e87b271f016f8fc3cac", "checkerName": "clang-diagnostic-unused-parameter", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 27, "file": 0, "line": 1372}, "message": "unused parameter 'ctx'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "31ffd2e3c8a8eeb104136e4ce166d03c", "checkerName": "clang-diagnostic-unused-parameter", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 35, "file": 0, "line": 1577}, "message": "{} (fixit)"}, {"location": {"col": 35, "file": 0, "line": 1577}, "message": "suggest braces around initialization of subobject"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "86c7f77e42a3a06c9b89ddee447ae5a7", "checkerName": "clang-diagnostic-missing-braces", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 35, "file": 0, "line": 1578}, "message": "{} (fixit)"}, {"location": {"col": 35, "file": 0, "line": 1578}, "message": "suggest braces around initialization of subobject"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "6eeecc2c3515409dfa61a8a016da9536", "checkerName": "clang-diagnostic-missing-braces", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 21, "file": 0, "line": 1587}, "message": "comparison of integers of different signs: 'MD_OFFSET' (aka 'unsigned int') and 'int'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "a8d8bc7efc2ff579f658ad7c79efb019", "checkerName": "clang-diagnostic-sign-compare", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 21, "file": 0, "line": 1592}, "message": "comparison of integers of different signs: 'MD_OFFSET' (aka 'unsigned int') and 'int'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "526776aaa2dd671261e7a63a152b4f15", "checkerName": "clang-diagnostic-sign-compare", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 46, "file": 0, "line": 3920}, "message": "unused parameter 'lines'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "c859a723c0aaec3e80f2bf3b16bed7d1", "checkerName": "clang-diagnostic-unused-parameter", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 57, "file": 0, "line": 3920}, "message": "unused parameter 'n_lines'"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "81b31bb7431573fe841f91b8a4e9baf9", "checkerName": "clang-diagnostic-unused-parameter", "reviewStatus": null, "severity": "MEDIUM"}, {"events": [{"location": {"col": 72, "file": 0, "line": 5661}, "message": "missing field 'beg' initializer"}], "macros": [], "notes": [], "path": "/home/qt/qtCode/qt5/qtbase/src/3rdparty/md4c/md4c.c", "reportHash": "6047bc9d8103cfa0ffecf492b10411c2", "checkerName": "clang-diagnostic-missing-field-initializers", "reviewStatus": null, "severity": "MEDIUM"}]}; window.onload = function() { if (!browserCompatible) { setNonCompatibleBrowserMessage(); } else { BugViewer.init(data.files, data.reports); BugViewer.create(); BugViewer.initByUrl(); } };
File:
Checker name:
Review status: