diff options
Diffstat (limited to 'libraries/hoedown/src/document.c')
-rw-r--r-- | libraries/hoedown/src/document.c | 4030 |
1 files changed, 2015 insertions, 2015 deletions
diff --git a/libraries/hoedown/src/document.c b/libraries/hoedown/src/document.c index 8ba82e47..e9e2ab11 100644 --- a/libraries/hoedown/src/document.c +++ b/libraries/hoedown/src/document.c @@ -10,7 +10,7 @@ #ifndef _MSC_VER #include <strings.h> #else -#define strncasecmp _strnicmp +#define strncasecmp _strnicmp #endif #define REF_TABLE_SIZE 8 @@ -18,7 +18,7 @@ #define BUFFER_BLOCK 0 #define BUFFER_SPAN 1 -#define HOEDOWN_LI_END 8 /* internal list flag */ +#define HOEDOWN_LI_END 8 /* internal list flag */ const char *hoedown_find_block_tag(const char *str, unsigned int len); @@ -28,35 +28,35 @@ const char *hoedown_find_block_tag(const char *str, unsigned int len); /* link_ref: reference to a link */ struct link_ref { - unsigned int id; + unsigned int id; - hoedown_buffer *link; - hoedown_buffer *title; + hoedown_buffer *link; + hoedown_buffer *title; - struct link_ref *next; + struct link_ref *next; }; /* footnote_ref: reference to a footnote */ struct footnote_ref { - unsigned int id; + unsigned int id; - int is_used; - unsigned int num; + int is_used; + unsigned int num; - hoedown_buffer *contents; + hoedown_buffer *contents; }; /* footnote_item: an item in a footnote_list */ struct footnote_item { - struct footnote_ref *ref; - struct footnote_item *next; + struct footnote_ref *ref; + struct footnote_item *next; }; /* footnote_list: linked list of footnote_item */ struct footnote_list { - unsigned int count; - struct footnote_item *head; - struct footnote_item *tail; + unsigned int count; + struct footnote_item *head; + struct footnote_item *tail; }; /* char_trigger: function pointer to render active chars */ @@ -81,51 +81,51 @@ static size_t char_superscript(hoedown_buffer *ob, hoedown_document *doc, uint8_ static size_t char_math(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size); enum markdown_char_t { - MD_CHAR_NONE = 0, - MD_CHAR_EMPHASIS, - MD_CHAR_CODESPAN, - MD_CHAR_LINEBREAK, - MD_CHAR_LINK, - MD_CHAR_LANGLE, - MD_CHAR_ESCAPE, - MD_CHAR_ENTITY, - MD_CHAR_AUTOLINK_URL, - MD_CHAR_AUTOLINK_EMAIL, - MD_CHAR_AUTOLINK_WWW, - MD_CHAR_SUPERSCRIPT, - MD_CHAR_QUOTE, - MD_CHAR_MATH + MD_CHAR_NONE = 0, + MD_CHAR_EMPHASIS, + MD_CHAR_CODESPAN, + MD_CHAR_LINEBREAK, + MD_CHAR_LINK, + MD_CHAR_LANGLE, + MD_CHAR_ESCAPE, + MD_CHAR_ENTITY, + MD_CHAR_AUTOLINK_URL, + MD_CHAR_AUTOLINK_EMAIL, + MD_CHAR_AUTOLINK_WWW, + MD_CHAR_SUPERSCRIPT, + MD_CHAR_QUOTE, + MD_CHAR_MATH }; static char_trigger markdown_char_ptrs[] = { - NULL, - &char_emphasis, - &char_codespan, - &char_linebreak, - &char_link, - &char_langle_tag, - &char_escape, - &char_entity, - &char_autolink_url, - &char_autolink_email, - &char_autolink_www, - &char_superscript, - &char_quote, - &char_math + NULL, + &char_emphasis, + &char_codespan, + &char_linebreak, + &char_link, + &char_langle_tag, + &char_escape, + &char_entity, + &char_autolink_url, + &char_autolink_email, + &char_autolink_www, + &char_superscript, + &char_quote, + &char_math }; struct hoedown_document { - hoedown_renderer md; - hoedown_renderer_data data; - - struct link_ref *refs[REF_TABLE_SIZE]; - struct footnote_list footnotes_found; - struct footnote_list footnotes_used; - uint8_t active_char[256]; - hoedown_stack work_bufs[2]; - hoedown_extensions ext_flags; - size_t max_nesting; - int in_link_body; + hoedown_renderer md; + hoedown_renderer_data data; + + struct link_ref *refs[REF_TABLE_SIZE]; + struct footnote_list footnotes_found; + struct footnote_list footnotes_used; + uint8_t active_char[256]; + hoedown_stack work_bufs[2]; + hoedown_extensions ext_flags; + size_t max_nesting; + int in_link_body; }; /*************************** @@ -135,177 +135,177 @@ struct hoedown_document { static hoedown_buffer * newbuf(hoedown_document *doc, int type) { - static const size_t buf_size[2] = {256, 64}; - hoedown_buffer *work = NULL; - hoedown_stack *pool = &doc->work_bufs[type]; + static const size_t buf_size[2] = {256, 64}; + hoedown_buffer *work = NULL; + hoedown_stack *pool = &doc->work_bufs[type]; - if (pool->size < pool->asize && - pool->item[pool->size] != NULL) { - work = pool->item[pool->size++]; - work->size = 0; - } else { - work = hoedown_buffer_new(buf_size[type]); - hoedown_stack_push(pool, work); - } + if (pool->size < pool->asize && + pool->item[pool->size] != NULL) { + work = pool->item[pool->size++]; + work->size = 0; + } else { + work = hoedown_buffer_new(buf_size[type]); + hoedown_stack_push(pool, work); + } - return work; + return work; } static void popbuf(hoedown_document *doc, int type) { - doc->work_bufs[type].size--; + doc->work_bufs[type].size--; } static void unscape_text(hoedown_buffer *ob, hoedown_buffer *src) { - size_t i = 0, org; - while (i < src->size) { - org = i; - while (i < src->size && src->data[i] != '\\') - i++; + size_t i = 0, org; + while (i < src->size) { + org = i; + while (i < src->size && src->data[i] != '\\') + i++; - if (i > org) - hoedown_buffer_put(ob, src->data + org, i - org); + if (i > org) + hoedown_buffer_put(ob, src->data + org, i - org); - if (i + 1 >= src->size) - break; + if (i + 1 >= src->size) + break; - hoedown_buffer_putc(ob, src->data[i + 1]); - i += 2; - } + hoedown_buffer_putc(ob, src->data[i + 1]); + i += 2; + } } static unsigned int hash_link_ref(const uint8_t *link_ref, size_t length) { - size_t i; - unsigned int hash = 0; + size_t i; + unsigned int hash = 0; - for (i = 0; i < length; ++i) - hash = tolower(link_ref[i]) + (hash << 6) + (hash << 16) - hash; + for (i = 0; i < length; ++i) + hash = tolower(link_ref[i]) + (hash << 6) + (hash << 16) - hash; - return hash; + return hash; } static struct link_ref * add_link_ref( - struct link_ref **references, - const uint8_t *name, size_t name_size) + struct link_ref **references, + const uint8_t *name, size_t name_size) { - struct link_ref *ref = hoedown_calloc(1, sizeof(struct link_ref)); + struct link_ref *ref = hoedown_calloc(1, sizeof(struct link_ref)); - ref->id = hash_link_ref(name, name_size); - ref->next = references[ref->id % REF_TABLE_SIZE]; + ref->id = hash_link_ref(name, name_size); + ref->next = references[ref->id % REF_TABLE_SIZE]; - references[ref->id % REF_TABLE_SIZE] = ref; - return ref; + references[ref->id % REF_TABLE_SIZE] = ref; + return ref; } static struct link_ref * find_link_ref(struct link_ref **references, uint8_t *name, size_t length) { - unsigned int hash = hash_link_ref(name, length); - struct link_ref *ref = NULL; + unsigned int hash = hash_link_ref(name, length); + struct link_ref *ref = NULL; - ref = references[hash % REF_TABLE_SIZE]; + ref = references[hash % REF_TABLE_SIZE]; - while (ref != NULL) { - if (ref->id == hash) - return ref; + while (ref != NULL) { + if (ref->id == hash) + return ref; - ref = ref->next; - } + ref = ref->next; + } - return NULL; + return NULL; } static void free_link_refs(struct link_ref **references) { - size_t i; + size_t i; - for (i = 0; i < REF_TABLE_SIZE; ++i) { - struct link_ref *r = references[i]; - struct link_ref *next; + for (i = 0; i < REF_TABLE_SIZE; ++i) { + struct link_ref *r = references[i]; + struct link_ref *next; - while (r) { - next = r->next; - hoedown_buffer_free(r->link); - hoedown_buffer_free(r->title); - free(r); - r = next; - } - } + while (r) { + next = r->next; + hoedown_buffer_free(r->link); + hoedown_buffer_free(r->title); + free(r); + r = next; + } + } } static struct footnote_ref * create_footnote_ref(struct footnote_list *list, const uint8_t *name, size_t name_size) { - struct footnote_ref *ref = hoedown_calloc(1, sizeof(struct footnote_ref)); + struct footnote_ref *ref = hoedown_calloc(1, sizeof(struct footnote_ref)); - ref->id = hash_link_ref(name, name_size); + ref->id = hash_link_ref(name, name_size); - return ref; + return ref; } static int add_footnote_ref(struct footnote_list *list, struct footnote_ref *ref) { - struct footnote_item *item = hoedown_calloc(1, sizeof(struct footnote_item)); - if (!item) - return 0; - item->ref = ref; + struct footnote_item *item = hoedown_calloc(1, sizeof(struct footnote_item)); + if (!item) + return 0; + item->ref = ref; - if (list->head == NULL) { - list->head = list->tail = item; - } else { - list->tail->next = item; - list->tail = item; - } - list->count++; + if (list->head == NULL) { + list->head = list->tail = item; + } else { + list->tail->next = item; + list->tail = item; + } + list->count++; - return 1; + return 1; } static struct footnote_ref * find_footnote_ref(struct footnote_list *list, uint8_t *name, size_t length) { - unsigned int hash = hash_link_ref(name, length); - struct footnote_item *item = NULL; + unsigned int hash = hash_link_ref(name, length); + struct footnote_item *item = NULL; - item = list->head; + item = list->head; - while (item != NULL) { - if (item->ref->id == hash) - return item->ref; - item = item->next; - } + while (item != NULL) { + if (item->ref->id == hash) + return item->ref; + item = item->next; + } - return NULL; + return NULL; } static void free_footnote_ref(struct footnote_ref *ref) { - hoedown_buffer_free(ref->contents); - free(ref); + hoedown_buffer_free(ref->contents); + free(ref); } static void free_footnote_list(struct footnote_list *list, int free_refs) { - struct footnote_item *item = list->head; - struct footnote_item *next; + struct footnote_item *item = list->head; + struct footnote_item *next; - while (item) { - next = item->next; - if (free_refs) - free_footnote_ref(item->ref); - free(item); - item = next; - } + while (item) { + next = item->next; + if (free_refs) + free_footnote_ref(item->ref); + free(item); + item = next; + } } @@ -323,16 +323,16 @@ free_footnote_list(struct footnote_list *list, int free_refs) static int _isspace(int c) { - return c == ' ' || c == '\n'; + return c == ' ' || c == '\n'; } /* is_empty_all: verify that all the data is spacing */ static int is_empty_all(const uint8_t *data, size_t size) { - size_t i = 0; - while (i < size && _isspace(data[i])) i++; - return i == size; + size_t i = 0; + while (i < size && _isspace(data[i])) i++; + return i == size; } /* @@ -342,19 +342,19 @@ is_empty_all(const uint8_t *data, size_t size) static void replace_spacing(hoedown_buffer *ob, const uint8_t *data, size_t size) { - size_t i = 0, mark; - hoedown_buffer_grow(ob, size); - while (1) { - mark = i; - while (i < size && data[i] != '\n') i++; - hoedown_buffer_put(ob, data + mark, i - mark); + size_t i = 0, mark; + hoedown_buffer_grow(ob, size); + while (1) { + mark = i; + while (i < size && data[i] != '\n') i++; + hoedown_buffer_put(ob, data + mark, i - mark); - if (i >= size) break; + if (i >= size) break; - if (!(i > 0 && data[i-1] == ' ')) - hoedown_buffer_putc(ob, ' '); - i++; - } + if (!(i > 0 && data[i-1] == ' ')) + hoedown_buffer_putc(ob, ' '); + i++; + } } /**************************** @@ -366,237 +366,237 @@ replace_spacing(hoedown_buffer *ob, const uint8_t *data, size_t size) static size_t is_mail_autolink(uint8_t *data, size_t size) { - size_t i = 0, nb = 0; + size_t i = 0, nb = 0; - /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */ - for (i = 0; i < size; ++i) { - if (isalnum(data[i])) - continue; + /* address is assumed to be: [-@._a-zA-Z0-9]+ with exactly one '@' */ + for (i = 0; i < size; ++i) { + if (isalnum(data[i])) + continue; - switch (data[i]) { - case '@': - nb++; + switch (data[i]) { + case '@': + nb++; - case '-': - case '.': - case '_': - break; + case '-': + case '.': + case '_': + break; - case '>': - return (nb == 1) ? i + 1 : 0; + case '>': + return (nb == 1) ? i + 1 : 0; - default: - return 0; - } - } + default: + return 0; + } + } - return 0; + return 0; } /* tag_length • returns the length of the given tag, or 0 is it's not valid */ static size_t tag_length(uint8_t *data, size_t size, hoedown_autolink_type *autolink) { - size_t i, j; + size_t i, j; - /* a valid tag can't be shorter than 3 chars */ - if (size < 3) return 0; + /* a valid tag can't be shorter than 3 chars */ + if (size < 3) return 0; - /* begins with a '<' optionally followed by '/', followed by letter or number */ - if (data[0] != '<') return 0; - i = (data[1] == '/') ? 2 : 1; + /* begins with a '<' optionally followed by '/', followed by letter or number */ + if (data[0] != '<') return 0; + i = (data[1] == '/') ? 2 : 1; - if (!isalnum(data[i])) - return 0; + if (!isalnum(data[i])) + return 0; - /* scheme test */ - *autolink = HOEDOWN_AUTOLINK_NONE; + /* scheme test */ + *autolink = HOEDOWN_AUTOLINK_NONE; - /* try to find the beginning of an URI */ - while (i < size && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-')) - i++; + /* try to find the beginning of an URI */ + while (i < size && (isalnum(data[i]) || data[i] == '.' || data[i] == '+' || data[i] == '-')) + i++; - if (i > 1 && data[i] == '@') { - if ((j = is_mail_autolink(data + i, size - i)) != 0) { - *autolink = HOEDOWN_AUTOLINK_EMAIL; - return i + j; - } - } + if (i > 1 && data[i] == '@') { + if ((j = is_mail_autolink(data + i, size - i)) != 0) { + *autolink = HOEDOWN_AUTOLINK_EMAIL; + return i + j; + } + } - if (i > 2 && data[i] == ':') { - *autolink = HOEDOWN_AUTOLINK_NORMAL; - i++; - } + if (i > 2 && data[i] == ':') { + *autolink = HOEDOWN_AUTOLINK_NORMAL; + i++; + } - /* completing autolink test: no spacing or ' or " */ - if (i >= size) - *autolink = HOEDOWN_AUTOLINK_NONE; + /* completing autolink test: no spacing or ' or " */ + if (i >= size) + *autolink = HOEDOWN_AUTOLINK_NONE; - else if (*autolink) { - j = i; + else if (*autolink) { + j = i; - while (i < size) { - if (data[i] == '\\') i += 2; - else if (data[i] == '>' || data[i] == '\'' || - data[i] == '"' || data[i] == ' ' || data[i] == '\n') - break; - else i++; - } + while (i < size) { + if (data[i] == '\\') i += 2; + else if (data[i] == '>' || data[i] == '\'' || + data[i] == '"' || data[i] == ' ' || data[i] == '\n') + break; + else i++; + } - if (i >= size) return 0; - if (i > j && data[i] == '>') return i + 1; - /* one of the forbidden chars has been found */ - *autolink = HOEDOWN_AUTOLINK_NONE; - } + if (i >= size) return 0; + if (i > j && data[i] == '>') return i + 1; + /* one of the forbidden chars has been found */ + *autolink = HOEDOWN_AUTOLINK_NONE; + } - /* looking for something looking like a tag end */ - while (i < size && data[i] != '>') i++; - if (i >= size) return 0; - return i + 1; + /* looking for something looking like a tag end */ + while (i < size && data[i] != '>') i++; + if (i >= size) return 0; + return i + 1; } /* parse_inline • parses inline markdown elements */ static void parse_inline(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { - size_t i = 0, end = 0, consumed = 0; - hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL }; - uint8_t *active_char = doc->active_char; - - if (doc->work_bufs[BUFFER_SPAN].size + - doc->work_bufs[BUFFER_BLOCK].size > doc->max_nesting) - return; - - while (i < size) { - /* copying inactive chars into the output */ - while (end < size && active_char[data[end]] == 0) - end++; - - if (doc->md.normal_text) { - work.data = data + i; - work.size = end - i; - doc->md.normal_text(ob, &work, &doc->data); - } - else - hoedown_buffer_put(ob, data + i, end - i); - - if (end >= size) break; - i = end; - - end = markdown_char_ptrs[ (int)active_char[data[end]] ](ob, doc, data + i, i - consumed, size - i); - if (!end) /* no action from the callback */ - end = i + 1; - else { - i += end; - end = i; - consumed = i; - } - } + size_t i = 0, end = 0, consumed = 0; + hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL }; + uint8_t *active_char = doc->active_char; + + if (doc->work_bufs[BUFFER_SPAN].size + + doc->work_bufs[BUFFER_BLOCK].size > doc->max_nesting) + return; + + while (i < size) { + /* copying inactive chars into the output */ + while (end < size && active_char[data[end]] == 0) + end++; + + if (doc->md.normal_text) { + work.data = data + i; + work.size = end - i; + doc->md.normal_text(ob, &work, &doc->data); + } + else + hoedown_buffer_put(ob, data + i, end - i); + + if (end >= size) break; + i = end; + + end = markdown_char_ptrs[ (int)active_char[data[end]] ](ob, doc, data + i, i - consumed, size - i); + if (!end) /* no action from the callback */ + end = i + 1; + else { + i += end; + end = i; + consumed = i; + } + } } /* is_escaped • returns whether special char at data[loc] is escaped by '\\' */ static int is_escaped(uint8_t *data, size_t loc) { - size_t i = loc; - while (i >= 1 && data[i - 1] == '\\') - i--; + size_t i = loc; + while (i >= 1 && data[i - 1] == '\\') + i--; - /* odd numbers of backslashes escapes data[loc] */ - return (loc - i) % 2; + /* odd numbers of backslashes escapes data[loc] */ + return (loc - i) % 2; } /* find_emph_char • looks for the next emph uint8_t, skipping other constructs */ static size_t find_emph_char(uint8_t *data, size_t size, uint8_t c) { - size_t i = 0; + size_t i = 0; - while (i < size) { - while (i < size && data[i] != c && data[i] != '[' && data[i] != '`') - i++; + while (i < size) { + while (i < size && data[i] != c && data[i] != '[' && data[i] != '`') + i++; - if (i == size) - return 0; + if (i == size) + return 0; - /* not counting escaped chars */ - if (is_escaped(data, i)) { - i++; continue; - } + /* not counting escaped chars */ + if (is_escaped(data, i)) { + i++; continue; + } - if (data[i] == c) - return i; + if (data[i] == c) + return i; - /* skipping a codespan */ - if (data[i] == '`') { - size_t span_nb = 0, bt; - size_t tmp_i = 0; + /* skipping a codespan */ + if (data[i] == '`') { + size_t span_nb = 0, bt; + size_t tmp_i = 0; - /* counting the number of opening backticks */ - while (i < size && data[i] == '`') { - i++; span_nb++; - } + /* counting the number of opening backticks */ + while (i < size && data[i] == '`') { + i++; span_nb++; + } - if (i >= size) return 0; + if (i >= size) return 0; - /* finding the matching closing sequence */ - bt = 0; - while (i < size && bt < span_nb) { - if (!tmp_i && data[i] == c) tmp_i = i; - if (data[i] == '`') bt++; - else bt = 0; - i++; - } + /* finding the matching closing sequence */ + bt = 0; + while (i < size && bt < span_nb) { + if (!tmp_i && data[i] == c) tmp_i = i; + if (data[i] == '`') bt++; + else bt = 0; + i++; + } - /* not a well-formed codespan; use found matching emph char */ - if (i >= size) return tmp_i; - } - /* skipping a link */ - else if (data[i] == '[') { - size_t tmp_i = 0; - uint8_t cc; + /* not a well-formed codespan; use found matching emph char */ + if (i >= size) return tmp_i; + } + /* skipping a link */ + else if (data[i] == '[') { + size_t tmp_i = 0; + uint8_t cc; - i++; - while (i < size && data[i] != ']') { - if (!tmp_i && data[i] == c) tmp_i = i; - i++; - } + i++; + while (i < size && data[i] != ']') { + if (!tmp_i && data[i] == c) tmp_i = i; + i++; + } - i++; - while (i < size && _isspace(data[i])) - i++; + i++; + while (i < size && _isspace(data[i])) + i++; - if (i >= size) - return tmp_i; + if (i >= size) + return tmp_i; - switch (data[i]) { - case '[': - cc = ']'; break; + switch (data[i]) { + case '[': + cc = ']'; break; - case '(': - cc = ')'; break; + case '(': + cc = ')'; break; - default: - if (tmp_i) - return tmp_i; - else - continue; - } + default: + if (tmp_i) + return tmp_i; + else + continue; + } - i++; - while (i < size && data[i] != cc) { - if (!tmp_i && data[i] == c) tmp_i = i; - i++; - } + i++; + while (i < size && data[i] != cc) { + if (!tmp_i && data[i] == c) tmp_i = i; + i++; + } - if (i >= size) - return tmp_i; + if (i >= size) + return tmp_i; - i++; - } - } + i++; + } + } - return 0; + return 0; } /* parse_emph1 • parsing single emphase */ @@ -604,72 +604,72 @@ find_emph_char(uint8_t *data, size_t size, uint8_t c) static size_t parse_emph1(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, uint8_t c) { - size_t i = 0, len; - hoedown_buffer *work = 0; - int r; + size_t i = 0, len; + hoedown_buffer *work = 0; + int r; - /* skipping one symbol if coming from emph3 */ - if (size > 1 && data[0] == c && data[1] == c) i = 1; + /* skipping one symbol if coming from emph3 */ + if (size > 1 && data[0] == c && data[1] == c) i = 1; - while (i < size) { - len = find_emph_char(data + i, size - i, c); - if (!len) return 0; - i += len; - if (i >= size) return 0; + while (i < size) { + len = find_emph_char(data + i, size - i, c); + if (!len) return 0; + i += len; + if (i >= size) return 0; - if (data[i] == c && !_isspace(data[i - 1])) { + if (data[i] == c && !_isspace(data[i - 1])) { - if (doc->ext_flags & HOEDOWN_EXT_NO_INTRA_EMPHASIS) { - if (i + 1 < size && isalnum(data[i + 1])) - continue; - } + if (doc->ext_flags & HOEDOWN_EXT_NO_INTRA_EMPHASIS) { + if (i + 1 < size && isalnum(data[i + 1])) + continue; + } - work = newbuf(doc, BUFFER_SPAN); - parse_inline(work, doc, data, i); + work = newbuf(doc, BUFFER_SPAN); + parse_inline(work, doc, data, i); - if (doc->ext_flags & HOEDOWN_EXT_UNDERLINE && c == '_') - r = doc->md.underline(ob, work, &doc->data); - else - r = doc->md.emphasis(ob, work, &doc->data); + if (doc->ext_flags & HOEDOWN_EXT_UNDERLINE && c == '_') + r = doc->md.underline(ob, work, &doc->data); + else + r = doc->md.emphasis(ob, work, &doc->data); - popbuf(doc, BUFFER_SPAN); - return r ? i + 1 : 0; - } - } + popbuf(doc, BUFFER_SPAN); + return r ? i + 1 : 0; + } + } - return 0; + return 0; } /* parse_emph2 • parsing single emphase */ static size_t parse_emph2(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, uint8_t c) { - size_t i = 0, len; - hoedown_buffer *work = 0; - int r; + size_t i = 0, len; + hoedown_buffer *work = 0; + int r; - while (i < size) { - len = find_emph_char(data + i, size - i, c); - if (!len) return 0; - i += len; + while (i < size) { + len = find_emph_char(data + i, size - i, c); + if (!len) return 0; + i += len; - if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) { - work = newbuf(doc, BUFFER_SPAN); - parse_inline(work, doc, data, i); + if (i + 1 < size && data[i] == c && data[i + 1] == c && i && !_isspace(data[i - 1])) { + work = newbuf(doc, BUFFER_SPAN); + parse_inline(work, doc, data, i); - if (c == '~') - r = doc->md.strikethrough(ob, work, &doc->data); - else if (c == '=') - r = doc->md.highlight(ob, work, &doc->data); - else - r = doc->md.double_emphasis(ob, work, &doc->data); + if (c == '~') + r = doc->md.strikethrough(ob, work, &doc->data); + else if (c == '=') + r = doc->md.highlight(ob, work, &doc->data); + else + r = doc->md.double_emphasis(ob, work, &doc->data); - popbuf(doc, BUFFER_SPAN); - return r ? i + 2 : 0; - } - i++; - } - return 0; + popbuf(doc, BUFFER_SPAN); + return r ? i + 2 : 0; + } + i++; + } + return 0; } /* parse_emph3 • parsing single emphase */ @@ -677,121 +677,121 @@ parse_emph2(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz static size_t parse_emph3(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, uint8_t c) { - size_t i = 0, len; - int r; + size_t i = 0, len; + int r; - while (i < size) { - len = find_emph_char(data + i, size - i, c); - if (!len) return 0; - i += len; + while (i < size) { + len = find_emph_char(data + i, size - i, c); + if (!len) return 0; + i += len; - /* skip spacing preceded symbols */ - if (data[i] != c || _isspace(data[i - 1])) - continue; + /* skip spacing preceded symbols */ + if (data[i] != c || _isspace(data[i - 1])) + continue; - if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && doc->md.triple_emphasis) { - /* triple symbol found */ - hoedown_buffer *work = newbuf(doc, BUFFER_SPAN); + if (i + 2 < size && data[i + 1] == c && data[i + 2] == c && doc->md.triple_emphasis) { + /* triple symbol found */ + hoedown_buffer *work = newbuf(doc, BUFFER_SPAN); - parse_inline(work, doc, data, i); - r = doc->md.triple_emphasis(ob, work, &doc->data); - popbuf(doc, BUFFER_SPAN); - return r ? i + 3 : 0; + parse_inline(work, doc, data, i); + r = doc->md.triple_emphasis(ob, work, &doc->data); + popbuf(doc, BUFFER_SPAN); + return r ? i + 3 : 0; - } else if (i + 1 < size && data[i + 1] == c) { - /* double symbol found, handing over to emph1 */ - len = parse_emph1(ob, doc, data - 2, size + 2, c); - if (!len) return 0; - else return len - 2; + } else if (i + 1 < size && data[i + 1] == c) { + /* double symbol found, handing over to emph1 */ + len = parse_emph1(ob, doc, data - 2, size + 2, c); + if (!len) return 0; + else return len - 2; - } else { - /* single symbol found, handing over to emph2 */ - len = parse_emph2(ob, doc, data - 1, size + 1, c); - if (!len) return 0; - else return len - 1; - } - } - return 0; + } else { + /* single symbol found, handing over to emph2 */ + len = parse_emph2(ob, doc, data - 1, size + 1, c); + if (!len) return 0; + else return len - 1; + } + } + return 0; } /* parse_math • parses a math span until the given ending delimiter */ static size_t parse_math(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size, const char *end, size_t delimsz, int displaymode) { - hoedown_buffer text = { NULL, 0, 0, 0, NULL, NULL, NULL }; - size_t i = delimsz; + hoedown_buffer text = { NULL, 0, 0, 0, NULL, NULL, NULL }; + size_t i = delimsz; - if (!doc->md.math) - return 0; + if (!doc->md.math) + return 0; - /* find ending delimiter */ - while (1) { - while (i < size && data[i] != (uint8_t)end[0]) - i++; + /* find ending delimiter */ + while (1) { + while (i < size && data[i] != (uint8_t)end[0]) + i++; - if (i >= size) - return 0; + if (i >= size) + return 0; - if (!is_escaped(data, i) && !(i + delimsz > size) - && memcmp(data + i, end, delimsz) == 0) - break; + if (!is_escaped(data, i) && !(i + delimsz > size) + && memcmp(data + i, end, delimsz) == 0) + break; - i++; - } + i++; + } - /* prepare buffers */ - text.data = data + delimsz; - text.size = i - delimsz; + /* prepare buffers */ + text.data = data + delimsz; + text.size = i - delimsz; - /* if this is a $$ and MATH_EXPLICIT is not active, - * guess whether displaymode should be enabled from the context */ - i += delimsz; - if (delimsz == 2 && !(doc->ext_flags & HOEDOWN_EXT_MATH_EXPLICIT)) - displaymode = is_empty_all(data - offset, offset) && is_empty_all(data + i, size - i); + /* if this is a $$ and MATH_EXPLICIT is not active, + * guess whether displaymode should be enabled from the context */ + i += delimsz; + if (delimsz == 2 && !(doc->ext_flags & HOEDOWN_EXT_MATH_EXPLICIT)) + displaymode = is_empty_all(data - offset, offset) && is_empty_all(data + i, size - i); - /* call callback */ - if (doc->md.math(ob, &text, displaymode, &doc->data)) - return i; + /* call callback */ + if (doc->md.math(ob, &text, displaymode, &doc->data)) + return i; - return 0; + return 0; } /* char_emphasis • single and double emphasis parsing */ static size_t char_emphasis(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - uint8_t c = data[0]; - size_t ret; + uint8_t c = data[0]; + size_t ret; - if (doc->ext_flags & HOEDOWN_EXT_NO_INTRA_EMPHASIS) { - if (offset > 0 && !_isspace(data[-1]) && data[-1] != '>' && data[-1] != '(') - return 0; - } + if (doc->ext_flags & HOEDOWN_EXT_NO_INTRA_EMPHASIS) { + if (offset > 0 && !_isspace(data[-1]) && data[-1] != '>' && data[-1] != '(') + return 0; + } - if (size > 2 && data[1] != c) { - /* spacing cannot follow an opening emphasis; - * strikethrough and highlight only takes two characters '~~' */ - if (c == '~' || c == '=' || _isspace(data[1]) || (ret = parse_emph1(ob, doc, data + 1, size - 1, c)) == 0) - return 0; + if (size > 2 && data[1] != c) { + /* spacing cannot follow an opening emphasis; + * strikethrough and highlight only takes two characters '~~' */ + if (c == '~' || c == '=' || _isspace(data[1]) || (ret = parse_emph1(ob, doc, data + 1, size - 1, c)) == 0) + return 0; - return ret + 1; - } + return ret + 1; + } - if (size > 3 && data[1] == c && data[2] != c) { - if (_isspace(data[2]) || (ret = parse_emph2(ob, doc, data + 2, size - 2, c)) == 0) - return 0; + if (size > 3 && data[1] == c && data[2] != c) { + if (_isspace(data[2]) || (ret = parse_emph2(ob, doc, data + 2, size - 2, c)) == 0) + return 0; - return ret + 2; - } + return ret + 2; + } - if (size > 4 && data[1] == c && data[2] == c && data[3] != c) { - if (c == '~' || c == '=' || _isspace(data[3]) || (ret = parse_emph3(ob, doc, data + 3, size - 3, c)) == 0) - return 0; + if (size > 4 && data[1] == c && data[2] == c && data[3] != c) { + if (c == '~' || c == '=' || _isspace(data[3]) || (ret = parse_emph3(ob, doc, data + 3, size - 3, c)) == 0) + return 0; - return ret + 3; - } + return ret + 3; + } - return 0; + return 0; } @@ -799,14 +799,14 @@ char_emphasis(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t o static size_t char_linebreak(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - if (offset < 2 || data[-1] != ' ' || data[-2] != ' ') - return 0; + if (offset < 2 || data[-1] != ' ' || data[-2] != ' ') + return 0; - /* removing the last space from ob and rendering */ - while (ob->size && ob->data[ob->size - 1] == ' ') - ob->size--; + /* removing the last space from ob and rendering */ + while (ob->size && ob->data[ob->size - 1] == ' ') + ob->size--; - return doc->md.linebreak(ob, &doc->data) ? 1 : 0; + return doc->md.linebreak(ob, &doc->data) ? 1 : 0; } @@ -814,91 +814,91 @@ char_linebreak(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t static size_t char_codespan(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; - size_t end, nb = 0, i, f_begin, f_end; + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; + size_t end, nb = 0, i, f_begin, f_end; - /* counting the number of backticks in the delimiter */ - while (nb < size && data[nb] == '`') - nb++; + /* counting the number of backticks in the delimiter */ + while (nb < size && data[nb] == '`') + nb++; - /* finding the next delimiter */ - i = 0; - for (end = nb; end < size && i < nb; end++) { - if (data[end] == '`') i++; - else i = 0; - } + /* finding the next delimiter */ + i = 0; + for (end = nb; end < size && i < nb; end++) { + if (data[end] == '`') i++; + else i = 0; + } - if (i < nb && end >= size) - return 0; /* no matching delimiter */ + if (i < nb && end >= size) + return 0; /* no matching delimiter */ - /* trimming outside spaces */ - f_begin = nb; - while (f_begin < end && data[f_begin] == ' ') - f_begin++; + /* trimming outside spaces */ + f_begin = nb; + while (f_begin < end && data[f_begin] == ' ') + f_begin++; - f_end = end - nb; - while (f_end > nb && data[f_end-1] == ' ') - f_end--; + f_end = end - nb; + while (f_end > nb && data[f_end-1] == ' ') + f_end--; - /* real code span */ - if (f_begin < f_end) { - work.data = data + f_begin; - work.size = f_end - f_begin; + /* real code span */ + if (f_begin < f_end) { + work.data = data + f_begin; + work.size = f_end - f_begin; - if (!doc->md.codespan(ob, &work, &doc->data)) - end = 0; - } else { - if (!doc->md.codespan(ob, 0, &doc->data)) - end = 0; - } + if (!doc->md.codespan(ob, &work, &doc->data)) + end = 0; + } else { + if (!doc->md.codespan(ob, 0, &doc->data)) + end = 0; + } - return end; + return end; } /* char_quote • '"' parsing a quote */ static size_t char_quote(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - size_t end, nq = 0, i, f_begin, f_end; + size_t end, nq = 0, i, f_begin, f_end; - /* counting the number of quotes in the delimiter */ - while (nq < size && data[nq] == '"') - nq++; + /* counting the number of quotes in the delimiter */ + while (nq < size && data[nq] == '"') + nq++; - /* finding the next delimiter */ - end = nq; - while (1) { - i = end; - end += find_emph_char(data + end, size - end, '"'); - if (end == i) return 0; /* no matching delimiter */ - i = end; - while (end < size && data[end] == '"' && end - i < nq) end++; - if (end - i >= nq) break; - } + /* finding the next delimiter */ + end = nq; + while (1) { + i = end; + end += find_emph_char(data + end, size - end, '"'); + if (end == i) return 0; /* no matching delimiter */ + i = end; + while (end < size && data[end] == '"' && end - i < nq) end++; + if (end - i >= nq) break; + } - /* trimming outside spaces */ - f_begin = nq; - while (f_begin < end && data[f_begin] == ' ') - f_begin++; + /* trimming outside spaces */ + f_begin = nq; + while (f_begin < end && data[f_begin] == ' ') + f_begin++; - f_end = end - nq; - while (f_end > nq && data[f_end-1] == ' ') - f_end--; + f_end = end - nq; + while (f_end > nq && data[f_end-1] == ' ') + f_end--; - /* real quote */ - if (f_begin < f_end) { - hoedown_buffer *work = newbuf(doc, BUFFER_SPAN); - parse_inline(work, doc, data + f_begin, f_end - f_begin); + /* real quote */ + if (f_begin < f_end) { + hoedown_buffer *work = newbuf(doc, BUFFER_SPAN); + parse_inline(work, doc, data + f_begin, f_end - f_begin); - if (!doc->md.quote(ob, work, &doc->data)) - end = 0; - popbuf(doc, BUFFER_SPAN); - } else { - if (!doc->md.quote(ob, 0, &doc->data)) - end = 0; - } + if (!doc->md.quote(ob, work, &doc->data)) + end = 0; + popbuf(doc, BUFFER_SPAN); + } else { + if (!doc->md.quote(ob, 0, &doc->data)) + end = 0; + } - return end; + return end; } @@ -906,32 +906,32 @@ char_quote(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offs static size_t char_escape(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - static const char *escape_chars = "\\`*_{}[]()#+-.!:|&<>^~=\"$"; - hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL }; - size_t w; + static const char *escape_chars = "\\`*_{}[]()#+-.!:|&<>^~=\"$"; + hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL }; + size_t w; - if (size > 1) { - if (data[1] == '\\' && (doc->ext_flags & HOEDOWN_EXT_MATH) && - size > 2 && (data[2] == '(' || data[2] == '[')) { - const char *end = (data[2] == '[') ? "\\\\]" : "\\\\)"; - w = parse_math(ob, doc, data, offset, size, end, 3, data[2] == '['); - if (w) return w; - } + if (size > 1) { + if (data[1] == '\\' && (doc->ext_flags & HOEDOWN_EXT_MATH) && + size > 2 && (data[2] == '(' || data[2] == '[')) { + const char *end = (data[2] == '[') ? "\\\\]" : "\\\\)"; + w = parse_math(ob, doc, data, offset, size, end, 3, data[2] == '['); + if (w) return w; + } - if (strchr(escape_chars, data[1]) == NULL) - return 0; + if (strchr(escape_chars, data[1]) == NULL) + return 0; - if (doc->md.normal_text) { - work.data = data + 1; - work.size = 1; - doc->md.normal_text(ob, &work, &doc->data); - } - else hoedown_buffer_putc(ob, data[1]); - } else if (size == 1) { - hoedown_buffer_putc(ob, data[0]); - } + if (doc->md.normal_text) { + work.data = data + 1; + work.size = 1; + doc->md.normal_text(ob, &work, &doc->data); + } + else hoedown_buffer_putc(ob, data[1]); + } else if (size == 1) { + hoedown_buffer_putc(ob, data[0]); + } - return 2; + return 2; } /* char_entity • '&' escaped when it doesn't belong to an entity */ @@ -939,403 +939,403 @@ char_escape(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t off static size_t char_entity(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - size_t end = 1; - hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL }; + size_t end = 1; + hoedown_buffer work = { 0, 0, 0, 0, NULL, NULL, NULL }; - if (end < size && data[end] == '#') - end++; + if (end < size && data[end] == '#') + end++; - while (end < size && isalnum(data[end])) - end++; + while (end < size && isalnum(data[end])) + end++; - if (end < size && data[end] == ';') - end++; /* real entity */ - else - return 0; /* lone '&' */ + if (end < size && data[end] == ';') + end++; /* real entity */ + else + return 0; /* lone '&' */ - if (doc->md.entity) { - work.data = data; - work.size = end; - doc->md.entity(ob, &work, &doc->data); - } - else hoedown_buffer_put(ob, data, end); + if (doc->md.entity) { + work.data = data; + work.size = end; + doc->md.entity(ob, &work, &doc->data); + } + else hoedown_buffer_put(ob, data, end); - return end; + return end; } /* char_langle_tag • '<' when tags or autolinks are allowed */ static size_t char_langle_tag(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; - hoedown_autolink_type altype = HOEDOWN_AUTOLINK_NONE; - size_t end = tag_length(data, size, &altype); - int ret = 0; + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; + hoedown_autolink_type altype = HOEDOWN_AUTOLINK_NONE; + size_t end = tag_length(data, size, &altype); + int ret = 0; - work.data = data; - work.size = end; + work.data = data; + work.size = end; - if (end > 2) { - if (doc->md.autolink && altype != HOEDOWN_AUTOLINK_NONE) { - hoedown_buffer *u_link = newbuf(doc, BUFFER_SPAN); - work.data = data + 1; - work.size = end - 2; - unscape_text(u_link, &work); - ret = doc->md.autolink(ob, u_link, altype, &doc->data); - popbuf(doc, BUFFER_SPAN); - } - else if (doc->md.raw_html) - ret = doc->md.raw_html(ob, &work, &doc->data); - } + if (end > 2) { + if (doc->md.autolink && altype != HOEDOWN_AUTOLINK_NONE) { + hoedown_buffer *u_link = newbuf(doc, BUFFER_SPAN); + work.data = data + 1; + work.size = end - 2; + unscape_text(u_link, &work); + ret = doc->md.autolink(ob, u_link, altype, &doc->data); + popbuf(doc, BUFFER_SPAN); + } + else if (doc->md.raw_html) + ret = doc->md.raw_html(ob, &work, &doc->data); + } - if (!ret) return 0; - else return end; + if (!ret) return 0; + else return end; } static size_t char_autolink_www(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - hoedown_buffer *link, *link_url, *link_text; - size_t link_len, rewind; + hoedown_buffer *link, *link_url, *link_text; + size_t link_len, rewind; - if (!doc->md.link || doc->in_link_body) - return 0; + if (!doc->md.link || doc->in_link_body) + return 0; - link = newbuf(doc, BUFFER_SPAN); + link = newbuf(doc, BUFFER_SPAN); - if ((link_len = hoedown_autolink__www(&rewind, link, data, offset, size, HOEDOWN_AUTOLINK_SHORT_DOMAINS)) > 0) { - link_url = newbuf(doc, BUFFER_SPAN); - HOEDOWN_BUFPUTSL(link_url, "http://"); - hoedown_buffer_put(link_url, link->data, link->size); + if ((link_len = hoedown_autolink__www(&rewind, link, data, offset, size, HOEDOWN_AUTOLINK_SHORT_DOMAINS)) > 0) { + link_url = newbuf(doc, BUFFER_SPAN); + HOEDOWN_BUFPUTSL(link_url, "http://"); + hoedown_buffer_put(link_url, link->data, link->size); - ob->size -= rewind; - if (doc->md.normal_text) { - link_text = newbuf(doc, BUFFER_SPAN); - doc->md.normal_text(link_text, link, &doc->data); - doc->md.link(ob, link_text, link_url, NULL, &doc->data); - popbuf(doc, BUFFER_SPAN); - } else { - doc->md.link(ob, link, link_url, NULL, &doc->data); - } - popbuf(doc, BUFFER_SPAN); - } + ob->size -= rewind; + if (doc->md.normal_text) { + link_text = newbuf(doc, BUFFER_SPAN); + doc->md.normal_text(link_text, link, &doc->data); + doc->md.link(ob, link_text, link_url, NULL, &doc->data); + popbuf(doc, BUFFER_SPAN); + } else { + doc->md.link(ob, link, link_url, NULL, &doc->data); + } + popbuf(doc, BUFFER_SPAN); + } - popbuf(doc, BUFFER_SPAN); - return link_len; + popbuf(doc, BUFFER_SPAN); + return link_len; } static size_t char_autolink_email(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - hoedown_buffer *link; - size_t link_len, rewind; + hoedown_buffer *link; + size_t link_len, rewind; - if (!doc->md.autolink || doc->in_link_body) - return 0; + if (!doc->md.autolink || doc->in_link_body) + return 0; - link = newbuf(doc, BUFFER_SPAN); + link = newbuf(doc, BUFFER_SPAN); - if ((link_len = hoedown_autolink__email(&rewind, link, data, offset, size, 0)) > 0) { - ob->size -= rewind; - doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_EMAIL, &doc->data); - } + if ((link_len = hoedown_autolink__email(&rewind, link, data, offset, size, 0)) > 0) { + ob->size -= rewind; + doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_EMAIL, &doc->data); + } - popbuf(doc, BUFFER_SPAN); - return link_len; + popbuf(doc, BUFFER_SPAN); + return link_len; } static size_t char_autolink_url(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - hoedown_buffer *link; - size_t link_len, rewind; + hoedown_buffer *link; + size_t link_len, rewind; - if (!doc->md.autolink || doc->in_link_body) - return 0; + if (!doc->md.autolink || doc->in_link_body) + return 0; - link = newbuf(doc, BUFFER_SPAN); + link = newbuf(doc, BUFFER_SPAN); - if ((link_len = hoedown_autolink__url(&rewind, link, data, offset, size, 0)) > 0) { - ob->size -= rewind; - doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_NORMAL, &doc->data); - } + if ((link_len = hoedown_autolink__url(&rewind, link, data, offset, size, 0)) > 0) { + ob->size -= rewind; + doc->md.autolink(ob, link, HOEDOWN_AUTOLINK_NORMAL, &doc->data); + } - popbuf(doc, BUFFER_SPAN); - return link_len; + popbuf(doc, BUFFER_SPAN); + return link_len; } /* char_link • '[': parsing a link, a footnote or an image */ static size_t char_link(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - int is_img = (offset && data[-1] == '!' && !is_escaped(data - offset, offset - 1)); - int is_footnote = (doc->ext_flags & HOEDOWN_EXT_FOOTNOTES && data[1] == '^'); - size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0; - hoedown_buffer *content = NULL; - hoedown_buffer *link = NULL; - hoedown_buffer *title = NULL; - hoedown_buffer *u_link = NULL; - size_t org_work_size = doc->work_bufs[BUFFER_SPAN].size; - int ret = 0, in_title = 0, qtype = 0; - - /* checking whether the correct renderer exists */ - if ((is_footnote && !doc->md.footnote_ref) || (is_img && !doc->md.image) - || (!is_img && !is_footnote && !doc->md.link)) - goto cleanup; - - /* looking for the matching closing bracket */ - i += find_emph_char(data + i, size - i, ']'); - txt_e = i; - - if (i < size && data[i] == ']') i++; - else goto cleanup; - - /* footnote link */ - if (is_footnote) { - hoedown_buffer id = { NULL, 0, 0, 0, NULL, NULL, NULL }; - struct footnote_ref *fr; - - if (txt_e < 3) - goto cleanup; - - id.data = data + 2; - id.size = txt_e - 2; - - fr = find_footnote_ref(&doc->footnotes_found, id.data, id.size); - - /* mark footnote used */ - if (fr && !fr->is_used) { - if(!add_footnote_ref(&doc->footnotes_used, fr)) - goto cleanup; - fr->is_used = 1; - fr->num = doc->footnotes_used.count; - - /* render */ - if (doc->md.footnote_ref) - ret = doc->md.footnote_ref(ob, fr->num, &doc->data); - } - - goto cleanup; - } - - /* skip any amount of spacing */ - /* (this is much more laxist than original markdown syntax) */ - while (i < size && _isspace(data[i])) - i++; - - /* inline style link */ - if (i < size && data[i] == '(') { - size_t nb_p; - - /* skipping initial spacing */ - i++; - - while (i < size && _isspace(data[i])) - i++; - - link_b = i; - - /* looking for link end: ' " ) */ - /* Count the number of open parenthesis */ - nb_p = 0; - - while (i < size) { - if (data[i] == '\\') i += 2; - else if (data[i] == '(' && i != 0) { - nb_p++; i++; - } - else if (data[i] == ')') { - if (nb_p == 0) break; - else nb_p--; i++; - } else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break; - else i++; - } - - if (i >= size) goto cleanup; - link_e = i; - - /* looking for title end if present */ - if (data[i] == '\'' || data[i] == '"') { - qtype = data[i]; - in_title = 1; - i++; - title_b = i; - - while (i < size) { - if (data[i] == '\\') i += 2; - else if (data[i] == qtype) {in_title = 0; i++;} - else if ((data[i] == ')') && !in_title) break; - else i++; - } - - if (i >= size) goto cleanup; - - /* skipping spacing after title */ - title_e = i - 1; - while (title_e > title_b && _isspace(data[title_e])) - title_e--; - - /* checking for closing quote presence */ - if (data[title_e] != '\'' && data[title_e] != '"') { - title_b = title_e = 0; - link_e = i; - } - } - - /* remove spacing at the end of the link */ - while (link_e > link_b && _isspace(data[link_e - 1])) - link_e--; - - /* remove optional angle brackets around the link */ - if (data[link_b] == '<') link_b++; - if (data[link_e - 1] == '>') link_e--; - - /* building escaped link and title */ - if (link_e > link_b) { - link = newbuf(doc, BUFFER_SPAN); - hoedown_buffer_put(link, data + link_b, link_e - link_b); - } - - if (title_e > title_b) { - title = newbuf(doc, BUFFER_SPAN); - hoedown_buffer_put(title, data + title_b, title_e - title_b); - } - - i++; - } - - /* reference style link */ - else if (i < size && data[i] == '[') { - hoedown_buffer *id = newbuf(doc, BUFFER_SPAN); - struct link_ref *lr; - - /* looking for the id */ - i++; - link_b = i; - while (i < size && data[i] != ']') i++; - if (i >= size) goto cleanup; - link_e = i; - - /* finding the link_ref */ - if (link_b == link_e) - replace_spacing(id, data + 1, txt_e - 1); - else - hoedown_buffer_put(id, data + link_b, link_e - link_b); - - lr = find_link_ref(doc->refs, id->data, id->size); - if (!lr) - goto cleanup; - - /* keeping link and title from link_ref */ - link = lr->link; - title = lr->title; - i++; - } - - /* shortcut reference style link */ - else { - hoedown_buffer *id = newbuf(doc, BUFFER_SPAN); - struct link_ref *lr; - - /* crafting the id */ - replace_spacing(id, data + 1, txt_e - 1); - - /* finding the link_ref */ - lr = find_link_ref(doc->refs, id->data, id->size); - if (!lr) - goto cleanup; - - /* keeping link and title from link_ref */ - link = lr->link; - title = lr->title; - - /* rewinding the spacing */ - i = txt_e + 1; - } - - /* building content: img alt is kept, only link content is parsed */ - if (txt_e > 1) { - content = newbuf(doc, BUFFER_SPAN); - if (is_img) { - hoedown_buffer_put(content, data + 1, txt_e - 1); - } else { - /* disable autolinking when parsing inline the - * content of a link */ - doc->in_link_body = 1; - parse_inline(content, doc, data + 1, txt_e - 1); - doc->in_link_body = 0; - } - } - - if (link) { - u_link = newbuf(doc, BUFFER_SPAN); - unscape_text(u_link, link); - } - - /* calling the relevant rendering function */ - if (is_img) { - if (ob->size && ob->data[ob->size - 1] == '!') - ob->size -= 1; - - ret = doc->md.image(ob, u_link, title, content, &doc->data); - } else { - ret = doc->md.link(ob, content, u_link, title, &doc->data); - } - - /* cleanup */ + int is_img = (offset && data[-1] == '!' && !is_escaped(data - offset, offset - 1)); + int is_footnote = (doc->ext_flags & HOEDOWN_EXT_FOOTNOTES && data[1] == '^'); + size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0; + hoedown_buffer *content = NULL; + hoedown_buffer *link = NULL; + hoedown_buffer *title = NULL; + hoedown_buffer *u_link = NULL; + size_t org_work_size = doc->work_bufs[BUFFER_SPAN].size; + int ret = 0, in_title = 0, qtype = 0; + + /* checking whether the correct renderer exists */ + if ((is_footnote && !doc->md.footnote_ref) || (is_img && !doc->md.image) + || (!is_img && !is_footnote && !doc->md.link)) + goto cleanup; + + /* looking for the matching closing bracket */ + i += find_emph_char(data + i, size - i, ']'); + txt_e = i; + + if (i < size && data[i] == ']') i++; + else goto cleanup; + + /* footnote link */ + if (is_footnote) { + hoedown_buffer id = { NULL, 0, 0, 0, NULL, NULL, NULL }; + struct footnote_ref *fr; + + if (txt_e < 3) + goto cleanup; + + id.data = data + 2; + id.size = txt_e - 2; + + fr = find_footnote_ref(&doc->footnotes_found, id.data, id.size); + + /* mark footnote used */ + if (fr && !fr->is_used) { + if(!add_footnote_ref(&doc->footnotes_used, fr)) + goto cleanup; + fr->is_used = 1; + fr->num = doc->footnotes_used.count; + + /* render */ + if (doc->md.footnote_ref) + ret = doc->md.footnote_ref(ob, fr->num, &doc->data); + } + + goto cleanup; + } + + /* skip any amount of spacing */ + /* (this is much more laxist than original markdown syntax) */ + while (i < size && _isspace(data[i])) + i++; + + /* inline style link */ + if (i < size && data[i] == '(') { + size_t nb_p; + + /* skipping initial spacing */ + i++; + + while (i < size && _isspace(data[i])) + i++; + + link_b = i; + + /* looking for link end: ' " ) */ + /* Count the number of open parenthesis */ + nb_p = 0; + + while (i < size) { + if (data[i] == '\\') i += 2; + else if (data[i] == '(' && i != 0) { + nb_p++; i++; + } + else if (data[i] == ')') { + if (nb_p == 0) break; + else nb_p--; i++; + } else if (i >= 1 && _isspace(data[i-1]) && (data[i] == '\'' || data[i] == '"')) break; + else i++; + } + + if (i >= size) goto cleanup; + link_e = i; + + /* looking for title end if present */ + if (data[i] == '\'' || data[i] == '"') { + qtype = data[i]; + in_title = 1; + i++; + title_b = i; + + while (i < size) { + if (data[i] == '\\') i += 2; + else if (data[i] == qtype) {in_title = 0; i++;} + else if ((data[i] == ')') && !in_title) break; + else i++; + } + + if (i >= size) goto cleanup; + + /* skipping spacing after title */ + title_e = i - 1; + while (title_e > title_b && _isspace(data[title_e])) + title_e--; + + /* checking for closing quote presence */ + if (data[title_e] != '\'' && data[title_e] != '"') { + title_b = title_e = 0; + link_e = i; + } + } + + /* remove spacing at the end of the link */ + while (link_e > link_b && _isspace(data[link_e - 1])) + link_e--; + + /* remove optional angle brackets around the link */ + if (data[link_b] == '<') link_b++; + if (data[link_e - 1] == '>') link_e--; + + /* building escaped link and title */ + if (link_e > link_b) { + link = newbuf(doc, BUFFER_SPAN); + hoedown_buffer_put(link, data + link_b, link_e - link_b); + } + + if (title_e > title_b) { + title = newbuf(doc, BUFFER_SPAN); + hoedown_buffer_put(title, data + title_b, title_e - title_b); + } + + i++; + } + + /* reference style link */ + else if (i < size && data[i] == '[') { + hoedown_buffer *id = newbuf(doc, BUFFER_SPAN); + struct link_ref *lr; + + /* looking for the id */ + i++; + link_b = i; + while (i < size && data[i] != ']') i++; + if (i >= size) goto cleanup; + link_e = i; + + /* finding the link_ref */ + if (link_b == link_e) + replace_spacing(id, data + 1, txt_e - 1); + else + hoedown_buffer_put(id, data + link_b, link_e - link_b); + + lr = find_link_ref(doc->refs, id->data, id->size); + if (!lr) + goto cleanup; + + /* keeping link and title from link_ref */ + link = lr->link; + title = lr->title; + i++; + } + + /* shortcut reference style link */ + else { + hoedown_buffer *id = newbuf(doc, BUFFER_SPAN); + struct link_ref *lr; + + /* crafting the id */ + replace_spacing(id, data + 1, txt_e - 1); + + /* finding the link_ref */ + lr = find_link_ref(doc->refs, id->data, id->size); + if (!lr) + goto cleanup; + + /* keeping link and title from link_ref */ + link = lr->link; + title = lr->title; + + /* rewinding the spacing */ + i = txt_e + 1; + } + + /* building content: img alt is kept, only link content is parsed */ + if (txt_e > 1) { + content = newbuf(doc, BUFFER_SPAN); + if (is_img) { + hoedown_buffer_put(content, data + 1, txt_e - 1); + } else { + /* disable autolinking when parsing inline the + * content of a link */ + doc->in_link_body = 1; + parse_inline(content, doc, data + 1, txt_e - 1); + doc->in_link_body = 0; + } + } + + if (link) { + u_link = newbuf(doc, BUFFER_SPAN); + unscape_text(u_link, link); + } + + /* calling the relevant rendering function */ + if (is_img) { + if (ob->size && ob->data[ob->size - 1] == '!') + ob->size -= 1; + + ret = doc->md.image(ob, u_link, title, content, &doc->data); + } else { + ret = doc->md.link(ob, content, u_link, title, &doc->data); + } + + /* cleanup */ cleanup: - doc->work_bufs[BUFFER_SPAN].size = (int)org_work_size; - return ret ? i : 0; + doc->work_bufs[BUFFER_SPAN].size = (int)org_work_size; + return ret ? i : 0; } static size_t char_superscript(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - size_t sup_start, sup_len; - hoedown_buffer *sup; + size_t sup_start, sup_len; + hoedown_buffer *sup; - if (!doc->md.superscript) - return 0; + if (!doc->md.superscript) + return 0; - if (size < 2) - return 0; + if (size < 2) + return 0; - if (data[1] == '(') { - sup_start = 2; - sup_len = find_emph_char(data + 2, size - 2, ')') + 2; + if (data[1] == '(') { + sup_start = 2; + sup_len = find_emph_char(data + 2, size - 2, ')') + 2; - if (sup_len == size) - return 0; - } else { - sup_start = sup_len = 1; + if (sup_len == size) + return 0; + } else { + sup_start = sup_len = 1; - while (sup_len < size && !_isspace(data[sup_len])) - sup_len++; - } + while (sup_len < size && !_isspace(data[sup_len])) + sup_len++; + } - if (sup_len - sup_start == 0) - return (sup_start == 2) ? 3 : 0; + if (sup_len - sup_start == 0) + return (sup_start == 2) ? 3 : 0; - sup = newbuf(doc, BUFFER_SPAN); - parse_inline(sup, doc, data + sup_start, sup_len - sup_start); - doc->md.superscript(ob, sup, &doc->data); - popbuf(doc, BUFFER_SPAN); + sup = newbuf(doc, BUFFER_SPAN); + parse_inline(sup, doc, data + sup_start, sup_len - sup_start); + doc->md.superscript(ob, sup, &doc->data); + popbuf(doc, BUFFER_SPAN); - return (sup_start == 2) ? sup_len + 1 : sup_len; + return (sup_start == 2) ? sup_len + 1 : sup_len; } static size_t char_math(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offset, size_t size) { - /* double dollar */ - if (size > 1 && data[1] == '$') - return parse_math(ob, doc, data, offset, size, "$$", 2, 1); + /* double dollar */ + if (size > 1 && data[1] == '$') + return parse_math(ob, doc, data, offset, size, "$$", 2, 1); - /* single dollar allowed only with MATH_EXPLICIT flag */ - if (doc->ext_flags & HOEDOWN_EXT_MATH_EXPLICIT) - return parse_math(ob, doc, data, offset, size, "$", 1, 0); + /* single dollar allowed only with MATH_EXPLICIT flag */ + if (doc->ext_flags & HOEDOWN_EXT_MATH_EXPLICIT) + return parse_math(ob, doc, data, offset, size, "$", 1, 0); - return 0; + return 0; } /********************************* @@ -1346,44 +1346,44 @@ char_math(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t offse static size_t is_empty(const uint8_t *data, size_t size) { - size_t i; + size_t i; - for (i = 0; i < size && data[i] != '\n'; i++) - if (data[i] != ' ') - return 0; + for (i = 0; i < size && data[i] != '\n'; i++) + if (data[i] != ' ') + return 0; - return i + 1; + return i + 1; } /* is_hrule • returns whether a line is a horizontal rule */ static int is_hrule(uint8_t *data, size_t size) { - size_t i = 0, n = 0; - uint8_t c; + size_t i = 0, n = 0; + uint8_t c; - /* skipping initial spaces */ - if (size < 3) return 0; - if (data[0] == ' ') { i++; - if (data[1] == ' ') { i++; - if (data[2] == ' ') { i++; } } } + /* skipping initial spaces */ + if (size < 3) return 0; + if (data[0] == ' ') { i++; + if (data[1] == ' ') { i++; + if (data[2] == ' ') { i++; } } } - /* looking at the hrule uint8_t */ - if (i + 2 >= size - || (data[i] != '*' && data[i] != '-' && data[i] != '_')) - return 0; - c = data[i]; + /* looking at the hrule uint8_t */ + if (i + 2 >= size + || (data[i] != '*' && data[i] != '-' && data[i] != '_')) + return 0; + c = data[i]; - /* the whole line must be the char or space */ - while (i < size && data[i] != '\n') { - if (data[i] == c) n++; - else if (data[i] != ' ') - return 0; + /* the whole line must be the char or space */ + while (i < size && data[i] != '\n') { + if (data[i] == c) n++; + else if (data[i] != ' ') + return 0; - i++; - } + i++; + } - return n >= 3; + return n >= 3; } /* check if a line is a code fence; return the @@ -1392,239 +1392,239 @@ is_hrule(uint8_t *data, size_t size) static size_t is_codefence(uint8_t *data, size_t size, size_t *width, uint8_t *chr) { - size_t i = 0, n = 1; - uint8_t c; + size_t i = 0, n = 1; + uint8_t c; - /* skipping initial spaces */ - if (size < 3) - return 0; + /* skipping initial spaces */ + if (size < 3) + return 0; - if (data[0] == ' ') { i++; - if (data[1] == ' ') { i++; - if (data[2] == ' ') { i++; } } } + if (data[0] == ' ') { i++; + if (data[1] == ' ') { i++; + if (data[2] == ' ') { i++; } } } - /* looking at the hrule uint8_t */ - c = data[i]; - if (i + 2 >= size || !(c=='~' || c=='`')) - return 0; + /* looking at the hrule uint8_t */ + c = data[i]; + if (i + 2 >= size || !(c=='~' || c=='`')) + return 0; - /* the fence must be that same character */ - while (++i < size && data[i] == c) - ++n; + /* the fence must be that same character */ + while (++i < size && data[i] == c) + ++n; - if (n < 3) - return 0; + if (n < 3) + return 0; - if (width) *width = n; - if (chr) *chr = c; - return i; + if (width) *width = n; + if (chr) *chr = c; + return i; } /* expects single line, checks if it's a codefence and extracts language */ static size_t parse_codefence(uint8_t *data, size_t size, hoedown_buffer *lang, size_t *width, uint8_t *chr) { - size_t i, w, lang_start; + size_t i, w, lang_start; - i = w = is_codefence(data, size, width, chr); - if (i == 0) - return 0; + i = w = is_codefence(data, size, width, chr); + if (i == 0) + return 0; - while (i < size && _isspace(data[i])) - i++; + while (i < size && _isspace(data[i])) + i++; - lang_start = i; + lang_start = i; - while (i < size && !_isspace(data[i])) - i++; + while (i < size && !_isspace(data[i])) + i++; - lang->data = data + lang_start; - lang->size = i - lang_start; + lang->data = data + lang_start; + lang->size = i - lang_start; - /* Avoid parsing a codespan as a fence */ - i = lang_start + 2; - while (i < size && !(data[i] == *chr && data[i-1] == *chr && data[i-2] == *chr)) i++; - if (i < size) return 0; + /* Avoid parsing a codespan as a fence */ + i = lang_start + 2; + while (i < size && !(data[i] == *chr && data[i-1] == *chr && data[i-2] == *chr)) i++; + if (i < size) return 0; - return w; + return w; } /* is_atxheader • returns whether the line is a hash-prefixed header */ static int is_atxheader(hoedown_document *doc, uint8_t *data, size_t size) { - if (data[0] != '#') - return 0; + if (data[0] != '#') + return 0; - if (doc->ext_flags & HOEDOWN_EXT_SPACE_HEADERS) { - size_t level = 0; + if (doc->ext_flags & HOEDOWN_EXT_SPACE_HEADERS) { + size_t level = 0; - while (level < size && level < 6 && data[level] == '#') - level++; + while (level < size && level < 6 && data[level] == '#') + level++; - if (level < size && data[level] != ' ') - return 0; - } + if (level < size && data[level] != ' ') + return 0; + } - return 1; + return 1; } /* is_headerline • returns whether the line is a setext-style hdr underline */ static int is_headerline(uint8_t *data, size_t size) { - size_t i = 0; + size_t i = 0; - /* test of level 1 header */ - if (data[i] == '=') { - for (i = 1; i < size && data[i] == '='; i++); - while (i < size && data[i] == ' ') i++; - return (i >= size || data[i] == '\n') ? 1 : 0; } + /* test of level 1 header */ + if (data[i] == '=') { + for (i = 1; i < size && data[i] == '='; i++); + while (i < size && data[i] == ' ') i++; + return (i >= size || data[i] == '\n') ? 1 : 0; } - /* test of level 2 header */ - if (data[i] == '-') { - for (i = 1; i < size && data[i] == '-'; i++); - while (i < size && data[i] == ' ') i++; - return (i >= size || data[i] == '\n') ? 2 : 0; } + /* test of level 2 header */ + if (data[i] == '-') { + for (i = 1; i < size && data[i] == '-'; i++); + while (i < size && data[i] == ' ') i++; + return (i >= size || data[i] == '\n') ? 2 : 0; } - return 0; + return 0; } static int is_next_headerline(uint8_t *data, size_t size) { - size_t i = 0; + size_t i = 0; - while (i < size && data[i] != '\n') - i++; + while (i < size && data[i] != '\n') + i++; - if (++i >= size) - return 0; + if (++i >= size) + return 0; - return is_headerline(data + i, size - i); + return is_headerline(data + i, size - i); } /* prefix_quote • returns blockquote prefix length */ static size_t prefix_quote(uint8_t *data, size_t size) { - size_t i = 0; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; + size_t i = 0; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == '>') { - if (i + 1 < size && data[i + 1] == ' ') - return i + 2; + if (i < size && data[i] == '>') { + if (i + 1 < size && data[i + 1] == ' ') + return i + 2; - return i + 1; - } + return i + 1; + } - return 0; + return 0; } /* prefix_code • returns prefix length for block code*/ static size_t prefix_code(uint8_t *data, size_t size) { - if (size > 3 && data[0] == ' ' && data[1] == ' ' - && data[2] == ' ' && data[3] == ' ') return 4; + if (size > 3 && data[0] == ' ' && data[1] == ' ' + && data[2] == ' ' && data[3] == ' ') return 4; - return 0; + return 0; } /* prefix_oli • returns ordered list item prefix */ static size_t prefix_oli(uint8_t *data, size_t size) { - size_t i = 0; + size_t i = 0; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; - if (i >= size || data[i] < '0' || data[i] > '9') - return 0; + if (i >= size || data[i] < '0' || data[i] > '9') + return 0; - while (i < size && data[i] >= '0' && data[i] <= '9') - i++; + while (i < size && data[i] >= '0' && data[i] <= '9') + i++; - if (i + 1 >= size || data[i] != '.' || data[i + 1] != ' ') - return 0; + if (i + 1 >= size || data[i] != '.' || data[i + 1] != ' ') + return 0; - if (is_next_headerline(data + i, size - i)) - return 0; + if (is_next_headerline(data + i, size - i)) + return 0; - return i + 2; + return i + 2; } /* prefix_uli • returns ordered list item prefix */ static size_t prefix_uli(uint8_t *data, size_t size) { - size_t i = 0; + size_t i = 0; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; - if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; + if (i < size && data[i] == ' ') i++; - if (i + 1 >= size || - (data[i] != '*' && data[i] != '+' && data[i] != '-') || - data[i + 1] != ' ') - return 0; + if (i + 1 >= size || + (data[i] != '*' && data[i] != '+' && data[i] != '-') || + data[i + 1] != ' ') + return 0; - if (is_next_headerline(data + i, size - i)) - return 0; + if (is_next_headerline(data + i, size - i)) + return 0; - return i + 2; + return i + 2; } /* parse_block • parsing of one block, returning next uint8_t to parse */ static void parse_block(hoedown_buffer *ob, hoedown_document *doc, - uint8_t *data, size_t size); + uint8_t *data, size_t size); /* parse_blockquote • handles parsing of a blockquote fragment */ static size_t parse_blockquote(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { - size_t beg, end = 0, pre, work_size = 0; - uint8_t *work_data = 0; - hoedown_buffer *out = 0; + size_t beg, end = 0, pre, work_size = 0; + uint8_t *work_data = 0; + hoedown_buffer *out = 0; - out = newbuf(doc, BUFFER_BLOCK); - beg = 0; - while (beg < size) { - for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); + out = newbuf(doc, BUFFER_BLOCK); + beg = 0; + while (beg < size) { + for (end = beg + 1; end < size && data[end - 1] != '\n'; end++); - pre = prefix_quote(data + beg, end - beg); + pre = prefix_quote(data + beg, end - beg); - if (pre) - beg += pre; /* skipping prefix */ + if (pre) + beg += pre; /* skipping prefix */ - /* empty line followed by non-quote line */ - else if (is_empty(data + beg, end - beg) && - (end >= size || (prefix_quote(data + end, size - end) == 0 && - !is_empty(data + end, size - end)))) - break; + /* empty line followed by non-quote line */ + else if (is_empty(data + beg, end - beg) && + (end >= size || (prefix_quote(data + end, size - end) == 0 && + !is_empty(data + end, size - end)))) + break; - if (beg < end) { /* copy into the in-place working buffer */ - /* hoedown_buffer_put(work, data + beg, end - beg); */ - if (!work_data) - work_data = data + beg; - else if (data + beg != work_data + work_size) - memmove(work_data + work_size, data + beg, end - beg); - work_size += end - beg; - } - beg = end; - } + if (beg < end) { /* copy into the in-place working buffer */ + /* hoedown_buffer_put(work, data + beg, end - beg); */ + if (!work_data) + work_data = data + beg; + else if (data + beg != work_data + work_size) + memmove(work_data + work_size, data + beg, end - beg); + work_size += end - beg; + } + beg = end; + } - parse_block(out, doc, work_data, work_size); - if (doc->md.blockquote) - doc->md.blockquote(ob, out, &doc->data); - popbuf(doc, BUFFER_BLOCK); - return end; + parse_block(out, doc, work_data, work_size); + if (doc->md.blockquote) + doc->md.blockquote(ob, out, &doc->data); + popbuf(doc, BUFFER_BLOCK); + return end; } static size_t @@ -1634,301 +1634,301 @@ parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t static size_t parse_paragraph(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { - hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; - size_t i = 0, end = 0; - int level = 0; + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; + size_t i = 0, end = 0; + int level = 0; - work.data = data; + work.data = data; - while (i < size) { - for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; + while (i < size) { + for (end = i + 1; end < size && data[end - 1] != '\n'; end++) /* empty */; - if (is_empty(data + i, size - i)) - break; + if (is_empty(data + i, size - i)) + break; - if ((level = is_headerline(data + i, size - i)) != 0) - break; + if ((level = is_headerline(data + i, size - i)) != 0) + break; - if (is_atxheader(doc, data + i, size - i) || - is_hrule(data + i, size - i) || - prefix_quote(data + i, size - i)) { - end = i; - break; - } + if (is_atxheader(doc, data + i, size - i) || + is_hrule(data + i, size - i) || + prefix_quote(data + i, size - i)) { + end = i; + break; + } - i = end; - } + i = end; + } - work.size = i; - while (work.size && data[work.size - 1] == '\n') - work.size--; + work.size = i; + while (work.size && data[work.size - 1] == '\n') + work.size--; - if (!level) { - hoedown_buffer *tmp = newbuf(doc, BUFFER_BLOCK); - parse_inline(tmp, doc, work.data, work.size); - if (doc->md.paragraph) - doc->md.paragraph(ob, tmp, &doc->data); - popbuf(doc, BUFFER_BLOCK); - } else { - hoedown_buffer *header_work; + if (!level) { + hoedown_buffer *tmp = newbuf(doc, BUFFER_BLOCK); + parse_inline(tmp, doc, work.data, work.size); + if (doc->md.paragraph) + doc->md.paragraph(ob, tmp, &doc->data); + popbuf(doc, BUFFER_BLOCK); + } else { + hoedown_buffer *header_work; - if (work.size) { - size_t beg; - i = work.size; - work.size -= 1; + if (work.size) { + size_t beg; + i = work.size; + work.size -= 1; - while (work.size && data[work.size] != '\n') - work.size -= 1; + while (work.size && data[work.size] != '\n') + work.size -= 1; - beg = work.size + 1; - while (work.size && data[work.size - 1] == '\n') - work.size -= 1; + beg = work.size + 1; + while (work.size && data[work.size - 1] == '\n') + work.size -= 1; - if (work.size > 0) { - hoedown_buffer *tmp = newbuf(doc, BUFFER_BLOCK); - parse_inline(tmp, doc, work.data, work.size); + if (work.size > 0) { + hoedown_buffer *tmp = newbuf(doc, BUFFER_BLOCK); + parse_inline(tmp, doc, work.data, work.size); - if (doc->md.paragraph) - doc->md.paragraph(ob, tmp, &doc->data); + if (doc->md.paragraph) + doc->md.paragraph(ob, tmp, &doc->data); - popbuf(doc, BUFFER_BLOCK); - work.data += beg; - work.size = i - beg; - } - else work.size = i; - } + popbuf(doc, BUFFER_BLOCK); + work.data += beg; + work.size = i - beg; + } + else work.size = i; + } - header_work = newbuf(doc, BUFFER_SPAN); - parse_inline(header_work, doc, work.data, work.size); + header_work = newbuf(doc, BUFFER_SPAN); + parse_inline(header_work, doc, work.data, work.size); - if (doc->md.header) - doc->md.header(ob, header_work, (int)level, &doc->data); + if (doc->md.header) + doc->md.header(ob, header_work, (int)level, &doc->data); - popbuf(doc, BUFFER_SPAN); - } + popbuf(doc, BUFFER_SPAN); + } - return end; + return end; } /* parse_fencedcode • handles parsing of a block-level code fragment */ static size_t parse_fencedcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { - hoedown_buffer text = { 0, 0, 0, 0, NULL, NULL, NULL }; - hoedown_buffer lang = { 0, 0, 0, 0, NULL, NULL, NULL }; - size_t i = 0, text_start, line_start; - size_t w, w2; - size_t width, width2; - uint8_t chr, chr2; + hoedown_buffer text = { 0, 0, 0, 0, NULL, NULL, NULL }; + hoedown_buffer lang = { 0, 0, 0, 0, NULL, NULL, NULL }; + size_t i = 0, text_start, line_start; + size_t w, w2; + size_t width, width2; + uint8_t chr, chr2; - /* parse codefence line */ - while (i < size && data[i] != '\n') - i++; + /* parse codefence line */ + while (i < size && data[i] != '\n') + i++; - w = parse_codefence(data, i, &lang, &width, &chr); - if (!w) - return 0; + w = parse_codefence(data, i, &lang, &width, &chr); + if (!w) + return 0; - /* search for end */ - i++; - text_start = i; - while ((line_start = i) < size) { - while (i < size && data[i] != '\n') - i++; + /* search for end */ + i++; + text_start = i; + while ((line_start = i) < size) { + while (i < size && data[i] != '\n') + i++; - w2 = is_codefence(data + line_start, i - line_start, &width2, &chr2); - if (w == w2 && width == width2 && chr == chr2 && - is_empty(data + (line_start+w), i - (line_start+w))) - break; + w2 = is_codefence(data + line_start, i - line_start, &width2, &chr2); + if (w == w2 && width == width2 && chr == chr2 && + is_empty(data + (line_start+w), i - (line_start+w))) + break; - i++; - } + i++; + } - text.data = data + text_start; - text.size = line_start - text_start; + text.data = data + text_start; + text.size = line_start - text_start; - if (doc->md.blockcode) - doc->md.blockcode(ob, text.size ? &text : NULL, lang.size ? &lang : NULL, &doc->data); + if (doc->md.blockcode) + doc->md.blockcode(ob, text.size ? &text : NULL, lang.size ? &lang : NULL, &doc->data); - return i; + return i; } static size_t parse_blockcode(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { - size_t beg, end, pre; - hoedown_buffer *work = 0; + size_t beg, end, pre; + hoedown_buffer *work = 0; - work = newbuf(doc, BUFFER_BLOCK); + work = newbuf(doc, BUFFER_BLOCK); - beg = 0; - while (beg < size) { - for (end = beg + 1; end < size && data[end - 1] != '\n'; end++) {}; - pre = prefix_code(data + beg, end - beg); + beg = 0; + while (beg < size) { + for (end = beg + 1; end < size && data[end - 1] != '\n'; end++) {}; + pre = prefix_code(data + beg, end - beg); - if (pre) - beg += pre; /* skipping prefix */ - else if (!is_empty(data + beg, end - beg)) - /* non-empty non-prefixed line breaks the pre */ - break; + if (pre) + beg += pre; /* skipping prefix */ + else if (!is_empty(data + beg, end - beg)) + /* non-empty non-prefixed line breaks the pre */ + break; - if (beg < end) { - /* verbatim copy to the working buffer, - escaping entities */ - if (is_empty(data + beg, end - beg)) - hoedown_buffer_putc(work, '\n'); - else hoedown_buffer_put(work, data + beg, end - beg); - } - beg = end; - } + if (beg < end) { + /* verbatim copy to the working buffer, + escaping entities */ + if (is_empty(data + beg, end - beg)) + hoedown_buffer_putc(work, '\n'); + else hoedown_buffer_put(work, data + beg, end - beg); + } + beg = end; + } - while (work->size && work->data[work->size - 1] == '\n') - work->size -= 1; + while (work->size && work->data[work->size - 1] == '\n') + work->size -= 1; - hoedown_buffer_putc(work, '\n'); + hoedown_buffer_putc(work, '\n'); - if (doc->md.blockcode) - doc->md.blockcode(ob, work, NULL, &doc->data); + if (doc->md.blockcode) + doc->md.blockcode(ob, work, NULL, &doc->data); - popbuf(doc, BUFFER_BLOCK); - return beg; + popbuf(doc, BUFFER_BLOCK); + return beg; } /* parse_listitem • parsing of a single list item */ -/* assuming initial prefix is already removed */ +/* assuming initial prefix is already removed */ static size_t parse_listitem(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, hoedown_list_flags *flags) { - hoedown_buffer *work = 0, *inter = 0; - size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; - int in_empty = 0, has_inside_empty = 0, in_fence = 0; - - /* keeping track of the first indentation prefix */ - while (orgpre < 3 && orgpre < size && data[orgpre] == ' ') - orgpre++; - - beg = prefix_uli(data, size); - if (!beg) - beg = prefix_oli(data, size); - - if (!beg) - return 0; - - /* skipping to the beginning of the following line */ - end = beg; - while (end < size && data[end - 1] != '\n') - end++; - - /* getting working buffers */ - work = newbuf(doc, BUFFER_SPAN); - inter = newbuf(doc, BUFFER_SPAN); - - /* putting the first line into the working buffer */ - hoedown_buffer_put(work, data + beg, end - beg); - beg = end; - - /* process the following lines */ - while (beg < size) { - size_t has_next_uli = 0, has_next_oli = 0; - - end++; - - while (end < size && data[end - 1] != '\n') - end++; - - /* process an empty line */ - if (is_empty(data + beg, end - beg)) { - in_empty = 1; - beg = end; - continue; - } - - /* calculating the indentation */ - i = 0; - while (i < 4 && beg + i < end && data[beg + i] == ' ') - i++; - - pre = i; - - if (doc->ext_flags & HOEDOWN_EXT_FENCED_CODE) { - if (is_codefence(data + beg + i, end - beg - i, NULL, NULL)) - in_fence = !in_fence; - } - - /* Only check for new list items if we are **not** inside - * a fenced code block */ - if (!in_fence) { - has_next_uli = prefix_uli(data + beg + i, end - beg - i); - has_next_oli = prefix_oli(data + beg + i, end - beg - i); - } - - /* checking for a new item */ - if ((has_next_uli && !is_hrule(data + beg + i, end - beg - i)) || has_next_oli) { - if (in_empty) - has_inside_empty = 1; - - /* the following item must have the same (or less) indentation */ - if (pre <= orgpre) { - /* if the following item has different list type, we end this list */ - if (in_empty && ( - ((*flags & HOEDOWN_LIST_ORDERED) && has_next_uli) || - (!(*flags & HOEDOWN_LIST_ORDERED) && has_next_oli))) - *flags |= HOEDOWN_LI_END; - - break; - } - - if (!sublist) - sublist = work->size; - } - /* joining only indented stuff after empty lines; - * note that now we only require 1 space of indentation - * to continue a list */ - else if (in_empty && pre == 0) { - *flags |= HOEDOWN_LI_END; - break; - } - - if (in_empty) { - hoedown_buffer_putc(work, '\n'); - has_inside_empty = 1; - in_empty = 0; - } - - /* adding the line without prefix into the working buffer */ - hoedown_buffer_put(work, data + beg + i, end - beg - i); - beg = end; - } - - /* render of li contents */ - if (has_inside_empty) - *flags |= HOEDOWN_LI_BLOCK; - - if (*flags & HOEDOWN_LI_BLOCK) { - /* intermediate render of block li */ - if (sublist && sublist < work->size) { - parse_block(inter, doc, work->data, sublist); - parse_block(inter, doc, work->data + sublist, work->size - sublist); - } - else - parse_block(inter, doc, work->data, work->size); - } else { - /* intermediate render of inline li */ - if (sublist && sublist < work->size) { - parse_inline(inter, doc, work->data, sublist); - parse_block(inter, doc, work->data + sublist, work->size - sublist); - } - else - parse_inline(inter, doc, work->data, work->size); - } - - /* render of li itself */ - if (doc->md.listitem) - doc->md.listitem(ob, inter, *flags, &doc->data); - - popbuf(doc, BUFFER_SPAN); - popbuf(doc, BUFFER_SPAN); - return beg; + hoedown_buffer *work = 0, *inter = 0; + size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i; + int in_empty = 0, has_inside_empty = 0, in_fence = 0; + + /* keeping track of the first indentation prefix */ + while (orgpre < 3 && orgpre < size && data[orgpre] == ' ') + orgpre++; + + beg = prefix_uli(data, size); + if (!beg) + beg = prefix_oli(data, size); + + if (!beg) + return 0; + + /* skipping to the beginning of the following line */ + end = beg; + while (end < size && data[end - 1] != '\n') + end++; + + /* getting working buffers */ + work = newbuf(doc, BUFFER_SPAN); + inter = newbuf(doc, BUFFER_SPAN); + + /* putting the first line into the working buffer */ + hoedown_buffer_put(work, data + beg, end - beg); + beg = end; + + /* process the following lines */ + while (beg < size) { + size_t has_next_uli = 0, has_next_oli = 0; + + end++; + + while (end < size && data[end - 1] != '\n') + end++; + + /* process an empty line */ + if (is_empty(data + beg, end - beg)) { + in_empty = 1; + beg = end; + continue; + } + + /* calculating the indentation */ + i = 0; + while (i < 4 && beg + i < end && data[beg + i] == ' ') + i++; + + pre = i; + + if (doc->ext_flags & HOEDOWN_EXT_FENCED_CODE) { + if (is_codefence(data + beg + i, end - beg - i, NULL, NULL)) + in_fence = !in_fence; + } + + /* Only check for new list items if we are **not** inside + * a fenced code block */ + if (!in_fence) { + has_next_uli = prefix_uli(data + beg + i, end - beg - i); + has_next_oli = prefix_oli(data + beg + i, end - beg - i); + } + + /* checking for a new item */ + if ((has_next_uli && !is_hrule(data + beg + i, end - beg - i)) || has_next_oli) { + if (in_empty) + has_inside_empty = 1; + + /* the following item must have the same (or less) indentation */ + if (pre <= orgpre) { + /* if the following item has different list type, we end this list */ + if (in_empty && ( + ((*flags & HOEDOWN_LIST_ORDERED) && has_next_uli) || + (!(*flags & HOEDOWN_LIST_ORDERED) && has_next_oli))) + *flags |= HOEDOWN_LI_END; + + break; + } + + if (!sublist) + sublist = work->size; + } + /* joining only indented stuff after empty lines; + * note that now we only require 1 space of indentation + * to continue a list */ + else if (in_empty && pre == 0) { + *flags |= HOEDOWN_LI_END; + break; + } + + if (in_empty) { + hoedown_buffer_putc(work, '\n'); + has_inside_empty = 1; + in_empty = 0; + } + + /* adding the line without prefix into the working buffer */ + hoedown_buffer_put(work, data + beg + i, end - beg - i); + beg = end; + } + + /* render of li contents */ + if (has_inside_empty) + *flags |= HOEDOWN_LI_BLOCK; + + if (*flags & HOEDOWN_LI_BLOCK) { + /* intermediate render of block li */ + if (sublist && sublist < work->size) { + parse_block(inter, doc, work->data, sublist); + parse_block(inter, doc, work->data + sublist, work->size - sublist); + } + else + parse_block(inter, doc, work->data, work->size); + } else { + /* intermediate render of inline li */ + if (sublist && sublist < work->size) { + parse_inline(inter, doc, work->data, sublist); + parse_block(inter, doc, work->data + sublist, work->size - sublist); + } + else + parse_inline(inter, doc, work->data, work->size); + } + + /* render of li itself */ + if (doc->md.listitem) + doc->md.listitem(ob, inter, *flags, &doc->data); + + popbuf(doc, BUFFER_SPAN); + popbuf(doc, BUFFER_SPAN); + return beg; } @@ -1936,460 +1936,460 @@ parse_listitem(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t static size_t parse_list(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, hoedown_list_flags flags) { - hoedown_buffer *work = 0; - size_t i = 0, j; + hoedown_buffer *work = 0; + size_t i = 0, j; - work = newbuf(doc, BUFFER_BLOCK); + work = newbuf(doc, BUFFER_BLOCK); - while (i < size) { - j = parse_listitem(work, doc, data + i, size - i, &flags); - i += j; + while (i < size) { + j = parse_listitem(work, doc, data + i, size - i, &flags); + i += j; - if (!j || (flags & HOEDOWN_LI_END)) - break; - } + if (!j || (flags & HOEDOWN_LI_END)) + break; + } - if (doc->md.list) - doc->md.list(ob, work, flags, &doc->data); - popbuf(doc, BUFFER_BLOCK); - return i; + if (doc->md.list) + doc->md.list(ob, work, flags, &doc->data); + popbuf(doc, BUFFER_BLOCK); + return i; } /* parse_atxheader • parsing of atx-style headers */ static size_t parse_atxheader(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { - size_t level = 0; - size_t i, end, skip; + size_t level = 0; + size_t i, end, skip; - while (level < size && level < 6 && data[level] == '#') - level++; + while (level < size && level < 6 && data[level] == '#') + level++; - for (i = level; i < size && data[i] == ' '; i++); + for (i = level; i < size && data[i] == ' '; i++); - for (end = i; end < size && data[end] != '\n'; end++); - skip = end; + for (end = i; end < size && data[end] != '\n'; end++); + skip = end; - while (end && data[end - 1] == '#') - end--; + while (end && data[end - 1] == '#') + end--; - while (end && data[end - 1] == ' ') - end--; + while (end && data[end - 1] == ' ') + end--; - if (end > i) { - hoedown_buffer *work = newbuf(doc, BUFFER_SPAN); + if (end > i) { + hoedown_buffer *work = newbuf(doc, BUFFER_SPAN); - parse_inline(work, doc, data + i, end - i); + parse_inline(work, doc, data + i, end - i); - if (doc->md.header) - doc->md.header(ob, work, (int)level, &doc->data); + if (doc->md.header) + doc->md.header(ob, work, (int)level, &doc->data); - popbuf(doc, BUFFER_SPAN); - } + popbuf(doc, BUFFER_SPAN); + } - return skip; + return skip; } /* parse_footnote_def • parse a single footnote definition */ static void parse_footnote_def(hoedown_buffer *ob, hoedown_document *doc, unsigned int num, uint8_t *data, size_t size) { - hoedown_buffer *work = 0; - work = newbuf(doc, BUFFER_SPAN); + hoedown_buffer *work = 0; + work = newbuf(doc, BUFFER_SPAN); - parse_block(work, doc, data, size); + parse_block(work, doc, data, size); - if (doc->md.footnote_def) - doc->md.footnote_def(ob, work, num, &doc->data); - popbuf(doc, BUFFER_SPAN); + if (doc->md.footnote_def) + doc->md.footnote_def(ob, work, num, &doc->data); + popbuf(doc, BUFFER_SPAN); } /* parse_footnote_list • render the contents of the footnotes */ static void parse_footnote_list(hoedown_buffer *ob, hoedown_document *doc, struct footnote_list *footnotes) { - hoedown_buffer *work = 0; - struct footnote_item *item; - struct footnote_ref *ref; + hoedown_buffer *work = 0; + struct footnote_item *item; + struct footnote_ref *ref; - if (footnotes->count == 0) - return; + if (footnotes->count == 0) + return; - work = newbuf(doc, BUFFER_BLOCK); + work = newbuf(doc, BUFFER_BLOCK); - item = footnotes->head; - while (item) { - ref = item->ref; - parse_footnote_def(work, doc, ref->num, ref->contents->data, ref->contents->size); - item = item->next; - } + item = footnotes->head; + while (item) { + ref = item->ref; + parse_footnote_def(work, doc, ref->num, ref->contents->data, ref->contents->size); + item = item->next; + } - if (doc->md.footnotes) - doc->md.footnotes(ob, work, &doc->data); - popbuf(doc, BUFFER_BLOCK); + if (doc->md.footnotes) + doc->md.footnotes(ob, work, &doc->data); + popbuf(doc, BUFFER_BLOCK); } /* htmlblock_is_end • check for end of HTML block : </tag>( *)\n */ -/* returns tag length on match, 0 otherwise */ -/* assumes data starts with "<" */ +/* returns tag length on match, 0 otherwise */ +/* assumes data starts with "<" */ static size_t htmlblock_is_end( - const char *tag, - size_t tag_len, - hoedown_document *doc, - uint8_t *data, - size_t size) + const char *tag, + size_t tag_len, + hoedown_document *doc, + uint8_t *data, + size_t size) { - size_t i = tag_len + 3, w; + size_t i = tag_len + 3, w; - /* try to match the end tag */ - /* note: we're not considering tags like "</tag >" which are still valid */ - if (i > size || - data[1] != '/' || - strncasecmp((char *)data + 2, tag, tag_len) != 0 || - data[tag_len + 2] != '>') - return 0; + /* try to match the end tag */ + /* note: we're not considering tags like "</tag >" which are still valid */ + if (i > size || + data[1] != '/' || + strncasecmp((char *)data + 2, tag, tag_len) != 0 || + data[tag_len + 2] != '>') + return 0; - /* rest of the line must be empty */ - if ((w = is_empty(data + i, size - i)) == 0 && i < size) - return 0; + /* rest of the line must be empty */ + if ((w = is_empty(data + i, size - i)) == 0 && i < size) + return 0; - return i + w; + return i + w; } /* htmlblock_find_end • try to find HTML block ending tag */ -/* returns the length on match, 0 otherwise */ +/* returns the length on match, 0 otherwise */ static size_t htmlblock_find_end( - const char *tag, - size_t tag_len, - hoedown_document *doc, - uint8_t *data, - size_t size) + const char *tag, + size_t tag_len, + hoedown_document *doc, + uint8_t *data, + size_t size) { - size_t i = 0, w; + size_t i = 0, w; - while (1) { - while (i < size && data[i] != '<') i++; - if (i >= size) return 0; + while (1) { + while (i < size && data[i] != '<') i++; + if (i >= size) return 0; - w = htmlblock_is_end(tag, tag_len, doc, data + i, size - i); - if (w) return i + w; - i++; - } + w = htmlblock_is_end(tag, tag_len, doc, data + i, size - i); + if (w) return i + w; + i++; + } } /* htmlblock_find_end_strict • try to find end of HTML block in strict mode */ -/* (it must be an unindented line, and have a blank line afterwads) */ -/* returns the length on match, 0 otherwise */ +/* (it must be an unindented line, and have a blank line afterwads) */ +/* returns the length on match, 0 otherwise */ static size_t htmlblock_find_end_strict( - const char *tag, - size_t tag_len, - hoedown_document *doc, - uint8_t *data, - size_t size) + const char *tag, + size_t tag_len, + hoedown_document *doc, + uint8_t *data, + size_t size) { - size_t i = 0, mark; + size_t i = 0, mark; - while (1) { - mark = i; - while (i < size && data[i] != '\n') i++; - if (i < size) i++; - if (i == mark) return 0; + while (1) { + mark = i; + while (i < size && data[i] != '\n') i++; + if (i < size) i++; + if (i == mark) return 0; - if (data[mark] == ' ' && mark > 0) continue; - mark += htmlblock_find_end(tag, tag_len, doc, data + mark, i - mark); - if (mark == i && (is_empty(data + i, size - i) || i >= size)) break; - } + if (data[mark] == ' ' && mark > 0) continue; + mark += htmlblock_find_end(tag, tag_len, doc, data + mark, i - mark); + if (mark == i && (is_empty(data + i, size - i) || i >= size)) break; + } - return i; + return i; } /* parse_htmlblock • parsing of inline HTML block */ static size_t parse_htmlblock(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size, int do_render) { - hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; - size_t i, j = 0, tag_len, tag_end; - const char *curtag = NULL; + hoedown_buffer work = { NULL, 0, 0, 0, NULL, NULL, NULL }; + size_t i, j = 0, tag_len, tag_end; + const char *curtag = NULL; - work.data = data; + work.data = data; - /* identification of the opening tag */ - if (size < 2 || data[0] != '<') - return 0; + /* identification of the opening tag */ + if (size < 2 || data[0] != '<') + return 0; - i = 1; - while (i < size && data[i] != '>' && data[i] != ' ') - i++; + i = 1; + while (i < size && data[i] != '>' && data[i] != ' ') + i++; - if (i < size) - curtag = hoedown_find_block_tag((char *)data + 1, (int)i - 1); + if (i < size) + curtag = hoedown_find_block_tag((char *)data + 1, (int)i - 1); - /* handling of special cases */ - if (!curtag) { + /* handling of special cases */ + if (!curtag) { - /* HTML comment, laxist form */ - if (size > 5 && data[1] == '!' && data[2] == '-' && data[3] == '-') { - i = 5; + /* HTML comment, laxist form */ + if (size > 5 && data[1] == '!' && data[2] == '-' && data[3] == '-') { + i = 5; - while (i < size && !(data[i - 2] == '-' && data[i - 1] == '-' && data[i] == '>')) - i++; + while (i < size && !(data[i - 2] == '-' && data[i - 1] == '-' && data[i] == '>')) + i++; - i++; + i++; - if (i < size) - j = is_empty(data + i, size - i); + if (i < size) + j = is_empty(data + i, size - i); - if (j) { - work.size = i + j; - if (do_render && doc->md.blockhtml) - doc->md.blockhtml(ob, &work, &doc->data); - return work.size; - } - } + if (j) { + work.size = i + j; + if (do_render && doc->md.blockhtml) + doc->md.blockhtml(ob, &work, &doc->data); + return work.size; + } + } - /* HR, which is the only self-closing block tag considered */ - if (size > 4 && (data[1] == 'h' || data[1] == 'H') && (data[2] == 'r' || data[2] == 'R')) { - i = 3; - while (i < size && data[i] != '>') - i++; + /* HR, which is the only self-closing block tag considered */ + if (size > 4 && (data[1] == 'h' || data[1] == 'H') && (data[2] == 'r' || data[2] == 'R')) { + i = 3; + while (i < size && data[i] != '>') + i++; - if (i + 1 < size) { - i++; - j = is_empty(data + i, size - i); - if (j) { - work.size = i + j; - if (do_render && doc->md.blockhtml) - doc->md.blockhtml(ob, &work, &doc->data); - return work.size; - } - } - } + if (i + 1 < size) { + i++; + j = is_empty(data + i, size - i); + if (j) { + work.size = i + j; + if (do_render && doc->md.blockhtml) + doc->md.blockhtml(ob, &work, &doc->data); + return work.size; + } + } + } - /* no special case recognised */ - return 0; - } + /* no special case recognised */ + return 0; + } - /* looking for a matching closing tag in strict mode */ - tag_len = strlen(curtag); - tag_end = htmlblock_find_end_strict(curtag, tag_len, doc, data, size); + /* looking for a matching closing tag in strict mode */ + tag_len = strlen(curtag); + tag_end = htmlblock_find_end_strict(curtag, tag_len, doc, data, size); - /* if not found, trying a second pass looking for indented match */ - /* but not if tag is "ins" or "del" (following original Markdown.pl) */ - if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) - tag_end = htmlblock_find_end(curtag, tag_len, doc, data, size); + /* if not found, trying a second pass looking for indented match */ + /* but not if tag is "ins" or "del" (following original Markdown.pl) */ + if (!tag_end && strcmp(curtag, "ins") != 0 && strcmp(curtag, "del") != 0) + tag_end = htmlblock_find_end(curtag, tag_len, doc, data, size); - if (!tag_end) - return 0; + if (!tag_end) + return 0; - /* the end of the block has been found */ - work.size = tag_end; - if (do_render && doc->md.blockhtml) - doc->md.blockhtml(ob, &work, &doc->data); + /* the end of the block has been found */ + work.size = tag_end; + if (do_render && doc->md.blockhtml) + doc->md.blockhtml(ob, &work, &doc->data); - return tag_end; + return tag_end; } static void parse_table_row( - hoedown_buffer *ob, - hoedown_document *doc, - uint8_t *data, - size_t size, - size_t columns, - hoedown_table_flags *col_data, - hoedown_table_flags header_flag) + hoedown_buffer *ob, + hoedown_document *doc, + uint8_t *data, + size_t size, + size_t columns, + hoedown_table_flags *col_data, + hoedown_table_flags header_flag) { - size_t i = 0, col, len; - hoedown_buffer *row_work = 0; + size_t i = 0, col, len; + hoedown_buffer *row_work = 0; - if (!doc->md.table_cell || !doc->md.table_row) - return; + if (!doc->md.table_cell || !doc->md.table_row) + return; - row_work = newbuf(doc, BUFFER_SPAN); + row_work = newbuf(doc, BUFFER_SPAN); - if (i < size && data[i] == '|') - i++; + if (i < size && data[i] == '|') + i++; - for (col = 0; col < columns && i < size; ++col) { - size_t cell_start, cell_end; - hoedown_buffer *cell_work; + for (col = 0; col < columns && i < size; ++col) { + size_t cell_start, cell_end; + hoedown_buffer *cell_work; - cell_work = newbuf(doc, BUFFER_SPAN); + cell_work = newbuf(doc, BUFFER_SPAN); - while (i < size && _isspace(data[i])) - i++; + while (i < size && _isspace(data[i])) + i++; - cell_start = i; + cell_start = i; - len = find_emph_char(data + i, size - i, '|'); - i += len ? len : size - i; + len = find_emph_char(data + i, size - i, '|'); + i += len ? len : size - i; - cell_end = i - 1; + cell_end = i - 1; - while (cell_end > cell_start && _isspace(data[cell_end])) - cell_end--; + while (cell_end > cell_start && _isspace(data[cell_end])) + cell_end--; - parse_inline(cell_work, doc, data + cell_start, 1 + cell_end - cell_start); - doc->md.table_cell(row_work, cell_work, col_data[col] | header_flag, &doc->data); + parse_inline(cell_work, doc, data + cell_start, 1 + cell_end - cell_start); + doc->md.table_cell(row_work, cell_work, col_data[col] | header_flag, &doc->data); - popbuf(doc, BUFFER_SPAN); - i++; - } + popbuf(doc, BUFFER_SPAN); + i++; + } - for (; col < columns; ++col) { - hoedown_buffer empty_cell = { 0, 0, 0, 0, NULL, NULL, NULL }; - doc->md.table_cell(row_work, &empty_cell, col_data[col] | header_flag, &doc->data); - } + for (; col < columns; ++col) { + hoedown_buffer empty_cell = { 0, 0, 0, 0, NULL, NULL, NULL }; + doc->md.table_cell(row_work, &empty_cell, col_data[col] | header_flag, &doc->data); + } - doc->md.table_row(ob, row_work, &doc->data); + doc->md.table_row(ob, row_work, &doc->data); - popbuf(doc, BUFFER_SPAN); + popbuf(doc, BUFFER_SPAN); } static size_t parse_table_header( - hoedown_buffer *ob, - hoedown_document *doc, - uint8_t *data, - size_t size, - size_t *columns, - hoedown_table_flags **column_data) + hoedown_buffer *ob, + hoedown_document *doc, + uint8_t *data, + size_t size, + size_t *columns, + hoedown_table_flags **column_data) { - int pipes; - size_t i = 0, col, header_end, under_end; + int pipes; + size_t i = 0, col, header_end, under_end; - pipes = 0; - while (i < size && data[i] != '\n') - if (data[i++] == '|') - pipes++; + pipes = 0; + while (i < size && data[i] != '\n') + if (data[i++] == '|') + pipes++; - if (i == size || pipes == 0) - return 0; + if (i == size || pipes == 0) + return 0; - header_end = i; + header_end = i; - while (header_end > 0 && _isspace(data[header_end - 1])) - header_end--; + while (header_end > 0 && _isspace(data[header_end - 1])) + header_end--; - if (data[0] == '|') - pipes--; + if (data[0] == '|') + pipes--; - if (header_end && data[header_end - 1] == '|') - pipes--; + if (header_end && data[header_end - 1] == '|') + pipes--; - if (pipes < 0) - return 0; + if (pipes < 0) + return 0; - *columns = pipes + 1; - *column_data = hoedown_calloc(*columns, sizeof(hoedown_table_flags)); + *columns = pipes + 1; + *column_data = hoedown_calloc(*columns, sizeof(hoedown_table_flags)); - /* Parse the header underline */ - i++; - if (i < size && data[i] == '|') - i++; + /* Parse the header underline */ + i++; + if (i < size && data[i] == '|') + i++; - under_end = i; - while (under_end < size && data[under_end] != '\n') - under_end++; + under_end = i; + while (under_end < size && data[under_end] != '\n') + under_end++; - for (col = 0; col < *columns && i < under_end; ++col) { - size_t dashes = 0; + for (col = 0; col < *columns && i < under_end; ++col) { + size_t dashes = 0; - while (i < under_end && data[i] == ' ') - i++; + while (i < under_end && data[i] == ' ') + i++; - if (data[i] == ':') { - i++; (*column_data)[col] |= HOEDOWN_TABLE_ALIGN_LEFT; - dashes++; - } + if (data[i] == ':') { + i++; (*column_data)[col] |= HOEDOWN_TABLE_ALIGN_LEFT; + dashes++; + } - while (i < under_end && data[i] == '-') { - i++; dashes++; - } + while (i < under_end && data[i] == '-') { + i++; dashes++; + } - if (i < under_end && data[i] == ':') { - i++; (*column_data)[col] |= HOEDOWN_TABLE_ALIGN_RIGHT; - dashes++; - } + if (i < under_end && data[i] == ':') { + i++; (*column_data)[col] |= HOEDOWN_TABLE_ALIGN_RIGHT; + dashes++; + } - while (i < under_end && data[i] == ' ') - i++; + while (i < under_end && data[i] == ' ') + i++; - if (i < under_end && data[i] != '|' && data[i] != '+') - break; + if (i < under_end && data[i] != '|' && data[i] != '+') + break; - if (dashes < 3) - break; + if (dashes < 3) + break; - i++; - } + i++; + } - if (col < *columns) - return 0; + if (col < *columns) + return 0; - parse_table_row( - ob, doc, data, - header_end, - *columns, - *column_data, - HOEDOWN_TABLE_HEADER - ); + parse_table_row( + ob, doc, data, + header_end, + *columns, + *column_data, + HOEDOWN_TABLE_HEADER + ); - return under_end + 1; + return under_end + 1; } static size_t parse_table( - hoedown_buffer *ob, - hoedown_document *doc, - uint8_t *data, - size_t size) + hoedown_buffer *ob, + hoedown_document *doc, + uint8_t *data, + size_t size) { - size_t i; + size_t i; - hoedown_buffer *work = 0; - hoedown_buffer *header_work = 0; - hoedown_buffer *body_work = 0; + hoedown_buffer *work = 0; + hoedown_buffer *header_work = 0; + hoedown_buffer *body_work = 0; - size_t columns; - hoedown_table_flags *col_data = NULL; + size_t columns; + hoedown_table_flags *col_data = NULL; - work = newbuf(doc, BUFFER_BLOCK); - header_work = newbuf(doc, BUFFER_SPAN); - body_work = newbuf(doc, BUFFER_BLOCK); + work = newbuf(doc, BUFFER_BLOCK); + header_work = newbuf(doc, BUFFER_SPAN); + body_work = newbuf(doc, BUFFER_BLOCK); - i = parse_table_header(header_work, doc, data, size, &columns, &col_data); - if (i > 0) { + i = parse_table_header(header_work, doc, data, size, &columns, &col_data); + if (i > 0) { - while (i < size) { - size_t row_start; - int pipes = 0; + while (i < size) { + size_t row_start; + int pipes = 0; - row_start = i; + row_start = i; - while (i < size && data[i] != '\n') - if (data[i++] == '|') - pipes++; + while (i < size && data[i] != '\n') + if (data[i++] == '|') + pipes++; - if (pipes == 0 || i == size) { - i = row_start; - break; - } + if (pipes == 0 || i == size) { + i = row_start; + break; + } - parse_table_row( - body_work, - doc, - data + row_start, - i - row_start, - columns, - col_data, 0 - ); + parse_table_row( + body_work, + doc, + data + row_start, + i - row_start, + columns, + col_data, 0 + ); - i++; - } + i++; + } if (doc->md.table_header) doc->md.table_header(work, header_work, &doc->data); @@ -2397,76 +2397,76 @@ parse_table( if (doc->md.table_body) doc->md.table_body(work, body_work, &doc->data); - if (doc->md.table) - doc->md.table(ob, work, &doc->data); - } + if (doc->md.table) + doc->md.table(ob, work, &doc->data); + } - free(col_data); - popbuf(doc, BUFFER_SPAN); - popbuf(doc, BUFFER_BLOCK); - popbuf(doc, BUFFER_BLOCK); - return i; + free(col_data); + popbuf(doc, BUFFER_SPAN); + popbuf(doc, BUFFER_BLOCK); + popbuf(doc, BUFFER_BLOCK); + return i; } /* parse_block • parsing of one block, returning next uint8_t to parse */ static void parse_block(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t size) { - size_t beg, end, i; - uint8_t *txt_data; - beg = 0; + size_t beg, end, i; + uint8_t *txt_data; + beg = 0; - if (doc->work_bufs[BUFFER_SPAN].size + - doc->work_bufs[BUFFER_BLOCK].size > doc->max_nesting) - return; + if (doc->work_bufs[BUFFER_SPAN].size + + doc->work_bufs[BUFFER_BLOCK].size > doc->max_nesting) + return; - while (beg < size) { - txt_data = data + beg; - end = size - beg; + while (beg < size) { + txt_data = data + beg; + end = size - beg; - if (is_atxheader(doc, txt_data, end)) - beg += parse_atxheader(ob, doc, txt_data, end); + if (is_atxheader(doc, txt_data, end)) + beg += parse_atxheader(ob, doc, txt_data, end); - else if (data[beg] == '<' && doc->md.blockhtml && - (i = parse_htmlblock(ob, doc, txt_data, end, 1)) != 0) - beg += i; + else if (data[beg] == '<' && doc->md.blockhtml && + (i = parse_htmlblock(ob, doc, txt_data, end, 1)) != 0) + beg += i; - else if ((i = is_empty(txt_data, end)) != 0) - beg += i; + else if ((i = is_empty(txt_data, end)) != 0) + beg += i; - else if (is_hrule(txt_data, end)) { - if (doc->md.hrule) - doc->md.hrule(ob, &doc->data); + else if (is_hrule(txt_data, end)) { + if (doc->md.hrule) + doc->md.hrule(ob, &doc->data); - while (beg < size && data[beg] != '\n') - beg++; + while (beg < size && data[beg] != '\n') + beg++; - beg++; - } + beg++; + } - else if ((doc->ext_flags & HOEDOWN_EXT_FENCED_CODE) != 0 && - (i = parse_fencedcode(ob, doc, txt_data, end)) != 0) - beg += i; + else if ((doc->ext_flags & HOEDOWN_EXT_FENCED_CODE) != 0 && + (i = parse_fencedcode(ob, doc, txt_data, end)) != 0) + beg += i; - else if ((doc->ext_flags & HOEDOWN_EXT_TABLES) != 0 && - (i = parse_table(ob, doc, txt_data, end)) != 0) - beg += i; + else if ((doc->ext_flags & HOEDOWN_EXT_TABLES) != 0 && + (i = parse_table(ob, doc, txt_data, end)) != 0) + beg += i; - else if (prefix_quote(txt_data, end)) - beg += parse_blockquote(ob, doc, txt_data, end); + else if (prefix_quote(txt_data, end)) + beg += parse_blockquote(ob, doc, txt_data, end); - else if (!(doc->ext_flags & HOEDOWN_EXT_DISABLE_INDENTED_CODE) && prefix_code(txt_data, end)) - beg += parse_blockcode(ob, doc, txt_data, end); + else if (!(doc->ext_flags & HOEDOWN_EXT_DISABLE_INDENTED_CODE) && prefix_code(txt_data, end)) + beg += parse_blockcode(ob, doc, txt_data, end); - else if (prefix_uli(txt_data, end)) - beg += parse_list(ob, doc, txt_data, end, 0); + else if (prefix_uli(txt_data, end)) + beg += parse_list(ob, doc, txt_data, end, 0); - else if (prefix_oli(txt_data, end)) - beg += parse_list(ob, doc, txt_data, end, HOEDOWN_LIST_ORDERED); + else if (prefix_oli(txt_data, end)) + beg += parse_list(ob, doc, txt_data, end, HOEDOWN_LIST_ORDERED); - else - beg += parse_paragraph(ob, doc, txt_data, end); - } + else + beg += parse_paragraph(ob, doc, txt_data, end); + } } @@ -2479,253 +2479,253 @@ parse_block(hoedown_buffer *ob, hoedown_document *doc, uint8_t *data, size_t siz static int is_footnote(const uint8_t *data, size_t beg, size_t end, size_t *last, struct footnote_list *list) { - size_t i = 0; - hoedown_buffer *contents = 0; - size_t ind = 0; - int in_empty = 0; - size_t start = 0; - - size_t id_offset, id_end; - - /* up to 3 optional leading spaces */ - if (beg + 3 >= end) return 0; - if (data[beg] == ' ') { i = 1; - if (data[beg + 1] == ' ') { i = 2; - if (data[beg + 2] == ' ') { i = 3; - if (data[beg + 3] == ' ') return 0; } } } - i += beg; - - /* id part: caret followed by anything between brackets */ - if (data[i] != '[') return 0; - i++; - if (i >= end || data[i] != '^') return 0; - i++; - id_offset = i; - while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') - i++; - if (i >= end || data[i] != ']') return 0; - id_end = i; - - /* spacer: colon (space | tab)* newline? (space | tab)* */ - i++; - if (i >= end || data[i] != ':') return 0; - i++; - - /* getting content buffer */ - contents = hoedown_buffer_new(64); - - start = i; - - /* process lines similar to a list item */ - while (i < end) { - while (i < end && data[i] != '\n' && data[i] != '\r') i++; - - /* process an empty line */ - if (is_empty(data + start, i - start)) { - in_empty = 1; - if (i < end && (data[i] == '\n' || data[i] == '\r')) { - i++; - if (i < end && data[i] == '\n' && data[i - 1] == '\r') i++; - } - start = i; - continue; - } - - /* calculating the indentation */ - ind = 0; - while (ind < 4 && start + ind < end && data[start + ind] == ' ') - ind++; - - /* joining only indented stuff after empty lines; - * note that now we only require 1 space of indentation - * to continue, just like lists */ - if (ind == 0) { - if (start == id_end + 2 && data[start] == '\t') {} - else break; - } - else if (in_empty) { - hoedown_buffer_putc(contents, '\n'); - } - - in_empty = 0; - - /* adding the line into the content buffer */ - hoedown_buffer_put(contents, data + start + ind, i - start - ind); - /* add carriage return */ - if (i < end) { - hoedown_buffer_putc(contents, '\n'); - if (i < end && (data[i] == '\n' || data[i] == '\r')) { - i++; - if (i < end && data[i] == '\n' && data[i - 1] == '\r') i++; - } - } - start = i; - } - - if (last) - *last = start; - - if (list) { - struct footnote_ref *ref; - ref = create_footnote_ref(list, data + id_offset, id_end - id_offset); - if (!ref) - return 0; - if (!add_footnote_ref(list, ref)) { - free_footnote_ref(ref); - return 0; - } - ref->contents = contents; - } - - return 1; + size_t i = 0; + hoedown_buffer *contents = 0; + size_t ind = 0; + int in_empty = 0; + size_t start = 0; + + size_t id_offset, id_end; + + /* up to 3 optional leading spaces */ + if (beg + 3 >= end) return 0; + if (data[beg] == ' ') { i = 1; + if (data[beg + 1] == ' ') { i = 2; + if (data[beg + 2] == ' ') { i = 3; + if (data[beg + 3] == ' ') return 0; } } } + i += beg; + + /* id part: caret followed by anything between brackets */ + if (data[i] != '[') return 0; + i++; + if (i >= end || data[i] != '^') return 0; + i++; + id_offset = i; + while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') + i++; + if (i >= end || data[i] != ']') return 0; + id_end = i; + + /* spacer: colon (space | tab)* newline? (space | tab)* */ + i++; + if (i >= end || data[i] != ':') return 0; + i++; + + /* getting content buffer */ + contents = hoedown_buffer_new(64); + + start = i; + + /* process lines similar to a list item */ + while (i < end) { + while (i < end && data[i] != '\n' && data[i] != '\r') i++; + + /* process an empty line */ + if (is_empty(data + start, i - start)) { + in_empty = 1; + if (i < end && (data[i] == '\n' || data[i] == '\r')) { + i++; + if (i < end && data[i] == '\n' && data[i - 1] == '\r') i++; + } + start = i; + continue; + } + + /* calculating the indentation */ + ind = 0; + while (ind < 4 && start + ind < end && data[start + ind] == ' ') + ind++; + + /* joining only indented stuff after empty lines; + * note that now we only require 1 space of indentation + * to continue, just like lists */ + if (ind == 0) { + if (start == id_end + 2 && data[start] == '\t') {} + else break; + } + else if (in_empty) { + hoedown_buffer_putc(contents, '\n'); + } + + in_empty = 0; + + /* adding the line into the content buffer */ + hoedown_buffer_put(contents, data + start + ind, i - start - ind); + /* add carriage return */ + if (i < end) { + hoedown_buffer_putc(contents, '\n'); + if (i < end && (data[i] == '\n' || data[i] == '\r')) { + i++; + if (i < end && data[i] == '\n' && data[i - 1] == '\r') i++; + } + } + start = i; + } + + if (last) + *last = start; + + if (list) { + struct footnote_ref *ref; + ref = create_footnote_ref(list, data + id_offset, id_end - id_offset); + if (!ref) + return 0; + if (!add_footnote_ref(list, ref)) { + free_footnote_ref(ref); + return 0; + } + ref->contents = contents; + } + + return 1; } /* is_ref • returns whether a line is a reference or not */ static int is_ref(const uint8_t *data, size_t beg, size_t end, size_t *last, struct link_ref **refs) { -/* int n; */ - size_t i = 0; - size_t id_offset, id_end; - size_t link_offset, link_end; - size_t title_offset, title_end; - size_t line_end; - - /* up to 3 optional leading spaces */ - if (beg + 3 >= end) return 0; - if (data[beg] == ' ') { i = 1; - if (data[beg + 1] == ' ') { i = 2; - if (data[beg + 2] == ' ') { i = 3; - if (data[beg + 3] == ' ') return 0; } } } - i += beg; - - /* id part: anything but a newline between brackets */ - if (data[i] != '[') return 0; - i++; - id_offset = i; - while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') - i++; - if (i >= end || data[i] != ']') return 0; - id_end = i; - - /* spacer: colon (space | tab)* newline? (space | tab)* */ - i++; - if (i >= end || data[i] != ':') return 0; - i++; - while (i < end && data[i] == ' ') i++; - if (i < end && (data[i] == '\n' || data[i] == '\r')) { - i++; - if (i < end && data[i] == '\r' && data[i - 1] == '\n') i++; } - while (i < end && data[i] == ' ') i++; - if (i >= end) return 0; - - /* link: spacing-free sequence, optionally between angle brackets */ - if (data[i] == '<') - i++; - - link_offset = i; - - while (i < end && data[i] != ' ' && data[i] != '\n' && data[i] != '\r') - i++; - - if (data[i - 1] == '>') link_end = i - 1; - else link_end = i; - - /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ - while (i < end && data[i] == ' ') i++; - if (i < end && data[i] != '\n' && data[i] != '\r' - && data[i] != '\'' && data[i] != '"' && data[i] != '(') - return 0; - line_end = 0; - /* computing end-of-line */ - if (i >= end || data[i] == '\r' || data[i] == '\n') line_end = i; - if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') - line_end = i + 1; - - /* optional (space|tab)* spacer after a newline */ - if (line_end) { - i = line_end + 1; - while (i < end && data[i] == ' ') i++; } - - /* optional title: any non-newline sequence enclosed in '"() - alone on its line */ - title_offset = title_end = 0; - if (i + 1 < end - && (data[i] == '\'' || data[i] == '"' || data[i] == '(')) { - i++; - title_offset = i; - /* looking for EOL */ - while (i < end && data[i] != '\n' && data[i] != '\r') i++; - if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') - title_end = i + 1; - else title_end = i; - /* stepping back */ - i -= 1; - while (i > title_offset && data[i] == ' ') - i -= 1; - if (i > title_offset - && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { - line_end = title_end; - title_end = i; } } - - if (!line_end || link_end == link_offset) - return 0; /* garbage after the link empty link */ - - /* a valid ref has been found, filling-in return structures */ - if (last) - *last = line_end; - - if (refs) { - struct link_ref *ref; - - ref = add_link_ref(refs, data + id_offset, id_end - id_offset); - if (!ref) - return 0; - - ref->link = hoedown_buffer_new(link_end - link_offset); - hoedown_buffer_put(ref->link, data + link_offset, link_end - link_offset); - - if (title_end > title_offset) { - ref->title = hoedown_buffer_new(title_end - title_offset); - hoedown_buffer_put(ref->title, data + title_offset, title_end - title_offset); - } - } - - return 1; +/* int n; */ + size_t i = 0; + size_t id_offset, id_end; + size_t link_offset, link_end; + size_t title_offset, title_end; + size_t line_end; + + /* up to 3 optional leading spaces */ + if (beg + 3 >= end) return 0; + if (data[beg] == ' ') { i = 1; + if (data[beg + 1] == ' ') { i = 2; + if (data[beg + 2] == ' ') { i = 3; + if (data[beg + 3] == ' ') return 0; } } } + i += beg; + + /* id part: anything but a newline between brackets */ + if (data[i] != '[') return 0; + i++; + id_offset = i; + while (i < end && data[i] != '\n' && data[i] != '\r' && data[i] != ']') + i++; + if (i >= end || data[i] != ']') return 0; + id_end = i; + + /* spacer: colon (space | tab)* newline? (space | tab)* */ + i++; + if (i >= end || data[i] != ':') return 0; + i++; + while (i < end && data[i] == ' ') i++; + if (i < end && (data[i] == '\n' || data[i] == '\r')) { + i++; + if (i < end && data[i] == '\r' && data[i - 1] == '\n') i++; } + while (i < end && data[i] == ' ') i++; + if (i >= end) return 0; + + /* link: spacing-free sequence, optionally between angle brackets */ + if (data[i] == '<') + i++; + + link_offset = i; + + while (i < end && data[i] != ' ' && data[i] != '\n' && data[i] != '\r') + i++; + + if (data[i - 1] == '>') link_end = i - 1; + else link_end = i; + + /* optional spacer: (space | tab)* (newline | '\'' | '"' | '(' ) */ + while (i < end && data[i] == ' ') i++; + if (i < end && data[i] != '\n' && data[i] != '\r' + && data[i] != '\'' && data[i] != '"' && data[i] != '(') + return 0; + line_end = 0; + /* computing end-of-line */ + if (i >= end || data[i] == '\r' || data[i] == '\n') line_end = i; + if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') + line_end = i + 1; + + /* optional (space|tab)* spacer after a newline */ + if (line_end) { + i = line_end + 1; + while (i < end && data[i] == ' ') i++; } + + /* optional title: any non-newline sequence enclosed in '"() + alone on its line */ + title_offset = title_end = 0; + if (i + 1 < end + && (data[i] == '\'' || data[i] == '"' || data[i] == '(')) { + i++; + title_offset = i; + /* looking for EOL */ + while (i < end && data[i] != '\n' && data[i] != '\r') i++; + if (i + 1 < end && data[i] == '\n' && data[i + 1] == '\r') + title_end = i + 1; + else title_end = i; + /* stepping back */ + i -= 1; + while (i > title_offset && data[i] == ' ') + i -= 1; + if (i > title_offset + && (data[i] == '\'' || data[i] == '"' || data[i] == ')')) { + line_end = title_end; + title_end = i; } } + + if (!line_end || link_end == link_offset) + return 0; /* garbage after the link empty link */ + + /* a valid ref has been found, filling-in return structures */ + if (last) + *last = line_end; + + if (refs) { + struct link_ref *ref; + + ref = add_link_ref(refs, data + id_offset, id_end - id_offset); + if (!ref) + return 0; + + ref->link = hoedown_buffer_new(link_end - link_offset); + hoedown_buffer_put(ref->link, data + link_offset, link_end - link_offset); + + if (title_end > title_offset) { + ref->title = hoedown_buffer_new(title_end - title_offset); + hoedown_buffer_put(ref->title, data + title_offset, title_end - title_offset); + } + } + + return 1; } static void expand_tabs(hoedown_buffer *ob, const uint8_t *line, size_t size) { - /* This code makes two assumptions: - * - Input is valid UTF-8. (Any byte with top two bits 10 is skipped, - * whether or not it is a valid UTF-8 continuation byte.) - * - Input contains no combining characters. (Combining characters - * should be skipped but are not.) - */ - size_t i = 0, tab = 0; + /* This code makes two assumptions: + * - Input is valid UTF-8. (Any byte with top two bits 10 is skipped, + * whether or not it is a valid UTF-8 continuation byte.) + * - Input contains no combining characters. (Combining characters + * should be skipped but are not.) + */ + size_t i = 0, tab = 0; - while (i < size) { - size_t org = i; + while (i < size) { + size_t org = i; - while (i < size && line[i] != '\t') { - /* ignore UTF-8 continuation bytes */ - if ((line[i] & 0xc0) != 0x80) - tab++; - i++; - } + while (i < size && line[i] != '\t') { + /* ignore UTF-8 continuation bytes */ + if ((line[i] & 0xc0) != 0x80) + tab++; + i++; + } - if (i > org) - hoedown_buffer_put(ob, line + org, i - org); + if (i > org) + hoedown_buffer_put(ob, line + org, i - org); - if (i >= size) - break; + if (i >= size) + break; - do { - hoedown_buffer_putc(ob, ' '); tab++; - } while (tab % 4); + do { + hoedown_buffer_putc(ob, ' '); tab++; + } while (tab % 4); - i++; - } + i++; + } } /********************** @@ -2734,225 +2734,225 @@ static void expand_tabs(hoedown_buffer *ob, const uint8_t *line, size_t size) hoedown_document * hoedown_document_new( - const hoedown_renderer *renderer, - hoedown_extensions extensions, - size_t max_nesting) + const hoedown_renderer *renderer, + hoedown_extensions extensions, + size_t max_nesting) { - hoedown_document *doc = NULL; + hoedown_document *doc = NULL; - assert(max_nesting > 0 && renderer); + assert(max_nesting > 0 && renderer); - doc = hoedown_malloc(sizeof(hoedown_document)); - memcpy(&doc->md, renderer, sizeof(hoedown_renderer)); + doc = hoedown_malloc(sizeof(hoedown_document)); + memcpy(&doc->md, renderer, sizeof(hoedown_renderer)); - doc->data.opaque = renderer->opaque; + doc->data.opaque = renderer->opaque; - hoedown_stack_init(&doc->work_bufs[BUFFER_BLOCK], 4); - hoedown_stack_init(&doc->work_bufs[BUFFER_SPAN], 8); + hoedown_stack_init(&doc->work_bufs[BUFFER_BLOCK], 4); + hoedown_stack_init(&doc->work_bufs[BUFFER_SPAN], 8); - memset(doc->active_char, 0x0, 256); + memset(doc->active_char, 0x0, 256); - if (extensions & HOEDOWN_EXT_UNDERLINE && doc->md.underline) { - doc->active_char['_'] = MD_CHAR_EMPHASIS; - } + if (extensions & HOEDOWN_EXT_UNDERLINE && doc->md.underline) { + doc->active_char['_'] = MD_CHAR_EMPHASIS; + } - if (doc->md.emphasis || doc->md.double_emphasis || doc->md.triple_emphasis) { - doc->active_char['*'] = MD_CHAR_EMPHASIS; - doc->active_char['_'] = MD_CHAR_EMPHASIS; - if (extensions & HOEDOWN_EXT_STRIKETHROUGH) - doc->active_char['~'] = MD_CHAR_EMPHASIS; - if (extensions & HOEDOWN_EXT_HIGHLIGHT) - doc->active_char['='] = MD_CHAR_EMPHASIS; - } + if (doc->md.emphasis || doc->md.double_emphasis || doc->md.triple_emphasis) { + doc->active_char['*'] = MD_CHAR_EMPHASIS; + doc->active_char['_'] = MD_CHAR_EMPHASIS; + if (extensions & HOEDOWN_EXT_STRIKETHROUGH) + doc->active_char['~'] = MD_CHAR_EMPHASIS; + if (extensions & HOEDOWN_EXT_HIGHLIGHT) + doc->active_char['='] = MD_CHAR_EMPHASIS; + } - if (doc->md.codespan) - doc->active_char['`'] = MD_CHAR_CODESPAN; + if (doc->md.codespan) + doc->active_char['`'] = MD_CHAR_CODESPAN; - if (doc->md.linebreak) - doc->active_char['\n'] = MD_CHAR_LINEBREAK; + if (doc->md.linebreak) + doc->active_char['\n'] = MD_CHAR_LINEBREAK; - if (doc->md.image || doc->md.link || doc->md.footnotes || doc->md.footnote_ref) - doc->active_char['['] = MD_CHAR_LINK; + if (doc->md.image || doc->md.link || doc->md.footnotes || doc->md.footnote_ref) + doc->active_char['['] = MD_CHAR_LINK; - doc->active_char['<'] = MD_CHAR_LANGLE; - doc->active_char['\\'] = MD_CHAR_ESCAPE; - doc->active_char['&'] = MD_CHAR_ENTITY; + doc->active_char['<'] = MD_CHAR_LANGLE; + doc->active_char['\\'] = MD_CHAR_ESCAPE; + doc->active_char['&'] = MD_CHAR_ENTITY; - if (extensions & HOEDOWN_EXT_AUTOLINK) { - doc->active_char[':'] = MD_CHAR_AUTOLINK_URL; - doc->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; - doc->active_char['w'] = MD_CHAR_AUTOLINK_WWW; - } + if (extensions & HOEDOWN_EXT_AUTOLINK) { + doc->active_char[':'] = MD_CHAR_AUTOLINK_URL; + doc->active_char['@'] = MD_CHAR_AUTOLINK_EMAIL; + doc->active_char['w'] = MD_CHAR_AUTOLINK_WWW; + } - if (extensions & HOEDOWN_EXT_SUPERSCRIPT) - doc->active_char['^'] = MD_CHAR_SUPERSCRIPT; + if (extensions & HOEDOWN_EXT_SUPERSCRIPT) + doc->active_char['^'] = MD_CHAR_SUPERSCRIPT; - if (extensions & HOEDOWN_EXT_QUOTE) - doc->active_char['"'] = MD_CHAR_QUOTE; + if (extensions & HOEDOWN_EXT_QUOTE) + doc->active_char['"'] = MD_CHAR_QUOTE; - if (extensions & HOEDOWN_EXT_MATH) - doc->active_char['$'] = MD_CHAR_MATH; + if (extensions & HOEDOWN_EXT_MATH) + doc->active_char['$'] = MD_CHAR_MATH; - /* Extension data */ - doc->ext_flags = extensions; - doc->max_nesting = max_nesting; - doc->in_link_body = 0; + /* Extension data */ + doc->ext_flags = extensions; + doc->max_nesting = max_nesting; + doc->in_link_body = 0; - return doc; + return doc; } void hoedown_document_render(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size) { - static const uint8_t UTF8_BOM[] = {0xEF, 0xBB, 0xBF}; + static const uint8_t UTF8_BOM[] = {0xEF, 0xBB, 0xBF}; - hoedown_buffer *text; - size_t beg, end; + hoedown_buffer *text; + size_t beg, end; - int footnotes_enabled; + int footnotes_enabled; - text = hoedown_buffer_new(64); + text = hoedown_buffer_new(64); - /* Preallocate enough space for our buffer to avoid expanding while copying */ - hoedown_buffer_grow(text, size); + /* Preallocate enough space for our buffer to avoid expanding while copying */ + hoedown_buffer_grow(text, size); - /* reset the references table */ - memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); + /* reset the references table */ + memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); - footnotes_enabled = doc->ext_flags & HOEDOWN_EXT_FOOTNOTES; + footnotes_enabled = doc->ext_flags & HOEDOWN_EXT_FOOTNOTES; - /* reset the footnotes lists */ - if (footnotes_enabled) { - memset(&doc->footnotes_found, 0x0, sizeof(doc->footnotes_found)); - memset(&doc->footnotes_used, 0x0, sizeof(doc->footnotes_used)); - } + /* reset the footnotes lists */ + if (footnotes_enabled) { + memset(&doc->footnotes_found, 0x0, sizeof(doc->footnotes_found)); + memset(&doc->footnotes_used, 0x0, sizeof(doc->footnotes_used)); + } - /* first pass: looking for references, copying everything else */ - beg = 0; + /* first pass: looking for references, copying everything else */ + beg = 0; - /* Skip a possible UTF-8 BOM, even though the Unicode standard - * discourages having these in UTF-8 documents */ - if (size >= 3 && memcmp(data, UTF8_BOM, 3) == 0) - beg += 3; + /* Skip a possible UTF-8 BOM, even though the Unicode standard + * discourages having these in UTF-8 documents */ + if (size >= 3 && memcmp(data, UTF8_BOM, 3) == 0) + beg += 3; - while (beg < size) /* iterating over lines */ - if (footnotes_enabled && is_footnote(data, beg, size, &end, &doc->footnotes_found)) - beg = end; - else if (is_ref(data, beg, size, &end, doc->refs)) - beg = end; - else { /* skipping to the next line */ - end = beg; - while (end < size && data[end] != '\n' && data[end] != '\r') - end++; + while (beg < size) /* iterating over lines */ + if (footnotes_enabled && is_footnote(data, beg, size, &end, &doc->footnotes_found)) + beg = end; + else if (is_ref(data, beg, size, &end, doc->refs)) + beg = end; + else { /* skipping to the next line */ + end = beg; + while (end < size && data[end] != '\n' && data[end] != '\r') + end++; - /* adding the line body if present */ - if (end > beg) - expand_tabs(text, data + beg, end - beg); + /* adding the line body if present */ + if (end > beg) + expand_tabs(text, data + beg, end - beg); - while (end < size && (data[end] == '\n' || data[end] == '\r')) { - /* add one \n per newline */ - if (data[end] == '\n' || (end + 1 < size && data[end + 1] != '\n')) - hoedown_buffer_putc(text, '\n'); - end++; - } + while (end < size && (data[end] == '\n' || data[end] == '\r')) { + /* add one \n per newline */ + if (data[end] == '\n' || (end + 1 < size && data[end + 1] != '\n')) + hoedown_buffer_putc(text, '\n'); + end++; + } - beg = end; - } + beg = end; + } - /* pre-grow the output buffer to minimize allocations */ - hoedown_buffer_grow(ob, text->size + (text->size >> 1)); + /* pre-grow the output buffer to minimize allocations */ + hoedown_buffer_grow(ob, text->size + (text->size >> 1)); - /* second pass: actual rendering */ - if (doc->md.doc_header) - doc->md.doc_header(ob, 0, &doc->data); + /* second pass: actual rendering */ + if (doc->md.doc_header) + doc->md.doc_header(ob, 0, &doc->data); - if (text->size) { - /* adding a final newline if not already present */ - if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r') - hoedown_buffer_putc(text, '\n'); + if (text->size) { + /* adding a final newline if not already present */ + if (text->data[text->size - 1] != '\n' && text->data[text->size - 1] != '\r') + hoedown_buffer_putc(text, '\n'); - parse_block(ob, doc, text->data, text->size); - } + parse_block(ob, doc, text->data, text->size); + } - /* footnotes */ - if (footnotes_enabled) - parse_footnote_list(ob, doc, &doc->footnotes_used); + /* footnotes */ + if (footnotes_enabled) + parse_footnote_list(ob, doc, &doc->footnotes_used); - if (doc->md.doc_footer) - doc->md.doc_footer(ob, 0, &doc->data); + if (doc->md.doc_footer) + doc->md.doc_footer(ob, 0, &doc->data); - /* clean-up */ - hoedown_buffer_free(text); - free_link_refs(doc->refs); - if (footnotes_enabled) { - free_footnote_list(&doc->footnotes_found, 1); - free_footnote_list(&doc->footnotes_used, 0); - } + /* clean-up */ + hoedown_buffer_free(text); + free_link_refs(doc->refs); + if (footnotes_enabled) { + free_footnote_list(&doc->footnotes_found, 1); + free_footnote_list(&doc->footnotes_used, 0); + } - assert(doc->work_bufs[BUFFER_SPAN].size == 0); - assert(doc->work_bufs[BUFFER_BLOCK].size == 0); + assert(doc->work_bufs[BUFFER_SPAN].size == 0); + assert(doc->work_bufs[BUFFER_BLOCK].size == 0); } void hoedown_document_render_inline(hoedown_document *doc, hoedown_buffer *ob, const uint8_t *data, size_t size) { - size_t i = 0, mark; - hoedown_buffer *text = hoedown_buffer_new(64); + size_t i = 0, mark; + hoedown_buffer *text = hoedown_buffer_new(64); - /* reset the references table */ - memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); + /* reset the references table */ + memset(&doc->refs, 0x0, REF_TABLE_SIZE * sizeof(void *)); - /* first pass: expand tabs and process newlines */ - hoedown_buffer_grow(text, size); - while (1) { - mark = i; - while (i < size && data[i] != '\n' && data[i] != '\r') - i++; + /* first pass: expand tabs and process newlines */ + hoedown_buffer_grow(text, size); + while (1) { + mark = i; + while (i < size && data[i] != '\n' && data[i] != '\r') + i++; - expand_tabs(text, data + mark, i - mark); + expand_tabs(text, data + mark, i - mark); - if (i >= size) - break; + if (i >= size) + break; - while (i < size && (data[i] == '\n' || data[i] == '\r')) { - /* add one \n per newline */ - if (data[i] == '\n' || (i + 1 < size && data[i + 1] != '\n')) - hoedown_buffer_putc(text, '\n'); - i++; - } - } + while (i < size && (data[i] == '\n' || data[i] == '\r')) { + /* add one \n per newline */ + if (data[i] == '\n' || (i + 1 < size && data[i + 1] != '\n')) + hoedown_buffer_putc(text, '\n'); + i++; + } + } - /* second pass: actual rendering */ - hoedown_buffer_grow(ob, text->size + (text->size >> 1)); + /* second pass: actual rendering */ + hoedown_buffer_grow(ob, text->size + (text->size >> 1)); - if (doc->md.doc_header) - doc->md.doc_header(ob, 1, &doc->data); + if (doc->md.doc_header) + doc->md.doc_header(ob, 1, &doc->data); - parse_inline(ob, doc, text->data, text->size); + parse_inline(ob, doc, text->data, text->size); - if (doc->md.doc_footer) - doc->md.doc_footer(ob, 1, &doc->data); + if (doc->md.doc_footer) + doc->md.doc_footer(ob, 1, &doc->data); - /* clean-up */ - hoedown_buffer_free(text); + /* clean-up */ + hoedown_buffer_free(text); - assert(doc->work_bufs[BUFFER_SPAN].size == 0); - assert(doc->work_bufs[BUFFER_BLOCK].size == 0); + assert(doc->work_bufs[BUFFER_SPAN].size == 0); + assert(doc->work_bufs[BUFFER_BLOCK].size == 0); } void hoedown_document_free(hoedown_document *doc) { - size_t i; + size_t i; - for (i = 0; i < (size_t)doc->work_bufs[BUFFER_SPAN].asize; ++i) - hoedown_buffer_free(doc->work_bufs[BUFFER_SPAN].item[i]); + for (i = 0; i < (size_t)doc->work_bufs[BUFFER_SPAN].asize; ++i) + hoedown_buffer_free(doc->work_bufs[BUFFER_SPAN].item[i]); - for (i = 0; i < (size_t)doc->work_bufs[BUFFER_BLOCK].asize; ++i) - hoedown_buffer_free(doc->work_bufs[BUFFER_BLOCK].item[i]); + for (i = 0; i < (size_t)doc->work_bufs[BUFFER_BLOCK].asize; ++i) + hoedown_buffer_free(doc->work_bufs[BUFFER_BLOCK].item[i]); - hoedown_stack_uninit(&doc->work_bufs[BUFFER_SPAN]); - hoedown_stack_uninit(&doc->work_bufs[BUFFER_BLOCK]); + hoedown_stack_uninit(&doc->work_bufs[BUFFER_SPAN]); + hoedown_stack_uninit(&doc->work_bufs[BUFFER_BLOCK]); - free(doc); + free(doc); } |