From e216094e2192c05ddbd0988458eb8c0012e7baf8 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 2 Sep 2014 01:10:54 +0200 Subject: lol --- src/blocks.c | 1352 ++++++++++++++++++++++++++++++---------------------------- 1 file changed, 691 insertions(+), 661 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 2776231..eabac03 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -10,738 +11,767 @@ static block* make_block(int tag, int start_line, int start_column) { - block* e; - e = (block*) malloc(sizeof(block)); - e->tag = tag; - e->open = true; - e->last_line_blank = false; - e->start_line = start_line; - e->start_column = start_column; - e->end_line = start_line; - e->children = NULL; - e->last_child = NULL; - e->parent = NULL; - e->top = NULL; - e->attributes.refmap = NULL; - e->string_content = bfromcstr(""); - e->inline_content = NULL; - e->next = NULL; - e->prev = NULL; - return e; + block* e; + e = (block*) malloc(sizeof(block)); + e->tag = tag; + e->open = true; + e->last_line_blank = false; + e->start_line = start_line; + e->start_column = start_column; + e->end_line = start_line; + e->children = NULL; + e->last_child = NULL; + e->parent = NULL; + e->top = NULL; + e->attributes.refmap = NULL; + gh_buf_init(&e->string_content, 32); + e->string_pos = 0; + e->inline_content = NULL; + e->next = NULL; + e->prev = NULL; + return e; } // Create a root document block. extern block* make_document() { - block * e = make_block(document, 1, 1); - reference * map = NULL; - reference ** refmap; - refmap = (reference**) malloc(sizeof(reference*)); - *refmap = map; - e->attributes.refmap = refmap; - e->top = e; - return e; + block * e = make_block(document, 1, 1); + reference * map = NULL; + reference ** refmap; + refmap = (reference**) malloc(sizeof(reference*)); + *refmap = map; + e->attributes.refmap = refmap; + e->top = e; + return e; } // Returns true if line has only space characters, else false. -bool is_blank(bstring s, int offset) +bool is_blank(gh_buf *s, int offset) { - char c; - while ((c = bchar(s, offset))) { - if (c == '\n') { - return true; - } else if (c == ' ') { - offset++; - } else { - return false; - } - } - return true; + while (offset < s->size) { + switch (s->ptr[offset]) { + case '\n': + return true; + case ' ': + offset++; + default: + return false; + } + } + + return true; } static inline bool can_contain(int parent_type, int child_type) { - return ( parent_type == document || - parent_type == block_quote || - parent_type == list_item || - (parent_type == list && child_type == list_item) ); + return ( parent_type == document || + parent_type == block_quote || + parent_type == list_item || + (parent_type == list && child_type == list_item) ); } static inline bool accepts_lines(int block_type) { - return (block_type == paragraph || - block_type == atx_header || - block_type == indented_code || - block_type == fenced_code); + return (block_type == paragraph || + block_type == atx_header || + block_type == indented_code || + block_type == fenced_code); } -static int add_line(block* block, bstring ln, int offset) +static void add_line(block* block, gh_buf *ln, int offset) { - bstring s = bmidstr(ln, offset, blength(ln) - offset); - check(block->open, "attempted to add line (%s) to closed container (%d)", - ln->data, block->tag); - check(bformata(block->string_content, "%s", s->data) == 0, - "could not append line to string_content"); - bdestroy(s); - return 0; - error: - return -1; + assert(block->open); + gh_buf_put(&block->string_content, ln->ptr + offset, ln->size - offset); } -static int remove_trailing_blank_lines(bstring ln) +static void remove_trailing_blank_lines(gh_buf *ln) { - bstring tofind = bfromcstr(" \t\r\n"); - int pos; - // find last nonspace: - pos = bninchrr(ln, blength(ln) - 1, tofind); - if (pos == BSTR_ERR) { // all spaces - bassigncstr(ln, ""); - } else { - // find next newline after it - pos = bstrchrp(ln, '\n', pos); - if (pos != BSTR_ERR) { - check(bdelete(ln, pos, blength(ln) - pos) != BSTR_ERR, - "failed to delete trailing blank lines"); - } - } - bdestroy(tofind); - return 0; - error: - return -1; + int i; + + for (i = ln->size - 1; i >= 0; --i) { + char c = ln->ptr[i]; + + if (c != ' ' && c != '\t' && c != '\r' && c != '\n') + break; + } + + if (i < 0) { + gh_buf_clear(ln); + return; + } + + i = gh_buf_strchr(ln, '\n', i); + if (i >= 0) + gh_buf_truncate(ln, i + 1); } // Check to see if a block ends with a blank line, descending // if needed into lists and sublists. static bool ends_with_blank_line(block* block) { - if (block->last_line_blank) { - return true; - } - if ((block->tag == list || block->tag == list_item) && block->last_child) { - return ends_with_blank_line(block->last_child); - } else { - return false; - } + if (block->last_line_blank) { + return true; + } + if ((block->tag == list || block->tag == list_item) && block->last_child) { + return ends_with_blank_line(block->last_child); + } else { + return false; + } } // Break out of all containing lists static int break_out_of_lists(block ** bptr, int line_number) { - block * container = *bptr; - block * b = container->top; - // find first containing list: - while (b && b->tag != list) { - b = b->last_child; - } - if (b) { - while (container && container != b) { - finalize(container, line_number); - container = container->parent; - } - finalize(b, line_number); - *bptr = b->parent; - } - return 0; + block * container = *bptr; + block * b = container->top; + // find first containing list: + while (b && b->tag != list) { + b = b->last_child; + } + if (b) { + while (container && container != b) { + finalize(container, line_number); + container = container->parent; + } + finalize(b, line_number); + *bptr = b->parent; + } + return 0; } -extern int finalize(block* b, int line_number) +extern void finalize(block* b, int line_number) { - int firstlinelen; - int pos; - block* item; - block* subitem; - - check(b != NULL, "finalize called on null block"); - if (!b->open) { - return 0; // don't do anything if the block is already closed - } - b->open = false; - if (line_number > b->start_line) { - b->end_line = line_number - 1; - } else { - b->end_line = line_number; - } - - switch (b->tag) { - - case paragraph: - pos = 0; - while (bchar(b->string_content, 0) == '[' && - (pos = parse_reference(b->string_content, - b->top->attributes.refmap))) { - bdelete(b->string_content, 0, pos); - } - if (is_blank(b->string_content, 0)) { - b->tag = reference_def; - } - break; - - case indented_code: - remove_trailing_blank_lines(b->string_content); - bformata(b->string_content, "\n"); - break; - - case fenced_code: - // first line of contents becomes info - firstlinelen = bstrchr(b->string_content, '\n'); - b->attributes.fenced_code_data.info = - bmidstr(b->string_content, 0, firstlinelen); - bdelete(b->string_content, 0, firstlinelen + 1); // +1 for \n - btrimws(b->attributes.fenced_code_data.info); - unescape(b->attributes.fenced_code_data.info); - break; - - case list: // determine tight/loose status - b->attributes.list_data.tight = true; // tight by default - item = b->children; - - while (item) { - // check for non-final non-empty list item ending with blank line: - if (item->last_line_blank && item->next) { - b->attributes.list_data.tight = false; - break; - } - // recurse into children of list item, to see if there are - // spaces between them: - subitem = item->children; - while (subitem) { - if (ends_with_blank_line(subitem) && - (item->next || subitem->next)) { - b->attributes.list_data.tight = false; - break; - } - subitem = subitem->next; - } - if (!(b->attributes.list_data.tight)) { - break; - } - item = item->next; - } - - break; - - default: - break; - } - - return 0; - error: - return -1; + int firstlinelen; + int pos; + block* item; + block* subitem; + + if (!b->open) + return; // don't do anything if the block is already closed + + b->open = false; + if (line_number > b->start_line) { + b->end_line = line_number - 1; + } else { + b->end_line = line_number; + } + + switch (b->tag) { + case paragraph: + pos = 0; + while (gh_buf_at(&b->string_content, b->string_pos) == '[' && + (pos = parse_reference(&b->string_content, b->string_pos, + b->top->attributes.refmap))) { + b->string_pos = pos; + } + if (is_blank(&b->string_content, b->string_pos)) { + b->tag = reference_def; + } + break; + + case indented_code: + remove_trailing_blank_lines(&b->string_content); + gh_buf_putc(&b->string_content, '\n'); + break; + + case fenced_code: + // first line of contents becomes info + firstlinelen = gh_buf_strchr(&b->string_content, '\n', b->string_pos); + gh_buf_set( + &b->attributes.fenced_code_data.info, + b->string_content.ptr + b->string_pos, + firstlinelen + ); + + b->string_pos = firstlinelen + 1; + + gh_buf_trim(&b->attributes.fenced_code_data.info); + unescape_buffer(&b->attributes.fenced_code_data.info); + break; + + case list: // determine tight/loose status + b->attributes.list_data.tight = true; // tight by default + item = b->children; + + while (item) { + // check for non-final non-empty list item ending with blank line: + if (item->last_line_blank && item->next) { + b->attributes.list_data.tight = false; + break; + } + // recurse into children of list item, to see if there are + // spaces between them: + subitem = item->children; + while (subitem) { + if (ends_with_blank_line(subitem) && + (item->next || subitem->next)) { + b->attributes.list_data.tight = false; + break; + } + subitem = subitem->next; + } + if (!(b->attributes.list_data.tight)) { + break; + } + item = item->next; + } + + break; + + default: + break; + } } // Add a block as child of another. Return pointer to child. extern block* add_child(block* parent, - int block_type, int start_line, int start_column) + int block_type, int start_line, int start_column) { - // if 'parent' isn't the kind of block that can accept this child, - // then back up til we hit a block that can. - while (!can_contain(parent->tag, block_type)) { - finalize(parent, start_line); - parent = parent->parent; - } - - check(parent != NULL, "parent container cannot accept children"); - - block* child = make_block(block_type, start_line, start_column); - child->parent = parent; - child->top = parent->top; - - if (parent->last_child) { - parent->last_child->next = child; - child->prev = parent->last_child; - } else { - parent->children = child; - child->prev = NULL; - } - parent->last_child = child; - return child; - error: - return NULL; + assert(parent); + + // if 'parent' isn't the kind of block that can accept this child, + // then back up til we hit a block that can. + while (!can_contain(parent->tag, block_type)) { + finalize(parent, start_line); + parent = parent->parent; + } + + block* child = make_block(block_type, start_line, start_column); + child->parent = parent; + child->top = parent->top; + + if (parent->last_child) { + parent->last_child->next = child; + child->prev = parent->last_child; + } else { + parent->children = child; + child->prev = NULL; + } + parent->last_child = child; + return child; } // Free a block list and any children. extern void free_blocks(block* e) { - block * next; - while (e != NULL) { - next = e->next; - free_inlines(e->inline_content); - bdestroy(e->string_content); - if (e->tag == fenced_code) { - bdestroy(e->attributes.fenced_code_data.info); - } else if (e->tag == document) { - free_reference_map(e->attributes.refmap); - } - free_blocks(e->children); - free(e); - e = next; - } + block * next; + while (e != NULL) { + next = e->next; + free_inlines(e->inline_content); + gh_buf_free(&e->string_content); + if (e->tag == fenced_code) { + gh_buf_free(&e->attributes.fenced_code_data.info); + } else if (e->tag == document) { + free_reference_map(e->attributes.refmap); + } + free_blocks(e->children); + free(e); + e = next; + } } // Walk through block and all children, recursively, parsing // string content into inline content where appropriate. -int process_inlines(block* cur, reference** refmap) +void process_inlines(block* cur, reference** refmap) { - switch (cur->tag) { - - case paragraph: - case atx_header: - case setext_header: - check(cur->string_content != NULL, "string_content is NULL"); - cur->inline_content = parse_inlines(cur->string_content, refmap); - bdestroy(cur->string_content); - cur->string_content = NULL; - break; - - default: - break; - } - - block * child = cur->children; - while (child != NULL) { - process_inlines(child, refmap); - child = child->next; - } - - return 0; - error: - return -1; + switch (cur->tag) { + case paragraph: + case atx_header: + case setext_header: + cur->inline_content = parse_inlines(&cur->string_content, cur->string_pos, refmap); + // MEM + // gh_buf_free(&cur->string_content); + break; + + default: + break; + } + + block *child = cur->children; + while (child != NULL) { + process_inlines(child, refmap); + child = child->next; + } } // Attempts to parse a list item marker (bullet or enumerated). // On success, returns length of the marker, and populates // data with the details. On failure, returns 0. -static int parse_list_marker(bstring ln, int pos, - struct ListData ** dataptr) +static int parse_list_marker(gh_buf *ln, int pos, + struct ListData ** dataptr) { - char c; - int startpos; - int start = 1; - struct ListData * data; - - startpos = pos; - c = bchar(ln, pos); - - if ((c == '*' || c == '-' || c == '+') && !scan_hrule(ln, pos)) { - pos++; - if (!isspace(bchar(ln, pos))) { - return 0; - } - data = malloc(sizeof(struct ListData)); - data->marker_offset = 0; // will be adjusted later - data->list_type = bullet; - data->bullet_char = c; - data->start = 1; - data->delimiter = period; - data->tight = false; - - } else if (isdigit(c)) { - - pos++; - while (isdigit(bchar(ln, pos))) { - pos++; - } - - if (!sscanf((char *) ln->data + startpos, "%d", &start)) { - log_err("sscanf failed"); - return 0; - } - - c = bchar(ln, pos); - if (c == '.' || c == ')') { - pos++; - if (!isspace(bchar(ln, pos))) { - return 0; - } - data = malloc(sizeof(struct ListData)); - data->marker_offset = 0; // will be adjusted later - data->list_type = ordered; - data->bullet_char = 0; - data->start = start; - data->delimiter = (c == '.' ? period : parens); - data->tight = false; - } else { - return 0; - } - - } else { - return 0; - } - - *dataptr = data; - return (pos - startpos); + char c; + int startpos; + struct ListData * data; + + startpos = pos; + c = gh_buf_at(ln, pos); + + if ((c == '*' || c == '-' || c == '+') && !scan_hrule(ln, pos)) { + pos++; + if (!isspace(gh_buf_at(ln, pos))) { + return 0; + } + data = malloc(sizeof(struct ListData)); + data->marker_offset = 0; // will be adjusted later + data->list_type = bullet; + data->bullet_char = c; + data->start = 1; + data->delimiter = period; + data->tight = false; + + } else if (isdigit(c)) { + int start = 0; + + do { + start = (10 * start) + (gh_buf_at(ln, pos) - '0'); + pos++; + } while (isdigit(gh_buf_at(ln, pos))); + + c = gh_buf_at(ln, pos); + if (c == '.' || c == ')') { + pos++; + if (!isspace(gh_buf_at(ln, pos))) { + return 0; + } + data = malloc(sizeof(struct ListData)); + data->marker_offset = 0; // will be adjusted later + data->list_type = ordered; + data->bullet_char = 0; + data->start = start; + data->delimiter = (c == '.' ? period : parens); + data->tight = false; + } else { + return 0; + } + + } else { + return 0; + } + + *dataptr = data; + return (pos - startpos); } // Return 1 if list item belongs in list, else 0. static int lists_match(struct ListData list_data, - struct ListData item_data) + struct ListData item_data) +{ + return (list_data.list_type == item_data.list_type && + list_data.delimiter == item_data.delimiter && + // list_data.marker_offset == item_data.marker_offset && + list_data.bullet_char == item_data.bullet_char); +} + +static void expand_tabs(gh_buf *ob, const char *line, size_t size) +{ + size_t i = 0, tab = 0; + + while (i < size) { + size_t org = i; + + while (i < size && line[i] != '\t') { + i++; tab++; + } + + if (i > org) + gh_buf_put(ob, line + org, i - org); + + if (i >= size) + break; + + do { + gh_buf_putc(ob, ' '); tab++; + } while (tab % 4); + + i++; + } +} + +extern block *stmd_parse_document(const char *buffer, size_t len) { - return (list_data.list_type == item_data.list_type && - list_data.delimiter == item_data.delimiter && - // list_data.marker_offset == item_data.marker_offset && - list_data.bullet_char == item_data.bullet_char); + gh_buf line = GH_BUF_INIT; + + block *document = make_document(); + int linenum = 1; + const char *end = buffer + len; + + while (buffer < end) { + const char *eol = memchr(buffer, '\n', end - buffer); + + if (!eol) { + expand_tabs(&line, buffer, end - buffer); + buffer = end; + } else { + expand_tabs(&line, buffer, (eol - buffer) + 1); + buffer += (eol - buffer) + 1; + } + + incorporate_line(&line, linenum, &document); + gh_buf_clear(&line); + linenum++; + } + + gh_buf_free(&line); + + while (document != document->top) { + finalize(document, linenum); + document = document->parent; + } + + finalize(document, linenum); + process_inlines(document, document->attributes.refmap); + + return document; } // Process one line at a time, modifying a block. // Returns 0 if successful. curptr is changed to point to // the currently open block. -extern int incorporate_line(bstring ln, int line_number, block** curptr) +extern void incorporate_line(gh_buf *ln, int line_number, block** curptr) { - block* last_matched_container; - int offset = 0; - int matched = 0; - int lev = 0; - int i; - struct ListData * data = NULL; - bool all_matched = true; - block* container; - block* cur = *curptr; - bool blank = false; - int first_nonspace; - int indent; - - // detab input line - check(bdetab(ln, 1) != BSTR_ERR, - "invalid UTF-8 sequence in line %d\n", line_number); - - // container starts at the document root. - container = cur->top; - - // for each containing block, try to parse the associated line start. - // bail out on failure: container will point to the last matching block. - - while (container->last_child && container->last_child->open) { - container = container->last_child; - - first_nonspace = offset; - while (bchar(ln, first_nonspace) == ' ') { - first_nonspace++; - } - - indent = first_nonspace - offset; - blank = bchar(ln, first_nonspace) == '\n'; - - if (container->tag == block_quote) { - - matched = indent <= 3 && bchar(ln, first_nonspace) == '>'; - if (matched) { - offset = first_nonspace + 1; - if (bchar(ln, offset) == ' ') { - offset++; - } - } else { - all_matched = false; - } - - } else if (container->tag == list_item) { - - if (indent >= container->attributes.list_data.marker_offset + - container->attributes.list_data.padding) { - offset += container->attributes.list_data.marker_offset + - container->attributes.list_data.padding; - } else if (blank) { - offset = first_nonspace; - } else { - all_matched = false; - } - - } else if (container->tag == indented_code) { - - if (indent >= CODE_INDENT) { - offset += CODE_INDENT; - } else if (blank) { - offset = first_nonspace; - } else { - all_matched = false; - } - - } else if (container->tag == atx_header || - container->tag == setext_header) { - - // a header can never contain more than one line - all_matched = false; - - } else if (container->tag == fenced_code) { - - // skip optional spaces of fence offset - i = container->attributes.fenced_code_data.fence_offset; - while (i > 0 && bchar(ln, offset) == ' ') { - offset++; - i--; - } - - } else if (container->tag == html_block) { - - if (blank) { - all_matched = false; - } - - } else if (container->tag == paragraph) { - - if (blank) { - container->last_line_blank =true; - all_matched = false; - } - - } - - if (!all_matched) { - container = container->parent; // back up to last matching block - break; - } - } - - last_matched_container = container; - - // check to see if we've hit 2nd blank line, break out of list: - if (blank && container->last_line_blank) { - break_out_of_lists(&container, line_number); - } - - // unless last matched container is code block, try new container starts: - while (container->tag != fenced_code && container->tag != indented_code && - container->tag != html_block) { - - first_nonspace = offset; - while (bchar(ln, first_nonspace) == ' ') { - first_nonspace++; - } - - indent = first_nonspace - offset; - blank = bchar(ln, first_nonspace) == '\n'; - - if (indent >= CODE_INDENT) { - - if (cur->tag != paragraph && !blank) { - offset += CODE_INDENT; - container = add_child(container, indented_code, line_number, offset + 1); - } else { // indent > 4 in lazy line - break; - } - - } else if (bchar(ln, first_nonspace) == '>') { - - offset = first_nonspace + 1; - // optional following character - if (bchar(ln, offset) == ' ') { - offset++; - } - container = add_child(container, block_quote, line_number, offset + 1); - - } else if ((matched = scan_atx_header_start(ln, first_nonspace))) { - - offset = first_nonspace + matched; - container = add_child(container, atx_header, line_number, offset + 1); - int hashpos = bstrchrp(ln, '#', first_nonspace); - check(hashpos != BSTR_ERR, "no # found in atx header start"); - int level = 0; - while (bchar(ln, hashpos) == '#') { - level++; - hashpos++; - } - container->attributes.header_level = level; - - } else if ((matched = scan_open_code_fence(ln, first_nonspace))) { - - container = add_child(container, fenced_code, line_number, - first_nonspace + 1); - container->attributes.fenced_code_data.fence_char = bchar(ln, - first_nonspace); - container->attributes.fenced_code_data.fence_length = matched; - container->attributes.fenced_code_data.fence_offset = - first_nonspace - offset; - offset = first_nonspace + matched; - - } else if ((matched = scan_html_block_tag(ln, first_nonspace))) { - - container = add_child(container, html_block, line_number, - first_nonspace + 1); - // note, we don't adjust offset because the tag is part of the text - - } else if (container->tag == paragraph && - (lev = scan_setext_header_line(ln, first_nonspace)) && - // check that there is only one line in the paragraph: - bstrrchrp(container->string_content, '\n', - blength(container->string_content) - 2) == BSTR_ERR) { - - container->tag = setext_header; - container->attributes.header_level = lev; - offset = blength(ln) - 1; - - } else if (!(container->tag == paragraph && !all_matched) && - (matched = scan_hrule(ln, first_nonspace))) { - - // it's only now that we know the line is not part of a setext header: - container = add_child(container, hrule, line_number, first_nonspace + 1); - finalize(container, line_number); - container = container->parent; - offset = blength(ln) - 1; - - } else if ((matched = parse_list_marker(ln, first_nonspace, &data))) { - - // compute padding: - offset = first_nonspace + matched; - i = 0; - while (i <= 5 && bchar(ln, offset + i) == ' ') { - i++; - } - // i = number of spaces after marker, up to 5 - if (i >= 5 || i < 1 || bchar(ln, offset) == '\n') { - data->padding = matched + 1; - if (i > 0) { - offset += 1; - } - } else { - data->padding = matched + i; - offset += i; - } - - // check container; if it's a list, see if this list item - // can continue the list; otherwise, create a list container. - - data->marker_offset = indent; - - if (container->tag != list || - !lists_match(container->attributes.list_data, *data)) { - container = add_child(container, list, line_number, - first_nonspace + 1); - container->attributes.list_data = *data; - } - - // add the list item - container = add_child(container, list_item, line_number, - first_nonspace + 1); - container->attributes.list_data = *data; - free(data); - - } else { - break; - } - - if (accepts_lines(container->tag)) { - // if it's a line container, it can't contain other containers - break; - } - } - - // what remains at offset is a text line. add the text to the - // appropriate container. - - first_nonspace = offset; - while (bchar(ln, first_nonspace) == ' ') { - first_nonspace++; - } - - indent = first_nonspace - offset; - blank = bchar(ln, first_nonspace) == '\n'; - - // block quote lines are never blank as they start with > - // and we don't count blanks in fenced code for purposes of tight/loose - // lists or breaking out of lists. we also don't set last_line_blank - // on an empty list item. - container->last_line_blank = (blank && - container->tag != block_quote && - container->tag != fenced_code && - !(container->tag == list_item && - container->children == NULL && - container->start_line == line_number)); - - block *cont = container; - while (cont->parent) { - cont->parent->last_line_blank = false; - cont = cont->parent; - } - - if (cur != last_matched_container && - container == last_matched_container && - !blank && - cur->tag == paragraph && - blength(cur->string_content) > 0) { - - check(add_line(cur, ln, offset) == 0, "could not add line"); - - } else { // not a lazy continuation - - // finalize any blocks that were not matched and set cur to container: - while (cur != last_matched_container) { - - finalize(cur, line_number); - cur = cur->parent; - check(cur != NULL, "cur is NULL, last_matched_container->tag = %d", - last_matched_container->tag); - - } - - if (container->tag == indented_code) { - - check(add_line(container, ln, offset) == 0, "could not add line"); - - } else if (container->tag == fenced_code) { - - matched = (indent <= 3 - && bchar(ln, first_nonspace) == container->attributes.fenced_code_data.fence_char) - && scan_close_code_fence(ln, first_nonspace, - container->attributes.fenced_code_data.fence_length); - if (matched) { - // if closing fence, don't add line to container; instead, close it: - finalize(container, line_number); - container = container->parent; // back up to parent - } else { - check(add_line(container, ln, offset) == 0, "could not add line"); - } - - } else if (container->tag == html_block) { - - check(add_line(container, ln, offset) == 0, "could not add line"); - - } else if (blank) { - - // ??? do nothing - - } else if (container->tag == atx_header) { - - // chop off trailing ###s...use a scanner? - brtrimws(ln); - int p = blength(ln) - 1; - int numhashes = 0; - // if string ends in #s, remove these: - while (bchar(ln, p) == '#') { - p--; - numhashes++; - } - if (bchar(ln, p) == '\\') { - // the last # was escaped, so we include it. - p++; - numhashes--; - } - check(bdelete(ln, p + 1, numhashes) != BSTR_ERR, - "could not delete final hashes"); - check(add_line(container, ln, first_nonspace) == 0, "could not add line"); - finalize(container, line_number); - container = container->parent; - - } else if (accepts_lines(container->tag)) { - - check(add_line(container, ln, first_nonspace) == 0, "could not add line"); + block* last_matched_container; + int offset = 0; + int matched = 0; + int lev = 0; + int i; + struct ListData * data = NULL; + bool all_matched = true; + block* container; + block* cur = *curptr; + bool blank = false; + int first_nonspace; + int indent; + + // container starts at the document root. + container = cur->top; + + // for each containing block, try to parse the associated line start. + // bail out on failure: container will point to the last matching block. + + while (container->last_child && container->last_child->open) { + container = container->last_child; + + first_nonspace = offset; + while (gh_buf_at(ln, first_nonspace) == ' ') { + first_nonspace++; + } + + indent = first_nonspace - offset; + blank = gh_buf_at(ln, first_nonspace) == '\n'; + + if (container->tag == block_quote) { + + matched = indent <= 3 && gh_buf_at(ln, first_nonspace) == '>'; + if (matched) { + offset = first_nonspace + 1; + if (gh_buf_at(ln, offset) == ' ') { + offset++; + } + } else { + all_matched = false; + } + + } else if (container->tag == list_item) { + + if (indent >= container->attributes.list_data.marker_offset + + container->attributes.list_data.padding) { + offset += container->attributes.list_data.marker_offset + + container->attributes.list_data.padding; + } else if (blank) { + offset = first_nonspace; + } else { + all_matched = false; + } + + } else if (container->tag == indented_code) { + + if (indent >= CODE_INDENT) { + offset += CODE_INDENT; + } else if (blank) { + offset = first_nonspace; + } else { + all_matched = false; + } + + } else if (container->tag == atx_header || + container->tag == setext_header) { + + // a header can never contain more than one line + all_matched = false; + + } else if (container->tag == fenced_code) { + + // skip optional spaces of fence offset + i = container->attributes.fenced_code_data.fence_offset; + while (i > 0 && gh_buf_at(ln, offset) == ' ') { + offset++; + i--; + } + + } else if (container->tag == html_block) { + + if (blank) { + all_matched = false; + } + + } else if (container->tag == paragraph) { + + if (blank) { + container->last_line_blank = true; + all_matched = false; + } + + } + + if (!all_matched) { + container = container->parent; // back up to last matching block + break; + } + } + + last_matched_container = container; + + // check to see if we've hit 2nd blank line, break out of list: + if (blank && container->last_line_blank) { + break_out_of_lists(&container, line_number); + } + + // unless last matched container is code block, try new container starts: + while (container->tag != fenced_code && container->tag != indented_code && + container->tag != html_block) { + + first_nonspace = offset; + while (gh_buf_at(ln, first_nonspace) == ' ') { + first_nonspace++; + } + + indent = first_nonspace - offset; + blank = gh_buf_at(ln, first_nonspace) == '\n'; + + if (indent >= CODE_INDENT) { + + if (cur->tag != paragraph && !blank) { + offset += CODE_INDENT; + container = add_child(container, indented_code, line_number, offset + 1); + } else { // indent > 4 in lazy line + break; + } + + } else if (gh_buf_at(ln, first_nonspace) == '>') { + + offset = first_nonspace + 1; + // optional following character + if (gh_buf_at(ln, offset) == ' ') { + offset++; + } + container = add_child(container, block_quote, line_number, offset + 1); + + } else if ((matched = scan_atx_header_start(ln, first_nonspace))) { + + offset = first_nonspace + matched; + container = add_child(container, atx_header, line_number, offset + 1); + + int hashpos = gh_buf_strchr(ln, '#', first_nonspace); + assert(hashpos >= 0); + + int level = 0; + while (gh_buf_at(ln, hashpos) == '#') { + level++; + hashpos++; + } + container->attributes.header_level = level; + + } else if ((matched = scan_open_code_fence(ln, first_nonspace))) { + + container = add_child(container, fenced_code, line_number, + first_nonspace + 1); + container->attributes.fenced_code_data.fence_char = gh_buf_at(ln, + first_nonspace); + container->attributes.fenced_code_data.fence_length = matched; + container->attributes.fenced_code_data.fence_offset = + first_nonspace - offset; + offset = first_nonspace + matched; + + } else if ((matched = scan_html_block_tag(ln, first_nonspace))) { + + container = add_child(container, html_block, line_number, + first_nonspace + 1); + // note, we don't adjust offset because the tag is part of the text + + } else if (container->tag == paragraph && + (lev = scan_setext_header_line(ln, first_nonspace)) && + // check that there is only one line in the paragraph: + gh_buf_strrchr(&container->string_content, '\n', + gh_buf_len(&container->string_content) - 2) < 0) { + + container->tag = setext_header; + container->attributes.header_level = lev; + offset = gh_buf_len(ln) - 1; + + } else if (!(container->tag == paragraph && !all_matched) && + (matched = scan_hrule(ln, first_nonspace))) { + + // it's only now that we know the line is not part of a setext header: + container = add_child(container, hrule, line_number, first_nonspace + 1); + finalize(container, line_number); + container = container->parent; + offset = gh_buf_len(ln) - 1; + + } else if ((matched = parse_list_marker(ln, first_nonspace, &data))) { + + // compute padding: + offset = first_nonspace + matched; + i = 0; + while (i <= 5 && gh_buf_at(ln, offset + i) == ' ') { + i++; + } + // i = number of spaces after marker, up to 5 + if (i >= 5 || i < 1 || gh_buf_at(ln, offset) == '\n') { + data->padding = matched + 1; + if (i > 0) { + offset += 1; + } + } else { + data->padding = matched + i; + offset += i; + } + + // check container; if it's a list, see if this list item + // can continue the list; otherwise, create a list container. + + data->marker_offset = indent; + + if (container->tag != list || + !lists_match(container->attributes.list_data, *data)) { + container = add_child(container, list, line_number, + first_nonspace + 1); + container->attributes.list_data = *data; + } + + // add the list item + container = add_child(container, list_item, line_number, + first_nonspace + 1); + container->attributes.list_data = *data; + free(data); + + } else { + break; + } + + if (accepts_lines(container->tag)) { + // if it's a line container, it can't contain other containers + break; + } + } + + // what remains at offset is a text line. add the text to the + // appropriate container. + + first_nonspace = offset; + while (gh_buf_at(ln, first_nonspace) == ' ') { + first_nonspace++; + } + + indent = first_nonspace - offset; + blank = gh_buf_at(ln, first_nonspace) == '\n'; + + // block quote lines are never blank as they start with > + // and we don't count blanks in fenced code for purposes of tight/loose + // lists or breaking out of lists. we also don't set last_line_blank + // on an empty list item. + container->last_line_blank = (blank && + container->tag != block_quote && + container->tag != fenced_code && + !(container->tag == list_item && + container->children == NULL && + container->start_line == line_number)); + + block *cont = container; + while (cont->parent) { + cont->parent->last_line_blank = false; + cont = cont->parent; + } + + if (cur != last_matched_container && + container == last_matched_container && + !blank && + cur->tag == paragraph && + gh_buf_len(&cur->string_content) > 0) { + + add_line(cur, ln, offset); + + } else { // not a lazy continuation + + // finalize any blocks that were not matched and set cur to container: + while (cur != last_matched_container) { + + finalize(cur, line_number); + cur = cur->parent; + assert(cur != NULL); + } + + if (container->tag == indented_code) { + + add_line(container, ln, offset); + + } else if (container->tag == fenced_code) { + + matched = (indent <= 3 + && gh_buf_at(ln, first_nonspace) == container->attributes.fenced_code_data.fence_char) + && scan_close_code_fence(ln, first_nonspace, + container->attributes.fenced_code_data.fence_length); + if (matched) { + // if closing fence, don't add line to container; instead, close it: + finalize(container, line_number); + container = container->parent; // back up to parent + } else { + add_line(container, ln, offset); + } + + } else if (container->tag == html_block) { + + add_line(container, ln, offset); + + } else if (blank) { + + // ??? do nothing + + } else if (container->tag == atx_header) { + // chop off trailing ###s...use a scanner? + gh_buf_trim(ln); + int p = gh_buf_len(ln) - 1; + + // if string ends in #s, remove these: + while (gh_buf_at(ln, p) == '#') { + p--; + } + if (gh_buf_at(ln, p) == '\\') { + // the last # was escaped, so we include it. + p++; + } + + gh_buf_truncate(ln, p + 1); + add_line(container, ln, first_nonspace); + finalize(container, line_number); + container = container->parent; + + } else if (accepts_lines(container->tag)) { + + add_line(container, ln, first_nonspace); + + } else if (container->tag != hrule && container->tag != setext_header) { + + // create paragraph container for line + container = add_child(container, paragraph, line_number, first_nonspace + 1); + add_line(container, ln, first_nonspace); - } else if (container->tag != hrule && container->tag != setext_header) { - - // create paragraph container for line - container = add_child(container, paragraph, line_number, first_nonspace + 1); - check(add_line(container, ln, first_nonspace) == 0, "could not add line"); - - } else { + } else { + assert(false); + } - log_warn("Line %d with container type %d did not match any condition:\n\"%s\"", - line_number, container->tag, ln->data); - - } - *curptr = container; - } - - return 0; - error: - return -1; + *curptr = container; + } } -- cgit v1.2.3 From 582674e662d1f8757350c51486a5e0a837195e15 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 2 Sep 2014 13:18:04 +0200 Subject: ffffix --- src/blocks.c | 58 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index eabac03..71dc830 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -3,11 +3,12 @@ #include #include #include -#include "bstrlib.h" + #include "stmd.h" -#include "uthash.h" -#include "debug.h" #include "scanners.h" +#include "uthash.h" + +static void finalize(block* b, int line_number); static block* make_block(int tag, int start_line, int start_column) { @@ -140,7 +141,7 @@ static int break_out_of_lists(block ** bptr, int line_number) } -extern void finalize(block* b, int line_number) +static void finalize(block* b, int line_number) { int firstlinelen; int pos; @@ -364,7 +365,7 @@ static int lists_match(struct ListData list_data, list_data.bullet_char == item_data.bullet_char); } -static void expand_tabs(gh_buf *ob, const char *line, size_t size) +static void expand_tabs(gh_buf *ob, const unsigned char *line, size_t size) { size_t i = 0, tab = 0; @@ -389,13 +390,43 @@ static void expand_tabs(gh_buf *ob, const char *line, size_t size) } } -extern block *stmd_parse_document(const char *buffer, size_t len) +static block *finalize_parsing(block *document, int linenum) { - gh_buf line = GH_BUF_INIT; + while (document != document->top) { + finalize(document, linenum); + document = document->parent; + } + + finalize(document, linenum); + process_inlines(document, document->attributes.refmap); + + return document; +} +extern block *stmd_parse_file(FILE *f) +{ + gh_buf line = GH_BUF_INIT; + unsigned char buffer[4096]; + int linenum = 1; block *document = make_document(); + + while (fgets((char *)buffer, sizeof(buffer), f)) { + expand_tabs(&line, buffer, strlen(buffer)); + incorporate_line(&line, linenum, &document); + gh_buf_clear(&line); + linenum++; + } + + gh_buf_free(&line); + return finalize_document(document, linenum); +} + +extern block *stmd_parse_document(const unsigned char *buffer, size_t len) +{ + gh_buf line = GH_BUF_INIT; int linenum = 1; - const char *end = buffer + len; + const unsigned char *end = buffer + len; + block *document = make_document(); while (buffer < end) { const char *eol = memchr(buffer, '\n', end - buffer); @@ -414,16 +445,7 @@ extern block *stmd_parse_document(const char *buffer, size_t len) } gh_buf_free(&line); - - while (document != document->top) { - finalize(document, linenum); - document = document->parent; - } - - finalize(document, linenum); - process_inlines(document, document->attributes.refmap); - - return document; + return finalize_document(document, linenum); } // Process one line at a time, modifying a block. -- cgit v1.2.3 From c28af79329264a7cf331a1b1c414919e4ed9e9f9 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Tue, 2 Sep 2014 13:37:34 +0200 Subject: It buiiiilds --- src/blocks.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 71dc830..42f20db 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -8,6 +8,7 @@ #include "scanners.h" #include "uthash.h" +static void incorporate_line(gh_buf *ln, int line_number, block** curptr); static void finalize(block* b, int line_number); static block* make_block(int tag, int start_line, int start_column) @@ -390,7 +391,7 @@ static void expand_tabs(gh_buf *ob, const unsigned char *line, size_t size) } } -static block *finalize_parsing(block *document, int linenum) +static block *finalize_document(block *document, int linenum) { while (document != document->top) { finalize(document, linenum); @@ -411,7 +412,7 @@ extern block *stmd_parse_file(FILE *f) block *document = make_document(); while (fgets((char *)buffer, sizeof(buffer), f)) { - expand_tabs(&line, buffer, strlen(buffer)); + expand_tabs(&line, buffer, strlen((char *)buffer)); incorporate_line(&line, linenum, &document); gh_buf_clear(&line); linenum++; @@ -429,7 +430,7 @@ extern block *stmd_parse_document(const unsigned char *buffer, size_t len) block *document = make_document(); while (buffer < end) { - const char *eol = memchr(buffer, '\n', end - buffer); + const unsigned char *eol = memchr(buffer, '\n', end - buffer); if (!eol) { expand_tabs(&line, buffer, end - buffer); @@ -449,9 +450,7 @@ extern block *stmd_parse_document(const unsigned char *buffer, size_t len) } // Process one line at a time, modifying a block. -// Returns 0 if successful. curptr is changed to point to -// the currently open block. -extern void incorporate_line(gh_buf *ln, int line_number, block** curptr) +static void incorporate_line(gh_buf *ln, int line_number, block** curptr) { block* last_matched_container; int offset = 0; -- cgit v1.2.3 From a7314deae649646f1f7ce5ede972641b5b62538c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 3 Sep 2014 03:40:23 +0200 Subject: 338/103 --- src/blocks.c | 173 ++++++++++++++++++++++++++++++----------------------------- 1 file changed, 87 insertions(+), 86 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 42f20db..94ff986 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -8,6 +8,8 @@ #include "scanners.h" #include "uthash.h" +#define peek_at(i, n) (i)->data[n] + static void incorporate_line(gh_buf *ln, int line_number, block** curptr); static void finalize(block* b, int line_number); @@ -27,7 +29,6 @@ static block* make_block(int tag, int start_line, int start_column) e->top = NULL; e->attributes.refmap = NULL; gh_buf_init(&e->string_content, 32); - e->string_pos = 0; e->inline_content = NULL; e->next = NULL; e->prev = NULL; @@ -80,10 +81,10 @@ static inline bool accepts_lines(int block_type) block_type == fenced_code); } -static void add_line(block* block, gh_buf *ln, int offset) +static void add_line(block* block, chunk *ch, int offset) { assert(block->open); - gh_buf_put(&block->string_content, ln->ptr + offset, ln->size - offset); + gh_buf_put(&block->string_content, ch->data + offset, ch->len - offset); } static void remove_trailing_blank_lines(gh_buf *ln) @@ -104,7 +105,7 @@ static void remove_trailing_blank_lines(gh_buf *ln) i = gh_buf_strchr(ln, '\n', i); if (i >= 0) - gh_buf_truncate(ln, i + 1); + gh_buf_truncate(ln, i); } // Check to see if a block ends with a blank line, descending @@ -162,12 +163,12 @@ static void finalize(block* b, int line_number) switch (b->tag) { case paragraph: pos = 0; - while (gh_buf_at(&b->string_content, b->string_pos) == '[' && - (pos = parse_reference(&b->string_content, b->string_pos, - b->top->attributes.refmap))) { - b->string_pos = pos; + while (gh_buf_at(&b->string_content, 0) == '[' && + (pos = parse_reference(&b->string_content, b->top->attributes.refmap))) { + + gh_buf_drop(&b->string_content, pos); } - if (is_blank(&b->string_content, b->string_pos)) { + if (is_blank(&b->string_content, 0)) { b->tag = reference_def; } break; @@ -179,14 +180,16 @@ static void finalize(block* b, int line_number) case fenced_code: // first line of contents becomes info - firstlinelen = gh_buf_strchr(&b->string_content, '\n', b->string_pos); + firstlinelen = gh_buf_strchr(&b->string_content, '\n', 0); + + gh_buf_init(&b->attributes.fenced_code_data.info, 0); gh_buf_set( &b->attributes.fenced_code_data.info, - b->string_content.ptr + b->string_pos, + b->string_content.ptr, firstlinelen ); - b->string_pos = firstlinelen + 1; + gh_buf_drop(&b->string_content, firstlinelen + 1); gh_buf_trim(&b->attributes.fenced_code_data.info); unescape_buffer(&b->attributes.fenced_code_data.info); @@ -281,7 +284,7 @@ void process_inlines(block* cur, reference** refmap) case paragraph: case atx_header: case setext_header: - cur->inline_content = parse_inlines(&cur->string_content, cur->string_pos, refmap); + cur->inline_content = parse_inlines(&cur->string_content, refmap); // MEM // gh_buf_free(&cur->string_content); break; @@ -300,19 +303,18 @@ void process_inlines(block* cur, reference** refmap) // Attempts to parse a list item marker (bullet or enumerated). // On success, returns length of the marker, and populates // data with the details. On failure, returns 0. -static int parse_list_marker(gh_buf *ln, int pos, - struct ListData ** dataptr) +static int parse_list_marker(chunk *input, int pos, struct ListData ** dataptr) { - char c; + unsigned char c; int startpos; struct ListData * data; startpos = pos; - c = gh_buf_at(ln, pos); + c = peek_at(input, pos); - if ((c == '*' || c == '-' || c == '+') && !scan_hrule(ln, pos)) { + if ((c == '*' || c == '-' || c == '+') && !scan_hrule(input, pos)) { pos++; - if (!isspace(gh_buf_at(ln, pos))) { + if (!isspace(peek_at(input, pos))) { return 0; } data = malloc(sizeof(struct ListData)); @@ -327,14 +329,14 @@ static int parse_list_marker(gh_buf *ln, int pos, int start = 0; do { - start = (10 * start) + (gh_buf_at(ln, pos) - '0'); + start = (10 * start) + (peek_at(input, pos) - '0'); pos++; - } while (isdigit(gh_buf_at(ln, pos))); + } while (isdigit(peek_at(input, pos))); - c = gh_buf_at(ln, pos); + c = peek_at(input, pos); if (c == '.' || c == ')') { pos++; - if (!isspace(gh_buf_at(ln, pos))) { + if (!isspace(peek_at(input, pos))) { return 0; } data = malloc(sizeof(struct ListData)); @@ -449,8 +451,26 @@ extern block *stmd_parse_document(const unsigned char *buffer, size_t len) return finalize_document(document, linenum); } +static void chop_trailing_hashtags(chunk *ch) +{ + int n; + + chunk_rtrim(ch); + n = ch->len - 1; + + // if string ends in #s, remove these: + while (n >= 0 && peek_at(ch, n) == '#') + n--; + + // the last # was escaped, so we include it. + if (n >= 0 && peek_at(ch, n) == '\\') + n++; + + ch->len = n + 1; +} + // Process one line at a time, modifying a block. -static void incorporate_line(gh_buf *ln, int line_number, block** curptr) +static void incorporate_line(gh_buf *line, int line_number, block** curptr) { block* last_matched_container; int offset = 0; @@ -464,6 +484,10 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) bool blank = false; int first_nonspace; int indent; + chunk input; + + input.data = line->ptr; + input.len = line->size; // container starts at the document root. container = cur->top; @@ -475,21 +499,19 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) container = container->last_child; first_nonspace = offset; - while (gh_buf_at(ln, first_nonspace) == ' ') { + while (peek_at(&input, first_nonspace) == ' ') { first_nonspace++; } indent = first_nonspace - offset; - blank = gh_buf_at(ln, first_nonspace) == '\n'; + blank = peek_at(&input, first_nonspace) == '\n'; if (container->tag == block_quote) { - - matched = indent <= 3 && gh_buf_at(ln, first_nonspace) == '>'; + matched = indent <= 3 && peek_at(&input, first_nonspace) == '>'; if (matched) { offset = first_nonspace + 1; - if (gh_buf_at(ln, offset) == ' ') { + if (peek_at(&input, offset) == ' ') offset++; - } } else { all_matched = false; } @@ -526,7 +548,7 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) // skip optional spaces of fence offset i = container->attributes.fenced_code_data.fence_offset; - while (i > 0 && gh_buf_at(ln, offset) == ' ') { + while (i > 0 && peek_at(&input, offset) == ' ') { offset++; i--; } @@ -564,15 +586,13 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) container->tag != html_block) { first_nonspace = offset; - while (gh_buf_at(ln, first_nonspace) == ' ') { + while (peek_at(&input, first_nonspace) == ' ') first_nonspace++; - } indent = first_nonspace - offset; - blank = gh_buf_at(ln, first_nonspace) == '\n'; + blank = peek_at(&input, first_nonspace) == '\n'; if (indent >= CODE_INDENT) { - if (cur->tag != paragraph && !blank) { offset += CODE_INDENT; container = add_child(container, indented_code, line_number, offset + 1); @@ -580,76 +600,70 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) break; } - } else if (gh_buf_at(ln, first_nonspace) == '>') { + } else if (peek_at(&input, first_nonspace) == '>') { offset = first_nonspace + 1; // optional following character - if (gh_buf_at(ln, offset) == ' ') { + if (peek_at(&input, offset) == ' ') offset++; - } container = add_child(container, block_quote, line_number, offset + 1); - } else if ((matched = scan_atx_header_start(ln, first_nonspace))) { + } else if ((matched = scan_atx_header_start(&input, first_nonspace))) { offset = first_nonspace + matched; container = add_child(container, atx_header, line_number, offset + 1); - int hashpos = gh_buf_strchr(ln, '#', first_nonspace); - assert(hashpos >= 0); - + int hashpos = chunk_strchr(&input, '#', first_nonspace); int level = 0; - while (gh_buf_at(ln, hashpos) == '#') { + + while (peek_at(&input, hashpos) == '#') { level++; hashpos++; } container->attributes.header_level = level; - } else if ((matched = scan_open_code_fence(ln, first_nonspace))) { + } else if ((matched = scan_open_code_fence(&input, first_nonspace))) { - container = add_child(container, fenced_code, line_number, - first_nonspace + 1); - container->attributes.fenced_code_data.fence_char = gh_buf_at(ln, - first_nonspace); + container = add_child(container, fenced_code, line_number, first_nonspace + 1); + container->attributes.fenced_code_data.fence_char = peek_at(&input, first_nonspace); container->attributes.fenced_code_data.fence_length = matched; - container->attributes.fenced_code_data.fence_offset = - first_nonspace - offset; + container->attributes.fenced_code_data.fence_offset = first_nonspace - offset; offset = first_nonspace + matched; - } else if ((matched = scan_html_block_tag(ln, first_nonspace))) { + } else if ((matched = scan_html_block_tag(&input, first_nonspace))) { - container = add_child(container, html_block, line_number, - first_nonspace + 1); + container = add_child(container, html_block, line_number, first_nonspace + 1); // note, we don't adjust offset because the tag is part of the text } else if (container->tag == paragraph && - (lev = scan_setext_header_line(ln, first_nonspace)) && + (lev = scan_setext_header_line(&input, first_nonspace)) && // check that there is only one line in the paragraph: gh_buf_strrchr(&container->string_content, '\n', gh_buf_len(&container->string_content) - 2) < 0) { container->tag = setext_header; container->attributes.header_level = lev; - offset = gh_buf_len(ln) - 1; + offset = input.len - 1; } else if (!(container->tag == paragraph && !all_matched) && - (matched = scan_hrule(ln, first_nonspace))) { + (matched = scan_hrule(&input, first_nonspace))) { // it's only now that we know the line is not part of a setext header: container = add_child(container, hrule, line_number, first_nonspace + 1); finalize(container, line_number); container = container->parent; - offset = gh_buf_len(ln) - 1; + offset = input.len - 1; - } else if ((matched = parse_list_marker(ln, first_nonspace, &data))) { + } else if ((matched = parse_list_marker(&input, first_nonspace, &data))) { // compute padding: offset = first_nonspace + matched; i = 0; - while (i <= 5 && gh_buf_at(ln, offset + i) == ' ') { + while (i <= 5 && peek_at(&input, offset + i) == ' ') { i++; } // i = number of spaces after marker, up to 5 - if (i >= 5 || i < 1 || gh_buf_at(ln, offset) == '\n') { + if (i >= 5 || i < 1 || peek_at(&input, offset) == '\n') { data->padding = matched + 1; if (i > 0) { offset += 1; @@ -674,6 +688,7 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) // add the list item container = add_child(container, list_item, line_number, first_nonspace + 1); + /* TODO: static */ container->attributes.list_data = *data; free(data); @@ -691,12 +706,11 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) // appropriate container. first_nonspace = offset; - while (gh_buf_at(ln, first_nonspace) == ' ') { + while (peek_at(&input, first_nonspace) == ' ') first_nonspace++; - } indent = first_nonspace - offset; - blank = gh_buf_at(ln, first_nonspace) == '\n'; + blank = peek_at(&input, first_nonspace) == '\n'; // block quote lines are never blank as they start with > // and we don't count blanks in fenced code for purposes of tight/loose @@ -721,13 +735,12 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) cur->tag == paragraph && gh_buf_len(&cur->string_content) > 0) { - add_line(cur, ln, offset); + add_line(cur, &input, offset); } else { // not a lazy continuation // finalize any blocks that were not matched and set cur to container: while (cur != last_matched_container) { - finalize(cur, line_number); cur = cur->parent; assert(cur != NULL); @@ -735,58 +748,46 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr) if (container->tag == indented_code) { - add_line(container, ln, offset); + add_line(container, &input, offset); } else if (container->tag == fenced_code) { matched = (indent <= 3 - && gh_buf_at(ln, first_nonspace) == container->attributes.fenced_code_data.fence_char) - && scan_close_code_fence(ln, first_nonspace, + && peek_at(&input, first_nonspace) == container->attributes.fenced_code_data.fence_char) + && scan_close_code_fence(&input, first_nonspace, container->attributes.fenced_code_data.fence_length); if (matched) { // if closing fence, don't add line to container; instead, close it: finalize(container, line_number); container = container->parent; // back up to parent } else { - add_line(container, ln, offset); + add_line(container, &input, offset); } } else if (container->tag == html_block) { - add_line(container, ln, offset); + add_line(container, &input, offset); } else if (blank) { // ??? do nothing } else if (container->tag == atx_header) { - // chop off trailing ###s...use a scanner? - gh_buf_trim(ln); - int p = gh_buf_len(ln) - 1; - - // if string ends in #s, remove these: - while (gh_buf_at(ln, p) == '#') { - p--; - } - if (gh_buf_at(ln, p) == '\\') { - // the last # was escaped, so we include it. - p++; - } - gh_buf_truncate(ln, p + 1); - add_line(container, ln, first_nonspace); + chop_trailing_hashtags(&input); + add_line(container, &input, first_nonspace); finalize(container, line_number); container = container->parent; } else if (accepts_lines(container->tag)) { - add_line(container, ln, first_nonspace); + add_line(container, &input, first_nonspace); } else if (container->tag != hrule && container->tag != setext_header) { // create paragraph container for line container = add_child(container, paragraph, line_number, first_nonspace + 1); - add_line(container, ln, first_nonspace); + add_line(container, &input, first_nonspace); } else { assert(false); -- cgit v1.2.3 From f5168c63ad305b3e331eb7d31efaf46b0541bba4 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 4 Sep 2014 06:41:18 +0200 Subject: 368/73 --- src/blocks.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 94ff986..bd25d6c 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -57,6 +57,7 @@ bool is_blank(gh_buf *s, int offset) return true; case ' ': offset++; + break; default: return false; } -- cgit v1.2.3 From 28be4a59c940bd55ed4fef668091d52638925c3c Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 4 Sep 2014 15:55:27 +0200 Subject: 379/62 --- src/blocks.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index bd25d6c..cf0e9e4 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -752,11 +752,15 @@ static void incorporate_line(gh_buf *line, int line_number, block** curptr) add_line(container, &input, offset); } else if (container->tag == fenced_code) { + matched = 0; + + if (indent <= 3 && + peek_at(&input, first_nonspace) == container->attributes.fenced_code_data.fence_char) { + int fence_len = scan_close_code_fence(&input, first_nonspace); + if (fence_len > container->attributes.fenced_code_data.fence_length) + matched = 1; + } - matched = (indent <= 3 - && peek_at(&input, first_nonspace) == container->attributes.fenced_code_data.fence_char) - && scan_close_code_fence(&input, first_nonspace, - container->attributes.fenced_code_data.fence_length); if (matched) { // if closing fence, don't add line to container; instead, close it: finalize(container, line_number); -- cgit v1.2.3 From 543c2c94d71adee42c7bd2f8027d75c87ed8120d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 4 Sep 2014 18:38:14 +0200 Subject: Rename to strbuf --- src/blocks.c | 64 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 32 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index cf0e9e4..9faccd9 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -10,7 +10,7 @@ #define peek_at(i, n) (i)->data[n] -static void incorporate_line(gh_buf *ln, int line_number, block** curptr); +static void incorporate_line(strbuf *ln, int line_number, block** curptr); static void finalize(block* b, int line_number); static block* make_block(int tag, int start_line, int start_column) @@ -28,7 +28,7 @@ static block* make_block(int tag, int start_line, int start_column) e->parent = NULL; e->top = NULL; e->attributes.refmap = NULL; - gh_buf_init(&e->string_content, 32); + strbuf_init(&e->string_content, 32); e->inline_content = NULL; e->next = NULL; e->prev = NULL; @@ -49,7 +49,7 @@ extern block* make_document() } // Returns true if line has only space characters, else false. -bool is_blank(gh_buf *s, int offset) +bool is_blank(strbuf *s, int offset) { while (offset < s->size) { switch (s->ptr[offset]) { @@ -85,10 +85,10 @@ static inline bool accepts_lines(int block_type) static void add_line(block* block, chunk *ch, int offset) { assert(block->open); - gh_buf_put(&block->string_content, ch->data + offset, ch->len - offset); + strbuf_put(&block->string_content, ch->data + offset, ch->len - offset); } -static void remove_trailing_blank_lines(gh_buf *ln) +static void remove_trailing_blank_lines(strbuf *ln) { int i; @@ -100,13 +100,13 @@ static void remove_trailing_blank_lines(gh_buf *ln) } if (i < 0) { - gh_buf_clear(ln); + strbuf_clear(ln); return; } - i = gh_buf_strchr(ln, '\n', i); + i = strbuf_strchr(ln, '\n', i); if (i >= 0) - gh_buf_truncate(ln, i); + strbuf_truncate(ln, i); } // Check to see if a block ends with a blank line, descending @@ -164,10 +164,10 @@ static void finalize(block* b, int line_number) switch (b->tag) { case paragraph: pos = 0; - while (gh_buf_at(&b->string_content, 0) == '[' && + while (strbuf_at(&b->string_content, 0) == '[' && (pos = parse_reference(&b->string_content, b->top->attributes.refmap))) { - gh_buf_drop(&b->string_content, pos); + strbuf_drop(&b->string_content, pos); } if (is_blank(&b->string_content, 0)) { b->tag = reference_def; @@ -176,23 +176,23 @@ static void finalize(block* b, int line_number) case indented_code: remove_trailing_blank_lines(&b->string_content); - gh_buf_putc(&b->string_content, '\n'); + strbuf_putc(&b->string_content, '\n'); break; case fenced_code: // first line of contents becomes info - firstlinelen = gh_buf_strchr(&b->string_content, '\n', 0); + firstlinelen = strbuf_strchr(&b->string_content, '\n', 0); - gh_buf_init(&b->attributes.fenced_code_data.info, 0); - gh_buf_set( + strbuf_init(&b->attributes.fenced_code_data.info, 0); + strbuf_set( &b->attributes.fenced_code_data.info, b->string_content.ptr, firstlinelen ); - gh_buf_drop(&b->string_content, firstlinelen + 1); + strbuf_drop(&b->string_content, firstlinelen + 1); - gh_buf_trim(&b->attributes.fenced_code_data.info); + strbuf_trim(&b->attributes.fenced_code_data.info); unescape_buffer(&b->attributes.fenced_code_data.info); break; @@ -265,9 +265,9 @@ extern void free_blocks(block* e) while (e != NULL) { next = e->next; free_inlines(e->inline_content); - gh_buf_free(&e->string_content); + strbuf_free(&e->string_content); if (e->tag == fenced_code) { - gh_buf_free(&e->attributes.fenced_code_data.info); + strbuf_free(&e->attributes.fenced_code_data.info); } else if (e->tag == document) { free_reference_map(e->attributes.refmap); } @@ -287,7 +287,7 @@ void process_inlines(block* cur, reference** refmap) case setext_header: cur->inline_content = parse_inlines(&cur->string_content, refmap); // MEM - // gh_buf_free(&cur->string_content); + // strbuf_free(&cur->string_content); break; default: @@ -369,7 +369,7 @@ static int lists_match(struct ListData list_data, list_data.bullet_char == item_data.bullet_char); } -static void expand_tabs(gh_buf *ob, const unsigned char *line, size_t size) +static void expand_tabs(strbuf *ob, const unsigned char *line, size_t size) { size_t i = 0, tab = 0; @@ -381,13 +381,13 @@ static void expand_tabs(gh_buf *ob, const unsigned char *line, size_t size) } if (i > org) - gh_buf_put(ob, line + org, i - org); + strbuf_put(ob, line + org, i - org); if (i >= size) break; do { - gh_buf_putc(ob, ' '); tab++; + strbuf_putc(ob, ' '); tab++; } while (tab % 4); i++; @@ -409,7 +409,7 @@ static block *finalize_document(block *document, int linenum) extern block *stmd_parse_file(FILE *f) { - gh_buf line = GH_BUF_INIT; + strbuf line = GH_BUF_INIT; unsigned char buffer[4096]; int linenum = 1; block *document = make_document(); @@ -417,17 +417,17 @@ extern block *stmd_parse_file(FILE *f) while (fgets((char *)buffer, sizeof(buffer), f)) { expand_tabs(&line, buffer, strlen((char *)buffer)); incorporate_line(&line, linenum, &document); - gh_buf_clear(&line); + strbuf_clear(&line); linenum++; } - gh_buf_free(&line); + strbuf_free(&line); return finalize_document(document, linenum); } extern block *stmd_parse_document(const unsigned char *buffer, size_t len) { - gh_buf line = GH_BUF_INIT; + strbuf line = GH_BUF_INIT; int linenum = 1; const unsigned char *end = buffer + len; block *document = make_document(); @@ -444,11 +444,11 @@ extern block *stmd_parse_document(const unsigned char *buffer, size_t len) } incorporate_line(&line, linenum, &document); - gh_buf_clear(&line); + strbuf_clear(&line); linenum++; } - gh_buf_free(&line); + strbuf_free(&line); return finalize_document(document, linenum); } @@ -471,7 +471,7 @@ static void chop_trailing_hashtags(chunk *ch) } // Process one line at a time, modifying a block. -static void incorporate_line(gh_buf *line, int line_number, block** curptr) +static void incorporate_line(strbuf *line, int line_number, block** curptr) { block* last_matched_container; int offset = 0; @@ -639,8 +639,8 @@ static void incorporate_line(gh_buf *line, int line_number, block** curptr) } else if (container->tag == paragraph && (lev = scan_setext_header_line(&input, first_nonspace)) && // check that there is only one line in the paragraph: - gh_buf_strrchr(&container->string_content, '\n', - gh_buf_len(&container->string_content) - 2) < 0) { + strbuf_strrchr(&container->string_content, '\n', + strbuf_len(&container->string_content) - 2) < 0) { container->tag = setext_header; container->attributes.header_level = lev; @@ -734,7 +734,7 @@ static void incorporate_line(gh_buf *line, int line_number, block** curptr) container == last_matched_container && !blank && cur->tag == paragraph && - gh_buf_len(&cur->string_content) > 0) { + strbuf_len(&cur->string_content) > 0) { add_line(cur, &input, offset); -- cgit v1.2.3 From 19ba82d7a30bd999a25fc303a8516056880abc9d Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 4 Sep 2014 18:49:33 +0200 Subject: Rename node_block --- src/blocks.c | 100 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 50 insertions(+), 50 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 9faccd9..d74ceb2 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -10,13 +10,13 @@ #define peek_at(i, n) (i)->data[n] -static void incorporate_line(strbuf *ln, int line_number, block** curptr); -static void finalize(block* b, int line_number); +static void incorporate_line(strbuf *ln, int line_number, node_block** curptr); +static void finalize(node_block* b, int line_number); -static block* make_block(int tag, int start_line, int start_column) +static node_block* make_block(int tag, int start_line, int start_column) { - block* e; - e = (block*) malloc(sizeof(block)); + node_block* e; + e = (node_block*) malloc(sizeof(node_block)); e->tag = tag; e->open = true; e->last_line_blank = false; @@ -35,10 +35,10 @@ static block* make_block(int tag, int start_line, int start_column) return e; } -// Create a root document block. -extern block* make_document() +// Create a root document node_block. +extern node_block* make_document() { - block * e = make_block(document, 1, 1); + node_block * e = make_block(document, 1, 1); reference * map = NULL; reference ** refmap; refmap = (reference**) malloc(sizeof(reference*)); @@ -82,10 +82,10 @@ static inline bool accepts_lines(int block_type) block_type == fenced_code); } -static void add_line(block* block, chunk *ch, int offset) +static void add_line(node_block* node_block, chunk *ch, int offset) { - assert(block->open); - strbuf_put(&block->string_content, ch->data + offset, ch->len - offset); + assert(node_block->open); + strbuf_put(&node_block->string_content, ch->data + offset, ch->len - offset); } static void remove_trailing_blank_lines(strbuf *ln) @@ -109,25 +109,25 @@ static void remove_trailing_blank_lines(strbuf *ln) strbuf_truncate(ln, i); } -// Check to see if a block ends with a blank line, descending +// Check to see if a node_block ends with a blank line, descending // if needed into lists and sublists. -static bool ends_with_blank_line(block* block) +static bool ends_with_blank_line(node_block* node_block) { - if (block->last_line_blank) { + if (node_block->last_line_blank) { return true; } - if ((block->tag == list || block->tag == list_item) && block->last_child) { - return ends_with_blank_line(block->last_child); + if ((node_block->tag == list || node_block->tag == list_item) && node_block->last_child) { + return ends_with_blank_line(node_block->last_child); } else { return false; } } // Break out of all containing lists -static int break_out_of_lists(block ** bptr, int line_number) +static int break_out_of_lists(node_block ** bptr, int line_number) { - block * container = *bptr; - block * b = container->top; + node_block * container = *bptr; + node_block * b = container->top; // find first containing list: while (b && b->tag != list) { b = b->last_child; @@ -144,15 +144,15 @@ static int break_out_of_lists(block ** bptr, int line_number) } -static void finalize(block* b, int line_number) +static void finalize(node_block* b, int line_number) { int firstlinelen; int pos; - block* item; - block* subitem; + node_block* item; + node_block* subitem; if (!b->open) - return; // don't do anything if the block is already closed + return; // don't do anything if the node_block is already closed b->open = false; if (line_number > b->start_line) { @@ -230,20 +230,20 @@ static void finalize(block* b, int line_number) } } -// Add a block as child of another. Return pointer to child. -extern block* add_child(block* parent, +// Add a node_block as child of another. Return pointer to child. +extern node_block* add_child(node_block* parent, int block_type, int start_line, int start_column) { assert(parent); - // if 'parent' isn't the kind of block that can accept this child, - // then back up til we hit a block that can. + // if 'parent' isn't the kind of node_block that can accept this child, + // then back up til we hit a node_block that can. while (!can_contain(parent->tag, block_type)) { finalize(parent, start_line); parent = parent->parent; } - block* child = make_block(block_type, start_line, start_column); + node_block* child = make_block(block_type, start_line, start_column); child->parent = parent; child->top = parent->top; @@ -258,10 +258,10 @@ extern block* add_child(block* parent, return child; } -// Free a block list and any children. -extern void free_blocks(block* e) +// Free a node_block list and any children. +extern void free_blocks(node_block* e) { - block * next; + node_block * next; while (e != NULL) { next = e->next; free_inlines(e->inline_content); @@ -277,9 +277,9 @@ extern void free_blocks(block* e) } } -// Walk through block and all children, recursively, parsing +// Walk through node_block and all children, recursively, parsing // string content into inline content where appropriate. -void process_inlines(block* cur, reference** refmap) +void process_inlines(node_block* cur, reference** refmap) { switch (cur->tag) { case paragraph: @@ -294,7 +294,7 @@ void process_inlines(block* cur, reference** refmap) break; } - block *child = cur->children; + node_block *child = cur->children; while (child != NULL) { process_inlines(child, refmap); child = child->next; @@ -394,7 +394,7 @@ static void expand_tabs(strbuf *ob, const unsigned char *line, size_t size) } } -static block *finalize_document(block *document, int linenum) +static node_block *finalize_document(node_block *document, int linenum) { while (document != document->top) { finalize(document, linenum); @@ -407,12 +407,12 @@ static block *finalize_document(block *document, int linenum) return document; } -extern block *stmd_parse_file(FILE *f) +extern node_block *stmd_parse_file(FILE *f) { strbuf line = GH_BUF_INIT; unsigned char buffer[4096]; int linenum = 1; - block *document = make_document(); + node_block *document = make_document(); while (fgets((char *)buffer, sizeof(buffer), f)) { expand_tabs(&line, buffer, strlen((char *)buffer)); @@ -425,12 +425,12 @@ extern block *stmd_parse_file(FILE *f) return finalize_document(document, linenum); } -extern block *stmd_parse_document(const unsigned char *buffer, size_t len) +extern node_block *stmd_parse_document(const unsigned char *buffer, size_t len) { strbuf line = GH_BUF_INIT; int linenum = 1; const unsigned char *end = buffer + len; - block *document = make_document(); + node_block *document = make_document(); while (buffer < end) { const unsigned char *eol = memchr(buffer, '\n', end - buffer); @@ -470,18 +470,18 @@ static void chop_trailing_hashtags(chunk *ch) ch->len = n + 1; } -// Process one line at a time, modifying a block. -static void incorporate_line(strbuf *line, int line_number, block** curptr) +// Process one line at a time, modifying a node_block. +static void incorporate_line(strbuf *line, int line_number, node_block** curptr) { - block* last_matched_container; + node_block* last_matched_container; int offset = 0; int matched = 0; int lev = 0; int i; struct ListData * data = NULL; bool all_matched = true; - block* container; - block* cur = *curptr; + node_block* container; + node_block* cur = *curptr; bool blank = false; int first_nonspace; int indent; @@ -493,8 +493,8 @@ static void incorporate_line(strbuf *line, int line_number, block** curptr) // container starts at the document root. container = cur->top; - // for each containing block, try to parse the associated line start. - // bail out on failure: container will point to the last matching block. + // for each containing node_block, try to parse the associated line start. + // bail out on failure: container will point to the last matching node_block. while (container->last_child && container->last_child->open) { container = container->last_child; @@ -570,7 +570,7 @@ static void incorporate_line(strbuf *line, int line_number, block** curptr) } if (!all_matched) { - container = container->parent; // back up to last matching block + container = container->parent; // back up to last matching node_block break; } } @@ -582,7 +582,7 @@ static void incorporate_line(strbuf *line, int line_number, block** curptr) break_out_of_lists(&container, line_number); } - // unless last matched container is code block, try new container starts: + // unless last matched container is code node_block, try new container starts: while (container->tag != fenced_code && container->tag != indented_code && container->tag != html_block) { @@ -713,7 +713,7 @@ static void incorporate_line(strbuf *line, int line_number, block** curptr) indent = first_nonspace - offset; blank = peek_at(&input, first_nonspace) == '\n'; - // block quote lines are never blank as they start with > + // node_block quote lines are never blank as they start with > // and we don't count blanks in fenced code for purposes of tight/loose // lists or breaking out of lists. we also don't set last_line_blank // on an empty list item. @@ -724,7 +724,7 @@ static void incorporate_line(strbuf *line, int line_number, block** curptr) container->children == NULL && container->start_line == line_number)); - block *cont = container; + node_block *cont = container; while (cont->parent) { cont->parent->last_line_blank = false; cont = cont->parent; -- cgit v1.2.3 From 806ff17755c90579afc68914b251b80e2f8c4b77 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Thu, 4 Sep 2014 18:56:52 +0200 Subject: Rename block literals --- src/blocks.c | 110 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 55 insertions(+), 55 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index d74ceb2..f671b5e 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -38,7 +38,7 @@ static node_block* make_block(int tag, int start_line, int start_column) // Create a root document node_block. extern node_block* make_document() { - node_block * e = make_block(document, 1, 1); + node_block * e = make_block(BLOCK_DOCUMENT, 1, 1); reference * map = NULL; reference ** refmap; refmap = (reference**) malloc(sizeof(reference*)); @@ -68,18 +68,18 @@ bool is_blank(strbuf *s, int offset) static inline bool can_contain(int parent_type, int child_type) { - return ( parent_type == document || - parent_type == block_quote || - parent_type == list_item || - (parent_type == list && child_type == list_item) ); + return ( parent_type == BLOCK_DOCUMENT || + parent_type == BLOCK_BQUOTE || + parent_type == BLOCK_LIST_ITEM || + (parent_type == BLOCK_LIST && child_type == BLOCK_LIST_ITEM) ); } static inline bool accepts_lines(int block_type) { - return (block_type == paragraph || - block_type == atx_header || - block_type == indented_code || - block_type == fenced_code); + return (block_type == BLOCK_PARAGRAPH || + block_type == BLOCK_ATX_HEADER || + block_type == BLOCK_INDENTED_CODE || + block_type == BLOCK_FENCED_CODE); } static void add_line(node_block* node_block, chunk *ch, int offset) @@ -116,7 +116,7 @@ static bool ends_with_blank_line(node_block* node_block) if (node_block->last_line_blank) { return true; } - if ((node_block->tag == list || node_block->tag == list_item) && node_block->last_child) { + if ((node_block->tag == BLOCK_LIST || node_block->tag == BLOCK_LIST_ITEM) && node_block->last_child) { return ends_with_blank_line(node_block->last_child); } else { return false; @@ -128,8 +128,8 @@ static int break_out_of_lists(node_block ** bptr, int line_number) { node_block * container = *bptr; node_block * b = container->top; - // find first containing list: - while (b && b->tag != list) { + // find first containing BLOCK_LIST: + while (b && b->tag != BLOCK_LIST) { b = b->last_child; } if (b) { @@ -162,7 +162,7 @@ static void finalize(node_block* b, int line_number) } switch (b->tag) { - case paragraph: + case BLOCK_PARAGRAPH: pos = 0; while (strbuf_at(&b->string_content, 0) == '[' && (pos = parse_reference(&b->string_content, b->top->attributes.refmap))) { @@ -170,16 +170,16 @@ static void finalize(node_block* b, int line_number) strbuf_drop(&b->string_content, pos); } if (is_blank(&b->string_content, 0)) { - b->tag = reference_def; + b->tag = BLOCK_REFERENCE_DEF; } break; - case indented_code: + case BLOCK_INDENTED_CODE: remove_trailing_blank_lines(&b->string_content); strbuf_putc(&b->string_content, '\n'); break; - case fenced_code: + case BLOCK_FENCED_CODE: // first line of contents becomes info firstlinelen = strbuf_strchr(&b->string_content, '\n', 0); @@ -196,7 +196,7 @@ static void finalize(node_block* b, int line_number) unescape_buffer(&b->attributes.fenced_code_data.info); break; - case list: // determine tight/loose status + case BLOCK_LIST: // determine tight/loose status b->attributes.list_data.tight = true; // tight by default item = b->children; @@ -266,9 +266,9 @@ extern void free_blocks(node_block* e) next = e->next; free_inlines(e->inline_content); strbuf_free(&e->string_content); - if (e->tag == fenced_code) { + if (e->tag == BLOCK_FENCED_CODE) { strbuf_free(&e->attributes.fenced_code_data.info); - } else if (e->tag == document) { + } else if (e->tag == BLOCK_DOCUMENT) { free_reference_map(e->attributes.refmap); } free_blocks(e->children); @@ -282,9 +282,9 @@ extern void free_blocks(node_block* e) void process_inlines(node_block* cur, reference** refmap) { switch (cur->tag) { - case paragraph: - case atx_header: - case setext_header: + case BLOCK_PARAGRAPH: + case BLOCK_ATX_HEADER: + case BLOCK_SETEXT_HEADER: cur->inline_content = parse_inlines(&cur->string_content, refmap); // MEM // strbuf_free(&cur->string_content); @@ -507,7 +507,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) indent = first_nonspace - offset; blank = peek_at(&input, first_nonspace) == '\n'; - if (container->tag == block_quote) { + if (container->tag == BLOCK_BQUOTE) { matched = indent <= 3 && peek_at(&input, first_nonspace) == '>'; if (matched) { offset = first_nonspace + 1; @@ -517,7 +517,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) all_matched = false; } - } else if (container->tag == list_item) { + } else if (container->tag == BLOCK_LIST_ITEM) { if (indent >= container->attributes.list_data.marker_offset + container->attributes.list_data.padding) { @@ -529,7 +529,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) all_matched = false; } - } else if (container->tag == indented_code) { + } else if (container->tag == BLOCK_INDENTED_CODE) { if (indent >= CODE_INDENT) { offset += CODE_INDENT; @@ -539,13 +539,13 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) all_matched = false; } - } else if (container->tag == atx_header || - container->tag == setext_header) { + } else if (container->tag == BLOCK_ATX_HEADER || + container->tag == BLOCK_SETEXT_HEADER) { // a header can never contain more than one line all_matched = false; - } else if (container->tag == fenced_code) { + } else if (container->tag == BLOCK_FENCED_CODE) { // skip optional spaces of fence offset i = container->attributes.fenced_code_data.fence_offset; @@ -554,13 +554,13 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) i--; } - } else if (container->tag == html_block) { + } else if (container->tag == BLOCK_HTML) { if (blank) { all_matched = false; } - } else if (container->tag == paragraph) { + } else if (container->tag == BLOCK_PARAGRAPH) { if (blank) { container->last_line_blank = true; @@ -583,8 +583,8 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) } // unless last matched container is code node_block, try new container starts: - while (container->tag != fenced_code && container->tag != indented_code && - container->tag != html_block) { + while (container->tag != BLOCK_FENCED_CODE && container->tag != BLOCK_INDENTED_CODE && + container->tag != BLOCK_HTML) { first_nonspace = offset; while (peek_at(&input, first_nonspace) == ' ') @@ -594,9 +594,9 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) blank = peek_at(&input, first_nonspace) == '\n'; if (indent >= CODE_INDENT) { - if (cur->tag != paragraph && !blank) { + if (cur->tag != BLOCK_PARAGRAPH && !blank) { offset += CODE_INDENT; - container = add_child(container, indented_code, line_number, offset + 1); + container = add_child(container, BLOCK_INDENTED_CODE, line_number, offset + 1); } else { // indent > 4 in lazy line break; } @@ -607,12 +607,12 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) // optional following character if (peek_at(&input, offset) == ' ') offset++; - container = add_child(container, block_quote, line_number, offset + 1); + container = add_child(container, BLOCK_BQUOTE, line_number, offset + 1); } else if ((matched = scan_atx_header_start(&input, first_nonspace))) { offset = first_nonspace + matched; - container = add_child(container, atx_header, line_number, offset + 1); + container = add_child(container, BLOCK_ATX_HEADER, line_number, offset + 1); int hashpos = chunk_strchr(&input, '#', first_nonspace); int level = 0; @@ -625,7 +625,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) } else if ((matched = scan_open_code_fence(&input, first_nonspace))) { - container = add_child(container, fenced_code, line_number, first_nonspace + 1); + container = add_child(container, BLOCK_FENCED_CODE, line_number, first_nonspace + 1); container->attributes.fenced_code_data.fence_char = peek_at(&input, first_nonspace); container->attributes.fenced_code_data.fence_length = matched; container->attributes.fenced_code_data.fence_offset = first_nonspace - offset; @@ -633,24 +633,24 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) } else if ((matched = scan_html_block_tag(&input, first_nonspace))) { - container = add_child(container, html_block, line_number, first_nonspace + 1); + container = add_child(container, BLOCK_HTML, line_number, first_nonspace + 1); // note, we don't adjust offset because the tag is part of the text - } else if (container->tag == paragraph && + } else if (container->tag == BLOCK_PARAGRAPH && (lev = scan_setext_header_line(&input, first_nonspace)) && // check that there is only one line in the paragraph: strbuf_strrchr(&container->string_content, '\n', strbuf_len(&container->string_content) - 2) < 0) { - container->tag = setext_header; + container->tag = BLOCK_SETEXT_HEADER; container->attributes.header_level = lev; offset = input.len - 1; - } else if (!(container->tag == paragraph && !all_matched) && + } else if (!(container->tag == BLOCK_PARAGRAPH && !all_matched) && (matched = scan_hrule(&input, first_nonspace))) { // it's only now that we know the line is not part of a setext header: - container = add_child(container, hrule, line_number, first_nonspace + 1); + container = add_child(container, BLOCK_HRULE, line_number, first_nonspace + 1); finalize(container, line_number); container = container->parent; offset = input.len - 1; @@ -679,15 +679,15 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) data->marker_offset = indent; - if (container->tag != list || + if (container->tag != BLOCK_LIST || !lists_match(container->attributes.list_data, *data)) { - container = add_child(container, list, line_number, + container = add_child(container, BLOCK_LIST, line_number, first_nonspace + 1); container->attributes.list_data = *data; } // add the list item - container = add_child(container, list_item, line_number, + container = add_child(container, BLOCK_LIST_ITEM, line_number, first_nonspace + 1); /* TODO: static */ container->attributes.list_data = *data; @@ -718,9 +718,9 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) // lists or breaking out of lists. we also don't set last_line_blank // on an empty list item. container->last_line_blank = (blank && - container->tag != block_quote && - container->tag != fenced_code && - !(container->tag == list_item && + container->tag != BLOCK_BQUOTE && + container->tag != BLOCK_FENCED_CODE && + !(container->tag == BLOCK_LIST_ITEM && container->children == NULL && container->start_line == line_number)); @@ -733,7 +733,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) if (cur != last_matched_container && container == last_matched_container && !blank && - cur->tag == paragraph && + cur->tag == BLOCK_PARAGRAPH && strbuf_len(&cur->string_content) > 0) { add_line(cur, &input, offset); @@ -747,11 +747,11 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) assert(cur != NULL); } - if (container->tag == indented_code) { + if (container->tag == BLOCK_INDENTED_CODE) { add_line(container, &input, offset); - } else if (container->tag == fenced_code) { + } else if (container->tag == BLOCK_FENCED_CODE) { matched = 0; if (indent <= 3 && @@ -769,7 +769,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) add_line(container, &input, offset); } - } else if (container->tag == html_block) { + } else if (container->tag == BLOCK_HTML) { add_line(container, &input, offset); @@ -777,7 +777,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) // ??? do nothing - } else if (container->tag == atx_header) { + } else if (container->tag == BLOCK_ATX_HEADER) { chop_trailing_hashtags(&input); add_line(container, &input, first_nonspace); @@ -788,10 +788,10 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) add_line(container, &input, first_nonspace); - } else if (container->tag != hrule && container->tag != setext_header) { + } else if (container->tag != BLOCK_HRULE && container->tag != BLOCK_SETEXT_HEADER) { // create paragraph container for line - container = add_child(container, paragraph, line_number, first_nonspace + 1); + container = add_child(container, BLOCK_PARAGRAPH, line_number, first_nonspace + 1); add_line(container, &input, first_nonspace); } else { -- cgit v1.2.3 From 61e3e606e64221eaa5cf3d83dc598d5a42818d10 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sat, 6 Sep 2014 20:48:05 +0200 Subject: UTF8-aware detabbing and entity handling --- src/blocks.c | 35 ++++++----------------------------- 1 file changed, 6 insertions(+), 29 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index f671b5e..8c7d49c 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -5,6 +5,8 @@ #include #include "stmd.h" +#include "utf8.h" +#include "html/houdini.h" #include "scanners.h" #include "uthash.h" @@ -184,7 +186,7 @@ static void finalize(node_block* b, int line_number) firstlinelen = strbuf_strchr(&b->string_content, '\n', 0); strbuf_init(&b->attributes.fenced_code_data.info, 0); - strbuf_set( + houdini_unescape_html_f( &b->attributes.fenced_code_data.info, b->string_content.ptr, firstlinelen @@ -369,31 +371,6 @@ static int lists_match(struct ListData list_data, list_data.bullet_char == item_data.bullet_char); } -static void expand_tabs(strbuf *ob, const unsigned char *line, size_t size) -{ - size_t i = 0, tab = 0; - - while (i < size) { - size_t org = i; - - while (i < size && line[i] != '\t') { - i++; tab++; - } - - if (i > org) - strbuf_put(ob, line + org, i - org); - - if (i >= size) - break; - - do { - strbuf_putc(ob, ' '); tab++; - } while (tab % 4); - - i++; - } -} - static node_block *finalize_document(node_block *document, int linenum) { while (document != document->top) { @@ -415,7 +392,7 @@ extern node_block *stmd_parse_file(FILE *f) node_block *document = make_document(); while (fgets((char *)buffer, sizeof(buffer), f)) { - expand_tabs(&line, buffer, strlen((char *)buffer)); + utf8proc_detab(&line, buffer, strlen((char *)buffer)); incorporate_line(&line, linenum, &document); strbuf_clear(&line); linenum++; @@ -436,10 +413,10 @@ extern node_block *stmd_parse_document(const unsigned char *buffer, size_t len) const unsigned char *eol = memchr(buffer, '\n', end - buffer); if (!eol) { - expand_tabs(&line, buffer, end - buffer); + utf8proc_detab(&line, buffer, end - buffer); buffer = end; } else { - expand_tabs(&line, buffer, (eol - buffer) + 1); + utf8proc_detab(&line, buffer, (eol - buffer) + 1); buffer += (eol - buffer) + 1; } -- cgit v1.2.3 From 7426f9ae60272a19bd4611b8579647118033a1e6 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sun, 7 Sep 2014 22:48:33 +0200 Subject: Abstract the Block union --- src/blocks.c | 94 +++++++++++++++++++++++++++++------------------------------- 1 file changed, 45 insertions(+), 49 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 8c7d49c..72b2dc2 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -18,35 +18,32 @@ static void finalize(node_block* b, int line_number); static node_block* make_block(int tag, int start_line, int start_column) { node_block* e; - e = (node_block*) malloc(sizeof(node_block)); + + e = malloc(sizeof(node_block)); + memset(e, 0x0, sizeof(*e)); + e->tag = tag; e->open = true; - e->last_line_blank = false; e->start_line = start_line; e->start_column = start_column; e->end_line = start_line; - e->children = NULL; - e->last_child = NULL; - e->parent = NULL; - e->top = NULL; - e->attributes.refmap = NULL; strbuf_init(&e->string_content, 32); - e->inline_content = NULL; - e->next = NULL; - e->prev = NULL; + return e; } // Create a root document node_block. extern node_block* make_document() { - node_block * e = make_block(BLOCK_DOCUMENT, 1, 1); - reference * map = NULL; + node_block *e = make_block(BLOCK_DOCUMENT, 1, 1); + reference *map = NULL; reference ** refmap; + refmap = (reference**) malloc(sizeof(reference*)); *refmap = map; - e->attributes.refmap = refmap; + e->as.document.refmap = refmap; e->top = e; + return e; } @@ -128,8 +125,8 @@ static bool ends_with_blank_line(node_block* node_block) // Break out of all containing lists static int break_out_of_lists(node_block ** bptr, int line_number) { - node_block * container = *bptr; - node_block * b = container->top; + node_block *container = *bptr; + node_block *b = container->top; // find first containing BLOCK_LIST: while (b && b->tag != BLOCK_LIST) { b = b->last_child; @@ -167,7 +164,7 @@ static void finalize(node_block* b, int line_number) case BLOCK_PARAGRAPH: pos = 0; while (strbuf_at(&b->string_content, 0) == '[' && - (pos = parse_reference(&b->string_content, b->top->attributes.refmap))) { + (pos = parse_reference(&b->string_content, b->top->as.document.refmap))) { strbuf_drop(&b->string_content, pos); } @@ -185,27 +182,27 @@ static void finalize(node_block* b, int line_number) // first line of contents becomes info firstlinelen = strbuf_strchr(&b->string_content, '\n', 0); - strbuf_init(&b->attributes.fenced_code_data.info, 0); + strbuf_init(&b->as.code.info, 0); houdini_unescape_html_f( - &b->attributes.fenced_code_data.info, + &b->as.code.info, b->string_content.ptr, firstlinelen ); strbuf_drop(&b->string_content, firstlinelen + 1); - strbuf_trim(&b->attributes.fenced_code_data.info); - unescape_buffer(&b->attributes.fenced_code_data.info); + strbuf_trim(&b->as.code.info); + unescape_buffer(&b->as.code.info); break; case BLOCK_LIST: // determine tight/loose status - b->attributes.list_data.tight = true; // tight by default + b->as.list.tight = true; // tight by default item = b->children; while (item) { // check for non-final non-empty list item ending with blank line: if (item->last_line_blank && item->next) { - b->attributes.list_data.tight = false; + b->as.list.tight = false; break; } // recurse into children of list item, to see if there are @@ -214,12 +211,12 @@ static void finalize(node_block* b, int line_number) while (subitem) { if (ends_with_blank_line(subitem) && (item->next || subitem->next)) { - b->attributes.list_data.tight = false; + b->as.list.tight = false; break; } subitem = subitem->next; } - if (!(b->attributes.list_data.tight)) { + if (!(b->as.list.tight)) { break; } item = item->next; @@ -269,9 +266,9 @@ extern void free_blocks(node_block* e) free_inlines(e->inline_content); strbuf_free(&e->string_content); if (e->tag == BLOCK_FENCED_CODE) { - strbuf_free(&e->attributes.fenced_code_data.info); + strbuf_free(&e->as.code.info); } else if (e->tag == BLOCK_DOCUMENT) { - free_reference_map(e->attributes.refmap); + free_reference_map(e->as.document.refmap); } free_blocks(e->children); free(e); @@ -362,13 +359,12 @@ static int parse_list_marker(chunk *input, int pos, struct ListData ** dataptr) } // Return 1 if list item belongs in list, else 0. -static int lists_match(struct ListData list_data, - struct ListData item_data) +static int lists_match(struct ListData *list_data, struct ListData *item_data) { - return (list_data.list_type == item_data.list_type && - list_data.delimiter == item_data.delimiter && - // list_data.marker_offset == item_data.marker_offset && - list_data.bullet_char == item_data.bullet_char); + return (list_data->list_type == item_data->list_type && + list_data->delimiter == item_data->delimiter && + // list_data->marker_offset == item_data.marker_offset && + list_data->bullet_char == item_data->bullet_char); } static node_block *finalize_document(node_block *document, int linenum) @@ -379,7 +375,7 @@ static node_block *finalize_document(node_block *document, int linenum) } finalize(document, linenum); - process_inlines(document, document->attributes.refmap); + process_inlines(document, document->as.document.refmap); return document; } @@ -496,10 +492,10 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) } else if (container->tag == BLOCK_LIST_ITEM) { - if (indent >= container->attributes.list_data.marker_offset + - container->attributes.list_data.padding) { - offset += container->attributes.list_data.marker_offset + - container->attributes.list_data.padding; + if (indent >= container->as.list.marker_offset + + container->as.list.padding) { + offset += container->as.list.marker_offset + + container->as.list.padding; } else if (blank) { offset = first_nonspace; } else { @@ -525,7 +521,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) } else if (container->tag == BLOCK_FENCED_CODE) { // skip optional spaces of fence offset - i = container->attributes.fenced_code_data.fence_offset; + i = container->as.code.fence_offset; while (i > 0 && peek_at(&input, offset) == ' ') { offset++; i--; @@ -598,14 +594,14 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) level++; hashpos++; } - container->attributes.header_level = level; + container->as.header.level = level; } else if ((matched = scan_open_code_fence(&input, first_nonspace))) { container = add_child(container, BLOCK_FENCED_CODE, line_number, first_nonspace + 1); - container->attributes.fenced_code_data.fence_char = peek_at(&input, first_nonspace); - container->attributes.fenced_code_data.fence_length = matched; - container->attributes.fenced_code_data.fence_offset = first_nonspace - offset; + container->as.code.fence_char = peek_at(&input, first_nonspace); + container->as.code.fence_length = matched; + container->as.code.fence_offset = first_nonspace - offset; offset = first_nonspace + matched; } else if ((matched = scan_html_block_tag(&input, first_nonspace))) { @@ -620,7 +616,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) strbuf_len(&container->string_content) - 2) < 0) { container->tag = BLOCK_SETEXT_HEADER; - container->attributes.header_level = lev; + container->as.header.level = lev; offset = input.len - 1; } else if (!(container->tag == BLOCK_PARAGRAPH && !all_matched) && @@ -657,19 +653,19 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) data->marker_offset = indent; if (container->tag != BLOCK_LIST || - !lists_match(container->attributes.list_data, *data)) { + !lists_match(&container->as.list, data)) { container = add_child(container, BLOCK_LIST, line_number, first_nonspace + 1); - container->attributes.list_data = *data; + + memcpy(&container->as.list, data, sizeof(*data)); } // add the list item container = add_child(container, BLOCK_LIST_ITEM, line_number, first_nonspace + 1); /* TODO: static */ - container->attributes.list_data = *data; + memcpy(&container->as.list, data, sizeof(*data)); free(data); - } else { break; } @@ -732,9 +728,9 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr) matched = 0; if (indent <= 3 && - peek_at(&input, first_nonspace) == container->attributes.fenced_code_data.fence_char) { + peek_at(&input, first_nonspace) == container->as.code.fence_char) { int fence_len = scan_close_code_fence(&input, first_nonspace); - if (fence_len > container->attributes.fenced_code_data.fence_length) + if (fence_len > container->as.code.fence_length) matched = 1; } -- cgit v1.2.3 From 94a79a605f3e76a43f1f87a5044f6761b99e5ca5 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 10 Sep 2014 18:33:27 +0200 Subject: Cleanup reference implementation --- src/blocks.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 72b2dc2..30a8284 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -8,7 +8,6 @@ #include "utf8.h" #include "html/houdini.h" #include "scanners.h" -#include "uthash.h" #define peek_at(i, n) (i)->data[n] @@ -36,12 +35,7 @@ static node_block* make_block(int tag, int start_line, int start_column) extern node_block* make_document() { node_block *e = make_block(BLOCK_DOCUMENT, 1, 1); - reference *map = NULL; - reference ** refmap; - - refmap = (reference**) malloc(sizeof(reference*)); - *refmap = map; - e->as.document.refmap = refmap; + e->as.document.refmap = reference_map_new(); e->top = e; return e; @@ -164,7 +158,7 @@ static void finalize(node_block* b, int line_number) case BLOCK_PARAGRAPH: pos = 0; while (strbuf_at(&b->string_content, 0) == '[' && - (pos = parse_reference(&b->string_content, b->top->as.document.refmap))) { + (pos = parse_reference_inline(&b->string_content, b->top->as.document.refmap))) { strbuf_drop(&b->string_content, pos); } @@ -192,7 +186,7 @@ static void finalize(node_block* b, int line_number) strbuf_drop(&b->string_content, firstlinelen + 1); strbuf_trim(&b->as.code.info); - unescape_buffer(&b->as.code.info); + strbuf_unescape(&b->as.code.info); break; case BLOCK_LIST: // determine tight/loose status @@ -268,7 +262,7 @@ extern void free_blocks(node_block* e) if (e->tag == BLOCK_FENCED_CODE) { strbuf_free(&e->as.code.info); } else if (e->tag == BLOCK_DOCUMENT) { - free_reference_map(e->as.document.refmap); + reference_map_free(e->as.document.refmap); } free_blocks(e->children); free(e); @@ -278,7 +272,7 @@ extern void free_blocks(node_block* e) // Walk through node_block and all children, recursively, parsing // string content into inline content where appropriate. -void process_inlines(node_block* cur, reference** refmap) +void process_inlines(node_block* cur, reference_map *refmap) { switch (cur->tag) { case BLOCK_PARAGRAPH: -- cgit v1.2.3 From 118e3d3c39242225baa876319cdbfbb1adadc77b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Mon, 15 Sep 2014 15:28:49 +0200 Subject: Cleanup external APIs --- src/blocks.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 30a8284..2ac7032 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -6,8 +6,9 @@ #include "stmd.h" #include "utf8.h" -#include "html/houdini.h" #include "scanners.h" +#include "inlines.h" +#include "html/houdini.h" #define peek_at(i, n) (i)->data[n] @@ -224,7 +225,7 @@ static void finalize(node_block* b, int line_number) } // Add a node_block as child of another. Return pointer to child. -extern node_block* add_child(node_block* parent, +static node_block* add_child(node_block* parent, int block_type, int start_line, int start_column) { assert(parent); @@ -252,7 +253,7 @@ extern node_block* add_child(node_block* parent, } // Free a node_block list and any children. -extern void free_blocks(node_block* e) +void stmd_free_nodes(node_block *e) { node_block * next; while (e != NULL) { @@ -264,7 +265,7 @@ extern void free_blocks(node_block* e) } else if (e->tag == BLOCK_DOCUMENT) { reference_map_free(e->as.document.refmap); } - free_blocks(e->children); + stmd_free_nodes(e->children); free(e); e = next; } @@ -279,8 +280,6 @@ void process_inlines(node_block* cur, reference_map *refmap) case BLOCK_ATX_HEADER: case BLOCK_SETEXT_HEADER: cur->inline_content = parse_inlines(&cur->string_content, refmap); - // MEM - // strbuf_free(&cur->string_content); break; default: -- cgit v1.2.3 From 3aa56049d4b52b55a2313e51698090ee81e10036 Mon Sep 17 00:00:00 2001 From: Jordan Milne Date: Fri, 12 Sep 2014 04:42:30 -0300 Subject: Better handle trailing backslashes in ATX-style headers Previously something like '# `\' would hang the parser while it waited for an extra character that wasn't there. --- src/blocks.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/blocks.c') diff --git a/src/blocks.c b/src/blocks.c index 2ac7032..5b38116 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -420,17 +420,17 @@ extern node_block *stmd_parse_document(const unsigned char *buffer, size_t len) static void chop_trailing_hashtags(chunk *ch) { - int n; + int n, orig_n; chunk_rtrim(ch); - n = ch->len - 1; + orig_n = n = ch->len - 1; // if string ends in #s, remove these: while (n >= 0 && peek_at(ch, n) == '#') n--; // the last # was escaped, so we include it. - if (n >= 0 && peek_at(ch, n) == '\\') + if (n != orig_n && n >= 0 && peek_at(ch, n) == '\\') n++; ch->len = n + 1; -- cgit v1.2.3