diff options
| -rw-r--r-- | Makefile | 4 | ||||
| -rw-r--r-- | src/blocks.c | 173 | ||||
| -rw-r--r-- | src/buffer.c | 26 | ||||
| -rw-r--r-- | src/buffer.h | 2 | ||||
| -rw-r--r-- | src/html/houdini_href_e.c | 10 | ||||
| -rw-r--r-- | src/html/houdini_html_e.c | 10 | ||||
| -rw-r--r-- | src/html/html.c | 4 | ||||
| -rw-r--r-- | src/inlines.c | 235 | ||||
| -rw-r--r-- | src/print.c | 2 | ||||
| -rw-r--r-- | src/scanners.h | 28 | ||||
| -rw-r--r-- | src/scanners.re | 85 | ||||
| -rw-r--r-- | src/stmd.h | 16 | 
12 files changed, 261 insertions, 334 deletions
@@ -1,5 +1,5 @@ -CFLAGS=-ggdb3 -O0 -Wall -Wextra -std=c99 -Isrc $(OPTFLAGS) -LDFLAGS=-ggdb3 -O0 -Wall -Werror +CFLAGS=-ggdb3 -O0 -Wall -Wextra -Wno-unused-variable -std=c99 -Isrc $(OPTFLAGS) +LDFLAGS=-ggdb3 -O0 -Wall -Wno-unused-variable # -Werror  SRCDIR=src  DATADIR=data diff --git a/src/blocks.c b/src/blocks.c index 42f20db..94ff986 100644 --- a/src/blocks.c +++ b/src/blocks.c @@ -8,6 +8,8 @@  #include "scanners.h"  #include "uthash.h" +#define peek_at(i, n) (i)->data[n] +  static void incorporate_line(gh_buf *ln, int line_number, block** curptr);  static void finalize(block* b, int line_number); @@ -27,7 +29,6 @@ static block* make_block(int tag, int start_line, int start_column)  	e->top = NULL;  	e->attributes.refmap = NULL;  	gh_buf_init(&e->string_content, 32); -	e->string_pos = 0;  	e->inline_content = NULL;  	e->next = NULL;  	e->prev = NULL; @@ -80,10 +81,10 @@ static inline bool accepts_lines(int block_type)  			block_type == fenced_code);  } -static void add_line(block* block, gh_buf *ln, int offset) +static void add_line(block* block, chunk *ch, int offset)  {  	assert(block->open); -	gh_buf_put(&block->string_content, ln->ptr + offset, ln->size - offset); +	gh_buf_put(&block->string_content, ch->data + offset, ch->len - offset);  }  static void remove_trailing_blank_lines(gh_buf *ln) @@ -104,7 +105,7 @@ static void remove_trailing_blank_lines(gh_buf *ln)  	i = gh_buf_strchr(ln, '\n', i);  	if (i >= 0) -		gh_buf_truncate(ln, i + 1); +		gh_buf_truncate(ln, i);  }  // Check to see if a block ends with a blank line, descending @@ -162,12 +163,12 @@ static void finalize(block* b, int line_number)  	switch (b->tag) {  		case paragraph:  			pos = 0; -			while (gh_buf_at(&b->string_content, b->string_pos) == '[' && -					(pos = parse_reference(&b->string_content, b->string_pos, -										   b->top->attributes.refmap))) { -				b->string_pos = pos; +			while (gh_buf_at(&b->string_content, 0) == '[' && +					(pos = parse_reference(&b->string_content, b->top->attributes.refmap))) { + +				gh_buf_drop(&b->string_content, pos);  			} -			if (is_blank(&b->string_content, b->string_pos)) { +			if (is_blank(&b->string_content, 0)) {  				b->tag = reference_def;  			}  			break; @@ -179,14 +180,16 @@ static void finalize(block* b, int line_number)  		case fenced_code:  			// first line of contents becomes info -			firstlinelen = gh_buf_strchr(&b->string_content, '\n', b->string_pos); +			firstlinelen = gh_buf_strchr(&b->string_content, '\n', 0); + +			gh_buf_init(&b->attributes.fenced_code_data.info, 0);  			gh_buf_set(  				&b->attributes.fenced_code_data.info, -				b->string_content.ptr + b->string_pos, +				b->string_content.ptr,  				firstlinelen  			); -			b->string_pos = firstlinelen + 1; +			gh_buf_drop(&b->string_content, firstlinelen + 1);  			gh_buf_trim(&b->attributes.fenced_code_data.info);  			unescape_buffer(&b->attributes.fenced_code_data.info); @@ -281,7 +284,7 @@ void process_inlines(block* cur, reference** refmap)  		case paragraph:  		case atx_header:  		case setext_header: -			cur->inline_content = parse_inlines(&cur->string_content, cur->string_pos, refmap); +			cur->inline_content = parse_inlines(&cur->string_content, refmap);  			// MEM  			// gh_buf_free(&cur->string_content);  			break; @@ -300,19 +303,18 @@ void process_inlines(block* cur, reference** refmap)  // Attempts to parse a list item marker (bullet or enumerated).  // On success, returns length of the marker, and populates  // data with the details.  On failure, returns 0. -static int parse_list_marker(gh_buf *ln, int pos, -		struct ListData ** dataptr) +static int parse_list_marker(chunk *input, int pos, struct ListData ** dataptr)  { -	char c; +	unsigned char c;  	int startpos;  	struct ListData * data;  	startpos = pos; -	c = gh_buf_at(ln, pos); +	c = peek_at(input, pos); -	if ((c == '*' || c == '-' || c == '+') && !scan_hrule(ln, pos)) { +	if ((c == '*' || c == '-' || c == '+') && !scan_hrule(input, pos)) {  		pos++; -		if (!isspace(gh_buf_at(ln, pos))) { +		if (!isspace(peek_at(input, pos))) {  			return 0;  		}  		data = malloc(sizeof(struct ListData)); @@ -327,14 +329,14 @@ static int parse_list_marker(gh_buf *ln, int pos,  		int start = 0;  		do { -			start = (10 * start) + (gh_buf_at(ln, pos) - '0'); +			start = (10 * start) + (peek_at(input, pos) - '0');  			pos++; -		} while (isdigit(gh_buf_at(ln, pos))); +		} while (isdigit(peek_at(input, pos))); -		c = gh_buf_at(ln, pos); +		c = peek_at(input, pos);  		if (c == '.' || c == ')') {  			pos++; -			if (!isspace(gh_buf_at(ln, pos))) { +			if (!isspace(peek_at(input, pos))) {  				return 0;  			}  			data = malloc(sizeof(struct ListData)); @@ -449,8 +451,26 @@ extern block *stmd_parse_document(const unsigned char *buffer, size_t len)  	return finalize_document(document, linenum);  } +static void chop_trailing_hashtags(chunk *ch) +{ +	int n; + +	chunk_rtrim(ch); +	n = ch->len - 1; + +	// if string ends in #s, remove these: +	while (n >= 0 && peek_at(ch, n) == '#') +		n--; + +	// the last # was escaped, so we include it. +	if (n >= 0 && peek_at(ch, n) == '\\') +		n++; + +	ch->len = n + 1; +} +  // Process one line at a time, modifying a block. -static void incorporate_line(gh_buf *ln, int line_number, block** curptr) +static void incorporate_line(gh_buf *line, int line_number, block** curptr)  {  	block* last_matched_container;  	int offset = 0; @@ -464,6 +484,10 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  	bool blank = false;  	int first_nonspace;  	int indent; +	chunk input; + +	input.data = line->ptr; +	input.len = line->size;  	// container starts at the document root.  	container = cur->top; @@ -475,21 +499,19 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  		container = container->last_child;  		first_nonspace = offset; -		while (gh_buf_at(ln, first_nonspace) == ' ') { +		while (peek_at(&input, first_nonspace) == ' ') {  			first_nonspace++;  		}  		indent = first_nonspace - offset; -		blank = gh_buf_at(ln, first_nonspace) == '\n'; +		blank = peek_at(&input, first_nonspace) == '\n';  		if (container->tag == block_quote) { - -			matched = indent <= 3 && gh_buf_at(ln, first_nonspace) == '>'; +			matched = indent <= 3 && peek_at(&input, first_nonspace) == '>';  			if (matched) {  				offset = first_nonspace + 1; -				if (gh_buf_at(ln, offset) == ' ') { +				if (peek_at(&input, offset) == ' ')  					offset++; -				}  			} else {  				all_matched = false;  			} @@ -526,7 +548,7 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  			// skip optional spaces of fence offset  			i = container->attributes.fenced_code_data.fence_offset; -			while (i > 0 && gh_buf_at(ln, offset) == ' ') { +			while (i > 0 && peek_at(&input, offset) == ' ') {  				offset++;  				i--;  			} @@ -564,15 +586,13 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  			container->tag != html_block) {  		first_nonspace = offset; -		while (gh_buf_at(ln, first_nonspace) == ' ') { +		while (peek_at(&input, first_nonspace) == ' ')  			first_nonspace++; -		}  		indent = first_nonspace - offset; -		blank = gh_buf_at(ln, first_nonspace) == '\n'; +		blank = peek_at(&input, first_nonspace) == '\n';  		if (indent >= CODE_INDENT) { -  			if (cur->tag != paragraph && !blank) {  				offset += CODE_INDENT;  				container = add_child(container, indented_code, line_number, offset + 1); @@ -580,76 +600,70 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  				break;  			} -		} else if (gh_buf_at(ln, first_nonspace) == '>') { +		} else if (peek_at(&input, first_nonspace) == '>') {  			offset = first_nonspace + 1;  			// optional following character -			if (gh_buf_at(ln, offset) == ' ') { +			if (peek_at(&input, offset) == ' ')  				offset++; -			}  			container = add_child(container, block_quote, line_number, offset + 1); -		} else if ((matched = scan_atx_header_start(ln, first_nonspace))) { +		} else if ((matched = scan_atx_header_start(&input, first_nonspace))) {  			offset = first_nonspace + matched;  			container = add_child(container, atx_header, line_number, offset + 1); -			int hashpos = gh_buf_strchr(ln, '#', first_nonspace); -			assert(hashpos >= 0); - +			int hashpos = chunk_strchr(&input, '#', first_nonspace);  			int level = 0; -			while (gh_buf_at(ln, hashpos) == '#') { + +			while (peek_at(&input, hashpos) == '#') {  				level++;  				hashpos++;  			}  			container->attributes.header_level = level; -		} else if ((matched = scan_open_code_fence(ln, first_nonspace))) { +		} else if ((matched = scan_open_code_fence(&input, first_nonspace))) { -			container = add_child(container, fenced_code, line_number, -					first_nonspace + 1); -			container->attributes.fenced_code_data.fence_char = gh_buf_at(ln, -					first_nonspace); +			container = add_child(container, fenced_code, line_number, first_nonspace + 1); +			container->attributes.fenced_code_data.fence_char = peek_at(&input, first_nonspace);  			container->attributes.fenced_code_data.fence_length = matched; -			container->attributes.fenced_code_data.fence_offset = -				first_nonspace - offset; +			container->attributes.fenced_code_data.fence_offset = first_nonspace - offset;  			offset = first_nonspace + matched; -		} else if ((matched = scan_html_block_tag(ln, first_nonspace))) { +		} else if ((matched = scan_html_block_tag(&input, first_nonspace))) { -			container = add_child(container, html_block, line_number, -					first_nonspace + 1); +			container = add_child(container, html_block, line_number, first_nonspace + 1);  			// note, we don't adjust offset because the tag is part of the text  		} else if (container->tag == paragraph && -				(lev = scan_setext_header_line(ln, first_nonspace)) && +				(lev = scan_setext_header_line(&input, first_nonspace)) &&  				// check that there is only one line in the paragraph:  				gh_buf_strrchr(&container->string_content, '\n',  					gh_buf_len(&container->string_content) - 2) < 0) {  			container->tag = setext_header;  			container->attributes.header_level = lev; -			offset = gh_buf_len(ln) - 1; +			offset = input.len - 1;  		} else if (!(container->tag == paragraph && !all_matched) && -				(matched = scan_hrule(ln, first_nonspace))) { +				(matched = scan_hrule(&input, first_nonspace))) {  			// it's only now that we know the line is not part of a setext header:  			container = add_child(container, hrule, line_number, first_nonspace + 1);  			finalize(container, line_number);  			container = container->parent; -			offset = gh_buf_len(ln) - 1; +			offset = input.len - 1; -		} else if ((matched = parse_list_marker(ln, first_nonspace, &data))) { +		} else if ((matched = parse_list_marker(&input, first_nonspace, &data))) {  			// compute padding:  			offset = first_nonspace + matched;  			i = 0; -			while (i <= 5 && gh_buf_at(ln, offset + i) == ' ') { +			while (i <= 5 && peek_at(&input, offset + i) == ' ') {  				i++;  			}  			// i = number of spaces after marker, up to 5 -			if (i >= 5 || i < 1 || gh_buf_at(ln, offset) == '\n') { +			if (i >= 5 || i < 1 || peek_at(&input, offset) == '\n') {  				data->padding = matched + 1;  				if (i > 0) {  					offset += 1; @@ -674,6 +688,7 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  			// add the list item  			container = add_child(container, list_item, line_number,  					first_nonspace + 1); +			/* TODO: static */  			container->attributes.list_data = *data;  			free(data); @@ -691,12 +706,11 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  	// appropriate container.  	first_nonspace = offset; -	while (gh_buf_at(ln, first_nonspace) == ' ') { +	while (peek_at(&input, first_nonspace) == ' ')  		first_nonspace++; -	}  	indent = first_nonspace - offset; -	blank = gh_buf_at(ln, first_nonspace) == '\n'; +	blank = peek_at(&input, first_nonspace) == '\n';  	// block quote lines are never blank as they start with >  	// and we don't count blanks in fenced code for purposes of tight/loose @@ -721,13 +735,12 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  			cur->tag == paragraph &&  			gh_buf_len(&cur->string_content) > 0) { -		add_line(cur, ln, offset); +		add_line(cur, &input, offset);  	} else { // not a lazy continuation  		// finalize any blocks that were not matched and set cur to container:  		while (cur != last_matched_container) { -  			finalize(cur, line_number);  			cur = cur->parent;  			assert(cur != NULL); @@ -735,58 +748,46 @@ static void incorporate_line(gh_buf *ln, int line_number, block** curptr)  		if (container->tag == indented_code) { -			add_line(container, ln, offset); +			add_line(container, &input, offset);  		} else if (container->tag == fenced_code) {  			matched = (indent <= 3 -					&& gh_buf_at(ln, first_nonspace) == container->attributes.fenced_code_data.fence_char) -				&& scan_close_code_fence(ln, first_nonspace, +					&& peek_at(&input, first_nonspace) == container->attributes.fenced_code_data.fence_char) +				&& scan_close_code_fence(&input, first_nonspace,  						container->attributes.fenced_code_data.fence_length);  			if (matched) {  				// if closing fence, don't add line to container; instead, close it:  				finalize(container, line_number);  				container = container->parent; // back up to parent  			} else { -				add_line(container, ln, offset); +				add_line(container, &input, offset);  			}  		} else if (container->tag == html_block) { -			add_line(container, ln, offset); +			add_line(container, &input, offset);  		} else if (blank) {  			// ??? do nothing  		} else if (container->tag == atx_header) { -			// chop off trailing ###s...use a scanner? -			gh_buf_trim(ln); -			int p = gh_buf_len(ln) - 1; - -			// if string ends in #s, remove these: -			while (gh_buf_at(ln, p) == '#') { -				p--; -			} -			if (gh_buf_at(ln, p) == '\\') { -				// the last # was escaped, so we include it. -				p++; -			} -			gh_buf_truncate(ln, p + 1); -			add_line(container, ln, first_nonspace); +			chop_trailing_hashtags(&input); +			add_line(container, &input, first_nonspace);  			finalize(container, line_number);  			container = container->parent;  		} else if (accepts_lines(container->tag)) { -			add_line(container, ln, first_nonspace); +			add_line(container, &input, first_nonspace);  		} else if (container->tag != hrule && container->tag != setext_header) {  			// create paragraph container for line  			container = add_child(container, paragraph, line_number, first_nonspace + 1); -			add_line(container, ln, first_nonspace); +			add_line(container, &input, first_nonspace);  		} else {  			assert(false); diff --git a/src/buffer.c b/src/buffer.c index cfc6a7e..dc4a405 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -95,7 +95,7 @@ void gh_buf_clear(gh_buf *buf)  int gh_buf_set(gh_buf *buf, const unsigned char *data, int len)  { -	if (len == 0 || data == NULL) { +	if (len <= 0 || data == NULL) {  		gh_buf_clear(buf);  	} else {  		if (data != buf->ptr) { @@ -125,6 +125,9 @@ int gh_buf_putc(gh_buf *buf, int c)  int gh_buf_put(gh_buf *buf, const unsigned char *data, int len)  { +	if (len <= 0) +		return 0; +  	ENSURE_SIZE(buf, buf->size + len + 1);  	memmove(buf->ptr + buf->size, data, len);  	buf->size += len; @@ -272,15 +275,28 @@ void gh_buf_truncate(gh_buf *buf, int len)  	}  } +void gh_buf_drop(gh_buf *buf, int n) +{ +	if (n > 0) { +		buf->size = buf->size - n; +		if (buf->size) +			memmove(buf->ptr, buf->ptr + n, buf->size); + +		buf->ptr[buf->size] = '\0'; +	} +} +  void gh_buf_trim(gh_buf *buf)  { -	/* TODO: leading whitespace? */ -	/* +	int i = 0; + +	if (!buf->size) +		return; +  	while (i < buf->size && isspace(buf->ptr[i]))  		i++; -	gh_buf_truncate(buf, i); -	*/ +	gh_buf_drop(buf, i);  	/* rtrim */  	while (buf->size > 0) { diff --git a/src/buffer.h b/src/buffer.h index 422ef02..0d5143e 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -105,8 +105,8 @@ extern void gh_buf_clear(gh_buf *buf);  int gh_buf_strchr(const gh_buf *buf, int c, int pos);  int gh_buf_strrchr(const gh_buf *buf, int c, int pos); +void gh_buf_drop(gh_buf *buf, int n);  void gh_buf_truncate(gh_buf *buf, int len); -void gh_buf_ltruncate(gh_buf *buf, int len);  void gh_buf_trim(gh_buf *buf);  #endif diff --git a/src/html/houdini_href_e.c b/src/html/houdini_href_e.c index 59fe850..b2a7d79 100644 --- a/src/html/houdini_href_e.c +++ b/src/html/houdini_href_e.c @@ -62,16 +62,8 @@ houdini_escape_href(gh_buf *ob, const uint8_t *src, size_t size)  		while (i < size && HREF_SAFE[src[i]] != 0)  			i++; -		if (likely(i > org)) { -			if (unlikely(org == 0)) { -				if (i >= size) -					return 0; - -				gh_buf_grow(ob, HOUDINI_ESCAPED_SIZE(size)); -			} - +		if (likely(i > org))  			gh_buf_put(ob, src + org, i - org); -		}  		/* escaping */  		if (i >= size) diff --git a/src/html/houdini_html_e.c b/src/html/houdini_html_e.c index 316c5ce..5cdd3dd 100644 --- a/src/html/houdini_html_e.c +++ b/src/html/houdini_html_e.c @@ -54,16 +54,8 @@ houdini_escape_html0(gh_buf *ob, const uint8_t *src, size_t size, int secure)  		while (i < size && (esc = HTML_ESCAPE_TABLE[src[i]]) == 0)  			i++; -		if (i > org) { -			if (unlikely(org == 0)) { -				if (i >= size) -					return 0; - -				gh_buf_grow(ob, HOUDINI_ESCAPED_SIZE(size)); -			} - +		if (i > org)  			gh_buf_put(ob, src + org, i - org); -		}  		/* escaping */  		if (unlikely(i >= size)) diff --git a/src/html/html.c b/src/html/html.c index 2f160ca..27ffe58 100644 --- a/src/html/html.c +++ b/src/html/html.c @@ -68,7 +68,7 @@ void blocks_to_html(gh_buf *html, block *b, bool tight)  				cr(html);  				gh_buf_puts(html, "<li>");  				blocks_to_html(html, b->children, tight); -				gh_buf_trim(html); +				gh_buf_trim(html); /* TODO: rtrim */  				gh_buf_puts(html, "</li>");  				cr(html);  				break; @@ -106,7 +106,7 @@ void blocks_to_html(gh_buf *html, block *b, bool tight)  				cr(html);  				gh_buf_puts(html, "<pre><code>");  				escape_html(html, b->string_content.ptr, b->string_content.size); -				gh_buf_puts(html, "</pre></code>"); +				gh_buf_puts(html, "</code></pre>");  				cr(html);  				break; diff --git a/src/inlines.c b/src/inlines.c index 7b48ad9..ef27a24 100644 --- a/src/inlines.c +++ b/src/inlines.c @@ -9,10 +9,10 @@  #include "scanners.h"  typedef struct Subject { -  const gh_buf   *buffer; -  int            pos; -  reference**    reference_map; -  int            label_nestlevel; +	chunk input; +	int pos; +	int            label_nestlevel; +	reference**    reference_map;  } subject;  reference* lookup_reference(reference** refmap, chunk *label); @@ -27,12 +27,16 @@ inline static void chunk_trim(chunk *c);  inline static chunk chunk_literal(const char *data);  inline static chunk chunk_buf_detach(gh_buf *buf); -inline static chunk chunk_buf(const gh_buf *buf, int pos, int len); +inline static chunk chunk_dup(const chunk *ch, int pos, int len);  static inl *parse_chunk_inlines(chunk *chunk, reference** refmap);  static inl *parse_inlines_while(subject* subj, int (*f)(subject*));  static int parse_inline(subject* subj, inl ** last); +static void subject_from_chunk(subject *e, chunk *chunk, reference** refmap); +static void subject_from_buf(subject *e, gh_buf *buffer, reference** refmap); +static int subject_find_special_char(subject *subj); +  extern void free_reference(reference *ref) {  	free(ref->label);  	free(ref->url); @@ -101,10 +105,12 @@ extern reference* make_reference(chunk *label, chunk *url, chunk *title)  extern void add_reference(reference** refmap, reference* ref)  {  	reference * t = NULL; -	HASH_FIND(hh, *refmap, (char*)ref->label, (unsigned)strlen(ref->label), t); +	const char *label = (const char *)ref->label; + +	HASH_FIND(hh, *refmap, label, strlen(label), t);  	if (t == NULL) { -		HASH_ADD_KEYPTR(hh, *refmap, (char*)ref->label, (unsigned)strlen(ref->label), ref); +		HASH_ADD_KEYPTR(hh, *refmap, label, strlen(label), ref);  	} else {  		free_reference(ref);  // we free this now since it won't be in the refmap  	} @@ -210,87 +216,49 @@ inline static inl* append_inlines(inl* a, inl* b)  	return a;  } -// Make a 'subject' from an input string. -static void init_subject(subject *e, gh_buf *buffer, int input_pos, reference** refmap) +static void subject_from_buf(subject *e, gh_buf *buffer, reference** refmap)  { -	e->buffer = buffer; -	e->pos = input_pos; +	e->input.data = buffer->ptr; +	e->input.len = buffer->size; +	e->input.alloc = 0; +	e->pos = 0;  	e->label_nestlevel = 0;  	e->reference_map = refmap; -} - -inline static int isbacktick(int c) -{ -	return (c == '`'); -} - -inline static void chunk_free(chunk *c) -{ -	if (c->alloc) -		free((char *)c->data); - -	c->data = NULL; -	c->alloc = 0; -	c->len = 0; -} - -inline static void chunk_trim(chunk *c) -{ -	while (c->len && isspace(c->data[0])) { -		c->data++; -		c->len--; -	} - -	while (c->len > 0) { -		if (!isspace(c->data[c->len - 1])) -			break; -		c->len--; -	} +	chunk_rtrim(&e->input);  } -inline static unsigned char *chunk_to_cstr(chunk *c) +static void subject_from_chunk(subject *e, chunk *chunk, reference** refmap)  { -	unsigned char *str; - -	str = malloc(c->len + 1); -	memcpy(str, c->data, c->len); -	str[c->len] = 0; +	e->input.data = chunk->data; +	e->input.len = chunk->len; +	e->input.alloc = 0; +	e->pos = 0; +	e->label_nestlevel = 0; +	e->reference_map = refmap; -	return str; +	chunk_rtrim(&e->input);  } -inline static chunk chunk_literal(const char *data) +inline static int isbacktick(int c)  { -	chunk c = {data, data ? strlen(data) : 0, 0}; -	return c; +	return (c == '`');  } -inline static chunk chunk_buf(const gh_buf *buf, int pos, int len) +static inline unsigned char peek_char(subject *subj)  { -	chunk c = {buf->ptr + pos, len, 0}; -	return c; +	return (subj->pos < subj->input.len) ? subj->input.data[subj->pos] : 0;  } -inline static chunk chunk_buf_detach(gh_buf *buf) +static inline unsigned char peek_at(subject *subj, int pos)  { -	chunk c; - -	c.len = buf->size; -	c.data = gh_buf_detach(buf); -	c.alloc = 1; - -	return c; +	return subj->input.data[pos];  } -// Return the next character in the subject, without advancing. -// Return 0 if at the end of the subject. -#define peek_char(subj) gh_buf_at((subj)->buffer, (subj)->pos) -  // Return true if there are more characters in the subject.  inline static int is_eof(subject* subj)  { -	return (subj->pos >= gh_buf_len(subj->buffer)); +	return (subj->pos >= subj->input.len);  }  // Advance the subject.  Doesn't check for eof. @@ -308,7 +276,7 @@ inline static chunk take_while(subject* subj, int (*f)(int))  		len++;  	} -	return chunk_buf(subj->buffer, startpos, len); +	return chunk_dup(&subj->input, startpos, len);  }  // Try to process a backtick code span that began with a @@ -388,7 +356,7 @@ static inl* handle_backticks(subject *subj)  	} else {  		gh_buf buf = GH_BUF_INIT; -		gh_buf_set(&buf, subj->buffer->ptr + startpos, endpos - startpos - openticks.len); +		gh_buf_set(&buf, subj->input.data + startpos, endpos - startpos - openticks.len);  		gh_buf_trim(&buf);  		normalize_whitespace(&buf); @@ -404,7 +372,7 @@ static int scan_delims(subject* subj, char c, bool * can_open, bool * can_close)  	char char_before, char_after;  	int startpos = subj->pos; -	char_before = subj->pos == 0 ? '\n' : gh_buf_at(subj->buffer, subj->pos - 1); +	char_before = subj->pos == 0 ? '\n' : peek_at(subj, subj->pos - 1);  	while (peek_char(subj) == c) {  		numdelims++;  		advance(subj); @@ -439,7 +407,7 @@ static inl* handle_strong_emph(subject* subj, char c)  	numdelims = scan_delims(subj, c, &can_open, &can_close);  	subj->pos += numdelims; -	new = make_str(chunk_buf(subj->buffer, subj->pos - numdelims, numdelims)); +	new = make_str(chunk_dup(&subj->input, subj->pos - numdelims, numdelims));  	*last = new;  	first_head = new;  	result = new; @@ -488,7 +456,7 @@ static inl* handle_strong_emph(subject* subj, char c)  				numdelims = scan_delims(subj, c, &can_open, &can_close);  				if (can_close && numdelims >= 1 && numdelims <= 3 &&  						numdelims != first_close_delims) { -					new = make_str(chunk_buf(subj->buffer, subj->pos, numdelims)); +					new = make_str(chunk_dup(&subj->input, subj->pos, numdelims));  					append_inlines(*last, new);  					*last = new;  					if (first_close_delims == 1 && numdelims > 2) { @@ -554,7 +522,7 @@ static inl* handle_backslash(subject *subj)  	unsigned char nextchar = peek_char(subj);  	if (ispunct(nextchar)) {  // only ascii symbols and newline can be escaped  		advance(subj); -		return make_str(chunk_buf(subj->buffer, subj->pos - 1, 1)); +		return make_str(chunk_dup(&subj->input, subj->pos - 1, 1));  	} else if (nextchar == '\n') {  		advance(subj);  		return make_linebreak(); @@ -569,9 +537,9 @@ static inl* handle_entity(subject* subj)  {  	int match;  	inl *result; -	match = scan_entity(subj->buffer, subj->pos); +	match = scan_entity(&subj->input, subj->pos);  	if (match) { -		result = make_entity(chunk_buf(subj->buffer, subj->pos, match)); +		result = make_entity(chunk_dup(&subj->input, subj->pos, match));  		subj->pos += match;  	} else {  		advance(subj); @@ -584,15 +552,13 @@ static inl* handle_entity(subject* subj)  // Returns an inline sequence consisting of str and entity elements.  static inl *make_str_with_entities(chunk *content)  { -	inl * result = NULL; -	inl * new; +	inl *result = NULL; +	inl *new;  	int searchpos;  	char c;  	subject subj; -	gh_buf content_buf = GH_BUF_INIT; -	gh_buf_set(&content_buf, content->data, content->len); -	init_subject(&subj, &content_buf, 0, NULL); +	subject_from_chunk(&subj, content, NULL);  	while ((c = peek_char(&subj))) {  		switch (c) { @@ -600,18 +566,13 @@ static inl *make_str_with_entities(chunk *content)  				new = handle_entity(&subj);  				break;  			default: -				searchpos = gh_buf_strchr(subj.buffer, '&', subj.pos); -				if (searchpos < 0) { -					searchpos = gh_buf_len(subj.buffer); -				} - -				new = make_str(chunk_buf(subj.buffer, subj.pos, searchpos - subj.pos)); +				searchpos = chunk_strchr(&subj.input, '&', subj.pos); +				new = make_str(chunk_dup(&subj.input, subj.pos, searchpos - subj.pos));  				subj.pos = searchpos;  		}  		result = append_inlines(result, new);  	} -	gh_buf_free(&content_buf);  	return result;  } @@ -678,9 +639,9 @@ static inl* handle_pointy_brace(subject* subj)  	advance(subj);  // advance past first <  	// first try to match a URL autolink -	matchlen = scan_autolink_uri(subj->buffer, subj->pos); +	matchlen = scan_autolink_uri(&subj->input, subj->pos);  	if (matchlen > 0) { -		contents = chunk_buf(subj->buffer, subj->pos, matchlen - 1); +		contents = chunk_dup(&subj->input, subj->pos, matchlen - 1);  		subj->pos += matchlen;  		return make_link( @@ -691,11 +652,11 @@ static inl* handle_pointy_brace(subject* subj)  	}  	// next try to match an email autolink -	matchlen = scan_autolink_email(subj->buffer, subj->pos); +	matchlen = scan_autolink_email(&subj->input, subj->pos);  	if (matchlen > 0) {  		gh_buf mail_url = GH_BUF_INIT; -		contents = chunk_buf(subj->buffer, subj->pos, matchlen - 1); +		contents = chunk_dup(&subj->input, subj->pos, matchlen - 1);  		subj->pos += matchlen;  		gh_buf_puts(&mail_url, "mailto:"); @@ -709,9 +670,9 @@ static inl* handle_pointy_brace(subject* subj)  	}  	// finally, try to match an html tag -	matchlen = scan_html_tag(subj->buffer, subj->pos); +	matchlen = scan_html_tag(&subj->input, subj->pos);  	if (matchlen > 0) { -		contents = chunk_buf(subj->buffer, subj->pos - 1, matchlen + 1); +		contents = chunk_dup(&subj->input, subj->pos - 1, matchlen + 1);  		subj->pos += matchlen;  		return make_raw_html(contents);  	} @@ -776,12 +737,7 @@ static int link_label(subject* subj, chunk *raw_label)  		}  	}  	if (c == ']') { -		*raw_label = chunk_buf( -			subj->buffer, -			startpos + 1, -			subj->pos - (startpos + 1) -		); - +		*raw_label = chunk_dup(&subj->input, startpos + 1, subj->pos - (startpos + 1));  		subj->label_nestlevel = 0;  		advance(subj);  // advance past ]  		return 1; @@ -813,25 +769,25 @@ static inl* handle_left_bracket(subject* subj)  	if (found_label) {  		if (peek_char(subj) == '(' && -				((sps = scan_spacechars(subj->buffer, subj->pos + 1)) > -1) && -				((n = scan_link_url(subj->buffer, 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 (  			endurl = starturl + n; -			starttitle = endurl + scan_spacechars(subj->buffer, endurl); +			starttitle = endurl + scan_spacechars(&subj->input, endurl);  			// ensure there are spaces btw url and title  			endtitle = (starttitle == endurl) ? starttitle : -				starttitle + scan_link_title(subj->buffer, starttitle); +				starttitle + scan_link_title(&subj->input, starttitle); -			endall = endtitle + scan_spacechars(subj->buffer, endtitle); +			endall = endtitle + scan_spacechars(&subj->input, endtitle); -			if (gh_buf_at(subj->buffer, endall) == ')') { +			if (peek_at(subj, endall) == ')') {  				subj->pos = endall + 1; -				url = chunk_buf(subj->buffer, starturl, endurl - starturl); -				title = chunk_buf(subj->buffer, starttitle, endtitle - starttitle); +				url = chunk_dup(&subj->input, starturl, endurl - starturl); +				title = chunk_dup(&subj->input, starttitle, endtitle - starttitle);  				lab = parse_chunk_inlines(&rawlabel, NULL);  				return make_link(lab, url, title); @@ -850,7 +806,7 @@ static inl* handle_left_bracket(subject* subj)  			// Check for reference link.  			// First, see if there's another label: -			subj->pos = subj->pos + scan_spacechars(subj->buffer, endlabel); +			subj->pos = subj->pos + scan_spacechars(&subj->input, endlabel);  			reflabel = rawlabel;  			// if followed by a nonempty link label, we change reflabel to it: @@ -892,8 +848,8 @@ static inl* handle_newline(subject *subj)  		advance(subj);  	}  	if (nlpos > 1 && -			gh_buf_at(subj->buffer, nlpos - 1) == ' ' && -			gh_buf_at(subj->buffer, nlpos - 2) == ' ') { +			peek_at(subj, nlpos - 1) == ' ' && +			peek_at(subj, nlpos - 2) == ' ') {  		return make_linebreak();  	} else {  		return make_softbreak(); @@ -917,30 +873,22 @@ extern inl* parse_inlines_while(subject* subj, int (*f)(subject*))  inl *parse_chunk_inlines(chunk *chunk, reference** refmap)  { -	inl *result;  	subject subj; -	gh_buf full_chunk = GH_BUF_INIT; - -	gh_buf_set(&full_chunk, chunk->data, chunk->len); -	init_subject(&subj, &full_chunk, 0, refmap); -	result = parse_inlines_while(&subj, not_eof); - -	gh_buf_free(&full_chunk); -	return result; +	subject_from_chunk(&subj, chunk, refmap); +	return parse_inlines_while(&subj, not_eof);  } -static int find_special_char(subject *subj) +static int subject_find_special_char(subject *subj)  {  	int n = subj->pos + 1; -	int size = (int)gh_buf_len(subj->buffer); -	while (n < size) { -		if (strchr("\n\\`&_*[]<!", gh_buf_at(subj->buffer, n))) +	while (n < subj->input.len) { +		if (strchr("\n\\`&_*[]<!", subj->input.data[n]))  			return n;  		n++;  	} -	return -1; +	return subj->input.len;  }  // Parse an inline, advancing subject, and add it to last element. @@ -973,11 +921,13 @@ static int parse_inline(subject* subj, inl ** last)  			new = handle_pointy_brace(subj);  			break;  		case '_': -			if (subj->pos > 0 && (isalnum(gh_buf_at(subj->buffer, subj->pos - 1)) || -						gh_buf_at(subj->buffer, subj->pos - 1) == '_')) { -				new = make_str(chunk_literal("_")); -				advance(subj); -				break; +			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, '_'); @@ -1002,18 +952,13 @@ static int parse_inline(subject* subj, inl ** last)  			}  			break;  		default: -		text_literal: -			endpos = find_special_char(subj); -			if (endpos < 0) { -				endpos = gh_buf_len(subj->buffer); -			} - -			contents = chunk_buf(subj->buffer, subj->pos, endpos - subj->pos); +			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_trim(&contents); +				chunk_rtrim(&contents);  			}  			new = make_str(contents); @@ -1026,10 +971,10 @@ static int parse_inline(subject* subj, inl ** last)  	return 1;  } -extern inl* parse_inlines(gh_buf *input, int input_pos, reference** refmap) +extern inl* parse_inlines(gh_buf *input, reference** refmap)  {  	subject subj; -	init_subject(&subj, input, input_pos, refmap); +	subject_from_buf(&subj, input, refmap);  	return parse_inlines_while(&subj, not_eof);  } @@ -1048,7 +993,7 @@ void spnl(subject* subj)  // Modify refmap if a reference is encountered.  // Return 0 if no reference found, otherwise position of subject  // after reference is parsed. -extern int parse_reference(gh_buf *input, int input_pos, reference** refmap) +extern int parse_reference(gh_buf *input, reference** refmap)  {  	subject subj; @@ -1058,9 +1003,9 @@ extern int parse_reference(gh_buf *input, int input_pos, reference** refmap)  	int matchlen = 0;  	int beforetitle; -	reference * new = NULL; +	reference *new = NULL; -	init_subject(&subj, input, input_pos, NULL); +	subject_from_buf(&subj, input, NULL);  	// parse label:  	if (!link_label(&subj, &lab)) @@ -1075,9 +1020,9 @@ extern int parse_reference(gh_buf *input, int input_pos, reference** refmap)  	// parse link url:  	spnl(&subj); -	matchlen = scan_link_url(subj.buffer, subj.pos); +	matchlen = scan_link_url(&subj.input, subj.pos);  	if (matchlen) { -		url = chunk_buf(subj.buffer, subj.pos, matchlen); +		url = chunk_dup(&subj.input, subj.pos, matchlen);  		subj.pos += matchlen;  	} else {  		return 0; @@ -1086,9 +1031,9 @@ extern int parse_reference(gh_buf *input, int input_pos, reference** refmap)  	// parse optional link_title  	beforetitle = subj.pos;  	spnl(&subj); -	matchlen = scan_link_title(subj.buffer, subj.pos); +	matchlen = scan_link_title(&subj.input, subj.pos);  	if (matchlen) { -		title = chunk_buf(subj.buffer, subj.pos, matchlen); +		title = chunk_dup(&subj.input, subj.pos, matchlen);  		subj.pos += matchlen;  	} else {  		subj.pos = beforetitle; diff --git a/src/print.c b/src/print.c index 0a87925..c262995 100644 --- a/src/print.c +++ b/src/print.c @@ -9,7 +9,7 @@ static void print_str(const unsigned char *s, int len)  	int i;  	if (len < 0) -		len = strlen(s); +		len = strlen((char *)s);  	putchar('"');  	for (i = 0; i < len; ++i) { diff --git a/src/scanners.h b/src/scanners.h index b6e586b..f96c42d 100644 --- a/src/scanners.h +++ b/src/scanners.h @@ -1,15 +1,15 @@ -#include "buffer.h" +#include "stmd.h" -int scan_autolink_uri(const gh_buf *s, int pos); -int scan_autolink_email(const gh_buf *s, int pos); -int scan_html_tag(const gh_buf *s, int pos); -int scan_html_block_tag(const gh_buf *s, int pos); -int scan_link_url(const gh_buf *s, int pos); -int scan_link_title(const gh_buf *s, int pos); -int scan_spacechars(const gh_buf *s, int pos); -int scan_atx_header_start(const gh_buf *s, int pos); -int scan_setext_header_line(const gh_buf *s, int pos); -int scan_hrule(const gh_buf *s, int pos); -int scan_open_code_fence(const gh_buf *s, int pos); -int scan_close_code_fence(const gh_buf *s, int pos, int len); -int scan_entity(const gh_buf *s, int pos); +int scan_autolink_uri(chunk *c, int offset); +int scan_autolink_email(chunk *c, int offset); +int scan_html_tag(chunk *c, int offset); +int scan_html_block_tag(chunk *c, int offset); +int scan_link_url(chunk *c, int offset); +int scan_link_title(chunk *c, int offset); +int scan_spacechars(chunk *c, int offset); +int scan_atx_header_start(chunk *c, int offset); +int scan_setext_header_line(chunk *c, int offset); +int scan_hrule(chunk *c, int offset); +int scan_open_code_fence(chunk *c, int offset); +int scan_close_code_fence(chunk *c, int offset, int len); +int scan_entity(chunk *c, int offset); diff --git a/src/scanners.re b/src/scanners.re index 7323ef9..5ac7c15 100644 --- a/src/scanners.re +++ b/src/scanners.re @@ -1,8 +1,15 @@ -#include "buffer.h" +#include "scanners.h" + +#define SCAN_DATA \ +  const unsigned char *marker = NULL; \ +  const unsigned char *p = c->data + offset; \ +  const unsigned char *start = p; \ +  const unsigned char *end = c->data + c->len  /*!re2c    re2c:define:YYCTYPE  = "unsigned char";    re2c:define:YYCURSOR = p; +  re2c:define:YYLIMIT = end;    re2c:define:YYMARKER = marker;    re2c:define:YYCTXMARKER = marker;    re2c:yyfill:enable = 0; @@ -55,11 +62,9 @@  */  // Try to match URI autolink after first <, returning number of chars matched. -extern int scan_autolink_uri(const gh_buf *s, int pos) +extern int scan_autolink_uri(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    scheme [:]([^\x00-\x20<>\\]|escaped_char)*[>]  { return (p - start); }    .? { return 0; } @@ -67,11 +72,9 @@ extern int scan_autolink_uri(const gh_buf *s, int pos)  }  // Try to match email autolink after first <, returning num of chars matched. -extern int scan_autolink_email(const gh_buf *s, int pos) +extern int scan_autolink_email(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    [a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+      [@] @@ -83,11 +86,9 @@ extern int scan_autolink_email(const gh_buf *s, int pos)  }  // Try to match an HTML tag after first <, returning num of chars matched. -extern int scan_html_tag(const gh_buf *s, int pos) +extern int scan_html_tag(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    htmltag { return (p - start); }    .? { return 0; } @@ -96,11 +97,9 @@ extern int scan_html_tag(const gh_buf *s, int pos)  // Try to match an HTML block tag including first <,  // returning num of chars matched. -extern int scan_html_block_tag(const gh_buf *s, int pos) +extern int scan_html_block_tag(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    [<] [/] blocktagname (spacechar | [>])  { return (p - start); }    [<] blocktagname (spacechar | [/>]) { return (p - start); } @@ -113,11 +112,9 @@ extern int scan_html_block_tag(const gh_buf *s, int pos)  // This may optionally be contained in <..>; otherwise  // whitespace and unbalanced right parentheses aren't allowed.  // Newlines aren't ever allowed. -extern int scan_link_url(const gh_buf *s, int pos) +extern int scan_link_url(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    [ \n]* [<] ([^<>\n\\\x00] | escaped_char | [\\])* [>] { return (p - start); }    [ \n]* (reg_char+ | escaped_char | in_parens_nosp)* { return (p - start); } @@ -128,11 +125,9 @@ extern int scan_link_url(const gh_buf *s, int pos)  // Try to match a link title (in single quotes, in double quotes, or  // in parentheses), returning number of chars matched.  Allow one  // level of internal nesting (quotes within quotes). -extern int scan_link_title(const gh_buf *s, int pos) +extern int scan_link_title(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    ["] (escaped_char|[^"\x00])* ["]   { return (p - start); }    ['] (escaped_char|[^'\x00])* ['] { return (p - start); } @@ -142,10 +137,9 @@ extern int scan_link_title(const gh_buf *s, int pos)  }  // Match space characters, including newlines. -extern int scan_spacechars(const gh_buf *s, int pos) +extern int scan_spacechars(chunk *c, int offset)  { -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    [ \t\n]* { return (p - start); }    . { return 0; } @@ -153,11 +147,9 @@ extern int scan_spacechars(const gh_buf *s, int pos)  }  // Match ATX header start. -extern int scan_atx_header_start(const gh_buf *s, int pos) +extern int scan_atx_header_start(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    [#]{1,6} ([ ]+|[\n])  { return (p - start); }    .? { return 0; } @@ -166,10 +158,9 @@ extern int scan_atx_header_start(const gh_buf *s, int pos)  // Match sexext header line.  Return 1 for level-1 header,  // 2 for level-2, 0 for no match. -extern int scan_setext_header_line(const gh_buf *s, int pos) +extern int scan_setext_header_line(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); +  SCAN_DATA;  /*!re2c    [=]+ [ ]* [\n] { return 1; }    [-]+ [ ]* [\n] { return 2; } @@ -180,11 +171,9 @@ extern int scan_setext_header_line(const gh_buf *s, int pos)  // Scan a horizontal rule line: "...three or more hyphens, asterisks,  // or underscores on a line by themselves. If you wish, you may use  // spaces between the hyphens or asterisks." -extern int scan_hrule(const gh_buf *s, int pos) +extern int scan_hrule(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    ([*][ ]*){3,} [ \t]* [\n] { return (p - start); }    ([_][ ]*){3,} [ \t]* [\n] { return (p - start); } @@ -194,11 +183,9 @@ extern int scan_hrule(const gh_buf *s, int pos)  }  // Scan an opening code fence. -extern int scan_open_code_fence(const gh_buf *s, int pos) +extern int scan_open_code_fence(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    [`]{3,} / [^`\n\x00]*[\n] { return (p - start); }    [~]{3,} / [^~\n\x00]*[\n] { return (p - start); } @@ -207,11 +194,9 @@ extern int scan_open_code_fence(const gh_buf *s, int pos)  }  // Scan a closing code fence with length at least len. -extern int scan_close_code_fence(const gh_buf *s, int pos, int len) +extern int scan_close_code_fence(chunk *c, int offset, int len)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    ([`]{3,} | [~]{3,}) / spacechar* [\n]                                { if (p - start > len) { @@ -225,11 +210,9 @@ extern int scan_close_code_fence(const gh_buf *s, int pos, int len)  // Scans an entity.  // Returns number of chars matched. -extern int scan_entity(const gh_buf *s, int pos) +extern int scan_entity(chunk *c, int offset)  { -  unsigned char * marker = NULL; -  unsigned char * p = &(s->ptr[pos]); -  unsigned char * start = p; +  SCAN_DATA;  /*!re2c    [&] ([#] ([Xx][A-Fa-f0-9]{1,8}|[0-9]{1,8}) |[A-Za-z][A-Za-z0-9]{1,31} ) [;]       { return (p - start); } @@ -1,17 +1,15 @@ +#ifndef _STDMD_H_ +#define _STDMD_H_ +  #include <stdbool.h>  #include <stdio.h>  #include "buffer.h" +#include "chunk.h"  #include "uthash.h"  #define VERSION "0.1"  #define CODE_INDENT 4 -typedef struct { -	const unsigned char *data; -	int len; -	int alloc; -} chunk; -  typedef struct Inline {  	enum { INL_STRING, INL_SOFTBREAK, INL_LINEBREAK, INL_CODE, INL_RAW_HTML, INL_ENTITY,  		INL_EMPH, INL_STRONG, INL_LINK, INL_IMAGE } tag; @@ -79,7 +77,6 @@ typedef struct Block {    struct Block*      parent;    struct Block*      top;    gh_buf			 string_content; -  int				 string_pos;    inl*               inline_content;    union  {      struct ListData       list_data; @@ -91,10 +88,10 @@ typedef struct Block {    struct Block *     prev;  } block; -inl* parse_inlines(gh_buf *input, int input_pos, reference** refmap); +inl* parse_inlines(gh_buf *input, reference** refmap);  void free_inlines(inl* e); -int parse_reference(gh_buf *input, int input_pos, reference** refmap); +int parse_reference(gh_buf *input, reference** refmap);  void free_reference(reference *ref);  void free_reference_map(reference **refmap); @@ -117,3 +114,4 @@ void inlines_to_html(gh_buf *html, inl *b);  void utf8proc_case_fold(gh_buf *dest, const unsigned char *str, int len); +#endif  | 
