Esempio n. 1
0
static void md_block_external_images(cmark_iter *const iter) {
	for(;;) {
		cmark_event_type const event = cmark_iter_next(iter);
		if(CMARK_EVENT_DONE == event) break;
		if(CMARK_EVENT_EXIT != event) continue;
		cmark_node *const node = cmark_iter_get_node(iter);
		if(CMARK_NODE_IMAGE != cmark_node_get_type(node)) continue;

		char const *const URI = cmark_node_get_url(node);
		if(URI) {
			if(0 == strncasecmp(URI, STR_LEN("hash:"))) continue;
			if(0 == strncasecmp(URI, STR_LEN("data:"))) continue;
		}

		cmark_node *link = cmark_node_new(CMARK_NODE_LINK);
		cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
		cmark_node_set_url(link, URI);
		for(;;) {
			cmark_node *child = cmark_node_first_child(node);
			if(!child) break;
			cmark_node_append_child(link, child);
		}
		if(cmark_node_first_child(link)) {
			cmark_node_set_literal(text, " (external image)");
		} else {
			cmark_node_set_literal(text, "(external image)");
		}
		cmark_node_append_child(link, text);

		cmark_node_insert_before(node, link);
		cmark_node_free(node);
	}
}
Esempio n. 2
0
static cmark_node *param_ref_match(cmark_syntax_extension *self,
                                   cmark_parser *parser,
                                   cmark_node *parent,
                                   cmark_inline_parser *inline_parser) {
    cmark_node *emph, *text_node;
    char *param_name;
    char prev_char;
    ParsingContext context;

    context.parser = inline_parser;
    context.allow_dashes = 0;

    prev_char = cmark_inline_parser_peek_at(
                    inline_parser,
                    cmark_inline_parser_get_offset(inline_parser) - 1);

    if (prev_char && prev_char != ' ' && prev_char != '\t' && prev_char != '\n')
        return NULL;

    cmark_inline_parser_advance_offset(inline_parser);
    param_name = cmark_inline_parser_take_while(inline_parser,
                 (CMarkInlinePredicate) is_valid_c, &context);

    if (!param_name)
        return NULL;

    emph = cmark_node_new(CMARK_NODE_EMPH);
    text_node = cmark_node_new(CMARK_NODE_TEXT);
    cmark_node_append_child(emph, text_node);

    cmark_node_set_literal(text_node, param_name);
    free(param_name);
    return emph;
}
Esempio n. 3
0
static CMARK_INLINE cmark_node *make_autolink(cmark_mem *mem, cmark_chunk url,
                                              int is_email) {
  cmark_node *link = make_simple(mem, CMARK_NODE_LINK);
  link->as.link.url = cmark_clean_autolink(mem, &url, is_email);
  link->as.link.title = cmark_chunk_literal("");
  cmark_node_append_child(link, make_str_with_entities(mem, &url));
  return link;
}
Esempio n. 4
0
static void md_autolink(cmark_iter *const iter) {
	regex_t linkify[1];
	// <http://daringfireball.net/2010/07/improved_regex_for_matching_urls>
	// Painstakingly ported to POSIX
	int rc = regcomp(linkify, "([a-z][a-z0-9_-]+:(/{1,3}|[a-z0-9%])|www[0-9]{0,3}[.]|[a-z0-9.-]+[.][a-z]{2,4}/)([^[:space:]()<>]+|\\(([^[:space:]()<>]+|(\\([^[:space:]()<>]+\\)))*\\))+(\\(([^[:space:]()<>]+|(\\([^[:space:]()<>]+\\)))*\\)|[^][[:space:]`!(){};:'\".,<>?«»“”‘’])", REG_ICASE | REG_EXTENDED);
	assert(0 == rc);

	for(;;) {
		cmark_event_type const event = cmark_iter_next(iter);
		if(CMARK_EVENT_DONE == event) break;
		if(CMARK_EVENT_ENTER != event) continue;
		cmark_node *const node = cmark_iter_get_node(iter);
		if(CMARK_NODE_TEXT != cmark_node_get_type(node)) continue;

		char const *const str = cmark_node_get_literal(node);
		char const *pos = str;
		regmatch_t match;
		while(0 == regexec(linkify, pos, 1, &match, 0)) {
			regoff_t const loc = match.rm_so;
			regoff_t const len = match.rm_eo - match.rm_so;

			char *pfx = strndup(pos, loc);
			char *link_abs = strndup(pos+loc, len);
			char *link_rel = aasprintf("/history/%s", link_abs);
			assert(pfx);
			assert(link_abs);
			assert(link_rel);

			cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
			cmark_node_set_literal(text, pfx);
			cmark_node *link = cmark_node_new(CMARK_NODE_LINK);
			cmark_node_set_url(link, link_rel);
			cmark_node *sup = superscript("^", "", link_abs);
			cmark_node *face = cmark_node_new(CMARK_NODE_TEXT);
			cmark_node_set_literal(face, link_abs);
			cmark_node_append_child(link, face);
			cmark_node_insert_before(node, text);
			cmark_node_insert_before(node, link);
			cmark_node_insert_before(node, sup);

			free(pfx); pfx = NULL;
			free(link_abs); link_abs = NULL;
			free(link_rel); link_rel = NULL;

			pos += loc+len;
		}

		if(str != pos) {
			cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
			cmark_node_set_literal(text, pos);
			cmark_node_insert_before(node, text);
			cmark_node_free(node);
		}

	}
	regfree(linkify);
}
Esempio n. 5
0
static delimiter *S_insert_emph(subject *subj, delimiter *opener,
                                delimiter *closer) {
  delimiter *delim, *tmp_delim;
  bufsize_t use_delims;
  cmark_node *opener_inl = opener->inl_text;
  cmark_node *closer_inl = closer->inl_text;
  bufsize_t opener_num_chars = opener_inl->as.literal.len;
  bufsize_t closer_num_chars = closer_inl->as.literal.len;
  cmark_node *tmp, *tmpnext, *emph;

  // calculate the actual number of characters used from this closer
  use_delims = (closer_num_chars >= 2 && opener_num_chars >=2) ? 2 : 1;

  // remove used characters from associated inlines.
  opener_num_chars -= use_delims;
  closer_num_chars -= use_delims;
  opener_inl->as.literal.len = opener_num_chars;
  closer_inl->as.literal.len = closer_num_chars;

  // free delimiters between opener and closer
  delim = closer->previous;
  while (delim != NULL && delim != opener) {
    tmp_delim = delim->previous;
    remove_delimiter(subj, delim);
    delim = tmp_delim;
  }

  // create new emph or strong, and splice it in to our inlines
  // between the opener and closer
  emph = use_delims == 1 ? make_emph(subj->mem) : make_strong(subj->mem);

  tmp = opener_inl->next;
  while (tmp && tmp != closer_inl) {
    tmpnext = tmp->next;
    cmark_node_append_child(emph, tmp);
    tmp = tmpnext;
  }
  cmark_node_insert_after(opener_inl, emph);

  // if opener has 0 characters, remove it and its associated inline
  if (opener_num_chars == 0) {
    cmark_node_free(opener_inl);
    remove_delimiter(subj, opener);
  }

  // if closer has 0 characters, remove it and its associated inline
  if (closer_num_chars == 0) {
    // remove empty closer inline
    cmark_node_free(closer_inl);
    // remove closer from list
    tmp_delim = closer->next;
    remove_delimiter(subj, closer);
    closer = tmp_delim;
  }

  return closer;
}
Esempio n. 6
0
static cmark_node *www_match(cmark_parser *parser, cmark_node *parent,
                             cmark_inline_parser *inline_parser) {
  cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
  size_t max_rewind = cmark_inline_parser_get_offset(inline_parser);
  uint8_t *data = chunk->data + max_rewind;
  size_t size = chunk->len - max_rewind;
  int start = cmark_inline_parser_get_column(inline_parser);

  size_t link_end;

  if (max_rewind > 0 && strchr("*_~(", data[-1]) == NULL &&
      !cmark_isspace(data[-1]))
    return 0;

  if (size < 4 || memcmp(data, "www.", strlen("www.")) != 0)
    return 0;

  link_end = check_domain(data, size, 0);

  if (link_end == 0)
    return NULL;

  while (link_end < size && !cmark_isspace(data[link_end]))
    link_end++;

  link_end = autolink_delim(data, link_end);

  if (link_end == 0)
    return NULL;

  cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end));

  cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);

  cmark_strbuf buf;
  cmark_strbuf_init(parser->mem, &buf, 10);
  cmark_strbuf_puts(&buf, "http://");
  cmark_strbuf_put(&buf, data, (bufsize_t)link_end);
  node->as.link.url = cmark_chunk_buf_detach(&buf);

  cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
  text->as.literal =
      cmark_chunk_dup(chunk, (bufsize_t)max_rewind, (bufsize_t)link_end);
  cmark_node_append_child(node, text);

  node->start_line = text->start_line =
    node->end_line = text->end_line =
    cmark_inline_parser_get_line(inline_parser);

  node->start_column = text->start_column = start - 1;
  node->end_column = text->end_column = cmark_inline_parser_get_column(inline_parser) - 1;

  return node;
}
Esempio n. 7
0
static cmark_node *superscript(char const *const label, char const *const title, char const *const link) {
	cmark_node *node = cmark_node_new(CMARK_NODE_CUSTOM_INLINE);

	cmark_node *a = cmark_node_new(CMARK_NODE_LINK);
	cmark_node_set_url(a, link);
	cmark_node_set_title(a, title);

	cmark_node *op = cmark_node_new(CMARK_NODE_INLINE_HTML);
	cmark_node_set_literal(op, "<sup>[");
	cmark_node *ed = cmark_node_new(CMARK_NODE_INLINE_HTML);
	cmark_node_set_literal(ed, "]</sup>");

	cmark_node *face = cmark_node_new(CMARK_NODE_TEXT);
	cmark_node_set_literal(face, label);
	cmark_node_append_child(a, face);

	cmark_node_append_child(node, op);
	cmark_node_append_child(node, a);
	cmark_node_append_child(node, ed);

	return node;
}
Esempio n. 8
0
static cmark_node *url_match(cmark_parser *parser, cmark_node *parent,
                             cmark_inline_parser *inline_parser) {
  size_t link_end, domain_len;
  int rewind = 0;

  cmark_chunk *chunk = cmark_inline_parser_get_chunk(inline_parser);
  int max_rewind = cmark_inline_parser_get_offset(inline_parser);
  uint8_t *data = chunk->data + max_rewind;
  size_t size = chunk->len - max_rewind;

  if (size < 4 || data[1] != '/' || data[2] != '/')
    return 0;

  while (rewind < max_rewind && cmark_isalpha(data[-rewind - 1]))
    rewind++;

  if (!sd_autolink_issafe(data - rewind, size + rewind))
    return 0;

  link_end = strlen("://");

  domain_len = check_domain(data + link_end, size - link_end, 1);

  if (domain_len == 0)
    return 0;

  link_end += domain_len;
  while (link_end < size && !cmark_isspace(data[link_end]))
    link_end++;

  link_end = autolink_delim(data, link_end);

  if (link_end == 0)
    return NULL;

  cmark_inline_parser_set_offset(inline_parser, (int)(max_rewind + link_end));
  cmark_node_unput(parent, rewind);

  cmark_node *node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);

  cmark_chunk url = cmark_chunk_dup(chunk, max_rewind - rewind,
                                    (bufsize_t)(link_end + rewind));
  node->as.link.url = url;

  cmark_node *text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
  text->as.literal = url;
  cmark_node_append_child(node, text);

  return node;
}
Esempio n. 9
0
static void md_escape(cmark_iter *const iter) {
	for(;;) {
		cmark_event_type const event = cmark_iter_next(iter);
		if(CMARK_EVENT_DONE == event) break;
		if(CMARK_EVENT_ENTER != event) continue;
		cmark_node *const node = cmark_iter_get_node(iter);
		if(CMARK_NODE_HTML != cmark_node_get_type(node)) continue;

		char const *const str = cmark_node_get_literal(node);
		cmark_node *p = cmark_node_new(CMARK_NODE_PARAGRAPH);
		cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
		cmark_node_set_literal(text, str);
		cmark_node_append_child(p, text);
		cmark_node_insert_before(node, p);
		cmark_node_free(node);
	}
}
Esempio n. 10
0
static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
                         cmark_inline_parser *inline_parser, delimiter *opener,
                         delimiter *closer) {
  cmark_node *strikethrough;
  cmark_node *tmp, *next;
  delimiter *delim, *tmp_delim;
  delimiter *res = closer->next;

  strikethrough = opener->inl_text;

  if (!cmark_node_set_type(strikethrough, CMARK_NODE_STRIKETHROUGH))
    goto done;

  cmark_node_set_syntax_extension(strikethrough, self);

  cmark_node_set_string_content(strikethrough, "~");
  tmp = cmark_node_next(opener->inl_text);

  while (tmp) {
    if (tmp == closer->inl_text)
      break;
    next = cmark_node_next(tmp);
    cmark_node_append_child(strikethrough, tmp);
    tmp = next;
  }

  strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
  cmark_node_free(closer->inl_text);

  delim = closer;
  while (delim != NULL && delim != opener) {
    tmp_delim = delim->previous;
    cmark_inline_parser_remove_delimiter(inline_parser, delim);
    delim = tmp_delim;
  }

  cmark_inline_parser_remove_delimiter(inline_parser, opener);

done:
  return res;
}
Esempio n. 11
0
File: main.c Progetto: txdv/cmark
static void
test_content(test_batch_runner *runner, cmark_node_type type,
	     int allowed_content)
{
	cmark_node *node = cmark_node_new(type);

	for (int i = 0; i < num_node_types; ++i) {
		cmark_node_type child_type = node_types[i];
		cmark_node *child = cmark_node_new(child_type);

		int got = cmark_node_append_child(node, child);
		int expected = (allowed_content >> child_type) & 1;

		INT_EQ(runner, got, expected,
		       "add %d as child of %d", child_type, type);

		cmark_node_free(child);
	}

	cmark_node_free(node);
}
Esempio n. 12
0
// Parse an inline, advancing subject, and add it as a child of parent.
// Return 0 if no inline can be parsed, 1 otherwise.
static int parse_inline(subject* subj, cmark_node * parent, int options)
{
	cmark_node* new_inl = NULL;
	cmark_chunk contents;
	unsigned char c;
	int endpos;
	c = peek_char(subj);
	if (c == 0) {
		return 0;
	}
	switch(c) {
	case '\n':
		new_inl = handle_newline(subj);
		break;
	case '`':
		new_inl = handle_backticks(subj);
		break;
	case '\\':
		new_inl = handle_backslash(subj);
		break;
	case '&':
		new_inl = handle_entity(subj);
		break;
	case '<':
		new_inl = handle_pointy_brace(subj);
		break;
	case '*':
	case '_':
	case '\'':
	case '"':
		new_inl = handle_delim(subj, c, options & CMARK_OPT_SMART);
		break;
	case '-':
		new_inl = handle_hyphen(subj, options & CMARK_OPT_SMART);
		break;
	case '.':
		new_inl = handle_period(subj, options & CMARK_OPT_SMART);
		break;
	case '[':
		advance(subj);
		new_inl = make_str(cmark_chunk_literal("["));
		push_delimiter(subj, '[', true, false, new_inl);
		break;
	case ']':
		new_inl = handle_close_bracket(subj, parent);
		break;
	case '!':
		advance(subj);
		if (peek_char(subj) == '[') {
			advance(subj);
			new_inl = make_str(cmark_chunk_literal("!["));
			push_delimiter(subj, '!', false, true, new_inl);
		} else {
			new_inl = make_str(cmark_chunk_literal("!"));
		}
		break;
	default:
		endpos = subject_find_special_char(subj, options);
		contents = cmark_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') {
			cmark_chunk_rtrim(&contents);
		}

		new_inl = make_str(contents);
	}
	if (new_inl != NULL) {
		cmark_node_append_child(parent, new_inl);
	}

	return 1;
}
Esempio n. 13
0
static void postprocess_text(cmark_parser *parser, cmark_node *text, int offset) {
  size_t link_end;
  uint8_t *data = text->as.literal.data,
    *at;
  size_t size = text->as.literal.len;
  int rewind, max_rewind,
      nb = 0, np = 0, ns = 0;

  if (offset < 0 || (size_t)offset >= size)
    return;

  data += offset;
  size -= offset;

  at = (uint8_t *)memchr(data, '@', size);
  if (!at)
    return;

  max_rewind = (int)(at - data);
  data += max_rewind;
  size -= max_rewind;

  for (rewind = 0; rewind < max_rewind; ++rewind) {
    uint8_t c = data[-rewind - 1];

    if (cmark_isalnum(c))
      continue;

    if (strchr(".+-_", c) != NULL)
      continue;

    if (c == '/')
      ns++;

    break;
  }

  if (rewind == 0 || ns > 0) {
    postprocess_text(parser, text, max_rewind + 1 + offset);
    return;
  }

  for (link_end = 0; link_end < size; ++link_end) {
    uint8_t c = data[link_end];

    if (cmark_isalnum(c))
      continue;

    if (c == '@')
      nb++;
    else if (c == '.' && link_end < size - 1 && cmark_isalnum(data[link_end + 1]))
      np++;
    else if (c != '-' && c != '_')
      break;
  }

  if (link_end < 2 || nb != 1 || np == 0 ||
      (!cmark_isalpha(data[link_end - 1]) && data[link_end - 1] != '.')) {
    postprocess_text(parser, text, max_rewind + 1 + offset);
    return;
  }

  link_end = autolink_delim(data, link_end);

  if (link_end == 0) {
    postprocess_text(parser, text, max_rewind + 1 + offset);
    return;
  }

  cmark_chunk_to_cstr(parser->mem, &text->as.literal);

  cmark_node *link_node = cmark_node_new_with_mem(CMARK_NODE_LINK, parser->mem);
  cmark_strbuf buf;
  cmark_strbuf_init(parser->mem, &buf, 10);
  cmark_strbuf_puts(&buf, "mailto:");
  cmark_strbuf_put(&buf, data - rewind, (bufsize_t)(link_end + rewind));
  link_node->as.link.url = cmark_chunk_buf_detach(&buf);

  cmark_node *link_text = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
  cmark_chunk email = cmark_chunk_dup(
      &text->as.literal,
      offset + max_rewind - rewind,
      (bufsize_t)(link_end + rewind));
  cmark_chunk_to_cstr(parser->mem, &email);
  link_text->as.literal = email;
  cmark_node_append_child(link_node, link_text);

  cmark_node_insert_after(text, link_node);

  cmark_node *post = cmark_node_new_with_mem(CMARK_NODE_TEXT, parser->mem);
  post->as.literal = cmark_chunk_dup(&text->as.literal,
    (bufsize_t)(offset + max_rewind + link_end),
    (bufsize_t)(size - link_end));
  cmark_chunk_to_cstr(parser->mem, &post->as.literal);

  cmark_node_insert_after(link_node, post);

  text->as.literal.len = offset + max_rewind - rewind;
  text->as.literal.data[text->as.literal.len] = 0;

  postprocess_text(parser, post, 0);
}
Esempio n. 14
0
// Return a link, an image, or a literal close bracket.
static cmark_node *handle_close_bracket(subject *subj) {
  bufsize_t initial_pos, after_link_text_pos;
  bufsize_t endurl, starttitle, endtitle, endall;
  bufsize_t sps, n;
  cmark_reference *ref = NULL;
  cmark_chunk url_chunk, title_chunk;
  cmark_chunk url, title;
  bracket *opener;
  cmark_node *inl;
  cmark_chunk raw_label;
  int found_label;
  cmark_node *tmp, *tmpnext;
  bool is_image;

  advance(subj); // advance past ]
  initial_pos = subj->pos;

  // get last [ or ![
  opener = subj->last_bracket;

  if (opener == NULL) {
    return make_str(subj->mem, cmark_chunk_literal("]"));
  }

  if (!opener->active) {
    // take delimiter off stack
    pop_bracket(subj);
    return make_str(subj->mem, cmark_chunk_literal("]"));
  }

  // If we got here, we matched a potential link/image text.
  // Now we check to see if it's a link/image.
  is_image = opener->image;

  after_link_text_pos = subj->pos;

  // First, look for an inline link.
  if (peek_char(subj) == '(' &&
      ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) &&
      ((n = manual_scan_link_url(&subj->input, subj->pos + 1 + sps, &url_chunk)) > -1)) {

    // try to parse an explicit link:
    endurl = subj->pos + 1 + sps + n;
    starttitle = endurl + scan_spacechars(&subj->input, endurl);

    // ensure there are spaces btw url and title
    endtitle = (starttitle == endurl)
                   ? starttitle
                   : starttitle + scan_link_title(&subj->input, starttitle);

    endall = endtitle + scan_spacechars(&subj->input, endtitle);

    if (peek_at(subj, endall) == ')') {
      subj->pos = endall + 1;

      title_chunk =
          cmark_chunk_dup(&subj->input, starttitle, endtitle - starttitle);
      url = cmark_clean_url(subj->mem, &url_chunk);
      title = cmark_clean_title(subj->mem, &title_chunk);
      cmark_chunk_free(subj->mem, &url_chunk);
      cmark_chunk_free(subj->mem, &title_chunk);
      goto match;

    } else {
      // it could still be a shortcut reference link
      subj->pos = after_link_text_pos;
    }
  }

  // Next, look for a following [link label] that matches in refmap.
  // skip spaces
  raw_label = cmark_chunk_literal("");
  found_label = link_label(subj, &raw_label);
  if (!found_label) {
    // If we have a shortcut reference link, back up
    // to before the spacse we skipped.
    subj->pos = initial_pos;
  }

  if ((!found_label || raw_label.len == 0) && !opener->bracket_after) {
    cmark_chunk_free(subj->mem, &raw_label);
    raw_label = cmark_chunk_dup(&subj->input, opener->position,
                                initial_pos - opener->position - 1);
    found_label = true;
  }

  if (found_label) {
    ref = cmark_reference_lookup(subj->refmap, &raw_label);
    cmark_chunk_free(subj->mem, &raw_label);
  }

  if (ref != NULL) { // found
    url = chunk_clone(subj->mem, &ref->url);
    title = chunk_clone(subj->mem, &ref->title);
    goto match;
  } else {
    goto noMatch;
  }

noMatch:
  // If we fall through to here, it means we didn't match a link:
  pop_bracket(subj); // remove this opener from delimiter list
  subj->pos = initial_pos;
  return make_str(subj->mem, cmark_chunk_literal("]"));

match:
  inl = make_simple(subj->mem, is_image ? CMARK_NODE_IMAGE : CMARK_NODE_LINK);
  inl->as.link.url = url;
  inl->as.link.title = title;
  cmark_node_insert_before(opener->inl_text, inl);
  // Add link text:
  tmp = opener->inl_text->next;
  while (tmp) {
    tmpnext = tmp->next;
    cmark_node_append_child(inl, tmp);
    tmp = tmpnext;
  }

  // Free the bracket [:
  cmark_node_free(opener->inl_text);

  process_emphasis(subj, opener->previous_delimiter);
  pop_bracket(subj);

  // Now, if we have a link, we also want to deactivate earlier link
  // delimiters. (This code can be removed if we decide to allow links
  // inside links.)
  if (!is_image) {
    opener = subj->last_bracket;
    while (opener != NULL) {
      if (!opener->image) {
        if (!opener->active) {
          break;
        } else {
          opener->active = false;
        }
      }
      opener = opener->previous;
    }
  }

  return NULL;
}
Esempio n. 15
0
File: main.c Progetto: txdv/cmark
void
hierarchy(test_batch_runner *runner)
{
	cmark_node *bquote1 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
	cmark_node *bquote2 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);
	cmark_node *bquote3 = cmark_node_new(CMARK_NODE_BLOCK_QUOTE);

	OK(runner, cmark_node_append_child(bquote1, bquote2),
	   "append bquote2");
	OK(runner, cmark_node_append_child(bquote2, bquote3),
	   "append bquote3");
	OK(runner, !cmark_node_append_child(bquote3, bquote3),
	   "adding a node as child of itself fails");
	OK(runner, !cmark_node_append_child(bquote3, bquote1),
	   "adding a parent as child fails");

	cmark_node_free(bquote1);

	int max_node_type = CMARK_NODE_LAST_BLOCK > CMARK_NODE_LAST_INLINE
			    ? CMARK_NODE_LAST_BLOCK : CMARK_NODE_LAST_INLINE;
	OK(runner, max_node_type < 32, "all node types < 32");

	int list_item_flag = 1 << CMARK_NODE_ITEM;
	int top_level_blocks =
		(1 << CMARK_NODE_BLOCK_QUOTE) |
		(1 << CMARK_NODE_LIST) |
		(1 << CMARK_NODE_CODE_BLOCK) |
		(1 << CMARK_NODE_HTML) |
		(1 << CMARK_NODE_PARAGRAPH) |
		(1 << CMARK_NODE_HEADER) |
		(1 << CMARK_NODE_HRULE);
	int all_inlines =
		(1 << CMARK_NODE_TEXT) |
		(1 << CMARK_NODE_SOFTBREAK) |
		(1 << CMARK_NODE_LINEBREAK) |
		(1 << CMARK_NODE_CODE) |
		(1 << CMARK_NODE_INLINE_HTML) |
		(1 << CMARK_NODE_EMPH) |
		(1 << CMARK_NODE_STRONG) |
		(1 << CMARK_NODE_LINK) |
		(1 << CMARK_NODE_IMAGE);

	test_content(runner, CMARK_NODE_DOCUMENT,      top_level_blocks);
	test_content(runner, CMARK_NODE_BLOCK_QUOTE,   top_level_blocks);
	test_content(runner, CMARK_NODE_LIST,          list_item_flag);
	test_content(runner, CMARK_NODE_ITEM,          top_level_blocks);
	test_content(runner, CMARK_NODE_CODE_BLOCK ,   0);
	test_content(runner, CMARK_NODE_HTML,          0);
	test_content(runner, CMARK_NODE_PARAGRAPH,     all_inlines);
	test_content(runner, CMARK_NODE_HEADER,        all_inlines);
	test_content(runner, CMARK_NODE_HRULE,         0);
	test_content(runner, CMARK_NODE_TEXT,	       0);
	test_content(runner, CMARK_NODE_SOFTBREAK,     0);
	test_content(runner, CMARK_NODE_LINEBREAK,     0);
	test_content(runner, CMARK_NODE_CODE,   0);
	test_content(runner, CMARK_NODE_INLINE_HTML,   0);
	test_content(runner, CMARK_NODE_EMPH,          all_inlines);
	test_content(runner, CMARK_NODE_STRONG,        all_inlines);
	test_content(runner, CMARK_NODE_LINK,          all_inlines);
	test_content(runner, CMARK_NODE_IMAGE,         all_inlines);
}
Esempio n. 16
0
File: main.c Progetto: txdv/cmark
static void
create_tree(test_batch_runner *runner)
{
	char *html;
	cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);

	cmark_node *p = cmark_node_new(CMARK_NODE_PARAGRAPH);
	OK(runner, !cmark_node_insert_before(doc, p),
	   "insert before root fails");
	OK(runner, !cmark_node_insert_after(doc, p),
	   "insert after root fails");
	OK(runner, cmark_node_append_child(doc, p), "append1");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append1 consistent");
	OK(runner, cmark_node_parent(p) == doc, "node_parent");

	cmark_node *emph = cmark_node_new(CMARK_NODE_EMPH);
	OK(runner, cmark_node_prepend_child(p, emph), "prepend1");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend1 consistent");

	cmark_node *str1 = cmark_node_new(CMARK_NODE_TEXT);
	cmark_node_set_literal(str1, "Hello, ");
	OK(runner, cmark_node_prepend_child(p, str1), "prepend2");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0, "prepend2 consistent");

	cmark_node *str3 = cmark_node_new(CMARK_NODE_TEXT);
	cmark_node_set_literal(str3, "!");
	OK(runner, cmark_node_append_child(p, str3), "append2");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append2 consistent");

	cmark_node *str2 = cmark_node_new(CMARK_NODE_TEXT);
	cmark_node_set_literal(str2, "world");
	OK(runner, cmark_node_append_child(emph, str2), "append3");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0, "append3 consistent");

	html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
	STR_EQ(runner, html, "<p>Hello, <em>world</em>!</p>\n",
	       "render_html");
	free(html);

	OK(runner, cmark_node_insert_before(str1, str3), "ins before1");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0,
	       "ins before1 consistent");
	// 31e
	OK(runner, cmark_node_first_child(p) == str3, "ins before1 works");

	OK(runner, cmark_node_insert_before(str1, emph), "ins before2");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0,
	       "ins before2 consistent");
	// 3e1
	OK(runner, cmark_node_last_child(p) == str1, "ins before2 works");

	OK(runner, cmark_node_insert_after(str1, str3), "ins after1");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0,
	       "ins after1 consistent");
	// e13
	OK(runner, cmark_node_next(str1) == str3, "ins after1 works");

	OK(runner, cmark_node_insert_after(str1, emph), "ins after2");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0,
	       "ins after2 consistent");
	// 1e3
	OK(runner, cmark_node_previous(emph) == str1, "ins after2 works");

	cmark_node_unlink(emph);

	html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
	STR_EQ(runner, html, "<p>Hello, !</p>\n",
	       "render_html after shuffling");
	free(html);

	cmark_node_free(doc);

	// TODO: Test that the contents of an unlinked inline are valid
	// after the parent block was destroyed. This doesn't work so far.
	cmark_node_free(emph);
}