summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/blocks.c201
-rw-r--r--src/buffer.c11
-rw-r--r--src/inlines.c465
-rw-r--r--src/main.c5
-rw-r--r--src/print.c34
-rw-r--r--src/references.c9
-rw-r--r--src/stmd.h2
-rw-r--r--src/utf8.c39
8 files changed, 376 insertions, 390 deletions
diff --git a/src/blocks.c b/src/blocks.c
index 024b8f0..8d6fd06 100644
--- a/src/blocks.c
+++ b/src/blocks.c
@@ -47,13 +47,13 @@ bool is_blank(strbuf *s, int offset)
{
while (offset < s->size) {
switch (s->ptr[offset]) {
- case '\n':
- return true;
- case ' ':
- offset++;
- break;
- default:
- return false;
+ case '\n':
+ return true;
+ case ' ':
+ offset++;
+ break;
+ default:
+ return false;
}
}
@@ -63,17 +63,17 @@ bool is_blank(strbuf *s, int offset)
static inline bool can_contain(int parent_type, int child_type)
{
return ( parent_type == BLOCK_DOCUMENT ||
- parent_type == BLOCK_BQUOTE ||
- parent_type == BLOCK_LIST_ITEM ||
- (parent_type == BLOCK_LIST && child_type == BLOCK_LIST_ITEM) );
+ parent_type == BLOCK_BQUOTE ||
+ parent_type == BLOCK_LIST_ITEM ||
+ (parent_type == BLOCK_LIST && child_type == BLOCK_LIST_ITEM) );
}
static inline bool accepts_lines(int block_type)
{
return (block_type == BLOCK_PARAGRAPH ||
- block_type == BLOCK_ATX_HEADER ||
- block_type == BLOCK_INDENTED_CODE ||
- block_type == BLOCK_FENCED_CODE);
+ block_type == BLOCK_ATX_HEADER ||
+ block_type == BLOCK_INDENTED_CODE ||
+ block_type == BLOCK_FENCED_CODE);
}
static void add_line(node_block* node_block, chunk *ch, int offset)
@@ -87,7 +87,7 @@ static void remove_trailing_blank_lines(strbuf *ln)
int i;
for (i = ln->size - 1; i >= 0; --i) {
- char c = ln->ptr[i];
+ unsigned char c = ln->ptr[i];
if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
break;
@@ -156,77 +156,77 @@ static void finalize(node_block* b, int line_number)
}
switch (b->tag) {
- case BLOCK_PARAGRAPH:
- pos = 0;
- while (strbuf_at(&b->string_content, 0) == '[' &&
- (pos = parse_reference_inline(&b->string_content, b->top->as.document.refmap))) {
-
- strbuf_drop(&b->string_content, pos);
- }
- if (is_blank(&b->string_content, 0)) {
- b->tag = BLOCK_REFERENCE_DEF;
- }
- break;
+ case BLOCK_PARAGRAPH:
+ pos = 0;
+ while (strbuf_at(&b->string_content, 0) == '[' &&
+ (pos = parse_reference_inline(&b->string_content, b->top->as.document.refmap))) {
- case BLOCK_INDENTED_CODE:
- remove_trailing_blank_lines(&b->string_content);
- strbuf_putc(&b->string_content, '\n');
- break;
-
- case BLOCK_FENCED_CODE:
- // first line of contents becomes info
- firstlinelen = strbuf_strchr(&b->string_content, '\n', 0);
-
- strbuf_init(&b->as.code.info, 0);
- houdini_unescape_html_f(
- &b->as.code.info,
- b->string_content.ptr,
- firstlinelen
+ strbuf_drop(&b->string_content, pos);
+ }
+ if (is_blank(&b->string_content, 0)) {
+ b->tag = BLOCK_REFERENCE_DEF;
+ }
+ break;
+
+ case BLOCK_INDENTED_CODE:
+ remove_trailing_blank_lines(&b->string_content);
+ strbuf_putc(&b->string_content, '\n');
+ break;
+
+ case BLOCK_FENCED_CODE:
+ // first line of contents becomes info
+ firstlinelen = strbuf_strchr(&b->string_content, '\n', 0);
+
+ strbuf_init(&b->as.code.info, 0);
+ houdini_unescape_html_f(
+ &b->as.code.info,
+ b->string_content.ptr,
+ firstlinelen
);
- strbuf_drop(&b->string_content, firstlinelen + 1);
+ strbuf_drop(&b->string_content, firstlinelen + 1);
- strbuf_trim(&b->as.code.info);
- strbuf_unescape(&b->as.code.info);
- break;
+ strbuf_trim(&b->as.code.info);
+ strbuf_unescape(&b->as.code.info);
+ break;
- case BLOCK_LIST: // determine tight/loose status
- b->as.list.tight = true; // tight by default
- item = b->children;
+ case BLOCK_LIST: // determine tight/loose status
+ b->as.list.tight = true; // tight by default
+ item = b->children;
- while (item) {
- // check for non-final non-empty list item ending with blank line:
- if (item->last_line_blank && item->next) {
+ while (item) {
+ // check for non-final non-empty list item ending with blank line:
+ if (item->last_line_blank && item->next) {
+ b->as.list.tight = false;
+ break;
+ }
+ // recurse into children of list item, to see if there are
+ // spaces between them:
+ subitem = item->children;
+ while (subitem) {
+ if (ends_with_blank_line(subitem) &&
+ (item->next || subitem->next)) {
b->as.list.tight = false;
break;
}
- // recurse into children of list item, to see if there are
- // spaces between them:
- subitem = item->children;
- while (subitem) {
- if (ends_with_blank_line(subitem) &&
- (item->next || subitem->next)) {
- b->as.list.tight = false;
- break;
- }
- subitem = subitem->next;
- }
- if (!(b->as.list.tight)) {
- break;
- }
- item = item->next;
+ subitem = subitem->next;
}
+ if (!(b->as.list.tight)) {
+ break;
+ }
+ item = item->next;
+ }
- break;
+ break;
- default:
- break;
+ default:
+ break;
}
}
// Add a node_block as child of another. Return pointer to child.
static node_block* add_child(node_block* parent,
- int block_type, int start_line, int start_column)
+ int block_type, int start_line, int start_column)
{
assert(parent);
@@ -276,14 +276,14 @@ void stmd_free_nodes(node_block *e)
void process_inlines(node_block* cur, reference_map *refmap)
{
switch (cur->tag) {
- case BLOCK_PARAGRAPH:
- case BLOCK_ATX_HEADER:
- case BLOCK_SETEXT_HEADER:
- cur->inline_content = parse_inlines(&cur->string_content, refmap);
- break;
-
- default:
- break;
+ case BLOCK_PARAGRAPH:
+ case BLOCK_ATX_HEADER:
+ case BLOCK_SETEXT_HEADER:
+ cur->inline_content = parse_inlines(&cur->string_content, refmap);
+ break;
+
+ default:
+ break;
}
node_block *child = cur->children;
@@ -362,9 +362,9 @@ static int parse_list_marker(chunk *input, int pos, struct ListData ** dataptr)
static int lists_match(struct ListData *list_data, struct ListData *item_data)
{
return (list_data->list_type == item_data->list_type &&
- list_data->delimiter == item_data->delimiter &&
- // list_data->marker_offset == item_data.marker_offset &&
- list_data->bullet_char == item_data->bullet_char);
+ list_data->delimiter == item_data->delimiter &&
+ // list_data->marker_offset == item_data.marker_offset &&
+ list_data->bullet_char == item_data->bullet_char);
}
static node_block *finalize_document(node_block *document, int linenum)
@@ -493,7 +493,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
} else if (container->tag == BLOCK_LIST_ITEM) {
if (indent >= container->as.list.marker_offset +
- container->as.list.padding) {
+ container->as.list.padding) {
offset += container->as.list.marker_offset +
container->as.list.padding;
} else if (blank) {
@@ -513,7 +513,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
}
} else if (container->tag == BLOCK_ATX_HEADER ||
- container->tag == BLOCK_SETEXT_HEADER) {
+ container->tag == BLOCK_SETEXT_HEADER) {
// a header can never contain more than one line
all_matched = false;
@@ -557,7 +557,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
// unless last matched container is code node_block, try new container starts:
while (container->tag != BLOCK_FENCED_CODE && container->tag != BLOCK_INDENTED_CODE &&
- container->tag != BLOCK_HTML) {
+ container->tag != BLOCK_HTML) {
first_nonspace = offset;
while (peek_at(&input, first_nonspace) == ' ')
@@ -610,17 +610,17 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
// note, we don't adjust offset because the tag is part of the text
} else if (container->tag == BLOCK_PARAGRAPH &&
- (lev = scan_setext_header_line(&input, first_nonspace)) &&
- // check that there is only one line in the paragraph:
- strbuf_strrchr(&container->string_content, '\n',
- strbuf_len(&container->string_content) - 2) < 0) {
+ (lev = scan_setext_header_line(&input, first_nonspace)) &&
+ // check that there is only one line in the paragraph:
+ strbuf_strrchr(&container->string_content, '\n',
+ strbuf_len(&container->string_content) - 2) < 0) {
container->tag = BLOCK_SETEXT_HEADER;
container->as.header.level = lev;
offset = input.len - 1;
} else if (!(container->tag == BLOCK_PARAGRAPH && !all_matched) &&
- (matched = scan_hrule(&input, first_nonspace))) {
+ (matched = scan_hrule(&input, first_nonspace))) {
// it's only now that we know the line is not part of a setext header:
container = add_child(container, BLOCK_HRULE, line_number, first_nonspace + 1);
@@ -653,16 +653,16 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
data->marker_offset = indent;
if (container->tag != BLOCK_LIST ||
- !lists_match(&container->as.list, data)) {
+ !lists_match(&container->as.list, data)) {
container = add_child(container, BLOCK_LIST, line_number,
- first_nonspace + 1);
+ first_nonspace + 1);
memcpy(&container->as.list, data, sizeof(*data));
}
// add the list item
container = add_child(container, BLOCK_LIST_ITEM, line_number,
- first_nonspace + 1);
+ first_nonspace + 1);
/* TODO: static */
memcpy(&container->as.list, data, sizeof(*data));
free(data);
@@ -691,11 +691,11 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
// lists or breaking out of lists. we also don't set last_line_blank
// on an empty list item.
container->last_line_blank = (blank &&
- container->tag != BLOCK_BQUOTE &&
- container->tag != BLOCK_FENCED_CODE &&
- !(container->tag == BLOCK_LIST_ITEM &&
- container->children == NULL &&
- container->start_line == line_number));
+ container->tag != BLOCK_BQUOTE &&
+ container->tag != BLOCK_FENCED_CODE &&
+ !(container->tag == BLOCK_LIST_ITEM &&
+ container->children == NULL &&
+ container->start_line == line_number));
node_block *cont = container;
while (cont->parent) {
@@ -704,10 +704,10 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
}
if (cur != last_matched_container &&
- container == last_matched_container &&
- !blank &&
- cur->tag == BLOCK_PARAGRAPH &&
- strbuf_len(&cur->string_content) > 0) {
+ container == last_matched_container &&
+ !blank &&
+ cur->tag == BLOCK_PARAGRAPH &&
+ strbuf_len(&cur->string_content) > 0) {
add_line(cur, &input, offset);
@@ -728,7 +728,7 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
matched = 0;
if (indent <= 3 &&
- peek_at(&input, first_nonspace) == container->as.code.fence_char) {
+ peek_at(&input, first_nonspace) == container->as.code.fence_char) {
int fence_len = scan_close_code_fence(&input, first_nonspace);
if (fence_len > container->as.code.fence_length)
matched = 1;
@@ -774,4 +774,3 @@ static void incorporate_line(strbuf *line, int line_number, node_block** curptr)
*curptr = container;
}
}
-
diff --git a/src/buffer.c b/src/buffer.c
index 7c2b86b..2e32720 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -15,8 +15,8 @@
unsigned char strbuf__initbuf[1];
unsigned char strbuf__oom[1];
-#define ENSURE_SIZE(b, d) \
- if ((d) > buf->asize && strbuf_grow(b, (d)) < 0)\
+#define ENSURE_SIZE(b, d) \
+ if ((d) > buf->asize && strbuf_grow(b, (d)) < 0) \
return -1;
void strbuf_init(strbuf *buf, int initial_size)
@@ -111,8 +111,8 @@ int strbuf_set(strbuf *buf, const unsigned char *data, int len)
int strbuf_sets(strbuf *buf, const char *string)
{
return strbuf_set(buf,
- (const unsigned char *)string,
- string ? strlen(string) : 0);
+ (const unsigned char *)string,
+ string ? strlen(string) : 0);
}
int strbuf_putc(strbuf *buf, int c)
@@ -155,7 +155,7 @@ int strbuf_vprintf(strbuf *buf, const char *format, va_list ap)
(char *)buf->ptr + buf->size,
buf->asize - buf->size,
format, args
- );
+ );
if (len < 0) {
free(buf->ptr);
@@ -351,4 +351,3 @@ extern void strbuf_unescape(strbuf *buf)
strbuf_truncate(buf, w);
}
-
diff --git a/src/inlines.c b/src/inlines.c
index f5c8e7b..4744312 100644
--- a/src/inlines.c
+++ b/src/inlines.c
@@ -10,11 +10,19 @@
#include "scanners.h"
#include "inlines.h"
+typedef struct InlineStack {
+ struct InlineStack *previous;
+ node_inl *first_inline;
+ int delim_count;
+ unsigned char delim_char;
+} inline_stack;
+
typedef struct Subject {
chunk input;
int pos;
int label_nestlevel;
reference_map *refmap;
+ inline_stack *emphasis_openers;
} subject;
static node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap);
@@ -118,26 +126,26 @@ extern void free_inlines(node_inl* e)
node_inl * next;
while (e != NULL) {
switch (e->tag){
- case INL_STRING:
- case INL_RAW_HTML:
- case INL_CODE:
- chunk_free(&e->content.literal);
- break;
- case INL_LINEBREAK:
- case INL_SOFTBREAK:
- break;
- case INL_LINK:
- case INL_IMAGE:
- free(e->content.linkable.url);
- free(e->content.linkable.title);
- free_inlines(e->content.linkable.label);
- break;
- case INL_EMPH:
- case INL_STRONG:
- free_inlines(e->content.inlines);
- break;
- default:
- break;
+ case INL_STRING:
+ case INL_RAW_HTML:
+ case INL_CODE:
+ chunk_free(&e->content.literal);
+ break;
+ case INL_LINEBREAK:
+ case INL_SOFTBREAK:
+ break;
+ case INL_LINK:
+ case INL_IMAGE:
+ free(e->content.linkable.url);
+ free(e->content.linkable.title);
+ free_inlines(e->content.linkable.label);
+ break;
+ case INL_EMPH:
+ case INL_STRONG:
+ free_inlines(e->content.inlines);
+ break;
+ default:
+ break;
}
next = e->next;
free(e);
@@ -168,6 +176,7 @@ static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap)
e->pos = 0;
e->label_nestlevel = 0;
e->refmap = refmap;
+ e->emphasis_openers = NULL;
chunk_rtrim(&e->input);
}
@@ -180,6 +189,7 @@ static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap)
e->pos = 0;
e->label_nestlevel = 0;
e->refmap = refmap;
+ e->emphasis_openers = NULL;
chunk_rtrim(&e->input);
}
@@ -231,7 +241,7 @@ inline static chunk take_while(subject* subj, int (*f)(int))
static int scan_to_closing_backticks(subject* subj, int openticklength)
{
// read non backticks
- char c;
+ unsigned char c;
while ((c = peek_char(subj)) && c != '`') {
advance(subj);
}
@@ -272,12 +282,11 @@ static node_inl* handle_backticks(subject *subj)
}
// Scan ***, **, or * and return number scanned, or 0.
-// Don't advance position.
-static int scan_delims(subject* subj, char c, bool * can_open, bool * can_close)
+// Advances position.
+static int scan_delims(subject* subj, unsigned char c, bool * can_open, bool * can_close)
{
int numdelims = 0;
- char char_before, char_after;
- int startpos = subj->pos;
+ unsigned char char_before, char_after;
char_before = subj->pos == 0 ? '\n' : peek_at(subj, subj->pos - 1);
while (peek_char(subj) == c) {
@@ -291,132 +300,109 @@ static int scan_delims(subject* subj, char c, bool * can_open, bool * can_close)
*can_open = *can_open && !isalnum(char_before);
*can_close = *can_close && !isalnum(char_after);
}
- subj->pos = startpos;
return numdelims;
}
+static void free_openers(subject* subj, inline_stack* istack)
+{
+ inline_stack * tempstack;
+ while (subj->emphasis_openers != istack) {
+ tempstack = subj->emphasis_openers;
+ subj->emphasis_openers = subj->emphasis_openers->previous;
+ free(tempstack);
+ }
+}
+
// Parse strong/emph or a fallback.
// Assumes the subject has '_' or '*' at the current position.
-static node_inl* handle_strong_emph(subject* subj, char c)
+static node_inl* handle_strong_emph(subject* subj, unsigned char c, node_inl **last)
{
bool can_open, can_close;
- node_inl * result = NULL;
- node_inl * last = NULL;
- node_inl * new;
- node_inl * il;
- node_inl * first_head = NULL;
- node_inl * first_close = NULL;
- int first_close_delims = 0;
int numdelims;
+ int useDelims;
+ inline_stack * istack;
+ node_inl * inl;
+ node_inl * emph;
+ node_inl * inl_text;
numdelims = scan_delims(subj, c, &can_open, &can_close);
- subj->pos += numdelims;
-
- new = make_str(chunk_dup(&subj->input, subj->pos - numdelims, numdelims));
- last = new;
- first_head = new;
- result = new;
-
- if (!can_open || numdelims == 0) {
- goto done;
- }
-
- switch (numdelims) {
- case 1:
- while (true) {
- numdelims = scan_delims(subj, c, &can_open, &can_close);
- if (numdelims >= 1 && can_close) {
- subj->pos += 1;
- first_head->tag = INL_EMPH;
- chunk_free(&first_head->content.literal);
- first_head->content.inlines = first_head->next;
- first_head->next = NULL;
- goto done;
- } else {
- if (!parse_inline(subj, &last)) {
- goto done;
- }
- }
- }
- break;
- case 2:
- while (true) {
- numdelims = scan_delims(subj, c, &can_open, &can_close);
- if (numdelims >= 2 && can_close) {
- subj->pos += 2;
- first_head->tag = INL_STRONG;
- chunk_free(&first_head->content.literal);
- first_head->content.inlines = first_head->next;
- first_head->next = NULL;
- goto done;
- } else {
- if (!parse_inline(subj, &last)) {
- goto done;
- }
- }
- }
- break;
- case 3:
- while (true) {
- numdelims = scan_delims(subj, c, &can_open, &can_close);
- if (can_close && numdelims >= 1 && numdelims <= 3 &&
- numdelims != first_close_delims) {
- new = make_str(chunk_dup(&subj->input, subj->pos, numdelims));
- append_inlines(last, new);
- last = new;
- if (first_close_delims == 1 && numdelims > 2) {
- numdelims = 2;
- } else if (first_close_delims == 2) {
- numdelims = 1;
- } else if (numdelims == 3) {
- // If we opened with ***, we interpret it as ** followed by *
- // giving us <strong><em>
- numdelims = 1;
- }
- subj->pos += numdelims;
- if (first_close) {
- first_head->tag = first_close_delims == 1 ? INL_STRONG : INL_EMPH;
- chunk_free(&first_head->content.literal);
- first_head->content.inlines =
- make_inlines(first_close_delims == 1 ? INL_EMPH : INL_STRONG,
- first_head->next);
-
- il = first_head->next;
- while (il->next && il->next != first_close) {
- il = il->next;
- }
- il->next = NULL;
-
- first_head->content.inlines->next = first_close->next;
-
- il = first_head->content.inlines;
- while (il->next && il->next != last) {
- il = il->next;
- }
- il->next = NULL;
- free_inlines(last);
-
- first_close->next = NULL;
- free_inlines(first_close);
- first_head->next = NULL;
- goto done;
- } else {
- first_close = last;
- first_close_delims = numdelims;
- }
- } else {
- if (!parse_inline(subj, &last)) {
- goto done;
- }
- }
- }
- break;
- default:
- goto done;
+
+ if (can_close)
+ {
+ // walk the stack and find a matching opener, if there is one
+ istack = subj->emphasis_openers;
+ while (true)
+ {
+ if (istack == NULL)
+ goto cannotClose;
+
+ if (istack->delim_char == c)
+ break;
+
+ istack = istack->previous;
+ }
+
+ // calculate the actual number of delimeters used from this closer
+ useDelims = istack->delim_count;
+ if (useDelims == 3) useDelims = numdelims == 3 ? 1 : numdelims;
+ else if (useDelims > numdelims) useDelims = 1;
+
+ if (istack->delim_count == useDelims)
+ {
+ // the opener is completely used up - remove the stack entry and reuse the inline element
+ inl = istack->first_inline;
+ inl->tag = useDelims == 1 ? INL_EMPH : INL_STRONG;
+ chunk_free(&inl->content.literal);
+ inl->content.inlines = inl->next;
+ inl->next = NULL;
+
+ // remove this opener and all later ones from stack:
+ free_openers(subj, istack->previous);
+ *last = inl;
+ }
+ else
+ {
+ // the opener will only partially be used - stack entry remains (truncated) and a new inline is added.
+ inl = istack->first_inline;
+ istack->delim_count -= useDelims;
+ inl->content.literal.len = istack->delim_count;
+
+ emph = useDelims == 1 ? make_emph(inl->next) : make_strong(inl->next);
+ inl->next = emph;
+
+ // remove all later openers from stack:
+ free_openers(subj, istack);
+
+ *last = emph;
+ }
+
+ // if the closer was not fully used, move back a char or two and try again.
+ if (useDelims < numdelims)
+ {
+ subj->pos = subj->pos - numdelims + useDelims;
+ return handle_strong_emph(subj, c, last);
+ }
+
+ return NULL; // make_str(chunk_literal(""));
+ }
+
+cannotClose:
+ inl_text = make_str(chunk_dup(&subj->input, subj->pos - numdelims, numdelims));
+
+ if (can_open)
+ {
+ istack = (inline_stack*)malloc(sizeof(inline_stack));
+ if (istack == NULL) {
+ return NULL;
+ }
+ istack->delim_count = numdelims;
+ istack->delim_char = c;
+ istack->first_inline = inl_text;
+ istack->previous = subj->emphasis_openers;
+ subj->emphasis_openers = istack;
}
-done:
- return result;
+ return inl_text;
}
// Parse backslash-escape or just a backslash, returning an inline.
@@ -445,9 +431,9 @@ static node_inl* handle_entity(subject* subj)
advance(subj);
len = houdini_unescape_ent(&ent,
- subj->input.data + subj->pos,
- subj->input.len - subj->pos
- );
+ subj->input.data + subj->pos,
+ subj->input.len - subj->pos
+ );
if (len == 0)
return make_str(chunk_literal("&"));
@@ -520,8 +506,8 @@ unsigned char *clean_title(chunk *title)
// remove surrounding quotes if any:
if ((first == '\'' && last == '\'') ||
- (first == '(' && last == ')') ||
- (first == '"' && last == '"')) {
+ (first == '(' && last == ')') ||
+ (first == '"' && last == '"')) {
houdini_unescape_html_f(&buf, title->data + 1, title->len - 2);
} else {
houdini_unescape_html_f(&buf, title->data, title->len);
@@ -549,7 +535,7 @@ static node_inl* handle_pointy_brace(subject* subj)
return make_autolink(
make_str_with_entities(&contents),
contents, 0
- );
+ );
}
// next try to match an email autolink
@@ -559,9 +545,9 @@ static node_inl* handle_pointy_brace(subject* subj)
subj->pos += matchlen;
return make_autolink(
- make_str_with_entities(&contents),
- contents, 1
- );
+ make_str_with_entities(&contents),
+ contents, 1
+ );
}
// finally, try to match an html tag
@@ -602,33 +588,33 @@ static int link_label(subject* subj, chunk *raw_label)
}
advance(subj); // advance past [
- char c;
+ unsigned char c;
while ((c = peek_char(subj)) && (c != ']' || nestlevel > 0)) {
switch (c) {
- case '`':
- tmp = handle_backticks(subj);
- free_inlines(tmp);
- break;
- case '<':
- tmp = handle_pointy_brace(subj);
- free_inlines(tmp);
- break;
- case '[': // nested []
- nestlevel++;
- advance(subj);
- break;
- case ']': // nested []
- nestlevel--;
- advance(subj);
- break;
- case '\\':
- advance(subj);
- if (ispunct(peek_char(subj))) {
- advance(subj);
- }
- break;
- default:
+ case '`':
+ tmp = handle_backticks(subj);
+ free_inlines(tmp);
+ break;
+ case '<':
+ tmp = handle_pointy_brace(subj);
+ free_inlines(tmp);
+ break;
+ case '[': // nested []
+ nestlevel++;
+ advance(subj);
+ break;
+ case ']': // nested []
+ nestlevel--;
+ advance(subj);
+ break;
+ case '\\':
+ advance(subj);
+ if (ispunct(peek_char(subj))) {
advance(subj);
+ }
+ break;
+ default:
+ advance(subj);
}
}
if (c == ']') {
@@ -664,8 +650,8 @@ static node_inl* handle_left_bracket(subject* subj)
if (found_label) {
if (peek_char(subj) == '(' &&
- ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) &&
- ((n = scan_link_url(&subj->input, subj->pos + 1 + sps)) > -1)) {
+ ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) &&
+ ((n = scan_link_url(&subj->input, subj->pos + 1 + sps)) > -1)) {
// try to parse an explicit link:
starturl = subj->pos + 1 + sps; // after (
@@ -691,8 +677,8 @@ static node_inl* handle_left_bracket(subject* subj)
subj->pos = endlabel;
lab = parse_chunk_inlines(&rawlabel, subj->refmap);
result = append_inlines(make_str(chunk_literal("[")),
- append_inlines(lab,
- make_str(chunk_literal("]"))));
+ append_inlines(lab,
+ make_str(chunk_literal("]"))));
return result;
}
} else {
@@ -721,7 +707,7 @@ static node_inl* handle_left_bracket(subject* subj)
subj->pos = endlabel;
lab = parse_chunk_inlines(&rawlabel, subj->refmap);
result = append_inlines(make_str(chunk_literal("[")),
- append_inlines(lab, make_str(chunk_literal("]"))));
+ append_inlines(lab, make_str(chunk_literal("]"))));
}
return result;
}
@@ -743,8 +729,8 @@ static node_inl* handle_newline(subject *subj)
advance(subj);
}
if (nlpos > 1 &&
- peek_at(subj, nlpos - 1) == ' ' &&
- peek_at(subj, nlpos - 2) == ' ') {
+ peek_at(subj, nlpos - 1) == ' ' &&
+ peek_at(subj, nlpos - 2) == ' ') {
return make_linebreak();
} else {
return make_softbreak();
@@ -761,9 +747,22 @@ extern node_inl* parse_inlines_while(subject* subj, int (*f)(subject*))
{
node_inl* result = NULL;
node_inl** last = &result;
+ node_inl* first = NULL;
while ((*f)(subj) && parse_inline(subj, last)) {
+ if (!first) {
+ first = *last;
+ }
+ }
+
+ inline_stack* istack = subj->emphasis_openers;
+ inline_stack* temp;
+ while (istack != NULL) {
+ temp = istack->previous;
+ free(istack);
+ istack = temp;
}
- return result;
+
+ return first;
}
node_inl *parse_chunk_inlines(chunk *chunk, reference_map *refmap)
@@ -819,69 +818,62 @@ static int parse_inline(subject* subj, node_inl ** last)
return 0;
}
switch(c){
- case '\n':
- new = handle_newline(subj);
- break;
- case '`':
- new = handle_backticks(subj);
- break;
- case '\\':
- new = handle_backslash(subj);
- break;
- case '&':
- new = handle_entity(subj);
- break;
- case '<':
- new = handle_pointy_brace(subj);
- break;
- case '_':
- if (subj->pos > 0) {
- unsigned char prev = peek_at(subj, subj->pos - 1);
- if (isalnum(prev) || prev == '_') {
- new = make_str(chunk_literal("_"));
- advance(subj);
- break;
- }
- }
-
- new = handle_strong_emph(subj, '_');
- break;
- case '*':
- new = handle_strong_emph(subj, '*');
- break;
- case '[':
+ case '\n':
+ new = handle_newline(subj);
+ break;
+ case '`':
+ new = handle_backticks(subj);
+ break;
+ case '\\':
+ new = handle_backslash(subj);
+ break;
+ case '&':
+ new = handle_entity(subj);
+ break;
+ case '<':
+ new = handle_pointy_brace(subj);
+ break;
+ case '_':
+ new = handle_strong_emph(subj, '_', last);
+ break;
+ case '*':
+ new = handle_strong_emph(subj, '*', last);
+ break;
+ case '[':
+ new = handle_left_bracket(subj);
+ break;
+ case '!':
+ advance(subj);
+ if (peek_char(subj) == '[') {
new = handle_left_bracket(subj);
- break;
- case '!':
- advance(subj);
- if (peek_char(subj) == '[') {
- new = handle_left_bracket(subj);
- if (new != NULL && new->tag == INL_LINK) {
- new->tag = INL_IMAGE;
- } else {
- new = append_inlines(make_str(chunk_literal("!")), new);
- }
+ if (new != NULL && new->tag == INL_LINK) {
+ new->tag = INL_IMAGE;
} else {
- new = make_str(chunk_literal("!"));
- }
- break;
- default:
- endpos = subject_find_special_char(subj);
- contents = chunk_dup(&subj->input, subj->pos, endpos - subj->pos);
- subj->pos = endpos;
-
- // if we're at a newline, strip trailing spaces.
- if (peek_char(subj) == '\n') {
- chunk_rtrim(&contents);
+ new = append_inlines(make_str(chunk_literal("!")), new);
}
+ } else {
+ new = make_str(chunk_literal("!"));
+ }
+ break;
+ default:
+ endpos = subject_find_special_char(subj);
+ contents = chunk_dup(&subj->input, subj->pos, endpos - subj->pos);
+ subj->pos = endpos;
+
+ // if we're at a newline, strip trailing spaces.
+ if (peek_char(subj) == '\n') {
+ chunk_rtrim(&contents);
+ }
- new = make_str(contents);
+ new = make_str(contents);
}
if (*last == NULL) {
*last = new;
- } else {
+ } else if (new) {
append_inlines(*last, new);
+ *last = new;
}
+
return 1;
}
@@ -897,8 +889,8 @@ void spnl(subject* subj)
{
bool seen_newline = false;
while (peek_char(subj) == ' ' ||
- (!seen_newline &&
- (seen_newline = peek_char(subj) == '\n'))) {
+ (!seen_newline &&
+ (seen_newline = peek_char(subj) == '\n'))) {
advance(subj);
}
}
@@ -965,4 +957,3 @@ int parse_reference_inline(strbuf *input, reference_map *refmap)
reference_create(refmap, &lab, &url, &title);
return subj.pos;
}
-
diff --git a/src/main.c b/src/main.c
index 76a0e12..99d14f8 100644
--- a/src/main.c
+++ b/src/main.c
@@ -38,7 +38,7 @@ int main(int argc, char *argv[])
printf(" - CommonMark converter (c) 2014 John MacFarlane\n");
exit(0);
} else if ((strcmp(argv[i], "--help") == 0) ||
- (strcmp(argv[i], "-h") == 0)) {
+ (strcmp(argv[i], "-h") == 0)) {
print_usage();
exit(0);
} else if (strcmp(argv[i], "--ast") == 0) {
@@ -61,7 +61,7 @@ int main(int argc, char *argv[])
if (fp == NULL) {
fprintf(stderr, "Error opening file %s: %s\n",
- argv[files[i]], strerror(errno));
+ argv[files[i]], strerror(errno));
exit(1);
}
@@ -74,4 +74,3 @@ int main(int argc, char *argv[])
return 0;
}
-
diff --git a/src/print.c b/src/print.c
index 83f8daa..f3bd8e5 100644
--- a/src/print.c
+++ b/src/print.c
@@ -16,17 +16,17 @@ static void print_str(const unsigned char *s, int len)
unsigned char c = s[i];
switch (c) {
- case '\n':
- printf("\\n");
- break;
- case '"':
- printf("\\\"");
- break;
- case '\\':
- printf("\\\\");
- break;
- default:
- putchar((int)c);
+ case '\n':
+ printf("\\n");
+ break;
+ case '"':
+ printf("\\\"");
+ break;
+ case '\\':
+ printf("\\\\");
+ break;
+ default:
+ putchar((int)c);
}
}
putchar('"');
@@ -116,13 +116,13 @@ static void print_blocks(node_block* b, int indent)
data = &(b->as.list);
if (data->list_type == ordered) {
printf("list (type=ordered tight=%s start=%d delim=%s)\n",
- (data->tight ? "true" : "false"),
- data->start,
- (data->delimiter == parens ? "parens" : "period"));
+ (data->tight ? "true" : "false"),
+ data->start,
+ (data->delimiter == parens ? "parens" : "period"));
} else {
printf("list (type=bullet tight=%s bullet_char=%c)\n",
- (data->tight ? "true" : "false"),
- data->bullet_char);
+ (data->tight ? "true" : "false"),
+ data->bullet_char);
}
print_blocks(b->children, indent + 2);
break;
@@ -148,7 +148,7 @@ static void print_blocks(node_block* b, int indent)
break;
case BLOCK_FENCED_CODE:
printf("fenced_code length=%d info=",
- b->as.code.fence_length);
+ b->as.code.fence_length);
print_str(b->as.code.info.ptr, -1);
putchar(' ');
print_str(b->string_content.ptr, -1);
diff --git a/src/references.c b/src/references.c
index 0ae7961..6759c2c 100644
--- a/src/references.c
+++ b/src/references.c
@@ -60,7 +60,7 @@ static void add_reference(reference_map *map, reference* ref)
while (t) {
if (t->hash == ref->hash &&
- !strcmp((char *)t->label, (char *)ref->label)) {
+ !strcmp((char *)t->label, (char *)ref->label)) {
reference_free(ref);
return;
}
@@ -99,10 +99,10 @@ reference* reference_lookup(reference_map *map, chunk *label)
reference *ref = NULL;
unsigned char *norm;
unsigned int hash;
-
+
if (map == NULL)
return NULL;
-
+
norm = normalize_reference(label);
if (norm == NULL)
return NULL;
@@ -112,7 +112,7 @@ reference* reference_lookup(reference_map *map, chunk *label)
while (ref) {
if (ref->hash == hash &&
- !strcmp((char *)ref->label, (char *)norm))
+ !strcmp((char *)ref->label, (char *)norm))
break;
ref = ref->next;
}
@@ -146,4 +146,3 @@ reference_map *reference_map_new(void)
{
return calloc(1, sizeof(reference_map));
}
-
diff --git a/src/stmd.h b/src/stmd.h
index c6473a6..552e60e 100644
--- a/src/stmd.h
+++ b/src/stmd.h
@@ -56,7 +56,7 @@ struct ListData {
struct FencedCodeData {
int fence_length;
int fence_offset;
- char fence_char;
+ unsigned char fence_char;
strbuf info;
};
diff --git a/src/utf8.c b/src/utf8.c
index 6b34831..8a786b7 100644
--- a/src/utf8.c
+++ b/src/utf8.c
@@ -103,24 +103,24 @@ int utf8proc_iterate(const uint8_t *str, int str_len, int32_t *dst)
return -1;
switch (length) {
- case 1:
- uc = str[0];
- break;
- case 2:
- uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
- if (uc < 0x80) uc = -1;
- break;
- case 3:
- uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6)
- + (str[2] & 0x3F);
- if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) ||
- (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1;
- break;
- case 4:
- uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
- + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
- if (uc < 0x10000 || uc >= 0x110000) uc = -1;
- break;
+ case 1:
+ uc = str[0];
+ break;
+ case 2:
+ uc = ((str[0] & 0x1F) << 6) + (str[1] & 0x3F);
+ if (uc < 0x80) uc = -1;
+ break;
+ case 3:
+ uc = ((str[0] & 0x0F) << 12) + ((str[1] & 0x3F) << 6)
+ + (str[2] & 0x3F);
+ if (uc < 0x800 || (uc >= 0xD800 && uc < 0xE000) ||
+ (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1;
+ break;
+ case 4:
+ uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12)
+ + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F);
+ if (uc < 0x10000 || uc >= 0x110000) uc = -1;
+ break;
}
if (uc < 0 || ((uc & 0xFFFF) >= 0xFFFE))
@@ -173,7 +173,7 @@ void utf8proc_case_fold(strbuf *dest, const uint8_t *str, int len)
{
int32_t c;
-#define bufpush(x) \
+#define bufpush(x) \
utf8proc_encode_char(x, dest)
while (len > 0) {
@@ -190,4 +190,3 @@ void utf8proc_case_fold(strbuf *dest, const uint8_t *str, int len)
len -= char_len;
}
}
-