示例#1
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;
}
示例#2
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);
	}
}
示例#3
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);
}
示例#4
0
static cmark_node *symbol_link_match(cmark_syntax_extension *self,
                                     cmark_parser *parser,
                                     cmark_node *parent,
                                     cmark_inline_parser *inline_parser) {
    cmark_node *link = NULL;
    char *symbol_name = NULL;
    NamedLink *named_link = NULL;
    int start_offset = cmark_inline_parser_get_offset(inline_parser);
    ParsingContext context;

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

    if (start_offset > 0) {
        char prev_char = cmark_inline_parser_peek_at(
                             inline_parser,
                             start_offset - 1);

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

    cmark_inline_parser_advance_offset(inline_parser);

    symbol_name = cmark_inline_parser_take_while(inline_parser,
                  (CMarkInlinePredicate) is_valid_symbol_name, &context);

    if (!symbol_name)
        goto done;

    named_link = PRIV(self)->link_resolve_func(symbol_name);
    if (!named_link || !named_link->ref) {
        int actual_line, actual_col;

        translate_sourcepos(get_first_parent_block(parent),
                            start_offset, &actual_line, &actual_col);
        cmark_strbuf *message = cmark_strbuf_new(0);
        cmark_strbuf_puts(message, "Trying to link to non-existing symbol ‘");
        cmark_strbuf_puts(message, symbol_name);
        cmark_strbuf_puts(message, "’");
        diagnose("gtk-doc-bad-link", cmark_strbuf_get(message), actual_line - 1, actual_col - 1);
        cmark_strbuf_free(message);
        link = cmark_node_new (CMARK_NODE_TEXT);
        cmark_node_set_literal (link, symbol_name);
    } else {
        link = cmark_node_new(CMARK_NODE_LINK);
    }

    cmark_node_set_url(link, symbol_name);

done:
    free(symbol_name);
    free_named_link(named_link);

    return link;
}
示例#5
0
文件: main.c 项目: txdv/cmark
static void
node_check(test_batch_runner *runner) {
	// Construct an incomplete tree.
	cmark_node *doc = cmark_node_new(CMARK_NODE_DOCUMENT);
	cmark_node *p1  = cmark_node_new(CMARK_NODE_PARAGRAPH);
	cmark_node *p2  = cmark_node_new(CMARK_NODE_PARAGRAPH);
	doc->first_child = p1;
	p1->next = p2;

	INT_EQ(runner, cmark_node_check(doc, NULL), 4, "node_check works");
	INT_EQ(runner, cmark_node_check(doc, NULL), 0,
	       "node_check fixes tree");

	cmark_node_free(doc);
}
示例#6
0
static cmark_node *symbol_link_match(cmark_syntax_extension *self,
                                cmark_parser *parser,
                                cmark_node *parent,
                                cmark_inline_parser *inline_parser) {
  cmark_node *link;
  char *symbol_name;

  if (cmark_inline_parser_get_offset(inline_parser) > 0) {
    char 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);

  symbol_name = cmark_inline_parser_take_while(inline_parser,
      (CMarkInlinePredicate) is_valid_symbol_name);

  if (!symbol_name)
    return NULL;

  link = cmark_node_new(CMARK_NODE_LINK);

  cmark_node_set_url(link, symbol_name);
  free(symbol_name);

  return link;
}
示例#7
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);
	}
}
示例#8
0
static cmark_node *fixup_nodes(cmark_inline_parser *inline_parser,
                                  cmark_node *parent,
                                  int size)
{
  int node_text_len;
  cmark_node *prev = NULL;
  cmark_node *tmp;
  int name_size = size;
  cmark_strbuf *name;

  for (prev = cmark_node_last_child(parent); prev; prev = cmark_node_previous(prev)) {
    if (cmark_node_get_type(prev) == CMARK_NODE_TEXT) {
      const char *text = cmark_node_get_literal(prev);
      node_text_len = strlen(text);
      size -= node_text_len;

      if (size <= 0) {
        if (size < 0) {
          char *split_text = my_strndup(text, size * -1);
          cmark_node *split = cmark_node_new(CMARK_NODE_TEXT);

          cmark_node_set_literal(split, split_text);
          free(split_text);

          split_text = my_strndup(text + (size * - 1), node_text_len - size);
          cmark_node_set_literal(prev, split_text);
          free(split_text);

          cmark_node_insert_before(prev, split);
        }
        break;
      }
    } else {
      return NULL;
    }
  }

  name = cmark_strbuf_new(name_size + 1);

  tmp = prev;

  while (tmp) {
    cmark_node *next = cmark_node_next(tmp);

    cmark_strbuf_puts(name, cmark_node_get_literal(tmp));
    if (tmp != prev)
      cmark_node_free(tmp);
    tmp = next;
  }

  cmark_node_set_type(prev, CMARK_NODE_LINK);
  cmark_node_set_url(prev, cmark_strbuf_get(name));

  cmark_strbuf_free(name);

  return prev;
}
示例#9
0
文件: main.c 项目: 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);
}
示例#10
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;
}
示例#11
0
文件: main.c 项目: txdv/cmark
static void
constructor(test_batch_runner *runner)
{
	for (int i = 0; i < num_node_types; ++i) {
		cmark_node_type type = node_types[i];
		cmark_node *node = cmark_node_new(type);
		OK(runner, node != NULL, "new type %d", type);
		INT_EQ(runner, cmark_node_get_type(node), type,
		       "get_type %d", type);

		switch (node->type) {
		case CMARK_NODE_HEADER:
			INT_EQ(runner, cmark_node_get_header_level(node), 1,
			       "default header level is 1");
			node->as.header.level = 1;
			break;

		case CMARK_NODE_LIST:
			INT_EQ(runner, cmark_node_get_list_type(node),
			       CMARK_BULLET_LIST,
			       "default is list type is bullet");
			INT_EQ(runner, cmark_node_get_list_delim(node),
			       CMARK_NO_DELIM,
			       "default is list delim is NO_DELIM");
			INT_EQ(runner, cmark_node_get_list_start(node), 1,
			       "default is list start is 1");
			INT_EQ(runner, cmark_node_get_list_tight(node), 0,
			       "default is list is loose");
			break;

		default:
			break;
		}

		cmark_node_free(node);
	}
}
示例#12
0
static cmark_node *fixup_nodes(cmark_syntax_extension *self,
                               cmark_parser *parser,
                               cmark_inline_parser *inline_parser,
                               cmark_node *parent,
                               int start_offset,
                               int size)
{
    int node_text_len;
    cmark_node *prev = NULL;
    cmark_node *tmp;
    int name_size = size;
    cmark_strbuf *name;
    NamedLink *named_link;

    for (prev = cmark_node_last_child(parent); prev; prev = cmark_node_previous(prev)) {
        if (cmark_node_get_type(prev) == CMARK_NODE_TEXT) {
            const char *text = cmark_node_get_literal(prev);
            node_text_len = strlen(text);
            size -= node_text_len;

            if (size <= 0) {
                if (size < 0) {
                    char *split_text = my_strndup(text, size * -1);
                    cmark_node *split = cmark_node_new(CMARK_NODE_TEXT);

                    cmark_node_set_literal(split, split_text);
                    free(split_text);

                    split_text = my_strndup(text + (size * - 1), node_text_len - size);
                    cmark_node_set_literal(prev, split_text);
                    free(split_text);

                    cmark_node_insert_before(prev, split);
                }
                break;
            }
        } else {
            return NULL;
        }
    }

    name = cmark_strbuf_new(name_size + 1);

    tmp = prev;

    while (tmp) {
        cmark_node *next = cmark_node_next(tmp);

        cmark_strbuf_puts(name, cmark_node_get_literal(tmp));
        if (tmp != prev)
            cmark_node_free(tmp);
        tmp = next;
    }

    named_link = PRIV(self)->link_resolve_func(cmark_strbuf_get(name));

    if (!named_link || !named_link->ref) {
        int actual_line, actual_col;

        translate_sourcepos(get_first_parent_block(parent),
                            start_offset, &actual_line, &actual_col);

        cmark_strbuf *message = cmark_strbuf_new(0);
        cmark_strbuf_puts(message, "Trying to link to non-existing symbol ‘");
        cmark_strbuf_puts(message, cmark_strbuf_get(name));
        cmark_strbuf_puts(message, "’");
        diagnose("gtk-doc-bad-link", cmark_strbuf_get(message), actual_line - 1,
                 actual_col - 1);
        cmark_strbuf_free(message);
        cmark_node_set_literal(prev, cmark_strbuf_get(name));
        cmark_strbuf_free(name);
        return prev;
    }

    free_named_link(named_link);

    cmark_node_set_type(prev, CMARK_NODE_LINK);
    cmark_node_set_url(prev, cmark_strbuf_get(name));

    cmark_strbuf_free(name);

    return prev;
}
示例#13
0
文件: main.c 项目: 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);
}
示例#14
0
文件: main.c 项目: 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);
}