예제 #1
0
/* markdown • parses the input buffer and renders it into the output buffer */
void
markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer) {
	struct link_ref *lr;
	struct buf *text = bufnew(TEXT_UNIT);
	size_t i, beg, end;
	struct render rndr;

	/* filling the render structure */
	if (!rndrer) return;
	rndr.make = *rndrer;
	if (rndr.make.max_work_stack < 1)
		rndr.make.max_work_stack = 1;
	arr_init(&rndr.refs, sizeof (struct link_ref));
	parr_init(&rndr.work);
	for (i = 0; i < 256; i += 1) rndr.active_char[i] = 0;
	if ((rndr.make.emphasis || rndr.make.double_emphasis
						|| rndr.make.triple_emphasis)
	&& rndr.make.emph_chars)
		for (i = 0; rndr.make.emph_chars[i]; i += 1)
			rndr.active_char[(unsigned char)rndr.make.emph_chars[i]]
				= char_emphasis;
	if (rndr.make.codespan) rndr.active_char['`'] = char_codespan;
	if (rndr.make.linebreak) rndr.active_char['\n'] = char_linebreak;
	if (rndr.make.image || rndr.make.link)
		rndr.active_char['['] = char_link;
	rndr.active_char['<'] = char_langle_tag;
	rndr.active_char['\\'] = char_escape;
	rndr.active_char['&'] = char_entity;

	/* first pass: looking for references, copying everything else */
	beg = 0;
	while (beg < ib->size) /* iterating over lines */
		if (is_ref(ib->data, beg, ib->size, &end, &rndr.refs))
			beg = end;
		else { /* skipping to the next line */
			end = beg;
			while (end < ib->size
			&& ib->data[end] != '\n' && ib->data[end] != '\r')
				end += 1;
			/* adding the line body if present */
			if (end > beg) bufput(text, ib->data + beg, end - beg);
			while (end < ib->size
			&& (ib->data[end] == '\n' || ib->data[end] == '\r')) {
				/* add one \n per newline */
				if (ib->data[end] == '\n'
				|| (end + 1 < ib->size
						&& ib->data[end + 1] != '\n'))
					bufputc(text, '\n');
				end += 1; }
			beg = end; }

	/* sorting the reference array */
	if (rndr.refs.size)
		qsort(rndr.refs.base, rndr.refs.size, rndr.refs.unit,
					cmp_link_ref_sort);

	/* adding a final newline if not already present */
	if (text->size
	&&  text->data[text->size - 1] != '\n'
	&&  text->data[text->size - 1] != '\r')
		bufputc(text, '\n');

	/* second pass: actual rendering */
	if (rndr.make.prolog)
		rndr.make.prolog(ob, rndr.make.opaque);
	parse_block(ob, &rndr, text->data, text->size);
	if (rndr.make.epilog)
		rndr.make.epilog(ob, rndr.make.opaque);

	/* clean-up */
	bufrelease(text);
	lr = rndr.refs.base;
	for (i = 0; i < rndr.refs.size; i += 1) {
		bufrelease(lr[i].id);
		bufrelease(lr[i].link);
		bufrelease(lr[i].title); }
	arr_free(&rndr.refs);
	assert(rndr.work.size == 0);
	for (i = 0; i < rndr.work.asize; i += 1)
		bufrelease(rndr.work.item[i]);
	parr_free(&rndr.work); }
예제 #2
0
파일: markdown.c 프로젝트: nono/upskirt
/* markdown • parses the input buffer and renders it into the output buffer */
void
ups_markdown(struct buf *ob, struct buf *ib, const struct mkd_renderer *rndrer, unsigned int extensions) {
	struct link_ref *lr;
	struct buf *text;
	size_t i, beg, end;
	struct render rndr;

	/* filling the render structure */
	if (!rndrer)
		return;

	text = bufnew(TEXT_UNIT);
	if (!text)
		return;

	rndr.make = *rndrer;
	arr_init(&rndr.refs, sizeof (struct link_ref));
	parr_init(&rndr.work);

	for (i = 0; i < 256; i += 1)
		rndr.active_char[i] = 0;

	if (rndr.make.emphasis || rndr.make.double_emphasis || rndr.make.triple_emphasis) {
		rndr.active_char['*'] = char_emphasis;
		rndr.active_char['_'] = char_emphasis;
		if (extensions & MKDEXT_STRIKETHROUGH)
			rndr.active_char['~'] = char_emphasis;
	}

	if (rndr.make.codespan)
		rndr.active_char['`'] = char_codespan;

	if (rndr.make.linebreak)
		rndr.active_char['\n'] = char_linebreak;

	if (rndr.make.image || rndr.make.link)
		rndr.active_char['['] = char_link;

	rndr.active_char['<'] = char_langle_tag;
	rndr.active_char['\\'] = char_escape;
	rndr.active_char['&'] = char_entity;

	if (extensions & MKDEXT_AUTOLINK) {
		rndr.active_char['h'] = char_autolink; // http, https
		rndr.active_char['H'] = char_autolink;

		rndr.active_char['f'] = char_autolink; // ftp
		rndr.active_char['F'] = char_autolink;

		rndr.active_char['m'] = char_autolink; // mailto
		rndr.active_char['M'] = char_autolink;
	}

	/* Extension data */
	rndr.ext_flags = extensions;
	rndr.max_nesting = 16;

	/* first pass: looking for references, copying everything else */
	beg = 0;
	while (beg < ib->size) /* iterating over lines */
		if (is_ref(ib->data, beg, ib->size, &end, &rndr.refs))
			beg = end;
		else { /* skipping to the next line */
			end = beg;
			while (end < ib->size && ib->data[end] != '\n' && ib->data[end] != '\r')
				end += 1;

			/* adding the line body if present */
			if (end > beg)
				expand_tabs(text, ib->data + beg, end - beg);

			while (end < ib->size && (ib->data[end] == '\n' || ib->data[end] == '\r')) {
				/* add one \n per newline */
				if (ib->data[end] == '\n' || (end + 1 < ib->size && ib->data[end + 1] != '\n'))
					bufputc(text, '\n');
				end += 1;
			}

			beg = end;
		}

	/* sorting the reference array */
	if (rndr.refs.size)
		qsort(rndr.refs.base, rndr.refs.size, rndr.refs.unit, cmp_link_ref_sort);

	/* adding a final newline if not already present */
	if (!text->size)
		goto cleanup;

	if (text->data[text->size - 1] != '\n' &&  text->data[text->size - 1] != '\r')
		bufputc(text, '\n');

	/* second pass: actual rendering */
	if (rndr.make.doc_header)
		rndr.make.doc_header(ob, rndr.make.opaque);

	parse_block(ob, &rndr, text->data, text->size);

	if (rndr.make.doc_footer)
		rndr.make.doc_footer(ob, rndr.make.opaque);

	/* clean-up */
cleanup:
	bufrelease(text);
	lr = rndr.refs.base;
	for (i = 0; i < (size_t)rndr.refs.size; i += 1) {
		bufrelease(lr[i].id);
		bufrelease(lr[i].link);
		bufrelease(lr[i].title);
	}

	arr_free(&rndr.refs);

	assert(rndr.work.size == 0);

	for (i = 0; i < (size_t)rndr.work.asize; i += 1)
		bufrelease(rndr.work.item[i]);

	parr_free(&rndr.work);
}