Exemple #1
0
char*
CFCPerlPod_md_to_pod(const char *md, CFCClass *klass, int header_level) {
    int options = CMARK_OPT_SMART
                  | CMARK_OPT_VALIDATE_UTF8;
    cmark_node *doc = cmark_parse_document(md, strlen(md), options);
    char *pod = S_node_to_pod(doc, klass, header_level);
    cmark_node_free(doc);

    return pod;
}
char*
CFCPerlPod_md_to_pod(CFCPerlPod *self, CFCClass *klass, const char *md) {
    (void)self; // unused

    cmark_node *doc = cmark_parse_document(md, strlen(md));
    char *pod = S_nodes_to_pod(klass, doc);
    cmark_node_free(doc);

    return pod;
}
Exemple #3
0
char *cmark_markdown_to_html(const char *text, size_t len, int options) {
  cmark_node *doc;
  char *result;

  doc = cmark_parse_document(text, len, options);

  result = cmark_render_html(doc, options, NULL);
  cmark_node_free(doc);

  return result;
}
Exemple #4
0
char *cmark_markdown_to_html(const char *text, int len)
{
	cmark_node *doc;
	char *result;

	doc = cmark_parse_document(text, len, CMARK_OPT_DEFAULT);

	result = cmark_render_html(doc, CMARK_OPT_DEFAULT);
	cmark_node_free(doc);

	return result;
}
Exemple #5
0
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);
}
Exemple #6
0
static void
iterator_delete(test_batch_runner *runner) {
	static const char md[] =
		"a *b* c\n"
		"\n"
		"* item1\n"
		"* item2\n"
		"\n"
		"a `b` c\n"
		"\n"
		"* item1\n"
		"* item2\n";
	cmark_node *doc  = cmark_parse_document(md, sizeof(md) - 1,
						CMARK_OPT_DEFAULT);
	cmark_iter *iter = cmark_iter_new(doc);
	cmark_event_type ev_type;

	while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
		cmark_node *node = cmark_iter_get_node(iter);
		// Delete list, emph, and code nodes.
		if ((ev_type == CMARK_EVENT_EXIT &&
		     node->type == CMARK_NODE_LIST) ||
		    (ev_type == CMARK_EVENT_EXIT &&
		     node->type == CMARK_NODE_EMPH) ||
		    (ev_type == CMARK_EVENT_ENTER &&
		     node->type == CMARK_NODE_CODE)) {
			cmark_node_free(node);
		}
	}

	char *html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
	static const char expected[] =
		"<p>a  c</p>\n"
		"<p>a  c</p>\n";
	STR_EQ(runner, html, expected, "iterate and delete nodes");

	free(html);
	cmark_iter_free(iter);
	cmark_node_free(doc);
}
Exemple #7
0
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);
}
Exemple #8
0
static void md_escape_inline(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_INLINE_HTML != cmark_node_get_type(node)) continue;

		char const *const str = cmark_node_get_literal(node);
		cmark_node *text = cmark_node_new(CMARK_NODE_TEXT);
		cmark_node_set_literal(text, str);
		cmark_node_insert_before(node, text);
		cmark_node_free(node);
	}
}
Exemple #9
0
static void
iterator(test_batch_runner *runner) {
	cmark_node *doc = cmark_parse_document("> a *b*\n\nc", 10, CMARK_OPT_DEFAULT);
	int parnodes = 0;
	cmark_event_type ev_type;
	cmark_iter *iter = cmark_iter_new(doc);
	cmark_node *cur;

	while ((ev_type = cmark_iter_next(iter)) != CMARK_EVENT_DONE) {
		cur = cmark_iter_get_node(iter);
		if (cur->type == CMARK_NODE_PARAGRAPH &&
		    ev_type == CMARK_EVENT_ENTER) {
			parnodes += 1;
		}
	}
	INT_EQ(runner, parnodes, 2, "iterate correctly counts paragraphs");

	cmark_iter_free(iter);
	cmark_node_free(doc);
}
char*
CFCPerlPod_md_doc_to_pod(const char *module, const char *md) {
    int options = CMARK_OPT_SMART
                  | CMARK_OPT_VALIDATE_UTF8;
    cmark_node *doc = cmark_parse_document(md, strlen(md), options);
    cmark_node *maybe_header = cmark_node_first_child(doc);
    char *name;
    char *desc;

    if (maybe_header
        && cmark_node_get_type(maybe_header) == CMARK_NODE_HEADER
       ) {
        cmark_node *header_child = cmark_node_first_child(maybe_header);
        char *short_desc = S_nodes_to_pod(header_child, NULL, 1);
        name = CFCUtil_sprintf("%s - %s", module, short_desc);
        FREEMEM(short_desc);

        cmark_node *remaining = cmark_node_next(maybe_header);
        desc = S_nodes_to_pod(remaining, NULL, 1);
    }
    else {
        // No header found.
        name = CFCUtil_strdup(module);
        desc = S_node_to_pod(doc, NULL, 1);
    }

    const char *pattern =
        "=head1 NAME\n"
        "\n"
        "%s\n"
        "\n"
        "=head1 DESCRIPTION\n"
        "\n"
        "%s";
    char *retval = CFCUtil_sprintf(pattern, name, desc);

    FREEMEM(name);
    FREEMEM(desc);
    cmark_node_free(doc);
    return retval;
}
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;
}
Exemple #12
0
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);
	}
}
Exemple #13
0
int main(int argc, char *argv[])
{
	int i, numfps = 0;
	int *files;
	int ok;
	char buffer[4096];
	cmark_parser *parser;
	size_t bytes;
	cmark_node *document;
	char *outfile = NULL;
	int options = CMARK_OPT_DEFAULT | CMARK_OPT_SAFE | CMARK_OPT_NORMALIZE;

#if defined(_WIN32) && !defined(__CYGWIN__)
	_setmode(_fileno(stdout), _O_BINARY);
#endif

	files = (int *)malloc(argc * sizeof(*files));

	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "--version") == 0) {
			printf("cmark %s", CMARK_VERSION_STRING);
			printf(" - CommonMark converter\n(C) 2014, 2015 John MacFarlane\n");
			exit(0);
		} else if (strcmp(argv[i], "--sourcepos") == 0) {
			options |= CMARK_OPT_SOURCEPOS;
		} else if (strcmp(argv[i], "--hardbreaks") == 0) {
			options |= CMARK_OPT_HARDBREAKS;
		} else if (strcmp(argv[i], "--smart") == 0) {
			options |= CMARK_OPT_SMART;
		} else if (strcmp(argv[i], "--validate-utf8") == 0) {
			options |= CMARK_OPT_VALIDATE_UTF8;
		} else if ((strcmp(argv[i], "--help") == 0) ||
		           (strcmp(argv[i], "-h") == 0)) {
			print_usage();
			exit(0);
		} else if ((strcmp(argv[i], "-o") == 0) ||
		           (strcmp(argv[i], "--output") == 0)) {
			i += 1;
			if (i < argc) {
				outfile = argv[i];
			} else {
				fprintf(stderr, "No argument provided for %s\n",
				        argv[i - 1]);
				exit(1);
			}
		} else if (*argv[i] == '-') {
			print_usage();
			exit(1);
		} else { // treat as file argument
			files[numfps++] = i;
		}
	}

	if (!outfile) {
		fprintf(stderr, "Specify an output file with -o/--output\n");
		exit(1);
	}

	parser = cmark_parser_new(options);
	for (i = 0; i < numfps; i++) {
		FILE *fp = fopen(argv[files[i]], "r");
		if (fp == NULL) {
			fprintf(stderr, "Error opening file %s: %s\n",
			        argv[files[i]], strerror(errno));
			exit(1);
		}

		while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
			cmark_parser_feed(parser, buffer, bytes);
			if (bytes < sizeof(buffer)) {
				break;
			}
		}

		fclose(fp);
	}

	if (numfps == 0) {

		while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
			cmark_parser_feed(parser, buffer, bytes);
			if (bytes < sizeof(buffer)) {
				break;
			}
		}
	}

	document = cmark_parser_finish(parser);
	cmark_parser_free(parser);

	ok = cmark_render_pdf(document, options, outfile);

	free(files);
	cmark_node_free(document);

	return ok ? 0 : 1;
}
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;
}
Exemple #15
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;
}
Exemple #16
0
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);
}
Exemple #17
0
static cmark_node*
finalize(cmark_parser *parser, cmark_node* b)
{
	int pos;
	cmark_node* item;
	cmark_node* subitem;
	cmark_node* parent;

	parent = b->parent;

	assert(b->open);  // shouldn't call finalize on closed blocks
	b->open = false;

	if (parser->curline->size == 0) {
		// end of input - line number has not been incremented
		b->end_line = parser->line_number;
		b->end_column = parser->last_line_length;
	} else if (b->type == NODE_DOCUMENT ||
	           (b->type == NODE_CODE_BLOCK && b->as.code.fenced) ||
	           (b->type == NODE_HEADER && b->as.header.setext)) {
		b->end_line = parser->line_number;
		b->end_column = parser->curline->size;
		if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\n')
			b->end_column--;
		if (b->end_column && parser->curline->ptr[b->end_column - 1] == '\r')
			b->end_column--;
	} else {
		b->end_line = parser->line_number - 1;
		b->end_column = parser->last_line_length;
	}

	switch (b->type) {
	case NODE_PARAGRAPH:
		while (cmark_strbuf_at(&b->string_content, 0) == '[' &&
		       (pos = cmark_parse_reference_inline(&b->string_content, parser->refmap))) {

			cmark_strbuf_drop(&b->string_content, pos);
		}
		if (is_blank(&b->string_content, 0)) {
			// remove blank node (former reference def)
			cmark_node_free(b);
		}
		break;

	case NODE_CODE_BLOCK:
		if (!b->as.code.fenced) { // indented code
			remove_trailing_blank_lines(&b->string_content);
			cmark_strbuf_putc(&b->string_content, '\n');
		} else {

			// first line of contents becomes info
			for (pos = 0; pos < b->string_content.size; ++pos) {
				if (b->string_content.ptr[pos] == '\r' ||
				    b->string_content.ptr[pos] == '\n')
					break;
			}
			assert(pos < b->string_content.size);

			cmark_strbuf tmp = GH_BUF_INIT;
			houdini_unescape_html_f(
			    &tmp,
			    b->string_content.ptr,
			    pos
			);
			cmark_strbuf_trim(&tmp);
			cmark_strbuf_unescape(&tmp);
			b->as.code.info = cmark_chunk_buf_detach(&tmp);

			if (b->string_content.ptr[pos] == '\r')
				pos += 1;
			if (b->string_content.ptr[pos] == '\n')
				pos += 1;
			cmark_strbuf_drop(&b->string_content, pos);
		}
		b->as.code.literal = cmark_chunk_buf_detach(&b->string_content);
		break;

	case NODE_HTML:
		b->as.literal = cmark_chunk_buf_detach(&b->string_content);
		break;

	case NODE_LIST: // determine tight/loose status
		b->as.list.tight = true; // tight by default
		item = b->first_child;

		while (item) {
			// check for non-final non-empty list item ending with blank line:
			if (item->last_line_blank && item->next) {
				b->as.list.tight = false;
				break;
			}
			// recurse into children of list item, to see if there are
			// spaces between them:
			subitem = item->first_child;
			while (subitem) {
				if (ends_with_blank_line(subitem) &&
				    (item->next || subitem->next)) {
					b->as.list.tight = false;
					break;
				}
				subitem = subitem->next;
			}
			if (!(b->as.list.tight)) {
				break;
			}
			item = item->next;
		}

		break;

	default:
		break;
	}
	return parent;
}
Exemple #18
0
static void
accessors(test_batch_runner *runner)
{
	static const char markdown[] =
		"## Header\n"
		"\n"
		"* Item 1\n"
		"* Item 2\n"
		"\n"
		"2. Item 1\n"
		"\n"
		"3. Item 2\n"
		"\n"
		"\n"
		"    code\n"
		"\n"
		"``` lang\n"
		"fenced\n"
		"```\n"
		"\n"
		"<div>html</div>\n"
		"\n"
		"[link](url 'title')\n";

	cmark_node *doc = cmark_parse_document(markdown, sizeof(markdown) - 1, CMARK_OPT_DEFAULT);

	// Getters

	cmark_node *header = cmark_node_first_child(doc);
	INT_EQ(runner, cmark_node_get_header_level(header), 2,
	       "get_header_level");

	cmark_node *bullet_list = cmark_node_next(header);
	INT_EQ(runner, cmark_node_get_list_type(bullet_list),
	       CMARK_BULLET_LIST, "get_list_type bullet");
	INT_EQ(runner, cmark_node_get_list_tight(bullet_list), 1,
	       "get_list_tight tight");

	cmark_node *ordered_list = cmark_node_next(bullet_list);
	INT_EQ(runner, cmark_node_get_list_type(ordered_list),
	       CMARK_ORDERED_LIST, "get_list_type ordered");
	INT_EQ(runner, cmark_node_get_list_delim(ordered_list),
	       CMARK_PERIOD_DELIM, "get_list_delim ordered");
	INT_EQ(runner, cmark_node_get_list_start(ordered_list), 2,
	       "get_list_start");
	INT_EQ(runner, cmark_node_get_list_tight(ordered_list), 0,
	       "get_list_tight loose");

	cmark_node *code = cmark_node_next(ordered_list);
	STR_EQ(runner, cmark_node_get_literal(code), "code\n",
	       "get_literal indented code");

	cmark_node *fenced = cmark_node_next(code);
	STR_EQ(runner, cmark_node_get_literal(fenced), "fenced\n",
	       "get_literal fenced code");
	STR_EQ(runner, cmark_node_get_fence_info(fenced), "lang",
	       "get_fence_info");

	cmark_node *html = cmark_node_next(fenced);
	STR_EQ(runner, cmark_node_get_literal(html),
	       "<div>html</div>\n", "get_literal html");

	cmark_node *paragraph = cmark_node_next(html);
	INT_EQ(runner, cmark_node_get_start_line(paragraph), 19,
	       "get_start_line");
	INT_EQ(runner, cmark_node_get_start_column(paragraph), 1,
	       "get_start_column");
	INT_EQ(runner, cmark_node_get_end_line(paragraph), 19,
	       "get_end_line");

	cmark_node *link = cmark_node_first_child(paragraph);
	STR_EQ(runner, cmark_node_get_url(link), "url",
	       "get_url");
	STR_EQ(runner, cmark_node_get_title(link), "title",
	       "get_title");

	cmark_node *string = cmark_node_first_child(link);
	STR_EQ(runner, cmark_node_get_literal(string), "link",
	       "get_literal string");

	// Setters

	OK(runner, cmark_node_set_header_level(header, 3),
	   "set_header_level");

	OK(runner, cmark_node_set_list_type(bullet_list, CMARK_ORDERED_LIST),
	   "set_list_type ordered");
	OK(runner, cmark_node_set_list_delim(bullet_list, CMARK_PAREN_DELIM),
	   "set_list_delim paren");
	OK(runner, cmark_node_set_list_start(bullet_list, 3),
	   "set_list_start");
	OK(runner, cmark_node_set_list_tight(bullet_list, 0),
	   "set_list_tight loose");

	OK(runner, cmark_node_set_list_type(ordered_list, CMARK_BULLET_LIST),
	   "set_list_type bullet");
	OK(runner, cmark_node_set_list_tight(ordered_list, 1),
	   "set_list_tight tight");

	OK(runner, cmark_node_set_literal(code, "CODE\n"),
	   "set_literal indented code");

	OK(runner, cmark_node_set_literal(fenced, "FENCED\n"),
	   "set_literal fenced code");
	OK(runner, cmark_node_set_fence_info(fenced, "LANG"),
	   "set_fence_info");

	OK(runner, cmark_node_set_literal(html, "<div>HTML</div>\n"),
	   "set_literal html");

	OK(runner, cmark_node_set_url(link, "URL"),
	   "set_url");
	OK(runner, cmark_node_set_title(link, "TITLE"),
	   "set_title");

	OK(runner, cmark_node_set_literal(string, "LINK"),
	   "set_literal string");

	char *rendered_html = cmark_render_html(doc, CMARK_OPT_DEFAULT);
	static const char expected_html[] =
		"<h3>Header</h3>\n"
		"<ol start=\"3\">\n"
		"<li>\n"
		"<p>Item 1</p>\n"
		"</li>\n"
		"<li>\n"
		"<p>Item 2</p>\n"
		"</li>\n"
		"</ol>\n"
		"<ul>\n"
		"<li>Item 1</li>\n"
		"<li>Item 2</li>\n"
		"</ul>\n"
		"<pre><code>CODE\n"
		"</code></pre>\n"
		"<pre><code class=\"language-LANG\">FENCED\n"
		"</code></pre>\n"
		"<div>HTML</div>\n"
		"<p><a href=\"URL\" title=\"TITLE\">LINK</a></p>\n";
	STR_EQ(runner, rendered_html, expected_html, "setters work");
	free(rendered_html);

	// Getter errors

	INT_EQ(runner, cmark_node_get_header_level(bullet_list), 0,
	       "get_header_level error");
	INT_EQ(runner, cmark_node_get_list_type(header), CMARK_NO_LIST,
	       "get_list_type error");
	INT_EQ(runner, cmark_node_get_list_start(code), 0,
	       "get_list_start error");
	INT_EQ(runner, cmark_node_get_list_tight(fenced), 0,
	       "get_list_tight error");
	OK(runner, cmark_node_get_literal(ordered_list) == NULL,
	   "get_literal error");
	OK(runner, cmark_node_get_fence_info(paragraph) == NULL,
	   "get_fence_info error");
	OK(runner, cmark_node_get_url(html) == NULL,
	   "get_url error");
	OK(runner, cmark_node_get_title(header) == NULL,
	   "get_title error");

	// Setter errors

	OK(runner, !cmark_node_set_header_level(bullet_list, 3),
	   "set_header_level error");
	OK(runner, !cmark_node_set_list_type(header, CMARK_ORDERED_LIST),
	   "set_list_type error");
	OK(runner, !cmark_node_set_list_start(code, 3),
	   "set_list_start error");
	OK(runner, !cmark_node_set_list_tight(fenced, 0),
	   "set_list_tight error");
	OK(runner, !cmark_node_set_literal(ordered_list, "content\n"),
	   "set_literal error");
	OK(runner, !cmark_node_set_fence_info(paragraph, "lang"),
	   "set_fence_info error");
	OK(runner, !cmark_node_set_url(html, "url"),
	   "set_url error");
	OK(runner, !cmark_node_set_title(header, "title"),
	   "set_title error");

	OK(runner, !cmark_node_set_header_level(header, 0),
	   "set_header_level too small");
	OK(runner, !cmark_node_set_header_level(header, 7),
	   "set_header_level too large");
	OK(runner, !cmark_node_set_list_type(bullet_list, CMARK_NO_LIST),
	   "set_list_type invalid");
	OK(runner, !cmark_node_set_list_start(bullet_list, -1),
	   "set_list_start negative");

	cmark_node_free(doc);
}
Exemple #19
0
static cmark_node*
finalize(cmark_parser *parser, cmark_node* b, int line_number)
{
	int firstlinelen;
	int pos;
	cmark_node* item;
	cmark_node* subitem;
	cmark_node* parent;

	parent = b->parent;

	// don't do anything if the cmark_node is already closed
	if (!b->open)
		return parent;

	b->open = false;
	if (line_number > b->start_line) {
		b->end_line = line_number - 1;
	} else {
		b->end_line = line_number;
	}

	switch (b->type) {
		case NODE_PARAGRAPH:
			while (cmark_strbuf_at(&b->string_content, 0) == '[' &&
					(pos = cmark_parse_reference_inline(&b->string_content, parser->refmap))) {

				cmark_strbuf_drop(&b->string_content, pos);
			}
			if (is_blank(&b->string_content, 0)) {
				// remove blank node (former reference def)
				cmark_node_free(b);
			}
			break;

		case NODE_CODE_BLOCK:
			if (!b->as.code.fenced) { // indented code
				remove_trailing_blank_lines(&b->string_content);
				cmark_strbuf_putc(&b->string_content, '\n');
			} else {

				// first line of contents becomes info
				firstlinelen = cmark_strbuf_strchr(&b->string_content, '\n', 0);

				cmark_strbuf tmp = GH_BUF_INIT;
				houdini_unescape_html_f(
					&tmp,
					b->string_content.ptr,
					firstlinelen
					);
				cmark_strbuf_trim(&tmp);
				cmark_strbuf_unescape(&tmp);
				b->as.code.info = cmark_chunk_buf_detach(&tmp);

				cmark_strbuf_drop(&b->string_content, firstlinelen + 1);
			}
			b->as.code.literal = cmark_chunk_buf_detach(&b->string_content);
			break;

	        case NODE_HTML:
			b->as.literal = cmark_chunk_buf_detach(&b->string_content);
			break;

		case NODE_LIST: // determine tight/loose status
			b->as.list.tight = true; // tight by default
			item = b->first_child;

			while (item) {
				// check for non-final non-empty list item ending with blank line:
				if (item->last_line_blank && item->next) {
					b->as.list.tight = false;
					break;
				}
				// recurse into children of list item, to see if there are
				// spaces between them:
				subitem = item->first_child;
				while (subitem) {
					if (ends_with_blank_line(subitem) &&
							(item->next || subitem->next)) {
						b->as.list.tight = false;
						break;
					}
					subitem = subitem->next;
				}
				if (!(b->as.list.tight)) {
					break;
				}
				item = item->next;
			}

			break;

		default:
			break;
	}
	return parent;
}
Exemple #20
0
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);
}
Exemple #21
0
static delimiter*
S_insert_emph(subject *subj, delimiter *opener, delimiter *closer)
{
	delimiter *delim, *tmp_delim;
	int use_delims;
	cmark_node *opener_inl = opener->inl_text;
	cmark_node *closer_inl = closer->inl_text;
	int opener_num_chars = opener_inl->as.literal.len;
	int closer_num_chars = closer_inl->as.literal.len;
	cmark_node *tmp, *emph, *first_child, *last_child;

	// calculate the actual number of characters used from this closer
	if (closer_num_chars < 3 || opener_num_chars < 3) {
		use_delims = closer_num_chars <= opener_num_chars ?
		             closer_num_chars : opener_num_chars;
	} else { // closer and opener both have >= 3 characters
		use_delims = closer_num_chars % 2 == 0 ? 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;
	}

	first_child = opener_inl->next;
	last_child  = closer_inl->prev;

	// if opener has 0 characters, remove it and its associated inline
	if (opener_num_chars == 0) {
		// replace empty opener inline with emph
		cmark_chunk_free(&(opener_inl->as.literal));
		emph = opener_inl;
		emph->type = use_delims == 1 ? NODE_EMPH : NODE_STRONG;
		// remove opener from list
		remove_delimiter(subj, opener);
	} else {
		// create new emph or strong, and splice it in to our inlines
		// between the opener and closer
		emph = use_delims == 1 ? make_emph() : make_strong();
		emph->parent = opener_inl->parent;
		emph->prev = opener_inl;
		opener_inl->next = emph;
	}

	// push children below emph
	emph->next = closer_inl;
	closer_inl->prev = emph;
	emph->first_child = first_child;
	emph->last_child  = last_child;

	// fix children pointers
	first_child->prev = NULL;
	last_child->next  = NULL;
	for (tmp = first_child; tmp != NULL; tmp = tmp->next) {
		tmp->parent = emph;
	}

	// 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;
}
Exemple #22
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
  if (closer_num_chars < 3 || opener_num_chars < 3) {
    use_delims = closer_num_chars <= opener_num_chars ? closer_num_chars
                                                      : opener_num_chars;
  } else { // closer and opener both have >= 3 characters
    use_delims = closer_num_chars % 2 == 0 ? 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;
}
Exemple #23
0
int main(int argc, char *argv[]) {
  int i, numfps = 0;
  int *files;
  char buffer[4096];
  cmark_parser *parser;
  size_t bytes;
  cmark_node *document;
  int width = 0;
  char *unparsed;
  writer_format writer = FORMAT_HTML;
  int options = CMARK_OPT_DEFAULT;

#if defined(_WIN32) && !defined(__CYGWIN__)
  _setmode(_fileno(stdout), _O_BINARY);
#endif

  files = (int *)malloc(argc * sizeof(*files));

  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "--version") == 0) {
      printf("cmark %s", CMARK_VERSION_STRING);
      printf(" - CommonMark converter\n(C) 2014, 2015 John MacFarlane\n");
      exit(0);
    } else if (strcmp(argv[i], "--sourcepos") == 0) {
      options |= CMARK_OPT_SOURCEPOS;
    } else if (strcmp(argv[i], "--hardbreaks") == 0) {
      options |= CMARK_OPT_HARDBREAKS;
    } else if (strcmp(argv[i], "--smart") == 0) {
      options |= CMARK_OPT_SMART;
    } else if (strcmp(argv[i], "--safe") == 0) {
      options |= CMARK_OPT_SAFE;
    } else if (strcmp(argv[i], "--normalize") == 0) {
      options |= CMARK_OPT_NORMALIZE;
    } else if (strcmp(argv[i], "--validate-utf8") == 0) {
      options |= CMARK_OPT_VALIDATE_UTF8;
    } else if ((strcmp(argv[i], "--help") == 0) ||
               (strcmp(argv[i], "-h") == 0)) {
      print_usage();
      exit(0);
    } else if (strcmp(argv[i], "--width") == 0) {
      i += 1;
      if (i < argc) {
        width = (int)strtol(argv[i], &unparsed, 10);
        if (unparsed && strlen(unparsed) > 0) {
          fprintf(stderr, "failed parsing width '%s' at '%s'\n", argv[i],
                  unparsed);
          exit(1);
        }
      } else {
        fprintf(stderr, "--width requires an argument\n");
        exit(1);
      }
    } else if ((strcmp(argv[i], "-t") == 0) || (strcmp(argv[i], "--to") == 0)) {
      i += 1;
      if (i < argc) {
        if (strcmp(argv[i], "man") == 0) {
          writer = FORMAT_MAN;
        } else if (strcmp(argv[i], "html") == 0) {
          writer = FORMAT_HTML;
        } else if (strcmp(argv[i], "xml") == 0) {
          writer = FORMAT_XML;
        } else if (strcmp(argv[i], "commonmark") == 0) {
          writer = FORMAT_COMMONMARK;
        } else if (strcmp(argv[i], "latex") == 0) {
          writer = FORMAT_LATEX;
        } else {
          fprintf(stderr, "Unknown format %s\n", argv[i]);
          exit(1);
        }
      } else {
        fprintf(stderr, "No argument provided for %s\n", argv[i - 1]);
        exit(1);
      }
    } else if (*argv[i] == '-') {
      print_usage();
      exit(1);
    } else { // treat as file argument
      files[numfps++] = i;
    }
  }

  parser = cmark_parser_new(options);
  for (i = 0; i < numfps; i++) {
    FILE *fp = fopen(argv[files[i]], "rb");
    if (fp == NULL) {
      fprintf(stderr, "Error opening file %s: %s\n", argv[files[i]],
              strerror(errno));
      exit(1);
    }

    while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
      cmark_parser_feed(parser, buffer, bytes);
      if (bytes < sizeof(buffer)) {
        break;
      }
    }

    fclose(fp);
  }

  if (numfps == 0) {

    while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
      cmark_parser_feed(parser, buffer, bytes);
      if (bytes < sizeof(buffer)) {
        break;
      }
    }
  }

  document = cmark_parser_finish(parser);
  cmark_parser_free(parser);

  print_document(document, writer, options, width);

  cmark_node_free(document);

  free(files);

  return 0;
}
Exemple #24
0
int main(int argc, char *argv[])
{
	int i, numfps = 0;
	bool ast = false;
	int *files;
	char buffer[4096];
	cmark_parser *parser;
	size_t bytes;
	cmark_node *document;

	parser = cmark_parser_new();
	files = (int *)malloc(argc * sizeof(*files));

	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "--version") == 0) {
			printf("cmark %s", CMARK_VERSION);
			printf(" - CommonMark converter (c) 2014 John MacFarlane\n");
			exit(0);
		} else if ((strcmp(argv[i], "--help") == 0) ||
			   (strcmp(argv[i], "-h") == 0)) {
			print_usage();
			exit(0);
		} else if (strcmp(argv[i], "--ast") == 0) {
			ast = true;
		} else if (*argv[i] == '-') {
			print_usage();
			exit(1);
		} else { // treat as file argument
			files[numfps++] = i;
		}
	}

	for (i = 0; i < numfps; i++) {
		FILE *fp = fopen(argv[files[i]], "r");
		if (fp == NULL) {
			fprintf(stderr, "Error opening file %s: %s\n",
				argv[files[i]], strerror(errno));
			exit(1);
		}

		start_timer();
		while ((bytes = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
			cmark_parser_feed(parser, buffer, bytes);
		}
		end_timer("processing lines");

		fclose(fp);
	}

	if (numfps == 0) {
		/*
		document = cmark_parse_file(stdin);
		print_document(document, ast);
		exit(0);
		*/

		while ((bytes = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
			cmark_parser_feed(parser, buffer, bytes);
		}
	}

	start_timer();
	document = cmark_parser_finish(parser);
	end_timer("finishing document");
	cmark_parser_free(parser);

	start_timer();
	print_document(document, ast);
	end_timer("print_document");

	start_timer();
	cmark_node_free(document);
	end_timer("free_blocks");

	free(files);

	return 0;
}