Ejemplo n.º 1
0
/* get_link_ref • extract referenced link and title from id */
static int
get_link_ref(struct render *rndr, struct buf *link, struct buf *title,
				char * data, size_t size) {
	struct link_ref *lr;

	/* find the link from its id (stored temporarily in link) */
	link->size = 0;
	if (build_ref_id(link, data, size) < 0)
		return -1;
	lr = arr_sorted_find(&rndr->refs, link, cmp_link_ref);
	if (!lr) return -1;

	/* fill the output buffers */
	link->size = 0;
	if (lr->link)
		bufput(link, lr->link->data, lr->link->size);
	title->size = 0;
	if (lr->title)
		bufput(title, lr->title->data, lr->title->size);
	return 0; }
Ejemplo n.º 2
0
/* char_link • '[': parsing a link or an image */
static size_t
char_link(struct buf *ob, struct render *rndr, char *data, size_t offset, size_t size)
{
	int is_img = (offset && data[-1] == '!'), level;
	size_t i = 1, txt_e, link_b = 0, link_e = 0, title_b = 0, title_e = 0;
	struct buf *content = 0;
	struct buf *link = 0;
	struct buf *title = 0;
	struct buf *u_link = 0;
	size_t org_work_size = rndr->work.size;
	int text_has_nl = 0, ret = 0;

	/* checking whether the correct renderer exists */
	if ((is_img && !rndr->make.image) || (!is_img && !rndr->make.link))
		goto cleanup;

	/* looking for the matching closing bracket */
	for (level = 1; i < size; i += 1) {
		if (data[i] == '\n')
			text_has_nl = 1;

		else if (data[i - 1] == '\\')
			continue;

		else if (data[i] == '[')
			level++;

		else if (data[i] == ']') {
			level--;
			if (level <= 0)
				break;
		}
	}

	if (i >= size)
		goto cleanup;

	txt_e = i;
	i += 1;

	/* skip any amount of whitespace or newline */
	/* (this is much more laxist than original markdown syntax) */
	while (i < size && isspace(data[i]))
		i++;

	/* inline style link */
	if (i < size && data[i] == '(') {
		/* skipping initial whitespace */
		i += 1;

		while (i < size && isspace(data[i]))
			i++;

		link_b = i;

		/* looking for link end: ' " ) */
		while (i < size) {
			if (data[i] == '\\') i += 2;
			else if (data[i] == ')' || data[i] == '\'' || data[i] == '"') break;
			else i += 1;
		}

		if (i >= size) goto cleanup;
		link_e = i;

		/* looking for title end if present */
		if (data[i] == '\'' || data[i] == '"') {
			i++;
			title_b = i;

			while (i < size) {
				if (data[i] == '\\') i += 2;
				else if (data[i] == ')') break;
				else i += 1;
			}

			if (i >= size) goto cleanup;

			/* skipping whitespaces 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 whitespace 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 = rndr_newbuf(rndr);
			bufput(link, data + link_b, link_e - link_b);
		}

		if (title_e > title_b) {
			title = rndr_newbuf(rndr);
			bufput(title, data + title_b, title_e - title_b);
		}

		i++;
	}

	/* reference style link */
	else if (i < size && data[i] == '[') {
		struct buf id = { 0, 0, 0, 0, 0 };
		struct link_ref *lr;

		/* looking for the id */
		i += 1;
		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) {
			if (text_has_nl) {
				struct buf *b = rndr_newbuf(rndr);
				size_t j;

				for (j = 1; j < txt_e; j++) {
					if (data[j] != '\n')
						bufputc(b, data[j]);
					else if (data[j - 1] != ' ')
						bufputc(b, ' ');
				}

				id.data = b->data;
				id.size = b->size;
			} else {
				id.data = data + 1;
				id.size = txt_e - 1;
			}
		} else {
			id.data = data + link_b;
			id.size = link_e - link_b;
		}

		lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref);
		if (!lr) goto cleanup;

		/* keeping link and title from link_ref */
		link = lr->link;
		title = lr->title;
		i += 1;
	}

	/* shortcut reference style link */
	else {
		struct buf id = { 0, 0, 0, 0, 0 };
		struct link_ref *lr;

		/* crafting the id */
		if (text_has_nl) {
			struct buf *b = rndr_newbuf(rndr);
			size_t j;

			for (j = 1; j < txt_e; j++) {
				if (data[j] != '\n')
					bufputc(b, data[j]);
				else if (data[j - 1] != ' ')
					bufputc(b, ' ');
			}

			id.data = b->data;
			id.size = b->size;
		} else {
			id.data = data + 1;
			id.size = txt_e - 1;
		}

		/* finding the link_ref */
		lr = arr_sorted_find(&rndr->refs, &id, cmp_link_ref);
		if (!lr) goto cleanup;

		/* keeping link and title from link_ref */
		link = lr->link;
		title = lr->title;

		/* rewinding the whitespace */
		i = txt_e + 1;
	}

	/* building content: img alt is escaped, link content is parsed */
	if (txt_e > 1) {
		content = rndr_newbuf(rndr);
		if (is_img) bufput(content, data + 1, txt_e - 1);
		else parse_inline(content, rndr, data + 1, txt_e - 1);
	}

	if (link) {
		u_link = rndr_newbuf(rndr);
		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 = rndr->make.image(ob, u_link, title, content, rndr->make.opaque);
	} else {
		ret = rndr->make.link(ob, u_link, title, content, rndr->make.opaque);
	}

	/* cleanup */
cleanup:
	rndr->work.size = (int)org_work_size;
	return ret ? i : 0;
}